From 41974ae5265fbc23a06f276f9e008d5dad020e0b Mon Sep 17 00:00:00 2001 From: Ben Longbons Date: Thu, 30 Aug 2012 16:16:25 -0700 Subject: Rename files for C++ conversion. Does not compile. After updating, you can remove these files, as shown in 'git status': Untracked files: (use "git add ..." to include in what will be committed) src/map/magic-interpreter-lexer.c src/map/magic-interpreter-parser.c src/map/magic-interpreter-parser.h --- .gitignore | 9 +- GNUmakefile | 43 +- deps.make | 308 - make.defs | 15 +- src/char/char.c | 4076 ----------- src/char/char.cpp | 4076 +++++++++++ src/char/char.h | 32 - src/char/char.hpp | 32 + src/char/int_guild.c | 1757 ----- src/char/int_guild.cpp | 1757 +++++ src/char/int_guild.h | 16 - src/char/int_guild.hpp | 16 + src/char/int_party.c | 673 -- src/char/int_party.cpp | 673 ++ src/char/int_party.h | 14 - src/char/int_party.hpp | 14 + src/char/int_storage.c | 576 -- src/char/int_storage.cpp | 576 ++ src/char/int_storage.h | 18 - src/char/int_storage.hpp | 18 + src/char/inter.c | 635 -- src/char/inter.cpp | 635 ++ src/char/inter.h | 19 - src/char/inter.hpp | 19 + src/common/core.c | 97 - src/common/core.cpp | 97 + src/common/core.h | 19 - src/common/core.hpp | 19 + src/common/db.c | 546 -- src/common/db.cpp | 546 ++ src/common/db.h | 87 - src/common/db.hpp | 87 + src/common/grfio.c | 212 - src/common/grfio.cpp | 212 + src/common/grfio.h | 17 - src/common/grfio.hpp | 17 + src/common/lock.c | 36 - src/common/lock.cpp | 36 + src/common/lock.h | 8 - src/common/lock.hpp | 8 + src/common/md5calc.c | 339 - src/common/md5calc.cpp | 339 + src/common/md5calc.h | 64 - src/common/md5calc.hpp | 64 + src/common/mmo.h | 283 - src/common/mmo.hpp | 283 + src/common/mt_rand.c | 116 - src/common/mt_rand.cpp | 116 + src/common/mt_rand.h | 24 - src/common/mt_rand.hpp | 24 + src/common/nullpo.c | 66 - src/common/nullpo.cpp | 66 + src/common/nullpo.h | 61 - src/common/nullpo.hpp | 61 + src/common/sanity.h | 36 - src/common/sanity.hpp | 31 + src/common/socket.c | 405 -- src/common/socket.cpp | 405 ++ src/common/socket.h | 135 - src/common/socket.hpp | 135 + src/common/timer.c | 257 - src/common/timer.cpp | 257 + src/common/timer.h | 61 - src/common/timer.hpp | 61 + src/common/utils.h | 18 - src/common/utils.hpp | 18 + src/common/version.h | 24 - src/common/version.hpp | 24 + src/ladmin/ladmin.c | 6476 ----------------- src/ladmin/ladmin.cpp | 6476 +++++++++++++++++ src/ladmin/ladmin.h | 11 - src/ladmin/ladmin.hpp | 11 + src/login/login.c | 5038 -------------- src/login/login.cpp | 5038 ++++++++++++++ src/login/login.h | 41 - src/login/login.hpp | 41 + src/map/atcommand.c | 8728 ----------------------- src/map/atcommand.cpp | 8728 +++++++++++++++++++++++ src/map/atcommand.h | 226 - src/map/atcommand.hpp | 226 + src/map/battle.c | 6282 ----------------- src/map/battle.cpp | 6282 +++++++++++++++++ src/map/battle.h | 357 - src/map/battle.hpp | 357 + src/map/chat.c | 395 -- src/map/chat.cpp | 395 ++ src/map/chat.h | 25 - src/map/chat.hpp | 25 + src/map/chrif.c | 1307 ---- src/map/chrif.cpp | 1307 ++++ src/map/chrif.h | 36 - src/map/chrif.hpp | 36 + src/map/clif.c | 10332 --------------------------- src/map/clif.cpp | 10332 +++++++++++++++++++++++++++ src/map/clif.h | 285 - src/map/clif.hpp | 285 + src/map/guild.c | 1915 ----- src/map/guild.cpp | 1915 +++++ src/map/guild.h | 95 - src/map/guild.hpp | 95 + src/map/intif.c | 1201 ---- src/map/intif.cpp | 1201 ++++ src/map/intif.h | 56 - src/map/intif.hpp | 56 + src/map/itemdb.c | 753 -- src/map/itemdb.cpp | 753 ++ src/map/itemdb.h | 82 - src/map/itemdb.hpp | 82 + src/map/magic-expr-eval.h | 44 - src/map/magic-expr-eval.hpp | 44 + src/map/magic-expr.c | 1655 ----- src/map/magic-expr.cpp | 1655 +++++ src/map/magic-expr.h | 95 - src/map/magic-expr.hpp | 95 + src/map/magic-interpreter-aux.h | 8 - src/map/magic-interpreter-aux.hpp | 8 + src/map/magic-interpreter-base.c | 562 -- src/map/magic-interpreter-base.cpp | 562 ++ src/map/magic-interpreter-lexer.l | 140 - src/map/magic-interpreter-lexer.lpp | 140 + src/map/magic-interpreter-parser.y | 1089 --- src/map/magic-interpreter-parser.ypp | 1089 +++ src/map/magic-interpreter.h | 500 -- src/map/magic-interpreter.hpp | 500 ++ src/map/magic-stmt.c | 1597 ----- src/map/magic-stmt.cpp | 1597 +++++ src/map/magic.c | 130 - src/map/magic.cpp | 130 + src/map/magic.h | 90 - src/map/magic.hpp | 90 + src/map/map.c | 2215 ------ src/map/map.cpp | 2215 ++++++ src/map/map.h | 822 --- src/map/map.hpp | 822 +++ src/map/mob.c | 5070 -------------- src/map/mob.cpp | 5070 ++++++++++++++ src/map/mob.h | 151 - src/map/mob.hpp | 151 + src/map/npc.c | 2378 ------- src/map/npc.cpp | 2378 +++++++ src/map/npc.h | 64 - src/map/npc.hpp | 64 + src/map/party.c | 790 --- src/map/party.cpp | 790 +++ src/map/party.h | 52 - src/map/party.hpp | 52 + src/map/path.c | 445 -- src/map/path.cpp | 445 ++ src/map/pc.c | 9032 ------------------------ src/map/pc.cpp | 9032 ++++++++++++++++++++++++ src/map/pc.h | 210 - src/map/pc.hpp | 210 + src/map/script.c | 8145 ---------------------- src/map/script.cpp | 8145 ++++++++++++++++++++++ src/map/script.h | 52 - src/map/script.hpp | 52 + src/map/skill-pools.c | 158 - src/map/skill-pools.cpp | 158 + src/map/skill.c | 12279 --------------------------------- src/map/skill.cpp | 12279 +++++++++++++++++++++++++++++++++ src/map/skill.h | 891 --- src/map/skill.hpp | 891 +++ src/map/storage.c | 787 --- src/map/storage.cpp | 787 +++ src/map/storage.h | 54 - src/map/storage.hpp | 54 + src/map/tmw.c | 187 - src/map/tmw.cpp | 187 + src/map/tmw.h | 14 - src/map/tmw.hpp | 14 + src/map/trade.c | 432 -- src/map/trade.cpp | 432 ++ src/map/trade.h | 14 - src/map/trade.hpp | 14 + src/tool/adduser.c | 115 - src/tool/adduser.cpp | 115 + src/tool/convert.c | 302 - src/tool/convert.cpp | 302 + src/tool/eathena-monitor.c | 223 - src/tool/eathena-monitor.cpp | 223 + src/tool/itemfrob.c | 130 - src/tool/itemfrob.cpp | 130 + src/tool/mapfrob.c | 129 - src/tool/mapfrob.cpp | 129 + src/tool/marriage-info.c | 482 -- src/tool/marriage-info.cpp | 482 ++ src/tool/moneycount/athena_text.cpp | 4 +- src/tool/moneycount/athena_text.h | 9 - src/tool/moneycount/athena_text.hpp | 9 + src/tool/moneycount/main.cpp | 4 +- src/tool/moneycount/mmo.h | 309 - src/tool/moneycount/mmo.hpp | 309 + src/tool/skillfrob.c | 80 - src/tool/skillfrob.cpp | 80 + src/webserver/generate.c | 35 - src/webserver/generate.cpp | 35 + src/webserver/htmlstyle.c | 45 - src/webserver/htmlstyle.cpp | 45 + src/webserver/logs.c | 8 - src/webserver/logs.cpp | 8 + src/webserver/main.c | 145 - src/webserver/main.cpp | 145 + src/webserver/pages/about.c | 6 - src/webserver/pages/about.cpp | 6 + src/webserver/pages/notdone.c | 6 - src/webserver/pages/notdone.cpp | 6 + src/webserver/pages/sample.c | 22 - src/webserver/pages/sample.cpp | 22 + src/webserver/parse.c | 132 - src/webserver/parse.cpp | 132 + 210 files changed, 106729 insertions(+), 107045 deletions(-) delete mode 100644 deps.make delete mode 100644 src/char/char.c create mode 100644 src/char/char.cpp delete mode 100644 src/char/char.h create mode 100644 src/char/char.hpp delete mode 100644 src/char/int_guild.c create mode 100644 src/char/int_guild.cpp delete mode 100644 src/char/int_guild.h create mode 100644 src/char/int_guild.hpp delete mode 100644 src/char/int_party.c create mode 100644 src/char/int_party.cpp delete mode 100644 src/char/int_party.h create mode 100644 src/char/int_party.hpp delete mode 100644 src/char/int_storage.c create mode 100644 src/char/int_storage.cpp delete mode 100644 src/char/int_storage.h create mode 100644 src/char/int_storage.hpp delete mode 100644 src/char/inter.c create mode 100644 src/char/inter.cpp delete mode 100644 src/char/inter.h create mode 100644 src/char/inter.hpp delete mode 100644 src/common/core.c create mode 100644 src/common/core.cpp delete mode 100644 src/common/core.h create mode 100644 src/common/core.hpp delete mode 100644 src/common/db.c create mode 100644 src/common/db.cpp delete mode 100644 src/common/db.h create mode 100644 src/common/db.hpp delete mode 100644 src/common/grfio.c create mode 100644 src/common/grfio.cpp delete mode 100644 src/common/grfio.h create mode 100644 src/common/grfio.hpp delete mode 100644 src/common/lock.c create mode 100644 src/common/lock.cpp delete mode 100644 src/common/lock.h create mode 100644 src/common/lock.hpp delete mode 100644 src/common/md5calc.c create mode 100644 src/common/md5calc.cpp delete mode 100644 src/common/md5calc.h create mode 100644 src/common/md5calc.hpp delete mode 100644 src/common/mmo.h create mode 100644 src/common/mmo.hpp delete mode 100644 src/common/mt_rand.c create mode 100644 src/common/mt_rand.cpp delete mode 100644 src/common/mt_rand.h create mode 100644 src/common/mt_rand.hpp delete mode 100644 src/common/nullpo.c create mode 100644 src/common/nullpo.cpp delete mode 100644 src/common/nullpo.h create mode 100644 src/common/nullpo.hpp delete mode 100644 src/common/sanity.h create mode 100644 src/common/sanity.hpp delete mode 100644 src/common/socket.c create mode 100644 src/common/socket.cpp delete mode 100644 src/common/socket.h create mode 100644 src/common/socket.hpp delete mode 100644 src/common/timer.c create mode 100644 src/common/timer.cpp delete mode 100644 src/common/timer.h create mode 100644 src/common/timer.hpp delete mode 100644 src/common/utils.h create mode 100644 src/common/utils.hpp delete mode 100644 src/common/version.h create mode 100644 src/common/version.hpp delete mode 100644 src/ladmin/ladmin.c create mode 100644 src/ladmin/ladmin.cpp delete mode 100644 src/ladmin/ladmin.h create mode 100644 src/ladmin/ladmin.hpp delete mode 100644 src/login/login.c create mode 100644 src/login/login.cpp delete mode 100644 src/login/login.h create mode 100644 src/login/login.hpp delete mode 100644 src/map/atcommand.c create mode 100644 src/map/atcommand.cpp delete mode 100644 src/map/atcommand.h create mode 100644 src/map/atcommand.hpp delete mode 100644 src/map/battle.c create mode 100644 src/map/battle.cpp delete mode 100644 src/map/battle.h create mode 100644 src/map/battle.hpp delete mode 100644 src/map/chat.c create mode 100644 src/map/chat.cpp delete mode 100644 src/map/chat.h create mode 100644 src/map/chat.hpp delete mode 100644 src/map/chrif.c create mode 100644 src/map/chrif.cpp delete mode 100644 src/map/chrif.h create mode 100644 src/map/chrif.hpp delete mode 100644 src/map/clif.c create mode 100644 src/map/clif.cpp delete mode 100644 src/map/clif.h create mode 100644 src/map/clif.hpp delete mode 100644 src/map/guild.c create mode 100644 src/map/guild.cpp delete mode 100644 src/map/guild.h create mode 100644 src/map/guild.hpp delete mode 100644 src/map/intif.c create mode 100644 src/map/intif.cpp delete mode 100644 src/map/intif.h create mode 100644 src/map/intif.hpp delete mode 100644 src/map/itemdb.c create mode 100644 src/map/itemdb.cpp delete mode 100644 src/map/itemdb.h create mode 100644 src/map/itemdb.hpp delete mode 100644 src/map/magic-expr-eval.h create mode 100644 src/map/magic-expr-eval.hpp delete mode 100644 src/map/magic-expr.c create mode 100644 src/map/magic-expr.cpp delete mode 100644 src/map/magic-expr.h create mode 100644 src/map/magic-expr.hpp delete mode 100644 src/map/magic-interpreter-aux.h create mode 100644 src/map/magic-interpreter-aux.hpp delete mode 100644 src/map/magic-interpreter-base.c create mode 100644 src/map/magic-interpreter-base.cpp delete mode 100644 src/map/magic-interpreter-lexer.l create mode 100644 src/map/magic-interpreter-lexer.lpp delete mode 100644 src/map/magic-interpreter-parser.y create mode 100644 src/map/magic-interpreter-parser.ypp delete mode 100644 src/map/magic-interpreter.h create mode 100644 src/map/magic-interpreter.hpp delete mode 100644 src/map/magic-stmt.c create mode 100644 src/map/magic-stmt.cpp delete mode 100644 src/map/magic.c create mode 100644 src/map/magic.cpp delete mode 100644 src/map/magic.h create mode 100644 src/map/magic.hpp delete mode 100644 src/map/map.c create mode 100644 src/map/map.cpp delete mode 100644 src/map/map.h create mode 100644 src/map/map.hpp delete mode 100644 src/map/mob.c create mode 100644 src/map/mob.cpp delete mode 100644 src/map/mob.h create mode 100644 src/map/mob.hpp delete mode 100644 src/map/npc.c create mode 100644 src/map/npc.cpp delete mode 100644 src/map/npc.h create mode 100644 src/map/npc.hpp delete mode 100644 src/map/party.c create mode 100644 src/map/party.cpp delete mode 100644 src/map/party.h create mode 100644 src/map/party.hpp delete mode 100644 src/map/path.c create mode 100644 src/map/path.cpp delete mode 100644 src/map/pc.c create mode 100644 src/map/pc.cpp delete mode 100644 src/map/pc.h create mode 100644 src/map/pc.hpp delete mode 100644 src/map/script.c create mode 100644 src/map/script.cpp delete mode 100644 src/map/script.h create mode 100644 src/map/script.hpp delete mode 100644 src/map/skill-pools.c create mode 100644 src/map/skill-pools.cpp delete mode 100644 src/map/skill.c create mode 100644 src/map/skill.cpp delete mode 100644 src/map/skill.h create mode 100644 src/map/skill.hpp delete mode 100644 src/map/storage.c create mode 100644 src/map/storage.cpp delete mode 100644 src/map/storage.h create mode 100644 src/map/storage.hpp delete mode 100644 src/map/tmw.c create mode 100644 src/map/tmw.cpp delete mode 100644 src/map/tmw.h create mode 100644 src/map/tmw.hpp delete mode 100644 src/map/trade.c create mode 100644 src/map/trade.cpp delete mode 100644 src/map/trade.h create mode 100644 src/map/trade.hpp delete mode 100644 src/tool/adduser.c create mode 100644 src/tool/adduser.cpp delete mode 100644 src/tool/convert.c create mode 100644 src/tool/convert.cpp delete mode 100644 src/tool/eathena-monitor.c create mode 100644 src/tool/eathena-monitor.cpp delete mode 100644 src/tool/itemfrob.c create mode 100644 src/tool/itemfrob.cpp delete mode 100644 src/tool/mapfrob.c create mode 100644 src/tool/mapfrob.cpp delete mode 100644 src/tool/marriage-info.c create mode 100644 src/tool/marriage-info.cpp delete mode 100644 src/tool/moneycount/athena_text.h create mode 100644 src/tool/moneycount/athena_text.hpp delete mode 100644 src/tool/moneycount/mmo.h create mode 100644 src/tool/moneycount/mmo.hpp delete mode 100644 src/tool/skillfrob.c create mode 100644 src/tool/skillfrob.cpp delete mode 100644 src/webserver/generate.c create mode 100644 src/webserver/generate.cpp delete mode 100644 src/webserver/htmlstyle.c create mode 100644 src/webserver/htmlstyle.cpp delete mode 100644 src/webserver/logs.c create mode 100644 src/webserver/logs.cpp delete mode 100644 src/webserver/main.c create mode 100644 src/webserver/main.cpp delete mode 100644 src/webserver/pages/about.c create mode 100644 src/webserver/pages/about.cpp delete mode 100644 src/webserver/pages/notdone.c create mode 100644 src/webserver/pages/notdone.cpp delete mode 100644 src/webserver/pages/sample.c create mode 100644 src/webserver/pages/sample.cpp delete mode 100644 src/webserver/parse.c create mode 100644 src/webserver/parse.cpp diff --git a/.gitignore b/.gitignore index d59b2ef..361fe2d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,8 @@ /map-server /eathena-monitor # Generated source files -src/map/magic-interpreter-parser.h -src/map/magic-interpreter-parser.c -src/map/magic-interpreter-lexer.c - +/src/map/magic-interpreter-parser.hpp +/src/map/magic-interpreter-parser.cpp +/src/map/magic-interpreter-lexer.cpp +# generated header dependencies +/deps.make diff --git a/GNUmakefile b/GNUmakefile index 4162d7a..b00e55c 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -11,29 +11,29 @@ include make.defs +mkdir -p $@ # The default recipe is suboptimal -%.c: %.l +%.cpp: %.lpp $(LEX) -o $@ $< -%.c %.h: %.y - $(BISON) -d -o $*.c $< +%.cpp %.h: %.ypp + $(BISON) -d -o $*.cpp $< # All this duplication is required because make handles pattern rules specially -${BUILD_DIR}/char/%.o: src/char/%.c | ${BUILD_DIR}/char/ - $(COMPILE.c) -o $@ $< -${BUILD_DIR}/common/%.o: src/common/%.c | ${BUILD_DIR}/common/ - $(COMPILE.c) -o $@ $< -${BUILD_DIR}/ladmin/%.o: src/ladmin/%.c | ${BUILD_DIR}/ladmin/ - $(COMPILE.c) -o $@ $< -${BUILD_DIR}/login/%.o: src/login/%.c | ${BUILD_DIR}/login/ - $(COMPILE.c) -o $@ $< -${BUILD_DIR}/map/%.o: src/map/%.c | ${BUILD_DIR}/map/ - $(COMPILE.c) -o $@ $< -${BUILD_DIR}/tool/%.o: src/tool/%.c | ${BUILD_DIR}/tool/ - $(COMPILE.c) -o $@ $< -${BUILD_DIR}/webserver/%.o: src/webserver/%.c | ${BUILD_DIR}/webserver/ - $(COMPILE.c) -o $@ $< -${BUILD_DIR}/webserver/pages/%.o: src/webserver/pages/%.c | ${BUILD_DIR}/webserver/pages/ - $(COMPILE.c) -o $@ $< +${BUILD_DIR}/char/%.o: src/char/%.cpp | ${BUILD_DIR}/char/ + $(COMPILE.cpp) -o $@ $< +${BUILD_DIR}/common/%.o: src/common/%.cpp | ${BUILD_DIR}/common/ + $(COMPILE.cpp) -o $@ $< +${BUILD_DIR}/ladmin/%.o: src/ladmin/%.cpp | ${BUILD_DIR}/ladmin/ + $(COMPILE.cpp) -o $@ $< +${BUILD_DIR}/login/%.o: src/login/%.cpp | ${BUILD_DIR}/login/ + $(COMPILE.cpp) -o $@ $< +${BUILD_DIR}/map/%.o: src/map/%.cpp | ${BUILD_DIR}/map/ + $(COMPILE.cpp) -o $@ $< +${BUILD_DIR}/tool/%.o: src/tool/%.cpp | ${BUILD_DIR}/tool/ + $(COMPILE.cpp) -o $@ $< +${BUILD_DIR}/webserver/%.o: src/webserver/%.cpp | ${BUILD_DIR}/webserver/ + $(COMPILE.cpp) -o $@ $< +${BUILD_DIR}/webserver/pages/%.o: src/webserver/pages/%.cpp | ${BUILD_DIR}/webserver/pages/ + $(COMPILE.cpp) -o $@ $< PROGS = login-server char-server map-server ladmin eathena-monitor webserver # Things to actually make @@ -60,7 +60,6 @@ webserver: ${BUILD_DIR}/webserver/main ${BUILD_DIR}/char/char: ${BUILD_DIR}/char/char.o ${BUILD_DIR}/char/inter.o ${BUILD_DIR}/char/int_party.o ${BUILD_DIR}/char/int_guild.o ${BUILD_DIR}/char/int_storage.o ${BUILD_DIR}/common/core.o ${BUILD_DIR}/common/socket.o ${BUILD_DIR}/common/timer.o ${BUILD_DIR}/common/db.o ${BUILD_DIR}/common/lock.o ${BUILD_DIR}/common/mt_rand.o ${BUILD_DIR}/ladmin/ladmin: ${BUILD_DIR}/ladmin/ladmin.o ${BUILD_DIR}/common/md5calc.o ${BUILD_DIR}/common/core.o ${BUILD_DIR}/common/socket.o ${BUILD_DIR}/common/timer.o ${BUILD_DIR}/common/db.o ${BUILD_DIR}/common/mt_rand.o ${BUILD_DIR}/login/login: ${BUILD_DIR}/login/login.o ${BUILD_DIR}/common/core.o ${BUILD_DIR}/common/socket.o ${BUILD_DIR}/common/timer.o ${BUILD_DIR}/common/db.o ${BUILD_DIR}/common/lock.o ${BUILD_DIR}/common/mt_rand.o ${BUILD_DIR}/common/md5calc.o -${BUILD_DIR}/map/map: LDLIBS=-lm ${BUILD_DIR}/map/map: ${BUILD_DIR}/map/map.o ${BUILD_DIR}/map/tmw.o ${BUILD_DIR}/map/magic-interpreter-lexer.o ${BUILD_DIR}/map/magic-interpreter-parser.o ${BUILD_DIR}/map/magic-interpreter-base.o ${BUILD_DIR}/map/magic-expr.o ${BUILD_DIR}/map/magic-stmt.o ${BUILD_DIR}/map/magic.o ${BUILD_DIR}/map/map.o ${BUILD_DIR}/map/chrif.o ${BUILD_DIR}/map/clif.o ${BUILD_DIR}/map/pc.o ${BUILD_DIR}/map/npc.o ${BUILD_DIR}/map/chat.o ${BUILD_DIR}/map/path.o ${BUILD_DIR}/map/itemdb.o ${BUILD_DIR}/map/mob.o ${BUILD_DIR}/map/script.o ${BUILD_DIR}/map/storage.o ${BUILD_DIR}/map/skill.o ${BUILD_DIR}/map/skill-pools.o ${BUILD_DIR}/map/atcommand.o ${BUILD_DIR}/map/battle.o ${BUILD_DIR}/map/intif.o ${BUILD_DIR}/map/trade.o ${BUILD_DIR}/map/party.o ${BUILD_DIR}/map/guild.o ${BUILD_DIR}/common/core.o ${BUILD_DIR}/common/socket.o ${BUILD_DIR}/common/timer.o ${BUILD_DIR}/common/grfio.o ${BUILD_DIR}/common/db.o ${BUILD_DIR}/common/lock.o ${BUILD_DIR}/common/nullpo.o ${BUILD_DIR}/common/mt_rand.o ${BUILD_DIR}/common/md5calc.o ${BUILD_DIR}/tool/eathena-monitor: ${BUILD_DIR}/tool/eathena-monitor.o ${BUILD_DIR}/tool/adduser: ${BUILD_DIR}/tool/adduser.o ${BUILD_DIR}/common/socket.o @@ -70,8 +69,8 @@ ${BUILD_DIR}/tool/marriage-info: ${BUILD_DIR}/tool/marriage-info.o ${BUILD_DIR}/ ${BUILD_DIR}/webserver/main: ${BUILD_DIR}/webserver/main.o ${BUILD_DIR}/webserver/parse.o ${BUILD_DIR}/webserver/generate.o ${BUILD_DIR}/webserver/htmlstyle.o ${BUILD_DIR}/webserver/logs.o ${BUILD_DIR}/webserver/pages/about.o ${BUILD_DIR}/webserver/pages/sample.o ${BUILD_DIR}/webserver/pages/notdone.o deps.make: - for F in `find src/ -name '*.c'`; do \ - gcc -m32 -std=c99 -MM "$$F" -MT "$$(sed 's/src/$${BUILD_DIR}/;s/\.c/.o/' <<< "$$F")"; \ + for F in `find src/ -name '*.cpp'`; do \ + ${CXX} ${CPPFLAGS} -MM "$$F" -MT "$$(sed 's/src/$${BUILD_DIR}/;s/\.cpp/.o/' <<< "$$F")"; \ done > deps.make include deps.make diff --git a/deps.make b/deps.make deleted file mode 100644 index 34c7328..0000000 --- a/deps.make +++ /dev/null @@ -1,308 +0,0 @@ -${BUILD_DIR}/webserver/main.o: src/webserver/main.c -${BUILD_DIR}/webserver/logs.o: src/webserver/logs.c -${BUILD_DIR}/webserver/generate.o: src/webserver/generate.c -${BUILD_DIR}/webserver/parse.o: src/webserver/parse.c -${BUILD_DIR}/webserver/pages/about.o: src/webserver/pages/about.c -${BUILD_DIR}/webserver/pages/notdone.o: src/webserver/pages/notdone.c -${BUILD_DIR}/webserver/pages/sample.o: src/webserver/pages/sample.c -${BUILD_DIR}/webserver/htmlstyle.o: src/webserver/htmlstyle.c -${BUILD_DIR}/common/mt_rand.o: src/common/mt_rand.c src/common/mt_rand.h \ - src/common/sanity.h -${BUILD_DIR}/common/timer.o: src/common/timer.c src/common/timer.h \ - src/common/sanity.h src/common/utils.h -${BUILD_DIR}/common/nullpo.o: src/common/nullpo.c src/common/nullpo.h \ - src/common/sanity.h -${BUILD_DIR}/common/lock.o: src/common/lock.c src/common/lock.h \ - src/common/socket.h src/common/sanity.h -${BUILD_DIR}/common/grfio.o: src/common/grfio.c src/common/utils.h \ - src/common/grfio.h src/common/mmo.h src/common/socket.h \ - src/common/sanity.h -${BUILD_DIR}/common/md5calc.o: src/common/md5calc.c src/common/md5calc.h \ - src/common/sanity.h src/common/mt_rand.h -${BUILD_DIR}/common/dbtest.o: src/common/dbtest.c src/common/db.h \ - src/common/sanity.h -${BUILD_DIR}/common/db.o: src/common/db.c src/common/db.h \ - src/common/sanity.h src/common/utils.h -${BUILD_DIR}/common/socket.o: src/common/socket.c src/common/mmo.h \ - src/common/utils.h src/common/socket.h src/common/sanity.h -${BUILD_DIR}/common/core.o: src/common/core.c src/common/core.h \ - src/common/socket.h src/common/sanity.h src/common/timer.h \ - src/common/version.h src/common/mt_rand.h src/common/nullpo.h -${BUILD_DIR}/login/login.o: src/login/login.c src/login/../common/core.h \ - src/login/../common/socket.h src/login/../common/sanity.h \ - src/login/../common/timer.h src/login/login.h src/login/../common/mmo.h \ - src/login/../common/utils.h src/login/../common/version.h \ - src/login/../common/db.h src/login/../common/lock.h \ - src/login/../common/mt_rand.h src/login/../common/md5calc.h -${BUILD_DIR}/char/int_guild.o: src/char/int_guild.c src/char/inter.h \ - src/char/int_guild.h src/char/int_storage.h src/char/../common/mmo.h \ - src/char/../common/utils.h src/char/char.h src/char/../common/socket.h \ - src/char/../common/sanity.h src/char/../common/db.h \ - src/char/../common/lock.h -${BUILD_DIR}/char/inter.o: src/char/inter.c src/char/../common/mmo.h \ - src/char/../common/utils.h src/char/char.h src/char/../common/socket.h \ - src/char/../common/sanity.h src/char/../common/timer.h \ - src/char/../common/db.h src/char/inter.h src/char/int_party.h \ - src/char/int_guild.h src/char/int_storage.h src/char/../common/lock.h -${BUILD_DIR}/char/int_party.o: src/char/int_party.c src/char/inter.h \ - src/char/int_party.h src/char/../common/mmo.h src/char/../common/utils.h \ - src/char/char.h src/char/../common/socket.h src/char/../common/sanity.h \ - src/char/../common/db.h src/char/../common/lock.h -${BUILD_DIR}/char/int_storage.o: src/char/int_storage.c \ - src/char/../common/mmo.h src/char/../common/utils.h \ - src/char/../common/socket.h src/char/../common/sanity.h \ - src/char/../common/db.h src/char/../common/lock.h src/char/char.h \ - src/char/inter.h src/char/int_storage.h src/char/int_guild.h -${BUILD_DIR}/char/char.o: src/char/char.c src/char/../common/core.h \ - src/char/../common/socket.h src/char/../common/sanity.h \ - src/char/../common/timer.h src/char/../common/mmo.h \ - src/char/../common/utils.h src/char/../common/version.h \ - src/char/../common/lock.h src/char/char.h src/char/inter.h \ - src/char/int_guild.h src/char/int_party.h src/char/int_storage.h -${BUILD_DIR}/tool/itemfrob.o: src/tool/itemfrob.c \ - src/tool/../common/mmo.h src/tool/../common/utils.h \ - src/tool/../char/char.c src/tool/../char/../common/core.h \ - src/tool/../char/../common/socket.h src/tool/../char/../common/sanity.h \ - src/tool/../char/../common/timer.h src/tool/../char/../common/mmo.h \ - src/tool/../char/../common/version.h src/tool/../char/../common/lock.h \ - src/tool/../char/char.h src/tool/../char/inter.h \ - src/tool/../char/int_guild.h src/tool/../char/int_party.h \ - src/tool/../char/int_storage.h -${BUILD_DIR}/tool/eathena-monitor.o: src/tool/eathena-monitor.c -${BUILD_DIR}/tool/adduser.o: src/tool/adduser.c -${BUILD_DIR}/tool/marriage-info.o: src/tool/marriage-info.c \ - src/tool/../login/login.h src/tool/../common/mmo.h \ - src/tool/../common/utils.h src/tool/../char/char.c \ - src/tool/../char/../common/core.h src/tool/../char/../common/socket.h \ - src/tool/../char/../common/sanity.h src/tool/../char/../common/timer.h \ - src/tool/../char/../common/mmo.h src/tool/../char/../common/version.h \ - src/tool/../char/../common/lock.h src/tool/../char/char.h \ - src/tool/../char/inter.h src/tool/../char/int_guild.h \ - src/tool/../char/int_party.h src/tool/../char/int_storage.h -${BUILD_DIR}/tool/skillfrob.o: src/tool/skillfrob.c \ - src/tool/../common/mmo.h src/tool/../common/utils.h \ - src/tool/../char/char.c src/tool/../char/../common/core.h \ - src/tool/../char/../common/socket.h src/tool/../char/../common/sanity.h \ - src/tool/../char/../common/timer.h src/tool/../char/../common/mmo.h \ - src/tool/../char/../common/version.h src/tool/../char/../common/lock.h \ - src/tool/../char/char.h src/tool/../char/inter.h \ - src/tool/../char/int_guild.h src/tool/../char/int_party.h \ - src/tool/../char/int_storage.h -${BUILD_DIR}/tool/convert.o: src/tool/convert.c -${BUILD_DIR}/tool/mapfrob.o: src/tool/mapfrob.c src/tool/../common/mmo.h \ - src/tool/../common/utils.h src/tool/../char/char.c \ - src/tool/../char/../common/core.h src/tool/../char/../common/socket.h \ - src/tool/../char/../common/sanity.h src/tool/../char/../common/timer.h \ - src/tool/../char/../common/mmo.h src/tool/../char/../common/version.h \ - src/tool/../char/../common/lock.h src/tool/../char/char.h \ - src/tool/../char/inter.h src/tool/../char/int_guild.h \ - src/tool/../char/int_party.h src/tool/../char/int_storage.h -${BUILD_DIR}/map/itemdb.o: src/map/itemdb.c src/map/../common/db.h \ - src/map/../common/sanity.h src/map/../common/grfio.h \ - src/map/../common/nullpo.h src/map/map.h src/map/../common/mmo.h \ - src/map/../common/utils.h src/map/../common/timer.h src/map/battle.h \ - src/map/itemdb.h src/map/script.h src/map/pc.h \ - src/map/../common/socket.h src/map/../common/mt_rand.h -${BUILD_DIR}/map/magic.o: src/map/magic.c src/map/magic-interpreter.h \ - src/map/../common/nullpo.h src/map/../common/sanity.h src/map/battle.h \ - src/map/chat.h src/map/map.h src/map/../common/mmo.h \ - src/map/../common/utils.h src/map/../common/timer.h \ - src/map/../common/db.h src/map/chrif.h src/map/clif.h src/map/storage.h \ - src/map/intif.h src/map/itemdb.h src/map/magic.h src/map/mob.h \ - src/map/npc.h src/map/pc.h src/map/party.h src/map/script.h \ - src/map/skill.h src/map/trade.h src/map/../common/socket.h -${BUILD_DIR}/map/guild.o: src/map/guild.c src/map/guild.h \ - src/map/storage.h src/map/../common/mmo.h src/map/../common/utils.h \ - src/map/../common/db.h src/map/../common/sanity.h \ - src/map/../common/timer.h src/map/../common/socket.h \ - src/map/../common/nullpo.h src/map/battle.h src/map/npc.h src/map/pc.h \ - src/map/map.h src/map/mob.h src/map/intif.h src/map/clif.h src/map/tmw.h -${BUILD_DIR}/map/mob.o: src/map/mob.c src/map/../common/timer.h \ - src/map/../common/sanity.h src/map/../common/socket.h \ - src/map/../common/db.h src/map/../common/nullpo.h \ - src/map/../common/mt_rand.h src/map/map.h src/map/../common/mmo.h \ - src/map/../common/utils.h src/map/clif.h src/map/storage.h \ - src/map/intif.h src/map/pc.h src/map/mob.h src/map/guild.h \ - src/map/itemdb.h src/map/skill.h src/map/magic.h src/map/battle.h \ - src/map/party.h src/map/npc.h -${BUILD_DIR}/map/storage.o: src/map/storage.c src/map/../common/db.h \ - src/map/../common/sanity.h src/map/../common/nullpo.h src/map/storage.h \ - src/map/../common/mmo.h src/map/../common/utils.h src/map/chrif.h \ - src/map/itemdb.h src/map/map.h src/map/../common/timer.h src/map/clif.h \ - src/map/intif.h src/map/pc.h src/map/guild.h src/map/battle.h \ - src/map/atcommand.h -${BUILD_DIR}/map/path.o: src/map/path.c src/map/map.h \ - src/map/../common/mmo.h src/map/../common/utils.h \ - src/map/../common/timer.h src/map/../common/sanity.h \ - src/map/../common/db.h src/map/battle.h src/map/../common/nullpo.h -${BUILD_DIR}/map/magic-interpreter-parser.o: \ - src/map/magic-interpreter-parser.c src/map/magic-interpreter.h \ - src/map/../common/nullpo.h src/map/../common/sanity.h src/map/battle.h \ - src/map/chat.h src/map/map.h src/map/../common/mmo.h \ - src/map/../common/utils.h src/map/../common/timer.h \ - src/map/../common/db.h src/map/chrif.h src/map/clif.h src/map/storage.h \ - src/map/intif.h src/map/itemdb.h src/map/magic.h src/map/mob.h \ - src/map/npc.h src/map/pc.h src/map/party.h src/map/script.h \ - src/map/skill.h src/map/trade.h src/map/../common/socket.h \ - src/map/magic-expr.h src/map/magic-interpreter-aux.h -${BUILD_DIR}/map/skill.o: src/map/skill.c src/map/../common/timer.h \ - src/map/../common/sanity.h src/map/../common/nullpo.h \ - src/map/../common/mt_rand.h src/map/magic.h src/map/clif.h src/map/map.h \ - src/map/../common/mmo.h src/map/../common/utils.h src/map/../common/db.h \ - src/map/storage.h src/map/intif.h src/map/battle.h src/map/itemdb.h \ - src/map/mob.h src/map/party.h src/map/pc.h src/map/script.h \ - src/map/skill.h src/map/../common/socket.h -${BUILD_DIR}/map/magic-interpreter-lexer.o: \ - src/map/magic-interpreter-lexer.c src/map/magic-interpreter.h \ - src/map/../common/nullpo.h src/map/../common/sanity.h src/map/battle.h \ - src/map/chat.h src/map/map.h src/map/../common/mmo.h \ - src/map/../common/utils.h src/map/../common/timer.h \ - src/map/../common/db.h src/map/chrif.h src/map/clif.h src/map/storage.h \ - src/map/intif.h src/map/itemdb.h src/map/magic.h src/map/mob.h \ - src/map/npc.h src/map/pc.h src/map/party.h src/map/script.h \ - src/map/skill.h src/map/trade.h src/map/../common/socket.h \ - src/map/magic-interpreter-parser.h -${BUILD_DIR}/map/magic-stmt.o: src/map/magic-stmt.c \ - src/map/magic-interpreter.h src/map/../common/nullpo.h \ - src/map/../common/sanity.h src/map/battle.h src/map/chat.h src/map/map.h \ - src/map/../common/mmo.h src/map/../common/utils.h \ - src/map/../common/timer.h src/map/../common/db.h src/map/chrif.h \ - src/map/clif.h src/map/storage.h src/map/intif.h src/map/itemdb.h \ - src/map/magic.h src/map/mob.h src/map/npc.h src/map/pc.h src/map/party.h \ - src/map/script.h src/map/skill.h src/map/trade.h \ - src/map/../common/socket.h src/map/magic-expr.h \ - src/map/magic-interpreter-aux.h src/map/magic-expr-eval.h -${BUILD_DIR}/map/chat.o: src/map/chat.c src/map/../common/db.h \ - src/map/../common/sanity.h src/map/../common/nullpo.h src/map/map.h \ - src/map/../common/mmo.h src/map/../common/utils.h \ - src/map/../common/timer.h src/map/clif.h src/map/storage.h src/map/pc.h \ - src/map/chat.h src/map/npc.h -${BUILD_DIR}/map/skill-pools.o: src/map/skill-pools.c \ - src/map/../common/timer.h src/map/../common/sanity.h \ - src/map/../common/nullpo.h src/map/../common/mt_rand.h src/map/magic.h \ - src/map/clif.h src/map/map.h src/map/../common/mmo.h \ - src/map/../common/utils.h src/map/../common/db.h src/map/storage.h \ - src/map/intif.h src/map/battle.h src/map/itemdb.h src/map/mob.h \ - src/map/party.h src/map/pc.h src/map/script.h src/map/skill.h \ - src/map/../common/socket.h -${BUILD_DIR}/map/trade.o: src/map/trade.c src/map/clif.h src/map/map.h \ - src/map/../common/mmo.h src/map/../common/utils.h \ - src/map/../common/timer.h src/map/../common/sanity.h \ - src/map/../common/db.h src/map/storage.h src/map/itemdb.h \ - src/map/trade.h src/map/pc.h src/map/npc.h src/map/battle.h \ - src/map/../common/nullpo.h -${BUILD_DIR}/map/party.o: src/map/party.c src/map/party.h \ - src/map/../common/db.h src/map/../common/sanity.h \ - src/map/../common/timer.h src/map/../common/socket.h \ - src/map/../common/nullpo.h src/map/pc.h src/map/map.h \ - src/map/../common/mmo.h src/map/../common/utils.h src/map/battle.h \ - src/map/intif.h src/map/clif.h src/map/storage.h src/map/skill.h \ - src/map/magic.h src/map/tmw.h -${BUILD_DIR}/map/npc.o: src/map/npc.c src/map/../common/nullpo.h \ - src/map/../common/sanity.h src/map/../common/timer.h src/map/battle.h \ - src/map/clif.h src/map/map.h src/map/../common/mmo.h \ - src/map/../common/utils.h src/map/../common/db.h src/map/storage.h \ - src/map/intif.h src/map/itemdb.h src/map/mob.h src/map/npc.h \ - src/map/pc.h src/map/script.h src/map/skill.h src/map/magic.h \ - src/map/../common/socket.h -${BUILD_DIR}/map/magic-interpreter-base.o: \ - src/map/magic-interpreter-base.c src/map/magic.h src/map/clif.h \ - src/map/map.h src/map/../common/mmo.h src/map/../common/utils.h \ - src/map/../common/timer.h src/map/../common/sanity.h \ - src/map/../common/db.h src/map/storage.h src/map/intif.h \ - src/map/magic-interpreter.h src/map/../common/nullpo.h src/map/battle.h \ - src/map/chat.h src/map/chrif.h src/map/itemdb.h src/map/mob.h \ - src/map/npc.h src/map/pc.h src/map/party.h src/map/script.h \ - src/map/skill.h src/map/trade.h src/map/../common/socket.h \ - src/map/magic-expr.h src/map/magic-interpreter-aux.h -${BUILD_DIR}/map/pc.o: src/map/pc.c src/map/../common/socket.h \ - src/map/../common/sanity.h src/map/../common/timer.h \ - src/map/../common/db.h src/map/../common/nullpo.h \ - src/map/../common/mt_rand.h src/map/atcommand.h src/map/map.h \ - src/map/../common/mmo.h src/map/../common/utils.h src/map/battle.h \ - src/map/chat.h src/map/chrif.h src/map/clif.h src/map/storage.h \ - src/map/guild.h src/map/intif.h src/map/itemdb.h src/map/mob.h \ - src/map/npc.h src/map/party.h src/map/pc.h src/map/script.h \ - src/map/skill.h src/map/magic.h src/map/trade.h -${BUILD_DIR}/map/tmw.o: src/map/tmw.c src/map/tmw.h src/map/map.h \ - src/map/../common/mmo.h src/map/../common/utils.h \ - src/map/../common/timer.h src/map/../common/sanity.h \ - src/map/../common/db.h src/map/../common/socket.h \ - src/map/../common/version.h src/map/../common/nullpo.h \ - src/map/atcommand.h src/map/battle.h src/map/chat.h src/map/chrif.h \ - src/map/clif.h src/map/storage.h src/map/guild.h src/map/intif.h \ - src/map/itemdb.h src/map/magic.h src/map/mob.h src/map/npc.h \ - src/map/party.h src/map/pc.h src/map/script.h src/map/skill.h \ - src/map/trade.h -${BUILD_DIR}/map/intif.o: src/map/intif.c src/map/../common/nullpo.h \ - src/map/../common/sanity.h src/map/../common/socket.h \ - src/map/../common/timer.h src/map/battle.h src/map/chrif.h \ - src/map/clif.h src/map/map.h src/map/../common/mmo.h \ - src/map/../common/utils.h src/map/../common/db.h src/map/storage.h \ - src/map/guild.h src/map/intif.h src/map/party.h src/map/pc.h -${BUILD_DIR}/map/magic-expr.o: src/map/magic-expr.c src/map/magic-expr.h \ - src/map/magic-interpreter.h src/map/../common/nullpo.h \ - src/map/../common/sanity.h src/map/battle.h src/map/chat.h src/map/map.h \ - src/map/../common/mmo.h src/map/../common/utils.h \ - src/map/../common/timer.h src/map/../common/db.h src/map/chrif.h \ - src/map/clif.h src/map/storage.h src/map/intif.h src/map/itemdb.h \ - src/map/magic.h src/map/mob.h src/map/npc.h src/map/pc.h src/map/party.h \ - src/map/script.h src/map/skill.h src/map/trade.h \ - src/map/../common/socket.h src/map/magic-interpreter-aux.h \ - src/map/magic-expr-eval.h src/map/../common/mt_rand.h -${BUILD_DIR}/map/battle.o: src/map/battle.c src/map/battle.h \ - src/map/../common/timer.h src/map/../common/sanity.h \ - src/map/../common/nullpo.h src/map/clif.h src/map/map.h \ - src/map/../common/mmo.h src/map/../common/utils.h src/map/../common/db.h \ - src/map/storage.h src/map/guild.h src/map/itemdb.h src/map/mob.h \ - src/map/pc.h src/map/skill.h src/map/magic.h src/map/intif.h \ - src/map/../common/socket.h src/map/../common/mt_rand.h -${BUILD_DIR}/map/script.o: src/map/script.c src/map/../common/socket.h \ - src/map/../common/sanity.h src/map/../common/timer.h \ - src/map/../common/lock.h src/map/../common/mt_rand.h src/map/atcommand.h \ - src/map/map.h src/map/../common/mmo.h src/map/../common/utils.h \ - src/map/../common/db.h src/map/battle.h src/map/chat.h src/map/chrif.h \ - src/map/clif.h src/map/storage.h src/map/guild.h src/map/intif.h \ - src/map/itemdb.h src/map/mob.h src/map/npc.h src/map/party.h \ - src/map/pc.h src/map/script.h src/map/skill.h src/map/magic.h -${BUILD_DIR}/map/clif.o: src/map/clif.c src/map/../common/socket.h \ - src/map/../common/sanity.h src/map/../common/timer.h \ - src/map/../common/version.h src/map/../common/nullpo.h \ - src/map/../common/md5calc.h src/map/../common/mt_rand.h \ - src/map/atcommand.h src/map/map.h src/map/../common/mmo.h \ - src/map/../common/utils.h src/map/../common/db.h src/map/battle.h \ - src/map/chat.h src/map/chrif.h src/map/clif.h src/map/storage.h \ - src/map/guild.h src/map/intif.h src/map/itemdb.h src/map/magic.h \ - src/map/mob.h src/map/npc.h src/map/party.h src/map/pc.h \ - src/map/script.h src/map/skill.h src/map/tmw.h src/map/trade.h -${BUILD_DIR}/map/chrif.o: src/map/chrif.c src/map/../common/socket.h \ - src/map/../common/sanity.h src/map/../common/timer.h src/map/map.h \ - src/map/../common/mmo.h src/map/../common/utils.h src/map/../common/db.h \ - src/map/battle.h src/map/chrif.h src/map/clif.h src/map/storage.h \ - src/map/intif.h src/map/npc.h src/map/pc.h src/map/../common/nullpo.h \ - src/map/itemdb.h -${BUILD_DIR}/map/atcommand.o: src/map/atcommand.c \ - src/map/../common/socket.h src/map/../common/sanity.h \ - src/map/../common/timer.h src/map/../common/nullpo.h \ - src/map/../common/mt_rand.h src/map/atcommand.h src/map/map.h \ - src/map/../common/mmo.h src/map/../common/utils.h src/map/../common/db.h \ - src/map/battle.h src/map/clif.h src/map/storage.h src/map/chrif.h \ - src/map/guild.h src/map/intif.h src/map/itemdb.h src/map/mob.h \ - src/map/npc.h src/map/pc.h src/map/party.h src/map/script.h \ - src/map/skill.h src/map/magic.h src/map/trade.h src/map/../common/core.h \ - src/map/tmw.h -${BUILD_DIR}/map/map.o: src/map/map.c src/map/../common/core.h \ - src/map/../common/timer.h src/map/../common/sanity.h \ - src/map/../common/db.h src/map/../common/grfio.h \ - src/map/../common/mt_rand.h src/map/map.h src/map/../common/mmo.h \ - src/map/../common/utils.h src/map/chrif.h src/map/clif.h \ - src/map/storage.h src/map/intif.h src/map/npc.h src/map/pc.h \ - src/map/mob.h src/map/chat.h src/map/itemdb.h src/map/skill.h \ - src/map/magic.h src/map/trade.h src/map/party.h src/map/battle.h \ - src/map/script.h src/map/guild.h src/map/atcommand.h \ - src/map/../common/nullpo.h src/map/../common/socket.h -${BUILD_DIR}/ladmin/ladmin.o: src/ladmin/ladmin.c \ - src/ladmin/../common/core.h src/ladmin/../common/socket.h \ - src/ladmin/../common/sanity.h src/ladmin/ladmin.h \ - src/ladmin/../common/version.h src/ladmin/../common/mmo.h \ - src/ladmin/../common/utils.h src/ladmin/../common/md5calc.h diff --git a/make.defs b/make.defs index 067c22b..9328688 100644 --- a/make.defs +++ b/make.defs @@ -1,16 +1,13 @@ # defaults -CC = gcc +CXX = g++ LEX = flex BISON = bison -CFLAGS = -pipe -g -O2 +CXXFLAGS = -pipe -g -O2 # works on both x86 and x86_64 -override CC += -m32 -std=gnu99 +override CXX += -m32 -std=c++0x +# for linking +override CC = ${CXX} -# TODO check if this is actually needed - I don't think it should be -ifeq ($(findstring CYGWIN,$(shell uname)), CYGWIN) - override CFLAGS += -DFD_SETSIZE=4096 -DCYGWIN -else - override CFLAGS += -fstack-protector -endif +override CXXFLAGS += -fstack-protector diff --git a/src/char/char.c b/src/char/char.c deleted file mode 100644 index 2a46283..0000000 --- a/src/char/char.c +++ /dev/null @@ -1,4076 +0,0 @@ -// $Id: char.c,v 1.3 2004/09/13 16:52:16 Yor Exp $ -// original : char2.c 2003/03/14 11:58:35 Rev.1.5 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../common/core.h" -#include "../common/socket.h" -#include "../common/timer.h" -#include "../common/mmo.h" -#include "../common/version.h" -#include "../common/lock.h" -#include "char.h" - -#include "inter.h" -#include "int_guild.h" -#include "int_party.h" -#include "int_storage.h" - -#ifdef MEMWATCH -#include "memwatch.h" -#endif - -struct mmo_map_server server[MAX_MAP_SERVERS]; -int server_fd[MAX_MAP_SERVERS]; -int server_freezeflag[MAX_MAP_SERVERS]; // Map-server anti-freeze system. Counter. 5 ok, 4...0 freezed -int anti_freeze_enable = 0; -int ANTI_FREEZE_INTERVAL = 6; - -int login_fd, char_fd; -char userid[24]; -char passwd[24]; -char server_name[20]; -char wisp_server_name[24] = "Server"; -char login_ip_str[16]; -int login_ip; -int login_port = 6900; -char char_ip_str[16]; -int char_ip; -int char_port = 6121; -int char_maintenance; -int char_new; -int email_creation = 0; // disabled by default -char char_txt[1024]; -char backup_txt[1024]; //By zanetheinsane -char backup_txt_flag = 0; // The backup_txt file was created because char deletion bug existed. Now it's finish and that take a lot of time to create a second file when there are a lot of characters. => option By [Yor] -char unknown_char_name[1024] = "Unknown"; -char char_log_filename[1024] = "log/char.log"; -//Added for lan support -char lan_map_ip[128]; -int subneti[4]; -int subnetmaski[4]; -int name_ignoring_case = 0; // Allow or not identical name for characters but with a different case by [Yor] -int char_name_option = 0; // Option to know which letters/symbols are authorised in the name of a character (0: all, 1: only those in char_name_letters, 2: all EXCEPT those in char_name_letters) by [Yor] -char char_name_letters[1024] = ""; // list of letters/symbols authorised (or not) in a character name. by [Yor] - -struct char_session_data -{ - int account_id, login_id1, login_id2, sex; - unsigned short packet_tmw_version; - int found_char[9]; - char email[40]; // e-mail (default: a@a.com) by [Yor] - time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) -}; - -#define AUTH_FIFO_SIZE 256 -struct -{ - int account_id, char_id, login_id1, login_id2, ip, char_pos, delflag, - sex; - unsigned short packet_tmw_version; - time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) -} auth_fifo[AUTH_FIFO_SIZE]; -int auth_fifo_pos = 0; - -int check_ip_flag = 1; // It's to check IP of a player between char-server and other servers (part of anti-hacking system) - -int char_id_count = 150000; -struct mmo_charstatus *char_dat; -int char_num, char_max; -int max_connect_user = 0; -int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; -int start_zeny = 500; -int start_weapon = 1201; -int start_armor = 1202; - -// Initial position (it's possible to set it in conf file) -struct point start_point = { "new_1-1.gat", 53, 111 }; - -struct gm_account *gm_account = NULL; -int GM_num = 0; - -// online players by [Yor] -char online_txt_filename[1024] = "online.txt"; -char online_html_filename[1024] = "online.html"; -int online_sorting_option = 0; // sorting option to display online players in online files -int online_display_option = 1; // display options: to know which columns must be displayed -int online_refresh_html = 20; // refresh time (in sec) of the html file in the explorer -int online_gm_display_min_level = 20; // minimum GM level to display 'GM' when we want to display it - -int *online_chars; // same size of char_dat, and id value of current server (or -1) -time_t update_online; // to update online files when we receiving information from a server (not less than 8 seconds) - -pid_t pid = 0; // For forked DB writes - -//------------------------------ -// Writing function of logs file -//------------------------------ -int char_log (char *fmt, ...) -{ - FILE *logfp; - va_list ap; - struct timeval tv; - char tmpstr[2048]; - - va_start (ap, fmt); - - logfp = fopen_ (char_log_filename, "a"); - if (logfp) - { - if (fmt[0] == '\0') // jump a line if no message - fprintf (logfp, "\n"); - else - { - gettimeofday (&tv, NULL); - strftime (tmpstr, 24, "%d-%m-%Y %H:%M:%S", gmtime (&(tv.tv_sec))); - sprintf (tmpstr + 19, ".%03d: %s", (int) tv.tv_usec / 1000, fmt); - vfprintf (logfp, tmpstr, ap); - } - fclose_ (logfp); - } - - va_end (ap); - return 0; -} - -//----------------------------------------------------- -// Function to suppress control characters in a string. -//----------------------------------------------------- -int remove_control_chars (unsigned char *str) -{ - int i; - int change = 0; - - for (i = 0; str[i]; i++) - { - if (str[i] < 32) - { - str[i] = '_'; - change = 1; - } - } - - return change; -} - -//---------------------------------------------------------------------- -// Determine if an account (id) is a GM account -// and returns its level (or 0 if it isn't a GM account or if not found) -//---------------------------------------------------------------------- -int isGM (int account_id) -{ - int i; - - for (i = 0; i < GM_num; i++) - if (gm_account[i].account_id == account_id) - return gm_account[i].level; - return 0; -} - -//---------------------------------------------- -// Search an character id -// (return character index or -1 (if not found)) -// If exact character name is not found, -// the function checks without case sensitive -// and returns index if only 1 character is found -// and similar to the searched name. -//---------------------------------------------- -int search_character_index (char *character_name) -{ - int i, quantity, index; - - quantity = 0; - index = -1; - for (i = 0; i < char_num; i++) - { - // Without case sensitive check (increase the number of similar character names found) - if (strcasecmp (char_dat[i].name, character_name) == 0) - { - // Strict comparison (if found, we finish the function immediatly with correct value) - if (strcmp (char_dat[i].name, character_name) == 0) - return i; - quantity++; - index = i; - } - } - // Here, the exact character name is not found - // We return the found index of a similar account ONLY if there is 1 similar character - if (quantity == 1) - return index; - - // Exact character name is not found and 0 or more than 1 similar characters have been found ==> we say not found - return -1; -} - -//------------------------------------- -// Return character name with the index -//------------------------------------- -char *search_character_name (int index) -{ - - if (index >= 0 && index < char_num) - return char_dat[index].name; - - return unknown_char_name; -} - -//------------------------------------------------- -// Function to create the character line (for save) -//------------------------------------------------- -int mmo_char_tostr (char *str, struct mmo_charstatus *p) -{ - int i; - char *str_p = str; - - // on multi-map server, sometimes it's posssible that last_point become void. (reason???) We check that to not lost character at restart. - if (p->last_point.map[0] == '\0') - { - memcpy (p->last_point.map, "prontera.gat", 16); - p->last_point.x = 273; - p->last_point.y = 354; - } - - str_p += sprintf (str_p, "%d\t%d,%d\t%s\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" "\t%s,%d,%d\t%s,%d,%d,%d\t", p->char_id, p->account_id, p->char_num, p->name, // - p->pc_class, p->base_level, p->job_level, p->base_exp, p->job_exp, p->zeny, p->hp, p->max_hp, p->sp, p->max_sp, p->str, p->agi, p->vit, p->int_, p->dex, p->luk, p->status_point, p->skill_point, p->option, p->karma, p->manner, // - p->party_id, p->guild_id, 0, p->hair, p->hair_color, p->clothes_color, p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, p->last_point.map, p->last_point.x, p->last_point.y, // - p->save_point.map, p->save_point.x, p->save_point.y, - p->partner_id); - for (i = 0; i < 10; i++) - if (p->memo_point[i].map[0]) - { - str_p += - sprintf (str_p, "%s,%d,%d", p->memo_point[i].map, - p->memo_point[i].x, p->memo_point[i].y); - } - *(str_p++) = '\t'; - - for (i = 0; i < MAX_INVENTORY; i++) - if (p->inventory[i].nameid) - { - str_p += sprintf (str_p, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d ", - p->inventory[i].id, p->inventory[i].nameid, - p->inventory[i].amount, p->inventory[i].equip, - p->inventory[i].identify, - p->inventory[i].refine, - p->inventory[i].attribute, - p->inventory[i].card[0], - p->inventory[i].card[1], - p->inventory[i].card[2], - p->inventory[i].card[3], - p->inventory[i].broken); - } - *(str_p++) = '\t'; - - for (i = 0; i < MAX_CART; i++) - if (p->cart[i].nameid) - { - str_p += sprintf (str_p, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d ", - p->cart[i].id, p->cart[i].nameid, - p->cart[i].amount, p->cart[i].equip, - p->cart[i].identify, p->cart[i].refine, - p->cart[i].attribute, p->cart[i].card[0], - p->cart[i].card[1], p->cart[i].card[2], - p->cart[i].card[3], p->cart[i].broken); - } - *(str_p++) = '\t'; - - for (i = 0; i < MAX_SKILL; i++) - if (p->skill[i].id) - { - str_p += - sprintf (str_p, "%d,%d ", p->skill[i].id, - p->skill[i].lv | (p->skill[i].flags << 16)); - } - *(str_p++) = '\t'; - - for (i = 0; i < p->global_reg_num; i++) - if (p->global_reg[i].str[0]) - str_p += - sprintf (str_p, "%s,%d ", p->global_reg[i].str, - p->global_reg[i].value); - *(str_p++) = '\t'; - - *str_p = '\0'; - return 0; -} - -//------------------------------------------------------------------------- -// Function to set the character from the line (at read of characters file) -//------------------------------------------------------------------------- -int mmo_char_fromstr (char *str, struct mmo_charstatus *p) -{ - int tmp_int[256]; - int set, next, len, i; - - // initilialise character - memset (p, '\0', sizeof (struct mmo_charstatus)); - - // If it's not char structure of version 1008 and after - if ((set = sscanf (str, "%d\t%d,%d\t%[^\t]\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" "\t%[^,],%d,%d\t%[^,],%d,%d,%d%n", &tmp_int[0], &tmp_int[1], &tmp_int[2], p->name, // - &tmp_int[3], &tmp_int[4], &tmp_int[5], &tmp_int[6], &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], &tmp_int[19], &tmp_int[20], &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], &tmp_int[26], &tmp_int[27], &tmp_int[28], &tmp_int[29], &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], p->last_point.map, &tmp_int[35], &tmp_int[36], // - p->save_point.map, &tmp_int[37], &tmp_int[38], - &tmp_int[39], &next)) != 43) - { - tmp_int[39] = 0; // partner id - // If not char structure from version 384 to 1007 - if ((set = sscanf (str, "%d\t%d,%d\t%[^\t]\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" "\t%[^,],%d,%d\t%[^,],%d,%d%n", &tmp_int[0], &tmp_int[1], &tmp_int[2], p->name, // - &tmp_int[3], &tmp_int[4], &tmp_int[5], &tmp_int[6], &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], &tmp_int[19], &tmp_int[20], &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], &tmp_int[26], &tmp_int[27], &tmp_int[28], &tmp_int[29], &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], p->last_point.map, &tmp_int[35], &tmp_int[36], // - p->save_point.map, &tmp_int[37], &tmp_int[38], - &next)) != 42) - { - // It's char structure of a version before 384 - tmp_int[26] = 0; // pet id - set = sscanf (str, "%d\t%d,%d\t%[^\t]\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" "\t%d,%d,%d\t%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" "\t%[^,],%d,%d\t%[^,],%d,%d%n", &tmp_int[0], &tmp_int[1], &tmp_int[2], p->name, // - &tmp_int[3], &tmp_int[4], &tmp_int[5], &tmp_int[6], &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], &tmp_int[19], &tmp_int[20], &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], // - &tmp_int[27], &tmp_int[28], &tmp_int[29], &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], p->last_point.map, &tmp_int[35], &tmp_int[36], // - p->save_point.map, &tmp_int[37], &tmp_int[38], - &next); - set += 2; - //printf("char: old char data ver.1\n"); - // Char structure of version 1007 or older - } - else - { - set++; - //printf("char: old char data ver.2\n"); - } - // Char structure of version 1008+ - } - else - { - //printf("char: new char data ver.3\n"); - } - if (set != 43) - return 0; - - p->char_id = tmp_int[0]; - p->account_id = tmp_int[1]; - p->char_num = tmp_int[2]; - p->pc_class = tmp_int[3]; - p->base_level = tmp_int[4]; - p->job_level = tmp_int[5]; - p->base_exp = tmp_int[6]; - p->job_exp = tmp_int[7]; - p->zeny = tmp_int[8]; - p->hp = tmp_int[9]; - p->max_hp = tmp_int[10]; - p->sp = tmp_int[11]; - p->max_sp = tmp_int[12]; - p->str = tmp_int[13]; - p->agi = tmp_int[14]; - p->vit = tmp_int[15]; - p->int_ = tmp_int[16]; - p->dex = tmp_int[17]; - p->luk = tmp_int[18]; - p->status_point = tmp_int[19]; - p->skill_point = tmp_int[20]; - p->option = tmp_int[21]; - p->karma = tmp_int[22]; - p->manner = tmp_int[23]; - p->party_id = tmp_int[24]; - p->guild_id = tmp_int[25]; -// p->pet_id = tmp_int[26]; - p->hair = tmp_int[27]; - p->hair_color = tmp_int[28]; - p->clothes_color = tmp_int[29]; - p->weapon = tmp_int[30]; - p->shield = tmp_int[31]; - p->head_top = tmp_int[32]; - p->head_mid = tmp_int[33]; - p->head_bottom = tmp_int[34]; - p->last_point.x = tmp_int[35]; - p->last_point.y = tmp_int[36]; - p->save_point.x = tmp_int[37]; - p->save_point.y = tmp_int[38]; - p->partner_id = tmp_int[39]; - - // Some checks - for (i = 0; i < char_num; i++) - { - if (char_dat[i].char_id == p->char_id) - { - printf - ("\033[1;31mmmo_auth_init: ******Error: a character has an identical id to another.\n"); - printf - (" character id #%d -> new character not readed.\n", - p->char_id); - printf (" Character saved in log file.\033[0m\n"); - return -1; - } - else if (strcmp (char_dat[i].name, p->name) == 0) - { - printf - ("\033[1;31mmmo_auth_init: ******Error: character name already exists.\n"); - printf - (" character name '%s' -> new character not readed.\n", - p->name); - printf (" Character saved in log file.\033[0m\n"); - return -2; - } - } - - if (strcasecmp (wisp_server_name, p->name) == 0) - { - printf - ("mmo_auth_init: ******WARNING: character name has wisp server name.\n"); - printf - (" Character name '%s' = wisp server name '%s'.\n", - p->name, wisp_server_name); - printf - (" Character readed. Suggestion: change the wisp server name.\n"); - char_log - ("mmo_auth_init: ******WARNING: character name has wisp server name: Character name '%s' = wisp server name '%s'.\n", - p->name, wisp_server_name); - } - - if (str[next] == '\n' || str[next] == '\r') - return 1; // 新規データ - - next++; - - for (i = 0; str[next] && str[next] != '\t'; i++) - { - if (sscanf - (str + next, "%[^,],%d,%d%n", p->memo_point[i].map, &tmp_int[0], - &tmp_int[1], &len) != 3) - return -3; - p->memo_point[i].x = tmp_int[0]; - p->memo_point[i].y = tmp_int[1]; - next += len; - if (str[next] == ' ') - next++; - } - - next++; - - for (i = 0; str[next] && str[next] != '\t'; i++) - { - if (sscanf (str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], - &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], - &tmp_int[11], &len) == 12) - { - // do nothing, it's ok - } - else if (sscanf (str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], - &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], - &len) == 11) - { - tmp_int[11] = 0; // broken doesn't exist in this version -> 0 - } - else // invalid structure - return -4; - p->inventory[i].id = tmp_int[0]; - p->inventory[i].nameid = tmp_int[1]; - p->inventory[i].amount = tmp_int[2]; - p->inventory[i].equip = tmp_int[3]; - p->inventory[i].identify = tmp_int[4]; - p->inventory[i].refine = tmp_int[5]; - p->inventory[i].attribute = tmp_int[6]; - p->inventory[i].card[0] = tmp_int[7]; - p->inventory[i].card[1] = tmp_int[8]; - p->inventory[i].card[2] = tmp_int[9]; - p->inventory[i].card[3] = tmp_int[10]; - p->inventory[i].broken = tmp_int[11]; - next += len; - if (str[next] == ' ') - next++; - } - - next++; - - for (i = 0; str[next] && str[next] != '\t'; i++) - { - if (sscanf (str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], - &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], - &tmp_int[11], &len) == 12) - { - // do nothing, it's ok - } - else if (sscanf (str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], - &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], - &len) == 11) - { - tmp_int[11] = 0; // broken doesn't exist in this version -> 0 - } - else // invalid structure - return -5; - p->cart[i].id = tmp_int[0]; - p->cart[i].nameid = tmp_int[1]; - p->cart[i].amount = tmp_int[2]; - p->cart[i].equip = tmp_int[3]; - p->cart[i].identify = tmp_int[4]; - p->cart[i].refine = tmp_int[5]; - p->cart[i].attribute = tmp_int[6]; - p->cart[i].card[0] = tmp_int[7]; - p->cart[i].card[1] = tmp_int[8]; - p->cart[i].card[2] = tmp_int[9]; - p->cart[i].card[3] = tmp_int[10]; - p->cart[i].broken = tmp_int[11]; - next += len; - if (str[next] == ' ') - next++; - } - - next++; - - for (i = 0; str[next] && str[next] != '\t'; i++) - { - if (sscanf (str + next, "%d,%d%n", &tmp_int[0], &tmp_int[1], &len) != - 2) - return -6; - p->skill[tmp_int[0]].id = tmp_int[0]; - p->skill[tmp_int[0]].lv = tmp_int[1] & 0xffff; - p->skill[tmp_int[0]].flags = ((tmp_int[1] >> 16) & 0xffff); - next += len; - if (str[next] == ' ') - next++; - } - - next++; - - for (i = 0; - str[next] && str[next] != '\t' && str[next] != '\n' - && str[next] != '\r'; i++) - { // global_reg実装以前のathena.txt互換のため一応'\n'チェック - if (sscanf - (str + next, "%[^,],%d%n", p->global_reg[i].str, - &p->global_reg[i].value, &len) != 2) - { - // because some scripts are not correct, the str can be "". So, we must check that. - // If it's, we must not refuse the character, but just this REG value. - // Character line will have something like: nov_2nd_cos,9 ,9 nov_1_2_cos_c,1 (here, ,9 is not good) - if (str[next] == ',' - && sscanf (str + next, ",%d%n", &p->global_reg[i].value, - &len) == 1) - i--; - else - return -7; - } - next += len; - if (str[next] == ' ') - next++; - } - p->global_reg_num = i; - - return 1; -} - -//--------------------------------- -// Function to read characters file -//--------------------------------- -int mmo_char_init (void) -{ - char line[65536]; - int i; - int ret, line_count; - FILE *fp; - - char_max = 256; - CREATE (char_dat, struct mmo_charstatus, 256); - CREATE (online_chars, int, 256); - for (i = 0; i < char_max; i++) - online_chars[i] = -1; - - char_num = 0; - - fp = fopen_ (char_txt, "r"); - if (fp == NULL) - { - printf ("Characters file not found: %s.\n", char_txt); - char_log ("Characters file not found: %s.\n", char_txt); - char_log ("Id for the next created character: %d.\n", - char_id_count); - return 0; - } - - line_count = 0; - while (fgets (line, sizeof (line) - 1, fp)) - { - int i, j; - line_count++; - - if (line[0] == '/' && line[1] == '/') - continue; - line[sizeof (line) - 1] = '\0'; - - j = 0; - if (sscanf (line, "%d\t%%newid%%%n", &i, &j) == 1 && j > 0) - { - if (char_id_count < i) - char_id_count = i; - continue; - } - - if (char_num >= char_max) - { - char_max += 256; - RECREATE (char_dat, struct mmo_charstatus, char_max); - RECREATE (online_chars, int, char_max); - for (i = char_max - 256; i < char_max; i++) - online_chars[i] = -1; - } - - ret = mmo_char_fromstr (line, &char_dat[char_num]); - if (ret > 0) - { // negative value or zero for errors - if (char_dat[char_num].char_id >= char_id_count) - char_id_count = char_dat[char_num].char_id + 1; - char_num++; - } - else - { - printf - ("mmo_char_init: in characters file, unable to read the line #%d.\n", - line_count); - printf (" -> Character saved in log file.\n"); - switch (ret) - { - case -1: - char_log - ("Duplicate character id in the next character line (character not readed):\n"); - break; - case -2: - char_log - ("Duplicate character name in the next character line (character not readed):\n"); - break; - case -3: - char_log - ("Invalid memo point structure in the next character line (character not readed):\n"); - break; - case -4: - char_log - ("Invalid inventory item structure in the next character line (character not readed):\n"); - break; - case -5: - char_log - ("Invalid cart item structure in the next character line (character not readed):\n"); - break; - case -6: - char_log - ("Invalid skill structure in the next character line (character not readed):\n"); - break; - case -7: - char_log - ("Invalid register structure in the next character line (character not readed):\n"); - break; - default: // 0 - char_log - ("Unabled to get a character in the next line - Basic structure of line (before inventory) is incorrect (character not readed):\n"); - break; - } - char_log ("%s", line); - } - } - fclose_ (fp); - - if (char_num == 0) - { - printf ("mmo_char_init: No character found in %s.\n", char_txt); - char_log ("mmo_char_init: No character found in %s.\n", - char_txt); - } - else if (char_num == 1) - { - printf ("mmo_char_init: 1 character read in %s.\n", char_txt); - char_log ("mmo_char_init: 1 character read in %s.\n", char_txt); - } - else - { - printf ("mmo_char_init: %d characters read in %s.\n", char_num, - char_txt); - char_log ("mmo_char_init: %d characters read in %s.\n", - char_num, char_txt); - } - - char_log ("Id for the next created character: %d.\n", - char_id_count); - - return 0; -} - -//--------------------------------------------------------- -// Function to save characters in files (speed up by [Yor]) -//--------------------------------------------------------- -void mmo_char_sync (void) -{ - char line[65536]; - int i, j, k; - int lock; - FILE *fp; - int id[char_num]; - - // Sorting before save (by [Yor]) - for (i = 0; i < char_num; i++) - { - id[i] = i; - for (j = 0; j < i; j++) - { - if ((char_dat[i].account_id < char_dat[id[j]].account_id) || - // if same account id, we sort by slot. - (char_dat[i].account_id == char_dat[id[j]].account_id && - char_dat[i].char_num < char_dat[id[j]].char_num)) - { - for (k = i; k > j; k--) - id[k] = id[k - 1]; - id[j] = i; // id[i] - break; - } - } - } - - // Data save - fp = lock_fopen (char_txt, &lock); - if (fp == NULL) - { - printf ("WARNING: Server can't not save characters.\n"); - char_log ("WARNING: Server can't not save characters.\n"); - } - else - { - for (i = 0; i < char_num; i++) - { - // create only once the line, and save it in the 2 files (it's speeder than repeat twice the loop and create twice the line) - mmo_char_tostr (line, &char_dat[id[i]]); // use of sorted index - fprintf (fp, "%s\n", line); - } - fprintf (fp, "%d\t%%newid%%\n", char_id_count); - lock_fclose (fp, char_txt, &lock); - } - - // Data save (backup) - if (backup_txt_flag) - { // The backup_txt file was created because char deletion bug existed. Now it's finish and that take a lot of time to create a second file when there are a lot of characters. => option By [Yor] - fp = lock_fopen (backup_txt, &lock); - if (fp == NULL) - { - printf - ("WARNING: Server can't not create backup of characters file.\n"); - char_log - ("WARNING: Server can't not create backup of characters file.\n"); - return; - } - for (i = 0; i < char_num; i++) - { - // create only once the line, and save it in the 2 files (it's speeder than repeat twice the loop and create twice the line) - mmo_char_tostr (line, &char_dat[id[i]]); // use of sorted index - fprintf (fp, "%s\n", line); - } - fprintf (fp, "%d\t%%newid%%\n", char_id_count); - lock_fclose (fp, backup_txt, &lock); - } - - return; -} - -//---------------------------------------------------- -// Function to save (in a periodic way) datas in files -//---------------------------------------------------- -void mmo_char_sync_timer (timer_id tid, tick_t tick, custom_id_t id, custom_data_t data) -{ - if (pid != 0) - { - int status; - pid_t temp = waitpid (pid, &status, WNOHANG); - - // Need to check status too? - if (temp == 0) - { - return; - } - } - - // This can take a lot of time. Fork a child to handle the work and return at once - // If we're unable to fork just continue running the function normally - if ((pid = fork ()) > 0) - return; - - mmo_char_sync (); - inter_save (); - - // If we're a child we should suicide now. - if (pid == 0) - _exit (0); -} - -//---------------------------------------------------- -// Remove trailing whitespace from a name -//---------------------------------------------------- -static void remove_trailing_blanks (char *name) -{ - char *tail = name + strlen (name) - 1; - - while (tail > name && *tail == ' ') - *tail-- = 0; -} - -//---------------------------------------------------- -// Remove prefix whitespace from a name -//---------------------------------------------------- -static void remove_prefix_blanks (char *name) -{ - char *dst = name; - char *src = name; - - while (*src == ' ') // find first nonblank - ++src; - while ((*dst++ = *src++)); // `strmove' -} - -//----------------------------------- -// Function to create a new character -//----------------------------------- -int make_new_char (int fd, unsigned char *dat) -{ - int i, j; - struct char_session_data *sd = (struct char_session_data *)session[fd]->session_data; - - // remove control characters from the name - dat[23] = '\0'; - if (remove_control_chars (dat)) - { - char_log - ("Make new char error (control char received in the name): (connection #%d, account: %d).\n", - fd, sd->account_id); - return -1; - } - - // Eliminate whitespace - remove_trailing_blanks ((char *) dat); - remove_prefix_blanks ((char *) dat); - - // check lenght of character name - if (strlen (dat) < 4) - { - char_log - ("Make new char error (character name too small): (connection #%d, account: %d, name: '%s').\n", - fd, sd->account_id, dat); - return -1; - } - - // Check Authorised letters/symbols in the name of the character - if (char_name_option == 1) - { // only letters/symbols in char_name_letters are authorised - for (i = 0; dat[i]; i++) - if (strchr (char_name_letters, dat[i]) == NULL) - { - char_log - ("Make new char error (invalid letter in the name): (connection #%d, account: %d), name: %s, invalid letter: %c.\n", - fd, sd->account_id, dat, dat[i]); - return -1; - } - } - else if (char_name_option == 2) - { // letters/symbols in char_name_letters are forbidden - for (i = 0; dat[i]; i++) - if (strchr (char_name_letters, dat[i]) != NULL) - { - char_log - ("Make new char error (invalid letter in the name): (connection #%d, account: %d), name: %s, invalid letter: %c.\n", - fd, sd->account_id, dat, dat[i]); - return -1; - } - } // else, all letters/symbols are authorised (except control char removed before) - - if (dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29] != 5 * 6 || // stats - dat[30] >= 9 || // slots (dat[30] can not be negativ) - dat[33] < 0 || dat[33] >= 20 || // hair style - dat[31] >= 12) - { // hair color (dat[31] can not be negativ) - char_log - ("Make new char error (invalid values): (connection #%d, account: %d) slot %d, name: %s, stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d\n", - fd, sd->account_id, dat[30], dat, dat[24], dat[25], - dat[26], dat[27], dat[28], dat[29], - dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], - dat[33], dat[31]); - return -1; - } - - // check individual stat value - for (i = 24; i <= 29; i++) - { - if (dat[i] < 1 || dat[i] > 9) - { - char_log - ("Make new char error (invalid stat value: not between 1 to 9): (connection #%d, account: %d) slot %d, name: %s, stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d\n", - fd, sd->account_id, dat[30], dat, dat[24], dat[25], - dat[26], dat[27], dat[28], dat[29], - dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], - dat[33], dat[31]); - return -1; - } - } - - for (i = 0; i < char_num; i++) - { - if ((name_ignoring_case != 0 && strcmp (char_dat[i].name, dat) == 0) - || (name_ignoring_case == 0 - && strcasecmp (char_dat[i].name, dat) == 0)) - { - char_log - ("Make new char error (name already exists): (connection #%d, account: %d) slot %d, name: %s (actual name of other char: %s), stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d.\n", - fd, sd->account_id, dat[30], dat, char_dat[i].name, - dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], - dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], - dat[33], dat[31]); - return -1; - } - if (char_dat[i].account_id == sd->account_id - && char_dat[i].char_num == dat[30]) - { - char_log - ("Make new char error (slot already used): (connection #%d, account: %d) slot %d, name: %s (actual name of other char: %s), stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d.\n", - fd, sd->account_id, dat[30], dat, char_dat[i].name, - dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], - dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], - dat[33], dat[31]); - return -1; - } - } - - if (strcmp (wisp_server_name, dat) == 0) - { - char_log - ("Make new char error (name used is wisp name for server): (connection #%d, account: %d) slot %d, name: %s (actual name of other char: %d), stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d.\n", - fd, sd->account_id, dat[30], dat, char_dat[i].name, - dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], - dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], - dat[33], dat[31]); - return -1; - } - - if (char_num >= char_max) - { - char_max += 256; - RECREATE (char_dat, struct mmo_charstatus, char_max); - RECREATE (online_chars, int, char_max); - for (j = char_max - 256; j < char_max; j++) - online_chars[j] = -1; - } - - char ip[16]; - unsigned char *sin_addr = - (unsigned char *) &session[fd]->client_addr.sin_addr; - sprintf (ip, "%d.%d.%d.%d", sin_addr[0], sin_addr[1], sin_addr[2], - sin_addr[3]); - - char_log - ("Creation of New Character: (connection #%d, account: %d) slot %d, character Name: %s, stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d. [%s]\n", - fd, sd->account_id, dat[30], dat, dat[24], dat[25], dat[26], - dat[27], dat[28], dat[29], - dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], dat[33], - dat[31], ip); - - memset (&char_dat[i], 0, sizeof (struct mmo_charstatus)); - - char_dat[i].char_id = char_id_count++; - char_dat[i].account_id = sd->account_id; - char_dat[i].char_num = dat[30]; - strcpy (char_dat[i].name, dat); - char_dat[i].pc_class = 0; - char_dat[i].base_level = 1; - char_dat[i].job_level = 1; - char_dat[i].base_exp = 0; - char_dat[i].job_exp = 0; - char_dat[i].zeny = start_zeny; - char_dat[i].str = dat[24]; - char_dat[i].agi = dat[25]; - char_dat[i].vit = dat[26]; - char_dat[i].int_ = dat[27]; - char_dat[i].dex = dat[28]; - char_dat[i].luk = dat[29]; - char_dat[i].max_hp = 40 * (100 + char_dat[i].vit) / 100; - char_dat[i].max_sp = 11 * (100 + char_dat[i].int_) / 100; - char_dat[i].hp = char_dat[i].max_hp; - char_dat[i].sp = char_dat[i].max_sp; - char_dat[i].status_point = 0; - char_dat[i].skill_point = 0; - char_dat[i].option = 0; - char_dat[i].karma = 0; - char_dat[i].manner = 0; - char_dat[i].party_id = 0; - char_dat[i].guild_id = 0; - char_dat[i].hair = dat[33]; - char_dat[i].hair_color = dat[31]; - char_dat[i].clothes_color = 0; - char_dat[i].inventory[0].nameid = start_weapon; // Knife - char_dat[i].inventory[0].amount = 1; - char_dat[i].inventory[0].equip = 0x02; - char_dat[i].inventory[0].identify = 1; - char_dat[i].inventory[0].broken = 0; - char_dat[i].inventory[1].nameid = start_armor; // Cotton Shirt - char_dat[i].inventory[1].amount = 1; - char_dat[i].inventory[1].equip = 0x10; - char_dat[i].inventory[1].identify = 1; - char_dat[i].inventory[1].broken = 0; - char_dat[i].weapon = 1; - char_dat[i].shield = 0; - char_dat[i].head_top = 0; - char_dat[i].head_mid = 0; - char_dat[i].head_bottom = 0; - memcpy (&char_dat[i].last_point, &start_point, sizeof (start_point)); - memcpy (&char_dat[i].save_point, &start_point, sizeof (start_point)); - char_num++; - - return i; -} - -//---------------------------------------------------- -// This function return the name of the job (by [Yor]) -//---------------------------------------------------- -char *job_name (int pc_class) -{ - switch (pc_class) - { - case 0: - return "Novice"; - case 1: - return "Swordsman"; - case 2: - return "Mage"; - case 3: - return "Archer"; - case 4: - return "Acolyte"; - case 5: - return "Merchant"; - case 6: - return "Thief"; - case 7: - return "Knight"; - case 8: - return "Priest"; - case 9: - return "Wizard"; - case 10: - return "Blacksmith"; - case 11: - return "Hunter"; - case 12: - return "Assassin"; - case 13: - return "Knight 2"; - case 14: - return "Crusader"; - case 15: - return "Monk"; - case 16: - return "Sage"; - case 17: - return "Rogue"; - case 18: - return "Alchemist"; - case 19: - return "Bard"; - case 20: - return "Dancer"; - case 21: - return "Crusader 2"; - case 22: - return "Wedding"; - case 23: - return "Super Novice"; - case 4001: - return "Novice High"; - case 4002: - return "Swordsman High"; - case 4003: - return "Mage High"; - case 4004: - return "Archer High"; - case 4005: - return "Acolyte High"; - case 4006: - return "Merchant High"; - case 4007: - return "Thief High"; - case 4008: - return "Lord Knight"; - case 4009: - return "High Priest"; - case 4010: - return "High Wizard"; - case 4011: - return "Whitesmith"; - case 4012: - return "Sniper"; - case 4013: - return "Assassin Cross"; - case 4014: - return "Peko Knight"; - case 4015: - return "Paladin"; - case 4016: - return "Champion"; - case 4017: - return "Professor"; - case 4018: - return "Stalker"; - case 4019: - return "Creator"; - case 4020: - return "Clown"; - case 4021: - return "Gypsy"; - case 4022: - return "Peko Paladin"; - case 4023: - return "Baby Novice"; - case 4024: - return "Baby Swordsman"; - case 4025: - return "Baby Mage"; - case 4026: - return "Baby Archer"; - case 4027: - return "Baby Acolyte"; - case 4028: - return "Baby Merchant"; - case 4029: - return "Baby Thief"; - case 4030: - return "Baby Knight"; - case 4031: - return "Baby Priest"; - case 4032: - return "Baby Wizard"; - case 4033: - return "Baby Blacksmith"; - case 4034: - return "Baby Hunter"; - case 4035: - return "Baby Assassin"; - case 4036: - return "Baby Peco Knight"; - case 4037: - return "Baby Crusader"; - case 4038: - return "Baby Monk"; - case 4039: - return "Baby Sage"; - case 4040: - return "Baby Rogue"; - case 4041: - return "Baby Alchemist"; - case 4042: - return "Baby Bard"; - case 4043: - return "Baby Dancer"; - case 4044: - return "Baby Peco Crusader"; - case 4045: - return "Super Baby"; - } - return "Unknown Job"; -} - -//------------------------------------------------------------- -// Function to create the online files (txt and html). by [Yor] -//------------------------------------------------------------- -void create_online_files (void) -{ - int i, j, k, l; // for loops - int players; // count the number of players - FILE *fp; // for the txt file - FILE *fp2; // for the html file - char temp[256]; // to prepare what we must display - time_t time_server; // for number of seconds - struct tm *datetime; // variable for time in structure ->tm_mday, ->tm_sec, ... - int id[char_num]; - - if (online_display_option == 0) // we display nothing, so return - return; - - //char_log("Creation of online players files.\n"); - - // Get number of online players, id of each online players - players = 0; - // sort online characters. - for (i = 0; i < char_num; i++) - { - if (online_chars[i] != -1) - { - id[players] = i; - // use sorting option - switch (online_sorting_option) - { - case 1: // by name (without case sensitive) - { - char *p_name = char_dat[i].name; //speed up sorting when there are a lot of players. But very rarely players have same name. - for (j = 0; j < players; j++) - if (strcasecmp (p_name, char_dat[id[j]].name) < 0 || - // if same name, we sort with case sensitive. - (strcasecmp (p_name, char_dat[id[j]].name) == 0 && - strcmp (p_name, char_dat[id[j]].name) < 0)) - { - for (k = players; k > j; k--) - id[k] = id[k - 1]; - id[j] = i; // id[players] - break; - } - } - break; - case 2: // by zeny - for (j = 0; j < players; j++) - if (char_dat[i].zeny < char_dat[id[j]].zeny || - // if same number of zenys, we sort by name. - (char_dat[i].zeny == char_dat[id[j]].zeny && - strcasecmp (char_dat[i].name, - char_dat[id[j]].name) < 0)) - { - for (k = players; k > j; k--) - id[k] = id[k - 1]; - id[j] = i; // id[players] - break; - } - break; - case 3: // by base level - for (j = 0; j < players; j++) - if (char_dat[i].base_level < - char_dat[id[j]].base_level || - // if same base level, we sort by base exp. - (char_dat[i].base_level == - char_dat[id[j]].base_level - && char_dat[i].base_exp < - char_dat[id[j]].base_exp)) - { - for (k = players; k > j; k--) - id[k] = id[k - 1]; - id[j] = i; // id[players] - break; - } - break; - case 4: // by job (and job level) - for (j = 0; j < players; j++) - if (char_dat[i].pc_class < char_dat[id[j]].pc_class || - // if same job, we sort by job level. - (char_dat[i].pc_class == char_dat[id[j]].pc_class && - char_dat[i].job_level < - char_dat[id[j]].job_level) || - // if same job and job level, we sort by job exp. - (char_dat[i].pc_class == char_dat[id[j]].pc_class && - char_dat[i].job_level == - char_dat[id[j]].job_level - && char_dat[i].job_exp < - char_dat[id[j]].job_exp)) - { - for (k = players; k > j; k--) - id[k] = id[k - 1]; - id[j] = i; // id[players] - break; - } - break; - case 5: // by location map name - { - int cpm_result; // A lot of player maps are identical. So, test if done often twice. - for (j = 0; j < players; j++) - if ((cpm_result = strcmp (char_dat[i].last_point.map, char_dat[id[j]].last_point.map)) < 0 || // no map are identical and with upper cases (not use strcasecmp) - // if same map name, we sort by name. - (cpm_result == 0 && - strcasecmp (char_dat[i].name, - char_dat[id[j]].name) < 0)) - { - for (k = players; k > j; k--) - id[k] = id[k - 1]; - id[j] = i; // id[players] - break; - } - } - break; - default: // 0 or invalid value: no sorting - break; - } - players++; - } - } - - // write files - fp = fopen_ (online_txt_filename, "w"); - if (fp != NULL) - { - fp2 = fopen_ (online_html_filename, "w"); - if (fp2 != NULL) - { - // get time - time (&time_server); // get time in seconds since 1/1/1970 - datetime = localtime (&time_server); // convert seconds in structure - strftime (temp, sizeof (temp), "%d %b %Y %X", datetime); // like sprintf, but only for date/time (05 dec 2003 15:12:52) - // write heading - fprintf (fp2, "\n"); - fprintf (fp2, " \n", online_refresh_html); // update on client explorer every x seconds - fprintf (fp2, " \n"); - fprintf (fp2, " Online Players on %s\n", - server_name); - fprintf (fp2, " \n"); - fprintf (fp2, " \n"); - fprintf (fp2, "

Online Players on %s (%s):

\n", - server_name, temp); - fprintf (fp, "Online Players on %s (%s):\n", server_name, temp); - fprintf (fp, "\n"); - - // If we display at least 1 player - if (players > 0) - { - j = 0; // count the number of characters for the txt version and to set the separate line - fprintf (fp2, " \n"); - fprintf (fp2, " \n"); - if ((online_display_option & 1) - || (online_display_option & 64)) - { - fprintf (fp2, " \n"); - if (online_display_option & 64) - { - fprintf (fp, "Name "); // 30 - j += 30; - } - else - { - fprintf (fp, "Name "); // 25 - j += 25; - } - } - if ((online_display_option & 6) == 6) - { - fprintf (fp2, " \n"); - fprintf (fp, "Job Levels "); // 27 - j += 27; - } - else if (online_display_option & 2) - { - fprintf (fp2, " \n"); - fprintf (fp, "Job "); // 19 - j += 19; - } - else if (online_display_option & 4) - { - fprintf (fp2, " \n"); - fprintf (fp, " Levels "); // 8 - j += 8; - } - if (online_display_option & 24) - { // 8 or 16 - fprintf (fp2, " \n"); - if (online_display_option & 16) - { - fprintf (fp, "Location ( x , y ) "); // 23 - j += 23; - } - else - { - fprintf (fp, "Location "); // 13 - j += 13; - } - } - if (online_display_option & 32) - { - fprintf (fp2, - " \n"); - fprintf (fp, " Zenys "); // 16 - j += 16; - } - fprintf (fp2, " \n"); - fprintf (fp, "\n"); - for (k = 0; k < j; k++) - fprintf (fp, "-"); - fprintf (fp, "\n"); - - // display each player. - for (i = 0; i < players; i++) - { - // get id of the character (more speed) - j = id[i]; - fprintf (fp2, " \n"); - // displaying the character name - if ((online_display_option & 1) - || (online_display_option & 64)) - { // without/with 'GM' display - strcpy (temp, char_dat[j].name); - l = isGM (char_dat[j].account_id); - if (online_display_option & 64) - { - if (l >= online_gm_display_min_level) - fprintf (fp, "%-24s (GM) ", temp); - else - fprintf (fp, "%-24s ", temp); - } - else - fprintf (fp, "%-24s ", temp); - // name of the character in the html (no < >, because that create problem in html code) - fprintf (fp2, " \n"); - } - // displaying of the job - if (online_display_option & 6) - { - char *jobname = job_name (char_dat[j].pc_class); - if ((online_display_option & 6) == 6) - { - fprintf (fp2, " \n", - jobname, char_dat[j].base_level, - char_dat[j].job_level); - fprintf (fp, "%-18s %3d/%3d ", jobname, - char_dat[j].base_level, - char_dat[j].job_level); - } - else if (online_display_option & 2) - { - fprintf (fp2, " \n", jobname); - fprintf (fp, "%-18s ", jobname); - } - else if (online_display_option & 4) - { - fprintf (fp2, " \n", - char_dat[j].base_level, - char_dat[j].job_level); - fprintf (fp, "%3d/%3d ", char_dat[j].base_level, - char_dat[j].job_level); - } - } - // displaying of the map - if (online_display_option & 24) - { // 8 or 16 - // prepare map name - memset (temp, 0, sizeof (temp)); - strncpy (temp, char_dat[j].last_point.map, 16); - if (strchr (temp, '.') != NULL) - temp[strchr (temp, '.') - temp] = '\0'; // suppress the '.gat' - // write map name - if (online_display_option & 16) - { // map-name AND coordonates - fprintf (fp2, " \n", - temp, char_dat[j].last_point.x, - char_dat[j].last_point.y); - fprintf (fp, "%-12s (%3d,%3d) ", temp, - char_dat[j].last_point.x, - char_dat[j].last_point.y); - } - else - { - fprintf (fp2, " \n", temp); - fprintf (fp, "%-12s ", temp); - } - } - // displaying number of zenys - if (online_display_option & 32) - { - // write number of zenys - if (char_dat[j].zeny == 0) - { // if no zeny - fprintf (fp2, - " \n"); - fprintf (fp, " no zeny "); - } - else - { - fprintf (fp2, - " \n", - char_dat[j].zeny); - fprintf (fp, "%13d z ", char_dat[j].zeny); - } - } - fprintf (fp, "\n"); - fprintf (fp2, " \n"); - } - fprintf (fp2, "
NameJob (levels)JobLevelsLocationzenys
"); - if ((online_display_option & 64) - && l >= online_gm_display_min_level) - fprintf (fp2, ""); - for (k = 0; temp[k]; k++) - { - switch (temp[k]) - { - case '<': // < - fprintf (fp2, "<"); - break; - case '>': // > - fprintf (fp2, ">"); - break; - default: - fprintf (fp2, "%c", temp[k]); - break; - }; - } - if ((online_display_option & 64) - && l >= online_gm_display_min_level) - fprintf (fp2, " (GM)"); - fprintf (fp2, "%s %d/%d%s%d/%d%s (%d, %d)%sno zeny%d z
\n"); - fprintf (fp, "\n"); - } - - // Displaying number of online players - if (players == 0) - { - fprintf (fp2, "

No user is online.

\n"); - fprintf (fp, "No user is online.\n"); - // no display if only 1 player - } - else if (players == 1) - { - } - else - { - fprintf (fp2, "

%d users are online.

\n", players); - fprintf (fp, "%d users are online.\n", players); - } - fprintf (fp2, " \n"); - fprintf (fp2, "\n"); - fclose_ (fp2); - } - fclose_ (fp); - } - - return; -} - -//--------------------------------------------------------------------- -// This function return the number of online players in all map-servers -//--------------------------------------------------------------------- -int count_users (void) -{ - int i, users; - - users = 0; - for (i = 0; i < MAX_MAP_SERVERS; i++) - if (server_fd[i] >= 0) - users += server[i].users; - - return users; -} - -//---------------------------------------- -// [Fate] Find inventory item based on equipment mask, return view. ID must match view ID (!). -//---------------------------------------- -static int find_equip_view (struct mmo_charstatus *p, unsigned int equipmask) -{ - int i; - for (i = 0; i < MAX_INVENTORY; i++) - if (p->inventory[i].nameid && p->inventory[i].amount - && p->inventory[i].equip & equipmask) - return p->inventory[i].nameid; - return 0; -} - -//---------------------------------------- -// Function to send characters to a player -//---------------------------------------- -int mmo_char_send006b (int fd, struct char_session_data *sd) -{ - int i, j, found_num; - struct mmo_charstatus *p; - const int offset = 24; - - found_num = 0; - for (i = 0; i < char_num; i++) - { - if (char_dat[i].account_id == sd->account_id) - { - sd->found_char[found_num] = i; - found_num++; - if (found_num == 9) - break; - } - } - for (i = found_num; i < 9; i++) - sd->found_char[i] = -1; - - memset (WFIFOP (fd, 0), 0, offset + found_num * 106); - WFIFOW (fd, 0) = 0x6b; - WFIFOW (fd, 2) = offset + found_num * 106; - - for (i = 0; i < found_num; i++) - { - p = &char_dat[sd->found_char[i]]; - j = offset + (i * 106); // increase speed of code - - WFIFOL (fd, j) = p->char_id; - WFIFOL (fd, j + 4) = p->base_exp; - WFIFOL (fd, j + 8) = p->zeny; - WFIFOL (fd, j + 12) = p->job_exp; - WFIFOL (fd, j + 16) = 0; //p->job_level; // [Fate] We no longer reveal this to the player, as its meaning is weird. - - WFIFOW (fd, j + 20) = find_equip_view (p, 0x0040); // 9: shoes - WFIFOW (fd, j + 22) = find_equip_view (p, 0x0004); // 10: gloves - WFIFOW (fd, j + 24) = find_equip_view (p, 0x0008); // 11: cape - WFIFOW (fd, j + 26) = find_equip_view (p, 0x0010); // 12: misc1 - WFIFOL (fd, j + 28) = p->option; - - WFIFOL (fd, j + 32) = p->karma; - WFIFOL (fd, j + 36) = p->manner; - - WFIFOW (fd, j + 40) = p->status_point; - WFIFOW (fd, j + 42) = (p->hp > 0x7fff) ? 0x7fff : p->hp; - WFIFOW (fd, j + 44) = (p->max_hp > 0x7fff) ? 0x7fff : p->max_hp; - WFIFOW (fd, j + 46) = (p->sp > 0x7fff) ? 0x7fff : p->sp; - WFIFOW (fd, j + 48) = (p->max_sp > 0x7fff) ? 0x7fff : p->max_sp; - WFIFOW (fd, j + 50) = DEFAULT_WALK_SPEED; // p->speed; - WFIFOW (fd, j + 52) = p->pc_class; - WFIFOW (fd, j + 54) = p->hair; -// WFIFOW(fd,j+56) = p->weapon; // dont send weapon since TMW does not support it - WFIFOW (fd, j + 56) = 0; - WFIFOW (fd, j + 58) = p->base_level; - WFIFOW (fd, j + 60) = p->skill_point; - WFIFOW (fd, j + 62) = p->head_bottom; - WFIFOW (fd, j + 64) = p->shield; - WFIFOW (fd, j + 66) = p->head_top; - WFIFOW (fd, j + 68) = p->head_mid; - WFIFOW (fd, j + 70) = p->hair_color; - WFIFOW (fd, j + 72) = find_equip_view (p, 0x0080); // 13: misc2 -// WFIFOW(fd,j+72) = p->clothes_color; - - memcpy (WFIFOP (fd, j + 74), p->name, 24); - - WFIFOB (fd, j + 98) = (p->str > 255) ? 255 : p->str; - WFIFOB (fd, j + 99) = (p->agi > 255) ? 255 : p->agi; - WFIFOB (fd, j + 100) = (p->vit > 255) ? 255 : p->vit; - WFIFOB (fd, j + 101) = (p->int_ > 255) ? 255 : p->int_; - WFIFOB (fd, j + 102) = (p->dex > 255) ? 255 : p->dex; - WFIFOB (fd, j + 103) = (p->luk > 255) ? 255 : p->luk; - WFIFOB (fd, j + 104) = p->char_num; - } - - WFIFOSET (fd, WFIFOW (fd, 2)); - - return 0; -} - -int set_account_reg2 (int acc, int num, struct global_reg *reg) -{ - int i, c; - - c = 0; - for (i = 0; i < char_num; i++) - { - if (char_dat[i].account_id == acc) - { - memcpy (char_dat[i].account_reg2, reg, - sizeof (char_dat[i].account_reg2)); - char_dat[i].account_reg2_num = num; - c++; - } - } - return c; -} - -// Divorce a character from it's partner and let the map server know -int char_divorce (struct mmo_charstatus *cs) -{ - int i; - char buf[10]; - - if (cs == NULL) - return 0; - - if (cs->partner_id <= 0) - { - WBUFW (buf, 0) = 0x2b12; - WBUFL (buf, 2) = cs->char_id; - WBUFL (buf, 6) = 0; // partner id 0 means failure - mapif_sendall (buf, 10); - return 0; - } - - WBUFW (buf, 0) = 0x2b12; - WBUFL (buf, 2) = cs->char_id; - - for (i = 0; i < char_num; i++) - { - if (char_dat[i].char_id == cs->partner_id - && char_dat[i].partner_id == cs->char_id) - { - WBUFL (buf, 6) = cs->partner_id; - mapif_sendall (buf, 10); - cs->partner_id = 0; - char_dat[i].partner_id = 0; - return 0; - } - // The other char doesn't have us as their partner, so just clear our partner - // Don't worry about this, as the map server should verify itself that the other doesn't have us as a partner, and so won't mess with their marriage - else if (char_dat[i].char_id == cs->partner_id) - { - WBUFL (buf, 6) = cs->partner_id; - mapif_sendall (buf, 10); - cs->partner_id = 0; - return 0; - } - } - - // Our partner wasn't found, so just clear our marriage - WBUFL (buf, 6) = cs->partner_id; - cs->partner_id = 0; - mapif_sendall (buf, 10); - - return 0; -} - -//------------------------------------------------------------ -// E-mail check: return 0 (not correct) or 1 (valid). by [Yor] -//------------------------------------------------------------ -int e_mail_check (unsigned char *email) -{ - char ch; - unsigned char *last_arobas; - - // athena limits - if (strlen (email) < 3 || strlen (email) > 39) - return 0; - - // part of RFC limits (official reference of e-mail description) - if (strchr (email, '@') == NULL || email[strlen (email) - 1] == '@') - return 0; - - if (email[strlen (email) - 1] == '.') - return 0; - - last_arobas = strrchr (email, '@'); - - if (strstr (last_arobas, "@.") != NULL || - strstr (last_arobas, "..") != NULL) - return 0; - - for (ch = 1; ch < 32; ch++) - { - if (strchr (last_arobas, ch) != NULL) - { - return 0; - break; - } - } - - if (strchr (last_arobas, ' ') != NULL || - strchr (last_arobas, ';') != NULL) - return 0; - - // all correct - return 1; -} - -//---------------------------------------------------------------------- -// Force disconnection of an online player (with account value) by [Yor] -//---------------------------------------------------------------------- -int disconnect_player (int accound_id) -{ - int i; - struct char_session_data *sd; - - // disconnect player if online on char-server - for (i = 0; i < fd_max; i++) - { - if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) - { - if (sd->account_id == accound_id) - { - session[i]->eof = 1; - return 1; - } - } - } - - return 0; -} - -// キャラ削除に伴うデータ削除 -static int char_delete (struct mmo_charstatus *cs) -{ - - // ギルド脱退 - if (cs->guild_id) - inter_guild_leave (cs->guild_id, cs->account_id, cs->char_id); - // パーティー脱退 - if (cs->party_id) - inter_party_leave (cs->party_id, cs->account_id); - // 離婚 - if (cs->partner_id) - char_divorce (cs); - - // Force the character (and all on the same account) to leave all map servers - { - unsigned char buf[6]; - WBUFW (buf, 0) = 0x2afe; - WBUFL (buf, 2) = cs->account_id; - mapif_sendall (buf, 6); - } - - return 0; -} - -void parse_tologin (int fd) -{ - int i; - struct char_session_data *sd; - - // only login-server can have an access to here. - // so, if it isn't the login-server, we disconnect the session (fd != login_fd). - if (fd != login_fd || session[fd]->eof) - { - if (fd == login_fd) - { - printf - ("Char-server can't connect to login-server (connection #%d).\n", - fd); - login_fd = -1; - } - close (fd); - delete_session (fd); - return; - } - - sd = (struct char_session_data*)session[fd]->session_data; - - while (RFIFOREST (fd) >= 2) - { -// printf("parse_tologin: connection #%d, packet: 0x%x (with being read: %d bytes).\n", fd, RFIFOW(fd,0), RFIFOREST(fd)); - - switch (RFIFOW (fd, 0)) - { - case 0x2711: - if (RFIFOREST (fd) < 3) - return; - if (RFIFOB (fd, 2)) - { -// printf("connect login server error : %d\n", RFIFOB(fd,2)); - printf ("Can not connect to login-server.\n"); - printf - ("The server communication passwords (default s1/p1) is probably invalid.\n"); - printf - ("Also, please make sure your accounts file (default: accounts.txt) has those values present.\n"); - printf - ("If you changed the communication passwords, change them back at map_athena.conf and char_athena.conf\n"); - exit (1); - } - else - { - printf ("Connected to login-server (connection #%d).\n", - fd); - // if no map-server already connected, display a message... - for (i = 0; i < MAX_MAP_SERVERS; i++) - if (server_fd[i] >= 0 && server[i].map[0][0]) // if map-server online and at least 1 map - break; - if (i == MAX_MAP_SERVERS) - printf ("Awaiting maps from map-server.\n"); - } - RFIFOSKIP (fd, 3); - break; - - case 0x2713: - if (RFIFOREST (fd) < 51) - return; -// printf("parse_tologin 2713 : %d\n", RFIFOB(fd,6)); - for (i = 0; i < fd_max; i++) - { - if (session[i] && (sd = (struct char_session_data*)session[i]->session_data) - && sd->account_id == RFIFOL (fd, 2)) - { - if (RFIFOB (fd, 6) != 0) - { - WFIFOW (i, 0) = 0x6c; - WFIFOB (i, 2) = 0x42; - WFIFOSET (i, 3); - } - else if (max_connect_user == 0 - || count_users () < max_connect_user) - { -// if (max_connect_user == 0) -// printf("max_connect_user (unlimited) -> accepted.\n"); -// else -// printf("count_users(): %d < max_connect_user (%d) -> accepted.\n", count_users(), max_connect_user); - memcpy (sd->email, RFIFOP (fd, 7), 40); - if (e_mail_check (sd->email) == 0) - strncpy (sd->email, "a@a.com", 40); // default e-mail - sd->connect_until_time = (time_t) RFIFOL (fd, 47); - // send characters to player - mmo_char_send006b (i, sd); - } - else - { - // refuse connection: too much online players -// printf("count_users(): %d < max_connect_use (%d) -> fail...\n", count_users(), max_connect_user); - WFIFOW (i, 0) = 0x6c; - WFIFOW (i, 2) = 0; - WFIFOSET (i, 3); - } - break; - } - } - RFIFOSKIP (fd, 51); - break; - - // Receiving of an e-mail/time limit from the login-server (answer of a request because a player comes back from map-server to char-server) by [Yor] - case 0x2717: - if (RFIFOREST (fd) < 50) - return; - for (i = 0; i < fd_max; i++) - { - if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) - { - if (sd->account_id == RFIFOL (fd, 2)) - { - memcpy (sd->email, RFIFOP (fd, 6), 40); - if (e_mail_check (sd->email) == 0) - strncpy (sd->email, "a@a.com", 40); // default e-mail - sd->connect_until_time = (time_t) RFIFOL (fd, 46); - break; - } - } - } - RFIFOSKIP (fd, 50); - break; - - case 0x2721: // gm reply - if (RFIFOREST (fd) < 10) - return; - { - unsigned char buf[10]; - WBUFW (buf, 0) = 0x2b0b; - WBUFL (buf, 2) = RFIFOL (fd, 2); // account - WBUFL (buf, 6) = RFIFOL (fd, 6); // GM level - mapif_sendall (buf, 10); -// printf("parse_tologin: To become GM answer: char -> map.\n"); - } - RFIFOSKIP (fd, 10); - break; - - case 0x2723: // changesex reply (modified by [Yor]) - if (RFIFOREST (fd) < 7) - return; - { - int acc, sex, i, j; - unsigned char buf[7]; - acc = RFIFOL (fd, 2); - sex = RFIFOB (fd, 6); - RFIFOSKIP (fd, 7); - if (acc > 0) - { - for (i = 0; i < char_num; i++) - { - if (char_dat[i].account_id == acc) - { - int jobclass = char_dat[i].pc_class; - char_dat[i].sex = sex; -// auth_fifo[i].sex = sex; - if (jobclass == 19 || jobclass == 20 || - jobclass == 4020 || jobclass == 4021 || - jobclass == 4042 || jobclass == 4043) - { - // job modification - if (jobclass == 19 || jobclass == 20) - { - char_dat[i].pc_class = (sex) ? 19 : 20; - } - else if (jobclass == 4020 - || jobclass == 4021) - { - char_dat[i].pc_class = - (sex) ? 4020 : 4021; - } - else if (jobclass == 4042 - || jobclass == 4043) - { - char_dat[i].pc_class = - (sex) ? 4042 : 4043; - } - } - // to avoid any problem with equipment and invalid sex, equipment is unequiped. - for (j = 0; j < MAX_INVENTORY; j++) - { - if (char_dat[i].inventory[j].nameid - && char_dat[i].inventory[j].equip) - char_dat[i].inventory[j].equip = 0; - } - char_dat[i].weapon = 0; - char_dat[i].shield = 0; - char_dat[i].head_top = 0; - char_dat[i].head_mid = 0; - char_dat[i].head_bottom = 0; - } - } - // disconnect player if online on char-server - disconnect_player (acc); - } - WBUFW (buf, 0) = 0x2b0d; - WBUFL (buf, 2) = acc; - WBUFB (buf, 6) = sex; - mapif_sendall (buf, 7); - } - break; - - case 0x2726: // Request to send a broadcast message (no answer) - if (RFIFOREST (fd) < 8 - || RFIFOREST (fd) < (8 + RFIFOL (fd, 4))) - return; - if (RFIFOL (fd, 4) < 1) - char_log - ("Receiving a message for broadcast, but message is void.\n"); - else - { - // at least 1 map-server - for (i = 0; i < MAX_MAP_SERVERS; i++) - if (server_fd[i] >= 0) - break; - if (i == MAX_MAP_SERVERS) - char_log - ("'ladmin': Receiving a message for broadcast, but no map-server is online.\n"); - else - { - char buf[128]; - char message[RFIFOL (fd, 4) + 1]; // +1 to add a null terminated if not exist in the packet - int lp; - char *p; - memset (message, '\0', sizeof (message)); - memcpy (message, RFIFOP (fd, 8), RFIFOL (fd, 4)); - message[sizeof (message) - 1] = '\0'; - remove_control_chars (message); - // remove all first spaces - p = message; - while (p[0] == ' ') - p++; - // if message is only composed of spaces - if (p[0] == '\0') - char_log - ("Receiving a message for broadcast, but message is only a lot of spaces.\n"); - // else send message to all map-servers - else - { - if (RFIFOW (fd, 2) == 0) - { - char_log - ("'ladmin': Receiving a message for broadcast (message (in yellow): %s)\n", - message); - lp = 4; - } - else - { - char_log - ("'ladmin': Receiving a message for broadcast (message (in blue): %s)\n", - message); - lp = 8; - } - // split message to max 80 char - while (p[0] != '\0') - { // if not finish - if (p[0] == ' ') // jump if first char is a space - p++; - else - { - char split[80]; - char *last_space; - sscanf (p, "%79[^\t]", split); // max 79 char, any char (\t is control char and control char was removed before) - split[sizeof (split) - 1] = '\0'; // last char always \0 - if ((last_space = - strrchr (split, ' ')) != NULL) - { // searching space from end of the string - last_space[0] = '\0'; // replace it by NULL to have correct length of split - p++; // to jump the new NULL - } - p += strlen (split); - // send broadcast to all map-servers - WBUFW (buf, 0) = 0x3800; - WBUFW (buf, 2) = lp + strlen (split) + 1; - WBUFL (buf, 4) = 0x65756c62; // only write if in blue (lp = 8) - memcpy (WBUFP (buf, lp), split, - strlen (split) + 1); - mapif_sendall (buf, WBUFW (buf, 2)); - } - } - } - } - } - RFIFOSKIP (fd, 8 + RFIFOL (fd, 4)); - break; - - // account_reg2変更通知 - case 0x2729: - if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) - return; - { - struct global_reg reg[ACCOUNT_REG2_NUM]; - unsigned char buf[4096]; - int j, p, acc; - acc = RFIFOL (fd, 4); - for (p = 8, j = 0; - p < RFIFOW (fd, 2) && j < ACCOUNT_REG2_NUM; - p += 36, j++) - { - memcpy (reg[j].str, RFIFOP (fd, p), 32); - reg[j].value = RFIFOL (fd, p + 32); - } - set_account_reg2 (acc, j, reg); - // 同垢ログインを禁止していれば送る必要は無い - memcpy (buf, RFIFOP (fd, 0), RFIFOW (fd, 2)); - WBUFW (buf, 0) = 0x2b11; - mapif_sendall (buf, WBUFW (buf, 2)); - RFIFOSKIP (fd, RFIFOW (fd, 2)); -// printf("char: save_account_reg_reply\n"); - } - break; - - case 0x7924: - { // [Fate] Itemfrob package: forwarded from login-server - if (RFIFOREST (fd) < 10) - return; - int source_id = RFIFOL (fd, 2); - int dest_id = RFIFOL (fd, 6); - unsigned char buf[10]; - - WBUFW (buf, 0) = 0x2afa; - WBUFL (buf, 2) = source_id; - WBUFL (buf, 6) = dest_id; - - mapif_sendall (buf, 10); // forward package to map servers - for (i = 0; i < char_num; i++) - { - struct mmo_charstatus *c = char_dat + i; - struct storage *s = account2storage (c->account_id); - int changes = 0; - int j; -#define FIX(v) if (v == source_id) {v = dest_id; ++changes; } - for (j = 0; j < MAX_INVENTORY; j++) - FIX (c->inventory[j].nameid); - for (j = 0; j < MAX_CART; j++) - FIX (c->cart[j].nameid); - FIX (c->weapon); - FIX (c->shield); - FIX (c->head_top); - FIX (c->head_mid); - FIX (c->head_bottom); - - if (s) - for (j = 0; j < s->storage_amount; j++) - FIX (s->storage_[j].nameid); -#undef FIX - if (changes) - char_log - ("itemfrob(%d -> %d): `%s'(%d, account %d): changed %d times\n", - source_id, dest_id, c->name, c->char_id, - c->account_id, changes); - - } - - mmo_char_sync (); - inter_storage_save (); - RFIFOSKIP (fd, 10); - break; - } - - // Account deletion notification (from login-server) - case 0x2730: - if (RFIFOREST (fd) < 6) - return; - // Deletion of all characters of the account - for (i = 0; i < char_num; i++) - { - if (char_dat[i].account_id == RFIFOL (fd, 2)) - { - char_delete (&char_dat[i]); - if (i < char_num - 1) - { - memcpy (&char_dat[i], &char_dat[char_num - 1], - sizeof (struct mmo_charstatus)); - // if moved character owns to deleted account, check again it's character - if (char_dat[i].account_id == RFIFOL (fd, 2)) - { - i--; - // Correct moved character reference in the character's owner by [Yor] - } - else - { - int j, k; - struct char_session_data *sd2; - for (j = 0; j < fd_max; j++) - { - if (session[j] - && (sd2 = (struct char_session_data*)session[j]->session_data) - && sd2->account_id == - char_dat[char_num - 1].account_id) - { - for (k = 0; k < 9; k++) - { - if (sd2->found_char[k] == - char_num - 1) - { - sd2->found_char[k] = i; - break; - } - } - break; - } - } - } - } - char_num--; - } - } - // Deletion of the storage - inter_storage_delete (RFIFOL (fd, 2)); - // send to all map-servers to disconnect the player - { - unsigned char buf[6]; - WBUFW (buf, 0) = 0x2b13; - WBUFL (buf, 2) = RFIFOL (fd, 2); - mapif_sendall (buf, 6); - } - // disconnect player if online on char-server - disconnect_player (RFIFOL (fd, 2)); - RFIFOSKIP (fd, 6); - break; - - // State change of account/ban notification (from login-server) by [Yor] - case 0x2731: - if (RFIFOREST (fd) < 11) - return; - // send to all map-servers to disconnect the player - { - unsigned char buf[11]; - WBUFW (buf, 0) = 0x2b14; - WBUFL (buf, 2) = RFIFOL (fd, 2); - WBUFB (buf, 6) = RFIFOB (fd, 6); // 0: change of statut, 1: ban - WBUFL (buf, 7) = RFIFOL (fd, 7); // status or final date of a banishment - mapif_sendall (buf, 11); - } - // disconnect player if online on char-server - disconnect_player (RFIFOL (fd, 2)); - RFIFOSKIP (fd, 11); - break; - - // Receiving GM acounts info from login-server (by [Yor]) - case 0x2732: - if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) - return; - { - char buf[32000]; - if (gm_account != NULL) - free (gm_account); - CREATE (gm_account, struct gm_account, (RFIFOW (fd, 2) - 4) / 5); - GM_num = 0; - for (i = 4; i < RFIFOW (fd, 2); i = i + 5) - { - gm_account[GM_num].account_id = RFIFOL (fd, i); - gm_account[GM_num].level = (int) RFIFOB (fd, i + 4); - //printf("GM account: %d -> level %d\n", gm_account[GM_num].account_id, gm_account[GM_num].level); - GM_num++; - } - printf - ("From login-server: receiving of %d GM accounts information.\n", - GM_num); - char_log - ("From login-server: receiving of %d GM accounts information.\n", - GM_num); - create_online_files (); // update online players files (perhaps some online players change of GM level) - // send new gm acccounts level to map-servers - memcpy (buf, RFIFOP (fd, 0), RFIFOW (fd, 2)); - WBUFW (buf, 0) = 0x2b15; - mapif_sendall (buf, RFIFOW (fd, 2)); - } - RFIFOSKIP (fd, RFIFOW (fd, 2)); - break; - - case 0x2741: // change password reply - if (RFIFOREST (fd) < 7) - return; - { - int acc, status, i; - acc = RFIFOL (fd, 2); - status = RFIFOB (fd, 6); - - for (i = 0; i < fd_max; i++) - { - if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) - { - if (sd->account_id == acc) - { - WFIFOW (i, 0) = 0x62; - WFIFOB (i, 2) = status; - WFIFOSET (i, 3); - break; - } - } - } - } - RFIFOSKIP (fd, 7); - break; - - default: - session[fd]->eof = 1; - return; - } - } - RFIFOFLUSH (fd); -} - -//-------------------------------- -// Map-server anti-freeze system -//-------------------------------- -void map_anti_freeze_system (timer_id tid, tick_t tick, custom_id_t id, custom_data_t data) -{ - int i; - - //printf("Entering in map_anti_freeze_system function to check freeze of servers.\n"); - for (i = 0; i < MAX_MAP_SERVERS; i++) - { - if (server_fd[i] >= 0) - { // if map-server is online - //printf("map_anti_freeze_system: server #%d, flag: %d.\n", i, server_freezeflag[i]); - if (server_freezeflag[i]-- < 1) - { // Map-server anti-freeze system. Counter. 5 ok, 4...0 freezed - printf - ("Map-server anti-freeze system: char-server #%d is freezed -> disconnection.\n", - i); - char_log - ("Map-server anti-freeze system: char-server #%d is freezed -> disconnection.\n", - i); - session[server_fd[i]]->eof = 1; - } - } - } -} - -void parse_frommap (int fd) -{ - int i, j; - int id; - - for (id = 0; id < MAX_MAP_SERVERS; id++) - if (server_fd[id] == fd) - break; - if (id == MAX_MAP_SERVERS || session[fd]->eof) - { - if (id < MAX_MAP_SERVERS) - { - printf ("Map-server %d (session #%d) has disconnected.\n", id, - fd); - memset (&server[id], 0, sizeof (struct mmo_map_server)); - server_fd[id] = -1; - for (j = 0; j < char_num; j++) - if (online_chars[j] == fd) - online_chars[j] = -1; - create_online_files (); // update online players files (to remove all online players of this server) - } - close (fd); - delete_session (fd); - return; - } - - while (RFIFOREST (fd) >= 2) - { -// printf("parse_frommap: connection #%d, packet: 0x%x (with being read: %d bytes).\n", fd, RFIFOW(fd,0), RFIFOREST(fd)); - - switch (RFIFOW (fd, 0)) - { - // request from map-server to reload GM accounts. Transmission to login-server (by Yor) - case 0x2af7: - if (login_fd > 0) - { // don't send request if no login-server - WFIFOW (login_fd, 0) = 0x2709; - WFIFOSET (login_fd, 2); -// printf("char : request from map-server to reload GM accounts -> login-server.\n"); - } - RFIFOSKIP (fd, 2); - break; - - // Receiving map names list from the map-server - case 0x2afa: - if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) - return; - memset (server[id].map, 0, sizeof (server[id].map)); - j = 0; - for (i = 4; i < RFIFOW (fd, 2); i += 16) - { - memcpy (server[id].map[j], RFIFOP (fd, i), 16); -// printf("set map %d.%d : %s\n", id, j, server[id].map[j]); - j++; - } - { - unsigned char *p = (unsigned char *) &server[id].ip; - printf - ("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n", - id, j, p[0], p[1], p[2], p[3], server[id].port); - printf ("Map-server %d loading complete.\n", id); - char_log - ("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d. Map-server %d loading complete.\n", - id, j, p[0], p[1], p[2], p[3], - server[id].port, id); - } - WFIFOW (fd, 0) = 0x2afb; - WFIFOB (fd, 2) = 0; - memcpy (WFIFOP (fd, 3), wisp_server_name, 24); // name for wisp to player - WFIFOSET (fd, 27); - { - unsigned char buf[16384]; - int x; - if (j == 0) - { - printf ("WARNING: Map-Server %d have NO map.\n", id); - char_log ("WARNING: Map-Server %d have NO map.\n", - id); - // Transmitting maps information to the other map-servers - } - else - { - WBUFW (buf, 0) = 0x2b04; - WBUFW (buf, 2) = j * 16 + 10; - WBUFL (buf, 4) = server[id].ip; - WBUFW (buf, 8) = server[id].port; - memcpy (WBUFP (buf, 10), RFIFOP (fd, 4), j * 16); - mapif_sendallwos (fd, buf, WBUFW (buf, 2)); - } - // Transmitting the maps of the other map-servers to the new map-server - for (x = 0; x < MAX_MAP_SERVERS; x++) - { - if (server_fd[x] >= 0 && x != id) - { - WFIFOW (fd, 0) = 0x2b04; - WFIFOL (fd, 4) = server[x].ip; - WFIFOW (fd, 8) = server[x].port; - j = 0; - for (i = 0; i < MAX_MAP_PER_SERVER; i++) - if (server[x].map[i][0]) - memcpy (WFIFOP (fd, 10 + (j++) * 16), - server[x].map[i], 16); - if (j > 0) - { - WFIFOW (fd, 2) = j * 16 + 10; - WFIFOSET (fd, WFIFOW (fd, 2)); - } - } - } - } - RFIFOSKIP (fd, RFIFOW (fd, 2)); - break; - - // 認証要求 - case 0x2afc: - if (RFIFOREST (fd) < 22) - return; - //printf("auth_fifo search: account: %d, char: %d, secure: %08x-%08x\n", RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14)); - for (i = 0; i < AUTH_FIFO_SIZE; i++) - { - if (auth_fifo[i].account_id == RFIFOL (fd, 2) && - auth_fifo[i].char_id == RFIFOL (fd, 6) && - auth_fifo[i].login_id1 == RFIFOL (fd, 10) && -#if CMP_AUTHFIFO_LOGIN2 != 0 - // here, it's the only area where it's possible that we doesn't know login_id2 (map-server asks just after 0x72 packet, that doesn't given the value) - (auth_fifo[i].login_id2 == RFIFOL (fd, 14) || RFIFOL (fd, 14) == 0) && // relate to the versions higher than 18 -#endif - (!check_ip_flag || auth_fifo[i].ip == RFIFOL (fd, 18)) - && !auth_fifo[i].delflag) - { - auth_fifo[i].delflag = 1; - WFIFOW (fd, 0) = 0x2afd; - WFIFOW (fd, 2) = 18 + sizeof (struct mmo_charstatus); - WFIFOL (fd, 4) = RFIFOL (fd, 2); - WFIFOL (fd, 8) = auth_fifo[i].login_id2; - WFIFOL (fd, 12) = - (unsigned long) auth_fifo[i].connect_until_time; - char_dat[auth_fifo[i].char_pos].sex = - auth_fifo[i].sex; - WFIFOW (fd, 16) = auth_fifo[i].packet_tmw_version; - fprintf (stderr, - "From queue index %d: recalling packet version %d\n", - i, auth_fifo[i].packet_tmw_version); - memcpy (WFIFOP (fd, 18), - &char_dat[auth_fifo[i].char_pos], - sizeof (struct mmo_charstatus)); - WFIFOSET (fd, WFIFOW (fd, 2)); - //printf("auth_fifo search success (auth #%d, account %d, character: %d).\n", i, RFIFOL(fd,2), RFIFOL(fd,6)); - break; - } - } - if (i == AUTH_FIFO_SIZE) - { - WFIFOW (fd, 0) = 0x2afe; - WFIFOL (fd, 2) = RFIFOL (fd, 2); - WFIFOSET (fd, 6); - printf - ("auth_fifo search error! account %d not authentified.\n", - RFIFOL (fd, 2)); - } - RFIFOSKIP (fd, 22); - break; - - // MAPサーバー上のユーザー数受信 - case 0x2aff: - if (RFIFOREST (fd) < 6 || RFIFOREST (fd) < RFIFOW (fd, 2)) - return; - server[id].users = RFIFOW (fd, 4); - if (anti_freeze_enable) - server_freezeflag[id] = 5; // Map anti-freeze system. Counter. 5 ok, 4...0 freezed - // remove all previously online players of the server - for (i = 0; i < char_num; i++) - if (online_chars[i] == id) - online_chars[i] = -1; - // add online players in the list by [Yor] - for (i = 0; i < server[id].users; i++) - { - int char_id = RFIFOL (fd, 6 + i * 4); - for (j = 0; j < char_num; j++) - if (char_dat[j].char_id == char_id) - { - online_chars[j] = id; - //printf("%d\n", char_id); - break; - } - } - if (update_online < time (NULL)) - { // Time is done - update_online = time (NULL) + 8; - create_online_files (); // only every 8 sec. (normally, 1 server send users every 5 sec.) Don't update every time, because that takes time, but only every 2 connection. - // it set to 8 sec because is more than 5 (sec) and if we have more than 1 map-server, informations can be received in shifted. - } - RFIFOSKIP (fd, 6 + i * 4); - break; - - // キャラデータ保存 - case 0x2b01: - if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) - return; - for (i = 0; i < char_num; i++) - { - if (char_dat[i].account_id == RFIFOL (fd, 4) && - char_dat[i].char_id == RFIFOL (fd, 8)) - break; - } - if (i != char_num) - memcpy (&char_dat[i], RFIFOP (fd, 12), - sizeof (struct mmo_charstatus)); - RFIFOSKIP (fd, RFIFOW (fd, 2)); - break; - - // キャラセレ要求 - case 0x2b02: - if (RFIFOREST (fd) < 18) - return; - if (auth_fifo_pos >= AUTH_FIFO_SIZE) - auth_fifo_pos = 0; - //printf("auth_fifo set (auth #%d) - account: %d, secure: %08x-%08x\n", auth_fifo_pos, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); - auth_fifo[auth_fifo_pos].account_id = RFIFOL (fd, 2); - auth_fifo[auth_fifo_pos].char_id = 0; - auth_fifo[auth_fifo_pos].login_id1 = RFIFOL (fd, 6); - auth_fifo[auth_fifo_pos].login_id2 = RFIFOL (fd, 10); - auth_fifo[auth_fifo_pos].delflag = 2; - auth_fifo[auth_fifo_pos].char_pos = 0; - auth_fifo[auth_fifo_pos].connect_until_time = 0; // unlimited/unknown time by default (not display in map-server) - auth_fifo[auth_fifo_pos].ip = RFIFOL (fd, 14); - auth_fifo_pos++; - WFIFOW (fd, 0) = 0x2b03; - WFIFOL (fd, 2) = RFIFOL (fd, 2); - WFIFOB (fd, 6) = 0; - WFIFOSET (fd, 7); - RFIFOSKIP (fd, 18); - break; - - // マップサーバー間移動要求 - case 0x2b05: - if (RFIFOREST (fd) < 49) - return; - if (auth_fifo_pos >= AUTH_FIFO_SIZE) - auth_fifo_pos = 0; - WFIFOW (fd, 0) = 0x2b06; - memcpy (WFIFOP (fd, 2), RFIFOP (fd, 2), 42); - //printf("auth_fifo set (auth#%d) - account: %d, secure: 0x%08x-0x%08x\n", auth_fifo_pos, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); - auth_fifo[auth_fifo_pos].account_id = RFIFOL (fd, 2); - auth_fifo[auth_fifo_pos].char_id = RFIFOL (fd, 14); - auth_fifo[auth_fifo_pos].login_id1 = RFIFOL (fd, 6); - auth_fifo[auth_fifo_pos].login_id2 = RFIFOL (fd, 10); - auth_fifo[auth_fifo_pos].delflag = 0; - auth_fifo[auth_fifo_pos].sex = RFIFOB (fd, 44); - auth_fifo[auth_fifo_pos].connect_until_time = 0; // unlimited/unknown time by default (not display in map-server) - auth_fifo[auth_fifo_pos].ip = RFIFOL (fd, 45); - for (i = 0; i < char_num; i++) - if (char_dat[i].account_id == RFIFOL (fd, 2) && - char_dat[i].char_id == RFIFOL (fd, 14)) - { - auth_fifo[auth_fifo_pos].char_pos = i; - auth_fifo_pos++; - WFIFOL (fd, 6) = 0; - break; - } - if (i == char_num) - WFIFOW (fd, 6) = 1; - WFIFOSET (fd, 44); - RFIFOSKIP (fd, 49); - break; - - // キャラ名検索 - case 0x2b08: - if (RFIFOREST (fd) < 6) - return; - for (i = 0; i < char_num; i++) - { - if (char_dat[i].char_id == RFIFOL (fd, 2)) - break; - } - WFIFOW (fd, 0) = 0x2b09; - WFIFOL (fd, 2) = RFIFOL (fd, 2); - if (i != char_num) - memcpy (WFIFOP (fd, 6), char_dat[i].name, 24); - else - memcpy (WFIFOP (fd, 6), unknown_char_name, 24); - WFIFOSET (fd, 30); - RFIFOSKIP (fd, 6); - break; - - // it is a request to become GM - case 0x2b0a: - if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) - return; -// printf("parse_frommap: change gm -> login, account: %d, pass: '%s'.\n", RFIFOL(fd,4), RFIFOP(fd,8)); - if (login_fd > 0) - { // don't send request if no login-server - WFIFOW (login_fd, 0) = 0x2720; - memcpy (WFIFOP (login_fd, 2), RFIFOP (fd, 2), - RFIFOW (fd, 2) - 2); - WFIFOSET (login_fd, RFIFOW (fd, 2)); - } - else - { - WFIFOW (fd, 0) = 0x2b0b; - WFIFOL (fd, 2) = RFIFOL (fd, 4); - WFIFOL (fd, 6) = 0; - WFIFOSET (fd, 10); - } - RFIFOSKIP (fd, RFIFOW (fd, 2)); - break; - - // Map server send information to change an email of an account -> login-server - case 0x2b0c: - if (RFIFOREST (fd) < 86) - return; - if (login_fd > 0) - { // don't send request if no login-server - memcpy (WFIFOP (login_fd, 0), RFIFOP (fd, 0), 86); // 0x2722 .L .40B .40B - WFIFOW (login_fd, 0) = 0x2722; - WFIFOSET (login_fd, 86); - } - RFIFOSKIP (fd, 86); - break; - - // Map server ask char-server about a character name to do some operations (all operations are transmitted to login-server) - case 0x2b0e: - if (RFIFOREST (fd) < 44) - return; - { - char character_name[24]; - int acc = RFIFOL (fd, 2); // account_id of who ask (-1 if nobody) - memcpy (character_name, RFIFOP (fd, 6), 24); - character_name[sizeof (character_name) - 1] = '\0'; - // prepare answer - WFIFOW (fd, 0) = 0x2b0f; // answer - WFIFOL (fd, 2) = acc; // who want do operation - WFIFOW (fd, 30) = RFIFOW (fd, 30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban, 5-changesex - // search character - i = search_character_index (character_name); - if (i >= 0) - { - memcpy (WFIFOP (fd, 6), search_character_name (i), 24); // put correct name if found - WFIFOW (fd, 32) = 0; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline - switch (RFIFOW (fd, 30)) - { - case 1: // block - if (acc == -1 - || isGM (acc) >= - isGM (char_dat[i].account_id)) - { - if (login_fd > 0) - { // don't send request if no login-server - WFIFOW (login_fd, 0) = 0x2724; - WFIFOL (login_fd, 2) = char_dat[i].account_id; // account value - WFIFOL (login_fd, 6) = 5; // status of the account - WFIFOSET (login_fd, 10); -// printf("char : status -> login: account %d, status: %d \n", char_dat[i].account_id, 5); - } - else - WFIFOW (fd, 32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline - } - else - WFIFOW (fd, 32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline - break; - case 2: // ban - if (acc == -1 - || isGM (acc) >= - isGM (char_dat[i].account_id)) - { - if (login_fd > 0) - { // don't send request if no login-server - WFIFOW (login_fd, 0) = 0x2725; - WFIFOL (login_fd, 2) = char_dat[i].account_id; // account value - WFIFOW (login_fd, 6) = RFIFOW (fd, 32); // year - WFIFOW (login_fd, 8) = RFIFOW (fd, 34); // month - WFIFOW (login_fd, 10) = RFIFOW (fd, 36); // day - WFIFOW (login_fd, 12) = RFIFOW (fd, 38); // hour - WFIFOW (login_fd, 14) = RFIFOW (fd, 40); // minute - WFIFOW (login_fd, 16) = RFIFOW (fd, 42); // second - WFIFOSET (login_fd, 18); -// printf("char : status -> login: account %d, ban: %dy %dm %dd %dh %dmn %ds\n", -// char_dat[i].account_id, (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), (short)RFIFOW(fd,38), (short)RFIFOW(fd,40), (short)RFIFOW(fd,42)); - } - else - WFIFOW (fd, 32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline - } - else - WFIFOW (fd, 32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline - break; - case 3: // unblock - if (acc == -1 - || isGM (acc) >= - isGM (char_dat[i].account_id)) - { - if (login_fd > 0) - { // don't send request if no login-server - WFIFOW (login_fd, 0) = 0x2724; - WFIFOL (login_fd, 2) = char_dat[i].account_id; // account value - WFIFOL (login_fd, 6) = 0; // status of the account - WFIFOSET (login_fd, 10); -// printf("char : status -> login: account %d, status: %d \n", char_dat[i].account_id, 0); - } - else - WFIFOW (fd, 32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline - } - else - WFIFOW (fd, 32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline - break; - case 4: // unban - if (acc == -1 - || isGM (acc) >= - isGM (char_dat[i].account_id)) - { - if (login_fd > 0) - { // don't send request if no login-server - WFIFOW (login_fd, 0) = 0x272a; - WFIFOL (login_fd, 2) = char_dat[i].account_id; // account value - WFIFOSET (login_fd, 6); -// printf("char : status -> login: account %d, unban request\n", char_dat[i].account_id); - } - else - WFIFOW (fd, 32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline - } - else - WFIFOW (fd, 32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline - break; - case 5: // changesex - if (acc == -1 - || isGM (acc) >= - isGM (char_dat[i].account_id)) - { - if (login_fd > 0) - { // don't send request if no login-server - WFIFOW (login_fd, 0) = 0x2727; - WFIFOL (login_fd, 2) = char_dat[i].account_id; // account value - WFIFOSET (login_fd, 6); -// printf("char : status -> login: account %d, change sex request\n", char_dat[i].account_id); - } - else - WFIFOW (fd, 32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline - } - else - WFIFOW (fd, 32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline - break; - } - } - else - { - // character name not found - memcpy (WFIFOP (fd, 6), character_name, 24); - WFIFOW (fd, 32) = 1; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline - } - // send answer if a player ask, not if the server ask - if (acc != -1) - { - WFIFOSET (fd, 34); - } - RFIFOSKIP (fd, 44); - break; - } - -// case 0x2b0f: not more used (available for futur usage) - - // account_reg保存要求 - case 0x2b10: - if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) - return; - { - struct global_reg reg[ACCOUNT_REG2_NUM]; - int p, acc; - acc = RFIFOL (fd, 4); - for (p = 8, j = 0; - p < RFIFOW (fd, 2) && j < ACCOUNT_REG2_NUM; - p += 36, j++) - { - memcpy (reg[j].str, RFIFOP (fd, p), 32); - reg[j].value = RFIFOL (fd, p + 32); - } - set_account_reg2 (acc, j, reg); - // loginサーバーへ送る - if (login_fd > 0) - { // don't send request if no login-server - memcpy (WFIFOP (login_fd, 0), RFIFOP (fd, 0), - RFIFOW (fd, 2)); - WFIFOW (login_fd, 0) = 0x2728; - WFIFOSET (login_fd, WFIFOW (login_fd, 2)); - } - // ワールドへの同垢ログインがなければmapサーバーに送る必要はない - //memcpy(buf, RFIFOP(fd,0), RFIFOW(fd,2)); - //WBUFW(buf,0) = 0x2b11; - //mapif_sendall(buf, WBUFW(buf,2)); - RFIFOSKIP (fd, RFIFOW (fd, 2)); -// printf("char: save_account_reg (from map)\n"); - break; - } - - // Map server is requesting a divorce - case 0x2b16: - if (RFIFOREST (fd) < 4) - return; - { - for (i = 0; i < char_num; i++) - if (char_dat[i].char_id == RFIFOL (fd, 2)) - break; - - if (i != char_num) - char_divorce (&char_dat[i]); - - RFIFOSKIP (fd, 6); - break; - - } - - default: - // inter server処理に渡す - { - int r = inter_parse_frommap (fd); - if (r == 1) // 処理できた - break; - if (r == 2) // パケット長が足りない - return; - } - // inter server処理でもない場合は切断 - printf - ("char: unknown packet 0x%04x (%d bytes to read in buffer)! (from map).\n", - RFIFOW (fd, 0), RFIFOREST (fd)); - session[fd]->eof = 1; - return; - } - } -} - -int search_mapserver (char *map) -{ - int i, j; - char temp_map[16]; - int temp_map_len; - -// printf("Searching the map-server for map '%s'... ", map); - strncpy (temp_map, map, sizeof (temp_map)); - temp_map[sizeof (temp_map) - 1] = '\0'; - if (strchr (temp_map, '.') != NULL) - temp_map[strchr (temp_map, '.') - temp_map + 1] = '\0'; // suppress the '.gat', but conserve the '.' to be sure of the name of the map - - temp_map_len = strlen (temp_map); - for (i = 0; i < MAX_MAP_SERVERS; i++) - if (server_fd[i] >= 0) - for (j = 0; server[i].map[j][0]; j++) - //printf("%s : %s = %d\n", server[i].map[j], map, strncmp(server[i].map[j], temp_map, temp_map_len)); - if (strncmp (server[i].map[j], temp_map, temp_map_len) == 0) - { -// printf("found -> server #%d.\n", i); - return i; - } - -// printf("not found.\n"); - return -1; -} - -// char_mapifの初期化処理(現在はinter_mapif初期化のみ) -static int char_mapif_init (int fd) -{ - return inter_mapif_init (fd); -} - -//----------------------------------------------------- -// Test to know if an IP come from LAN or WAN. by [Yor] -//----------------------------------------------------- -int lan_ip_check (unsigned char *p) -{ - int i; - int lancheck = 1; - -// printf("lan_ip_check: to compare: %d.%d.%d.%d, network: %d.%d.%d.%d/%d.%d.%d.%d\n", -// p[0], p[1], p[2], p[3], -// subneti[0], subneti[1], subneti[2], subneti[3], -// subnetmaski[0], subnetmaski[1], subnetmaski[2], subnetmaski[3]); - for (i = 0; i < 4; i++) - { - if ((subneti[i] & subnetmaski[i]) != (p[i] & subnetmaski[i])) - { - lancheck = 0; - break; - } - } - printf ("LAN test (result): %s source\033[0m.\n", - (lancheck) ? "\033[1;36mLAN" : "\033[1;32mWAN"); - return lancheck; -} - -void parse_char (int fd) -{ - int i, ch; - char email[40]; - struct char_session_data *sd; - unsigned char *p = (unsigned char *) &session[fd]->client_addr.sin_addr; - - if (login_fd < 0 || session[fd]->eof) - { // disconnect any player (already connected to char-server or coming back from map-server) if login-server is diconnected. - if (fd == login_fd) - login_fd = -1; - close (fd); - delete_session (fd); - return; - } - - sd = (struct char_session_data*)session[fd]->session_data; - - while (RFIFOREST (fd) >= 2) - { -// if (RFIFOW(fd,0) < 30000) -// printf("parse_char: connection #%d, packet: 0x%x (with being read: %d bytes).\n", fd, RFIFOW(fd,0), RFIFOREST(fd)); - - switch (RFIFOW (fd, 0)) - { - case 0x20b: //20040622暗号化ragexe対応 - if (RFIFOREST (fd) < 19) - return; - RFIFOSKIP (fd, 19); - break; - - case 0x61: // change password request - if (RFIFOREST (fd) < 50) - return; - { - WFIFOW (login_fd, 0) = 0x2740; - WFIFOL (login_fd, 2) = sd->account_id; - memcpy (WFIFOP (login_fd, 6), RFIFOP (fd, 2), 24); - memcpy (WFIFOP (login_fd, 30), RFIFOP (fd, 26), 24); - WFIFOSET (login_fd, 54); - } - RFIFOSKIP (fd, 50); - break; - - case 0x65: // 接続要求 - if (RFIFOREST (fd) < 17) - return; - { - int GM_value; - if ((GM_value = isGM (RFIFOL (fd, 2)))) - printf - ("Account Logged On; Account ID: %d (GM level %d).\n", - RFIFOL (fd, 2), GM_value); - else - printf ("Account Logged On; Account ID: %d.\n", - RFIFOL (fd, 2)); - if (sd == NULL) - { - CREATE (sd, struct char_session_data, 1); - session[fd]->session_data = sd; - memcpy (sd->email, "no mail", 40); // put here a mail without '@' to refuse deletion if we don't receive the e-mail - sd->connect_until_time = 0; // unknow or illimited (not displaying on map-server) - } - sd->account_id = RFIFOL (fd, 2); - sd->login_id1 = RFIFOL (fd, 6); - sd->login_id2 = RFIFOL (fd, 10); - sd->packet_tmw_version = RFIFOW (fd, 14); - sd->sex = RFIFOB (fd, 16); - // send back account_id - WFIFOL (fd, 0) = RFIFOL (fd, 2); - WFIFOSET (fd, 4); - // search authentification - for (i = 0; i < AUTH_FIFO_SIZE; i++) - { - if (auth_fifo[i].account_id == sd->account_id && - auth_fifo[i].login_id1 == sd->login_id1 && -#if CMP_AUTHFIFO_LOGIN2 != 0 - auth_fifo[i].login_id2 == sd->login_id2 && // relate to the versions higher than 18 -#endif - (!check_ip_flag - || auth_fifo[i].ip == - session[fd]->client_addr.sin_addr.s_addr) - && auth_fifo[i].delflag == 2) - { - auth_fifo[i].delflag = 1; - if (max_connect_user == 0 - || count_users () < max_connect_user) - { - if (login_fd > 0) - { // don't send request if no login-server - // request to login-server to obtain e-mail/time limit - WFIFOW (login_fd, 0) = 0x2716; - WFIFOL (login_fd, 2) = sd->account_id; - WFIFOSET (login_fd, 6); - } - // Record client version - auth_fifo[i].packet_tmw_version = - sd->packet_tmw_version; - // send characters to player - mmo_char_send006b (fd, sd); - } - else - { - // refuse connection (over populated) - WFIFOW (fd, 0) = 0x6c; - WFIFOW (fd, 2) = 0; - WFIFOSET (fd, 3); - } - break; - } - } - // authentification not found - if (i == AUTH_FIFO_SIZE) - { - if (login_fd > 0) - { // don't send request if no login-server - WFIFOW (login_fd, 0) = 0x2712; // ask login-server to authentify an account - WFIFOL (login_fd, 2) = sd->account_id; - WFIFOL (login_fd, 6) = sd->login_id1; - WFIFOL (login_fd, 10) = sd->login_id2; // relate to the versions higher than 18 - WFIFOB (login_fd, 14) = sd->sex; - WFIFOL (login_fd, 15) = - session[fd]->client_addr.sin_addr.s_addr; - WFIFOSET (login_fd, 19); - } - else - { // if no login-server, we must refuse connection - WFIFOW (fd, 0) = 0x6c; - WFIFOW (fd, 2) = 0; - WFIFOSET (fd, 3); - } - } - } - RFIFOSKIP (fd, 17); - break; - - case 0x66: // キャラ選択 - if (!sd || RFIFOREST (fd) < 3) - return; - - char ip[16]; - unsigned char *sin_addr = - (unsigned char *) &session[fd]->client_addr.sin_addr; - sprintf (ip, "%d.%d.%d.%d", sin_addr[0], sin_addr[1], - sin_addr[2], sin_addr[3]); - - // if we activated email creation and email is default email - if (email_creation != 0 && strcmp (sd->email, "a@a.com") == 0 - && login_fd > 0) - { // to modify an e-mail, login-server must be online - WFIFOW (fd, 0) = 0x70; - WFIFOB (fd, 2) = 0; // 00 = Incorrect Email address - WFIFOSET (fd, 3); - - // otherwise, load the character - } - else - { - for (ch = 0; ch < 9; ch++) - if (sd->found_char[ch] >= 0 - && char_dat[sd->found_char[ch]].char_num == - RFIFOB (fd, 2)) - break; - if (ch != 9) - { - char_log - ("Character Selected, Account ID: %d, Character Slot: %d, Character Name: %s [%s]\n", - sd->account_id, RFIFOB (fd, 2), - char_dat[sd->found_char[ch]].name, ip); - // searching map server - i = search_mapserver (char_dat - [sd->found_char[ch]].last_point. - map); - // if map is not found, we check major cities - if (i < 0) - { - if ((i = search_mapserver ("prontera.gat")) >= 0) - { // check is done without 'gat'. - memcpy (char_dat - [sd->found_char[ch]].last_point.map, - "prontera.gat", 16); - char_dat[sd->found_char[ch]].last_point.x = 273; // savepoint coordonates - char_dat[sd->found_char[ch]].last_point.y = - 354; - } - else if ((i = - search_mapserver ("geffen.gat")) >= 0) - { // check is done without 'gat'. - memcpy (char_dat - [sd->found_char[ch]].last_point.map, - "geffen.gat", 16); - char_dat[sd->found_char[ch]].last_point.x = 120; // savepoint coordonates - char_dat[sd->found_char[ch]].last_point.y = - 100; - } - else if ((i = - search_mapserver ("morocc.gat")) >= 0) - { // check is done without 'gat'. - memcpy (char_dat - [sd->found_char[ch]].last_point.map, - "morocc.gat", 16); - char_dat[sd->found_char[ch]].last_point.x = 160; // savepoint coordonates - char_dat[sd->found_char[ch]].last_point.y = - 94; - } - else if ((i = - search_mapserver ("alberta.gat")) >= 0) - { // check is done without 'gat'. - memcpy (char_dat - [sd->found_char[ch]].last_point.map, - "alberta.gat", 16); - char_dat[sd->found_char[ch]].last_point.x = 116; // savepoint coordonates - char_dat[sd->found_char[ch]].last_point.y = - 57; - } - else if ((i = - search_mapserver ("payon.gat")) >= 0) - { // check is done without 'gat'. - memcpy (char_dat - [sd->found_char[ch]].last_point.map, - "payon.gat", 16); - char_dat[sd->found_char[ch]].last_point.x = 87; // savepoint coordonates - char_dat[sd->found_char[ch]].last_point.y = - 117; - } - else if ((i = - search_mapserver ("izlude.gat")) >= 0) - { // check is done without 'gat'. - memcpy (char_dat - [sd->found_char[ch]].last_point.map, - "izlude.gat", 16); - char_dat[sd->found_char[ch]].last_point.x = 94; // savepoint coordonates - char_dat[sd->found_char[ch]].last_point.y = - 103; - } - else - { - int j; - // get first online server (with a map) - i = 0; - for (j = 0; j < MAX_MAP_SERVERS; j++) - if (server_fd[j] >= 0 - && server[j].map[0][0]) - { // change save point to one of map found on the server (the first) - i = j; - memcpy (char_dat - [sd-> - found_char[ch]].last_point. - map, server[j].map[0], 16); - printf - ("Map-server #%d found with a map: '%s'.\n", - j, server[j].map[0]); - // coordonates are unknown - break; - } - // if no map-server is connected, we send: server closed - if (j == MAX_MAP_SERVERS) - { - WFIFOW (fd, 0) = 0x81; - WFIFOL (fd, 2) = 1; // 01 = Server closed - WFIFOSET (fd, 3); - RFIFOSKIP (fd, 3); - break; - } - } - } - WFIFOW (fd, 0) = 0x71; - WFIFOL (fd, 2) = char_dat[sd->found_char[ch]].char_id; - memcpy (WFIFOP (fd, 6), - char_dat[sd->found_char[ch]].last_point.map, - 16); - printf - ("Character selection '%s' (account: %d, slot: %d) [%s]\n", - char_dat[sd->found_char[ch]].name, - sd->account_id, ch, ip); - printf ("--Send IP of map-server. "); - if (lan_ip_check (p)) - WFIFOL (fd, 22) = inet_addr (lan_map_ip); - else - WFIFOL (fd, 22) = server[i].ip; - WFIFOW (fd, 26) = server[i].port; - WFIFOSET (fd, 28); - if (auth_fifo_pos >= AUTH_FIFO_SIZE) - auth_fifo_pos = 0; - //printf("auth_fifo set #%d - account %d, char: %d, secure: %08x-%08x\n", auth_fifo_pos, sd->account_id, char_dat[sd->found_char[ch]].char_id, sd->login_id1, sd->login_id2); - auth_fifo[auth_fifo_pos].account_id = sd->account_id; - auth_fifo[auth_fifo_pos].char_id = - char_dat[sd->found_char[ch]].char_id; - auth_fifo[auth_fifo_pos].login_id1 = sd->login_id1; - auth_fifo[auth_fifo_pos].login_id2 = sd->login_id2; - auth_fifo[auth_fifo_pos].delflag = 0; - auth_fifo[auth_fifo_pos].char_pos = - sd->found_char[ch]; - auth_fifo[auth_fifo_pos].sex = sd->sex; - auth_fifo[auth_fifo_pos].connect_until_time = - sd->connect_until_time; - auth_fifo[auth_fifo_pos].ip = - session[fd]->client_addr.sin_addr.s_addr; - auth_fifo[auth_fifo_pos].packet_tmw_version = - sd->packet_tmw_version; - auth_fifo_pos++; - } - } - RFIFOSKIP (fd, 3); - break; - - case 0x67: // 作成 - if (!sd || RFIFOREST (fd) < 37) - return; - i = make_new_char (fd, RFIFOP (fd, 2)); - if (i < 0) - { - WFIFOW (fd, 0) = 0x6e; - WFIFOB (fd, 2) = 0x00; - WFIFOSET (fd, 3); - RFIFOSKIP (fd, 37); - break; - } - - WFIFOW (fd, 0) = 0x6d; - memset (WFIFOP (fd, 2), 0, 106); - - WFIFOL (fd, 2) = char_dat[i].char_id; - WFIFOL (fd, 2 + 4) = char_dat[i].base_exp; - WFIFOL (fd, 2 + 8) = char_dat[i].zeny; - WFIFOL (fd, 2 + 12) = char_dat[i].job_exp; - WFIFOL (fd, 2 + 16) = char_dat[i].job_level; - - WFIFOL (fd, 2 + 28) = char_dat[i].karma; - WFIFOL (fd, 2 + 32) = char_dat[i].manner; - - WFIFOW (fd, 2 + 40) = 0x30; - WFIFOW (fd, 2 + 42) = - (char_dat[i].hp > 0x7fff) ? 0x7fff : char_dat[i].hp; - WFIFOW (fd, 2 + 44) = - (char_dat[i].max_hp > - 0x7fff) ? 0x7fff : char_dat[i].max_hp; - WFIFOW (fd, 2 + 46) = - (char_dat[i].sp > 0x7fff) ? 0x7fff : char_dat[i].sp; - WFIFOW (fd, 2 + 48) = - (char_dat[i].max_sp > - 0x7fff) ? 0x7fff : char_dat[i].max_sp; - WFIFOW (fd, 2 + 50) = DEFAULT_WALK_SPEED; // char_dat[i].speed; - WFIFOW (fd, 2 + 52) = char_dat[i].pc_class; - WFIFOW (fd, 2 + 54) = char_dat[i].hair; - - WFIFOW (fd, 2 + 58) = char_dat[i].base_level; - WFIFOW (fd, 2 + 60) = char_dat[i].skill_point; - - WFIFOW (fd, 2 + 64) = char_dat[i].shield; - WFIFOW (fd, 2 + 66) = char_dat[i].head_top; - WFIFOW (fd, 2 + 68) = char_dat[i].head_mid; - WFIFOW (fd, 2 + 70) = char_dat[i].hair_color; - - memcpy (WFIFOP (fd, 2 + 74), char_dat[i].name, 24); - - WFIFOB (fd, 2 + 98) = - (char_dat[i].str > 255) ? 255 : char_dat[i].str; - WFIFOB (fd, 2 + 99) = - (char_dat[i].agi > 255) ? 255 : char_dat[i].agi; - WFIFOB (fd, 2 + 100) = - (char_dat[i].vit > 255) ? 255 : char_dat[i].vit; - WFIFOB (fd, 2 + 101) = - (char_dat[i].int_ > 255) ? 255 : char_dat[i].int_; - WFIFOB (fd, 2 + 102) = - (char_dat[i].dex > 255) ? 255 : char_dat[i].dex; - WFIFOB (fd, 2 + 103) = - (char_dat[i].luk > 255) ? 255 : char_dat[i].luk; - WFIFOB (fd, 2 + 104) = char_dat[i].char_num; - - WFIFOSET (fd, 108); - RFIFOSKIP (fd, 37); - for (ch = 0; ch < 9; ch++) - { - if (sd->found_char[ch] == -1) - { - sd->found_char[ch] = i; - break; - } - } - - case 0x68: // delete char //Yor's Fix - if (!sd || RFIFOREST (fd) < 46) - return; - memcpy (email, RFIFOP (fd, 6), 40); - if (e_mail_check (email) == 0) - strncpy (email, "a@a.com", 40); // default e-mail - - // if we activated email creation and email is default email - if (email_creation != 0 && strcmp (sd->email, "a@a.com") == 0 - && login_fd > 0) - { // to modify an e-mail, login-server must be online - // if sended email is incorrect e-mail - if (strcmp (email, "a@a.com") == 0) - { - WFIFOW (fd, 0) = 0x70; - WFIFOB (fd, 2) = 0; // 00 = Incorrect Email address - WFIFOSET (fd, 3); - RFIFOSKIP (fd, 46); - // we act like we have selected a character - } - else - { - // we change the packet to set it like selection. - for (i = 0; i < 9; i++) - if (char_dat[sd->found_char[i]].char_id == - RFIFOL (fd, 2)) - { - // we save new e-mail - memcpy (sd->email, email, 40); - // we send new e-mail to login-server ('online' login-server is checked before) - WFIFOW (login_fd, 0) = 0x2715; - WFIFOL (login_fd, 2) = sd->account_id; - memcpy (WFIFOP (login_fd, 6), email, 40); - WFIFOSET (login_fd, 46); - // skip part of the packet! (46, but leave the size of select packet: 3) - RFIFOSKIP (fd, 43); - // change value to put new packet (char selection) - RFIFOW (fd, 0) = 0x66; - RFIFOB (fd, 2) = - char_dat[sd->found_char[i]].char_num; - // not send packet, it's modify of actual packet - break; - } - if (i == 9) - { - WFIFOW (fd, 0) = 0x70; - WFIFOB (fd, 2) = 0; // 00 = Incorrect Email address - WFIFOSET (fd, 3); - RFIFOSKIP (fd, 46); - } - } - - // otherwise, we delete the character - } - else - { - /*if (strcasecmp(email, sd->email) != 0) { // if it's an invalid email - * WFIFOW(fd, 0) = 0x70; - * WFIFOB(fd, 2) = 0; // 00 = Incorrect Email address - * WFIFOSET(fd, 3); - * // if mail is correct - * } else { */ - for (i = 0; i < 9; i++) - { - struct mmo_charstatus *cs = NULL; - if (sd->found_char[i] >= 0 - && (cs = - &char_dat[sd->found_char[i]])->char_id == - RFIFOL (fd, 2)) - { - char_delete (cs); // deletion process - - if (sd->found_char[i] != char_num - 1) - { - memcpy (&char_dat[sd->found_char[i]], - &char_dat[char_num - 1], - sizeof (struct mmo_charstatus)); - // Correct moved character reference in the character's owner - { - int j, k; - struct char_session_data *sd2; - for (j = 0; j < fd_max; j++) - { - if (session[j] - && (sd2 = (struct char_session_data*) - session[j]->session_data) - && sd2->account_id == - char_dat[char_num - 1].account_id) - { - for (k = 0; k < 9; k++) - { - if (sd2->found_char[k] == - char_num - 1) - { - sd2->found_char[k] = - sd->found_char[i]; - break; - } - } - break; - } - } - } - } - - char_num--; - for (ch = i; ch < 9 - 1; ch++) - sd->found_char[ch] = sd->found_char[ch + 1]; - sd->found_char[8] = -1; - WFIFOW (fd, 0) = 0x6f; - WFIFOSET (fd, 2); - break; - } - } - - if (i == 9) - { - WFIFOW (fd, 0) = 0x70; - WFIFOB (fd, 2) = 0; - WFIFOSET (fd, 3); - } - //} - RFIFOSKIP (fd, 46); - } - break; - - case 0x2af8: // マップサーバーログイン - if (RFIFOREST (fd) < 60) - return; - WFIFOW (fd, 0) = 0x2af9; - for (i = 0; i < MAX_MAP_SERVERS; i++) - { - if (server_fd[i] < 0) - break; - } - if (i == MAX_MAP_SERVERS || strcmp (RFIFOP (fd, 2), userid) - || strcmp (RFIFOP (fd, 26), passwd)) - { - WFIFOB (fd, 2) = 3; - WFIFOSET (fd, 3); - RFIFOSKIP (fd, 60); - } - else - { - int len; - WFIFOB (fd, 2) = 0; - session[fd]->func_parse = parse_frommap; - server_fd[i] = fd; - if (anti_freeze_enable) - server_freezeflag[i] = 5; // Map anti-freeze system. Counter. 5 ok, 4...0 freezed - server[i].ip = RFIFOL (fd, 54); - server[i].port = RFIFOW (fd, 58); - server[i].users = 0; - memset (server[i].map, 0, sizeof (server[i].map)); - WFIFOSET (fd, 3); - RFIFOSKIP (fd, 60); - realloc_fifo (fd, FIFOSIZE_SERVERLINK, - FIFOSIZE_SERVERLINK); - char_mapif_init (fd); - // send gm acccounts level to map-servers - len = 4; - WFIFOW (fd, 0) = 0x2b15; - for (i = 0; i < GM_num; i++) - { - WFIFOL (fd, len) = gm_account[i].account_id; - WFIFOB (fd, len + 4) = - (unsigned char) gm_account[i].level; - len += 5; - } - WFIFOW (fd, 2) = len; - WFIFOSET (fd, len); - return; - } - break; - - case 0x187: // Alive信号? - if (RFIFOREST (fd) < 6) - return; - RFIFOSKIP (fd, 6); - break; - - case 0x7530: // Athena情報所得 - WFIFOW (fd, 0) = 0x7531; - WFIFOB (fd, 2) = ATHENA_MAJOR_VERSION; - WFIFOB (fd, 3) = ATHENA_MINOR_VERSION; - WFIFOB (fd, 4) = ATHENA_REVISION; - WFIFOB (fd, 5) = ATHENA_RELEASE_FLAG; - WFIFOB (fd, 6) = ATHENA_OFFICIAL_FLAG; - WFIFOB (fd, 7) = ATHENA_SERVER_INTER | ATHENA_SERVER_CHAR; - WFIFOW (fd, 8) = ATHENA_MOD_VERSION; - WFIFOSET (fd, 10); - RFIFOSKIP (fd, 2); - return; - - case 0x7532: // 接続の切断(defaultと処理は一緒だが明示的にするため) - session[fd]->eof = 1; - return; - - default: - session[fd]->eof = 1; - return; - } - } -} - -// 全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す) -int mapif_sendall (char *buf, unsigned int len) -{ - int i, c; - - c = 0; - for (i = 0; i < MAX_MAP_SERVERS; i++) - { - int fd; - if ((fd = server_fd[i]) >= 0) - { - memcpy (WFIFOP (fd, 0), buf, len); - WFIFOSET (fd, len); - c++; - } - } - return c; -} - -// 自分以外の全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す) -int mapif_sendallwos (int sfd, unsigned char *buf, unsigned int len) -{ - int i, c; - - c = 0; - for (i = 0; i < MAX_MAP_SERVERS; i++) - { - int fd; - if ((fd = server_fd[i]) >= 0 && fd != sfd) - { - memcpy (WFIFOP (fd, 0), buf, len); - WFIFOSET (fd, len); - c++; - } - } - return c; -} - -// MAPサーバーにデータ送信(map鯖生存確認有り) -int mapif_send (int fd, unsigned char *buf, unsigned int len) -{ - int i; - - if (fd >= 0) - { - for (i = 0; i < MAX_MAP_SERVERS; i++) - { - if (fd == server_fd[i]) - { - memcpy (WFIFOP (fd, 0), buf, len); - WFIFOSET (fd, len); - return 1; - } - } - } - return 0; -} - -void send_users_tologin (timer_id tid, tick_t tick, custom_id_t id, custom_data_t data) -{ - int users = count_users (); - char buf[16]; - - if (login_fd > 0 && session[login_fd]) - { - // send number of user to login server - WFIFOW (login_fd, 0) = 0x2714; - WFIFOL (login_fd, 2) = users; - WFIFOSET (login_fd, 6); - } - // send number of players to all map-servers - WBUFW (buf, 0) = 0x2b00; - WBUFL (buf, 2) = users; - mapif_sendall (buf, 6); -} - -void check_connect_login_server (timer_id tid, tick_t tick, custom_id_t id, custom_data_t data) -{ - if (login_fd <= 0 || session[login_fd] == NULL) - { - printf ("Attempt to connect to login-server...\n"); - if ((login_fd = make_connection (login_ip, login_port)) < 0) - return; - session[login_fd]->func_parse = parse_tologin; - realloc_fifo (login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); - WFIFOW (login_fd, 0) = 0x2710; - memset (WFIFOP (login_fd, 2), 0, 24); - memcpy (WFIFOP (login_fd, 2), userid, - strlen (userid) < 24 ? strlen (userid) : 24); - memset (WFIFOP (login_fd, 26), 0, 24); - memcpy (WFIFOP (login_fd, 26), passwd, - strlen (passwd) < 24 ? strlen (passwd) : 24); - WFIFOL (login_fd, 50) = 0; - WFIFOL (login_fd, 54) = char_ip; - WFIFOL (login_fd, 58) = char_port; - memset (WFIFOP (login_fd, 60), 0, 20); - memcpy (WFIFOP (login_fd, 60), server_name, - strlen (server_name) < 20 ? strlen (server_name) : 20); - WFIFOW (login_fd, 80) = 0; - WFIFOW (login_fd, 82) = char_maintenance; - WFIFOW (login_fd, 84) = char_new; - WFIFOSET (login_fd, 86); - } -} - -//---------------------------------------------------------- -// Return numerical value of a switch configuration by [Yor] -// on/off, english, français, deutsch, español -//---------------------------------------------------------- -int config_switch (const char *str) -{ - if (strcasecmp (str, "on") == 0 || strcasecmp (str, "yes") == 0 - || strcasecmp (str, "oui") == 0 || strcasecmp (str, "ja") == 0 - || strcasecmp (str, "si") == 0) - return 1; - if (strcasecmp (str, "off") == 0 || strcasecmp (str, "no") == 0 - || strcasecmp (str, "non") == 0 || strcasecmp (str, "nein") == 0) - return 0; - - return atoi (str); -} - -//------------------------------------------- -// Reading Lan Support configuration by [Yor] -//------------------------------------------- -int lan_config_read (const char *lancfgName) -{ - int j; - struct hostent *h = NULL; - char line[1024], w1[1024], w2[1024]; - FILE *fp; - - // set default configuration - strncpy (lan_map_ip, "127.0.0.1", sizeof (lan_map_ip)); - subneti[0] = 127; - subneti[1] = 0; - subneti[2] = 0; - subneti[3] = 1; - for (j = 0; j < 4; j++) - subnetmaski[j] = 255; - - fp = fopen_ (lancfgName, "r"); - - if (fp == NULL) - { - printf ("LAN support configuration file not found: %s\n", lancfgName); - return 1; - } - - printf ("---start reading of Lan Support configuration...\n"); - - while (fgets (line, sizeof (line) - 1, fp)) - { - if (line[0] == '/' && line[1] == '/') - continue; - - line[sizeof (line) - 1] = '\0'; - if (sscanf (line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - remove_control_chars (w1); - remove_control_chars (w2); - if (strcasecmp (w1, "lan_map_ip") == 0) - { // Read map-server Lan IP Address - h = gethostbyname (w2); - if (h != NULL) - { - sprintf (lan_map_ip, "%d.%d.%d.%d", - (unsigned char) h->h_addr[0], - (unsigned char) h->h_addr[1], - (unsigned char) h->h_addr[2], - (unsigned char) h->h_addr[3]); - } - else - { - strncpy (lan_map_ip, w2, sizeof (lan_map_ip)); - lan_map_ip[sizeof (lan_map_ip) - 1] = 0; - } - printf ("LAN IP of map-server: %s.\n", lan_map_ip); - } - else if (strcasecmp (w1, "subnet") == 0) - { // Read Subnetwork - for (j = 0; j < 4; j++) - subneti[j] = 0; - h = gethostbyname (w2); - if (h != NULL) - { - for (j = 0; j < 4; j++) - subneti[j] = (unsigned char) h->h_addr[j]; - } - else - { - sscanf (w2, "%d.%d.%d.%d", &subneti[0], &subneti[1], - &subneti[2], &subneti[3]); - } - printf ("Sub-network of the map-server: %d.%d.%d.%d.\n", - subneti[0], subneti[1], subneti[2], subneti[3]); - } - else if (strcasecmp (w1, "subnetmask") == 0) - { // Read Subnetwork Mask - for (j = 0; j < 4; j++) - subnetmaski[j] = 255; - h = gethostbyname (w2); - if (h != NULL) - { - for (j = 0; j < 4; j++) - subnetmaski[j] = (unsigned char) h->h_addr[j]; - } - else - { - sscanf (w2, "%d.%d.%d.%d", &subnetmaski[0], &subnetmaski[1], - &subnetmaski[2], &subnetmaski[3]); - } - printf ("Sub-network mask of the map-server: %d.%d.%d.%d.\n", - subnetmaski[0], subnetmaski[1], subnetmaski[2], - subnetmaski[3]); - } - } - fclose_ (fp); - - // sub-network check of the map-server - { - unsigned int a0, a1, a2, a3; - unsigned char p[4]; - sscanf (lan_map_ip, "%d.%d.%d.%d", &a0, &a1, &a2, &a3); - p[0] = a0; - p[1] = a1; - p[2] = a2; - p[3] = a3; - printf ("LAN test of LAN IP of the map-server: "); - if (lan_ip_check (p) == 0) - { - printf - ("\033[1;31m***ERROR: LAN IP of the map-server doesn't belong to the specified Sub-network.\033[0m\n"); - } - } - - printf ("---End reading of Lan Support configuration...\n"); - - return 0; -} - -int char_config_read (const char *cfgName) -{ - struct hostent *h = NULL; - char line[1024], w1[1024], w2[1024]; - FILE *fp = fopen_ (cfgName, "r"); - - if (fp == NULL) - { - printf ("Configuration file not found: %s.\n", cfgName); - exit (1); - } - - while (fgets (line, sizeof (line) - 1, fp)) - { - if (line[0] == '/' && line[1] == '/') - continue; - - line[sizeof (line) - 1] = '\0'; - if (sscanf (line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - remove_control_chars (w1); - remove_control_chars (w2); - if (strcasecmp (w1, "userid") == 0) - { - memcpy (userid, w2, 24); - } - else if (strcasecmp (w1, "passwd") == 0) - { - memcpy (passwd, w2, 24); - } - else if (strcasecmp (w1, "server_name") == 0) - { - memcpy (server_name, w2, sizeof (server_name)); - server_name[sizeof (server_name) - 1] = '\0'; - printf ("%s server has been intialized\n", w2); - } - else if (strcasecmp (w1, "wisp_server_name") == 0) - { - if (strlen (w2) >= 4) - { - strncpy (wisp_server_name, w2, sizeof (wisp_server_name)); - wisp_server_name[sizeof (wisp_server_name) - 1] = '\0'; - } - } - else if (strcasecmp (w1, "login_ip") == 0) - { - h = gethostbyname (w2); - if (h != NULL) - { - printf ("Login server IP address : %s -> %d.%d.%d.%d\n", w2, - (unsigned char) h->h_addr[0], - (unsigned char) h->h_addr[1], - (unsigned char) h->h_addr[2], - (unsigned char) h->h_addr[3]); - sprintf (login_ip_str, "%d.%d.%d.%d", - (unsigned char) h->h_addr[0], - (unsigned char) h->h_addr[1], - (unsigned char) h->h_addr[2], - (unsigned char) h->h_addr[3]); - } - else - memcpy (login_ip_str, w2, 16); - } - else if (strcasecmp (w1, "login_port") == 0) - { - login_port = atoi (w2); - } - else if (strcasecmp (w1, "char_ip") == 0) - { - h = gethostbyname (w2); - if (h != NULL) - { - printf ("Character server IP address : %s -> %d.%d.%d.%d\n", - w2, (unsigned char) h->h_addr[0], - (unsigned char) h->h_addr[1], - (unsigned char) h->h_addr[2], - (unsigned char) h->h_addr[3]); - sprintf (char_ip_str, "%d.%d.%d.%d", - (unsigned char) h->h_addr[0], - (unsigned char) h->h_addr[1], - (unsigned char) h->h_addr[2], - (unsigned char) h->h_addr[3]); - } - else - memcpy (char_ip_str, w2, 16); - } - else if (strcasecmp (w1, "char_port") == 0) - { - char_port = atoi (w2); - } - else if (strcasecmp (w1, "char_maintenance") == 0) - { - char_maintenance = atoi (w2); - } - else if (strcasecmp (w1, "char_new") == 0) - { - char_new = atoi (w2); - } - else if (strcasecmp (w1, "email_creation") == 0) - { - email_creation = config_switch (w2); - } - else if (strcasecmp (w1, "char_txt") == 0) - { - strcpy (char_txt, w2); - } - else if (strcasecmp (w1, "backup_txt") == 0) - { //By zanetheinsane - strcpy (backup_txt, w2); - } - else if (strcasecmp (w1, "backup_txt_flag") == 0) - { // The backup_txt file was created because char deletion bug existed. Now it's finish and that take a lot of time to create a second file when there are a lot of characters. By [Yor] - backup_txt_flag = config_switch (w2); - } - else if (strcasecmp (w1, "max_connect_user") == 0) - { - max_connect_user = atoi (w2); - if (max_connect_user < 0) - max_connect_user = 0; // unlimited online players - } - else if (strcasecmp (w1, "check_ip_flag") == 0) - { - check_ip_flag = config_switch (w2); - } - else if (strcasecmp (w1, "autosave_time") == 0) - { - autosave_interval = atoi (w2) * 1000; - if (autosave_interval <= 0) - autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; - } - else if (strcasecmp (w1, "start_point") == 0) - { - char map[32]; - int x, y; - if (sscanf (w2, "%[^,],%d,%d", map, &x, &y) < 3) - continue; - if (strstr (map, ".gat") != NULL) - { // Verify at least if '.gat' is in the map name - memcpy (start_point.map, map, 16); - start_point.x = x; - start_point.y = y; - } - } - else if (strcasecmp (w1, "start_zeny") == 0) - { - start_zeny = atoi (w2); - if (start_zeny < 0) - start_zeny = 0; - } - else if (strcasecmp (w1, "start_weapon") == 0) - { - start_weapon = atoi (w2); - if (start_weapon < 0) - start_weapon = 0; - } - else if (strcasecmp (w1, "start_armor") == 0) - { - start_armor = atoi (w2); - if (start_armor < 0) - start_armor = 0; - } - else if (strcasecmp (w1, "unknown_char_name") == 0) - { - strcpy (unknown_char_name, w2); - unknown_char_name[24] = 0; - } - else if (strcasecmp (w1, "char_log_filename") == 0) - { - strcpy (char_log_filename, w2); - } - else if (strcasecmp (w1, "name_ignoring_case") == 0) - { - name_ignoring_case = config_switch (w2); - } - else if (strcasecmp (w1, "char_name_option") == 0) - { - char_name_option = atoi (w2); - } - else if (strcasecmp (w1, "char_name_letters") == 0) - { - strcpy (char_name_letters, w2); -// online files options - } - else if (strcasecmp (w1, "online_txt_filename") == 0) - { - strcpy (online_txt_filename, w2); - } - else if (strcasecmp (w1, "online_html_filename") == 0) - { - strcpy (online_html_filename, w2); - } - else if (strcasecmp (w1, "online_sorting_option") == 0) - { - online_sorting_option = atoi (w2); - } - else if (strcasecmp (w1, "online_display_option") == 0) - { - online_display_option = atoi (w2); - } - else if (strcasecmp (w1, "online_gm_display_min_level") == 0) - { // minimum GM level to display 'GM' when we want to display it - online_gm_display_min_level = atoi (w2); - if (online_gm_display_min_level < 5) // send online file every 5 seconds to player is enough - online_gm_display_min_level = 5; - } - else if (strcasecmp (w1, "online_refresh_html") == 0) - { - online_refresh_html = atoi (w2); - if (online_refresh_html < 1) - online_refresh_html = 1; - } - else if (strcasecmp (w1, "anti_freeze_enable") == 0) - { - anti_freeze_enable = config_switch (w2); - } - else if (strcasecmp (w1, "anti_freeze_interval") == 0) - { - ANTI_FREEZE_INTERVAL = atoi (w2); - if (ANTI_FREEZE_INTERVAL < 5) - ANTI_FREEZE_INTERVAL = 5; // minimum 5 seconds - } - else if (strcasecmp (w1, "import") == 0) - { - char_config_read (w2); - } - } - fclose_ (fp); - - return 0; -} - -void term_func (void) -{ - int i; - - // write online players files with no player - for (i = 0; i < char_num; i++) - online_chars[i] = -1; - create_online_files (); - free (online_chars); - - mmo_char_sync (); - inter_save (); - - if (gm_account != NULL) - free (gm_account); - - free (char_dat); - delete_session (login_fd); - delete_session (char_fd); - - char_log ("----End of char-server (normal end with closing of all files).\n"); -} - -int do_init (int argc, char **argv) -{ - int i; - - // a newline in the log... - char_log (""); - char_log ("The char-server starting...\n"); - - char_config_read ((argc < 2) ? CHAR_CONF_NAME : argv[1]); - lan_config_read ((argc > 1) ? argv[1] : LOGIN_LAN_CONF_NAME); - - login_ip = inet_addr (login_ip_str); - char_ip = inet_addr (char_ip_str); - - for (i = 0; i < MAX_MAP_SERVERS; i++) - { - memset (&server[i], 0, sizeof (struct mmo_map_server)); - server_fd[i] = -1; - } - - mmo_char_init (); - - update_online = time (NULL); - create_online_files (); // update online players files at start of the server - - inter_init ((argc > 2) ? argv[2] : inter_cfgName); // inter server 初期化 - -// set_termfunc (do_final); - set_defaultparse (parse_char); - - char_fd = make_listen_port (char_port); - -// add_timer_func_list (check_connect_login_server, "check_connect_login_server"); -// add_timer_func_list (send_users_tologin, "send_users_tologin"); -// add_timer_func_list (mmo_char_sync_timer, "mmo_char_sync_timer"); - - i = add_timer_interval (gettick () + 1000, check_connect_login_server, 0, - 0, 10 * 1000); - i = add_timer_interval (gettick () + 1000, send_users_tologin, 0, 0, - 5 * 1000); - i = add_timer_interval (gettick () + autosave_interval, - mmo_char_sync_timer, 0, 0, autosave_interval); - - if (anti_freeze_enable > 0) - { -// add_timer_func_list (map_anti_freeze_system, "map_anti_freeze_system"); - i = add_timer_interval (gettick () + 1000, map_anti_freeze_system, 0, 0, ANTI_FREEZE_INTERVAL * 1000); // checks every X seconds user specifies - } - - char_log ("The char-server is ready (Server is listening on the port %d).\n", - char_port); - - printf - ("The char-server is \033[1;32mready\033[0m (Server is listening on the port %d).\n\n", - char_port); - - return 0; -} diff --git a/src/char/char.cpp b/src/char/char.cpp new file mode 100644 index 0000000..a57520b --- /dev/null +++ b/src/char/char.cpp @@ -0,0 +1,4076 @@ +// $Id: char.c,v 1.3 2004/09/13 16:52:16 Yor Exp $ +// original : char2.c 2003/03/14 11:58:35 Rev.1.5 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/core.hpp" +#include "../common/socket.hpp" +#include "../common/timer.hpp" +#include "../common/mmo.hpp" +#include "../common/version.hpp" +#include "../common/lock.hpp" +#include "char.hpp" + +#include "inter.hpp" +#include "int_guild.hpp" +#include "int_party.hpp" +#include "int_storage.hpp" + +#ifdef MEMWATCH +#include "memwatch.hpp" +#endif + +struct mmo_map_server server[MAX_MAP_SERVERS]; +int server_fd[MAX_MAP_SERVERS]; +int server_freezeflag[MAX_MAP_SERVERS]; // Map-server anti-freeze system. Counter. 5 ok, 4...0 freezed +int anti_freeze_enable = 0; +int ANTI_FREEZE_INTERVAL = 6; + +int login_fd, char_fd; +char userid[24]; +char passwd[24]; +char server_name[20]; +char wisp_server_name[24] = "Server"; +char login_ip_str[16]; +int login_ip; +int login_port = 6900; +char char_ip_str[16]; +int char_ip; +int char_port = 6121; +int char_maintenance; +int char_new; +int email_creation = 0; // disabled by default +char char_txt[1024]; +char backup_txt[1024]; //By zanetheinsane +char backup_txt_flag = 0; // The backup_txt file was created because char deletion bug existed. Now it's finish and that take a lot of time to create a second file when there are a lot of characters. => option By [Yor] +char unknown_char_name[1024] = "Unknown"; +char char_log_filename[1024] = "log/char.log"; +//Added for lan support +char lan_map_ip[128]; +int subneti[4]; +int subnetmaski[4]; +int name_ignoring_case = 0; // Allow or not identical name for characters but with a different case by [Yor] +int char_name_option = 0; // Option to know which letters/symbols are authorised in the name of a character (0: all, 1: only those in char_name_letters, 2: all EXCEPT those in char_name_letters) by [Yor] +char char_name_letters[1024] = ""; // list of letters/symbols authorised (or not) in a character name. by [Yor] + +struct char_session_data +{ + int account_id, login_id1, login_id2, sex; + unsigned short packet_tmw_version; + int found_char[9]; + char email[40]; // e-mail (default: a@a.com) by [Yor] + time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) +}; + +#define AUTH_FIFO_SIZE 256 +struct +{ + int account_id, char_id, login_id1, login_id2, ip, char_pos, delflag, + sex; + unsigned short packet_tmw_version; + time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) +} auth_fifo[AUTH_FIFO_SIZE]; +int auth_fifo_pos = 0; + +int check_ip_flag = 1; // It's to check IP of a player between char-server and other servers (part of anti-hacking system) + +int char_id_count = 150000; +struct mmo_charstatus *char_dat; +int char_num, char_max; +int max_connect_user = 0; +int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; +int start_zeny = 500; +int start_weapon = 1201; +int start_armor = 1202; + +// Initial position (it's possible to set it in conf file) +struct point start_point = { "new_1-1.gat", 53, 111 }; + +struct gm_account *gm_account = NULL; +int GM_num = 0; + +// online players by [Yor] +char online_txt_filename[1024] = "online.txt"; +char online_html_filename[1024] = "online.html"; +int online_sorting_option = 0; // sorting option to display online players in online files +int online_display_option = 1; // display options: to know which columns must be displayed +int online_refresh_html = 20; // refresh time (in sec) of the html file in the explorer +int online_gm_display_min_level = 20; // minimum GM level to display 'GM' when we want to display it + +int *online_chars; // same size of char_dat, and id value of current server (or -1) +time_t update_online; // to update online files when we receiving information from a server (not less than 8 seconds) + +pid_t pid = 0; // For forked DB writes + +//------------------------------ +// Writing function of logs file +//------------------------------ +int char_log (char *fmt, ...) +{ + FILE *logfp; + va_list ap; + struct timeval tv; + char tmpstr[2048]; + + va_start (ap, fmt); + + logfp = fopen_ (char_log_filename, "a"); + if (logfp) + { + if (fmt[0] == '\0') // jump a line if no message + fprintf (logfp, "\n"); + else + { + gettimeofday (&tv, NULL); + strftime (tmpstr, 24, "%d-%m-%Y %H:%M:%S", gmtime (&(tv.tv_sec))); + sprintf (tmpstr + 19, ".%03d: %s", (int) tv.tv_usec / 1000, fmt); + vfprintf (logfp, tmpstr, ap); + } + fclose_ (logfp); + } + + va_end (ap); + return 0; +} + +//----------------------------------------------------- +// Function to suppress control characters in a string. +//----------------------------------------------------- +int remove_control_chars (unsigned char *str) +{ + int i; + int change = 0; + + for (i = 0; str[i]; i++) + { + if (str[i] < 32) + { + str[i] = '_'; + change = 1; + } + } + + return change; +} + +//---------------------------------------------------------------------- +// Determine if an account (id) is a GM account +// and returns its level (or 0 if it isn't a GM account or if not found) +//---------------------------------------------------------------------- +int isGM (int account_id) +{ + int i; + + for (i = 0; i < GM_num; i++) + if (gm_account[i].account_id == account_id) + return gm_account[i].level; + return 0; +} + +//---------------------------------------------- +// Search an character id +// (return character index or -1 (if not found)) +// If exact character name is not found, +// the function checks without case sensitive +// and returns index if only 1 character is found +// and similar to the searched name. +//---------------------------------------------- +int search_character_index (char *character_name) +{ + int i, quantity, index; + + quantity = 0; + index = -1; + for (i = 0; i < char_num; i++) + { + // Without case sensitive check (increase the number of similar character names found) + if (strcasecmp (char_dat[i].name, character_name) == 0) + { + // Strict comparison (if found, we finish the function immediatly with correct value) + if (strcmp (char_dat[i].name, character_name) == 0) + return i; + quantity++; + index = i; + } + } + // Here, the exact character name is not found + // We return the found index of a similar account ONLY if there is 1 similar character + if (quantity == 1) + return index; + + // Exact character name is not found and 0 or more than 1 similar characters have been found ==> we say not found + return -1; +} + +//------------------------------------- +// Return character name with the index +//------------------------------------- +char *search_character_name (int index) +{ + + if (index >= 0 && index < char_num) + return char_dat[index].name; + + return unknown_char_name; +} + +//------------------------------------------------- +// Function to create the character line (for save) +//------------------------------------------------- +int mmo_char_tostr (char *str, struct mmo_charstatus *p) +{ + int i; + char *str_p = str; + + // on multi-map server, sometimes it's posssible that last_point become void. (reason???) We check that to not lost character at restart. + if (p->last_point.map[0] == '\0') + { + memcpy (p->last_point.map, "prontera.gat", 16); + p->last_point.x = 273; + p->last_point.y = 354; + } + + str_p += sprintf (str_p, "%d\t%d,%d\t%s\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" "\t%s,%d,%d\t%s,%d,%d,%d\t", p->char_id, p->account_id, p->char_num, p->name, // + p->pc_class, p->base_level, p->job_level, p->base_exp, p->job_exp, p->zeny, p->hp, p->max_hp, p->sp, p->max_sp, p->str, p->agi, p->vit, p->int_, p->dex, p->luk, p->status_point, p->skill_point, p->option, p->karma, p->manner, // + p->party_id, p->guild_id, 0, p->hair, p->hair_color, p->clothes_color, p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, p->last_point.map, p->last_point.x, p->last_point.y, // + p->save_point.map, p->save_point.x, p->save_point.y, + p->partner_id); + for (i = 0; i < 10; i++) + if (p->memo_point[i].map[0]) + { + str_p += + sprintf (str_p, "%s,%d,%d", p->memo_point[i].map, + p->memo_point[i].x, p->memo_point[i].y); + } + *(str_p++) = '\t'; + + for (i = 0; i < MAX_INVENTORY; i++) + if (p->inventory[i].nameid) + { + str_p += sprintf (str_p, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d ", + p->inventory[i].id, p->inventory[i].nameid, + p->inventory[i].amount, p->inventory[i].equip, + p->inventory[i].identify, + p->inventory[i].refine, + p->inventory[i].attribute, + p->inventory[i].card[0], + p->inventory[i].card[1], + p->inventory[i].card[2], + p->inventory[i].card[3], + p->inventory[i].broken); + } + *(str_p++) = '\t'; + + for (i = 0; i < MAX_CART; i++) + if (p->cart[i].nameid) + { + str_p += sprintf (str_p, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d ", + p->cart[i].id, p->cart[i].nameid, + p->cart[i].amount, p->cart[i].equip, + p->cart[i].identify, p->cart[i].refine, + p->cart[i].attribute, p->cart[i].card[0], + p->cart[i].card[1], p->cart[i].card[2], + p->cart[i].card[3], p->cart[i].broken); + } + *(str_p++) = '\t'; + + for (i = 0; i < MAX_SKILL; i++) + if (p->skill[i].id) + { + str_p += + sprintf (str_p, "%d,%d ", p->skill[i].id, + p->skill[i].lv | (p->skill[i].flags << 16)); + } + *(str_p++) = '\t'; + + for (i = 0; i < p->global_reg_num; i++) + if (p->global_reg[i].str[0]) + str_p += + sprintf (str_p, "%s,%d ", p->global_reg[i].str, + p->global_reg[i].value); + *(str_p++) = '\t'; + + *str_p = '\0'; + return 0; +} + +//------------------------------------------------------------------------- +// Function to set the character from the line (at read of characters file) +//------------------------------------------------------------------------- +int mmo_char_fromstr (char *str, struct mmo_charstatus *p) +{ + int tmp_int[256]; + int set, next, len, i; + + // initilialise character + memset (p, '\0', sizeof (struct mmo_charstatus)); + + // If it's not char structure of version 1008 and after + if ((set = sscanf (str, "%d\t%d,%d\t%[^\t]\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" "\t%[^,],%d,%d\t%[^,],%d,%d,%d%n", &tmp_int[0], &tmp_int[1], &tmp_int[2], p->name, // + &tmp_int[3], &tmp_int[4], &tmp_int[5], &tmp_int[6], &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], &tmp_int[19], &tmp_int[20], &tmp_int[21], &tmp_int[22], &tmp_int[23], // + &tmp_int[24], &tmp_int[25], &tmp_int[26], &tmp_int[27], &tmp_int[28], &tmp_int[29], &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], p->last_point.map, &tmp_int[35], &tmp_int[36], // + p->save_point.map, &tmp_int[37], &tmp_int[38], + &tmp_int[39], &next)) != 43) + { + tmp_int[39] = 0; // partner id + // If not char structure from version 384 to 1007 + if ((set = sscanf (str, "%d\t%d,%d\t%[^\t]\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" "\t%[^,],%d,%d\t%[^,],%d,%d%n", &tmp_int[0], &tmp_int[1], &tmp_int[2], p->name, // + &tmp_int[3], &tmp_int[4], &tmp_int[5], &tmp_int[6], &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], &tmp_int[19], &tmp_int[20], &tmp_int[21], &tmp_int[22], &tmp_int[23], // + &tmp_int[24], &tmp_int[25], &tmp_int[26], &tmp_int[27], &tmp_int[28], &tmp_int[29], &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], p->last_point.map, &tmp_int[35], &tmp_int[36], // + p->save_point.map, &tmp_int[37], &tmp_int[38], + &next)) != 42) + { + // It's char structure of a version before 384 + tmp_int[26] = 0; // pet id + set = sscanf (str, "%d\t%d,%d\t%[^\t]\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" "\t%d,%d,%d\t%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" "\t%[^,],%d,%d\t%[^,],%d,%d%n", &tmp_int[0], &tmp_int[1], &tmp_int[2], p->name, // + &tmp_int[3], &tmp_int[4], &tmp_int[5], &tmp_int[6], &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], &tmp_int[19], &tmp_int[20], &tmp_int[21], &tmp_int[22], &tmp_int[23], // + &tmp_int[24], &tmp_int[25], // + &tmp_int[27], &tmp_int[28], &tmp_int[29], &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], p->last_point.map, &tmp_int[35], &tmp_int[36], // + p->save_point.map, &tmp_int[37], &tmp_int[38], + &next); + set += 2; + //printf("char: old char data ver.1\n"); + // Char structure of version 1007 or older + } + else + { + set++; + //printf("char: old char data ver.2\n"); + } + // Char structure of version 1008+ + } + else + { + //printf("char: new char data ver.3\n"); + } + if (set != 43) + return 0; + + p->char_id = tmp_int[0]; + p->account_id = tmp_int[1]; + p->char_num = tmp_int[2]; + p->pc_class = tmp_int[3]; + p->base_level = tmp_int[4]; + p->job_level = tmp_int[5]; + p->base_exp = tmp_int[6]; + p->job_exp = tmp_int[7]; + p->zeny = tmp_int[8]; + p->hp = tmp_int[9]; + p->max_hp = tmp_int[10]; + p->sp = tmp_int[11]; + p->max_sp = tmp_int[12]; + p->str = tmp_int[13]; + p->agi = tmp_int[14]; + p->vit = tmp_int[15]; + p->int_ = tmp_int[16]; + p->dex = tmp_int[17]; + p->luk = tmp_int[18]; + p->status_point = tmp_int[19]; + p->skill_point = tmp_int[20]; + p->option = tmp_int[21]; + p->karma = tmp_int[22]; + p->manner = tmp_int[23]; + p->party_id = tmp_int[24]; + p->guild_id = tmp_int[25]; +// p->pet_id = tmp_int[26]; + p->hair = tmp_int[27]; + p->hair_color = tmp_int[28]; + p->clothes_color = tmp_int[29]; + p->weapon = tmp_int[30]; + p->shield = tmp_int[31]; + p->head_top = tmp_int[32]; + p->head_mid = tmp_int[33]; + p->head_bottom = tmp_int[34]; + p->last_point.x = tmp_int[35]; + p->last_point.y = tmp_int[36]; + p->save_point.x = tmp_int[37]; + p->save_point.y = tmp_int[38]; + p->partner_id = tmp_int[39]; + + // Some checks + for (i = 0; i < char_num; i++) + { + if (char_dat[i].char_id == p->char_id) + { + printf + ("\033[1;31mmmo_auth_init: ******Error: a character has an identical id to another.\n"); + printf + (" character id #%d -> new character not readed.\n", + p->char_id); + printf (" Character saved in log file.\033[0m\n"); + return -1; + } + else if (strcmp (char_dat[i].name, p->name) == 0) + { + printf + ("\033[1;31mmmo_auth_init: ******Error: character name already exists.\n"); + printf + (" character name '%s' -> new character not readed.\n", + p->name); + printf (" Character saved in log file.\033[0m\n"); + return -2; + } + } + + if (strcasecmp (wisp_server_name, p->name) == 0) + { + printf + ("mmo_auth_init: ******WARNING: character name has wisp server name.\n"); + printf + (" Character name '%s' = wisp server name '%s'.\n", + p->name, wisp_server_name); + printf + (" Character readed. Suggestion: change the wisp server name.\n"); + char_log + ("mmo_auth_init: ******WARNING: character name has wisp server name: Character name '%s' = wisp server name '%s'.\n", + p->name, wisp_server_name); + } + + if (str[next] == '\n' || str[next] == '\r') + return 1; // 新規データ + + next++; + + for (i = 0; str[next] && str[next] != '\t'; i++) + { + if (sscanf + (str + next, "%[^,],%d,%d%n", p->memo_point[i].map, &tmp_int[0], + &tmp_int[1], &len) != 3) + return -3; + p->memo_point[i].x = tmp_int[0]; + p->memo_point[i].y = tmp_int[1]; + next += len; + if (str[next] == ' ') + next++; + } + + next++; + + for (i = 0; str[next] && str[next] != '\t'; i++) + { + if (sscanf (str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n", + &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], + &tmp_int[4], &tmp_int[5], &tmp_int[6], + &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], + &tmp_int[11], &len) == 12) + { + // do nothing, it's ok + } + else if (sscanf (str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n", + &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], + &tmp_int[4], &tmp_int[5], &tmp_int[6], + &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], + &len) == 11) + { + tmp_int[11] = 0; // broken doesn't exist in this version -> 0 + } + else // invalid structure + return -4; + p->inventory[i].id = tmp_int[0]; + p->inventory[i].nameid = tmp_int[1]; + p->inventory[i].amount = tmp_int[2]; + p->inventory[i].equip = tmp_int[3]; + p->inventory[i].identify = tmp_int[4]; + p->inventory[i].refine = tmp_int[5]; + p->inventory[i].attribute = tmp_int[6]; + p->inventory[i].card[0] = tmp_int[7]; + p->inventory[i].card[1] = tmp_int[8]; + p->inventory[i].card[2] = tmp_int[9]; + p->inventory[i].card[3] = tmp_int[10]; + p->inventory[i].broken = tmp_int[11]; + next += len; + if (str[next] == ' ') + next++; + } + + next++; + + for (i = 0; str[next] && str[next] != '\t'; i++) + { + if (sscanf (str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n", + &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], + &tmp_int[4], &tmp_int[5], &tmp_int[6], + &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], + &tmp_int[11], &len) == 12) + { + // do nothing, it's ok + } + else if (sscanf (str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n", + &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], + &tmp_int[4], &tmp_int[5], &tmp_int[6], + &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], + &len) == 11) + { + tmp_int[11] = 0; // broken doesn't exist in this version -> 0 + } + else // invalid structure + return -5; + p->cart[i].id = tmp_int[0]; + p->cart[i].nameid = tmp_int[1]; + p->cart[i].amount = tmp_int[2]; + p->cart[i].equip = tmp_int[3]; + p->cart[i].identify = tmp_int[4]; + p->cart[i].refine = tmp_int[5]; + p->cart[i].attribute = tmp_int[6]; + p->cart[i].card[0] = tmp_int[7]; + p->cart[i].card[1] = tmp_int[8]; + p->cart[i].card[2] = tmp_int[9]; + p->cart[i].card[3] = tmp_int[10]; + p->cart[i].broken = tmp_int[11]; + next += len; + if (str[next] == ' ') + next++; + } + + next++; + + for (i = 0; str[next] && str[next] != '\t'; i++) + { + if (sscanf (str + next, "%d,%d%n", &tmp_int[0], &tmp_int[1], &len) != + 2) + return -6; + p->skill[tmp_int[0]].id = tmp_int[0]; + p->skill[tmp_int[0]].lv = tmp_int[1] & 0xffff; + p->skill[tmp_int[0]].flags = ((tmp_int[1] >> 16) & 0xffff); + next += len; + if (str[next] == ' ') + next++; + } + + next++; + + for (i = 0; + str[next] && str[next] != '\t' && str[next] != '\n' + && str[next] != '\r'; i++) + { // global_reg実装以前のathena.txt互換のため一応'\n'チェック + if (sscanf + (str + next, "%[^,],%d%n", p->global_reg[i].str, + &p->global_reg[i].value, &len) != 2) + { + // because some scripts are not correct, the str can be "". So, we must check that. + // If it's, we must not refuse the character, but just this REG value. + // Character line will have something like: nov_2nd_cos,9 ,9 nov_1_2_cos_c,1 (here, ,9 is not good) + if (str[next] == ',' + && sscanf (str + next, ",%d%n", &p->global_reg[i].value, + &len) == 1) + i--; + else + return -7; + } + next += len; + if (str[next] == ' ') + next++; + } + p->global_reg_num = i; + + return 1; +} + +//--------------------------------- +// Function to read characters file +//--------------------------------- +int mmo_char_init (void) +{ + char line[65536]; + int i; + int ret, line_count; + FILE *fp; + + char_max = 256; + CREATE (char_dat, struct mmo_charstatus, 256); + CREATE (online_chars, int, 256); + for (i = 0; i < char_max; i++) + online_chars[i] = -1; + + char_num = 0; + + fp = fopen_ (char_txt, "r"); + if (fp == NULL) + { + printf ("Characters file not found: %s.\n", char_txt); + char_log ("Characters file not found: %s.\n", char_txt); + char_log ("Id for the next created character: %d.\n", + char_id_count); + return 0; + } + + line_count = 0; + while (fgets (line, sizeof (line) - 1, fp)) + { + int i, j; + line_count++; + + if (line[0] == '/' && line[1] == '/') + continue; + line[sizeof (line) - 1] = '\0'; + + j = 0; + if (sscanf (line, "%d\t%%newid%%%n", &i, &j) == 1 && j > 0) + { + if (char_id_count < i) + char_id_count = i; + continue; + } + + if (char_num >= char_max) + { + char_max += 256; + RECREATE (char_dat, struct mmo_charstatus, char_max); + RECREATE (online_chars, int, char_max); + for (i = char_max - 256; i < char_max; i++) + online_chars[i] = -1; + } + + ret = mmo_char_fromstr (line, &char_dat[char_num]); + if (ret > 0) + { // negative value or zero for errors + if (char_dat[char_num].char_id >= char_id_count) + char_id_count = char_dat[char_num].char_id + 1; + char_num++; + } + else + { + printf + ("mmo_char_init: in characters file, unable to read the line #%d.\n", + line_count); + printf (" -> Character saved in log file.\n"); + switch (ret) + { + case -1: + char_log + ("Duplicate character id in the next character line (character not readed):\n"); + break; + case -2: + char_log + ("Duplicate character name in the next character line (character not readed):\n"); + break; + case -3: + char_log + ("Invalid memo point structure in the next character line (character not readed):\n"); + break; + case -4: + char_log + ("Invalid inventory item structure in the next character line (character not readed):\n"); + break; + case -5: + char_log + ("Invalid cart item structure in the next character line (character not readed):\n"); + break; + case -6: + char_log + ("Invalid skill structure in the next character line (character not readed):\n"); + break; + case -7: + char_log + ("Invalid register structure in the next character line (character not readed):\n"); + break; + default: // 0 + char_log + ("Unabled to get a character in the next line - Basic structure of line (before inventory) is incorrect (character not readed):\n"); + break; + } + char_log ("%s", line); + } + } + fclose_ (fp); + + if (char_num == 0) + { + printf ("mmo_char_init: No character found in %s.\n", char_txt); + char_log ("mmo_char_init: No character found in %s.\n", + char_txt); + } + else if (char_num == 1) + { + printf ("mmo_char_init: 1 character read in %s.\n", char_txt); + char_log ("mmo_char_init: 1 character read in %s.\n", char_txt); + } + else + { + printf ("mmo_char_init: %d characters read in %s.\n", char_num, + char_txt); + char_log ("mmo_char_init: %d characters read in %s.\n", + char_num, char_txt); + } + + char_log ("Id for the next created character: %d.\n", + char_id_count); + + return 0; +} + +//--------------------------------------------------------- +// Function to save characters in files (speed up by [Yor]) +//--------------------------------------------------------- +void mmo_char_sync (void) +{ + char line[65536]; + int i, j, k; + int lock; + FILE *fp; + int id[char_num]; + + // Sorting before save (by [Yor]) + for (i = 0; i < char_num; i++) + { + id[i] = i; + for (j = 0; j < i; j++) + { + if ((char_dat[i].account_id < char_dat[id[j]].account_id) || + // if same account id, we sort by slot. + (char_dat[i].account_id == char_dat[id[j]].account_id && + char_dat[i].char_num < char_dat[id[j]].char_num)) + { + for (k = i; k > j; k--) + id[k] = id[k - 1]; + id[j] = i; // id[i] + break; + } + } + } + + // Data save + fp = lock_fopen (char_txt, &lock); + if (fp == NULL) + { + printf ("WARNING: Server can't not save characters.\n"); + char_log ("WARNING: Server can't not save characters.\n"); + } + else + { + for (i = 0; i < char_num; i++) + { + // create only once the line, and save it in the 2 files (it's speeder than repeat twice the loop and create twice the line) + mmo_char_tostr (line, &char_dat[id[i]]); // use of sorted index + fprintf (fp, "%s\n", line); + } + fprintf (fp, "%d\t%%newid%%\n", char_id_count); + lock_fclose (fp, char_txt, &lock); + } + + // Data save (backup) + if (backup_txt_flag) + { // The backup_txt file was created because char deletion bug existed. Now it's finish and that take a lot of time to create a second file when there are a lot of characters. => option By [Yor] + fp = lock_fopen (backup_txt, &lock); + if (fp == NULL) + { + printf + ("WARNING: Server can't not create backup of characters file.\n"); + char_log + ("WARNING: Server can't not create backup of characters file.\n"); + return; + } + for (i = 0; i < char_num; i++) + { + // create only once the line, and save it in the 2 files (it's speeder than repeat twice the loop and create twice the line) + mmo_char_tostr (line, &char_dat[id[i]]); // use of sorted index + fprintf (fp, "%s\n", line); + } + fprintf (fp, "%d\t%%newid%%\n", char_id_count); + lock_fclose (fp, backup_txt, &lock); + } + + return; +} + +//---------------------------------------------------- +// Function to save (in a periodic way) datas in files +//---------------------------------------------------- +void mmo_char_sync_timer (timer_id tid, tick_t tick, custom_id_t id, custom_data_t data) +{ + if (pid != 0) + { + int status; + pid_t temp = waitpid (pid, &status, WNOHANG); + + // Need to check status too? + if (temp == 0) + { + return; + } + } + + // This can take a lot of time. Fork a child to handle the work and return at once + // If we're unable to fork just continue running the function normally + if ((pid = fork ()) > 0) + return; + + mmo_char_sync (); + inter_save (); + + // If we're a child we should suicide now. + if (pid == 0) + _exit (0); +} + +//---------------------------------------------------- +// Remove trailing whitespace from a name +//---------------------------------------------------- +static void remove_trailing_blanks (char *name) +{ + char *tail = name + strlen (name) - 1; + + while (tail > name && *tail == ' ') + *tail-- = 0; +} + +//---------------------------------------------------- +// Remove prefix whitespace from a name +//---------------------------------------------------- +static void remove_prefix_blanks (char *name) +{ + char *dst = name; + char *src = name; + + while (*src == ' ') // find first nonblank + ++src; + while ((*dst++ = *src++)); // `strmove' +} + +//----------------------------------- +// Function to create a new character +//----------------------------------- +int make_new_char (int fd, unsigned char *dat) +{ + int i, j; + struct char_session_data *sd = (struct char_session_data *)session[fd]->session_data; + + // remove control characters from the name + dat[23] = '\0'; + if (remove_control_chars (dat)) + { + char_log + ("Make new char error (control char received in the name): (connection #%d, account: %d).\n", + fd, sd->account_id); + return -1; + } + + // Eliminate whitespace + remove_trailing_blanks ((char *) dat); + remove_prefix_blanks ((char *) dat); + + // check lenght of character name + if (strlen (dat) < 4) + { + char_log + ("Make new char error (character name too small): (connection #%d, account: %d, name: '%s').\n", + fd, sd->account_id, dat); + return -1; + } + + // Check Authorised letters/symbols in the name of the character + if (char_name_option == 1) + { // only letters/symbols in char_name_letters are authorised + for (i = 0; dat[i]; i++) + if (strchr (char_name_letters, dat[i]) == NULL) + { + char_log + ("Make new char error (invalid letter in the name): (connection #%d, account: %d), name: %s, invalid letter: %c.\n", + fd, sd->account_id, dat, dat[i]); + return -1; + } + } + else if (char_name_option == 2) + { // letters/symbols in char_name_letters are forbidden + for (i = 0; dat[i]; i++) + if (strchr (char_name_letters, dat[i]) != NULL) + { + char_log + ("Make new char error (invalid letter in the name): (connection #%d, account: %d), name: %s, invalid letter: %c.\n", + fd, sd->account_id, dat, dat[i]); + return -1; + } + } // else, all letters/symbols are authorised (except control char removed before) + + if (dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29] != 5 * 6 || // stats + dat[30] >= 9 || // slots (dat[30] can not be negativ) + dat[33] < 0 || dat[33] >= 20 || // hair style + dat[31] >= 12) + { // hair color (dat[31] can not be negativ) + char_log + ("Make new char error (invalid values): (connection #%d, account: %d) slot %d, name: %s, stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d\n", + fd, sd->account_id, dat[30], dat, dat[24], dat[25], + dat[26], dat[27], dat[28], dat[29], + dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], + dat[33], dat[31]); + return -1; + } + + // check individual stat value + for (i = 24; i <= 29; i++) + { + if (dat[i] < 1 || dat[i] > 9) + { + char_log + ("Make new char error (invalid stat value: not between 1 to 9): (connection #%d, account: %d) slot %d, name: %s, stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d\n", + fd, sd->account_id, dat[30], dat, dat[24], dat[25], + dat[26], dat[27], dat[28], dat[29], + dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], + dat[33], dat[31]); + return -1; + } + } + + for (i = 0; i < char_num; i++) + { + if ((name_ignoring_case != 0 && strcmp (char_dat[i].name, dat) == 0) + || (name_ignoring_case == 0 + && strcasecmp (char_dat[i].name, dat) == 0)) + { + char_log + ("Make new char error (name already exists): (connection #%d, account: %d) slot %d, name: %s (actual name of other char: %s), stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d.\n", + fd, sd->account_id, dat[30], dat, char_dat[i].name, + dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], + dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], + dat[33], dat[31]); + return -1; + } + if (char_dat[i].account_id == sd->account_id + && char_dat[i].char_num == dat[30]) + { + char_log + ("Make new char error (slot already used): (connection #%d, account: %d) slot %d, name: %s (actual name of other char: %s), stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d.\n", + fd, sd->account_id, dat[30], dat, char_dat[i].name, + dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], + dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], + dat[33], dat[31]); + return -1; + } + } + + if (strcmp (wisp_server_name, dat) == 0) + { + char_log + ("Make new char error (name used is wisp name for server): (connection #%d, account: %d) slot %d, name: %s (actual name of other char: %d), stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d.\n", + fd, sd->account_id, dat[30], dat, char_dat[i].name, + dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], + dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], + dat[33], dat[31]); + return -1; + } + + if (char_num >= char_max) + { + char_max += 256; + RECREATE (char_dat, struct mmo_charstatus, char_max); + RECREATE (online_chars, int, char_max); + for (j = char_max - 256; j < char_max; j++) + online_chars[j] = -1; + } + + char ip[16]; + unsigned char *sin_addr = + (unsigned char *) &session[fd]->client_addr.sin_addr; + sprintf (ip, "%d.%d.%d.%d", sin_addr[0], sin_addr[1], sin_addr[2], + sin_addr[3]); + + char_log + ("Creation of New Character: (connection #%d, account: %d) slot %d, character Name: %s, stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d. [%s]\n", + fd, sd->account_id, dat[30], dat, dat[24], dat[25], dat[26], + dat[27], dat[28], dat[29], + dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], dat[33], + dat[31], ip); + + memset (&char_dat[i], 0, sizeof (struct mmo_charstatus)); + + char_dat[i].char_id = char_id_count++; + char_dat[i].account_id = sd->account_id; + char_dat[i].char_num = dat[30]; + strcpy (char_dat[i].name, dat); + char_dat[i].pc_class = 0; + char_dat[i].base_level = 1; + char_dat[i].job_level = 1; + char_dat[i].base_exp = 0; + char_dat[i].job_exp = 0; + char_dat[i].zeny = start_zeny; + char_dat[i].str = dat[24]; + char_dat[i].agi = dat[25]; + char_dat[i].vit = dat[26]; + char_dat[i].int_ = dat[27]; + char_dat[i].dex = dat[28]; + char_dat[i].luk = dat[29]; + char_dat[i].max_hp = 40 * (100 + char_dat[i].vit) / 100; + char_dat[i].max_sp = 11 * (100 + char_dat[i].int_) / 100; + char_dat[i].hp = char_dat[i].max_hp; + char_dat[i].sp = char_dat[i].max_sp; + char_dat[i].status_point = 0; + char_dat[i].skill_point = 0; + char_dat[i].option = 0; + char_dat[i].karma = 0; + char_dat[i].manner = 0; + char_dat[i].party_id = 0; + char_dat[i].guild_id = 0; + char_dat[i].hair = dat[33]; + char_dat[i].hair_color = dat[31]; + char_dat[i].clothes_color = 0; + char_dat[i].inventory[0].nameid = start_weapon; // Knife + char_dat[i].inventory[0].amount = 1; + char_dat[i].inventory[0].equip = 0x02; + char_dat[i].inventory[0].identify = 1; + char_dat[i].inventory[0].broken = 0; + char_dat[i].inventory[1].nameid = start_armor; // Cotton Shirt + char_dat[i].inventory[1].amount = 1; + char_dat[i].inventory[1].equip = 0x10; + char_dat[i].inventory[1].identify = 1; + char_dat[i].inventory[1].broken = 0; + char_dat[i].weapon = 1; + char_dat[i].shield = 0; + char_dat[i].head_top = 0; + char_dat[i].head_mid = 0; + char_dat[i].head_bottom = 0; + memcpy (&char_dat[i].last_point, &start_point, sizeof (start_point)); + memcpy (&char_dat[i].save_point, &start_point, sizeof (start_point)); + char_num++; + + return i; +} + +//---------------------------------------------------- +// This function return the name of the job (by [Yor]) +//---------------------------------------------------- +char *job_name (int pc_class) +{ + switch (pc_class) + { + case 0: + return "Novice"; + case 1: + return "Swordsman"; + case 2: + return "Mage"; + case 3: + return "Archer"; + case 4: + return "Acolyte"; + case 5: + return "Merchant"; + case 6: + return "Thief"; + case 7: + return "Knight"; + case 8: + return "Priest"; + case 9: + return "Wizard"; + case 10: + return "Blacksmith"; + case 11: + return "Hunter"; + case 12: + return "Assassin"; + case 13: + return "Knight 2"; + case 14: + return "Crusader"; + case 15: + return "Monk"; + case 16: + return "Sage"; + case 17: + return "Rogue"; + case 18: + return "Alchemist"; + case 19: + return "Bard"; + case 20: + return "Dancer"; + case 21: + return "Crusader 2"; + case 22: + return "Wedding"; + case 23: + return "Super Novice"; + case 4001: + return "Novice High"; + case 4002: + return "Swordsman High"; + case 4003: + return "Mage High"; + case 4004: + return "Archer High"; + case 4005: + return "Acolyte High"; + case 4006: + return "Merchant High"; + case 4007: + return "Thief High"; + case 4008: + return "Lord Knight"; + case 4009: + return "High Priest"; + case 4010: + return "High Wizard"; + case 4011: + return "Whitesmith"; + case 4012: + return "Sniper"; + case 4013: + return "Assassin Cross"; + case 4014: + return "Peko Knight"; + case 4015: + return "Paladin"; + case 4016: + return "Champion"; + case 4017: + return "Professor"; + case 4018: + return "Stalker"; + case 4019: + return "Creator"; + case 4020: + return "Clown"; + case 4021: + return "Gypsy"; + case 4022: + return "Peko Paladin"; + case 4023: + return "Baby Novice"; + case 4024: + return "Baby Swordsman"; + case 4025: + return "Baby Mage"; + case 4026: + return "Baby Archer"; + case 4027: + return "Baby Acolyte"; + case 4028: + return "Baby Merchant"; + case 4029: + return "Baby Thief"; + case 4030: + return "Baby Knight"; + case 4031: + return "Baby Priest"; + case 4032: + return "Baby Wizard"; + case 4033: + return "Baby Blacksmith"; + case 4034: + return "Baby Hunter"; + case 4035: + return "Baby Assassin"; + case 4036: + return "Baby Peco Knight"; + case 4037: + return "Baby Crusader"; + case 4038: + return "Baby Monk"; + case 4039: + return "Baby Sage"; + case 4040: + return "Baby Rogue"; + case 4041: + return "Baby Alchemist"; + case 4042: + return "Baby Bard"; + case 4043: + return "Baby Dancer"; + case 4044: + return "Baby Peco Crusader"; + case 4045: + return "Super Baby"; + } + return "Unknown Job"; +} + +//------------------------------------------------------------- +// Function to create the online files (txt and html). by [Yor] +//------------------------------------------------------------- +void create_online_files (void) +{ + int i, j, k, l; // for loops + int players; // count the number of players + FILE *fp; // for the txt file + FILE *fp2; // for the html file + char temp[256]; // to prepare what we must display + time_t time_server; // for number of seconds + struct tm *datetime; // variable for time in structure ->tm_mday, ->tm_sec, ... + int id[char_num]; + + if (online_display_option == 0) // we display nothing, so return + return; + + //char_log("Creation of online players files.\n"); + + // Get number of online players, id of each online players + players = 0; + // sort online characters. + for (i = 0; i < char_num; i++) + { + if (online_chars[i] != -1) + { + id[players] = i; + // use sorting option + switch (online_sorting_option) + { + case 1: // by name (without case sensitive) + { + char *p_name = char_dat[i].name; //speed up sorting when there are a lot of players. But very rarely players have same name. + for (j = 0; j < players; j++) + if (strcasecmp (p_name, char_dat[id[j]].name) < 0 || + // if same name, we sort with case sensitive. + (strcasecmp (p_name, char_dat[id[j]].name) == 0 && + strcmp (p_name, char_dat[id[j]].name) < 0)) + { + for (k = players; k > j; k--) + id[k] = id[k - 1]; + id[j] = i; // id[players] + break; + } + } + break; + case 2: // by zeny + for (j = 0; j < players; j++) + if (char_dat[i].zeny < char_dat[id[j]].zeny || + // if same number of zenys, we sort by name. + (char_dat[i].zeny == char_dat[id[j]].zeny && + strcasecmp (char_dat[i].name, + char_dat[id[j]].name) < 0)) + { + for (k = players; k > j; k--) + id[k] = id[k - 1]; + id[j] = i; // id[players] + break; + } + break; + case 3: // by base level + for (j = 0; j < players; j++) + if (char_dat[i].base_level < + char_dat[id[j]].base_level || + // if same base level, we sort by base exp. + (char_dat[i].base_level == + char_dat[id[j]].base_level + && char_dat[i].base_exp < + char_dat[id[j]].base_exp)) + { + for (k = players; k > j; k--) + id[k] = id[k - 1]; + id[j] = i; // id[players] + break; + } + break; + case 4: // by job (and job level) + for (j = 0; j < players; j++) + if (char_dat[i].pc_class < char_dat[id[j]].pc_class || + // if same job, we sort by job level. + (char_dat[i].pc_class == char_dat[id[j]].pc_class && + char_dat[i].job_level < + char_dat[id[j]].job_level) || + // if same job and job level, we sort by job exp. + (char_dat[i].pc_class == char_dat[id[j]].pc_class && + char_dat[i].job_level == + char_dat[id[j]].job_level + && char_dat[i].job_exp < + char_dat[id[j]].job_exp)) + { + for (k = players; k > j; k--) + id[k] = id[k - 1]; + id[j] = i; // id[players] + break; + } + break; + case 5: // by location map name + { + int cpm_result; // A lot of player maps are identical. So, test if done often twice. + for (j = 0; j < players; j++) + if ((cpm_result = strcmp (char_dat[i].last_point.map, char_dat[id[j]].last_point.map)) < 0 || // no map are identical and with upper cases (not use strcasecmp) + // if same map name, we sort by name. + (cpm_result == 0 && + strcasecmp (char_dat[i].name, + char_dat[id[j]].name) < 0)) + { + for (k = players; k > j; k--) + id[k] = id[k - 1]; + id[j] = i; // id[players] + break; + } + } + break; + default: // 0 or invalid value: no sorting + break; + } + players++; + } + } + + // write files + fp = fopen_ (online_txt_filename, "w"); + if (fp != NULL) + { + fp2 = fopen_ (online_html_filename, "w"); + if (fp2 != NULL) + { + // get time + time (&time_server); // get time in seconds since 1/1/1970 + datetime = localtime (&time_server); // convert seconds in structure + strftime (temp, sizeof (temp), "%d %b %Y %X", datetime); // like sprintf, but only for date/time (05 dec 2003 15:12:52) + // write heading + fprintf (fp2, "\n"); + fprintf (fp2, " \n", online_refresh_html); // update on client explorer every x seconds + fprintf (fp2, " \n"); + fprintf (fp2, " Online Players on %s\n", + server_name); + fprintf (fp2, " \n"); + fprintf (fp2, " \n"); + fprintf (fp2, "

Online Players on %s (%s):

\n", + server_name, temp); + fprintf (fp, "Online Players on %s (%s):\n", server_name, temp); + fprintf (fp, "\n"); + + // If we display at least 1 player + if (players > 0) + { + j = 0; // count the number of characters for the txt version and to set the separate line + fprintf (fp2, " \n"); + fprintf (fp2, " \n"); + if ((online_display_option & 1) + || (online_display_option & 64)) + { + fprintf (fp2, " \n"); + if (online_display_option & 64) + { + fprintf (fp, "Name "); // 30 + j += 30; + } + else + { + fprintf (fp, "Name "); // 25 + j += 25; + } + } + if ((online_display_option & 6) == 6) + { + fprintf (fp2, " \n"); + fprintf (fp, "Job Levels "); // 27 + j += 27; + } + else if (online_display_option & 2) + { + fprintf (fp2, " \n"); + fprintf (fp, "Job "); // 19 + j += 19; + } + else if (online_display_option & 4) + { + fprintf (fp2, " \n"); + fprintf (fp, " Levels "); // 8 + j += 8; + } + if (online_display_option & 24) + { // 8 or 16 + fprintf (fp2, " \n"); + if (online_display_option & 16) + { + fprintf (fp, "Location ( x , y ) "); // 23 + j += 23; + } + else + { + fprintf (fp, "Location "); // 13 + j += 13; + } + } + if (online_display_option & 32) + { + fprintf (fp2, + " \n"); + fprintf (fp, " Zenys "); // 16 + j += 16; + } + fprintf (fp2, " \n"); + fprintf (fp, "\n"); + for (k = 0; k < j; k++) + fprintf (fp, "-"); + fprintf (fp, "\n"); + + // display each player. + for (i = 0; i < players; i++) + { + // get id of the character (more speed) + j = id[i]; + fprintf (fp2, " \n"); + // displaying the character name + if ((online_display_option & 1) + || (online_display_option & 64)) + { // without/with 'GM' display + strcpy (temp, char_dat[j].name); + l = isGM (char_dat[j].account_id); + if (online_display_option & 64) + { + if (l >= online_gm_display_min_level) + fprintf (fp, "%-24s (GM) ", temp); + else + fprintf (fp, "%-24s ", temp); + } + else + fprintf (fp, "%-24s ", temp); + // name of the character in the html (no < >, because that create problem in html code) + fprintf (fp2, " \n"); + } + // displaying of the job + if (online_display_option & 6) + { + char *jobname = job_name (char_dat[j].pc_class); + if ((online_display_option & 6) == 6) + { + fprintf (fp2, " \n", + jobname, char_dat[j].base_level, + char_dat[j].job_level); + fprintf (fp, "%-18s %3d/%3d ", jobname, + char_dat[j].base_level, + char_dat[j].job_level); + } + else if (online_display_option & 2) + { + fprintf (fp2, " \n", jobname); + fprintf (fp, "%-18s ", jobname); + } + else if (online_display_option & 4) + { + fprintf (fp2, " \n", + char_dat[j].base_level, + char_dat[j].job_level); + fprintf (fp, "%3d/%3d ", char_dat[j].base_level, + char_dat[j].job_level); + } + } + // displaying of the map + if (online_display_option & 24) + { // 8 or 16 + // prepare map name + memset (temp, 0, sizeof (temp)); + strncpy (temp, char_dat[j].last_point.map, 16); + if (strchr (temp, '.') != NULL) + temp[strchr (temp, '.') - temp] = '\0'; // suppress the '.gat' + // write map name + if (online_display_option & 16) + { // map-name AND coordonates + fprintf (fp2, " \n", + temp, char_dat[j].last_point.x, + char_dat[j].last_point.y); + fprintf (fp, "%-12s (%3d,%3d) ", temp, + char_dat[j].last_point.x, + char_dat[j].last_point.y); + } + else + { + fprintf (fp2, " \n", temp); + fprintf (fp, "%-12s ", temp); + } + } + // displaying number of zenys + if (online_display_option & 32) + { + // write number of zenys + if (char_dat[j].zeny == 0) + { // if no zeny + fprintf (fp2, + " \n"); + fprintf (fp, " no zeny "); + } + else + { + fprintf (fp2, + " \n", + char_dat[j].zeny); + fprintf (fp, "%13d z ", char_dat[j].zeny); + } + } + fprintf (fp, "\n"); + fprintf (fp2, " \n"); + } + fprintf (fp2, "
NameJob (levels)JobLevelsLocationzenys
"); + if ((online_display_option & 64) + && l >= online_gm_display_min_level) + fprintf (fp2, ""); + for (k = 0; temp[k]; k++) + { + switch (temp[k]) + { + case '<': // < + fprintf (fp2, "<"); + break; + case '>': // > + fprintf (fp2, ">"); + break; + default: + fprintf (fp2, "%c", temp[k]); + break; + }; + } + if ((online_display_option & 64) + && l >= online_gm_display_min_level) + fprintf (fp2, " (GM)"); + fprintf (fp2, "%s %d/%d%s%d/%d%s (%d, %d)%sno zeny%d z
\n"); + fprintf (fp, "\n"); + } + + // Displaying number of online players + if (players == 0) + { + fprintf (fp2, "

No user is online.

\n"); + fprintf (fp, "No user is online.\n"); + // no display if only 1 player + } + else if (players == 1) + { + } + else + { + fprintf (fp2, "

%d users are online.

\n", players); + fprintf (fp, "%d users are online.\n", players); + } + fprintf (fp2, " \n"); + fprintf (fp2, "\n"); + fclose_ (fp2); + } + fclose_ (fp); + } + + return; +} + +//--------------------------------------------------------------------- +// This function return the number of online players in all map-servers +//--------------------------------------------------------------------- +int count_users (void) +{ + int i, users; + + users = 0; + for (i = 0; i < MAX_MAP_SERVERS; i++) + if (server_fd[i] >= 0) + users += server[i].users; + + return users; +} + +//---------------------------------------- +// [Fate] Find inventory item based on equipment mask, return view. ID must match view ID (!). +//---------------------------------------- +static int find_equip_view (struct mmo_charstatus *p, unsigned int equipmask) +{ + int i; + for (i = 0; i < MAX_INVENTORY; i++) + if (p->inventory[i].nameid && p->inventory[i].amount + && p->inventory[i].equip & equipmask) + return p->inventory[i].nameid; + return 0; +} + +//---------------------------------------- +// Function to send characters to a player +//---------------------------------------- +int mmo_char_send006b (int fd, struct char_session_data *sd) +{ + int i, j, found_num; + struct mmo_charstatus *p; + const int offset = 24; + + found_num = 0; + for (i = 0; i < char_num; i++) + { + if (char_dat[i].account_id == sd->account_id) + { + sd->found_char[found_num] = i; + found_num++; + if (found_num == 9) + break; + } + } + for (i = found_num; i < 9; i++) + sd->found_char[i] = -1; + + memset (WFIFOP (fd, 0), 0, offset + found_num * 106); + WFIFOW (fd, 0) = 0x6b; + WFIFOW (fd, 2) = offset + found_num * 106; + + for (i = 0; i < found_num; i++) + { + p = &char_dat[sd->found_char[i]]; + j = offset + (i * 106); // increase speed of code + + WFIFOL (fd, j) = p->char_id; + WFIFOL (fd, j + 4) = p->base_exp; + WFIFOL (fd, j + 8) = p->zeny; + WFIFOL (fd, j + 12) = p->job_exp; + WFIFOL (fd, j + 16) = 0; //p->job_level; // [Fate] We no longer reveal this to the player, as its meaning is weird. + + WFIFOW (fd, j + 20) = find_equip_view (p, 0x0040); // 9: shoes + WFIFOW (fd, j + 22) = find_equip_view (p, 0x0004); // 10: gloves + WFIFOW (fd, j + 24) = find_equip_view (p, 0x0008); // 11: cape + WFIFOW (fd, j + 26) = find_equip_view (p, 0x0010); // 12: misc1 + WFIFOL (fd, j + 28) = p->option; + + WFIFOL (fd, j + 32) = p->karma; + WFIFOL (fd, j + 36) = p->manner; + + WFIFOW (fd, j + 40) = p->status_point; + WFIFOW (fd, j + 42) = (p->hp > 0x7fff) ? 0x7fff : p->hp; + WFIFOW (fd, j + 44) = (p->max_hp > 0x7fff) ? 0x7fff : p->max_hp; + WFIFOW (fd, j + 46) = (p->sp > 0x7fff) ? 0x7fff : p->sp; + WFIFOW (fd, j + 48) = (p->max_sp > 0x7fff) ? 0x7fff : p->max_sp; + WFIFOW (fd, j + 50) = DEFAULT_WALK_SPEED; // p->speed; + WFIFOW (fd, j + 52) = p->pc_class; + WFIFOW (fd, j + 54) = p->hair; +// WFIFOW(fd,j+56) = p->weapon; // dont send weapon since TMW does not support it + WFIFOW (fd, j + 56) = 0; + WFIFOW (fd, j + 58) = p->base_level; + WFIFOW (fd, j + 60) = p->skill_point; + WFIFOW (fd, j + 62) = p->head_bottom; + WFIFOW (fd, j + 64) = p->shield; + WFIFOW (fd, j + 66) = p->head_top; + WFIFOW (fd, j + 68) = p->head_mid; + WFIFOW (fd, j + 70) = p->hair_color; + WFIFOW (fd, j + 72) = find_equip_view (p, 0x0080); // 13: misc2 +// WFIFOW(fd,j+72) = p->clothes_color; + + memcpy (WFIFOP (fd, j + 74), p->name, 24); + + WFIFOB (fd, j + 98) = (p->str > 255) ? 255 : p->str; + WFIFOB (fd, j + 99) = (p->agi > 255) ? 255 : p->agi; + WFIFOB (fd, j + 100) = (p->vit > 255) ? 255 : p->vit; + WFIFOB (fd, j + 101) = (p->int_ > 255) ? 255 : p->int_; + WFIFOB (fd, j + 102) = (p->dex > 255) ? 255 : p->dex; + WFIFOB (fd, j + 103) = (p->luk > 255) ? 255 : p->luk; + WFIFOB (fd, j + 104) = p->char_num; + } + + WFIFOSET (fd, WFIFOW (fd, 2)); + + return 0; +} + +int set_account_reg2 (int acc, int num, struct global_reg *reg) +{ + int i, c; + + c = 0; + for (i = 0; i < char_num; i++) + { + if (char_dat[i].account_id == acc) + { + memcpy (char_dat[i].account_reg2, reg, + sizeof (char_dat[i].account_reg2)); + char_dat[i].account_reg2_num = num; + c++; + } + } + return c; +} + +// Divorce a character from it's partner and let the map server know +int char_divorce (struct mmo_charstatus *cs) +{ + int i; + char buf[10]; + + if (cs == NULL) + return 0; + + if (cs->partner_id <= 0) + { + WBUFW (buf, 0) = 0x2b12; + WBUFL (buf, 2) = cs->char_id; + WBUFL (buf, 6) = 0; // partner id 0 means failure + mapif_sendall (buf, 10); + return 0; + } + + WBUFW (buf, 0) = 0x2b12; + WBUFL (buf, 2) = cs->char_id; + + for (i = 0; i < char_num; i++) + { + if (char_dat[i].char_id == cs->partner_id + && char_dat[i].partner_id == cs->char_id) + { + WBUFL (buf, 6) = cs->partner_id; + mapif_sendall (buf, 10); + cs->partner_id = 0; + char_dat[i].partner_id = 0; + return 0; + } + // The other char doesn't have us as their partner, so just clear our partner + // Don't worry about this, as the map server should verify itself that the other doesn't have us as a partner, and so won't mess with their marriage + else if (char_dat[i].char_id == cs->partner_id) + { + WBUFL (buf, 6) = cs->partner_id; + mapif_sendall (buf, 10); + cs->partner_id = 0; + return 0; + } + } + + // Our partner wasn't found, so just clear our marriage + WBUFL (buf, 6) = cs->partner_id; + cs->partner_id = 0; + mapif_sendall (buf, 10); + + return 0; +} + +//------------------------------------------------------------ +// E-mail check: return 0 (not correct) or 1 (valid). by [Yor] +//------------------------------------------------------------ +int e_mail_check (unsigned char *email) +{ + char ch; + unsigned char *last_arobas; + + // athena limits + if (strlen (email) < 3 || strlen (email) > 39) + return 0; + + // part of RFC limits (official reference of e-mail description) + if (strchr (email, '@') == NULL || email[strlen (email) - 1] == '@') + return 0; + + if (email[strlen (email) - 1] == '.') + return 0; + + last_arobas = strrchr (email, '@'); + + if (strstr (last_arobas, "@.") != NULL || + strstr (last_arobas, "..") != NULL) + return 0; + + for (ch = 1; ch < 32; ch++) + { + if (strchr (last_arobas, ch) != NULL) + { + return 0; + break; + } + } + + if (strchr (last_arobas, ' ') != NULL || + strchr (last_arobas, ';') != NULL) + return 0; + + // all correct + return 1; +} + +//---------------------------------------------------------------------- +// Force disconnection of an online player (with account value) by [Yor] +//---------------------------------------------------------------------- +int disconnect_player (int accound_id) +{ + int i; + struct char_session_data *sd; + + // disconnect player if online on char-server + for (i = 0; i < fd_max; i++) + { + if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) + { + if (sd->account_id == accound_id) + { + session[i]->eof = 1; + return 1; + } + } + } + + return 0; +} + +// キャラ削除に伴うデータ削除 +static int char_delete (struct mmo_charstatus *cs) +{ + + // ギルド脱退 + if (cs->guild_id) + inter_guild_leave (cs->guild_id, cs->account_id, cs->char_id); + // パーティー脱退 + if (cs->party_id) + inter_party_leave (cs->party_id, cs->account_id); + // 離婚 + if (cs->partner_id) + char_divorce (cs); + + // Force the character (and all on the same account) to leave all map servers + { + unsigned char buf[6]; + WBUFW (buf, 0) = 0x2afe; + WBUFL (buf, 2) = cs->account_id; + mapif_sendall (buf, 6); + } + + return 0; +} + +void parse_tologin (int fd) +{ + int i; + struct char_session_data *sd; + + // only login-server can have an access to here. + // so, if it isn't the login-server, we disconnect the session (fd != login_fd). + if (fd != login_fd || session[fd]->eof) + { + if (fd == login_fd) + { + printf + ("Char-server can't connect to login-server (connection #%d).\n", + fd); + login_fd = -1; + } + close (fd); + delete_session (fd); + return; + } + + sd = (struct char_session_data*)session[fd]->session_data; + + while (RFIFOREST (fd) >= 2) + { +// printf("parse_tologin: connection #%d, packet: 0x%x (with being read: %d bytes).\n", fd, RFIFOW(fd,0), RFIFOREST(fd)); + + switch (RFIFOW (fd, 0)) + { + case 0x2711: + if (RFIFOREST (fd) < 3) + return; + if (RFIFOB (fd, 2)) + { +// printf("connect login server error : %d\n", RFIFOB(fd,2)); + printf ("Can not connect to login-server.\n"); + printf + ("The server communication passwords (default s1/p1) is probably invalid.\n"); + printf + ("Also, please make sure your accounts file (default: accounts.txt) has those values present.\n"); + printf + ("If you changed the communication passwords, change them back at map_athena.conf and char_athena.conf\n"); + exit (1); + } + else + { + printf ("Connected to login-server (connection #%d).\n", + fd); + // if no map-server already connected, display a message... + for (i = 0; i < MAX_MAP_SERVERS; i++) + if (server_fd[i] >= 0 && server[i].map[0][0]) // if map-server online and at least 1 map + break; + if (i == MAX_MAP_SERVERS) + printf ("Awaiting maps from map-server.\n"); + } + RFIFOSKIP (fd, 3); + break; + + case 0x2713: + if (RFIFOREST (fd) < 51) + return; +// printf("parse_tologin 2713 : %d\n", RFIFOB(fd,6)); + for (i = 0; i < fd_max; i++) + { + if (session[i] && (sd = (struct char_session_data*)session[i]->session_data) + && sd->account_id == RFIFOL (fd, 2)) + { + if (RFIFOB (fd, 6) != 0) + { + WFIFOW (i, 0) = 0x6c; + WFIFOB (i, 2) = 0x42; + WFIFOSET (i, 3); + } + else if (max_connect_user == 0 + || count_users () < max_connect_user) + { +// if (max_connect_user == 0) +// printf("max_connect_user (unlimited) -> accepted.\n"); +// else +// printf("count_users(): %d < max_connect_user (%d) -> accepted.\n", count_users(), max_connect_user); + memcpy (sd->email, RFIFOP (fd, 7), 40); + if (e_mail_check (sd->email) == 0) + strncpy (sd->email, "a@a.com", 40); // default e-mail + sd->connect_until_time = (time_t) RFIFOL (fd, 47); + // send characters to player + mmo_char_send006b (i, sd); + } + else + { + // refuse connection: too much online players +// printf("count_users(): %d < max_connect_use (%d) -> fail...\n", count_users(), max_connect_user); + WFIFOW (i, 0) = 0x6c; + WFIFOW (i, 2) = 0; + WFIFOSET (i, 3); + } + break; + } + } + RFIFOSKIP (fd, 51); + break; + + // Receiving of an e-mail/time limit from the login-server (answer of a request because a player comes back from map-server to char-server) by [Yor] + case 0x2717: + if (RFIFOREST (fd) < 50) + return; + for (i = 0; i < fd_max; i++) + { + if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) + { + if (sd->account_id == RFIFOL (fd, 2)) + { + memcpy (sd->email, RFIFOP (fd, 6), 40); + if (e_mail_check (sd->email) == 0) + strncpy (sd->email, "a@a.com", 40); // default e-mail + sd->connect_until_time = (time_t) RFIFOL (fd, 46); + break; + } + } + } + RFIFOSKIP (fd, 50); + break; + + case 0x2721: // gm reply + if (RFIFOREST (fd) < 10) + return; + { + unsigned char buf[10]; + WBUFW (buf, 0) = 0x2b0b; + WBUFL (buf, 2) = RFIFOL (fd, 2); // account + WBUFL (buf, 6) = RFIFOL (fd, 6); // GM level + mapif_sendall (buf, 10); +// printf("parse_tologin: To become GM answer: char -> map.\n"); + } + RFIFOSKIP (fd, 10); + break; + + case 0x2723: // changesex reply (modified by [Yor]) + if (RFIFOREST (fd) < 7) + return; + { + int acc, sex, i, j; + unsigned char buf[7]; + acc = RFIFOL (fd, 2); + sex = RFIFOB (fd, 6); + RFIFOSKIP (fd, 7); + if (acc > 0) + { + for (i = 0; i < char_num; i++) + { + if (char_dat[i].account_id == acc) + { + int jobclass = char_dat[i].pc_class; + char_dat[i].sex = sex; +// auth_fifo[i].sex = sex; + if (jobclass == 19 || jobclass == 20 || + jobclass == 4020 || jobclass == 4021 || + jobclass == 4042 || jobclass == 4043) + { + // job modification + if (jobclass == 19 || jobclass == 20) + { + char_dat[i].pc_class = (sex) ? 19 : 20; + } + else if (jobclass == 4020 + || jobclass == 4021) + { + char_dat[i].pc_class = + (sex) ? 4020 : 4021; + } + else if (jobclass == 4042 + || jobclass == 4043) + { + char_dat[i].pc_class = + (sex) ? 4042 : 4043; + } + } + // to avoid any problem with equipment and invalid sex, equipment is unequiped. + for (j = 0; j < MAX_INVENTORY; j++) + { + if (char_dat[i].inventory[j].nameid + && char_dat[i].inventory[j].equip) + char_dat[i].inventory[j].equip = 0; + } + char_dat[i].weapon = 0; + char_dat[i].shield = 0; + char_dat[i].head_top = 0; + char_dat[i].head_mid = 0; + char_dat[i].head_bottom = 0; + } + } + // disconnect player if online on char-server + disconnect_player (acc); + } + WBUFW (buf, 0) = 0x2b0d; + WBUFL (buf, 2) = acc; + WBUFB (buf, 6) = sex; + mapif_sendall (buf, 7); + } + break; + + case 0x2726: // Request to send a broadcast message (no answer) + if (RFIFOREST (fd) < 8 + || RFIFOREST (fd) < (8 + RFIFOL (fd, 4))) + return; + if (RFIFOL (fd, 4) < 1) + char_log + ("Receiving a message for broadcast, but message is void.\n"); + else + { + // at least 1 map-server + for (i = 0; i < MAX_MAP_SERVERS; i++) + if (server_fd[i] >= 0) + break; + if (i == MAX_MAP_SERVERS) + char_log + ("'ladmin': Receiving a message for broadcast, but no map-server is online.\n"); + else + { + char buf[128]; + char message[RFIFOL (fd, 4) + 1]; // +1 to add a null terminated if not exist in the packet + int lp; + char *p; + memset (message, '\0', sizeof (message)); + memcpy (message, RFIFOP (fd, 8), RFIFOL (fd, 4)); + message[sizeof (message) - 1] = '\0'; + remove_control_chars (message); + // remove all first spaces + p = message; + while (p[0] == ' ') + p++; + // if message is only composed of spaces + if (p[0] == '\0') + char_log + ("Receiving a message for broadcast, but message is only a lot of spaces.\n"); + // else send message to all map-servers + else + { + if (RFIFOW (fd, 2) == 0) + { + char_log + ("'ladmin': Receiving a message for broadcast (message (in yellow): %s)\n", + message); + lp = 4; + } + else + { + char_log + ("'ladmin': Receiving a message for broadcast (message (in blue): %s)\n", + message); + lp = 8; + } + // split message to max 80 char + while (p[0] != '\0') + { // if not finish + if (p[0] == ' ') // jump if first char is a space + p++; + else + { + char split[80]; + char *last_space; + sscanf (p, "%79[^\t]", split); // max 79 char, any char (\t is control char and control char was removed before) + split[sizeof (split) - 1] = '\0'; // last char always \0 + if ((last_space = + strrchr (split, ' ')) != NULL) + { // searching space from end of the string + last_space[0] = '\0'; // replace it by NULL to have correct length of split + p++; // to jump the new NULL + } + p += strlen (split); + // send broadcast to all map-servers + WBUFW (buf, 0) = 0x3800; + WBUFW (buf, 2) = lp + strlen (split) + 1; + WBUFL (buf, 4) = 0x65756c62; // only write if in blue (lp = 8) + memcpy (WBUFP (buf, lp), split, + strlen (split) + 1); + mapif_sendall (buf, WBUFW (buf, 2)); + } + } + } + } + } + RFIFOSKIP (fd, 8 + RFIFOL (fd, 4)); + break; + + // account_reg2変更通知 + case 0x2729: + if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) + return; + { + struct global_reg reg[ACCOUNT_REG2_NUM]; + unsigned char buf[4096]; + int j, p, acc; + acc = RFIFOL (fd, 4); + for (p = 8, j = 0; + p < RFIFOW (fd, 2) && j < ACCOUNT_REG2_NUM; + p += 36, j++) + { + memcpy (reg[j].str, RFIFOP (fd, p), 32); + reg[j].value = RFIFOL (fd, p + 32); + } + set_account_reg2 (acc, j, reg); + // 同垢ログインを禁止していれば送る必要は無い + memcpy (buf, RFIFOP (fd, 0), RFIFOW (fd, 2)); + WBUFW (buf, 0) = 0x2b11; + mapif_sendall (buf, WBUFW (buf, 2)); + RFIFOSKIP (fd, RFIFOW (fd, 2)); +// printf("char: save_account_reg_reply\n"); + } + break; + + case 0x7924: + { // [Fate] Itemfrob package: forwarded from login-server + if (RFIFOREST (fd) < 10) + return; + int source_id = RFIFOL (fd, 2); + int dest_id = RFIFOL (fd, 6); + unsigned char buf[10]; + + WBUFW (buf, 0) = 0x2afa; + WBUFL (buf, 2) = source_id; + WBUFL (buf, 6) = dest_id; + + mapif_sendall (buf, 10); // forward package to map servers + for (i = 0; i < char_num; i++) + { + struct mmo_charstatus *c = char_dat + i; + struct storage *s = account2storage (c->account_id); + int changes = 0; + int j; +#define FIX(v) if (v == source_id) {v = dest_id; ++changes; } + for (j = 0; j < MAX_INVENTORY; j++) + FIX (c->inventory[j].nameid); + for (j = 0; j < MAX_CART; j++) + FIX (c->cart[j].nameid); + FIX (c->weapon); + FIX (c->shield); + FIX (c->head_top); + FIX (c->head_mid); + FIX (c->head_bottom); + + if (s) + for (j = 0; j < s->storage_amount; j++) + FIX (s->storage_[j].nameid); +#undef FIX + if (changes) + char_log + ("itemfrob(%d -> %d): `%s'(%d, account %d): changed %d times\n", + source_id, dest_id, c->name, c->char_id, + c->account_id, changes); + + } + + mmo_char_sync (); + inter_storage_save (); + RFIFOSKIP (fd, 10); + break; + } + + // Account deletion notification (from login-server) + case 0x2730: + if (RFIFOREST (fd) < 6) + return; + // Deletion of all characters of the account + for (i = 0; i < char_num; i++) + { + if (char_dat[i].account_id == RFIFOL (fd, 2)) + { + char_delete (&char_dat[i]); + if (i < char_num - 1) + { + memcpy (&char_dat[i], &char_dat[char_num - 1], + sizeof (struct mmo_charstatus)); + // if moved character owns to deleted account, check again it's character + if (char_dat[i].account_id == RFIFOL (fd, 2)) + { + i--; + // Correct moved character reference in the character's owner by [Yor] + } + else + { + int j, k; + struct char_session_data *sd2; + for (j = 0; j < fd_max; j++) + { + if (session[j] + && (sd2 = (struct char_session_data*)session[j]->session_data) + && sd2->account_id == + char_dat[char_num - 1].account_id) + { + for (k = 0; k < 9; k++) + { + if (sd2->found_char[k] == + char_num - 1) + { + sd2->found_char[k] = i; + break; + } + } + break; + } + } + } + } + char_num--; + } + } + // Deletion of the storage + inter_storage_delete (RFIFOL (fd, 2)); + // send to all map-servers to disconnect the player + { + unsigned char buf[6]; + WBUFW (buf, 0) = 0x2b13; + WBUFL (buf, 2) = RFIFOL (fd, 2); + mapif_sendall (buf, 6); + } + // disconnect player if online on char-server + disconnect_player (RFIFOL (fd, 2)); + RFIFOSKIP (fd, 6); + break; + + // State change of account/ban notification (from login-server) by [Yor] + case 0x2731: + if (RFIFOREST (fd) < 11) + return; + // send to all map-servers to disconnect the player + { + unsigned char buf[11]; + WBUFW (buf, 0) = 0x2b14; + WBUFL (buf, 2) = RFIFOL (fd, 2); + WBUFB (buf, 6) = RFIFOB (fd, 6); // 0: change of statut, 1: ban + WBUFL (buf, 7) = RFIFOL (fd, 7); // status or final date of a banishment + mapif_sendall (buf, 11); + } + // disconnect player if online on char-server + disconnect_player (RFIFOL (fd, 2)); + RFIFOSKIP (fd, 11); + break; + + // Receiving GM acounts info from login-server (by [Yor]) + case 0x2732: + if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) + return; + { + char buf[32000]; + if (gm_account != NULL) + free (gm_account); + CREATE (gm_account, struct gm_account, (RFIFOW (fd, 2) - 4) / 5); + GM_num = 0; + for (i = 4; i < RFIFOW (fd, 2); i = i + 5) + { + gm_account[GM_num].account_id = RFIFOL (fd, i); + gm_account[GM_num].level = (int) RFIFOB (fd, i + 4); + //printf("GM account: %d -> level %d\n", gm_account[GM_num].account_id, gm_account[GM_num].level); + GM_num++; + } + printf + ("From login-server: receiving of %d GM accounts information.\n", + GM_num); + char_log + ("From login-server: receiving of %d GM accounts information.\n", + GM_num); + create_online_files (); // update online players files (perhaps some online players change of GM level) + // send new gm acccounts level to map-servers + memcpy (buf, RFIFOP (fd, 0), RFIFOW (fd, 2)); + WBUFW (buf, 0) = 0x2b15; + mapif_sendall (buf, RFIFOW (fd, 2)); + } + RFIFOSKIP (fd, RFIFOW (fd, 2)); + break; + + case 0x2741: // change password reply + if (RFIFOREST (fd) < 7) + return; + { + int acc, status, i; + acc = RFIFOL (fd, 2); + status = RFIFOB (fd, 6); + + for (i = 0; i < fd_max; i++) + { + if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) + { + if (sd->account_id == acc) + { + WFIFOW (i, 0) = 0x62; + WFIFOB (i, 2) = status; + WFIFOSET (i, 3); + break; + } + } + } + } + RFIFOSKIP (fd, 7); + break; + + default: + session[fd]->eof = 1; + return; + } + } + RFIFOFLUSH (fd); +} + +//-------------------------------- +// Map-server anti-freeze system +//-------------------------------- +void map_anti_freeze_system (timer_id tid, tick_t tick, custom_id_t id, custom_data_t data) +{ + int i; + + //printf("Entering in map_anti_freeze_system function to check freeze of servers.\n"); + for (i = 0; i < MAX_MAP_SERVERS; i++) + { + if (server_fd[i] >= 0) + { // if map-server is online + //printf("map_anti_freeze_system: server #%d, flag: %d.\n", i, server_freezeflag[i]); + if (server_freezeflag[i]-- < 1) + { // Map-server anti-freeze system. Counter. 5 ok, 4...0 freezed + printf + ("Map-server anti-freeze system: char-server #%d is freezed -> disconnection.\n", + i); + char_log + ("Map-server anti-freeze system: char-server #%d is freezed -> disconnection.\n", + i); + session[server_fd[i]]->eof = 1; + } + } + } +} + +void parse_frommap (int fd) +{ + int i, j; + int id; + + for (id = 0; id < MAX_MAP_SERVERS; id++) + if (server_fd[id] == fd) + break; + if (id == MAX_MAP_SERVERS || session[fd]->eof) + { + if (id < MAX_MAP_SERVERS) + { + printf ("Map-server %d (session #%d) has disconnected.\n", id, + fd); + memset (&server[id], 0, sizeof (struct mmo_map_server)); + server_fd[id] = -1; + for (j = 0; j < char_num; j++) + if (online_chars[j] == fd) + online_chars[j] = -1; + create_online_files (); // update online players files (to remove all online players of this server) + } + close (fd); + delete_session (fd); + return; + } + + while (RFIFOREST (fd) >= 2) + { +// printf("parse_frommap: connection #%d, packet: 0x%x (with being read: %d bytes).\n", fd, RFIFOW(fd,0), RFIFOREST(fd)); + + switch (RFIFOW (fd, 0)) + { + // request from map-server to reload GM accounts. Transmission to login-server (by Yor) + case 0x2af7: + if (login_fd > 0) + { // don't send request if no login-server + WFIFOW (login_fd, 0) = 0x2709; + WFIFOSET (login_fd, 2); +// printf("char : request from map-server to reload GM accounts -> login-server.\n"); + } + RFIFOSKIP (fd, 2); + break; + + // Receiving map names list from the map-server + case 0x2afa: + if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) + return; + memset (server[id].map, 0, sizeof (server[id].map)); + j = 0; + for (i = 4; i < RFIFOW (fd, 2); i += 16) + { + memcpy (server[id].map[j], RFIFOP (fd, i), 16); +// printf("set map %d.%d : %s\n", id, j, server[id].map[j]); + j++; + } + { + unsigned char *p = (unsigned char *) &server[id].ip; + printf + ("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n", + id, j, p[0], p[1], p[2], p[3], server[id].port); + printf ("Map-server %d loading complete.\n", id); + char_log + ("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d. Map-server %d loading complete.\n", + id, j, p[0], p[1], p[2], p[3], + server[id].port, id); + } + WFIFOW (fd, 0) = 0x2afb; + WFIFOB (fd, 2) = 0; + memcpy (WFIFOP (fd, 3), wisp_server_name, 24); // name for wisp to player + WFIFOSET (fd, 27); + { + unsigned char buf[16384]; + int x; + if (j == 0) + { + printf ("WARNING: Map-Server %d have NO map.\n", id); + char_log ("WARNING: Map-Server %d have NO map.\n", + id); + // Transmitting maps information to the other map-servers + } + else + { + WBUFW (buf, 0) = 0x2b04; + WBUFW (buf, 2) = j * 16 + 10; + WBUFL (buf, 4) = server[id].ip; + WBUFW (buf, 8) = server[id].port; + memcpy (WBUFP (buf, 10), RFIFOP (fd, 4), j * 16); + mapif_sendallwos (fd, buf, WBUFW (buf, 2)); + } + // Transmitting the maps of the other map-servers to the new map-server + for (x = 0; x < MAX_MAP_SERVERS; x++) + { + if (server_fd[x] >= 0 && x != id) + { + WFIFOW (fd, 0) = 0x2b04; + WFIFOL (fd, 4) = server[x].ip; + WFIFOW (fd, 8) = server[x].port; + j = 0; + for (i = 0; i < MAX_MAP_PER_SERVER; i++) + if (server[x].map[i][0]) + memcpy (WFIFOP (fd, 10 + (j++) * 16), + server[x].map[i], 16); + if (j > 0) + { + WFIFOW (fd, 2) = j * 16 + 10; + WFIFOSET (fd, WFIFOW (fd, 2)); + } + } + } + } + RFIFOSKIP (fd, RFIFOW (fd, 2)); + break; + + // 認証要求 + case 0x2afc: + if (RFIFOREST (fd) < 22) + return; + //printf("auth_fifo search: account: %d, char: %d, secure: %08x-%08x\n", RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14)); + for (i = 0; i < AUTH_FIFO_SIZE; i++) + { + if (auth_fifo[i].account_id == RFIFOL (fd, 2) && + auth_fifo[i].char_id == RFIFOL (fd, 6) && + auth_fifo[i].login_id1 == RFIFOL (fd, 10) && +#if CMP_AUTHFIFO_LOGIN2 != 0 + // here, it's the only area where it's possible that we doesn't know login_id2 (map-server asks just after 0x72 packet, that doesn't given the value) + (auth_fifo[i].login_id2 == RFIFOL (fd, 14) || RFIFOL (fd, 14) == 0) && // relate to the versions higher than 18 +#endif + (!check_ip_flag || auth_fifo[i].ip == RFIFOL (fd, 18)) + && !auth_fifo[i].delflag) + { + auth_fifo[i].delflag = 1; + WFIFOW (fd, 0) = 0x2afd; + WFIFOW (fd, 2) = 18 + sizeof (struct mmo_charstatus); + WFIFOL (fd, 4) = RFIFOL (fd, 2); + WFIFOL (fd, 8) = auth_fifo[i].login_id2; + WFIFOL (fd, 12) = + (unsigned long) auth_fifo[i].connect_until_time; + char_dat[auth_fifo[i].char_pos].sex = + auth_fifo[i].sex; + WFIFOW (fd, 16) = auth_fifo[i].packet_tmw_version; + fprintf (stderr, + "From queue index %d: recalling packet version %d\n", + i, auth_fifo[i].packet_tmw_version); + memcpy (WFIFOP (fd, 18), + &char_dat[auth_fifo[i].char_pos], + sizeof (struct mmo_charstatus)); + WFIFOSET (fd, WFIFOW (fd, 2)); + //printf("auth_fifo search success (auth #%d, account %d, character: %d).\n", i, RFIFOL(fd,2), RFIFOL(fd,6)); + break; + } + } + if (i == AUTH_FIFO_SIZE) + { + WFIFOW (fd, 0) = 0x2afe; + WFIFOL (fd, 2) = RFIFOL (fd, 2); + WFIFOSET (fd, 6); + printf + ("auth_fifo search error! account %d not authentified.\n", + RFIFOL (fd, 2)); + } + RFIFOSKIP (fd, 22); + break; + + // MAPサーバー上のユーザー数受信 + case 0x2aff: + if (RFIFOREST (fd) < 6 || RFIFOREST (fd) < RFIFOW (fd, 2)) + return; + server[id].users = RFIFOW (fd, 4); + if (anti_freeze_enable) + server_freezeflag[id] = 5; // Map anti-freeze system. Counter. 5 ok, 4...0 freezed + // remove all previously online players of the server + for (i = 0; i < char_num; i++) + if (online_chars[i] == id) + online_chars[i] = -1; + // add online players in the list by [Yor] + for (i = 0; i < server[id].users; i++) + { + int char_id = RFIFOL (fd, 6 + i * 4); + for (j = 0; j < char_num; j++) + if (char_dat[j].char_id == char_id) + { + online_chars[j] = id; + //printf("%d\n", char_id); + break; + } + } + if (update_online < time (NULL)) + { // Time is done + update_online = time (NULL) + 8; + create_online_files (); // only every 8 sec. (normally, 1 server send users every 5 sec.) Don't update every time, because that takes time, but only every 2 connection. + // it set to 8 sec because is more than 5 (sec) and if we have more than 1 map-server, informations can be received in shifted. + } + RFIFOSKIP (fd, 6 + i * 4); + break; + + // キャラデータ保存 + case 0x2b01: + if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) + return; + for (i = 0; i < char_num; i++) + { + if (char_dat[i].account_id == RFIFOL (fd, 4) && + char_dat[i].char_id == RFIFOL (fd, 8)) + break; + } + if (i != char_num) + memcpy (&char_dat[i], RFIFOP (fd, 12), + sizeof (struct mmo_charstatus)); + RFIFOSKIP (fd, RFIFOW (fd, 2)); + break; + + // キャラセレ要求 + case 0x2b02: + if (RFIFOREST (fd) < 18) + return; + if (auth_fifo_pos >= AUTH_FIFO_SIZE) + auth_fifo_pos = 0; + //printf("auth_fifo set (auth #%d) - account: %d, secure: %08x-%08x\n", auth_fifo_pos, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); + auth_fifo[auth_fifo_pos].account_id = RFIFOL (fd, 2); + auth_fifo[auth_fifo_pos].char_id = 0; + auth_fifo[auth_fifo_pos].login_id1 = RFIFOL (fd, 6); + auth_fifo[auth_fifo_pos].login_id2 = RFIFOL (fd, 10); + auth_fifo[auth_fifo_pos].delflag = 2; + auth_fifo[auth_fifo_pos].char_pos = 0; + auth_fifo[auth_fifo_pos].connect_until_time = 0; // unlimited/unknown time by default (not display in map-server) + auth_fifo[auth_fifo_pos].ip = RFIFOL (fd, 14); + auth_fifo_pos++; + WFIFOW (fd, 0) = 0x2b03; + WFIFOL (fd, 2) = RFIFOL (fd, 2); + WFIFOB (fd, 6) = 0; + WFIFOSET (fd, 7); + RFIFOSKIP (fd, 18); + break; + + // マップサーバー間移動要求 + case 0x2b05: + if (RFIFOREST (fd) < 49) + return; + if (auth_fifo_pos >= AUTH_FIFO_SIZE) + auth_fifo_pos = 0; + WFIFOW (fd, 0) = 0x2b06; + memcpy (WFIFOP (fd, 2), RFIFOP (fd, 2), 42); + //printf("auth_fifo set (auth#%d) - account: %d, secure: 0x%08x-0x%08x\n", auth_fifo_pos, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); + auth_fifo[auth_fifo_pos].account_id = RFIFOL (fd, 2); + auth_fifo[auth_fifo_pos].char_id = RFIFOL (fd, 14); + auth_fifo[auth_fifo_pos].login_id1 = RFIFOL (fd, 6); + auth_fifo[auth_fifo_pos].login_id2 = RFIFOL (fd, 10); + auth_fifo[auth_fifo_pos].delflag = 0; + auth_fifo[auth_fifo_pos].sex = RFIFOB (fd, 44); + auth_fifo[auth_fifo_pos].connect_until_time = 0; // unlimited/unknown time by default (not display in map-server) + auth_fifo[auth_fifo_pos].ip = RFIFOL (fd, 45); + for (i = 0; i < char_num; i++) + if (char_dat[i].account_id == RFIFOL (fd, 2) && + char_dat[i].char_id == RFIFOL (fd, 14)) + { + auth_fifo[auth_fifo_pos].char_pos = i; + auth_fifo_pos++; + WFIFOL (fd, 6) = 0; + break; + } + if (i == char_num) + WFIFOW (fd, 6) = 1; + WFIFOSET (fd, 44); + RFIFOSKIP (fd, 49); + break; + + // キャラ名検索 + case 0x2b08: + if (RFIFOREST (fd) < 6) + return; + for (i = 0; i < char_num; i++) + { + if (char_dat[i].char_id == RFIFOL (fd, 2)) + break; + } + WFIFOW (fd, 0) = 0x2b09; + WFIFOL (fd, 2) = RFIFOL (fd, 2); + if (i != char_num) + memcpy (WFIFOP (fd, 6), char_dat[i].name, 24); + else + memcpy (WFIFOP (fd, 6), unknown_char_name, 24); + WFIFOSET (fd, 30); + RFIFOSKIP (fd, 6); + break; + + // it is a request to become GM + case 0x2b0a: + if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) + return; +// printf("parse_frommap: change gm -> login, account: %d, pass: '%s'.\n", RFIFOL(fd,4), RFIFOP(fd,8)); + if (login_fd > 0) + { // don't send request if no login-server + WFIFOW (login_fd, 0) = 0x2720; + memcpy (WFIFOP (login_fd, 2), RFIFOP (fd, 2), + RFIFOW (fd, 2) - 2); + WFIFOSET (login_fd, RFIFOW (fd, 2)); + } + else + { + WFIFOW (fd, 0) = 0x2b0b; + WFIFOL (fd, 2) = RFIFOL (fd, 4); + WFIFOL (fd, 6) = 0; + WFIFOSET (fd, 10); + } + RFIFOSKIP (fd, RFIFOW (fd, 2)); + break; + + // Map server send information to change an email of an account -> login-server + case 0x2b0c: + if (RFIFOREST (fd) < 86) + return; + if (login_fd > 0) + { // don't send request if no login-server + memcpy (WFIFOP (login_fd, 0), RFIFOP (fd, 0), 86); // 0x2722 .L .40B .40B + WFIFOW (login_fd, 0) = 0x2722; + WFIFOSET (login_fd, 86); + } + RFIFOSKIP (fd, 86); + break; + + // Map server ask char-server about a character name to do some operations (all operations are transmitted to login-server) + case 0x2b0e: + if (RFIFOREST (fd) < 44) + return; + { + char character_name[24]; + int acc = RFIFOL (fd, 2); // account_id of who ask (-1 if nobody) + memcpy (character_name, RFIFOP (fd, 6), 24); + character_name[sizeof (character_name) - 1] = '\0'; + // prepare answer + WFIFOW (fd, 0) = 0x2b0f; // answer + WFIFOL (fd, 2) = acc; // who want do operation + WFIFOW (fd, 30) = RFIFOW (fd, 30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban, 5-changesex + // search character + i = search_character_index (character_name); + if (i >= 0) + { + memcpy (WFIFOP (fd, 6), search_character_name (i), 24); // put correct name if found + WFIFOW (fd, 32) = 0; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + switch (RFIFOW (fd, 30)) + { + case 1: // block + if (acc == -1 + || isGM (acc) >= + isGM (char_dat[i].account_id)) + { + if (login_fd > 0) + { // don't send request if no login-server + WFIFOW (login_fd, 0) = 0x2724; + WFIFOL (login_fd, 2) = char_dat[i].account_id; // account value + WFIFOL (login_fd, 6) = 5; // status of the account + WFIFOSET (login_fd, 10); +// printf("char : status -> login: account %d, status: %d \n", char_dat[i].account_id, 5); + } + else + WFIFOW (fd, 32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + } + else + WFIFOW (fd, 32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + break; + case 2: // ban + if (acc == -1 + || isGM (acc) >= + isGM (char_dat[i].account_id)) + { + if (login_fd > 0) + { // don't send request if no login-server + WFIFOW (login_fd, 0) = 0x2725; + WFIFOL (login_fd, 2) = char_dat[i].account_id; // account value + WFIFOW (login_fd, 6) = RFIFOW (fd, 32); // year + WFIFOW (login_fd, 8) = RFIFOW (fd, 34); // month + WFIFOW (login_fd, 10) = RFIFOW (fd, 36); // day + WFIFOW (login_fd, 12) = RFIFOW (fd, 38); // hour + WFIFOW (login_fd, 14) = RFIFOW (fd, 40); // minute + WFIFOW (login_fd, 16) = RFIFOW (fd, 42); // second + WFIFOSET (login_fd, 18); +// printf("char : status -> login: account %d, ban: %dy %dm %dd %dh %dmn %ds\n", +// char_dat[i].account_id, (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), (short)RFIFOW(fd,38), (short)RFIFOW(fd,40), (short)RFIFOW(fd,42)); + } + else + WFIFOW (fd, 32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + } + else + WFIFOW (fd, 32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + break; + case 3: // unblock + if (acc == -1 + || isGM (acc) >= + isGM (char_dat[i].account_id)) + { + if (login_fd > 0) + { // don't send request if no login-server + WFIFOW (login_fd, 0) = 0x2724; + WFIFOL (login_fd, 2) = char_dat[i].account_id; // account value + WFIFOL (login_fd, 6) = 0; // status of the account + WFIFOSET (login_fd, 10); +// printf("char : status -> login: account %d, status: %d \n", char_dat[i].account_id, 0); + } + else + WFIFOW (fd, 32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + } + else + WFIFOW (fd, 32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + break; + case 4: // unban + if (acc == -1 + || isGM (acc) >= + isGM (char_dat[i].account_id)) + { + if (login_fd > 0) + { // don't send request if no login-server + WFIFOW (login_fd, 0) = 0x272a; + WFIFOL (login_fd, 2) = char_dat[i].account_id; // account value + WFIFOSET (login_fd, 6); +// printf("char : status -> login: account %d, unban request\n", char_dat[i].account_id); + } + else + WFIFOW (fd, 32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + } + else + WFIFOW (fd, 32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + break; + case 5: // changesex + if (acc == -1 + || isGM (acc) >= + isGM (char_dat[i].account_id)) + { + if (login_fd > 0) + { // don't send request if no login-server + WFIFOW (login_fd, 0) = 0x2727; + WFIFOL (login_fd, 2) = char_dat[i].account_id; // account value + WFIFOSET (login_fd, 6); +// printf("char : status -> login: account %d, change sex request\n", char_dat[i].account_id); + } + else + WFIFOW (fd, 32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + } + else + WFIFOW (fd, 32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + break; + } + } + else + { + // character name not found + memcpy (WFIFOP (fd, 6), character_name, 24); + WFIFOW (fd, 32) = 1; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline + } + // send answer if a player ask, not if the server ask + if (acc != -1) + { + WFIFOSET (fd, 34); + } + RFIFOSKIP (fd, 44); + break; + } + +// case 0x2b0f: not more used (available for futur usage) + + // account_reg保存要求 + case 0x2b10: + if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) + return; + { + struct global_reg reg[ACCOUNT_REG2_NUM]; + int p, acc; + acc = RFIFOL (fd, 4); + for (p = 8, j = 0; + p < RFIFOW (fd, 2) && j < ACCOUNT_REG2_NUM; + p += 36, j++) + { + memcpy (reg[j].str, RFIFOP (fd, p), 32); + reg[j].value = RFIFOL (fd, p + 32); + } + set_account_reg2 (acc, j, reg); + // loginサーバーへ送る + if (login_fd > 0) + { // don't send request if no login-server + memcpy (WFIFOP (login_fd, 0), RFIFOP (fd, 0), + RFIFOW (fd, 2)); + WFIFOW (login_fd, 0) = 0x2728; + WFIFOSET (login_fd, WFIFOW (login_fd, 2)); + } + // ワールドへの同垢ログインがなければmapサーバーに送る必要はない + //memcpy(buf, RFIFOP(fd,0), RFIFOW(fd,2)); + //WBUFW(buf,0) = 0x2b11; + //mapif_sendall(buf, WBUFW(buf,2)); + RFIFOSKIP (fd, RFIFOW (fd, 2)); +// printf("char: save_account_reg (from map)\n"); + break; + } + + // Map server is requesting a divorce + case 0x2b16: + if (RFIFOREST (fd) < 4) + return; + { + for (i = 0; i < char_num; i++) + if (char_dat[i].char_id == RFIFOL (fd, 2)) + break; + + if (i != char_num) + char_divorce (&char_dat[i]); + + RFIFOSKIP (fd, 6); + break; + + } + + default: + // inter server処理に渡す + { + int r = inter_parse_frommap (fd); + if (r == 1) // 処理できた + break; + if (r == 2) // パケット長が足りない + return; + } + // inter server処理でもない場合は切断 + printf + ("char: unknown packet 0x%04x (%d bytes to read in buffer)! (from map).\n", + RFIFOW (fd, 0), RFIFOREST (fd)); + session[fd]->eof = 1; + return; + } + } +} + +int search_mapserver (char *map) +{ + int i, j; + char temp_map[16]; + int temp_map_len; + +// printf("Searching the map-server for map '%s'... ", map); + strncpy (temp_map, map, sizeof (temp_map)); + temp_map[sizeof (temp_map) - 1] = '\0'; + if (strchr (temp_map, '.') != NULL) + temp_map[strchr (temp_map, '.') - temp_map + 1] = '\0'; // suppress the '.gat', but conserve the '.' to be sure of the name of the map + + temp_map_len = strlen (temp_map); + for (i = 0; i < MAX_MAP_SERVERS; i++) + if (server_fd[i] >= 0) + for (j = 0; server[i].map[j][0]; j++) + //printf("%s : %s = %d\n", server[i].map[j], map, strncmp(server[i].map[j], temp_map, temp_map_len)); + if (strncmp (server[i].map[j], temp_map, temp_map_len) == 0) + { +// printf("found -> server #%d.\n", i); + return i; + } + +// printf("not found.\n"); + return -1; +} + +// char_mapifの初期化処理(現在はinter_mapif初期化のみ) +static int char_mapif_init (int fd) +{ + return inter_mapif_init (fd); +} + +//----------------------------------------------------- +// Test to know if an IP come from LAN or WAN. by [Yor] +//----------------------------------------------------- +int lan_ip_check (unsigned char *p) +{ + int i; + int lancheck = 1; + +// printf("lan_ip_check: to compare: %d.%d.%d.%d, network: %d.%d.%d.%d/%d.%d.%d.%d\n", +// p[0], p[1], p[2], p[3], +// subneti[0], subneti[1], subneti[2], subneti[3], +// subnetmaski[0], subnetmaski[1], subnetmaski[2], subnetmaski[3]); + for (i = 0; i < 4; i++) + { + if ((subneti[i] & subnetmaski[i]) != (p[i] & subnetmaski[i])) + { + lancheck = 0; + break; + } + } + printf ("LAN test (result): %s source\033[0m.\n", + (lancheck) ? "\033[1;36mLAN" : "\033[1;32mWAN"); + return lancheck; +} + +void parse_char (int fd) +{ + int i, ch; + char email[40]; + struct char_session_data *sd; + unsigned char *p = (unsigned char *) &session[fd]->client_addr.sin_addr; + + if (login_fd < 0 || session[fd]->eof) + { // disconnect any player (already connected to char-server or coming back from map-server) if login-server is diconnected. + if (fd == login_fd) + login_fd = -1; + close (fd); + delete_session (fd); + return; + } + + sd = (struct char_session_data*)session[fd]->session_data; + + while (RFIFOREST (fd) >= 2) + { +// if (RFIFOW(fd,0) < 30000) +// printf("parse_char: connection #%d, packet: 0x%x (with being read: %d bytes).\n", fd, RFIFOW(fd,0), RFIFOREST(fd)); + + switch (RFIFOW (fd, 0)) + { + case 0x20b: //20040622暗号化ragexe対応 + if (RFIFOREST (fd) < 19) + return; + RFIFOSKIP (fd, 19); + break; + + case 0x61: // change password request + if (RFIFOREST (fd) < 50) + return; + { + WFIFOW (login_fd, 0) = 0x2740; + WFIFOL (login_fd, 2) = sd->account_id; + memcpy (WFIFOP (login_fd, 6), RFIFOP (fd, 2), 24); + memcpy (WFIFOP (login_fd, 30), RFIFOP (fd, 26), 24); + WFIFOSET (login_fd, 54); + } + RFIFOSKIP (fd, 50); + break; + + case 0x65: // 接続要求 + if (RFIFOREST (fd) < 17) + return; + { + int GM_value; + if ((GM_value = isGM (RFIFOL (fd, 2)))) + printf + ("Account Logged On; Account ID: %d (GM level %d).\n", + RFIFOL (fd, 2), GM_value); + else + printf ("Account Logged On; Account ID: %d.\n", + RFIFOL (fd, 2)); + if (sd == NULL) + { + CREATE (sd, struct char_session_data, 1); + session[fd]->session_data = sd; + memcpy (sd->email, "no mail", 40); // put here a mail without '@' to refuse deletion if we don't receive the e-mail + sd->connect_until_time = 0; // unknow or illimited (not displaying on map-server) + } + sd->account_id = RFIFOL (fd, 2); + sd->login_id1 = RFIFOL (fd, 6); + sd->login_id2 = RFIFOL (fd, 10); + sd->packet_tmw_version = RFIFOW (fd, 14); + sd->sex = RFIFOB (fd, 16); + // send back account_id + WFIFOL (fd, 0) = RFIFOL (fd, 2); + WFIFOSET (fd, 4); + // search authentification + for (i = 0; i < AUTH_FIFO_SIZE; i++) + { + if (auth_fifo[i].account_id == sd->account_id && + auth_fifo[i].login_id1 == sd->login_id1 && +#if CMP_AUTHFIFO_LOGIN2 != 0 + auth_fifo[i].login_id2 == sd->login_id2 && // relate to the versions higher than 18 +#endif + (!check_ip_flag + || auth_fifo[i].ip == + session[fd]->client_addr.sin_addr.s_addr) + && auth_fifo[i].delflag == 2) + { + auth_fifo[i].delflag = 1; + if (max_connect_user == 0 + || count_users () < max_connect_user) + { + if (login_fd > 0) + { // don't send request if no login-server + // request to login-server to obtain e-mail/time limit + WFIFOW (login_fd, 0) = 0x2716; + WFIFOL (login_fd, 2) = sd->account_id; + WFIFOSET (login_fd, 6); + } + // Record client version + auth_fifo[i].packet_tmw_version = + sd->packet_tmw_version; + // send characters to player + mmo_char_send006b (fd, sd); + } + else + { + // refuse connection (over populated) + WFIFOW (fd, 0) = 0x6c; + WFIFOW (fd, 2) = 0; + WFIFOSET (fd, 3); + } + break; + } + } + // authentification not found + if (i == AUTH_FIFO_SIZE) + { + if (login_fd > 0) + { // don't send request if no login-server + WFIFOW (login_fd, 0) = 0x2712; // ask login-server to authentify an account + WFIFOL (login_fd, 2) = sd->account_id; + WFIFOL (login_fd, 6) = sd->login_id1; + WFIFOL (login_fd, 10) = sd->login_id2; // relate to the versions higher than 18 + WFIFOB (login_fd, 14) = sd->sex; + WFIFOL (login_fd, 15) = + session[fd]->client_addr.sin_addr.s_addr; + WFIFOSET (login_fd, 19); + } + else + { // if no login-server, we must refuse connection + WFIFOW (fd, 0) = 0x6c; + WFIFOW (fd, 2) = 0; + WFIFOSET (fd, 3); + } + } + } + RFIFOSKIP (fd, 17); + break; + + case 0x66: // キャラ選択 + if (!sd || RFIFOREST (fd) < 3) + return; + + char ip[16]; + unsigned char *sin_addr = + (unsigned char *) &session[fd]->client_addr.sin_addr; + sprintf (ip, "%d.%d.%d.%d", sin_addr[0], sin_addr[1], + sin_addr[2], sin_addr[3]); + + // if we activated email creation and email is default email + if (email_creation != 0 && strcmp (sd->email, "a@a.com") == 0 + && login_fd > 0) + { // to modify an e-mail, login-server must be online + WFIFOW (fd, 0) = 0x70; + WFIFOB (fd, 2) = 0; // 00 = Incorrect Email address + WFIFOSET (fd, 3); + + // otherwise, load the character + } + else + { + for (ch = 0; ch < 9; ch++) + if (sd->found_char[ch] >= 0 + && char_dat[sd->found_char[ch]].char_num == + RFIFOB (fd, 2)) + break; + if (ch != 9) + { + char_log + ("Character Selected, Account ID: %d, Character Slot: %d, Character Name: %s [%s]\n", + sd->account_id, RFIFOB (fd, 2), + char_dat[sd->found_char[ch]].name, ip); + // searching map server + i = search_mapserver (char_dat + [sd->found_char[ch]].last_point. + map); + // if map is not found, we check major cities + if (i < 0) + { + if ((i = search_mapserver ("prontera.gat")) >= 0) + { // check is done without 'gat'. + memcpy (char_dat + [sd->found_char[ch]].last_point.map, + "prontera.gat", 16); + char_dat[sd->found_char[ch]].last_point.x = 273; // savepoint coordonates + char_dat[sd->found_char[ch]].last_point.y = + 354; + } + else if ((i = + search_mapserver ("geffen.gat")) >= 0) + { // check is done without 'gat'. + memcpy (char_dat + [sd->found_char[ch]].last_point.map, + "geffen.gat", 16); + char_dat[sd->found_char[ch]].last_point.x = 120; // savepoint coordonates + char_dat[sd->found_char[ch]].last_point.y = + 100; + } + else if ((i = + search_mapserver ("morocc.gat")) >= 0) + { // check is done without 'gat'. + memcpy (char_dat + [sd->found_char[ch]].last_point.map, + "morocc.gat", 16); + char_dat[sd->found_char[ch]].last_point.x = 160; // savepoint coordonates + char_dat[sd->found_char[ch]].last_point.y = + 94; + } + else if ((i = + search_mapserver ("alberta.gat")) >= 0) + { // check is done without 'gat'. + memcpy (char_dat + [sd->found_char[ch]].last_point.map, + "alberta.gat", 16); + char_dat[sd->found_char[ch]].last_point.x = 116; // savepoint coordonates + char_dat[sd->found_char[ch]].last_point.y = + 57; + } + else if ((i = + search_mapserver ("payon.gat")) >= 0) + { // check is done without 'gat'. + memcpy (char_dat + [sd->found_char[ch]].last_point.map, + "payon.gat", 16); + char_dat[sd->found_char[ch]].last_point.x = 87; // savepoint coordonates + char_dat[sd->found_char[ch]].last_point.y = + 117; + } + else if ((i = + search_mapserver ("izlude.gat")) >= 0) + { // check is done without 'gat'. + memcpy (char_dat + [sd->found_char[ch]].last_point.map, + "izlude.gat", 16); + char_dat[sd->found_char[ch]].last_point.x = 94; // savepoint coordonates + char_dat[sd->found_char[ch]].last_point.y = + 103; + } + else + { + int j; + // get first online server (with a map) + i = 0; + for (j = 0; j < MAX_MAP_SERVERS; j++) + if (server_fd[j] >= 0 + && server[j].map[0][0]) + { // change save point to one of map found on the server (the first) + i = j; + memcpy (char_dat + [sd-> + found_char[ch]].last_point. + map, server[j].map[0], 16); + printf + ("Map-server #%d found with a map: '%s'.\n", + j, server[j].map[0]); + // coordonates are unknown + break; + } + // if no map-server is connected, we send: server closed + if (j == MAX_MAP_SERVERS) + { + WFIFOW (fd, 0) = 0x81; + WFIFOL (fd, 2) = 1; // 01 = Server closed + WFIFOSET (fd, 3); + RFIFOSKIP (fd, 3); + break; + } + } + } + WFIFOW (fd, 0) = 0x71; + WFIFOL (fd, 2) = char_dat[sd->found_char[ch]].char_id; + memcpy (WFIFOP (fd, 6), + char_dat[sd->found_char[ch]].last_point.map, + 16); + printf + ("Character selection '%s' (account: %d, slot: %d) [%s]\n", + char_dat[sd->found_char[ch]].name, + sd->account_id, ch, ip); + printf ("--Send IP of map-server. "); + if (lan_ip_check (p)) + WFIFOL (fd, 22) = inet_addr (lan_map_ip); + else + WFIFOL (fd, 22) = server[i].ip; + WFIFOW (fd, 26) = server[i].port; + WFIFOSET (fd, 28); + if (auth_fifo_pos >= AUTH_FIFO_SIZE) + auth_fifo_pos = 0; + //printf("auth_fifo set #%d - account %d, char: %d, secure: %08x-%08x\n", auth_fifo_pos, sd->account_id, char_dat[sd->found_char[ch]].char_id, sd->login_id1, sd->login_id2); + auth_fifo[auth_fifo_pos].account_id = sd->account_id; + auth_fifo[auth_fifo_pos].char_id = + char_dat[sd->found_char[ch]].char_id; + auth_fifo[auth_fifo_pos].login_id1 = sd->login_id1; + auth_fifo[auth_fifo_pos].login_id2 = sd->login_id2; + auth_fifo[auth_fifo_pos].delflag = 0; + auth_fifo[auth_fifo_pos].char_pos = + sd->found_char[ch]; + auth_fifo[auth_fifo_pos].sex = sd->sex; + auth_fifo[auth_fifo_pos].connect_until_time = + sd->connect_until_time; + auth_fifo[auth_fifo_pos].ip = + session[fd]->client_addr.sin_addr.s_addr; + auth_fifo[auth_fifo_pos].packet_tmw_version = + sd->packet_tmw_version; + auth_fifo_pos++; + } + } + RFIFOSKIP (fd, 3); + break; + + case 0x67: // 作成 + if (!sd || RFIFOREST (fd) < 37) + return; + i = make_new_char (fd, RFIFOP (fd, 2)); + if (i < 0) + { + WFIFOW (fd, 0) = 0x6e; + WFIFOB (fd, 2) = 0x00; + WFIFOSET (fd, 3); + RFIFOSKIP (fd, 37); + break; + } + + WFIFOW (fd, 0) = 0x6d; + memset (WFIFOP (fd, 2), 0, 106); + + WFIFOL (fd, 2) = char_dat[i].char_id; + WFIFOL (fd, 2 + 4) = char_dat[i].base_exp; + WFIFOL (fd, 2 + 8) = char_dat[i].zeny; + WFIFOL (fd, 2 + 12) = char_dat[i].job_exp; + WFIFOL (fd, 2 + 16) = char_dat[i].job_level; + + WFIFOL (fd, 2 + 28) = char_dat[i].karma; + WFIFOL (fd, 2 + 32) = char_dat[i].manner; + + WFIFOW (fd, 2 + 40) = 0x30; + WFIFOW (fd, 2 + 42) = + (char_dat[i].hp > 0x7fff) ? 0x7fff : char_dat[i].hp; + WFIFOW (fd, 2 + 44) = + (char_dat[i].max_hp > + 0x7fff) ? 0x7fff : char_dat[i].max_hp; + WFIFOW (fd, 2 + 46) = + (char_dat[i].sp > 0x7fff) ? 0x7fff : char_dat[i].sp; + WFIFOW (fd, 2 + 48) = + (char_dat[i].max_sp > + 0x7fff) ? 0x7fff : char_dat[i].max_sp; + WFIFOW (fd, 2 + 50) = DEFAULT_WALK_SPEED; // char_dat[i].speed; + WFIFOW (fd, 2 + 52) = char_dat[i].pc_class; + WFIFOW (fd, 2 + 54) = char_dat[i].hair; + + WFIFOW (fd, 2 + 58) = char_dat[i].base_level; + WFIFOW (fd, 2 + 60) = char_dat[i].skill_point; + + WFIFOW (fd, 2 + 64) = char_dat[i].shield; + WFIFOW (fd, 2 + 66) = char_dat[i].head_top; + WFIFOW (fd, 2 + 68) = char_dat[i].head_mid; + WFIFOW (fd, 2 + 70) = char_dat[i].hair_color; + + memcpy (WFIFOP (fd, 2 + 74), char_dat[i].name, 24); + + WFIFOB (fd, 2 + 98) = + (char_dat[i].str > 255) ? 255 : char_dat[i].str; + WFIFOB (fd, 2 + 99) = + (char_dat[i].agi > 255) ? 255 : char_dat[i].agi; + WFIFOB (fd, 2 + 100) = + (char_dat[i].vit > 255) ? 255 : char_dat[i].vit; + WFIFOB (fd, 2 + 101) = + (char_dat[i].int_ > 255) ? 255 : char_dat[i].int_; + WFIFOB (fd, 2 + 102) = + (char_dat[i].dex > 255) ? 255 : char_dat[i].dex; + WFIFOB (fd, 2 + 103) = + (char_dat[i].luk > 255) ? 255 : char_dat[i].luk; + WFIFOB (fd, 2 + 104) = char_dat[i].char_num; + + WFIFOSET (fd, 108); + RFIFOSKIP (fd, 37); + for (ch = 0; ch < 9; ch++) + { + if (sd->found_char[ch] == -1) + { + sd->found_char[ch] = i; + break; + } + } + + case 0x68: // delete char //Yor's Fix + if (!sd || RFIFOREST (fd) < 46) + return; + memcpy (email, RFIFOP (fd, 6), 40); + if (e_mail_check (email) == 0) + strncpy (email, "a@a.com", 40); // default e-mail + + // if we activated email creation and email is default email + if (email_creation != 0 && strcmp (sd->email, "a@a.com") == 0 + && login_fd > 0) + { // to modify an e-mail, login-server must be online + // if sended email is incorrect e-mail + if (strcmp (email, "a@a.com") == 0) + { + WFIFOW (fd, 0) = 0x70; + WFIFOB (fd, 2) = 0; // 00 = Incorrect Email address + WFIFOSET (fd, 3); + RFIFOSKIP (fd, 46); + // we act like we have selected a character + } + else + { + // we change the packet to set it like selection. + for (i = 0; i < 9; i++) + if (char_dat[sd->found_char[i]].char_id == + RFIFOL (fd, 2)) + { + // we save new e-mail + memcpy (sd->email, email, 40); + // we send new e-mail to login-server ('online' login-server is checked before) + WFIFOW (login_fd, 0) = 0x2715; + WFIFOL (login_fd, 2) = sd->account_id; + memcpy (WFIFOP (login_fd, 6), email, 40); + WFIFOSET (login_fd, 46); + // skip part of the packet! (46, but leave the size of select packet: 3) + RFIFOSKIP (fd, 43); + // change value to put new packet (char selection) + RFIFOW (fd, 0) = 0x66; + RFIFOB (fd, 2) = + char_dat[sd->found_char[i]].char_num; + // not send packet, it's modify of actual packet + break; + } + if (i == 9) + { + WFIFOW (fd, 0) = 0x70; + WFIFOB (fd, 2) = 0; // 00 = Incorrect Email address + WFIFOSET (fd, 3); + RFIFOSKIP (fd, 46); + } + } + + // otherwise, we delete the character + } + else + { + /*if (strcasecmp(email, sd->email) != 0) { // if it's an invalid email + * WFIFOW(fd, 0) = 0x70; + * WFIFOB(fd, 2) = 0; // 00 = Incorrect Email address + * WFIFOSET(fd, 3); + * // if mail is correct + * } else { */ + for (i = 0; i < 9; i++) + { + struct mmo_charstatus *cs = NULL; + if (sd->found_char[i] >= 0 + && (cs = + &char_dat[sd->found_char[i]])->char_id == + RFIFOL (fd, 2)) + { + char_delete (cs); // deletion process + + if (sd->found_char[i] != char_num - 1) + { + memcpy (&char_dat[sd->found_char[i]], + &char_dat[char_num - 1], + sizeof (struct mmo_charstatus)); + // Correct moved character reference in the character's owner + { + int j, k; + struct char_session_data *sd2; + for (j = 0; j < fd_max; j++) + { + if (session[j] + && (sd2 = (struct char_session_data*) + session[j]->session_data) + && sd2->account_id == + char_dat[char_num - 1].account_id) + { + for (k = 0; k < 9; k++) + { + if (sd2->found_char[k] == + char_num - 1) + { + sd2->found_char[k] = + sd->found_char[i]; + break; + } + } + break; + } + } + } + } + + char_num--; + for (ch = i; ch < 9 - 1; ch++) + sd->found_char[ch] = sd->found_char[ch + 1]; + sd->found_char[8] = -1; + WFIFOW (fd, 0) = 0x6f; + WFIFOSET (fd, 2); + break; + } + } + + if (i == 9) + { + WFIFOW (fd, 0) = 0x70; + WFIFOB (fd, 2) = 0; + WFIFOSET (fd, 3); + } + //} + RFIFOSKIP (fd, 46); + } + break; + + case 0x2af8: // マップサーバーログイン + if (RFIFOREST (fd) < 60) + return; + WFIFOW (fd, 0) = 0x2af9; + for (i = 0; i < MAX_MAP_SERVERS; i++) + { + if (server_fd[i] < 0) + break; + } + if (i == MAX_MAP_SERVERS || strcmp (RFIFOP (fd, 2), userid) + || strcmp (RFIFOP (fd, 26), passwd)) + { + WFIFOB (fd, 2) = 3; + WFIFOSET (fd, 3); + RFIFOSKIP (fd, 60); + } + else + { + int len; + WFIFOB (fd, 2) = 0; + session[fd]->func_parse = parse_frommap; + server_fd[i] = fd; + if (anti_freeze_enable) + server_freezeflag[i] = 5; // Map anti-freeze system. Counter. 5 ok, 4...0 freezed + server[i].ip = RFIFOL (fd, 54); + server[i].port = RFIFOW (fd, 58); + server[i].users = 0; + memset (server[i].map, 0, sizeof (server[i].map)); + WFIFOSET (fd, 3); + RFIFOSKIP (fd, 60); + realloc_fifo (fd, FIFOSIZE_SERVERLINK, + FIFOSIZE_SERVERLINK); + char_mapif_init (fd); + // send gm acccounts level to map-servers + len = 4; + WFIFOW (fd, 0) = 0x2b15; + for (i = 0; i < GM_num; i++) + { + WFIFOL (fd, len) = gm_account[i].account_id; + WFIFOB (fd, len + 4) = + (unsigned char) gm_account[i].level; + len += 5; + } + WFIFOW (fd, 2) = len; + WFIFOSET (fd, len); + return; + } + break; + + case 0x187: // Alive信号? + if (RFIFOREST (fd) < 6) + return; + RFIFOSKIP (fd, 6); + break; + + case 0x7530: // Athena情報所得 + WFIFOW (fd, 0) = 0x7531; + WFIFOB (fd, 2) = ATHENA_MAJOR_VERSION; + WFIFOB (fd, 3) = ATHENA_MINOR_VERSION; + WFIFOB (fd, 4) = ATHENA_REVISION; + WFIFOB (fd, 5) = ATHENA_RELEASE_FLAG; + WFIFOB (fd, 6) = ATHENA_OFFICIAL_FLAG; + WFIFOB (fd, 7) = ATHENA_SERVER_INTER | ATHENA_SERVER_CHAR; + WFIFOW (fd, 8) = ATHENA_MOD_VERSION; + WFIFOSET (fd, 10); + RFIFOSKIP (fd, 2); + return; + + case 0x7532: // 接続の切断(defaultと処理は一緒だが明示的にするため) + session[fd]->eof = 1; + return; + + default: + session[fd]->eof = 1; + return; + } + } +} + +// 全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す) +int mapif_sendall (char *buf, unsigned int len) +{ + int i, c; + + c = 0; + for (i = 0; i < MAX_MAP_SERVERS; i++) + { + int fd; + if ((fd = server_fd[i]) >= 0) + { + memcpy (WFIFOP (fd, 0), buf, len); + WFIFOSET (fd, len); + c++; + } + } + return c; +} + +// 自分以外の全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す) +int mapif_sendallwos (int sfd, unsigned char *buf, unsigned int len) +{ + int i, c; + + c = 0; + for (i = 0; i < MAX_MAP_SERVERS; i++) + { + int fd; + if ((fd = server_fd[i]) >= 0 && fd != sfd) + { + memcpy (WFIFOP (fd, 0), buf, len); + WFIFOSET (fd, len); + c++; + } + } + return c; +} + +// MAPサーバーにデータ送信(map鯖生存確認有り) +int mapif_send (int fd, unsigned char *buf, unsigned int len) +{ + int i; + + if (fd >= 0) + { + for (i = 0; i < MAX_MAP_SERVERS; i++) + { + if (fd == server_fd[i]) + { + memcpy (WFIFOP (fd, 0), buf, len); + WFIFOSET (fd, len); + return 1; + } + } + } + return 0; +} + +void send_users_tologin (timer_id tid, tick_t tick, custom_id_t id, custom_data_t data) +{ + int users = count_users (); + char buf[16]; + + if (login_fd > 0 && session[login_fd]) + { + // send number of user to login server + WFIFOW (login_fd, 0) = 0x2714; + WFIFOL (login_fd, 2) = users; + WFIFOSET (login_fd, 6); + } + // send number of players to all map-servers + WBUFW (buf, 0) = 0x2b00; + WBUFL (buf, 2) = users; + mapif_sendall (buf, 6); +} + +void check_connect_login_server (timer_id tid, tick_t tick, custom_id_t id, custom_data_t data) +{ + if (login_fd <= 0 || session[login_fd] == NULL) + { + printf ("Attempt to connect to login-server...\n"); + if ((login_fd = make_connection (login_ip, login_port)) < 0) + return; + session[login_fd]->func_parse = parse_tologin; + realloc_fifo (login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); + WFIFOW (login_fd, 0) = 0x2710; + memset (WFIFOP (login_fd, 2), 0, 24); + memcpy (WFIFOP (login_fd, 2), userid, + strlen (userid) < 24 ? strlen (userid) : 24); + memset (WFIFOP (login_fd, 26), 0, 24); + memcpy (WFIFOP (login_fd, 26), passwd, + strlen (passwd) < 24 ? strlen (passwd) : 24); + WFIFOL (login_fd, 50) = 0; + WFIFOL (login_fd, 54) = char_ip; + WFIFOL (login_fd, 58) = char_port; + memset (WFIFOP (login_fd, 60), 0, 20); + memcpy (WFIFOP (login_fd, 60), server_name, + strlen (server_name) < 20 ? strlen (server_name) : 20); + WFIFOW (login_fd, 80) = 0; + WFIFOW (login_fd, 82) = char_maintenance; + WFIFOW (login_fd, 84) = char_new; + WFIFOSET (login_fd, 86); + } +} + +//---------------------------------------------------------- +// Return numerical value of a switch configuration by [Yor] +// on/off, english, français, deutsch, español +//---------------------------------------------------------- +int config_switch (const char *str) +{ + if (strcasecmp (str, "on") == 0 || strcasecmp (str, "yes") == 0 + || strcasecmp (str, "oui") == 0 || strcasecmp (str, "ja") == 0 + || strcasecmp (str, "si") == 0) + return 1; + if (strcasecmp (str, "off") == 0 || strcasecmp (str, "no") == 0 + || strcasecmp (str, "non") == 0 || strcasecmp (str, "nein") == 0) + return 0; + + return atoi (str); +} + +//------------------------------------------- +// Reading Lan Support configuration by [Yor] +//------------------------------------------- +int lan_config_read (const char *lancfgName) +{ + int j; + struct hostent *h = NULL; + char line[1024], w1[1024], w2[1024]; + FILE *fp; + + // set default configuration + strncpy (lan_map_ip, "127.0.0.1", sizeof (lan_map_ip)); + subneti[0] = 127; + subneti[1] = 0; + subneti[2] = 0; + subneti[3] = 1; + for (j = 0; j < 4; j++) + subnetmaski[j] = 255; + + fp = fopen_ (lancfgName, "r"); + + if (fp == NULL) + { + printf ("LAN support configuration file not found: %s\n", lancfgName); + return 1; + } + + printf ("---start reading of Lan Support configuration...\n"); + + while (fgets (line, sizeof (line) - 1, fp)) + { + if (line[0] == '/' && line[1] == '/') + continue; + + line[sizeof (line) - 1] = '\0'; + if (sscanf (line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; + + remove_control_chars (w1); + remove_control_chars (w2); + if (strcasecmp (w1, "lan_map_ip") == 0) + { // Read map-server Lan IP Address + h = gethostbyname (w2); + if (h != NULL) + { + sprintf (lan_map_ip, "%d.%d.%d.%d", + (unsigned char) h->h_addr[0], + (unsigned char) h->h_addr[1], + (unsigned char) h->h_addr[2], + (unsigned char) h->h_addr[3]); + } + else + { + strncpy (lan_map_ip, w2, sizeof (lan_map_ip)); + lan_map_ip[sizeof (lan_map_ip) - 1] = 0; + } + printf ("LAN IP of map-server: %s.\n", lan_map_ip); + } + else if (strcasecmp (w1, "subnet") == 0) + { // Read Subnetwork + for (j = 0; j < 4; j++) + subneti[j] = 0; + h = gethostbyname (w2); + if (h != NULL) + { + for (j = 0; j < 4; j++) + subneti[j] = (unsigned char) h->h_addr[j]; + } + else + { + sscanf (w2, "%d.%d.%d.%d", &subneti[0], &subneti[1], + &subneti[2], &subneti[3]); + } + printf ("Sub-network of the map-server: %d.%d.%d.%d.\n", + subneti[0], subneti[1], subneti[2], subneti[3]); + } + else if (strcasecmp (w1, "subnetmask") == 0) + { // Read Subnetwork Mask + for (j = 0; j < 4; j++) + subnetmaski[j] = 255; + h = gethostbyname (w2); + if (h != NULL) + { + for (j = 0; j < 4; j++) + subnetmaski[j] = (unsigned char) h->h_addr[j]; + } + else + { + sscanf (w2, "%d.%d.%d.%d", &subnetmaski[0], &subnetmaski[1], + &subnetmaski[2], &subnetmaski[3]); + } + printf ("Sub-network mask of the map-server: %d.%d.%d.%d.\n", + subnetmaski[0], subnetmaski[1], subnetmaski[2], + subnetmaski[3]); + } + } + fclose_ (fp); + + // sub-network check of the map-server + { + unsigned int a0, a1, a2, a3; + unsigned char p[4]; + sscanf (lan_map_ip, "%d.%d.%d.%d", &a0, &a1, &a2, &a3); + p[0] = a0; + p[1] = a1; + p[2] = a2; + p[3] = a3; + printf ("LAN test of LAN IP of the map-server: "); + if (lan_ip_check (p) == 0) + { + printf + ("\033[1;31m***ERROR: LAN IP of the map-server doesn't belong to the specified Sub-network.\033[0m\n"); + } + } + + printf ("---End reading of Lan Support configuration...\n"); + + return 0; +} + +int char_config_read (const char *cfgName) +{ + struct hostent *h = NULL; + char line[1024], w1[1024], w2[1024]; + FILE *fp = fopen_ (cfgName, "r"); + + if (fp == NULL) + { + printf ("Configuration file not found: %s.\n", cfgName); + exit (1); + } + + while (fgets (line, sizeof (line) - 1, fp)) + { + if (line[0] == '/' && line[1] == '/') + continue; + + line[sizeof (line) - 1] = '\0'; + if (sscanf (line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; + + remove_control_chars (w1); + remove_control_chars (w2); + if (strcasecmp (w1, "userid") == 0) + { + memcpy (userid, w2, 24); + } + else if (strcasecmp (w1, "passwd") == 0) + { + memcpy (passwd, w2, 24); + } + else if (strcasecmp (w1, "server_name") == 0) + { + memcpy (server_name, w2, sizeof (server_name)); + server_name[sizeof (server_name) - 1] = '\0'; + printf ("%s server has been intialized\n", w2); + } + else if (strcasecmp (w1, "wisp_server_name") == 0) + { + if (strlen (w2) >= 4) + { + strncpy (wisp_server_name, w2, sizeof (wisp_server_name)); + wisp_server_name[sizeof (wisp_server_name) - 1] = '\0'; + } + } + else if (strcasecmp (w1, "login_ip") == 0) + { + h = gethostbyname (w2); + if (h != NULL) + { + printf ("Login server IP address : %s -> %d.%d.%d.%d\n", w2, + (unsigned char) h->h_addr[0], + (unsigned char) h->h_addr[1], + (unsigned char) h->h_addr[2], + (unsigned char) h->h_addr[3]); + sprintf (login_ip_str, "%d.%d.%d.%d", + (unsigned char) h->h_addr[0], + (unsigned char) h->h_addr[1], + (unsigned char) h->h_addr[2], + (unsigned char) h->h_addr[3]); + } + else + memcpy (login_ip_str, w2, 16); + } + else if (strcasecmp (w1, "login_port") == 0) + { + login_port = atoi (w2); + } + else if (strcasecmp (w1, "char_ip") == 0) + { + h = gethostbyname (w2); + if (h != NULL) + { + printf ("Character server IP address : %s -> %d.%d.%d.%d\n", + w2, (unsigned char) h->h_addr[0], + (unsigned char) h->h_addr[1], + (unsigned char) h->h_addr[2], + (unsigned char) h->h_addr[3]); + sprintf (char_ip_str, "%d.%d.%d.%d", + (unsigned char) h->h_addr[0], + (unsigned char) h->h_addr[1], + (unsigned char) h->h_addr[2], + (unsigned char) h->h_addr[3]); + } + else + memcpy (char_ip_str, w2, 16); + } + else if (strcasecmp (w1, "char_port") == 0) + { + char_port = atoi (w2); + } + else if (strcasecmp (w1, "char_maintenance") == 0) + { + char_maintenance = atoi (w2); + } + else if (strcasecmp (w1, "char_new") == 0) + { + char_new = atoi (w2); + } + else if (strcasecmp (w1, "email_creation") == 0) + { + email_creation = config_switch (w2); + } + else if (strcasecmp (w1, "char_txt") == 0) + { + strcpy (char_txt, w2); + } + else if (strcasecmp (w1, "backup_txt") == 0) + { //By zanetheinsane + strcpy (backup_txt, w2); + } + else if (strcasecmp (w1, "backup_txt_flag") == 0) + { // The backup_txt file was created because char deletion bug existed. Now it's finish and that take a lot of time to create a second file when there are a lot of characters. By [Yor] + backup_txt_flag = config_switch (w2); + } + else if (strcasecmp (w1, "max_connect_user") == 0) + { + max_connect_user = atoi (w2); + if (max_connect_user < 0) + max_connect_user = 0; // unlimited online players + } + else if (strcasecmp (w1, "check_ip_flag") == 0) + { + check_ip_flag = config_switch (w2); + } + else if (strcasecmp (w1, "autosave_time") == 0) + { + autosave_interval = atoi (w2) * 1000; + if (autosave_interval <= 0) + autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; + } + else if (strcasecmp (w1, "start_point") == 0) + { + char map[32]; + int x, y; + if (sscanf (w2, "%[^,],%d,%d", map, &x, &y) < 3) + continue; + if (strstr (map, ".gat") != NULL) + { // Verify at least if '.gat' is in the map name + memcpy (start_point.map, map, 16); + start_point.x = x; + start_point.y = y; + } + } + else if (strcasecmp (w1, "start_zeny") == 0) + { + start_zeny = atoi (w2); + if (start_zeny < 0) + start_zeny = 0; + } + else if (strcasecmp (w1, "start_weapon") == 0) + { + start_weapon = atoi (w2); + if (start_weapon < 0) + start_weapon = 0; + } + else if (strcasecmp (w1, "start_armor") == 0) + { + start_armor = atoi (w2); + if (start_armor < 0) + start_armor = 0; + } + else if (strcasecmp (w1, "unknown_char_name") == 0) + { + strcpy (unknown_char_name, w2); + unknown_char_name[24] = 0; + } + else if (strcasecmp (w1, "char_log_filename") == 0) + { + strcpy (char_log_filename, w2); + } + else if (strcasecmp (w1, "name_ignoring_case") == 0) + { + name_ignoring_case = config_switch (w2); + } + else if (strcasecmp (w1, "char_name_option") == 0) + { + char_name_option = atoi (w2); + } + else if (strcasecmp (w1, "char_name_letters") == 0) + { + strcpy (char_name_letters, w2); +// online files options + } + else if (strcasecmp (w1, "online_txt_filename") == 0) + { + strcpy (online_txt_filename, w2); + } + else if (strcasecmp (w1, "online_html_filename") == 0) + { + strcpy (online_html_filename, w2); + } + else if (strcasecmp (w1, "online_sorting_option") == 0) + { + online_sorting_option = atoi (w2); + } + else if (strcasecmp (w1, "online_display_option") == 0) + { + online_display_option = atoi (w2); + } + else if (strcasecmp (w1, "online_gm_display_min_level") == 0) + { // minimum GM level to display 'GM' when we want to display it + online_gm_display_min_level = atoi (w2); + if (online_gm_display_min_level < 5) // send online file every 5 seconds to player is enough + online_gm_display_min_level = 5; + } + else if (strcasecmp (w1, "online_refresh_html") == 0) + { + online_refresh_html = atoi (w2); + if (online_refresh_html < 1) + online_refresh_html = 1; + } + else if (strcasecmp (w1, "anti_freeze_enable") == 0) + { + anti_freeze_enable = config_switch (w2); + } + else if (strcasecmp (w1, "anti_freeze_interval") == 0) + { + ANTI_FREEZE_INTERVAL = atoi (w2); + if (ANTI_FREEZE_INTERVAL < 5) + ANTI_FREEZE_INTERVAL = 5; // minimum 5 seconds + } + else if (strcasecmp (w1, "import") == 0) + { + char_config_read (w2); + } + } + fclose_ (fp); + + return 0; +} + +void term_func (void) +{ + int i; + + // write online players files with no player + for (i = 0; i < char_num; i++) + online_chars[i] = -1; + create_online_files (); + free (online_chars); + + mmo_char_sync (); + inter_save (); + + if (gm_account != NULL) + free (gm_account); + + free (char_dat); + delete_session (login_fd); + delete_session (char_fd); + + char_log ("----End of char-server (normal end with closing of all files).\n"); +} + +int do_init (int argc, char **argv) +{ + int i; + + // a newline in the log... + char_log (""); + char_log ("The char-server starting...\n"); + + char_config_read ((argc < 2) ? CHAR_CONF_NAME : argv[1]); + lan_config_read ((argc > 1) ? argv[1] : LOGIN_LAN_CONF_NAME); + + login_ip = inet_addr (login_ip_str); + char_ip = inet_addr (char_ip_str); + + for (i = 0; i < MAX_MAP_SERVERS; i++) + { + memset (&server[i], 0, sizeof (struct mmo_map_server)); + server_fd[i] = -1; + } + + mmo_char_init (); + + update_online = time (NULL); + create_online_files (); // update online players files at start of the server + + inter_init ((argc > 2) ? argv[2] : inter_cfgName); // inter server 初期化 + +// set_termfunc (do_final); + set_defaultparse (parse_char); + + char_fd = make_listen_port (char_port); + +// add_timer_func_list (check_connect_login_server, "check_connect_login_server"); +// add_timer_func_list (send_users_tologin, "send_users_tologin"); +// add_timer_func_list (mmo_char_sync_timer, "mmo_char_sync_timer"); + + i = add_timer_interval (gettick () + 1000, check_connect_login_server, 0, + 0, 10 * 1000); + i = add_timer_interval (gettick () + 1000, send_users_tologin, 0, 0, + 5 * 1000); + i = add_timer_interval (gettick () + autosave_interval, + mmo_char_sync_timer, 0, 0, autosave_interval); + + if (anti_freeze_enable > 0) + { +// add_timer_func_list (map_anti_freeze_system, "map_anti_freeze_system"); + i = add_timer_interval (gettick () + 1000, map_anti_freeze_system, 0, 0, ANTI_FREEZE_INTERVAL * 1000); // checks every X seconds user specifies + } + + char_log ("The char-server is ready (Server is listening on the port %d).\n", + char_port); + + printf + ("The char-server is \033[1;32mready\033[0m (Server is listening on the port %d).\n\n", + char_port); + + return 0; +} diff --git a/src/char/char.h b/src/char/char.h deleted file mode 100644 index cc64024..0000000 --- a/src/char/char.h +++ /dev/null @@ -1,32 +0,0 @@ -// $Id: char.h,v 1.1.1.1 2004/09/10 17:26:50 MagicalTux Exp $ -#ifndef _CHAR_H_ -#define _CHAR_H_ - -#define MAX_MAP_SERVERS 30 - -#define CHAR_CONF_NAME "conf/char_athena.conf" - -#define LOGIN_LAN_CONF_NAME "conf/lan_support.conf" - -#define DEFAULT_AUTOSAVE_INTERVAL 300*1000 - -struct mmo_map_server -{ - long ip; - short port; - int users; - char map[MAX_MAP_PER_SERVER][16]; -}; - -int search_character_index (char *character_name); -char *search_character_name (int index); - -int mapif_sendall (char *buf, unsigned int len); -int mapif_sendallwos (int fd, unsigned char *buf, unsigned int len); -int mapif_send (int fd, unsigned char *buf, unsigned int len); - -int char_log (char *fmt, ...); - -extern int autosave_interval; - -#endif diff --git a/src/char/char.hpp b/src/char/char.hpp new file mode 100644 index 0000000..22b7678 --- /dev/null +++ b/src/char/char.hpp @@ -0,0 +1,32 @@ +// $Id: char.h,v 1.1.1.1 2004/09/10 17:26:50 MagicalTux Exp $ +#ifndef CHAR_HPP +#define CHAR_HPP + +#define MAX_MAP_SERVERS 30 + +#define CHAR_CONF_NAME "conf/char_athena.conf" + +#define LOGIN_LAN_CONF_NAME "conf/lan_support.conf" + +#define DEFAULT_AUTOSAVE_INTERVAL 300*1000 + +struct mmo_map_server +{ + long ip; + short port; + int users; + char map[MAX_MAP_PER_SERVER][16]; +}; + +int search_character_index (char *character_name); +char *search_character_name (int index); + +int mapif_sendall (char *buf, unsigned int len); +int mapif_sendallwos (int fd, unsigned char *buf, unsigned int len); +int mapif_send (int fd, unsigned char *buf, unsigned int len); + +int char_log (char *fmt, ...); + +extern int autosave_interval; + +#endif diff --git a/src/char/int_guild.c b/src/char/int_guild.c deleted file mode 100644 index 05aae6b..0000000 --- a/src/char/int_guild.c +++ /dev/null @@ -1,1757 +0,0 @@ -// $Id: int_guild.c,v 1.2 2004/09/25 19:36:53 Akitasha Exp $ -#include "inter.h" -#include "int_guild.h" -#include "int_storage.h" -#include "../common/mmo.h" -#include "char.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/lock.h" - -#include -#include -#include - -char guild_txt[1024] = "save/guild.txt"; -char castle_txt[1024] = "save/castle.txt"; - -static struct dbt *guild_db; -static struct dbt *castle_db; - -static int guild_newid = 10000; - -static int guild_exp[100]; - -int mapif_parse_GuildLeave (int fd, int guild_id, int account_id, - int char_id, int flag, const char *mes); -int mapif_guild_broken (int guild_id, int flag); -int guild_check_empty (struct guild *g); -int guild_calcinfo (struct guild *g); -int mapif_guild_basicinfochanged (int guild_id, int type, const void *data, - int len); -int mapif_guild_info (int fd, struct guild *g); -void guild_break_sub (db_key_t key, db_val_t data, va_list ap); - -// ギルドデータの文字列への変換 -int inter_guild_tostr (char *str, struct guild *g) -{ - int i, c, len; - - // 基本データ - len = sprintf (str, "%d\t%s\t%s\t%d,%d,%d,%d,%d\t%s#\t%s#\t", - g->guild_id, g->name, g->master, - g->guild_lv, g->max_member, g->exp, g->skill_point, - g->castle_id, g->mes1, g->mes2); - // メンバー - for (i = 0; i < g->max_member; i++) - { - struct guild_member *m = &g->member[i]; - len += sprintf (str + len, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\t%s\t", - m->account_id, m->char_id, - m->hair, m->hair_color, m->gender, - m->pc_class, m->lv, m->exp, m->exp_payper, m->position, - ((m->account_id > 0) ? m->name : "-")); - } - // 役職 - for (i = 0; i < MAX_GUILDPOSITION; i++) - { - struct guild_position *p = &g->position[i]; - len += - sprintf (str + len, "%d,%d\t%s#\t", p->mode, p->exp_mode, - p->name); - } - // エンブレム - len += sprintf (str + len, "%d,%d,", g->emblem_len, g->emblem_id); - for (i = 0; i < g->emblem_len; i++) - { - len += - sprintf (str + len, "%02x", (unsigned char) (g->emblem_data[i])); - } - len += sprintf (str + len, "$\t"); - // 同盟リスト - c = 0; - for (i = 0; i < MAX_GUILDALLIANCE; i++) - if (g->alliance[i].guild_id > 0) - c++; - len += sprintf (str + len, "%d\t", c); - for (i = 0; i < MAX_GUILDALLIANCE; i++) - { - struct guild_alliance *a = &g->alliance[i]; - if (a->guild_id > 0) - len += - sprintf (str + len, "%d,%d\t%s\t", a->guild_id, a->opposition, - a->name); - } - // 追放リスト - c = 0; - for (i = 0; i < MAX_GUILDEXPLUSION; i++) - if (g->explusion[i].account_id > 0) - c++; - len += sprintf (str + len, "%d\t", c); - for (i = 0; i < MAX_GUILDEXPLUSION; i++) - { - struct guild_explusion *e = &g->explusion[i]; - if (e->account_id > 0) - len += sprintf (str + len, "%d,%d,%d,%d\t%s\t%s\t%s#\t", - e->account_id, e->rsv1, e->rsv2, e->rsv3, - e->name, e->acc, e->mes); - } - // ギルドスキル - for (i = 0; i < MAX_GUILDSKILL; i++) - { - len += sprintf (str + len, "%d,%d ", g->skill[i].id, g->skill[i].lv); - } - len += sprintf (str + len, "\t"); - - return 0; -} - -// ギルドデータの文字列からの変換 -int inter_guild_fromstr (char *str, struct guild *g) -{ - int i, j, c; - int tmp_int[16]; - char tmp_str[4][256]; - char tmp_str2[4096]; - char *pstr; - - // 基本データ - memset (g, 0, sizeof (struct guild)); - if (sscanf - (str, "%d\t%[^\t]\t%[^\t]\t%d,%d,%d,%d,%d\t%[^\t]\t%[^\t]\t", - &tmp_int[0], tmp_str[0], tmp_str[1], &tmp_int[1], &tmp_int[2], - &tmp_int[3], &tmp_int[4], &tmp_int[5], tmp_str[2], tmp_str[3]) < 8) - return 1; - - g->guild_id = tmp_int[0]; - g->guild_lv = tmp_int[1]; - g->max_member = tmp_int[2]; - g->exp = tmp_int[3]; - g->skill_point = tmp_int[4]; - g->castle_id = tmp_int[5]; - memcpy (g->name, tmp_str[0], 24); - memcpy (g->master, tmp_str[1], 24); - memcpy (g->mes1, tmp_str[2], 60); - memcpy (g->mes2, tmp_str[3], 120); - g->mes1[strlen (g->mes1) - 1] = 0; - g->mes2[strlen (g->mes2) - 1] = 0; - - for (j = 0; j < 6 && str != NULL; j++) // 位置スキップ - str = strchr (str + 1, '\t'); -// printf("GuildBaseInfo OK\n"); - - // メンバー - for (i = 0; i < g->max_member; i++) - { - struct guild_member *m = &g->member[i]; - if (sscanf (str + 1, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\t%[^\t]\t", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], &tmp_int[7], - &tmp_int[8], &tmp_int[9], tmp_str[0]) < 11) - return 1; - m->account_id = tmp_int[0]; - m->char_id = 0 /*tmp_int[1]*/; - m->hair = tmp_int[2]; - m->hair_color = tmp_int[3]; - m->gender = tmp_int[4]; - m->pc_class = tmp_int[5]; - m->lv = tmp_int[6]; - m->exp = tmp_int[7]; - m->exp_payper = tmp_int[8]; - m->position = tmp_int[9]; - memcpy (m->name, tmp_str[0], 24); - - for (j = 0; j < 2 && str != NULL; j++) // 位置スキップ - str = strchr (str + 1, '\t'); - } -// printf("GuildMemberInfo OK\n"); - // 役職 - i = 0; - while (sscanf (str + 1, "%d,%d%n", &tmp_int[0], &tmp_int[1], &j) == 2 - && str[1 + j] == '\t') - { - struct guild_position *p = &g->position[i]; - if (sscanf - (str + 1, "%d,%d\t%[^\t]\t", &tmp_int[0], &tmp_int[1], - tmp_str[0]) < 3) - return 1; - p->mode = tmp_int[0]; - p->exp_mode = tmp_int[1]; - tmp_str[0][strlen (tmp_str[0]) - 1] = 0; - memcpy (p->name, tmp_str[0], 24); - - for (j = 0; j < 2 && str != NULL; j++) // 位置スキップ - str = strchr (str + 1, '\t'); - i++; - } -// printf("GuildPositionInfo OK\n"); - // エンブレム - tmp_int[1] = 0; - if (sscanf (str + 1, "%d,%d,%[^\t]\t", &tmp_int[0], &tmp_int[1], tmp_str2) - < 3 && sscanf (str + 1, "%d,%[^\t]\t", &tmp_int[0], tmp_str2) < 2) - return 1; - g->emblem_len = tmp_int[0]; - g->emblem_id = tmp_int[1]; - for (i = 0, pstr = tmp_str2; i < g->emblem_len; i++, pstr += 2) - { - int c1 = pstr[0], c2 = pstr[1], x1 = 0, x2 = 0; - if (c1 >= '0' && c1 <= '9') - x1 = c1 - '0'; - if (c1 >= 'a' && c1 <= 'f') - x1 = c1 - 'a' + 10; - if (c1 >= 'A' && c1 <= 'F') - x1 = c1 - 'A' + 10; - if (c2 >= '0' && c2 <= '9') - x2 = c2 - '0'; - if (c2 >= 'a' && c2 <= 'f') - x2 = c2 - 'a' + 10; - if (c2 >= 'A' && c2 <= 'F') - x2 = c2 - 'A' + 10; - g->emblem_data[i] = (x1 << 4) | x2; - } -// printf("GuildEmblemInfo OK\n"); - str = strchr (str + 1, '\t'); // 位置スキップ - - // 同盟リスト - if (sscanf (str + 1, "%d\t", &c) < 1) - return 1; - str = strchr (str + 1, '\t'); // 位置スキップ - for (i = 0; i < c; i++) - { - struct guild_alliance *a = &g->alliance[i]; - if (sscanf - (str + 1, "%d,%d\t%[^\t]\t", &tmp_int[0], &tmp_int[1], - tmp_str[0]) < 3) - return 1; - a->guild_id = tmp_int[0]; - a->opposition = tmp_int[1]; - memcpy (a->name, tmp_str[0], 24); - - for (j = 0; j < 2 && str != NULL; j++) // 位置スキップ - str = strchr (str + 1, '\t'); - } -// printf("GuildAllianceInfo OK\n"); - // 追放リスト - if (sscanf (str + 1, "%d\t", &c) < 1) - return 1; - str = strchr (str + 1, '\t'); // 位置スキップ - for (i = 0; i < c; i++) - { - struct guild_explusion *e = &g->explusion[i]; - if (sscanf (str + 1, "%d,%d,%d,%d\t%[^\t]\t%[^\t]\t%[^\t]\t", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - tmp_str[0], tmp_str[1], tmp_str[2]) < 6) - return 1; - e->account_id = tmp_int[0]; - e->rsv1 = tmp_int[1]; - e->rsv2 = tmp_int[2]; - e->rsv3 = tmp_int[3]; - memcpy (e->name, tmp_str[0], 24); - memcpy (e->acc, tmp_str[1], 24); - tmp_str[2][strlen (tmp_str[2]) - 1] = 0; - memcpy (e->mes, tmp_str[2], 40); - - for (j = 0; j < 4 && str != NULL; j++) // 位置スキップ - str = strchr (str + 1, '\t'); - } -// printf("GuildExplusionInfo OK\n"); - // ギルドスキル - for (i = 0; i < MAX_GUILDSKILL; i++) - { - if (sscanf (str + 1, "%d,%d ", &tmp_int[0], &tmp_int[1]) < 2) - break; - g->skill[i].id = tmp_int[0]; - g->skill[i].lv = tmp_int[1]; - str = strchr (str + 1, ' '); - } - str = strchr (str + 1, '\t'); -// printf("GuildSkillInfo OK\n"); - - return 0; -} - -// ギルド城データの文字列への変換 -int inter_guildcastle_tostr (char *str, struct guild_castle *gc) -{ - int len; - - len = sprintf (str, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", // added Guardian HP [Valaris] - gc->castle_id, gc->guild_id, gc->economy, gc->defense, - gc->triggerE, gc->triggerD, gc->nextTime, gc->payTime, - gc->createTime, gc->visibleC, gc->visibleG0, gc->visibleG1, - gc->visibleG2, gc->visibleG3, gc->visibleG4, gc->visibleG5, - gc->visibleG6, gc->visibleG7, gc->Ghp0, gc->Ghp1, gc->Ghp2, - gc->Ghp3, gc->Ghp4, gc->Ghp5, gc->Ghp6, gc->Ghp7); - - return 0; -} - -// ギルド城データの文字列からの変換 -int inter_guildcastle_fromstr (char *str, struct guild_castle *gc) -{ - int tmp_int[26]; - - memset (gc, 0, sizeof (struct guild_castle)); - // new structure of guild castle - if (sscanf - (str, - "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], &tmp_int[4], - &tmp_int[5], &tmp_int[6], &tmp_int[7], &tmp_int[8], &tmp_int[9], - &tmp_int[10], &tmp_int[11], &tmp_int[12], &tmp_int[13], &tmp_int[14], - &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], &tmp_int[19], - &tmp_int[20], &tmp_int[21], &tmp_int[22], &tmp_int[23], &tmp_int[24], - &tmp_int[25]) == 26) - { - gc->castle_id = tmp_int[0]; - gc->guild_id = tmp_int[1]; - gc->economy = tmp_int[2]; - gc->defense = tmp_int[3]; - gc->triggerE = tmp_int[4]; - gc->triggerD = tmp_int[5]; - gc->nextTime = tmp_int[6]; - gc->payTime = tmp_int[7]; - gc->createTime = tmp_int[8]; - gc->visibleC = tmp_int[9]; - gc->visibleG0 = tmp_int[10]; - gc->visibleG1 = tmp_int[11]; - gc->visibleG2 = tmp_int[12]; - gc->visibleG3 = tmp_int[13]; - gc->visibleG4 = tmp_int[14]; - gc->visibleG5 = tmp_int[15]; - gc->visibleG6 = tmp_int[16]; - gc->visibleG7 = tmp_int[17]; - gc->Ghp0 = tmp_int[18]; - gc->Ghp1 = tmp_int[19]; - gc->Ghp2 = tmp_int[20]; - gc->Ghp3 = tmp_int[21]; - gc->Ghp4 = tmp_int[22]; - gc->Ghp5 = tmp_int[23]; - gc->Ghp6 = tmp_int[24]; - gc->Ghp7 = tmp_int[25]; // end additions [Valaris] - // old structure of guild castle - } - else if (sscanf - (str, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], &tmp_int[4], - &tmp_int[5], &tmp_int[6], &tmp_int[7], &tmp_int[8], &tmp_int[9], - &tmp_int[10], &tmp_int[11], &tmp_int[12], &tmp_int[13], - &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17]) == 18) - { - gc->castle_id = tmp_int[0]; - gc->guild_id = tmp_int[1]; - gc->economy = tmp_int[2]; - gc->defense = tmp_int[3]; - gc->triggerE = tmp_int[4]; - gc->triggerD = tmp_int[5]; - gc->nextTime = tmp_int[6]; - gc->payTime = tmp_int[7]; - gc->createTime = tmp_int[8]; - gc->visibleC = tmp_int[9]; - gc->visibleG0 = tmp_int[10]; - gc->visibleG1 = tmp_int[11]; - gc->visibleG2 = tmp_int[12]; - gc->visibleG3 = tmp_int[13]; - gc->visibleG4 = tmp_int[14]; - gc->visibleG5 = tmp_int[15]; - gc->visibleG6 = tmp_int[16]; - gc->visibleG7 = tmp_int[17]; - if (gc->visibleG0 == 1) - gc->Ghp0 = 15670 + 2000 * gc->defense; - else - gc->Ghp0 = 0; - if (gc->visibleG1 == 1) - gc->Ghp1 = 15670 + 2000 * gc->defense; - else - gc->Ghp1 = 0; - if (gc->visibleG2 == 1) - gc->Ghp2 = 15670 + 2000 * gc->defense; - else - gc->Ghp2 = 0; - if (gc->visibleG3 == 1) - gc->Ghp3 = 30214 + 2000 * gc->defense; - else - gc->Ghp3 = 0; - if (gc->visibleG4 == 1) - gc->Ghp4 = 30214 + 2000 * gc->defense; - else - gc->Ghp4 = 0; - if (gc->visibleG5 == 1) - gc->Ghp5 = 28634 + 2000 * gc->defense; - else - gc->Ghp5 = 0; - if (gc->visibleG6 == 1) - gc->Ghp6 = 28634 + 2000 * gc->defense; - else - gc->Ghp6 = 0; - if (gc->visibleG7 == 1) - gc->Ghp7 = 28634 + 2000 * gc->defense; - else - gc->Ghp7 = 0; - } - else - { - return 1; - } - - return 0; -} - -// ギルド関連データベース読み込み -int inter_guild_readdb (void) -{ - int i; - FILE *fp; - char line[1024]; - - fp = fopen_ ("db/exp_guild.txt", "r"); - if (fp == NULL) - { - printf ("can't read db/exp_guild.txt\n"); - return 1; - } - i = 0; - while (fgets (line, sizeof (line) - 1, fp) && i < 100) - { - if (line[0] == '/' && line[1] == '/') - continue; - guild_exp[i] = atoi (line); - i++; - } - fclose_ (fp); - - return 0; -} - -// ギルドデータの読み込み -int inter_guild_init (void) -{ - char line[16384]; - struct guild *g; - struct guild_castle *gc; - FILE *fp; - int i, j, c = 0; - - inter_guild_readdb (); - - guild_db = numdb_init (); - castle_db = numdb_init (); - - if ((fp = fopen_ (guild_txt, "r")) == NULL) - return 1; - while (fgets (line, sizeof (line) - 1, fp)) - { - j = 0; - if (sscanf (line, "%d\t%%newid%%\n%n", &i, &j) == 1 && j > 0 - && guild_newid <= i) - { - guild_newid = i; - continue; - } - CREATE (g, struct guild, 1); - if (inter_guild_fromstr (line, g) == 0 && g->guild_id > 0) - { - if (g->guild_id >= guild_newid) - guild_newid = g->guild_id + 1; - numdb_insert (guild_db, g->guild_id, g); - guild_check_empty (g); - guild_calcinfo (g); - } - else - { - printf ("int_guild: broken data [%s] line %d\n", guild_txt, c); - free (g); - } - c++; - } - fclose_ (fp); -// printf("int_guild: %s read done (%d guilds)\n", guild_txt, c); - - c = 0; //カウンタ初期化 - - if ((fp = fopen_ (castle_txt, "r")) == NULL) - { - return 1; - } - - while (fgets (line, sizeof (line) - 1, fp)) - { - CREATE (gc, struct guild_castle, 1); - if (inter_guildcastle_fromstr (line, gc) == 0) - { - numdb_insert (castle_db, gc->castle_id, gc); - } - else - { - printf ("int_guild: broken data [%s] line %d\n", castle_txt, c); - free (gc); - } - c++; - } - - if (!c) - { - printf (" %s - making Default Data...\n", castle_txt); - //デフォルトデータを作成 - for (i = 0; i < MAX_GUILDCASTLE; i++) - { - CREATE (gc, struct guild_castle, 1); - gc->castle_id = i; - gc->guild_id = 0; - gc->economy = 0; - gc->defense = 0; - gc->triggerE = 0; - gc->triggerD = 0; - gc->nextTime = 0; - gc->payTime = 0; - gc->createTime = 0; - gc->visibleC = 0; - gc->visibleG0 = 0; - gc->visibleG1 = 0; - gc->visibleG2 = 0; - gc->visibleG3 = 0; - gc->visibleG4 = 0; - gc->visibleG5 = 0; - gc->visibleG6 = 0; - gc->visibleG7 = 0; - gc->Ghp0 = 0; // guardian HP [Valaris] - gc->Ghp1 = 0; - gc->Ghp2 = 0; - gc->Ghp3 = 0; - gc->Ghp4 = 0; - gc->Ghp5 = 0; - gc->Ghp6 = 0; - gc->Ghp7 = 0; // end additions [Valaris] - numdb_insert (castle_db, gc->castle_id, gc); - } - printf (" %s - making done\n", castle_txt); - return 0; - } - - fclose_ (fp); - - return 0; -} - -struct guild *inter_guild_search (int guild_id) -{ - struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); - - return g; -} - -// ギルドデータのセーブ用 -void inter_guild_save_sub (db_key_t key, db_val_t data, va_list ap) -{ - char line[16384]; - FILE *fp; - - inter_guild_tostr (line, (struct guild *) data); - fp = va_arg (ap, FILE *); - fprintf (fp, "%s\n", line); -} - -// ギルド城データのセーブ用 -void inter_castle_save_sub (db_key_t key, db_val_t data, va_list ap) -{ - char line[16384]; - FILE *fp; - - inter_guildcastle_tostr (line, (struct guild_castle *) data); - fp = va_arg (ap, FILE *); - fprintf (fp, "%s\n", line); -} - -// ギルドデータのセーブ -int inter_guild_save (void) -{ - FILE *fp; - int lock; - - if ((fp = lock_fopen (guild_txt, &lock)) == NULL) - { - printf ("int_guild: cant write [%s] !!! data is lost !!!\n", - guild_txt); - return 1; - } - numdb_foreach (guild_db, inter_guild_save_sub, fp); -// fprintf(fp, "%d\t%%newid%%\n", guild_newid); - lock_fclose (fp, guild_txt, &lock); -// printf("int_guild: %s saved.\n", guild_txt); - - if ((fp = lock_fopen (castle_txt, &lock)) == NULL) - { - printf ("int_guild: cant write [%s] !!! data is lost !!!\n", - castle_txt); - return 1; - } - numdb_foreach (castle_db, inter_castle_save_sub, fp); - lock_fclose (fp, castle_txt, &lock); - - return 0; -} - -// ギルド名検索用 -void search_guildname_sub (db_key_t key, db_val_t data, va_list ap) -{ - struct guild *g = (struct guild *) data, **dst; - char *str; - - str = va_arg (ap, char *); - dst = va_arg (ap, struct guild **); - if (strcasecmp (g->name, str) == 0) - *dst = g; -} - -// ギルド名検索 -struct guild *search_guildname (char *str) -{ - struct guild *g = NULL; - numdb_foreach (guild_db, search_guildname_sub, str, &g); - return g; -} - -// ギルドが空かどうかチェック -int guild_check_empty (struct guild *g) -{ - int i; - - for (i = 0; i < g->max_member; i++) - { - if (g->member[i].account_id > 0) - { - return 0; - } - } - // 誰もいないので解散 - numdb_foreach (guild_db, guild_break_sub, g->guild_id); - numdb_erase (guild_db, g->guild_id); - inter_guild_storage_delete (g->guild_id); - mapif_guild_broken (g->guild_id, 0); - free (g); - - return 1; -} - -// キャラの競合がないかチェック用 -void guild_check_conflict_sub (db_key_t key, db_val_t data, va_list ap) -{ - struct guild *g = (struct guild *) data; - int guild_id, account_id, char_id, i; - - guild_id = va_arg (ap, int); - account_id = va_arg (ap, int); - char_id = va_arg (ap, int); - - if (g->guild_id == guild_id) // 本来の所属なので問題なし - return; - - for (i = 0; i < MAX_GUILD; i++) - { - if (g->member[i].account_id == account_id) - { - // 別のギルドに偽の所属データがあるので脱退 - printf ("int_guild: guild conflict! %d,%d %d!=%d\n", account_id, - char_id, guild_id, g->guild_id); - mapif_parse_GuildLeave (-1, g->guild_id, account_id, 0 /*char_id*/, 0, - "**データ競合**"); - } - } -} - -// キャラの競合がないかチェック -int guild_check_conflict (int guild_id, int account_id, int char_id) -{ - numdb_foreach (guild_db, guild_check_conflict_sub, guild_id, account_id, - 0 /*char_id*/); - - return 0; -} - -int guild_nextexp (int level) -{ - if (level < 100) - return guild_exp[level - 1]; - - return 0; -} - -// ギルドスキルがあるか確認 -int guild_checkskill (struct guild *g, int id) -{ - return g->skill[id - 10000].lv; -} - -// ギルドの情報の再計算 -int guild_calcinfo (struct guild *g) -{ - int i, c, nextexp; - struct guild before = *g; - - // スキルIDの設定 - for (i = 0; i < 5; i++) - g->skill[i].id = i + 10000; - - // ギルドレベル - if (g->guild_lv <= 0) - g->guild_lv = 1; - nextexp = guild_nextexp (g->guild_lv); - if (nextexp > 0) - { - while (g->exp >= nextexp) - { // レベルアップ処理 - g->exp -= nextexp; - g->guild_lv++; - g->skill_point++; - nextexp = guild_nextexp (g->guild_lv); - } - } - - // ギルドの次の経験値 - g->next_exp = guild_nextexp (g->guild_lv); - - // メンバ上限(ギルド拡張適用) - g->max_member = 100 + guild_checkskill (g, 10004) * 2; - - // 平均レベルとオンライン人数 - g->average_lv = 0; - g->connect_member = 0; - c = 0; - for (i = 0; i < g->max_member; i++) - { - if (g->member[i].account_id > 0) - { - g->average_lv += g->member[i].lv; - c++; - if (g->member[i].online > 0) - g->connect_member++; - } - } - g->average_lv /= c; - - // 全データを送る必要がありそう - if (g->max_member != before.max_member || - g->guild_lv != before.guild_lv || - g->skill_point != before.skill_point) - { - mapif_guild_info (-1, g); - return 1; - } - - return 0; -} - -//------------------------------------------------------------------- -// map serverへの通信 - -// ギルド作成可否 -int mapif_guild_created (int fd, int account_id, struct guild *g) -{ - WFIFOW (fd, 0) = 0x3830; - WFIFOL (fd, 2) = account_id; - if (g != NULL) - { - WFIFOL (fd, 6) = g->guild_id; - printf ("int_guild: created! %d %s\n", g->guild_id, g->name); - } - else - { - WFIFOL (fd, 6) = 0; - } - WFIFOSET (fd, 10); - return 0; -} - -// ギルド情報見つからず -int mapif_guild_noinfo (int fd, int guild_id) -{ - WFIFOW (fd, 0) = 0x3831; - WFIFOW (fd, 2) = 8; - WFIFOL (fd, 4) = guild_id; - WFIFOSET (fd, 8); - printf ("int_guild: info not found %d\n", guild_id); - - return 0; -} - -// ギルド情報まとめ送り -int mapif_guild_info (int fd, struct guild *g) -{ - unsigned char buf[4 + sizeof (struct guild)]; - - WBUFW (buf, 0) = 0x3831; - memcpy (buf + 4, g, sizeof (struct guild)); - WBUFW (buf, 2) = 4 + sizeof (struct guild); -// printf("int_guild: sizeof(guild)=%d\n", sizeof(struct guild)); - if (fd < 0) - mapif_sendall (buf, WBUFW (buf, 2)); - else - mapif_send (fd, buf, WBUFW (buf, 2)); -// printf("int_guild: info %d %s\n", p->guild_id, p->name); - - return 0; -} - -// メンバ追加可否 -int mapif_guild_memberadded (int fd, int guild_id, int account_id, - int char_id, int flag) -{ - WFIFOW (fd, 0) = 0x3832; - WFIFOL (fd, 2) = guild_id; - WFIFOL (fd, 6) = account_id; - WFIFOL (fd, 10) = 0 /*char_id*/; - WFIFOB (fd, 14) = flag; - WFIFOSET (fd, 15); - - return 0; -} - -// 脱退/追放通知 -int mapif_guild_leaved (int guild_id, int account_id, int char_id, int flag, - const char *name, const char *mes) -{ - unsigned char buf[79]; - - WBUFW (buf, 0) = 0x3834; - WBUFL (buf, 2) = guild_id; - WBUFL (buf, 6) = account_id; - WBUFL (buf, 10) = 0 /*char_id*/; - WBUFB (buf, 14) = flag; - memcpy (WBUFP (buf, 15), mes, 40); - memcpy (WBUFP (buf, 55), name, 24); - mapif_sendall (buf, 79); - printf ("int_guild: guild leaved %d %d %s %s\n", guild_id, account_id, - name, mes); - - return 0; -} - -// オンライン状態とLv更新通知 -int mapif_guild_memberinfoshort (struct guild *g, int idx) -{ - unsigned char buf[19]; - - WBUFW (buf, 0) = 0x3835; - WBUFL (buf, 2) = g->guild_id; - WBUFL (buf, 6) = g->member[idx].account_id; - WBUFL (buf, 10) = 0 /*g->member[idx].char_id*/; - WBUFB (buf, 14) = g->member[idx].online; - WBUFW (buf, 15) = g->member[idx].lv; - WBUFW (buf, 17) = g->member[idx].pc_class; - mapif_sendall (buf, 19); - return 0; -} - -// 解散通知 -int mapif_guild_broken (int guild_id, int flag) -{ - unsigned char buf[7]; - - WBUFW (buf, 0) = 0x3836; - WBUFL (buf, 2) = guild_id; - WBUFB (buf, 6) = flag; - mapif_sendall (buf, 7); - printf ("int_guild: broken %d\n", guild_id); - - return 0; -} - -// ギルド内発言 -int mapif_guild_message (int guild_id, int account_id, char *mes, int len) -{ - unsigned char buf[len + 12]; - - WBUFW (buf, 0) = 0x3837; - WBUFW (buf, 2) = len + 12; - WBUFL (buf, 4) = guild_id; - WBUFL (buf, 8) = account_id; - memcpy (WBUFP (buf, 12), mes, len); - mapif_sendall (buf, len + 12); - - return 0; -} - -// ギルド基本情報変更通知 -int mapif_guild_basicinfochanged (int guild_id, int type, const void *data, - int len) -{ - unsigned char buf[2048]; - - WBUFW (buf, 0) = 0x3839; - WBUFW (buf, 2) = len + 10; - WBUFL (buf, 4) = guild_id; - WBUFW (buf, 8) = type; - memcpy (WBUFP (buf, 10), data, len); - mapif_sendall (buf, len + 10); - return 0; -} - -// ギルドメンバ情報変更通知 -int mapif_guild_memberinfochanged (int guild_id, int account_id, int char_id, - int type, const void *data, int len) -{ - unsigned char buf[len + 18]; - - WBUFW (buf, 0) = 0x383a; - WBUFW (buf, 2) = len + 18; - WBUFL (buf, 4) = guild_id; - WBUFL (buf, 8) = account_id; - WBUFL (buf, 12) = 0 /*char_id*/; - WBUFW (buf, 16) = type; - memcpy (WBUFP (buf, 18), data, len); - mapif_sendall (buf, len + 18); - - return 0; -} - -// ギルドスキルアップ通知 -int mapif_guild_skillupack (int guild_id, int skill_num, int account_id) -{ - unsigned char buf[14]; - - WBUFW (buf, 0) = 0x383c; - WBUFL (buf, 2) = guild_id; - WBUFL (buf, 6) = skill_num; - WBUFL (buf, 10) = account_id; - mapif_sendall (buf, 14); - - return 0; -} - -// ギルド同盟/敵対通知 -int mapif_guild_alliance (int guild_id1, int guild_id2, int account_id1, - int account_id2, int flag, const char *name1, - const char *name2) -{ - unsigned char buf[67]; - - WBUFW (buf, 0) = 0x383d; - WBUFL (buf, 2) = guild_id1; - WBUFL (buf, 6) = guild_id2; - WBUFL (buf, 10) = account_id1; - WBUFL (buf, 14) = account_id2; - WBUFB (buf, 18) = flag; - memcpy (WBUFP (buf, 19), name1, 24); - memcpy (WBUFP (buf, 43), name2, 24); - mapif_sendall (buf, 67); - - return 0; -} - -// ギルド役職変更通知 -int mapif_guild_position (struct guild *g, int idx) -{ - unsigned char buf[sizeof (struct guild_position) + 12]; - - WBUFW (buf, 0) = 0x383b; - WBUFW (buf, 2) = sizeof (struct guild_position) + 12; - WBUFL (buf, 4) = g->guild_id; - WBUFL (buf, 8) = idx; - memcpy (WBUFP (buf, 12), &g->position[idx], - sizeof (struct guild_position)); - mapif_sendall (buf, WBUFW (buf, 2)); - - return 0; -} - -// ギルド告知変更通知 -int mapif_guild_notice (struct guild *g) -{ - unsigned char buf[186]; - - WBUFW (buf, 0) = 0x383e; - WBUFL (buf, 2) = g->guild_id; - memcpy (WBUFP (buf, 6), g->mes1, 60); - memcpy (WBUFP (buf, 66), g->mes2, 120); - mapif_sendall (buf, 186); - - return 0; -} - -// ギルドエンブレム変更通知 -int mapif_guild_emblem (struct guild *g) -{ - unsigned char buf[2048]; - - WBUFW (buf, 0) = 0x383f; - WBUFW (buf, 2) = g->emblem_len + 12; - WBUFL (buf, 4) = g->guild_id; - WBUFL (buf, 8) = g->emblem_id; - memcpy (WBUFP (buf, 12), g->emblem_data, g->emblem_len); - mapif_sendall (buf, WBUFW (buf, 2)); - - return 0; -} - -int mapif_guild_castle_dataload (int castle_id, int index, int value) -{ - unsigned char buf[9]; - - WBUFW (buf, 0) = 0x3840; - WBUFW (buf, 2) = castle_id; - WBUFB (buf, 4) = index; - WBUFL (buf, 5) = value; - mapif_sendall (buf, 9); - - return 0; -} - -int mapif_guild_castle_datasave (int castle_id, int index, int value) -{ - unsigned char buf[9]; - - WBUFW (buf, 0) = 0x3841; - WBUFW (buf, 2) = castle_id; - WBUFB (buf, 4) = index; - WBUFL (buf, 5) = value; - mapif_sendall (buf, 9); - - return 0; -} - -void mapif_guild_castle_alldataload_sub (db_key_t key, db_val_t data, va_list ap) -{ - int fd = va_arg (ap, int); - int *p = va_arg (ap, int *); - - memcpy (WFIFOP (fd, *p), (struct guild_castle *) data, - sizeof (struct guild_castle)); - (*p) += sizeof (struct guild_castle); -} - -int mapif_guild_castle_alldataload (int fd) -{ - int len = 4; - - WFIFOW (fd, 0) = 0x3842; - numdb_foreach (castle_db, mapif_guild_castle_alldataload_sub, fd, &len); - WFIFOW (fd, 2) = len; - WFIFOSET (fd, len); - - return 0; -} - -//------------------------------------------------------------------- -// map serverからの通信 - -// ギルド作成要求 -int mapif_parse_CreateGuild (int fd, int account_id, char *name, - struct guild_member *master) -{ - struct guild *g; - int i; - - for (i = 0; i < 24 && name[i]; i++) - { - if (!(name[i] & 0xe0) || name[i] == 0x7f) - { - printf ("int_guild: illeagal guild name [%s]\n", name); - mapif_guild_created (fd, account_id, NULL); - return 0; - } - } - - if ((g = search_guildname (name)) != NULL) - { - printf ("int_guild: same name guild exists [%s]\n", name); - mapif_guild_created (fd, account_id, NULL); - return 0; - } - CREATE (g, struct guild, 1); - g->guild_id = guild_newid++; - memcpy (g->name, name, 24); - memcpy (g->master, master->name, 24); - memcpy (&g->member[0], master, sizeof (struct guild_member)); - - g->position[0].mode = 0x11; - strcpy (g->position[0].name, "GuildMaster"); - strcpy (g->position[MAX_GUILDPOSITION - 1].name, "Newbie"); - for (i = 1; i < MAX_GUILDPOSITION - 1; i++) - sprintf (g->position[i].name, "Position %d", i + 1); - - // ここでギルド情報計算が必要と思われる - g->max_member = 100; - g->average_lv = master->lv; - for (i = 0; i < 5; i++) - g->skill[i].id = i + 10000; - - numdb_insert (guild_db, g->guild_id, g); - - mapif_guild_created (fd, account_id, g); - mapif_guild_info (fd, g); - - inter_log ("guild %s (id=%d) created by master %s (id=%d)\n", - name, g->guild_id, master->name, master->account_id); - - return 0; -} - -// ギルド情報要求 -int mapif_parse_GuildInfo (int fd, int guild_id) -{ - struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); - if (g != NULL) - { - guild_calcinfo (g); - mapif_guild_info (fd, g); - } - else - mapif_guild_noinfo (fd, guild_id); - - return 0; -} - -// ギルドメンバ追加要求 -int mapif_parse_GuildAddMember (int fd, int guild_id, struct guild_member *m) -{ - struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); - if (g == NULL) - { - mapif_guild_memberadded (fd, guild_id, m->account_id, 0 /*char_id*/, 1); - return 0; - } - - for (int i = 0; i < g->max_member; i++) - { - if (g->member[i].account_id == 0) - { - memcpy (&g->member[i], m, sizeof (struct guild_member)); - mapif_guild_memberadded (fd, guild_id, m->account_id, 0 /*char_id*/, - 0); - guild_calcinfo (g); - mapif_guild_info (-1, g); - - return 0; - } - } - mapif_guild_memberadded (fd, guild_id, m->account_id, 0 /*char_id*/, 1); - - return 0; -} - -// ギルド脱退/追放要求 -int mapif_parse_GuildLeave (int fd, int guild_id, int account_id, int char_id, - int flag, const char *mes) -{ - struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); - if (g != NULL) - { - for (int i = 0; i < MAX_GUILD; i++) - { - if (g->member[i].account_id == account_id) - { -// printf("%d %d\n", i, (int)(&g->member[i])); -// printf("%d %s\n", i, g->member[i].name); - - if (flag) - { - int j; - // 追放の場合追放リストに入れる - for (j = 0; j < MAX_GUILDEXPLUSION; j++) - { - if (g->explusion[j].account_id == 0) - break; - } - if (j == MAX_GUILDEXPLUSION) - { // 一杯なので古いのを消す - for (j = 0; j < MAX_GUILDEXPLUSION - 1; j++) - g->explusion[j] = g->explusion[j + 1]; - j = MAX_GUILDEXPLUSION - 1; - } - g->explusion[j].account_id = account_id; - memcpy (g->explusion[j].acc, "dummy", 24); - memcpy (g->explusion[j].name, g->member[i].name, 24); - memcpy (g->explusion[j].mes, mes, 40); - } - - mapif_guild_leaved (guild_id, account_id, 0 /*char_id*/, flag, - g->member[i].name, mes); -// printf("%d %d\n", i, (int)(&g->member[i])); -// printf("%d %s\n", i, (&g->member[i])->name); - memset (&g->member[i], 0, sizeof (struct guild_member)); - - if (guild_check_empty (g) == 0) - mapif_guild_info (-1, g); // まだ人がいるのでデータ送信 - - return 0; - } - } - } - return 0; -} - -// オンライン/Lv更新 -int mapif_parse_GuildChangeMemberInfoShort (int fd, int guild_id, - int account_id, int char_id, - int online, int lv, int pc_class) -{ - struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); - if (g == NULL) - return 0; - - g->connect_member = 0; - - int alv = 0; - int c = 0; - for (int i = 0; i < MAX_GUILD; i++) - { - if (g->member[i].account_id == account_id) - { - g->member[i].online = online; - g->member[i].lv = lv; - g->member[i].pc_class = pc_class; - mapif_guild_memberinfoshort (g, i); - } - if (g->member[i].account_id > 0) - { - alv += g->member[i].lv; - c++; - } - if (g->member[i].online) - g->connect_member++; - } - // 平均レベル - g->average_lv = alv / c; - - return 0; -} - -// ギルド解散処理用(同盟/敵対を解除) -void guild_break_sub (db_key_t key, db_val_t data, va_list ap) -{ - struct guild *g = (struct guild *) data; - int guild_id = va_arg (ap, int); - int i; - - for (i = 0; i < MAX_GUILDALLIANCE; i++) - { - if (g->alliance[i].guild_id == guild_id) - g->alliance[i].guild_id = 0; - } -} - -// ギルド解散要求 -int mapif_parse_BreakGuild (int fd, int guild_id) -{ - struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); - if (g == NULL) - return 0; - - numdb_foreach (guild_db, guild_break_sub, guild_id); - numdb_erase (guild_db, guild_id); - inter_guild_storage_delete (guild_id); - mapif_guild_broken (guild_id, 0); - - inter_log ("guild %s (id=%d) broken\n", g->name, guild_id); - free (g); - - return 0; -} - -// ギルドメッセージ送信 -int mapif_parse_GuildMessage (int fd, int guild_id, int account_id, char *mes, - int len) -{ - return mapif_guild_message (guild_id, account_id, mes, len); -} - -// ギルド基本データ変更要求 -int mapif_parse_GuildBasicInfoChange (int fd, int guild_id, int type, - const char *data, int len) -{ - short dw = *((short *) data); - - struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); - if (g == NULL) - return 0; - - switch (type) - { - case GBI_GUILDLV: - if (dw > 0 && g->guild_lv + dw <= 50) - { - g->guild_lv += dw; - g->skill_point += dw; - } - else if (dw < 0 && g->guild_lv + dw >= 1) - g->guild_lv += dw; - mapif_guild_info (-1, g); - return 0; - default: - printf ("int_guild: GuildBasicInfoChange: Unknown type %d\n", - type); - break; - } - mapif_guild_basicinfochanged (guild_id, type, data, len); - - return 0; -} - -// ギルドメンバデータ変更要求 -int mapif_parse_GuildMemberInfoChange (int fd, int guild_id, int account_id, - int char_id, int type, - const char *data, int len) -{ - int i; - struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); - if (g == NULL) - return 0; - - for (i = 0; i < g->max_member; i++) - if (g->member[i].account_id == account_id) - break; - if (i == g->max_member) - { - printf ("int_guild: GuildMemberChange: Not found %d,%d in %d[%s]\n", - account_id, char_id, guild_id, g->name); - return 0; - } - switch (type) - { - case GMI_POSITION: // 役職 - g->member[i].position = *((int *) data); - break; - case GMI_EXP: // EXP - { - int exp, oldexp = g->member[i].exp; - exp = g->member[i].exp = *((unsigned int *) data); - g->exp += (exp - oldexp); - guild_calcinfo (g); // Lvアップ判断 - mapif_guild_basicinfochanged (guild_id, GBI_EXP, &g->exp, 4); - } - break; - default: - printf ("int_guild: GuildMemberInfoChange: Unknown type %d\n", - type); - break; - } - mapif_guild_memberinfochanged (guild_id, account_id, char_id, type, data, - len); - - return 0; -} - -// ギルド役職名変更要求 -int mapif_parse_GuildPosition (int fd, int guild_id, int idx, - struct guild_position *p) -{ - struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); - - if (g == NULL || idx < 0 || idx >= MAX_GUILDPOSITION) - { - return 0; - } - memcpy (&g->position[idx], p, sizeof (struct guild_position)); - mapif_guild_position (g, idx); - printf ("int_guild: position changed %d\n", idx); - - return 0; -} - -// ギルドスキルアップ要求 -int mapif_parse_GuildSkillUp (int fd, int guild_id, int skill_num, - int account_id) -{ - struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); - int idx = skill_num - 10000; - - if (g == NULL || skill_num < 10000) - return 0; - - if (g->skill_point > 0 && g->skill[idx].id > 0 && g->skill[idx].lv < 10) - { - g->skill[idx].lv++; - g->skill_point--; - if (guild_calcinfo (g) == 0) - mapif_guild_info (-1, g); - mapif_guild_skillupack (guild_id, skill_num, account_id); - printf ("int_guild: skill %d up\n", skill_num); - } - - return 0; -} - -// ギルド同盟要求 -int mapif_parse_GuildAlliance (int fd, int guild_id1, int guild_id2, - int account_id1, int account_id2, int flag) -{ - struct guild *g[2]; - int j, i; - - g[0] = (struct guild *)numdb_search (guild_db, guild_id1); - g[1] = (struct guild *)numdb_search (guild_db, guild_id2); - if (g[0] == NULL || g[1] == NULL) - return 0; - - if (!(flag & 0x8)) - { - for (i = 0; i < 2 - (flag & 1); i++) - { - for (j = 0; j < MAX_GUILDALLIANCE; j++) - if (g[i]->alliance[j].guild_id == 0) - { - g[i]->alliance[j].guild_id = g[1 - i]->guild_id; - memcpy (g[i]->alliance[j].name, g[1 - i]->name, 24); - g[i]->alliance[j].opposition = flag & 1; - break; - } - } - } - else - { // 関係解消 - for (i = 0; i < 2 - (flag & 1); i++) - { - for (j = 0; j < MAX_GUILDALLIANCE; j++) - if (g[i]->alliance[j].guild_id == g[1 - i]->guild_id - && g[i]->alliance[j].opposition == (flag & 1)) - { - g[i]->alliance[j].guild_id = 0; - break; - } - } - } - mapif_guild_alliance (guild_id1, guild_id2, account_id1, account_id2, - flag, g[0]->name, g[1]->name); - - return 0; -} - -// ギルド告知変更要求 -int mapif_parse_GuildNotice (int fd, int guild_id, const char *mes1, - const char *mes2) -{ - struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); - if (g == NULL) - return 0; - memcpy (g->mes1, mes1, 60); - memcpy (g->mes2, mes2, 120); - - return mapif_guild_notice (g); -} - -// ギルドエンブレム変更要求 -int mapif_parse_GuildEmblem (int fd, int len, int guild_id, int dummy, - const char *data) -{ - struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); - if (g == NULL) - return 0; - memcpy (g->emblem_data, data, len); - g->emblem_len = len; - g->emblem_id++; - - return mapif_guild_emblem (g); -} - -int mapif_parse_GuildCastleDataLoad (int fd, int castle_id, int index) -{ - struct guild_castle *gc = (struct guild_castle *)numdb_search (castle_db, castle_id); - - if (gc == NULL) - { - return mapif_guild_castle_dataload (castle_id, 0, 0); - } - switch (index) - { - case 1: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->guild_id); - case 2: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->economy); - case 3: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->defense); - case 4: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->triggerE); - case 5: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->triggerD); - case 6: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->nextTime); - case 7: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->payTime); - case 8: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->createTime); - case 9: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->visibleC); - case 10: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->visibleG0); - case 11: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->visibleG1); - case 12: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->visibleG2); - case 13: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->visibleG3); - case 14: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->visibleG4); - case 15: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->visibleG5); - case 16: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->visibleG6); - case 17: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->visibleG7); - case 18: - return mapif_guild_castle_dataload (gc->castle_id, index, gc->Ghp0); // guardian HP [Valaris] - case 19: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->Ghp1); - case 20: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->Ghp2); - case 21: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->Ghp3); - case 22: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->Ghp4); - case 23: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->Ghp5); - case 24: - return mapif_guild_castle_dataload (gc->castle_id, index, - gc->Ghp6); - case 25: - return mapif_guild_castle_dataload (gc->castle_id, index, gc->Ghp7); // end additions [Valaris] - - default: - printf - ("mapif_parse_GuildCastleDataLoad ERROR!! (Not found index=%d)\n", - index); - return 0; - } - - return 0; -} - -int mapif_parse_GuildCastleDataSave (int fd, int castle_id, int index, - int value) -{ - struct guild_castle *gc = (struct guild_castle *)numdb_search (castle_db, castle_id); - - if (gc == NULL) - { - return mapif_guild_castle_datasave (castle_id, index, value); - } - switch (index) - { - case 1: - if (gc->guild_id != value) - { - int gid = (value) ? value : gc->guild_id; - struct guild *g = (struct guild *)numdb_search (guild_db, gid); - inter_log ("guild %s (id=%d) %s castle id=%d\n", - (g) ? g->name : "??", gid, - (value) ? "occupy" : "abandon", index); - } - gc->guild_id = value; - break; - case 2: - gc->economy = value; - break; - case 3: - gc->defense = value; - break; - case 4: - gc->triggerE = value; - break; - case 5: - gc->triggerD = value; - break; - case 6: - gc->nextTime = value; - break; - case 7: - gc->payTime = value; - break; - case 8: - gc->createTime = value; - break; - case 9: - gc->visibleC = value; - break; - case 10: - gc->visibleG0 = value; - break; - case 11: - gc->visibleG1 = value; - break; - case 12: - gc->visibleG2 = value; - break; - case 13: - gc->visibleG3 = value; - break; - case 14: - gc->visibleG4 = value; - break; - case 15: - gc->visibleG5 = value; - break; - case 16: - gc->visibleG6 = value; - break; - case 17: - gc->visibleG7 = value; - break; - case 18: - gc->Ghp0 = value; - break; // guardian HP [Valaris] - case 19: - gc->Ghp1 = value; - break; - case 20: - gc->Ghp2 = value; - break; - case 21: - gc->Ghp3 = value; - break; - case 22: - gc->Ghp4 = value; - break; - case 23: - gc->Ghp5 = value; - break; - case 24: - gc->Ghp6 = value; - break; - case 25: - gc->Ghp7 = value; - break; // end additions [Valaris] - default: - printf - ("mapif_parse_GuildCastleDataSave ERROR!! (Not found index=%d)\n", - index); - return 0; - } - - return mapif_guild_castle_datasave (gc->castle_id, index, value); -} - -// ギルドチェック要求 -int mapif_parse_GuildCheck (int fd, int guild_id, int account_id, int char_id) -{ - return guild_check_conflict (guild_id, account_id, 0 /*char_id*/); -} - -// map server からの通信 -// ・1パケットのみ解析すること -// ・パケット長データはinter.cにセットしておくこと -// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない -// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない -int inter_guild_parse_frommap (int fd) -{ - switch (RFIFOW (fd, 0)) - { - case 0x3030: - mapif_parse_CreateGuild (fd, RFIFOL (fd, 4), RFIFOP (fd, 8), - (struct guild_member *) RFIFOP (fd, 32)); - break; - case 0x3031: - mapif_parse_GuildInfo (fd, RFIFOL (fd, 2)); - break; - case 0x3032: - mapif_parse_GuildAddMember (fd, RFIFOL (fd, 4), - (struct guild_member *) RFIFOP (fd, - 8)); - break; - case 0x3034: - mapif_parse_GuildLeave (fd, RFIFOL (fd, 2), RFIFOL (fd, 6), - RFIFOL (fd, 10), RFIFOB (fd, 14), - RFIFOP (fd, 15)); - break; - case 0x3035: - mapif_parse_GuildChangeMemberInfoShort (fd, RFIFOL (fd, 2), - RFIFOL (fd, 6), - RFIFOL (fd, 10), - RFIFOB (fd, 14), - RFIFOW (fd, 15), - RFIFOW (fd, 17)); - break; - case 0x3036: - mapif_parse_BreakGuild (fd, RFIFOL (fd, 2)); - break; - case 0x3037: - mapif_parse_GuildMessage (fd, RFIFOL (fd, 4), RFIFOL (fd, 8), - RFIFOP (fd, 12), RFIFOW (fd, 2) - 12); - break; - case 0x3038: - mapif_parse_GuildCheck (fd, RFIFOL (fd, 2), RFIFOL (fd, 6), - RFIFOL (fd, 10)); - break; - case 0x3039: - mapif_parse_GuildBasicInfoChange (fd, RFIFOL (fd, 4), - RFIFOW (fd, 8), RFIFOP (fd, 10), - RFIFOW (fd, 2) - 10); - break; - case 0x303A: - mapif_parse_GuildMemberInfoChange (fd, RFIFOL (fd, 4), - RFIFOL (fd, 8), RFIFOL (fd, - 12), - RFIFOW (fd, 16), RFIFOP (fd, - 18), - RFIFOW (fd, 2) - 18); - break; - case 0x303B: - mapif_parse_GuildPosition (fd, RFIFOL (fd, 4), RFIFOL (fd, 8), - (struct guild_position *) RFIFOP (fd, - 12)); - break; - case 0x303C: - mapif_parse_GuildSkillUp (fd, RFIFOL (fd, 2), RFIFOL (fd, 6), - RFIFOL (fd, 10)); - break; - case 0x303D: - mapif_parse_GuildAlliance (fd, RFIFOL (fd, 2), RFIFOL (fd, 6), - RFIFOL (fd, 10), RFIFOL (fd, 14), - RFIFOB (fd, 18)); - break; - case 0x303E: - mapif_parse_GuildNotice (fd, RFIFOL (fd, 2), RFIFOP (fd, 6), - RFIFOP (fd, 66)); - break; - case 0x303F: - mapif_parse_GuildEmblem (fd, RFIFOW (fd, 2) - 12, RFIFOL (fd, 4), - RFIFOL (fd, 8), RFIFOP (fd, 12)); - break; - case 0x3040: - mapif_parse_GuildCastleDataLoad (fd, RFIFOW (fd, 2), - RFIFOB (fd, 4)); - break; - case 0x3041: - mapif_parse_GuildCastleDataSave (fd, RFIFOW (fd, 2), - RFIFOB (fd, 4), RFIFOL (fd, 5)); - break; - - default: - return 0; - } - - return 1; -} - -// マップサーバーの接続時処理 -int inter_guild_mapif_init (int fd) -{ - return mapif_guild_castle_alldataload (fd); -} - -// サーバーから脱退要求(キャラ削除用) -int inter_guild_leave (int guild_id, int account_id, int char_id) -{ - return mapif_parse_GuildLeave (-1, guild_id, account_id, 0 /*char_id*/, 0, - "**サーバー命令**"); -} diff --git a/src/char/int_guild.cpp b/src/char/int_guild.cpp new file mode 100644 index 0000000..fe9a95b --- /dev/null +++ b/src/char/int_guild.cpp @@ -0,0 +1,1757 @@ +// $Id: int_guild.c,v 1.2 2004/09/25 19:36:53 Akitasha Exp $ +#include "inter.hpp" +#include "int_guild.hpp" +#include "int_storage.hpp" +#include "../common/mmo.hpp" +#include "char.hpp" +#include "../common/socket.hpp" +#include "../common/db.hpp" +#include "../common/lock.hpp" + +#include +#include +#include + +char guild_txt[1024] = "save/guild.txt"; +char castle_txt[1024] = "save/castle.txt"; + +static struct dbt *guild_db; +static struct dbt *castle_db; + +static int guild_newid = 10000; + +static int guild_exp[100]; + +int mapif_parse_GuildLeave (int fd, int guild_id, int account_id, + int char_id, int flag, const char *mes); +int mapif_guild_broken (int guild_id, int flag); +int guild_check_empty (struct guild *g); +int guild_calcinfo (struct guild *g); +int mapif_guild_basicinfochanged (int guild_id, int type, const void *data, + int len); +int mapif_guild_info (int fd, struct guild *g); +void guild_break_sub (db_key_t key, db_val_t data, va_list ap); + +// ギルドデータの文字列への変換 +int inter_guild_tostr (char *str, struct guild *g) +{ + int i, c, len; + + // 基本データ + len = sprintf (str, "%d\t%s\t%s\t%d,%d,%d,%d,%d\t%s#\t%s#\t", + g->guild_id, g->name, g->master, + g->guild_lv, g->max_member, g->exp, g->skill_point, + g->castle_id, g->mes1, g->mes2); + // メンバー + for (i = 0; i < g->max_member; i++) + { + struct guild_member *m = &g->member[i]; + len += sprintf (str + len, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\t%s\t", + m->account_id, m->char_id, + m->hair, m->hair_color, m->gender, + m->pc_class, m->lv, m->exp, m->exp_payper, m->position, + ((m->account_id > 0) ? m->name : "-")); + } + // 役職 + for (i = 0; i < MAX_GUILDPOSITION; i++) + { + struct guild_position *p = &g->position[i]; + len += + sprintf (str + len, "%d,%d\t%s#\t", p->mode, p->exp_mode, + p->name); + } + // エンブレム + len += sprintf (str + len, "%d,%d,", g->emblem_len, g->emblem_id); + for (i = 0; i < g->emblem_len; i++) + { + len += + sprintf (str + len, "%02x", (unsigned char) (g->emblem_data[i])); + } + len += sprintf (str + len, "$\t"); + // 同盟リスト + c = 0; + for (i = 0; i < MAX_GUILDALLIANCE; i++) + if (g->alliance[i].guild_id > 0) + c++; + len += sprintf (str + len, "%d\t", c); + for (i = 0; i < MAX_GUILDALLIANCE; i++) + { + struct guild_alliance *a = &g->alliance[i]; + if (a->guild_id > 0) + len += + sprintf (str + len, "%d,%d\t%s\t", a->guild_id, a->opposition, + a->name); + } + // 追放リスト + c = 0; + for (i = 0; i < MAX_GUILDEXPLUSION; i++) + if (g->explusion[i].account_id > 0) + c++; + len += sprintf (str + len, "%d\t", c); + for (i = 0; i < MAX_GUILDEXPLUSION; i++) + { + struct guild_explusion *e = &g->explusion[i]; + if (e->account_id > 0) + len += sprintf (str + len, "%d,%d,%d,%d\t%s\t%s\t%s#\t", + e->account_id, e->rsv1, e->rsv2, e->rsv3, + e->name, e->acc, e->mes); + } + // ギルドスキル + for (i = 0; i < MAX_GUILDSKILL; i++) + { + len += sprintf (str + len, "%d,%d ", g->skill[i].id, g->skill[i].lv); + } + len += sprintf (str + len, "\t"); + + return 0; +} + +// ギルドデータの文字列からの変換 +int inter_guild_fromstr (char *str, struct guild *g) +{ + int i, j, c; + int tmp_int[16]; + char tmp_str[4][256]; + char tmp_str2[4096]; + char *pstr; + + // 基本データ + memset (g, 0, sizeof (struct guild)); + if (sscanf + (str, "%d\t%[^\t]\t%[^\t]\t%d,%d,%d,%d,%d\t%[^\t]\t%[^\t]\t", + &tmp_int[0], tmp_str[0], tmp_str[1], &tmp_int[1], &tmp_int[2], + &tmp_int[3], &tmp_int[4], &tmp_int[5], tmp_str[2], tmp_str[3]) < 8) + return 1; + + g->guild_id = tmp_int[0]; + g->guild_lv = tmp_int[1]; + g->max_member = tmp_int[2]; + g->exp = tmp_int[3]; + g->skill_point = tmp_int[4]; + g->castle_id = tmp_int[5]; + memcpy (g->name, tmp_str[0], 24); + memcpy (g->master, tmp_str[1], 24); + memcpy (g->mes1, tmp_str[2], 60); + memcpy (g->mes2, tmp_str[3], 120); + g->mes1[strlen (g->mes1) - 1] = 0; + g->mes2[strlen (g->mes2) - 1] = 0; + + for (j = 0; j < 6 && str != NULL; j++) // 位置スキップ + str = strchr (str + 1, '\t'); +// printf("GuildBaseInfo OK\n"); + + // メンバー + for (i = 0; i < g->max_member; i++) + { + struct guild_member *m = &g->member[i]; + if (sscanf (str + 1, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\t%[^\t]\t", + &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], + &tmp_int[4], &tmp_int[5], &tmp_int[6], &tmp_int[7], + &tmp_int[8], &tmp_int[9], tmp_str[0]) < 11) + return 1; + m->account_id = tmp_int[0]; + m->char_id = 0 /*tmp_int[1]*/; + m->hair = tmp_int[2]; + m->hair_color = tmp_int[3]; + m->gender = tmp_int[4]; + m->pc_class = tmp_int[5]; + m->lv = tmp_int[6]; + m->exp = tmp_int[7]; + m->exp_payper = tmp_int[8]; + m->position = tmp_int[9]; + memcpy (m->name, tmp_str[0], 24); + + for (j = 0; j < 2 && str != NULL; j++) // 位置スキップ + str = strchr (str + 1, '\t'); + } +// printf("GuildMemberInfo OK\n"); + // 役職 + i = 0; + while (sscanf (str + 1, "%d,%d%n", &tmp_int[0], &tmp_int[1], &j) == 2 + && str[1 + j] == '\t') + { + struct guild_position *p = &g->position[i]; + if (sscanf + (str + 1, "%d,%d\t%[^\t]\t", &tmp_int[0], &tmp_int[1], + tmp_str[0]) < 3) + return 1; + p->mode = tmp_int[0]; + p->exp_mode = tmp_int[1]; + tmp_str[0][strlen (tmp_str[0]) - 1] = 0; + memcpy (p->name, tmp_str[0], 24); + + for (j = 0; j < 2 && str != NULL; j++) // 位置スキップ + str = strchr (str + 1, '\t'); + i++; + } +// printf("GuildPositionInfo OK\n"); + // エンブレム + tmp_int[1] = 0; + if (sscanf (str + 1, "%d,%d,%[^\t]\t", &tmp_int[0], &tmp_int[1], tmp_str2) + < 3 && sscanf (str + 1, "%d,%[^\t]\t", &tmp_int[0], tmp_str2) < 2) + return 1; + g->emblem_len = tmp_int[0]; + g->emblem_id = tmp_int[1]; + for (i = 0, pstr = tmp_str2; i < g->emblem_len; i++, pstr += 2) + { + int c1 = pstr[0], c2 = pstr[1], x1 = 0, x2 = 0; + if (c1 >= '0' && c1 <= '9') + x1 = c1 - '0'; + if (c1 >= 'a' && c1 <= 'f') + x1 = c1 - 'a' + 10; + if (c1 >= 'A' && c1 <= 'F') + x1 = c1 - 'A' + 10; + if (c2 >= '0' && c2 <= '9') + x2 = c2 - '0'; + if (c2 >= 'a' && c2 <= 'f') + x2 = c2 - 'a' + 10; + if (c2 >= 'A' && c2 <= 'F') + x2 = c2 - 'A' + 10; + g->emblem_data[i] = (x1 << 4) | x2; + } +// printf("GuildEmblemInfo OK\n"); + str = strchr (str + 1, '\t'); // 位置スキップ + + // 同盟リスト + if (sscanf (str + 1, "%d\t", &c) < 1) + return 1; + str = strchr (str + 1, '\t'); // 位置スキップ + for (i = 0; i < c; i++) + { + struct guild_alliance *a = &g->alliance[i]; + if (sscanf + (str + 1, "%d,%d\t%[^\t]\t", &tmp_int[0], &tmp_int[1], + tmp_str[0]) < 3) + return 1; + a->guild_id = tmp_int[0]; + a->opposition = tmp_int[1]; + memcpy (a->name, tmp_str[0], 24); + + for (j = 0; j < 2 && str != NULL; j++) // 位置スキップ + str = strchr (str + 1, '\t'); + } +// printf("GuildAllianceInfo OK\n"); + // 追放リスト + if (sscanf (str + 1, "%d\t", &c) < 1) + return 1; + str = strchr (str + 1, '\t'); // 位置スキップ + for (i = 0; i < c; i++) + { + struct guild_explusion *e = &g->explusion[i]; + if (sscanf (str + 1, "%d,%d,%d,%d\t%[^\t]\t%[^\t]\t%[^\t]\t", + &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], + tmp_str[0], tmp_str[1], tmp_str[2]) < 6) + return 1; + e->account_id = tmp_int[0]; + e->rsv1 = tmp_int[1]; + e->rsv2 = tmp_int[2]; + e->rsv3 = tmp_int[3]; + memcpy (e->name, tmp_str[0], 24); + memcpy (e->acc, tmp_str[1], 24); + tmp_str[2][strlen (tmp_str[2]) - 1] = 0; + memcpy (e->mes, tmp_str[2], 40); + + for (j = 0; j < 4 && str != NULL; j++) // 位置スキップ + str = strchr (str + 1, '\t'); + } +// printf("GuildExplusionInfo OK\n"); + // ギルドスキル + for (i = 0; i < MAX_GUILDSKILL; i++) + { + if (sscanf (str + 1, "%d,%d ", &tmp_int[0], &tmp_int[1]) < 2) + break; + g->skill[i].id = tmp_int[0]; + g->skill[i].lv = tmp_int[1]; + str = strchr (str + 1, ' '); + } + str = strchr (str + 1, '\t'); +// printf("GuildSkillInfo OK\n"); + + return 0; +} + +// ギルド城データの文字列への変換 +int inter_guildcastle_tostr (char *str, struct guild_castle *gc) +{ + int len; + + len = sprintf (str, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", // added Guardian HP [Valaris] + gc->castle_id, gc->guild_id, gc->economy, gc->defense, + gc->triggerE, gc->triggerD, gc->nextTime, gc->payTime, + gc->createTime, gc->visibleC, gc->visibleG0, gc->visibleG1, + gc->visibleG2, gc->visibleG3, gc->visibleG4, gc->visibleG5, + gc->visibleG6, gc->visibleG7, gc->Ghp0, gc->Ghp1, gc->Ghp2, + gc->Ghp3, gc->Ghp4, gc->Ghp5, gc->Ghp6, gc->Ghp7); + + return 0; +} + +// ギルド城データの文字列からの変換 +int inter_guildcastle_fromstr (char *str, struct guild_castle *gc) +{ + int tmp_int[26]; + + memset (gc, 0, sizeof (struct guild_castle)); + // new structure of guild castle + if (sscanf + (str, + "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", + &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], &tmp_int[4], + &tmp_int[5], &tmp_int[6], &tmp_int[7], &tmp_int[8], &tmp_int[9], + &tmp_int[10], &tmp_int[11], &tmp_int[12], &tmp_int[13], &tmp_int[14], + &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], &tmp_int[19], + &tmp_int[20], &tmp_int[21], &tmp_int[22], &tmp_int[23], &tmp_int[24], + &tmp_int[25]) == 26) + { + gc->castle_id = tmp_int[0]; + gc->guild_id = tmp_int[1]; + gc->economy = tmp_int[2]; + gc->defense = tmp_int[3]; + gc->triggerE = tmp_int[4]; + gc->triggerD = tmp_int[5]; + gc->nextTime = tmp_int[6]; + gc->payTime = tmp_int[7]; + gc->createTime = tmp_int[8]; + gc->visibleC = tmp_int[9]; + gc->visibleG0 = tmp_int[10]; + gc->visibleG1 = tmp_int[11]; + gc->visibleG2 = tmp_int[12]; + gc->visibleG3 = tmp_int[13]; + gc->visibleG4 = tmp_int[14]; + gc->visibleG5 = tmp_int[15]; + gc->visibleG6 = tmp_int[16]; + gc->visibleG7 = tmp_int[17]; + gc->Ghp0 = tmp_int[18]; + gc->Ghp1 = tmp_int[19]; + gc->Ghp2 = tmp_int[20]; + gc->Ghp3 = tmp_int[21]; + gc->Ghp4 = tmp_int[22]; + gc->Ghp5 = tmp_int[23]; + gc->Ghp6 = tmp_int[24]; + gc->Ghp7 = tmp_int[25]; // end additions [Valaris] + // old structure of guild castle + } + else if (sscanf + (str, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", + &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], &tmp_int[4], + &tmp_int[5], &tmp_int[6], &tmp_int[7], &tmp_int[8], &tmp_int[9], + &tmp_int[10], &tmp_int[11], &tmp_int[12], &tmp_int[13], + &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17]) == 18) + { + gc->castle_id = tmp_int[0]; + gc->guild_id = tmp_int[1]; + gc->economy = tmp_int[2]; + gc->defense = tmp_int[3]; + gc->triggerE = tmp_int[4]; + gc->triggerD = tmp_int[5]; + gc->nextTime = tmp_int[6]; + gc->payTime = tmp_int[7]; + gc->createTime = tmp_int[8]; + gc->visibleC = tmp_int[9]; + gc->visibleG0 = tmp_int[10]; + gc->visibleG1 = tmp_int[11]; + gc->visibleG2 = tmp_int[12]; + gc->visibleG3 = tmp_int[13]; + gc->visibleG4 = tmp_int[14]; + gc->visibleG5 = tmp_int[15]; + gc->visibleG6 = tmp_int[16]; + gc->visibleG7 = tmp_int[17]; + if (gc->visibleG0 == 1) + gc->Ghp0 = 15670 + 2000 * gc->defense; + else + gc->Ghp0 = 0; + if (gc->visibleG1 == 1) + gc->Ghp1 = 15670 + 2000 * gc->defense; + else + gc->Ghp1 = 0; + if (gc->visibleG2 == 1) + gc->Ghp2 = 15670 + 2000 * gc->defense; + else + gc->Ghp2 = 0; + if (gc->visibleG3 == 1) + gc->Ghp3 = 30214 + 2000 * gc->defense; + else + gc->Ghp3 = 0; + if (gc->visibleG4 == 1) + gc->Ghp4 = 30214 + 2000 * gc->defense; + else + gc->Ghp4 = 0; + if (gc->visibleG5 == 1) + gc->Ghp5 = 28634 + 2000 * gc->defense; + else + gc->Ghp5 = 0; + if (gc->visibleG6 == 1) + gc->Ghp6 = 28634 + 2000 * gc->defense; + else + gc->Ghp6 = 0; + if (gc->visibleG7 == 1) + gc->Ghp7 = 28634 + 2000 * gc->defense; + else + gc->Ghp7 = 0; + } + else + { + return 1; + } + + return 0; +} + +// ギルド関連データベース読み込み +int inter_guild_readdb (void) +{ + int i; + FILE *fp; + char line[1024]; + + fp = fopen_ ("db/exp_guild.txt", "r"); + if (fp == NULL) + { + printf ("can't read db/exp_guild.txt\n"); + return 1; + } + i = 0; + while (fgets (line, sizeof (line) - 1, fp) && i < 100) + { + if (line[0] == '/' && line[1] == '/') + continue; + guild_exp[i] = atoi (line); + i++; + } + fclose_ (fp); + + return 0; +} + +// ギルドデータの読み込み +int inter_guild_init (void) +{ + char line[16384]; + struct guild *g; + struct guild_castle *gc; + FILE *fp; + int i, j, c = 0; + + inter_guild_readdb (); + + guild_db = numdb_init (); + castle_db = numdb_init (); + + if ((fp = fopen_ (guild_txt, "r")) == NULL) + return 1; + while (fgets (line, sizeof (line) - 1, fp)) + { + j = 0; + if (sscanf (line, "%d\t%%newid%%\n%n", &i, &j) == 1 && j > 0 + && guild_newid <= i) + { + guild_newid = i; + continue; + } + CREATE (g, struct guild, 1); + if (inter_guild_fromstr (line, g) == 0 && g->guild_id > 0) + { + if (g->guild_id >= guild_newid) + guild_newid = g->guild_id + 1; + numdb_insert (guild_db, g->guild_id, g); + guild_check_empty (g); + guild_calcinfo (g); + } + else + { + printf ("int_guild: broken data [%s] line %d\n", guild_txt, c); + free (g); + } + c++; + } + fclose_ (fp); +// printf("int_guild: %s read done (%d guilds)\n", guild_txt, c); + + c = 0; //カウンタ初期化 + + if ((fp = fopen_ (castle_txt, "r")) == NULL) + { + return 1; + } + + while (fgets (line, sizeof (line) - 1, fp)) + { + CREATE (gc, struct guild_castle, 1); + if (inter_guildcastle_fromstr (line, gc) == 0) + { + numdb_insert (castle_db, gc->castle_id, gc); + } + else + { + printf ("int_guild: broken data [%s] line %d\n", castle_txt, c); + free (gc); + } + c++; + } + + if (!c) + { + printf (" %s - making Default Data...\n", castle_txt); + //デフォルトデータを作成 + for (i = 0; i < MAX_GUILDCASTLE; i++) + { + CREATE (gc, struct guild_castle, 1); + gc->castle_id = i; + gc->guild_id = 0; + gc->economy = 0; + gc->defense = 0; + gc->triggerE = 0; + gc->triggerD = 0; + gc->nextTime = 0; + gc->payTime = 0; + gc->createTime = 0; + gc->visibleC = 0; + gc->visibleG0 = 0; + gc->visibleG1 = 0; + gc->visibleG2 = 0; + gc->visibleG3 = 0; + gc->visibleG4 = 0; + gc->visibleG5 = 0; + gc->visibleG6 = 0; + gc->visibleG7 = 0; + gc->Ghp0 = 0; // guardian HP [Valaris] + gc->Ghp1 = 0; + gc->Ghp2 = 0; + gc->Ghp3 = 0; + gc->Ghp4 = 0; + gc->Ghp5 = 0; + gc->Ghp6 = 0; + gc->Ghp7 = 0; // end additions [Valaris] + numdb_insert (castle_db, gc->castle_id, gc); + } + printf (" %s - making done\n", castle_txt); + return 0; + } + + fclose_ (fp); + + return 0; +} + +struct guild *inter_guild_search (int guild_id) +{ + struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); + + return g; +} + +// ギルドデータのセーブ用 +void inter_guild_save_sub (db_key_t key, db_val_t data, va_list ap) +{ + char line[16384]; + FILE *fp; + + inter_guild_tostr (line, (struct guild *) data); + fp = va_arg (ap, FILE *); + fprintf (fp, "%s\n", line); +} + +// ギルド城データのセーブ用 +void inter_castle_save_sub (db_key_t key, db_val_t data, va_list ap) +{ + char line[16384]; + FILE *fp; + + inter_guildcastle_tostr (line, (struct guild_castle *) data); + fp = va_arg (ap, FILE *); + fprintf (fp, "%s\n", line); +} + +// ギルドデータのセーブ +int inter_guild_save (void) +{ + FILE *fp; + int lock; + + if ((fp = lock_fopen (guild_txt, &lock)) == NULL) + { + printf ("int_guild: cant write [%s] !!! data is lost !!!\n", + guild_txt); + return 1; + } + numdb_foreach (guild_db, inter_guild_save_sub, fp); +// fprintf(fp, "%d\t%%newid%%\n", guild_newid); + lock_fclose (fp, guild_txt, &lock); +// printf("int_guild: %s saved.\n", guild_txt); + + if ((fp = lock_fopen (castle_txt, &lock)) == NULL) + { + printf ("int_guild: cant write [%s] !!! data is lost !!!\n", + castle_txt); + return 1; + } + numdb_foreach (castle_db, inter_castle_save_sub, fp); + lock_fclose (fp, castle_txt, &lock); + + return 0; +} + +// ギルド名検索用 +void search_guildname_sub (db_key_t key, db_val_t data, va_list ap) +{ + struct guild *g = (struct guild *) data, **dst; + char *str; + + str = va_arg (ap, char *); + dst = va_arg (ap, struct guild **); + if (strcasecmp (g->name, str) == 0) + *dst = g; +} + +// ギルド名検索 +struct guild *search_guildname (char *str) +{ + struct guild *g = NULL; + numdb_foreach (guild_db, search_guildname_sub, str, &g); + return g; +} + +// ギルドが空かどうかチェック +int guild_check_empty (struct guild *g) +{ + int i; + + for (i = 0; i < g->max_member; i++) + { + if (g->member[i].account_id > 0) + { + return 0; + } + } + // 誰もいないので解散 + numdb_foreach (guild_db, guild_break_sub, g->guild_id); + numdb_erase (guild_db, g->guild_id); + inter_guild_storage_delete (g->guild_id); + mapif_guild_broken (g->guild_id, 0); + free (g); + + return 1; +} + +// キャラの競合がないかチェック用 +void guild_check_conflict_sub (db_key_t key, db_val_t data, va_list ap) +{ + struct guild *g = (struct guild *) data; + int guild_id, account_id, char_id, i; + + guild_id = va_arg (ap, int); + account_id = va_arg (ap, int); + char_id = va_arg (ap, int); + + if (g->guild_id == guild_id) // 本来の所属なので問題なし + return; + + for (i = 0; i < MAX_GUILD; i++) + { + if (g->member[i].account_id == account_id) + { + // 別のギルドに偽の所属データがあるので脱退 + printf ("int_guild: guild conflict! %d,%d %d!=%d\n", account_id, + char_id, guild_id, g->guild_id); + mapif_parse_GuildLeave (-1, g->guild_id, account_id, 0 /*char_id*/, 0, + "**データ競合**"); + } + } +} + +// キャラの競合がないかチェック +int guild_check_conflict (int guild_id, int account_id, int char_id) +{ + numdb_foreach (guild_db, guild_check_conflict_sub, guild_id, account_id, + 0 /*char_id*/); + + return 0; +} + +int guild_nextexp (int level) +{ + if (level < 100) + return guild_exp[level - 1]; + + return 0; +} + +// ギルドスキルがあるか確認 +int guild_checkskill (struct guild *g, int id) +{ + return g->skill[id - 10000].lv; +} + +// ギルドの情報の再計算 +int guild_calcinfo (struct guild *g) +{ + int i, c, nextexp; + struct guild before = *g; + + // スキルIDの設定 + for (i = 0; i < 5; i++) + g->skill[i].id = i + 10000; + + // ギルドレベル + if (g->guild_lv <= 0) + g->guild_lv = 1; + nextexp = guild_nextexp (g->guild_lv); + if (nextexp > 0) + { + while (g->exp >= nextexp) + { // レベルアップ処理 + g->exp -= nextexp; + g->guild_lv++; + g->skill_point++; + nextexp = guild_nextexp (g->guild_lv); + } + } + + // ギルドの次の経験値 + g->next_exp = guild_nextexp (g->guild_lv); + + // メンバ上限(ギルド拡張適用) + g->max_member = 100 + guild_checkskill (g, 10004) * 2; + + // 平均レベルとオンライン人数 + g->average_lv = 0; + g->connect_member = 0; + c = 0; + for (i = 0; i < g->max_member; i++) + { + if (g->member[i].account_id > 0) + { + g->average_lv += g->member[i].lv; + c++; + if (g->member[i].online > 0) + g->connect_member++; + } + } + g->average_lv /= c; + + // 全データを送る必要がありそう + if (g->max_member != before.max_member || + g->guild_lv != before.guild_lv || + g->skill_point != before.skill_point) + { + mapif_guild_info (-1, g); + return 1; + } + + return 0; +} + +//------------------------------------------------------------------- +// map serverへの通信 + +// ギルド作成可否 +int mapif_guild_created (int fd, int account_id, struct guild *g) +{ + WFIFOW (fd, 0) = 0x3830; + WFIFOL (fd, 2) = account_id; + if (g != NULL) + { + WFIFOL (fd, 6) = g->guild_id; + printf ("int_guild: created! %d %s\n", g->guild_id, g->name); + } + else + { + WFIFOL (fd, 6) = 0; + } + WFIFOSET (fd, 10); + return 0; +} + +// ギルド情報見つからず +int mapif_guild_noinfo (int fd, int guild_id) +{ + WFIFOW (fd, 0) = 0x3831; + WFIFOW (fd, 2) = 8; + WFIFOL (fd, 4) = guild_id; + WFIFOSET (fd, 8); + printf ("int_guild: info not found %d\n", guild_id); + + return 0; +} + +// ギルド情報まとめ送り +int mapif_guild_info (int fd, struct guild *g) +{ + unsigned char buf[4 + sizeof (struct guild)]; + + WBUFW (buf, 0) = 0x3831; + memcpy (buf + 4, g, sizeof (struct guild)); + WBUFW (buf, 2) = 4 + sizeof (struct guild); +// printf("int_guild: sizeof(guild)=%d\n", sizeof(struct guild)); + if (fd < 0) + mapif_sendall (buf, WBUFW (buf, 2)); + else + mapif_send (fd, buf, WBUFW (buf, 2)); +// printf("int_guild: info %d %s\n", p->guild_id, p->name); + + return 0; +} + +// メンバ追加可否 +int mapif_guild_memberadded (int fd, int guild_id, int account_id, + int char_id, int flag) +{ + WFIFOW (fd, 0) = 0x3832; + WFIFOL (fd, 2) = guild_id; + WFIFOL (fd, 6) = account_id; + WFIFOL (fd, 10) = 0 /*char_id*/; + WFIFOB (fd, 14) = flag; + WFIFOSET (fd, 15); + + return 0; +} + +// 脱退/追放通知 +int mapif_guild_leaved (int guild_id, int account_id, int char_id, int flag, + const char *name, const char *mes) +{ + unsigned char buf[79]; + + WBUFW (buf, 0) = 0x3834; + WBUFL (buf, 2) = guild_id; + WBUFL (buf, 6) = account_id; + WBUFL (buf, 10) = 0 /*char_id*/; + WBUFB (buf, 14) = flag; + memcpy (WBUFP (buf, 15), mes, 40); + memcpy (WBUFP (buf, 55), name, 24); + mapif_sendall (buf, 79); + printf ("int_guild: guild leaved %d %d %s %s\n", guild_id, account_id, + name, mes); + + return 0; +} + +// オンライン状態とLv更新通知 +int mapif_guild_memberinfoshort (struct guild *g, int idx) +{ + unsigned char buf[19]; + + WBUFW (buf, 0) = 0x3835; + WBUFL (buf, 2) = g->guild_id; + WBUFL (buf, 6) = g->member[idx].account_id; + WBUFL (buf, 10) = 0 /*g->member[idx].char_id*/; + WBUFB (buf, 14) = g->member[idx].online; + WBUFW (buf, 15) = g->member[idx].lv; + WBUFW (buf, 17) = g->member[idx].pc_class; + mapif_sendall (buf, 19); + return 0; +} + +// 解散通知 +int mapif_guild_broken (int guild_id, int flag) +{ + unsigned char buf[7]; + + WBUFW (buf, 0) = 0x3836; + WBUFL (buf, 2) = guild_id; + WBUFB (buf, 6) = flag; + mapif_sendall (buf, 7); + printf ("int_guild: broken %d\n", guild_id); + + return 0; +} + +// ギルド内発言 +int mapif_guild_message (int guild_id, int account_id, char *mes, int len) +{ + unsigned char buf[len + 12]; + + WBUFW (buf, 0) = 0x3837; + WBUFW (buf, 2) = len + 12; + WBUFL (buf, 4) = guild_id; + WBUFL (buf, 8) = account_id; + memcpy (WBUFP (buf, 12), mes, len); + mapif_sendall (buf, len + 12); + + return 0; +} + +// ギルド基本情報変更通知 +int mapif_guild_basicinfochanged (int guild_id, int type, const void *data, + int len) +{ + unsigned char buf[2048]; + + WBUFW (buf, 0) = 0x3839; + WBUFW (buf, 2) = len + 10; + WBUFL (buf, 4) = guild_id; + WBUFW (buf, 8) = type; + memcpy (WBUFP (buf, 10), data, len); + mapif_sendall (buf, len + 10); + return 0; +} + +// ギルドメンバ情報変更通知 +int mapif_guild_memberinfochanged (int guild_id, int account_id, int char_id, + int type, const void *data, int len) +{ + unsigned char buf[len + 18]; + + WBUFW (buf, 0) = 0x383a; + WBUFW (buf, 2) = len + 18; + WBUFL (buf, 4) = guild_id; + WBUFL (buf, 8) = account_id; + WBUFL (buf, 12) = 0 /*char_id*/; + WBUFW (buf, 16) = type; + memcpy (WBUFP (buf, 18), data, len); + mapif_sendall (buf, len + 18); + + return 0; +} + +// ギルドスキルアップ通知 +int mapif_guild_skillupack (int guild_id, int skill_num, int account_id) +{ + unsigned char buf[14]; + + WBUFW (buf, 0) = 0x383c; + WBUFL (buf, 2) = guild_id; + WBUFL (buf, 6) = skill_num; + WBUFL (buf, 10) = account_id; + mapif_sendall (buf, 14); + + return 0; +} + +// ギルド同盟/敵対通知 +int mapif_guild_alliance (int guild_id1, int guild_id2, int account_id1, + int account_id2, int flag, const char *name1, + const char *name2) +{ + unsigned char buf[67]; + + WBUFW (buf, 0) = 0x383d; + WBUFL (buf, 2) = guild_id1; + WBUFL (buf, 6) = guild_id2; + WBUFL (buf, 10) = account_id1; + WBUFL (buf, 14) = account_id2; + WBUFB (buf, 18) = flag; + memcpy (WBUFP (buf, 19), name1, 24); + memcpy (WBUFP (buf, 43), name2, 24); + mapif_sendall (buf, 67); + + return 0; +} + +// ギルド役職変更通知 +int mapif_guild_position (struct guild *g, int idx) +{ + unsigned char buf[sizeof (struct guild_position) + 12]; + + WBUFW (buf, 0) = 0x383b; + WBUFW (buf, 2) = sizeof (struct guild_position) + 12; + WBUFL (buf, 4) = g->guild_id; + WBUFL (buf, 8) = idx; + memcpy (WBUFP (buf, 12), &g->position[idx], + sizeof (struct guild_position)); + mapif_sendall (buf, WBUFW (buf, 2)); + + return 0; +} + +// ギルド告知変更通知 +int mapif_guild_notice (struct guild *g) +{ + unsigned char buf[186]; + + WBUFW (buf, 0) = 0x383e; + WBUFL (buf, 2) = g->guild_id; + memcpy (WBUFP (buf, 6), g->mes1, 60); + memcpy (WBUFP (buf, 66), g->mes2, 120); + mapif_sendall (buf, 186); + + return 0; +} + +// ギルドエンブレム変更通知 +int mapif_guild_emblem (struct guild *g) +{ + unsigned char buf[2048]; + + WBUFW (buf, 0) = 0x383f; + WBUFW (buf, 2) = g->emblem_len + 12; + WBUFL (buf, 4) = g->guild_id; + WBUFL (buf, 8) = g->emblem_id; + memcpy (WBUFP (buf, 12), g->emblem_data, g->emblem_len); + mapif_sendall (buf, WBUFW (buf, 2)); + + return 0; +} + +int mapif_guild_castle_dataload (int castle_id, int index, int value) +{ + unsigned char buf[9]; + + WBUFW (buf, 0) = 0x3840; + WBUFW (buf, 2) = castle_id; + WBUFB (buf, 4) = index; + WBUFL (buf, 5) = value; + mapif_sendall (buf, 9); + + return 0; +} + +int mapif_guild_castle_datasave (int castle_id, int index, int value) +{ + unsigned char buf[9]; + + WBUFW (buf, 0) = 0x3841; + WBUFW (buf, 2) = castle_id; + WBUFB (buf, 4) = index; + WBUFL (buf, 5) = value; + mapif_sendall (buf, 9); + + return 0; +} + +void mapif_guild_castle_alldataload_sub (db_key_t key, db_val_t data, va_list ap) +{ + int fd = va_arg (ap, int); + int *p = va_arg (ap, int *); + + memcpy (WFIFOP (fd, *p), (struct guild_castle *) data, + sizeof (struct guild_castle)); + (*p) += sizeof (struct guild_castle); +} + +int mapif_guild_castle_alldataload (int fd) +{ + int len = 4; + + WFIFOW (fd, 0) = 0x3842; + numdb_foreach (castle_db, mapif_guild_castle_alldataload_sub, fd, &len); + WFIFOW (fd, 2) = len; + WFIFOSET (fd, len); + + return 0; +} + +//------------------------------------------------------------------- +// map serverからの通信 + +// ギルド作成要求 +int mapif_parse_CreateGuild (int fd, int account_id, char *name, + struct guild_member *master) +{ + struct guild *g; + int i; + + for (i = 0; i < 24 && name[i]; i++) + { + if (!(name[i] & 0xe0) || name[i] == 0x7f) + { + printf ("int_guild: illeagal guild name [%s]\n", name); + mapif_guild_created (fd, account_id, NULL); + return 0; + } + } + + if ((g = search_guildname (name)) != NULL) + { + printf ("int_guild: same name guild exists [%s]\n", name); + mapif_guild_created (fd, account_id, NULL); + return 0; + } + CREATE (g, struct guild, 1); + g->guild_id = guild_newid++; + memcpy (g->name, name, 24); + memcpy (g->master, master->name, 24); + memcpy (&g->member[0], master, sizeof (struct guild_member)); + + g->position[0].mode = 0x11; + strcpy (g->position[0].name, "GuildMaster"); + strcpy (g->position[MAX_GUILDPOSITION - 1].name, "Newbie"); + for (i = 1; i < MAX_GUILDPOSITION - 1; i++) + sprintf (g->position[i].name, "Position %d", i + 1); + + // ここでギルド情報計算が必要と思われる + g->max_member = 100; + g->average_lv = master->lv; + for (i = 0; i < 5; i++) + g->skill[i].id = i + 10000; + + numdb_insert (guild_db, g->guild_id, g); + + mapif_guild_created (fd, account_id, g); + mapif_guild_info (fd, g); + + inter_log ("guild %s (id=%d) created by master %s (id=%d)\n", + name, g->guild_id, master->name, master->account_id); + + return 0; +} + +// ギルド情報要求 +int mapif_parse_GuildInfo (int fd, int guild_id) +{ + struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); + if (g != NULL) + { + guild_calcinfo (g); + mapif_guild_info (fd, g); + } + else + mapif_guild_noinfo (fd, guild_id); + + return 0; +} + +// ギルドメンバ追加要求 +int mapif_parse_GuildAddMember (int fd, int guild_id, struct guild_member *m) +{ + struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); + if (g == NULL) + { + mapif_guild_memberadded (fd, guild_id, m->account_id, 0 /*char_id*/, 1); + return 0; + } + + for (int i = 0; i < g->max_member; i++) + { + if (g->member[i].account_id == 0) + { + memcpy (&g->member[i], m, sizeof (struct guild_member)); + mapif_guild_memberadded (fd, guild_id, m->account_id, 0 /*char_id*/, + 0); + guild_calcinfo (g); + mapif_guild_info (-1, g); + + return 0; + } + } + mapif_guild_memberadded (fd, guild_id, m->account_id, 0 /*char_id*/, 1); + + return 0; +} + +// ギルド脱退/追放要求 +int mapif_parse_GuildLeave (int fd, int guild_id, int account_id, int char_id, + int flag, const char *mes) +{ + struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); + if (g != NULL) + { + for (int i = 0; i < MAX_GUILD; i++) + { + if (g->member[i].account_id == account_id) + { +// printf("%d %d\n", i, (int)(&g->member[i])); +// printf("%d %s\n", i, g->member[i].name); + + if (flag) + { + int j; + // 追放の場合追放リストに入れる + for (j = 0; j < MAX_GUILDEXPLUSION; j++) + { + if (g->explusion[j].account_id == 0) + break; + } + if (j == MAX_GUILDEXPLUSION) + { // 一杯なので古いのを消す + for (j = 0; j < MAX_GUILDEXPLUSION - 1; j++) + g->explusion[j] = g->explusion[j + 1]; + j = MAX_GUILDEXPLUSION - 1; + } + g->explusion[j].account_id = account_id; + memcpy (g->explusion[j].acc, "dummy", 24); + memcpy (g->explusion[j].name, g->member[i].name, 24); + memcpy (g->explusion[j].mes, mes, 40); + } + + mapif_guild_leaved (guild_id, account_id, 0 /*char_id*/, flag, + g->member[i].name, mes); +// printf("%d %d\n", i, (int)(&g->member[i])); +// printf("%d %s\n", i, (&g->member[i])->name); + memset (&g->member[i], 0, sizeof (struct guild_member)); + + if (guild_check_empty (g) == 0) + mapif_guild_info (-1, g); // まだ人がいるのでデータ送信 + + return 0; + } + } + } + return 0; +} + +// オンライン/Lv更新 +int mapif_parse_GuildChangeMemberInfoShort (int fd, int guild_id, + int account_id, int char_id, + int online, int lv, int pc_class) +{ + struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); + if (g == NULL) + return 0; + + g->connect_member = 0; + + int alv = 0; + int c = 0; + for (int i = 0; i < MAX_GUILD; i++) + { + if (g->member[i].account_id == account_id) + { + g->member[i].online = online; + g->member[i].lv = lv; + g->member[i].pc_class = pc_class; + mapif_guild_memberinfoshort (g, i); + } + if (g->member[i].account_id > 0) + { + alv += g->member[i].lv; + c++; + } + if (g->member[i].online) + g->connect_member++; + } + // 平均レベル + g->average_lv = alv / c; + + return 0; +} + +// ギルド解散処理用(同盟/敵対を解除) +void guild_break_sub (db_key_t key, db_val_t data, va_list ap) +{ + struct guild *g = (struct guild *) data; + int guild_id = va_arg (ap, int); + int i; + + for (i = 0; i < MAX_GUILDALLIANCE; i++) + { + if (g->alliance[i].guild_id == guild_id) + g->alliance[i].guild_id = 0; + } +} + +// ギルド解散要求 +int mapif_parse_BreakGuild (int fd, int guild_id) +{ + struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); + if (g == NULL) + return 0; + + numdb_foreach (guild_db, guild_break_sub, guild_id); + numdb_erase (guild_db, guild_id); + inter_guild_storage_delete (guild_id); + mapif_guild_broken (guild_id, 0); + + inter_log ("guild %s (id=%d) broken\n", g->name, guild_id); + free (g); + + return 0; +} + +// ギルドメッセージ送信 +int mapif_parse_GuildMessage (int fd, int guild_id, int account_id, char *mes, + int len) +{ + return mapif_guild_message (guild_id, account_id, mes, len); +} + +// ギルド基本データ変更要求 +int mapif_parse_GuildBasicInfoChange (int fd, int guild_id, int type, + const char *data, int len) +{ + short dw = *((short *) data); + + struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); + if (g == NULL) + return 0; + + switch (type) + { + case GBI_GUILDLV: + if (dw > 0 && g->guild_lv + dw <= 50) + { + g->guild_lv += dw; + g->skill_point += dw; + } + else if (dw < 0 && g->guild_lv + dw >= 1) + g->guild_lv += dw; + mapif_guild_info (-1, g); + return 0; + default: + printf ("int_guild: GuildBasicInfoChange: Unknown type %d\n", + type); + break; + } + mapif_guild_basicinfochanged (guild_id, type, data, len); + + return 0; +} + +// ギルドメンバデータ変更要求 +int mapif_parse_GuildMemberInfoChange (int fd, int guild_id, int account_id, + int char_id, int type, + const char *data, int len) +{ + int i; + struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); + if (g == NULL) + return 0; + + for (i = 0; i < g->max_member; i++) + if (g->member[i].account_id == account_id) + break; + if (i == g->max_member) + { + printf ("int_guild: GuildMemberChange: Not found %d,%d in %d[%s]\n", + account_id, char_id, guild_id, g->name); + return 0; + } + switch (type) + { + case GMI_POSITION: // 役職 + g->member[i].position = *((int *) data); + break; + case GMI_EXP: // EXP + { + int exp, oldexp = g->member[i].exp; + exp = g->member[i].exp = *((unsigned int *) data); + g->exp += (exp - oldexp); + guild_calcinfo (g); // Lvアップ判断 + mapif_guild_basicinfochanged (guild_id, GBI_EXP, &g->exp, 4); + } + break; + default: + printf ("int_guild: GuildMemberInfoChange: Unknown type %d\n", + type); + break; + } + mapif_guild_memberinfochanged (guild_id, account_id, char_id, type, data, + len); + + return 0; +} + +// ギルド役職名変更要求 +int mapif_parse_GuildPosition (int fd, int guild_id, int idx, + struct guild_position *p) +{ + struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); + + if (g == NULL || idx < 0 || idx >= MAX_GUILDPOSITION) + { + return 0; + } + memcpy (&g->position[idx], p, sizeof (struct guild_position)); + mapif_guild_position (g, idx); + printf ("int_guild: position changed %d\n", idx); + + return 0; +} + +// ギルドスキルアップ要求 +int mapif_parse_GuildSkillUp (int fd, int guild_id, int skill_num, + int account_id) +{ + struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); + int idx = skill_num - 10000; + + if (g == NULL || skill_num < 10000) + return 0; + + if (g->skill_point > 0 && g->skill[idx].id > 0 && g->skill[idx].lv < 10) + { + g->skill[idx].lv++; + g->skill_point--; + if (guild_calcinfo (g) == 0) + mapif_guild_info (-1, g); + mapif_guild_skillupack (guild_id, skill_num, account_id); + printf ("int_guild: skill %d up\n", skill_num); + } + + return 0; +} + +// ギルド同盟要求 +int mapif_parse_GuildAlliance (int fd, int guild_id1, int guild_id2, + int account_id1, int account_id2, int flag) +{ + struct guild *g[2]; + int j, i; + + g[0] = (struct guild *)numdb_search (guild_db, guild_id1); + g[1] = (struct guild *)numdb_search (guild_db, guild_id2); + if (g[0] == NULL || g[1] == NULL) + return 0; + + if (!(flag & 0x8)) + { + for (i = 0; i < 2 - (flag & 1); i++) + { + for (j = 0; j < MAX_GUILDALLIANCE; j++) + if (g[i]->alliance[j].guild_id == 0) + { + g[i]->alliance[j].guild_id = g[1 - i]->guild_id; + memcpy (g[i]->alliance[j].name, g[1 - i]->name, 24); + g[i]->alliance[j].opposition = flag & 1; + break; + } + } + } + else + { // 関係解消 + for (i = 0; i < 2 - (flag & 1); i++) + { + for (j = 0; j < MAX_GUILDALLIANCE; j++) + if (g[i]->alliance[j].guild_id == g[1 - i]->guild_id + && g[i]->alliance[j].opposition == (flag & 1)) + { + g[i]->alliance[j].guild_id = 0; + break; + } + } + } + mapif_guild_alliance (guild_id1, guild_id2, account_id1, account_id2, + flag, g[0]->name, g[1]->name); + + return 0; +} + +// ギルド告知変更要求 +int mapif_parse_GuildNotice (int fd, int guild_id, const char *mes1, + const char *mes2) +{ + struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); + if (g == NULL) + return 0; + memcpy (g->mes1, mes1, 60); + memcpy (g->mes2, mes2, 120); + + return mapif_guild_notice (g); +} + +// ギルドエンブレム変更要求 +int mapif_parse_GuildEmblem (int fd, int len, int guild_id, int dummy, + const char *data) +{ + struct guild *g = (struct guild *)numdb_search (guild_db, guild_id); + if (g == NULL) + return 0; + memcpy (g->emblem_data, data, len); + g->emblem_len = len; + g->emblem_id++; + + return mapif_guild_emblem (g); +} + +int mapif_parse_GuildCastleDataLoad (int fd, int castle_id, int index) +{ + struct guild_castle *gc = (struct guild_castle *)numdb_search (castle_db, castle_id); + + if (gc == NULL) + { + return mapif_guild_castle_dataload (castle_id, 0, 0); + } + switch (index) + { + case 1: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->guild_id); + case 2: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->economy); + case 3: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->defense); + case 4: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->triggerE); + case 5: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->triggerD); + case 6: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->nextTime); + case 7: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->payTime); + case 8: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->createTime); + case 9: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->visibleC); + case 10: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->visibleG0); + case 11: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->visibleG1); + case 12: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->visibleG2); + case 13: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->visibleG3); + case 14: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->visibleG4); + case 15: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->visibleG5); + case 16: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->visibleG6); + case 17: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->visibleG7); + case 18: + return mapif_guild_castle_dataload (gc->castle_id, index, gc->Ghp0); // guardian HP [Valaris] + case 19: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->Ghp1); + case 20: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->Ghp2); + case 21: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->Ghp3); + case 22: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->Ghp4); + case 23: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->Ghp5); + case 24: + return mapif_guild_castle_dataload (gc->castle_id, index, + gc->Ghp6); + case 25: + return mapif_guild_castle_dataload (gc->castle_id, index, gc->Ghp7); // end additions [Valaris] + + default: + printf + ("mapif_parse_GuildCastleDataLoad ERROR!! (Not found index=%d)\n", + index); + return 0; + } + + return 0; +} + +int mapif_parse_GuildCastleDataSave (int fd, int castle_id, int index, + int value) +{ + struct guild_castle *gc = (struct guild_castle *)numdb_search (castle_db, castle_id); + + if (gc == NULL) + { + return mapif_guild_castle_datasave (castle_id, index, value); + } + switch (index) + { + case 1: + if (gc->guild_id != value) + { + int gid = (value) ? value : gc->guild_id; + struct guild *g = (struct guild *)numdb_search (guild_db, gid); + inter_log ("guild %s (id=%d) %s castle id=%d\n", + (g) ? g->name : "??", gid, + (value) ? "occupy" : "abandon", index); + } + gc->guild_id = value; + break; + case 2: + gc->economy = value; + break; + case 3: + gc->defense = value; + break; + case 4: + gc->triggerE = value; + break; + case 5: + gc->triggerD = value; + break; + case 6: + gc->nextTime = value; + break; + case 7: + gc->payTime = value; + break; + case 8: + gc->createTime = value; + break; + case 9: + gc->visibleC = value; + break; + case 10: + gc->visibleG0 = value; + break; + case 11: + gc->visibleG1 = value; + break; + case 12: + gc->visibleG2 = value; + break; + case 13: + gc->visibleG3 = value; + break; + case 14: + gc->visibleG4 = value; + break; + case 15: + gc->visibleG5 = value; + break; + case 16: + gc->visibleG6 = value; + break; + case 17: + gc->visibleG7 = value; + break; + case 18: + gc->Ghp0 = value; + break; // guardian HP [Valaris] + case 19: + gc->Ghp1 = value; + break; + case 20: + gc->Ghp2 = value; + break; + case 21: + gc->Ghp3 = value; + break; + case 22: + gc->Ghp4 = value; + break; + case 23: + gc->Ghp5 = value; + break; + case 24: + gc->Ghp6 = value; + break; + case 25: + gc->Ghp7 = value; + break; // end additions [Valaris] + default: + printf + ("mapif_parse_GuildCastleDataSave ERROR!! (Not found index=%d)\n", + index); + return 0; + } + + return mapif_guild_castle_datasave (gc->castle_id, index, value); +} + +// ギルドチェック要求 +int mapif_parse_GuildCheck (int fd, int guild_id, int account_id, int char_id) +{ + return guild_check_conflict (guild_id, account_id, 0 /*char_id*/); +} + +// map server からの通信 +// ・1パケットのみ解析すること +// ・パケット長データはinter.cにセットしておくこと +// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない +// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない +int inter_guild_parse_frommap (int fd) +{ + switch (RFIFOW (fd, 0)) + { + case 0x3030: + mapif_parse_CreateGuild (fd, RFIFOL (fd, 4), RFIFOP (fd, 8), + (struct guild_member *) RFIFOP (fd, 32)); + break; + case 0x3031: + mapif_parse_GuildInfo (fd, RFIFOL (fd, 2)); + break; + case 0x3032: + mapif_parse_GuildAddMember (fd, RFIFOL (fd, 4), + (struct guild_member *) RFIFOP (fd, + 8)); + break; + case 0x3034: + mapif_parse_GuildLeave (fd, RFIFOL (fd, 2), RFIFOL (fd, 6), + RFIFOL (fd, 10), RFIFOB (fd, 14), + RFIFOP (fd, 15)); + break; + case 0x3035: + mapif_parse_GuildChangeMemberInfoShort (fd, RFIFOL (fd, 2), + RFIFOL (fd, 6), + RFIFOL (fd, 10), + RFIFOB (fd, 14), + RFIFOW (fd, 15), + RFIFOW (fd, 17)); + break; + case 0x3036: + mapif_parse_BreakGuild (fd, RFIFOL (fd, 2)); + break; + case 0x3037: + mapif_parse_GuildMessage (fd, RFIFOL (fd, 4), RFIFOL (fd, 8), + RFIFOP (fd, 12), RFIFOW (fd, 2) - 12); + break; + case 0x3038: + mapif_parse_GuildCheck (fd, RFIFOL (fd, 2), RFIFOL (fd, 6), + RFIFOL (fd, 10)); + break; + case 0x3039: + mapif_parse_GuildBasicInfoChange (fd, RFIFOL (fd, 4), + RFIFOW (fd, 8), RFIFOP (fd, 10), + RFIFOW (fd, 2) - 10); + break; + case 0x303A: + mapif_parse_GuildMemberInfoChange (fd, RFIFOL (fd, 4), + RFIFOL (fd, 8), RFIFOL (fd, + 12), + RFIFOW (fd, 16), RFIFOP (fd, + 18), + RFIFOW (fd, 2) - 18); + break; + case 0x303B: + mapif_parse_GuildPosition (fd, RFIFOL (fd, 4), RFIFOL (fd, 8), + (struct guild_position *) RFIFOP (fd, + 12)); + break; + case 0x303C: + mapif_parse_GuildSkillUp (fd, RFIFOL (fd, 2), RFIFOL (fd, 6), + RFIFOL (fd, 10)); + break; + case 0x303D: + mapif_parse_GuildAlliance (fd, RFIFOL (fd, 2), RFIFOL (fd, 6), + RFIFOL (fd, 10), RFIFOL (fd, 14), + RFIFOB (fd, 18)); + break; + case 0x303E: + mapif_parse_GuildNotice (fd, RFIFOL (fd, 2), RFIFOP (fd, 6), + RFIFOP (fd, 66)); + break; + case 0x303F: + mapif_parse_GuildEmblem (fd, RFIFOW (fd, 2) - 12, RFIFOL (fd, 4), + RFIFOL (fd, 8), RFIFOP (fd, 12)); + break; + case 0x3040: + mapif_parse_GuildCastleDataLoad (fd, RFIFOW (fd, 2), + RFIFOB (fd, 4)); + break; + case 0x3041: + mapif_parse_GuildCastleDataSave (fd, RFIFOW (fd, 2), + RFIFOB (fd, 4), RFIFOL (fd, 5)); + break; + + default: + return 0; + } + + return 1; +} + +// マップサーバーの接続時処理 +int inter_guild_mapif_init (int fd) +{ + return mapif_guild_castle_alldataload (fd); +} + +// サーバーから脱退要求(キャラ削除用) +int inter_guild_leave (int guild_id, int account_id, int char_id) +{ + return mapif_parse_GuildLeave (-1, guild_id, account_id, 0 /*char_id*/, 0, + "**サーバー命令**"); +} diff --git a/src/char/int_guild.h b/src/char/int_guild.h deleted file mode 100644 index 5ac9a51..0000000 --- a/src/char/int_guild.h +++ /dev/null @@ -1,16 +0,0 @@ -// $Id: int_guild.h,v 1.1.1.1 2004/09/10 17:26:51 MagicalTux Exp $ -#ifndef _INT_GUILD_H_ -#define _INT_GUILD_H_ - -int inter_guild_init (void); -int inter_guild_save (void); -int inter_guild_parse_frommap (int fd); -struct guild *inter_guild_search (int guild_id); -int inter_guild_mapif_init (int fd); - -int inter_guild_leave (int guild_id, int account_id, int char_id); - -extern char guild_txt[1024]; -extern char castle_txt[1024]; - -#endif diff --git a/src/char/int_guild.hpp b/src/char/int_guild.hpp new file mode 100644 index 0000000..2833e2d --- /dev/null +++ b/src/char/int_guild.hpp @@ -0,0 +1,16 @@ +// $Id: int_guild.h,v 1.1.1.1 2004/09/10 17:26:51 MagicalTux Exp $ +#ifndef INT_GUILD_HPP +#define INT_GUILD_HPP + +int inter_guild_init (void); +int inter_guild_save (void); +int inter_guild_parse_frommap (int fd); +struct guild *inter_guild_search (int guild_id); +int inter_guild_mapif_init (int fd); + +int inter_guild_leave (int guild_id, int account_id, int char_id); + +extern char guild_txt[1024]; +extern char castle_txt[1024]; + +#endif diff --git a/src/char/int_party.c b/src/char/int_party.c deleted file mode 100644 index 6f8d023..0000000 --- a/src/char/int_party.c +++ /dev/null @@ -1,673 +0,0 @@ -// $Id: int_party.c,v 1.1.1.1 2004/09/10 17:26:51 MagicalTux Exp $ -#include "inter.h" -#include "int_party.h" -#include "../common/mmo.h" -#include "char.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/lock.h" -#include -#include -#include - -char party_txt[1024] = "save/party.txt"; - -static struct dbt *party_db; -static int party_newid = 100; - -int mapif_party_broken (int party_id, int flag); -int party_check_empty (struct party *p); -int mapif_parse_PartyLeave (int fd, int party_id, int account_id); - -// パーティデータの文字列への変換 -int inter_party_tostr (char *str, struct party *p) -{ - int i, len; - - len = - sprintf (str, "%d\t%s\t%d,%d\t", p->party_id, p->name, p->exp, - p->item); - for (i = 0; i < MAX_PARTY; i++) - { - struct party_member *m = &p->member[i]; - len += - sprintf (str + len, "%d,%d\t%s\t", m->account_id, m->leader, - ((m->account_id > 0) ? m->name : "NoMember")); - } - - return 0; -} - -// パーティデータの文字列からの変換 -int inter_party_fromstr (char *str, struct party *p) -{ - int i, j; - int tmp_int[16]; - char tmp_str[256]; - - memset (p, 0, sizeof (struct party)); - -// printf("sscanf party main info\n"); - if (sscanf - (str, "%d\t%[^\t]\t%d,%d\t", &tmp_int[0], tmp_str, &tmp_int[1], - &tmp_int[2]) != 4) - return 1; - - p->party_id = tmp_int[0]; - strcpy (p->name, tmp_str); - p->exp = tmp_int[1]; - p->item = tmp_int[2]; -// printf("%d [%s] %d %d\n", tmp_int[0], tmp_str[0], tmp_int[1], tmp_int[2]); - - for (j = 0; j < 3 && str != NULL; j++) - str = strchr (str + 1, '\t'); - - for (i = 0; i < MAX_PARTY; i++) - { - struct party_member *m = &p->member[i]; - if (str == NULL) - return 1; -// printf("sscanf party member info %d\n", i); - - if (sscanf - (str + 1, "%d,%d\t%[^\t]\t", &tmp_int[0], &tmp_int[1], - tmp_str) != 3) - return 1; - - m->account_id = tmp_int[0]; - m->leader = tmp_int[1]; - strncpy (m->name, tmp_str, sizeof (m->name)); -// printf(" %d %d [%s]\n", tmp_int[0], tmp_int[1], tmp_str); - - for (j = 0; j < 2 && str != NULL; j++) - str = strchr (str + 1, '\t'); - } - - return 0; -} - -// パーティデータのロード -int inter_party_init (void) -{ - char line[8192]; - struct party *p; - FILE *fp; - int c = 0; - int i, j; - - party_db = numdb_init (); - - if ((fp = fopen_ (party_txt, "r")) == NULL) - return 1; - - while (fgets (line, sizeof (line) - 1, fp)) - { - j = 0; - if (sscanf (line, "%d\t%%newid%%\n%n", &i, &j) == 1 && j > 0 - && party_newid <= i) - { - party_newid = i; - continue; - } - - CREATE (p, struct party, 1); - if (inter_party_fromstr (line, p) == 0 && p->party_id > 0) - { - if (p->party_id >= party_newid) - party_newid = p->party_id + 1; - numdb_insert (party_db, p->party_id, p); - party_check_empty (p); - } - else - { - printf ("int_party: broken data [%s] line %d\n", party_txt, - c + 1); - free (p); - } - c++; - } - fclose_ (fp); -// printf("int_party: %s read done (%d parties)\n", party_txt, c); - - return 0; -} - -// パーティーデータのセーブ用 -void inter_party_save_sub (db_key_t key, db_val_t data, va_list ap) -{ - char line[8192]; - FILE *fp; - - inter_party_tostr (line, (struct party *) data); - fp = va_arg (ap, FILE *); - fprintf (fp, "%s\n", line); -} - -// パーティーデータのセーブ -int inter_party_save (void) -{ - FILE *fp; - int lock; - - if ((fp = lock_fopen (party_txt, &lock)) == NULL) - { - printf ("int_party: cant write [%s] !!! data is lost !!!\n", - party_txt); - return 1; - } - numdb_foreach (party_db, inter_party_save_sub, fp); -// fprintf(fp, "%d\t%%newid%%\n", party_newid); - lock_fclose (fp, party_txt, &lock); -// printf("int_party: %s saved.\n", party_txt); - - return 0; -} - -// パーティ名検索用 -void search_partyname_sub (db_key_t key, db_val_t data, va_list ap) -{ - struct party *p = (struct party *) data, **dst; - char *str; - - str = va_arg (ap, char *); - dst = va_arg (ap, struct party **); - if (strcasecmp (p->name, str) == 0) - *dst = p; -} - -// パーティ名検索 -struct party *search_partyname (char *str) -{ - struct party *p = NULL; - numdb_foreach (party_db, search_partyname_sub, str, &p); - - return p; -} - -// EXP公平分配できるかチェック -int party_check_exp_share (struct party *p) -{ - int i; - int maxlv = 0, minlv = 0x7fffffff; - - for (i = 0; i < MAX_PARTY; i++) - { - int lv = p->member[i].lv; - if (p->member[i].online) - { - if (lv < minlv) - minlv = lv; - if (maxlv < lv) - maxlv = lv; - } - } - - return (maxlv == 0 || maxlv - minlv <= party_share_level); -} - -// パーティが空かどうかチェック -int party_check_empty (struct party *p) -{ - int i; - -// printf("party check empty %08X\n", (int)p); - for (i = 0; i < MAX_PARTY; i++) - { -// printf("%d acc=%d\n", i, p->member[i].account_id); - if (p->member[i].account_id > 0) - { - return 0; - } - } - // 誰もいないので解散 - mapif_party_broken (p->party_id, 0); - numdb_erase (party_db, p->party_id); - free (p); - - return 1; -} - -// キャラの競合がないかチェック用 -void party_check_conflict_sub (db_key_t key, db_val_t data, va_list ap) -{ - struct party *p = (struct party *) data; - int party_id, account_id, i; - char *nick; - - party_id = va_arg (ap, int); - account_id = va_arg (ap, int); - nick = va_arg (ap, char *); - - if (p->party_id == party_id) // 本来の所属なので問題なし - return; - - for (i = 0; i < MAX_PARTY; i++) - { - if (p->member[i].account_id == account_id - && strcmp (p->member[i].name, nick) == 0) - { - // 別のパーティに偽の所属データがあるので脱退 - printf ("int_party: party conflict! %d %d %d\n", account_id, - party_id, p->party_id); - mapif_parse_PartyLeave (-1, p->party_id, account_id); - } - } -} - -// キャラの競合がないかチェック -int party_check_conflict (int party_id, int account_id, char *nick) -{ - numdb_foreach (party_db, party_check_conflict_sub, party_id, account_id, - nick); - - return 0; -} - -//------------------------------------------------------------------- -// map serverへの通信 - -// パーティ作成可否 -int mapif_party_created (int fd, int account_id, struct party *p) -{ - WFIFOW (fd, 0) = 0x3820; - WFIFOL (fd, 2) = account_id; - if (p != NULL) - { - WFIFOB (fd, 6) = 0; - WFIFOL (fd, 7) = p->party_id; - memcpy (WFIFOP (fd, 11), p->name, 24); - printf ("int_party: created! %d %s\n", p->party_id, p->name); - } - else - { - WFIFOB (fd, 6) = 1; - WFIFOL (fd, 7) = 0; - memcpy (WFIFOP (fd, 11), "error", 24); - } - WFIFOSET (fd, 35); - - return 0; -} - -// パーティ情報見つからず -int mapif_party_noinfo (int fd, int party_id) -{ - WFIFOW (fd, 0) = 0x3821; - WFIFOW (fd, 2) = 8; - WFIFOL (fd, 4) = party_id; - WFIFOSET (fd, 8); - printf ("int_party: info not found %d\n", party_id); - - return 0; -} - -// パーティ情報まとめ送り -int mapif_party_info (int fd, struct party *p) -{ - unsigned char buf[4 + sizeof (struct party)]; - - WBUFW (buf, 0) = 0x3821; - memcpy (buf + 4, p, sizeof (struct party)); - WBUFW (buf, 2) = 4 + sizeof (struct party); - if (fd < 0) - mapif_sendall (buf, WBUFW (buf, 2)); - else - mapif_send (fd, buf, WBUFW (buf, 2)); -// printf("int_party: info %d %s\n", p->party_id, p->name); - - return 0; -} - -// パーティメンバ追加可否 -int mapif_party_memberadded (int fd, int party_id, int account_id, int flag) -{ - WFIFOW (fd, 0) = 0x3822; - WFIFOL (fd, 2) = party_id; - WFIFOL (fd, 6) = account_id; - WFIFOB (fd, 10) = flag; - WFIFOSET (fd, 11); - - return 0; -} - -// パーティ設定変更通知 -int mapif_party_optionchanged (int fd, struct party *p, int account_id, - int flag) -{ - unsigned char buf[15]; - - WBUFW (buf, 0) = 0x3823; - WBUFL (buf, 2) = p->party_id; - WBUFL (buf, 6) = account_id; - WBUFW (buf, 10) = p->exp; - WBUFW (buf, 12) = p->item; - WBUFB (buf, 14) = flag; - if (flag == 0) - mapif_sendall (buf, 15); - else - mapif_send (fd, buf, 15); - printf ("int_party: option changed %d %d %d %d %d\n", p->party_id, - account_id, p->exp, p->item, flag); - - return 0; -} - -// パーティ脱退通知 -int mapif_party_leaved (int party_id, int account_id, char *name) -{ - unsigned char buf[34]; - - WBUFW (buf, 0) = 0x3824; - WBUFL (buf, 2) = party_id; - WBUFL (buf, 6) = account_id; - memcpy (WBUFP (buf, 10), name, 24); - mapif_sendall (buf, 34); - printf ("int_party: party leaved %d %d %s\n", party_id, account_id, name); - - return 0; -} - -// パーティマップ更新通知 -int mapif_party_membermoved (struct party *p, int idx) -{ - unsigned char buf[29]; - - WBUFW (buf, 0) = 0x3825; - WBUFL (buf, 2) = p->party_id; - WBUFL (buf, 6) = p->member[idx].account_id; - memcpy (WBUFP (buf, 10), p->member[idx].map, 16); - WBUFB (buf, 26) = p->member[idx].online; - WBUFW (buf, 27) = p->member[idx].lv; - mapif_sendall (buf, 29); - - return 0; -} - -// パーティ解散通知 -int mapif_party_broken (int party_id, int flag) -{ - unsigned char buf[7]; - WBUFW (buf, 0) = 0x3826; - WBUFL (buf, 2) = party_id; - WBUFB (buf, 6) = flag; - mapif_sendall (buf, 7); - printf ("int_party: broken %d\n", party_id); - - return 0; -} - -// パーティ内発言 -int mapif_party_message (int party_id, int account_id, char *mes, int len) -{ - unsigned char buf[len + 12]; - - WBUFW (buf, 0) = 0x3827; - WBUFW (buf, 2) = len + 12; - WBUFL (buf, 4) = party_id; - WBUFL (buf, 8) = account_id; - memcpy (WBUFP (buf, 12), mes, len); - mapif_sendall (buf, len + 12); - - return 0; -} - -//------------------------------------------------------------------- -// map serverからの通信 - -// パーティ -int mapif_parse_CreateParty (int fd, int account_id, char *name, char *nick, - char *map, int lv) -{ - struct party *p; - int i; - - for (i = 0; i < 24 && name[i]; i++) - { - if (!(name[i] & 0xe0) || name[i] == 0x7f) - { - printf ("int_party: illegal party name [%s]\n", name); - mapif_party_created (fd, account_id, NULL); - return 0; - } - } - - if ((p = search_partyname (name)) != NULL) - { - printf ("int_party: same name party exists [%s]\n", name); - mapif_party_created (fd, account_id, NULL); - return 0; - } - CREATE (p, struct party, 1); - p->party_id = party_newid++; - memcpy (p->name, name, 24); - p->exp = 0; - p->item = 0; - p->member[0].account_id = account_id; - memcpy (p->member[0].name, nick, 24); - memcpy (p->member[0].map, map, 16); - p->member[0].leader = 1; - p->member[0].online = 1; - p->member[0].lv = lv; - - numdb_insert (party_db, p->party_id, p); - - mapif_party_created (fd, account_id, p); - mapif_party_info (fd, p); - - return 0; -} - -// パーティ情報要求 -int mapif_parse_PartyInfo (int fd, int party_id) -{ - struct party *p = (struct party *)numdb_search (party_db, party_id); - if (p != NULL) - mapif_party_info (fd, p); - else - mapif_party_noinfo (fd, party_id); - - return 0; -} - -// パーティ追加要求 -int mapif_parse_PartyAddMember (int fd, int party_id, int account_id, - char *nick, char *map, int lv) -{ - struct party *p = (struct party *)numdb_search (party_db, party_id); - if (p == NULL) - { - mapif_party_memberadded (fd, party_id, account_id, 1); - return 0; - } - - for (int i = 0; i < MAX_PARTY; i++) - { - if (p->member[i].account_id == 0) - { - int flag = 0; - - p->member[i].account_id = account_id; - memcpy (p->member[i].name, nick, 24); - memcpy (p->member[i].map, map, 16); - p->member[i].leader = 0; - p->member[i].online = 1; - p->member[i].lv = lv; - mapif_party_memberadded (fd, party_id, account_id, 0); - mapif_party_info (-1, p); - - if (p->exp > 0 && !party_check_exp_share (p)) - { - p->exp = 0; - flag = 0x01; - } - if (flag) - mapif_party_optionchanged (fd, p, 0, 0); - return 0; - } - } - mapif_party_memberadded (fd, party_id, account_id, 1); - - return 0; -} - -// パーティー設定変更要求 -int mapif_parse_PartyChangeOption (int fd, int party_id, int account_id, - int exp, int item) -{ - struct party *p = (struct party *)numdb_search (party_db, party_id); - if (p == NULL) - return 0; - - p->exp = exp; - int flag = 0; - if (exp > 0 && !party_check_exp_share (p)) - { - flag |= 0x01; - p->exp = 0; - } - - p->item = item; - - mapif_party_optionchanged (fd, p, account_id, flag); - return 0; -} - -// パーティ脱退要求 -int mapif_parse_PartyLeave (int fd, int party_id, int account_id) -{ - struct party *p = (struct party *)numdb_search (party_db, party_id); - if (p != NULL) - { - for (int i = 0; i < MAX_PARTY; i++) - { - if (p->member[i].account_id == account_id) - { - mapif_party_leaved (party_id, account_id, p->member[i].name); - - memset (&p->member[i], 0, sizeof (struct party_member)); - if (party_check_empty (p) == 0) - mapif_party_info (-1, p); // まだ人がいるのでデータ送信 - return 0; - } - } - } - - return 0; -} - -// パーティマップ更新要求 -int mapif_parse_PartyChangeMap (int fd, int party_id, int account_id, - char *map, int online, int lv) -{ - struct party *p = (struct party *)numdb_search (party_db, party_id); - if (p == NULL) - return 0; - - for (int i = 0; i < MAX_PARTY; i++) - { - if (p->member[i].account_id == account_id) - { - int flag = 0; - - memcpy (p->member[i].map, map, 16); - p->member[i].online = online; - p->member[i].lv = lv; - mapif_party_membermoved (p, i); - - if (p->exp > 0 && !party_check_exp_share (p)) - { - p->exp = 0; - flag = 1; - } - if (flag) - mapif_party_optionchanged (fd, p, 0, 0); - break; - } - } - - return 0; -} - -// パーティ解散要求 -int mapif_parse_BreakParty (int fd, int party_id) -{ - struct party *p = (struct party *)numdb_search (party_db, party_id); - if (p == NULL) - return 0; - - numdb_erase (party_db, party_id); - mapif_party_broken (fd, party_id); - - return 0; -} - -// パーティメッセージ送信 -int mapif_parse_PartyMessage (int fd, int party_id, int account_id, char *mes, - int len) -{ - return mapif_party_message (party_id, account_id, mes, len); -} - -// パーティチェック要求 -int mapif_parse_PartyCheck (int fd, int party_id, int account_id, char *nick) -{ - return party_check_conflict (party_id, account_id, nick); -} - -// map server からの通信 -// ・1パケットのみ解析すること -// ・パケット長データはinter.cにセットしておくこと -// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない -// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない -int inter_party_parse_frommap (int fd) -{ - switch (RFIFOW (fd, 0)) - { - case 0x3020: - mapif_parse_CreateParty (fd, RFIFOL (fd, 2), RFIFOP (fd, 6), - RFIFOP (fd, 30), RFIFOP (fd, 54), - RFIFOW (fd, 70)); - break; - case 0x3021: - mapif_parse_PartyInfo (fd, RFIFOL (fd, 2)); - break; - case 0x3022: - mapif_parse_PartyAddMember (fd, RFIFOL (fd, 2), RFIFOL (fd, 6), - RFIFOP (fd, 10), RFIFOP (fd, 34), - RFIFOW (fd, 50)); - break; - case 0x3023: - mapif_parse_PartyChangeOption (fd, RFIFOL (fd, 2), RFIFOL (fd, 6), - RFIFOW (fd, 10), RFIFOW (fd, 12)); - break; - case 0x3024: - mapif_parse_PartyLeave (fd, RFIFOL (fd, 2), RFIFOL (fd, 6)); - break; - case 0x3025: - mapif_parse_PartyChangeMap (fd, RFIFOL (fd, 2), RFIFOL (fd, 6), - RFIFOP (fd, 10), RFIFOB (fd, 26), - RFIFOW (fd, 27)); - break; - case 0x3026: - mapif_parse_BreakParty (fd, RFIFOL (fd, 2)); - break; - case 0x3027: - mapif_parse_PartyMessage (fd, RFIFOL (fd, 4), RFIFOL (fd, 8), - RFIFOP (fd, 12), RFIFOW (fd, 2) - 12); - break; - case 0x3028: - mapif_parse_PartyCheck (fd, RFIFOL (fd, 2), RFIFOL (fd, 6), - RFIFOP (fd, 10)); - break; - default: - return 0; - } - - return 1; -} - -// サーバーから脱退要求(キャラ削除用) -int inter_party_leave (int party_id, int account_id) -{ - return mapif_parse_PartyLeave (-1, party_id, account_id); -} diff --git a/src/char/int_party.cpp b/src/char/int_party.cpp new file mode 100644 index 0000000..7d0e0ce --- /dev/null +++ b/src/char/int_party.cpp @@ -0,0 +1,673 @@ +// $Id: int_party.c,v 1.1.1.1 2004/09/10 17:26:51 MagicalTux Exp $ +#include "inter.hpp" +#include "int_party.hpp" +#include "../common/mmo.hpp" +#include "char.hpp" +#include "../common/socket.hpp" +#include "../common/db.hpp" +#include "../common/lock.hpp" +#include +#include +#include + +char party_txt[1024] = "save/party.txt"; + +static struct dbt *party_db; +static int party_newid = 100; + +int mapif_party_broken (int party_id, int flag); +int party_check_empty (struct party *p); +int mapif_parse_PartyLeave (int fd, int party_id, int account_id); + +// パーティデータの文字列への変換 +int inter_party_tostr (char *str, struct party *p) +{ + int i, len; + + len = + sprintf (str, "%d\t%s\t%d,%d\t", p->party_id, p->name, p->exp, + p->item); + for (i = 0; i < MAX_PARTY; i++) + { + struct party_member *m = &p->member[i]; + len += + sprintf (str + len, "%d,%d\t%s\t", m->account_id, m->leader, + ((m->account_id > 0) ? m->name : "NoMember")); + } + + return 0; +} + +// パーティデータの文字列からの変換 +int inter_party_fromstr (char *str, struct party *p) +{ + int i, j; + int tmp_int[16]; + char tmp_str[256]; + + memset (p, 0, sizeof (struct party)); + +// printf("sscanf party main info\n"); + if (sscanf + (str, "%d\t%[^\t]\t%d,%d\t", &tmp_int[0], tmp_str, &tmp_int[1], + &tmp_int[2]) != 4) + return 1; + + p->party_id = tmp_int[0]; + strcpy (p->name, tmp_str); + p->exp = tmp_int[1]; + p->item = tmp_int[2]; +// printf("%d [%s] %d %d\n", tmp_int[0], tmp_str[0], tmp_int[1], tmp_int[2]); + + for (j = 0; j < 3 && str != NULL; j++) + str = strchr (str + 1, '\t'); + + for (i = 0; i < MAX_PARTY; i++) + { + struct party_member *m = &p->member[i]; + if (str == NULL) + return 1; +// printf("sscanf party member info %d\n", i); + + if (sscanf + (str + 1, "%d,%d\t%[^\t]\t", &tmp_int[0], &tmp_int[1], + tmp_str) != 3) + return 1; + + m->account_id = tmp_int[0]; + m->leader = tmp_int[1]; + strncpy (m->name, tmp_str, sizeof (m->name)); +// printf(" %d %d [%s]\n", tmp_int[0], tmp_int[1], tmp_str); + + for (j = 0; j < 2 && str != NULL; j++) + str = strchr (str + 1, '\t'); + } + + return 0; +} + +// パーティデータのロード +int inter_party_init (void) +{ + char line[8192]; + struct party *p; + FILE *fp; + int c = 0; + int i, j; + + party_db = numdb_init (); + + if ((fp = fopen_ (party_txt, "r")) == NULL) + return 1; + + while (fgets (line, sizeof (line) - 1, fp)) + { + j = 0; + if (sscanf (line, "%d\t%%newid%%\n%n", &i, &j) == 1 && j > 0 + && party_newid <= i) + { + party_newid = i; + continue; + } + + CREATE (p, struct party, 1); + if (inter_party_fromstr (line, p) == 0 && p->party_id > 0) + { + if (p->party_id >= party_newid) + party_newid = p->party_id + 1; + numdb_insert (party_db, p->party_id, p); + party_check_empty (p); + } + else + { + printf ("int_party: broken data [%s] line %d\n", party_txt, + c + 1); + free (p); + } + c++; + } + fclose_ (fp); +// printf("int_party: %s read done (%d parties)\n", party_txt, c); + + return 0; +} + +// パーティーデータのセーブ用 +void inter_party_save_sub (db_key_t key, db_val_t data, va_list ap) +{ + char line[8192]; + FILE *fp; + + inter_party_tostr (line, (struct party *) data); + fp = va_arg (ap, FILE *); + fprintf (fp, "%s\n", line); +} + +// パーティーデータのセーブ +int inter_party_save (void) +{ + FILE *fp; + int lock; + + if ((fp = lock_fopen (party_txt, &lock)) == NULL) + { + printf ("int_party: cant write [%s] !!! data is lost !!!\n", + party_txt); + return 1; + } + numdb_foreach (party_db, inter_party_save_sub, fp); +// fprintf(fp, "%d\t%%newid%%\n", party_newid); + lock_fclose (fp, party_txt, &lock); +// printf("int_party: %s saved.\n", party_txt); + + return 0; +} + +// パーティ名検索用 +void search_partyname_sub (db_key_t key, db_val_t data, va_list ap) +{ + struct party *p = (struct party *) data, **dst; + char *str; + + str = va_arg (ap, char *); + dst = va_arg (ap, struct party **); + if (strcasecmp (p->name, str) == 0) + *dst = p; +} + +// パーティ名検索 +struct party *search_partyname (char *str) +{ + struct party *p = NULL; + numdb_foreach (party_db, search_partyname_sub, str, &p); + + return p; +} + +// EXP公平分配できるかチェック +int party_check_exp_share (struct party *p) +{ + int i; + int maxlv = 0, minlv = 0x7fffffff; + + for (i = 0; i < MAX_PARTY; i++) + { + int lv = p->member[i].lv; + if (p->member[i].online) + { + if (lv < minlv) + minlv = lv; + if (maxlv < lv) + maxlv = lv; + } + } + + return (maxlv == 0 || maxlv - minlv <= party_share_level); +} + +// パーティが空かどうかチェック +int party_check_empty (struct party *p) +{ + int i; + +// printf("party check empty %08X\n", (int)p); + for (i = 0; i < MAX_PARTY; i++) + { +// printf("%d acc=%d\n", i, p->member[i].account_id); + if (p->member[i].account_id > 0) + { + return 0; + } + } + // 誰もいないので解散 + mapif_party_broken (p->party_id, 0); + numdb_erase (party_db, p->party_id); + free (p); + + return 1; +} + +// キャラの競合がないかチェック用 +void party_check_conflict_sub (db_key_t key, db_val_t data, va_list ap) +{ + struct party *p = (struct party *) data; + int party_id, account_id, i; + char *nick; + + party_id = va_arg (ap, int); + account_id = va_arg (ap, int); + nick = va_arg (ap, char *); + + if (p->party_id == party_id) // 本来の所属なので問題なし + return; + + for (i = 0; i < MAX_PARTY; i++) + { + if (p->member[i].account_id == account_id + && strcmp (p->member[i].name, nick) == 0) + { + // 別のパーティに偽の所属データがあるので脱退 + printf ("int_party: party conflict! %d %d %d\n", account_id, + party_id, p->party_id); + mapif_parse_PartyLeave (-1, p->party_id, account_id); + } + } +} + +// キャラの競合がないかチェック +int party_check_conflict (int party_id, int account_id, char *nick) +{ + numdb_foreach (party_db, party_check_conflict_sub, party_id, account_id, + nick); + + return 0; +} + +//------------------------------------------------------------------- +// map serverへの通信 + +// パーティ作成可否 +int mapif_party_created (int fd, int account_id, struct party *p) +{ + WFIFOW (fd, 0) = 0x3820; + WFIFOL (fd, 2) = account_id; + if (p != NULL) + { + WFIFOB (fd, 6) = 0; + WFIFOL (fd, 7) = p->party_id; + memcpy (WFIFOP (fd, 11), p->name, 24); + printf ("int_party: created! %d %s\n", p->party_id, p->name); + } + else + { + WFIFOB (fd, 6) = 1; + WFIFOL (fd, 7) = 0; + memcpy (WFIFOP (fd, 11), "error", 24); + } + WFIFOSET (fd, 35); + + return 0; +} + +// パーティ情報見つからず +int mapif_party_noinfo (int fd, int party_id) +{ + WFIFOW (fd, 0) = 0x3821; + WFIFOW (fd, 2) = 8; + WFIFOL (fd, 4) = party_id; + WFIFOSET (fd, 8); + printf ("int_party: info not found %d\n", party_id); + + return 0; +} + +// パーティ情報まとめ送り +int mapif_party_info (int fd, struct party *p) +{ + unsigned char buf[4 + sizeof (struct party)]; + + WBUFW (buf, 0) = 0x3821; + memcpy (buf + 4, p, sizeof (struct party)); + WBUFW (buf, 2) = 4 + sizeof (struct party); + if (fd < 0) + mapif_sendall (buf, WBUFW (buf, 2)); + else + mapif_send (fd, buf, WBUFW (buf, 2)); +// printf("int_party: info %d %s\n", p->party_id, p->name); + + return 0; +} + +// パーティメンバ追加可否 +int mapif_party_memberadded (int fd, int party_id, int account_id, int flag) +{ + WFIFOW (fd, 0) = 0x3822; + WFIFOL (fd, 2) = party_id; + WFIFOL (fd, 6) = account_id; + WFIFOB (fd, 10) = flag; + WFIFOSET (fd, 11); + + return 0; +} + +// パーティ設定変更通知 +int mapif_party_optionchanged (int fd, struct party *p, int account_id, + int flag) +{ + unsigned char buf[15]; + + WBUFW (buf, 0) = 0x3823; + WBUFL (buf, 2) = p->party_id; + WBUFL (buf, 6) = account_id; + WBUFW (buf, 10) = p->exp; + WBUFW (buf, 12) = p->item; + WBUFB (buf, 14) = flag; + if (flag == 0) + mapif_sendall (buf, 15); + else + mapif_send (fd, buf, 15); + printf ("int_party: option changed %d %d %d %d %d\n", p->party_id, + account_id, p->exp, p->item, flag); + + return 0; +} + +// パーティ脱退通知 +int mapif_party_leaved (int party_id, int account_id, char *name) +{ + unsigned char buf[34]; + + WBUFW (buf, 0) = 0x3824; + WBUFL (buf, 2) = party_id; + WBUFL (buf, 6) = account_id; + memcpy (WBUFP (buf, 10), name, 24); + mapif_sendall (buf, 34); + printf ("int_party: party leaved %d %d %s\n", party_id, account_id, name); + + return 0; +} + +// パーティマップ更新通知 +int mapif_party_membermoved (struct party *p, int idx) +{ + unsigned char buf[29]; + + WBUFW (buf, 0) = 0x3825; + WBUFL (buf, 2) = p->party_id; + WBUFL (buf, 6) = p->member[idx].account_id; + memcpy (WBUFP (buf, 10), p->member[idx].map, 16); + WBUFB (buf, 26) = p->member[idx].online; + WBUFW (buf, 27) = p->member[idx].lv; + mapif_sendall (buf, 29); + + return 0; +} + +// パーティ解散通知 +int mapif_party_broken (int party_id, int flag) +{ + unsigned char buf[7]; + WBUFW (buf, 0) = 0x3826; + WBUFL (buf, 2) = party_id; + WBUFB (buf, 6) = flag; + mapif_sendall (buf, 7); + printf ("int_party: broken %d\n", party_id); + + return 0; +} + +// パーティ内発言 +int mapif_party_message (int party_id, int account_id, char *mes, int len) +{ + unsigned char buf[len + 12]; + + WBUFW (buf, 0) = 0x3827; + WBUFW (buf, 2) = len + 12; + WBUFL (buf, 4) = party_id; + WBUFL (buf, 8) = account_id; + memcpy (WBUFP (buf, 12), mes, len); + mapif_sendall (buf, len + 12); + + return 0; +} + +//------------------------------------------------------------------- +// map serverからの通信 + +// パーティ +int mapif_parse_CreateParty (int fd, int account_id, char *name, char *nick, + char *map, int lv) +{ + struct party *p; + int i; + + for (i = 0; i < 24 && name[i]; i++) + { + if (!(name[i] & 0xe0) || name[i] == 0x7f) + { + printf ("int_party: illegal party name [%s]\n", name); + mapif_party_created (fd, account_id, NULL); + return 0; + } + } + + if ((p = search_partyname (name)) != NULL) + { + printf ("int_party: same name party exists [%s]\n", name); + mapif_party_created (fd, account_id, NULL); + return 0; + } + CREATE (p, struct party, 1); + p->party_id = party_newid++; + memcpy (p->name, name, 24); + p->exp = 0; + p->item = 0; + p->member[0].account_id = account_id; + memcpy (p->member[0].name, nick, 24); + memcpy (p->member[0].map, map, 16); + p->member[0].leader = 1; + p->member[0].online = 1; + p->member[0].lv = lv; + + numdb_insert (party_db, p->party_id, p); + + mapif_party_created (fd, account_id, p); + mapif_party_info (fd, p); + + return 0; +} + +// パーティ情報要求 +int mapif_parse_PartyInfo (int fd, int party_id) +{ + struct party *p = (struct party *)numdb_search (party_db, party_id); + if (p != NULL) + mapif_party_info (fd, p); + else + mapif_party_noinfo (fd, party_id); + + return 0; +} + +// パーティ追加要求 +int mapif_parse_PartyAddMember (int fd, int party_id, int account_id, + char *nick, char *map, int lv) +{ + struct party *p = (struct party *)numdb_search (party_db, party_id); + if (p == NULL) + { + mapif_party_memberadded (fd, party_id, account_id, 1); + return 0; + } + + for (int i = 0; i < MAX_PARTY; i++) + { + if (p->member[i].account_id == 0) + { + int flag = 0; + + p->member[i].account_id = account_id; + memcpy (p->member[i].name, nick, 24); + memcpy (p->member[i].map, map, 16); + p->member[i].leader = 0; + p->member[i].online = 1; + p->member[i].lv = lv; + mapif_party_memberadded (fd, party_id, account_id, 0); + mapif_party_info (-1, p); + + if (p->exp > 0 && !party_check_exp_share (p)) + { + p->exp = 0; + flag = 0x01; + } + if (flag) + mapif_party_optionchanged (fd, p, 0, 0); + return 0; + } + } + mapif_party_memberadded (fd, party_id, account_id, 1); + + return 0; +} + +// パーティー設定変更要求 +int mapif_parse_PartyChangeOption (int fd, int party_id, int account_id, + int exp, int item) +{ + struct party *p = (struct party *)numdb_search (party_db, party_id); + if (p == NULL) + return 0; + + p->exp = exp; + int flag = 0; + if (exp > 0 && !party_check_exp_share (p)) + { + flag |= 0x01; + p->exp = 0; + } + + p->item = item; + + mapif_party_optionchanged (fd, p, account_id, flag); + return 0; +} + +// パーティ脱退要求 +int mapif_parse_PartyLeave (int fd, int party_id, int account_id) +{ + struct party *p = (struct party *)numdb_search (party_db, party_id); + if (p != NULL) + { + for (int i = 0; i < MAX_PARTY; i++) + { + if (p->member[i].account_id == account_id) + { + mapif_party_leaved (party_id, account_id, p->member[i].name); + + memset (&p->member[i], 0, sizeof (struct party_member)); + if (party_check_empty (p) == 0) + mapif_party_info (-1, p); // まだ人がいるのでデータ送信 + return 0; + } + } + } + + return 0; +} + +// パーティマップ更新要求 +int mapif_parse_PartyChangeMap (int fd, int party_id, int account_id, + char *map, int online, int lv) +{ + struct party *p = (struct party *)numdb_search (party_db, party_id); + if (p == NULL) + return 0; + + for (int i = 0; i < MAX_PARTY; i++) + { + if (p->member[i].account_id == account_id) + { + int flag = 0; + + memcpy (p->member[i].map, map, 16); + p->member[i].online = online; + p->member[i].lv = lv; + mapif_party_membermoved (p, i); + + if (p->exp > 0 && !party_check_exp_share (p)) + { + p->exp = 0; + flag = 1; + } + if (flag) + mapif_party_optionchanged (fd, p, 0, 0); + break; + } + } + + return 0; +} + +// パーティ解散要求 +int mapif_parse_BreakParty (int fd, int party_id) +{ + struct party *p = (struct party *)numdb_search (party_db, party_id); + if (p == NULL) + return 0; + + numdb_erase (party_db, party_id); + mapif_party_broken (fd, party_id); + + return 0; +} + +// パーティメッセージ送信 +int mapif_parse_PartyMessage (int fd, int party_id, int account_id, char *mes, + int len) +{ + return mapif_party_message (party_id, account_id, mes, len); +} + +// パーティチェック要求 +int mapif_parse_PartyCheck (int fd, int party_id, int account_id, char *nick) +{ + return party_check_conflict (party_id, account_id, nick); +} + +// map server からの通信 +// ・1パケットのみ解析すること +// ・パケット長データはinter.cにセットしておくこと +// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない +// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない +int inter_party_parse_frommap (int fd) +{ + switch (RFIFOW (fd, 0)) + { + case 0x3020: + mapif_parse_CreateParty (fd, RFIFOL (fd, 2), RFIFOP (fd, 6), + RFIFOP (fd, 30), RFIFOP (fd, 54), + RFIFOW (fd, 70)); + break; + case 0x3021: + mapif_parse_PartyInfo (fd, RFIFOL (fd, 2)); + break; + case 0x3022: + mapif_parse_PartyAddMember (fd, RFIFOL (fd, 2), RFIFOL (fd, 6), + RFIFOP (fd, 10), RFIFOP (fd, 34), + RFIFOW (fd, 50)); + break; + case 0x3023: + mapif_parse_PartyChangeOption (fd, RFIFOL (fd, 2), RFIFOL (fd, 6), + RFIFOW (fd, 10), RFIFOW (fd, 12)); + break; + case 0x3024: + mapif_parse_PartyLeave (fd, RFIFOL (fd, 2), RFIFOL (fd, 6)); + break; + case 0x3025: + mapif_parse_PartyChangeMap (fd, RFIFOL (fd, 2), RFIFOL (fd, 6), + RFIFOP (fd, 10), RFIFOB (fd, 26), + RFIFOW (fd, 27)); + break; + case 0x3026: + mapif_parse_BreakParty (fd, RFIFOL (fd, 2)); + break; + case 0x3027: + mapif_parse_PartyMessage (fd, RFIFOL (fd, 4), RFIFOL (fd, 8), + RFIFOP (fd, 12), RFIFOW (fd, 2) - 12); + break; + case 0x3028: + mapif_parse_PartyCheck (fd, RFIFOL (fd, 2), RFIFOL (fd, 6), + RFIFOP (fd, 10)); + break; + default: + return 0; + } + + return 1; +} + +// サーバーから脱退要求(キャラ削除用) +int inter_party_leave (int party_id, int account_id) +{ + return mapif_parse_PartyLeave (-1, party_id, account_id); +} diff --git a/src/char/int_party.h b/src/char/int_party.h deleted file mode 100644 index 2007ed5..0000000 --- a/src/char/int_party.h +++ /dev/null @@ -1,14 +0,0 @@ -// $Id: int_party.h,v 1.1.1.1 2004/09/10 17:26:51 MagicalTux Exp $ -#ifndef _INT_PARTY_H_ -#define _INT_PARTY_H_ - -int inter_party_init (void); -int inter_party_save (void); - -int inter_party_parse_frommap (int fd); - -int inter_party_leave (int party_id, int account_id); - -extern char party_txt[1024]; - -#endif diff --git a/src/char/int_party.hpp b/src/char/int_party.hpp new file mode 100644 index 0000000..93e8887 --- /dev/null +++ b/src/char/int_party.hpp @@ -0,0 +1,14 @@ +// $Id: int_party.h,v 1.1.1.1 2004/09/10 17:26:51 MagicalTux Exp $ +#ifndef INT_PARTY_HPP +#define INT_PARTY_HPP + +int inter_party_init (void); +int inter_party_save (void); + +int inter_party_parse_frommap (int fd); + +int inter_party_leave (int party_id, int account_id); + +extern char party_txt[1024]; + +#endif diff --git a/src/char/int_storage.c b/src/char/int_storage.c deleted file mode 100644 index e565572..0000000 --- a/src/char/int_storage.c +++ /dev/null @@ -1,576 +0,0 @@ -// $Id: int_storage.c,v 1.1.1.1 2004/09/10 17:26:51 MagicalTux Exp $ - -#include -#include - -#include "../common/mmo.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/lock.h" -#include "char.h" -#include "inter.h" -#include "int_storage.h" -#include "int_guild.h" - -// ファイル名のデフォルト -// inter_config_read()で再設定される -char storage_txt[1024] = "save/storage.txt"; -char guild_storage_txt[1024] = "save/g_storage.txt"; - -static struct dbt *storage_db; -static struct dbt *guild_storage_db; - -// 倉庫データを文字列に変換 -int storage_tostr (char *str, struct storage *p) -{ - int i, f = 0; - char *str_p = str; - str_p += sprintf (str_p, "%d,%d\t", p->account_id, p->storage_amount); - - for (i = 0; i < MAX_STORAGE; i++) - if ((p->storage_[i].nameid) && (p->storage_[i].amount)) - { - str_p += sprintf (str_p, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d ", - p->storage_[i].id, p->storage_[i].nameid, - p->storage_[i].amount, p->storage_[i].equip, - p->storage_[i].identify, p->storage_[i].refine, - p->storage_[i].attribute, - p->storage_[i].card[0], p->storage_[i].card[1], - p->storage_[i].card[2], p->storage_[i].card[3]); - f++; - } - - *(str_p++) = '\t'; - - *str_p = '\0'; - if (!f) - str[0] = 0; - return 0; -} - -// 文字列を倉庫データに変換 -int storage_fromstr (char *str, struct storage *p) -{ - int tmp_int[256]; - int set, next, len, i; - - set = sscanf (str, "%d,%d%n", &tmp_int[0], &tmp_int[1], &next); - p->storage_amount = tmp_int[1]; - - if (set != 2) - return 1; - if (str[next] == '\n' || str[next] == '\r') - return 0; - next++; - for (i = 0; str[next] && str[next] != '\t' && i < MAX_STORAGE; i++) - { - if (sscanf (str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], - &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], - &tmp_int[10], &len) == 12) - { - p->storage_[i].id = tmp_int[0]; - p->storage_[i].nameid = tmp_int[1]; - p->storage_[i].amount = tmp_int[2]; - p->storage_[i].equip = tmp_int[3]; - p->storage_[i].identify = tmp_int[4]; - p->storage_[i].refine = tmp_int[5]; - p->storage_[i].attribute = tmp_int[6]; - p->storage_[i].card[0] = tmp_int[7]; - p->storage_[i].card[1] = tmp_int[8]; - p->storage_[i].card[2] = tmp_int[9]; - p->storage_[i].card[3] = tmp_int[10]; - next += len; - if (str[next] == ' ') - next++; - } - - else if (sscanf (str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], - &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], - &len) == 11) - { - p->storage_[i].id = tmp_int[0]; - p->storage_[i].nameid = tmp_int[1]; - p->storage_[i].amount = tmp_int[2]; - p->storage_[i].equip = tmp_int[3]; - p->storage_[i].identify = tmp_int[4]; - p->storage_[i].refine = tmp_int[5]; - p->storage_[i].attribute = tmp_int[6]; - p->storage_[i].card[0] = tmp_int[7]; - p->storage_[i].card[1] = tmp_int[8]; - p->storage_[i].card[2] = tmp_int[9]; - p->storage_[i].card[3] = tmp_int[10]; - next += len; - if (str[next] == ' ') - next++; - } - - else - return 1; - } - if (i >= MAX_STORAGE && str[next] && str[next] != '\t') - printf - ("storage_fromstr: Found a storage line with more items than MAX_STORAGE (%d), remaining items have been discarded!\n", - MAX_STORAGE); - return 0; -} - -int guild_storage_tostr (char *str, struct guild_storage *p) -{ - int i, f = 0; - char *str_p = str; - str_p += sprintf (str, "%d,%d\t", p->guild_id, p->storage_amount); - - for (i = 0; i < MAX_GUILD_STORAGE; i++) - if ((p->storage_[i].nameid) && (p->storage_[i].amount)) - { - str_p += sprintf (str_p, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d ", - p->storage_[i].id, p->storage_[i].nameid, - p->storage_[i].amount, p->storage_[i].equip, - p->storage_[i].identify, p->storage_[i].refine, - p->storage_[i].attribute, - p->storage_[i].card[0], p->storage_[i].card[1], - p->storage_[i].card[2], p->storage_[i].card[3]); - f++; - } - - *(str_p++) = '\t'; - - *str_p = '\0'; - if (!f) - str[0] = 0; - return 0; -} - -int guild_storage_fromstr (char *str, struct guild_storage *p) -{ - int tmp_int[256]; - int set, next, len, i; - - set = sscanf (str, "%d,%d%n", &tmp_int[0], &tmp_int[1], &next); - p->storage_amount = tmp_int[1]; - - if (set != 2) - return 1; - if (str[next] == '\n' || str[next] == '\r') - return 0; - next++; - for (i = 0; str[next] && str[next] != '\t' && i < MAX_GUILD_STORAGE; i++) - { - if (sscanf (str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], - &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], - &tmp_int[10], &len) == 12) - { - p->storage_[i].id = tmp_int[0]; - p->storage_[i].nameid = tmp_int[1]; - p->storage_[i].amount = tmp_int[2]; - p->storage_[i].equip = tmp_int[3]; - p->storage_[i].identify = tmp_int[4]; - p->storage_[i].refine = tmp_int[5]; - p->storage_[i].attribute = tmp_int[6]; - p->storage_[i].card[0] = tmp_int[7]; - p->storage_[i].card[1] = tmp_int[8]; - p->storage_[i].card[2] = tmp_int[9]; - p->storage_[i].card[3] = tmp_int[10]; - next += len; - if (str[next] == ' ') - next++; - } - - else if (sscanf (str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], - &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], - &len) == 11) - { - p->storage_[i].id = tmp_int[0]; - p->storage_[i].nameid = tmp_int[1]; - p->storage_[i].amount = tmp_int[2]; - p->storage_[i].equip = tmp_int[3]; - p->storage_[i].identify = tmp_int[4]; - p->storage_[i].refine = tmp_int[5]; - p->storage_[i].attribute = tmp_int[6]; - p->storage_[i].card[0] = tmp_int[7]; - p->storage_[i].card[1] = tmp_int[8]; - p->storage_[i].card[2] = tmp_int[9]; - p->storage_[i].card[3] = tmp_int[10]; - next += len; - if (str[next] == ' ') - next++; - } - - else - return 1; - } - if (i >= MAX_GUILD_STORAGE && str[next] && str[next] != '\t') - printf - ("guild_storage_fromstr: Found a storage line with more items than MAX_GUILD_STORAGE (%d), remaining items have been discarded!\n", - MAX_GUILD_STORAGE); - return 0; -} - -// アカウントから倉庫データインデックスを得る(新規倉庫追加可能) -struct storage *account2storage (int account_id) -{ - struct storage *s; - s = (struct storage *) numdb_search (storage_db, account_id); - if (s == NULL) - { - CREATE (s, struct storage, 1); - memset (s, 0, sizeof (struct storage)); - s->account_id = account_id; - numdb_insert (storage_db, s->account_id, s); - } - return s; -} - -struct guild_storage *guild2storage (int guild_id) -{ - struct guild_storage *gs = NULL; - if (inter_guild_search (guild_id) != NULL) - { - gs = (struct guild_storage *) numdb_search (guild_storage_db, - guild_id); - if (gs == NULL) - { - CREATE (gs, struct guild_storage, 1); - gs->guild_id = guild_id; - numdb_insert (guild_storage_db, gs->guild_id, gs); - } - } - return gs; -} - -//--------------------------------------------------------- -// 倉庫データを読み込む -int inter_storage_init (void) -{ - char line[65536]; - int c = 0, tmp_int; - struct storage *s; - struct guild_storage *gs; - FILE *fp; - - storage_db = numdb_init (); - - fp = fopen_ (storage_txt, "r"); - if (fp == NULL) - { - printf ("cant't read : %s\n", storage_txt); - return 1; - } - while (fgets (line, 65535, fp)) - { - sscanf (line, "%d", &tmp_int); - CREATE (s, struct storage, 1); - s->account_id = tmp_int; - if (s->account_id > 0 && storage_fromstr (line, s) == 0) - { - numdb_insert (storage_db, s->account_id, s); - } - else - { - printf ("int_storage: broken data [%s] line %d\n", storage_txt, - c); - free (s); - } - c++; - } - fclose_ (fp); - - c = 0; - guild_storage_db = numdb_init (); - - fp = fopen_ (guild_storage_txt, "r"); - if (fp == NULL) - { - printf ("cant't read : %s\n", guild_storage_txt); - return 1; - } - while (fgets (line, 65535, fp)) - { - sscanf (line, "%d", &tmp_int); - CREATE (gs, struct guild_storage, 1); - gs->guild_id = tmp_int; - if (gs->guild_id > 0 && guild_storage_fromstr (line, gs) == 0) - { - numdb_insert (guild_storage_db, gs->guild_id, gs); - } - else - { - printf ("int_storage: broken data [%s] line %d\n", - guild_storage_txt, c); - free (gs); - } - c++; - } - fclose_ (fp); - - return 0; -} - -void storage_db_final (db_key_t k, db_val_t data, va_list ap) -{ - struct storage *p = (struct storage *) data; - if (p) - free (p); -} - -void guild_storage_db_final (db_key_t k, db_val_t data, va_list ap) -{ - struct guild_storage *p = (struct guild_storage *) data; - if (p) - free (p); -} - -void inter_storage_final (void) -{ - numdb_final (storage_db, storage_db_final); - numdb_final (guild_storage_db, guild_storage_db_final); - return; -} - -void inter_storage_save_sub (db_key_t key, db_val_t data, va_list ap) -{ - char line[65536]; - FILE *fp; - storage_tostr (line, (struct storage *) data); - fp = va_arg (ap, FILE *); - if (*line) - fprintf (fp, "%s\n", line); -} - -//--------------------------------------------------------- -// 倉庫データを書き込む -int inter_storage_save (void) -{ - FILE *fp; - int lock; - - if (!storage_db) - return 1; - - if ((fp = lock_fopen (storage_txt, &lock)) == NULL) - { - printf ("int_storage: cant write [%s] !!! data is lost !!!\n", - storage_txt); - return 1; - } - numdb_foreach (storage_db, inter_storage_save_sub, fp); - lock_fclose (fp, storage_txt, &lock); -// printf("int_storage: %s saved.\n",storage_txt); - return 0; -} - -void inter_guild_storage_save_sub (db_key_t key, db_val_t data, va_list ap) -{ - char line[65536]; - FILE *fp; - - if (inter_guild_search (((struct guild_storage *) data)->guild_id) != - NULL) - { - guild_storage_tostr (line, (struct guild_storage *) data); - fp = va_arg (ap, FILE *); - if (*line) - fprintf (fp, "%s\n", line); - } -} - -//--------------------------------------------------------- -// 倉庫データを書き込む -int inter_guild_storage_save (void) -{ - FILE *fp; - int lock; - - if (!guild_storage_db) - return 1; - - if ((fp = lock_fopen (guild_storage_txt, &lock)) == NULL) - { - printf ("int_storage: cant write [%s] !!! data is lost !!!\n", - guild_storage_txt); - return 1; - } - numdb_foreach (guild_storage_db, inter_guild_storage_save_sub, fp); - lock_fclose (fp, guild_storage_txt, &lock); -// printf("int_storage: %s saved.\n",guild_storage_txt); - return 0; -} - -// 倉庫データ削除 -int inter_storage_delete (int account_id) -{ - struct storage *s = - (struct storage *) numdb_search (storage_db, account_id); - if (s) - { - numdb_erase (storage_db, account_id); - free (s); - } - return 0; -} - -// ギルド倉庫データ削除 -int inter_guild_storage_delete (int guild_id) -{ - struct guild_storage *gs = - (struct guild_storage *) numdb_search (guild_storage_db, guild_id); - if (gs) - { - numdb_erase (guild_storage_db, guild_id); - free (gs); - } - return 0; -} - -//--------------------------------------------------------- -// map serverへの通信 - -// 倉庫データの送信 -int mapif_load_storage (int fd, int account_id) -{ - struct storage *s = account2storage (account_id); - WFIFOW (fd, 0) = 0x3810; - WFIFOW (fd, 2) = sizeof (struct storage) + 8; - WFIFOL (fd, 4) = account_id; - memcpy (WFIFOP (fd, 8), s, sizeof (struct storage)); - WFIFOSET (fd, WFIFOW (fd, 2)); - return 0; -} - -// 倉庫データ保存完了送信 -int mapif_save_storage_ack (int fd, int account_id) -{ - WFIFOW (fd, 0) = 0x3811; - WFIFOL (fd, 2) = account_id; - WFIFOB (fd, 6) = 0; - WFIFOSET (fd, 7); - return 0; -} - -int mapif_load_guild_storage (int fd, int account_id, int guild_id) -{ - struct guild_storage *gs = guild2storage (guild_id); - WFIFOW (fd, 0) = 0x3818; - if (gs) - { - WFIFOW (fd, 2) = sizeof (struct guild_storage) + 12; - WFIFOL (fd, 4) = account_id; - WFIFOL (fd, 8) = guild_id; - memcpy (WFIFOP (fd, 12), gs, sizeof (struct guild_storage)); - } - else - { - WFIFOW (fd, 2) = 12; - WFIFOL (fd, 4) = account_id; - WFIFOL (fd, 8) = 0; - } - WFIFOSET (fd, WFIFOW (fd, 2)); - - return 0; -} - -int mapif_save_guild_storage_ack (int fd, int account_id, int guild_id, - int fail) -{ - WFIFOW (fd, 0) = 0x3819; - WFIFOL (fd, 2) = account_id; - WFIFOL (fd, 6) = guild_id; - WFIFOB (fd, 10) = fail; - WFIFOSET (fd, 11); - return 0; -} - -//--------------------------------------------------------- -// map serverからの通信 - -// 倉庫データ要求受信 -int mapif_parse_LoadStorage (int fd) -{ - mapif_load_storage (fd, RFIFOL (fd, 2)); - return 0; -} - -// 倉庫データ受信&保存 -int mapif_parse_SaveStorage (int fd) -{ - struct storage *s; - int account_id = RFIFOL (fd, 4); - int len = RFIFOW (fd, 2); - if (sizeof (struct storage) != len - 8) - { - printf ("inter storage: data size error %d %d\n", - sizeof (struct storage), len - 8); - } - else - { - s = account2storage (account_id); - memcpy (s, RFIFOP (fd, 8), sizeof (struct storage)); - mapif_save_storage_ack (fd, account_id); - } - return 0; -} - -int mapif_parse_LoadGuildStorage (int fd) -{ - mapif_load_guild_storage (fd, RFIFOL (fd, 2), RFIFOL (fd, 6)); - return 0; -} - -int mapif_parse_SaveGuildStorage (int fd) -{ - struct guild_storage *gs; - int guild_id = RFIFOL (fd, 8); - int len = RFIFOW (fd, 2); - if (sizeof (struct guild_storage) != len - 12) - { - printf ("inter storage: data size error %d %d\n", - sizeof (struct guild_storage), len - 12); - } - else - { - gs = guild2storage (guild_id); - if (gs) - { - memcpy (gs, RFIFOP (fd, 12), sizeof (struct guild_storage)); - mapif_save_guild_storage_ack (fd, RFIFOL (fd, 4), guild_id, 0); - } - else - mapif_save_guild_storage_ack (fd, RFIFOL (fd, 4), guild_id, 1); - } - return 0; -} - -// map server からの通信 -// ・1パケットのみ解析すること -// ・パケット長データはinter.cにセットしておくこと -// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない -// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない -int inter_storage_parse_frommap (int fd) -{ - switch (RFIFOW (fd, 0)) - { - case 0x3010: - mapif_parse_LoadStorage (fd); - break; - case 0x3011: - mapif_parse_SaveStorage (fd); - break; - case 0x3018: - mapif_parse_LoadGuildStorage (fd); - break; - case 0x3019: - mapif_parse_SaveGuildStorage (fd); - break; - default: - return 0; - } - return 1; -} diff --git a/src/char/int_storage.cpp b/src/char/int_storage.cpp new file mode 100644 index 0000000..b197213 --- /dev/null +++ b/src/char/int_storage.cpp @@ -0,0 +1,576 @@ +// $Id: int_storage.c,v 1.1.1.1 2004/09/10 17:26:51 MagicalTux Exp $ + +#include +#include + +#include "../common/mmo.hpp" +#include "../common/socket.hpp" +#include "../common/db.hpp" +#include "../common/lock.hpp" +#include "char.hpp" +#include "inter.hpp" +#include "int_storage.hpp" +#include "int_guild.hpp" + +// ファイル名のデフォルト +// inter_config_read()で再設定される +char storage_txt[1024] = "save/storage.txt"; +char guild_storage_txt[1024] = "save/g_storage.txt"; + +static struct dbt *storage_db; +static struct dbt *guild_storage_db; + +// 倉庫データを文字列に変換 +int storage_tostr (char *str, struct storage *p) +{ + int i, f = 0; + char *str_p = str; + str_p += sprintf (str_p, "%d,%d\t", p->account_id, p->storage_amount); + + for (i = 0; i < MAX_STORAGE; i++) + if ((p->storage_[i].nameid) && (p->storage_[i].amount)) + { + str_p += sprintf (str_p, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d ", + p->storage_[i].id, p->storage_[i].nameid, + p->storage_[i].amount, p->storage_[i].equip, + p->storage_[i].identify, p->storage_[i].refine, + p->storage_[i].attribute, + p->storage_[i].card[0], p->storage_[i].card[1], + p->storage_[i].card[2], p->storage_[i].card[3]); + f++; + } + + *(str_p++) = '\t'; + + *str_p = '\0'; + if (!f) + str[0] = 0; + return 0; +} + +// 文字列を倉庫データに変換 +int storage_fromstr (char *str, struct storage *p) +{ + int tmp_int[256]; + int set, next, len, i; + + set = sscanf (str, "%d,%d%n", &tmp_int[0], &tmp_int[1], &next); + p->storage_amount = tmp_int[1]; + + if (set != 2) + return 1; + if (str[next] == '\n' || str[next] == '\r') + return 0; + next++; + for (i = 0; str[next] && str[next] != '\t' && i < MAX_STORAGE; i++) + { + if (sscanf (str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n", + &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], + &tmp_int[4], &tmp_int[5], &tmp_int[6], + &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], + &tmp_int[10], &len) == 12) + { + p->storage_[i].id = tmp_int[0]; + p->storage_[i].nameid = tmp_int[1]; + p->storage_[i].amount = tmp_int[2]; + p->storage_[i].equip = tmp_int[3]; + p->storage_[i].identify = tmp_int[4]; + p->storage_[i].refine = tmp_int[5]; + p->storage_[i].attribute = tmp_int[6]; + p->storage_[i].card[0] = tmp_int[7]; + p->storage_[i].card[1] = tmp_int[8]; + p->storage_[i].card[2] = tmp_int[9]; + p->storage_[i].card[3] = tmp_int[10]; + next += len; + if (str[next] == ' ') + next++; + } + + else if (sscanf (str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n", + &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], + &tmp_int[4], &tmp_int[5], &tmp_int[6], + &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], + &len) == 11) + { + p->storage_[i].id = tmp_int[0]; + p->storage_[i].nameid = tmp_int[1]; + p->storage_[i].amount = tmp_int[2]; + p->storage_[i].equip = tmp_int[3]; + p->storage_[i].identify = tmp_int[4]; + p->storage_[i].refine = tmp_int[5]; + p->storage_[i].attribute = tmp_int[6]; + p->storage_[i].card[0] = tmp_int[7]; + p->storage_[i].card[1] = tmp_int[8]; + p->storage_[i].card[2] = tmp_int[9]; + p->storage_[i].card[3] = tmp_int[10]; + next += len; + if (str[next] == ' ') + next++; + } + + else + return 1; + } + if (i >= MAX_STORAGE && str[next] && str[next] != '\t') + printf + ("storage_fromstr: Found a storage line with more items than MAX_STORAGE (%d), remaining items have been discarded!\n", + MAX_STORAGE); + return 0; +} + +int guild_storage_tostr (char *str, struct guild_storage *p) +{ + int i, f = 0; + char *str_p = str; + str_p += sprintf (str, "%d,%d\t", p->guild_id, p->storage_amount); + + for (i = 0; i < MAX_GUILD_STORAGE; i++) + if ((p->storage_[i].nameid) && (p->storage_[i].amount)) + { + str_p += sprintf (str_p, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d ", + p->storage_[i].id, p->storage_[i].nameid, + p->storage_[i].amount, p->storage_[i].equip, + p->storage_[i].identify, p->storage_[i].refine, + p->storage_[i].attribute, + p->storage_[i].card[0], p->storage_[i].card[1], + p->storage_[i].card[2], p->storage_[i].card[3]); + f++; + } + + *(str_p++) = '\t'; + + *str_p = '\0'; + if (!f) + str[0] = 0; + return 0; +} + +int guild_storage_fromstr (char *str, struct guild_storage *p) +{ + int tmp_int[256]; + int set, next, len, i; + + set = sscanf (str, "%d,%d%n", &tmp_int[0], &tmp_int[1], &next); + p->storage_amount = tmp_int[1]; + + if (set != 2) + return 1; + if (str[next] == '\n' || str[next] == '\r') + return 0; + next++; + for (i = 0; str[next] && str[next] != '\t' && i < MAX_GUILD_STORAGE; i++) + { + if (sscanf (str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n", + &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], + &tmp_int[4], &tmp_int[5], &tmp_int[6], + &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], + &tmp_int[10], &len) == 12) + { + p->storage_[i].id = tmp_int[0]; + p->storage_[i].nameid = tmp_int[1]; + p->storage_[i].amount = tmp_int[2]; + p->storage_[i].equip = tmp_int[3]; + p->storage_[i].identify = tmp_int[4]; + p->storage_[i].refine = tmp_int[5]; + p->storage_[i].attribute = tmp_int[6]; + p->storage_[i].card[0] = tmp_int[7]; + p->storage_[i].card[1] = tmp_int[8]; + p->storage_[i].card[2] = tmp_int[9]; + p->storage_[i].card[3] = tmp_int[10]; + next += len; + if (str[next] == ' ') + next++; + } + + else if (sscanf (str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n", + &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], + &tmp_int[4], &tmp_int[5], &tmp_int[6], + &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], + &len) == 11) + { + p->storage_[i].id = tmp_int[0]; + p->storage_[i].nameid = tmp_int[1]; + p->storage_[i].amount = tmp_int[2]; + p->storage_[i].equip = tmp_int[3]; + p->storage_[i].identify = tmp_int[4]; + p->storage_[i].refine = tmp_int[5]; + p->storage_[i].attribute = tmp_int[6]; + p->storage_[i].card[0] = tmp_int[7]; + p->storage_[i].card[1] = tmp_int[8]; + p->storage_[i].card[2] = tmp_int[9]; + p->storage_[i].card[3] = tmp_int[10]; + next += len; + if (str[next] == ' ') + next++; + } + + else + return 1; + } + if (i >= MAX_GUILD_STORAGE && str[next] && str[next] != '\t') + printf + ("guild_storage_fromstr: Found a storage line with more items than MAX_GUILD_STORAGE (%d), remaining items have been discarded!\n", + MAX_GUILD_STORAGE); + return 0; +} + +// アカウントから倉庫データインデックスを得る(新規倉庫追加可能) +struct storage *account2storage (int account_id) +{ + struct storage *s; + s = (struct storage *) numdb_search (storage_db, account_id); + if (s == NULL) + { + CREATE (s, struct storage, 1); + memset (s, 0, sizeof (struct storage)); + s->account_id = account_id; + numdb_insert (storage_db, s->account_id, s); + } + return s; +} + +struct guild_storage *guild2storage (int guild_id) +{ + struct guild_storage *gs = NULL; + if (inter_guild_search (guild_id) != NULL) + { + gs = (struct guild_storage *) numdb_search (guild_storage_db, + guild_id); + if (gs == NULL) + { + CREATE (gs, struct guild_storage, 1); + gs->guild_id = guild_id; + numdb_insert (guild_storage_db, gs->guild_id, gs); + } + } + return gs; +} + +//--------------------------------------------------------- +// 倉庫データを読み込む +int inter_storage_init (void) +{ + char line[65536]; + int c = 0, tmp_int; + struct storage *s; + struct guild_storage *gs; + FILE *fp; + + storage_db = numdb_init (); + + fp = fopen_ (storage_txt, "r"); + if (fp == NULL) + { + printf ("cant't read : %s\n", storage_txt); + return 1; + } + while (fgets (line, 65535, fp)) + { + sscanf (line, "%d", &tmp_int); + CREATE (s, struct storage, 1); + s->account_id = tmp_int; + if (s->account_id > 0 && storage_fromstr (line, s) == 0) + { + numdb_insert (storage_db, s->account_id, s); + } + else + { + printf ("int_storage: broken data [%s] line %d\n", storage_txt, + c); + free (s); + } + c++; + } + fclose_ (fp); + + c = 0; + guild_storage_db = numdb_init (); + + fp = fopen_ (guild_storage_txt, "r"); + if (fp == NULL) + { + printf ("cant't read : %s\n", guild_storage_txt); + return 1; + } + while (fgets (line, 65535, fp)) + { + sscanf (line, "%d", &tmp_int); + CREATE (gs, struct guild_storage, 1); + gs->guild_id = tmp_int; + if (gs->guild_id > 0 && guild_storage_fromstr (line, gs) == 0) + { + numdb_insert (guild_storage_db, gs->guild_id, gs); + } + else + { + printf ("int_storage: broken data [%s] line %d\n", + guild_storage_txt, c); + free (gs); + } + c++; + } + fclose_ (fp); + + return 0; +} + +void storage_db_final (db_key_t k, db_val_t data, va_list ap) +{ + struct storage *p = (struct storage *) data; + if (p) + free (p); +} + +void guild_storage_db_final (db_key_t k, db_val_t data, va_list ap) +{ + struct guild_storage *p = (struct guild_storage *) data; + if (p) + free (p); +} + +void inter_storage_final (void) +{ + numdb_final (storage_db, storage_db_final); + numdb_final (guild_storage_db, guild_storage_db_final); + return; +} + +void inter_storage_save_sub (db_key_t key, db_val_t data, va_list ap) +{ + char line[65536]; + FILE *fp; + storage_tostr (line, (struct storage *) data); + fp = va_arg (ap, FILE *); + if (*line) + fprintf (fp, "%s\n", line); +} + +//--------------------------------------------------------- +// 倉庫データを書き込む +int inter_storage_save (void) +{ + FILE *fp; + int lock; + + if (!storage_db) + return 1; + + if ((fp = lock_fopen (storage_txt, &lock)) == NULL) + { + printf ("int_storage: cant write [%s] !!! data is lost !!!\n", + storage_txt); + return 1; + } + numdb_foreach (storage_db, inter_storage_save_sub, fp); + lock_fclose (fp, storage_txt, &lock); +// printf("int_storage: %s saved.\n",storage_txt); + return 0; +} + +void inter_guild_storage_save_sub (db_key_t key, db_val_t data, va_list ap) +{ + char line[65536]; + FILE *fp; + + if (inter_guild_search (((struct guild_storage *) data)->guild_id) != + NULL) + { + guild_storage_tostr (line, (struct guild_storage *) data); + fp = va_arg (ap, FILE *); + if (*line) + fprintf (fp, "%s\n", line); + } +} + +//--------------------------------------------------------- +// 倉庫データを書き込む +int inter_guild_storage_save (void) +{ + FILE *fp; + int lock; + + if (!guild_storage_db) + return 1; + + if ((fp = lock_fopen (guild_storage_txt, &lock)) == NULL) + { + printf ("int_storage: cant write [%s] !!! data is lost !!!\n", + guild_storage_txt); + return 1; + } + numdb_foreach (guild_storage_db, inter_guild_storage_save_sub, fp); + lock_fclose (fp, guild_storage_txt, &lock); +// printf("int_storage: %s saved.\n",guild_storage_txt); + return 0; +} + +// 倉庫データ削除 +int inter_storage_delete (int account_id) +{ + struct storage *s = + (struct storage *) numdb_search (storage_db, account_id); + if (s) + { + numdb_erase (storage_db, account_id); + free (s); + } + return 0; +} + +// ギルド倉庫データ削除 +int inter_guild_storage_delete (int guild_id) +{ + struct guild_storage *gs = + (struct guild_storage *) numdb_search (guild_storage_db, guild_id); + if (gs) + { + numdb_erase (guild_storage_db, guild_id); + free (gs); + } + return 0; +} + +//--------------------------------------------------------- +// map serverへの通信 + +// 倉庫データの送信 +int mapif_load_storage (int fd, int account_id) +{ + struct storage *s = account2storage (account_id); + WFIFOW (fd, 0) = 0x3810; + WFIFOW (fd, 2) = sizeof (struct storage) + 8; + WFIFOL (fd, 4) = account_id; + memcpy (WFIFOP (fd, 8), s, sizeof (struct storage)); + WFIFOSET (fd, WFIFOW (fd, 2)); + return 0; +} + +// 倉庫データ保存完了送信 +int mapif_save_storage_ack (int fd, int account_id) +{ + WFIFOW (fd, 0) = 0x3811; + WFIFOL (fd, 2) = account_id; + WFIFOB (fd, 6) = 0; + WFIFOSET (fd, 7); + return 0; +} + +int mapif_load_guild_storage (int fd, int account_id, int guild_id) +{ + struct guild_storage *gs = guild2storage (guild_id); + WFIFOW (fd, 0) = 0x3818; + if (gs) + { + WFIFOW (fd, 2) = sizeof (struct guild_storage) + 12; + WFIFOL (fd, 4) = account_id; + WFIFOL (fd, 8) = guild_id; + memcpy (WFIFOP (fd, 12), gs, sizeof (struct guild_storage)); + } + else + { + WFIFOW (fd, 2) = 12; + WFIFOL (fd, 4) = account_id; + WFIFOL (fd, 8) = 0; + } + WFIFOSET (fd, WFIFOW (fd, 2)); + + return 0; +} + +int mapif_save_guild_storage_ack (int fd, int account_id, int guild_id, + int fail) +{ + WFIFOW (fd, 0) = 0x3819; + WFIFOL (fd, 2) = account_id; + WFIFOL (fd, 6) = guild_id; + WFIFOB (fd, 10) = fail; + WFIFOSET (fd, 11); + return 0; +} + +//--------------------------------------------------------- +// map serverからの通信 + +// 倉庫データ要求受信 +int mapif_parse_LoadStorage (int fd) +{ + mapif_load_storage (fd, RFIFOL (fd, 2)); + return 0; +} + +// 倉庫データ受信&保存 +int mapif_parse_SaveStorage (int fd) +{ + struct storage *s; + int account_id = RFIFOL (fd, 4); + int len = RFIFOW (fd, 2); + if (sizeof (struct storage) != len - 8) + { + printf ("inter storage: data size error %d %d\n", + sizeof (struct storage), len - 8); + } + else + { + s = account2storage (account_id); + memcpy (s, RFIFOP (fd, 8), sizeof (struct storage)); + mapif_save_storage_ack (fd, account_id); + } + return 0; +} + +int mapif_parse_LoadGuildStorage (int fd) +{ + mapif_load_guild_storage (fd, RFIFOL (fd, 2), RFIFOL (fd, 6)); + return 0; +} + +int mapif_parse_SaveGuildStorage (int fd) +{ + struct guild_storage *gs; + int guild_id = RFIFOL (fd, 8); + int len = RFIFOW (fd, 2); + if (sizeof (struct guild_storage) != len - 12) + { + printf ("inter storage: data size error %d %d\n", + sizeof (struct guild_storage), len - 12); + } + else + { + gs = guild2storage (guild_id); + if (gs) + { + memcpy (gs, RFIFOP (fd, 12), sizeof (struct guild_storage)); + mapif_save_guild_storage_ack (fd, RFIFOL (fd, 4), guild_id, 0); + } + else + mapif_save_guild_storage_ack (fd, RFIFOL (fd, 4), guild_id, 1); + } + return 0; +} + +// map server からの通信 +// ・1パケットのみ解析すること +// ・パケット長データはinter.cにセットしておくこと +// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない +// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない +int inter_storage_parse_frommap (int fd) +{ + switch (RFIFOW (fd, 0)) + { + case 0x3010: + mapif_parse_LoadStorage (fd); + break; + case 0x3011: + mapif_parse_SaveStorage (fd); + break; + case 0x3018: + mapif_parse_LoadGuildStorage (fd); + break; + case 0x3019: + mapif_parse_SaveGuildStorage (fd); + break; + default: + return 0; + } + return 1; +} diff --git a/src/char/int_storage.h b/src/char/int_storage.h deleted file mode 100644 index f1859c6..0000000 --- a/src/char/int_storage.h +++ /dev/null @@ -1,18 +0,0 @@ -// $Id: int_storage.h,v 1.1.1.1 2004/09/10 17:26:51 MagicalTux Exp $ -#ifndef _INT_STORAGE_H_ -#define _INT_STORAGE_H_ - -int inter_storage_init (void); -void inter_storage_final (void); -int inter_storage_save (void); -int inter_guild_storage_save (void); -int inter_storage_delete (int account_id); -int inter_guild_storage_delete (int guild_id); -struct storage *account2storage (int account_id); - -int inter_storage_parse_frommap (int fd); - -extern char storage_txt[1024]; -extern char guild_storage_txt[1024]; - -#endif diff --git a/src/char/int_storage.hpp b/src/char/int_storage.hpp new file mode 100644 index 0000000..9986f2d --- /dev/null +++ b/src/char/int_storage.hpp @@ -0,0 +1,18 @@ +// $Id: int_storage.h,v 1.1.1.1 2004/09/10 17:26:51 MagicalTux Exp $ +#ifndef INT_STORAGE_HPP +#define INT_STORAGE_HPP + +int inter_storage_init (void); +void inter_storage_final (void); +int inter_storage_save (void); +int inter_guild_storage_save (void); +int inter_storage_delete (int account_id); +int inter_guild_storage_delete (int guild_id); +struct storage *account2storage (int account_id); + +int inter_storage_parse_frommap (int fd); + +extern char storage_txt[1024]; +extern char guild_storage_txt[1024]; + +#endif diff --git a/src/char/inter.c b/src/char/inter.c deleted file mode 100644 index e886bf6..0000000 --- a/src/char/inter.c +++ /dev/null @@ -1,635 +0,0 @@ -// $Id: inter.c,v 1.1.1.1 2004/09/10 17:26:51 MagicalTux Exp $ -#include "../common/mmo.h" -#include "char.h" -#include "../common/socket.h" -#include "../common/timer.h" -#include "../common/db.h" -#include -#include - -#include "inter.h" -#include "int_party.h" -#include "int_guild.h" -#include "int_storage.h" -#include "../common/lock.h" - -#define WISDATA_TTL (60*1000) // Existence time of Wisp/page data (60 seconds) - // that is the waiting time of answers of all map-servers -#define WISDELLIST_MAX 256 // Number of elements of Wisp/page data deletion list - -char inter_log_filename[1024] = "log/inter.log"; - -char accreg_txt[1024] = "save/accreg.txt"; -static struct dbt *accreg_db = NULL; - -struct accreg -{ - int account_id, reg_num; - struct global_reg reg[ACCOUNT_REG_NUM]; -}; - -int party_share_level = 10; - -// 送信パケット長リスト -int inter_send_packet_length[] = { - -1, -1, 27, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - -1, 7, 0, 0, 0, 0, 0, 0, -1, 11, 0, 0, 0, 0, 0, 0, - 35, -1, 11, 15, 34, 29, 7, -1, 0, 0, 0, 0, 0, 0, 0, 0, - 10, -1, 15, 0, 79, 19, 7, -1, 0, -1, -1, -1, 14, 67, 186, -1, - 9, 9, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 11, -1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -// 受信パケット長リスト -int inter_recv_packet_length[] = { - -1, -1, 7, -1, -1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 6, -1, 0, 0, 0, 0, 0, 0, 10, -1, 0, 0, 0, 0, 0, 0, - 72, 6, 52, 14, 10, 29, 6, -1, 34, 0, 0, 0, 0, 0, 0, 0, - -1, 6, -1, 0, 55, 19, 6, -1, 14, -1, -1, -1, 14, 19, 186, -1, - 5, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 48, 14, -1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -struct WisData -{ - int id, fd, count, len; - unsigned long tick; - unsigned char src[24], dst[24], msg[1024]; -}; -static struct dbt *wis_db = NULL; -static int wis_dellist[WISDELLIST_MAX], wis_delnum; - -//-------------------------------------------------------- - -// アカウント変数を文字列へ変換 -int inter_accreg_tostr (char *str, struct accreg *reg) -{ - int j; - char *p = str; - - p += sprintf (p, "%d\t", reg->account_id); - for (j = 0; j < reg->reg_num; j++) - { - p += sprintf (p, "%s,%d ", reg->reg[j].str, reg->reg[j].value); - } - - return 0; -} - -// アカウント変数を文字列から変換 -int inter_accreg_fromstr (const char *str, struct accreg *reg) -{ - int j, v, n; - char buf[128]; - const char *p = str; - - if (sscanf (p, "%d\t%n", ®->account_id, &n) != 1 - || reg->account_id <= 0) - return 1; - - for (j = 0, p += n; j < ACCOUNT_REG_NUM; j++, p += n) - { - if (sscanf (p, "%[^,],%d %n", buf, &v, &n) != 2) - break; - memcpy (reg->reg[j].str, buf, 32); - reg->reg[j].value = v; - } - reg->reg_num = j; - - return 0; -} - -// アカウント変数の読み込み -int inter_accreg_init (void) -{ - char line[8192]; - FILE *fp; - int c = 0; - struct accreg *reg; - - accreg_db = numdb_init (); - - if ((fp = fopen_ (accreg_txt, "r")) == NULL) - return 1; - while (fgets (line, sizeof (line) - 1, fp)) - { - line[sizeof (line) - 1] = '\0'; - CREATE (reg, struct accreg, 1); - if (inter_accreg_fromstr (line, reg) == 0 && reg->account_id > 0) - { - numdb_insert (accreg_db, reg->account_id, reg); - } - else - { - printf ("inter: accreg: broken data [%s] line %d\n", accreg_txt, - c); - free (reg); - } - c++; - } - fclose_ (fp); -// printf("inter: %s read done (%d)\n", accreg_txt, c); - - return 0; -} - -// アカウント変数のセーブ用 -void inter_accreg_save_sub (db_key_t key, db_val_t data, va_list ap) -{ - char line[8192]; - FILE *fp; - struct accreg *reg = (struct accreg *) data; - - if (reg->reg_num > 0) - { - inter_accreg_tostr (line, reg); - fp = va_arg (ap, FILE *); - fprintf (fp, "%s\n", line); - } -} - -// アカウント変数のセーブ -int inter_accreg_save (void) -{ - FILE *fp; - int lock; - - if ((fp = lock_fopen (accreg_txt, &lock)) == NULL) - { - printf ("int_accreg: cant write [%s] !!! data is lost !!!\n", - accreg_txt); - return 1; - } - numdb_foreach (accreg_db, inter_accreg_save_sub, fp); - lock_fclose (fp, accreg_txt, &lock); -// printf("inter: %s saved.\n", accreg_txt); - - return 0; -} - -//-------------------------------------------------------- - -/*========================================== - * 設定ファイルを読み込む - *------------------------------------------ - */ -int inter_config_read (const char *cfgName) -{ - char line[1024], w1[1024], w2[1024]; - FILE *fp; - - fp = fopen_ (cfgName, "r"); - if (fp == NULL) - { - printf ("file not found: %s\n", cfgName); - return 1; - } - while (fgets (line, sizeof (line) - 1, fp)) - { - if (line[0] == '/' && line[1] == '/') - continue; - line[sizeof (line) - 1] = '\0'; - - if (sscanf (line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - if (strcasecmp (w1, "storage_txt") == 0) - { - strncpy (storage_txt, w2, sizeof (storage_txt)); - } - else if (strcasecmp (w1, "party_txt") == 0) - { - strncpy (party_txt, w2, sizeof (party_txt)); - } - else if (strcasecmp (w1, "guild_txt") == 0) - { - strncpy (guild_txt, w2, sizeof (guild_txt)); - } - else if (strcasecmp (w1, "castle_txt") == 0) - { - strncpy (castle_txt, w2, sizeof (castle_txt)); - } - else if (strcasecmp (w1, "accreg_txt") == 0) - { - strncpy (accreg_txt, w2, sizeof (accreg_txt)); - } - else if (strcasecmp (w1, "guild_storage_txt") == 0) - { - strncpy (guild_storage_txt, w2, sizeof (guild_storage_txt)); - } - else if (strcasecmp (w1, "party_share_level") == 0) - { - party_share_level = atoi (w2); - if (party_share_level < 0) - party_share_level = 0; - } - else if (strcasecmp (w1, "inter_log_filename") == 0) - { - strncpy (inter_log_filename, w2, sizeof (inter_log_filename)); - } - else if (strcasecmp (w1, "import") == 0) - { - inter_config_read (w2); - } - } - fclose_ (fp); - - return 0; -} - -// ログ書き出し -int inter_log (char *fmt, ...) -{ - FILE *logfp; - va_list ap; - - va_start (ap, fmt); - logfp = fopen_ (inter_log_filename, "a"); - if (logfp) - { - vfprintf (logfp, fmt, ap); - fclose_ (logfp); - } - va_end (ap); - - return 0; -} - -// セーブ -int inter_save (void) -{ - inter_party_save (); - inter_guild_save (); - inter_storage_save (); - inter_guild_storage_save (); - inter_accreg_save (); - - return 0; -} - -// 初期化 -int inter_init (const char *file) -{ - inter_config_read (file); - - wis_db = numdb_init (); - - inter_party_init (); - inter_guild_init (); - inter_storage_init (); - inter_accreg_init (); - - return 0; -} - -// マップサーバー接続 -int inter_mapif_init (int fd) -{ - inter_guild_mapif_init (fd); - - return 0; -} - -//-------------------------------------------------------- -// sended packets to map-server - -// GMメッセージ送信 -int mapif_GMmessage (unsigned char *mes, int len) -{ - unsigned char buf[len]; - - WBUFW (buf, 0) = 0x3800; - WBUFW (buf, 2) = len; - memcpy (WBUFP (buf, 4), mes, len - 4); - mapif_sendall (buf, len); -// printf("inter server: GM:%d %s\n", len, mes); - - return 0; -} - -// Wisp/page transmission to all map-server -int mapif_wis_message (struct WisData *wd) -{ - unsigned char buf[56 + wd->len]; - - WBUFW (buf, 0) = 0x3801; - WBUFW (buf, 2) = 56 + wd->len; - WBUFL (buf, 4) = wd->id; - memcpy (WBUFP (buf, 8), wd->src, 24); - memcpy (WBUFP (buf, 32), wd->dst, 24); - memcpy (WBUFP (buf, 56), wd->msg, wd->len); - wd->count = mapif_sendall (buf, WBUFW (buf, 2)); - - return 0; -} - -// Wisp/page transmission result to map-server -int mapif_wis_end (struct WisData *wd, int flag) -{ - unsigned char buf[27]; - - WBUFW (buf, 0) = 0x3802; - memcpy (WBUFP (buf, 2), wd->src, 24); - WBUFB (buf, 26) = flag; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - mapif_send (wd->fd, buf, 27); -// printf("inter server wis_end: flag: %d\n", flag); - - return 0; -} - -// アカウント変数送信 -int mapif_account_reg (int fd, unsigned char *src) -{ - unsigned char buf[WBUFW (src, 2)]; - - memcpy (WBUFP (buf, 0), src, WBUFW (src, 2)); - WBUFW (buf, 0) = 0x3804; - mapif_sendallwos (fd, buf, WBUFW (buf, 2)); - - return 0; -} - -// アカウント変数要求返信 -int mapif_account_reg_reply (int fd, int account_id) -{ - struct accreg *reg = (struct accreg *)numdb_search (accreg_db, account_id); - - WFIFOW (fd, 0) = 0x3804; - WFIFOL (fd, 4) = account_id; - if (reg == NULL) - { - WFIFOW (fd, 2) = 8; - } - else - { - int j, p; - for (j = 0, p = 8; j < reg->reg_num; j++, p += 36) - { - memcpy (WFIFOP (fd, p), reg->reg[j].str, 32); - WFIFOL (fd, p + 32) = reg->reg[j].value; - } - WFIFOW (fd, 2) = p; - } - WFIFOSET (fd, WFIFOW (fd, 2)); - - return 0; -} - -//-------------------------------------------------------- - -// Existence check of WISP data -void check_ttl_wisdata_sub (db_key_t key, db_val_t data, va_list ap) -{ - unsigned long tick; - struct WisData *wd = (struct WisData *) data; - tick = va_arg (ap, unsigned long); - - if (DIFF_TICK (tick, wd->tick) > WISDATA_TTL - && wis_delnum < WISDELLIST_MAX) - wis_dellist[wis_delnum++] = wd->id; -} - -int check_ttl_wisdata (void) -{ - unsigned long tick = gettick (); - int i; - - do - { - wis_delnum = 0; - numdb_foreach (wis_db, check_ttl_wisdata_sub, tick); - for (i = 0; i < wis_delnum; i++) - { - struct WisData *wd = (struct WisData *)numdb_search (wis_db, wis_dellist[i]); - printf ("inter: wis data id=%d time out : from %s to %s\n", - wd->id, wd->src, wd->dst); - // removed. not send information after a timeout. Just no answer for the player - //mapif_wis_end(wd, 1); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - numdb_erase (wis_db, wd->id); - free (wd); - } - } - while (wis_delnum >= WISDELLIST_MAX); - - return 0; -} - -//-------------------------------------------------------- -// received packets from map-server - -// GMメッセージ送信 -int mapif_parse_GMmessage (int fd) -{ - mapif_GMmessage (RFIFOP (fd, 4), RFIFOW (fd, 2)); - - return 0; -} - -// Wisp/page request to send -int mapif_parse_WisRequest (int fd) -{ - struct WisData *wd; - static int wisid = 0; - int index; - - if (RFIFOW (fd, 2) - 52 >= sizeof (wd->msg)) - { - printf ("inter: Wis message size too long.\n"); - return 0; - } - else if (RFIFOW (fd, 2) - 52 <= 0) - { // normaly, impossible, but who knows... - printf ("inter: Wis message doesn't exist.\n"); - return 0; - } - - // search if character exists before to ask all map-servers - if ((index = search_character_index (RFIFOP (fd, 28))) == -1) - { - unsigned char buf[27]; - WBUFW (buf, 0) = 0x3802; - memcpy (WBUFP (buf, 2), RFIFOP (fd, 4), 24); - WBUFB (buf, 26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - mapif_send (fd, buf, 27); - // Character exists. So, ask all map-servers - } - else - { - // to be sure of the correct name, rewrite it - memset (RFIFOP (fd, 28), 0, 24); - strncpy (RFIFOP (fd, 28), search_character_name (index), 24); - // if source is destination, don't ask other servers. - if (strcmp (RFIFOP (fd, 4), RFIFOP (fd, 28)) == 0) - { - unsigned char buf[27]; - WBUFW (buf, 0) = 0x3802; - memcpy (WBUFP (buf, 2), RFIFOP (fd, 4), 24); - WBUFB (buf, 26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - mapif_send (fd, buf, 27); - } - else - { - CREATE (wd, struct WisData, 1); - - // Whether the failure of previous wisp/page transmission (timeout) - check_ttl_wisdata (); - - wd->id = ++wisid; - wd->fd = fd; - wd->len = RFIFOW (fd, 2) - 52; - memcpy (wd->src, RFIFOP (fd, 4), 24); - memcpy (wd->dst, RFIFOP (fd, 28), 24); - memcpy (wd->msg, RFIFOP (fd, 52), wd->len); - wd->tick = gettick (); - numdb_insert (wis_db, wd->id, wd); - mapif_wis_message (wd); - } - } - - return 0; -} - -// Wisp/page transmission result -int mapif_parse_WisReply (int fd) -{ - int id = RFIFOL (fd, 2), flag = RFIFOB (fd, 6); - struct WisData *wd = (struct WisData *)numdb_search (wis_db, id); - - if (wd == NULL) - return 0; // This wisp was probably suppress before, because it was timeout of because of target was found on another map-server - - if ((--wd->count) <= 0 || flag != 1) - { - mapif_wis_end (wd, flag); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - numdb_erase (wis_db, id); - free (wd); - } - - return 0; -} - -// Received wisp message from map-server for ALL gm (just copy the message and resends it to ALL map-servers) -int mapif_parse_WisToGM (int fd) -{ - unsigned char buf[RFIFOW (fd, 2)]; // 0x3003/0x3803 .w .24B .w .?B - - memcpy (WBUFP (buf, 0), RFIFOP (fd, 0), RFIFOW (fd, 2)); - WBUFW (buf, 0) = 0x3803; - mapif_sendall (buf, RFIFOW (fd, 2)); - - return 0; -} - -// アカウント変数保存要求 -int mapif_parse_AccReg (int fd) -{ - int j, p; - struct accreg *reg = (struct accreg*)numdb_search (accreg_db, (numdb_key_t)RFIFOL (fd, 4)); - - if (reg == NULL) - { - CREATE (reg, struct accreg, 1); - reg->account_id = RFIFOL (fd, 4); - numdb_insert (accreg_db, (numdb_key_t)RFIFOL (fd, 4), reg); - } - - for (j = 0, p = 8; j < ACCOUNT_REG_NUM && p < RFIFOW (fd, 2); - j++, p += 36) - { - memcpy (reg->reg[j].str, RFIFOP (fd, p), 32); - reg->reg[j].value = RFIFOL (fd, p + 32); - } - reg->reg_num = j; - - mapif_account_reg (fd, RFIFOP (fd, 0)); // 他のMAPサーバーに送信 - - return 0; -} - -// アカウント変数送信要求 -int mapif_parse_AccRegRequest (int fd) -{ -// printf("mapif: accreg request\n"); - return mapif_account_reg_reply (fd, RFIFOL (fd, 2)); -} - -//-------------------------------------------------------- - -// map server からの通信(1パケットのみ解析すること) -// エラーなら0(false)、処理できたなら1、 -// パケット長が足りなければ2をかえさなければならない -int inter_parse_frommap (int fd) -{ - int cmd = RFIFOW (fd, 0); - int len = 0; - - // inter鯖管轄かを調べる - if (cmd < 0x3000 - || cmd >= - 0x3000 + - (sizeof (inter_recv_packet_length) / - sizeof (inter_recv_packet_length[0]))) - return 0; - - // パケット長を調べる - if ((len = - inter_check_length (fd, - inter_recv_packet_length[cmd - 0x3000])) == 0) - return 2; - - switch (cmd) - { - case 0x3000: - mapif_parse_GMmessage (fd); - break; - case 0x3001: - mapif_parse_WisRequest (fd); - break; - case 0x3002: - mapif_parse_WisReply (fd); - break; - case 0x3003: - mapif_parse_WisToGM (fd); - break; - case 0x3004: - mapif_parse_AccReg (fd); - break; - case 0x3005: - mapif_parse_AccRegRequest (fd); - break; - default: - if (inter_party_parse_frommap (fd)) - break; - if (inter_guild_parse_frommap (fd)) - break; - if (inter_storage_parse_frommap (fd)) - break; - return 0; - } - RFIFOSKIP (fd, len); - - return 1; -} - -// RFIFOのパケット長確認 -// 必要パケット長があればパケット長、まだ足りなければ0 -int inter_check_length (int fd, int length) -{ - if (length == -1) - { // 可変パケット長 - if (RFIFOREST (fd) < 4) // パケット長が未着 - return 0; - length = RFIFOW (fd, 2); - } - - if (RFIFOREST (fd) < length) // パケットが未着 - return 0; - - return length; -} diff --git a/src/char/inter.cpp b/src/char/inter.cpp new file mode 100644 index 0000000..af95a2d --- /dev/null +++ b/src/char/inter.cpp @@ -0,0 +1,635 @@ +// $Id: inter.c,v 1.1.1.1 2004/09/10 17:26:51 MagicalTux Exp $ +#include "../common/mmo.hpp" +#include "char.hpp" +#include "../common/socket.hpp" +#include "../common/timer.hpp" +#include "../common/db.hpp" +#include +#include + +#include "inter.hpp" +#include "int_party.hpp" +#include "int_guild.hpp" +#include "int_storage.hpp" +#include "../common/lock.hpp" + +#define WISDATA_TTL (60*1000) // Existence time of Wisp/page data (60 seconds) + // that is the waiting time of answers of all map-servers +#define WISDELLIST_MAX 256 // Number of elements of Wisp/page data deletion list + +char inter_log_filename[1024] = "log/inter.log"; + +char accreg_txt[1024] = "save/accreg.txt"; +static struct dbt *accreg_db = NULL; + +struct accreg +{ + int account_id, reg_num; + struct global_reg reg[ACCOUNT_REG_NUM]; +}; + +int party_share_level = 10; + +// 送信パケット長リスト +int inter_send_packet_length[] = { + -1, -1, 27, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -1, 7, 0, 0, 0, 0, 0, 0, -1, 11, 0, 0, 0, 0, 0, 0, + 35, -1, 11, 15, 34, 29, 7, -1, 0, 0, 0, 0, 0, 0, 0, 0, + 10, -1, 15, 0, 79, 19, 7, -1, 0, -1, -1, -1, 14, 67, 186, -1, + 9, 9, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 11, -1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +// 受信パケット長リスト +int inter_recv_packet_length[] = { + -1, -1, 7, -1, -1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, -1, 0, 0, 0, 0, 0, 0, 10, -1, 0, 0, 0, 0, 0, 0, + 72, 6, 52, 14, 10, 29, 6, -1, 34, 0, 0, 0, 0, 0, 0, 0, + -1, 6, -1, 0, 55, 19, 6, -1, 14, -1, -1, -1, 14, 19, 186, -1, + 5, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 14, -1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +struct WisData +{ + int id, fd, count, len; + unsigned long tick; + unsigned char src[24], dst[24], msg[1024]; +}; +static struct dbt *wis_db = NULL; +static int wis_dellist[WISDELLIST_MAX], wis_delnum; + +//-------------------------------------------------------- + +// アカウント変数を文字列へ変換 +int inter_accreg_tostr (char *str, struct accreg *reg) +{ + int j; + char *p = str; + + p += sprintf (p, "%d\t", reg->account_id); + for (j = 0; j < reg->reg_num; j++) + { + p += sprintf (p, "%s,%d ", reg->reg[j].str, reg->reg[j].value); + } + + return 0; +} + +// アカウント変数を文字列から変換 +int inter_accreg_fromstr (const char *str, struct accreg *reg) +{ + int j, v, n; + char buf[128]; + const char *p = str; + + if (sscanf (p, "%d\t%n", ®->account_id, &n) != 1 + || reg->account_id <= 0) + return 1; + + for (j = 0, p += n; j < ACCOUNT_REG_NUM; j++, p += n) + { + if (sscanf (p, "%[^,],%d %n", buf, &v, &n) != 2) + break; + memcpy (reg->reg[j].str, buf, 32); + reg->reg[j].value = v; + } + reg->reg_num = j; + + return 0; +} + +// アカウント変数の読み込み +int inter_accreg_init (void) +{ + char line[8192]; + FILE *fp; + int c = 0; + struct accreg *reg; + + accreg_db = numdb_init (); + + if ((fp = fopen_ (accreg_txt, "r")) == NULL) + return 1; + while (fgets (line, sizeof (line) - 1, fp)) + { + line[sizeof (line) - 1] = '\0'; + CREATE (reg, struct accreg, 1); + if (inter_accreg_fromstr (line, reg) == 0 && reg->account_id > 0) + { + numdb_insert (accreg_db, reg->account_id, reg); + } + else + { + printf ("inter: accreg: broken data [%s] line %d\n", accreg_txt, + c); + free (reg); + } + c++; + } + fclose_ (fp); +// printf("inter: %s read done (%d)\n", accreg_txt, c); + + return 0; +} + +// アカウント変数のセーブ用 +void inter_accreg_save_sub (db_key_t key, db_val_t data, va_list ap) +{ + char line[8192]; + FILE *fp; + struct accreg *reg = (struct accreg *) data; + + if (reg->reg_num > 0) + { + inter_accreg_tostr (line, reg); + fp = va_arg (ap, FILE *); + fprintf (fp, "%s\n", line); + } +} + +// アカウント変数のセーブ +int inter_accreg_save (void) +{ + FILE *fp; + int lock; + + if ((fp = lock_fopen (accreg_txt, &lock)) == NULL) + { + printf ("int_accreg: cant write [%s] !!! data is lost !!!\n", + accreg_txt); + return 1; + } + numdb_foreach (accreg_db, inter_accreg_save_sub, fp); + lock_fclose (fp, accreg_txt, &lock); +// printf("inter: %s saved.\n", accreg_txt); + + return 0; +} + +//-------------------------------------------------------- + +/*========================================== + * 設定ファイルを読み込む + *------------------------------------------ + */ +int inter_config_read (const char *cfgName) +{ + char line[1024], w1[1024], w2[1024]; + FILE *fp; + + fp = fopen_ (cfgName, "r"); + if (fp == NULL) + { + printf ("file not found: %s\n", cfgName); + return 1; + } + while (fgets (line, sizeof (line) - 1, fp)) + { + if (line[0] == '/' && line[1] == '/') + continue; + line[sizeof (line) - 1] = '\0'; + + if (sscanf (line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; + + if (strcasecmp (w1, "storage_txt") == 0) + { + strncpy (storage_txt, w2, sizeof (storage_txt)); + } + else if (strcasecmp (w1, "party_txt") == 0) + { + strncpy (party_txt, w2, sizeof (party_txt)); + } + else if (strcasecmp (w1, "guild_txt") == 0) + { + strncpy (guild_txt, w2, sizeof (guild_txt)); + } + else if (strcasecmp (w1, "castle_txt") == 0) + { + strncpy (castle_txt, w2, sizeof (castle_txt)); + } + else if (strcasecmp (w1, "accreg_txt") == 0) + { + strncpy (accreg_txt, w2, sizeof (accreg_txt)); + } + else if (strcasecmp (w1, "guild_storage_txt") == 0) + { + strncpy (guild_storage_txt, w2, sizeof (guild_storage_txt)); + } + else if (strcasecmp (w1, "party_share_level") == 0) + { + party_share_level = atoi (w2); + if (party_share_level < 0) + party_share_level = 0; + } + else if (strcasecmp (w1, "inter_log_filename") == 0) + { + strncpy (inter_log_filename, w2, sizeof (inter_log_filename)); + } + else if (strcasecmp (w1, "import") == 0) + { + inter_config_read (w2); + } + } + fclose_ (fp); + + return 0; +} + +// ログ書き出し +int inter_log (char *fmt, ...) +{ + FILE *logfp; + va_list ap; + + va_start (ap, fmt); + logfp = fopen_ (inter_log_filename, "a"); + if (logfp) + { + vfprintf (logfp, fmt, ap); + fclose_ (logfp); + } + va_end (ap); + + return 0; +} + +// セーブ +int inter_save (void) +{ + inter_party_save (); + inter_guild_save (); + inter_storage_save (); + inter_guild_storage_save (); + inter_accreg_save (); + + return 0; +} + +// 初期化 +int inter_init (const char *file) +{ + inter_config_read (file); + + wis_db = numdb_init (); + + inter_party_init (); + inter_guild_init (); + inter_storage_init (); + inter_accreg_init (); + + return 0; +} + +// マップサーバー接続 +int inter_mapif_init (int fd) +{ + inter_guild_mapif_init (fd); + + return 0; +} + +//-------------------------------------------------------- +// sended packets to map-server + +// GMメッセージ送信 +int mapif_GMmessage (unsigned char *mes, int len) +{ + unsigned char buf[len]; + + WBUFW (buf, 0) = 0x3800; + WBUFW (buf, 2) = len; + memcpy (WBUFP (buf, 4), mes, len - 4); + mapif_sendall (buf, len); +// printf("inter server: GM:%d %s\n", len, mes); + + return 0; +} + +// Wisp/page transmission to all map-server +int mapif_wis_message (struct WisData *wd) +{ + unsigned char buf[56 + wd->len]; + + WBUFW (buf, 0) = 0x3801; + WBUFW (buf, 2) = 56 + wd->len; + WBUFL (buf, 4) = wd->id; + memcpy (WBUFP (buf, 8), wd->src, 24); + memcpy (WBUFP (buf, 32), wd->dst, 24); + memcpy (WBUFP (buf, 56), wd->msg, wd->len); + wd->count = mapif_sendall (buf, WBUFW (buf, 2)); + + return 0; +} + +// Wisp/page transmission result to map-server +int mapif_wis_end (struct WisData *wd, int flag) +{ + unsigned char buf[27]; + + WBUFW (buf, 0) = 0x3802; + memcpy (WBUFP (buf, 2), wd->src, 24); + WBUFB (buf, 26) = flag; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + mapif_send (wd->fd, buf, 27); +// printf("inter server wis_end: flag: %d\n", flag); + + return 0; +} + +// アカウント変数送信 +int mapif_account_reg (int fd, unsigned char *src) +{ + unsigned char buf[WBUFW (src, 2)]; + + memcpy (WBUFP (buf, 0), src, WBUFW (src, 2)); + WBUFW (buf, 0) = 0x3804; + mapif_sendallwos (fd, buf, WBUFW (buf, 2)); + + return 0; +} + +// アカウント変数要求返信 +int mapif_account_reg_reply (int fd, int account_id) +{ + struct accreg *reg = (struct accreg *)numdb_search (accreg_db, account_id); + + WFIFOW (fd, 0) = 0x3804; + WFIFOL (fd, 4) = account_id; + if (reg == NULL) + { + WFIFOW (fd, 2) = 8; + } + else + { + int j, p; + for (j = 0, p = 8; j < reg->reg_num; j++, p += 36) + { + memcpy (WFIFOP (fd, p), reg->reg[j].str, 32); + WFIFOL (fd, p + 32) = reg->reg[j].value; + } + WFIFOW (fd, 2) = p; + } + WFIFOSET (fd, WFIFOW (fd, 2)); + + return 0; +} + +//-------------------------------------------------------- + +// Existence check of WISP data +void check_ttl_wisdata_sub (db_key_t key, db_val_t data, va_list ap) +{ + unsigned long tick; + struct WisData *wd = (struct WisData *) data; + tick = va_arg (ap, unsigned long); + + if (DIFF_TICK (tick, wd->tick) > WISDATA_TTL + && wis_delnum < WISDELLIST_MAX) + wis_dellist[wis_delnum++] = wd->id; +} + +int check_ttl_wisdata (void) +{ + unsigned long tick = gettick (); + int i; + + do + { + wis_delnum = 0; + numdb_foreach (wis_db, check_ttl_wisdata_sub, tick); + for (i = 0; i < wis_delnum; i++) + { + struct WisData *wd = (struct WisData *)numdb_search (wis_db, wis_dellist[i]); + printf ("inter: wis data id=%d time out : from %s to %s\n", + wd->id, wd->src, wd->dst); + // removed. not send information after a timeout. Just no answer for the player + //mapif_wis_end(wd, 1); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + numdb_erase (wis_db, wd->id); + free (wd); + } + } + while (wis_delnum >= WISDELLIST_MAX); + + return 0; +} + +//-------------------------------------------------------- +// received packets from map-server + +// GMメッセージ送信 +int mapif_parse_GMmessage (int fd) +{ + mapif_GMmessage (RFIFOP (fd, 4), RFIFOW (fd, 2)); + + return 0; +} + +// Wisp/page request to send +int mapif_parse_WisRequest (int fd) +{ + struct WisData *wd; + static int wisid = 0; + int index; + + if (RFIFOW (fd, 2) - 52 >= sizeof (wd->msg)) + { + printf ("inter: Wis message size too long.\n"); + return 0; + } + else if (RFIFOW (fd, 2) - 52 <= 0) + { // normaly, impossible, but who knows... + printf ("inter: Wis message doesn't exist.\n"); + return 0; + } + + // search if character exists before to ask all map-servers + if ((index = search_character_index (RFIFOP (fd, 28))) == -1) + { + unsigned char buf[27]; + WBUFW (buf, 0) = 0x3802; + memcpy (WBUFP (buf, 2), RFIFOP (fd, 4), 24); + WBUFB (buf, 26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + mapif_send (fd, buf, 27); + // Character exists. So, ask all map-servers + } + else + { + // to be sure of the correct name, rewrite it + memset (RFIFOP (fd, 28), 0, 24); + strncpy (RFIFOP (fd, 28), search_character_name (index), 24); + // if source is destination, don't ask other servers. + if (strcmp (RFIFOP (fd, 4), RFIFOP (fd, 28)) == 0) + { + unsigned char buf[27]; + WBUFW (buf, 0) = 0x3802; + memcpy (WBUFP (buf, 2), RFIFOP (fd, 4), 24); + WBUFB (buf, 26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + mapif_send (fd, buf, 27); + } + else + { + CREATE (wd, struct WisData, 1); + + // Whether the failure of previous wisp/page transmission (timeout) + check_ttl_wisdata (); + + wd->id = ++wisid; + wd->fd = fd; + wd->len = RFIFOW (fd, 2) - 52; + memcpy (wd->src, RFIFOP (fd, 4), 24); + memcpy (wd->dst, RFIFOP (fd, 28), 24); + memcpy (wd->msg, RFIFOP (fd, 52), wd->len); + wd->tick = gettick (); + numdb_insert (wis_db, wd->id, wd); + mapif_wis_message (wd); + } + } + + return 0; +} + +// Wisp/page transmission result +int mapif_parse_WisReply (int fd) +{ + int id = RFIFOL (fd, 2), flag = RFIFOB (fd, 6); + struct WisData *wd = (struct WisData *)numdb_search (wis_db, id); + + if (wd == NULL) + return 0; // This wisp was probably suppress before, because it was timeout of because of target was found on another map-server + + if ((--wd->count) <= 0 || flag != 1) + { + mapif_wis_end (wd, flag); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + numdb_erase (wis_db, id); + free (wd); + } + + return 0; +} + +// Received wisp message from map-server for ALL gm (just copy the message and resends it to ALL map-servers) +int mapif_parse_WisToGM (int fd) +{ + unsigned char buf[RFIFOW (fd, 2)]; // 0x3003/0x3803 .w .24B .w .?B + + memcpy (WBUFP (buf, 0), RFIFOP (fd, 0), RFIFOW (fd, 2)); + WBUFW (buf, 0) = 0x3803; + mapif_sendall (buf, RFIFOW (fd, 2)); + + return 0; +} + +// アカウント変数保存要求 +int mapif_parse_AccReg (int fd) +{ + int j, p; + struct accreg *reg = (struct accreg*)numdb_search (accreg_db, (numdb_key_t)RFIFOL (fd, 4)); + + if (reg == NULL) + { + CREATE (reg, struct accreg, 1); + reg->account_id = RFIFOL (fd, 4); + numdb_insert (accreg_db, (numdb_key_t)RFIFOL (fd, 4), reg); + } + + for (j = 0, p = 8; j < ACCOUNT_REG_NUM && p < RFIFOW (fd, 2); + j++, p += 36) + { + memcpy (reg->reg[j].str, RFIFOP (fd, p), 32); + reg->reg[j].value = RFIFOL (fd, p + 32); + } + reg->reg_num = j; + + mapif_account_reg (fd, RFIFOP (fd, 0)); // 他のMAPサーバーに送信 + + return 0; +} + +// アカウント変数送信要求 +int mapif_parse_AccRegRequest (int fd) +{ +// printf("mapif: accreg request\n"); + return mapif_account_reg_reply (fd, RFIFOL (fd, 2)); +} + +//-------------------------------------------------------- + +// map server からの通信(1パケットのみ解析すること) +// エラーなら0(false)、処理できたなら1、 +// パケット長が足りなければ2をかえさなければならない +int inter_parse_frommap (int fd) +{ + int cmd = RFIFOW (fd, 0); + int len = 0; + + // inter鯖管轄かを調べる + if (cmd < 0x3000 + || cmd >= + 0x3000 + + (sizeof (inter_recv_packet_length) / + sizeof (inter_recv_packet_length[0]))) + return 0; + + // パケット長を調べる + if ((len = + inter_check_length (fd, + inter_recv_packet_length[cmd - 0x3000])) == 0) + return 2; + + switch (cmd) + { + case 0x3000: + mapif_parse_GMmessage (fd); + break; + case 0x3001: + mapif_parse_WisRequest (fd); + break; + case 0x3002: + mapif_parse_WisReply (fd); + break; + case 0x3003: + mapif_parse_WisToGM (fd); + break; + case 0x3004: + mapif_parse_AccReg (fd); + break; + case 0x3005: + mapif_parse_AccRegRequest (fd); + break; + default: + if (inter_party_parse_frommap (fd)) + break; + if (inter_guild_parse_frommap (fd)) + break; + if (inter_storage_parse_frommap (fd)) + break; + return 0; + } + RFIFOSKIP (fd, len); + + return 1; +} + +// RFIFOのパケット長確認 +// 必要パケット長があればパケット長、まだ足りなければ0 +int inter_check_length (int fd, int length) +{ + if (length == -1) + { // 可変パケット長 + if (RFIFOREST (fd) < 4) // パケット長が未着 + return 0; + length = RFIFOW (fd, 2); + } + + if (RFIFOREST (fd) < length) // パケットが未着 + return 0; + + return length; +} diff --git a/src/char/inter.h b/src/char/inter.h deleted file mode 100644 index 219f195..0000000 --- a/src/char/inter.h +++ /dev/null @@ -1,19 +0,0 @@ -// $Id: inter.h,v 1.1.1.1 2004/09/10 17:26:51 MagicalTux Exp $ -#ifndef _INTER_H_ -#define _INTER_H_ - -int inter_init (const char *file); -int inter_save (void); -int inter_parse_frommap (int fd); -int inter_mapif_init (int fd); - -int inter_check_length (int fd, int length); - -int inter_log (char *fmt, ...); - -#define inter_cfgName "conf/inter_athena.conf" - -extern int party_share_level; -extern char inter_log_filename[1024]; - -#endif diff --git a/src/char/inter.hpp b/src/char/inter.hpp new file mode 100644 index 0000000..769324c --- /dev/null +++ b/src/char/inter.hpp @@ -0,0 +1,19 @@ +// $Id: inter.h,v 1.1.1.1 2004/09/10 17:26:51 MagicalTux Exp $ +#ifndef INTER_HPP +#define INTER_HPP + +int inter_init (const char *file); +int inter_save (void); +int inter_parse_frommap (int fd); +int inter_mapif_init (int fd); + +int inter_check_length (int fd, int length); + +int inter_log (char *fmt, ...); + +#define inter_cfgName "conf/inter_athena.conf" + +extern int party_share_level; +extern char inter_log_filename[1024]; + +#endif diff --git a/src/common/core.c b/src/common/core.c deleted file mode 100644 index b08276c..0000000 --- a/src/common/core.c +++ /dev/null @@ -1,97 +0,0 @@ -#include -#include -#include -#include -#include - -#include "core.h" -#include "socket.h" -#include "timer.h" -#include "version.h" -#include "mt_rand.h" -#include "nullpo.h" - -/// Defined by each server -extern int do_init (int, char **); -extern void term_func (void); - -// Added by Gabuzomeu -// -// This is an implementation of signal() using sigaction() for portability. -// (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced -// Programming in the UNIX Environment_. -// -typedef void (*sigfunc)(int); -sigfunc compat_signal (int signo, sigfunc func) -{ - struct sigaction sact, oact; - - sact.sa_handler = func; - sigfillset (&sact.sa_mask); - sigdelset(&sact.sa_mask, SIGSEGV); - sigdelset(&sact.sa_mask, SIGBUS); - sigdelset(&sact.sa_mask, SIGTRAP); - sigdelset(&sact.sa_mask, SIGILL); - sigdelset(&sact.sa_mask, SIGFPE); - sact.sa_flags = 0; - - if (sigaction (signo, &sact, &oact) < 0) - return SIG_ERR; - - return oact.sa_handler; -} - -static void chld_proc (int UNUSED) -{ - wait(NULL); -} -static void sig_proc (int UNUSED) -{ - for (int i = 1; i < 31; ++i) - compat_signal(i, SIG_IGN); - term_func (); - _exit (0); -} - -bool runflag = true; - -/* - Note about fatal signals: - - Under certain circumstances, - the following signals MUST not be ignored: - SIGFPE, SIGSEGV, SIGILL - Unless you use SA_SIGINFO and *carefully* check the origin, - that means they must be SIG_DFL. - */ -int main (int argc, char **argv) -{ - /// Note that getpid() and getppid() may be very close - mt_seed (time (NULL) ^ (getpid () << 16) ^ (getppid () << 8)); - - do_socket (); - - do_init (argc, argv); - // set up exit handlers *after* the initialization has happened. - // This is because term_func is likely to depend on successful init. - - compat_signal (SIGPIPE, SIG_IGN); - compat_signal (SIGTERM, sig_proc); - compat_signal (SIGINT, sig_proc); - compat_signal (SIGCHLD, chld_proc); - - // Signal to create coredumps by system when necessary (crash) - compat_signal (SIGSEGV, SIG_DFL); - compat_signal (SIGBUS, SIG_DFL); - compat_signal (SIGTRAP, SIG_DFL); - compat_signal (SIGILL, SIG_DFL); - compat_signal (SIGFPE, SIG_DFL); - - atexit (term_func); - - while (runflag) - { - do_sendrecv (do_timer (gettick_nocache ())); - do_parsepacket (); - } -} diff --git a/src/common/core.cpp b/src/common/core.cpp new file mode 100644 index 0000000..38b2260 --- /dev/null +++ b/src/common/core.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include + +#include "core.hpp" +#include "socket.hpp" +#include "timer.hpp" +#include "version.hpp" +#include "mt_rand.hpp" +#include "nullpo.hpp" + +/// Defined by each server +extern int do_init (int, char **); +extern void term_func (void); + +// Added by Gabuzomeu +// +// This is an implementation of signal() using sigaction() for portability. +// (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced +// Programming in the UNIX Environment_. +// +typedef void (*sigfunc)(int); +sigfunc compat_signal (int signo, sigfunc func) +{ + struct sigaction sact, oact; + + sact.sa_handler = func; + sigfillset (&sact.sa_mask); + sigdelset(&sact.sa_mask, SIGSEGV); + sigdelset(&sact.sa_mask, SIGBUS); + sigdelset(&sact.sa_mask, SIGTRAP); + sigdelset(&sact.sa_mask, SIGILL); + sigdelset(&sact.sa_mask, SIGFPE); + sact.sa_flags = 0; + + if (sigaction (signo, &sact, &oact) < 0) + return SIG_ERR; + + return oact.sa_handler; +} + +static void chld_proc (int UNUSED) +{ + wait(NULL); +} +static void sig_proc (int UNUSED) +{ + for (int i = 1; i < 31; ++i) + compat_signal(i, SIG_IGN); + term_func (); + _exit (0); +} + +bool runflag = true; + +/* + Note about fatal signals: + + Under certain circumstances, + the following signals MUST not be ignored: + SIGFPE, SIGSEGV, SIGILL + Unless you use SA_SIGINFO and *carefully* check the origin, + that means they must be SIG_DFL. + */ +int main (int argc, char **argv) +{ + /// Note that getpid() and getppid() may be very close + mt_seed (time (NULL) ^ (getpid () << 16) ^ (getppid () << 8)); + + do_socket (); + + do_init (argc, argv); + // set up exit handlers *after* the initialization has happened. + // This is because term_func is likely to depend on successful init. + + compat_signal (SIGPIPE, SIG_IGN); + compat_signal (SIGTERM, sig_proc); + compat_signal (SIGINT, sig_proc); + compat_signal (SIGCHLD, chld_proc); + + // Signal to create coredumps by system when necessary (crash) + compat_signal (SIGSEGV, SIG_DFL); + compat_signal (SIGBUS, SIG_DFL); + compat_signal (SIGTRAP, SIG_DFL); + compat_signal (SIGILL, SIG_DFL); + compat_signal (SIGFPE, SIG_DFL); + + atexit (term_func); + + while (runflag) + { + do_sendrecv (do_timer (gettick_nocache ())); + do_parsepacket (); + } +} diff --git a/src/common/core.h b/src/common/core.h deleted file mode 100644 index 44473e9..0000000 --- a/src/common/core.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef CORE_H -#define CORE_H -#include -/// core.c contains a server-independent main() function -/// and then runs a do_sendrecv loop - -/// When this is cleared, the server exits gracefully -/// only used by map server's GM command: @mapexit -extern bool runflag; - -/// This is an external function defined by each server -/// This function must register stuff for the parse loop -extern int do_init (int, char **); - -/// Cleanup function called whenever a signal kills us -/// or when if we manage to exit() gracefully. -extern void term_func (void); - -#endif // CORE_H diff --git a/src/common/core.hpp b/src/common/core.hpp new file mode 100644 index 0000000..8a52c55 --- /dev/null +++ b/src/common/core.hpp @@ -0,0 +1,19 @@ +#ifndef CORE_HPP +#define CORE_HPP +#include +/// core.c contains a server-independent main() function +/// and then runs a do_sendrecv loop + +/// When this is cleared, the server exits gracefully +/// only used by map server's GM command: @mapexit +extern bool runflag; + +/// This is an external function defined by each server +/// This function must register stuff for the parse loop +extern int do_init (int, char **); + +/// Cleanup function called whenever a signal kills us +/// or when if we manage to exit() gracefully. +extern void term_func (void); + +#endif // CORE_HPP diff --git a/src/common/db.c b/src/common/db.c deleted file mode 100644 index f56a511..0000000 --- a/src/common/db.c +++ /dev/null @@ -1,546 +0,0 @@ -#include "db.h" - -#include -#include -#include - -#include "utils.h" - -#define ROOT_SIZE 4096 - -static int strdb_cmp (struct dbt *table, const char *a, const char* b) -{ - if (table->maxlen) - return strncmp (a, b, table->maxlen); - return strcmp (a, b); -} - -static hash_t strdb_hash (struct dbt *table, const char *a) -{ - size_t i = table->maxlen; - if (i == 0) - i = (size_t)-1; - hash_t h = 0; - const unsigned char *p = (const unsigned char*)a; - while (*p && i--) - { - h = (h * 33 + *p++) ^ (h >> 24); - } - return h; -} - -struct dbt *strdb_init (size_t maxlen) -{ - struct dbt *table; - CREATE (table, struct dbt, 1); - table->type = DB_STRING; - table->maxlen = maxlen; - return table; -} - -static int numdb_cmp (numdb_key_t a, numdb_key_t b) -{ - if (a == b) - return 0; - if (a < b) - return -1; - return 1; -} - -static hash_t numdb_hash (numdb_key_t a) -{ - return (hash_t) a; -} - -struct dbt *numdb_init (void) -{ - struct dbt *table; - CREATE (table, struct dbt, 1); - table->type = DB_NUMBER; - return table; -} - -static int table_cmp (struct dbt *table, db_key_t a, db_key_t b) -{ - switch(table->type) - { - case DB_NUMBER: return numdb_cmp (a.i, b.i); - case DB_STRING: return strdb_cmp (table, a.s, b.s); - } - abort(); -} - -static hash_t table_hash (struct dbt *table, db_key_t key) -{ - switch(table->type) - { - case DB_NUMBER: return numdb_hash (key.i); - case DB_STRING: return strdb_hash (table, key.s); - } - abort(); -} - -/// Search for a node with the given key -db_val_t db_search (struct dbt *table, db_key_t key) -{ - struct dbn *p = table->ht[table_hash (table, key) % HASH_SIZE]; - - while (p) - { - int c = table_cmp (table, key, p->key); - if (c == 0) - return p->data; - if (c < 0) - p = p->left; - else - p = p->right; - } - return NULL; -} - -// Tree maintainance methods -static void db_rotate_left (struct dbn *p, struct dbn **root) -{ - struct dbn *y = p->right; - p->right = y->left; - if (y->left) - y->left->parent = p; - y->parent = p->parent; - - if (p == *root) - *root = y; - else if (p == p->parent->left) - p->parent->left = y; - else - p->parent->right = y; - y->left = p; - p->parent = y; -} - -static void db_rotate_right (struct dbn *p, struct dbn **root) -{ - struct dbn *y = p->left; - p->left = y->right; - if (y->right) - y->right->parent = p; - y->parent = p->parent; - - if (p == *root) - *root = y; - else if (p == p->parent->right) - p->parent->right = y; - else - p->parent->left = y; - y->right = p; - p->parent = y; -} - -static void db_rebalance (struct dbn *p, struct dbn **root) -{ - p->color = RED; - while (p != *root && p->parent->color == RED) - { - if (p->parent == p->parent->parent->left) - { - struct dbn *y = p->parent->parent->right; - if (y && y->color == RED) - { - p->parent->color = BLACK; - y->color = BLACK; - p->parent->parent->color = RED; - p = p->parent->parent; - } - else - { - if (p == p->parent->right) - { - p = p->parent; - db_rotate_left (p, root); - } - p->parent->color = BLACK; - p->parent->parent->color = RED; - db_rotate_right (p->parent->parent, root); - } - } - else - { - struct dbn *y = p->parent->parent->left; - if (y && y->color == RED) - { - p->parent->color = BLACK; - y->color = BLACK; - p->parent->parent->color = RED; - p = p->parent->parent; - } - else - { - if (p == p->parent->left) - { - p = p->parent; - db_rotate_right (p, root); - } - p->parent->color = BLACK; - p->parent->parent->color = RED; - db_rotate_left (p->parent->parent, root); - } - } - } - (*root)->color = BLACK; -} - -// param z = node to remove -static void db_rebalance_erase (struct dbn *z, struct dbn **root) -{ - struct dbn *y = z; - struct dbn *x = NULL; - - if (!y->left) - x = y->right; - else if (!y->right) - x = y->left; - else - { - y = y->right; - while (y->left) - y = y->left; - x = y->right; - } - struct dbn *x_parent = NULL; - if (y != z) - { - z->left->parent = y; - y->left = z->left; - if (y != z->right) - { - x_parent = y->parent; - if (x) - x->parent = y->parent; - y->parent->left = x; - y->right = z->right; - z->right->parent = y; - } - else - x_parent = y; - if (*root == z) - *root = y; - else if (z->parent->left == z) - z->parent->left = y; - else - z->parent->right = y; - y->parent = z->parent; - { - dbn_color tmp = y->color; - y->color = z->color; - z->color = tmp; - } - y = z; - } - else - { - x_parent = y->parent; - if (x) - x->parent = y->parent; - if (*root == z) - *root = x; - else if (z->parent->left == z) - z->parent->left = x; - else - z->parent->right = x; - } - if (y->color != RED) - { - while (x != *root && (!x || x->color == BLACK)) - if (x == x_parent->left) - { - struct dbn *w = x_parent->right; - if (w->color == RED) - { - w->color = BLACK; - x_parent->color = RED; - db_rotate_left (x_parent, root); - w = x_parent->right; - } - if ((!w->left || w->left->color == BLACK) && - (!w->right || w->right->color == BLACK)) - { - w->color = RED; - x = x_parent; - x_parent = x->parent; - } - else - { - if (!w->right|| w->right->color == BLACK) - { - if (w->left) - w->left->color = BLACK; - w->color = RED; - db_rotate_right (w, root); - w = x_parent->right; - } - w->color = x_parent->color; - x_parent->color = BLACK; - if (w->right) - w->right->color = BLACK; - db_rotate_left (x_parent, root); - break; - } - } - else - { - // same as above, with right <-> left. - struct dbn *w = x_parent->left; - if (w->color == RED) - { - w->color = BLACK; - x_parent->color = RED; - db_rotate_right (x_parent, root); - w = x_parent->left; - } - if ((!w->right || w->right->color == BLACK) && - (!w->left || w->left->color == BLACK)) - { - w->color = RED; - x = x_parent; - x_parent = x_parent->parent; - } - else - { - if (!w->left || w->left->color == BLACK) - { - if (w->right) - w->right->color = BLACK; - w->color = RED; - db_rotate_left (w, root); - w = x_parent->left; - } - w->color = x_parent->color; - x_parent->color = BLACK; - if (w->left) - w->left->color = BLACK; - db_rotate_right (x_parent, root); - break; - } - } - if (x) - x->color = BLACK; - } -} - -struct dbn *db_insert (struct dbt *table, db_key_t key, db_val_t data) -{ - hash_t hash = table_hash (table, key) % HASH_SIZE; - int c = 0; - struct dbn *prev = NULL; - struct dbn *p = table->ht[hash]; - while (p) - { - c = table_cmp (table, key, p->key); - if (c == 0) - { - // key found in table, replace - // Tell the user of the table to free the key and value - if (table->release) - table->release (p->key, p->data); - p->data = data; - p->key = key; - return p; - } - // prev is always p->parent? - prev = p; - if (c < 0) - p = p->left; - else - p = p->right; - } - CREATE (p, struct dbn, 1); - p->key = key; - p->data = data; - p->color = RED; - if (c == 0) - { // hash entry is empty - table->ht[hash] = p; - p->color = BLACK; - return p; - } - p->parent = prev; - if (c < 0) - prev->left = p; - else - prev->right = p; - if (prev->color == RED) - { - // must rebalance - db_rebalance (p, &table->ht[hash]); - } - return p; -} - -db_val_t db_erase (struct dbt *table, db_key_t key) -{ - hash_t hash = table_hash (table, key) % HASH_SIZE; - struct dbn *p = table->ht[hash]; - while (p) - { - int c = table_cmp (table, key, p->key); - if (c == 0) - break; - if (c < 0) - p = p->left; - else - p = p->right; - } - if (!p) - return NULL; - db_val_t data = p->data; - db_rebalance_erase (p, &table->ht[hash]); - free (p); - return data; -} -#ifdef SMART_WALK_TREE -static inline void db_walk_tree (bool dealloc, struct dbn* p, db_func_t func, va_list ap) -{ - if (!p) - return; - if (!dealloc && !func) - { - fprintf(stderr, "DEBUG: Must walk tree to either free or invoke a function.\n"); - abort(); - } - if (p->parent) - { - fprintf(stderr, "DEBUG: Root nodes must not have parents\n"); - abort(); - } - while (true) - { - // apply_func loop - if (func) - func (p->key, p->data, ap); - if (p->left) - { - // continue descending - p = p->left; - continue; //goto apply_func; - } - if (p->right) - { - // descending the other side - p = p->right; - continue; //goto apply_func; - } - while (true) - { - // backtrack loop - if (!p->parent) - { - if (dealloc) - free (p); - // if we have already done both children, there is no more to do - return; - } - if (p->parent->left == p && p->parent->right) - { - // finished the left tree, now walk the right tree - p = p->parent->right; - if (dealloc) - free (p->parent->left); - break; //goto apply_func; - } - // p->parent->right == p - // or p->parent->left == p but p->parent->right == NULL - // keep backtracking - p = p->parent; - if (dealloc) - free (p->right?:p->left); - } //backtrack loop - } // apply_func loop -} -#endif // SMART_WALK_TREE - -void db_foreach (struct dbt *table, db_func_t func, ...) -{ - va_list ap; - va_start (ap, func); - - for (int i = 0; i < HASH_SIZE; i++) - { -#ifdef SMART_WALK_TREE - db_walk_tree (false, table->ht[i], func, ap); -#else - struct dbn *p = table->ht[i]; - if (!p) - continue; - struct dbn *stack[64]; - int sp = 0; - while (1) - { - func (p->key, p->data, ap); - struct dbn *pn = p->left; - if (pn) - { - if (p->right) - stack[sp++] = p->right; - p = pn; - } - else // pn == NULL, time to do the right branch - { - if (p->right) - p = p->right; - else - { - if (sp == 0) - break; - p = stack[--sp]; - } - } // if pn else if !pn - } // while true -#endif // else ! SMART_WALK_TREE - } // for i - va_end (ap); -} - -// This function is suspiciously similar to the previous -void db_final (struct dbt *table, db_func_t func, ...) -{ - va_list ap; - va_start (ap, func); - - for (int i = 0; i < HASH_SIZE; i++) - { -#ifdef SMART_WALK_TREE - db_walk_tree (true, table->ht[i], func, ap); -#else - struct dbn *p = table->ht[i]; - if (!p) - continue; - struct dbn *stack[64]; - int sp = 0; - while (1) - { - if (func) - func (p->key, p->data, ap); - struct dbn *pn = p->left; - if (pn) - { - if (p->right) - stack[sp++] = p->right; - } - else // pn == NULL, check the right - { - if (p->right) - pn = p->right; - else - { - if (sp == 0) - break; - pn = stack[--sp]; - } - } // if pn else if !pn - free (p); - p = pn; - } // while true -#endif // else ! SMART_WALK_TREE - } // for i - free (table); - va_end (ap); -} diff --git a/src/common/db.cpp b/src/common/db.cpp new file mode 100644 index 0000000..21a3597 --- /dev/null +++ b/src/common/db.cpp @@ -0,0 +1,546 @@ +#include "db.hpp" + +#include +#include +#include + +#include "utils.hpp" + +#define ROOT_SIZE 4096 + +static int strdb_cmp (struct dbt *table, const char *a, const char* b) +{ + if (table->maxlen) + return strncmp (a, b, table->maxlen); + return strcmp (a, b); +} + +static hash_t strdb_hash (struct dbt *table, const char *a) +{ + size_t i = table->maxlen; + if (i == 0) + i = (size_t)-1; + hash_t h = 0; + const unsigned char *p = (const unsigned char*)a; + while (*p && i--) + { + h = (h * 33 + *p++) ^ (h >> 24); + } + return h; +} + +struct dbt *strdb_init (size_t maxlen) +{ + struct dbt *table; + CREATE (table, struct dbt, 1); + table->type = DB_STRING; + table->maxlen = maxlen; + return table; +} + +static int numdb_cmp (numdb_key_t a, numdb_key_t b) +{ + if (a == b) + return 0; + if (a < b) + return -1; + return 1; +} + +static hash_t numdb_hash (numdb_key_t a) +{ + return (hash_t) a; +} + +struct dbt *numdb_init (void) +{ + struct dbt *table; + CREATE (table, struct dbt, 1); + table->type = DB_NUMBER; + return table; +} + +static int table_cmp (struct dbt *table, db_key_t a, db_key_t b) +{ + switch(table->type) + { + case DB_NUMBER: return numdb_cmp (a.i, b.i); + case DB_STRING: return strdb_cmp (table, a.s, b.s); + } + abort(); +} + +static hash_t table_hash (struct dbt *table, db_key_t key) +{ + switch(table->type) + { + case DB_NUMBER: return numdb_hash (key.i); + case DB_STRING: return strdb_hash (table, key.s); + } + abort(); +} + +/// Search for a node with the given key +db_val_t db_search (struct dbt *table, db_key_t key) +{ + struct dbn *p = table->ht[table_hash (table, key) % HASH_SIZE]; + + while (p) + { + int c = table_cmp (table, key, p->key); + if (c == 0) + return p->data; + if (c < 0) + p = p->left; + else + p = p->right; + } + return NULL; +} + +// Tree maintainance methods +static void db_rotate_left (struct dbn *p, struct dbn **root) +{ + struct dbn *y = p->right; + p->right = y->left; + if (y->left) + y->left->parent = p; + y->parent = p->parent; + + if (p == *root) + *root = y; + else if (p == p->parent->left) + p->parent->left = y; + else + p->parent->right = y; + y->left = p; + p->parent = y; +} + +static void db_rotate_right (struct dbn *p, struct dbn **root) +{ + struct dbn *y = p->left; + p->left = y->right; + if (y->right) + y->right->parent = p; + y->parent = p->parent; + + if (p == *root) + *root = y; + else if (p == p->parent->right) + p->parent->right = y; + else + p->parent->left = y; + y->right = p; + p->parent = y; +} + +static void db_rebalance (struct dbn *p, struct dbn **root) +{ + p->color = RED; + while (p != *root && p->parent->color == RED) + { + if (p->parent == p->parent->parent->left) + { + struct dbn *y = p->parent->parent->right; + if (y && y->color == RED) + { + p->parent->color = BLACK; + y->color = BLACK; + p->parent->parent->color = RED; + p = p->parent->parent; + } + else + { + if (p == p->parent->right) + { + p = p->parent; + db_rotate_left (p, root); + } + p->parent->color = BLACK; + p->parent->parent->color = RED; + db_rotate_right (p->parent->parent, root); + } + } + else + { + struct dbn *y = p->parent->parent->left; + if (y && y->color == RED) + { + p->parent->color = BLACK; + y->color = BLACK; + p->parent->parent->color = RED; + p = p->parent->parent; + } + else + { + if (p == p->parent->left) + { + p = p->parent; + db_rotate_right (p, root); + } + p->parent->color = BLACK; + p->parent->parent->color = RED; + db_rotate_left (p->parent->parent, root); + } + } + } + (*root)->color = BLACK; +} + +// param z = node to remove +static void db_rebalance_erase (struct dbn *z, struct dbn **root) +{ + struct dbn *y = z; + struct dbn *x = NULL; + + if (!y->left) + x = y->right; + else if (!y->right) + x = y->left; + else + { + y = y->right; + while (y->left) + y = y->left; + x = y->right; + } + struct dbn *x_parent = NULL; + if (y != z) + { + z->left->parent = y; + y->left = z->left; + if (y != z->right) + { + x_parent = y->parent; + if (x) + x->parent = y->parent; + y->parent->left = x; + y->right = z->right; + z->right->parent = y; + } + else + x_parent = y; + if (*root == z) + *root = y; + else if (z->parent->left == z) + z->parent->left = y; + else + z->parent->right = y; + y->parent = z->parent; + { + dbn_color tmp = y->color; + y->color = z->color; + z->color = tmp; + } + y = z; + } + else + { + x_parent = y->parent; + if (x) + x->parent = y->parent; + if (*root == z) + *root = x; + else if (z->parent->left == z) + z->parent->left = x; + else + z->parent->right = x; + } + if (y->color != RED) + { + while (x != *root && (!x || x->color == BLACK)) + if (x == x_parent->left) + { + struct dbn *w = x_parent->right; + if (w->color == RED) + { + w->color = BLACK; + x_parent->color = RED; + db_rotate_left (x_parent, root); + w = x_parent->right; + } + if ((!w->left || w->left->color == BLACK) && + (!w->right || w->right->color == BLACK)) + { + w->color = RED; + x = x_parent; + x_parent = x->parent; + } + else + { + if (!w->right|| w->right->color == BLACK) + { + if (w->left) + w->left->color = BLACK; + w->color = RED; + db_rotate_right (w, root); + w = x_parent->right; + } + w->color = x_parent->color; + x_parent->color = BLACK; + if (w->right) + w->right->color = BLACK; + db_rotate_left (x_parent, root); + break; + } + } + else + { + // same as above, with right <-> left. + struct dbn *w = x_parent->left; + if (w->color == RED) + { + w->color = BLACK; + x_parent->color = RED; + db_rotate_right (x_parent, root); + w = x_parent->left; + } + if ((!w->right || w->right->color == BLACK) && + (!w->left || w->left->color == BLACK)) + { + w->color = RED; + x = x_parent; + x_parent = x_parent->parent; + } + else + { + if (!w->left || w->left->color == BLACK) + { + if (w->right) + w->right->color = BLACK; + w->color = RED; + db_rotate_left (w, root); + w = x_parent->left; + } + w->color = x_parent->color; + x_parent->color = BLACK; + if (w->left) + w->left->color = BLACK; + db_rotate_right (x_parent, root); + break; + } + } + if (x) + x->color = BLACK; + } +} + +struct dbn *db_insert (struct dbt *table, db_key_t key, db_val_t data) +{ + hash_t hash = table_hash (table, key) % HASH_SIZE; + int c = 0; + struct dbn *prev = NULL; + struct dbn *p = table->ht[hash]; + while (p) + { + c = table_cmp (table, key, p->key); + if (c == 0) + { + // key found in table, replace + // Tell the user of the table to free the key and value + if (table->release) + table->release (p->key, p->data); + p->data = data; + p->key = key; + return p; + } + // prev is always p->parent? + prev = p; + if (c < 0) + p = p->left; + else + p = p->right; + } + CREATE (p, struct dbn, 1); + p->key = key; + p->data = data; + p->color = RED; + if (c == 0) + { // hash entry is empty + table->ht[hash] = p; + p->color = BLACK; + return p; + } + p->parent = prev; + if (c < 0) + prev->left = p; + else + prev->right = p; + if (prev->color == RED) + { + // must rebalance + db_rebalance (p, &table->ht[hash]); + } + return p; +} + +db_val_t db_erase (struct dbt *table, db_key_t key) +{ + hash_t hash = table_hash (table, key) % HASH_SIZE; + struct dbn *p = table->ht[hash]; + while (p) + { + int c = table_cmp (table, key, p->key); + if (c == 0) + break; + if (c < 0) + p = p->left; + else + p = p->right; + } + if (!p) + return NULL; + db_val_t data = p->data; + db_rebalance_erase (p, &table->ht[hash]); + free (p); + return data; +} +#ifdef SMART_WALK_TREE +static inline void db_walk_tree (bool dealloc, struct dbn* p, db_func_t func, va_list ap) +{ + if (!p) + return; + if (!dealloc && !func) + { + fprintf(stderr, "DEBUG: Must walk tree to either free or invoke a function.\n"); + abort(); + } + if (p->parent) + { + fprintf(stderr, "DEBUG: Root nodes must not have parents\n"); + abort(); + } + while (true) + { + // apply_func loop + if (func) + func (p->key, p->data, ap); + if (p->left) + { + // continue descending + p = p->left; + continue; //goto apply_func; + } + if (p->right) + { + // descending the other side + p = p->right; + continue; //goto apply_func; + } + while (true) + { + // backtrack loop + if (!p->parent) + { + if (dealloc) + free (p); + // if we have already done both children, there is no more to do + return; + } + if (p->parent->left == p && p->parent->right) + { + // finished the left tree, now walk the right tree + p = p->parent->right; + if (dealloc) + free (p->parent->left); + break; //goto apply_func; + } + // p->parent->right == p + // or p->parent->left == p but p->parent->right == NULL + // keep backtracking + p = p->parent; + if (dealloc) + free (p->right?:p->left); + } //backtrack loop + } // apply_func loop +} +#endif // SMART_WALK_TREE + +void db_foreach (struct dbt *table, db_func_t func, ...) +{ + va_list ap; + va_start (ap, func); + + for (int i = 0; i < HASH_SIZE; i++) + { +#ifdef SMART_WALK_TREE + db_walk_tree (false, table->ht[i], func, ap); +#else + struct dbn *p = table->ht[i]; + if (!p) + continue; + struct dbn *stack[64]; + int sp = 0; + while (1) + { + func (p->key, p->data, ap); + struct dbn *pn = p->left; + if (pn) + { + if (p->right) + stack[sp++] = p->right; + p = pn; + } + else // pn == NULL, time to do the right branch + { + if (p->right) + p = p->right; + else + { + if (sp == 0) + break; + p = stack[--sp]; + } + } // if pn else if !pn + } // while true +#endif // else ! SMART_WALK_TREE + } // for i + va_end (ap); +} + +// This function is suspiciously similar to the previous +void db_final (struct dbt *table, db_func_t func, ...) +{ + va_list ap; + va_start (ap, func); + + for (int i = 0; i < HASH_SIZE; i++) + { +#ifdef SMART_WALK_TREE + db_walk_tree (true, table->ht[i], func, ap); +#else + struct dbn *p = table->ht[i]; + if (!p) + continue; + struct dbn *stack[64]; + int sp = 0; + while (1) + { + if (func) + func (p->key, p->data, ap); + struct dbn *pn = p->left; + if (pn) + { + if (p->right) + stack[sp++] = p->right; + } + else // pn == NULL, check the right + { + if (p->right) + pn = p->right; + else + { + if (sp == 0) + break; + pn = stack[--sp]; + } + } // if pn else if !pn + free (p); + p = pn; + } // while true +#endif // else ! SMART_WALK_TREE + } // for i + free (table); + va_end (ap); +} diff --git a/src/common/db.h b/src/common/db.h deleted file mode 100644 index 7152854..0000000 --- a/src/common/db.h +++ /dev/null @@ -1,87 +0,0 @@ -// WARNING: there is a system header by this name -#ifndef DB_H -#define DB_H -# include "sanity.h" - -# include - -/// Number of tree roots -// Somewhat arbitrary - larger wastes more space but is faster for large trees -// num % HASH_SIZE minimize collisions even for similar num -# define HASH_SIZE (256+27) - -typedef enum dbn_color -{ - RED, - BLACK -} dbn_color; - -typedef intptr_t numdb_key_t; -typedef union db_key_t -{ - char *ms __attribute__((deprecated)); - const char* s; - numdb_key_t i; -} db_key_t; -typedef void* db_val_t; -typedef uint32_t hash_t; -typedef void (*db_func_t)(db_key_t, db_val_t, va_list); - -/// DataBase Node -struct dbn -{ - struct dbn *parent, *left, *right; - dbn_color color; - db_key_t key; - db_val_t data; -}; - -typedef enum dbt_type -{ - DB_NUMBER, - DB_STRING, -} dbt_type; - -/// DataBase Table -struct dbt -{ - dbt_type type; - /// Note, before replacement, key/values to be replaced - // TODO refactor to decrease/eliminate the uses of this? - void (*release) (db_key_t, db_val_t) __attribute__((deprecated)); - /// Maximum length of a string key - TODO refactor to ensure all strings are NUL-terminated - size_t maxlen __attribute__((deprecated)); - /// The root trees - struct dbn *ht[HASH_SIZE]; -}; - -# define strdb_search(t,k) db_search((t),(db_key_t)(k)) -# define strdb_insert(t,k,d) db_insert((t),(db_key_t)(k),(db_val_t)(d)) -# define strdb_erase(t,k) db_erase ((t),(db_key_t)(k)) -# define strdb_foreach db_foreach -# define strdb_final db_final -# define numdb_search(t,k) db_search((t),(db_key_t)(k)) -# define numdb_insert(t,k,d) db_insert((t),(db_key_t)(k),(db_val_t)(d)) -# define numdb_erase(t,k) db_erase ((t),(db_key_t)(k)) -# define numdb_foreach db_foreach -# define numdb_final db_final - -/// Create a map from char* to void*, with strings possibly not null-terminated -struct dbt *strdb_init (size_t maxlen); -/// Create a map from int to void* -struct dbt *numdb_init (void); -/// Return the value corresponding to the key, or NULL if not found -db_val_t db_search (struct dbt *table, db_key_t key); -/// Add or replace table[key] = data -// if it was already there, call release -struct dbn *db_insert (struct dbt *table, db_key_t key, db_val_t data); -/// Remove a key from the table, returning the data -db_val_t db_erase (struct dbt *table, db_key_t key); - -/// Execute a function for every element, in unspecified order -void db_foreach (struct dbt *, db_func_t, ...); -// opposite of init? Calls release for every element and frees memory -// This probably isn't really needed: we don't have to free memory while exiting -void db_final (struct dbt *, db_func_t, ...) __attribute__((deprecated)); - -#endif diff --git a/src/common/db.hpp b/src/common/db.hpp new file mode 100644 index 0000000..145ba13 --- /dev/null +++ b/src/common/db.hpp @@ -0,0 +1,87 @@ +// WARNING: there is a system header by this name +#ifndef DB_HPP +#define DB_HPP +# include "sanity.hpp" + +# include + +/// Number of tree roots +// Somewhat arbitrary - larger wastes more space but is faster for large trees +// num % HASH_SIZE minimize collisions even for similar num +# define HASH_SIZE (256+27) + +typedef enum dbn_color +{ + RED, + BLACK +} dbn_color; + +typedef intptr_t numdb_key_t; +typedef union db_key_t +{ + char *ms __attribute__((deprecated)); + const char* s; + numdb_key_t i; +} db_key_t; +typedef void* db_val_t; +typedef uint32_t hash_t; +typedef void (*db_func_t)(db_key_t, db_val_t, va_list); + +/// DataBase Node +struct dbn +{ + struct dbn *parent, *left, *right; + dbn_color color; + db_key_t key; + db_val_t data; +}; + +typedef enum dbt_type +{ + DB_NUMBER, + DB_STRING, +} dbt_type; + +/// DataBase Table +struct dbt +{ + dbt_type type; + /// Note, before replacement, key/values to be replaced + // TODO refactor to decrease/eliminate the uses of this? + void (*release) (db_key_t, db_val_t) __attribute__((deprecated)); + /// Maximum length of a string key - TODO refactor to ensure all strings are NUL-terminated + size_t maxlen __attribute__((deprecated)); + /// The root trees + struct dbn *ht[HASH_SIZE]; +}; + +# define strdb_search(t,k) db_search((t),(db_key_t)(k)) +# define strdb_insert(t,k,d) db_insert((t),(db_key_t)(k),(db_val_t)(d)) +# define strdb_erase(t,k) db_erase ((t),(db_key_t)(k)) +# define strdb_foreach db_foreach +# define strdb_final db_final +# define numdb_search(t,k) db_search((t),(db_key_t)(k)) +# define numdb_insert(t,k,d) db_insert((t),(db_key_t)(k),(db_val_t)(d)) +# define numdb_erase(t,k) db_erase ((t),(db_key_t)(k)) +# define numdb_foreach db_foreach +# define numdb_final db_final + +/// Create a map from char* to void*, with strings possibly not null-terminated +struct dbt *strdb_init (size_t maxlen); +/// Create a map from int to void* +struct dbt *numdb_init (void); +/// Return the value corresponding to the key, or NULL if not found +db_val_t db_search (struct dbt *table, db_key_t key); +/// Add or replace table[key] = data +// if it was already there, call release +struct dbn *db_insert (struct dbt *table, db_key_t key, db_val_t data); +/// Remove a key from the table, returning the data +db_val_t db_erase (struct dbt *table, db_key_t key); + +/// Execute a function for every element, in unspecified order +void db_foreach (struct dbt *, db_func_t, ...); +// opposite of init? Calls release for every element and frees memory +// This probably isn't really needed: we don't have to free memory while exiting +void db_final (struct dbt *, db_func_t, ...) __attribute__((deprecated)); + +#endif diff --git a/src/common/grfio.c b/src/common/grfio.c deleted file mode 100644 index d640263..0000000 --- a/src/common/grfio.c +++ /dev/null @@ -1,212 +0,0 @@ -// Reads .gat files by name-mapping .wlk files -#include -#include -#include -#include - -#include "utils.h" -#include "grfio.h" -#include "mmo.h" -#include "socket.h" - -//---------------------------- -// file entry table struct -//---------------------------- -typedef struct -{ - size_t declen; - int16_t next; // next index into the filelist[] array, or -1 - char fn[128 - 4 - 2]; // file name -} FILELIST; - -#define FILELIST_LIMIT 32768 // limit to number of filelists - if you increase this, change all shorts to int -#define FILELIST_ADDS 1024 // amount to increment when reallocing - -static FILELIST *filelist = NULL; -/// Number of entries used -static uint16_t filelist_entrys = 0; -/// Number of FILELIST entries actually allocated -static uint16_t filelist_maxentry = 0; - -/// First index of the given hash, into the filelist[] array -static int16_t filelist_hash[256] = {[0 ... 255] = -1}; - -/// Hash a filename -static uint8_t filehash (const char *fname) -{ - // Larger than the return type - upper bits are used in the process - uint32_t hash = 0; - while (*fname) - { - hash = (hash << 1) + (hash >> 7) * 9 + (unsigned char)*fname; - fname++; - } - return hash; -} - -/// Find the filelist entry for the given filename, or NULL if it is not -FILELIST *filelist_find (const char *fname) -{ - int16_t index = filelist_hash[filehash (fname)]; - while (index >= 0) - { - if (strcmp (filelist[index].fn, fname) == 0) - return &filelist[index]; - index = filelist[index].next; - } - return NULL; -} - -/// Copy a temporary entry into the hash map -static FILELIST *filelist_add (FILELIST * entry) -{ - if (filelist_entrys >= FILELIST_LIMIT) - { - fprintf (stderr, "filelist limit : filelist_add\n"); - exit (1); - } - - if (filelist_entrys >= filelist_maxentry) - { - RECREATE(filelist, FILELIST, filelist_maxentry + FILELIST_ADDS); - memset (filelist + filelist_maxentry, '\0', - FILELIST_ADDS * sizeof (FILELIST)); - filelist_maxentry += FILELIST_ADDS; - } - - uint16_t new_index = filelist_entrys++; - uint8_t hash = filehash (entry->fn); - entry->next = filelist_hash[hash]; - filelist_hash[hash] = new_index; - - filelist[new_index] = *entry; - - return &filelist[new_index]; -} - -static FILELIST *filelist_modify (FILELIST * entry) -{ - FILELIST *fentry = filelist_find (entry->fn); - if (fentry) - { - entry->next = fentry->next; - *fentry = *entry; - return fentry; - } - return filelist_add (entry); -} - -/// Change fname data/*.gat to lfname data/*.wlk -// TODO even if the file exists, don't keep reopening it every time one loads -void grfio_resnametable (const char *fname, char *lfname) -{ - char restable[] = "data/resnametable.txt"; - - FILE *fp = fopen_ (restable, "rb"); - if (fp == NULL) - { - fprintf(stderr, "No resnametable, can't look for %s\n", fname); - strcpy(lfname, fname); - char* ext = lfname + strlen(lfname) - 4; - if (!strcmp(ext, ".gat")) - strcpy(ext, ".wlk"); - return; - } - - char line[512]; - while (fgets (line, sizeof (line), fp)) - { - char w1[256], w2[256]; - if ( - // line is of the form foo.gat#foo.wlk# - (sscanf (line, "%[^#]#%[^#]#", w1, w2) == 2) - // strip data/ from foo.gat before comparing - && (!strcmp (w1, fname + 5))) - { - strcpy (lfname, "data/"); - strcpy (lfname + 5, w2); - fclose_ (fp); - return; - } - } - fprintf(stderr, "Unable to find resource: %s\n", fname); - fclose_ (fp); - - strcpy(lfname, fname); - char* ext = lfname + strlen(lfname) - 4; - if (!strcmp(ext, ".gat")) - strcpy(ext, ".wlk"); - return; -} - -/// Size of resource -size_t grfio_size (const char *fname) -{ - FILELIST *entry = filelist_find (fname); - if (entry) - return entry->declen; - - char lfname[256]; - FILELIST lentry; - struct stat st; - - grfio_resnametable (fname, lfname); - - for (char *p = lfname; *p; p++) - if (*p == '\\') - *p = '/'; - - if (stat (lfname, &st) == 0) - { - strncpy (lentry.fn, fname, sizeof (lentry.fn) - 1); - lentry.declen = st.st_size; - entry = filelist_modify (&lentry); - } - else - { - printf ("%s not found\n", fname); - return 0; - } - return entry->declen; -} - -void *grfio_reads (const char *fname, size_t *size) -{ - char lfname[256]; - grfio_resnametable (fname, lfname); - - for (char *p = &lfname[0]; *p != 0; p++) - if (*p == '\\') - *p = '/'; // * At the time of Unix - - FILE *in = fopen_ (lfname, "rb"); - if (!in) - { - fprintf (stderr, "%s not found\n", fname); - return NULL; - } - FILELIST lentry; - FILELIST *entry = filelist_find (fname); - if (entry) - { - lentry.declen = entry->declen; - } - else - { - fseek (in, 0, SEEK_END); - lentry.declen = ftell (in); - fseek (in, 0, SEEK_SET); - strncpy (lentry.fn, fname, sizeof (lentry.fn) - 1); - entry = filelist_modify (&lentry); - } - uint8_t *buf2; - CREATE (buf2, uint8_t, lentry.declen + 1024); - if (fread (buf2, 1, lentry.declen, in) != lentry.declen) - exit(1); - fclose_ (in); - in = NULL; - - if (size) - *size = entry->declen; - return buf2; -} diff --git a/src/common/grfio.cpp b/src/common/grfio.cpp new file mode 100644 index 0000000..1b89b18 --- /dev/null +++ b/src/common/grfio.cpp @@ -0,0 +1,212 @@ +// Reads .gat files by name-mapping .wlk files +#include +#include +#include +#include + +#include "utils.hpp" +#include "grfio.hpp" +#include "mmo.hpp" +#include "socket.hpp" + +//---------------------------- +// file entry table struct +//---------------------------- +typedef struct +{ + size_t declen; + int16_t next; // next index into the filelist[] array, or -1 + char fn[128 - 4 - 2]; // file name +} FILELIST; + +#define FILELIST_LIMIT 32768 // limit to number of filelists - if you increase this, change all shorts to int +#define FILELIST_ADDS 1024 // amount to increment when reallocing + +static FILELIST *filelist = NULL; +/// Number of entries used +static uint16_t filelist_entrys = 0; +/// Number of FILELIST entries actually allocated +static uint16_t filelist_maxentry = 0; + +/// First index of the given hash, into the filelist[] array +static int16_t filelist_hash[256] = {[0 ... 255] = -1}; + +/// Hash a filename +static uint8_t filehash (const char *fname) +{ + // Larger than the return type - upper bits are used in the process + uint32_t hash = 0; + while (*fname) + { + hash = (hash << 1) + (hash >> 7) * 9 + (unsigned char)*fname; + fname++; + } + return hash; +} + +/// Find the filelist entry for the given filename, or NULL if it is not +FILELIST *filelist_find (const char *fname) +{ + int16_t index = filelist_hash[filehash (fname)]; + while (index >= 0) + { + if (strcmp (filelist[index].fn, fname) == 0) + return &filelist[index]; + index = filelist[index].next; + } + return NULL; +} + +/// Copy a temporary entry into the hash map +static FILELIST *filelist_add (FILELIST * entry) +{ + if (filelist_entrys >= FILELIST_LIMIT) + { + fprintf (stderr, "filelist limit : filelist_add\n"); + exit (1); + } + + if (filelist_entrys >= filelist_maxentry) + { + RECREATE(filelist, FILELIST, filelist_maxentry + FILELIST_ADDS); + memset (filelist + filelist_maxentry, '\0', + FILELIST_ADDS * sizeof (FILELIST)); + filelist_maxentry += FILELIST_ADDS; + } + + uint16_t new_index = filelist_entrys++; + uint8_t hash = filehash (entry->fn); + entry->next = filelist_hash[hash]; + filelist_hash[hash] = new_index; + + filelist[new_index] = *entry; + + return &filelist[new_index]; +} + +static FILELIST *filelist_modify (FILELIST * entry) +{ + FILELIST *fentry = filelist_find (entry->fn); + if (fentry) + { + entry->next = fentry->next; + *fentry = *entry; + return fentry; + } + return filelist_add (entry); +} + +/// Change fname data/*.gat to lfname data/*.wlk +// TODO even if the file exists, don't keep reopening it every time one loads +void grfio_resnametable (const char *fname, char *lfname) +{ + char restable[] = "data/resnametable.txt"; + + FILE *fp = fopen_ (restable, "rb"); + if (fp == NULL) + { + fprintf(stderr, "No resnametable, can't look for %s\n", fname); + strcpy(lfname, fname); + char* ext = lfname + strlen(lfname) - 4; + if (!strcmp(ext, ".gat")) + strcpy(ext, ".wlk"); + return; + } + + char line[512]; + while (fgets (line, sizeof (line), fp)) + { + char w1[256], w2[256]; + if ( + // line is of the form foo.gat#foo.wlk# + (sscanf (line, "%[^#]#%[^#]#", w1, w2) == 2) + // strip data/ from foo.gat before comparing + && (!strcmp (w1, fname + 5))) + { + strcpy (lfname, "data/"); + strcpy (lfname + 5, w2); + fclose_ (fp); + return; + } + } + fprintf(stderr, "Unable to find resource: %s\n", fname); + fclose_ (fp); + + strcpy(lfname, fname); + char* ext = lfname + strlen(lfname) - 4; + if (!strcmp(ext, ".gat")) + strcpy(ext, ".wlk"); + return; +} + +/// Size of resource +size_t grfio_size (const char *fname) +{ + FILELIST *entry = filelist_find (fname); + if (entry) + return entry->declen; + + char lfname[256]; + FILELIST lentry; + struct stat st; + + grfio_resnametable (fname, lfname); + + for (char *p = lfname; *p; p++) + if (*p == '\\') + *p = '/'; + + if (stat (lfname, &st) == 0) + { + strncpy (lentry.fn, fname, sizeof (lentry.fn) - 1); + lentry.declen = st.st_size; + entry = filelist_modify (&lentry); + } + else + { + printf ("%s not found\n", fname); + return 0; + } + return entry->declen; +} + +void *grfio_reads (const char *fname, size_t *size) +{ + char lfname[256]; + grfio_resnametable (fname, lfname); + + for (char *p = &lfname[0]; *p != 0; p++) + if (*p == '\\') + *p = '/'; // * At the time of Unix + + FILE *in = fopen_ (lfname, "rb"); + if (!in) + { + fprintf (stderr, "%s not found\n", fname); + return NULL; + } + FILELIST lentry; + FILELIST *entry = filelist_find (fname); + if (entry) + { + lentry.declen = entry->declen; + } + else + { + fseek (in, 0, SEEK_END); + lentry.declen = ftell (in); + fseek (in, 0, SEEK_SET); + strncpy (lentry.fn, fname, sizeof (lentry.fn) - 1); + entry = filelist_modify (&lentry); + } + uint8_t *buf2; + CREATE (buf2, uint8_t, lentry.declen + 1024); + if (fread (buf2, 1, lentry.declen, in) != lentry.declen) + exit(1); + fclose_ (in); + in = NULL; + + if (size) + *size = entry->declen; + return buf2; +} diff --git a/src/common/grfio.h b/src/common/grfio.h deleted file mode 100644 index 4919a7b..0000000 --- a/src/common/grfio.h +++ /dev/null @@ -1,17 +0,0 @@ -/// Accessor to the .gat map virtual files -// Note .gat files are mapped to .wlk files by data/resnametable.txt -// Note that there currently is a 1-1 correlation between them, -// but it is possible for a single .wlk to have multiple .gats reference it -#ifndef GRFIO_H -#define GRFIO_H - -/// Load file into memory -# define grfio_read(resourcename) grfio_reads (resourcename, NULL) -/// Load file into memory and possibly record length -// For some reason, this allocates an extra 1024 bytes at the end -void *grfio_reads (const char *resourcename, size_t *size); -/// Get size of file -// This is only called once, and that is to check the existence of a file. -size_t grfio_size (const char *resourcename) __attribute__((deprecated)); - -#endif // GRFIO_H diff --git a/src/common/grfio.hpp b/src/common/grfio.hpp new file mode 100644 index 0000000..3485904 --- /dev/null +++ b/src/common/grfio.hpp @@ -0,0 +1,17 @@ +/// Accessor to the .gat map virtual files +// Note .gat files are mapped to .wlk files by data/resnametable.txt +// Note that there currently is a 1-1 correlation between them, +// but it is possible for a single .wlk to have multiple .gats reference it +#ifndef GRFIO_HPP +#define GRFIO_HPP + +/// Load file into memory +# define grfio_read(resourcename) grfio_reads (resourcename, NULL) +/// Load file into memory and possibly record length +// For some reason, this allocates an extra 1024 bytes at the end +void *grfio_reads (const char *resourcename, size_t *size); +/// Get size of file +// This is only called once, and that is to check the existence of a file. +size_t grfio_size (const char *resourcename) __attribute__((deprecated)); + +#endif // GRFIO_HPP diff --git a/src/common/lock.c b/src/common/lock.c deleted file mode 100644 index dd42ef2..0000000 --- a/src/common/lock.c +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include -#include "lock.h" -#include "socket.h" - -/// Protected file writing -/// (Until the file is closed, it keeps the old file) - -// Start writing a tmpfile -FILE *lock_fopen (const char *filename, int *info) -{ - char newfile[512]; - FILE *fp; - int no = getpid (); - - // Get a filename that doesn't already exist - do - { - sprintf (newfile, "%s_%d.tmp", filename, no++); - } - while ((fp = fopen_ (newfile, "r")) && (fclose_ (fp), 1)); - *info = --no; - return fopen_ (newfile, "w"); -} - -// Delete the old file and rename the new file -void lock_fclose (FILE * fp, const char *filename, int *info) -{ - char newfile[512]; - if (fp) - { - fclose_ (fp); - sprintf (newfile, "%s_%d.tmp", filename, *info); - rename (newfile, filename); - } -} diff --git a/src/common/lock.cpp b/src/common/lock.cpp new file mode 100644 index 0000000..2ba9a0a --- /dev/null +++ b/src/common/lock.cpp @@ -0,0 +1,36 @@ +#include +#include +#include "lock.hpp" +#include "socket.hpp" + +/// Protected file writing +/// (Until the file is closed, it keeps the old file) + +// Start writing a tmpfile +FILE *lock_fopen (const char *filename, int *info) +{ + char newfile[512]; + FILE *fp; + int no = getpid (); + + // Get a filename that doesn't already exist + do + { + sprintf (newfile, "%s_%d.tmp", filename, no++); + } + while ((fp = fopen_ (newfile, "r")) && (fclose_ (fp), 1)); + *info = --no; + return fopen_ (newfile, "w"); +} + +// Delete the old file and rename the new file +void lock_fclose (FILE * fp, const char *filename, int *info) +{ + char newfile[512]; + if (fp) + { + fclose_ (fp); + sprintf (newfile, "%s_%d.tmp", filename, *info); + rename (newfile, filename); + } +} diff --git a/src/common/lock.h b/src/common/lock.h deleted file mode 100644 index 2f087fd..0000000 --- a/src/common/lock.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef LOCK_H -#define LOCK_H -/// Locked FILE I/O -// Changes are made in a separate file until lock_fclose -FILE *lock_fopen (const char *filename, int *info); -void lock_fclose (FILE * fp, const char *filename, int *info); - -#endif // LOCK_H diff --git a/src/common/lock.hpp b/src/common/lock.hpp new file mode 100644 index 0000000..19c1302 --- /dev/null +++ b/src/common/lock.hpp @@ -0,0 +1,8 @@ +#ifndef LOCK_HPP +#define LOCK_HPP +/// Locked FILE I/O +// Changes are made in a separate file until lock_fclose +FILE *lock_fopen (const char *filename, int *info); +void lock_fclose (FILE * fp, const char *filename, int *info); + +#endif // LOCK_HPP diff --git a/src/common/md5calc.c b/src/common/md5calc.c deleted file mode 100644 index ba8f6af..0000000 --- a/src/common/md5calc.c +++ /dev/null @@ -1,339 +0,0 @@ -#include "md5calc.h" -#include -#include "mt_rand.h" - -// auxilary data -/* -sin() constant table -# Reformatted output of: -echo 'scale=40; obase=16; for (i=1;i<=64;i++) print 2^32 * sin(i), "\n"' | -bc | sed 's/^-//;s/^/0x/;s/\..*$/,/' -*/ -static const uint32_t T[64] = -{ - // used by round 1 - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, //0 - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, //4 - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, //8 - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, //12 - // used by round 2 - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, //16 - 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, //20 - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, //24 - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, //28 - // used by round 3 - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, //32 - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, //36 - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, //40 - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, //44 - // used by round 4 - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, //48 - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, //52 - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, //56 - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, //60 -}; - -// auxilary functions -// note - the RFC defines these by non-CS conventions: or=v, and=(empty) -static inline uint32_t rotate_left(uint32_t val, unsigned shift) -{ - return val << shift | val >> (32-shift); -} - -static inline uint32_t F(uint32_t X, uint32_t Y, uint32_t Z) -{ - return (X & Y) | (~X & Z); -} -static inline uint32_t G(uint32_t X, uint32_t Y, uint32_t Z) -{ - return (X & Z) | (Y & ~Z); -} -static inline uint32_t H(uint32_t X, uint32_t Y, uint32_t Z) -{ - return X ^ Y ^ Z; -} -static inline uint32_t I(uint32_t X, uint32_t Y, uint32_t Z) -{ - return Y ^ (X | ~Z); -} - -static const struct -{ - uint8_t k : 4; - uint8_t : 0; - uint8_t s : 5; -// uint8_t i : 6; just increments constantly, from 1 .. 64 over all rounds -} -MD5_round1[16] = -{ - { 0, 7}, { 1, 12}, { 2, 17}, { 3, 22}, - { 4, 7}, { 5, 12}, { 6, 17}, { 7, 22}, - { 8, 7}, { 9, 12}, {10, 17}, {11, 22}, - {12, 7}, {13, 12}, {14, 17}, {15, 22}, -}, -MD5_round2[16] = -{ - { 1, 5}, { 6, 9}, {11, 14}, { 0, 20}, - { 5, 5}, {10, 9}, {15, 14}, { 4, 20}, - { 9, 5}, {14, 9}, { 3, 14}, { 8, 20}, - {13, 5}, { 2, 9}, { 7, 14}, {12, 20}, -}, -MD5_round3[16] = -{ - { 5, 4}, { 8, 11}, {11, 16}, {14, 23}, - { 1, 4}, { 4, 11}, { 7, 16}, {10, 23}, - {13, 4}, { 0, 11}, { 3, 16}, { 6, 23}, - { 9, 4}, {12, 11}, {15, 16}, { 2, 23}, -}, -MD5_round4[16] = -{ - { 0, 6}, { 7, 10}, {14, 15}, { 5, 21}, - {12, 6}, { 3, 10}, {10, 15}, { 1, 21}, - { 8, 6}, {15, 10}, { 6, 15}, {13, 21}, - { 4, 6}, {11, 10}, { 2, 15}, { 9, 21}, -}; - - -void MD5_init(MD5_state* state) -{ - // in the RFC, these are specified as bytes, interpreted as little-endian - state->val[0] = 0x67452301; - state->val[1] = 0xEFCDAB89; - state->val[2] = 0x98BADCFE; - state->val[3] = 0x10325476; -} - -void MD5_do_block(MD5_state* state, MD5_block block) -{ -#define X block.data -#define a state->val[(16-i)%4] -#define b state->val[(17-i)%4] -#define c state->val[(18-i)%4] -#define d state->val[(19-i)%4] - // save the values - const MD5_state saved = *state; - // round 1 - for (int i=0; i<16; i++) - { -#define k MD5_round1[i].k -#define s MD5_round1[i].s - a = b + rotate_left(a + F(b,c,d) + X[k] + T[i+0x0], s); -#undef k -#undef s - } - // round 2 - for (int i=0; i<16; i++) - { -#define k MD5_round2[i].k -#define s MD5_round2[i].s - a = b + rotate_left(a + G(b,c,d) + X[k] + T[i+0x10], s); -#undef k -#undef s - } - // round 3 - for (int i=0; i<16; i++) - { -#define k MD5_round3[i].k -#define s MD5_round3[i].s - a = b + rotate_left(a + H(b,c,d) + X[k] + T[i+0x20], s); -#undef k -#undef s - } - // round 4 - for (int i=0; i<16; i++) - { -#define k MD5_round4[i].k -#define s MD5_round4[i].s - a = b + rotate_left(a + I(b,c,d) + X[k] + T[i+0x30], s); -#undef k -#undef s - } - // adjust state based on original - state->val[0] += saved.val[0]; - state->val[1] += saved.val[1]; - state->val[2] += saved.val[2]; - state->val[3] += saved.val[3]; -#undef a -#undef b -#undef c -#undef d -} - -void MD5_to_bin(MD5_state state, uint8_t out[0x10]) -{ - for (int i=0; i<0x10; i++) - out[i] = state.val[i/4] >> 8*(i%4); -} - -static const char hex[] = "0123456789abcdef"; - -void MD5_to_str(MD5_state state, char out[0x21]) -{ - uint8_t bin[16]; - MD5_to_bin(state, bin); - for (int i=0; i<0x10; i++) - out[2*i] = hex[bin[i] >> 4], - out[2*i+1] = hex[bin[i] & 0xf]; - out[0x20] = '\0'; -} - -MD5_state MD5_from_string(const char* msg, const size_t msglen) -{ - MD5_state state; - MD5_init(&state); - MD5_block block; - size_t rem = msglen; - while (rem >= 64) - { - for (int i=0; i<0x10; i++) - X[i] = msg[4*i+0] | msg[4*i+1]<<8 | msg[4*i+2]<<16 | msg[4*i+3]<<24; - MD5_do_block(&state, block); - msg += 64; - rem -= 64; - } - // now pad 1-512 bits + the 64-bit length - may be two blocks - uint8_t buf[0x40] = {}; - memcpy (buf, msg, rem); - buf[rem] = 0x80; // a single one bit - if (64 - rem > 8) - { - for (int i=0; i<8; i++) - buf[0x38+i] = ((uint64_t)msglen*8) >> (i*8); - } - for (int i=0; i<0x10; i++) - X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; - MD5_do_block(&state, block); - if (64 - rem <= 8) - { - memset(buf,'\0', 0x38); - for (int i=0; i<8; i++) - buf[0x38+i] = ((uint64_t)msglen*8) >> (i*8); - for (int i=0; i<0x10; i++) - X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; - MD5_do_block(&state, block); - } - return state; -} - -// This could be reimplemented without the strlen() -MD5_state MD5_from_cstring(const char* msg) -{ - return MD5_from_string(msg, strlen(msg)); -} - -MD5_state MD5_from_FILE(FILE* in) { - uint64_t total_len = 0; - - uint8_t buf[0x40]; - uint8_t block_len = 0; - - MD5_state state; - MD5_init(&state); - - MD5_block block; - - while (true) - { - size_t rv = fread(buf + block_len, 1, 0x40 - block_len, in); - if (!rv) - break; - total_len += 8*rv; // in bits - block_len += rv; - if (block_len != 0x40) - continue; - for (int i=0; i<0x10; i++) - X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; - MD5_do_block(&state, block); - block_len = 0; - } - // no more input, just pad and append the length - buf[block_len] = 0x80; - memset(buf + block_len + 1, '\0', 0x40 - block_len - 1); - if (block_len < 0x38) - { - for (int i=0; i<8; i++) - buf[0x38+i] = total_len >> i*8; - } - for (int i=0; i<0x10; i++) - X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; - MD5_do_block(&state, block); - if (0x38 <= block_len) - { - memset(buf, '\0', 0x38); - for (int i=0; i<8; i++) - buf[0x38+i] = total_len >> i*8; - for (int i=0; i<0x10; i++) - X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; - MD5_do_block(&state, block); - } - return state; -} - - -// Hash a password with a salt. -// Whoever wrote this FAILS programming -const char *MD5_saltcrypt(const char *key, const char *salt) -{ - char buf[65]; - - // hash the key then the salt - // buf ends up as a 64-char NUL-terminated string - MD5_to_str(MD5_from_cstring(key), buf); - MD5_to_str(MD5_from_cstring(salt), buf+32); - - // Hash the buffer back into sbuf - this is stupid - // (luckily, putting the result into itself is safe) - MD5_to_str(MD5_from_cstring(buf), buf+32); - - static char obuf[33]; - // This truncates the string, but we have to keep it like that for compatibility - snprintf(obuf, 32, "!%s$%s", salt, buf+32); - return obuf; -} - -const char *make_salt(void) { - static char salt[6]; - for (int i=0; i<5; i++) - salt[i] = MPRAND(48, 78); - return salt; -} - -bool pass_ok(const char *password, const char *crypted) { - char buf[40]; - strncpy(buf, crypted, 40); - char *salt = buf + 1; - *strchr(salt, '$') = '\0'; - - return !strcmp(crypted, MD5_saltcrypt(password, salt)); -} - -// [M|h]ashes up an IP address and a secret key -// to return a hopefully unique masked IP. -in_addr_t MD5_ip(char *secret, in_addr_t ip) -{ - char ipbuf[32]; - uint8_t obuf[16]; - union { - struct bytes { - uint8_t b1; - uint8_t b2; - uint8_t b3; - uint8_t b4; - } bytes; - in_addr_t ip; - } conv; - - // MD5sum a secret + the IP address - memset(&ipbuf, 0, sizeof(ipbuf)); - snprintf(ipbuf, sizeof(ipbuf), "%lu%s", (unsigned long)ip, secret); - /// TODO stop it from being a cstring - MD5_to_bin(MD5_from_cstring(ipbuf), obuf); - - // Fold the md5sum to 32 bits, pack the bytes to an in_addr_t - conv.bytes.b1 = obuf[0] ^ obuf[1] ^ obuf[8] ^ obuf[9]; - conv.bytes.b2 = obuf[2] ^ obuf[3] ^ obuf[10] ^ obuf[11]; - conv.bytes.b3 = obuf[4] ^ obuf[5] ^ obuf[12] ^ obuf[13]; - conv.bytes.b4 = obuf[6] ^ obuf[7] ^ obuf[14] ^ obuf[15]; - - return conv.ip; -} diff --git a/src/common/md5calc.cpp b/src/common/md5calc.cpp new file mode 100644 index 0000000..f00861d --- /dev/null +++ b/src/common/md5calc.cpp @@ -0,0 +1,339 @@ +#include "md5calc.hpp" +#include +#include "mt_rand.hpp" + +// auxilary data +/* +sin() constant table +# Reformatted output of: +echo 'scale=40; obase=16; for (i=1;i<=64;i++) print 2^32 * sin(i), "\n"' | +bc | sed 's/^-//;s/^/0x/;s/\..*$/,/' +*/ +static const uint32_t T[64] = +{ + // used by round 1 + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, //0 + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, //4 + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, //8 + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, //12 + // used by round 2 + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, //16 + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, //20 + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, //24 + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, //28 + // used by round 3 + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, //32 + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, //36 + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, //40 + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, //44 + // used by round 4 + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, //48 + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, //52 + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, //56 + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, //60 +}; + +// auxilary functions +// note - the RFC defines these by non-CS conventions: or=v, and=(empty) +static inline uint32_t rotate_left(uint32_t val, unsigned shift) +{ + return val << shift | val >> (32-shift); +} + +static inline uint32_t F(uint32_t X, uint32_t Y, uint32_t Z) +{ + return (X & Y) | (~X & Z); +} +static inline uint32_t G(uint32_t X, uint32_t Y, uint32_t Z) +{ + return (X & Z) | (Y & ~Z); +} +static inline uint32_t H(uint32_t X, uint32_t Y, uint32_t Z) +{ + return X ^ Y ^ Z; +} +static inline uint32_t I(uint32_t X, uint32_t Y, uint32_t Z) +{ + return Y ^ (X | ~Z); +} + +static const struct +{ + uint8_t k : 4; + uint8_t : 0; + uint8_t s : 5; +// uint8_t i : 6; just increments constantly, from 1 .. 64 over all rounds +} +MD5_round1[16] = +{ + { 0, 7}, { 1, 12}, { 2, 17}, { 3, 22}, + { 4, 7}, { 5, 12}, { 6, 17}, { 7, 22}, + { 8, 7}, { 9, 12}, {10, 17}, {11, 22}, + {12, 7}, {13, 12}, {14, 17}, {15, 22}, +}, +MD5_round2[16] = +{ + { 1, 5}, { 6, 9}, {11, 14}, { 0, 20}, + { 5, 5}, {10, 9}, {15, 14}, { 4, 20}, + { 9, 5}, {14, 9}, { 3, 14}, { 8, 20}, + {13, 5}, { 2, 9}, { 7, 14}, {12, 20}, +}, +MD5_round3[16] = +{ + { 5, 4}, { 8, 11}, {11, 16}, {14, 23}, + { 1, 4}, { 4, 11}, { 7, 16}, {10, 23}, + {13, 4}, { 0, 11}, { 3, 16}, { 6, 23}, + { 9, 4}, {12, 11}, {15, 16}, { 2, 23}, +}, +MD5_round4[16] = +{ + { 0, 6}, { 7, 10}, {14, 15}, { 5, 21}, + {12, 6}, { 3, 10}, {10, 15}, { 1, 21}, + { 8, 6}, {15, 10}, { 6, 15}, {13, 21}, + { 4, 6}, {11, 10}, { 2, 15}, { 9, 21}, +}; + + +void MD5_init(MD5_state* state) +{ + // in the RFC, these are specified as bytes, interpreted as little-endian + state->val[0] = 0x67452301; + state->val[1] = 0xEFCDAB89; + state->val[2] = 0x98BADCFE; + state->val[3] = 0x10325476; +} + +void MD5_do_block(MD5_state* state, MD5_block block) +{ +#define X block.data +#define a state->val[(16-i)%4] +#define b state->val[(17-i)%4] +#define c state->val[(18-i)%4] +#define d state->val[(19-i)%4] + // save the values + const MD5_state saved = *state; + // round 1 + for (int i=0; i<16; i++) + { +#define k MD5_round1[i].k +#define s MD5_round1[i].s + a = b + rotate_left(a + F(b,c,d) + X[k] + T[i+0x0], s); +#undef k +#undef s + } + // round 2 + for (int i=0; i<16; i++) + { +#define k MD5_round2[i].k +#define s MD5_round2[i].s + a = b + rotate_left(a + G(b,c,d) + X[k] + T[i+0x10], s); +#undef k +#undef s + } + // round 3 + for (int i=0; i<16; i++) + { +#define k MD5_round3[i].k +#define s MD5_round3[i].s + a = b + rotate_left(a + H(b,c,d) + X[k] + T[i+0x20], s); +#undef k +#undef s + } + // round 4 + for (int i=0; i<16; i++) + { +#define k MD5_round4[i].k +#define s MD5_round4[i].s + a = b + rotate_left(a + I(b,c,d) + X[k] + T[i+0x30], s); +#undef k +#undef s + } + // adjust state based on original + state->val[0] += saved.val[0]; + state->val[1] += saved.val[1]; + state->val[2] += saved.val[2]; + state->val[3] += saved.val[3]; +#undef a +#undef b +#undef c +#undef d +} + +void MD5_to_bin(MD5_state state, uint8_t out[0x10]) +{ + for (int i=0; i<0x10; i++) + out[i] = state.val[i/4] >> 8*(i%4); +} + +static const char hex[] = "0123456789abcdef"; + +void MD5_to_str(MD5_state state, char out[0x21]) +{ + uint8_t bin[16]; + MD5_to_bin(state, bin); + for (int i=0; i<0x10; i++) + out[2*i] = hex[bin[i] >> 4], + out[2*i+1] = hex[bin[i] & 0xf]; + out[0x20] = '\0'; +} + +MD5_state MD5_from_string(const char* msg, const size_t msglen) +{ + MD5_state state; + MD5_init(&state); + MD5_block block; + size_t rem = msglen; + while (rem >= 64) + { + for (int i=0; i<0x10; i++) + X[i] = msg[4*i+0] | msg[4*i+1]<<8 | msg[4*i+2]<<16 | msg[4*i+3]<<24; + MD5_do_block(&state, block); + msg += 64; + rem -= 64; + } + // now pad 1-512 bits + the 64-bit length - may be two blocks + uint8_t buf[0x40] = {}; + memcpy (buf, msg, rem); + buf[rem] = 0x80; // a single one bit + if (64 - rem > 8) + { + for (int i=0; i<8; i++) + buf[0x38+i] = ((uint64_t)msglen*8) >> (i*8); + } + for (int i=0; i<0x10; i++) + X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; + MD5_do_block(&state, block); + if (64 - rem <= 8) + { + memset(buf,'\0', 0x38); + for (int i=0; i<8; i++) + buf[0x38+i] = ((uint64_t)msglen*8) >> (i*8); + for (int i=0; i<0x10; i++) + X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; + MD5_do_block(&state, block); + } + return state; +} + +// This could be reimplemented without the strlen() +MD5_state MD5_from_cstring(const char* msg) +{ + return MD5_from_string(msg, strlen(msg)); +} + +MD5_state MD5_from_FILE(FILE* in) { + uint64_t total_len = 0; + + uint8_t buf[0x40]; + uint8_t block_len = 0; + + MD5_state state; + MD5_init(&state); + + MD5_block block; + + while (true) + { + size_t rv = fread(buf + block_len, 1, 0x40 - block_len, in); + if (!rv) + break; + total_len += 8*rv; // in bits + block_len += rv; + if (block_len != 0x40) + continue; + for (int i=0; i<0x10; i++) + X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; + MD5_do_block(&state, block); + block_len = 0; + } + // no more input, just pad and append the length + buf[block_len] = 0x80; + memset(buf + block_len + 1, '\0', 0x40 - block_len - 1); + if (block_len < 0x38) + { + for (int i=0; i<8; i++) + buf[0x38+i] = total_len >> i*8; + } + for (int i=0; i<0x10; i++) + X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; + MD5_do_block(&state, block); + if (0x38 <= block_len) + { + memset(buf, '\0', 0x38); + for (int i=0; i<8; i++) + buf[0x38+i] = total_len >> i*8; + for (int i=0; i<0x10; i++) + X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; + MD5_do_block(&state, block); + } + return state; +} + + +// Hash a password with a salt. +// Whoever wrote this FAILS programming +const char *MD5_saltcrypt(const char *key, const char *salt) +{ + char buf[65]; + + // hash the key then the salt + // buf ends up as a 64-char NUL-terminated string + MD5_to_str(MD5_from_cstring(key), buf); + MD5_to_str(MD5_from_cstring(salt), buf+32); + + // Hash the buffer back into sbuf - this is stupid + // (luckily, putting the result into itself is safe) + MD5_to_str(MD5_from_cstring(buf), buf+32); + + static char obuf[33]; + // This truncates the string, but we have to keep it like that for compatibility + snprintf(obuf, 32, "!%s$%s", salt, buf+32); + return obuf; +} + +const char *make_salt(void) { + static char salt[6]; + for (int i=0; i<5; i++) + salt[i] = MPRAND(48, 78); + return salt; +} + +bool pass_ok(const char *password, const char *crypted) { + char buf[40]; + strncpy(buf, crypted, 40); + char *salt = buf + 1; + *strchr(salt, '$') = '\0'; + + return !strcmp(crypted, MD5_saltcrypt(password, salt)); +} + +// [M|h]ashes up an IP address and a secret key +// to return a hopefully unique masked IP. +in_addr_t MD5_ip(char *secret, in_addr_t ip) +{ + char ipbuf[32]; + uint8_t obuf[16]; + union { + struct bytes { + uint8_t b1; + uint8_t b2; + uint8_t b3; + uint8_t b4; + } bytes; + in_addr_t ip; + } conv; + + // MD5sum a secret + the IP address + memset(&ipbuf, 0, sizeof(ipbuf)); + snprintf(ipbuf, sizeof(ipbuf), "%lu%s", (unsigned long)ip, secret); + /// TODO stop it from being a cstring + MD5_to_bin(MD5_from_cstring(ipbuf), obuf); + + // Fold the md5sum to 32 bits, pack the bytes to an in_addr_t + conv.bytes.b1 = obuf[0] ^ obuf[1] ^ obuf[8] ^ obuf[9]; + conv.bytes.b2 = obuf[2] ^ obuf[3] ^ obuf[10] ^ obuf[11]; + conv.bytes.b3 = obuf[4] ^ obuf[5] ^ obuf[12] ^ obuf[13]; + conv.bytes.b4 = obuf[6] ^ obuf[7] ^ obuf[14] ^ obuf[15]; + + return conv.ip; +} diff --git a/src/common/md5calc.h b/src/common/md5calc.h deleted file mode 100644 index b864791..0000000 --- a/src/common/md5calc.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef MD5CALC_H -#define MD5CALC_H - -#include "sanity.h" - -#include - -#include // uint32_t, uint8_t -#include // size_t -#include // FILE* - -/// The digest state - becomes the output -typedef struct -{ - // classically named {A,B,C,D} - // but use an so we can index - uint32_t val[4]; -} MD5_state; -typedef struct -{ - uint32_t data[16]; -} MD5_block; - -// Implementation -void MD5_init(MD5_state* state); -void MD5_do_block(MD5_state* state, MD5_block block); - -// Output formatting -void MD5_to_bin(MD5_state state, uint8_t out[0x10]); -void MD5_to_str(MD5_state state, char out[0x21]); - -// Convenience -MD5_state MD5_from_string(const char* msg, const size_t msglen); -MD5_state MD5_from_cstring(const char* msg); -MD5_state MD5_from_FILE(FILE* in); - - -/// Output in ASCII - with lowercase hex digits, null-terminated -// these may overlap safely -static void MD5_String (const char *string, char output[33]) __attribute__((deprecated)); -static inline void MD5_String (const char *string, char output[33]) { - MD5_to_str(MD5_from_cstring(string), output); -} -/// Output in binary -static void MD5_String2binary (const char *string, uint8_t output[16]) __attribute__((deprecated)); -static inline void MD5_String2binary (const char *string, uint8_t output[16]) { - MD5_to_bin(MD5_from_cstring(string), output); -} - -// statically-allocated output -// whoever wrote this fails basic understanding of -const char *MD5_saltcrypt(const char *key, const char *salt); - -/// return some random characters (statically allocated) -// Currently, returns a 5-char string -const char *make_salt(void); - -/// check plaintext password against saved saltcrypt -bool pass_ok(const char *password, const char *crypted); - -/// This returns an in_addr_t because it is configurable whether it gets called at all -in_addr_t MD5_ip(char *secret, in_addr_t ip); - -#endif diff --git a/src/common/md5calc.hpp b/src/common/md5calc.hpp new file mode 100644 index 0000000..1dde2ed --- /dev/null +++ b/src/common/md5calc.hpp @@ -0,0 +1,64 @@ +#ifndef MD5CALC_HPP +#define MD5CALC_HPP + +#include "sanity.hpp" + +#include + +#include // uint32_t, uint8_t +#include // size_t +#include // FILE* + +/// The digest state - becomes the output +typedef struct +{ + // classically named {A,B,C,D} + // but use an so we can index + uint32_t val[4]; +} MD5_state; +typedef struct +{ + uint32_t data[16]; +} MD5_block; + +// Implementation +void MD5_init(MD5_state* state); +void MD5_do_block(MD5_state* state, MD5_block block); + +// Output formatting +void MD5_to_bin(MD5_state state, uint8_t out[0x10]); +void MD5_to_str(MD5_state state, char out[0x21]); + +// Convenience +MD5_state MD5_from_string(const char* msg, const size_t msglen); +MD5_state MD5_from_cstring(const char* msg); +MD5_state MD5_from_FILE(FILE* in); + + +/// Output in ASCII - with lowercase hex digits, null-terminated +// these may overlap safely +static void MD5_String (const char *string, char output[33]) __attribute__((deprecated)); +static inline void MD5_String (const char *string, char output[33]) { + MD5_to_str(MD5_from_cstring(string), output); +} +/// Output in binary +static void MD5_String2binary (const char *string, uint8_t output[16]) __attribute__((deprecated)); +static inline void MD5_String2binary (const char *string, uint8_t output[16]) { + MD5_to_bin(MD5_from_cstring(string), output); +} + +// statically-allocated output +// whoever wrote this fails basic understanding of +const char *MD5_saltcrypt(const char *key, const char *salt); + +/// return some random characters (statically allocated) +// Currently, returns a 5-char string +const char *make_salt(void); + +/// check plaintext password against saved saltcrypt +bool pass_ok(const char *password, const char *crypted); + +/// This returns an in_addr_t because it is configurable whether it gets called at all +in_addr_t MD5_ip(char *secret, in_addr_t ip); + +#endif diff --git a/src/common/mmo.h b/src/common/mmo.h deleted file mode 100644 index 64e0523..0000000 --- a/src/common/mmo.h +++ /dev/null @@ -1,283 +0,0 @@ -/// Global structures and defines -#ifndef MMO_H -#define MMO_H - -# include -# include "utils.h" // LCCWIN32 - -# define FIFOSIZE_SERVERLINK 256*1024 - -// set to 0 to not check IP of player between each server. -// set to another value if you want to check (1) -# define CMP_AUTHFIFO_IP 1 - -# define CMP_AUTHFIFO_LOGIN2 1 - -# define MAX_MAP_PER_SERVER 512 -# define MAX_INVENTORY 100 -# define MAX_AMOUNT 30000 -# define MAX_ZENY 1000000000 // 1G zeny -# define MAX_CART 100 -# define MAX_SKILL 450 -# define GLOBAL_REG_NUM 96 -# define ACCOUNT_REG_NUM 16 -# define ACCOUNT_REG2_NUM 16 -# define DEFAULT_WALK_SPEED 150 -# define MIN_WALK_SPEED 0 -# define MAX_WALK_SPEED 1000 -# define MAX_STORAGE 300 -# define MAX_GUILD_STORAGE 1000 -# define MAX_PARTY 12 -# define MAX_GUILD 120 // increased max guild members to accomodate for +2 increase for extension levels [Valaris] (removed) [PoW] -# define MAX_GUILDPOSITION 20 // increased max guild positions to accomodate for all members [Valaris] (removed) [PoW] -# define MAX_GUILDEXPLUSION 32 -# define MAX_GUILDALLIANCE 16 -# define MAX_GUILDSKILL 8 -# define MAX_GUILDCASTLE 24 // increased to include novice castles [Valaris] -# define MAX_GUILDLEVEL 50 - -# define MIN_HAIR_STYLE battle_config.min_hair_style -# define MAX_HAIR_STYLE battle_config.max_hair_style -# define MIN_HAIR_COLOR battle_config.min_hair_color -# define MAX_HAIR_COLOR battle_config.max_hair_color -# define MIN_CLOTH_COLOR battle_config.min_cloth_color -# define MAX_CLOTH_COLOR battle_config.max_cloth_color - -// for produce -# define MIN_ATTRIBUTE 0 -# define MAX_ATTRIBUTE 4 -# define ATTRIBUTE_NORMAL 0 -# define MIN_STAR 0 -# define MAX_STAR 3 - -# define MIN_PORTAL_MEMO 0 -# define MAX_PORTAL_MEMO 2 - -# define MAX_STATUS_TYPE 5 - -# define CHAR_CONF_NAME "conf/char_athena.conf" - -struct item -{ - int id; - short nameid; - short amount; - unsigned short equip; - char identify; - char refine; - char attribute; - short card[4]; - short broken; -}; - -struct point -{ - char map[24]; - short x, y; -}; - -struct skill -{ - unsigned short id, lv, flags; -}; - -struct global_reg -{ - char str[32]; - int value; -}; - -struct mmo_charstatus -{ - int char_id; - int account_id; - int partner_id; - - int base_exp, job_exp, zeny; - - short pc_class; - short status_point, skill_point; - int hp, max_hp, sp, max_sp; - short option, karma, manner; - short hair, hair_color, clothes_color; - int party_id, guild_id; - - short weapon, shield; - short head_top, head_mid, head_bottom; - - char name[24]; - unsigned char base_level, job_level; - short str, agi, vit, int_, dex, luk; - unsigned char char_num, sex; - - unsigned long mapip; - unsigned int mapport; - - struct point last_point, save_point, memo_point[10]; - struct item inventory[MAX_INVENTORY], cart[MAX_CART]; - struct skill skill[MAX_SKILL]; - int global_reg_num; - struct global_reg global_reg[GLOBAL_REG_NUM]; - int account_reg_num; - struct global_reg account_reg[ACCOUNT_REG_NUM]; - int account_reg2_num; - struct global_reg account_reg2[ACCOUNT_REG2_NUM]; -}; - -struct storage -{ - int dirty; - int account_id; - short storage_status; - short storage_amount; - struct item storage_[MAX_STORAGE]; -}; - -struct guild_storage -{ - int dirty; - int guild_id; - short storage_status; - short storage_amount; - struct item storage_[MAX_GUILD_STORAGE]; -}; - -struct map_session_data; - -struct gm_account -{ - int account_id; - int level; -}; - -struct party_member -{ - int account_id; - char name[24], map[24]; - int leader, online, lv; - struct map_session_data *sd; -}; - -struct party -{ - int party_id; - char name[24]; - int exp; - int item; - struct party_member member[MAX_PARTY]; -}; - -struct guild_member -{ - int account_id, char_id; - short hair, hair_color, gender, pc_class, lv; - int exp, exp_payper; - short online, position; - int rsv1, rsv2; - char name[24]; - struct map_session_data *sd; -}; - -struct guild_position -{ - char name[24]; - int mode; - int exp_mode; -}; - -struct guild_alliance -{ - int opposition; - int guild_id; - char name[24]; -}; - -struct guild_explusion -{ - char name[24]; - char mes[40]; - char acc[40]; - int account_id; - int rsv1, rsv2, rsv3; -}; - -struct guild_skill -{ - int id, lv; -}; - -struct guild -{ - int guild_id; - short guild_lv, connect_member, max_member, average_lv; - int exp, next_exp, skill_point, castle_id; - char name[24], master[24]; - struct guild_member member[MAX_GUILD]; - struct guild_position position[MAX_GUILDPOSITION]; - char mes1[60], mes2[120]; - int emblem_len, emblem_id; - char emblem_data[2048]; - struct guild_alliance alliance[MAX_GUILDALLIANCE]; - struct guild_explusion explusion[MAX_GUILDEXPLUSION]; - struct guild_skill skill[MAX_GUILDSKILL]; -}; - -struct guild_castle -{ - int castle_id; - char map_name[24]; - char castle_name[24]; - char castle_event[24]; - int guild_id; - int economy; - int defense; - int triggerE; - int triggerD; - int nextTime; - int payTime; - int createTime; - int visibleC; - int visibleG0; - int visibleG1; - int visibleG2; - int visibleG3; - int visibleG4; - int visibleG5; - int visibleG6; - int visibleG7; - int Ghp0; // added Guardian HP [Valaris] - int Ghp1; - int Ghp2; - int Ghp3; - int Ghp4; - int Ghp5; - int Ghp6; - int Ghp7; - int GID0; - int GID1; - int GID2; - int GID3; - int GID4; - int GID5; - int GID6; - int GID7; // end addition [Valaris] -}; -struct square -{ - int val1[5]; - int val2[5]; -}; - -enum -{ - GBI_EXP = 1, // ギルドのEXP - GBI_GUILDLV = 2, // ギルドのLv - GBI_SKILLPOINT = 3, // ギルドのスキルポイント - GBI_SKILLLV = 4, // ギルドスキルLv - - GMI_POSITION = 0, // メンバーの役職変更 - GMI_EXP = 1, // メンバーのEXP - -}; - -#endif // MMO_H diff --git a/src/common/mmo.hpp b/src/common/mmo.hpp new file mode 100644 index 0000000..2ca93b0 --- /dev/null +++ b/src/common/mmo.hpp @@ -0,0 +1,283 @@ +/// Global structures and defines +#ifndef MMO_HPP +#define MMO_HPP + +# include +# include "utils.hpp" // LCCWIN32 + +# define FIFOSIZE_SERVERLINK 256*1024 + +// set to 0 to not check IP of player between each server. +// set to another value if you want to check (1) +# define CMP_AUTHFIFO_IP 1 + +# define CMP_AUTHFIFO_LOGIN2 1 + +# define MAX_MAP_PER_SERVER 512 +# define MAX_INVENTORY 100 +# define MAX_AMOUNT 30000 +# define MAX_ZENY 1000000000 // 1G zeny +# define MAX_CART 100 +# define MAX_SKILL 450 +# define GLOBAL_REG_NUM 96 +# define ACCOUNT_REG_NUM 16 +# define ACCOUNT_REG2_NUM 16 +# define DEFAULT_WALK_SPEED 150 +# define MIN_WALK_SPEED 0 +# define MAX_WALK_SPEED 1000 +# define MAX_STORAGE 300 +# define MAX_GUILD_STORAGE 1000 +# define MAX_PARTY 12 +# define MAX_GUILD 120 // increased max guild members to accomodate for +2 increase for extension levels [Valaris] (removed) [PoW] +# define MAX_GUILDPOSITION 20 // increased max guild positions to accomodate for all members [Valaris] (removed) [PoW] +# define MAX_GUILDEXPLUSION 32 +# define MAX_GUILDALLIANCE 16 +# define MAX_GUILDSKILL 8 +# define MAX_GUILDCASTLE 24 // increased to include novice castles [Valaris] +# define MAX_GUILDLEVEL 50 + +# define MIN_HAIR_STYLE battle_config.min_hair_style +# define MAX_HAIR_STYLE battle_config.max_hair_style +# define MIN_HAIR_COLOR battle_config.min_hair_color +# define MAX_HAIR_COLOR battle_config.max_hair_color +# define MIN_CLOTH_COLOR battle_config.min_cloth_color +# define MAX_CLOTH_COLOR battle_config.max_cloth_color + +// for produce +# define MIN_ATTRIBUTE 0 +# define MAX_ATTRIBUTE 4 +# define ATTRIBUTE_NORMAL 0 +# define MIN_STAR 0 +# define MAX_STAR 3 + +# define MIN_PORTAL_MEMO 0 +# define MAX_PORTAL_MEMO 2 + +# define MAX_STATUS_TYPE 5 + +# define CHAR_CONF_NAME "conf/char_athena.conf" + +struct item +{ + int id; + short nameid; + short amount; + unsigned short equip; + char identify; + char refine; + char attribute; + short card[4]; + short broken; +}; + +struct point +{ + char map[24]; + short x, y; +}; + +struct skill +{ + unsigned short id, lv, flags; +}; + +struct global_reg +{ + char str[32]; + int value; +}; + +struct mmo_charstatus +{ + int char_id; + int account_id; + int partner_id; + + int base_exp, job_exp, zeny; + + short pc_class; + short status_point, skill_point; + int hp, max_hp, sp, max_sp; + short option, karma, manner; + short hair, hair_color, clothes_color; + int party_id, guild_id; + + short weapon, shield; + short head_top, head_mid, head_bottom; + + char name[24]; + unsigned char base_level, job_level; + short str, agi, vit, int_, dex, luk; + unsigned char char_num, sex; + + unsigned long mapip; + unsigned int mapport; + + struct point last_point, save_point, memo_point[10]; + struct item inventory[MAX_INVENTORY], cart[MAX_CART]; + struct skill skill[MAX_SKILL]; + int global_reg_num; + struct global_reg global_reg[GLOBAL_REG_NUM]; + int account_reg_num; + struct global_reg account_reg[ACCOUNT_REG_NUM]; + int account_reg2_num; + struct global_reg account_reg2[ACCOUNT_REG2_NUM]; +}; + +struct storage +{ + int dirty; + int account_id; + short storage_status; + short storage_amount; + struct item storage_[MAX_STORAGE]; +}; + +struct guild_storage +{ + int dirty; + int guild_id; + short storage_status; + short storage_amount; + struct item storage_[MAX_GUILD_STORAGE]; +}; + +struct map_session_data; + +struct gm_account +{ + int account_id; + int level; +}; + +struct party_member +{ + int account_id; + char name[24], map[24]; + int leader, online, lv; + struct map_session_data *sd; +}; + +struct party +{ + int party_id; + char name[24]; + int exp; + int item; + struct party_member member[MAX_PARTY]; +}; + +struct guild_member +{ + int account_id, char_id; + short hair, hair_color, gender, pc_class, lv; + int exp, exp_payper; + short online, position; + int rsv1, rsv2; + char name[24]; + struct map_session_data *sd; +}; + +struct guild_position +{ + char name[24]; + int mode; + int exp_mode; +}; + +struct guild_alliance +{ + int opposition; + int guild_id; + char name[24]; +}; + +struct guild_explusion +{ + char name[24]; + char mes[40]; + char acc[40]; + int account_id; + int rsv1, rsv2, rsv3; +}; + +struct guild_skill +{ + int id, lv; +}; + +struct guild +{ + int guild_id; + short guild_lv, connect_member, max_member, average_lv; + int exp, next_exp, skill_point, castle_id; + char name[24], master[24]; + struct guild_member member[MAX_GUILD]; + struct guild_position position[MAX_GUILDPOSITION]; + char mes1[60], mes2[120]; + int emblem_len, emblem_id; + char emblem_data[2048]; + struct guild_alliance alliance[MAX_GUILDALLIANCE]; + struct guild_explusion explusion[MAX_GUILDEXPLUSION]; + struct guild_skill skill[MAX_GUILDSKILL]; +}; + +struct guild_castle +{ + int castle_id; + char map_name[24]; + char castle_name[24]; + char castle_event[24]; + int guild_id; + int economy; + int defense; + int triggerE; + int triggerD; + int nextTime; + int payTime; + int createTime; + int visibleC; + int visibleG0; + int visibleG1; + int visibleG2; + int visibleG3; + int visibleG4; + int visibleG5; + int visibleG6; + int visibleG7; + int Ghp0; // added Guardian HP [Valaris] + int Ghp1; + int Ghp2; + int Ghp3; + int Ghp4; + int Ghp5; + int Ghp6; + int Ghp7; + int GID0; + int GID1; + int GID2; + int GID3; + int GID4; + int GID5; + int GID6; + int GID7; // end addition [Valaris] +}; +struct square +{ + int val1[5]; + int val2[5]; +}; + +enum +{ + GBI_EXP = 1, // ギルドのEXP + GBI_GUILDLV = 2, // ギルドのLv + GBI_SKILLPOINT = 3, // ギルドのスキルポイント + GBI_SKILLLV = 4, // ギルドスキルLv + + GMI_POSITION = 0, // メンバーの役職変更 + GMI_EXP = 1, // メンバーのEXP + +}; + +#endif // MMO_HPP diff --git a/src/common/mt_rand.c b/src/common/mt_rand.c deleted file mode 100644 index e4e8d12..0000000 --- a/src/common/mt_rand.c +++ /dev/null @@ -1,116 +0,0 @@ -/* -// This is the ``Mersenne Twister'' random number generator MT19937, which -// generates pseudorandom integers uniformly distributed in 0..(2^32 - 1) -// starting from any odd seed in 0..(2^32 - 1). This version is a recode -// by Shawn Cokus (Cokus@math.washington.edu) on March 8, 1998 of a version by -// Takuji Nishimura (who had suggestions from Topher Cooper and Marc Rieffel in -// July-August 1997). -// -// Effectiveness of the recoding (on Goedel2.math.washington.edu, a DEC Alpha -// running OSF/1) using GCC -O3 as a compiler: before recoding: 51.6 sec. to -// generate 300 million random numbers; after recoding: 24.0 sec. for the same -// (i.e., 46.5% of original time), so speed is now about 12.5 million random -// number generations per second on this machine. -// -// According to the URL -// (and paraphrasing a bit in places), the Mersenne Twister is ``designed -// with consideration of the flaws of various existing generators,'' has -// a period of 2^19937 - 1, gives a sequence that is 623-dimensionally -// equidistributed, and ``has passed many stringent tests, including the -// die-hard test of G. Marsaglia and the load test of P. Hellekalek and -// S. Wegenkittl.'' It is efficient in memory usage (typically using 2506 -// to 5012 bytes of static data, depending on data type sizes, and the code -// is quite short as well). It generates random numbers in batches of 624 -// at a time, so the caching and pipelining of modern systems is exploited. -// It is also divide- and mod-free. -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Library General Public License as published by -// the Free Software Foundation (either version 2 of the License or, at your -// option, any later version). This library 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 Library General Public License for more details. You should have -// received a copy of the GNU Library General Public License along with this -// library; if not, write to the Free Software Foundation, Inc., 59 Temple -// Place, Suite 330, Boston, MA 02111-1307, USA. -// -// The code as Shawn received it included the following notice: -// -// Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. When -// you use this, send an e-mail to with -// an appropriate reference to your work. -// -// It would be nice to CC: when you write. -// -*/ - -#include -#include "mt_rand.h" - -#define N 624 // length of state vector -#define M 397 // a period parameter -#define K 0x9908B0DFU // a magic constant - -#define hiBit(u) ((u) & 0x80000000U) // mask all but highest bit of u -#define loBit(u) ((u) & 0x00000001U) // mask all but lowest bit of u -#define loBits(u) ((u) & 0x7FFFFFFFU) // mask the highest bit of u -#define mixBits(u, v) (hiBit(u)|loBits(v)) // move hi bit of u to hi bit of v - -static uint32_t state[N+1]; // state vector the +1 is needed due to the coding -static uint32_t *next; // next random value is computed from here -static int left = -1; // can *next++ this many times before reloading - -void mt_seed (uint32_t seed) -{ - uint32_t x = seed | 1U; - uint32_t *s = state; - left = 0; - - for (int j = N; *s++ = x, --j; x *= 69069U); -} - -void mt_reload (void) -{ - // if mt_seed has never been called - if (left < -1) - mt_seed (time (NULL)); - - // conceptually, these are indices into the state that wrap - uint32_t *p0 = state; - uint32_t *p2 = state + 2; - uint32_t *pM = state + M; - - uint32_t s0 = state[0]; - uint32_t s1 = state[1]; - - // regenerate the lower N-M elements of the state - for (int j = N-M+1; --j != 0; s0 = s1, s1 = *p2++) - *p0++ = *pM++ ^ (mixBits (s0, s1) >> 1) ^ (loBit (s1) ? K : 0U); - - pM = state; - // regenerate the next M-1 elements of the state - // note that s1 is set to state[N] at the end, but discarded - for (int j = M; --j != 0; s0 = s1, s1 = *p2++) - *p0++ = *pM++ ^ (mixBits (s0, s1) >> 1) ^ (loBit (s1) ? K : 0U); - - // regenerate the last 1 element of the state - s1 = state[0]; - *p0 = *pM ^ (mixBits (s0, s1) >> 1) ^ (loBit (s1) ? K : 0U); - - // ready for the normal mt_random algorithm - left = N; - next = state; -} - -uint32_t mt_random (void) -{ - if (--left < 0) - mt_reload (); - - uint32_t y = *next++; - y ^= (y >> 11); - y ^= (y << 7) & 0x9D2C5680U; - y ^= (y << 15) & 0xEFC60000U; - return y ^ (y >> 18); -} diff --git a/src/common/mt_rand.cpp b/src/common/mt_rand.cpp new file mode 100644 index 0000000..89872ad --- /dev/null +++ b/src/common/mt_rand.cpp @@ -0,0 +1,116 @@ +/* +// This is the ``Mersenne Twister'' random number generator MT19937, which +// generates pseudorandom integers uniformly distributed in 0..(2^32 - 1) +// starting from any odd seed in 0..(2^32 - 1). This version is a recode +// by Shawn Cokus (Cokus@math.washington.edu) on March 8, 1998 of a version by +// Takuji Nishimura (who had suggestions from Topher Cooper and Marc Rieffel in +// July-August 1997). +// +// Effectiveness of the recoding (on Goedel2.math.washington.edu, a DEC Alpha +// running OSF/1) using GCC -O3 as a compiler: before recoding: 51.6 sec. to +// generate 300 million random numbers; after recoding: 24.0 sec. for the same +// (i.e., 46.5% of original time), so speed is now about 12.5 million random +// number generations per second on this machine. +// +// According to the URL +// (and paraphrasing a bit in places), the Mersenne Twister is ``designed +// with consideration of the flaws of various existing generators,'' has +// a period of 2^19937 - 1, gives a sequence that is 623-dimensionally +// equidistributed, and ``has passed many stringent tests, including the +// die-hard test of G. Marsaglia and the load test of P. Hellekalek and +// S. Wegenkittl.'' It is efficient in memory usage (typically using 2506 +// to 5012 bytes of static data, depending on data type sizes, and the code +// is quite short as well). It generates random numbers in batches of 624 +// at a time, so the caching and pipelining of modern systems is exploited. +// It is also divide- and mod-free. +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published by +// the Free Software Foundation (either version 2 of the License or, at your +// option, any later version). This library 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 Library General Public License for more details. You should have +// received a copy of the GNU Library General Public License along with this +// library; if not, write to the Free Software Foundation, Inc., 59 Temple +// Place, Suite 330, Boston, MA 02111-1307, USA. +// +// The code as Shawn received it included the following notice: +// +// Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. When +// you use this, send an e-mail to with +// an appropriate reference to your work. +// +// It would be nice to CC: when you write. +// +*/ + +#include +#include "mt_rand.hpp" + +#define N 624 // length of state vector +#define M 397 // a period parameter +#define K 0x9908B0DFU // a magic constant + +#define hiBit(u) ((u) & 0x80000000U) // mask all but highest bit of u +#define loBit(u) ((u) & 0x00000001U) // mask all but lowest bit of u +#define loBits(u) ((u) & 0x7FFFFFFFU) // mask the highest bit of u +#define mixBits(u, v) (hiBit(u)|loBits(v)) // move hi bit of u to hi bit of v + +static uint32_t state[N+1]; // state vector the +1 is needed due to the coding +static uint32_t *next; // next random value is computed from here +static int left = -1; // can *next++ this many times before reloading + +void mt_seed (uint32_t seed) +{ + uint32_t x = seed | 1U; + uint32_t *s = state; + left = 0; + + for (int j = N; *s++ = x, --j; x *= 69069U); +} + +void mt_reload (void) +{ + // if mt_seed has never been called + if (left < -1) + mt_seed (time (NULL)); + + // conceptually, these are indices into the state that wrap + uint32_t *p0 = state; + uint32_t *p2 = state + 2; + uint32_t *pM = state + M; + + uint32_t s0 = state[0]; + uint32_t s1 = state[1]; + + // regenerate the lower N-M elements of the state + for (int j = N-M+1; --j != 0; s0 = s1, s1 = *p2++) + *p0++ = *pM++ ^ (mixBits (s0, s1) >> 1) ^ (loBit (s1) ? K : 0U); + + pM = state; + // regenerate the next M-1 elements of the state + // note that s1 is set to state[N] at the end, but discarded + for (int j = M; --j != 0; s0 = s1, s1 = *p2++) + *p0++ = *pM++ ^ (mixBits (s0, s1) >> 1) ^ (loBit (s1) ? K : 0U); + + // regenerate the last 1 element of the state + s1 = state[0]; + *p0 = *pM ^ (mixBits (s0, s1) >> 1) ^ (loBit (s1) ? K : 0U); + + // ready for the normal mt_random algorithm + left = N; + next = state; +} + +uint32_t mt_random (void) +{ + if (--left < 0) + mt_reload (); + + uint32_t y = *next++; + y ^= (y >> 11); + y ^= (y << 7) & 0x9D2C5680U; + y ^= (y << 15) & 0xEFC60000U; + return y ^ (y >> 18); +} diff --git a/src/common/mt_rand.h b/src/common/mt_rand.h deleted file mode 100644 index 84d32e5..0000000 --- a/src/common/mt_rand.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef MT_RAND_H -#define MT_RAND_H - -# include "sanity.h" - -/// Initialize the generator (called automatically with time() if you don't) -void mt_seed (uint32_t seed); -/// Get a random number -uint32_t mt_random (void); - -/** - * ModuloRand and ModuloPlusRand - * These macros are used to replace the vast number of calls to rand()%mod - * TODO eliminate the rest of the calls to rand() - * MRAND(10) returns 0..9 - * MPRAND(5,10) returns 5..14 - */ -// The cast is essential because the result is sometimes -// compared with a possibly negative number. -// Because it's using modulus, high numbers shouldn't happen anyway. -# define MRAND(mod) ((int)(mt_random() % (mod))) -# define MPRAND(add, mod) ((add) + MRAND(mod)) - -#endif // MT_RAND_H diff --git a/src/common/mt_rand.hpp b/src/common/mt_rand.hpp new file mode 100644 index 0000000..c7bae4e --- /dev/null +++ b/src/common/mt_rand.hpp @@ -0,0 +1,24 @@ +#ifndef MT_RAND_HPP +#define MT_RAND_HPP + +# include "sanity.hpp" + +/// Initialize the generator (called automatically with time() if you don't) +void mt_seed (uint32_t seed); +/// Get a random number +uint32_t mt_random (void); + +/** + * ModuloRand and ModuloPlusRand + * These macros are used to replace the vast number of calls to rand()%mod + * TODO eliminate the rest of the calls to rand() + * MRAND(10) returns 0..9 + * MPRAND(5,10) returns 5..14 + */ +// The cast is essential because the result is sometimes +// compared with a possibly negative number. +// Because it's using modulus, high numbers shouldn't happen anyway. +# define MRAND(mod) ((int)(mt_random() % (mod))) +# define MPRAND(add, mod) ((add) + MRAND(mod)) + +#endif // MT_RAND_HPP diff --git a/src/common/nullpo.c b/src/common/nullpo.c deleted file mode 100644 index 8c7c405..0000000 --- a/src/common/nullpo.c +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include -#include -#include "nullpo.h" - -static void nullpo_info_core (const char *file, int line, const char *func, - const char *fmt, va_list ap); - -/// Null check and print format -bool nullpo_chk_f (const char *file, int line, const char *func, - const void *target, const char *fmt, ...) -{ - va_list ap; - - if (target) - return 0; - - va_start (ap, fmt); - nullpo_info_core (file, line, func, fmt, ap); - va_end (ap); - return 1; -} -bool nullpo_chk (const char *file, int line, const char *func, - const void *target) -{ - if (target) - return 0; - - nullpo_info_core (file, line, func, NULL, NULL); - return 1; -} - -/// External functions -void nullpo_info_f (const char *file, int line, const char *func, - const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - nullpo_info_core (file, line, func, fmt, ap); - va_end (ap); -} -void nullpo_info (const char *file, int line, const char *func) -{ - nullpo_info_core (file, line, func, NULL, NULL); -} - -/// Actual output function -static void nullpo_info_core (const char *file, int line, const char *func, - const char *fmt, va_list ap) __attribute__((format(printf, 4, 0))); -static void nullpo_info_core (const char *file, int line, const char *func, - const char *fmt, va_list ap) -{ - if (!file) - file = "??"; - if (!func || !*func) - func = "unknown"; - - fprintf (stderr, "%s:%d: in func `%s': NULL pointer\n", file, line, func); - if (fmt && *fmt) - { - vfprintf (stderr, fmt, ap); - if (fmt[strlen (fmt) - 1] != '\n') - fputc('\n', stderr); - } -} diff --git a/src/common/nullpo.cpp b/src/common/nullpo.cpp new file mode 100644 index 0000000..6dd2736 --- /dev/null +++ b/src/common/nullpo.cpp @@ -0,0 +1,66 @@ +#include +#include +#include +#include "nullpo.hpp" + +static void nullpo_info_core (const char *file, int line, const char *func, + const char *fmt, va_list ap); + +/// Null check and print format +bool nullpo_chk_f (const char *file, int line, const char *func, + const void *target, const char *fmt, ...) +{ + va_list ap; + + if (target) + return 0; + + va_start (ap, fmt); + nullpo_info_core (file, line, func, fmt, ap); + va_end (ap); + return 1; +} +bool nullpo_chk (const char *file, int line, const char *func, + const void *target) +{ + if (target) + return 0; + + nullpo_info_core (file, line, func, NULL, NULL); + return 1; +} + +/// External functions +void nullpo_info_f (const char *file, int line, const char *func, + const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + nullpo_info_core (file, line, func, fmt, ap); + va_end (ap); +} +void nullpo_info (const char *file, int line, const char *func) +{ + nullpo_info_core (file, line, func, NULL, NULL); +} + +/// Actual output function +static void nullpo_info_core (const char *file, int line, const char *func, + const char *fmt, va_list ap) __attribute__((format(printf, 4, 0))); +static void nullpo_info_core (const char *file, int line, const char *func, + const char *fmt, va_list ap) +{ + if (!file) + file = "??"; + if (!func || !*func) + func = "unknown"; + + fprintf (stderr, "%s:%d: in func `%s': NULL pointer\n", file, line, func); + if (fmt && *fmt) + { + vfprintf (stderr, fmt, ap); + if (fmt[strlen (fmt) - 1] != '\n') + fputc('\n', stderr); + } +} diff --git a/src/common/nullpo.h b/src/common/nullpo.h deleted file mode 100644 index 9b33b4b..0000000 --- a/src/common/nullpo.h +++ /dev/null @@ -1,61 +0,0 @@ -/// return wrappers for unexpected NULL pointers -#ifndef NULLPO_H -#define NULLPO_H -/// Comment this out to live dangerously -# define NULLPO_CHECK - -/// All functions print to standard error (was: standard output) -/// nullpo_ret(cond) - return 0 if given pointer is NULL -/// nullpo_retv(cond) - just return (function returns void) -/// nullpo_retr(rv, cond) - return given value instead -/// the _f variants take a printf-format string and arguments - -# ifdef NULLPO_CHECK -# define NLP_MARK __FILE__, __LINE__, __func__ -# define nullpo_ret(t) \ - if (nullpo_chk(NLP_MARK, t)) \ - return 0; -# define nullpo_retv(t) \ - if (nullpo_chk(NLP_MARK, t)) \ - return; -# define nullpo_retr(ret, t) \ - if (nullpo_chk(NLP_MARK, t)) \ - return ret; -# define nullpo_ret_f(t, fmt, ...) \ - if (nullpo_chk_f(NLP_MARK, t, fmt, ##__VA_ARGS__)) \ - return 0; -# define nullpo_retv_f(t, fmt, ...) \ - if (nullpo_chk_f(NLP_MARK, t, fmt, ##__VA_ARGS__)) \ - return; -# define nullpo_retr_f(ret, t, fmt, ...) \ - if (nullpo_chk_f(NLP_MARK, t, fmt, ##__VA_ARGS__)) \ - return ret; -# else // NULLPO_CHECK -# define nullpo_ret(t) t; -# define nullpo_retv(t) t; -# define nullpo_retr(ret, t) t; -# define nullpo_ret_f(t, fmt, ...) t; -# define nullpo_retv_f(t, fmt, ...) t; -# define nullpo_retr_f(ret, t, fmt, ...) t; -# endif // NULLPO_CHECK - -# include "sanity.h" - -/// Used by macros in this header -bool nullpo_chk (const char *file, int line, const char *func, - const void *target); - -/// Used by macros in this header -bool nullpo_chk_f (const char *file, int line, const char *func, - const void *target, const char *fmt, ...) - __attribute__ ((format (printf, 5, 6))); - -/// Used only by map/battle.c -void nullpo_info (const char *file, int line, const char *func); - -/// Not used -void nullpo_info_f (const char *file, int line, const char *func, - const char *fmt, ...) - __attribute__ ((format (printf, 4, 5))); - -#endif // NULLPO_H diff --git a/src/common/nullpo.hpp b/src/common/nullpo.hpp new file mode 100644 index 0000000..7aff691 --- /dev/null +++ b/src/common/nullpo.hpp @@ -0,0 +1,61 @@ +/// return wrappers for unexpected NULL pointers +#ifndef NULLPO_HPP +#define NULLPO_HPP +/// Comment this out to live dangerously +# define NULLPO_CHECK + +/// All functions print to standard error (was: standard output) +/// nullpo_ret(cond) - return 0 if given pointer is NULL +/// nullpo_retv(cond) - just return (function returns void) +/// nullpo_retr(rv, cond) - return given value instead +/// the _f variants take a printf-format string and arguments + +# ifdef NULLPO_CHECK +# define NLP_MARK __FILE__, __LINE__, __func__ +# define nullpo_ret(t) \ + if (nullpo_chk(NLP_MARK, t)) \ + return 0; +# define nullpo_retv(t) \ + if (nullpo_chk(NLP_MARK, t)) \ + return; +# define nullpo_retr(ret, t) \ + if (nullpo_chk(NLP_MARK, t)) \ + return ret; +# define nullpo_ret_f(t, fmt, ...) \ + if (nullpo_chk_f(NLP_MARK, t, fmt, ##__VA_ARGS__)) \ + return 0; +# define nullpo_retv_f(t, fmt, ...) \ + if (nullpo_chk_f(NLP_MARK, t, fmt, ##__VA_ARGS__)) \ + return; +# define nullpo_retr_f(ret, t, fmt, ...) \ + if (nullpo_chk_f(NLP_MARK, t, fmt, ##__VA_ARGS__)) \ + return ret; +# else // NULLPO_CHECK +# define nullpo_ret(t) t; +# define nullpo_retv(t) t; +# define nullpo_retr(ret, t) t; +# define nullpo_ret_f(t, fmt, ...) t; +# define nullpo_retv_f(t, fmt, ...) t; +# define nullpo_retr_f(ret, t, fmt, ...) t; +# endif // NULLPO_CHECK + +# include "sanity.hpp" + +/// Used by macros in this header +bool nullpo_chk (const char *file, int line, const char *func, + const void *target); + +/// Used by macros in this header +bool nullpo_chk_f (const char *file, int line, const char *func, + const void *target, const char *fmt, ...) + __attribute__ ((format (printf, 5, 6))); + +/// Used only by map/battle.c +void nullpo_info (const char *file, int line, const char *func); + +/// Not used +void nullpo_info_f (const char *file, int line, const char *func, + const char *fmt, ...) + __attribute__ ((format (printf, 4, 5))); + +#endif // NULLPO_HPP diff --git a/src/common/sanity.h b/src/common/sanity.h deleted file mode 100644 index 168671f..0000000 --- a/src/common/sanity.h +++ /dev/null @@ -1,36 +0,0 @@ -/// return wrappers for unexpected NULL pointers -#ifndef SANITY_H -#define SANITY_H -# if __STDC_VERSION__ < 199901L -# error "Please compile in C99 mode" -# endif -# if __GNUC__ < 3 -// I don't specifically know what version this requires, -// but GCC 3 was the beginning of modern GCC -# error "Please upgrade your compiler to at least GCC 3" -# endif -# ifndef __i386__ -// Known platform dependencies: -// endianness for the [RW]FIFO.* macros -// possibly, some signal-handling -# error "Unsupported platform" -# endif -# ifdef __x86_64__ -// I'm working on it - I know there are some pointer-size assumptions. -# error "Sorry, this code is believed not to be 64-bit safe" -# error "please compile with -m32" -# endif - -/// A name for unused function arguments - can be repeated -# define UNUSED UNUSED_IMPL(__COUNTER__) -// Don't you just love the hoops the preprocessor makes you go through? -# define UNUSED_IMPL(arg) UNUSED_IMPL2(arg) -# define UNUSED_IMPL2(suffix) unused_ ## suffix __attribute__((unused)) -/// Convert conditions to use the bool type -# include -/// Convert type assumptions to use the standard types here -# include -/// size_t, NULL -# include - -#endif // SANITY_H diff --git a/src/common/sanity.hpp b/src/common/sanity.hpp new file mode 100644 index 0000000..7ffd077 --- /dev/null +++ b/src/common/sanity.hpp @@ -0,0 +1,31 @@ +/// return wrappers for unexpected NULL pointers +#ifndef SANITY_HPP +#define SANITY_HPP +# ifndef __cplusplus +# error "Please compile in C++ mode" +# endif +# if __GNUC__ < 3 +// I don't specifically know what version this requires, +// but GCC 3 was the beginning of modern GCC +# error "Please upgrade your compiler to at least GCC 3" +# endif +# ifndef __i386__ +// Known platform dependencies: +// endianness for the [RW]FIFO.* macros +// possibly, some signal-handling +# error "Unsupported platform" +# endif +# ifdef __x86_64__ +// I'm working on it - I know there are some pointer-size assumptions. +# error "Sorry, this code is believed not to be 64-bit safe" +# error "please compile with -m32" +# endif + +/// A name for unused function arguments - can be repeated +# define UNUSED /* empty works for C++ */ +/// Convert type assumptions to use the standard types here +# include +/// size_t, NULL +# include + +#endif // SANITY_HPP diff --git a/src/common/socket.c b/src/common/socket.c deleted file mode 100644 index 67a5102..0000000 --- a/src/common/socket.c +++ /dev/null @@ -1,405 +0,0 @@ -// $Id: socket.c,v 1.1.1.1 2004/09/10 17:44:49 MagicalTux Exp $ -// original : core.c 2003/02/26 18:03:12 Rev 1.7 - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "mmo.h" // [Valaris] thanks to fov -#include "socket.h" -#include "utils.h" - -fd_set readfds; -int fd_max; -int currentuse; - -const uint32_t RFIFO_SIZE = 65536; -const uint32_t WFIFO_SIZE = 65536; - -struct socket_data *session[FD_SETSIZE]; - -/// Discard all input -static void null_parse (int fd); -/// Default parser for new connections -static void (*default_func_parse) (int) = null_parse; - -void set_defaultparse (void (*defaultparse) (int)) -{ - default_func_parse = defaultparse; -} - -/// Read from socket to the queue -static void recv_to_fifo (int fd) -{ - if (session[fd]->eof) - return; - - ssize_t len = read (fd, session[fd]->rdata + session[fd]->rdata_size, - RFIFOSPACE (fd)); - - if (len > 0) - { - session[fd]->rdata_size += len; - session[fd]->connected = 1; - } - else - { - session[fd]->eof = 1; - } -} - -static void send_from_fifo (int fd) -{ - if (session[fd]->eof) - return; - - ssize_t len = write (fd, session[fd]->wdata, session[fd]->wdata_size); - - if (len > 0) - { - session[fd]->wdata_size -= len; - if (len < (ssize_t)session[fd]->wdata_size) - { - memmove (session[fd]->wdata, session[fd]->wdata + len, - session[fd]->wdata_size); - } - session[fd]->connected = 1; - } - else - { - session[fd]->eof = 1; - } -} - -static void null_parse (int fd) -{ - printf ("null_parse : %d\n", fd); - RFIFOSKIP (fd, RFIFOREST (fd)); -} - - -static void connect_client (int listen_fd) -{ - struct sockaddr_in client_address; - socklen_t len = sizeof (client_address); - - int fd = accept (listen_fd, (struct sockaddr *) &client_address, &len); - if (fd == -1) - { - perror ("accept"); - return; - } - if (fd_max <= fd) - { - fd_max = fd + 1; - } - if (!free_fds ()) - { - fprintf (stderr, "softlimit reached, disconnecting : %d\n", fd); - delete_session (fd); - return; - } - - const int yes = 1; - /// Allow to bind() again after the server restarts. - // Since the socket is still in the TIME_WAIT, there's a possibility - // that formerly lost packets might be delivered and confuse the server. - setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); - /// Send packets as soon as possible - /// even if the kernel thinks there is too little for it to be worth it! - // I'm not convinced this is a good idea; although in minimizes the - // latency for an individual write, it increases traffic in general. - setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); - - FD_SET (fd, &readfds); - - fcntl (fd, F_SETFL, O_NONBLOCK); - - CREATE (session[fd], struct socket_data, 1); - CREATE (session[fd]->rdata, uint8_t, RFIFO_SIZE); - CREATE (session[fd]->wdata, uint8_t, WFIFO_SIZE); - - session[fd]->max_rdata = RFIFO_SIZE; - session[fd]->max_wdata = WFIFO_SIZE; - session[fd]->func_recv = recv_to_fifo; - session[fd]->func_send = send_from_fifo; - session[fd]->func_parse = default_func_parse; - session[fd]->client_addr = client_address; - session[fd]->created = time (NULL); - session[fd]->connected = 0; - - currentuse++; -} - -int make_listen_port (uint16_t port) -{ - struct sockaddr_in server_address; - int fd = socket (AF_INET, SOCK_STREAM, 0); - if (fd == -1) - { - perror ("socket"); - return -1; - } - if (fd_max <= fd) - fd_max = fd + 1; - - fcntl (fd, F_SETFL, O_NONBLOCK); - - const int yes = 1; - /// Allow to bind() again after the server restarts. - // Since the socket is still in the TIME_WAIT, there's a possibility - // that formerly lost packets might be delivered and confuse the server. - setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); - /// Send packets as soon as possible - /// even if the kernel thinks there is too little for it to be worth it! - // I'm not convinced this is a good idea; although in minimizes the - // latency for an individual write, it increases traffic in general. - setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); - - server_address.sin_family = AF_INET; - server_address.sin_addr.s_addr = htonl (INADDR_ANY); - server_address.sin_port = htons (port); - - if (bind (fd, (struct sockaddr *) &server_address, - sizeof (server_address)) == -1) - { - perror ("bind"); - exit (1); - } - if (listen (fd, 5) == -1) - { /* error */ - perror ("listen"); - exit (1); - } - - FD_SET (fd, &readfds); - - CREATE (session[fd], struct socket_data, 1); - - session[fd]->func_recv = connect_client; - session[fd]->created = time (NULL); - session[fd]->connected = 1; - - currentuse++; - return fd; -} - -int make_connection (uint32_t ip, uint16_t port) -{ - struct sockaddr_in server_address; - int fd = socket (AF_INET, SOCK_STREAM, 0); - if (fd == -1) - { - perror ("socket"); - return -1; - } - if (fd_max <= fd) - fd_max = fd + 1; - - const int yes = 1; - /// Allow to bind() again after the server restarts. - // Since the socket is still in the TIME_WAIT, there's a possibility - // that formerly lost packets might be delivered and confuse the server. - setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); - /// Send packets as soon as possible - /// even if the kernel thinks there is too little for it to be worth it! - // I'm not convinced this is a good idea; although in minimizes the - // latency for an individual write, it increases traffic in general. - setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); - - server_address.sin_family = AF_INET; - server_address.sin_addr.s_addr = ip; - server_address.sin_port = htons (port); - - fcntl (fd, F_SETFL, O_NONBLOCK); - - /// Errors not caught - we must not block - /// Let the main select() loop detect when we know the state - connect (fd, (struct sockaddr *) &server_address, - sizeof (struct sockaddr_in)); - - FD_SET (fd, &readfds); - - CREATE (session[fd], struct socket_data, 1); - CREATE (session[fd]->rdata, uint8_t, RFIFO_SIZE); - CREATE (session[fd]->wdata, uint8_t, WFIFO_SIZE); - - session[fd]->max_rdata = RFIFO_SIZE; - session[fd]->max_wdata = WFIFO_SIZE; - session[fd]->func_recv = recv_to_fifo; - session[fd]->func_send = send_from_fifo; - session[fd]->func_parse = default_func_parse; - session[fd]->created = time (NULL); - session[fd]->connected = 1; - - currentuse++; - return fd; -} - -void delete_session (int fd) -{ - if (fd < 0 || fd >= FD_SETSIZE) - return; - // If this was the highest fd, decrease it - // We could add a loop to decrement fd_max further for every null session, - // but this is cheap and good enough for the typical case - if (fd == fd_max - 1) - fd_max--; - FD_CLR (fd, &readfds); - if (session[fd]) - { - free (session[fd]->rdata); - free (session[fd]->wdata); - free (session[fd]->session_data); - free (session[fd]); - } - session[fd] = NULL; - - // just close() would try to keep sending buffers - shutdown (fd, SHUT_RDWR); - close (fd); - currentuse--; - if (currentuse < 0) - { - fprintf (stderr, "delete_session: current sessions negative!\n"); - currentuse = 0; - } - return; -} - -void realloc_fifo (int fd, size_t rfifo_size, size_t wfifo_size) -{ - struct socket_data *s = session[fd]; - if (s->max_rdata != rfifo_size && s->rdata_size < rfifo_size) - { - RECREATE (s->rdata, uint8_t, rfifo_size); - s->max_rdata = rfifo_size; - } - if (s->max_wdata != wfifo_size && s->wdata_size < wfifo_size) - { - RECREATE (s->wdata, uint8_t, wfifo_size); - s->max_wdata = wfifo_size; - } -} - -void WFIFOSET (int fd, size_t len) -{ - struct socket_data *s = session[fd]; - if (s->wdata_size + len + 16384 > s->max_wdata) - { - realloc_fifo (fd, s->max_rdata, s->max_wdata << 1); - printf ("socket: %d wdata expanded to %d bytes.\n", fd, s->max_wdata); - } - if (s->wdata_size + len + 2048 < s->max_wdata) - s->wdata_size += len; - else - fprintf (stderr, "socket: %d wdata lost !!\n", fd), abort (); -} - -void do_sendrecv (uint32_t next) -{ - fd_set rfd = readfds, wfd; - FD_ZERO (&wfd); - for (int i = 0; i < fd_max; i++) - { - if (session[i] && session[i]->wdata_size) - FD_SET (i, &wfd); - } - struct timeval timeout; - timeout.tv_sec = next / 1000; - timeout.tv_usec = next % 1000 * 1000; - if (select (fd_max, &rfd, &wfd, NULL, &timeout) <= 0) - return; - for (int i = 0; i < fd_max; i++) - { - if (!session[i]) - continue; - if (FD_ISSET (i, &wfd)) - { - if (session[i]->func_send) - //send_from_fifo(i); - session[i]->func_send (i); - } - if (FD_ISSET (i, &rfd)) - { - if (session[i]->func_recv) - //recv_to_fifo(i); - //or connect_client(i); - session[i]->func_recv (i); - } - } -} - -void do_parsepacket (void) -{ - for (int i = 0; i < fd_max; i++) - { - if (!session[i]) - continue; - if (!session[i]->connected - && time (NULL) - session[i]->created > CONNECT_TIMEOUT) - { - printf ("Session #%d timed out\n", i); - session[i]->eof = 1; - } - if (!session[i]->rdata_size && !session[i]->eof) - continue; - if (session[i]->func_parse) - { - session[i]->func_parse (i); - /// some func_parse may call delete_session - if (!session[i]) - continue; - } - /// Reclaim buffer space for what was read - RFIFOFLUSH (i); - } -} - -void do_socket (void) -{ - FD_ZERO (&readfds); - currentuse = 3; -} - -void RFIFOSKIP (int fd, size_t len) -{ - struct socket_data *s = session[fd]; - s->rdata_pos += len; - - if (s->rdata_size < s->rdata_pos) - { - fprintf (stderr, "too many skip\n"); - abort (); - } -} - -void fclose_ (FILE * fp) -{ - if (fclose (fp)) - perror ("fclose"), abort (); - currentuse--; -} - -FILE *fopen_ (const char *path, const char *mode) -{ - FILE *f = fopen (path, mode); - if (f) - currentuse++; - return f; -} - -bool free_fds (void) -{ - return currentuse < SOFT_LIMIT; -} diff --git a/src/common/socket.cpp b/src/common/socket.cpp new file mode 100644 index 0000000..cc6e4b3 --- /dev/null +++ b/src/common/socket.cpp @@ -0,0 +1,405 @@ +// $Id: socket.c,v 1.1.1.1 2004/09/10 17:44:49 MagicalTux Exp $ +// original : core.c 2003/02/26 18:03:12 Rev 1.7 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "mmo.hpp" // [Valaris] thanks to fov +#include "socket.hpp" +#include "utils.hpp" + +fd_set readfds; +int fd_max; +int currentuse; + +const uint32_t RFIFO_SIZE = 65536; +const uint32_t WFIFO_SIZE = 65536; + +struct socket_data *session[FD_SETSIZE]; + +/// Discard all input +static void null_parse (int fd); +/// Default parser for new connections +static void (*default_func_parse) (int) = null_parse; + +void set_defaultparse (void (*defaultparse) (int)) +{ + default_func_parse = defaultparse; +} + +/// Read from socket to the queue +static void recv_to_fifo (int fd) +{ + if (session[fd]->eof) + return; + + ssize_t len = read (fd, session[fd]->rdata + session[fd]->rdata_size, + RFIFOSPACE (fd)); + + if (len > 0) + { + session[fd]->rdata_size += len; + session[fd]->connected = 1; + } + else + { + session[fd]->eof = 1; + } +} + +static void send_from_fifo (int fd) +{ + if (session[fd]->eof) + return; + + ssize_t len = write (fd, session[fd]->wdata, session[fd]->wdata_size); + + if (len > 0) + { + session[fd]->wdata_size -= len; + if (len < (ssize_t)session[fd]->wdata_size) + { + memmove (session[fd]->wdata, session[fd]->wdata + len, + session[fd]->wdata_size); + } + session[fd]->connected = 1; + } + else + { + session[fd]->eof = 1; + } +} + +static void null_parse (int fd) +{ + printf ("null_parse : %d\n", fd); + RFIFOSKIP (fd, RFIFOREST (fd)); +} + + +static void connect_client (int listen_fd) +{ + struct sockaddr_in client_address; + socklen_t len = sizeof (client_address); + + int fd = accept (listen_fd, (struct sockaddr *) &client_address, &len); + if (fd == -1) + { + perror ("accept"); + return; + } + if (fd_max <= fd) + { + fd_max = fd + 1; + } + if (!free_fds ()) + { + fprintf (stderr, "softlimit reached, disconnecting : %d\n", fd); + delete_session (fd); + return; + } + + const int yes = 1; + /// Allow to bind() again after the server restarts. + // Since the socket is still in the TIME_WAIT, there's a possibility + // that formerly lost packets might be delivered and confuse the server. + setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); + /// Send packets as soon as possible + /// even if the kernel thinks there is too little for it to be worth it! + // I'm not convinced this is a good idea; although in minimizes the + // latency for an individual write, it increases traffic in general. + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); + + FD_SET (fd, &readfds); + + fcntl (fd, F_SETFL, O_NONBLOCK); + + CREATE (session[fd], struct socket_data, 1); + CREATE (session[fd]->rdata, uint8_t, RFIFO_SIZE); + CREATE (session[fd]->wdata, uint8_t, WFIFO_SIZE); + + session[fd]->max_rdata = RFIFO_SIZE; + session[fd]->max_wdata = WFIFO_SIZE; + session[fd]->func_recv = recv_to_fifo; + session[fd]->func_send = send_from_fifo; + session[fd]->func_parse = default_func_parse; + session[fd]->client_addr = client_address; + session[fd]->created = time (NULL); + session[fd]->connected = 0; + + currentuse++; +} + +int make_listen_port (uint16_t port) +{ + struct sockaddr_in server_address; + int fd = socket (AF_INET, SOCK_STREAM, 0); + if (fd == -1) + { + perror ("socket"); + return -1; + } + if (fd_max <= fd) + fd_max = fd + 1; + + fcntl (fd, F_SETFL, O_NONBLOCK); + + const int yes = 1; + /// Allow to bind() again after the server restarts. + // Since the socket is still in the TIME_WAIT, there's a possibility + // that formerly lost packets might be delivered and confuse the server. + setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); + /// Send packets as soon as possible + /// even if the kernel thinks there is too little for it to be worth it! + // I'm not convinced this is a good idea; although in minimizes the + // latency for an individual write, it increases traffic in general. + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); + + server_address.sin_family = AF_INET; + server_address.sin_addr.s_addr = htonl (INADDR_ANY); + server_address.sin_port = htons (port); + + if (bind (fd, (struct sockaddr *) &server_address, + sizeof (server_address)) == -1) + { + perror ("bind"); + exit (1); + } + if (listen (fd, 5) == -1) + { /* error */ + perror ("listen"); + exit (1); + } + + FD_SET (fd, &readfds); + + CREATE (session[fd], struct socket_data, 1); + + session[fd]->func_recv = connect_client; + session[fd]->created = time (NULL); + session[fd]->connected = 1; + + currentuse++; + return fd; +} + +int make_connection (uint32_t ip, uint16_t port) +{ + struct sockaddr_in server_address; + int fd = socket (AF_INET, SOCK_STREAM, 0); + if (fd == -1) + { + perror ("socket"); + return -1; + } + if (fd_max <= fd) + fd_max = fd + 1; + + const int yes = 1; + /// Allow to bind() again after the server restarts. + // Since the socket is still in the TIME_WAIT, there's a possibility + // that formerly lost packets might be delivered and confuse the server. + setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); + /// Send packets as soon as possible + /// even if the kernel thinks there is too little for it to be worth it! + // I'm not convinced this is a good idea; although in minimizes the + // latency for an individual write, it increases traffic in general. + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); + + server_address.sin_family = AF_INET; + server_address.sin_addr.s_addr = ip; + server_address.sin_port = htons (port); + + fcntl (fd, F_SETFL, O_NONBLOCK); + + /// Errors not caught - we must not block + /// Let the main select() loop detect when we know the state + connect (fd, (struct sockaddr *) &server_address, + sizeof (struct sockaddr_in)); + + FD_SET (fd, &readfds); + + CREATE (session[fd], struct socket_data, 1); + CREATE (session[fd]->rdata, uint8_t, RFIFO_SIZE); + CREATE (session[fd]->wdata, uint8_t, WFIFO_SIZE); + + session[fd]->max_rdata = RFIFO_SIZE; + session[fd]->max_wdata = WFIFO_SIZE; + session[fd]->func_recv = recv_to_fifo; + session[fd]->func_send = send_from_fifo; + session[fd]->func_parse = default_func_parse; + session[fd]->created = time (NULL); + session[fd]->connected = 1; + + currentuse++; + return fd; +} + +void delete_session (int fd) +{ + if (fd < 0 || fd >= FD_SETSIZE) + return; + // If this was the highest fd, decrease it + // We could add a loop to decrement fd_max further for every null session, + // but this is cheap and good enough for the typical case + if (fd == fd_max - 1) + fd_max--; + FD_CLR (fd, &readfds); + if (session[fd]) + { + free (session[fd]->rdata); + free (session[fd]->wdata); + free (session[fd]->session_data); + free (session[fd]); + } + session[fd] = NULL; + + // just close() would try to keep sending buffers + shutdown (fd, SHUT_RDWR); + close (fd); + currentuse--; + if (currentuse < 0) + { + fprintf (stderr, "delete_session: current sessions negative!\n"); + currentuse = 0; + } + return; +} + +void realloc_fifo (int fd, size_t rfifo_size, size_t wfifo_size) +{ + struct socket_data *s = session[fd]; + if (s->max_rdata != rfifo_size && s->rdata_size < rfifo_size) + { + RECREATE (s->rdata, uint8_t, rfifo_size); + s->max_rdata = rfifo_size; + } + if (s->max_wdata != wfifo_size && s->wdata_size < wfifo_size) + { + RECREATE (s->wdata, uint8_t, wfifo_size); + s->max_wdata = wfifo_size; + } +} + +void WFIFOSET (int fd, size_t len) +{ + struct socket_data *s = session[fd]; + if (s->wdata_size + len + 16384 > s->max_wdata) + { + realloc_fifo (fd, s->max_rdata, s->max_wdata << 1); + printf ("socket: %d wdata expanded to %d bytes.\n", fd, s->max_wdata); + } + if (s->wdata_size + len + 2048 < s->max_wdata) + s->wdata_size += len; + else + fprintf (stderr, "socket: %d wdata lost !!\n", fd), abort (); +} + +void do_sendrecv (uint32_t next) +{ + fd_set rfd = readfds, wfd; + FD_ZERO (&wfd); + for (int i = 0; i < fd_max; i++) + { + if (session[i] && session[i]->wdata_size) + FD_SET (i, &wfd); + } + struct timeval timeout; + timeout.tv_sec = next / 1000; + timeout.tv_usec = next % 1000 * 1000; + if (select (fd_max, &rfd, &wfd, NULL, &timeout) <= 0) + return; + for (int i = 0; i < fd_max; i++) + { + if (!session[i]) + continue; + if (FD_ISSET (i, &wfd)) + { + if (session[i]->func_send) + //send_from_fifo(i); + session[i]->func_send (i); + } + if (FD_ISSET (i, &rfd)) + { + if (session[i]->func_recv) + //recv_to_fifo(i); + //or connect_client(i); + session[i]->func_recv (i); + } + } +} + +void do_parsepacket (void) +{ + for (int i = 0; i < fd_max; i++) + { + if (!session[i]) + continue; + if (!session[i]->connected + && time (NULL) - session[i]->created > CONNECT_TIMEOUT) + { + printf ("Session #%d timed out\n", i); + session[i]->eof = 1; + } + if (!session[i]->rdata_size && !session[i]->eof) + continue; + if (session[i]->func_parse) + { + session[i]->func_parse (i); + /// some func_parse may call delete_session + if (!session[i]) + continue; + } + /// Reclaim buffer space for what was read + RFIFOFLUSH (i); + } +} + +void do_socket (void) +{ + FD_ZERO (&readfds); + currentuse = 3; +} + +void RFIFOSKIP (int fd, size_t len) +{ + struct socket_data *s = session[fd]; + s->rdata_pos += len; + + if (s->rdata_size < s->rdata_pos) + { + fprintf (stderr, "too many skip\n"); + abort (); + } +} + +void fclose_ (FILE * fp) +{ + if (fclose (fp)) + perror ("fclose"), abort (); + currentuse--; +} + +FILE *fopen_ (const char *path, const char *mode) +{ + FILE *f = fopen (path, mode); + if (f) + currentuse++; + return f; +} + +bool free_fds (void) +{ + return currentuse < SOFT_LIMIT; +} diff --git a/src/common/socket.h b/src/common/socket.h deleted file mode 100644 index b886df0..0000000 --- a/src/common/socket.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef SOCKET_H -#define SOCKET_H - -# include "sanity.h" - -# include - -# include -# include -# include - -# include - -/// Check how much can be read -# define RFIFOREST(fd) (session[fd]->rdata_size-session[fd]->rdata_pos) -/// Read from the queue -# define RFIFOP(fd,pos) (session[fd]->rdata+session[fd]->rdata_pos+(pos)) -# define RFIFOB(fd,pos) (*(uint8_t*)(RFIFOP(fd, pos))) -# define RFIFOW(fd,pos) (*(uint16_t*)(RFIFOP(fd, pos))) -# define RFIFOL(fd,pos) (*(uint32_t*)(RFIFOP(fd, pos))) -/// Done reading -void RFIFOSKIP (int fd, size_t len); -/// Internal - clean up by discarding handled bytes -// Atm this is also called in char/char.c, but that is unnecessary -# define RFIFOFLUSH(fd) (memmove(session[fd]->rdata,RFIFOP(fd,0),RFIFOREST(fd)),\ -session[fd]->rdata_size=RFIFOREST(fd),\ -session[fd]->rdata_pos=0) - -/// Used internally - how much room there is to read more data -# define RFIFOSPACE(fd) (session[fd]->max_rdata-session[fd]->rdata_size) - -/// Read from an arbitrary buffer -# define RBUFP(p,pos) (((uint8_t*)(p))+(pos)) -# define RBUFB(p,pos) (*(uint8_t*)RBUFP((p),(pos))) -# define RBUFW(p,pos) (*(uint16_t*)RBUFP((p),(pos))) -# define RBUFL(p,pos) (*(uint32_t*)RBUFP((p),(pos))) - - - -/// Unused - check how much data can be written -# define WFIFOSPACE(fd) (session[fd]->max_wdata-session[fd]->wdata_size) -/// Write to the queue -# define WFIFOP(fd,pos) (session[fd]->wdata+session[fd]->wdata_size+(pos)) -# define WFIFOB(fd,pos) (*(uint8_t*)(WFIFOP(fd,pos))) -# define WFIFOW(fd,pos) (*(uint16_t*)(WFIFOP(fd,pos))) -# define WFIFOL(fd,pos) (*(uint32_t*)(WFIFOP(fd,pos))) -/// Finish writing -void WFIFOSET (int fd, size_t len); - -/// Write to an arbitrary buffer -#define WBUFP(p,pos) (((uint8_t*)(p))+(pos)) -#define WBUFB(p,pos) (*(uint8_t*)WBUFP((p),(pos))) -#define WBUFW(p,pos) (*(uint16_t*)WBUFP((p),(pos))) -#define WBUFL(p,pos) (*(uint32_t*)WBUFP((p),(pos))) - -// Struct declaration - -struct socket_data -{ - /// Checks whether a newly-connected socket actually does anything - time_t created; - bool connected; - - /// Flag needed since structure must be freed in a server-dependent manner - bool eof; - - /// Since this is a single-threaded application, it can't block - /// These are the read/write queues - uint8_t *rdata, *wdata; - size_t max_rdata, max_wdata; - /// How much is actually in the queue - size_t rdata_size, wdata_size; - /// How much has already been read from the queue - /// Note that there is no need for a wdata_pos - size_t rdata_pos; - - struct sockaddr_in client_addr; - - /// Send or recieve - /// Only called when select() indicates the socket is ready - /// If, after that, nothing is read, it sets eof - // These could probably be hard-coded with a little work - void (*func_recv) (int); - void (*func_send) (int); - /// This is the important one - /// Set to different functions depending on whether the connection - /// is a player or a server/ladmin - /// Can be set explicitly or via set_defaultparse - void (*func_parse) (int); - /// Server-specific data type - void *session_data; -}; - -// save file descriptors for important stuff -# define SOFT_LIMIT (FD_SETSIZE - 50) - -// socket timeout to establish a full connection in seconds -# define CONNECT_TIMEOUT 15 - -/// Everyone who has connected -// note: call delete_session(i) to null out an element -extern struct socket_data *session[FD_SETSIZE]; - -/// Maximum used FD, +1 -extern int fd_max; - -/// open a socket, bind, and listen. Return an fd, or -1 if socket() fails, -/// but exit if bind() or listen() fails -int make_listen_port (uint16_t port); -/// Connect to an address, return a connected socket or -1 -// FIXME - this is IPv4 only! -int make_connection (uint32_t ip, uint16_t port); -/// free() the structure and close() the fd -void delete_session (int); -/// Make a the internal queues bigger -void realloc_fifo (int fd, size_t rfifo_size, size_t wfifo_size); -/// Update all sockets that can be read/written from the queues -void do_sendrecv (uint32_t next); -/// Call the parser function for every socket that has read data -void do_parsepacket (void); - -/// An init function -void do_socket (void); - -/// Change the default parser for newly connected clients -// typically called once per server, but individual clients may identify -// themselves as servers -void set_defaultparse (void (*defaultparse) (int)); - -/// Wrappers to track number of free FDs -void fclose_ (FILE * fp); -FILE *fopen_ (const char *path, const char *mode); -bool free_fds (void); - -#endif // SOCKET_H diff --git a/src/common/socket.hpp b/src/common/socket.hpp new file mode 100644 index 0000000..00f2df0 --- /dev/null +++ b/src/common/socket.hpp @@ -0,0 +1,135 @@ +#ifndef SOCKET_HPP +#define SOCKET_HPP + +# include "sanity.hpp" + +# include + +# include +# include +# include + +# include + +/// Check how much can be read +# define RFIFOREST(fd) (session[fd]->rdata_size-session[fd]->rdata_pos) +/// Read from the queue +# define RFIFOP(fd,pos) (session[fd]->rdata+session[fd]->rdata_pos+(pos)) +# define RFIFOB(fd,pos) (*(uint8_t*)(RFIFOP(fd, pos))) +# define RFIFOW(fd,pos) (*(uint16_t*)(RFIFOP(fd, pos))) +# define RFIFOL(fd,pos) (*(uint32_t*)(RFIFOP(fd, pos))) +/// Done reading +void RFIFOSKIP (int fd, size_t len); +/// Internal - clean up by discarding handled bytes +// Atm this is also called in char/char.c, but that is unnecessary +# define RFIFOFLUSH(fd) (memmove(session[fd]->rdata,RFIFOP(fd,0),RFIFOREST(fd)),\ +session[fd]->rdata_size=RFIFOREST(fd),\ +session[fd]->rdata_pos=0) + +/// Used internally - how much room there is to read more data +# define RFIFOSPACE(fd) (session[fd]->max_rdata-session[fd]->rdata_size) + +/// Read from an arbitrary buffer +# define RBUFP(p,pos) (((uint8_t*)(p))+(pos)) +# define RBUFB(p,pos) (*(uint8_t*)RBUFP((p),(pos))) +# define RBUFW(p,pos) (*(uint16_t*)RBUFP((p),(pos))) +# define RBUFL(p,pos) (*(uint32_t*)RBUFP((p),(pos))) + + + +/// Unused - check how much data can be written +# define WFIFOSPACE(fd) (session[fd]->max_wdata-session[fd]->wdata_size) +/// Write to the queue +# define WFIFOP(fd,pos) (session[fd]->wdata+session[fd]->wdata_size+(pos)) +# define WFIFOB(fd,pos) (*(uint8_t*)(WFIFOP(fd,pos))) +# define WFIFOW(fd,pos) (*(uint16_t*)(WFIFOP(fd,pos))) +# define WFIFOL(fd,pos) (*(uint32_t*)(WFIFOP(fd,pos))) +/// Finish writing +void WFIFOSET (int fd, size_t len); + +/// Write to an arbitrary buffer +#define WBUFP(p,pos) (((uint8_t*)(p))+(pos)) +#define WBUFB(p,pos) (*(uint8_t*)WBUFP((p),(pos))) +#define WBUFW(p,pos) (*(uint16_t*)WBUFP((p),(pos))) +#define WBUFL(p,pos) (*(uint32_t*)WBUFP((p),(pos))) + +// Struct declaration + +struct socket_data +{ + /// Checks whether a newly-connected socket actually does anything + time_t created; + bool connected; + + /// Flag needed since structure must be freed in a server-dependent manner + bool eof; + + /// Since this is a single-threaded application, it can't block + /// These are the read/write queues + uint8_t *rdata, *wdata; + size_t max_rdata, max_wdata; + /// How much is actually in the queue + size_t rdata_size, wdata_size; + /// How much has already been read from the queue + /// Note that there is no need for a wdata_pos + size_t rdata_pos; + + struct sockaddr_in client_addr; + + /// Send or recieve + /// Only called when select() indicates the socket is ready + /// If, after that, nothing is read, it sets eof + // These could probably be hard-coded with a little work + void (*func_recv) (int); + void (*func_send) (int); + /// This is the important one + /// Set to different functions depending on whether the connection + /// is a player or a server/ladmin + /// Can be set explicitly or via set_defaultparse + void (*func_parse) (int); + /// Server-specific data type + void *session_data; +}; + +// save file descriptors for important stuff +# define SOFT_LIMIT (FD_SETSIZE - 50) + +// socket timeout to establish a full connection in seconds +# define CONNECT_TIMEOUT 15 + +/// Everyone who has connected +// note: call delete_session(i) to null out an element +extern struct socket_data *session[FD_SETSIZE]; + +/// Maximum used FD, +1 +extern int fd_max; + +/// open a socket, bind, and listen. Return an fd, or -1 if socket() fails, +/// but exit if bind() or listen() fails +int make_listen_port (uint16_t port); +/// Connect to an address, return a connected socket or -1 +// FIXME - this is IPv4 only! +int make_connection (uint32_t ip, uint16_t port); +/// free() the structure and close() the fd +void delete_session (int); +/// Make a the internal queues bigger +void realloc_fifo (int fd, size_t rfifo_size, size_t wfifo_size); +/// Update all sockets that can be read/written from the queues +void do_sendrecv (uint32_t next); +/// Call the parser function for every socket that has read data +void do_parsepacket (void); + +/// An init function +void do_socket (void); + +/// Change the default parser for newly connected clients +// typically called once per server, but individual clients may identify +// themselves as servers +void set_defaultparse (void (*defaultparse) (int)); + +/// Wrappers to track number of free FDs +void fclose_ (FILE * fp); +FILE *fopen_ (const char *path, const char *mode); +bool free_fds (void); + +#endif // SOCKET_HPP diff --git a/src/common/timer.c b/src/common/timer.c deleted file mode 100644 index 6795824..0000000 --- a/src/common/timer.c +++ /dev/null @@ -1,257 +0,0 @@ -#include -#include -#include -#include - -#include -#include - -#include "timer.h" -#include "utils.h" - -static struct TimerData *timer_data; -static uint32_t timer_data_max, timer_data_num; -static timer_id *free_timer_list; -static uint32_t free_timer_list_max, free_timer_list_pos; - -/// Okay, I think I understand this structure now: -/// the timer heap is a magic queue that allows inserting timers and then popping them in order -/// designed to copy only log2(N) entries instead of N -// timer_heap[0] is the size (greatest index into the heap) -// timer_heap[1] is the first actual element -// timer_heap_max increases 256 at a time and never decreases -static uint32_t timer_heap_max = 0; -/// FIXME: refactor the code to put the size in a separate variable -//nontrivial because indices get multiplied -static timer_id *timer_heap = NULL; - - -static uint32_t gettick_cache; -static uint8_t gettick_count = 0; - -uint32_t gettick_nocache (void) -{ - struct timeval tval; - // BUG: This will cause strange behavior if the system clock is changed! - // it should be reimplemented in terms of clock_gettime(CLOCK_MONOTONIC, ) - gettimeofday (&tval, NULL); - gettick_count = 255; - return gettick_cache = tval.tv_sec * 1000 + tval.tv_usec / 1000; -} - -uint32_t gettick (void) -{ - if (gettick_count--) - return gettick_cache; - return gettick_nocache (); -} - -static void push_timer_heap (timer_id index) -{ - if (timer_heap == NULL || timer_heap[0] + 1 >= timer_heap_max) - { - timer_heap_max += 256; - RECREATE (timer_heap, timer_id, timer_heap_max); - memset (timer_heap + (timer_heap_max - 256), 0, sizeof (timer_id) * 256); - } -// timer_heap[0] is the greatest index into the heap, which increases - timer_heap[0]++; - - timer_id h = timer_heap[0]-1, i = (h - 1) / 2; - while (h) - { - // avoid wraparound problems, it really means this: - // timer_data[index].tick >= timer_data[timer_heap[i+1]].tick - if ( DIFF_TICK(timer_data[index].tick, timer_data[timer_heap[i+1]].tick) >= 0) - break; - timer_heap[h + 1] = timer_heap[i + 1]; - h = i; - i = (h - 1) / 2; - } - timer_heap[h + 1] = index; -} - -static timer_id top_timer_heap (void) -{ - if (!timer_heap || !timer_heap[0]) - return -1; - return timer_heap[1]; -} - -static timer_id pop_timer_heap (void) -{ - if (!timer_heap || !timer_heap[0]) - return -1; - timer_id ret = timer_heap[1]; - timer_id last = timer_heap[timer_heap[0]]; - timer_heap[0]--; - - uint32_t h, k; - for (h = 0, k = 2; k < timer_heap[0]; k = k * 2 + 2) - { - if (DIFF_TICK(timer_data[timer_heap[k + 1]].tick, timer_data[timer_heap[k]].tick) > 0) - k--; - timer_heap[h + 1] = timer_heap[k + 1], h = k; - } - if (k == timer_heap[0]) - timer_heap[h + 1] = timer_heap[k], h = k - 1; - - uint32_t i = (h - 1) / 2; - while (h) - { - if (DIFF_TICK (timer_data[timer_heap[i + 1]].tick, timer_data[last].tick) <= 0) - break; - timer_heap[h + 1] = timer_heap[i + 1]; - h = i; - i = (h - 1) / 2; - } - timer_heap[h + 1] = last; - - return ret; -} - -timer_id add_timer (tick_t tick, timer_func func, custom_id_t id, custom_data_t data) -{ - timer_id i; - - if (free_timer_list_pos) - { - // Retrieve a freed timer id instead of a new one - // I think it should be possible to avoid the loop somehow - do - { - i = free_timer_list[--free_timer_list_pos]; - } - while (i >= timer_data_num && free_timer_list_pos > 0); - } - else - i = timer_data_num; - - // I have no idea what this is doing - if (i >= timer_data_num) - for (i = timer_data_num; i < timer_data_max && timer_data[i].type; i++) - ; - if (i >= timer_data_num && i >= timer_data_max) - { - if (timer_data_max == 0) - { - timer_data_max = 256; - CREATE (timer_data, struct TimerData, timer_data_max); - } - else - { - timer_data_max += 256; - RECREATE (timer_data, struct TimerData, timer_data_max); - memset (timer_data + (timer_data_max - 256), 0, - sizeof (struct TimerData) * 256); - } - } - timer_data[i].tick = tick; - timer_data[i].func = func; - timer_data[i].id = id; - timer_data[i].data = data; - timer_data[i].type = TIMER_ONCE_AUTODEL; - timer_data[i].interval = 1000; - push_timer_heap (i); - if (i >= timer_data_num) - timer_data_num = i + 1; - return i; -} - -timer_id add_timer_interval (tick_t tick, timer_func func, custom_id_t id, - custom_data_t data, interval_t interval) -{ - timer_id tid = add_timer (tick, func, id, data); - timer_data[tid].type = TIMER_INTERVAL; - timer_data[tid].interval = interval; - return tid; -} - -void delete_timer (timer_id id, timer_func func) -{ - if (id == 0 || id >= timer_data_num) - { - fprintf (stderr, "delete_timer error : no such timer %d\n", id); - abort (); - } - if (timer_data[id].func != func) - { - fprintf (stderr, "Timer mismatch\n"); - abort (); - } - // "to let them disappear" - is this just in case? - timer_data[id].func = NULL; - timer_data[id].type = TIMER_ONCE_AUTODEL; - timer_data[id].tick -= 60 * 60 * 1000; -} - -tick_t addtick_timer (timer_id tid, interval_t tick) -{ - return timer_data[tid].tick += tick; -} - -struct TimerData *get_timer (timer_id tid) -{ - return &timer_data[tid]; -} - -interval_t do_timer (tick_t tick) -{ - timer_id i; - /// Number of milliseconds until it calls this again - // this says to wait 1 sec if all timers get popped - interval_t nextmin = 1000; - - while ((i = top_timer_heap ()) != (timer_id)-1) - { - // while the heap is not empty and - if (DIFF_TICK (timer_data[i].tick, tick) > 0) - { - /// Return the time until the next timer needs to goes off - nextmin = DIFF_TICK (timer_data[i].tick, tick); - break; - } - pop_timer_heap (); - if (timer_data[i].func) - { - if (DIFF_TICK (timer_data[i].tick, tick) < -1000) - { - // If we are too far past the requested tick, call with the current tick instead to fix reregistering problems - timer_data[i].func (i, tick, timer_data[i].id, timer_data[i].data); - } - else - { - timer_data[i].func (i, timer_data[i].tick, timer_data[i].id, timer_data[i].data); - } - } - switch (timer_data[i].type) - { - case TIMER_ONCE_AUTODEL: - timer_data[i].type = TIMER_NONE; - if (free_timer_list_pos >= free_timer_list_max) - { - free_timer_list_max += 256; - RECREATE (free_timer_list, uint32_t, free_timer_list_max); - memset (free_timer_list + (free_timer_list_max - 256), - 0, 256 * sizeof (uint32_t)); - } - free_timer_list[free_timer_list_pos++] = i; - break; - case TIMER_INTERVAL: - if (DIFF_TICK (timer_data[i].tick, tick) < -1000) - { - timer_data[i].tick = tick + timer_data[i].interval; - } - else - { - timer_data[i].tick += timer_data[i].interval; - } - push_timer_heap (i); - break; - } - } - - if (nextmin < 10) - nextmin = 10; - return nextmin; -} diff --git a/src/common/timer.cpp b/src/common/timer.cpp new file mode 100644 index 0000000..66aaa9b --- /dev/null +++ b/src/common/timer.cpp @@ -0,0 +1,257 @@ +#include +#include +#include +#include + +#include +#include + +#include "timer.hpp" +#include "utils.hpp" + +static struct TimerData *timer_data; +static uint32_t timer_data_max, timer_data_num; +static timer_id *free_timer_list; +static uint32_t free_timer_list_max, free_timer_list_pos; + +/// Okay, I think I understand this structure now: +/// the timer heap is a magic queue that allows inserting timers and then popping them in order +/// designed to copy only log2(N) entries instead of N +// timer_heap[0] is the size (greatest index into the heap) +// timer_heap[1] is the first actual element +// timer_heap_max increases 256 at a time and never decreases +static uint32_t timer_heap_max = 0; +/// FIXME: refactor the code to put the size in a separate variable +//nontrivial because indices get multiplied +static timer_id *timer_heap = NULL; + + +static uint32_t gettick_cache; +static uint8_t gettick_count = 0; + +uint32_t gettick_nocache (void) +{ + struct timeval tval; + // BUG: This will cause strange behavior if the system clock is changed! + // it should be reimplemented in terms of clock_gettime(CLOCK_MONOTONIC, ) + gettimeofday (&tval, NULL); + gettick_count = 255; + return gettick_cache = tval.tv_sec * 1000 + tval.tv_usec / 1000; +} + +uint32_t gettick (void) +{ + if (gettick_count--) + return gettick_cache; + return gettick_nocache (); +} + +static void push_timer_heap (timer_id index) +{ + if (timer_heap == NULL || timer_heap[0] + 1 >= timer_heap_max) + { + timer_heap_max += 256; + RECREATE (timer_heap, timer_id, timer_heap_max); + memset (timer_heap + (timer_heap_max - 256), 0, sizeof (timer_id) * 256); + } +// timer_heap[0] is the greatest index into the heap, which increases + timer_heap[0]++; + + timer_id h = timer_heap[0]-1, i = (h - 1) / 2; + while (h) + { + // avoid wraparound problems, it really means this: + // timer_data[index].tick >= timer_data[timer_heap[i+1]].tick + if ( DIFF_TICK(timer_data[index].tick, timer_data[timer_heap[i+1]].tick) >= 0) + break; + timer_heap[h + 1] = timer_heap[i + 1]; + h = i; + i = (h - 1) / 2; + } + timer_heap[h + 1] = index; +} + +static timer_id top_timer_heap (void) +{ + if (!timer_heap || !timer_heap[0]) + return -1; + return timer_heap[1]; +} + +static timer_id pop_timer_heap (void) +{ + if (!timer_heap || !timer_heap[0]) + return -1; + timer_id ret = timer_heap[1]; + timer_id last = timer_heap[timer_heap[0]]; + timer_heap[0]--; + + uint32_t h, k; + for (h = 0, k = 2; k < timer_heap[0]; k = k * 2 + 2) + { + if (DIFF_TICK(timer_data[timer_heap[k + 1]].tick, timer_data[timer_heap[k]].tick) > 0) + k--; + timer_heap[h + 1] = timer_heap[k + 1], h = k; + } + if (k == timer_heap[0]) + timer_heap[h + 1] = timer_heap[k], h = k - 1; + + uint32_t i = (h - 1) / 2; + while (h) + { + if (DIFF_TICK (timer_data[timer_heap[i + 1]].tick, timer_data[last].tick) <= 0) + break; + timer_heap[h + 1] = timer_heap[i + 1]; + h = i; + i = (h - 1) / 2; + } + timer_heap[h + 1] = last; + + return ret; +} + +timer_id add_timer (tick_t tick, timer_func func, custom_id_t id, custom_data_t data) +{ + timer_id i; + + if (free_timer_list_pos) + { + // Retrieve a freed timer id instead of a new one + // I think it should be possible to avoid the loop somehow + do + { + i = free_timer_list[--free_timer_list_pos]; + } + while (i >= timer_data_num && free_timer_list_pos > 0); + } + else + i = timer_data_num; + + // I have no idea what this is doing + if (i >= timer_data_num) + for (i = timer_data_num; i < timer_data_max && timer_data[i].type; i++) + ; + if (i >= timer_data_num && i >= timer_data_max) + { + if (timer_data_max == 0) + { + timer_data_max = 256; + CREATE (timer_data, struct TimerData, timer_data_max); + } + else + { + timer_data_max += 256; + RECREATE (timer_data, struct TimerData, timer_data_max); + memset (timer_data + (timer_data_max - 256), 0, + sizeof (struct TimerData) * 256); + } + } + timer_data[i].tick = tick; + timer_data[i].func = func; + timer_data[i].id = id; + timer_data[i].data = data; + timer_data[i].type = TIMER_ONCE_AUTODEL; + timer_data[i].interval = 1000; + push_timer_heap (i); + if (i >= timer_data_num) + timer_data_num = i + 1; + return i; +} + +timer_id add_timer_interval (tick_t tick, timer_func func, custom_id_t id, + custom_data_t data, interval_t interval) +{ + timer_id tid = add_timer (tick, func, id, data); + timer_data[tid].type = TIMER_INTERVAL; + timer_data[tid].interval = interval; + return tid; +} + +void delete_timer (timer_id id, timer_func func) +{ + if (id == 0 || id >= timer_data_num) + { + fprintf (stderr, "delete_timer error : no such timer %d\n", id); + abort (); + } + if (timer_data[id].func != func) + { + fprintf (stderr, "Timer mismatch\n"); + abort (); + } + // "to let them disappear" - is this just in case? + timer_data[id].func = NULL; + timer_data[id].type = TIMER_ONCE_AUTODEL; + timer_data[id].tick -= 60 * 60 * 1000; +} + +tick_t addtick_timer (timer_id tid, interval_t tick) +{ + return timer_data[tid].tick += tick; +} + +struct TimerData *get_timer (timer_id tid) +{ + return &timer_data[tid]; +} + +interval_t do_timer (tick_t tick) +{ + timer_id i; + /// Number of milliseconds until it calls this again + // this says to wait 1 sec if all timers get popped + interval_t nextmin = 1000; + + while ((i = top_timer_heap ()) != (timer_id)-1) + { + // while the heap is not empty and + if (DIFF_TICK (timer_data[i].tick, tick) > 0) + { + /// Return the time until the next timer needs to goes off + nextmin = DIFF_TICK (timer_data[i].tick, tick); + break; + } + pop_timer_heap (); + if (timer_data[i].func) + { + if (DIFF_TICK (timer_data[i].tick, tick) < -1000) + { + // If we are too far past the requested tick, call with the current tick instead to fix reregistering problems + timer_data[i].func (i, tick, timer_data[i].id, timer_data[i].data); + } + else + { + timer_data[i].func (i, timer_data[i].tick, timer_data[i].id, timer_data[i].data); + } + } + switch (timer_data[i].type) + { + case TIMER_ONCE_AUTODEL: + timer_data[i].type = TIMER_NONE; + if (free_timer_list_pos >= free_timer_list_max) + { + free_timer_list_max += 256; + RECREATE (free_timer_list, uint32_t, free_timer_list_max); + memset (free_timer_list + (free_timer_list_max - 256), + 0, 256 * sizeof (uint32_t)); + } + free_timer_list[free_timer_list_pos++] = i; + break; + case TIMER_INTERVAL: + if (DIFF_TICK (timer_data[i].tick, tick) < -1000) + { + timer_data[i].tick = tick + timer_data[i].interval; + } + else + { + timer_data[i].tick += timer_data[i].interval; + } + push_timer_heap (i); + break; + } + } + + if (nextmin < 10) + nextmin = 10; + return nextmin; +} diff --git a/src/common/timer.h b/src/common/timer.h deleted file mode 100644 index e6a292c..0000000 --- a/src/common/timer.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef TIMER_H -#define TIMER_H - -# include "sanity.h" - -enum TIMER_TYPE -{ - TIMER_NONE, - TIMER_ONCE_AUTODEL, - TIMER_INTERVAL, -}; -/// This is needed to produce a signed result when 2 ticks are subtracted -# define DIFF_TICK(a,b) ((int32_t)((a)-(b))) - -// TODO replace with signed 64-bit to make code more clear and protect from the future -typedef uint32_t tick_t; -typedef uint32_t interval_t; -typedef uint32_t timer_id; -// BUG: pointers are stored in here -typedef int32_t custom_id_t; -typedef int32_t custom_data_t; -typedef void (*timer_func) (timer_id, tick_t, custom_id_t, custom_data_t); - -struct TimerData -{ - /// When it will be triggered - tick_t tick; - /// What will be done - timer_func func; - /// Arbitrary data. WARNING, callers are stupid and put pointers in here - // Should we change to void* or intptr_t ? - custom_id_t id; - custom_data_t data; - /// Type of timer - 0 initially - enum TIMER_TYPE type; - /// Repeat rate - interval_t interval; -}; - -/// Server time, in milliseconds, since the epoch, -/// but use of 32-bit integers means it wraps every 49 days. -// The only external caller of this function is the core.c main loop, but that makes sense -// in fact, it might make more sense if gettick() ALWAYS returned that cached value -tick_t gettick_nocache (void); -/// This function is called enough that it's worth caching the result for -/// the next 255 times -tick_t gettick (void); - -timer_id add_timer (tick_t, timer_func, custom_id_t, custom_data_t); -timer_id add_timer_interval (tick_t, timer_func, custom_id_t, custom_data_t, interval_t); -void delete_timer (timer_id, timer_func); - -tick_t addtick_timer (timer_id, interval_t); -struct TimerData *get_timer (timer_id tid); - -/// Do all timers scheduled before tick, and return the number of milliseconds until the next timer happens -interval_t do_timer (tick_t tick); - - - -#endif // TIMER_H diff --git a/src/common/timer.hpp b/src/common/timer.hpp new file mode 100644 index 0000000..fdda344 --- /dev/null +++ b/src/common/timer.hpp @@ -0,0 +1,61 @@ +#ifndef TIMER_HPP +#define TIMER_HPP + +# include "sanity.hpp" + +enum TIMER_TYPE +{ + TIMER_NONE, + TIMER_ONCE_AUTODEL, + TIMER_INTERVAL, +}; +/// This is needed to produce a signed result when 2 ticks are subtracted +# define DIFF_TICK(a,b) ((int32_t)((a)-(b))) + +// TODO replace with signed 64-bit to make code more clear and protect from the future +typedef uint32_t tick_t; +typedef uint32_t interval_t; +typedef uint32_t timer_id; +// BUG: pointers are stored in here +typedef int32_t custom_id_t; +typedef int32_t custom_data_t; +typedef void (*timer_func) (timer_id, tick_t, custom_id_t, custom_data_t); + +struct TimerData +{ + /// When it will be triggered + tick_t tick; + /// What will be done + timer_func func; + /// Arbitrary data. WARNING, callers are stupid and put pointers in here + // Should we change to void* or intptr_t ? + custom_id_t id; + custom_data_t data; + /// Type of timer - 0 initially + enum TIMER_TYPE type; + /// Repeat rate + interval_t interval; +}; + +/// Server time, in milliseconds, since the epoch, +/// but use of 32-bit integers means it wraps every 49 days. +// The only external caller of this function is the core.c main loop, but that makes sense +// in fact, it might make more sense if gettick() ALWAYS returned that cached value +tick_t gettick_nocache (void); +/// This function is called enough that it's worth caching the result for +/// the next 255 times +tick_t gettick (void); + +timer_id add_timer (tick_t, timer_func, custom_id_t, custom_data_t); +timer_id add_timer_interval (tick_t, timer_func, custom_id_t, custom_data_t, interval_t); +void delete_timer (timer_id, timer_func); + +tick_t addtick_timer (timer_id, interval_t); +struct TimerData *get_timer (timer_id tid); + +/// Do all timers scheduled before tick, and return the number of milliseconds until the next timer happens +interval_t do_timer (tick_t tick); + + + +#endif // TIMER_HPP diff --git a/src/common/utils.h b/src/common/utils.h deleted file mode 100644 index 961d960..0000000 --- a/src/common/utils.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef UTILS_H -#define UTILS_H -/* -Notes about memory allocation in tmwAthena: -There used to be 3 sources of allocation: these macros, -a{C,M,Re}alloc in common/malloc.{h,c}, and direct calls. -I deleted malloc.{h,c} because it was redundant; -future calls should either use this or depend on the coming segfault. -*/ -# define CREATE(result, type, number) \ - if (!((result) = (type *) calloc ((number), sizeof(type)))) \ - { perror("SYSERR: malloc failure"); abort(); } else (void)0 - -# define RECREATE(result,type,number) \ - if (!((result) = (type *) realloc ((result), sizeof(type) * (number))))\ - { perror("SYSERR: realloc failure"); abort(); } else (void)0 - -#endif //UTILS_H diff --git a/src/common/utils.hpp b/src/common/utils.hpp new file mode 100644 index 0000000..7c7da16 --- /dev/null +++ b/src/common/utils.hpp @@ -0,0 +1,18 @@ +#ifndef UTILS_HPP +#define UTILS_HPP +/* +Notes about memory allocation in tmwAthena: +There used to be 3 sources of allocation: these macros, +a{C,M,Re}alloc in common/malloc.{h,c}, and direct calls. +I deleted malloc.{h,c} because it was redundant; +future calls should either use this or depend on the coming segfault. +*/ +# define CREATE(result, type, number) \ + if (!((result) = (type *) calloc ((number), sizeof(type)))) \ + { perror("SYSERR: malloc failure"); abort(); } else (void)0 + +# define RECREATE(result,type,number) \ + if (!((result) = (type *) realloc ((result), sizeof(type) * (number))))\ + { perror("SYSERR: realloc failure"); abort(); } else (void)0 + +#endif //UTILS_HPP diff --git a/src/common/version.h b/src/common/version.h deleted file mode 100644 index 46165aa..0000000 --- a/src/common/version.h +++ /dev/null @@ -1,24 +0,0 @@ -/// Some constants to identify the version of (e)Athena -/// The values are different if the client connects (-1,'T','M','W',flags32) -// These numbers have never been changed while TMW -#ifndef VERSION_H -#define VERSION_H -//When a server receives a 0x7530 packet from an admin connection, -//it sends an 0x7531 packet with the following bytes -# define ATHENA_MAJOR_VERSION 1 // Major Version -# define ATHENA_MINOR_VERSION 0 // Minor Version -# define ATHENA_REVISION 0 // Revision - -# define ATHENA_RELEASE_FLAG 1 // 1=Develop,0=Stable -# define ATHENA_OFFICIAL_FLAG 1 // 1=Mod,0=Official - -// and a bitmask of these (the char server sends char and inter) -# define ATHENA_SERVER_LOGIN 1 // login server -# define ATHENA_SERVER_CHAR 2 // char server -# define ATHENA_SERVER_INTER 4 // inter server -# define ATHENA_SERVER_MAP 8 // map server - -// and this as two bytes -# define ATHENA_MOD_VERSION 1052 // mod version (patch No.) - -#endif // VERSION_H diff --git a/src/common/version.hpp b/src/common/version.hpp new file mode 100644 index 0000000..d72f41e --- /dev/null +++ b/src/common/version.hpp @@ -0,0 +1,24 @@ +/// Some constants to identify the version of (e)Athena +/// The values are different if the client connects (-1,'T','M','W',flags32) +// These numbers have never been changed while TMW +#ifndef VERSION_HPP +#define VERSION_HPP +//When a server receives a 0x7530 packet from an admin connection, +//it sends an 0x7531 packet with the following bytes +# define ATHENA_MAJOR_VERSION 1 // Major Version +# define ATHENA_MINOR_VERSION 0 // Minor Version +# define ATHENA_REVISION 0 // Revision + +# define ATHENA_RELEASE_FLAG 1 // 1=Develop,0=Stable +# define ATHENA_OFFICIAL_FLAG 1 // 1=Mod,0=Official + +// and a bitmask of these (the char server sends char and inter) +# define ATHENA_SERVER_LOGIN 1 // login server +# define ATHENA_SERVER_CHAR 2 // char server +# define ATHENA_SERVER_INTER 4 // inter server +# define ATHENA_SERVER_MAP 8 // map server + +// and this as two bytes +# define ATHENA_MOD_VERSION 1052 // mod version (patch No.) + +#endif // VERSION_HPP diff --git a/src/ladmin/ladmin.c b/src/ladmin/ladmin.c deleted file mode 100644 index 3728799..0000000 --- a/src/ladmin/ladmin.c +++ /dev/null @@ -1,6476 +0,0 @@ -// $Id: ladmin.c,v 1.1.1.1 2004/09/10 17:26:52 MagicalTux Exp $ -/////////////////////////////////////////////////////////////////////////// -// EAthena login-server remote administration tool -// Ladamin in C by [Yor] -// if you modify this software, modify ladmin in tool too. -/////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include // gettimeofday -#include -#include -#include // close -#include -#include -#include // str* -#include // inet_addr -#include // gethostbyname -#include // valist -#include // tolower - -#include "../common/core.h" -#include "../common/socket.h" -#include "ladmin.h" -#include "../common/version.h" -#include "../common/mmo.h" - -#ifdef PASSWORDENC -#include "../common/md5calc.h" -#endif - -#ifdef MEMWATCH -#include "memwatch.h" -#endif - -int eathena_interactive_session; // from core.c -#define Iprintf if (eathena_interactive_session) printf - -//-------------------------------INSTRUCTIONS------------------------------ -// Set the variables below: -// IP of the login server. -// Port where the login-server listens incoming packets. -// Password of administration (same of config_athena.conf). -// Displayed language of the sofware (if not correct, english is used). -// IMPORTANT: -// Be sure that you authorize remote administration in login-server -// (see login_athena.conf, 'admin_state' parameter) -//------------------------------------------------------------------------- -char loginserverip[16] = "127.0.0.1"; // IP of login-server -int loginserverport = 6900; // Port of login-server -char loginserveradminpassword[24] = "admin"; // Administration password -#ifdef PASSWORDENC -int passenc = 2; // Encoding type of the password -#else -int passenc = 0; // Encoding type of the password -#endif -char defaultlanguage = 'E'; // Default language (F: Français/E: English) - // (if it's not 'F', default is English) -char ladmin_log_filename[1024] = "log/ladmin.log"; -char date_format[32] = "%Y-%m-%d %H:%M:%S"; -//------------------------------------------------------------------------- -// LIST of COMMANDs that you can type at the prompt: -// To use these commands you can only type only the first letters. -// You must type a minimum of letters (you can not type 'a', -// because ladmin doesn't know if it's for 'aide' or for 'add') -// q <= quit, li <= list, pass <= passwd, etc. -// -// Note: every time you must give a account_name, you can use "" or '' (spaces can be included) -// -// aide/help/? -// Display the description of the commands -// aide/help/? [command] -// Display the description of the specified command -// -// add -// Create an account with the default email (a@a.com). -// Concerning the sex, only the first letter is used (F or M). -// The e-mail is set to a@a.com (default e-mail). It's like to have no e-mail. -// When the password is omitted, the input is done without displaying of the pressed keys. -// add testname Male testpass -// -// ban/banish yyyy/mm/dd hh:mm:ss -// Changes the final date of a banishment of an account. -// Like banset, but is at end. -// -// banadd -// Adds or substracts time from the final date of a banishment of an account. -// Modifier is done as follows: -// Adjustment value (-1, 1, +1, etc...) -// Modified element: -// a or y: year -// m: month -// j or d: day -// h: hour -// mn: minute -// s: second -// banadd testname +1m-2mn1s-6y -// this example adds 1 month and 1 second, and substracts 2 minutes and 6 years at the same time. -// NOTE: If you modify the final date of a non-banished account, -// you fix the final date to (actual time +- adjustments) -// -// banset yyyy/mm/dd [hh:mm:ss] -// Changes the final date of a banishment of an account. -// Default time [hh:mm:ss]: 23:59:59. -// banset 0 -// Set a non-banished account (0 = unbanished). -// -// block -// Set state 5 (You have been blocked by the GM Team) to an account. -// Like state 5. -// -// check -// Check the validity of a password for an account -// NOTE: Server will never sends back a password. -// It's the only method you have to know if a password is correct. -// The other method is to have a ('physical') access to the accounts file. -// -// create -// Like the 'add' command, but with e-mail moreover. -// create testname Male my@mail.com testpass -// -// del -// Remove an account. -// This order requires confirmation. After confirmation, the account is deleted. -// -// email -// Modify the e-mail of an account. -// -// getcount -// Give the number of players online on all char-servers. -// -// gm [GM_level] -// Modify the GM level of an account. -// Default value remove GM level (GM level = 0). -// gm testname 80 -// -// id -// Give the id of an account. -// -// info -// Display complete information of an account. -// -// kami -// Sends a broadcast message on all map-server (in yellow). -// kamib -// Sends a broadcast message on all map-server (in blue). -// -// language -// Change the language of displaying. -// -// list/ls [start_id [end_id]] -// Display a list of accounts. -// 'start_id', 'end_id': indicate end and start identifiers. -// Research by name is not possible with this command. -// list 10 9999999 -// -// listBan/lsBan [start_id [end_id]] -// Like list/ls, but only for accounts with state or banished -// -// listGM/lsGM [start_id [end_id]] -// Like list/ls, but only for GM accounts -// -// listOK/lsOK [start_id [end_id]] -// Like list/ls, but only for accounts without state and not banished -// -// memo -// Modify the memo of an account. -// 'memo': it can have until 253 characters (with spaces or not). -// -// name -// Give the name of an account. -// -// passwd -// Change the password of an account. -// When new password is omitted, the input is done without displaying of the pressed keys. -// -// quit/end/exit -// End of the program of administration -// -// reloadGM -// Reload GM configuration file -// -// search -// Seek accounts. -// Displays the accounts whose names correspond. -// search -r/-e/--expr/--regex -// Seek accounts by regular expression. -// Displays the accounts whose names correspond. -// -// sex -// Modify the sex of an account. -// sex testname Male -// -// state -// Change the state of an account. -// 'new_state': state is the state of the packet 0x006a + 1. The possibilities are: -// 0 = Account ok 6 = Your Game's EXE file is not the latest version -// 1 = Unregistered ID 7 = You are Prohibited to log in until %s -// 2 = Incorrect Password 8 = Server is jammed due to over populated -// 3 = This ID is expired 9 = No MSG -// 4 = Rejected from Server 100 = This ID has been totally erased -// 5 = You have been blocked by the GM Team -// all other values are 'No MSG', then use state 9 please. -// 'error_message_#7': message of the code error 6 = Your are Prohibited to log in until %s (packet 0x006a) -// -// timeadd -// Adds or substracts time from the validity limit of an account. -// Modifier is done as follows: -// Adjustment value (-1, 1, +1, etc...) -// Modified element: -// a or y: year -// m: month -// j or d: day -// h: hour -// mn: minute -// s: second -// timeadd testname +1m-2mn1s-6y -// this example adds 1 month and 1 second, and substracts 2 minutes and 6 years at the same time. -// NOTE: You can not modify a unlimited validity limit. -// If you want modify it, you want probably create a limited validity limit. -// So, at first, you must set the validity limit to a date/time. -// -// timeset yyyy/mm/dd [hh:mm:ss] -// Changes the validity limit of an account. -// Default time [hh:mm:ss]: 23:59:59. -// timeset 0 -// Gives an unlimited validity limit (0 = unlimited). -// -// unban/unbanish -// Unban an account. -// Like banset 0. -// -// unblock -// Set state 0 (Account ok) to an account. -// Like state 0. -// -// version -// Display the version of the login-server. -// -// who -// Displays complete information of an account. -// -//------------------------------------------------------------------------- -int login_fd; -int login_ip; -int bytes_to_read = 0; // flag to know if we waiting bytes from login-server -char command[1024]; -char parameters[1024]; -int list_first, list_last, list_type, list_count; // parameter to display a list of accounts -int already_exit_function = 0; // sometimes, the exit function is called twice... so, don't log twice the message - -//------------------------------ -// Writing function of logs file -//------------------------------ -int ladmin_log (const char *fmt, ...) -{ - FILE *logfp; - va_list ap; - struct timeval tv; - char tmpstr[2048]; - - va_start (ap, fmt); - - logfp = fopen_ (ladmin_log_filename, "a"); - if (logfp) - { - if (fmt[0] == '\0') // jump a line if no message - fprintf (logfp, "\n"); - else - { - gettimeofday (&tv, NULL); - strftime (tmpstr, 24, date_format, localtime (&(tv.tv_sec))); - sprintf (tmpstr + strlen (tmpstr), ".%03d: %s", - (int) tv.tv_usec / 1000, fmt); - vfprintf (logfp, tmpstr, ap); - } - fclose_ (logfp); - } - - va_end (ap); - return 0; -} - -//----------------------------------------------------- -// Function to suppress control characters in a string. -//----------------------------------------------------- -int remove_control_chars (unsigned char *str) -{ - int i; - int change = 0; - - for (i = 0; str[i]; i++) - { - if (str[i] < 32) - { - str[i] = '_'; - change = 1; - } - } - - return change; -} - -//--------------------------------------------- -// Function to return ordonal text of a number. -//--------------------------------------------- -const char *makeordinal (int number) -{ - if (defaultlanguage == 'F') - { - if (number == 0) - return ""; - else if (number == 1) - return "er"; - else - return "ème"; - } - else - { - if ((number % 10) < 4 && (number % 10) != 0 - && (number < 10 || number > 20)) - { - if ((number % 10) == 1) - return "st"; - else if ((number % 10) == 2) - return "nd"; - else - return "rd"; - } - else - { - return "th"; - } - } - return ""; -} - -//----------------------------------------------------------------------------------------- -// Function to test of the validity of an account name (return 0 if incorrect, and 1 if ok) -//----------------------------------------------------------------------------------------- -int verify_accountname (char *account_name) -{ - int i; - - for (i = 0; account_name[i]; i++) - { - if (account_name[i] < 32) - { - if (defaultlanguage == 'F') - { - printf - ("Caractère interdit trouvé dans le nom du compte (%d%s caractère).\n", - i + 1, makeordinal (i + 1)); - ladmin_log - ("Caractère interdit trouvé dans le nom du compte (%d%s caractère).\n", - i + 1, makeordinal (i + 1)); - } - else - { - printf - ("Illegal character found in the account name (%d%s character).\n", - i + 1, makeordinal (i + 1)); - ladmin_log - ("Illegal character found in the account name (%d%s character).\n", - i + 1, makeordinal (i + 1)); - } - return 0; - } - } - - if (strlen (account_name) < 4) - { - if (defaultlanguage == 'F') - { - printf - ("Nom du compte trop court. Entrez un nom de compte de 4-23 caractères.\n"); - ladmin_log - ("Nom du compte trop court. Entrez un nom de compte de 4-23 caractères.\n"); - } - else - { - printf - ("Account name is too short. Please input an account name of 4-23 bytes.\n"); - ladmin_log - ("Account name is too short. Please input an account name of 4-23 bytes.\n"); - } - return 0; - } - - if (strlen (account_name) > 23) - { - if (defaultlanguage == 'F') - { - printf - ("Nom du compte trop long. Entrez un nom de compte de 4-23 caractères.\n"); - ladmin_log - ("Nom du compte trop long. Entrez un nom de compte de 4-23 caractères.\n"); - } - else - { - printf - ("Account name is too long. Please input an account name of 4-23 bytes.\n"); - ladmin_log - ("Account name is too long. Please input an account name of 4-23 bytes.\n"); - } - return 0; - } - - return 1; -} - -//--------------------------------------------------- -// E-mail check: return 0 (not correct) or 1 (valid). -//--------------------------------------------------- -int e_mail_check (unsigned char *email) -{ - char ch; - unsigned char *last_arobas; - - // athena limits - if (strlen (email) < 3 || strlen (email) > 39) - return 0; - - // part of RFC limits (official reference of e-mail description) - if (strchr (email, '@') == NULL || email[strlen (email) - 1] == '@') - return 0; - - if (email[strlen (email) - 1] == '.') - return 0; - - last_arobas = strrchr (email, '@'); - - if (strstr (last_arobas, "@.") != NULL || - strstr (last_arobas, "..") != NULL) - return 0; - - for (ch = 1; ch < 32; ch++) - { - if (strchr (last_arobas, ch) != NULL) - { - return 0; - break; - } - } - - if (strchr (last_arobas, ' ') != NULL || - strchr (last_arobas, ';') != NULL) - return 0; - - // all correct - return 1; -} - -//---------------------------------- -// Sub-function: Input of a password -//---------------------------------- -int typepasswd (char *password) -{ - char password1[1023], password2[1023]; - int letter; - int i; - - if (defaultlanguage == 'F') - { - ladmin_log - ("Aucun mot de passe n'a été donné. Demande d'un mot de passe.\n"); - } - else - { - ladmin_log ("No password was given. Request to obtain a password.\n"); - } - - memset (password1, '\0', sizeof (password1)); - memset (password2, '\0', sizeof (password2)); - if (defaultlanguage == 'F') - printf ("\033[1;36m Entrez le mot de passe > \033[0;32;42m"); - else - printf ("\033[1;36m Type the password > \033[0;32;42m"); - i = 0; - while ((letter = getchar ()) != '\n') - password1[i++] = letter; - if (defaultlanguage == 'F') - printf - ("\033[0m\033[1;36m Ré-entrez le mot de passe > \033[0;32;42m"); - else - printf ("\033[0m\033[1;36m Verify the password > \033[0;32;42m"); - i = 0; - while ((letter = getchar ()) != '\n') - password2[i++] = letter; - - printf ("\033[0m"); - fflush (stdout); - fflush (stdin); - - if (strcmp (password1, password2) != 0) - { - if (defaultlanguage == 'F') - { - printf - ("Erreur de vérification du mot de passe: Saisissez le même mot de passe svp.\n"); - ladmin_log - ("Erreur de vérification du mot de passe: Saisissez le même mot de passe svp.\n"); - ladmin_log (" Premier mot de passe: %s, second mot de passe: %s.\n", - password1, password2); - } - else - { - printf - ("Password verification failed. Please input same password.\n"); - ladmin_log - ("Password verification failed. Please input same password.\n"); - ladmin_log (" First password: %s, second password: %s.\n", - password1, password2); - } - return 0; - } - if (defaultlanguage == 'F') - { - ladmin_log ("Mot de passe saisi: %s.\n", password1); - } - else - { - ladmin_log ("Typed password: %s.\n", password1); - } - strcpy (password, password1); - return 1; -} - -//------------------------------------------------------------------------------------ -// Sub-function: Test of the validity of password (return 0 if incorrect, and 1 if ok) -//------------------------------------------------------------------------------------ -int verify_password (char *password) -{ - int i; - - for (i = 0; password[i]; i++) - { - if (password[i] < 32) - { - if (defaultlanguage == 'F') - { - printf - ("Caractère interdit trouvé dans le mot de passe (%d%s caractère).\n", - i + 1, makeordinal (i + 1)); - ladmin_log - ("Caractère interdit trouvé dans le nom du compte (%d%s caractère).\n", - i + 1, makeordinal (i + 1)); - } - else - { - printf - ("Illegal character found in the password (%d%s character).\n", - i + 1, makeordinal (i + 1)); - ladmin_log - ("Illegal character found in the password (%d%s character).\n", - i + 1, makeordinal (i + 1)); - } - return 0; - } - } - - if (strlen (password) < 4) - { - if (defaultlanguage == 'F') - { - printf - ("Nom du compte trop court. Entrez un nom de compte de 4-23 caractères.\n"); - ladmin_log - ("Nom du compte trop court. Entrez un nom de compte de 4-23 caractères.\n"); - } - else - { - printf - ("Account name is too short. Please input an account name of 4-23 bytes.\n"); - ladmin_log - ("Account name is too short. Please input an account name of 4-23 bytes.\n"); - } - return 0; - } - - if (strlen (password) > 23) - { - if (defaultlanguage == 'F') - { - printf - ("Mot de passe trop long. Entrez un mot de passe de 4-23 caractères.\n"); - ladmin_log - ("Mot de passe trop long. Entrez un mot de passe de 4-23 caractères.\n"); - } - else - { - printf - ("Password is too long. Please input a password of 4-23 bytes.\n"); - ladmin_log - ("Password is too long. Please input a password of 4-23 bytes.\n"); - } - return 0; - } - - return 1; -} - -//------------------------------------------------------------------ -// Sub-function: Check the name of a command (return complete name) -//----------------------------------------------------------------- -int check_command (char *command) -{ -// help - if (strncmp (command, "aide", 2) == 0 && strncmp (command, "aide", strlen (command)) == 0) // not 1 letter command: 'aide' or 'add'? - strcpy (command, "aide"); - else if (strncmp (command, "help", 1) == 0 - && strncmp (command, "help", strlen (command)) == 0) - strcpy (command, "help"); -// general commands - else if (strncmp (command, "add", 2) == 0 && strncmp (command, "add", strlen (command)) == 0) // not 1 letter command: 'aide' or 'add'? - strcpy (command, "add"); - else if ((strncmp (command, "ban", 3) == 0 - && strncmp (command, "ban", strlen (command)) == 0) - || (strncmp (command, "banish", 4) == 0 - && strncmp (command, "banish", strlen (command)) == 0)) - strcpy (command, "ban"); - else if ((strncmp (command, "banadd", 4) == 0 && strncmp (command, "banadd", strlen (command)) == 0) || // not 1 letter command: 'ba' or 'bs'? 'banadd' or 'banset' ? - strcmp (command, "ba") == 0) - strcpy (command, "banadd"); - else if ((strncmp (command, "banset", 4) == 0 && strncmp (command, "banset", strlen (command)) == 0) || // not 1 letter command: 'ba' or 'bs'? 'banadd' or 'banset' ? - strcmp (command, "bs") == 0) - strcpy (command, "banset"); - else if (strncmp (command, "block", 2) == 0 - && strncmp (command, "block", strlen (command)) == 0) - strcpy (command, "block"); - else if (strncmp (command, "check", 2) == 0 && strncmp (command, "check", strlen (command)) == 0) // not 1 letter command: 'check' or 'create'? - strcpy (command, "check"); - else if (strncmp (command, "create", 2) == 0 && strncmp (command, "create", strlen (command)) == 0) // not 1 letter command: 'check' or 'create'? - strcpy (command, "create"); - else if (strncmp (command, "delete", 1) == 0 - && strncmp (command, "delete", strlen (command)) == 0) - strcpy (command, "delete"); - else if ((strncmp (command, "email", 2) == 0 && strncmp (command, "email", strlen (command)) == 0) || // not 1 letter command: 'email', 'end' or 'exit'? - (strncmp (command, "e-mail", 2) == 0 - && strncmp (command, "e-mail", strlen (command)) == 0)) - strcpy (command, "email"); - else if (strncmp (command, "getcount", 2) == 0 && strncmp (command, "getcount", strlen (command)) == 0) // not 1 letter command: 'getcount' or 'gm'? - strcpy (command, "getcount"); -// else if (strncmp(command, "gm", 2) == 0 && strncmp(command, "gm", strlen(command)) == 0) // not 1 letter command: 'getcount' or 'gm'? -// strcpy(command, "gm"); -// else if (strncmp(command, "id", 2) == 0 && strncmp(command, "id", strlen(command)) == 0) // not 1 letter command: 'id' or 'info'? -// strcpy(command, "id"); - else if (strncmp (command, "info", 2) == 0 && strncmp (command, "info", strlen (command)) == 0) // not 1 letter command: 'id' or 'info'? - strcpy (command, "info"); -// else if (strncmp(command, "kami", 4) == 0 && strncmp(command, "kami", strlen(command)) == 0) // only all letters command: 'kami' or 'kamib'? -// strcpy(command, "kami"); -// else if (strncmp(command, "kamib", 5) == 0 && strncmp(command, "kamib", strlen(command)) == 0) // only all letters command: 'kami' or 'kamib'? -// strcpy(command, "kamib"); - else if ((strncmp (command, "language", 2) == 0 && strncmp (command, "language", strlen (command)) == 0)) // not 1 letter command: 'language' or 'list'? - strcpy (command, "language"); - else if ((strncmp (command, "list", 2) == 0 && strncmp (command, "list", strlen (command)) == 0) || // 'list' is default list command // not 1 letter command: 'language' or 'list'? - strcmp (command, "ls") == 0) - strcpy (command, "list"); - else if (strncmp (command, "itemfrob", 6) == 0) - strcpy (command, "itemfrob"); - else if ((strncmp (command, "listban", 5) == 0 - && strncmp (command, "listban", strlen (command)) == 0) - || (strncmp (command, "lsban", 3) == 0 - && strncmp (command, "lsban", strlen (command)) == 0) - || strcmp (command, "lb") == 0) - strcpy (command, "listban"); - else if ((strncmp (command, "listgm", 5) == 0 - && strncmp (command, "listgm", strlen (command)) == 0) - || (strncmp (command, "lsgm", 3) == 0 - && strncmp (command, "lsgm", strlen (command)) == 0) - || strcmp (command, "lg") == 0) - strcpy (command, "listgm"); - else if ((strncmp (command, "listok", 5) == 0 - && strncmp (command, "listok", strlen (command)) == 0) - || (strncmp (command, "lsok", 3) == 0 - && strncmp (command, "lsok", strlen (command)) == 0) - || strcmp (command, "lo") == 0) - strcpy (command, "listok"); - else if (strncmp (command, "memo", 1) == 0 - && strncmp (command, "memo", strlen (command)) == 0) - strcpy (command, "memo"); - else if (strncmp (command, "name", 1) == 0 - && strncmp (command, "name", strlen (command)) == 0) - strcpy (command, "name"); - else if ((strncmp (command, "password", 1) == 0 - && strncmp (command, "password", strlen (command)) == 0) - || strcmp (command, "passwd") == 0) - strcpy (command, "password"); - else if (strncmp (command, "reloadgm", 1) == 0 - && strncmp (command, "reloadgm", strlen (command)) == 0) - strcpy (command, "reloadgm"); - else if (strncmp (command, "search", 3) == 0 && strncmp (command, "search", strlen (command)) == 0) // not 1 letter command: 'search', 'state' or 'sex'? - strcpy (command, "search"); // not 2 letters command: 'search' or 'sex'? -// else if (strncmp(command, "sex", 3) == 0 && strncmp(command, "sex", strlen(command)) == 0) // not 1 letter command: 'search', 'state' or 'sex'? -// strcpy(command, "sex"); // not 2 letters command: 'search' or 'sex'? - else if (strncmp (command, "state", 2) == 0 && strncmp (command, "state", strlen (command)) == 0) // not 1 letter command: 'search', 'state' or 'sex'? - strcpy (command, "state"); - else if ((strncmp (command, "timeadd", 5) == 0 && strncmp (command, "timeadd", strlen (command)) == 0) || // not 1 letter command: 'ta' or 'ts'? 'timeadd' or 'timeset'? - strcmp (command, "ta") == 0) - strcpy (command, "timeadd"); - else if ((strncmp (command, "timeset", 5) == 0 && strncmp (command, "timeset", strlen (command)) == 0) || // not 1 letter command: 'ta' or 'ts'? 'timeadd' or 'timeset'? - strcmp (command, "ts") == 0) - strcpy (command, "timeset"); - else if ((strncmp (command, "unban", 5) == 0 - && strncmp (command, "unban", strlen (command)) == 0) - || (strncmp (command, "unbanish", 4) == 0 - && strncmp (command, "unbanish", strlen (command)) == 0)) - strcpy (command, "unban"); - else if (strncmp (command, "unblock", 4) == 0 - && strncmp (command, "unblock", strlen (command)) == 0) - strcpy (command, "unblock"); - else if (strncmp (command, "version", 1) == 0 - && strncmp (command, "version", strlen (command)) == 0) - strcpy (command, "version"); - else if (strncmp (command, "who", 1) == 0 - && strncmp (command, "who", strlen (command)) == 0) - strcpy (command, "who"); -// quit - else if (strncmp (command, "quit", 1) == 0 - && strncmp (command, "quit", strlen (command)) == 0) - strcpy (command, "quit"); - else if (strncmp (command, "exit", 2) == 0 && strncmp (command, "exit", strlen (command)) == 0) // not 1 letter command: 'email', 'end' or 'exit'? - strcpy (command, "exit"); - else if (strncmp (command, "end", 2) == 0 && strncmp (command, "end", strlen (command)) == 0) // not 1 letter command: 'email', 'end' or 'exit'? - strcpy (command, "end"); - - return 0; -} - -//----------------------------------------- -// Sub-function: Display commands of ladmin -//----------------------------------------- -void display_help (char *param, int language) -{ - char command[1023]; - int i; - - memset (command, '\0', sizeof (command)); - - if (sscanf (param, "%s ", command) < 1 || strlen (command) == 0) - strcpy (command, ""); // any value that is not a command - - if (command[0] == '?') - { - if (defaultlanguage == 'F') - strcpy (command, "aide"); - else - strcpy (command, "help"); - } - - // lowercase for command - for (i = 0; command[i]; i++) - command[i] = tolower (command[i]); - - // Analyse of the command - check_command (command); // give complete name to the command - - if (defaultlanguage == 'F') - { - ladmin_log ("Affichage des commandes ou d'une commande.\n"); - } - else - { - ladmin_log ("Displaying of the commands or a command.\n"); - } - - if (language == 1) - { - if (strcmp (command, "aide") == 0) - { - printf ("aide/help/?\n"); - printf (" Affiche la description des commandes\n"); - printf ("aide/help/? [commande]\n"); - printf (" Affiche la description de la commande specifiée\n"); - } - else if (strcmp (command, "help") == 0) - { - printf ("aide/help/?\n"); - printf (" Display the description of the commands\n"); - printf ("aide/help/? [command]\n"); - printf (" Display the description of the specified command\n"); -// general commands - } - else if (strcmp (command, "add") == 0) - { - printf ("add \n"); - printf (" Crée un compte avec l'email par défaut (a@a.com).\n"); - printf - (" Concernant le sexe, seule la première lettre compte (F ou M).\n"); - printf - (" L'e-mail est a@a.com (e-mail par défaut). C'est comme n'avoir aucun e-mail.\n"); - printf - (" Lorsque motdepasse est omis, la saisie se fait sans que la frappe se voit.\n"); - printf (" add testname Male testpass\n"); - } - else if (strcmp (command, "ban") == 0) - { - printf ("ban/banish aaaa/mm/jj hh:mm:ss \n"); - printf (" Change la date de fin de bannissement d'un compte.\n"); - printf (" Comme banset, mais est à la fin.\n"); - } - else if (strcmp (command, "banadd") == 0) - { - printf ("banadd \n"); - printf - (" Ajoute ou soustrait du temps à la date de banissement d'un compte.\n"); - printf (" Les modificateurs sont construits comme suit:\n"); - printf (" Valeur d'ajustement (-1, 1, +1, etc...)\n"); - printf (" Elément modifié:\n"); - printf (" a ou y: année\n"); - printf (" m: mois\n"); - printf (" j ou d: jour\n"); - printf (" h: heure\n"); - printf (" mn: minute\n"); - printf (" s: seconde\n"); - printf (" banadd testname +1m-2mn1s-6a\n"); - printf - (" Cette exemple ajoute 1 mois et une seconde, et soustrait 2 minutes\n"); - printf (" et 6 ans dans le même temps.\n"); - printf - ("NOTE: Si vous modifez la date de banissement d'un compte non bani,\n"); - printf - (" vous indiquez comme date (le moment actuel +- les ajustements)\n"); - } - else if (strcmp (command, "banset") == 0) - { - printf ("banset aaaa/mm/jj [hh:mm:ss]\n"); - printf (" Change la date de fin de bannissement d'un compte.\n"); - printf (" Heure par défaut [hh:mm:ss]: 23:59:59.\n"); - printf ("banset 0\n"); - printf (" Débanni un compte (0 = de-banni).\n"); - } - else if (strcmp (command, "block") == 0) - { - printf ("block \n"); - printf - (" Place le status d'un compte à 5 (You have been blocked by the GM Team).\n"); - printf - (" La commande est l'équivalent de state 5.\n"); - } - else if (strcmp (command, "check") == 0) - { - printf ("check \n"); - printf - (" Vérifie la validité d'un mot de passe pour un compte\n"); - printf (" NOTE: Le serveur n'enverra jamais un mot de passe.\n"); - printf - (" C'est la seule méthode que vous possédez pour savoir\n"); - printf - (" si un mot de passe est le bon. L'autre méthode est\n"); - printf - (" d'avoir un accès ('physique') au fichier des comptes.\n"); - } - else if (strcmp (command, "create") == 0) - { - printf ("create \n"); - printf (" Comme la commande add, mais avec l'e-mail en plus.\n"); - printf - (" create testname Male mon@mail.com testpass\n"); - } - else if (strcmp (command, "delete") == 0) - { - printf ("del \n"); - printf (" Supprime un compte.\n"); - printf - (" La commande demande confirmation. Après confirmation, le compte est détruit.\n"); - } - else if (strcmp (command, "email") == 0) - { - printf ("email \n"); - printf (" Modifie l'e-mail d'un compte.\n"); - } - else if (strcmp (command, "getcount") == 0) - { - printf ("getcount\n"); - printf - (" Donne le nombre de joueurs en ligne par serveur de char.\n"); - } - else if (strcmp (command, "gm") == 0) - { - printf ("gm [Niveau_GM]\n"); - printf (" Modifie le niveau de GM d'un compte.\n"); - printf - (" Valeur par défaut: 0 (suppression du niveau de GM).\n"); - printf (" gm nomtest 80\n"); - } - else if (strcmp (command, "id") == 0) - { - printf ("id \n"); - printf (" Donne l'id d'un compte.\n"); - } - else if (strcmp (command, "info") == 0) - { - printf ("info \n"); - printf (" Affiche les informations sur un compte.\n"); - } - else if (strcmp (command, "kami") == 0) - { - printf ("kami \n"); - printf - (" Envoi un message général sur tous les serveurs de map (en jaune).\n"); - } - else if (strcmp (command, "kamib") == 0) - { - printf ("kamib \n"); - printf - (" Envoi un message général sur tous les serveurs de map (en bleu).\n"); - } - else if (strcmp (command, "language") == 0) - { - printf ("language \n"); - printf (" Change la langue d'affichage.\n"); - printf (" Langues possibles: 'Français' ou 'English'.\n"); - } - else if (strcmp (command, "list") == 0) - { - printf ("list/ls [Premier_id [Dernier_id]]\n"); - printf (" Affiche une liste de comptes.\n"); - printf - (" 'Premier_id', 'Dernier_id': indique les identifiants de départ et de fin.\n"); - printf - (" La recherche par nom n'est pas possible avec cette commande.\n"); - printf (" list 10 9999999\n"); - } - else if (strcmp (command, "itemfrob") == 0) - { - printf ("Not localised yet.\n"); - } - else if (strcmp (command, "listban") == 0) - { - printf ("listBan/lsBan [Premier_id [Dernier_id]]\n"); - printf - (" Comme list/ls, mais seulement pour les comptes avec statut ou bannis.\n"); - } - else if (strcmp (command, "listgm") == 0) - { - printf ("listGM/lsGM [Premier_id [Dernier_id]]\n"); - printf (" Comme list/ls, mais seulement pour les comptes GM.\n"); - } - else if (strcmp (command, "listok") == 0) - { - printf ("listOK/lsOK [Premier_id [Dernier_id]]\n"); - printf - (" Comme list/ls, mais seulement pour les comptes sans statut et non bannis.\n"); - } - else if (strcmp (command, "memo") == 0) - { - printf ("memo \n"); - printf (" Modifie le mémo d'un compte.\n"); - printf - (" 'memo': Il peut avoir jusqu'à 253 caractères (avec des espaces ou non).\n"); - } - else if (strcmp (command, "name") == 0) - { - printf ("name \n"); - printf (" Donne le nom d'un compte.\n"); - } - else if (strcmp (command, "password") == 0) - { - printf ("passwd \n"); - printf (" Change le mot de passe d'un compte.\n"); - printf (" Lorsque nouveaumotdepasse est omis,\n"); - printf (" la saisie se fait sans que la frappe ne se voit.\n"); - } - else if (strcmp (command, "reloadgm") == 0) - { - printf ("reloadGM\n"); - printf (" Reload GM configuration file\n"); - } - else if (strcmp (command, "search") == 0) - { - printf ("search \n"); - printf (" Cherche des comptes.\n"); - printf (" Affiche les comptes dont les noms correspondent.\n"); -// printf("search -r/-e/--expr/--regex \n"); -// printf(" Cherche des comptes par expression regulière.\n"); -// printf(" Affiche les comptes dont les noms correspondent.\n"); - } - else if (strcmp (command, "sex") == 0) - { - printf ("sex \n"); - printf (" Modifie le sexe d'un compte.\n"); - printf (" sex testname Male\n"); - } - else if (strcmp (command, "state") == 0) - { - printf ("state \n"); - printf (" Change le statut d'un compte.\n"); - printf - (" 'nouveaustatut': Le statut est le même que celui du packet 0x006a + 1.\n"); - printf (" les possibilités sont:\n"); - printf (" 0 = Compte ok\n"); - printf (" 1 = Unregistered ID\n"); - printf (" 2 = Incorrect Password\n"); - printf (" 3 = This ID is expired\n"); - printf (" 4 = Rejected from Server\n"); - printf - (" 5 = You have been blocked by the GM Team\n"); - printf - (" 6 = Your Game's EXE file is not the latest version\n"); - printf - (" 7 = You are Prohibited to log in until...\n"); - printf - (" 8 = Server is jammed due to over populated\n"); - printf (" 9 = No MSG\n"); - printf (" 100 = This ID has been totally erased\n"); - printf - (" all other values are 'No MSG', then use state 9 please.\n"); - printf (" 'message_erreur_7': message du code erreur 6 =\n"); - printf - (" = Your are Prohibited to log in until... (packet 0x006a)\n"); - } - else if (strcmp (command, "timeadd") == 0) - { - printf ("timeadd \n"); - printf - (" Ajoute/soustrait du temps à la limite de validité d'un compte.\n"); - printf (" Le modificateur est composé comme suit:\n"); - printf (" Valeur modificatrice (-1, 1, +1, etc...)\n"); - printf (" Elément modifié:\n"); - printf (" a ou y: année\n"); - printf (" m: mois\n"); - printf (" j ou d: jour\n"); - printf (" h: heure\n"); - printf (" mn: minute\n"); - printf (" s: seconde\n"); - printf (" timeadd testname +1m-2mn1s-6a\n"); - printf - (" Cette exemple ajoute 1 mois et une seconde, et soustrait 2 minutes\n"); - printf (" et 6 ans dans le même temps.\n"); - printf - ("NOTE: Vous ne pouvez pas modifier une limite de validité illimitée. Si vous\n"); - printf - (" désirez le faire, c'est que vous voulez probablement créer un limite de\n"); - printf - (" validité limitée. Donc, en premier, fixé une limite de valitidé.\n"); - } - else if (strcmp (command, "timeadd") == 0) - { - printf ("timeset aaaa/mm/jj [hh:mm:ss]\n"); - printf (" Change la limite de validité d'un compte.\n"); - printf (" Heure par défaut [hh:mm:ss]: 23:59:59.\n"); - printf ("timeset 0\n"); - printf - (" Donne une limite de validité illimitée (0 = illimitée).\n"); - } - else if (strcmp (command, "unban") == 0) - { - printf ("unban/unbanish \n"); - printf (" Ote le banissement d'un compte.\n"); - printf - (" La commande est l'équivalent de banset 0.\n"); - } - else if (strcmp (command, "unblock") == 0) - { - printf ("unblock \n"); - printf (" Place le status d'un compte à 0 (Compte ok).\n"); - printf - (" La commande est l'équivalent de state 0.\n"); - } - else if (strcmp (command, "version") == 0) - { - printf ("version\n"); - printf (" Affiche la version du login-serveur.\n"); - } - else if (strcmp (command, "who") == 0) - { - printf ("who \n"); - printf (" Affiche les informations sur un compte.\n"); -// quit - } - else if (strcmp (command, "quit") == 0 || - strcmp (command, "exit") == 0 || - strcmp (command, "end") == 0) - { - printf ("quit/end/exit\n"); - printf (" Fin du programme d'administration.\n"); -// unknown command - } - else - { - if (strlen (command) > 0) - printf - ("Commande inconnue [%s] pour l'aide. Affichage de toutes les commandes.\n", - command); - printf - (" aide/help/? -- Affiche cet aide\n"); - printf - (" aide/help/? [commande] -- Affiche l'aide de la commande\n"); - printf - (" add -- Crée un compte (sans email)\n"); - printf - (" ban/banish aaaa/mm/jj hh:mm:ss -- Fixe la date finale de banismnt\n"); - printf - (" banadd/ba -- Ajout/soustrait du temps à la\n"); - printf - (" exemple: ba moncompte +1m-2mn1s-2y date finale de banissement\n"); - printf - (" banset/bs aaaa/mm/jj [hh:mm:ss] -- Change la date fin de banisemnt\n"); - printf - (" banset/bs 0 -- Dé-banis un compte.\n"); - printf - (" block -- Mets le status d'un compte à 5 (blocked by the GM Team)\n"); - printf - (" check -- Vérifie un mot de passe d'un compte\n"); - printf - (" create -- Crée un compte (avec email)\n"); - printf - (" del -- Supprime un compte\n"); - printf - (" email -- Modifie l'e-mail d'un compte\n"); - printf - (" getcount -- Donne le nb de joueurs en ligne\n"); - printf - (" gm [Niveau_GM] -- Modifie le niveau de GM d'un compte\n"); - printf - (" id -- Donne l'id d'un compte\n"); - printf - (" info -- Affiche les infos sur un compte\n"); - printf - (" kami -- Envoi un message général (en jaune)\n"); - printf - (" kamib -- Envoi un message général (en bleu)\n"); - printf - (" language -- Change la langue d'affichage.\n"); - printf - (" list/ls [Premier_id [Dernier_id] ] -- Affiche une liste de comptes\n"); - printf - (" listBan/lsBan [Premier_id [Dernier_id] ] -- Affiche une liste de comptes\n"); - printf - (" avec un statut ou bannis\n"); - printf - (" listGM/lsGM [Premier_id [Dernier_id] ] -- Affiche une liste de comptes GM\n"); - printf - (" listOK/lsOK [Premier_id [Dernier_id] ] -- Affiche une liste de comptes\n"); - printf - (" sans status et non bannis\n"); - printf - (" memo -- Modifie le memo d'un compte\n"); - printf - (" name -- Donne le nom d'un compte\n"); - printf - (" passwd -- Change le mot de passe d'un compte\n"); - printf - (" quit/end/exit -- Fin du programme d'administation\n"); - printf - (" reloadGM -- Recharger le fichier de config des GM\n"); - printf - (" search -- Cherche des comptes\n"); -// printf(" search -e/-r/--expr/--regex -- Cherche des comptes par REGEX\n"); - printf - (" sex -- Modifie le sexe d'un compte\n"); - printf - (" state -- Change le statut d'1 compte\n"); - printf - (" timeadd/ta -- Ajout/soustrait du temps à la\n"); - printf - (" exemple: ta moncompte +1m-2mn1s-2y limite de validité\n"); - printf - (" timeset/ts aaaa/mm/jj [hh:mm:ss] -- Change la limite de validité\n"); - printf - (" timeset/ts 0 -- limite de validité = illimitée\n"); - printf - (" unban/unbanish -- Ote le banissement d'un compte\n"); - printf - (" unblock -- Mets le status d'un compte à 0 (Compte ok)\n"); - printf - (" version -- Donne la version du login-serveur\n"); - printf - (" who -- Affiche les infos sur un compte\n"); - printf - (" Note: Pour les noms de compte avec des espaces, tapez \"\" (ou ').\n"); - } - } - else - { - if (strcmp (command, "aide") == 0) - { - printf ("aide/help/?\n"); - printf (" Display the description of the commands\n"); - printf ("aide/help/? [command]\n"); - printf (" Display the description of the specified command\n"); - } - else if (strcmp (command, "help") == 0) - { - printf ("aide/help/?\n"); - printf (" Display the description of the commands\n"); - printf ("aide/help/? [command]\n"); - printf (" Display the description of the specified command\n"); -// general commands - } - else if (strcmp (command, "add") == 0) - { - printf ("add \n"); - printf - (" Create an account with the default email (a@a.com).\n"); - printf - (" Concerning the sex, only the first letter is used (F or M).\n"); - printf - (" The e-mail is set to a@a.com (default e-mail). It's like to have no e-mail.\n"); - printf (" When the password is omitted,\n"); - printf - (" the input is done without displaying of the pressed keys.\n"); - printf (" add testname Male testpass\n"); - } - else if (strcmp (command, "ban") == 0) - { - printf ("ban/banish yyyy/mm/dd hh:mm:ss \n"); - printf - (" Changes the final date of a banishment of an account.\n"); - printf (" Like banset, but is at end.\n"); - } - else if (strcmp (command, "banadd") == 0) - { - printf ("banadd \n"); - printf - (" Adds or substracts time from the final date of a banishment of an account.\n"); - printf (" Modifier is done as follows:\n"); - printf (" Adjustment value (-1, 1, +1, etc...)\n"); - printf (" Modified element:\n"); - printf (" a or y: year\n"); - printf (" m: month\n"); - printf (" j or d: day\n"); - printf (" h: hour\n"); - printf (" mn: minute\n"); - printf (" s: second\n"); - printf (" banadd testname +1m-2mn1s-6y\n"); - printf - (" this example adds 1 month and 1 second, and substracts 2 minutes\n"); - printf (" and 6 years at the same time.\n"); - printf - ("NOTE: If you modify the final date of a non-banished account,\n"); - printf - (" you fix the final date to (actual time +- adjustments)\n"); - } - else if (strcmp (command, "banset") == 0) - { - printf ("banset yyyy/mm/dd [hh:mm:ss]\n"); - printf - (" Changes the final date of a banishment of an account.\n"); - printf (" Default time [hh:mm:ss]: 23:59:59.\n"); - printf ("banset 0\n"); - printf (" Set a non-banished account (0 = unbanished).\n"); - } - else if (strcmp (command, "block") == 0) - { - printf ("block \n"); - printf - (" Set state 5 (You have been blocked by the GM Team) to an account.\n"); - printf (" This command works like state 5.\n"); - } - else if (strcmp (command, "check") == 0) - { - printf ("check \n"); - printf (" Check the validity of a password for an account.\n"); - printf (" NOTE: Server will never sends back a password.\n"); - printf - (" It's the only method you have to know if a password is correct.\n"); - printf - (" The other method is to have a ('physical') access to the accounts file.\n"); - } - else if (strcmp (command, "create") == 0) - { - printf ("create \n"); - printf (" Like the 'add' command, but with e-mail moreover.\n"); - printf - (" create testname Male my@mail.com testpass\n"); - } - else if (strcmp (command, "delete") == 0) - { - printf ("del \n"); - printf (" Remove an account.\n"); - printf - (" This order requires confirmation. After confirmation, the account is deleted.\n"); - } - else if (strcmp (command, "email") == 0) - { - printf ("email \n"); - printf (" Modify the e-mail of an account.\n"); - } - else if (strcmp (command, "getcount") == 0) - { - printf ("getcount\n"); - printf - (" Give the number of players online on all char-servers.\n"); - } - else if (strcmp (command, "gm") == 0) - { - printf ("gm [GM_level]\n"); - printf (" Modify the GM level of an account.\n"); - printf (" Default value remove GM level (GM level = 0).\n"); - printf (" gm testname 80\n"); - } - else if (strcmp (command, "id") == 0) - { - printf ("id \n"); - printf (" Give the id of an account.\n"); - } - else if (strcmp (command, "info") == 0) - { - printf ("info \n"); - printf (" Display complete information of an account.\n"); - } - else if (strcmp (command, "kami") == 0) - { - printf ("kami \n"); - printf - (" Sends a broadcast message on all map-server (in yellow).\n"); - } - else if (strcmp (command, "kamib") == 0) - { - printf ("kamib \n"); - printf - (" Sends a broadcast message on all map-server (in blue).\n"); - } - else if (strcmp (command, "language") == 0) - { - printf ("language \n"); - printf (" Change the language of displaying.\n"); - printf (" Possible languages: Français or English.\n"); - } - else if (strcmp (command, "list") == 0) - { - printf ("list/ls [start_id [end_id]]\n"); - printf (" Display a list of accounts.\n"); - printf - (" 'start_id', 'end_id': indicate end and start identifiers.\n"); - printf - (" Research by name is not possible with this command.\n"); - printf (" list 10 9999999\n"); - } - else if (strcmp (command, "itemfrob") == 0) - { - printf ("itemfrob \n"); - printf (" Translates item IDs for all accounts.\n"); - printf - (" Any items matching the source item ID will be mapped to the dest-id.\n"); - printf (" itemfrob 500 700\n"); - } - else if (strcmp (command, "listban") == 0) - { - printf ("listBan/lsBan [start_id [end_id]]\n"); - printf - (" Like list/ls, but only for accounts with state or banished.\n"); - } - else if (strcmp (command, "listgm") == 0) - { - printf ("listGM/lsGM [start_id [end_id]]\n"); - printf (" Like list/ls, but only for GM accounts.\n"); - } - else if (strcmp (command, "listok") == 0) - { - printf ("listOK/lsOK [start_id [end_id]]\n"); - printf - (" Like list/ls, but only for accounts without state and not banished.\n"); - } - else if (strcmp (command, "memo") == 0) - { - printf ("memo \n"); - printf (" Modify the memo of an account.\n"); - printf - (" 'memo': it can have until 253 characters (with spaces or not).\n"); - } - else if (strcmp (command, "name") == 0) - { - printf ("name \n"); - printf (" Give the name of an account.\n"); - } - else if (strcmp (command, "password") == 0) - { - printf ("passwd \n"); - printf (" Change the password of an account.\n"); - printf (" When new password is omitted,\n"); - printf - (" the input is done without displaying of the pressed keys.\n"); - } - else if (strcmp (command, "reloadgm") == 0) - { - printf ("reloadGM\n"); - printf (" Reload GM configuration file\n"); - } - else if (strcmp (command, "search") == 0) - { - printf ("search \n"); - printf (" Seek accounts.\n"); - printf (" Displays the accounts whose names correspond.\n"); -// printf("search -r/-e/--expr/--regex \n"); -// printf(" Seek accounts by regular expression.\n"); -// printf(" Displays the accounts whose names correspond.\n"); - } - else if (strcmp (command, "sex") == 0) - { - printf ("sex \n"); - printf (" Modify the sex of an account.\n"); - printf (" sex testname Male\n"); - } - else if (strcmp (command, "state") == 0) - { - printf ("state \n"); - printf (" Change the state of an account.\n"); - printf - (" 'new_state': state is the state of the packet 0x006a + 1.\n"); - printf (" The possibilities are:\n"); - printf (" 0 = Account ok\n"); - printf (" 1 = Unregistered ID\n"); - printf (" 2 = Incorrect Password\n"); - printf (" 3 = This ID is expired\n"); - printf (" 4 = Rejected from Server\n"); - printf - (" 5 = You have been blocked by the GM Team\n"); - printf - (" 6 = Your Game's EXE file is not the latest version\n"); - printf - (" 7 = You are Prohibited to log in until...\n"); - printf - (" 8 = Server is jammed due to over populated\n"); - printf (" 9 = No MSG\n"); - printf (" 100 = This ID has been totally erased\n"); - printf - (" all other values are 'No MSG', then use state 9 please.\n"); - printf (" 'error_message_#7': message of the code error 6\n"); - printf - (" = Your are Prohibited to log in until... (packet 0x006a)\n"); - } - else if (strcmp (command, "timeadd") == 0) - { - printf ("timeadd \n"); - printf - (" Adds or substracts time from the validity limit of an account.\n"); - printf (" Modifier is done as follows:\n"); - printf (" Adjustment value (-1, 1, +1, etc...)\n"); - printf (" Modified element:\n"); - printf (" a or y: year\n"); - printf (" m: month\n"); - printf (" j or d: day\n"); - printf (" h: hour\n"); - printf (" mn: minute\n"); - printf (" s: second\n"); - printf (" timeadd testname +1m-2mn1s-6y\n"); - printf - (" this example adds 1 month and 1 second, and substracts 2 minutes\n"); - printf (" and 6 years at the same time.\n"); - printf ("NOTE: You can not modify a unlimited validity limit.\n"); - printf - (" If you want modify it, you want probably create a limited validity limit.\n"); - printf - (" So, at first, you must set the validity limit to a date/time.\n"); - } - else if (strcmp (command, "timeadd") == 0) - { - printf ("timeset yyyy/mm/dd [hh:mm:ss]\n"); - printf (" Changes the validity limit of an account.\n"); - printf (" Default time [hh:mm:ss]: 23:59:59.\n"); - printf ("timeset 0\n"); - printf (" Gives an unlimited validity limit (0 = unlimited).\n"); - } - else if (strcmp (command, "unban") == 0) - { - printf ("unban/unbanish \n"); - printf (" Remove the banishment of an account.\n"); - printf (" This command works like banset 0.\n"); - } - else if (strcmp (command, "unblock") == 0) - { - printf ("unblock \n"); - printf (" Set state 0 (Account ok) to an account.\n"); - printf (" This command works like state 0.\n"); - } - else if (strcmp (command, "version") == 0) - { - printf ("version\n"); - printf (" Display the version of the login-server.\n"); - } - else if (strcmp (command, "who") == 0) - { - printf ("who \n"); - printf (" Displays complete information of an account.\n"); -// quit - } - else if (strcmp (command, "quit") == 0 || - strcmp (command, "exit") == 0 || - strcmp (command, "end") == 0) - { - printf ("quit/end/exit\n"); - printf (" End of the program of administration.\n"); -// unknown command - } - else - { - if (strlen (command) > 0) - printf - ("Unknown command [%s] for help. Displaying of all commands.\n", - command); - printf - (" aide/help/? -- Display this help\n"); - printf - (" aide/help/? [command] -- Display the help of the command\n"); - printf - (" add -- Create an account with default email\n"); - printf - (" ban/banish yyyy/mm/dd hh:mm:ss -- Change final date of a ban\n"); - printf - (" banadd/ba -- Add or substract time from the final\n"); - printf - (" example: ba apple +1m-2mn1s-2y date of a banishment of an account\n"); - printf - (" banset/bs yyyy/mm/dd [hh:mm:ss] -- Change final date of a ban\n"); - printf - (" banset/bs 0 -- Un-banish an account\n"); - printf - (" block -- Set state 5 (blocked by the GM Team) to an account\n"); - printf - (" check -- Check the validity of a password\n"); - printf - (" create -- Create an account with email\n"); - printf - (" del -- Remove an account\n"); - printf - (" email -- Modify an email of an account\n"); - printf - (" getcount -- Give the number of players online\n"); - printf - (" gm [GM_level] -- Modify the GM level of an account\n"); - printf - (" id -- Give the id of an account\n"); - printf - (" info -- Display all information of an account\n"); - printf - (" itemfrob -- Map all items from one item ID to another\n"); - printf - (" kami -- Sends a broadcast message (in yellow)\n"); - printf - (" kamib -- Sends a broadcast message (in blue)\n"); - printf - (" language -- Change the language of displaying.\n"); - printf - (" list/ls [First_id [Last_id]] -- Display a list of accounts\n"); - printf - (" listBan/lsBan [First_id [Last_id] ] -- Display a list of accounts\n"); - printf - (" with state or banished\n"); - printf - (" listGM/lsGM [First_id [Last_id]] -- Display a list of GM accounts\n"); - printf - (" listOK/lsOK [First_id [Last_id] ] -- Display a list of accounts\n"); - printf - (" without state and not banished\n"); - printf - (" memo -- Modify the memo of an account\n"); - printf - (" name -- Give the name of an account\n"); - printf - (" passwd -- Change the password of an account\n"); - printf - (" quit/end/exit -- End of the program of administation\n"); - printf - (" reloadGM -- Reload GM configuration file\n"); - printf - (" search -- Seek accounts\n"); -// printf(" search -e/-r/--expr/--regex -- Seek accounts by regular-expression\n"); - printf - (" sex -- Modify the sex of an account\n"); - printf - (" state -- Change the state\n"); - printf - (" timeadd/ta -- Add or substract time from the\n"); - printf - (" example: ta apple +1m-2mn1s-2y validity limit of an account\n"); - printf - (" timeset/ts yyyy/mm/dd [hh:mm:ss] -- Change the validify limit\n"); - printf - (" timeset/ts 0 -- Give a unlimited validity limit\n"); - printf - (" unban/unbanish -- Remove the banishment of an account\n"); - printf - (" unblock -- Set state 0 (Account ok) to an account\n"); - printf - (" version -- Gives the version of the login-server\n"); - printf - (" who -- Display all information of an account\n"); - printf - (" who -- Display all information of an account\n"); - printf - (" Note: To use spaces in an account name, type \"\" (or ').\n"); - } - } -} - -//----------------------------- -// Sub-function: add an account -//----------------------------- -int addaccount (char *param, int emailflag) -{ - char name[1023], sex[1023], email[1023], password[1023]; -// int i; - - memset (name, '\0', sizeof (name)); - memset (sex, '\0', sizeof (sex)); - memset (email, '\0', sizeof (email)); - memset (password, '\0', sizeof (password)); - - if (emailflag == 0) - { // add command - if (sscanf (param, "\"%[^\"]\" %s %[^\r\n]", name, sex, password) < 2 && // password can be void - sscanf (param, "'%[^']' %s %[^\r\n]", name, sex, password) < 2 && // password can be void - sscanf (param, "%s %s %[^\r\n]", name, sex, password) < 2) - { // password can be void - if (defaultlanguage == 'F') - { - printf - ("Entrez un nom de compte, un sexe et un mot de passe svp.\n"); - printf (" add nomtest Male motdepassetest\n"); - ladmin_log - ("Nombre incorrect de paramètres pour créer un compte (commande 'add').\n"); - } - else - { - printf - ("Please input an account name, a sex and a password.\n"); - printf (" add testname Male testpass\n"); - ladmin_log - ("Incomplete parameters to create an account ('add' command).\n"); - } - return 136; - } - strcpy (email, "a@a.com"); // default email - } - else - { // 1: create command - if (sscanf (param, "\"%[^\"]\" %s %s %[^\r\n]", name, sex, email, password) < 3 && // password can be void - sscanf (param, "'%[^']' %s %s %[^\r\n]", name, sex, email, password) < 3 && // password can be void - sscanf (param, "%s %s %s %[^\r\n]", name, sex, email, - password) < 3) - { // password can be void - if (defaultlanguage == 'F') - { - printf - ("Entrez un nom de compte, un sexe et un mot de passe svp.\n"); - printf - (" create nomtest Male mo@mail.com motdepassetest\n"); - ladmin_log - ("Nombre incorrect de paramètres pour créer un compte (commande 'create').\n"); - } - else - { - printf - ("Please input an account name, a sex and a password.\n"); - printf - (" create testname Male my@mail.com testpass\n"); - ladmin_log - ("Incomplete parameters to create an account ('create' command).\n"); - } - return 136; - } - } - if (verify_accountname (name) == 0) - { - return 102; - } - -/* for(i = 0; name[i]; i++) { - if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_", name[i]) == NULL) { - if (defaultlanguage == 'F') { - printf("Caractère interdit (%c) trouvé dans le nom du compte (%d%s caractère).\n", name[i], i+1, makeordinal(i+1)); - ladmin_log("Caractère interdit (%c) trouvé dans le nom du compte (%d%s caractère).\n", name[i], i+1, makeordinal(i+1)); - } else { - printf("Illegal character (%c) found in the account name (%d%s character).\n", name[i], i+1, makeordinal(i+1)); - ladmin_log("Illegal character (%c) found in the account name (%d%s character).\n", name[i], i+1, makeordinal(i+1)); - } - return 101; - } - }*/ - - sex[0] = toupper (sex[0]); - if (strchr ("MF", sex[0]) == NULL) - { - if (defaultlanguage == 'F') - { - printf ("Sexe incorrect [%s]. Entrez M ou F svp.\n", sex); - ladmin_log ("Sexe incorrect [%s]. Entrez M ou F svp.\n", - sex); - } - else - { - printf ("Illegal gender [%s]. Please input M or F.\n", sex); - ladmin_log ("Illegal gender [%s]. Please input M or F.\n", - sex); - } - return 103; - } - - if (strlen (email) < 3) - { - if (defaultlanguage == 'F') - { - printf ("Email trop courte [%s]. Entrez une e-mail valide svp.\n", - email); - ladmin_log - ("Email trop courte [%s]. Entrez une e-mail valide svp.\n", - email); - } - else - { - printf ("Email is too short [%s]. Please input a valid e-mail.\n", - email); - ladmin_log - ("Email is too short [%s]. Please input a valid e-mail.\n", - email); - } - return 109; - } - if (strlen (email) > 39) - { - if (defaultlanguage == 'F') - { - printf - ("Email trop longue [%s]. Entrez une e-mail de 39 caractères maximum svp.\n", - email); - ladmin_log - ("Email trop longue [%s]. Entrez une e-mail de 39 caractères maximum svp.\n", - email); - } - else - { - printf - ("Email is too long [%s]. Please input an e-mail with 39 bytes at the most.\n", - email); - ladmin_log - ("Email is too long [%s]. Please input an e-mail with 39 bytes at the most.\n", - email); - } - return 109; - } - if (e_mail_check (email) == 0) - { - if (defaultlanguage == 'F') - { - printf ("Email incorrecte [%s]. Entrez une e-mail valide svp.\n", - email); - ladmin_log ("Email incorrecte [%s]. Entrez une e-mail valide svp.\n", - email); - } - else - { - printf ("Invalid email [%s]. Please input a valid e-mail.\n", - email); - ladmin_log ("Invalid email [%s]. Please input a valid e-mail.\n", - email); - } - return 109; - } - - if (strlen (password) == 0) - { - if (typepasswd (password) == 0) - return 108; - } - if (verify_password (password) == 0) - return 104; - - if (defaultlanguage == 'F') - { - ladmin_log - ("Envoi d'un requête au serveur de logins pour créer un compte.\n"); - } - else - { - ladmin_log ("Request to login-server to create an account.\n"); - } - - WFIFOW (login_fd, 0) = 0x7930; - memcpy (WFIFOP (login_fd, 2), name, 24); - memcpy (WFIFOP (login_fd, 26), password, 24); - WFIFOB (login_fd, 50) = sex[0]; - memcpy (WFIFOP (login_fd, 51), email, 40); - WFIFOSET (login_fd, 91); - bytes_to_read = 1; - - return 0; -} - -//--------------------------------------------------------------------------------- -// Sub-function: Add/substract time to the final date of a banishment of an account -//--------------------------------------------------------------------------------- -int banaddaccount (char *param) -{ - char name[1023], modif[1023]; - int year, month, day, hour, minute, second; - char *p_modif; - int value, i; - - memset (name, '\0', sizeof (name)); - memset (modif, '\0', sizeof (modif)); - year = month = day = hour = minute = second = 0; - - if (sscanf (param, "\"%[^\"]\" %[^\r\n]", name, modif) < 2 && - sscanf (param, "'%[^']' %[^\r\n]", name, modif) < 2 && - sscanf (param, "%s %[^\r\n]", name, modif) < 2) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un nom de compte et un modificateur svp.\n"); - printf (" banadd nomtest +1m-2mn1s-6y\n"); - printf - (" Cette exemple ajoute 1 mois et 1 seconde, et soustrait 2 minutes\n"); - printf (" et 6 ans dans le même temps.\n"); - ladmin_log - ("Nombre incorrect de paramètres pour modifier la fin de ban d'un compte (commande 'banadd').\n"); - } - else - { - printf ("Please input an account name and a modifier.\n"); - printf (" : banadd testname +1m-2mn1s-6y\n"); - printf - (" this example adds 1 month and 1 second, and substracts 2 minutes\n"); - printf (" and 6 years at the same time.\n"); - ladmin_log - ("Incomplete parameters to modify the ban date/time of an account ('banadd' command).\n"); - } - return 136; - } - if (verify_accountname (name) == 0) - { - return 102; - } - - // lowercase for modif - for (i = 0; modif[i]; i++) - modif[i] = tolower (modif[i]); - p_modif = modif; - while (strlen (p_modif) > 0) - { - value = atoi (p_modif); - if (value == 0) - { - p_modif++; - } - else - { - if (p_modif[0] == '-' || p_modif[0] == '+') - p_modif++; - while (strlen (p_modif) > 0 && p_modif[0] >= '0' - && p_modif[0] <= '9') - { - p_modif++; - } - if (p_modif[0] == 's') - { - second = value; - p_modif++; - } - else if (p_modif[0] == 'm' && p_modif[1] == 'n') - { - minute = value; - p_modif += 2; - } - else if (p_modif[0] == 'h') - { - hour = value; - p_modif++; - } - else if (p_modif[0] == 'd' || p_modif[0] == 'j') - { - day = value; - p_modif += 2; - } - else if (p_modif[0] == 'm') - { - month = value; - p_modif++; - } - else if (p_modif[0] == 'y' || p_modif[0] == 'a') - { - year = value; - p_modif++; - } - else - { - p_modif++; - } - } - } - - if (defaultlanguage == 'F') - { - printf (" année: %d\n", year); - printf (" mois: %d\n", month); - printf (" jour: %d\n", day); - printf (" heure: %d\n", hour); - printf (" minute: %d\n", minute); - printf (" seconde: %d\n", second); - } - else - { - printf (" year: %d\n", year); - printf (" month: %d\n", month); - printf (" day: %d\n", day); - printf (" hour: %d\n", hour); - printf (" minute: %d\n", minute); - printf (" second: %d\n", second); - } - - if (year == 0 && month == 0 && day == 0 && hour == 0 && minute == 0 - && second == 0) - { - if (defaultlanguage == 'F') - { - printf - ("Vous devez entrer un ajustement avec cette commande, svp:\n"); - printf (" Valeur d'ajustement (-1, 1, +1, etc...)\n"); - printf (" Element modifié:\n"); - printf (" a ou y: année\n"); - printf (" m: mois\n"); - printf (" j ou d: jour\n"); - printf (" h: heure\n"); - printf (" mn: minute\n"); - printf (" s: seconde\n"); - printf (" banadd nomtest +1m-2mn1s-6y\n"); - printf - (" Cette exemple ajoute 1 mois et 1 seconde, et soustrait 2 minutes\n"); - printf (" et 6 ans dans le même temps.\n"); - ladmin_log - ("Aucun ajustement n'est pas un ajustement (commande 'banadd').\n"); - } - else - { - printf ("Please give an adjustment with this command:\n"); - printf (" Adjustment value (-1, 1, +1, etc...)\n"); - printf (" Modified element:\n"); - printf (" a or y: year\n"); - printf (" m: month\n"); - printf (" j or d: day\n"); - printf (" h: hour\n"); - printf (" mn: minute\n"); - printf (" s: second\n"); - printf (" banadd testname +1m-2mn1s-6y\n"); - printf - (" this example adds 1 month and 1 second, and substracts 2 minutes\n"); - printf (" and 6 years at the same time.\n"); - ladmin_log - ("No adjustment isn't an adjustment ('banadd' command).\n"); - } - return 137; - } - if (year > 127 || year < -127) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez un ajustement d'années correct (de -127 à 127), svp.\n"); - ladmin_log - ("Ajustement de l'année hors norme (commande 'banadd').\n"); - } - else - { - printf - ("Please give a correct adjustment for the years (from -127 to 127).\n"); - ladmin_log - ("Abnormal adjustement for the year ('banadd' command).\n"); - } - return 137; - } - if (month > 255 || month < -255) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez un ajustement de mois correct (de -255 à 255), svp.\n"); - ladmin_log ("Ajustement du mois hors norme (commande 'banadd').\n"); - } - else - { - printf - ("Please give a correct adjustment for the months (from -255 to 255).\n"); - ladmin_log - ("Abnormal adjustement for the month ('banadd' command).\n"); - } - return 137; - } - if (day > 32767 || day < -32767) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez un ajustement de jours correct (de -32767 à 32767), svp.\n"); - ladmin_log ("Ajustement des jours hors norme (commande 'banadd').\n"); - } - else - { - printf - ("Please give a correct adjustment for the days (from -32767 to 32767).\n"); - ladmin_log - ("Abnormal adjustement for the days ('banadd' command).\n"); - } - return 137; - } - if (hour > 32767 || hour < -32767) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez un ajustement d'heures correct (de -32767 à 32767), svp.\n"); - ladmin_log - ("Ajustement des heures hors norme (commande 'banadd').\n"); - } - else - { - printf - ("Please give a correct adjustment for the hours (from -32767 to 32767).\n"); - ladmin_log - ("Abnormal adjustement for the hours ('banadd' command).\n"); - } - return 137; - } - if (minute > 32767 || minute < -32767) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez un ajustement de minutes correct (de -32767 à 32767), svp.\n"); - ladmin_log - ("Ajustement des minutes hors norme (commande 'banadd').\n"); - } - else - { - printf - ("Please give a correct adjustment for the minutes (from -32767 to 32767).\n"); - ladmin_log - ("Abnormal adjustement for the minutes ('banadd' command).\n"); - } - return 137; - } - if (second > 32767 || second < -32767) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez un ajustement de secondes correct (de -32767 à 32767), svp.\n"); - ladmin_log - ("Ajustement des secondes hors norme (commande 'banadd').\n"); - } - else - { - printf - ("Please give a correct adjustment for the seconds (from -32767 to 32767).\n"); - ladmin_log - ("Abnormal adjustement for the seconds ('banadd' command).\n"); - } - return 137; - } - - if (defaultlanguage == 'F') - { - ladmin_log - ("Envoi d'un requête au serveur de logins pour modifier la date d'un bannissement.\n"); - } - else - { - ladmin_log ("Request to login-server to modify a ban date/time.\n"); - } - - WFIFOW (login_fd, 0) = 0x794c; - memcpy (WFIFOP (login_fd, 2), name, 24); - WFIFOW (login_fd, 26) = (short) year; - WFIFOW (login_fd, 28) = (short) month; - WFIFOW (login_fd, 30) = (short) day; - WFIFOW (login_fd, 32) = (short) hour; - WFIFOW (login_fd, 34) = (short) minute; - WFIFOW (login_fd, 36) = (short) second; - WFIFOSET (login_fd, 38); - bytes_to_read = 1; - - return 0; -} - -//----------------------------------------------------------------------- -// Sub-function of sub-function banaccount, unbanaccount or bansetaccount -// Set the final date of a banishment of an account -//----------------------------------------------------------------------- -int bansetaccountsub (char *name, char *date, char *time) -{ - int year, month, day, hour, minute, second; - time_t ban_until_time; // # of seconds 1/1/1970 (timestamp): ban time limit of the account (0 = no ban) - struct tm *tmtime; - - year = month = day = hour = minute = second = 0; - ban_until_time = 0; - tmtime = localtime (&ban_until_time); // initialize - - if (verify_accountname (name) == 0) - { - return 102; - } - - if (atoi (date) != 0 && - ((sscanf (date, "%d/%d/%d", &year, &month, &day) < 3 && - sscanf (date, "%d-%d-%d", &year, &month, &day) < 3 && - sscanf (date, "%d.%d.%d", &year, &month, &day) < 3) || - sscanf (time, "%d:%d:%d", &hour, &minute, &second) < 3)) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez une date et une heure svp (format: aaaa/mm/jj hh:mm:ss).\n"); - printf - ("Vous pouvez aussi mettre 0 à la place si vous utilisez la commande 'banset'.\n"); - ladmin_log - ("Format incorrect pour la date/heure (commande'banset' ou 'ban').\n"); - } - else - { - printf - ("Please input a date and a time (format: yyyy/mm/dd hh:mm:ss).\n"); - printf - ("You can imput 0 instead of if you use 'banset' command.\n"); - ladmin_log - ("Invalid format for the date/time ('banset' or 'ban' command).\n"); - } - return 102; - } - - if (atoi (date) == 0) - { - ban_until_time = 0; - } - else - { - if (year < 70) - { - year = year + 100; - } - if (year >= 1900) - { - year = year - 1900; - } - if (month < 1 || month > 12) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un mois correct svp (entre 1 et 12).\n"); - ladmin_log - ("Mois incorrect pour la date (command 'banset' ou 'ban').\n"); - } - else - { - printf - ("Please give a correct value for the month (from 1 to 12).\n"); - ladmin_log - ("Invalid month for the date ('banset' or 'ban' command).\n"); - } - return 102; - } - month = month - 1; - if (day < 1 || day > 31) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un jour correct svp (entre 1 et 31).\n"); - ladmin_log - ("Jour incorrect pour la date (command 'banset' ou 'ban').\n"); - } - else - { - printf - ("Please give a correct value for the day (from 1 to 31).\n"); - ladmin_log - ("Invalid day for the date ('banset' or 'ban' command).\n"); - } - return 102; - } - if (((month == 3 || month == 5 || month == 8 || month == 10) - && day > 30) || (month == 1 && day > 29)) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez un jour correct en fonction du mois (%d) svp.\n", - month); - ladmin_log - ("Jour incorrect pour ce mois correspondant (command 'banset' ou 'ban').\n"); - } - else - { - printf - ("Please give a correct value for a day of this month (%d).\n", - month); - ladmin_log - ("Invalid day for this month ('banset' or 'ban' command).\n"); - } - return 102; - } - if (hour < 0 || hour > 23) - { - if (defaultlanguage == 'F') - { - printf ("Entrez une heure correcte svp (entre 0 et 23).\n"); - ladmin_log - ("Heure incorrecte pour l'heure (command 'banset' ou 'ban').\n"); - } - else - { - printf - ("Please give a correct value for the hour (from 0 to 23).\n"); - ladmin_log - ("Invalid hour for the time ('banset' or 'ban' command).\n"); - } - return 102; - } - if (minute < 0 || minute > 59) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez des minutes correctes svp (entre 0 et 59).\n"); - ladmin_log - ("Minute incorrecte pour l'heure (command 'banset' ou 'ban').\n"); - } - else - { - printf - ("Please give a correct value for the minutes (from 0 to 59).\n"); - ladmin_log - ("Invalid minute for the time ('banset' or 'ban' command).\n"); - } - return 102; - } - if (second < 0 || second > 59) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez des secondes correctes svp (entre 0 et 59).\n"); - ladmin_log - ("Seconde incorrecte pour l'heure (command 'banset' ou 'ban').\n"); - } - else - { - printf - ("Please give a correct value for the seconds (from 0 to 59).\n"); - ladmin_log - ("Invalid second for the time ('banset' or 'ban' command).\n"); - } - return 102; - } - tmtime->tm_year = year; - tmtime->tm_mon = month; - tmtime->tm_mday = day; - tmtime->tm_hour = hour; - tmtime->tm_min = minute; - tmtime->tm_sec = second; - tmtime->tm_isdst = -1; // -1: no winter/summer time modification - ban_until_time = timegm (tmtime); - if (ban_until_time == -1) - { - if (defaultlanguage == 'F') - { - printf ("Date incorrecte.\n"); - printf - ("Entrez une date et une heure svp (format: aaaa/mm/jj hh:mm:ss).\n"); - printf - ("Vous pouvez aussi mettre 0 à la place si vous utilisez la commande 'banset'.\n"); - ladmin_log ("Date incorrecte. (command 'banset' ou 'ban').\n"); - } - else - { - printf ("Invalid date.\n"); - printf - ("Please input a date and a time (format: yyyy/mm/dd hh:mm:ss).\n"); - printf - ("You can imput 0 instead of if you use 'banset' command.\n"); - ladmin_log ("Invalid date. ('banset' or 'ban' command).\n"); - } - return 102; - } - } - - if (defaultlanguage == 'F') - { - ladmin_log - ("Envoi d'un requête au serveur de logins pour fixer un ban.\n"); - } - else - { - ladmin_log ("Request to login-server to set a ban.\n"); - } - - WFIFOW (login_fd, 0) = 0x794a; - memcpy (WFIFOP (login_fd, 2), name, 24); - WFIFOL (login_fd, 26) = (int) ban_until_time; - WFIFOSET (login_fd, 30); - bytes_to_read = 1; - - return 0; -} - -//--------------------------------------------------------------------- -// Sub-function: Set the final date of a banishment of an account (ban) -//--------------------------------------------------------------------- -int banaccount (char *param) -{ - char name[1023], date[1023], time[1023]; - - memset (name, '\0', sizeof (name)); - memset (date, '\0', sizeof (date)); - memset (time, '\0', sizeof (time)); - - if (sscanf (param, "%s %s \"%[^\"]\"", date, time, name) < 3 && - sscanf (param, "%s %s '%[^']'", date, time, name) < 3 && - sscanf (param, "%s %s %[^\r\n]", date, time, name) < 3) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un nom de compte, une date et une heure svp.\n"); - printf - (": banset aaaa/mm/jj [hh:mm:ss]\n"); - printf (" banset 0 (0 = dé-bani)\n"); - printf - (" ban/banish aaaa/mm/jj hh:mm:ss \n"); - printf (" unban/unbanish \n"); - printf (" Heure par défaut [hh:mm:ss]: 23:59:59.\n"); - ladmin_log - ("Nombre incorrect de paramètres pour fixer un ban (commande 'banset' ou 'ban').\n"); - } - else - { - printf ("Please input an account name, a date and a hour.\n"); - printf - (": banset yyyy/mm/dd [hh:mm:ss]\n"); - printf - (" banset 0 (0 = un-banished)\n"); - printf - (" ban/banish yyyy/mm/dd hh:mm:ss \n"); - printf (" unban/unbanish \n"); - printf (" Default time [hh:mm:ss]: 23:59:59.\n"); - ladmin_log - ("Incomplete parameters to set a ban ('banset' or 'ban' command).\n"); - } - return 136; - } - - return bansetaccountsub (name, date, time); -} - -//------------------------------------------------------------------------ -// Sub-function: Set the final date of a banishment of an account (banset) -//------------------------------------------------------------------------ -int bansetaccount (char *param) -{ - char name[1023], date[1023], time[1023]; - - memset (name, '\0', sizeof (name)); - memset (date, '\0', sizeof (date)); - memset (time, '\0', sizeof (time)); - - if (sscanf (param, "\"%[^\"]\" %s %[^\r\n]", name, date, time) < 2 && // if date = 0, time can be void - sscanf (param, "'%[^']' %s %[^\r\n]", name, date, time) < 2 && // if date = 0, time can be void - sscanf (param, "%s %s %[^\r\n]", name, date, time) < 2) - { // if date = 0, time can be void - if (defaultlanguage == 'F') - { - printf ("Entrez un nom de compte, une date et une heure svp.\n"); - printf - (": banset aaaa/mm/jj [hh:mm:ss]\n"); - printf (" banset 0 (0 = dé-bani)\n"); - printf - (" ban/banish aaaa/mm/jj hh:mm:ss \n"); - printf (" unban/unbanish \n"); - printf (" Heure par défaut [hh:mm:ss]: 23:59:59.\n"); - ladmin_log - ("Nombre incorrect de paramètres pour fixer un ban (commande 'banset' ou 'ban').\n"); - } - else - { - printf ("Please input an account name, a date and a hour.\n"); - printf - (": banset yyyy/mm/dd [hh:mm:ss]\n"); - printf - (" banset 0 (0 = un-banished)\n"); - printf - (" ban/banish yyyy/mm/dd hh:mm:ss \n"); - printf (" unban/unbanish \n"); - printf (" Default time [hh:mm:ss]: 23:59:59.\n"); - ladmin_log - ("Incomplete parameters to set a ban ('banset' or 'ban' command).\n"); - } - return 136; - } - - if (time[0] == '\0') - strcpy (time, "23:59:59"); - - return bansetaccountsub (name, date, time); -} - -//------------------------------------------------- -// Sub-function: unbanishment of an account (unban) -//------------------------------------------------- -int unbanaccount (char *param) -{ - char name[1023]; - - memset (name, '\0', sizeof (name)); - - if (strlen (param) == 0 || - (sscanf (param, "\"%[^\"]\"", name) < 1 && - sscanf (param, "'%[^']'", name) < 1 && - sscanf (param, "%[^\r\n]", name) < 1) || strlen (name) == 0) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un nom de compte svp.\n"); - printf - (": banset aaaa/mm/jj [hh:mm:ss]\n"); - printf (" banset 0 (0 = dé-bani)\n"); - printf - (" ban/banish aaaa/mm/jj hh:mm:ss \n"); - printf (" unban/unbanish \n"); - printf (" Heure par défaut [hh:mm:ss]: 23:59:59.\n"); - ladmin_log - ("Nombre incorrect de paramètres pour fixer un ban (commande 'unban').\n"); - } - else - { - printf ("Please input an account name.\n"); - printf - (": banset yyyy/mm/dd [hh:mm:ss]\n"); - printf - (" banset 0 (0 = un-banished)\n"); - printf - (" ban/banish yyyy/mm/dd hh:mm:ss \n"); - printf (" unban/unbanish \n"); - printf (" Default time [hh:mm:ss]: 23:59:59.\n"); - ladmin_log - ("Incomplete parameters to set a ban ('unban' command).\n"); - } - return 136; - } - - return bansetaccountsub (name, "0", ""); -} - -//--------------------------------------------------------- -// Sub-function: Asking to check the validity of a password -// (Note: never send back a password with login-server!! security of passwords) -//--------------------------------------------------------- -int checkaccount (char *param) -{ - char name[1023], password[1023]; - - memset (name, '\0', sizeof (name)); - memset (password, '\0', sizeof (password)); - - if (sscanf (param, "\"%[^\"]\" %[^\r\n]", name, password) < 1 && // password can be void - sscanf (param, "'%[^']' %[^\r\n]", name, password) < 1 && // password can be void - sscanf (param, "%s %[^\r\n]", name, password) < 1) - { // password can be void - if (defaultlanguage == 'F') - { - printf ("Entrez un nom de compte svp.\n"); - printf (" check testname motdepasse\n"); - ladmin_log - ("Nombre incorrect de paramètres pour tester le mot d'un passe d'un compte (commande 'check').\n"); - } - else - { - printf ("Please input an account name.\n"); - printf (" check testname password\n"); - ladmin_log - ("Incomplete parameters to check the password of an account ('check' command).\n"); - } - return 136; - } - - if (verify_accountname (name) == 0) - { - return 102; - } - - if (strlen (password) == 0) - { - if (typepasswd (password) == 0) - return 134; - } - if (verify_password (password) == 0) - return 131; - - if (defaultlanguage == 'F') - { - ladmin_log - ("Envoi d'un requête au serveur de logins pour test un mot de passe.\n"); - } - else - { - ladmin_log ("Request to login-server to check a password.\n"); - } - - WFIFOW (login_fd, 0) = 0x793a; - memcpy (WFIFOP (login_fd, 2), name, 24); - memcpy (WFIFOP (login_fd, 26), password, 24); - WFIFOSET (login_fd, 50); - bytes_to_read = 1; - - return 0; -} - -//------------------------------------------------ -// Sub-function: Asking for deletion of an account -//------------------------------------------------ -int delaccount (char *param) -{ - char name[1023]; - char letter; - char confirm[1023]; - int i; - - memset (name, '\0', sizeof (name)); - - if (strlen (param) == 0 || - (sscanf (param, "\"%[^\"]\"", name) < 1 && - sscanf (param, "'%[^']'", name) < 1 && - sscanf (param, "%[^\r\n]", name) < 1) || strlen (name) == 0) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un nom de compte svp.\n"); - printf (" del nomtestasupprimer\n"); - ladmin_log - ("Aucun nom donné pour supprimer un compte (commande 'delete').\n"); - } - else - { - printf ("Please input an account name.\n"); - printf (" del testnametodelete\n"); - ladmin_log - ("No name given to delete an account ('delete' command).\n"); - } - return 136; - } - - if (verify_accountname (name) == 0) - { - return 102; - } - - memset (confirm, '\0', sizeof (confirm)); - while ((confirm[0] != 'o' || defaultlanguage != 'F') && confirm[0] != 'n' - && (confirm[0] != 'y' || defaultlanguage == 'F')) - { - if (defaultlanguage == 'F') - printf - ("\033[1;36m ** Etes-vous vraiment sûr de vouloir SUPPRIMER le compte [$userid]? (o/n) > \033[0m"); - else - printf - ("\033[1;36m ** Are you really sure to DELETE account [$userid]? (y/n) > \033[0m"); - fflush (stdout); - memset (confirm, '\0', sizeof (confirm)); - i = 0; - while ((letter = getchar ()) != '\n') - confirm[i++] = letter; - } - - if (confirm[0] == 'n') - { - if (defaultlanguage == 'F') - { - printf ("Suppression annulée.\n"); - ladmin_log - ("Suppression annulée par l'utilisateur (commande 'delete').\n"); - } - else - { - printf ("Deletion canceled.\n"); - ladmin_log ("Deletion canceled by user ('delete' command).\n"); - } - return 121; - } - - if (defaultlanguage == 'F') - { - ladmin_log - ("Envoi d'un requête au serveur de logins pour détruire un compte.\n"); - } - else - { - ladmin_log ("Request to login-server to delete an acount.\n"); - } - - WFIFOW (login_fd, 0) = 0x7932; - memcpy (WFIFOP (login_fd, 2), name, 24); - WFIFOSET (login_fd, 26); - bytes_to_read = 1; - - return 0; -} - -//---------------------------------------------------------- -// Sub-function: Asking to modification of an account e-mail -//---------------------------------------------------------- -int changeemail (char *param) -{ - char name[1023], email[1023]; - - memset (name, '\0', sizeof (name)); - memset (email, '\0', sizeof (email)); - - if (sscanf (param, "\"%[^\"]\" %[^\r\n]", name, email) < 2 && - sscanf (param, "'%[^']' %[^\r\n]", name, email) < 2 && - sscanf (param, "%s %[^\r\n]", name, email) < 2) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un nom de compte et une email svp.\n"); - printf (" email testname nouveauemail\n"); - ladmin_log - ("Nombre incorrect de paramètres pour changer l'email d'un compte (commande 'email').\n"); - } - else - { - printf ("Please input an account name and an email.\n"); - printf (" email testname newemail\n"); - ladmin_log - ("Incomplete parameters to change the email of an account ('email' command).\n"); - } - return 136; - } - - if (verify_accountname (name) == 0) - { - return 102; - } - - if (strlen (email) < 3) - { - if (defaultlanguage == 'F') - { - printf ("Email trop courte [%s]. Entrez une e-mail valide svp.\n", - email); - ladmin_log - ("Email trop courte [%s]. Entrez une e-mail valide svp.\n", - email); - } - else - { - printf ("Email is too short [%s]. Please input a valid e-mail.\n", - email); - ladmin_log - ("Email is too short [%s]. Please input a valid e-mail.\n", - email); - } - return 109; - } - if (strlen (email) > 39) - { - if (defaultlanguage == 'F') - { - printf - ("Email trop longue [%s]. Entrez une e-mail de 39 caractères maximum svp.\n", - email); - ladmin_log - ("Email trop longue [%s]. Entrez une e-mail de 39 caractères maximum svp.\n", - email); - } - else - { - printf - ("Email is too long [%s]. Please input an e-mail with 39 bytes at the most.\n", - email); - ladmin_log - ("Email is too long [%s]. Please input an e-mail with 39 bytes at the most.\n", - email); - } - return 109; - } - if (e_mail_check (email) == 0) - { - if (defaultlanguage == 'F') - { - printf ("Email incorrecte [%s]. Entrez une e-mail valide svp.\n", - email); - ladmin_log ("Email incorrecte [%s]. Entrez une e-mail valide svp.\n", - email); - } - else - { - printf ("Invalid email [%s]. Please input a valid e-mail.\n", - email); - ladmin_log ("Invalid email [%s]. Please input a valid e-mail.\n", - email); - } - return 109; - } - - if (defaultlanguage == 'F') - { - ladmin_log - ("Envoi d'un requête au serveur de logins pour changer une email.\n"); - } - else - { - ladmin_log ("Request to login-server to change an email.\n"); - } - - WFIFOW (login_fd, 0) = 0x7940; - memcpy (WFIFOP (login_fd, 2), name, 24); - memcpy (WFIFOP (login_fd, 26), email, 40); - WFIFOSET (login_fd, 66); - bytes_to_read = 1; - - return 0; -} - -//----------------------------------------------------- -// Sub-function: Asking of the number of online players -//----------------------------------------------------- -int getlogincount (void) -{ - if (defaultlanguage == 'F') - { - ladmin_log - ("Envoi d'un requête au serveur de logins pour obtenir le nombre de joueurs en jeu.\n"); - } - else - { - ladmin_log - ("Request to login-server to obtain the # of online players.\n"); - } - - WFIFOW (login_fd, 0) = 0x7938; - WFIFOSET (login_fd, 2); - bytes_to_read = 1; - - return 0; -} - -//---------------------------------------------------------- -// Sub-function: Asking to modify the GM level of an account -//---------------------------------------------------------- -int changegmlevel (char *param) -{ - char name[1023]; - int GM_level; - - memset (name, '\0', sizeof (name)); - GM_level = 0; - - if (sscanf (param, "\"%[^\"]\" %d", name, &GM_level) < 1 && - sscanf (param, "'%[^']' %d", name, &GM_level) < 1 && - sscanf (param, "%s %d", name, &GM_level) < 1) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un nom de compte et un niveau de GM svp.\n"); - printf (" gm nomtest 80\n"); - ladmin_log - ("Nombre incorrect de paramètres pour changer le Niveau de GM d'un compte (commande 'gm').\n"); - } - else - { - printf ("Please input an account name and a GM level.\n"); - printf (" gm testname 80\n"); - ladmin_log - ("Incomplete parameters to change the GM level of an account ('gm' command).\n"); - } - return 136; - } - - if (verify_accountname (name) == 0) - { - return 102; - } - - if (GM_level < 0 || GM_level > 99) - { - if (defaultlanguage == 'F') - { - printf - ("Niveau de GM incorrect [%d]. Entrez une valeur de 0 à 99 svp.\n", - GM_level); - ladmin_log - ("Niveau de GM incorrect [%d]. La valeur peut être de 0 à 99.\n", - GM_level); - } - else - { - printf - ("Illegal GM level [%d]. Please input a value from 0 to 99.\n", - GM_level); - ladmin_log - ("Illegal GM level [%d]. The value can be from 0 to 99.\n", - GM_level); - } - return 103; - } - - if (defaultlanguage == 'F') - { - ladmin_log - ("Envoi d'un requête au serveur de logins pour changer un niveau de GM.\n"); - } - else - { - ladmin_log ("Request to login-server to change a GM level.\n"); - } - - WFIFOW (login_fd, 0) = 0x793e; - memcpy (WFIFOP (login_fd, 2), name, 24); - WFIFOB (login_fd, 26) = GM_level; - WFIFOSET (login_fd, 27); - bytes_to_read = 1; - - return 0; -} - -//--------------------------------------------- -// Sub-function: Asking to obtain an account id -//--------------------------------------------- -int idaccount (char *param) -{ - char name[1023]; - - memset (name, '\0', sizeof (name)); - - if (strlen (param) == 0 || - (sscanf (param, "\"%[^\"]\"", name) < 1 && - sscanf (param, "'%[^']'", name) < 1 && - sscanf (param, "%[^\r\n]", name) < 1) || strlen (name) == 0) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un nom de compte svp.\n"); - printf (" id nomtest\n"); - ladmin_log - ("Aucun nom donné pour rechecher l'id d'un compte (commande 'id').\n"); - } - else - { - printf ("Please input an account name.\n"); - printf (" id testname\n"); - ladmin_log - ("No name given to search an account id ('id' command).\n"); - } - return 136; - } - - if (verify_accountname (name) == 0) - { - return 102; - } - - if (defaultlanguage == 'F') - { - ladmin_log - ("Envoi d'un requête au serveur de logins pour connaître l'id d'un compte.\n"); - } - else - { - ladmin_log ("Request to login-server to know an account id.\n"); - } - - WFIFOW (login_fd, 0) = 0x7944; - memcpy (WFIFOP (login_fd, 2), name, 24); - WFIFOSET (login_fd, 26); - bytes_to_read = 1; - - return 0; -} - -//---------------------------------------------------------------------------- -// Sub-function: Asking to displaying information about an account (by its id) -//---------------------------------------------------------------------------- -int infoaccount (int account_id) -{ - if (account_id < 0) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un id ayant une valeur positive svp.\n"); - ladmin_log - ("Une valeur négative a été donné pour trouver le compte.\n"); - } - else - { - printf ("Please input a positive value for the id.\n"); - ladmin_log ("Negative value was given to found the account.\n"); - } - return 136; - } - - if (defaultlanguage == 'F') - { - ladmin_log - ("Envoi d'un requête au serveur de logins pour obtenir le information d'un compte (par l'id).\n"); - } - else - { - ladmin_log - ("Request to login-server to obtain information about an account (by its id).\n"); - } - - WFIFOW (login_fd, 0) = 0x7954; - WFIFOL (login_fd, 2) = account_id; - WFIFOSET (login_fd, 6); - bytes_to_read = 1; - - return 0; -} - -//--------------------------------------- -// Sub-function: Send a broadcast message -//--------------------------------------- -int sendbroadcast (short type, char *message) -{ - if (strlen (message) == 0) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un message svp.\n"); - if (type == 0) - { - printf (" kami un message\n"); - } - else - { - printf (" kamib un message\n"); - } - ladmin_log ("Le message est vide (commande 'kami(b)').\n"); - } - else - { - printf ("Please input a message.\n"); - if (type == 0) - { - printf (" kami a message\n"); - } - else - { - printf (" kamib a message\n"); - } - ladmin_log ("The message is void ('kami(b)' command).\n"); - } - return 136; - } - - WFIFOW (login_fd, 0) = 0x794e; - WFIFOW (login_fd, 2) = type; - WFIFOL (login_fd, 4) = strlen (message) + 1; - memcpy (WFIFOP (login_fd, 8), message, strlen (message) + 1); - WFIFOSET (login_fd, 8 + strlen (message) + 1); - bytes_to_read = 1; - - return 0; -} - -//-------------------------------------------- -// Sub-function: Change language of displaying -//-------------------------------------------- -int changelanguage (char *language) -{ - if (strlen (language) == 0) - { - if (defaultlanguage == 'F') - { - printf ("Entrez une langue svp.\n"); - printf (" language english\n"); - printf (" language français\n"); - ladmin_log ("La langue est vide (commande 'language').\n"); - } - else - { - printf ("Please input a language.\n"); - printf (" language english\n"); - printf (" language français\n"); - ladmin_log ("The language is void ('language' command).\n"); - } - return 136; - } - - language[0] = toupper (language[0]); - if (language[0] == 'F' || language[0] == 'E') - { - defaultlanguage = language[0]; - if (defaultlanguage == 'F') - { - printf ("Changement de la langue d'affichage en Français.\n"); - ladmin_log ("Changement de la langue d'affichage en Français.\n"); - } - else - { - printf ("Displaying language changed to English.\n"); - ladmin_log ("Displaying language changed to English.\n"); - } - } - else - { - if (defaultlanguage == 'F') - { - printf - ("Langue non paramétrée (langues possibles: 'Français' ou 'English').\n"); - ladmin_log - ("Langue non paramétrée (Français ou English nécessaire).\n"); - } - else - { - printf - ("Undefined language (possible languages: Français or English).\n"); - ladmin_log ("Undefined language (must be Français or English).\n"); - } - } - - return 0; -} - -//-------------------------------------------------------- -// Sub-function: Asking to Displaying of the accounts list -//-------------------------------------------------------- -int listaccount (char *param, int type) -{ -//int list_first, list_last, list_type; // parameter to display a list of accounts - int i; - - list_type = type; - - // set default values - list_first = 0; - list_last = 0; - - if (list_type == 1) - { // if listgm - // get all accounts = use default - } - else if (list_type == 2) - { // if search - for (i = 0; param[i]; i++) - param[i] = tolower (param[i]); - // get all accounts = use default - } - else if (list_type == 3) - { // if listban - // get all accounts = use default - } - else if (list_type == 4) - { // if listok - // get all accounts = use default - } - else - { // if list (list_type == 0) - switch (sscanf (param, "%d %d", &list_first, &list_last)) - { - case 0: - // get all accounts = use default - break; - case 1: - list_last = 0; - // use tests of the following value - default: - if (list_first < 0) - list_first = 0; - if (list_last < list_first || list_last < 0) - list_last = 0; - break; - } - } - - if (defaultlanguage == 'F') - { - ladmin_log - ("Envoi d'un requête au serveur de logins pour obtenir la liste des comptes de %d à %d.\n", - list_first, list_last); - } - else - { - ladmin_log - ("Request to login-server to obtain the list of accounts from %d to %d.\n", - list_first, list_last); - } - - WFIFOW (login_fd, 0) = 0x7920; - WFIFOL (login_fd, 2) = list_first; - WFIFOL (login_fd, 6) = list_last; - WFIFOSET (login_fd, 10); - bytes_to_read = 1; - - // 0123456789 01 01234567890123456789012301234 012345 0123456789012345678901234567 - if (defaultlanguage == 'F') - { - Iprintf - (" id_compte GM nom_utilisateur sexe count statut\n"); - } - else - { - Iprintf - ("account_id GM user_name sex count state\n"); - } - Iprintf - ("-------------------------------------------------------------------------------\n"); - list_count = 0; - - return 0; -} - -//-------------------------------------------------------- -// Sub-function: Frobnicate items -//-------------------------------------------------------- -int itemfrob (char *param) -{ - int source_id, dest_id; - - if (sscanf (param, "%d %d", &source_id, &dest_id) < 2) - { - printf ("You must provide the source and destination item IDs.\n"); - return 1; - } - - WFIFOW (login_fd, 0) = 0x7924; - WFIFOL (login_fd, 2) = source_id; - WFIFOL (login_fd, 6) = dest_id; - WFIFOSET (login_fd, 10); - bytes_to_read = 1; // all logging is done to the three main servers - - return 0; -} - -//-------------------------------------------- -// Sub-function: Asking to modify a memo field -//-------------------------------------------- -int changememo (char *param) -{ - char name[1023], memo[1023]; - - memset (name, '\0', sizeof (name)); - memset (memo, '\0', sizeof (memo)); - - if (sscanf (param, "\"%[^\"]\" %[^\r\n]", name, memo) < 1 && // memo can be void - sscanf (param, "'%[^']' %[^\r\n]", name, memo) < 1 && // memo can be void - sscanf (param, "%s %[^\r\n]", name, memo) < 1) - { // memo can be void - if (defaultlanguage == 'F') - { - printf ("Entrez un nom de compte et un mémo svp.\n"); - printf (" memo nomtest nouveau memo\n"); - ladmin_log - ("Nombre incorrect de paramètres pour changer le mémo d'un compte (commande 'email').\n"); - } - else - { - printf ("Please input an account name and a memo.\n"); - printf (" memo testname new memo\n"); - ladmin_log - ("Incomplete parameters to change the memo of an account ('email' command).\n"); - } - return 136; - } - - if (verify_accountname (name) == 0) - { - return 102; - } - - if (strlen (memo) > 254) - { - if (defaultlanguage == 'F') - { - printf ("Mémo trop long (%d caractères).\n", strlen (memo)); - printf ("Entrez un mémo de 254 caractères maximum svp.\n"); - ladmin_log - ("Mémo trop long (%d caractères). Entrez un mémo de 254 caractères maximum svp.\n", - strlen (memo)); - } - else - { - printf ("Memo is too long (%d characters).\n", strlen (memo)); - printf ("Please input a memo of 254 bytes at the maximum.\n"); - ladmin_log - ("Email is too long (%d characters). Please input a memo of 254 bytes at the maximum.\n", - strlen (memo)); - } - return 102; - } - - if (defaultlanguage == 'F') - { - ladmin_log - ("Envoi d'un requête au serveur de logins pour changer un mémo.\n"); - } - else - { - ladmin_log ("Request to login-server to change a memo.\n"); - } - - WFIFOW (login_fd, 0) = 0x7942; - memcpy (WFIFOP (login_fd, 2), name, 24); - WFIFOW (login_fd, 26) = strlen (memo); - if (strlen (memo) > 0) - memcpy (WFIFOP (login_fd, 28), memo, strlen (memo)); - WFIFOSET (login_fd, 28 + strlen (memo)); - bytes_to_read = 1; - - return 0; -} - -//----------------------------------------------- -// Sub-function: Asking to obtain an account name -//----------------------------------------------- -int nameaccount (int id) -{ - if (id < 0) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un id ayant une valeur positive svp.\n"); - ladmin_log - ("Id négatif donné pour rechecher le nom d'un compte (commande 'name').\n"); - } - else - { - printf ("Please input a positive value for the id.\n"); - ladmin_log - ("Negativ id given to search an account name ('name' command).\n"); - } - return 136; - } - - if (defaultlanguage == 'F') - ladmin_log - ("Envoi d'un requête au serveur de logins pour connaître le nom d'un compte.\n"); - else - ladmin_log ("Request to login-server to know an account name.\n"); - - WFIFOW (login_fd, 0) = 0x7946; - WFIFOL (login_fd, 2) = id; - WFIFOSET (login_fd, 6); - bytes_to_read = 1; - - return 0; -} - -//------------------------------------------ -// Sub-function: Asking to modify a password -// (Note: never send back a password with login-server!! security of passwords) -//------------------------------------------ -int changepasswd (char *param) -{ - char name[1023], password[1023]; - - memset (name, '\0', sizeof (name)); - memset (password, '\0', sizeof (password)); - - if (sscanf (param, "\"%[^\"]\" %[^\r\n]", name, password) < 1 && - sscanf (param, "'%[^']' %[^\r\n]", name, password) < 1 && - sscanf (param, "%s %[^\r\n]", name, password) < 1) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un nom de compte svp.\n"); - printf (" passwd nomtest nouveaumotdepasse\n"); - ladmin_log - ("Nombre incorrect de paramètres pour changer le mot d'un passe d'un compte (commande 'password').\n"); - } - else - { - printf ("Please input an account name.\n"); - printf (" passwd testname newpassword\n"); - ladmin_log - ("Incomplete parameters to change the password of an account ('password' command).\n"); - } - return 136; - } - - if (verify_accountname (name) == 0) - { - return 102; - } - - if (strlen (password) == 0) - { - if (typepasswd (password) == 0) - return 134; - } - if (verify_password (password) == 0) - return 131; - - if (defaultlanguage == 'F') - { - ladmin_log - ("Envoi d'un requête au serveur de logins pour changer un mot de passe.\n"); - } - else - { - ladmin_log ("Request to login-server to change a password.\n"); - } - - WFIFOW (login_fd, 0) = 0x7934; - memcpy (WFIFOP (login_fd, 2), name, 24); - memcpy (WFIFOP (login_fd, 26), password, 24); - WFIFOSET (login_fd, 50); - bytes_to_read = 1; - - return 0; -} - -//---------------------------------------------------------------------- -// Sub-function: Request to login-server to reload GM configuration file -// this function have no answer -//---------------------------------------------------------------------- -int reloadGM (void) -{ - WFIFOW (login_fd, 0) = 0x7955; - WFIFOSET (login_fd, 2); - bytes_to_read = 0; - - if (defaultlanguage == 'F') - { - ladmin_log - ("Demande de recharger le fichier de configuration des GM envoyée.\n"); - printf - ("Demande de recharger le fichier de configuration des GM envoyée.\n"); - printf ("Vérifiez les comptes GM actuels (après rechargement):\n"); - } - else - { - ladmin_log ("Request to reload the GM configuration file sended.\n"); - printf ("Request to reload the GM configuration file sended.\n"); - printf ("Check the actual GM accounts (after reloading):\n"); - } - listaccount (parameters, 1); // 1: to list only GM - - return 180; -} - -//----------------------------------------------------- -// Sub-function: Asking to modify the sex of an account -//----------------------------------------------------- -int changesex (char *param) -{ - char name[1023], sex[1023]; - - memset (name, '\0', sizeof (name)); - memset (sex, '\0', sizeof (sex)); - - if (sscanf (param, "\"%[^\"]\" %[^\r\n]", name, sex) < 2 && - sscanf (param, "'%[^']' %[^\r\n]", name, sex) < 2 && - sscanf (param, "%s %[^\r\n]", name, sex) < 2) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un nom de compte et un sexe svp.\n"); - printf (" sex nomtest Male\n"); - ladmin_log - ("Nombre incorrect de paramètres pour changer le sexe d'un compte (commande 'sex').\n"); - } - else - { - printf ("Please input an account name and a sex.\n"); - printf (" sex testname Male\n"); - ladmin_log - ("Incomplete parameters to change the sex of an account ('sex' command).\n"); - } - return 136; - } - - if (verify_accountname (name) == 0) - { - return 102; - } - - sex[0] = toupper (sex[0]); - if (strchr ("MF", sex[0]) == NULL) - { - if (defaultlanguage == 'F') - { - printf ("Sexe incorrect [%s]. Entrez M ou F svp.\n", sex); - ladmin_log ("Sexe incorrect [%s]. Entrez M ou F svp.\n", - sex); - } - else - { - printf ("Illegal gender [%s]. Please input M or F.\n", sex); - ladmin_log ("Illegal gender [%s]. Please input M or F.\n", - sex); - } - return 103; - } - - if (defaultlanguage == 'F') - { - ladmin_log - ("Envoi d'un requête au serveur de logins pour changer un sexe.\n"); - } - else - { - ladmin_log ("Request to login-server to change a sex.\n"); - } - - WFIFOW (login_fd, 0) = 0x793c; - memcpy (WFIFOP (login_fd, 2), name, 24); - WFIFOB (login_fd, 26) = sex[0]; - WFIFOSET (login_fd, 27); - bytes_to_read = 1; - - return 0; -} - -//------------------------------------------------------------------------- -// Sub-function of sub-function changestate, blockaccount or unblockaccount -// Asking to modify the state of an account -//------------------------------------------------------------------------- -int changestatesub (char *name, int state, char *error_message7) -{ - char error_message[1023]; // need to use, because we can modify error_message7 - - memset (error_message, '\0', sizeof (error_message)); - strncpy (error_message, error_message7, sizeof (error_message) - 1); - - if ((state < 0 || state > 9) && state != 100) - { // Valid values: 0: ok, or value of the 0x006a packet + 1 - if (defaultlanguage == 'F') - { - printf ("Entrez une des statuts suivantes svp:\n"); - printf - (" 0 = Compte ok 6 = Your Game's EXE file is not the latest version\n"); - } - else - { - printf ("Please input one of these states:\n"); - printf - (" 0 = Account ok 6 = Your Game's EXE file is not the latest version\n"); - } - printf - (" 1 = Unregistered ID 7 = You are Prohibited to log in until + message\n"); - printf - (" 2 = Incorrect Password 8 = Server is jammed due to over populated\n"); - printf (" 3 = This ID is expired 9 = No MSG\n"); - printf - (" 4 = Rejected from Server 100 = This ID has been totally erased\n"); - printf (" 5 = You have been blocked by the GM Team\n"); - if (defaultlanguage == 'F') - { - printf (" state nomtest 5\n"); - printf (" state nomtest 7 fin de votre ban\n"); - printf (" block \n"); - printf (" unblock \n"); - ladmin_log - ("Valeur incorrecte pour le statut d'un compte (commande 'state', 'block' ou 'unblock').\n"); - } - else - { - printf (" state testname 5\n"); - printf (" state testname 7 end of your ban\n"); - printf (" block \n"); - printf (" unblock \n"); - ladmin_log - ("Invalid value for the state of an account ('state', 'block' or 'unblock' command).\n"); - } - return 151; - } - - if (verify_accountname (name) == 0) - { - return 102; - } - - if (state != 7) - { - strcpy (error_message, "-"); - } - else - { - if (strlen (error_message) < 1) - { - if (defaultlanguage == 'F') - { - printf - ("Message d'erreur trop court. Entrez un message de 1-19 caractères.\n"); - ladmin_log - ("Message d'erreur trop court. Entrez un message de 1-19 caractères.\n"); - } - else - { - printf - ("Error message is too short. Please input a message of 1-19 bytes.\n"); - ladmin_log - ("Error message is too short. Please input a message of 1-19 bytes.\n"); - } - return 102; - } - if (strlen (error_message) > 19) - { - if (defaultlanguage == 'F') - { - printf - ("Message d'erreur trop long. Entrez un message de 1-19 caractères.\n"); - ladmin_log - ("Message d'erreur trop long. Entrez un message de 1-19 caractères.\n"); - } - else - { - printf - ("Error message is too long. Please input a message of 1-19 bytes.\n"); - ladmin_log - ("Error message is too long. Please input a message of 1-19 bytes.\n"); - } - return 102; - } - } - - if (defaultlanguage == 'F') - { - ladmin_log - ("Envoi d'un requête au serveur de logins pour changer un statut.\n"); - } - else - { - ladmin_log ("Request to login-server to change a state.\n"); - } - - WFIFOW (login_fd, 0) = 0x7936; - memcpy (WFIFOP (login_fd, 2), name, 24); - WFIFOL (login_fd, 26) = state; - memcpy (WFIFOP (login_fd, 30), error_message, 20); - WFIFOSET (login_fd, 50); - bytes_to_read = 1; - - return 0; -} - -//------------------------------------------------------- -// Sub-function: Asking to modify the state of an account -//------------------------------------------------------- -int changestate (char *param) -{ - char name[1023], error_message[1023]; - int state; - - memset (name, '\0', sizeof (name)); - memset (error_message, '\0', sizeof (error_message)); - - if (sscanf (param, "\"%[^\"]\" %d %[^\r\n]", name, &state, error_message) - < 2 - && sscanf (param, "'%[^']' %d %[^\r\n]", name, &state, - error_message) < 2 - && sscanf (param, "%s %d %[^\r\n]", name, &state, error_message) < 2) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un nom de compte et un statut svp.\n"); - printf (" state nomtest 5\n"); - printf (" state nomtest 7 fin de votre ban\n"); - printf (" block \n"); - printf (" unblock \n"); - ladmin_log - ("Nombre incorrect de paramètres pour changer le statut d'un compte (commande 'state').\n"); - } - else - { - printf ("Please input an account name and a state.\n"); - printf (" state testname 5\n"); - printf (" state testname 7 end of your ban\n"); - printf (" block \n"); - printf (" unblock \n"); - ladmin_log - ("Incomplete parameters to change the state of an account ('state' command).\n"); - } - return 136; - } - - return changestatesub (name, state, error_message); -} - -//------------------------------------------- -// Sub-function: Asking to unblock an account -//------------------------------------------- -int unblockaccount (char *param) -{ - char name[1023]; - - memset (name, '\0', sizeof (name)); - - if (strlen (param) == 0 || - (sscanf (param, "\"%[^\"]\"", name) < 1 && - sscanf (param, "'%[^']'", name) < 1 && - sscanf (param, "%[^\r\n]", name) < 1) || strlen (name) == 0) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un nom de compte svp.\n"); - printf (" state nomtest 5\n"); - printf (" state nomtest 7 fin de votre ban\n"); - printf (" block \n"); - printf (" unblock \n"); - ladmin_log - ("Nombre incorrect de paramètres pour changer le statut d'un compte (commande 'unblock').\n"); - } - else - { - printf ("Please input an account name.\n"); - printf (" state testname 5\n"); - printf (" state testname 7 end of your ban\n"); - printf (" block \n"); - printf (" unblock \n"); - ladmin_log - ("Incomplete parameters to change the state of an account ('unblock' command).\n"); - } - return 136; - } - - return changestatesub (name, 0, "-"); // state 0, no error message -} - -//------------------------------------------- -// Sub-function: Asking to unblock an account -//------------------------------------------- -int blockaccount (char *param) -{ - char name[1023]; - - memset (name, '\0', sizeof (name)); - - if (strlen (param) == 0 || - (sscanf (param, "\"%[^\"]\"", name) < 1 && - sscanf (param, "'%[^']'", name) < 1 && - sscanf (param, "%[^\r\n]", name) < 1) || strlen (name) == 0) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un nom de compte svp.\n"); - printf (" state nomtest 5\n"); - printf (" state nomtest 7 fin de votre ban\n"); - printf (" block \n"); - printf (" unblock \n"); - ladmin_log - ("Nombre incorrect de paramètres pour changer le statut d'un compte (commande 'block').\n"); - } - else - { - printf ("Please input an account name.\n"); - printf (" state testname 5\n"); - printf (" state testname 7 end of your ban\n"); - printf (" block \n"); - printf (" unblock \n"); - ladmin_log - ("Incomplete parameters to change the state of an account ('block' command).\n"); - } - return 136; - } - - return changestatesub (name, 5, "-"); // state 5, no error message -} - -//--------------------------------------------------------------------- -// Sub-function: Add/substract time to the validity limit of an account -//--------------------------------------------------------------------- -int timeaddaccount (char *param) -{ - char name[1023], modif[1023]; - int year, month, day, hour, minute, second; - char *p_modif; - int value, i; - - memset (name, '\0', sizeof (name)); - memset (modif, '\0', sizeof (modif)); - year = month = day = hour = minute = second = 0; - - if (sscanf (param, "\"%[^\"]\" %[^\r\n]", name, modif) < 2 && - sscanf (param, "'%[^']' %[^\r\n]", name, modif) < 2 && - sscanf (param, "%s %[^\r\n]", name, modif) < 2) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un nom de compte et un modificateur svp.\n"); - printf (" timeadd nomtest +1m-2mn1s-6y\n"); - printf - (" Cette exemple ajoute 1 mois et 1 seconde, et soustrait 2 minutes\n"); - printf (" et 6 ans dans le même temps.\n"); - ladmin_log - ("Nombre incorrect de paramètres pour modifier une date limite d'utilisation (commande 'timeadd').\n"); - } - else - { - printf ("Please input an account name and a modifier.\n"); - printf (" : timeadd testname +1m-2mn1s-6y\n"); - printf - (" this example adds 1 month and 1 second, and substracts 2 minutes\n"); - printf (" and 6 years at the same time.\n"); - ladmin_log - ("Incomplete parameters to modify a limit time ('timeadd' command).\n"); - } - return 136; - } - if (verify_accountname (name) == 0) - { - return 102; - } - - // lowercase for modif - for (i = 0; modif[i]; i++) - modif[i] = tolower (modif[i]); - p_modif = modif; - while (strlen (p_modif) > 0) - { - value = atoi (p_modif); - if (value == 0) - { - p_modif++; - } - else - { - if (p_modif[0] == '-' || p_modif[0] == '+') - p_modif++; - while (strlen (p_modif) > 0 && p_modif[0] >= '0' - && p_modif[0] <= '9') - { - p_modif++; - } - if (p_modif[0] == 's') - { - second = value; - p_modif++; - } - else if (p_modif[0] == 'm' && p_modif[1] == 'n') - { - minute = value; - p_modif += 2; - } - else if (p_modif[0] == 'h') - { - hour = value; - p_modif++; - } - else if (p_modif[0] == 'd' || p_modif[0] == 'j') - { - day = value; - p_modif += 2; - } - else if (p_modif[0] == 'm') - { - month = value; - p_modif++; - } - else if (p_modif[0] == 'y' || p_modif[0] == 'a') - { - year = value; - p_modif++; - } - else - { - p_modif++; - } - } - } - - if (defaultlanguage == 'F') - { - printf (" année: %d\n", year); - printf (" mois: %d\n", month); - printf (" jour: %d\n", day); - printf (" heure: %d\n", hour); - printf (" minute: %d\n", minute); - printf (" seconde: %d\n", second); - } - else - { - printf (" year: %d\n", year); - printf (" month: %d\n", month); - printf (" day: %d\n", day); - printf (" hour: %d\n", hour); - printf (" minute: %d\n", minute); - printf (" second: %d\n", second); - } - - if (year == 0 && month == 0 && day == 0 && hour == 0 && minute == 0 - && second == 0) - { - if (defaultlanguage == 'F') - { - printf - ("Vous devez entrer un ajustement avec cette commande, svp:\n"); - printf (" Valeur d'ajustement (-1, 1, +1, etc...)\n"); - printf (" Elément modifié:\n"); - printf (" a ou y: année\n"); - printf (" m: mois\n"); - printf (" j ou d: jour\n"); - printf (" h: heure\n"); - printf (" mn: minute\n"); - printf (" s: seconde\n"); - printf (" timeadd nomtest +1m-2mn1s-6y\n"); - printf - (" Cette exemple ajoute 1 mois et 1 seconde, et soustrait 2 minutes\n"); - printf (" et 6 ans dans le même temps.\n"); - ladmin_log - ("Aucun ajustement n'est pas un ajustement (commande 'timeadd').\n"); - } - else - { - printf ("Please give an adjustment with this command:\n"); - printf (" Adjustment value (-1, 1, +1, etc...)\n"); - printf (" Modified element:\n"); - printf (" a or y: year\n"); - printf (" m: month\n"); - printf (" j or d: day\n"); - printf (" h: hour\n"); - printf (" mn: minute\n"); - printf (" s: second\n"); - printf (" timeadd testname +1m-2mn1s-6y\n"); - printf - (" this example adds 1 month and 1 second, and substracts 2 minutes\n"); - printf (" and 6 years at the same time.\n"); - ladmin_log - ("No adjustment isn't an adjustment ('timeadd' command).\n"); - } - return 137; - } - if (year > 127 || year < -127) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez un ajustement d'années correct (de -127 à 127), svp.\n"); - ladmin_log - ("Ajustement de l'année hors norme ('timeadd' command).\n"); - } - else - { - printf - ("Please give a correct adjustment for the years (from -127 to 127).\n"); - ladmin_log - ("Abnormal adjustement for the year ('timeadd' command).\n"); - } - return 137; - } - if (month > 255 || month < -255) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez un ajustement de mois correct (de -255 à 255), svp.\n"); - ladmin_log ("Ajustement du mois hors norme ('timeadd' command).\n"); - } - else - { - printf - ("Please give a correct adjustment for the months (from -255 to 255).\n"); - ladmin_log - ("Abnormal adjustement for the month ('timeadd' command).\n"); - } - return 137; - } - if (day > 32767 || day < -32767) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez un ajustement de jours correct (de -32767 à 32767), svp.\n"); - ladmin_log ("Ajustement des jours hors norme ('timeadd' command).\n"); - } - else - { - printf - ("Please give a correct adjustment for the days (from -32767 to 32767).\n"); - ladmin_log - ("Abnormal adjustement for the days ('timeadd' command).\n"); - } - return 137; - } - if (hour > 32767 || hour < -32767) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez un ajustement d'heures correct (de -32767 à 32767), svp.\n"); - ladmin_log - ("Ajustement des heures hors norme ('timeadd' command).\n"); - } - else - { - printf - ("Please give a correct adjustment for the hours (from -32767 to 32767).\n"); - ladmin_log - ("Abnormal adjustement for the hours ('timeadd' command).\n"); - } - return 137; - } - if (minute > 32767 || minute < -32767) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez un ajustement de minutes correct (de -32767 à 32767), svp.\n"); - ladmin_log - ("Ajustement des minutes hors norme ('timeadd' command).\n"); - } - else - { - printf - ("Please give a correct adjustment for the minutes (from -32767 to 32767).\n"); - ladmin_log - ("Abnormal adjustement for the minutes ('timeadd' command).\n"); - } - return 137; - } - if (second > 32767 || second < -32767) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez un ajustement de secondes correct (de -32767 à 32767), svp.\n"); - ladmin_log - ("Ajustement des secondes hors norme ('timeadd' command).\n"); - } - else - { - printf - ("Please give a correct adjustment for the seconds (from -32767 to 32767).\n"); - ladmin_log - ("Abnormal adjustement for the seconds ('timeadd' command).\n"); - } - return 137; - } - - if (defaultlanguage == 'F') - { - ladmin_log - ("Envoi d'un requête au serveur de logins pour modifier une date limite d'utilisation.\n"); - } - else - { - ladmin_log ("Request to login-server to modify a time limit.\n"); - } - - WFIFOW (login_fd, 0) = 0x7950; - memcpy (WFIFOP (login_fd, 2), name, 24); - WFIFOW (login_fd, 26) = (short) year; - WFIFOW (login_fd, 28) = (short) month; - WFIFOW (login_fd, 30) = (short) day; - WFIFOW (login_fd, 32) = (short) hour; - WFIFOW (login_fd, 34) = (short) minute; - WFIFOW (login_fd, 36) = (short) second; - WFIFOSET (login_fd, 38); - bytes_to_read = 1; - - return 0; -} - -//------------------------------------------------- -// Sub-function: Set a validity limit of an account -//------------------------------------------------- -int timesetaccount (char *param) -{ - char name[1023], date[1023], time[1023]; - int year, month, day, hour, minute, second; - time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) - struct tm *tmtime; - - memset (name, '\0', sizeof (name)); - memset (date, '\0', sizeof (date)); - memset (time, '\0', sizeof (time)); - year = month = day = hour = minute = second = 0; - connect_until_time = 0; - tmtime = localtime (&connect_until_time); // initialize - - if (sscanf (param, "\"%[^\"]\" %s %[^\r\n]", name, date, time) < 2 && // if date = 0, time can be void - sscanf (param, "'%[^']' %s %[^\r\n]", name, date, time) < 2 && // if date = 0, time can be void - sscanf (param, "%s %s %[^\r\n]", name, date, time) < 2) - { // if date = 0, time can be void - if (defaultlanguage == 'F') - { - printf ("Entrez un nom de compte, une date et une heure svp.\n"); - printf - (": timeset aaaa/mm/jj [hh:mm:ss]\n"); - printf - (" timeset 0 (0 = illimité)\n"); - printf (" Heure par défaut [hh:mm:ss]: 23:59:59.\n"); - ladmin_log - ("Nombre incorrect de paramètres pour fixer une date limite d'utilisation (commande 'timeset').\n"); - } - else - { - printf ("Please input an account name, a date and a hour.\n"); - printf - (": timeset yyyy/mm/dd [hh:mm:ss]\n"); - printf - (" timeset 0 (0 = unlimited)\n"); - printf (" Default time [hh:mm:ss]: 23:59:59.\n"); - ladmin_log - ("Incomplete parameters to set a limit time ('timeset' command).\n"); - } - return 136; - } - if (verify_accountname (name) == 0) - { - return 102; - } - - if (time[0] == '\0') - strcpy (time, "23:59:59"); - - if (atoi (date) != 0 && - ((sscanf (date, "%d/%d/%d", &year, &month, &day) < 3 && - sscanf (date, "%d-%d-%d", &year, &month, &day) < 3 && - sscanf (date, "%d.%d.%d", &year, &month, &day) < 3 && - sscanf (date, "%d'%d'%d", &year, &month, &day) < 3) || - sscanf (time, "%d:%d:%d", &hour, &minute, &second) < 3)) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez 0 ou une date et une heure svp (format: 0 ou aaaa/mm/jj hh:mm:ss).\n"); - ladmin_log - ("Format incorrect pour la date/heure ('timeset' command).\n"); - } - else - { - printf - ("Please input 0 or a date and a time (format: 0 or yyyy/mm/dd hh:mm:ss).\n"); - ladmin_log - ("Invalid format for the date/time ('timeset' command).\n"); - } - return 102; - } - - if (atoi (date) == 0) - { - connect_until_time = 0; - } - else - { - if (year < 70) - { - year = year + 100; - } - if (year >= 1900) - { - year = year - 1900; - } - if (month < 1 || month > 12) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un mois correct svp (entre 1 et 12).\n"); - ladmin_log ("Mois incorrect pour la date ('timeset' command).\n"); - } - else - { - printf - ("Please give a correct value for the month (from 1 to 12).\n"); - ladmin_log ("Invalid month for the date ('timeset' command).\n"); - } - return 102; - } - month = month - 1; - if (day < 1 || day > 31) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un jour correct svp (entre 1 et 31).\n"); - ladmin_log ("Jour incorrect pour la date ('timeset' command).\n"); - } - else - { - printf - ("Please give a correct value for the day (from 1 to 31).\n"); - ladmin_log ("Invalid day for the date ('timeset' command).\n"); - } - return 102; - } - if (((month == 3 || month == 5 || month == 8 || month == 10) - && day > 30) || (month == 1 && day > 29)) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez un jour correct en fonction du mois (%d) svp.\n", - month); - ladmin_log - ("Jour incorrect pour ce mois correspondant ('timeset' command).\n"); - } - else - { - printf - ("Please give a correct value for a day of this month (%d).\n", - month); - ladmin_log ("Invalid day for this month ('timeset' command).\n"); - } - return 102; - } - if (hour < 0 || hour > 23) - { - if (defaultlanguage == 'F') - { - printf ("Entrez une heure correcte svp (entre 0 et 23).\n"); - ladmin_log - ("Heure incorrecte pour l'heure ('timeset' command).\n"); - } - else - { - printf - ("Please give a correct value for the hour (from 0 to 23).\n"); - ladmin_log ("Invalid hour for the time ('timeset' command).\n"); - } - return 102; - } - if (minute < 0 || minute > 59) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez des minutes correctes svp (entre 0 et 59).\n"); - ladmin_log - ("Minute incorrecte pour l'heure ('timeset' command).\n"); - } - else - { - printf - ("Please give a correct value for the minutes (from 0 to 59).\n"); - ladmin_log ("Invalid minute for the time ('timeset' command).\n"); - } - return 102; - } - if (second < 0 || second > 59) - { - if (defaultlanguage == 'F') - { - printf - ("Entrez des secondes correctes svp (entre 0 et 59).\n"); - ladmin_log - ("Seconde incorrecte pour l'heure ('timeset' command).\n"); - } - else - { - printf - ("Please give a correct value for the seconds (from 0 to 59).\n"); - ladmin_log ("Invalid second for the time ('timeset' command).\n"); - } - return 102; - } - tmtime->tm_year = year; - tmtime->tm_mon = month; - tmtime->tm_mday = day; - tmtime->tm_hour = hour; - tmtime->tm_min = minute; - tmtime->tm_sec = second; - tmtime->tm_isdst = -1; // -1: no winter/summer time modification - connect_until_time = timegm (tmtime); - if (connect_until_time == -1) - { - if (defaultlanguage == 'F') - { - printf ("Date incorrecte.\n"); - printf - ("Ajoutez 0 ou une date et une heure svp (format: 0 ou aaaa/mm/jj hh:mm:ss).\n"); - ladmin_log ("Date incorrecte. ('timeset' command).\n"); - } - else - { - printf ("Invalid date.\n"); - printf - ("Please add 0 or a date and a time (format: 0 or yyyy/mm/dd hh:mm:ss).\n"); - ladmin_log ("Invalid date. ('timeset' command).\n"); - } - return 102; - } - } - - if (defaultlanguage == 'F') - { - ladmin_log - ("Envoi d'un requête au serveur de logins pour fixer une date limite d'utilisation.\n"); - } - else - { - ladmin_log ("Request to login-server to set a time limit.\n"); - } - - WFIFOW (login_fd, 0) = 0x7948; - memcpy (WFIFOP (login_fd, 2), name, 24); - WFIFOL (login_fd, 26) = (int) connect_until_time; - WFIFOSET (login_fd, 30); - bytes_to_read = 1; - - return 0; -} - -//------------------------------------------------------------------------------ -// Sub-function: Asking to displaying information about an account (by its name) -//------------------------------------------------------------------------------ -int whoaccount (char *param) -{ - char name[1023]; - - memset (name, '\0', sizeof (name)); - - if (strlen (param) == 0 || - (sscanf (param, "\"%[^\"]\"", name) < 1 && - sscanf (param, "'%[^']'", name) < 1 && - sscanf (param, "%[^\r\n]", name) < 1) || strlen (name) == 0) - { - if (defaultlanguage == 'F') - { - printf ("Entrez un nom de compte svp.\n"); - printf (" who nomtest\n"); - ladmin_log ("Aucun nom n'a été donné pour trouver le compte.\n"); - } - else - { - printf ("Please input an account name.\n"); - printf (" who testname\n"); - ladmin_log ("No name was given to found the account.\n"); - } - return 136; - } - if (verify_accountname (name) == 0) - { - return 102; - } - - if (defaultlanguage == 'F') - { - ladmin_log - ("Envoi d'un requête au serveur de logins pour obtenir le information d'un compte (par le nom).\n"); - } - else - { - ladmin_log - ("Request to login-server to obtain information about an account (by its name).\n"); - } - - WFIFOW (login_fd, 0) = 0x7952; - memcpy (WFIFOP (login_fd, 2), name, 24); - WFIFOSET (login_fd, 26); - bytes_to_read = 1; - - return 0; -} - -//-------------------------------------------------------- -// Sub-function: Asking of the version of the login-server -//-------------------------------------------------------- -int checkloginversion (void) -{ - if (defaultlanguage == 'F') - ladmin_log - ("Envoi d'un requête au serveur de logins pour obtenir sa version.\n"); - else - ladmin_log ("Request to login-server to obtain its version.\n"); - - WFIFOW (login_fd, 0) = 0x7530; - WFIFOSET (login_fd, 2); - bytes_to_read = 1; - - return 0; -} - -//--------------------------------------------- -// Prompt function -// this function wait until user type a command -// and analyse the command. -//--------------------------------------------- -int prompt (void) -{ - int i, j; - char buf[1024]; - char *p; - - // while we don't wait new packets - while (bytes_to_read == 0) - { - // for help with the console colors look here: - // http://www.edoceo.com/liberum/?doc=printf-with-color - // some code explanation (used here): - // \033[2J : clear screen and go up/left (0, 0 position) - // \033[K : clear line from actual position to end of the line - // \033[0m : reset color parameter - // \033[1m : use bold for font - Iprintf ("\n"); - if (defaultlanguage == 'F') - { - Iprintf - ("\033[32mPour afficher les commandes, tapez 'Entrée'.\033[0m\n"); - } - else - Iprintf ("\033[32mTo list the commands, type 'enter'.\033[0m\n"); - Iprintf ("\033[0;36mLadmin-> \033[0m"); - Iprintf ("\033[1m"); - fflush (stdout); - - // get command and parameter - memset (buf, '\0', sizeof (buf)); - fflush (stdin); - if (!fgets (buf, 1023, stdin)) - exit (0); - buf[1023] = '\0'; - - Iprintf ("\033[0m"); - fflush (stdout); - - if (!eathena_interactive_session && !strlen (buf)) - exit (0); - - // remove final \n - if ((p = strrchr (buf, '\n')) != NULL) - p[0] = '\0'; - // remove all control char - for (i = 0; buf[i]; i++) - if (buf[i] < 32) - { - // remove cursor control. - if (buf[i] == 27 && buf[i + 1] == '[' && (buf[i + 2] == 'H' || // home position (cursor) - buf[i + 2] == 'J' || // clear screen - buf[i + 2] == 'A' || // up 1 line - buf[i + 2] == 'B' || // down 1 line - buf[i + 2] == 'C' || // right 1 position - buf[i + 2] == 'D' || // left 1 position - buf[i + 2] == 'G')) - { // center cursor (windows) - for (j = i; buf[j]; j++) - buf[j] = buf[j + 3]; - } - else if (buf[i] == 27 && buf[i + 1] == '[' - && buf[i + 2] == '2' && buf[i + 3] == 'J') - { // clear screen - for (j = i; buf[j]; j++) - buf[j] = buf[j + 4]; - } - else if (buf[i] == 27 && buf[i + 1] == '[' && buf[i + 3] == '~' && (buf[i + 2] == '1' || // home (windows) - buf[i + 2] == '2' || // insert (windows) - buf[i + 2] == '3' || // del (windows) - buf[i + 2] == '4' || // end (windows) - buf[i + 2] == '5' || // pgup (windows) - buf - [i - + - 2] - == - '6')) - { // pgdown (windows) - for (j = i; buf[j]; j++) - buf[j] = buf[j + 4]; - } - else - { - // remove other control char. - for (j = i; buf[j]; j++) - buf[j] = buf[j + 1]; - } - i--; - } - - // extract command name and parameters - memset (command, '\0', sizeof (command)); - memset (parameters, '\0', sizeof (parameters)); - sscanf (buf, "%1023s %[^\n]", command, parameters); - command[1023] = '\0'; - parameters[1023] = '\0'; - - // lowercase for command line - for (i = 0; command[i]; i++) - command[i] = tolower (command[i]); - - if (command[0] == '?' || strlen (command) == 0) - { - if (defaultlanguage == 'F') - { - strcpy (buf, "aide"); - strcpy (command, "aide"); - } - else - { - strcpy (buf, "help"); - strcpy (command, "help"); - } - } - - // Analyse of the command - check_command (command); // give complete name to the command - - if (strlen (parameters) == 0) - { - if (defaultlanguage == 'F') - { - ladmin_log ("Commande: '%s' (sans paramètre)\n", - command, parameters); - } - else - { - ladmin_log ("Command: '%s' (without parameters)\n", - command, parameters); - } - } - else - { - if (defaultlanguage == 'F') - { - ladmin_log ("Commande: '%s', paramètres: '%s'\n", - command, parameters); - } - else - { - ladmin_log ("Command: '%s', parameters: '%s'\n", - command, parameters); - } - } - - // Analyse of the command -// help - if (strcmp (command, "aide") == 0) - { - display_help (parameters, 1); // 1: french - } - else if (strcmp (command, "help") == 0) - { - display_help (parameters, 0); // 0: english -// general commands - } - else if (strcmp (command, "add") == 0) - { - addaccount (parameters, 0); // 0: no email - } - else if (strcmp (command, "ban") == 0) - { - banaccount (parameters); - } - else if (strcmp (command, "banadd") == 0) - { - banaddaccount (parameters); - } - else if (strcmp (command, "banset") == 0) - { - bansetaccount (parameters); - } - else if (strcmp (command, "block") == 0) - { - blockaccount (parameters); - } - else if (strcmp (command, "check") == 0) - { - checkaccount (parameters); - } - else if (strcmp (command, "create") == 0) - { - addaccount (parameters, 1); // 1: with email - } - else if (strcmp (command, "delete") == 0) - { - delaccount (parameters); - } - else if (strcmp (command, "email") == 0) - { - changeemail (parameters); - } - else if (strcmp (command, "getcount") == 0) - { - getlogincount (); - } - else if (strcmp (command, "gm") == 0) - { - changegmlevel (parameters); - } - else if (strcmp (command, "id") == 0) - { - idaccount (parameters); - } - else if (strcmp (command, "info") == 0) - { - infoaccount (atoi (parameters)); - } - else if (strcmp (command, "kami") == 0) - { - sendbroadcast (0, parameters); // flag for normal - } - else if (strcmp (command, "kamib") == 0) - { - sendbroadcast (0x10, parameters); // flag for blue - } - else if (strcmp (command, "language") == 0) - { - changelanguage (parameters); - } - else if (strcmp (command, "itemfrob") == 0) - { - itemfrob (parameters); // 0: to list all - } - else if (strcmp (command, "list") == 0) - { - listaccount (parameters, 0); // 0: to list all - } - else if (strcmp (command, "listban") == 0) - { - listaccount (parameters, 3); // 3: to list only accounts with state or bannished - } - else if (strcmp (command, "listgm") == 0) - { - listaccount (parameters, 1); // 1: to list only GM - } - else if (strcmp (command, "listok") == 0) - { - listaccount (parameters, 4); // 4: to list only accounts without state and not bannished - } - else if (strcmp (command, "memo") == 0) - { - changememo (parameters); - } - else if (strcmp (command, "name") == 0) - { - nameaccount (atoi (parameters)); - } - else if (strcmp (command, "password") == 0) - { - changepasswd (parameters); - } - else if (strcmp (command, "reloadgm") == 0) - { - reloadGM (); - } - else if (strcmp (command, "search") == 0) - { // no regex in C version - listaccount (parameters, 2); // 2: to list with pattern - } - else if (strcmp (command, "sex") == 0) - { - changesex (parameters); - } - else if (strcmp (command, "state") == 0) - { - changestate (parameters); - } - else if (strcmp (command, "timeadd") == 0) - { - timeaddaccount (parameters); - } - else if (strcmp (command, "timeset") == 0) - { - timesetaccount (parameters); - } - else if (strcmp (command, "unban") == 0) - { - unbanaccount (parameters); - } - else if (strcmp (command, "unblock") == 0) - { - unblockaccount (parameters); - } - else if (strcmp (command, "version") == 0) - { - checkloginversion (); - } - else if (strcmp (command, "who") == 0) - { - whoaccount (parameters); -// quit - } - else if (strcmp (command, "quit") == 0 || - strcmp (command, "exit") == 0 || - strcmp (command, "end") == 0) - { - if (defaultlanguage == 'F') - { - printf ("Au revoir.\n"); - } - else - { - printf ("Bye.\n"); - } - exit (0); -// unknown command - } - else - { - if (defaultlanguage == 'F') - { - printf ("Commande inconnue [%s].\n", buf); - ladmin_log ("Commande inconnue [%s].\n", buf); - } - else - { - printf ("Unknown command [%s].\n", buf); - ladmin_log ("Unknown command [%s].\n", buf); - } - } - } - - return 0; -} - -//------------------------------------------------------------- -// Function: Parse receiving informations from the login-server -//------------------------------------------------------------- -void parse_fromlogin (int fd) -{ - struct char_session_data *sd; - - if (session[fd]->eof) - { - if (defaultlanguage == 'F') - { - printf - ("Impossible de se connecter au serveur de login [%s:%d] !\n", - loginserverip, loginserverport); - ladmin_log - ("Impossible de se connecter au serveur de login [%s:%d] !\n", - loginserverip, loginserverport); - } - else - { - printf - ("Impossible to have a connection with the login-server [%s:%d] !\n", - loginserverip, loginserverport); - ladmin_log - ("Impossible to have a connection with the login-server [%s:%d] !\n", - loginserverip, loginserverport); - } - close (fd); - delete_session (fd); - exit (0); - } - -// printf("parse_fromlogin : %d %d %d\n", fd, RFIFOREST(fd), RFIFOW(fd,0)); - sd = (struct char_session_data *)session[fd]->session_data; - - while (RFIFOREST (fd) >= 2) - { - switch (RFIFOW (fd, 0)) - { - case 0x7919: // answer of a connection request - if (RFIFOREST (fd) < 3) - return; - if (RFIFOB (fd, 2) != 0) - { - if (defaultlanguage == 'F') - { - printf ("Erreur de login:\n"); - printf (" - mot de passe incorrect,\n"); - printf - (" - système d'administration non activé, ou\n"); - printf (" - IP non autorisée.\n"); - ladmin_log - ("Erreur de login: mot de passe incorrect, système d'administration non activé, ou IP non autorisée.\n"); - } - else - { - printf ("Error at login:\n"); - printf (" - incorrect password,\n"); - printf - (" - administration system not activated, or\n"); - printf (" - unauthorised IP.\n"); - ladmin_log - ("Error at login: incorrect password, administration system not activated, or unauthorised IP.\n"); - } - session[fd]->eof = 1; - //bytes_to_read = 1; // not stop at prompt - } - else - { - if (defaultlanguage == 'F') - { - printf ("Connexion établie.\n"); - ladmin_log ("Connexion établie.\n"); - printf - ("Lecture de la version du serveur de login...\n"); - ladmin_log - ("Lecture de la version du serveur de login...\n"); - } - else - { - Iprintf ("Established connection.\n"); - ladmin_log ("Established connection.\n"); - Iprintf - ("Reading of the version of the login-server...\n"); - ladmin_log - ("Reading of the version of the login-server...\n"); - } - //bytes_to_read = 1; // unchanged - checkloginversion (); - } - RFIFOSKIP (fd, 3); - break; - -#ifdef PASSWORDENC - case 0x01dc: // answer of a coding key request - if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) - return; - { - char md5str[64] = - "", md5bin[32], md5key[RFIFOW (fd, 2) - 4 + 1]; - memcpy (md5key, RFIFOP (fd, 4), RFIFOW (fd, 2) - 4); - md5key[sizeof (md5key) - 1] = '0'; - if (passenc == 1) - { - strncpy (md5str, RFIFOP (fd, 4), RFIFOW (fd, 2) - 4); - strcat (md5str, loginserveradminpassword); - } - else if (passenc == 2) - { - strncpy (md5str, loginserveradminpassword, - sizeof (loginserveradminpassword)); - strcat (md5str, RFIFOP (fd, 4)); - } - MD5_to_bin(MD5_from_cstring(md5str), md5bin); - WFIFOW (login_fd, 0) = 0x7918; // Request for administation login (encrypted password) - WFIFOW (login_fd, 2) = passenc; // Encrypted type - memcpy (WFIFOP (login_fd, 4), md5bin, 16); - WFIFOSET (login_fd, 20); - if (defaultlanguage == 'F') - { - Iprintf ("Réception de la clef MD5.\n"); - ladmin_log ("Réception de la clef MD5.\n"); - Iprintf ("Envoi du mot de passe crypté...\n"); - ladmin_log ("Envoi du mot de passe crypté...\n"); - } - else - { - Iprintf ("Receiving of the MD5 key.\n"); - ladmin_log ("Receiving of the MD5 key.\n"); - Iprintf ("Sending of the encrypted password...\n"); - ladmin_log ("Sending of the encrypted password...\n"); - } - } - bytes_to_read = 1; - RFIFOSKIP (fd, RFIFOW (fd, 2)); - break; -#endif - - case 0x7531: // Displaying of the version of the login-server - if (RFIFOREST (fd) < 10) - return; - Iprintf (" Login-Server [%s:%d]\n", loginserverip, - loginserverport); - if (((int) RFIFOB (login_fd, 5)) == 0) - { - Iprintf (" eAthena version stable-%d.%d", - (int) RFIFOB (login_fd, 2), - (int) RFIFOB (login_fd, 3)); - } - else - { - Iprintf (" eAthena version dev-%d.%d", - (int) RFIFOB (login_fd, 2), - (int) RFIFOB (login_fd, 3)); - } - if (((int) RFIFOB (login_fd, 4)) == 0) - Iprintf (" revision %d", (int) RFIFOB (login_fd, 4)); - if (((int) RFIFOB (login_fd, 6)) == 0) - { - Iprintf ("%d.\n", RFIFOW (login_fd, 8)); - } - else - Iprintf ("-mod%d.\n", RFIFOW (login_fd, 8)); - bytes_to_read = 0; - RFIFOSKIP (fd, 10); - break; - - case 0x7925: // Itemfrob-OK - RFIFOSKIP (fd, 2); - bytes_to_read = 0; - break; - - case 0x7921: // Displaying of the list of accounts - if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) - return; - if (RFIFOW (fd, 2) < 5) - { - if (defaultlanguage == 'F') - { - ladmin_log - (" Réception d'une liste des comptes vide.\n"); - if (list_count == 0) - printf ("Aucun compte trouvé.\n"); - else if (list_count == 1) - printf ("1 compte trouvé.\n"); - else - printf ("%d comptes trouvés.\n", list_count); - } - else - { - ladmin_log (" Receiving of a void accounts list.\n"); - if (list_count == 0) - { - Iprintf ("No account found.\n"); - } - else if (list_count == 1) - { - Iprintf ("1 account found.\n"); - } - else - Iprintf ("%d accounts found.\n", list_count); - } - bytes_to_read = 0; - } - else - { - int i; - if (defaultlanguage == 'F') - ladmin_log (" Réception d'une liste des comptes.\n"); - else - ladmin_log (" Receiving of a accounts list.\n"); - for (i = 4; i < RFIFOW (fd, 2); i += 38) - { - int j; - char userid[24]; - char lower_userid[24]; - memcpy (userid, RFIFOP (fd, i + 5), sizeof (userid)); - userid[sizeof (userid) - 1] = '\0'; - memset (lower_userid, '\0', sizeof (lower_userid)); - for (j = 0; userid[j]; j++) - lower_userid[j] = tolower (userid[j]); - list_first = RFIFOL (fd, i) + 1; - // here are checks... - if (list_type == 0 || - (list_type == 1 && RFIFOB (fd, i + 4) > 0) || - (list_type == 2 - && strstr (lower_userid, parameters) != NULL) - || (list_type == 3 && RFIFOL (fd, i + 34) != 0) - || (list_type == 4 && RFIFOL (fd, i + 34) == 0)) - { - printf ("%10d ", RFIFOL (fd, i)); - if (RFIFOB (fd, i + 4) == 0) - printf (" "); - else - printf ("%2d ", (int) RFIFOB (fd, i + 4)); - printf ("%-24s", userid); - if (defaultlanguage == 'F') - { - if (RFIFOB (fd, i + 29) == 0) - printf ("%-5s ", "Femme"); - else if (RFIFOB (fd, i + 29) == 1) - printf ("%-5s ", "Male"); - else - printf ("%-5s ", "Servr"); - } - else - { - if (RFIFOB (fd, i + 29) == 0) - printf ("%-5s ", "Femal"); - else if (RFIFOB (fd, i + 29) == 1) - printf ("%-5s ", "Male"); - else - printf ("%-5s ", "Servr"); - } - printf ("%6d ", RFIFOL (fd, i + 30)); - switch (RFIFOL (fd, i + 34)) - { - case 0: - if (defaultlanguage == 'F') - printf ("%-27s\n", "Compte Ok"); - else - printf ("%-27s\n", "Account OK"); - break; - case 1: - printf ("%-27s\n", "Unregistered ID"); - break; - case 2: - printf ("%-27s\n", "Incorrect Password"); - break; - case 3: - printf ("%-27s\n", "This ID is expired"); - break; - case 4: - printf ("%-27s\n", - "Rejected from Server"); - break; - case 5: - printf ("%-27s\n", "Blocked by the GM Team"); // You have been blocked by the GM Team - break; - case 6: - printf ("%-27s\n", "Your EXE file is too old"); // Your Game's EXE file is not the latest version - break; - case 7: - printf ("%-27s\n", "Banishement or"); - printf (" Prohibited to login until...\n"); // You are Prohibited to log in until %s - break; - case 8: - printf ("%-27s\n", - "Server is over populated"); - break; - case 9: - printf ("%-27s\n", "No MSG"); - break; - default: // 100 - printf ("%-27s\n", "This ID is totally erased"); // This ID has been totally erased - break; - } - list_count++; - } - } - // asking of the following acounts - if (defaultlanguage == 'F') - ladmin_log - ("Envoi d'un requête au serveur de logins pour obtenir la liste des comptes de %d à %d (complément).\n", - list_first, list_last); - else - ladmin_log - ("Request to login-server to obtain the list of accounts from %d to %d (complement).\n", - list_first, list_last); - WFIFOW (login_fd, 0) = 0x7920; - WFIFOL (login_fd, 2) = list_first; - WFIFOL (login_fd, 6) = list_last; - WFIFOSET (login_fd, 10); - bytes_to_read = 1; - } - RFIFOSKIP (fd, RFIFOW (fd, 2)); - break; - - case 0x7931: // Answer of login-server about an account creation - if (RFIFOREST (fd) < 30) - return; - if (RFIFOL (fd, 2) == -1) - { - if (defaultlanguage == 'F') - { - printf - ("Echec à la création du compte [%s]. Un compte identique existe déjà.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Echec à la création du compte [%s]. Un compte identique existe déjà.\n", - RFIFOP (fd, 6)); - } - else - { - printf - ("Account [%s] creation failed. Same account already exists.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Account [%s] creation failed. Same account already exists.\n", - RFIFOP (fd, 6)); - } - } - else - { - if (defaultlanguage == 'F') - { - printf ("Compte [%s] créé avec succès [id: %d].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log ("Compte [%s] créé avec succès [id: %d].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - else - { - printf - ("Account [%s] is successfully created [id: %d].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Account [%s] is successfully created [id: %d].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - } - bytes_to_read = 0; - RFIFOSKIP (fd, 30); - break; - - case 0x7933: // Answer of login-server about an account deletion - if (RFIFOREST (fd) < 30) - return; - if (RFIFOL (fd, 2) == -1) - { - if (defaultlanguage == 'F') - { - printf - ("Echec de la suppression du compte [%s]. Le compte n'existe pas.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Echec de la suppression du compte [%s]. Le compte n'existe pas.\n", - RFIFOP (fd, 6)); - } - else - { - printf - ("Account [%s] deletion failed. Account doesn't exist.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Account [%s] deletion failed. Account doesn't exist.\n", - RFIFOP (fd, 6)); - } - } - else - { - if (defaultlanguage == 'F') - { - printf ("Compte [%s][id: %d] SUPPRIME avec succès.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Compte [%s][id: %d] SUPPRIME avec succès.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - else - { - printf - ("Account [%s][id: %d] is successfully DELETED.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Account [%s][id: %d] is successfully DELETED.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - } - bytes_to_read = 0; - RFIFOSKIP (fd, 30); - break; - - case 0x7935: // answer of the change of an account password - if (RFIFOREST (fd) < 30) - return; - if (RFIFOL (fd, 2) == -1) - { - if (defaultlanguage == 'F') - { - printf - ("Echec de la modification du mot de passe du compte [%s].\n", - RFIFOP (fd, 6)); - printf ("Le compte [%s] n'existe pas.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Echec de la modification du mot de passe du compte. Le compte [%s] n'existe pas.\n", - RFIFOP (fd, 6)); - } - else - { - printf ("Account [%s] password changing failed.\n", - RFIFOP (fd, 6)); - printf ("Account [%s] doesn't exist.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Account password changing failed. The compte [%s] doesn't exist.\n", - RFIFOP (fd, 6)); - } - } - else - { - if (defaultlanguage == 'F') - { - printf - ("Modification du mot de passe du compte [%s][id: %d] réussie.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Modification du mot de passe du compte [%s][id: %d] réussie.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - else - { - printf - ("Account [%s][id: %d] password successfully changed.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Account [%s][id: %d] password successfully changed.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - } - bytes_to_read = 0; - RFIFOSKIP (fd, 30); - break; - - case 0x7937: // answer of the change of an account state - if (RFIFOREST (fd) < 34) - return; - if (RFIFOL (fd, 2) == -1) - { - if (defaultlanguage == 'F') - { - printf - ("Echec du changement du statut du compte [%s]. Le compte n'existe pas.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Echec du changement du statut du compte [%s]. Le compte n'existe pas.\n", - RFIFOP (fd, 6)); - } - else - { - printf - ("Account [%s] state changing failed. Account doesn't exist.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Account [%s] state changing failed. Account doesn't exist.\n", - RFIFOP (fd, 6)); - } - } - else - { - char tmpstr[256]; - if (defaultlanguage == 'F') - { - sprintf (tmpstr, - "Statut du compte [%s] changé avec succès en [", - RFIFOP (fd, 6)); - } - else - { - sprintf (tmpstr, - "Account [%s] state successfully changed in [", - RFIFOP (fd, 6)); - } - switch (RFIFOL (fd, 30)) - { - case 0: - if (defaultlanguage == 'F') - strcat (tmpstr, "0: Compte Ok"); - else - strcat (tmpstr, "0: Account OK"); - break; - case 1: - strcat (tmpstr, "1: Unregistered ID"); - break; - case 2: - strcat (tmpstr, "2: Incorrect Password"); - break; - case 3: - strcat (tmpstr, "3: This ID is expired"); - break; - case 4: - strcat (tmpstr, "4: Rejected from Server"); - break; - case 5: - strcat (tmpstr, - "5: You have been blocked by the GM Team"); - break; - case 6: - strcat (tmpstr, - "6: [Your Game's EXE file is not the latest version"); - break; - case 7: - strcat (tmpstr, - "7: You are Prohibited to log in until..."); - break; - case 8: - strcat (tmpstr, - "8: Server is jammed due to over populated"); - break; - case 9: - strcat (tmpstr, "9: No MSG"); - break; - default: // 100 - strcat (tmpstr, "100: This ID is totally erased"); - break; - } - strcat (tmpstr, "]"); - printf ("%s\n", tmpstr); - ladmin_log ("%s%s", tmpstr, "\n"); - } - bytes_to_read = 0; - RFIFOSKIP (fd, 34); - break; - - case 0x7939: // answer of the number of online players - if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) - return; - { - // Get length of the received packet - int i; - char name[20]; - if (defaultlanguage == 'F') - { - ladmin_log - (" Réception du nombre de joueurs en ligne.\n"); - } - else - { - ladmin_log - (" Receiving of the number of online players.\n"); - } - // Read information of the servers - if (RFIFOW (fd, 2) < 5) - { - if (defaultlanguage == 'F') - { - printf - (" Aucun serveur n'est connecté au login serveur.\n"); - } - else - { - printf - (" No server is connected to the login-server.\n"); - } - } - else - { - if (defaultlanguage == 'F') - { - printf - (" Nombre de joueurs en ligne (serveur: nb):\n"); - } - else - { - printf - (" Number of online players (server: number).\n"); - } - // Displaying of result - for (i = 4; i < RFIFOW (fd, 2); i += 32) - { - memcpy (name, RFIFOP (fd, i + 6), sizeof (name)); - name[sizeof (name) - 1] = '\0'; - printf (" %-20s : %5d\n", name, - RFIFOW (fd, i + 26)); - } - } - } - bytes_to_read = 0; - RFIFOSKIP (fd, RFIFOW (fd, 2)); - break; - - case 0x793b: // answer of the check of a password - if (RFIFOREST (fd) < 30) - return; - if (RFIFOL (fd, 2) == -1) - { - if (defaultlanguage == 'F') - { - printf - ("Le compte [%s] n'existe pas ou le mot de passe est incorrect.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Le compte [%s] n'existe pas ou le mot de passe est incorrect.\n", - RFIFOP (fd, 6)); - } - else - { - printf - ("The account [%s] doesn't exist or the password is incorrect.\n", - RFIFOP (fd, 6)); - ladmin_log - ("The account [%s] doesn't exist or the password is incorrect.\n", - RFIFOP (fd, 6)); - } - } - else - { - if (defaultlanguage == 'F') - { - printf - ("Le mot de passe donné correspond bien au compte [%s][id: %d].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Le mot de passe donné correspond bien au compte [%s][id: %d].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - else - { - printf - ("The proposed password is correct for the account [%s][id: %d].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("The proposed password is correct for the account [%s][id: %d].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - } - bytes_to_read = 0; - RFIFOSKIP (fd, 30); - break; - - case 0x793d: // answer of the change of an account sex - if (RFIFOREST (fd) < 30) - return; - if (RFIFOL (fd, 2) == -1) - { - if (defaultlanguage == 'F') - { - printf - ("Echec de la modification du sexe du compte [%s].\n", - RFIFOP (fd, 6)); - printf - ("Le compte [%s] n'existe pas ou le sexe est déjà celui demandé.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Echec de la modification du sexe du compte. Le compte [%s] n'existe pas ou le sexe est déjà celui demandé.\n", - RFIFOP (fd, 6)); - } - else - { - printf ("Account [%s] sex changing failed.\n", - RFIFOP (fd, 6)); - printf - ("Account [%s] doesn't exist or the sex is already the good sex.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Account sex changing failed. The compte [%s] doesn't exist or the sex is already the good sex.\n", - RFIFOP (fd, 6)); - } - } - else - { - if (defaultlanguage == 'F') - { - printf - ("Sexe du compte [%s][id: %d] changé avec succès.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Sexe du compte [%s][id: %d] changé avec succès.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - else - { - printf - ("Account [%s][id: %d] sex successfully changed.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Account [%s][id: %d] sex successfully changed.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - } - bytes_to_read = 0; - RFIFOSKIP (fd, 30); - break; - - case 0x793f: // answer of the change of an account GM level - if (RFIFOREST (fd) < 30) - return; - if (RFIFOL (fd, 2) == -1) - { - if (defaultlanguage == 'F') - { - printf - ("Echec de la modification du niveau de GM du compte [%s].\n", - RFIFOP (fd, 6)); - printf - ("Le compte [%s] n'existe pas, le niveau de GM est déjà celui demandé\n", - RFIFOP (fd, 6)); - printf - ("ou il est impossible de modifier le fichier des comptes GM.\n"); - ladmin_log - ("Echec de la modification du niveau de GM du compte. Le compte [%s] n'existe pas, le niveau de GM est déjà celui demandé ou il est impossible de modifier le fichier des comptes GM.\n", - RFIFOP (fd, 6)); - } - else - { - printf ("Account [%s] GM level changing failed.\n", - RFIFOP (fd, 6)); - printf - ("Account [%s] doesn't exist, the GM level is already the good GM level\n", - RFIFOP (fd, 6)); - printf - ("or it's impossible to modify the GM accounts file.\n"); - ladmin_log - ("Account GM level changing failed. The compte [%s] doesn't exist, the GM level is already the good sex or it's impossible to modify the GM accounts file.\n", - RFIFOP (fd, 6)); - } - } - else - { - if (defaultlanguage == 'F') - { - printf - ("Niveau de GM du compte [%s][id: %d] changé avec succès.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Niveau de GM du compte [%s][id: %d] changé avec succès.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - else - { - printf - ("Account [%s][id: %d] GM level successfully changed.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Account [%s][id: %d] GM level successfully changed.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - } - bytes_to_read = 0; - RFIFOSKIP (fd, 30); - break; - - case 0x7941: // answer of the change of an account email - if (RFIFOREST (fd) < 30) - return; - if (RFIFOL (fd, 2) == -1) - { - if (defaultlanguage == 'F') - { - printf - ("Echec de la modification de l'e-mail du compte [%s].\n", - RFIFOP (fd, 6)); - printf ("Le compte [%s] n'existe pas.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Echec de la modification de l'e-mail du compte. Le compte [%s] n'existe pas.\n", - RFIFOP (fd, 6)); - } - else - { - printf ("Account [%s] e-mail changing failed.\n", - RFIFOP (fd, 6)); - printf ("Account [%s] doesn't exist.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Account e-mail changing failed. The compte [%s] doesn't exist.\n", - RFIFOP (fd, 6)); - } - } - else - { - if (defaultlanguage == 'F') - { - printf - ("Modification de l'e-mail du compte [%s][id: %d] réussie.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Modification de l'e-mail du compte [%s][id: %d] réussie.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - else - { - printf - ("Account [%s][id: %d] e-mail successfully changed.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Account [%s][id: %d] e-mail successfully changed.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - } - bytes_to_read = 0; - RFIFOSKIP (fd, 30); - break; - - case 0x7943: // answer of the change of an account memo - if (RFIFOREST (fd) < 30) - return; - if (RFIFOL (fd, 2) == -1) - { - if (defaultlanguage == 'F') - { - printf - ("Echec du changement du mémo du compte [%s]. Le compte n'existe pas.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Echec du changement du mémo du compte [%s]. Le compte n'existe pas.\n", - RFIFOP (fd, 6)); - } - else - { - printf - ("Account [%s] memo changing failed. Account doesn't exist.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Account [%s] memo changing failed. Account doesn't exist.\n", - RFIFOP (fd, 6)); - } - } - else - { - if (defaultlanguage == 'F') - { - printf - ("Mémo du compte [%s][id: %d] changé avec succès.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Mémo du compte [%s][id: %d] changé avec succès.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - else - { - printf - ("Account [%s][id: %d] memo successfully changed.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Account [%s][id: %d] memo successfully changed.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - } - bytes_to_read = 0; - RFIFOSKIP (fd, 30); - break; - - case 0x7945: // answer of an account id search - if (RFIFOREST (fd) < 30) - return; - if (RFIFOL (fd, 2) == -1) - { - if (defaultlanguage == 'F') - { - printf - ("Impossible de trouver l'id du compte [%s]. Le compte n'existe pas.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Impossible de trouver l'id du compte [%s]. Le compte n'existe pas.\n", - RFIFOP (fd, 6)); - } - else - { - printf - ("Unable to find the account [%s] id. Account doesn't exist.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Unable to find the account [%s] id. Account doesn't exist.\n", - RFIFOP (fd, 6)); - } - } - else - { - if (defaultlanguage == 'F') - { - printf ("Le compte [%s] a pour id: %d.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log ("Le compte [%s] a pour id: %d.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - else - { - printf ("The account [%s] have the id: %d.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log ("The account [%s] have the id: %d.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - } - bytes_to_read = 0; - RFIFOSKIP (fd, 30); - break; - - case 0x7947: // answer of an account name search - if (RFIFOREST (fd) < 30) - return; - if (strcmp (RFIFOP (fd, 6), "") == 0) - { - if (defaultlanguage == 'F') - { - printf - ("Impossible de trouver le nom du compte [%d]. Le compte n'existe pas.\n", - RFIFOL (fd, 2)); - ladmin_log - ("Impossible de trouver le nom du compte [%d]. Le compte n'existe pas.\n", - RFIFOL (fd, 2)); - } - else - { - printf - ("Unable to find the account [%d] name. Account doesn't exist.\n", - RFIFOL (fd, 2)); - ladmin_log - ("Unable to find the account [%d] name. Account doesn't exist.\n", - RFIFOL (fd, 2)); - } - } - else - { - if (defaultlanguage == 'F') - { - printf ("Le compte [id: %d] a pour nom: %s.\n", - RFIFOL (fd, 2), RFIFOP (fd, 6)); - ladmin_log ("Le compte [id: %d] a pour nom: %s.\n", - RFIFOL (fd, 2), RFIFOP (fd, 6)); - } - else - { - printf ("The account [id: %d] have the name: %s.\n", - RFIFOL (fd, 2), RFIFOP (fd, 6)); - ladmin_log ("The account [id: %d] have the name: %s.\n", - RFIFOL (fd, 2), RFIFOP (fd, 6)); - } - } - bytes_to_read = 0; - RFIFOSKIP (fd, 30); - break; - - case 0x7949: // answer of an account validity limit set - if (RFIFOREST (fd) < 34) - return; - if (RFIFOL (fd, 2) == -1) - { - if (defaultlanguage == 'F') - { - printf - ("Echec du changement de la validité du compte [%s]. Le compte n'existe pas.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Echec du changement de la validité du compte [%s]. Le compte n'existe pas.\n", - RFIFOP (fd, 6)); - } - else - { - printf - ("Account [%s] validity limit changing failed. Account doesn't exist.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Account [%s] validity limit changing failed. Account doesn't exist.\n", - RFIFOP (fd, 6)); - } - } - else - { - time_t timestamp = RFIFOL (fd, 30); - if (timestamp == 0) - { - if (defaultlanguage == 'F') - { - printf - ("Limite de validité du compte [%s][id: %d] changée avec succès en [illimité].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Limite de validité du compte [%s][id: %d] changée avec succès en [illimité].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - else - { - printf - ("Validity Limit of the account [%s][id: %d] successfully changed to [unlimited].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Validity Limit of the account [%s][id: %d] successfully changed to [unlimited].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - } - else - { - char tmpstr[128]; - strftime (tmpstr, 24, date_format, - localtime (×tamp)); - if (defaultlanguage == 'F') - { - printf - ("Limite de validité du compte [%s][id: %d] changée avec succès pour être jusqu'au %s.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2), tmpstr); - ladmin_log - ("Limite de validité du compte [%s][id: %d] changée avec succès pour être jusqu'au %s.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2), - tmpstr); - } - else - { - printf - ("Validity Limit of the account [%s][id: %d] successfully changed to be until %s.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2), tmpstr); - ladmin_log - ("Validity Limit of the account [%s][id: %d] successfully changed to be until %s.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2), - tmpstr); - } - } - } - bytes_to_read = 0; - RFIFOSKIP (fd, 34); - break; - - case 0x794b: // answer of an account ban set - if (RFIFOREST (fd) < 34) - return; - if (RFIFOL (fd, 2) == -1) - { - if (defaultlanguage == 'F') - { - printf - ("Echec du changement de la date finale de banissement du compte [%s]. Le compte n'existe pas.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Echec du changement de la date finale de banissement du compte [%s]. Le compte n'existe pas.\n", - RFIFOP (fd, 6)); - } - else - { - printf - ("Account [%s] final date of banishment changing failed. Account doesn't exist.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Account [%s] final date of banishment changing failed. Account doesn't exist.\n", - RFIFOP (fd, 6)); - } - } - else - { - time_t timestamp = RFIFOL (fd, 30); - if (timestamp == 0) - { - if (defaultlanguage == 'F') - { - printf - ("Date finale de banissement du compte [%s][id: %d] changée avec succès en [dé-bannie].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Date finale de banissement du compte [%s][id: %d] changée avec succès en [dé-bannie].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - else - { - printf - ("Final date of banishment of the account [%s][id: %d] successfully changed to [unbanished].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Final date of banishment of the account [%s][id: %d] successfully changed to [unbanished].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - } - else - { - char tmpstr[128]; - strftime (tmpstr, 24, date_format, - localtime (×tamp)); - if (defaultlanguage == 'F') - { - printf - ("Date finale de banissement du compte [%s][id: %d] changée avec succès pour être jusqu'au %s.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2), tmpstr); - ladmin_log - ("Date finale de banissement du compte [%s][id: %d] changée avec succès pour être jusqu'au %s.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2), - tmpstr); - } - else - { - printf - ("Final date of banishment of the account [%s][id: %d] successfully changed to be until %s.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2), tmpstr); - ladmin_log - ("Final date of banishment of the account [%s][id: %d] successfully changed to be until %s.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2), - tmpstr); - } - } - } - bytes_to_read = 0; - RFIFOSKIP (fd, 34); - break; - - case 0x794d: // answer of an account ban date/time changing - if (RFIFOREST (fd) < 34) - return; - if (RFIFOL (fd, 2) == -1) - { - if (defaultlanguage == 'F') - { - printf - ("Echec du changement de la date finale de banissement du compte [%s]. Le compte n'existe pas.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Echec du changement de la date finale de banissement du compte [%s]. Le compte n'existe pas.\n", - RFIFOP (fd, 6)); - } - else - { - printf - ("Account [%s] final date of banishment changing failed. Account doesn't exist.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Account [%s] final date of banishment changing failed. Account doesn't exist.\n", - RFIFOP (fd, 6)); - } - } - else - { - time_t timestamp = RFIFOL (fd, 30); - if (timestamp == 0) - { - if (defaultlanguage == 'F') - { - printf - ("Date finale de banissement du compte [%s][id: %d] changée avec succès en [dé-bannie].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Date finale de banissement du compte [%s][id: %d] changée avec succès en [dé-bannie].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - else - { - printf - ("Final date of banishment of the account [%s][id: %d] successfully changed to [unbanished].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - ladmin_log - ("Final date of banishment of the account [%s][id: %d] successfully changed to [unbanished].\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - } - else - { - char tmpstr[128]; - strftime (tmpstr, 24, date_format, - localtime (×tamp)); - if (defaultlanguage == 'F') - { - printf - ("Date finale de banissement du compte [%s][id: %d] changée avec succès pour être jusqu'au %s.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2), tmpstr); - ladmin_log - ("Date finale de banissement du compte [%s][id: %d] changée avec succès pour être jusqu'au %s.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2), - tmpstr); - } - else - { - printf - ("Final date of banishment of the account [%s][id: %d] successfully changed to be until %s.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2), tmpstr); - ladmin_log - ("Final date of banishment of the account [%s][id: %d] successfully changed to be until %s.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2), - tmpstr); - } - } - } - bytes_to_read = 0; - RFIFOSKIP (fd, 34); - break; - - case 0x794f: // answer of a broadcast - if (RFIFOREST (fd) < 4) - return; - if (RFIFOW (fd, 2) == (unsigned short) -1) - { - if (defaultlanguage == 'F') - { - printf - ("Echec de l'envoi du message. Aucun server de char en ligne.\n"); - ladmin_log - ("Echec de l'envoi du message. Aucun server de char en ligne.\n"); - } - else - { - printf - ("Message sending failed. No online char-server.\n"); - ladmin_log - ("Message sending failed. No online char-server.\n"); - } - } - else - { - if (defaultlanguage == 'F') - { - printf - ("Message transmis au server de logins avec succès.\n"); - ladmin_log - ("Message transmis au server de logins avec succès.\n"); - } - else - { - printf - ("Message successfully sended to login-server.\n"); - ladmin_log - ("Message successfully sended to login-server.\n"); - } - } - bytes_to_read = 0; - RFIFOSKIP (fd, 4); - break; - - case 0x7951: // answer of an account validity limit changing - if (RFIFOREST (fd) < 34) - return; - if (RFIFOL (fd, 2) == -1) - { - if (defaultlanguage == 'F') - { - printf - ("Echec du changement de la validité du compte [%s]. Le compte n'existe pas.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Echec du changement de la validité du compte [%s]. Le compte n'existe pas.\n", - RFIFOP (fd, 6)); - } - else - { - printf - ("Account [%s] validity limit changing failed. Account doesn't exist.\n", - RFIFOP (fd, 6)); - ladmin_log - ("Account [%s] validity limit changing failed. Account doesn't exist.\n", - RFIFOP (fd, 6)); - } - } - else - { - time_t timestamp = RFIFOL (fd, 30); - if (timestamp == 0) - { - if (defaultlanguage == 'F') - { - printf - ("Limite de validité du compte [%s][id: %d] inchangée.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - printf - ("Le compte a une validité illimitée ou\n"); - printf - ("la modification est impossible avec les ajustements demandés.\n"); - ladmin_log - ("Limite de validité du compte [%s][id: %d] inchangée. Le compte a une validité illimitée ou la modification est impossible avec les ajustements demandés.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - else - { - printf - ("Validity limit of the account [%s][id: %d] unchanged.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - printf - ("The account have an unlimited validity limit or\n"); - printf - ("the changing is impossible with the proposed adjustments.\n"); - ladmin_log - ("Validity limit of the account [%s][id: %d] unchanged. The account have an unlimited validity limit or the changing is impossible with the proposed adjustments.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2)); - } - } - else - { - char tmpstr[128]; - strftime (tmpstr, 24, date_format, - localtime (×tamp)); - if (defaultlanguage == 'F') - { - printf - ("Limite de validité du compte [%s][id: %d] changée avec succès pour être jusqu'au %s.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2), tmpstr); - ladmin_log - ("Limite de validité du compte [%s][id: %d] changée avec succès pour être jusqu'au %s.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2), - tmpstr); - } - else - { - printf - ("Validity limit of the account [%s][id: %d] successfully changed to be until %s.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2), tmpstr); - ladmin_log - ("Validity limit of the account [%s][id: %d] successfully changed to be until %s.\n", - RFIFOP (fd, 6), RFIFOL (fd, 2), - tmpstr); - } - } - } - bytes_to_read = 0; - RFIFOSKIP (fd, 34); - break; - - case 0x7953: // answer of a request about informations of an account (by account name/id) - if (RFIFOREST (fd) < 150 - || RFIFOREST (fd) < (150 + RFIFOW (fd, 148))) - return; - { - char userid[24], error_message[20], lastlogin[24], - last_ip[16], email[40], memo[255]; - time_t ban_until_time; // # of seconds 1/1/1970 (timestamp): ban time limit of the account (0 = no ban) - time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) - memcpy (userid, RFIFOP (fd, 7), sizeof (userid)); - userid[sizeof (userid) - 1] = '\0'; - memcpy (error_message, RFIFOP (fd, 40), - sizeof (error_message)); - error_message[sizeof (error_message) - 1] = '\0'; - memcpy (lastlogin, RFIFOP (fd, 60), sizeof (lastlogin)); - lastlogin[sizeof (lastlogin) - 1] = '\0'; - memcpy (last_ip, RFIFOP (fd, 84), sizeof (last_ip)); - last_ip[sizeof (last_ip) - 1] = '\0'; - memcpy (email, RFIFOP (fd, 100), sizeof (email)); - email[sizeof (email) - 1] = '\0'; - connect_until_time = (time_t) RFIFOL (fd, 140); - ban_until_time = (time_t) RFIFOL (fd, 144); - memset (memo, '\0', sizeof (memo)); - strncpy (memo, RFIFOP (fd, 150), RFIFOW (fd, 148)); - if (RFIFOL (fd, 2) == -1) - { - if (defaultlanguage == 'F') - { - printf - ("Impossible de trouver le compte [%s]. Le compte n'existe pas.\n", - parameters); - ladmin_log - ("Impossible de trouver le compte [%s]. Le compte n'existe pas.\n", - parameters); - } - else - { - printf - ("Unabled to find the account [%s]. Account doesn't exist.\n", - parameters); - ladmin_log - ("Unabled to find the account [%s]. Account doesn't exist.\n", - parameters); - } - } - else if (strlen (userid) == 0) - { - if (defaultlanguage == 'F') - { - printf - ("Impossible de trouver le compte [id: %s]. Le compte n'existe pas.\n", - parameters); - ladmin_log - ("Impossible de trouver le compte [id: %s]. Le compte n'existe pas.\n", - parameters); - } - else - { - printf - ("Unabled to find the account [id: %s]. Account doesn't exist.\n", - parameters); - ladmin_log - ("Unabled to find the account [id: %s]. Account doesn't exist.\n", - parameters); - } - } - else - { - if (defaultlanguage == 'F') - { - ladmin_log - ("Réception d'information concernant un compte.\n"); - printf - ("Le compte a les caractéristiques suivantes:\n"); - } - else - { - ladmin_log - ("Receiving information about an account.\n"); - printf ("The account is set with:\n"); - } - if (RFIFOB (fd, 6) == 0) - { - printf (" Id: %d (non-GM)\n", RFIFOL (fd, 2)); - } - else - { - if (defaultlanguage == 'F') - { - printf (" Id: %d (GM niveau %d)\n", - RFIFOL (fd, 2), (int) RFIFOB (fd, 6)); - } - else - { - printf (" Id: %d (GM level %d)\n", - RFIFOL (fd, 2), (int) RFIFOB (fd, 6)); - } - } - if (defaultlanguage == 'F') - { - printf (" Nom: '%s'\n", userid); - if (RFIFOB (fd, 31) == 0) - printf (" Sexe: Femme\n"); - else if (RFIFOB (fd, 31) == 1) - printf (" Sexe: Male\n"); - else - printf (" Sexe: Serveur\n"); - } - else - { - printf (" Name: '%s'\n", userid); - if (RFIFOB (fd, 31) == 0) - printf (" Sex: Female\n"); - else if (RFIFOB (fd, 31) == 1) - printf (" Sex: Male\n"); - else - printf (" Sex: Server\n"); - } - printf (" E-mail: %s\n", email); - switch (RFIFOL (fd, 36)) - { - case 0: - if (defaultlanguage == 'F') - printf (" Statut: 0 [Compte Ok]\n"); - else - printf (" Statut: 0 [Account OK]\n"); - break; - case 1: - printf (" Statut: 1 [Unregistered ID]\n"); - break; - case 2: - printf (" Statut: 2 [Incorrect Password]\n"); - break; - case 3: - printf (" Statut: 3 [This ID is expired]\n"); - break; - case 4: - printf - (" Statut: 4 [Rejected from Server]\n"); - break; - case 5: - printf - (" Statut: 5 [You have been blocked by the GM Team]\n"); - break; - case 6: - printf - (" Statut: 6 [Your Game's EXE file is not the latest version]\n"); - break; - case 7: - printf - (" Statut: 7 [You are Prohibited to log in until %s]\n", - error_message); - break; - case 8: - printf - (" Statut: 8 [Server is jammed due to over populated]\n"); - break; - case 9: - printf (" Statut: 9 [No MSG]\n"); - break; - default: // 100 - printf - (" Statut: %d [This ID is totally erased]\n", - RFIFOL (fd, 36)); - break; - } - if (defaultlanguage == 'F') - { - if (ban_until_time == 0) - { - printf (" Banissement: non banni.\n"); - } - else - { - char tmpstr[128]; - strftime (tmpstr, 24, date_format, - localtime (&ban_until_time)); - printf (" Banissement: jusqu'au %s.\n", - tmpstr); - } - if (RFIFOL (fd, 32) > 1) - printf (" Compteur: %d connexions.\n", - RFIFOL (fd, 32)); - else - printf (" Compteur: %d connexion.\n", - RFIFOL (fd, 32)); - printf (" Dernière connexion le: %s (ip: %s)\n", - lastlogin, last_ip); - if (connect_until_time == 0) - { - printf (" Limite de validité: illimité.\n"); - } - else - { - char tmpstr[128]; - strftime (tmpstr, 24, date_format, - localtime (&connect_until_time)); - printf (" Limite de validité: jusqu'au %s.\n", - tmpstr); - } - } - else - { - if (ban_until_time == 0) - { - printf (" Banishment: not banished.\n"); - } - else - { - char tmpstr[128]; - strftime (tmpstr, 24, date_format, - localtime (&ban_until_time)); - printf (" Banishment: until %s.\n", tmpstr); - } - if (RFIFOL (fd, 32) > 1) - printf (" Count: %d connections.\n", - RFIFOL (fd, 32)); - else - printf (" Count: %d connection.\n", - RFIFOL (fd, 32)); - printf (" Last connection at: %s (ip: %s)\n", - lastlogin, last_ip); - if (connect_until_time == 0) - { - printf (" Validity limit: unlimited.\n"); - } - else - { - char tmpstr[128]; - strftime (tmpstr, 24, date_format, - localtime (&connect_until_time)); - printf (" Validity limit: until %s.\n", - tmpstr); - } - } - printf (" Memo: '%s'\n", memo); - } - } - bytes_to_read = 0; - RFIFOSKIP (fd, 150 + RFIFOW (fd, 148)); - break; - - default: - printf - ("Remote administration has been disconnected (unknown packet).\n"); - ladmin_log ("'End of connection, unknown packet.\n"); - session[fd]->eof = 1; - return; - } - } - - // if we don't wait new packets, do the prompt - prompt (); -} - -//------------------------------------ -// Function to connect to login-server -//------------------------------------ -int Connect_login_server (void) -{ - if (defaultlanguage == 'F') - { - Iprintf ("Essai de connection au server de logins...\n"); - ladmin_log ("Essai de connection au server de logins...\n"); - } - else - { - Iprintf ("Attempt to connect to login-server...\n"); - ladmin_log ("Attempt to connect to login-server...\n"); - } - - if ((login_fd = make_connection (login_ip, loginserverport)) < 0) - return 0; - -#ifdef PASSWORDENC - if (passenc == 0) - { -#endif - WFIFOW (login_fd, 0) = 0x7918; // Request for administation login - WFIFOW (login_fd, 2) = 0; // no encrypted - memcpy (WFIFOP (login_fd, 4), loginserveradminpassword, 24); - WFIFOSET (login_fd, 28); - bytes_to_read = 1; - - if (defaultlanguage == 'F') - { - Iprintf ("Envoi du mot de passe...\n"); - ladmin_log ("Envoi du mot de passe...\n"); - } - else - { - Iprintf ("Sending of the password...\n"); - ladmin_log ("Sending of the password...\n"); - } -#ifdef PASSWORDENC - } - else - { - WFIFOW (login_fd, 0) = 0x791a; // Sending request about the coding key - WFIFOSET (login_fd, 2); - bytes_to_read = 1; - if (defaultlanguage == 'F') - { - Iprintf ("Demande de la clef MD5...\n"); - ladmin_log ("Demande de la clef MD5...\n"); - } - else - { - Iprintf ("Request about the MD5 key...\n"); - ladmin_log ("Request about the MD5 key...\n"); - } - } -#endif - - return 0; -} - -//------------------------------------------------- -// Return numerical value of a switch configuration -// on/off, english, français, deutsch, español -//------------------------------------------------- -int config_switch (const char *str) -{ - if (strcasecmp (str, "on") == 0 || strcasecmp (str, "yes") == 0 - || strcasecmp (str, "oui") == 0 || strcasecmp (str, "ja") == 0 - || strcasecmp (str, "si") == 0) - return 1; - if (strcasecmp (str, "off") == 0 || strcasecmp (str, "no") == 0 - || strcasecmp (str, "non") == 0 || strcasecmp (str, "nein") == 0) - return 0; - - return atoi (str); -} - -//----------------------------------- -// Reading general configuration file -//----------------------------------- -int ladmin_config_read (const char *cfgName) -{ - char line[1024], w1[1024], w2[1024]; - FILE *fp; - - fp = fopen_ (cfgName, "r"); - if (fp == NULL) - { - if (defaultlanguage == 'F') - { - printf ("\033[0mFichier de configuration (%s) non trouvé.\n", - cfgName); - } - else - { - printf ("\033[0mConfiguration file (%s) not found.\n", cfgName); - } - return 1; - } - - if (defaultlanguage == 'F') - { - Iprintf - ("\033[0m---Début de lecture du fichier de configuration Ladmin (%s)\n", - cfgName); - } - else - { - Iprintf - ("\033[0m---Start reading of Ladmin configuration file (%s)\n", - cfgName); - } - while (fgets (line, sizeof (line) - 1, fp)) - { - if (line[0] == '/' && line[1] == '/') - continue; - - line[sizeof (line) - 1] = '\0'; - if (sscanf (line, "%[^:]: %[^\r\n]", w1, w2) == 2) - { - remove_control_chars (w1); - remove_control_chars (w2); - - if (strcasecmp (w1, "login_ip") == 0) - { - struct hostent *h = gethostbyname (w2); - if (h != NULL) - { - if (defaultlanguage == 'F') - { - Iprintf - ("Adresse du serveur de logins: %s -> %d.%d.%d.%d\n", - w2, (unsigned char) h->h_addr[0], - (unsigned char) h->h_addr[1], - (unsigned char) h->h_addr[2], - (unsigned char) h->h_addr[3]); - } - else - { - Iprintf - ("Login server IP address: %s -> %d.%d.%d.%d\n", - w2, (unsigned char) h->h_addr[0], - (unsigned char) h->h_addr[1], - (unsigned char) h->h_addr[2], - (unsigned char) h->h_addr[3]); - } - sprintf (loginserverip, "%d.%d.%d.%d", - (unsigned char) h->h_addr[0], - (unsigned char) h->h_addr[1], - (unsigned char) h->h_addr[2], - (unsigned char) h->h_addr[3]); - } - else - memcpy (loginserverip, w2, 16); - } - else if (strcasecmp (w1, "login_port") == 0) - { - loginserverport = atoi (w2); - } - else if (strcasecmp (w1, "admin_pass") == 0) - { - strncpy (loginserveradminpassword, w2, - sizeof (loginserveradminpassword)); - loginserveradminpassword[sizeof (loginserveradminpassword) - - 1] = '\0'; -#ifdef PASSWORDENC - } - else if (strcasecmp (w1, "passenc") == 0) - { - passenc = atoi (w2); - if (passenc < 0 || passenc > 2) - passenc = 0; -#endif - } - else if (strcasecmp (w1, "defaultlanguage") == 0) - { - if (w2[0] == 'F' || w2[0] == 'E') - defaultlanguage = w2[0]; - } - else if (strcasecmp (w1, "ladmin_log_filename") == 0) - { - strncpy (ladmin_log_filename, w2, - sizeof (ladmin_log_filename)); - ladmin_log_filename[sizeof (ladmin_log_filename) - 1] = '\0'; - } - else if (strcasecmp (w1, "date_format") == 0) - { // note: never have more than 19 char for the date! - switch (atoi (w2)) - { - case 0: - strcpy (date_format, "%d-%m-%Y %H:%M:%S"); // 31-12-2004 23:59:59 - break; - case 1: - strcpy (date_format, "%m-%d-%Y %H:%M:%S"); // 12-31-2004 23:59:59 - break; - case 2: - strcpy (date_format, "%Y-%d-%m %H:%M:%S"); // 2004-31-12 23:59:59 - break; - case 3: - strcpy (date_format, "%Y-%m-%d %H:%M:%S"); // 2004-12-31 23:59:59 - break; - } - } - else if (strcasecmp (w1, "import") == 0) - { - ladmin_config_read (w2); - } - } - } - fclose_ (fp); - - login_ip = inet_addr (loginserverip); - - if (defaultlanguage == 'F') - { - Iprintf ("---Lecture du fichier de configuration Ladmin terminée.\n"); - } - else - { - Iprintf ("---End reading of Ladmin configuration file.\n"); - } - - return 0; -} - -//-------------------------------------- -// Function called at exit of the server -//-------------------------------------- -void term_func (void) -{ - - if (already_exit_function == 0) - { - delete_session (login_fd); - - if (defaultlanguage == 'F') - { - Iprintf - ("\033[0m----Fin de Ladmin (fin normale avec fermeture de tous les fichiers).\n"); - ladmin_log - ("----Fin de Ladmin (fin normale avec fermeture de tous les fichiers).\n"); - } - else - { - Iprintf - ("\033[0m----End of Ladmin (normal end with closing of all files).\n"); - ladmin_log - ("----End of Ladmin (normal end with closing of all files).\n"); - } - - already_exit_function = 1; - } -} - -//------------------------ -// Main function of ladmin -//------------------------ -int do_init (int argc, char **argv) -{ - eathena_interactive_session = isatty (0); - // read ladmin configuration - ladmin_config_read ((argc > 1) ? argv[1] : LADMIN_CONF_NAME); - - ladmin_log (""); - if (defaultlanguage == 'F') - { - ladmin_log ("Fichier de configuration lu.\n"); - } - else - { - ladmin_log ("Configuration file readed.\n"); - } - - srand (time (NULL)); - - set_defaultparse (parse_fromlogin); - - if (defaultlanguage == 'F') - { - Iprintf ("Outil d'administration à distance de eAthena.\n"); - Iprintf ("(pour eAthena version %d.%d.%d.)\n", ATHENA_MAJOR_VERSION, - ATHENA_MINOR_VERSION, ATHENA_REVISION); - } - else - { - Iprintf ("EAthena login-server administration tool.\n"); - Iprintf ("(for eAthena version %d.%d.%d.)\n", ATHENA_MAJOR_VERSION, - ATHENA_MINOR_VERSION, ATHENA_REVISION); - } - - if (defaultlanguage == 'F') - { - ladmin_log ("Ladmin est prêt.\n"); - Iprintf ("Ladmin est \033[1;32mprêt\033[0m.\n\n"); - } - else - { - ladmin_log ("Ladmin is ready.\n"); - Iprintf ("Ladmin is \033[1;32mready\033[0m.\n\n"); - } - - Connect_login_server (); - - return 0; -} diff --git a/src/ladmin/ladmin.cpp b/src/ladmin/ladmin.cpp new file mode 100644 index 0000000..01eb244 --- /dev/null +++ b/src/ladmin/ladmin.cpp @@ -0,0 +1,6476 @@ +// $Id: ladmin.c,v 1.1.1.1 2004/09/10 17:26:52 MagicalTux Exp $ +/////////////////////////////////////////////////////////////////////////// +// EAthena login-server remote administration tool +// Ladamin in C by [Yor] +// if you modify this software, modify ladmin in tool too. +/////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include // gettimeofday +#include +#include +#include // close +#include +#include +#include // str* +#include // inet_addr +#include // gethostbyname +#include // valist +#include // tolower + +#include "../common/core.hpp" +#include "../common/socket.hpp" +#include "ladmin.hpp" +#include "../common/version.hpp" +#include "../common/mmo.hpp" + +#ifdef PASSWORDENC +#include "../common/md5calc.hpp" +#endif + +#ifdef MEMWATCH +#include "memwatch.hpp" +#endif + +int eathena_interactive_session; // from core.c +#define Iprintf if (eathena_interactive_session) printf + +//-------------------------------INSTRUCTIONS------------------------------ +// Set the variables below: +// IP of the login server. +// Port where the login-server listens incoming packets. +// Password of administration (same of config_athena.conf). +// Displayed language of the sofware (if not correct, english is used). +// IMPORTANT: +// Be sure that you authorize remote administration in login-server +// (see login_athena.conf, 'admin_state' parameter) +//------------------------------------------------------------------------- +char loginserverip[16] = "127.0.0.1"; // IP of login-server +int loginserverport = 6900; // Port of login-server +char loginserveradminpassword[24] = "admin"; // Administration password +#ifdef PASSWORDENC +int passenc = 2; // Encoding type of the password +#else +int passenc = 0; // Encoding type of the password +#endif +char defaultlanguage = 'E'; // Default language (F: Français/E: English) + // (if it's not 'F', default is English) +char ladmin_log_filename[1024] = "log/ladmin.log"; +char date_format[32] = "%Y-%m-%d %H:%M:%S"; +//------------------------------------------------------------------------- +// LIST of COMMANDs that you can type at the prompt: +// To use these commands you can only type only the first letters. +// You must type a minimum of letters (you can not type 'a', +// because ladmin doesn't know if it's for 'aide' or for 'add') +// q <= quit, li <= list, pass <= passwd, etc. +// +// Note: every time you must give a account_name, you can use "" or '' (spaces can be included) +// +// aide/help/? +// Display the description of the commands +// aide/help/? [command] +// Display the description of the specified command +// +// add +// Create an account with the default email (a@a.com). +// Concerning the sex, only the first letter is used (F or M). +// The e-mail is set to a@a.com (default e-mail). It's like to have no e-mail. +// When the password is omitted, the input is done without displaying of the pressed keys. +// add testname Male testpass +// +// ban/banish yyyy/mm/dd hh:mm:ss +// Changes the final date of a banishment of an account. +// Like banset, but is at end. +// +// banadd +// Adds or substracts time from the final date of a banishment of an account. +// Modifier is done as follows: +// Adjustment value (-1, 1, +1, etc...) +// Modified element: +// a or y: year +// m: month +// j or d: day +// h: hour +// mn: minute +// s: second +// banadd testname +1m-2mn1s-6y +// this example adds 1 month and 1 second, and substracts 2 minutes and 6 years at the same time. +// NOTE: If you modify the final date of a non-banished account, +// you fix the final date to (actual time +- adjustments) +// +// banset yyyy/mm/dd [hh:mm:ss] +// Changes the final date of a banishment of an account. +// Default time [hh:mm:ss]: 23:59:59. +// banset 0 +// Set a non-banished account (0 = unbanished). +// +// block +// Set state 5 (You have been blocked by the GM Team) to an account. +// Like state 5. +// +// check +// Check the validity of a password for an account +// NOTE: Server will never sends back a password. +// It's the only method you have to know if a password is correct. +// The other method is to have a ('physical') access to the accounts file. +// +// create +// Like the 'add' command, but with e-mail moreover. +// create testname Male my@mail.com testpass +// +// del +// Remove an account. +// This order requires confirmation. After confirmation, the account is deleted. +// +// email +// Modify the e-mail of an account. +// +// getcount +// Give the number of players online on all char-servers. +// +// gm [GM_level] +// Modify the GM level of an account. +// Default value remove GM level (GM level = 0). +// gm testname 80 +// +// id +// Give the id of an account. +// +// info +// Display complete information of an account. +// +// kami +// Sends a broadcast message on all map-server (in yellow). +// kamib +// Sends a broadcast message on all map-server (in blue). +// +// language +// Change the language of displaying. +// +// list/ls [start_id [end_id]] +// Display a list of accounts. +// 'start_id', 'end_id': indicate end and start identifiers. +// Research by name is not possible with this command. +// list 10 9999999 +// +// listBan/lsBan [start_id [end_id]] +// Like list/ls, but only for accounts with state or banished +// +// listGM/lsGM [start_id [end_id]] +// Like list/ls, but only for GM accounts +// +// listOK/lsOK [start_id [end_id]] +// Like list/ls, but only for accounts without state and not banished +// +// memo +// Modify the memo of an account. +// 'memo': it can have until 253 characters (with spaces or not). +// +// name +// Give the name of an account. +// +// passwd +// Change the password of an account. +// When new password is omitted, the input is done without displaying of the pressed keys. +// +// quit/end/exit +// End of the program of administration +// +// reloadGM +// Reload GM configuration file +// +// search +// Seek accounts. +// Displays the accounts whose names correspond. +// search -r/-e/--expr/--regex +// Seek accounts by regular expression. +// Displays the accounts whose names correspond. +// +// sex +// Modify the sex of an account. +// sex testname Male +// +// state +// Change the state of an account. +// 'new_state': state is the state of the packet 0x006a + 1. The possibilities are: +// 0 = Account ok 6 = Your Game's EXE file is not the latest version +// 1 = Unregistered ID 7 = You are Prohibited to log in until %s +// 2 = Incorrect Password 8 = Server is jammed due to over populated +// 3 = This ID is expired 9 = No MSG +// 4 = Rejected from Server 100 = This ID has been totally erased +// 5 = You have been blocked by the GM Team +// all other values are 'No MSG', then use state 9 please. +// 'error_message_#7': message of the code error 6 = Your are Prohibited to log in until %s (packet 0x006a) +// +// timeadd +// Adds or substracts time from the validity limit of an account. +// Modifier is done as follows: +// Adjustment value (-1, 1, +1, etc...) +// Modified element: +// a or y: year +// m: month +// j or d: day +// h: hour +// mn: minute +// s: second +// timeadd testname +1m-2mn1s-6y +// this example adds 1 month and 1 second, and substracts 2 minutes and 6 years at the same time. +// NOTE: You can not modify a unlimited validity limit. +// If you want modify it, you want probably create a limited validity limit. +// So, at first, you must set the validity limit to a date/time. +// +// timeset yyyy/mm/dd [hh:mm:ss] +// Changes the validity limit of an account. +// Default time [hh:mm:ss]: 23:59:59. +// timeset 0 +// Gives an unlimited validity limit (0 = unlimited). +// +// unban/unbanish +// Unban an account. +// Like banset 0. +// +// unblock +// Set state 0 (Account ok) to an account. +// Like state 0. +// +// version +// Display the version of the login-server. +// +// who +// Displays complete information of an account. +// +//------------------------------------------------------------------------- +int login_fd; +int login_ip; +int bytes_to_read = 0; // flag to know if we waiting bytes from login-server +char command[1024]; +char parameters[1024]; +int list_first, list_last, list_type, list_count; // parameter to display a list of accounts +int already_exit_function = 0; // sometimes, the exit function is called twice... so, don't log twice the message + +//------------------------------ +// Writing function of logs file +//------------------------------ +int ladmin_log (const char *fmt, ...) +{ + FILE *logfp; + va_list ap; + struct timeval tv; + char tmpstr[2048]; + + va_start (ap, fmt); + + logfp = fopen_ (ladmin_log_filename, "a"); + if (logfp) + { + if (fmt[0] == '\0') // jump a line if no message + fprintf (logfp, "\n"); + else + { + gettimeofday (&tv, NULL); + strftime (tmpstr, 24, date_format, localtime (&(tv.tv_sec))); + sprintf (tmpstr + strlen (tmpstr), ".%03d: %s", + (int) tv.tv_usec / 1000, fmt); + vfprintf (logfp, tmpstr, ap); + } + fclose_ (logfp); + } + + va_end (ap); + return 0; +} + +//----------------------------------------------------- +// Function to suppress control characters in a string. +//----------------------------------------------------- +int remove_control_chars (unsigned char *str) +{ + int i; + int change = 0; + + for (i = 0; str[i]; i++) + { + if (str[i] < 32) + { + str[i] = '_'; + change = 1; + } + } + + return change; +} + +//--------------------------------------------- +// Function to return ordonal text of a number. +//--------------------------------------------- +const char *makeordinal (int number) +{ + if (defaultlanguage == 'F') + { + if (number == 0) + return ""; + else if (number == 1) + return "er"; + else + return "ème"; + } + else + { + if ((number % 10) < 4 && (number % 10) != 0 + && (number < 10 || number > 20)) + { + if ((number % 10) == 1) + return "st"; + else if ((number % 10) == 2) + return "nd"; + else + return "rd"; + } + else + { + return "th"; + } + } + return ""; +} + +//----------------------------------------------------------------------------------------- +// Function to test of the validity of an account name (return 0 if incorrect, and 1 if ok) +//----------------------------------------------------------------------------------------- +int verify_accountname (char *account_name) +{ + int i; + + for (i = 0; account_name[i]; i++) + { + if (account_name[i] < 32) + { + if (defaultlanguage == 'F') + { + printf + ("Caractère interdit trouvé dans le nom du compte (%d%s caractère).\n", + i + 1, makeordinal (i + 1)); + ladmin_log + ("Caractère interdit trouvé dans le nom du compte (%d%s caractère).\n", + i + 1, makeordinal (i + 1)); + } + else + { + printf + ("Illegal character found in the account name (%d%s character).\n", + i + 1, makeordinal (i + 1)); + ladmin_log + ("Illegal character found in the account name (%d%s character).\n", + i + 1, makeordinal (i + 1)); + } + return 0; + } + } + + if (strlen (account_name) < 4) + { + if (defaultlanguage == 'F') + { + printf + ("Nom du compte trop court. Entrez un nom de compte de 4-23 caractères.\n"); + ladmin_log + ("Nom du compte trop court. Entrez un nom de compte de 4-23 caractères.\n"); + } + else + { + printf + ("Account name is too short. Please input an account name of 4-23 bytes.\n"); + ladmin_log + ("Account name is too short. Please input an account name of 4-23 bytes.\n"); + } + return 0; + } + + if (strlen (account_name) > 23) + { + if (defaultlanguage == 'F') + { + printf + ("Nom du compte trop long. Entrez un nom de compte de 4-23 caractères.\n"); + ladmin_log + ("Nom du compte trop long. Entrez un nom de compte de 4-23 caractères.\n"); + } + else + { + printf + ("Account name is too long. Please input an account name of 4-23 bytes.\n"); + ladmin_log + ("Account name is too long. Please input an account name of 4-23 bytes.\n"); + } + return 0; + } + + return 1; +} + +//--------------------------------------------------- +// E-mail check: return 0 (not correct) or 1 (valid). +//--------------------------------------------------- +int e_mail_check (unsigned char *email) +{ + char ch; + unsigned char *last_arobas; + + // athena limits + if (strlen (email) < 3 || strlen (email) > 39) + return 0; + + // part of RFC limits (official reference of e-mail description) + if (strchr (email, '@') == NULL || email[strlen (email) - 1] == '@') + return 0; + + if (email[strlen (email) - 1] == '.') + return 0; + + last_arobas = strrchr (email, '@'); + + if (strstr (last_arobas, "@.") != NULL || + strstr (last_arobas, "..") != NULL) + return 0; + + for (ch = 1; ch < 32; ch++) + { + if (strchr (last_arobas, ch) != NULL) + { + return 0; + break; + } + } + + if (strchr (last_arobas, ' ') != NULL || + strchr (last_arobas, ';') != NULL) + return 0; + + // all correct + return 1; +} + +//---------------------------------- +// Sub-function: Input of a password +//---------------------------------- +int typepasswd (char *password) +{ + char password1[1023], password2[1023]; + int letter; + int i; + + if (defaultlanguage == 'F') + { + ladmin_log + ("Aucun mot de passe n'a été donné. Demande d'un mot de passe.\n"); + } + else + { + ladmin_log ("No password was given. Request to obtain a password.\n"); + } + + memset (password1, '\0', sizeof (password1)); + memset (password2, '\0', sizeof (password2)); + if (defaultlanguage == 'F') + printf ("\033[1;36m Entrez le mot de passe > \033[0;32;42m"); + else + printf ("\033[1;36m Type the password > \033[0;32;42m"); + i = 0; + while ((letter = getchar ()) != '\n') + password1[i++] = letter; + if (defaultlanguage == 'F') + printf + ("\033[0m\033[1;36m Ré-entrez le mot de passe > \033[0;32;42m"); + else + printf ("\033[0m\033[1;36m Verify the password > \033[0;32;42m"); + i = 0; + while ((letter = getchar ()) != '\n') + password2[i++] = letter; + + printf ("\033[0m"); + fflush (stdout); + fflush (stdin); + + if (strcmp (password1, password2) != 0) + { + if (defaultlanguage == 'F') + { + printf + ("Erreur de vérification du mot de passe: Saisissez le même mot de passe svp.\n"); + ladmin_log + ("Erreur de vérification du mot de passe: Saisissez le même mot de passe svp.\n"); + ladmin_log (" Premier mot de passe: %s, second mot de passe: %s.\n", + password1, password2); + } + else + { + printf + ("Password verification failed. Please input same password.\n"); + ladmin_log + ("Password verification failed. Please input same password.\n"); + ladmin_log (" First password: %s, second password: %s.\n", + password1, password2); + } + return 0; + } + if (defaultlanguage == 'F') + { + ladmin_log ("Mot de passe saisi: %s.\n", password1); + } + else + { + ladmin_log ("Typed password: %s.\n", password1); + } + strcpy (password, password1); + return 1; +} + +//------------------------------------------------------------------------------------ +// Sub-function: Test of the validity of password (return 0 if incorrect, and 1 if ok) +//------------------------------------------------------------------------------------ +int verify_password (char *password) +{ + int i; + + for (i = 0; password[i]; i++) + { + if (password[i] < 32) + { + if (defaultlanguage == 'F') + { + printf + ("Caractère interdit trouvé dans le mot de passe (%d%s caractère).\n", + i + 1, makeordinal (i + 1)); + ladmin_log + ("Caractère interdit trouvé dans le nom du compte (%d%s caractère).\n", + i + 1, makeordinal (i + 1)); + } + else + { + printf + ("Illegal character found in the password (%d%s character).\n", + i + 1, makeordinal (i + 1)); + ladmin_log + ("Illegal character found in the password (%d%s character).\n", + i + 1, makeordinal (i + 1)); + } + return 0; + } + } + + if (strlen (password) < 4) + { + if (defaultlanguage == 'F') + { + printf + ("Nom du compte trop court. Entrez un nom de compte de 4-23 caractères.\n"); + ladmin_log + ("Nom du compte trop court. Entrez un nom de compte de 4-23 caractères.\n"); + } + else + { + printf + ("Account name is too short. Please input an account name of 4-23 bytes.\n"); + ladmin_log + ("Account name is too short. Please input an account name of 4-23 bytes.\n"); + } + return 0; + } + + if (strlen (password) > 23) + { + if (defaultlanguage == 'F') + { + printf + ("Mot de passe trop long. Entrez un mot de passe de 4-23 caractères.\n"); + ladmin_log + ("Mot de passe trop long. Entrez un mot de passe de 4-23 caractères.\n"); + } + else + { + printf + ("Password is too long. Please input a password of 4-23 bytes.\n"); + ladmin_log + ("Password is too long. Please input a password of 4-23 bytes.\n"); + } + return 0; + } + + return 1; +} + +//------------------------------------------------------------------ +// Sub-function: Check the name of a command (return complete name) +//----------------------------------------------------------------- +int check_command (char *command) +{ +// help + if (strncmp (command, "aide", 2) == 0 && strncmp (command, "aide", strlen (command)) == 0) // not 1 letter command: 'aide' or 'add'? + strcpy (command, "aide"); + else if (strncmp (command, "help", 1) == 0 + && strncmp (command, "help", strlen (command)) == 0) + strcpy (command, "help"); +// general commands + else if (strncmp (command, "add", 2) == 0 && strncmp (command, "add", strlen (command)) == 0) // not 1 letter command: 'aide' or 'add'? + strcpy (command, "add"); + else if ((strncmp (command, "ban", 3) == 0 + && strncmp (command, "ban", strlen (command)) == 0) + || (strncmp (command, "banish", 4) == 0 + && strncmp (command, "banish", strlen (command)) == 0)) + strcpy (command, "ban"); + else if ((strncmp (command, "banadd", 4) == 0 && strncmp (command, "banadd", strlen (command)) == 0) || // not 1 letter command: 'ba' or 'bs'? 'banadd' or 'banset' ? + strcmp (command, "ba") == 0) + strcpy (command, "banadd"); + else if ((strncmp (command, "banset", 4) == 0 && strncmp (command, "banset", strlen (command)) == 0) || // not 1 letter command: 'ba' or 'bs'? 'banadd' or 'banset' ? + strcmp (command, "bs") == 0) + strcpy (command, "banset"); + else if (strncmp (command, "block", 2) == 0 + && strncmp (command, "block", strlen (command)) == 0) + strcpy (command, "block"); + else if (strncmp (command, "check", 2) == 0 && strncmp (command, "check", strlen (command)) == 0) // not 1 letter command: 'check' or 'create'? + strcpy (command, "check"); + else if (strncmp (command, "create", 2) == 0 && strncmp (command, "create", strlen (command)) == 0) // not 1 letter command: 'check' or 'create'? + strcpy (command, "create"); + else if (strncmp (command, "delete", 1) == 0 + && strncmp (command, "delete", strlen (command)) == 0) + strcpy (command, "delete"); + else if ((strncmp (command, "email", 2) == 0 && strncmp (command, "email", strlen (command)) == 0) || // not 1 letter command: 'email', 'end' or 'exit'? + (strncmp (command, "e-mail", 2) == 0 + && strncmp (command, "e-mail", strlen (command)) == 0)) + strcpy (command, "email"); + else if (strncmp (command, "getcount", 2) == 0 && strncmp (command, "getcount", strlen (command)) == 0) // not 1 letter command: 'getcount' or 'gm'? + strcpy (command, "getcount"); +// else if (strncmp(command, "gm", 2) == 0 && strncmp(command, "gm", strlen(command)) == 0) // not 1 letter command: 'getcount' or 'gm'? +// strcpy(command, "gm"); +// else if (strncmp(command, "id", 2) == 0 && strncmp(command, "id", strlen(command)) == 0) // not 1 letter command: 'id' or 'info'? +// strcpy(command, "id"); + else if (strncmp (command, "info", 2) == 0 && strncmp (command, "info", strlen (command)) == 0) // not 1 letter command: 'id' or 'info'? + strcpy (command, "info"); +// else if (strncmp(command, "kami", 4) == 0 && strncmp(command, "kami", strlen(command)) == 0) // only all letters command: 'kami' or 'kamib'? +// strcpy(command, "kami"); +// else if (strncmp(command, "kamib", 5) == 0 && strncmp(command, "kamib", strlen(command)) == 0) // only all letters command: 'kami' or 'kamib'? +// strcpy(command, "kamib"); + else if ((strncmp (command, "language", 2) == 0 && strncmp (command, "language", strlen (command)) == 0)) // not 1 letter command: 'language' or 'list'? + strcpy (command, "language"); + else if ((strncmp (command, "list", 2) == 0 && strncmp (command, "list", strlen (command)) == 0) || // 'list' is default list command // not 1 letter command: 'language' or 'list'? + strcmp (command, "ls") == 0) + strcpy (command, "list"); + else if (strncmp (command, "itemfrob", 6) == 0) + strcpy (command, "itemfrob"); + else if ((strncmp (command, "listban", 5) == 0 + && strncmp (command, "listban", strlen (command)) == 0) + || (strncmp (command, "lsban", 3) == 0 + && strncmp (command, "lsban", strlen (command)) == 0) + || strcmp (command, "lb") == 0) + strcpy (command, "listban"); + else if ((strncmp (command, "listgm", 5) == 0 + && strncmp (command, "listgm", strlen (command)) == 0) + || (strncmp (command, "lsgm", 3) == 0 + && strncmp (command, "lsgm", strlen (command)) == 0) + || strcmp (command, "lg") == 0) + strcpy (command, "listgm"); + else if ((strncmp (command, "listok", 5) == 0 + && strncmp (command, "listok", strlen (command)) == 0) + || (strncmp (command, "lsok", 3) == 0 + && strncmp (command, "lsok", strlen (command)) == 0) + || strcmp (command, "lo") == 0) + strcpy (command, "listok"); + else if (strncmp (command, "memo", 1) == 0 + && strncmp (command, "memo", strlen (command)) == 0) + strcpy (command, "memo"); + else if (strncmp (command, "name", 1) == 0 + && strncmp (command, "name", strlen (command)) == 0) + strcpy (command, "name"); + else if ((strncmp (command, "password", 1) == 0 + && strncmp (command, "password", strlen (command)) == 0) + || strcmp (command, "passwd") == 0) + strcpy (command, "password"); + else if (strncmp (command, "reloadgm", 1) == 0 + && strncmp (command, "reloadgm", strlen (command)) == 0) + strcpy (command, "reloadgm"); + else if (strncmp (command, "search", 3) == 0 && strncmp (command, "search", strlen (command)) == 0) // not 1 letter command: 'search', 'state' or 'sex'? + strcpy (command, "search"); // not 2 letters command: 'search' or 'sex'? +// else if (strncmp(command, "sex", 3) == 0 && strncmp(command, "sex", strlen(command)) == 0) // not 1 letter command: 'search', 'state' or 'sex'? +// strcpy(command, "sex"); // not 2 letters command: 'search' or 'sex'? + else if (strncmp (command, "state", 2) == 0 && strncmp (command, "state", strlen (command)) == 0) // not 1 letter command: 'search', 'state' or 'sex'? + strcpy (command, "state"); + else if ((strncmp (command, "timeadd", 5) == 0 && strncmp (command, "timeadd", strlen (command)) == 0) || // not 1 letter command: 'ta' or 'ts'? 'timeadd' or 'timeset'? + strcmp (command, "ta") == 0) + strcpy (command, "timeadd"); + else if ((strncmp (command, "timeset", 5) == 0 && strncmp (command, "timeset", strlen (command)) == 0) || // not 1 letter command: 'ta' or 'ts'? 'timeadd' or 'timeset'? + strcmp (command, "ts") == 0) + strcpy (command, "timeset"); + else if ((strncmp (command, "unban", 5) == 0 + && strncmp (command, "unban", strlen (command)) == 0) + || (strncmp (command, "unbanish", 4) == 0 + && strncmp (command, "unbanish", strlen (command)) == 0)) + strcpy (command, "unban"); + else if (strncmp (command, "unblock", 4) == 0 + && strncmp (command, "unblock", strlen (command)) == 0) + strcpy (command, "unblock"); + else if (strncmp (command, "version", 1) == 0 + && strncmp (command, "version", strlen (command)) == 0) + strcpy (command, "version"); + else if (strncmp (command, "who", 1) == 0 + && strncmp (command, "who", strlen (command)) == 0) + strcpy (command, "who"); +// quit + else if (strncmp (command, "quit", 1) == 0 + && strncmp (command, "quit", strlen (command)) == 0) + strcpy (command, "quit"); + else if (strncmp (command, "exit", 2) == 0 && strncmp (command, "exit", strlen (command)) == 0) // not 1 letter command: 'email', 'end' or 'exit'? + strcpy (command, "exit"); + else if (strncmp (command, "end", 2) == 0 && strncmp (command, "end", strlen (command)) == 0) // not 1 letter command: 'email', 'end' or 'exit'? + strcpy (command, "end"); + + return 0; +} + +//----------------------------------------- +// Sub-function: Display commands of ladmin +//----------------------------------------- +void display_help (char *param, int language) +{ + char command[1023]; + int i; + + memset (command, '\0', sizeof (command)); + + if (sscanf (param, "%s ", command) < 1 || strlen (command) == 0) + strcpy (command, ""); // any value that is not a command + + if (command[0] == '?') + { + if (defaultlanguage == 'F') + strcpy (command, "aide"); + else + strcpy (command, "help"); + } + + // lowercase for command + for (i = 0; command[i]; i++) + command[i] = tolower (command[i]); + + // Analyse of the command + check_command (command); // give complete name to the command + + if (defaultlanguage == 'F') + { + ladmin_log ("Affichage des commandes ou d'une commande.\n"); + } + else + { + ladmin_log ("Displaying of the commands or a command.\n"); + } + + if (language == 1) + { + if (strcmp (command, "aide") == 0) + { + printf ("aide/help/?\n"); + printf (" Affiche la description des commandes\n"); + printf ("aide/help/? [commande]\n"); + printf (" Affiche la description de la commande specifiée\n"); + } + else if (strcmp (command, "help") == 0) + { + printf ("aide/help/?\n"); + printf (" Display the description of the commands\n"); + printf ("aide/help/? [command]\n"); + printf (" Display the description of the specified command\n"); +// general commands + } + else if (strcmp (command, "add") == 0) + { + printf ("add \n"); + printf (" Crée un compte avec l'email par défaut (a@a.com).\n"); + printf + (" Concernant le sexe, seule la première lettre compte (F ou M).\n"); + printf + (" L'e-mail est a@a.com (e-mail par défaut). C'est comme n'avoir aucun e-mail.\n"); + printf + (" Lorsque motdepasse est omis, la saisie se fait sans que la frappe se voit.\n"); + printf (" add testname Male testpass\n"); + } + else if (strcmp (command, "ban") == 0) + { + printf ("ban/banish aaaa/mm/jj hh:mm:ss \n"); + printf (" Change la date de fin de bannissement d'un compte.\n"); + printf (" Comme banset, mais est à la fin.\n"); + } + else if (strcmp (command, "banadd") == 0) + { + printf ("banadd \n"); + printf + (" Ajoute ou soustrait du temps à la date de banissement d'un compte.\n"); + printf (" Les modificateurs sont construits comme suit:\n"); + printf (" Valeur d'ajustement (-1, 1, +1, etc...)\n"); + printf (" Elément modifié:\n"); + printf (" a ou y: année\n"); + printf (" m: mois\n"); + printf (" j ou d: jour\n"); + printf (" h: heure\n"); + printf (" mn: minute\n"); + printf (" s: seconde\n"); + printf (" banadd testname +1m-2mn1s-6a\n"); + printf + (" Cette exemple ajoute 1 mois et une seconde, et soustrait 2 minutes\n"); + printf (" et 6 ans dans le même temps.\n"); + printf + ("NOTE: Si vous modifez la date de banissement d'un compte non bani,\n"); + printf + (" vous indiquez comme date (le moment actuel +- les ajustements)\n"); + } + else if (strcmp (command, "banset") == 0) + { + printf ("banset aaaa/mm/jj [hh:mm:ss]\n"); + printf (" Change la date de fin de bannissement d'un compte.\n"); + printf (" Heure par défaut [hh:mm:ss]: 23:59:59.\n"); + printf ("banset 0\n"); + printf (" Débanni un compte (0 = de-banni).\n"); + } + else if (strcmp (command, "block") == 0) + { + printf ("block \n"); + printf + (" Place le status d'un compte à 5 (You have been blocked by the GM Team).\n"); + printf + (" La commande est l'équivalent de state 5.\n"); + } + else if (strcmp (command, "check") == 0) + { + printf ("check \n"); + printf + (" Vérifie la validité d'un mot de passe pour un compte\n"); + printf (" NOTE: Le serveur n'enverra jamais un mot de passe.\n"); + printf + (" C'est la seule méthode que vous possédez pour savoir\n"); + printf + (" si un mot de passe est le bon. L'autre méthode est\n"); + printf + (" d'avoir un accès ('physique') au fichier des comptes.\n"); + } + else if (strcmp (command, "create") == 0) + { + printf ("create \n"); + printf (" Comme la commande add, mais avec l'e-mail en plus.\n"); + printf + (" create testname Male mon@mail.com testpass\n"); + } + else if (strcmp (command, "delete") == 0) + { + printf ("del \n"); + printf (" Supprime un compte.\n"); + printf + (" La commande demande confirmation. Après confirmation, le compte est détruit.\n"); + } + else if (strcmp (command, "email") == 0) + { + printf ("email \n"); + printf (" Modifie l'e-mail d'un compte.\n"); + } + else if (strcmp (command, "getcount") == 0) + { + printf ("getcount\n"); + printf + (" Donne le nombre de joueurs en ligne par serveur de char.\n"); + } + else if (strcmp (command, "gm") == 0) + { + printf ("gm [Niveau_GM]\n"); + printf (" Modifie le niveau de GM d'un compte.\n"); + printf + (" Valeur par défaut: 0 (suppression du niveau de GM).\n"); + printf (" gm nomtest 80\n"); + } + else if (strcmp (command, "id") == 0) + { + printf ("id \n"); + printf (" Donne l'id d'un compte.\n"); + } + else if (strcmp (command, "info") == 0) + { + printf ("info \n"); + printf (" Affiche les informations sur un compte.\n"); + } + else if (strcmp (command, "kami") == 0) + { + printf ("kami \n"); + printf + (" Envoi un message général sur tous les serveurs de map (en jaune).\n"); + } + else if (strcmp (command, "kamib") == 0) + { + printf ("kamib \n"); + printf + (" Envoi un message général sur tous les serveurs de map (en bleu).\n"); + } + else if (strcmp (command, "language") == 0) + { + printf ("language \n"); + printf (" Change la langue d'affichage.\n"); + printf (" Langues possibles: 'Français' ou 'English'.\n"); + } + else if (strcmp (command, "list") == 0) + { + printf ("list/ls [Premier_id [Dernier_id]]\n"); + printf (" Affiche une liste de comptes.\n"); + printf + (" 'Premier_id', 'Dernier_id': indique les identifiants de départ et de fin.\n"); + printf + (" La recherche par nom n'est pas possible avec cette commande.\n"); + printf (" list 10 9999999\n"); + } + else if (strcmp (command, "itemfrob") == 0) + { + printf ("Not localised yet.\n"); + } + else if (strcmp (command, "listban") == 0) + { + printf ("listBan/lsBan [Premier_id [Dernier_id]]\n"); + printf + (" Comme list/ls, mais seulement pour les comptes avec statut ou bannis.\n"); + } + else if (strcmp (command, "listgm") == 0) + { + printf ("listGM/lsGM [Premier_id [Dernier_id]]\n"); + printf (" Comme list/ls, mais seulement pour les comptes GM.\n"); + } + else if (strcmp (command, "listok") == 0) + { + printf ("listOK/lsOK [Premier_id [Dernier_id]]\n"); + printf + (" Comme list/ls, mais seulement pour les comptes sans statut et non bannis.\n"); + } + else if (strcmp (command, "memo") == 0) + { + printf ("memo \n"); + printf (" Modifie le mémo d'un compte.\n"); + printf + (" 'memo': Il peut avoir jusqu'à 253 caractères (avec des espaces ou non).\n"); + } + else if (strcmp (command, "name") == 0) + { + printf ("name \n"); + printf (" Donne le nom d'un compte.\n"); + } + else if (strcmp (command, "password") == 0) + { + printf ("passwd \n"); + printf (" Change le mot de passe d'un compte.\n"); + printf (" Lorsque nouveaumotdepasse est omis,\n"); + printf (" la saisie se fait sans que la frappe ne se voit.\n"); + } + else if (strcmp (command, "reloadgm") == 0) + { + printf ("reloadGM\n"); + printf (" Reload GM configuration file\n"); + } + else if (strcmp (command, "search") == 0) + { + printf ("search \n"); + printf (" Cherche des comptes.\n"); + printf (" Affiche les comptes dont les noms correspondent.\n"); +// printf("search -r/-e/--expr/--regex \n"); +// printf(" Cherche des comptes par expression regulière.\n"); +// printf(" Affiche les comptes dont les noms correspondent.\n"); + } + else if (strcmp (command, "sex") == 0) + { + printf ("sex \n"); + printf (" Modifie le sexe d'un compte.\n"); + printf (" sex testname Male\n"); + } + else if (strcmp (command, "state") == 0) + { + printf ("state \n"); + printf (" Change le statut d'un compte.\n"); + printf + (" 'nouveaustatut': Le statut est le même que celui du packet 0x006a + 1.\n"); + printf (" les possibilités sont:\n"); + printf (" 0 = Compte ok\n"); + printf (" 1 = Unregistered ID\n"); + printf (" 2 = Incorrect Password\n"); + printf (" 3 = This ID is expired\n"); + printf (" 4 = Rejected from Server\n"); + printf + (" 5 = You have been blocked by the GM Team\n"); + printf + (" 6 = Your Game's EXE file is not the latest version\n"); + printf + (" 7 = You are Prohibited to log in until...\n"); + printf + (" 8 = Server is jammed due to over populated\n"); + printf (" 9 = No MSG\n"); + printf (" 100 = This ID has been totally erased\n"); + printf + (" all other values are 'No MSG', then use state 9 please.\n"); + printf (" 'message_erreur_7': message du code erreur 6 =\n"); + printf + (" = Your are Prohibited to log in until... (packet 0x006a)\n"); + } + else if (strcmp (command, "timeadd") == 0) + { + printf ("timeadd \n"); + printf + (" Ajoute/soustrait du temps à la limite de validité d'un compte.\n"); + printf (" Le modificateur est composé comme suit:\n"); + printf (" Valeur modificatrice (-1, 1, +1, etc...)\n"); + printf (" Elément modifié:\n"); + printf (" a ou y: année\n"); + printf (" m: mois\n"); + printf (" j ou d: jour\n"); + printf (" h: heure\n"); + printf (" mn: minute\n"); + printf (" s: seconde\n"); + printf (" timeadd testname +1m-2mn1s-6a\n"); + printf + (" Cette exemple ajoute 1 mois et une seconde, et soustrait 2 minutes\n"); + printf (" et 6 ans dans le même temps.\n"); + printf + ("NOTE: Vous ne pouvez pas modifier une limite de validité illimitée. Si vous\n"); + printf + (" désirez le faire, c'est que vous voulez probablement créer un limite de\n"); + printf + (" validité limitée. Donc, en premier, fixé une limite de valitidé.\n"); + } + else if (strcmp (command, "timeadd") == 0) + { + printf ("timeset aaaa/mm/jj [hh:mm:ss]\n"); + printf (" Change la limite de validité d'un compte.\n"); + printf (" Heure par défaut [hh:mm:ss]: 23:59:59.\n"); + printf ("timeset 0\n"); + printf + (" Donne une limite de validité illimitée (0 = illimitée).\n"); + } + else if (strcmp (command, "unban") == 0) + { + printf ("unban/unbanish \n"); + printf (" Ote le banissement d'un compte.\n"); + printf + (" La commande est l'équivalent de banset 0.\n"); + } + else if (strcmp (command, "unblock") == 0) + { + printf ("unblock \n"); + printf (" Place le status d'un compte à 0 (Compte ok).\n"); + printf + (" La commande est l'équivalent de state 0.\n"); + } + else if (strcmp (command, "version") == 0) + { + printf ("version\n"); + printf (" Affiche la version du login-serveur.\n"); + } + else if (strcmp (command, "who") == 0) + { + printf ("who \n"); + printf (" Affiche les informations sur un compte.\n"); +// quit + } + else if (strcmp (command, "quit") == 0 || + strcmp (command, "exit") == 0 || + strcmp (command, "end") == 0) + { + printf ("quit/end/exit\n"); + printf (" Fin du programme d'administration.\n"); +// unknown command + } + else + { + if (strlen (command) > 0) + printf + ("Commande inconnue [%s] pour l'aide. Affichage de toutes les commandes.\n", + command); + printf + (" aide/help/? -- Affiche cet aide\n"); + printf + (" aide/help/? [commande] -- Affiche l'aide de la commande\n"); + printf + (" add -- Crée un compte (sans email)\n"); + printf + (" ban/banish aaaa/mm/jj hh:mm:ss -- Fixe la date finale de banismnt\n"); + printf + (" banadd/ba -- Ajout/soustrait du temps à la\n"); + printf + (" exemple: ba moncompte +1m-2mn1s-2y date finale de banissement\n"); + printf + (" banset/bs aaaa/mm/jj [hh:mm:ss] -- Change la date fin de banisemnt\n"); + printf + (" banset/bs 0 -- Dé-banis un compte.\n"); + printf + (" block -- Mets le status d'un compte à 5 (blocked by the GM Team)\n"); + printf + (" check -- Vérifie un mot de passe d'un compte\n"); + printf + (" create -- Crée un compte (avec email)\n"); + printf + (" del -- Supprime un compte\n"); + printf + (" email -- Modifie l'e-mail d'un compte\n"); + printf + (" getcount -- Donne le nb de joueurs en ligne\n"); + printf + (" gm [Niveau_GM] -- Modifie le niveau de GM d'un compte\n"); + printf + (" id -- Donne l'id d'un compte\n"); + printf + (" info -- Affiche les infos sur un compte\n"); + printf + (" kami -- Envoi un message général (en jaune)\n"); + printf + (" kamib -- Envoi un message général (en bleu)\n"); + printf + (" language -- Change la langue d'affichage.\n"); + printf + (" list/ls [Premier_id [Dernier_id] ] -- Affiche une liste de comptes\n"); + printf + (" listBan/lsBan [Premier_id [Dernier_id] ] -- Affiche une liste de comptes\n"); + printf + (" avec un statut ou bannis\n"); + printf + (" listGM/lsGM [Premier_id [Dernier_id] ] -- Affiche une liste de comptes GM\n"); + printf + (" listOK/lsOK [Premier_id [Dernier_id] ] -- Affiche une liste de comptes\n"); + printf + (" sans status et non bannis\n"); + printf + (" memo -- Modifie le memo d'un compte\n"); + printf + (" name -- Donne le nom d'un compte\n"); + printf + (" passwd -- Change le mot de passe d'un compte\n"); + printf + (" quit/end/exit -- Fin du programme d'administation\n"); + printf + (" reloadGM -- Recharger le fichier de config des GM\n"); + printf + (" search -- Cherche des comptes\n"); +// printf(" search -e/-r/--expr/--regex -- Cherche des comptes par REGEX\n"); + printf + (" sex -- Modifie le sexe d'un compte\n"); + printf + (" state -- Change le statut d'1 compte\n"); + printf + (" timeadd/ta -- Ajout/soustrait du temps à la\n"); + printf + (" exemple: ta moncompte +1m-2mn1s-2y limite de validité\n"); + printf + (" timeset/ts aaaa/mm/jj [hh:mm:ss] -- Change la limite de validité\n"); + printf + (" timeset/ts 0 -- limite de validité = illimitée\n"); + printf + (" unban/unbanish -- Ote le banissement d'un compte\n"); + printf + (" unblock -- Mets le status d'un compte à 0 (Compte ok)\n"); + printf + (" version -- Donne la version du login-serveur\n"); + printf + (" who -- Affiche les infos sur un compte\n"); + printf + (" Note: Pour les noms de compte avec des espaces, tapez \"\" (ou ').\n"); + } + } + else + { + if (strcmp (command, "aide") == 0) + { + printf ("aide/help/?\n"); + printf (" Display the description of the commands\n"); + printf ("aide/help/? [command]\n"); + printf (" Display the description of the specified command\n"); + } + else if (strcmp (command, "help") == 0) + { + printf ("aide/help/?\n"); + printf (" Display the description of the commands\n"); + printf ("aide/help/? [command]\n"); + printf (" Display the description of the specified command\n"); +// general commands + } + else if (strcmp (command, "add") == 0) + { + printf ("add \n"); + printf + (" Create an account with the default email (a@a.com).\n"); + printf + (" Concerning the sex, only the first letter is used (F or M).\n"); + printf + (" The e-mail is set to a@a.com (default e-mail). It's like to have no e-mail.\n"); + printf (" When the password is omitted,\n"); + printf + (" the input is done without displaying of the pressed keys.\n"); + printf (" add testname Male testpass\n"); + } + else if (strcmp (command, "ban") == 0) + { + printf ("ban/banish yyyy/mm/dd hh:mm:ss \n"); + printf + (" Changes the final date of a banishment of an account.\n"); + printf (" Like banset, but is at end.\n"); + } + else if (strcmp (command, "banadd") == 0) + { + printf ("banadd \n"); + printf + (" Adds or substracts time from the final date of a banishment of an account.\n"); + printf (" Modifier is done as follows:\n"); + printf (" Adjustment value (-1, 1, +1, etc...)\n"); + printf (" Modified element:\n"); + printf (" a or y: year\n"); + printf (" m: month\n"); + printf (" j or d: day\n"); + printf (" h: hour\n"); + printf (" mn: minute\n"); + printf (" s: second\n"); + printf (" banadd testname +1m-2mn1s-6y\n"); + printf + (" this example adds 1 month and 1 second, and substracts 2 minutes\n"); + printf (" and 6 years at the same time.\n"); + printf + ("NOTE: If you modify the final date of a non-banished account,\n"); + printf + (" you fix the final date to (actual time +- adjustments)\n"); + } + else if (strcmp (command, "banset") == 0) + { + printf ("banset yyyy/mm/dd [hh:mm:ss]\n"); + printf + (" Changes the final date of a banishment of an account.\n"); + printf (" Default time [hh:mm:ss]: 23:59:59.\n"); + printf ("banset 0\n"); + printf (" Set a non-banished account (0 = unbanished).\n"); + } + else if (strcmp (command, "block") == 0) + { + printf ("block \n"); + printf + (" Set state 5 (You have been blocked by the GM Team) to an account.\n"); + printf (" This command works like state 5.\n"); + } + else if (strcmp (command, "check") == 0) + { + printf ("check \n"); + printf (" Check the validity of a password for an account.\n"); + printf (" NOTE: Server will never sends back a password.\n"); + printf + (" It's the only method you have to know if a password is correct.\n"); + printf + (" The other method is to have a ('physical') access to the accounts file.\n"); + } + else if (strcmp (command, "create") == 0) + { + printf ("create \n"); + printf (" Like the 'add' command, but with e-mail moreover.\n"); + printf + (" create testname Male my@mail.com testpass\n"); + } + else if (strcmp (command, "delete") == 0) + { + printf ("del \n"); + printf (" Remove an account.\n"); + printf + (" This order requires confirmation. After confirmation, the account is deleted.\n"); + } + else if (strcmp (command, "email") == 0) + { + printf ("email \n"); + printf (" Modify the e-mail of an account.\n"); + } + else if (strcmp (command, "getcount") == 0) + { + printf ("getcount\n"); + printf + (" Give the number of players online on all char-servers.\n"); + } + else if (strcmp (command, "gm") == 0) + { + printf ("gm [GM_level]\n"); + printf (" Modify the GM level of an account.\n"); + printf (" Default value remove GM level (GM level = 0).\n"); + printf (" gm testname 80\n"); + } + else if (strcmp (command, "id") == 0) + { + printf ("id \n"); + printf (" Give the id of an account.\n"); + } + else if (strcmp (command, "info") == 0) + { + printf ("info \n"); + printf (" Display complete information of an account.\n"); + } + else if (strcmp (command, "kami") == 0) + { + printf ("kami \n"); + printf + (" Sends a broadcast message on all map-server (in yellow).\n"); + } + else if (strcmp (command, "kamib") == 0) + { + printf ("kamib \n"); + printf + (" Sends a broadcast message on all map-server (in blue).\n"); + } + else if (strcmp (command, "language") == 0) + { + printf ("language \n"); + printf (" Change the language of displaying.\n"); + printf (" Possible languages: Français or English.\n"); + } + else if (strcmp (command, "list") == 0) + { + printf ("list/ls [start_id [end_id]]\n"); + printf (" Display a list of accounts.\n"); + printf + (" 'start_id', 'end_id': indicate end and start identifiers.\n"); + printf + (" Research by name is not possible with this command.\n"); + printf (" list 10 9999999\n"); + } + else if (strcmp (command, "itemfrob") == 0) + { + printf ("itemfrob \n"); + printf (" Translates item IDs for all accounts.\n"); + printf + (" Any items matching the source item ID will be mapped to the dest-id.\n"); + printf (" itemfrob 500 700\n"); + } + else if (strcmp (command, "listban") == 0) + { + printf ("listBan/lsBan [start_id [end_id]]\n"); + printf + (" Like list/ls, but only for accounts with state or banished.\n"); + } + else if (strcmp (command, "listgm") == 0) + { + printf ("listGM/lsGM [start_id [end_id]]\n"); + printf (" Like list/ls, but only for GM accounts.\n"); + } + else if (strcmp (command, "listok") == 0) + { + printf ("listOK/lsOK [start_id [end_id]]\n"); + printf + (" Like list/ls, but only for accounts without state and not banished.\n"); + } + else if (strcmp (command, "memo") == 0) + { + printf ("memo \n"); + printf (" Modify the memo of an account.\n"); + printf + (" 'memo': it can have until 253 characters (with spaces or not).\n"); + } + else if (strcmp (command, "name") == 0) + { + printf ("name \n"); + printf (" Give the name of an account.\n"); + } + else if (strcmp (command, "password") == 0) + { + printf ("passwd \n"); + printf (" Change the password of an account.\n"); + printf (" When new password is omitted,\n"); + printf + (" the input is done without displaying of the pressed keys.\n"); + } + else if (strcmp (command, "reloadgm") == 0) + { + printf ("reloadGM\n"); + printf (" Reload GM configuration file\n"); + } + else if (strcmp (command, "search") == 0) + { + printf ("search \n"); + printf (" Seek accounts.\n"); + printf (" Displays the accounts whose names correspond.\n"); +// printf("search -r/-e/--expr/--regex \n"); +// printf(" Seek accounts by regular expression.\n"); +// printf(" Displays the accounts whose names correspond.\n"); + } + else if (strcmp (command, "sex") == 0) + { + printf ("sex \n"); + printf (" Modify the sex of an account.\n"); + printf (" sex testname Male\n"); + } + else if (strcmp (command, "state") == 0) + { + printf ("state \n"); + printf (" Change the state of an account.\n"); + printf + (" 'new_state': state is the state of the packet 0x006a + 1.\n"); + printf (" The possibilities are:\n"); + printf (" 0 = Account ok\n"); + printf (" 1 = Unregistered ID\n"); + printf (" 2 = Incorrect Password\n"); + printf (" 3 = This ID is expired\n"); + printf (" 4 = Rejected from Server\n"); + printf + (" 5 = You have been blocked by the GM Team\n"); + printf + (" 6 = Your Game's EXE file is not the latest version\n"); + printf + (" 7 = You are Prohibited to log in until...\n"); + printf + (" 8 = Server is jammed due to over populated\n"); + printf (" 9 = No MSG\n"); + printf (" 100 = This ID has been totally erased\n"); + printf + (" all other values are 'No MSG', then use state 9 please.\n"); + printf (" 'error_message_#7': message of the code error 6\n"); + printf + (" = Your are Prohibited to log in until... (packet 0x006a)\n"); + } + else if (strcmp (command, "timeadd") == 0) + { + printf ("timeadd \n"); + printf + (" Adds or substracts time from the validity limit of an account.\n"); + printf (" Modifier is done as follows:\n"); + printf (" Adjustment value (-1, 1, +1, etc...)\n"); + printf (" Modified element:\n"); + printf (" a or y: year\n"); + printf (" m: month\n"); + printf (" j or d: day\n"); + printf (" h: hour\n"); + printf (" mn: minute\n"); + printf (" s: second\n"); + printf (" timeadd testname +1m-2mn1s-6y\n"); + printf + (" this example adds 1 month and 1 second, and substracts 2 minutes\n"); + printf (" and 6 years at the same time.\n"); + printf ("NOTE: You can not modify a unlimited validity limit.\n"); + printf + (" If you want modify it, you want probably create a limited validity limit.\n"); + printf + (" So, at first, you must set the validity limit to a date/time.\n"); + } + else if (strcmp (command, "timeadd") == 0) + { + printf ("timeset yyyy/mm/dd [hh:mm:ss]\n"); + printf (" Changes the validity limit of an account.\n"); + printf (" Default time [hh:mm:ss]: 23:59:59.\n"); + printf ("timeset 0\n"); + printf (" Gives an unlimited validity limit (0 = unlimited).\n"); + } + else if (strcmp (command, "unban") == 0) + { + printf ("unban/unbanish \n"); + printf (" Remove the banishment of an account.\n"); + printf (" This command works like banset 0.\n"); + } + else if (strcmp (command, "unblock") == 0) + { + printf ("unblock \n"); + printf (" Set state 0 (Account ok) to an account.\n"); + printf (" This command works like state 0.\n"); + } + else if (strcmp (command, "version") == 0) + { + printf ("version\n"); + printf (" Display the version of the login-server.\n"); + } + else if (strcmp (command, "who") == 0) + { + printf ("who \n"); + printf (" Displays complete information of an account.\n"); +// quit + } + else if (strcmp (command, "quit") == 0 || + strcmp (command, "exit") == 0 || + strcmp (command, "end") == 0) + { + printf ("quit/end/exit\n"); + printf (" End of the program of administration.\n"); +// unknown command + } + else + { + if (strlen (command) > 0) + printf + ("Unknown command [%s] for help. Displaying of all commands.\n", + command); + printf + (" aide/help/? -- Display this help\n"); + printf + (" aide/help/? [command] -- Display the help of the command\n"); + printf + (" add -- Create an account with default email\n"); + printf + (" ban/banish yyyy/mm/dd hh:mm:ss -- Change final date of a ban\n"); + printf + (" banadd/ba -- Add or substract time from the final\n"); + printf + (" example: ba apple +1m-2mn1s-2y date of a banishment of an account\n"); + printf + (" banset/bs yyyy/mm/dd [hh:mm:ss] -- Change final date of a ban\n"); + printf + (" banset/bs 0 -- Un-banish an account\n"); + printf + (" block -- Set state 5 (blocked by the GM Team) to an account\n"); + printf + (" check -- Check the validity of a password\n"); + printf + (" create -- Create an account with email\n"); + printf + (" del -- Remove an account\n"); + printf + (" email -- Modify an email of an account\n"); + printf + (" getcount -- Give the number of players online\n"); + printf + (" gm [GM_level] -- Modify the GM level of an account\n"); + printf + (" id -- Give the id of an account\n"); + printf + (" info -- Display all information of an account\n"); + printf + (" itemfrob -- Map all items from one item ID to another\n"); + printf + (" kami -- Sends a broadcast message (in yellow)\n"); + printf + (" kamib -- Sends a broadcast message (in blue)\n"); + printf + (" language -- Change the language of displaying.\n"); + printf + (" list/ls [First_id [Last_id]] -- Display a list of accounts\n"); + printf + (" listBan/lsBan [First_id [Last_id] ] -- Display a list of accounts\n"); + printf + (" with state or banished\n"); + printf + (" listGM/lsGM [First_id [Last_id]] -- Display a list of GM accounts\n"); + printf + (" listOK/lsOK [First_id [Last_id] ] -- Display a list of accounts\n"); + printf + (" without state and not banished\n"); + printf + (" memo -- Modify the memo of an account\n"); + printf + (" name -- Give the name of an account\n"); + printf + (" passwd -- Change the password of an account\n"); + printf + (" quit/end/exit -- End of the program of administation\n"); + printf + (" reloadGM -- Reload GM configuration file\n"); + printf + (" search -- Seek accounts\n"); +// printf(" search -e/-r/--expr/--regex -- Seek accounts by regular-expression\n"); + printf + (" sex -- Modify the sex of an account\n"); + printf + (" state -- Change the state\n"); + printf + (" timeadd/ta -- Add or substract time from the\n"); + printf + (" example: ta apple +1m-2mn1s-2y validity limit of an account\n"); + printf + (" timeset/ts yyyy/mm/dd [hh:mm:ss] -- Change the validify limit\n"); + printf + (" timeset/ts 0 -- Give a unlimited validity limit\n"); + printf + (" unban/unbanish -- Remove the banishment of an account\n"); + printf + (" unblock -- Set state 0 (Account ok) to an account\n"); + printf + (" version -- Gives the version of the login-server\n"); + printf + (" who -- Display all information of an account\n"); + printf + (" who -- Display all information of an account\n"); + printf + (" Note: To use spaces in an account name, type \"\" (or ').\n"); + } + } +} + +//----------------------------- +// Sub-function: add an account +//----------------------------- +int addaccount (char *param, int emailflag) +{ + char name[1023], sex[1023], email[1023], password[1023]; +// int i; + + memset (name, '\0', sizeof (name)); + memset (sex, '\0', sizeof (sex)); + memset (email, '\0', sizeof (email)); + memset (password, '\0', sizeof (password)); + + if (emailflag == 0) + { // add command + if (sscanf (param, "\"%[^\"]\" %s %[^\r\n]", name, sex, password) < 2 && // password can be void + sscanf (param, "'%[^']' %s %[^\r\n]", name, sex, password) < 2 && // password can be void + sscanf (param, "%s %s %[^\r\n]", name, sex, password) < 2) + { // password can be void + if (defaultlanguage == 'F') + { + printf + ("Entrez un nom de compte, un sexe et un mot de passe svp.\n"); + printf (" add nomtest Male motdepassetest\n"); + ladmin_log + ("Nombre incorrect de paramètres pour créer un compte (commande 'add').\n"); + } + else + { + printf + ("Please input an account name, a sex and a password.\n"); + printf (" add testname Male testpass\n"); + ladmin_log + ("Incomplete parameters to create an account ('add' command).\n"); + } + return 136; + } + strcpy (email, "a@a.com"); // default email + } + else + { // 1: create command + if (sscanf (param, "\"%[^\"]\" %s %s %[^\r\n]", name, sex, email, password) < 3 && // password can be void + sscanf (param, "'%[^']' %s %s %[^\r\n]", name, sex, email, password) < 3 && // password can be void + sscanf (param, "%s %s %s %[^\r\n]", name, sex, email, + password) < 3) + { // password can be void + if (defaultlanguage == 'F') + { + printf + ("Entrez un nom de compte, un sexe et un mot de passe svp.\n"); + printf + (" create nomtest Male mo@mail.com motdepassetest\n"); + ladmin_log + ("Nombre incorrect de paramètres pour créer un compte (commande 'create').\n"); + } + else + { + printf + ("Please input an account name, a sex and a password.\n"); + printf + (" create testname Male my@mail.com testpass\n"); + ladmin_log + ("Incomplete parameters to create an account ('create' command).\n"); + } + return 136; + } + } + if (verify_accountname (name) == 0) + { + return 102; + } + +/* for(i = 0; name[i]; i++) { + if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_", name[i]) == NULL) { + if (defaultlanguage == 'F') { + printf("Caractère interdit (%c) trouvé dans le nom du compte (%d%s caractère).\n", name[i], i+1, makeordinal(i+1)); + ladmin_log("Caractère interdit (%c) trouvé dans le nom du compte (%d%s caractère).\n", name[i], i+1, makeordinal(i+1)); + } else { + printf("Illegal character (%c) found in the account name (%d%s character).\n", name[i], i+1, makeordinal(i+1)); + ladmin_log("Illegal character (%c) found in the account name (%d%s character).\n", name[i], i+1, makeordinal(i+1)); + } + return 101; + } + }*/ + + sex[0] = toupper (sex[0]); + if (strchr ("MF", sex[0]) == NULL) + { + if (defaultlanguage == 'F') + { + printf ("Sexe incorrect [%s]. Entrez M ou F svp.\n", sex); + ladmin_log ("Sexe incorrect [%s]. Entrez M ou F svp.\n", + sex); + } + else + { + printf ("Illegal gender [%s]. Please input M or F.\n", sex); + ladmin_log ("Illegal gender [%s]. Please input M or F.\n", + sex); + } + return 103; + } + + if (strlen (email) < 3) + { + if (defaultlanguage == 'F') + { + printf ("Email trop courte [%s]. Entrez une e-mail valide svp.\n", + email); + ladmin_log + ("Email trop courte [%s]. Entrez une e-mail valide svp.\n", + email); + } + else + { + printf ("Email is too short [%s]. Please input a valid e-mail.\n", + email); + ladmin_log + ("Email is too short [%s]. Please input a valid e-mail.\n", + email); + } + return 109; + } + if (strlen (email) > 39) + { + if (defaultlanguage == 'F') + { + printf + ("Email trop longue [%s]. Entrez une e-mail de 39 caractères maximum svp.\n", + email); + ladmin_log + ("Email trop longue [%s]. Entrez une e-mail de 39 caractères maximum svp.\n", + email); + } + else + { + printf + ("Email is too long [%s]. Please input an e-mail with 39 bytes at the most.\n", + email); + ladmin_log + ("Email is too long [%s]. Please input an e-mail with 39 bytes at the most.\n", + email); + } + return 109; + } + if (e_mail_check (email) == 0) + { + if (defaultlanguage == 'F') + { + printf ("Email incorrecte [%s]. Entrez une e-mail valide svp.\n", + email); + ladmin_log ("Email incorrecte [%s]. Entrez une e-mail valide svp.\n", + email); + } + else + { + printf ("Invalid email [%s]. Please input a valid e-mail.\n", + email); + ladmin_log ("Invalid email [%s]. Please input a valid e-mail.\n", + email); + } + return 109; + } + + if (strlen (password) == 0) + { + if (typepasswd (password) == 0) + return 108; + } + if (verify_password (password) == 0) + return 104; + + if (defaultlanguage == 'F') + { + ladmin_log + ("Envoi d'un requête au serveur de logins pour créer un compte.\n"); + } + else + { + ladmin_log ("Request to login-server to create an account.\n"); + } + + WFIFOW (login_fd, 0) = 0x7930; + memcpy (WFIFOP (login_fd, 2), name, 24); + memcpy (WFIFOP (login_fd, 26), password, 24); + WFIFOB (login_fd, 50) = sex[0]; + memcpy (WFIFOP (login_fd, 51), email, 40); + WFIFOSET (login_fd, 91); + bytes_to_read = 1; + + return 0; +} + +//--------------------------------------------------------------------------------- +// Sub-function: Add/substract time to the final date of a banishment of an account +//--------------------------------------------------------------------------------- +int banaddaccount (char *param) +{ + char name[1023], modif[1023]; + int year, month, day, hour, minute, second; + char *p_modif; + int value, i; + + memset (name, '\0', sizeof (name)); + memset (modif, '\0', sizeof (modif)); + year = month = day = hour = minute = second = 0; + + if (sscanf (param, "\"%[^\"]\" %[^\r\n]", name, modif) < 2 && + sscanf (param, "'%[^']' %[^\r\n]", name, modif) < 2 && + sscanf (param, "%s %[^\r\n]", name, modif) < 2) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un nom de compte et un modificateur svp.\n"); + printf (" banadd nomtest +1m-2mn1s-6y\n"); + printf + (" Cette exemple ajoute 1 mois et 1 seconde, et soustrait 2 minutes\n"); + printf (" et 6 ans dans le même temps.\n"); + ladmin_log + ("Nombre incorrect de paramètres pour modifier la fin de ban d'un compte (commande 'banadd').\n"); + } + else + { + printf ("Please input an account name and a modifier.\n"); + printf (" : banadd testname +1m-2mn1s-6y\n"); + printf + (" this example adds 1 month and 1 second, and substracts 2 minutes\n"); + printf (" and 6 years at the same time.\n"); + ladmin_log + ("Incomplete parameters to modify the ban date/time of an account ('banadd' command).\n"); + } + return 136; + } + if (verify_accountname (name) == 0) + { + return 102; + } + + // lowercase for modif + for (i = 0; modif[i]; i++) + modif[i] = tolower (modif[i]); + p_modif = modif; + while (strlen (p_modif) > 0) + { + value = atoi (p_modif); + if (value == 0) + { + p_modif++; + } + else + { + if (p_modif[0] == '-' || p_modif[0] == '+') + p_modif++; + while (strlen (p_modif) > 0 && p_modif[0] >= '0' + && p_modif[0] <= '9') + { + p_modif++; + } + if (p_modif[0] == 's') + { + second = value; + p_modif++; + } + else if (p_modif[0] == 'm' && p_modif[1] == 'n') + { + minute = value; + p_modif += 2; + } + else if (p_modif[0] == 'h') + { + hour = value; + p_modif++; + } + else if (p_modif[0] == 'd' || p_modif[0] == 'j') + { + day = value; + p_modif += 2; + } + else if (p_modif[0] == 'm') + { + month = value; + p_modif++; + } + else if (p_modif[0] == 'y' || p_modif[0] == 'a') + { + year = value; + p_modif++; + } + else + { + p_modif++; + } + } + } + + if (defaultlanguage == 'F') + { + printf (" année: %d\n", year); + printf (" mois: %d\n", month); + printf (" jour: %d\n", day); + printf (" heure: %d\n", hour); + printf (" minute: %d\n", minute); + printf (" seconde: %d\n", second); + } + else + { + printf (" year: %d\n", year); + printf (" month: %d\n", month); + printf (" day: %d\n", day); + printf (" hour: %d\n", hour); + printf (" minute: %d\n", minute); + printf (" second: %d\n", second); + } + + if (year == 0 && month == 0 && day == 0 && hour == 0 && minute == 0 + && second == 0) + { + if (defaultlanguage == 'F') + { + printf + ("Vous devez entrer un ajustement avec cette commande, svp:\n"); + printf (" Valeur d'ajustement (-1, 1, +1, etc...)\n"); + printf (" Element modifié:\n"); + printf (" a ou y: année\n"); + printf (" m: mois\n"); + printf (" j ou d: jour\n"); + printf (" h: heure\n"); + printf (" mn: minute\n"); + printf (" s: seconde\n"); + printf (" banadd nomtest +1m-2mn1s-6y\n"); + printf + (" Cette exemple ajoute 1 mois et 1 seconde, et soustrait 2 minutes\n"); + printf (" et 6 ans dans le même temps.\n"); + ladmin_log + ("Aucun ajustement n'est pas un ajustement (commande 'banadd').\n"); + } + else + { + printf ("Please give an adjustment with this command:\n"); + printf (" Adjustment value (-1, 1, +1, etc...)\n"); + printf (" Modified element:\n"); + printf (" a or y: year\n"); + printf (" m: month\n"); + printf (" j or d: day\n"); + printf (" h: hour\n"); + printf (" mn: minute\n"); + printf (" s: second\n"); + printf (" banadd testname +1m-2mn1s-6y\n"); + printf + (" this example adds 1 month and 1 second, and substracts 2 minutes\n"); + printf (" and 6 years at the same time.\n"); + ladmin_log + ("No adjustment isn't an adjustment ('banadd' command).\n"); + } + return 137; + } + if (year > 127 || year < -127) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez un ajustement d'années correct (de -127 à 127), svp.\n"); + ladmin_log + ("Ajustement de l'année hors norme (commande 'banadd').\n"); + } + else + { + printf + ("Please give a correct adjustment for the years (from -127 to 127).\n"); + ladmin_log + ("Abnormal adjustement for the year ('banadd' command).\n"); + } + return 137; + } + if (month > 255 || month < -255) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez un ajustement de mois correct (de -255 à 255), svp.\n"); + ladmin_log ("Ajustement du mois hors norme (commande 'banadd').\n"); + } + else + { + printf + ("Please give a correct adjustment for the months (from -255 to 255).\n"); + ladmin_log + ("Abnormal adjustement for the month ('banadd' command).\n"); + } + return 137; + } + if (day > 32767 || day < -32767) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez un ajustement de jours correct (de -32767 à 32767), svp.\n"); + ladmin_log ("Ajustement des jours hors norme (commande 'banadd').\n"); + } + else + { + printf + ("Please give a correct adjustment for the days (from -32767 to 32767).\n"); + ladmin_log + ("Abnormal adjustement for the days ('banadd' command).\n"); + } + return 137; + } + if (hour > 32767 || hour < -32767) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez un ajustement d'heures correct (de -32767 à 32767), svp.\n"); + ladmin_log + ("Ajustement des heures hors norme (commande 'banadd').\n"); + } + else + { + printf + ("Please give a correct adjustment for the hours (from -32767 to 32767).\n"); + ladmin_log + ("Abnormal adjustement for the hours ('banadd' command).\n"); + } + return 137; + } + if (minute > 32767 || minute < -32767) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez un ajustement de minutes correct (de -32767 à 32767), svp.\n"); + ladmin_log + ("Ajustement des minutes hors norme (commande 'banadd').\n"); + } + else + { + printf + ("Please give a correct adjustment for the minutes (from -32767 to 32767).\n"); + ladmin_log + ("Abnormal adjustement for the minutes ('banadd' command).\n"); + } + return 137; + } + if (second > 32767 || second < -32767) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez un ajustement de secondes correct (de -32767 à 32767), svp.\n"); + ladmin_log + ("Ajustement des secondes hors norme (commande 'banadd').\n"); + } + else + { + printf + ("Please give a correct adjustment for the seconds (from -32767 to 32767).\n"); + ladmin_log + ("Abnormal adjustement for the seconds ('banadd' command).\n"); + } + return 137; + } + + if (defaultlanguage == 'F') + { + ladmin_log + ("Envoi d'un requête au serveur de logins pour modifier la date d'un bannissement.\n"); + } + else + { + ladmin_log ("Request to login-server to modify a ban date/time.\n"); + } + + WFIFOW (login_fd, 0) = 0x794c; + memcpy (WFIFOP (login_fd, 2), name, 24); + WFIFOW (login_fd, 26) = (short) year; + WFIFOW (login_fd, 28) = (short) month; + WFIFOW (login_fd, 30) = (short) day; + WFIFOW (login_fd, 32) = (short) hour; + WFIFOW (login_fd, 34) = (short) minute; + WFIFOW (login_fd, 36) = (short) second; + WFIFOSET (login_fd, 38); + bytes_to_read = 1; + + return 0; +} + +//----------------------------------------------------------------------- +// Sub-function of sub-function banaccount, unbanaccount or bansetaccount +// Set the final date of a banishment of an account +//----------------------------------------------------------------------- +int bansetaccountsub (char *name, char *date, char *time) +{ + int year, month, day, hour, minute, second; + time_t ban_until_time; // # of seconds 1/1/1970 (timestamp): ban time limit of the account (0 = no ban) + struct tm *tmtime; + + year = month = day = hour = minute = second = 0; + ban_until_time = 0; + tmtime = localtime (&ban_until_time); // initialize + + if (verify_accountname (name) == 0) + { + return 102; + } + + if (atoi (date) != 0 && + ((sscanf (date, "%d/%d/%d", &year, &month, &day) < 3 && + sscanf (date, "%d-%d-%d", &year, &month, &day) < 3 && + sscanf (date, "%d.%d.%d", &year, &month, &day) < 3) || + sscanf (time, "%d:%d:%d", &hour, &minute, &second) < 3)) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez une date et une heure svp (format: aaaa/mm/jj hh:mm:ss).\n"); + printf + ("Vous pouvez aussi mettre 0 à la place si vous utilisez la commande 'banset'.\n"); + ladmin_log + ("Format incorrect pour la date/heure (commande'banset' ou 'ban').\n"); + } + else + { + printf + ("Please input a date and a time (format: yyyy/mm/dd hh:mm:ss).\n"); + printf + ("You can imput 0 instead of if you use 'banset' command.\n"); + ladmin_log + ("Invalid format for the date/time ('banset' or 'ban' command).\n"); + } + return 102; + } + + if (atoi (date) == 0) + { + ban_until_time = 0; + } + else + { + if (year < 70) + { + year = year + 100; + } + if (year >= 1900) + { + year = year - 1900; + } + if (month < 1 || month > 12) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un mois correct svp (entre 1 et 12).\n"); + ladmin_log + ("Mois incorrect pour la date (command 'banset' ou 'ban').\n"); + } + else + { + printf + ("Please give a correct value for the month (from 1 to 12).\n"); + ladmin_log + ("Invalid month for the date ('banset' or 'ban' command).\n"); + } + return 102; + } + month = month - 1; + if (day < 1 || day > 31) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un jour correct svp (entre 1 et 31).\n"); + ladmin_log + ("Jour incorrect pour la date (command 'banset' ou 'ban').\n"); + } + else + { + printf + ("Please give a correct value for the day (from 1 to 31).\n"); + ladmin_log + ("Invalid day for the date ('banset' or 'ban' command).\n"); + } + return 102; + } + if (((month == 3 || month == 5 || month == 8 || month == 10) + && day > 30) || (month == 1 && day > 29)) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez un jour correct en fonction du mois (%d) svp.\n", + month); + ladmin_log + ("Jour incorrect pour ce mois correspondant (command 'banset' ou 'ban').\n"); + } + else + { + printf + ("Please give a correct value for a day of this month (%d).\n", + month); + ladmin_log + ("Invalid day for this month ('banset' or 'ban' command).\n"); + } + return 102; + } + if (hour < 0 || hour > 23) + { + if (defaultlanguage == 'F') + { + printf ("Entrez une heure correcte svp (entre 0 et 23).\n"); + ladmin_log + ("Heure incorrecte pour l'heure (command 'banset' ou 'ban').\n"); + } + else + { + printf + ("Please give a correct value for the hour (from 0 to 23).\n"); + ladmin_log + ("Invalid hour for the time ('banset' or 'ban' command).\n"); + } + return 102; + } + if (minute < 0 || minute > 59) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez des minutes correctes svp (entre 0 et 59).\n"); + ladmin_log + ("Minute incorrecte pour l'heure (command 'banset' ou 'ban').\n"); + } + else + { + printf + ("Please give a correct value for the minutes (from 0 to 59).\n"); + ladmin_log + ("Invalid minute for the time ('banset' or 'ban' command).\n"); + } + return 102; + } + if (second < 0 || second > 59) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez des secondes correctes svp (entre 0 et 59).\n"); + ladmin_log + ("Seconde incorrecte pour l'heure (command 'banset' ou 'ban').\n"); + } + else + { + printf + ("Please give a correct value for the seconds (from 0 to 59).\n"); + ladmin_log + ("Invalid second for the time ('banset' or 'ban' command).\n"); + } + return 102; + } + tmtime->tm_year = year; + tmtime->tm_mon = month; + tmtime->tm_mday = day; + tmtime->tm_hour = hour; + tmtime->tm_min = minute; + tmtime->tm_sec = second; + tmtime->tm_isdst = -1; // -1: no winter/summer time modification + ban_until_time = timegm (tmtime); + if (ban_until_time == -1) + { + if (defaultlanguage == 'F') + { + printf ("Date incorrecte.\n"); + printf + ("Entrez une date et une heure svp (format: aaaa/mm/jj hh:mm:ss).\n"); + printf + ("Vous pouvez aussi mettre 0 à la place si vous utilisez la commande 'banset'.\n"); + ladmin_log ("Date incorrecte. (command 'banset' ou 'ban').\n"); + } + else + { + printf ("Invalid date.\n"); + printf + ("Please input a date and a time (format: yyyy/mm/dd hh:mm:ss).\n"); + printf + ("You can imput 0 instead of if you use 'banset' command.\n"); + ladmin_log ("Invalid date. ('banset' or 'ban' command).\n"); + } + return 102; + } + } + + if (defaultlanguage == 'F') + { + ladmin_log + ("Envoi d'un requête au serveur de logins pour fixer un ban.\n"); + } + else + { + ladmin_log ("Request to login-server to set a ban.\n"); + } + + WFIFOW (login_fd, 0) = 0x794a; + memcpy (WFIFOP (login_fd, 2), name, 24); + WFIFOL (login_fd, 26) = (int) ban_until_time; + WFIFOSET (login_fd, 30); + bytes_to_read = 1; + + return 0; +} + +//--------------------------------------------------------------------- +// Sub-function: Set the final date of a banishment of an account (ban) +//--------------------------------------------------------------------- +int banaccount (char *param) +{ + char name[1023], date[1023], time[1023]; + + memset (name, '\0', sizeof (name)); + memset (date, '\0', sizeof (date)); + memset (time, '\0', sizeof (time)); + + if (sscanf (param, "%s %s \"%[^\"]\"", date, time, name) < 3 && + sscanf (param, "%s %s '%[^']'", date, time, name) < 3 && + sscanf (param, "%s %s %[^\r\n]", date, time, name) < 3) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un nom de compte, une date et une heure svp.\n"); + printf + (": banset aaaa/mm/jj [hh:mm:ss]\n"); + printf (" banset 0 (0 = dé-bani)\n"); + printf + (" ban/banish aaaa/mm/jj hh:mm:ss \n"); + printf (" unban/unbanish \n"); + printf (" Heure par défaut [hh:mm:ss]: 23:59:59.\n"); + ladmin_log + ("Nombre incorrect de paramètres pour fixer un ban (commande 'banset' ou 'ban').\n"); + } + else + { + printf ("Please input an account name, a date and a hour.\n"); + printf + (": banset yyyy/mm/dd [hh:mm:ss]\n"); + printf + (" banset 0 (0 = un-banished)\n"); + printf + (" ban/banish yyyy/mm/dd hh:mm:ss \n"); + printf (" unban/unbanish \n"); + printf (" Default time [hh:mm:ss]: 23:59:59.\n"); + ladmin_log + ("Incomplete parameters to set a ban ('banset' or 'ban' command).\n"); + } + return 136; + } + + return bansetaccountsub (name, date, time); +} + +//------------------------------------------------------------------------ +// Sub-function: Set the final date of a banishment of an account (banset) +//------------------------------------------------------------------------ +int bansetaccount (char *param) +{ + char name[1023], date[1023], time[1023]; + + memset (name, '\0', sizeof (name)); + memset (date, '\0', sizeof (date)); + memset (time, '\0', sizeof (time)); + + if (sscanf (param, "\"%[^\"]\" %s %[^\r\n]", name, date, time) < 2 && // if date = 0, time can be void + sscanf (param, "'%[^']' %s %[^\r\n]", name, date, time) < 2 && // if date = 0, time can be void + sscanf (param, "%s %s %[^\r\n]", name, date, time) < 2) + { // if date = 0, time can be void + if (defaultlanguage == 'F') + { + printf ("Entrez un nom de compte, une date et une heure svp.\n"); + printf + (": banset aaaa/mm/jj [hh:mm:ss]\n"); + printf (" banset 0 (0 = dé-bani)\n"); + printf + (" ban/banish aaaa/mm/jj hh:mm:ss \n"); + printf (" unban/unbanish \n"); + printf (" Heure par défaut [hh:mm:ss]: 23:59:59.\n"); + ladmin_log + ("Nombre incorrect de paramètres pour fixer un ban (commande 'banset' ou 'ban').\n"); + } + else + { + printf ("Please input an account name, a date and a hour.\n"); + printf + (": banset yyyy/mm/dd [hh:mm:ss]\n"); + printf + (" banset 0 (0 = un-banished)\n"); + printf + (" ban/banish yyyy/mm/dd hh:mm:ss \n"); + printf (" unban/unbanish \n"); + printf (" Default time [hh:mm:ss]: 23:59:59.\n"); + ladmin_log + ("Incomplete parameters to set a ban ('banset' or 'ban' command).\n"); + } + return 136; + } + + if (time[0] == '\0') + strcpy (time, "23:59:59"); + + return bansetaccountsub (name, date, time); +} + +//------------------------------------------------- +// Sub-function: unbanishment of an account (unban) +//------------------------------------------------- +int unbanaccount (char *param) +{ + char name[1023]; + + memset (name, '\0', sizeof (name)); + + if (strlen (param) == 0 || + (sscanf (param, "\"%[^\"]\"", name) < 1 && + sscanf (param, "'%[^']'", name) < 1 && + sscanf (param, "%[^\r\n]", name) < 1) || strlen (name) == 0) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un nom de compte svp.\n"); + printf + (": banset aaaa/mm/jj [hh:mm:ss]\n"); + printf (" banset 0 (0 = dé-bani)\n"); + printf + (" ban/banish aaaa/mm/jj hh:mm:ss \n"); + printf (" unban/unbanish \n"); + printf (" Heure par défaut [hh:mm:ss]: 23:59:59.\n"); + ladmin_log + ("Nombre incorrect de paramètres pour fixer un ban (commande 'unban').\n"); + } + else + { + printf ("Please input an account name.\n"); + printf + (": banset yyyy/mm/dd [hh:mm:ss]\n"); + printf + (" banset 0 (0 = un-banished)\n"); + printf + (" ban/banish yyyy/mm/dd hh:mm:ss \n"); + printf (" unban/unbanish \n"); + printf (" Default time [hh:mm:ss]: 23:59:59.\n"); + ladmin_log + ("Incomplete parameters to set a ban ('unban' command).\n"); + } + return 136; + } + + return bansetaccountsub (name, "0", ""); +} + +//--------------------------------------------------------- +// Sub-function: Asking to check the validity of a password +// (Note: never send back a password with login-server!! security of passwords) +//--------------------------------------------------------- +int checkaccount (char *param) +{ + char name[1023], password[1023]; + + memset (name, '\0', sizeof (name)); + memset (password, '\0', sizeof (password)); + + if (sscanf (param, "\"%[^\"]\" %[^\r\n]", name, password) < 1 && // password can be void + sscanf (param, "'%[^']' %[^\r\n]", name, password) < 1 && // password can be void + sscanf (param, "%s %[^\r\n]", name, password) < 1) + { // password can be void + if (defaultlanguage == 'F') + { + printf ("Entrez un nom de compte svp.\n"); + printf (" check testname motdepasse\n"); + ladmin_log + ("Nombre incorrect de paramètres pour tester le mot d'un passe d'un compte (commande 'check').\n"); + } + else + { + printf ("Please input an account name.\n"); + printf (" check testname password\n"); + ladmin_log + ("Incomplete parameters to check the password of an account ('check' command).\n"); + } + return 136; + } + + if (verify_accountname (name) == 0) + { + return 102; + } + + if (strlen (password) == 0) + { + if (typepasswd (password) == 0) + return 134; + } + if (verify_password (password) == 0) + return 131; + + if (defaultlanguage == 'F') + { + ladmin_log + ("Envoi d'un requête au serveur de logins pour test un mot de passe.\n"); + } + else + { + ladmin_log ("Request to login-server to check a password.\n"); + } + + WFIFOW (login_fd, 0) = 0x793a; + memcpy (WFIFOP (login_fd, 2), name, 24); + memcpy (WFIFOP (login_fd, 26), password, 24); + WFIFOSET (login_fd, 50); + bytes_to_read = 1; + + return 0; +} + +//------------------------------------------------ +// Sub-function: Asking for deletion of an account +//------------------------------------------------ +int delaccount (char *param) +{ + char name[1023]; + char letter; + char confirm[1023]; + int i; + + memset (name, '\0', sizeof (name)); + + if (strlen (param) == 0 || + (sscanf (param, "\"%[^\"]\"", name) < 1 && + sscanf (param, "'%[^']'", name) < 1 && + sscanf (param, "%[^\r\n]", name) < 1) || strlen (name) == 0) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un nom de compte svp.\n"); + printf (" del nomtestasupprimer\n"); + ladmin_log + ("Aucun nom donné pour supprimer un compte (commande 'delete').\n"); + } + else + { + printf ("Please input an account name.\n"); + printf (" del testnametodelete\n"); + ladmin_log + ("No name given to delete an account ('delete' command).\n"); + } + return 136; + } + + if (verify_accountname (name) == 0) + { + return 102; + } + + memset (confirm, '\0', sizeof (confirm)); + while ((confirm[0] != 'o' || defaultlanguage != 'F') && confirm[0] != 'n' + && (confirm[0] != 'y' || defaultlanguage == 'F')) + { + if (defaultlanguage == 'F') + printf + ("\033[1;36m ** Etes-vous vraiment sûr de vouloir SUPPRIMER le compte [$userid]? (o/n) > \033[0m"); + else + printf + ("\033[1;36m ** Are you really sure to DELETE account [$userid]? (y/n) > \033[0m"); + fflush (stdout); + memset (confirm, '\0', sizeof (confirm)); + i = 0; + while ((letter = getchar ()) != '\n') + confirm[i++] = letter; + } + + if (confirm[0] == 'n') + { + if (defaultlanguage == 'F') + { + printf ("Suppression annulée.\n"); + ladmin_log + ("Suppression annulée par l'utilisateur (commande 'delete').\n"); + } + else + { + printf ("Deletion canceled.\n"); + ladmin_log ("Deletion canceled by user ('delete' command).\n"); + } + return 121; + } + + if (defaultlanguage == 'F') + { + ladmin_log + ("Envoi d'un requête au serveur de logins pour détruire un compte.\n"); + } + else + { + ladmin_log ("Request to login-server to delete an acount.\n"); + } + + WFIFOW (login_fd, 0) = 0x7932; + memcpy (WFIFOP (login_fd, 2), name, 24); + WFIFOSET (login_fd, 26); + bytes_to_read = 1; + + return 0; +} + +//---------------------------------------------------------- +// Sub-function: Asking to modification of an account e-mail +//---------------------------------------------------------- +int changeemail (char *param) +{ + char name[1023], email[1023]; + + memset (name, '\0', sizeof (name)); + memset (email, '\0', sizeof (email)); + + if (sscanf (param, "\"%[^\"]\" %[^\r\n]", name, email) < 2 && + sscanf (param, "'%[^']' %[^\r\n]", name, email) < 2 && + sscanf (param, "%s %[^\r\n]", name, email) < 2) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un nom de compte et une email svp.\n"); + printf (" email testname nouveauemail\n"); + ladmin_log + ("Nombre incorrect de paramètres pour changer l'email d'un compte (commande 'email').\n"); + } + else + { + printf ("Please input an account name and an email.\n"); + printf (" email testname newemail\n"); + ladmin_log + ("Incomplete parameters to change the email of an account ('email' command).\n"); + } + return 136; + } + + if (verify_accountname (name) == 0) + { + return 102; + } + + if (strlen (email) < 3) + { + if (defaultlanguage == 'F') + { + printf ("Email trop courte [%s]. Entrez une e-mail valide svp.\n", + email); + ladmin_log + ("Email trop courte [%s]. Entrez une e-mail valide svp.\n", + email); + } + else + { + printf ("Email is too short [%s]. Please input a valid e-mail.\n", + email); + ladmin_log + ("Email is too short [%s]. Please input a valid e-mail.\n", + email); + } + return 109; + } + if (strlen (email) > 39) + { + if (defaultlanguage == 'F') + { + printf + ("Email trop longue [%s]. Entrez une e-mail de 39 caractères maximum svp.\n", + email); + ladmin_log + ("Email trop longue [%s]. Entrez une e-mail de 39 caractères maximum svp.\n", + email); + } + else + { + printf + ("Email is too long [%s]. Please input an e-mail with 39 bytes at the most.\n", + email); + ladmin_log + ("Email is too long [%s]. Please input an e-mail with 39 bytes at the most.\n", + email); + } + return 109; + } + if (e_mail_check (email) == 0) + { + if (defaultlanguage == 'F') + { + printf ("Email incorrecte [%s]. Entrez une e-mail valide svp.\n", + email); + ladmin_log ("Email incorrecte [%s]. Entrez une e-mail valide svp.\n", + email); + } + else + { + printf ("Invalid email [%s]. Please input a valid e-mail.\n", + email); + ladmin_log ("Invalid email [%s]. Please input a valid e-mail.\n", + email); + } + return 109; + } + + if (defaultlanguage == 'F') + { + ladmin_log + ("Envoi d'un requête au serveur de logins pour changer une email.\n"); + } + else + { + ladmin_log ("Request to login-server to change an email.\n"); + } + + WFIFOW (login_fd, 0) = 0x7940; + memcpy (WFIFOP (login_fd, 2), name, 24); + memcpy (WFIFOP (login_fd, 26), email, 40); + WFIFOSET (login_fd, 66); + bytes_to_read = 1; + + return 0; +} + +//----------------------------------------------------- +// Sub-function: Asking of the number of online players +//----------------------------------------------------- +int getlogincount (void) +{ + if (defaultlanguage == 'F') + { + ladmin_log + ("Envoi d'un requête au serveur de logins pour obtenir le nombre de joueurs en jeu.\n"); + } + else + { + ladmin_log + ("Request to login-server to obtain the # of online players.\n"); + } + + WFIFOW (login_fd, 0) = 0x7938; + WFIFOSET (login_fd, 2); + bytes_to_read = 1; + + return 0; +} + +//---------------------------------------------------------- +// Sub-function: Asking to modify the GM level of an account +//---------------------------------------------------------- +int changegmlevel (char *param) +{ + char name[1023]; + int GM_level; + + memset (name, '\0', sizeof (name)); + GM_level = 0; + + if (sscanf (param, "\"%[^\"]\" %d", name, &GM_level) < 1 && + sscanf (param, "'%[^']' %d", name, &GM_level) < 1 && + sscanf (param, "%s %d", name, &GM_level) < 1) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un nom de compte et un niveau de GM svp.\n"); + printf (" gm nomtest 80\n"); + ladmin_log + ("Nombre incorrect de paramètres pour changer le Niveau de GM d'un compte (commande 'gm').\n"); + } + else + { + printf ("Please input an account name and a GM level.\n"); + printf (" gm testname 80\n"); + ladmin_log + ("Incomplete parameters to change the GM level of an account ('gm' command).\n"); + } + return 136; + } + + if (verify_accountname (name) == 0) + { + return 102; + } + + if (GM_level < 0 || GM_level > 99) + { + if (defaultlanguage == 'F') + { + printf + ("Niveau de GM incorrect [%d]. Entrez une valeur de 0 à 99 svp.\n", + GM_level); + ladmin_log + ("Niveau de GM incorrect [%d]. La valeur peut être de 0 à 99.\n", + GM_level); + } + else + { + printf + ("Illegal GM level [%d]. Please input a value from 0 to 99.\n", + GM_level); + ladmin_log + ("Illegal GM level [%d]. The value can be from 0 to 99.\n", + GM_level); + } + return 103; + } + + if (defaultlanguage == 'F') + { + ladmin_log + ("Envoi d'un requête au serveur de logins pour changer un niveau de GM.\n"); + } + else + { + ladmin_log ("Request to login-server to change a GM level.\n"); + } + + WFIFOW (login_fd, 0) = 0x793e; + memcpy (WFIFOP (login_fd, 2), name, 24); + WFIFOB (login_fd, 26) = GM_level; + WFIFOSET (login_fd, 27); + bytes_to_read = 1; + + return 0; +} + +//--------------------------------------------- +// Sub-function: Asking to obtain an account id +//--------------------------------------------- +int idaccount (char *param) +{ + char name[1023]; + + memset (name, '\0', sizeof (name)); + + if (strlen (param) == 0 || + (sscanf (param, "\"%[^\"]\"", name) < 1 && + sscanf (param, "'%[^']'", name) < 1 && + sscanf (param, "%[^\r\n]", name) < 1) || strlen (name) == 0) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un nom de compte svp.\n"); + printf (" id nomtest\n"); + ladmin_log + ("Aucun nom donné pour rechecher l'id d'un compte (commande 'id').\n"); + } + else + { + printf ("Please input an account name.\n"); + printf (" id testname\n"); + ladmin_log + ("No name given to search an account id ('id' command).\n"); + } + return 136; + } + + if (verify_accountname (name) == 0) + { + return 102; + } + + if (defaultlanguage == 'F') + { + ladmin_log + ("Envoi d'un requête au serveur de logins pour connaître l'id d'un compte.\n"); + } + else + { + ladmin_log ("Request to login-server to know an account id.\n"); + } + + WFIFOW (login_fd, 0) = 0x7944; + memcpy (WFIFOP (login_fd, 2), name, 24); + WFIFOSET (login_fd, 26); + bytes_to_read = 1; + + return 0; +} + +//---------------------------------------------------------------------------- +// Sub-function: Asking to displaying information about an account (by its id) +//---------------------------------------------------------------------------- +int infoaccount (int account_id) +{ + if (account_id < 0) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un id ayant une valeur positive svp.\n"); + ladmin_log + ("Une valeur négative a été donné pour trouver le compte.\n"); + } + else + { + printf ("Please input a positive value for the id.\n"); + ladmin_log ("Negative value was given to found the account.\n"); + } + return 136; + } + + if (defaultlanguage == 'F') + { + ladmin_log + ("Envoi d'un requête au serveur de logins pour obtenir le information d'un compte (par l'id).\n"); + } + else + { + ladmin_log + ("Request to login-server to obtain information about an account (by its id).\n"); + } + + WFIFOW (login_fd, 0) = 0x7954; + WFIFOL (login_fd, 2) = account_id; + WFIFOSET (login_fd, 6); + bytes_to_read = 1; + + return 0; +} + +//--------------------------------------- +// Sub-function: Send a broadcast message +//--------------------------------------- +int sendbroadcast (short type, char *message) +{ + if (strlen (message) == 0) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un message svp.\n"); + if (type == 0) + { + printf (" kami un message\n"); + } + else + { + printf (" kamib un message\n"); + } + ladmin_log ("Le message est vide (commande 'kami(b)').\n"); + } + else + { + printf ("Please input a message.\n"); + if (type == 0) + { + printf (" kami a message\n"); + } + else + { + printf (" kamib a message\n"); + } + ladmin_log ("The message is void ('kami(b)' command).\n"); + } + return 136; + } + + WFIFOW (login_fd, 0) = 0x794e; + WFIFOW (login_fd, 2) = type; + WFIFOL (login_fd, 4) = strlen (message) + 1; + memcpy (WFIFOP (login_fd, 8), message, strlen (message) + 1); + WFIFOSET (login_fd, 8 + strlen (message) + 1); + bytes_to_read = 1; + + return 0; +} + +//-------------------------------------------- +// Sub-function: Change language of displaying +//-------------------------------------------- +int changelanguage (char *language) +{ + if (strlen (language) == 0) + { + if (defaultlanguage == 'F') + { + printf ("Entrez une langue svp.\n"); + printf (" language english\n"); + printf (" language français\n"); + ladmin_log ("La langue est vide (commande 'language').\n"); + } + else + { + printf ("Please input a language.\n"); + printf (" language english\n"); + printf (" language français\n"); + ladmin_log ("The language is void ('language' command).\n"); + } + return 136; + } + + language[0] = toupper (language[0]); + if (language[0] == 'F' || language[0] == 'E') + { + defaultlanguage = language[0]; + if (defaultlanguage == 'F') + { + printf ("Changement de la langue d'affichage en Français.\n"); + ladmin_log ("Changement de la langue d'affichage en Français.\n"); + } + else + { + printf ("Displaying language changed to English.\n"); + ladmin_log ("Displaying language changed to English.\n"); + } + } + else + { + if (defaultlanguage == 'F') + { + printf + ("Langue non paramétrée (langues possibles: 'Français' ou 'English').\n"); + ladmin_log + ("Langue non paramétrée (Français ou English nécessaire).\n"); + } + else + { + printf + ("Undefined language (possible languages: Français or English).\n"); + ladmin_log ("Undefined language (must be Français or English).\n"); + } + } + + return 0; +} + +//-------------------------------------------------------- +// Sub-function: Asking to Displaying of the accounts list +//-------------------------------------------------------- +int listaccount (char *param, int type) +{ +//int list_first, list_last, list_type; // parameter to display a list of accounts + int i; + + list_type = type; + + // set default values + list_first = 0; + list_last = 0; + + if (list_type == 1) + { // if listgm + // get all accounts = use default + } + else if (list_type == 2) + { // if search + for (i = 0; param[i]; i++) + param[i] = tolower (param[i]); + // get all accounts = use default + } + else if (list_type == 3) + { // if listban + // get all accounts = use default + } + else if (list_type == 4) + { // if listok + // get all accounts = use default + } + else + { // if list (list_type == 0) + switch (sscanf (param, "%d %d", &list_first, &list_last)) + { + case 0: + // get all accounts = use default + break; + case 1: + list_last = 0; + // use tests of the following value + default: + if (list_first < 0) + list_first = 0; + if (list_last < list_first || list_last < 0) + list_last = 0; + break; + } + } + + if (defaultlanguage == 'F') + { + ladmin_log + ("Envoi d'un requête au serveur de logins pour obtenir la liste des comptes de %d à %d.\n", + list_first, list_last); + } + else + { + ladmin_log + ("Request to login-server to obtain the list of accounts from %d to %d.\n", + list_first, list_last); + } + + WFIFOW (login_fd, 0) = 0x7920; + WFIFOL (login_fd, 2) = list_first; + WFIFOL (login_fd, 6) = list_last; + WFIFOSET (login_fd, 10); + bytes_to_read = 1; + + // 0123456789 01 01234567890123456789012301234 012345 0123456789012345678901234567 + if (defaultlanguage == 'F') + { + Iprintf + (" id_compte GM nom_utilisateur sexe count statut\n"); + } + else + { + Iprintf + ("account_id GM user_name sex count state\n"); + } + Iprintf + ("-------------------------------------------------------------------------------\n"); + list_count = 0; + + return 0; +} + +//-------------------------------------------------------- +// Sub-function: Frobnicate items +//-------------------------------------------------------- +int itemfrob (char *param) +{ + int source_id, dest_id; + + if (sscanf (param, "%d %d", &source_id, &dest_id) < 2) + { + printf ("You must provide the source and destination item IDs.\n"); + return 1; + } + + WFIFOW (login_fd, 0) = 0x7924; + WFIFOL (login_fd, 2) = source_id; + WFIFOL (login_fd, 6) = dest_id; + WFIFOSET (login_fd, 10); + bytes_to_read = 1; // all logging is done to the three main servers + + return 0; +} + +//-------------------------------------------- +// Sub-function: Asking to modify a memo field +//-------------------------------------------- +int changememo (char *param) +{ + char name[1023], memo[1023]; + + memset (name, '\0', sizeof (name)); + memset (memo, '\0', sizeof (memo)); + + if (sscanf (param, "\"%[^\"]\" %[^\r\n]", name, memo) < 1 && // memo can be void + sscanf (param, "'%[^']' %[^\r\n]", name, memo) < 1 && // memo can be void + sscanf (param, "%s %[^\r\n]", name, memo) < 1) + { // memo can be void + if (defaultlanguage == 'F') + { + printf ("Entrez un nom de compte et un mémo svp.\n"); + printf (" memo nomtest nouveau memo\n"); + ladmin_log + ("Nombre incorrect de paramètres pour changer le mémo d'un compte (commande 'email').\n"); + } + else + { + printf ("Please input an account name and a memo.\n"); + printf (" memo testname new memo\n"); + ladmin_log + ("Incomplete parameters to change the memo of an account ('email' command).\n"); + } + return 136; + } + + if (verify_accountname (name) == 0) + { + return 102; + } + + if (strlen (memo) > 254) + { + if (defaultlanguage == 'F') + { + printf ("Mémo trop long (%d caractères).\n", strlen (memo)); + printf ("Entrez un mémo de 254 caractères maximum svp.\n"); + ladmin_log + ("Mémo trop long (%d caractères). Entrez un mémo de 254 caractères maximum svp.\n", + strlen (memo)); + } + else + { + printf ("Memo is too long (%d characters).\n", strlen (memo)); + printf ("Please input a memo of 254 bytes at the maximum.\n"); + ladmin_log + ("Email is too long (%d characters). Please input a memo of 254 bytes at the maximum.\n", + strlen (memo)); + } + return 102; + } + + if (defaultlanguage == 'F') + { + ladmin_log + ("Envoi d'un requête au serveur de logins pour changer un mémo.\n"); + } + else + { + ladmin_log ("Request to login-server to change a memo.\n"); + } + + WFIFOW (login_fd, 0) = 0x7942; + memcpy (WFIFOP (login_fd, 2), name, 24); + WFIFOW (login_fd, 26) = strlen (memo); + if (strlen (memo) > 0) + memcpy (WFIFOP (login_fd, 28), memo, strlen (memo)); + WFIFOSET (login_fd, 28 + strlen (memo)); + bytes_to_read = 1; + + return 0; +} + +//----------------------------------------------- +// Sub-function: Asking to obtain an account name +//----------------------------------------------- +int nameaccount (int id) +{ + if (id < 0) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un id ayant une valeur positive svp.\n"); + ladmin_log + ("Id négatif donné pour rechecher le nom d'un compte (commande 'name').\n"); + } + else + { + printf ("Please input a positive value for the id.\n"); + ladmin_log + ("Negativ id given to search an account name ('name' command).\n"); + } + return 136; + } + + if (defaultlanguage == 'F') + ladmin_log + ("Envoi d'un requête au serveur de logins pour connaître le nom d'un compte.\n"); + else + ladmin_log ("Request to login-server to know an account name.\n"); + + WFIFOW (login_fd, 0) = 0x7946; + WFIFOL (login_fd, 2) = id; + WFIFOSET (login_fd, 6); + bytes_to_read = 1; + + return 0; +} + +//------------------------------------------ +// Sub-function: Asking to modify a password +// (Note: never send back a password with login-server!! security of passwords) +//------------------------------------------ +int changepasswd (char *param) +{ + char name[1023], password[1023]; + + memset (name, '\0', sizeof (name)); + memset (password, '\0', sizeof (password)); + + if (sscanf (param, "\"%[^\"]\" %[^\r\n]", name, password) < 1 && + sscanf (param, "'%[^']' %[^\r\n]", name, password) < 1 && + sscanf (param, "%s %[^\r\n]", name, password) < 1) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un nom de compte svp.\n"); + printf (" passwd nomtest nouveaumotdepasse\n"); + ladmin_log + ("Nombre incorrect de paramètres pour changer le mot d'un passe d'un compte (commande 'password').\n"); + } + else + { + printf ("Please input an account name.\n"); + printf (" passwd testname newpassword\n"); + ladmin_log + ("Incomplete parameters to change the password of an account ('password' command).\n"); + } + return 136; + } + + if (verify_accountname (name) == 0) + { + return 102; + } + + if (strlen (password) == 0) + { + if (typepasswd (password) == 0) + return 134; + } + if (verify_password (password) == 0) + return 131; + + if (defaultlanguage == 'F') + { + ladmin_log + ("Envoi d'un requête au serveur de logins pour changer un mot de passe.\n"); + } + else + { + ladmin_log ("Request to login-server to change a password.\n"); + } + + WFIFOW (login_fd, 0) = 0x7934; + memcpy (WFIFOP (login_fd, 2), name, 24); + memcpy (WFIFOP (login_fd, 26), password, 24); + WFIFOSET (login_fd, 50); + bytes_to_read = 1; + + return 0; +} + +//---------------------------------------------------------------------- +// Sub-function: Request to login-server to reload GM configuration file +// this function have no answer +//---------------------------------------------------------------------- +int reloadGM (void) +{ + WFIFOW (login_fd, 0) = 0x7955; + WFIFOSET (login_fd, 2); + bytes_to_read = 0; + + if (defaultlanguage == 'F') + { + ladmin_log + ("Demande de recharger le fichier de configuration des GM envoyée.\n"); + printf + ("Demande de recharger le fichier de configuration des GM envoyée.\n"); + printf ("Vérifiez les comptes GM actuels (après rechargement):\n"); + } + else + { + ladmin_log ("Request to reload the GM configuration file sended.\n"); + printf ("Request to reload the GM configuration file sended.\n"); + printf ("Check the actual GM accounts (after reloading):\n"); + } + listaccount (parameters, 1); // 1: to list only GM + + return 180; +} + +//----------------------------------------------------- +// Sub-function: Asking to modify the sex of an account +//----------------------------------------------------- +int changesex (char *param) +{ + char name[1023], sex[1023]; + + memset (name, '\0', sizeof (name)); + memset (sex, '\0', sizeof (sex)); + + if (sscanf (param, "\"%[^\"]\" %[^\r\n]", name, sex) < 2 && + sscanf (param, "'%[^']' %[^\r\n]", name, sex) < 2 && + sscanf (param, "%s %[^\r\n]", name, sex) < 2) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un nom de compte et un sexe svp.\n"); + printf (" sex nomtest Male\n"); + ladmin_log + ("Nombre incorrect de paramètres pour changer le sexe d'un compte (commande 'sex').\n"); + } + else + { + printf ("Please input an account name and a sex.\n"); + printf (" sex testname Male\n"); + ladmin_log + ("Incomplete parameters to change the sex of an account ('sex' command).\n"); + } + return 136; + } + + if (verify_accountname (name) == 0) + { + return 102; + } + + sex[0] = toupper (sex[0]); + if (strchr ("MF", sex[0]) == NULL) + { + if (defaultlanguage == 'F') + { + printf ("Sexe incorrect [%s]. Entrez M ou F svp.\n", sex); + ladmin_log ("Sexe incorrect [%s]. Entrez M ou F svp.\n", + sex); + } + else + { + printf ("Illegal gender [%s]. Please input M or F.\n", sex); + ladmin_log ("Illegal gender [%s]. Please input M or F.\n", + sex); + } + return 103; + } + + if (defaultlanguage == 'F') + { + ladmin_log + ("Envoi d'un requête au serveur de logins pour changer un sexe.\n"); + } + else + { + ladmin_log ("Request to login-server to change a sex.\n"); + } + + WFIFOW (login_fd, 0) = 0x793c; + memcpy (WFIFOP (login_fd, 2), name, 24); + WFIFOB (login_fd, 26) = sex[0]; + WFIFOSET (login_fd, 27); + bytes_to_read = 1; + + return 0; +} + +//------------------------------------------------------------------------- +// Sub-function of sub-function changestate, blockaccount or unblockaccount +// Asking to modify the state of an account +//------------------------------------------------------------------------- +int changestatesub (char *name, int state, char *error_message7) +{ + char error_message[1023]; // need to use, because we can modify error_message7 + + memset (error_message, '\0', sizeof (error_message)); + strncpy (error_message, error_message7, sizeof (error_message) - 1); + + if ((state < 0 || state > 9) && state != 100) + { // Valid values: 0: ok, or value of the 0x006a packet + 1 + if (defaultlanguage == 'F') + { + printf ("Entrez une des statuts suivantes svp:\n"); + printf + (" 0 = Compte ok 6 = Your Game's EXE file is not the latest version\n"); + } + else + { + printf ("Please input one of these states:\n"); + printf + (" 0 = Account ok 6 = Your Game's EXE file is not the latest version\n"); + } + printf + (" 1 = Unregistered ID 7 = You are Prohibited to log in until + message\n"); + printf + (" 2 = Incorrect Password 8 = Server is jammed due to over populated\n"); + printf (" 3 = This ID is expired 9 = No MSG\n"); + printf + (" 4 = Rejected from Server 100 = This ID has been totally erased\n"); + printf (" 5 = You have been blocked by the GM Team\n"); + if (defaultlanguage == 'F') + { + printf (" state nomtest 5\n"); + printf (" state nomtest 7 fin de votre ban\n"); + printf (" block \n"); + printf (" unblock \n"); + ladmin_log + ("Valeur incorrecte pour le statut d'un compte (commande 'state', 'block' ou 'unblock').\n"); + } + else + { + printf (" state testname 5\n"); + printf (" state testname 7 end of your ban\n"); + printf (" block \n"); + printf (" unblock \n"); + ladmin_log + ("Invalid value for the state of an account ('state', 'block' or 'unblock' command).\n"); + } + return 151; + } + + if (verify_accountname (name) == 0) + { + return 102; + } + + if (state != 7) + { + strcpy (error_message, "-"); + } + else + { + if (strlen (error_message) < 1) + { + if (defaultlanguage == 'F') + { + printf + ("Message d'erreur trop court. Entrez un message de 1-19 caractères.\n"); + ladmin_log + ("Message d'erreur trop court. Entrez un message de 1-19 caractères.\n"); + } + else + { + printf + ("Error message is too short. Please input a message of 1-19 bytes.\n"); + ladmin_log + ("Error message is too short. Please input a message of 1-19 bytes.\n"); + } + return 102; + } + if (strlen (error_message) > 19) + { + if (defaultlanguage == 'F') + { + printf + ("Message d'erreur trop long. Entrez un message de 1-19 caractères.\n"); + ladmin_log + ("Message d'erreur trop long. Entrez un message de 1-19 caractères.\n"); + } + else + { + printf + ("Error message is too long. Please input a message of 1-19 bytes.\n"); + ladmin_log + ("Error message is too long. Please input a message of 1-19 bytes.\n"); + } + return 102; + } + } + + if (defaultlanguage == 'F') + { + ladmin_log + ("Envoi d'un requête au serveur de logins pour changer un statut.\n"); + } + else + { + ladmin_log ("Request to login-server to change a state.\n"); + } + + WFIFOW (login_fd, 0) = 0x7936; + memcpy (WFIFOP (login_fd, 2), name, 24); + WFIFOL (login_fd, 26) = state; + memcpy (WFIFOP (login_fd, 30), error_message, 20); + WFIFOSET (login_fd, 50); + bytes_to_read = 1; + + return 0; +} + +//------------------------------------------------------- +// Sub-function: Asking to modify the state of an account +//------------------------------------------------------- +int changestate (char *param) +{ + char name[1023], error_message[1023]; + int state; + + memset (name, '\0', sizeof (name)); + memset (error_message, '\0', sizeof (error_message)); + + if (sscanf (param, "\"%[^\"]\" %d %[^\r\n]", name, &state, error_message) + < 2 + && sscanf (param, "'%[^']' %d %[^\r\n]", name, &state, + error_message) < 2 + && sscanf (param, "%s %d %[^\r\n]", name, &state, error_message) < 2) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un nom de compte et un statut svp.\n"); + printf (" state nomtest 5\n"); + printf (" state nomtest 7 fin de votre ban\n"); + printf (" block \n"); + printf (" unblock \n"); + ladmin_log + ("Nombre incorrect de paramètres pour changer le statut d'un compte (commande 'state').\n"); + } + else + { + printf ("Please input an account name and a state.\n"); + printf (" state testname 5\n"); + printf (" state testname 7 end of your ban\n"); + printf (" block \n"); + printf (" unblock \n"); + ladmin_log + ("Incomplete parameters to change the state of an account ('state' command).\n"); + } + return 136; + } + + return changestatesub (name, state, error_message); +} + +//------------------------------------------- +// Sub-function: Asking to unblock an account +//------------------------------------------- +int unblockaccount (char *param) +{ + char name[1023]; + + memset (name, '\0', sizeof (name)); + + if (strlen (param) == 0 || + (sscanf (param, "\"%[^\"]\"", name) < 1 && + sscanf (param, "'%[^']'", name) < 1 && + sscanf (param, "%[^\r\n]", name) < 1) || strlen (name) == 0) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un nom de compte svp.\n"); + printf (" state nomtest 5\n"); + printf (" state nomtest 7 fin de votre ban\n"); + printf (" block \n"); + printf (" unblock \n"); + ladmin_log + ("Nombre incorrect de paramètres pour changer le statut d'un compte (commande 'unblock').\n"); + } + else + { + printf ("Please input an account name.\n"); + printf (" state testname 5\n"); + printf (" state testname 7 end of your ban\n"); + printf (" block \n"); + printf (" unblock \n"); + ladmin_log + ("Incomplete parameters to change the state of an account ('unblock' command).\n"); + } + return 136; + } + + return changestatesub (name, 0, "-"); // state 0, no error message +} + +//------------------------------------------- +// Sub-function: Asking to unblock an account +//------------------------------------------- +int blockaccount (char *param) +{ + char name[1023]; + + memset (name, '\0', sizeof (name)); + + if (strlen (param) == 0 || + (sscanf (param, "\"%[^\"]\"", name) < 1 && + sscanf (param, "'%[^']'", name) < 1 && + sscanf (param, "%[^\r\n]", name) < 1) || strlen (name) == 0) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un nom de compte svp.\n"); + printf (" state nomtest 5\n"); + printf (" state nomtest 7 fin de votre ban\n"); + printf (" block \n"); + printf (" unblock \n"); + ladmin_log + ("Nombre incorrect de paramètres pour changer le statut d'un compte (commande 'block').\n"); + } + else + { + printf ("Please input an account name.\n"); + printf (" state testname 5\n"); + printf (" state testname 7 end of your ban\n"); + printf (" block \n"); + printf (" unblock \n"); + ladmin_log + ("Incomplete parameters to change the state of an account ('block' command).\n"); + } + return 136; + } + + return changestatesub (name, 5, "-"); // state 5, no error message +} + +//--------------------------------------------------------------------- +// Sub-function: Add/substract time to the validity limit of an account +//--------------------------------------------------------------------- +int timeaddaccount (char *param) +{ + char name[1023], modif[1023]; + int year, month, day, hour, minute, second; + char *p_modif; + int value, i; + + memset (name, '\0', sizeof (name)); + memset (modif, '\0', sizeof (modif)); + year = month = day = hour = minute = second = 0; + + if (sscanf (param, "\"%[^\"]\" %[^\r\n]", name, modif) < 2 && + sscanf (param, "'%[^']' %[^\r\n]", name, modif) < 2 && + sscanf (param, "%s %[^\r\n]", name, modif) < 2) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un nom de compte et un modificateur svp.\n"); + printf (" timeadd nomtest +1m-2mn1s-6y\n"); + printf + (" Cette exemple ajoute 1 mois et 1 seconde, et soustrait 2 minutes\n"); + printf (" et 6 ans dans le même temps.\n"); + ladmin_log + ("Nombre incorrect de paramètres pour modifier une date limite d'utilisation (commande 'timeadd').\n"); + } + else + { + printf ("Please input an account name and a modifier.\n"); + printf (" : timeadd testname +1m-2mn1s-6y\n"); + printf + (" this example adds 1 month and 1 second, and substracts 2 minutes\n"); + printf (" and 6 years at the same time.\n"); + ladmin_log + ("Incomplete parameters to modify a limit time ('timeadd' command).\n"); + } + return 136; + } + if (verify_accountname (name) == 0) + { + return 102; + } + + // lowercase for modif + for (i = 0; modif[i]; i++) + modif[i] = tolower (modif[i]); + p_modif = modif; + while (strlen (p_modif) > 0) + { + value = atoi (p_modif); + if (value == 0) + { + p_modif++; + } + else + { + if (p_modif[0] == '-' || p_modif[0] == '+') + p_modif++; + while (strlen (p_modif) > 0 && p_modif[0] >= '0' + && p_modif[0] <= '9') + { + p_modif++; + } + if (p_modif[0] == 's') + { + second = value; + p_modif++; + } + else if (p_modif[0] == 'm' && p_modif[1] == 'n') + { + minute = value; + p_modif += 2; + } + else if (p_modif[0] == 'h') + { + hour = value; + p_modif++; + } + else if (p_modif[0] == 'd' || p_modif[0] == 'j') + { + day = value; + p_modif += 2; + } + else if (p_modif[0] == 'm') + { + month = value; + p_modif++; + } + else if (p_modif[0] == 'y' || p_modif[0] == 'a') + { + year = value; + p_modif++; + } + else + { + p_modif++; + } + } + } + + if (defaultlanguage == 'F') + { + printf (" année: %d\n", year); + printf (" mois: %d\n", month); + printf (" jour: %d\n", day); + printf (" heure: %d\n", hour); + printf (" minute: %d\n", minute); + printf (" seconde: %d\n", second); + } + else + { + printf (" year: %d\n", year); + printf (" month: %d\n", month); + printf (" day: %d\n", day); + printf (" hour: %d\n", hour); + printf (" minute: %d\n", minute); + printf (" second: %d\n", second); + } + + if (year == 0 && month == 0 && day == 0 && hour == 0 && minute == 0 + && second == 0) + { + if (defaultlanguage == 'F') + { + printf + ("Vous devez entrer un ajustement avec cette commande, svp:\n"); + printf (" Valeur d'ajustement (-1, 1, +1, etc...)\n"); + printf (" Elément modifié:\n"); + printf (" a ou y: année\n"); + printf (" m: mois\n"); + printf (" j ou d: jour\n"); + printf (" h: heure\n"); + printf (" mn: minute\n"); + printf (" s: seconde\n"); + printf (" timeadd nomtest +1m-2mn1s-6y\n"); + printf + (" Cette exemple ajoute 1 mois et 1 seconde, et soustrait 2 minutes\n"); + printf (" et 6 ans dans le même temps.\n"); + ladmin_log + ("Aucun ajustement n'est pas un ajustement (commande 'timeadd').\n"); + } + else + { + printf ("Please give an adjustment with this command:\n"); + printf (" Adjustment value (-1, 1, +1, etc...)\n"); + printf (" Modified element:\n"); + printf (" a or y: year\n"); + printf (" m: month\n"); + printf (" j or d: day\n"); + printf (" h: hour\n"); + printf (" mn: minute\n"); + printf (" s: second\n"); + printf (" timeadd testname +1m-2mn1s-6y\n"); + printf + (" this example adds 1 month and 1 second, and substracts 2 minutes\n"); + printf (" and 6 years at the same time.\n"); + ladmin_log + ("No adjustment isn't an adjustment ('timeadd' command).\n"); + } + return 137; + } + if (year > 127 || year < -127) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez un ajustement d'années correct (de -127 à 127), svp.\n"); + ladmin_log + ("Ajustement de l'année hors norme ('timeadd' command).\n"); + } + else + { + printf + ("Please give a correct adjustment for the years (from -127 to 127).\n"); + ladmin_log + ("Abnormal adjustement for the year ('timeadd' command).\n"); + } + return 137; + } + if (month > 255 || month < -255) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez un ajustement de mois correct (de -255 à 255), svp.\n"); + ladmin_log ("Ajustement du mois hors norme ('timeadd' command).\n"); + } + else + { + printf + ("Please give a correct adjustment for the months (from -255 to 255).\n"); + ladmin_log + ("Abnormal adjustement for the month ('timeadd' command).\n"); + } + return 137; + } + if (day > 32767 || day < -32767) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez un ajustement de jours correct (de -32767 à 32767), svp.\n"); + ladmin_log ("Ajustement des jours hors norme ('timeadd' command).\n"); + } + else + { + printf + ("Please give a correct adjustment for the days (from -32767 to 32767).\n"); + ladmin_log + ("Abnormal adjustement for the days ('timeadd' command).\n"); + } + return 137; + } + if (hour > 32767 || hour < -32767) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez un ajustement d'heures correct (de -32767 à 32767), svp.\n"); + ladmin_log + ("Ajustement des heures hors norme ('timeadd' command).\n"); + } + else + { + printf + ("Please give a correct adjustment for the hours (from -32767 to 32767).\n"); + ladmin_log + ("Abnormal adjustement for the hours ('timeadd' command).\n"); + } + return 137; + } + if (minute > 32767 || minute < -32767) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez un ajustement de minutes correct (de -32767 à 32767), svp.\n"); + ladmin_log + ("Ajustement des minutes hors norme ('timeadd' command).\n"); + } + else + { + printf + ("Please give a correct adjustment for the minutes (from -32767 to 32767).\n"); + ladmin_log + ("Abnormal adjustement for the minutes ('timeadd' command).\n"); + } + return 137; + } + if (second > 32767 || second < -32767) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez un ajustement de secondes correct (de -32767 à 32767), svp.\n"); + ladmin_log + ("Ajustement des secondes hors norme ('timeadd' command).\n"); + } + else + { + printf + ("Please give a correct adjustment for the seconds (from -32767 to 32767).\n"); + ladmin_log + ("Abnormal adjustement for the seconds ('timeadd' command).\n"); + } + return 137; + } + + if (defaultlanguage == 'F') + { + ladmin_log + ("Envoi d'un requête au serveur de logins pour modifier une date limite d'utilisation.\n"); + } + else + { + ladmin_log ("Request to login-server to modify a time limit.\n"); + } + + WFIFOW (login_fd, 0) = 0x7950; + memcpy (WFIFOP (login_fd, 2), name, 24); + WFIFOW (login_fd, 26) = (short) year; + WFIFOW (login_fd, 28) = (short) month; + WFIFOW (login_fd, 30) = (short) day; + WFIFOW (login_fd, 32) = (short) hour; + WFIFOW (login_fd, 34) = (short) minute; + WFIFOW (login_fd, 36) = (short) second; + WFIFOSET (login_fd, 38); + bytes_to_read = 1; + + return 0; +} + +//------------------------------------------------- +// Sub-function: Set a validity limit of an account +//------------------------------------------------- +int timesetaccount (char *param) +{ + char name[1023], date[1023], time[1023]; + int year, month, day, hour, minute, second; + time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) + struct tm *tmtime; + + memset (name, '\0', sizeof (name)); + memset (date, '\0', sizeof (date)); + memset (time, '\0', sizeof (time)); + year = month = day = hour = minute = second = 0; + connect_until_time = 0; + tmtime = localtime (&connect_until_time); // initialize + + if (sscanf (param, "\"%[^\"]\" %s %[^\r\n]", name, date, time) < 2 && // if date = 0, time can be void + sscanf (param, "'%[^']' %s %[^\r\n]", name, date, time) < 2 && // if date = 0, time can be void + sscanf (param, "%s %s %[^\r\n]", name, date, time) < 2) + { // if date = 0, time can be void + if (defaultlanguage == 'F') + { + printf ("Entrez un nom de compte, une date et une heure svp.\n"); + printf + (": timeset aaaa/mm/jj [hh:mm:ss]\n"); + printf + (" timeset 0 (0 = illimité)\n"); + printf (" Heure par défaut [hh:mm:ss]: 23:59:59.\n"); + ladmin_log + ("Nombre incorrect de paramètres pour fixer une date limite d'utilisation (commande 'timeset').\n"); + } + else + { + printf ("Please input an account name, a date and a hour.\n"); + printf + (": timeset yyyy/mm/dd [hh:mm:ss]\n"); + printf + (" timeset 0 (0 = unlimited)\n"); + printf (" Default time [hh:mm:ss]: 23:59:59.\n"); + ladmin_log + ("Incomplete parameters to set a limit time ('timeset' command).\n"); + } + return 136; + } + if (verify_accountname (name) == 0) + { + return 102; + } + + if (time[0] == '\0') + strcpy (time, "23:59:59"); + + if (atoi (date) != 0 && + ((sscanf (date, "%d/%d/%d", &year, &month, &day) < 3 && + sscanf (date, "%d-%d-%d", &year, &month, &day) < 3 && + sscanf (date, "%d.%d.%d", &year, &month, &day) < 3 && + sscanf (date, "%d'%d'%d", &year, &month, &day) < 3) || + sscanf (time, "%d:%d:%d", &hour, &minute, &second) < 3)) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez 0 ou une date et une heure svp (format: 0 ou aaaa/mm/jj hh:mm:ss).\n"); + ladmin_log + ("Format incorrect pour la date/heure ('timeset' command).\n"); + } + else + { + printf + ("Please input 0 or a date and a time (format: 0 or yyyy/mm/dd hh:mm:ss).\n"); + ladmin_log + ("Invalid format for the date/time ('timeset' command).\n"); + } + return 102; + } + + if (atoi (date) == 0) + { + connect_until_time = 0; + } + else + { + if (year < 70) + { + year = year + 100; + } + if (year >= 1900) + { + year = year - 1900; + } + if (month < 1 || month > 12) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un mois correct svp (entre 1 et 12).\n"); + ladmin_log ("Mois incorrect pour la date ('timeset' command).\n"); + } + else + { + printf + ("Please give a correct value for the month (from 1 to 12).\n"); + ladmin_log ("Invalid month for the date ('timeset' command).\n"); + } + return 102; + } + month = month - 1; + if (day < 1 || day > 31) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un jour correct svp (entre 1 et 31).\n"); + ladmin_log ("Jour incorrect pour la date ('timeset' command).\n"); + } + else + { + printf + ("Please give a correct value for the day (from 1 to 31).\n"); + ladmin_log ("Invalid day for the date ('timeset' command).\n"); + } + return 102; + } + if (((month == 3 || month == 5 || month == 8 || month == 10) + && day > 30) || (month == 1 && day > 29)) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez un jour correct en fonction du mois (%d) svp.\n", + month); + ladmin_log + ("Jour incorrect pour ce mois correspondant ('timeset' command).\n"); + } + else + { + printf + ("Please give a correct value for a day of this month (%d).\n", + month); + ladmin_log ("Invalid day for this month ('timeset' command).\n"); + } + return 102; + } + if (hour < 0 || hour > 23) + { + if (defaultlanguage == 'F') + { + printf ("Entrez une heure correcte svp (entre 0 et 23).\n"); + ladmin_log + ("Heure incorrecte pour l'heure ('timeset' command).\n"); + } + else + { + printf + ("Please give a correct value for the hour (from 0 to 23).\n"); + ladmin_log ("Invalid hour for the time ('timeset' command).\n"); + } + return 102; + } + if (minute < 0 || minute > 59) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez des minutes correctes svp (entre 0 et 59).\n"); + ladmin_log + ("Minute incorrecte pour l'heure ('timeset' command).\n"); + } + else + { + printf + ("Please give a correct value for the minutes (from 0 to 59).\n"); + ladmin_log ("Invalid minute for the time ('timeset' command).\n"); + } + return 102; + } + if (second < 0 || second > 59) + { + if (defaultlanguage == 'F') + { + printf + ("Entrez des secondes correctes svp (entre 0 et 59).\n"); + ladmin_log + ("Seconde incorrecte pour l'heure ('timeset' command).\n"); + } + else + { + printf + ("Please give a correct value for the seconds (from 0 to 59).\n"); + ladmin_log ("Invalid second for the time ('timeset' command).\n"); + } + return 102; + } + tmtime->tm_year = year; + tmtime->tm_mon = month; + tmtime->tm_mday = day; + tmtime->tm_hour = hour; + tmtime->tm_min = minute; + tmtime->tm_sec = second; + tmtime->tm_isdst = -1; // -1: no winter/summer time modification + connect_until_time = timegm (tmtime); + if (connect_until_time == -1) + { + if (defaultlanguage == 'F') + { + printf ("Date incorrecte.\n"); + printf + ("Ajoutez 0 ou une date et une heure svp (format: 0 ou aaaa/mm/jj hh:mm:ss).\n"); + ladmin_log ("Date incorrecte. ('timeset' command).\n"); + } + else + { + printf ("Invalid date.\n"); + printf + ("Please add 0 or a date and a time (format: 0 or yyyy/mm/dd hh:mm:ss).\n"); + ladmin_log ("Invalid date. ('timeset' command).\n"); + } + return 102; + } + } + + if (defaultlanguage == 'F') + { + ladmin_log + ("Envoi d'un requête au serveur de logins pour fixer une date limite d'utilisation.\n"); + } + else + { + ladmin_log ("Request to login-server to set a time limit.\n"); + } + + WFIFOW (login_fd, 0) = 0x7948; + memcpy (WFIFOP (login_fd, 2), name, 24); + WFIFOL (login_fd, 26) = (int) connect_until_time; + WFIFOSET (login_fd, 30); + bytes_to_read = 1; + + return 0; +} + +//------------------------------------------------------------------------------ +// Sub-function: Asking to displaying information about an account (by its name) +//------------------------------------------------------------------------------ +int whoaccount (char *param) +{ + char name[1023]; + + memset (name, '\0', sizeof (name)); + + if (strlen (param) == 0 || + (sscanf (param, "\"%[^\"]\"", name) < 1 && + sscanf (param, "'%[^']'", name) < 1 && + sscanf (param, "%[^\r\n]", name) < 1) || strlen (name) == 0) + { + if (defaultlanguage == 'F') + { + printf ("Entrez un nom de compte svp.\n"); + printf (" who nomtest\n"); + ladmin_log ("Aucun nom n'a été donné pour trouver le compte.\n"); + } + else + { + printf ("Please input an account name.\n"); + printf (" who testname\n"); + ladmin_log ("No name was given to found the account.\n"); + } + return 136; + } + if (verify_accountname (name) == 0) + { + return 102; + } + + if (defaultlanguage == 'F') + { + ladmin_log + ("Envoi d'un requête au serveur de logins pour obtenir le information d'un compte (par le nom).\n"); + } + else + { + ladmin_log + ("Request to login-server to obtain information about an account (by its name).\n"); + } + + WFIFOW (login_fd, 0) = 0x7952; + memcpy (WFIFOP (login_fd, 2), name, 24); + WFIFOSET (login_fd, 26); + bytes_to_read = 1; + + return 0; +} + +//-------------------------------------------------------- +// Sub-function: Asking of the version of the login-server +//-------------------------------------------------------- +int checkloginversion (void) +{ + if (defaultlanguage == 'F') + ladmin_log + ("Envoi d'un requête au serveur de logins pour obtenir sa version.\n"); + else + ladmin_log ("Request to login-server to obtain its version.\n"); + + WFIFOW (login_fd, 0) = 0x7530; + WFIFOSET (login_fd, 2); + bytes_to_read = 1; + + return 0; +} + +//--------------------------------------------- +// Prompt function +// this function wait until user type a command +// and analyse the command. +//--------------------------------------------- +int prompt (void) +{ + int i, j; + char buf[1024]; + char *p; + + // while we don't wait new packets + while (bytes_to_read == 0) + { + // for help with the console colors look here: + // http://www.edoceo.com/liberum/?doc=printf-with-color + // some code explanation (used here): + // \033[2J : clear screen and go up/left (0, 0 position) + // \033[K : clear line from actual position to end of the line + // \033[0m : reset color parameter + // \033[1m : use bold for font + Iprintf ("\n"); + if (defaultlanguage == 'F') + { + Iprintf + ("\033[32mPour afficher les commandes, tapez 'Entrée'.\033[0m\n"); + } + else + Iprintf ("\033[32mTo list the commands, type 'enter'.\033[0m\n"); + Iprintf ("\033[0;36mLadmin-> \033[0m"); + Iprintf ("\033[1m"); + fflush (stdout); + + // get command and parameter + memset (buf, '\0', sizeof (buf)); + fflush (stdin); + if (!fgets (buf, 1023, stdin)) + exit (0); + buf[1023] = '\0'; + + Iprintf ("\033[0m"); + fflush (stdout); + + if (!eathena_interactive_session && !strlen (buf)) + exit (0); + + // remove final \n + if ((p = strrchr (buf, '\n')) != NULL) + p[0] = '\0'; + // remove all control char + for (i = 0; buf[i]; i++) + if (buf[i] < 32) + { + // remove cursor control. + if (buf[i] == 27 && buf[i + 1] == '[' && (buf[i + 2] == 'H' || // home position (cursor) + buf[i + 2] == 'J' || // clear screen + buf[i + 2] == 'A' || // up 1 line + buf[i + 2] == 'B' || // down 1 line + buf[i + 2] == 'C' || // right 1 position + buf[i + 2] == 'D' || // left 1 position + buf[i + 2] == 'G')) + { // center cursor (windows) + for (j = i; buf[j]; j++) + buf[j] = buf[j + 3]; + } + else if (buf[i] == 27 && buf[i + 1] == '[' + && buf[i + 2] == '2' && buf[i + 3] == 'J') + { // clear screen + for (j = i; buf[j]; j++) + buf[j] = buf[j + 4]; + } + else if (buf[i] == 27 && buf[i + 1] == '[' && buf[i + 3] == '~' && (buf[i + 2] == '1' || // home (windows) + buf[i + 2] == '2' || // insert (windows) + buf[i + 2] == '3' || // del (windows) + buf[i + 2] == '4' || // end (windows) + buf[i + 2] == '5' || // pgup (windows) + buf + [i + + + 2] + == + '6')) + { // pgdown (windows) + for (j = i; buf[j]; j++) + buf[j] = buf[j + 4]; + } + else + { + // remove other control char. + for (j = i; buf[j]; j++) + buf[j] = buf[j + 1]; + } + i--; + } + + // extract command name and parameters + memset (command, '\0', sizeof (command)); + memset (parameters, '\0', sizeof (parameters)); + sscanf (buf, "%1023s %[^\n]", command, parameters); + command[1023] = '\0'; + parameters[1023] = '\0'; + + // lowercase for command line + for (i = 0; command[i]; i++) + command[i] = tolower (command[i]); + + if (command[0] == '?' || strlen (command) == 0) + { + if (defaultlanguage == 'F') + { + strcpy (buf, "aide"); + strcpy (command, "aide"); + } + else + { + strcpy (buf, "help"); + strcpy (command, "help"); + } + } + + // Analyse of the command + check_command (command); // give complete name to the command + + if (strlen (parameters) == 0) + { + if (defaultlanguage == 'F') + { + ladmin_log ("Commande: '%s' (sans paramètre)\n", + command, parameters); + } + else + { + ladmin_log ("Command: '%s' (without parameters)\n", + command, parameters); + } + } + else + { + if (defaultlanguage == 'F') + { + ladmin_log ("Commande: '%s', paramètres: '%s'\n", + command, parameters); + } + else + { + ladmin_log ("Command: '%s', parameters: '%s'\n", + command, parameters); + } + } + + // Analyse of the command +// help + if (strcmp (command, "aide") == 0) + { + display_help (parameters, 1); // 1: french + } + else if (strcmp (command, "help") == 0) + { + display_help (parameters, 0); // 0: english +// general commands + } + else if (strcmp (command, "add") == 0) + { + addaccount (parameters, 0); // 0: no email + } + else if (strcmp (command, "ban") == 0) + { + banaccount (parameters); + } + else if (strcmp (command, "banadd") == 0) + { + banaddaccount (parameters); + } + else if (strcmp (command, "banset") == 0) + { + bansetaccount (parameters); + } + else if (strcmp (command, "block") == 0) + { + blockaccount (parameters); + } + else if (strcmp (command, "check") == 0) + { + checkaccount (parameters); + } + else if (strcmp (command, "create") == 0) + { + addaccount (parameters, 1); // 1: with email + } + else if (strcmp (command, "delete") == 0) + { + delaccount (parameters); + } + else if (strcmp (command, "email") == 0) + { + changeemail (parameters); + } + else if (strcmp (command, "getcount") == 0) + { + getlogincount (); + } + else if (strcmp (command, "gm") == 0) + { + changegmlevel (parameters); + } + else if (strcmp (command, "id") == 0) + { + idaccount (parameters); + } + else if (strcmp (command, "info") == 0) + { + infoaccount (atoi (parameters)); + } + else if (strcmp (command, "kami") == 0) + { + sendbroadcast (0, parameters); // flag for normal + } + else if (strcmp (command, "kamib") == 0) + { + sendbroadcast (0x10, parameters); // flag for blue + } + else if (strcmp (command, "language") == 0) + { + changelanguage (parameters); + } + else if (strcmp (command, "itemfrob") == 0) + { + itemfrob (parameters); // 0: to list all + } + else if (strcmp (command, "list") == 0) + { + listaccount (parameters, 0); // 0: to list all + } + else if (strcmp (command, "listban") == 0) + { + listaccount (parameters, 3); // 3: to list only accounts with state or bannished + } + else if (strcmp (command, "listgm") == 0) + { + listaccount (parameters, 1); // 1: to list only GM + } + else if (strcmp (command, "listok") == 0) + { + listaccount (parameters, 4); // 4: to list only accounts without state and not bannished + } + else if (strcmp (command, "memo") == 0) + { + changememo (parameters); + } + else if (strcmp (command, "name") == 0) + { + nameaccount (atoi (parameters)); + } + else if (strcmp (command, "password") == 0) + { + changepasswd (parameters); + } + else if (strcmp (command, "reloadgm") == 0) + { + reloadGM (); + } + else if (strcmp (command, "search") == 0) + { // no regex in C version + listaccount (parameters, 2); // 2: to list with pattern + } + else if (strcmp (command, "sex") == 0) + { + changesex (parameters); + } + else if (strcmp (command, "state") == 0) + { + changestate (parameters); + } + else if (strcmp (command, "timeadd") == 0) + { + timeaddaccount (parameters); + } + else if (strcmp (command, "timeset") == 0) + { + timesetaccount (parameters); + } + else if (strcmp (command, "unban") == 0) + { + unbanaccount (parameters); + } + else if (strcmp (command, "unblock") == 0) + { + unblockaccount (parameters); + } + else if (strcmp (command, "version") == 0) + { + checkloginversion (); + } + else if (strcmp (command, "who") == 0) + { + whoaccount (parameters); +// quit + } + else if (strcmp (command, "quit") == 0 || + strcmp (command, "exit") == 0 || + strcmp (command, "end") == 0) + { + if (defaultlanguage == 'F') + { + printf ("Au revoir.\n"); + } + else + { + printf ("Bye.\n"); + } + exit (0); +// unknown command + } + else + { + if (defaultlanguage == 'F') + { + printf ("Commande inconnue [%s].\n", buf); + ladmin_log ("Commande inconnue [%s].\n", buf); + } + else + { + printf ("Unknown command [%s].\n", buf); + ladmin_log ("Unknown command [%s].\n", buf); + } + } + } + + return 0; +} + +//------------------------------------------------------------- +// Function: Parse receiving informations from the login-server +//------------------------------------------------------------- +void parse_fromlogin (int fd) +{ + struct char_session_data *sd; + + if (session[fd]->eof) + { + if (defaultlanguage == 'F') + { + printf + ("Impossible de se connecter au serveur de login [%s:%d] !\n", + loginserverip, loginserverport); + ladmin_log + ("Impossible de se connecter au serveur de login [%s:%d] !\n", + loginserverip, loginserverport); + } + else + { + printf + ("Impossible to have a connection with the login-server [%s:%d] !\n", + loginserverip, loginserverport); + ladmin_log + ("Impossible to have a connection with the login-server [%s:%d] !\n", + loginserverip, loginserverport); + } + close (fd); + delete_session (fd); + exit (0); + } + +// printf("parse_fromlogin : %d %d %d\n", fd, RFIFOREST(fd), RFIFOW(fd,0)); + sd = (struct char_session_data *)session[fd]->session_data; + + while (RFIFOREST (fd) >= 2) + { + switch (RFIFOW (fd, 0)) + { + case 0x7919: // answer of a connection request + if (RFIFOREST (fd) < 3) + return; + if (RFIFOB (fd, 2) != 0) + { + if (defaultlanguage == 'F') + { + printf ("Erreur de login:\n"); + printf (" - mot de passe incorrect,\n"); + printf + (" - système d'administration non activé, ou\n"); + printf (" - IP non autorisée.\n"); + ladmin_log + ("Erreur de login: mot de passe incorrect, système d'administration non activé, ou IP non autorisée.\n"); + } + else + { + printf ("Error at login:\n"); + printf (" - incorrect password,\n"); + printf + (" - administration system not activated, or\n"); + printf (" - unauthorised IP.\n"); + ladmin_log + ("Error at login: incorrect password, administration system not activated, or unauthorised IP.\n"); + } + session[fd]->eof = 1; + //bytes_to_read = 1; // not stop at prompt + } + else + { + if (defaultlanguage == 'F') + { + printf ("Connexion établie.\n"); + ladmin_log ("Connexion établie.\n"); + printf + ("Lecture de la version du serveur de login...\n"); + ladmin_log + ("Lecture de la version du serveur de login...\n"); + } + else + { + Iprintf ("Established connection.\n"); + ladmin_log ("Established connection.\n"); + Iprintf + ("Reading of the version of the login-server...\n"); + ladmin_log + ("Reading of the version of the login-server...\n"); + } + //bytes_to_read = 1; // unchanged + checkloginversion (); + } + RFIFOSKIP (fd, 3); + break; + +#ifdef PASSWORDENC + case 0x01dc: // answer of a coding key request + if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) + return; + { + char md5str[64] = + "", md5bin[32], md5key[RFIFOW (fd, 2) - 4 + 1]; + memcpy (md5key, RFIFOP (fd, 4), RFIFOW (fd, 2) - 4); + md5key[sizeof (md5key) - 1] = '0'; + if (passenc == 1) + { + strncpy (md5str, RFIFOP (fd, 4), RFIFOW (fd, 2) - 4); + strcat (md5str, loginserveradminpassword); + } + else if (passenc == 2) + { + strncpy (md5str, loginserveradminpassword, + sizeof (loginserveradminpassword)); + strcat (md5str, RFIFOP (fd, 4)); + } + MD5_to_bin(MD5_from_cstring(md5str), md5bin); + WFIFOW (login_fd, 0) = 0x7918; // Request for administation login (encrypted password) + WFIFOW (login_fd, 2) = passenc; // Encrypted type + memcpy (WFIFOP (login_fd, 4), md5bin, 16); + WFIFOSET (login_fd, 20); + if (defaultlanguage == 'F') + { + Iprintf ("Réception de la clef MD5.\n"); + ladmin_log ("Réception de la clef MD5.\n"); + Iprintf ("Envoi du mot de passe crypté...\n"); + ladmin_log ("Envoi du mot de passe crypté...\n"); + } + else + { + Iprintf ("Receiving of the MD5 key.\n"); + ladmin_log ("Receiving of the MD5 key.\n"); + Iprintf ("Sending of the encrypted password...\n"); + ladmin_log ("Sending of the encrypted password...\n"); + } + } + bytes_to_read = 1; + RFIFOSKIP (fd, RFIFOW (fd, 2)); + break; +#endif + + case 0x7531: // Displaying of the version of the login-server + if (RFIFOREST (fd) < 10) + return; + Iprintf (" Login-Server [%s:%d]\n", loginserverip, + loginserverport); + if (((int) RFIFOB (login_fd, 5)) == 0) + { + Iprintf (" eAthena version stable-%d.%d", + (int) RFIFOB (login_fd, 2), + (int) RFIFOB (login_fd, 3)); + } + else + { + Iprintf (" eAthena version dev-%d.%d", + (int) RFIFOB (login_fd, 2), + (int) RFIFOB (login_fd, 3)); + } + if (((int) RFIFOB (login_fd, 4)) == 0) + Iprintf (" revision %d", (int) RFIFOB (login_fd, 4)); + if (((int) RFIFOB (login_fd, 6)) == 0) + { + Iprintf ("%d.\n", RFIFOW (login_fd, 8)); + } + else + Iprintf ("-mod%d.\n", RFIFOW (login_fd, 8)); + bytes_to_read = 0; + RFIFOSKIP (fd, 10); + break; + + case 0x7925: // Itemfrob-OK + RFIFOSKIP (fd, 2); + bytes_to_read = 0; + break; + + case 0x7921: // Displaying of the list of accounts + if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) + return; + if (RFIFOW (fd, 2) < 5) + { + if (defaultlanguage == 'F') + { + ladmin_log + (" Réception d'une liste des comptes vide.\n"); + if (list_count == 0) + printf ("Aucun compte trouvé.\n"); + else if (list_count == 1) + printf ("1 compte trouvé.\n"); + else + printf ("%d comptes trouvés.\n", list_count); + } + else + { + ladmin_log (" Receiving of a void accounts list.\n"); + if (list_count == 0) + { + Iprintf ("No account found.\n"); + } + else if (list_count == 1) + { + Iprintf ("1 account found.\n"); + } + else + Iprintf ("%d accounts found.\n", list_count); + } + bytes_to_read = 0; + } + else + { + int i; + if (defaultlanguage == 'F') + ladmin_log (" Réception d'une liste des comptes.\n"); + else + ladmin_log (" Receiving of a accounts list.\n"); + for (i = 4; i < RFIFOW (fd, 2); i += 38) + { + int j; + char userid[24]; + char lower_userid[24]; + memcpy (userid, RFIFOP (fd, i + 5), sizeof (userid)); + userid[sizeof (userid) - 1] = '\0'; + memset (lower_userid, '\0', sizeof (lower_userid)); + for (j = 0; userid[j]; j++) + lower_userid[j] = tolower (userid[j]); + list_first = RFIFOL (fd, i) + 1; + // here are checks... + if (list_type == 0 || + (list_type == 1 && RFIFOB (fd, i + 4) > 0) || + (list_type == 2 + && strstr (lower_userid, parameters) != NULL) + || (list_type == 3 && RFIFOL (fd, i + 34) != 0) + || (list_type == 4 && RFIFOL (fd, i + 34) == 0)) + { + printf ("%10d ", RFIFOL (fd, i)); + if (RFIFOB (fd, i + 4) == 0) + printf (" "); + else + printf ("%2d ", (int) RFIFOB (fd, i + 4)); + printf ("%-24s", userid); + if (defaultlanguage == 'F') + { + if (RFIFOB (fd, i + 29) == 0) + printf ("%-5s ", "Femme"); + else if (RFIFOB (fd, i + 29) == 1) + printf ("%-5s ", "Male"); + else + printf ("%-5s ", "Servr"); + } + else + { + if (RFIFOB (fd, i + 29) == 0) + printf ("%-5s ", "Femal"); + else if (RFIFOB (fd, i + 29) == 1) + printf ("%-5s ", "Male"); + else + printf ("%-5s ", "Servr"); + } + printf ("%6d ", RFIFOL (fd, i + 30)); + switch (RFIFOL (fd, i + 34)) + { + case 0: + if (defaultlanguage == 'F') + printf ("%-27s\n", "Compte Ok"); + else + printf ("%-27s\n", "Account OK"); + break; + case 1: + printf ("%-27s\n", "Unregistered ID"); + break; + case 2: + printf ("%-27s\n", "Incorrect Password"); + break; + case 3: + printf ("%-27s\n", "This ID is expired"); + break; + case 4: + printf ("%-27s\n", + "Rejected from Server"); + break; + case 5: + printf ("%-27s\n", "Blocked by the GM Team"); // You have been blocked by the GM Team + break; + case 6: + printf ("%-27s\n", "Your EXE file is too old"); // Your Game's EXE file is not the latest version + break; + case 7: + printf ("%-27s\n", "Banishement or"); + printf (" Prohibited to login until...\n"); // You are Prohibited to log in until %s + break; + case 8: + printf ("%-27s\n", + "Server is over populated"); + break; + case 9: + printf ("%-27s\n", "No MSG"); + break; + default: // 100 + printf ("%-27s\n", "This ID is totally erased"); // This ID has been totally erased + break; + } + list_count++; + } + } + // asking of the following acounts + if (defaultlanguage == 'F') + ladmin_log + ("Envoi d'un requête au serveur de logins pour obtenir la liste des comptes de %d à %d (complément).\n", + list_first, list_last); + else + ladmin_log + ("Request to login-server to obtain the list of accounts from %d to %d (complement).\n", + list_first, list_last); + WFIFOW (login_fd, 0) = 0x7920; + WFIFOL (login_fd, 2) = list_first; + WFIFOL (login_fd, 6) = list_last; + WFIFOSET (login_fd, 10); + bytes_to_read = 1; + } + RFIFOSKIP (fd, RFIFOW (fd, 2)); + break; + + case 0x7931: // Answer of login-server about an account creation + if (RFIFOREST (fd) < 30) + return; + if (RFIFOL (fd, 2) == -1) + { + if (defaultlanguage == 'F') + { + printf + ("Echec à la création du compte [%s]. Un compte identique existe déjà.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Echec à la création du compte [%s]. Un compte identique existe déjà.\n", + RFIFOP (fd, 6)); + } + else + { + printf + ("Account [%s] creation failed. Same account already exists.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Account [%s] creation failed. Same account already exists.\n", + RFIFOP (fd, 6)); + } + } + else + { + if (defaultlanguage == 'F') + { + printf ("Compte [%s] créé avec succès [id: %d].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log ("Compte [%s] créé avec succès [id: %d].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + else + { + printf + ("Account [%s] is successfully created [id: %d].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Account [%s] is successfully created [id: %d].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + } + bytes_to_read = 0; + RFIFOSKIP (fd, 30); + break; + + case 0x7933: // Answer of login-server about an account deletion + if (RFIFOREST (fd) < 30) + return; + if (RFIFOL (fd, 2) == -1) + { + if (defaultlanguage == 'F') + { + printf + ("Echec de la suppression du compte [%s]. Le compte n'existe pas.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Echec de la suppression du compte [%s]. Le compte n'existe pas.\n", + RFIFOP (fd, 6)); + } + else + { + printf + ("Account [%s] deletion failed. Account doesn't exist.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Account [%s] deletion failed. Account doesn't exist.\n", + RFIFOP (fd, 6)); + } + } + else + { + if (defaultlanguage == 'F') + { + printf ("Compte [%s][id: %d] SUPPRIME avec succès.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Compte [%s][id: %d] SUPPRIME avec succès.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + else + { + printf + ("Account [%s][id: %d] is successfully DELETED.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Account [%s][id: %d] is successfully DELETED.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + } + bytes_to_read = 0; + RFIFOSKIP (fd, 30); + break; + + case 0x7935: // answer of the change of an account password + if (RFIFOREST (fd) < 30) + return; + if (RFIFOL (fd, 2) == -1) + { + if (defaultlanguage == 'F') + { + printf + ("Echec de la modification du mot de passe du compte [%s].\n", + RFIFOP (fd, 6)); + printf ("Le compte [%s] n'existe pas.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Echec de la modification du mot de passe du compte. Le compte [%s] n'existe pas.\n", + RFIFOP (fd, 6)); + } + else + { + printf ("Account [%s] password changing failed.\n", + RFIFOP (fd, 6)); + printf ("Account [%s] doesn't exist.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Account password changing failed. The compte [%s] doesn't exist.\n", + RFIFOP (fd, 6)); + } + } + else + { + if (defaultlanguage == 'F') + { + printf + ("Modification du mot de passe du compte [%s][id: %d] réussie.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Modification du mot de passe du compte [%s][id: %d] réussie.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + else + { + printf + ("Account [%s][id: %d] password successfully changed.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Account [%s][id: %d] password successfully changed.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + } + bytes_to_read = 0; + RFIFOSKIP (fd, 30); + break; + + case 0x7937: // answer of the change of an account state + if (RFIFOREST (fd) < 34) + return; + if (RFIFOL (fd, 2) == -1) + { + if (defaultlanguage == 'F') + { + printf + ("Echec du changement du statut du compte [%s]. Le compte n'existe pas.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Echec du changement du statut du compte [%s]. Le compte n'existe pas.\n", + RFIFOP (fd, 6)); + } + else + { + printf + ("Account [%s] state changing failed. Account doesn't exist.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Account [%s] state changing failed. Account doesn't exist.\n", + RFIFOP (fd, 6)); + } + } + else + { + char tmpstr[256]; + if (defaultlanguage == 'F') + { + sprintf (tmpstr, + "Statut du compte [%s] changé avec succès en [", + RFIFOP (fd, 6)); + } + else + { + sprintf (tmpstr, + "Account [%s] state successfully changed in [", + RFIFOP (fd, 6)); + } + switch (RFIFOL (fd, 30)) + { + case 0: + if (defaultlanguage == 'F') + strcat (tmpstr, "0: Compte Ok"); + else + strcat (tmpstr, "0: Account OK"); + break; + case 1: + strcat (tmpstr, "1: Unregistered ID"); + break; + case 2: + strcat (tmpstr, "2: Incorrect Password"); + break; + case 3: + strcat (tmpstr, "3: This ID is expired"); + break; + case 4: + strcat (tmpstr, "4: Rejected from Server"); + break; + case 5: + strcat (tmpstr, + "5: You have been blocked by the GM Team"); + break; + case 6: + strcat (tmpstr, + "6: [Your Game's EXE file is not the latest version"); + break; + case 7: + strcat (tmpstr, + "7: You are Prohibited to log in until..."); + break; + case 8: + strcat (tmpstr, + "8: Server is jammed due to over populated"); + break; + case 9: + strcat (tmpstr, "9: No MSG"); + break; + default: // 100 + strcat (tmpstr, "100: This ID is totally erased"); + break; + } + strcat (tmpstr, "]"); + printf ("%s\n", tmpstr); + ladmin_log ("%s%s", tmpstr, "\n"); + } + bytes_to_read = 0; + RFIFOSKIP (fd, 34); + break; + + case 0x7939: // answer of the number of online players + if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) + return; + { + // Get length of the received packet + int i; + char name[20]; + if (defaultlanguage == 'F') + { + ladmin_log + (" Réception du nombre de joueurs en ligne.\n"); + } + else + { + ladmin_log + (" Receiving of the number of online players.\n"); + } + // Read information of the servers + if (RFIFOW (fd, 2) < 5) + { + if (defaultlanguage == 'F') + { + printf + (" Aucun serveur n'est connecté au login serveur.\n"); + } + else + { + printf + (" No server is connected to the login-server.\n"); + } + } + else + { + if (defaultlanguage == 'F') + { + printf + (" Nombre de joueurs en ligne (serveur: nb):\n"); + } + else + { + printf + (" Number of online players (server: number).\n"); + } + // Displaying of result + for (i = 4; i < RFIFOW (fd, 2); i += 32) + { + memcpy (name, RFIFOP (fd, i + 6), sizeof (name)); + name[sizeof (name) - 1] = '\0'; + printf (" %-20s : %5d\n", name, + RFIFOW (fd, i + 26)); + } + } + } + bytes_to_read = 0; + RFIFOSKIP (fd, RFIFOW (fd, 2)); + break; + + case 0x793b: // answer of the check of a password + if (RFIFOREST (fd) < 30) + return; + if (RFIFOL (fd, 2) == -1) + { + if (defaultlanguage == 'F') + { + printf + ("Le compte [%s] n'existe pas ou le mot de passe est incorrect.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Le compte [%s] n'existe pas ou le mot de passe est incorrect.\n", + RFIFOP (fd, 6)); + } + else + { + printf + ("The account [%s] doesn't exist or the password is incorrect.\n", + RFIFOP (fd, 6)); + ladmin_log + ("The account [%s] doesn't exist or the password is incorrect.\n", + RFIFOP (fd, 6)); + } + } + else + { + if (defaultlanguage == 'F') + { + printf + ("Le mot de passe donné correspond bien au compte [%s][id: %d].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Le mot de passe donné correspond bien au compte [%s][id: %d].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + else + { + printf + ("The proposed password is correct for the account [%s][id: %d].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("The proposed password is correct for the account [%s][id: %d].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + } + bytes_to_read = 0; + RFIFOSKIP (fd, 30); + break; + + case 0x793d: // answer of the change of an account sex + if (RFIFOREST (fd) < 30) + return; + if (RFIFOL (fd, 2) == -1) + { + if (defaultlanguage == 'F') + { + printf + ("Echec de la modification du sexe du compte [%s].\n", + RFIFOP (fd, 6)); + printf + ("Le compte [%s] n'existe pas ou le sexe est déjà celui demandé.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Echec de la modification du sexe du compte. Le compte [%s] n'existe pas ou le sexe est déjà celui demandé.\n", + RFIFOP (fd, 6)); + } + else + { + printf ("Account [%s] sex changing failed.\n", + RFIFOP (fd, 6)); + printf + ("Account [%s] doesn't exist or the sex is already the good sex.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Account sex changing failed. The compte [%s] doesn't exist or the sex is already the good sex.\n", + RFIFOP (fd, 6)); + } + } + else + { + if (defaultlanguage == 'F') + { + printf + ("Sexe du compte [%s][id: %d] changé avec succès.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Sexe du compte [%s][id: %d] changé avec succès.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + else + { + printf + ("Account [%s][id: %d] sex successfully changed.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Account [%s][id: %d] sex successfully changed.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + } + bytes_to_read = 0; + RFIFOSKIP (fd, 30); + break; + + case 0x793f: // answer of the change of an account GM level + if (RFIFOREST (fd) < 30) + return; + if (RFIFOL (fd, 2) == -1) + { + if (defaultlanguage == 'F') + { + printf + ("Echec de la modification du niveau de GM du compte [%s].\n", + RFIFOP (fd, 6)); + printf + ("Le compte [%s] n'existe pas, le niveau de GM est déjà celui demandé\n", + RFIFOP (fd, 6)); + printf + ("ou il est impossible de modifier le fichier des comptes GM.\n"); + ladmin_log + ("Echec de la modification du niveau de GM du compte. Le compte [%s] n'existe pas, le niveau de GM est déjà celui demandé ou il est impossible de modifier le fichier des comptes GM.\n", + RFIFOP (fd, 6)); + } + else + { + printf ("Account [%s] GM level changing failed.\n", + RFIFOP (fd, 6)); + printf + ("Account [%s] doesn't exist, the GM level is already the good GM level\n", + RFIFOP (fd, 6)); + printf + ("or it's impossible to modify the GM accounts file.\n"); + ladmin_log + ("Account GM level changing failed. The compte [%s] doesn't exist, the GM level is already the good sex or it's impossible to modify the GM accounts file.\n", + RFIFOP (fd, 6)); + } + } + else + { + if (defaultlanguage == 'F') + { + printf + ("Niveau de GM du compte [%s][id: %d] changé avec succès.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Niveau de GM du compte [%s][id: %d] changé avec succès.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + else + { + printf + ("Account [%s][id: %d] GM level successfully changed.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Account [%s][id: %d] GM level successfully changed.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + } + bytes_to_read = 0; + RFIFOSKIP (fd, 30); + break; + + case 0x7941: // answer of the change of an account email + if (RFIFOREST (fd) < 30) + return; + if (RFIFOL (fd, 2) == -1) + { + if (defaultlanguage == 'F') + { + printf + ("Echec de la modification de l'e-mail du compte [%s].\n", + RFIFOP (fd, 6)); + printf ("Le compte [%s] n'existe pas.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Echec de la modification de l'e-mail du compte. Le compte [%s] n'existe pas.\n", + RFIFOP (fd, 6)); + } + else + { + printf ("Account [%s] e-mail changing failed.\n", + RFIFOP (fd, 6)); + printf ("Account [%s] doesn't exist.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Account e-mail changing failed. The compte [%s] doesn't exist.\n", + RFIFOP (fd, 6)); + } + } + else + { + if (defaultlanguage == 'F') + { + printf + ("Modification de l'e-mail du compte [%s][id: %d] réussie.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Modification de l'e-mail du compte [%s][id: %d] réussie.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + else + { + printf + ("Account [%s][id: %d] e-mail successfully changed.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Account [%s][id: %d] e-mail successfully changed.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + } + bytes_to_read = 0; + RFIFOSKIP (fd, 30); + break; + + case 0x7943: // answer of the change of an account memo + if (RFIFOREST (fd) < 30) + return; + if (RFIFOL (fd, 2) == -1) + { + if (defaultlanguage == 'F') + { + printf + ("Echec du changement du mémo du compte [%s]. Le compte n'existe pas.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Echec du changement du mémo du compte [%s]. Le compte n'existe pas.\n", + RFIFOP (fd, 6)); + } + else + { + printf + ("Account [%s] memo changing failed. Account doesn't exist.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Account [%s] memo changing failed. Account doesn't exist.\n", + RFIFOP (fd, 6)); + } + } + else + { + if (defaultlanguage == 'F') + { + printf + ("Mémo du compte [%s][id: %d] changé avec succès.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Mémo du compte [%s][id: %d] changé avec succès.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + else + { + printf + ("Account [%s][id: %d] memo successfully changed.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Account [%s][id: %d] memo successfully changed.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + } + bytes_to_read = 0; + RFIFOSKIP (fd, 30); + break; + + case 0x7945: // answer of an account id search + if (RFIFOREST (fd) < 30) + return; + if (RFIFOL (fd, 2) == -1) + { + if (defaultlanguage == 'F') + { + printf + ("Impossible de trouver l'id du compte [%s]. Le compte n'existe pas.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Impossible de trouver l'id du compte [%s]. Le compte n'existe pas.\n", + RFIFOP (fd, 6)); + } + else + { + printf + ("Unable to find the account [%s] id. Account doesn't exist.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Unable to find the account [%s] id. Account doesn't exist.\n", + RFIFOP (fd, 6)); + } + } + else + { + if (defaultlanguage == 'F') + { + printf ("Le compte [%s] a pour id: %d.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log ("Le compte [%s] a pour id: %d.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + else + { + printf ("The account [%s] have the id: %d.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log ("The account [%s] have the id: %d.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + } + bytes_to_read = 0; + RFIFOSKIP (fd, 30); + break; + + case 0x7947: // answer of an account name search + if (RFIFOREST (fd) < 30) + return; + if (strcmp (RFIFOP (fd, 6), "") == 0) + { + if (defaultlanguage == 'F') + { + printf + ("Impossible de trouver le nom du compte [%d]. Le compte n'existe pas.\n", + RFIFOL (fd, 2)); + ladmin_log + ("Impossible de trouver le nom du compte [%d]. Le compte n'existe pas.\n", + RFIFOL (fd, 2)); + } + else + { + printf + ("Unable to find the account [%d] name. Account doesn't exist.\n", + RFIFOL (fd, 2)); + ladmin_log + ("Unable to find the account [%d] name. Account doesn't exist.\n", + RFIFOL (fd, 2)); + } + } + else + { + if (defaultlanguage == 'F') + { + printf ("Le compte [id: %d] a pour nom: %s.\n", + RFIFOL (fd, 2), RFIFOP (fd, 6)); + ladmin_log ("Le compte [id: %d] a pour nom: %s.\n", + RFIFOL (fd, 2), RFIFOP (fd, 6)); + } + else + { + printf ("The account [id: %d] have the name: %s.\n", + RFIFOL (fd, 2), RFIFOP (fd, 6)); + ladmin_log ("The account [id: %d] have the name: %s.\n", + RFIFOL (fd, 2), RFIFOP (fd, 6)); + } + } + bytes_to_read = 0; + RFIFOSKIP (fd, 30); + break; + + case 0x7949: // answer of an account validity limit set + if (RFIFOREST (fd) < 34) + return; + if (RFIFOL (fd, 2) == -1) + { + if (defaultlanguage == 'F') + { + printf + ("Echec du changement de la validité du compte [%s]. Le compte n'existe pas.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Echec du changement de la validité du compte [%s]. Le compte n'existe pas.\n", + RFIFOP (fd, 6)); + } + else + { + printf + ("Account [%s] validity limit changing failed. Account doesn't exist.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Account [%s] validity limit changing failed. Account doesn't exist.\n", + RFIFOP (fd, 6)); + } + } + else + { + time_t timestamp = RFIFOL (fd, 30); + if (timestamp == 0) + { + if (defaultlanguage == 'F') + { + printf + ("Limite de validité du compte [%s][id: %d] changée avec succès en [illimité].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Limite de validité du compte [%s][id: %d] changée avec succès en [illimité].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + else + { + printf + ("Validity Limit of the account [%s][id: %d] successfully changed to [unlimited].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Validity Limit of the account [%s][id: %d] successfully changed to [unlimited].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + } + else + { + char tmpstr[128]; + strftime (tmpstr, 24, date_format, + localtime (×tamp)); + if (defaultlanguage == 'F') + { + printf + ("Limite de validité du compte [%s][id: %d] changée avec succès pour être jusqu'au %s.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2), tmpstr); + ladmin_log + ("Limite de validité du compte [%s][id: %d] changée avec succès pour être jusqu'au %s.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2), + tmpstr); + } + else + { + printf + ("Validity Limit of the account [%s][id: %d] successfully changed to be until %s.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2), tmpstr); + ladmin_log + ("Validity Limit of the account [%s][id: %d] successfully changed to be until %s.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2), + tmpstr); + } + } + } + bytes_to_read = 0; + RFIFOSKIP (fd, 34); + break; + + case 0x794b: // answer of an account ban set + if (RFIFOREST (fd) < 34) + return; + if (RFIFOL (fd, 2) == -1) + { + if (defaultlanguage == 'F') + { + printf + ("Echec du changement de la date finale de banissement du compte [%s]. Le compte n'existe pas.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Echec du changement de la date finale de banissement du compte [%s]. Le compte n'existe pas.\n", + RFIFOP (fd, 6)); + } + else + { + printf + ("Account [%s] final date of banishment changing failed. Account doesn't exist.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Account [%s] final date of banishment changing failed. Account doesn't exist.\n", + RFIFOP (fd, 6)); + } + } + else + { + time_t timestamp = RFIFOL (fd, 30); + if (timestamp == 0) + { + if (defaultlanguage == 'F') + { + printf + ("Date finale de banissement du compte [%s][id: %d] changée avec succès en [dé-bannie].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Date finale de banissement du compte [%s][id: %d] changée avec succès en [dé-bannie].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + else + { + printf + ("Final date of banishment of the account [%s][id: %d] successfully changed to [unbanished].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Final date of banishment of the account [%s][id: %d] successfully changed to [unbanished].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + } + else + { + char tmpstr[128]; + strftime (tmpstr, 24, date_format, + localtime (×tamp)); + if (defaultlanguage == 'F') + { + printf + ("Date finale de banissement du compte [%s][id: %d] changée avec succès pour être jusqu'au %s.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2), tmpstr); + ladmin_log + ("Date finale de banissement du compte [%s][id: %d] changée avec succès pour être jusqu'au %s.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2), + tmpstr); + } + else + { + printf + ("Final date of banishment of the account [%s][id: %d] successfully changed to be until %s.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2), tmpstr); + ladmin_log + ("Final date of banishment of the account [%s][id: %d] successfully changed to be until %s.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2), + tmpstr); + } + } + } + bytes_to_read = 0; + RFIFOSKIP (fd, 34); + break; + + case 0x794d: // answer of an account ban date/time changing + if (RFIFOREST (fd) < 34) + return; + if (RFIFOL (fd, 2) == -1) + { + if (defaultlanguage == 'F') + { + printf + ("Echec du changement de la date finale de banissement du compte [%s]. Le compte n'existe pas.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Echec du changement de la date finale de banissement du compte [%s]. Le compte n'existe pas.\n", + RFIFOP (fd, 6)); + } + else + { + printf + ("Account [%s] final date of banishment changing failed. Account doesn't exist.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Account [%s] final date of banishment changing failed. Account doesn't exist.\n", + RFIFOP (fd, 6)); + } + } + else + { + time_t timestamp = RFIFOL (fd, 30); + if (timestamp == 0) + { + if (defaultlanguage == 'F') + { + printf + ("Date finale de banissement du compte [%s][id: %d] changée avec succès en [dé-bannie].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Date finale de banissement du compte [%s][id: %d] changée avec succès en [dé-bannie].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + else + { + printf + ("Final date of banishment of the account [%s][id: %d] successfully changed to [unbanished].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + ladmin_log + ("Final date of banishment of the account [%s][id: %d] successfully changed to [unbanished].\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + } + else + { + char tmpstr[128]; + strftime (tmpstr, 24, date_format, + localtime (×tamp)); + if (defaultlanguage == 'F') + { + printf + ("Date finale de banissement du compte [%s][id: %d] changée avec succès pour être jusqu'au %s.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2), tmpstr); + ladmin_log + ("Date finale de banissement du compte [%s][id: %d] changée avec succès pour être jusqu'au %s.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2), + tmpstr); + } + else + { + printf + ("Final date of banishment of the account [%s][id: %d] successfully changed to be until %s.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2), tmpstr); + ladmin_log + ("Final date of banishment of the account [%s][id: %d] successfully changed to be until %s.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2), + tmpstr); + } + } + } + bytes_to_read = 0; + RFIFOSKIP (fd, 34); + break; + + case 0x794f: // answer of a broadcast + if (RFIFOREST (fd) < 4) + return; + if (RFIFOW (fd, 2) == (unsigned short) -1) + { + if (defaultlanguage == 'F') + { + printf + ("Echec de l'envoi du message. Aucun server de char en ligne.\n"); + ladmin_log + ("Echec de l'envoi du message. Aucun server de char en ligne.\n"); + } + else + { + printf + ("Message sending failed. No online char-server.\n"); + ladmin_log + ("Message sending failed. No online char-server.\n"); + } + } + else + { + if (defaultlanguage == 'F') + { + printf + ("Message transmis au server de logins avec succès.\n"); + ladmin_log + ("Message transmis au server de logins avec succès.\n"); + } + else + { + printf + ("Message successfully sended to login-server.\n"); + ladmin_log + ("Message successfully sended to login-server.\n"); + } + } + bytes_to_read = 0; + RFIFOSKIP (fd, 4); + break; + + case 0x7951: // answer of an account validity limit changing + if (RFIFOREST (fd) < 34) + return; + if (RFIFOL (fd, 2) == -1) + { + if (defaultlanguage == 'F') + { + printf + ("Echec du changement de la validité du compte [%s]. Le compte n'existe pas.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Echec du changement de la validité du compte [%s]. Le compte n'existe pas.\n", + RFIFOP (fd, 6)); + } + else + { + printf + ("Account [%s] validity limit changing failed. Account doesn't exist.\n", + RFIFOP (fd, 6)); + ladmin_log + ("Account [%s] validity limit changing failed. Account doesn't exist.\n", + RFIFOP (fd, 6)); + } + } + else + { + time_t timestamp = RFIFOL (fd, 30); + if (timestamp == 0) + { + if (defaultlanguage == 'F') + { + printf + ("Limite de validité du compte [%s][id: %d] inchangée.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + printf + ("Le compte a une validité illimitée ou\n"); + printf + ("la modification est impossible avec les ajustements demandés.\n"); + ladmin_log + ("Limite de validité du compte [%s][id: %d] inchangée. Le compte a une validité illimitée ou la modification est impossible avec les ajustements demandés.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + else + { + printf + ("Validity limit of the account [%s][id: %d] unchanged.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + printf + ("The account have an unlimited validity limit or\n"); + printf + ("the changing is impossible with the proposed adjustments.\n"); + ladmin_log + ("Validity limit of the account [%s][id: %d] unchanged. The account have an unlimited validity limit or the changing is impossible with the proposed adjustments.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2)); + } + } + else + { + char tmpstr[128]; + strftime (tmpstr, 24, date_format, + localtime (×tamp)); + if (defaultlanguage == 'F') + { + printf + ("Limite de validité du compte [%s][id: %d] changée avec succès pour être jusqu'au %s.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2), tmpstr); + ladmin_log + ("Limite de validité du compte [%s][id: %d] changée avec succès pour être jusqu'au %s.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2), + tmpstr); + } + else + { + printf + ("Validity limit of the account [%s][id: %d] successfully changed to be until %s.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2), tmpstr); + ladmin_log + ("Validity limit of the account [%s][id: %d] successfully changed to be until %s.\n", + RFIFOP (fd, 6), RFIFOL (fd, 2), + tmpstr); + } + } + } + bytes_to_read = 0; + RFIFOSKIP (fd, 34); + break; + + case 0x7953: // answer of a request about informations of an account (by account name/id) + if (RFIFOREST (fd) < 150 + || RFIFOREST (fd) < (150 + RFIFOW (fd, 148))) + return; + { + char userid[24], error_message[20], lastlogin[24], + last_ip[16], email[40], memo[255]; + time_t ban_until_time; // # of seconds 1/1/1970 (timestamp): ban time limit of the account (0 = no ban) + time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) + memcpy (userid, RFIFOP (fd, 7), sizeof (userid)); + userid[sizeof (userid) - 1] = '\0'; + memcpy (error_message, RFIFOP (fd, 40), + sizeof (error_message)); + error_message[sizeof (error_message) - 1] = '\0'; + memcpy (lastlogin, RFIFOP (fd, 60), sizeof (lastlogin)); + lastlogin[sizeof (lastlogin) - 1] = '\0'; + memcpy (last_ip, RFIFOP (fd, 84), sizeof (last_ip)); + last_ip[sizeof (last_ip) - 1] = '\0'; + memcpy (email, RFIFOP (fd, 100), sizeof (email)); + email[sizeof (email) - 1] = '\0'; + connect_until_time = (time_t) RFIFOL (fd, 140); + ban_until_time = (time_t) RFIFOL (fd, 144); + memset (memo, '\0', sizeof (memo)); + strncpy (memo, RFIFOP (fd, 150), RFIFOW (fd, 148)); + if (RFIFOL (fd, 2) == -1) + { + if (defaultlanguage == 'F') + { + printf + ("Impossible de trouver le compte [%s]. Le compte n'existe pas.\n", + parameters); + ladmin_log + ("Impossible de trouver le compte [%s]. Le compte n'existe pas.\n", + parameters); + } + else + { + printf + ("Unabled to find the account [%s]. Account doesn't exist.\n", + parameters); + ladmin_log + ("Unabled to find the account [%s]. Account doesn't exist.\n", + parameters); + } + } + else if (strlen (userid) == 0) + { + if (defaultlanguage == 'F') + { + printf + ("Impossible de trouver le compte [id: %s]. Le compte n'existe pas.\n", + parameters); + ladmin_log + ("Impossible de trouver le compte [id: %s]. Le compte n'existe pas.\n", + parameters); + } + else + { + printf + ("Unabled to find the account [id: %s]. Account doesn't exist.\n", + parameters); + ladmin_log + ("Unabled to find the account [id: %s]. Account doesn't exist.\n", + parameters); + } + } + else + { + if (defaultlanguage == 'F') + { + ladmin_log + ("Réception d'information concernant un compte.\n"); + printf + ("Le compte a les caractéristiques suivantes:\n"); + } + else + { + ladmin_log + ("Receiving information about an account.\n"); + printf ("The account is set with:\n"); + } + if (RFIFOB (fd, 6) == 0) + { + printf (" Id: %d (non-GM)\n", RFIFOL (fd, 2)); + } + else + { + if (defaultlanguage == 'F') + { + printf (" Id: %d (GM niveau %d)\n", + RFIFOL (fd, 2), (int) RFIFOB (fd, 6)); + } + else + { + printf (" Id: %d (GM level %d)\n", + RFIFOL (fd, 2), (int) RFIFOB (fd, 6)); + } + } + if (defaultlanguage == 'F') + { + printf (" Nom: '%s'\n", userid); + if (RFIFOB (fd, 31) == 0) + printf (" Sexe: Femme\n"); + else if (RFIFOB (fd, 31) == 1) + printf (" Sexe: Male\n"); + else + printf (" Sexe: Serveur\n"); + } + else + { + printf (" Name: '%s'\n", userid); + if (RFIFOB (fd, 31) == 0) + printf (" Sex: Female\n"); + else if (RFIFOB (fd, 31) == 1) + printf (" Sex: Male\n"); + else + printf (" Sex: Server\n"); + } + printf (" E-mail: %s\n", email); + switch (RFIFOL (fd, 36)) + { + case 0: + if (defaultlanguage == 'F') + printf (" Statut: 0 [Compte Ok]\n"); + else + printf (" Statut: 0 [Account OK]\n"); + break; + case 1: + printf (" Statut: 1 [Unregistered ID]\n"); + break; + case 2: + printf (" Statut: 2 [Incorrect Password]\n"); + break; + case 3: + printf (" Statut: 3 [This ID is expired]\n"); + break; + case 4: + printf + (" Statut: 4 [Rejected from Server]\n"); + break; + case 5: + printf + (" Statut: 5 [You have been blocked by the GM Team]\n"); + break; + case 6: + printf + (" Statut: 6 [Your Game's EXE file is not the latest version]\n"); + break; + case 7: + printf + (" Statut: 7 [You are Prohibited to log in until %s]\n", + error_message); + break; + case 8: + printf + (" Statut: 8 [Server is jammed due to over populated]\n"); + break; + case 9: + printf (" Statut: 9 [No MSG]\n"); + break; + default: // 100 + printf + (" Statut: %d [This ID is totally erased]\n", + RFIFOL (fd, 36)); + break; + } + if (defaultlanguage == 'F') + { + if (ban_until_time == 0) + { + printf (" Banissement: non banni.\n"); + } + else + { + char tmpstr[128]; + strftime (tmpstr, 24, date_format, + localtime (&ban_until_time)); + printf (" Banissement: jusqu'au %s.\n", + tmpstr); + } + if (RFIFOL (fd, 32) > 1) + printf (" Compteur: %d connexions.\n", + RFIFOL (fd, 32)); + else + printf (" Compteur: %d connexion.\n", + RFIFOL (fd, 32)); + printf (" Dernière connexion le: %s (ip: %s)\n", + lastlogin, last_ip); + if (connect_until_time == 0) + { + printf (" Limite de validité: illimité.\n"); + } + else + { + char tmpstr[128]; + strftime (tmpstr, 24, date_format, + localtime (&connect_until_time)); + printf (" Limite de validité: jusqu'au %s.\n", + tmpstr); + } + } + else + { + if (ban_until_time == 0) + { + printf (" Banishment: not banished.\n"); + } + else + { + char tmpstr[128]; + strftime (tmpstr, 24, date_format, + localtime (&ban_until_time)); + printf (" Banishment: until %s.\n", tmpstr); + } + if (RFIFOL (fd, 32) > 1) + printf (" Count: %d connections.\n", + RFIFOL (fd, 32)); + else + printf (" Count: %d connection.\n", + RFIFOL (fd, 32)); + printf (" Last connection at: %s (ip: %s)\n", + lastlogin, last_ip); + if (connect_until_time == 0) + { + printf (" Validity limit: unlimited.\n"); + } + else + { + char tmpstr[128]; + strftime (tmpstr, 24, date_format, + localtime (&connect_until_time)); + printf (" Validity limit: until %s.\n", + tmpstr); + } + } + printf (" Memo: '%s'\n", memo); + } + } + bytes_to_read = 0; + RFIFOSKIP (fd, 150 + RFIFOW (fd, 148)); + break; + + default: + printf + ("Remote administration has been disconnected (unknown packet).\n"); + ladmin_log ("'End of connection, unknown packet.\n"); + session[fd]->eof = 1; + return; + } + } + + // if we don't wait new packets, do the prompt + prompt (); +} + +//------------------------------------ +// Function to connect to login-server +//------------------------------------ +int Connect_login_server (void) +{ + if (defaultlanguage == 'F') + { + Iprintf ("Essai de connection au server de logins...\n"); + ladmin_log ("Essai de connection au server de logins...\n"); + } + else + { + Iprintf ("Attempt to connect to login-server...\n"); + ladmin_log ("Attempt to connect to login-server...\n"); + } + + if ((login_fd = make_connection (login_ip, loginserverport)) < 0) + return 0; + +#ifdef PASSWORDENC + if (passenc == 0) + { +#endif + WFIFOW (login_fd, 0) = 0x7918; // Request for administation login + WFIFOW (login_fd, 2) = 0; // no encrypted + memcpy (WFIFOP (login_fd, 4), loginserveradminpassword, 24); + WFIFOSET (login_fd, 28); + bytes_to_read = 1; + + if (defaultlanguage == 'F') + { + Iprintf ("Envoi du mot de passe...\n"); + ladmin_log ("Envoi du mot de passe...\n"); + } + else + { + Iprintf ("Sending of the password...\n"); + ladmin_log ("Sending of the password...\n"); + } +#ifdef PASSWORDENC + } + else + { + WFIFOW (login_fd, 0) = 0x791a; // Sending request about the coding key + WFIFOSET (login_fd, 2); + bytes_to_read = 1; + if (defaultlanguage == 'F') + { + Iprintf ("Demande de la clef MD5...\n"); + ladmin_log ("Demande de la clef MD5...\n"); + } + else + { + Iprintf ("Request about the MD5 key...\n"); + ladmin_log ("Request about the MD5 key...\n"); + } + } +#endif + + return 0; +} + +//------------------------------------------------- +// Return numerical value of a switch configuration +// on/off, english, français, deutsch, español +//------------------------------------------------- +int config_switch (const char *str) +{ + if (strcasecmp (str, "on") == 0 || strcasecmp (str, "yes") == 0 + || strcasecmp (str, "oui") == 0 || strcasecmp (str, "ja") == 0 + || strcasecmp (str, "si") == 0) + return 1; + if (strcasecmp (str, "off") == 0 || strcasecmp (str, "no") == 0 + || strcasecmp (str, "non") == 0 || strcasecmp (str, "nein") == 0) + return 0; + + return atoi (str); +} + +//----------------------------------- +// Reading general configuration file +//----------------------------------- +int ladmin_config_read (const char *cfgName) +{ + char line[1024], w1[1024], w2[1024]; + FILE *fp; + + fp = fopen_ (cfgName, "r"); + if (fp == NULL) + { + if (defaultlanguage == 'F') + { + printf ("\033[0mFichier de configuration (%s) non trouvé.\n", + cfgName); + } + else + { + printf ("\033[0mConfiguration file (%s) not found.\n", cfgName); + } + return 1; + } + + if (defaultlanguage == 'F') + { + Iprintf + ("\033[0m---Début de lecture du fichier de configuration Ladmin (%s)\n", + cfgName); + } + else + { + Iprintf + ("\033[0m---Start reading of Ladmin configuration file (%s)\n", + cfgName); + } + while (fgets (line, sizeof (line) - 1, fp)) + { + if (line[0] == '/' && line[1] == '/') + continue; + + line[sizeof (line) - 1] = '\0'; + if (sscanf (line, "%[^:]: %[^\r\n]", w1, w2) == 2) + { + remove_control_chars (w1); + remove_control_chars (w2); + + if (strcasecmp (w1, "login_ip") == 0) + { + struct hostent *h = gethostbyname (w2); + if (h != NULL) + { + if (defaultlanguage == 'F') + { + Iprintf + ("Adresse du serveur de logins: %s -> %d.%d.%d.%d\n", + w2, (unsigned char) h->h_addr[0], + (unsigned char) h->h_addr[1], + (unsigned char) h->h_addr[2], + (unsigned char) h->h_addr[3]); + } + else + { + Iprintf + ("Login server IP address: %s -> %d.%d.%d.%d\n", + w2, (unsigned char) h->h_addr[0], + (unsigned char) h->h_addr[1], + (unsigned char) h->h_addr[2], + (unsigned char) h->h_addr[3]); + } + sprintf (loginserverip, "%d.%d.%d.%d", + (unsigned char) h->h_addr[0], + (unsigned char) h->h_addr[1], + (unsigned char) h->h_addr[2], + (unsigned char) h->h_addr[3]); + } + else + memcpy (loginserverip, w2, 16); + } + else if (strcasecmp (w1, "login_port") == 0) + { + loginserverport = atoi (w2); + } + else if (strcasecmp (w1, "admin_pass") == 0) + { + strncpy (loginserveradminpassword, w2, + sizeof (loginserveradminpassword)); + loginserveradminpassword[sizeof (loginserveradminpassword) - + 1] = '\0'; +#ifdef PASSWORDENC + } + else if (strcasecmp (w1, "passenc") == 0) + { + passenc = atoi (w2); + if (passenc < 0 || passenc > 2) + passenc = 0; +#endif + } + else if (strcasecmp (w1, "defaultlanguage") == 0) + { + if (w2[0] == 'F' || w2[0] == 'E') + defaultlanguage = w2[0]; + } + else if (strcasecmp (w1, "ladmin_log_filename") == 0) + { + strncpy (ladmin_log_filename, w2, + sizeof (ladmin_log_filename)); + ladmin_log_filename[sizeof (ladmin_log_filename) - 1] = '\0'; + } + else if (strcasecmp (w1, "date_format") == 0) + { // note: never have more than 19 char for the date! + switch (atoi (w2)) + { + case 0: + strcpy (date_format, "%d-%m-%Y %H:%M:%S"); // 31-12-2004 23:59:59 + break; + case 1: + strcpy (date_format, "%m-%d-%Y %H:%M:%S"); // 12-31-2004 23:59:59 + break; + case 2: + strcpy (date_format, "%Y-%d-%m %H:%M:%S"); // 2004-31-12 23:59:59 + break; + case 3: + strcpy (date_format, "%Y-%m-%d %H:%M:%S"); // 2004-12-31 23:59:59 + break; + } + } + else if (strcasecmp (w1, "import") == 0) + { + ladmin_config_read (w2); + } + } + } + fclose_ (fp); + + login_ip = inet_addr (loginserverip); + + if (defaultlanguage == 'F') + { + Iprintf ("---Lecture du fichier de configuration Ladmin terminée.\n"); + } + else + { + Iprintf ("---End reading of Ladmin configuration file.\n"); + } + + return 0; +} + +//-------------------------------------- +// Function called at exit of the server +//-------------------------------------- +void term_func (void) +{ + + if (already_exit_function == 0) + { + delete_session (login_fd); + + if (defaultlanguage == 'F') + { + Iprintf + ("\033[0m----Fin de Ladmin (fin normale avec fermeture de tous les fichiers).\n"); + ladmin_log + ("----Fin de Ladmin (fin normale avec fermeture de tous les fichiers).\n"); + } + else + { + Iprintf + ("\033[0m----End of Ladmin (normal end with closing of all files).\n"); + ladmin_log + ("----End of Ladmin (normal end with closing of all files).\n"); + } + + already_exit_function = 1; + } +} + +//------------------------ +// Main function of ladmin +//------------------------ +int do_init (int argc, char **argv) +{ + eathena_interactive_session = isatty (0); + // read ladmin configuration + ladmin_config_read ((argc > 1) ? argv[1] : LADMIN_CONF_NAME); + + ladmin_log (""); + if (defaultlanguage == 'F') + { + ladmin_log ("Fichier de configuration lu.\n"); + } + else + { + ladmin_log ("Configuration file readed.\n"); + } + + srand (time (NULL)); + + set_defaultparse (parse_fromlogin); + + if (defaultlanguage == 'F') + { + Iprintf ("Outil d'administration à distance de eAthena.\n"); + Iprintf ("(pour eAthena version %d.%d.%d.)\n", ATHENA_MAJOR_VERSION, + ATHENA_MINOR_VERSION, ATHENA_REVISION); + } + else + { + Iprintf ("EAthena login-server administration tool.\n"); + Iprintf ("(for eAthena version %d.%d.%d.)\n", ATHENA_MAJOR_VERSION, + ATHENA_MINOR_VERSION, ATHENA_REVISION); + } + + if (defaultlanguage == 'F') + { + ladmin_log ("Ladmin est prêt.\n"); + Iprintf ("Ladmin est \033[1;32mprêt\033[0m.\n\n"); + } + else + { + ladmin_log ("Ladmin is ready.\n"); + Iprintf ("Ladmin is \033[1;32mready\033[0m.\n\n"); + } + + Connect_login_server (); + + return 0; +} diff --git a/src/ladmin/ladmin.h b/src/ladmin/ladmin.h deleted file mode 100644 index dc1efe6..0000000 --- a/src/ladmin/ladmin.h +++ /dev/null @@ -1,11 +0,0 @@ -// $Id: ladmin.h,v 1.1.1.1 2004/09/10 17:26:52 MagicalTux Exp $ -#ifndef _LADMIN_H_ -#define _LADMIN_H_ - -#define LADMIN_CONF_NAME "conf/ladmin_athena.conf" -#define PASSWORDENC 3 // A definition is given when making an encryption password correspond. - // It is 1 at the time of passwordencrypt. - // It is made into 2 at the time of passwordencrypt2. - // When it is made 3, it corresponds to both. - -#endif diff --git a/src/ladmin/ladmin.hpp b/src/ladmin/ladmin.hpp new file mode 100644 index 0000000..77d7fe4 --- /dev/null +++ b/src/ladmin/ladmin.hpp @@ -0,0 +1,11 @@ +// $Id: ladmin.h,v 1.1.1.1 2004/09/10 17:26:52 MagicalTux Exp $ +#ifndef LADMIN_HPP +#define LADMIN_HPP + +#define LADMIN_CONF_NAME "conf/ladmin_athena.conf" +#define PASSWORDENC 3 // A definition is given when making an encryption password correspond. + // It is 1 at the time of passwordencrypt. + // It is made into 2 at the time of passwordencrypt2. + // When it is made 3, it corresponds to both. + +#endif diff --git a/src/login/login.c b/src/login/login.c deleted file mode 100644 index cd46049..0000000 --- a/src/login/login.c +++ /dev/null @@ -1,5038 +0,0 @@ -// $Id: login.c,v 1.1.1.1 2004/09/10 17:26:53 MagicalTux Exp $ -// new version of the login-server by [Yor] - -#include -#include -#include -#include -#include -#include -#include -#include -#include // for stat/lstat/fstat -#include -#include -#include -#include -#include -#include -#include - -#include "../common/core.h" -#include "../common/socket.h" -#include "../common/timer.h" -#include "login.h" -#include "../common/mmo.h" -#include "../common/version.h" -#include "../common/db.h" -#include "../common/lock.h" -#include "../common/mt_rand.h" - -#include "../common/md5calc.h" - -#ifdef MEMWATCH -#include "memwatch.h" -#endif - -int account_id_count = START_ACCOUNT_NUM; -int server_num; -int new_account_flag = 0; -int login_port = 6900; -char lan_char_ip[16]; -int subneti[4]; -int subnetmaski[4]; -char update_host[128] = ""; -char main_server[20] = ""; - -char account_filename[1024] = "save/account.txt"; -char GM_account_filename[1024] = "conf/GM_account.txt"; -char login_log_filename[1024] = "log/login.log"; -char login_log_unknown_packets_filename[1024] = - "log/login_unknown_packets.log"; -char date_format[32] = "%Y-%m-%d %H:%M:%S"; -int save_unknown_packets = 0; -long creation_time_GM_account_file; -int gm_account_filename_check_timer = 15; // Timer to check if GM_account file has been changed and reload GM account automaticaly (in seconds; default: 15) - -int display_parse_login = 0; // 0: no, 1: yes -int display_parse_admin = 0; // 0: no, 1: yes -int display_parse_fromchar = 0; // 0: no, 1: yes (without packet 0x2714), 2: all packets - -struct mmo_char_server server[MAX_SERVERS]; -int server_fd[MAX_SERVERS]; -int server_freezeflag[MAX_SERVERS]; // Char-server anti-freeze system. Counter. 5 ok, 4...0 freezed -int anti_freeze_enable = 0; -int ANTI_FREEZE_INTERVAL = 15; - -int login_fd; - -enum -{ - ACO_DENY_ALLOW = 0, - ACO_ALLOW_DENY, - ACO_MUTUAL_FAILTURE, - ACO_STRSIZE = 128, -}; - -int access_order = ACO_DENY_ALLOW; -int access_allownum = 0; -int access_denynum = 0; -char *access_allow = NULL; -char *access_deny = NULL; - -int access_ladmin_allownum = 0; -char *access_ladmin_allow = NULL; - -int min_level_to_connect = 0; // minimum level of player/GM (0: player, 1-99: gm) to connect on the server -int add_to_unlimited_account = 0; // Give possibility or not to adjust (ladmin command: timeadd) the time of an unlimited account. -int start_limited_time = -1; // Starting additional sec from now for the limited time at creation of accounts (-1: unlimited time, 0 or more: additional sec from now) -int check_ip_flag = 1; // It's to check IP of a player between login-server and char-server (part of anti-hacking system) - -struct login_session_data -{ - int md5keylen; - char md5key[20]; -}; - -#define AUTH_FIFO_SIZE 256 -struct -{ - int account_id, login_id1, login_id2; - int ip, sex, delflag; -} auth_fifo[AUTH_FIFO_SIZE]; -int auth_fifo_pos = 0; - -struct auth_dat -{ - int account_id, sex; - char userid[24], pass[40], lastlogin[24]; - int logincount; - int state; // packet 0x006a value + 1 (0: compte OK) - char email[40]; // e-mail (by default: a@a.com) - char error_message[20]; // Message of error code #6 = Your are Prohibited to log in until %s (packet 0x006a) - time_t ban_until_time; // # of seconds 1/1/1970 (timestamp): ban time limit of the account (0 = no ban) - time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) - char last_ip[16]; // save of last IP of connection - char memo[255]; // a memo field - int account_reg2_num; - struct global_reg account_reg2[ACCOUNT_REG2_NUM]; -} *auth_dat; - -int auth_num = 0, auth_max = 0; - -int admin_state = 0; -char admin_pass[24] = ""; -char gm_pass[64] = ""; -int level_new_gm = 60; - -static struct dbt *gm_account_db; - -pid_t pid = 0; // For forked DB writes - - -#define VERSION_2_UPDATEHOST 0x01 // client supports updatehost -#define VERSION_2_SERVERORDER 0x02 // send servers in forward order -//------------------------------ -// Writing function of logs file -//------------------------------ -int login_log (char *fmt, ...) -{ - FILE *logfp; - va_list ap; - struct timeval tv; - char tmpstr[2048]; - - va_start (ap, fmt); - - logfp = fopen_ (login_log_filename, "a"); - if (logfp) - { - if (fmt[0] == '\0') // jump a line if no message - fprintf (logfp, "\n"); - else - { - gettimeofday (&tv, NULL); - strftime (tmpstr, 24, date_format, gmtime (&(tv.tv_sec))); - sprintf (tmpstr + strlen (tmpstr), ".%03d: %s", - (int) tv.tv_usec / 1000, fmt); - vfprintf (logfp, tmpstr, ap); - } - fclose_ (logfp); - } - - va_end (ap); - return 0; -} - -//---------------------------------------------------------------------- -// Determine if an account (id) is a GM account -// and returns its level (or 0 if it isn't a GM account or if not found) -//---------------------------------------------------------------------- -int isGM (int account_id) -{ - struct gm_account *p = (struct gm_account*) numdb_search (gm_account_db, account_id); - if (p == NULL) - return 0; - return p->level; -} - -//------------------------------------------------------- -// Reading function of GM accounts file (and their level) -//------------------------------------------------------- -int read_gm_account (void) -{ - char line[512]; - struct gm_account *p; - FILE *fp; - int c = 0; - int GM_level; - struct stat file_stat; - - free (gm_account_db); - gm_account_db = numdb_init (); - - // get last modify time/date - if (stat (GM_account_filename, &file_stat)) - creation_time_GM_account_file = 0; // error - else - creation_time_GM_account_file = file_stat.st_mtime; - - if ((fp = fopen_ (GM_account_filename, "r")) == NULL) - { - printf ("read_gm_account: GM accounts file [%s] not found.\n", - GM_account_filename); - printf - (" Actually, there is no GM accounts on the server.\n"); - login_log ("read_gm_account: GM accounts file [%s] not found.\n", - GM_account_filename); - login_log - (" Actually, there is no GM accounts on the server.\n"); - return 1; - } - // limited to 4000, because we send information to char-servers (more than 4000 GM accounts???) - // int (id) + int (level) = 8 bytes * 4000 = 32k (limit of packets in windows) - while (fgets (line, sizeof (line) - 1, fp) && c < 4000) - { - if ((line[0] == '/' && line[1] == '/') || line[0] == '\0' - || line[0] == '\n' || line[0] == '\r') - continue; - CREATE (p, struct gm_account, 1); - if (sscanf (line, "%d %d", &p->account_id, &p->level) != 2 - && sscanf (line, "%d: %d", &p->account_id, &p->level) != 2) - printf - ("read_gm_account: file [%s], invalid 'id_acount level' format.\n", - GM_account_filename); - else if (p->level <= 0) - printf - ("read_gm_account: file [%s] %dth account (invalid level [0 or negative]: %d).\n", - GM_account_filename, c + 1, p->level); - else - { - if (p->level > 99) - { - printf - ("read_gm_account: file [%s] %dth account (invalid level, but corrected: %d->99).\n", - GM_account_filename, c + 1, p->level); - p->level = 99; - } - if ((GM_level = isGM (p->account_id)) > 0) - { // if it's not a new account - if (GM_level == p->level) - printf - ("read_gm_account: GM account %d defined twice (same level: %d).\n", - p->account_id, p->level); - else - printf - ("read_gm_account: GM account %d defined twice (levels: %d and %d).\n", - p->account_id, GM_level, p->level); - } - if (GM_level != p->level) - { // if new account or new level - numdb_insert (gm_account_db, p->account_id, p); - //printf("GM account:%d, level: %d->%d\n", p->account_id, GM_level, p->level); - if (GM_level == 0) - { // if new account - c++; - if (c >= 4000) - { - printf - ("***WARNING: 4000 GM accounts found. Next GM accounts are not readed.\n"); - login_log - ("***WARNING: 4000 GM accounts found. Next GM accounts are not readed.\n"); - } - } - } - } - } - fclose_ (fp); - - printf ("read_gm_account: file '%s' readed (%d GM accounts found).\n", - GM_account_filename, c); - login_log ("read_gm_account: file '%s' readed (%d GM accounts found).\n", - GM_account_filename, c); - - return 0; -} - -//-------------------------------------------------------------- -// Test of the IP mask -// (ip: IP to be tested, str: mask x.x.x.x/# or x.x.x.x/y.y.y.y) -//-------------------------------------------------------------- -int check_ipmask (unsigned int ip, const unsigned char *str) -{ - unsigned int mask = 0, i = 0, m, ip2, a0, a1, a2, a3; - unsigned char *p = (unsigned char *) &ip2, *p2 = (unsigned char *) &mask; - - if (sscanf (str, "%d.%d.%d.%d/%n", &a0, &a1, &a2, &a3, &i) != 4 || i == 0) - return 0; - p[0] = a0; - p[1] = a1; - p[2] = a2; - p[3] = a3; - - if (sscanf (str + i, "%d.%d.%d.%d", &a0, &a1, &a2, &a3) == 4) - { - p2[0] = a0; - p2[1] = a1; - p2[2] = a2; - p2[3] = a3; - mask = ntohl (mask); - } - else if (sscanf (str + i, "%d", &m) == 1 && m >= 0 && m <= 32) - { - for (i = 0; i < m && i < 32; i++) - mask = (mask >> 1) | 0x80000000; - } - else - { - printf ("check_ipmask: invalid mask [%s].\n", str); - return 0; - } - -// printf("Tested IP: %08x, network: %08x, network mask: %08x\n", -// (unsigned int)ntohl(ip), (unsigned int)ntohl(ip2), (unsigned int)mask); - return ((ntohl (ip) & mask) == (ntohl (ip2) & mask)); -} - -//--------------------- -// Access control by IP -//--------------------- -int check_ip (unsigned int ip) -{ - int i; - unsigned char *p = (unsigned char *) &ip; - char buf[32]; - enum - { ACF_DEF, ACF_ALLOW, ACF_DENY } flag = ACF_DEF; - - if (access_allownum == 0 && access_denynum == 0) - return 1; // When there is no restriction, all IP are authorised. - -// + 012.345.: front match form, or -// all: all IP are matched, or -// 012.345.678.901/24: network form (mask with # of bits), or -// 012.345.678.901/255.255.255.0: network form (mask with ip mask) -// + Note about the DNS resolution (like www.ne.jp, etc.): -// There is no guarantee to have an answer. -// If we have an answer, there is no guarantee to have a 100% correct value. -// And, the waiting time (to check) can be long (over 1 minute to a timeout). That can block the software. -// So, DNS notation isn't authorised for ip checking. - sprintf (buf, "%d.%d.%d.%d.", p[0], p[1], p[2], p[3]); - - for (i = 0; i < access_allownum; i++) - { - const char *p = access_allow + i * ACO_STRSIZE; - if (memcmp (p, buf, strlen (p)) == 0 || check_ipmask (ip, p)) - { - flag = ACF_ALLOW; - if (access_order == ACO_ALLOW_DENY) - return 1; // With 'allow, deny' (deny if not allow), allow has priority - break; - } - } - - for (i = 0; i < access_denynum; i++) - { - const char *p = access_deny + i * ACO_STRSIZE; - if (memcmp (p, buf, strlen (p)) == 0 || check_ipmask (ip, p)) - { - flag = ACF_DENY; - return 0; // At this point, if it's 'deny', we refuse connection. - break; - } - } - - return (flag == ACF_ALLOW || access_order == ACO_DENY_ALLOW) ? 1 : 0; - // With 'mutual-failture', only 'allow' and non 'deny' IP are authorised. - // A non 'allow' (even non 'deny') IP is not authorised. It's like: if allowed and not denied, it's authorised. - // So, it's disapproval if you have no description at the time of 'mutual-failture'. - // With 'deny,allow' (allow if not deny), because here it's not deny, we authorise. -} - -//-------------------------------- -// Access control by IP for ladmin -//-------------------------------- -int check_ladminip (unsigned int ip) -{ - int i; - unsigned char *p = (unsigned char *) &ip; - char buf[32]; - - if (access_ladmin_allownum == 0) - return 1; // When there is no restriction, all IP are authorised. - -// + 012.345.: front match form, or -// all: all IP are matched, or -// 012.345.678.901/24: network form (mask with # of bits), or -// 012.345.678.901/255.255.255.0: network form (mask with ip mask) -// + Note about the DNS resolution (like www.ne.jp, etc.): -// There is no guarantee to have an answer. -// If we have an answer, there is no guarantee to have a 100% correct value. -// And, the waiting time (to check) can be long (over 1 minute to a timeout). That can block the software. -// So, DNS notation isn't authorised for ip checking. - sprintf (buf, "%d.%d.%d.%d.", p[0], p[1], p[2], p[3]); - - for (i = 0; i < access_ladmin_allownum; i++) - { - const char *p = access_ladmin_allow + i * ACO_STRSIZE; - if (memcmp (p, buf, strlen (p)) == 0 || check_ipmask (ip, p)) - { - return 1; - } - } - - return 0; -} - -//----------------------------------------------------- -// Function to suppress control characters in a string. -//----------------------------------------------------- -int remove_control_chars (unsigned char *str) -{ - int i; - int change = 0; - - for (i = 0; str[i]; i++) - { - if (str[i] < 32) - { - str[i] = '_'; - change = 1; - } - } - - return change; -} - -//--------------------------------------------------- -// E-mail check: return 0 (not correct) or 1 (valid). -//--------------------------------------------------- -int e_mail_check (unsigned char *email) -{ - char ch; - unsigned char *last_arobas; - - // athena limits - if (strlen (email) < 3 || strlen (email) > 39) - return 0; - - // part of RFC limits (official reference of e-mail description) - if (strchr (email, '@') == NULL || email[strlen (email) - 1] == '@') - return 0; - - if (email[strlen (email) - 1] == '.') - return 0; - - last_arobas = strrchr (email, '@'); - - if (strstr (last_arobas, "@.") != NULL || - strstr (last_arobas, "..") != NULL) - return 0; - - for (ch = 1; ch < 32; ch++) - { - if (strchr (last_arobas, ch) != NULL) - { - return 0; - break; - } - } - - if (strchr (last_arobas, ' ') != NULL || - strchr (last_arobas, ';') != NULL) - return 0; - - // all correct - return 1; -} - -//----------------------------------------------- -// Search an account id -// (return account index or -1 (if not found)) -// If exact account name is not found, -// the function checks without case sensitive -// and returns index if only 1 account is found -// and similar to the searched name. -//----------------------------------------------- -int search_account_index (char *account_name) -{ - int i, quantity, index; - - quantity = 0; - index = -1; - for (i = 0; i < auth_num; i++) - { - // Without case sensitive check (increase the number of similar account names found) - if (strcasecmp (auth_dat[i].userid, account_name) == 0) - { - // Strict comparison (if found, we finish the function immediatly with correct value) - if (strcmp (auth_dat[i].userid, account_name) == 0) - return i; - quantity++; - index = i; - } - } - // Here, the exact account name is not found - // We return the found index of a similar account ONLY if there is 1 similar account - if (quantity == 1) - return index; - - // Exact account name is not found and 0 or more than 1 similar accounts have been found ==> we say not found - return -1; -} - -//-------------------------------------------------------- -// Create a string to save the account in the account file -//-------------------------------------------------------- -int mmo_auth_tostr (char *str, struct auth_dat *p) -{ - int i; - char *str_p = str; - - str_p += sprintf (str_p, "%d\t%s\t%s\t%s\t%c\t%d\t%d\t" - "%s\t%s\t%ld\t%s\t%s\t%ld\t", - p->account_id, p->userid, p->pass, p->lastlogin, - (p->sex == 2) ? 'S' : (p->sex ? 'M' : 'F'), - p->logincount, p->state, - p->email, p->error_message, - p->connect_until_time, p->last_ip, p->memo, - p->ban_until_time); - - for (i = 0; i < p->account_reg2_num; i++) - if (p->account_reg2[i].str[0]) - str_p += - sprintf (str_p, "%s,%d ", p->account_reg2[i].str, - p->account_reg2[i].value); - - return 0; -} - -//--------------------------------- -// Reading of the accounts database -//--------------------------------- -int mmo_auth_init (void) -{ - FILE *fp; - int account_id, logincount, state, n, i, j, v; - char line[2048], *p, userid[2048], pass[2048], lastlogin[2048], sex, - email[2048], error_message[2048], last_ip[2048], memo[2048]; - time_t ban_until_time; - time_t connect_until_time; - char str[2048]; - int GM_count = 0; - int server_count = 0; - - CREATE (auth_dat, struct auth_dat, 256); - auth_max = 256; - - fp = fopen_ (account_filename, "r"); - if (fp == NULL) - { - // no account file -> no account -> no login, including char-server (ERROR) - printf - ("\033[1;31mmmo_auth_init: Accounts file [%s] not found.\033[0m\n", - account_filename); - return 0; - } - - while (fgets (line, sizeof (line) - 1, fp) != NULL) - { - if (line[0] == '/' && line[1] == '/') - continue; - line[sizeof (line) - 1] = '\0'; - p = line; - - // database version reading (v2) - if (((i = sscanf (line, "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%d\t" - "%[^\t]\t%[^\t]\t%ld\t%[^\t]\t%[^\t]\t%ld%n", - &account_id, userid, pass, lastlogin, &sex, - &logincount, &state, email, error_message, - &connect_until_time, last_ip, memo, &ban_until_time, - &n)) == 13 && line[n] == '\t') - || - ((i = - sscanf (line, - "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%d\t" - "%[^\t]\t%[^\t]\t%ld\t%[^\t]\t%[^\t]%n", &account_id, - userid, pass, lastlogin, &sex, &logincount, &state, - email, error_message, &connect_until_time, last_ip, - memo, &n)) == 12 && line[n] == '\t')) - { - n = n + 1; - - // Some checks - if (account_id > END_ACCOUNT_NUM) - { - printf - ("\033[1;31mmmo_auth_init: ******Error: an account has an id higher than %d\n", - END_ACCOUNT_NUM); - printf - (" account id #%d -> account not read (saved in log file).\033[0m\n", - account_id); - login_log - ("mmmo_auth_init: ******Error: an account has an id higher than %d.\n", - END_ACCOUNT_NUM); - login_log - (" account id #%d -> account not read (saved in next line):\n", - account_id); - login_log ("%s", line); - continue; - } - userid[23] = '\0'; - remove_control_chars (userid); - for (j = 0; j < auth_num; j++) - { - if (auth_dat[j].account_id == account_id) - { - printf - ("\033[1;31mmmo_auth_init: ******Error: an account has an identical id to another.\n"); - printf - (" account id #%d -> new account not read (saved in log file).\033[0m\n", - account_id); - login_log - ("mmmo_auth_init: ******Error: an account has an identical id to another.\n"); - login_log - (" account id #%d -> new account not read (saved in next line):\n", - account_id); - login_log ("%s", line); - break; - } - else if (strcmp (auth_dat[j].userid, userid) == 0) - { - printf - ("\033[1;31mmmo_auth_init: ******Error: account name already exists.\n"); - printf (" account name '%s' -> new account not read.\n", userid); // 2 lines, account name can be long. - printf - (" Account saved in log file.\033[0m\n"); - login_log - ("mmmo_auth_init: ******Error: an account has an identical id to another.\n"); - login_log - (" account id #%d -> new account not read (saved in next line):\n", - account_id); - login_log ("%s", line); - break; - } - } - if (j != auth_num) - continue; - - if (auth_num >= auth_max) - { - auth_max += 256; - RECREATE (auth_dat, struct auth_dat, auth_max); - } - - memset (&auth_dat[auth_num], '\0', sizeof (struct auth_dat)); - - auth_dat[auth_num].account_id = account_id; - - strncpy (auth_dat[auth_num].userid, userid, 24); - - memo[254] = '\0'; - remove_control_chars (memo); - strncpy (auth_dat[auth_num].memo, memo, 255); - - pass[39] = '\0'; - remove_control_chars (pass); - // If a password is not encrypted, we encrypt it now. - // A password beginning with ! and - in the memo field is our magic - if (pass[0] != '!' && memo[0] == '-') { - strcpy(auth_dat[auth_num].pass, MD5_saltcrypt(pass, make_salt())); - auth_dat[auth_num].memo[0] = '!'; - printf("encrypting pass: %s %s\n", pass, auth_dat[auth_num].pass); - } - else - strcpy(auth_dat[auth_num].pass, pass); - - lastlogin[23] = '\0'; - remove_control_chars (lastlogin); - strncpy (auth_dat[auth_num].lastlogin, lastlogin, 24); - - auth_dat[auth_num].sex = (sex == 'S' - || sex == 's') ? 2 : (sex == 'M' - || sex == 'm'); - - if (logincount >= 0) - auth_dat[auth_num].logincount = logincount; - else - auth_dat[auth_num].logincount = 0; - - if (state > 255) - auth_dat[auth_num].state = 100; - else if (state < 0) - auth_dat[auth_num].state = 0; - else - auth_dat[auth_num].state = state; - - if (e_mail_check (email) == 0) - { - printf - ("Account %s (%d): invalid e-mail (replaced par a@a.com).\n", - auth_dat[auth_num].userid, - auth_dat[auth_num].account_id); - strncpy (auth_dat[auth_num].email, "a@a.com", 40); - } - else - { - remove_control_chars (email); - strncpy (auth_dat[auth_num].email, email, 40); - } - - error_message[19] = '\0'; - remove_control_chars (error_message); - if (error_message[0] == '\0' || state != 7) - { // 7, because state is packet 0x006a value + 1 - strncpy (auth_dat[auth_num].error_message, "-", 20); - } - else - { - strncpy (auth_dat[auth_num].error_message, error_message, 20); - } - - if (i == 13) - auth_dat[auth_num].ban_until_time = ban_until_time; - else - auth_dat[auth_num].ban_until_time = 0; - - auth_dat[auth_num].connect_until_time = connect_until_time; - - last_ip[15] = '\0'; - remove_control_chars (last_ip); - strncpy (auth_dat[auth_num].last_ip, last_ip, 16); - - for (j = 0; j < ACCOUNT_REG2_NUM; j++) - { - p += n; - if (sscanf (p, "%[^\t,],%d %n", str, &v, &n) != 2) - { - // We must check if a str is void. If it's, we can continue to read other REG2. - // Account line will have something like: str2,9 ,9 str3,1 (here, ,9 is not good) - if (p[0] == ',' && sscanf (p, ",%d %n", &v, &n) == 1) - { - j--; - continue; - } - else - break; - } - str[31] = '\0'; - remove_control_chars (str); - strncpy (auth_dat[auth_num].account_reg2[j].str, str, 32); - auth_dat[auth_num].account_reg2[j].value = v; - } - auth_dat[auth_num].account_reg2_num = j; - - if (isGM (account_id) > 0) - GM_count++; - if (auth_dat[auth_num].sex == 2) - server_count++; - - auth_num++; - if (account_id >= account_id_count) - account_id_count = account_id + 1; - - // Old athena database version reading (v1) - } - else if ((i = - sscanf (line, "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%d\t%n", - &account_id, userid, pass, lastlogin, &sex, - &logincount, &state, &n)) >= 5) - { - if (account_id > END_ACCOUNT_NUM) - { - printf - ("\033[1;31mmmo_auth_init: ******Error: an account has an id higher than %d\n", - END_ACCOUNT_NUM); - printf - (" account id #%d -> account not read (saved in log file).\033[0m\n", - account_id); - login_log - ("mmmo_auth_init: ******Error: an account has an id higher than %d.\n", - END_ACCOUNT_NUM); - login_log - (" account id #%d -> account not read (saved in next line):\n", - account_id); - login_log ("%s", line); - continue; - } - userid[23] = '\0'; - remove_control_chars (userid); - for (j = 0; j < auth_num; j++) - { - if (auth_dat[j].account_id == account_id) - { - printf - ("\033[1;31mmmo_auth_init: ******Error: an account has an identical id to another.\n"); - printf - (" account id #%d -> new account not read (saved in log file).\033[0m\n", - account_id); - login_log - ("mmmo_auth_init: ******Error: an account has an identical id to another.\n"); - login_log - (" account id #%d -> new account not read (saved in next line):\n", - account_id); - login_log ("%s", line); - break; - } - else if (strcmp (auth_dat[j].userid, userid) == 0) - { - printf - ("\033[1;31mmmo_auth_init: ******Error: account name already exists.\n"); - printf (" account name '%s' -> new account not read.\n", userid); // 2 lines, account name can be long. - printf - (" Account saved in log file.\033[0m\n"); - login_log - ("mmmo_auth_init: ******Error: an account has an identical id to another.\n"); - login_log - (" account id #%d -> new account not read (saved in next line):\n", - account_id); - login_log ("%s", line); - break; - } - } - if (j != auth_num) - continue; - - if (auth_num >= auth_max) - { - auth_max += 256; - RECREATE (auth_dat, struct auth_dat, auth_max); - } - - memset (&auth_dat[auth_num], '\0', sizeof (struct auth_dat)); - - auth_dat[auth_num].account_id = account_id; - - strncpy (auth_dat[auth_num].userid, userid, 24); - - lastlogin[23] = '\0'; - remove_control_chars (lastlogin); - strncpy (auth_dat[auth_num].lastlogin, lastlogin, 24); - - auth_dat[auth_num].sex = (sex == 'S' - || sex == 's') ? 2 : (sex == 'M' - || sex == 'm'); - - if (i >= 6) - { - if (logincount >= 0) - auth_dat[auth_num].logincount = logincount; - else - auth_dat[auth_num].logincount = 0; - } - else - auth_dat[auth_num].logincount = 0; - - if (i >= 7) - { - if (state > 255) - auth_dat[auth_num].state = 100; - else if (state < 0) - auth_dat[auth_num].state = 0; - else - auth_dat[auth_num].state = state; - } - else - auth_dat[auth_num].state = 0; - - // Initialization of new data - strncpy (auth_dat[auth_num].email, "a@a.com", 40); - strncpy (auth_dat[auth_num].error_message, "-", 20); - auth_dat[auth_num].ban_until_time = 0; - auth_dat[auth_num].connect_until_time = 0; - strncpy (auth_dat[auth_num].last_ip, "-", 16); - strncpy (auth_dat[auth_num].memo, "!", 255); - - for (j = 0; j < ACCOUNT_REG2_NUM; j++) - { - p += n; - if (sscanf (p, "%[^\t,],%d %n", str, &v, &n) != 2) - { - // We must check if a str is void. If it's, we can continue to read other REG2. - // Account line will have something like: str2,9 ,9 str3,1 (here, ,9 is not good) - if (p[0] == ',' && sscanf (p, ",%d %n", &v, &n) == 1) - { - j--; - continue; - } - else - break; - } - str[31] = '\0'; - remove_control_chars (str); - strncpy (auth_dat[auth_num].account_reg2[j].str, str, 32); - auth_dat[auth_num].account_reg2[j].value = v; - } - auth_dat[auth_num].account_reg2_num = j; - - if (isGM (account_id) > 0) - GM_count++; - if (auth_dat[auth_num].sex == 2) - server_count++; - - auth_num++; - if (account_id >= account_id_count) - account_id_count = account_id + 1; - - } - else - { - i = 0; - if (sscanf (line, "%d\t%%newid%%\n%n", &account_id, &i) == 1 && - i > 0 && account_id > account_id_count) - account_id_count = account_id; - } - } - fclose_ (fp); - - if (auth_num == 0) - { - printf ("mmo_auth_init: No account found in %s.\n", account_filename); - sprintf (line, "No account found in %s.", account_filename); - } - else - { - if (auth_num == 1) - { - printf ("mmo_auth_init: 1 account read in %s,\n", - account_filename); - sprintf (line, "1 account read in %s,", account_filename); - } - else - { - printf ("mmo_auth_init: %d accounts read in %s,\n", auth_num, - account_filename); - sprintf (line, "%d accounts read in %s,", auth_num, - account_filename); - } - if (GM_count == 0) - { - printf (" of which is no GM account, and "); - sprintf (str, "%s of which is no GM account and", line); - } - else if (GM_count == 1) - { - printf (" of which is 1 GM account, and "); - sprintf (str, "%s of which is 1 GM account and", line); - } - else - { - printf (" of which is %d GM accounts, and ", - GM_count); - sprintf (str, "%s of which is %d GM accounts and", line, - GM_count); - } - if (server_count == 0) - { - printf ("no server account ('S').\n"); - sprintf (line, "%s no server account ('S').", str); - } - else if (server_count == 1) - { - printf ("1 server account ('S').\n"); - sprintf (line, "%s 1 server account ('S').", str); - } - else - { - printf ("%d server accounts ('S').\n", server_count); - sprintf (line, "%s %d server accounts ('S').", str, server_count); - } - } - login_log ("%s\n", line); - - return 0; -} - -//------------------------------------------ -// Writing of the accounts database file -// (accounts are sorted by id before save) -//------------------------------------------ -void mmo_auth_sync (void) -{ - FILE *fp; - int i, j, k, lock; - int id[auth_num]; - char line[65536]; - - // Sorting before save - for (i = 0; i < auth_num; i++) - { - id[i] = i; - for (j = 0; j < i; j++) - { - if (auth_dat[i].account_id < auth_dat[id[j]].account_id) - { - for (k = i; k > j; k--) - id[k] = id[k - 1]; - id[j] = i; // id[i] - break; - } - } - } - - // Data save - fp = lock_fopen (account_filename, &lock); - if (fp == NULL) - return; - fprintf (fp, - "// Accounts file: here are saved all information about the accounts.\n"); - fprintf (fp, - "// Structure: ID, account name, password, last login time, sex, # of logins, state, email, error message for state 7, validity time, last (accepted) login ip, memo field, ban timestamp, repeated(register text, register value)\n"); - fprintf (fp, "// Some explanations:\n"); - fprintf (fp, - "// account name : between 4 to 23 char for a normal account (standard client can't send less than 4 char).\n"); - fprintf (fp, "// account password: between 4 to 23 char\n"); - fprintf (fp, - "// sex : M or F for normal accounts, S for server accounts\n"); - fprintf (fp, - "// state : 0: account is ok, 1 to 256: error code of packet 0x006a + 1\n"); - fprintf (fp, - "// email : between 3 to 39 char (a@a.com is like no email)\n"); - fprintf (fp, - "// error message : text for the state 7: 'Your are Prohibited to login until '. Max 19 char\n"); - fprintf (fp, - "// valitidy time : 0: unlimited account, : date calculated by addition of 1/1/1970 + value (number of seconds since the 1/1/1970)\n"); - fprintf (fp, "// memo field : max 254 char\n"); - fprintf (fp, - "// ban time : 0: no ban, : banned until the date: date calculated by addition of 1/1/1970 + value (number of seconds since the 1/1/1970)\n"); - for (i = 0; i < auth_num; i++) - { - k = id[i]; // use of sorted index - if (auth_dat[k].account_id < 0) - continue; - - mmo_auth_tostr (line, &auth_dat[k]); - fprintf (fp, "%s\n", line); - } - fprintf (fp, "%d\t%%newid%%\n", account_id_count); - - lock_fclose (fp, account_filename, &lock); - - return; -} - -// We want to sync the DB to disk as little as possible as it's fairly -// resource intensive. therefore most player-triggerable events that -// update the account DB will not immideately trigger a save. Instead -// we save periodicly on a timer. -//----------------------------------------------------- -void check_auth_sync (timer_id tid, tick_t tick, custom_id_t id, custom_data_t data) -{ - if (pid != 0) - { - int status; - pid_t temp = waitpid (pid, &status, WNOHANG); - - // Need to check status too? - if (temp == 0) - { - return; - } - } - - // This can take a lot of time. Fork a child to handle the work and return at once - // If we're unable to fork just continue running the function normally - if ((pid = fork ()) > 0) - return; - - mmo_auth_sync (); - - // If we're a child we should suicide now. - if (pid == 0) - _exit (0); - - return; -} - -//-------------------------------------------------------------------- -// Packet send to all char-servers, except one (wos: without our self) -//-------------------------------------------------------------------- -int charif_sendallwos (int sfd, unsigned char *buf, unsigned int len) -{ - int i, c; - - for (i = 0, c = 0; i < MAX_SERVERS; i++) - { - int fd; - if ((fd = server_fd[i]) >= 0 && fd != sfd) - { - memcpy (WFIFOP (fd, 0), buf, len); - WFIFOSET (fd, len); - c++; - } - } - return c; -} - -//----------------------------------------------------- -// Send GM accounts to all char-server -//----------------------------------------------------- -void send_GM_accounts (void) -{ - int i; - char buf[32000]; - int GM_value; - int len; - - len = 4; - WBUFW (buf, 0) = 0x2732; - for (i = 0; i < auth_num; i++) - // send only existing accounts. We can not create a GM account when server is online. - if ((GM_value = isGM (auth_dat[i].account_id)) > 0) - { - WBUFL (buf, len) = auth_dat[i].account_id; - WBUFB (buf, len + 4) = (unsigned char) GM_value; - len += 5; - } - WBUFW (buf, 2) = len; - charif_sendallwos (-1, buf, len); - - return; -} - -//----------------------------------------------------- -// Check if GM file account have been changed -//----------------------------------------------------- -void check_GM_file (timer_id tid, tick_t tick, custom_id_t id, custom_data_t data) -{ - struct stat file_stat; - long new_time; - - // if we would not check - if (gm_account_filename_check_timer < 1) - return; - - // get last modify time/date - if (stat (GM_account_filename, &file_stat)) - new_time = 0; // error - else - new_time = file_stat.st_mtime; - - if (new_time != creation_time_GM_account_file) - { - read_gm_account (); - send_GM_accounts (); - } -} - -//------------------------------------- -// Account creation (with e-mail check) -//------------------------------------- -int mmo_auth_new (struct mmo_account *account, char sex, char *email) -{ - time_t timestamp, timestamp_temp; - struct tm *tmtime; - int i = auth_num; - - if (auth_num >= auth_max) - { - auth_max += 256; - RECREATE (auth_dat, struct auth_dat, auth_max); - } - - memset (&auth_dat[i], '\0', sizeof (struct auth_dat)); - - while (isGM (account_id_count) > 0) - account_id_count++; - - auth_dat[i].account_id = account_id_count++; - - strncpy (auth_dat[i].userid, account->userid, 24); - auth_dat[i].userid[23] = '\0'; - - strcpy(auth_dat[i].pass, MD5_saltcrypt(account->passwd, make_salt())); - auth_dat[i].pass[39] = '\0'; - - memcpy (auth_dat[i].lastlogin, "-", 2); - - auth_dat[i].sex = (sex == 'M'); - - auth_dat[i].logincount = 0; - - auth_dat[i].state = 0; - - if (e_mail_check (email) == 0) - strncpy (auth_dat[i].email, "a@a.com", 40); - else - strncpy (auth_dat[i].email, email, 40); - - strncpy (auth_dat[i].error_message, "-", 20); - - auth_dat[i].ban_until_time = 0; - - if (start_limited_time < 0) - auth_dat[i].connect_until_time = 0; // unlimited - else - { // limited time - timestamp = time (NULL) + start_limited_time; - // double conversion to be sure that it is possible - tmtime = gmtime (×tamp); - timestamp_temp = mktime (tmtime); - if (timestamp_temp != -1 && (timestamp_temp + 3600) >= timestamp) // check possible value and overflow (and avoid summer/winter hour) - auth_dat[i].connect_until_time = timestamp_temp; - else - auth_dat[i].connect_until_time = 0; // unlimited - } - - strncpy (auth_dat[i].last_ip, "-", 16); - - strncpy (auth_dat[i].memo, "!", 255); - - auth_dat[i].account_reg2_num = 0; - - auth_num++; - - return (account_id_count - 1); -} - -//--------------------------------------- -// Check/authentification of a connection -//--------------------------------------- -int mmo_auth (struct mmo_account *account, int fd) -{ - int i; - struct timeval tv; - char tmpstr[256]; - int len, newaccount = 0; -#ifdef PASSWDENC - char md5str[64], md5bin[32]; -#endif - char ip[16]; - unsigned char *sin_addr = - (unsigned char *) &session[fd]->client_addr.sin_addr; - - sprintf (ip, "%d.%d.%d.%d", sin_addr[0], sin_addr[1], sin_addr[2], - sin_addr[3]); - - len = strlen (account->userid) - 2; - // Account creation with _M/_F - if (account->passwdenc == 0 && account->userid[len] == '_' && - (account->userid[len + 1] == 'F' || account->userid[len + 1] == 'M') - && new_account_flag == 1 && account_id_count <= END_ACCOUNT_NUM - && len >= 4 && strlen (account->passwd) >= 4) - { - if (new_account_flag == 1) - newaccount = 1; - account->userid[len] = '\0'; - } - - // Strict account search - for (i = 0; i < auth_num; i++) - { - if (strcmp (account->userid, auth_dat[i].userid) == 0) - break; - } - // if there is no creation request and strict account search fails, we do a no sensitive case research for index - if (newaccount == 0 && i == auth_num) - { - i = search_account_index (account->userid); - if (i == -1) - i = auth_num; - else - memcpy (account->userid, auth_dat[i].userid, 24); // for the possible tests/checks afterwards (copy correcte sensitive case). - } - - if (i != auth_num) - { - int encpasswdok = 0; - struct login_session_data *ld; - if (newaccount) - { - login_log - ("Attempt of creation of an already existant account (account: %s_%c, ip: %s)\n", - account->userid, account->userid[len + 1], ip); - return 9; // 9 = Account already exists - } - ld = (struct login_session_data*) session[fd]->session_data; -#ifdef PASSWORDENC - if (account->passwdenc > 0) - { - int j = account->passwdenc; - if (!ld) - { - login_log ("Md5 key not created (account: %s, ip: %s)\n", - account->userid, ip); - return 1; // 1 = Incorrect Password - } - if (j > 2) - j = 1; - do - { - if (j == 1) - { - strncpy (md5str, ld->md5key, sizeof (ld->md5key)); // 20 - strcat (md5str, auth_dat[i].pass); // 24 - } - else if (j == 2) - { - strncpy (md5str, auth_dat[i].pass, sizeof (auth_dat[i].pass)); // 24 - strcat (md5str, ld->md5key); // 20 - } - else - md5str[0] = '\0'; - md5str[sizeof (md5str) - 1] = '\0'; // 64 - MD5_String2binary (md5str, md5bin); - encpasswdok = (memcmp (account->passwd, md5bin, 16) == 0); - } - while (j < 2 && !encpasswdok && (j++) != account->passwdenc); -// printf("key[%s] md5 [%s] ", md5key, md5); -// printf("client [%s] accountpass [%s]\n", account->passwd, auth_dat[i].pass); - } -#endif - if ((!pass_ok (account->passwd, auth_dat[i].pass)) && !encpasswdok) - { - if (account->passwdenc == 0) - login_log - ("Invalid password (account: %s, ip: %s)\n", - account->userid, ip); - -#ifdef PASSWORDENC - else - { - char logbuf[512], *p = logbuf; - int j; - p += sprintf (p, - "Invalid password (account: %s, received md5[", - account->userid); - for (j = 0; j < 16; j++) - p += sprintf (p, "%02x", - ((unsigned char *) account->passwd)[j]); - p += sprintf (p, "] calculated md5["); - for (j = 0; j < 16; j++) - p += sprintf (p, "%02x", ((unsigned char *) md5bin)[j]); - p += sprintf (p, "] md5 key["); - for (j = 0; j < ld->md5keylen; j++) - p += sprintf (p, "%02x", - ((unsigned char *) ld->md5key)[j]); - p += sprintf (p, "], ip: %s)\n", ip); - login_log (logbuf); - } -#endif - return 1; // 1 = Incorrect Password - } - - if (auth_dat[i].state) - { - login_log - ("Connection refused (account: %s, state: %d, ip: %s)\n", - account->userid, auth_dat[i].state, - ip); - switch (auth_dat[i].state) - { // packet 0x006a value + 1 - case 1: // 0 = Unregistered ID - case 2: // 1 = Incorrect Password - case 3: // 2 = This ID is expired - case 4: // 3 = Rejected from Server - case 5: // 4 = You have been blocked by the GM Team - case 6: // 5 = Your Game's EXE file is not the latest version - case 7: // 6 = Your are Prohibited to log in until %s - case 8: // 7 = Server is jammed due to over populated - case 9: // 8 = No MSG (actually, all states after 9 except 99 are No MSG, use only this) - case 100: // 99 = This ID has been totally erased - return auth_dat[i].state - 1; - break; - default: - return 99; // 99 = ID has been totally erased - break; - } - } - - if (auth_dat[i].ban_until_time != 0) - { // if account is banned - strftime (tmpstr, 20, date_format, - gmtime (&auth_dat[i].ban_until_time)); - tmpstr[19] = '\0'; - if (auth_dat[i].ban_until_time > time (NULL)) - { // always banned - login_log - ("Connection refused (account: %s, banned until %s, ip: %s)\n", - account->userid, tmpstr, ip); - return 6; // 6 = Your are Prohibited to log in until %s - } - else - { // ban is finished - login_log - ("End of ban (account: %s, previously banned until %s -> not more banned, ip: %s)\n", - account->userid, tmpstr, ip); - auth_dat[i].ban_until_time = 0; // reset the ban time - } - } - - if (auth_dat[i].connect_until_time != 0 - && auth_dat[i].connect_until_time < time (NULL)) - { - login_log - ("Connection refused (account: %s, expired ID, ip: %s)\n", - account->userid, ip); - return 2; // 2 = This ID is expired - } - - login_log ("Authentification accepted (account: %s (id: %d), ip: %s)\n", - account->userid, auth_dat[i].account_id, ip); - } - else - { - if (newaccount == 0) - { - login_log - ("Unknown account (account: %s, ip: %s)\n", - account->userid, ip); - return 0; // 0 = Unregistered ID - } - else - { - int new_id = - mmo_auth_new (account, account->userid[len + 1], "a@a.com"); - login_log - ("Account creation and authentification accepted (account %s (id: %d), sex: %c, connection with _F/_M, ip: %s)\n", - account->userid, new_id, - account->userid[len + 1], ip); - } - } - - gettimeofday (&tv, NULL); - strftime (tmpstr, 24, date_format, gmtime (&(tv.tv_sec))); - sprintf (tmpstr + strlen (tmpstr), ".%03d", (int) tv.tv_usec / 1000); - - account->account_id = auth_dat[i].account_id; - account->login_id1 = mt_random (); - account->login_id2 = mt_random (); - memcpy (account->lastlogin, auth_dat[i].lastlogin, 24); - memcpy (auth_dat[i].lastlogin, tmpstr, 24); - account->sex = auth_dat[i].sex; - strncpy (auth_dat[i].last_ip, ip, 16); - auth_dat[i].logincount++; - - return -1; // account OK -} - -//------------------------------- -// Char-server anti-freeze system -//------------------------------- -void char_anti_freeze_system (timer_id tid, tick_t tick, custom_id_t id, custom_data_t data) -{ - int i; - - //printf("Entering in char_anti_freeze_system function to check freeze of servers.\n"); - for (i = 0; i < MAX_SERVERS; i++) - { - if (server_fd[i] >= 0) - { // if char-server is online - //printf("char_anti_freeze_system: server #%d '%s', flag: %d.\n", i, server[i].name, server_freezeflag[i]); - if (server_freezeflag[i]-- < 1) - { // Char-server anti-freeze system. Counter. 5 ok, 4...0 freezed - printf - ("Char-server anti-freeze system: char-server #%d '%s' is freezed -> disconnection.\n", - i, server[i].name); - login_log - ("Char-server anti-freeze system: char-server #%d '%s' is freezed -> disconnection.\n", - i, server[i].name); - session[server_fd[i]]->eof = 1; - } - } - } -} - -//-------------------------------- -// Packet parsing for char-servers -//-------------------------------- -void parse_fromchar (int fd) -{ - int i, j, id; - unsigned char *p = (unsigned char *) &session[fd]->client_addr.sin_addr; - char ip[16]; - - sprintf (ip, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); - - for (id = 0; id < MAX_SERVERS; id++) - if (server_fd[id] == fd) - break; - if (id == MAX_SERVERS || session[fd]->eof) - { - if (id < MAX_SERVERS) - { - printf ("Char-server '%s' has disconnected.\n", server[id].name); - login_log ("Char-server '%s' has disconnected (ip: %s).\n", - server[id].name, ip); - server_fd[id] = -1; - memset (&server[id], 0, sizeof (struct mmo_char_server)); - } - close (fd); - delete_session (fd); - return; - } - - while (RFIFOREST (fd) >= 2) - { - if (display_parse_fromchar == 2 || (display_parse_fromchar == 1 && RFIFOW (fd, 0) != 0x2714)) // 0x2714 is done very often (number of players) - printf - ("parse_fromchar: connection #%d, packet: 0x%x (with being read: %d bytes).\n", - fd, RFIFOW (fd, 0), RFIFOREST (fd)); - - switch (RFIFOW (fd, 0)) - { - // request from map-server via char-server to reload GM accounts (by Yor). - case 0x2709: - login_log - ("Char-server '%s': Request to re-load GM configuration file (ip: %s).\n", - server[id].name, ip); - read_gm_account (); - // send GM accounts to all char-servers - send_GM_accounts (); - RFIFOSKIP (fd, 2); - break; - - case 0x2712: // request from char-server to authentify an account - if (RFIFOREST (fd) < 19) - return; - { - int acc; - acc = RFIFOL (fd, 2); // speed up - for (i = 0; i < AUTH_FIFO_SIZE; i++) - { - if (auth_fifo[i].account_id == acc && - auth_fifo[i].login_id1 == RFIFOL (fd, 6) && -#if CMP_AUTHFIFO_LOGIN2 != 0 - auth_fifo[i].login_id2 == RFIFOL (fd, 10) && // relate to the versions higher than 18 -#endif - auth_fifo[i].sex == RFIFOB (fd, 14) && - (!check_ip_flag - || auth_fifo[i].ip == RFIFOL (fd, 15)) - && !auth_fifo[i].delflag) - { - int p, k; - auth_fifo[i].delflag = 1; - login_log - ("Char-server '%s': authentification of the account %d accepted (ip: %s).\n", - server[id].name, acc, ip); -// printf("%d\n", i); - for (k = 0; k < auth_num; k++) - { - if (auth_dat[k].account_id == acc) - { - WFIFOW (fd, 0) = 0x2729; // Sending of the account_reg2 - WFIFOL (fd, 4) = acc; - for (p = 8, j = 0; - j < auth_dat[k].account_reg2_num; - p += 36, j++) - { - memcpy (WFIFOP (fd, p), - auth_dat[k]. - account_reg2[j].str, 32); - WFIFOL (fd, p + 32) = - auth_dat[k].account_reg2[j].value; - } - WFIFOW (fd, 2) = p; - WFIFOSET (fd, p); -// printf("parse_fromchar: Sending of account_reg2: login->char (auth fifo)\n"); - WFIFOW (fd, 0) = 0x2713; - WFIFOL (fd, 2) = acc; - WFIFOB (fd, 6) = 0; - memcpy (WFIFOP (fd, 7), auth_dat[k].email, - 40); - WFIFOL (fd, 47) = - (unsigned long) - auth_dat[k].connect_until_time; - WFIFOSET (fd, 51); - break; - } - } - break; - } - } - // authentification not found - if (i == AUTH_FIFO_SIZE) - { - login_log - ("Char-server '%s': authentification of the account %d REFUSED (ip: %s).\n", - server[id].name, acc, ip); - WFIFOW (fd, 0) = 0x2713; - WFIFOL (fd, 2) = acc; - WFIFOB (fd, 6) = 1; - // It is unnecessary to send email - // It is unnecessary to send validity date of the account - WFIFOSET (fd, 51); - } - } - RFIFOSKIP (fd, 19); - break; - - case 0x2714: - if (RFIFOREST (fd) < 6) - return; - //printf("parse_fromchar: Receiving of the users number of the server '%s': %d\n", server[id].name, RFIFOL(fd,2)); - server[id].users = RFIFOL (fd, 2); - if (anti_freeze_enable) - server_freezeflag[id] = 5; // Char anti-freeze system. Counter. 5 ok, 4...0 freezed - RFIFOSKIP (fd, 6); - break; - - // we receive a e-mail creation of an account with a default e-mail (no answer) - case 0x2715: - { - int acc; - char email[40]; - if (RFIFOREST (fd) < 46) - return; - acc = RFIFOL (fd, 2); // speed up - memcpy (email, RFIFOP (fd, 6), 40); - email[39] = '\0'; - remove_control_chars (email); - //printf("parse_fromchar: an e-mail creation of an account with a default e-mail: server '%s', account: %d, e-mail: '%s'.\n", server[id].name, acc, RFIFOP(fd,6)); - if (e_mail_check (email) == 0) - login_log - ("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - e-mail is invalid (account: %d, ip: %s)\n", - server[id].name, acc, ip); - else - { - for (i = 0; i < auth_num; i++) - { - if (auth_dat[i].account_id == acc - && (strcmp (auth_dat[i].email, "a@a.com") == 0 - || auth_dat[i].email[0] == '\0')) - { - memcpy (auth_dat[i].email, email, 40); - login_log - ("Char-server '%s': Create an e-mail on an account with a default e-mail (account: %d, new e-mail: %s, ip: %s).\n", - server[id].name, acc, email, ip); - break; - } - } - if (i == auth_num) - login_log - ("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - account doesn't exist or e-mail of account isn't default e-mail (account: %d, ip: %s).\n", - server[id].name, acc, ip); - } - RFIFOSKIP (fd, 46); - break; - - // We receive an e-mail/limited time request, because a player comes back from a map-server to the char-server - } - case 0x2716: - if (RFIFOREST (fd) < 6) - return; - //printf("parse_fromchar: E-mail/limited time request from '%s' server (concerned account: %d)\n", server[id].name, RFIFOL(fd,2)); - for (i = 0; i < auth_num; i++) - { - if (auth_dat[i].account_id == RFIFOL (fd, 2)) - { - login_log - ("Char-server '%s': e-mail of the account %d found (ip: %s).\n", - server[id].name, RFIFOL (fd, 2), ip); - WFIFOW (fd, 0) = 0x2717; - WFIFOL (fd, 2) = RFIFOL (fd, 2); - memcpy (WFIFOP (fd, 6), auth_dat[i].email, 40); - WFIFOL (fd, 46) = - (unsigned long) auth_dat[i].connect_until_time; - WFIFOSET (fd, 50); - break; - } - } - if (i == auth_num) - { - login_log - ("Char-server '%s': e-mail of the account %d NOT found (ip: %s).\n", - server[id].name, RFIFOL (fd, 2), ip); - } - RFIFOSKIP (fd, 6); - break; - - case 0x2720: // To become GM request - if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) - return; - { - int acc; - unsigned char buf[10]; - FILE *fp; - acc = RFIFOL (fd, 4); - //printf("parse_fromchar: Request to become a GM acount from %d account.\n", acc); - WBUFW (buf, 0) = 0x2721; - WBUFL (buf, 2) = acc; - WBUFL (buf, 6) = 0; - if (strcmp (RFIFOP (fd, 8), gm_pass) == 0) - { - // only non-GM can become GM - if (isGM (acc) == 0) - { - // if we autorise creation - if (level_new_gm > 0) - { - // if we can open the file to add the new GM - if ((fp = - fopen_ (GM_account_filename, - "a")) != NULL) - { - char tmpstr[24]; - struct timeval tv; - gettimeofday (&tv, NULL); - strftime (tmpstr, 23, date_format, - gmtime (&(tv.tv_sec))); - fprintf (fp, - "\n// %s: @GM command on account %d\n%d %d\n", - tmpstr, - acc, acc, level_new_gm); - fclose_ (fp); - WBUFL (buf, 6) = level_new_gm; - read_gm_account (); - send_GM_accounts (); - printf - ("GM Change of the account %d: level 0 -> %d.\n", - acc, level_new_gm); - login_log - ("Char-server '%s': GM Change of the account %d: level 0 -> %d (ip: %s).\n", - server[id].name, acc, - level_new_gm, ip); - } - else - { - printf - ("Error of GM change (suggested account: %d, correct password, unable to add a GM account in GM accounts file)\n", - acc); - login_log - ("Char-server '%s': Error of GM change (suggested account: %d, correct password, unable to add a GM account in GM accounts file, ip: %s).\n", - server[id].name, acc, ip); - } - } - else - { - printf - ("Error of GM change (suggested account: %d, correct password, but GM creation is disable (level_new_gm = 0))\n", - acc); - login_log - ("Char-server '%s': Error of GM change (suggested account: %d, correct password, but GM creation is disable (level_new_gm = 0), ip: %s).\n", - server[id].name, acc, ip); - } - } - else - { - printf - ("Error of GM change (suggested account: %d (already GM), correct password).\n", - acc); - login_log - ("Char-server '%s': Error of GM change (suggested account: %d (already GM), correct password, ip: %s).\n", - server[id].name, acc, ip); - } - } - else - { - printf - ("Error of GM change (suggested account: %d, invalid password).\n", - acc); - login_log - ("Char-server '%s': Error of GM change (suggested account: %d, invalid password, ip: %s).\n", - server[id].name, acc, ip); - } - charif_sendallwos (-1, buf, 10); - } - RFIFOSKIP (fd, RFIFOW (fd, 2)); - return; - - // Map server send information to change an email of an account via char-server - case 0x2722: // 0x2722 .L .40B .40B - if (RFIFOREST (fd) < 86) - return; - { - int acc; - char actual_email[40], new_email[40]; - acc = RFIFOL (fd, 2); - memcpy (actual_email, RFIFOP (fd, 6), 40); - actual_email[39] = '\0'; - remove_control_chars (actual_email); - memcpy (new_email, RFIFOP (fd, 46), 40); - new_email[39] = '\0'; - remove_control_chars (new_email); - if (e_mail_check (actual_email) == 0) - login_log - ("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual email is invalid (account: %d, ip: %s)\n", - server[id].name, acc, ip); - else if (e_mail_check (new_email) == 0) - login_log - ("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a invalid new e-mail (account: %d, ip: %s)\n", - server[id].name, acc, ip); - else if (strcasecmp (new_email, "a@a.com") == 0) - login_log - ("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a default e-mail (account: %d, ip: %s)\n", - server[id].name, acc, ip); - else - { - for (i = 0; i < auth_num; i++) - { - if (auth_dat[i].account_id == acc) - { - if (strcasecmp (auth_dat[i].email, actual_email) - == 0) - { - memcpy (auth_dat[i].email, new_email, 40); - login_log - ("Char-server '%s': Modify an e-mail on an account (@email GM command) (account: %d (%s), new e-mail: %s, ip: %s).\n", - server[id].name, acc, - auth_dat[i].userid, new_email, ip); - } - else - login_log - ("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual e-mail is incorrect (account: %d (%s), actual e-mail: %s, proposed e-mail: %s, ip: %s).\n", - server[id].name, acc, - auth_dat[i].userid, - auth_dat[i].email, actual_email, ip); - break; - } - } - if (i == auth_num) - login_log - ("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but account doesn't exist (account: %d, ip: %s).\n", - server[id].name, acc, ip); - } - } - RFIFOSKIP (fd, 86); - break; - - // Receiving of map-server via char-server a status change resquest (by Yor) - case 0x2724: - if (RFIFOREST (fd) < 10) - return; - { - int acc, statut; - acc = RFIFOL (fd, 2); - statut = RFIFOL (fd, 6); - for (i = 0; i < auth_num; i++) - { - if (auth_dat[i].account_id == acc) - { - if (auth_dat[i].state != statut) - { - login_log - ("Char-server '%s': Status change (account: %d, new status %d, ip: %s).\n", - server[id].name, acc, statut, - ip); - if (statut != 0) - { - unsigned char buf[16]; - WBUFW (buf, 0) = 0x2731; - WBUFL (buf, 2) = acc; - WBUFB (buf, 6) = 0; // 0: change of statut, 1: ban - WBUFL (buf, 7) = statut; // status or final date of a banishment - charif_sendallwos (-1, buf, 11); - for (j = 0; j < AUTH_FIFO_SIZE; j++) - if (auth_fifo[j].account_id == acc) - auth_fifo[j].login_id1++; // to avoid reconnection error when come back from map-server (char-server will ask again the authentification) - } - auth_dat[i].state = statut; - } - else - login_log - ("Char-server '%s': Error of Status change - actual status is already the good status (account: %d, status %d, ip: %s).\n", - server[id].name, acc, statut, - ip); - break; - } - } - if (i == auth_num) - { - login_log - ("Char-server '%s': Error of Status change (account: %d not found, suggested status %d, ip: %s).\n", - server[id].name, acc, statut, ip); - } - RFIFOSKIP (fd, 10); - } - return; - - case 0x2725: // Receiving of map-server via char-server a ban resquest (by Yor) - if (RFIFOREST (fd) < 18) - return; - { - int acc; - acc = RFIFOL (fd, 2); - for (i = 0; i < auth_num; i++) - { - if (auth_dat[i].account_id == acc) - { - time_t timestamp; - struct tm *tmtime; - if (auth_dat[i].ban_until_time == 0 - || auth_dat[i].ban_until_time < time (NULL)) - timestamp = time (NULL); - else - timestamp = auth_dat[i].ban_until_time; - tmtime = gmtime (×tamp); - tmtime->tm_year = - tmtime->tm_year + (short) RFIFOW (fd, 6); - tmtime->tm_mon = - tmtime->tm_mon + (short) RFIFOW (fd, 8); - tmtime->tm_mday = - tmtime->tm_mday + (short) RFIFOW (fd, 10); - tmtime->tm_hour = - tmtime->tm_hour + (short) RFIFOW (fd, 12); - tmtime->tm_min = - tmtime->tm_min + (short) RFIFOW (fd, 14); - tmtime->tm_sec = - tmtime->tm_sec + (short) RFIFOW (fd, 16); - timestamp = timegm (tmtime); - if (timestamp != -1) - { - if (timestamp <= time (NULL)) - timestamp = 0; - if (auth_dat[i].ban_until_time != timestamp) - { - if (timestamp != 0) - { - unsigned char buf[16]; - char tmpstr[2048]; - strftime (tmpstr, 24, date_format, - gmtime (×tamp)); - login_log - ("Char-server '%s': Ban request (account: %d, new final date of banishment: %d (%s), ip: %s).\n", - server[id].name, acc, - timestamp, - (timestamp == - 0 ? "no banishment" : tmpstr), - ip); - WBUFW (buf, 0) = 0x2731; - WBUFL (buf, 2) = - auth_dat[i].account_id; - WBUFB (buf, 6) = 1; // 0: change of statut, 1: ban - WBUFL (buf, 7) = timestamp; // status or final date of a banishment - charif_sendallwos (-1, buf, 11); - for (j = 0; j < AUTH_FIFO_SIZE; j++) - if (auth_fifo[j].account_id == - acc) - auth_fifo[j].login_id1++; // to avoid reconnection error when come back from map-server (char-server will ask again the authentification) - } - else - { - login_log - ("Char-server '%s': Error of ban request (account: %d, new date unbans the account, ip: %s).\n", - server[id].name, acc, - ip); - } - auth_dat[i].ban_until_time = timestamp; - } - else - { - login_log - ("Char-server '%s': Error of ban request (account: %d, no change for ban date, ip: %s).\n", - server[id].name, acc, ip); - } - } - else - { - login_log - ("Char-server '%s': Error of ban request (account: %d, invalid date, ip: %s).\n", - server[id].name, acc, ip); - } - break; - } - } - if (i == auth_num) - { - login_log - ("Char-server '%s': Error of ban request (account: %d not found, ip: %s).\n", - server[id].name, acc, ip); - } - RFIFOSKIP (fd, 18); - } - return; - - case 0x2727: // Change of sex (sex is reversed) - if (RFIFOREST (fd) < 6) - return; - { - int acc, sex; - acc = RFIFOL (fd, 2); - for (i = 0; i < auth_num; i++) - { -// printf("%d,", auth_dat[i].account_id); - if (auth_dat[i].account_id == acc) - { - if (auth_dat[i].sex == 2) - login_log - ("Char-server '%s': Error of sex change - Server account (suggested account: %d, actual sex %d (Server), ip: %s).\n", - server[id].name, acc, - auth_dat[i].sex, ip); - else - { - unsigned char buf[16]; - if (auth_dat[i].sex == 0) - sex = 1; - else - sex = 0; - login_log - ("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n", - server[id].name, acc, - (sex == 2) ? 'S' : (sex ? 'M' : 'F'), - ip); - for (j = 0; j < AUTH_FIFO_SIZE; j++) - if (auth_fifo[j].account_id == acc) - auth_fifo[j].login_id1++; // to avoid reconnection error when come back from map-server (char-server will ask again the authentification) - auth_dat[i].sex = sex; - WBUFW (buf, 0) = 0x2723; - WBUFL (buf, 2) = acc; - WBUFB (buf, 6) = sex; - charif_sendallwos (-1, buf, 7); - } - break; - } - } - if (i == auth_num) - { - login_log - ("Char-server '%s': Error of sex change (account: %d not found, sex would be reversed, ip: %s).\n", - server[id].name, acc, ip); - } - RFIFOSKIP (fd, 6); - } - return; - - case 0x2728: // We receive account_reg2 from a char-server, and we send them to other char-servers. - if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) - return; - { - int acc, p; - acc = RFIFOL (fd, 4); - for (i = 0; i < auth_num; i++) - { - if (auth_dat[i].account_id == acc) - { - unsigned char buf[RFIFOW (fd, 2) + 1]; - login_log - ("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d, ip: %s).\n", - server[id].name, acc, ip); - for (p = 8, j = 0; - p < RFIFOW (fd, 2) && j < ACCOUNT_REG2_NUM; - p += 36, j++) - { - memcpy (auth_dat[i].account_reg2[j].str, - RFIFOP (fd, p), 32); - auth_dat[i].account_reg2[j].str[31] = '\0'; - remove_control_chars (auth_dat[i].account_reg2 - [j].str); - auth_dat[i].account_reg2[j].value = - RFIFOL (fd, p + 32); - } - auth_dat[i].account_reg2_num = j; - // Sending information towards the other char-servers. - memcpy (WBUFP (buf, 0), RFIFOP (fd, 0), - RFIFOW (fd, 2)); - WBUFW (buf, 0) = 0x2729; - charif_sendallwos (fd, buf, WBUFW (buf, 2)); -// printf("parse_fromchar: receiving (from the char-server) of account_reg2 (account id: %d).\n", acc); - break; - } - } - if (i == auth_num) - { -// printf("parse_fromchar: receiving (from the char-server) of account_reg2 (unknwon account id: %d).\n", acc); - login_log - ("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d not found, ip: %s).\n", - server[id].name, acc, ip); - } - } - RFIFOSKIP (fd, RFIFOW (fd, 2)); - break; - - case 0x272a: // Receiving of map-server via char-server a unban resquest (by Yor) - if (RFIFOREST (fd) < 6) - return; - { - int acc; - acc = RFIFOL (fd, 2); - for (i = 0; i < auth_num; i++) - { - if (auth_dat[i].account_id == acc) - { - if (auth_dat[i].ban_until_time != 0) - { - auth_dat[i].ban_until_time = 0; - login_log - ("Char-server '%s': UnBan request (account: %d, ip: %s).\n", - server[id].name, acc, ip); - } - else - { - login_log - ("Char-server '%s': Error of UnBan request (account: %d, no change for unban date, ip: %s).\n", - server[id].name, acc, ip); - } - break; - } - } - if (i == auth_num) - { - login_log - ("Char-server '%s': Error of UnBan request (account: %d not found, ip: %s).\n", - server[id].name, acc, ip); - } - RFIFOSKIP (fd, 6); - } - return; - - // request from char-server to change account password - case 0x2740: // 0x2740 .L .24B .24B - if (RFIFOREST (fd) < 54) - return; - { - int acc; - char actual_pass[24], new_pass[24]; - acc = RFIFOL (fd, 2); - memcpy (actual_pass, RFIFOP (fd, 6), 24); - actual_pass[23] = '\0'; - remove_control_chars (actual_pass); - memcpy (new_pass, RFIFOP (fd, 30), 24); - new_pass[23] = '\0'; - remove_control_chars (new_pass); - - int status = 0; - - for (i = 0; i < auth_num; i++) - { - if (auth_dat[i].account_id == acc) - { - if (pass_ok (actual_pass, auth_dat[i].pass)) - { - if (strlen (new_pass) < 4) - status = 3; - else - { - status = 1; - strcpy (auth_dat[i].pass, MD5_saltcrypt(new_pass, make_salt())); - login_log - ("Char-server '%s': Change pass success (account: %d (%s), ip: %s.\n", - server[id].name, acc, - auth_dat[i].userid, ip); - } - } - else - { - status = 2; - login_log - ("Char-server '%s': Attempt to modify a pass failed, wrong password. (account: %d (%s), ip: %s).\n", - server[id].name, acc, - auth_dat[i].userid, ip); - } - break; - } - } - WFIFOW (fd, 0) = 0x2741; - WFIFOL (fd, 2) = acc; - WFIFOB (fd, 6) = status; // 0: acc not found, 1: success, 2: password mismatch, 3: pass too short - WFIFOSET (fd, 7); - } - - RFIFOSKIP (fd, 54); - break; - - default: - { - FILE *logfp; - char tmpstr[24]; - struct timeval tv; - logfp = fopen_ (login_log_unknown_packets_filename, "a"); - if (logfp) - { - gettimeofday (&tv, NULL); - strftime (tmpstr, 23, date_format, gmtime (&(tv.tv_sec))); - fprintf (logfp, - "%s.%03d: receiving of an unknown packet -> disconnection\n", - tmpstr, (int) tv.tv_usec / 1000); - fprintf (logfp, - "parse_fromchar: connection #%d (ip: %s), packet: 0x%x (with being read: %d).\n", - fd, ip, RFIFOW (fd, 0), RFIFOREST (fd)); - fprintf (logfp, "Detail (in hex):\n"); - fprintf (logfp, - "---- 00-01-02-03-04-05-06-07 08-09-0A-0B-0C-0D-0E-0F\n"); - memset (tmpstr, '\0', sizeof (tmpstr)); - for (i = 0; i < RFIFOREST (fd); i++) - { - if ((i & 15) == 0) - fprintf (logfp, "%04X ", i); - fprintf (logfp, "%02x ", RFIFOB (fd, i)); - if (RFIFOB (fd, i) > 0x1f) - tmpstr[i % 16] = RFIFOB (fd, i); - else - tmpstr[i % 16] = '.'; - if ((i - 7) % 16 == 0) // -8 + 1 - fprintf (logfp, " "); - else if ((i + 1) % 16 == 0) - { - fprintf (logfp, " %s\n", tmpstr); - memset (tmpstr, '\0', sizeof (tmpstr)); - } - } - if (i % 16 != 0) - { - for (j = i; j % 16 != 0; j++) - { - fprintf (logfp, " "); - if ((j - 7) % 16 == 0) // -8 + 1 - fprintf (logfp, " "); - } - fprintf (logfp, " %s\n", tmpstr); - } - fprintf (logfp, "\n"); - fclose_ (logfp); - } - } - printf - ("parse_fromchar: Unknown packet 0x%x (from a char-server)! -> disconnection.\n", - RFIFOW (fd, 0)); - session[fd]->eof = 1; - printf - ("Char-server has been disconnected (unknown packet).\n"); - return; - } - } - return; -} - -//--------------------------------------- -// Packet parsing for administation login -//--------------------------------------- -void parse_admin (int fd) -{ - int i, j; - unsigned char *p = (unsigned char *) &session[fd]->client_addr.sin_addr; - char *account_name; - char ip[16]; - - sprintf (ip, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); - - if (session[fd]->eof) - { - close (fd); - delete_session (fd); - printf ("Remote administration has disconnected (session #%d).\n", - fd); - return; - } - - while (RFIFOREST (fd) >= 2) - { - if (display_parse_admin == 1) - printf - ("parse_admin: connection #%d, packet: 0x%x (with being read: %d).\n", - fd, RFIFOW (fd, 0), RFIFOREST (fd)); - - switch (RFIFOW (fd, 0)) - { - case 0x7530: // Request of the server version - login_log ("'ladmin': Sending of the server version (ip: %s)\n", - ip); - WFIFOW (fd, 0) = 0x7531; - WFIFOB (fd, 2) = ATHENA_MAJOR_VERSION; - WFIFOB (fd, 3) = ATHENA_MINOR_VERSION; - WFIFOB (fd, 4) = ATHENA_REVISION; - WFIFOB (fd, 5) = ATHENA_RELEASE_FLAG; - WFIFOB (fd, 6) = ATHENA_OFFICIAL_FLAG; - WFIFOB (fd, 7) = ATHENA_SERVER_LOGIN; - WFIFOW (fd, 8) = ATHENA_MOD_VERSION; - WFIFOSET (fd, 10); - RFIFOSKIP (fd, 2); - break; - - case 0x7532: // Request of end of connection - login_log ("'ladmin': End of connection (ip: %s)\n", - ip); - RFIFOSKIP (fd, 2); - session[fd]->eof = 1; - break; - - case 0x7920: // Request of an accounts list - if (RFIFOREST (fd) < 10) - return; - { - int st, ed, len; - int id[auth_num]; - st = RFIFOL (fd, 2); - ed = RFIFOL (fd, 6); - RFIFOSKIP (fd, 10); - WFIFOW (fd, 0) = 0x7921; - if (st < 0) - st = 0; - if (ed > END_ACCOUNT_NUM || ed < st || ed <= 0) - ed = END_ACCOUNT_NUM; - login_log - ("'ladmin': Sending an accounts list (ask: from %d to %d, ip: %s)\n", - st, ed, ip); - // Sort before send - for (i = 0; i < auth_num; i++) - { - int k; - id[i] = i; - for (j = 0; j < i; j++) - { - if (auth_dat[id[i]].account_id < - auth_dat[id[j]].account_id) - { - for (k = i; k > j; k--) - { - id[k] = id[k - 1]; - } - id[j] = i; // id[i] - break; - } - } - } - // Sending accounts information - len = 4; - for (i = 0; i < auth_num && len < 30000; i++) - { - int account_id = auth_dat[id[i]].account_id; // use sorted index - if (account_id >= st && account_id <= ed) - { - j = id[i]; - WFIFOL (fd, len) = account_id; - WFIFOB (fd, len + 4) = - (unsigned char) isGM (account_id); - memcpy (WFIFOP (fd, len + 5), auth_dat[j].userid, - 24); - WFIFOB (fd, len + 29) = auth_dat[j].sex; - WFIFOL (fd, len + 30) = auth_dat[j].logincount; - if (auth_dat[j].state == 0 && auth_dat[j].ban_until_time != 0) // if no state and banished - WFIFOL (fd, len + 34) = 7; // 6 = Your are Prohibited to log in until %s - else - WFIFOL (fd, len + 34) = auth_dat[j].state; - len += 38; - } - } - WFIFOW (fd, 2) = len; - WFIFOSET (fd, len); - } - break; - - case 0x7924: - { // [Fate] Itemfrob package: change item IDs - if (RFIFOREST (fd) < 10) - return; - charif_sendallwos (-1, RFIFOP (fd, 0), 10); // forward package to char servers - RFIFOSKIP (fd, 10); - WFIFOW (fd, 0) = 0x7925; - WFIFOSET (fd, 2); - break; - } - - case 0x7930: // Request for an account creation - if (RFIFOREST (fd) < 91) - return; - { - struct mmo_account ma; - ma.userid = RFIFOP (fd, 2); - ma.passwd = RFIFOP (fd, 26); - memcpy (ma.lastlogin, "-", 2); - ma.sex = RFIFOB (fd, 50); - WFIFOW (fd, 0) = 0x7931; - WFIFOL (fd, 2) = -1; - memcpy (WFIFOP (fd, 6), RFIFOP (fd, 2), 24); - if (strlen (ma.userid) > 23 || strlen (ma.passwd) > 23) - { - login_log - ("'ladmin': Attempt to create an invalid account (account or pass is too long, ip: %s)\n", - ip); - } - else if (strlen (ma.userid) < 4 || strlen (ma.passwd) < 4) - { - login_log - ("'ladmin': Attempt to create an invalid account (account or pass is too short, ip: %s)\n", - ip); - } - else if (ma.sex != 'F' && ma.sex != 'M') - { - login_log - ("'ladmin': Attempt to create an invalid account (account: %s, invalid sex, ip: %s)\n", - ma.userid, ip); - } - else if (account_id_count > END_ACCOUNT_NUM) - { - login_log - ("'ladmin': Attempt to create an account, but there is no more available id number (account: %s, sex: %c, ip: %s)\n", - ma.userid, ma.sex, ip); - } - else - { - remove_control_chars (ma.userid); - remove_control_chars (ma.passwd); - for (i = 0; i < auth_num; i++) - { - if (strncmp (auth_dat[i].userid, ma.userid, 24) == - 0) - { - login_log - ("'ladmin': Attempt to create an already existing account (account: %s ip: %s)\n", - auth_dat[i].userid, ip); - break; - } - } - if (i == auth_num) - { - int new_id; - char email[40]; - memcpy (email, RFIFOP (fd, 51), 40); - email[39] = '\0'; - remove_control_chars (email); - new_id = mmo_auth_new (&ma, ma.sex, email); - login_log - ("'ladmin': Account creation (account: %s (id: %d), sex: %c, email: %s, ip: %s)\n", - ma.userid, new_id, - ma.sex, auth_dat[i].email, ip); - WFIFOL (fd, 2) = new_id; - } - } - WFIFOSET (fd, 30); - RFIFOSKIP (fd, 91); - } - break; - - case 0x7932: // Request for an account deletion - if (RFIFOREST (fd) < 26) - return; - WFIFOW (fd, 0) = 0x7933; - WFIFOL (fd, 2) = -1; - account_name = RFIFOP (fd, 2); - account_name[23] = '\0'; - remove_control_chars (account_name); - i = search_account_index (account_name); - if (i != -1) - { - // Char-server is notified of deletion (for characters deletion). - unsigned char buf[65535]; - WBUFW (buf, 0) = 0x2730; - WBUFL (buf, 2) = auth_dat[i].account_id; - charif_sendallwos (-1, buf, 6); - // send answer - memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); - WFIFOL (fd, 2) = auth_dat[i].account_id; - // save deleted account in log file - login_log - ("'ladmin': Account deletion (account: %s, id: %d, ip: %s) - saved in next line:\n", - auth_dat[i].userid, auth_dat[i].account_id, - ip); - mmo_auth_tostr (buf, &auth_dat[i]); - login_log ("%s\n", buf); - // delete account - memset (auth_dat[i].userid, '\0', - sizeof (auth_dat[i].userid)); - auth_dat[i].account_id = -1; - } - else - { - memcpy (WFIFOP (fd, 6), account_name, 24); - login_log - ("'ladmin': Attempt to delete an unknown account (account: %s, ip: %s)\n", - account_name, ip); - } - WFIFOSET (fd, 30); - RFIFOSKIP (fd, 26); - break; - - case 0x7934: // Request to change a password - if (RFIFOREST (fd) < 50) - return; - WFIFOW (fd, 0) = 0x7935; - WFIFOL (fd, 2) = -1; - account_name = RFIFOP (fd, 2); - account_name[23] = '\0'; - remove_control_chars (account_name); - i = search_account_index (account_name); - if (i != -1) - { - memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); - strcpy (auth_dat[i].pass, MD5_saltcrypt(RFIFOP (fd, 26), make_salt())); - auth_dat[i].pass[39] = '\0'; - WFIFOL (fd, 2) = auth_dat[i].account_id; - login_log - ("'ladmin': Modification of a password (account: %s, new password: %s, ip: %s)\n", - auth_dat[i].userid, auth_dat[i].pass, ip); - } - else - { - memcpy (WFIFOP (fd, 6), account_name, 24); - login_log - ("'ladmin': Attempt to modify the password of an unknown account (account: %s, ip: %s)\n", - account_name, ip); - } - WFIFOSET (fd, 30); - RFIFOSKIP (fd, 50); - break; - - case 0x7936: // Request to modify a state - if (RFIFOREST (fd) < 50) - return; - { - char error_message[20]; - int statut; - WFIFOW (fd, 0) = 0x7937; - WFIFOL (fd, 2) = -1; - account_name = RFIFOP (fd, 2); - account_name[23] = '\0'; - remove_control_chars (account_name); - statut = RFIFOL (fd, 26); - memcpy (error_message, RFIFOP (fd, 30), 20); - error_message[19] = '\0'; - remove_control_chars (error_message); - if (statut != 7 || error_message[0] == '\0') - { // 7: // 6 = Your are Prohibited to log in until %s - strcpy (error_message, "-"); - } - i = search_account_index (account_name); - if (i != -1) - { - memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); - WFIFOL (fd, 2) = auth_dat[i].account_id; - if (auth_dat[i].state == statut - && strcmp (auth_dat[i].error_message, - error_message) == 0) - login_log - ("'ladmin': Modification of a state, but the state of the account is already the good state (account: %s, received state: %d, ip: %s)\n", - account_name, statut, ip); - else - { - if (statut == 7) - login_log - ("'ladmin': Modification of a state (account: %s, new state: %d - prohibited to login until '%s', ip: %s)\n", - auth_dat[i].userid, statut, - error_message, ip); - else - login_log - ("'ladmin': Modification of a state (account: %s, new state: %d, ip: %s)\n", - auth_dat[i].userid, statut, ip); - if (auth_dat[i].state == 0) - { - unsigned char buf[16]; - WBUFW (buf, 0) = 0x2731; - WBUFL (buf, 2) = auth_dat[i].account_id; - WBUFB (buf, 6) = 0; // 0: change of statut, 1: ban - WBUFL (buf, 7) = statut; // status or final date of a banishment - charif_sendallwos (-1, buf, 11); - for (j = 0; j < AUTH_FIFO_SIZE; j++) - if (auth_fifo[j].account_id == - auth_dat[i].account_id) - auth_fifo[j].login_id1++; // to avoid reconnection error when come back from map-server (char-server will ask again the authentification) - } - auth_dat[i].state = statut; - memcpy (auth_dat[i].error_message, error_message, - 20); - } - } - else - { - memcpy (WFIFOP (fd, 6), account_name, 24); - login_log - ("'ladmin': Attempt to modify the state of an unknown account (account: %s, received state: %d, ip: %s)\n", - account_name, statut, ip); - } - WFIFOL (fd, 30) = statut; - } - WFIFOSET (fd, 34); - RFIFOSKIP (fd, 50); - break; - - case 0x7938: // Request for servers list and # of online players - login_log ("'ladmin': Sending of servers list (ip: %s)\n", ip); - server_num = 0; - for (i = 0; i < MAX_SERVERS; i++) - { - if (server_fd[i] >= 0) - { - WFIFOL (fd, 4 + server_num * 32) = server[i].ip; - WFIFOW (fd, 4 + server_num * 32 + 4) = server[i].port; - memcpy (WFIFOP (fd, 4 + server_num * 32 + 6), - server[i].name, 20); - WFIFOW (fd, 4 + server_num * 32 + 26) = - server[i].users; - WFIFOW (fd, 4 + server_num * 32 + 28) = - server[i].maintenance; - WFIFOW (fd, 4 + server_num * 32 + 30) = server[i].is_new; - server_num++; - } - } - WFIFOW (fd, 0) = 0x7939; - WFIFOW (fd, 2) = 4 + 32 * server_num; - WFIFOSET (fd, 4 + 32 * server_num); - RFIFOSKIP (fd, 2); - break; - - case 0x793a: // Request to password check - if (RFIFOREST (fd) < 50) - return; - WFIFOW (fd, 0) = 0x793b; - WFIFOL (fd, 2) = -1; - account_name = RFIFOP (fd, 2); - account_name[23] = '\0'; - remove_control_chars (account_name); - i = search_account_index (account_name); - if (i != -1) - { - memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); - if ( pass_ok(RFIFOP (fd, 26), auth_dat[i].pass) ) - { - WFIFOL (fd, 2) = auth_dat[i].account_id; - login_log - ("'ladmin': Check of password OK (account: %s, password: %s, ip: %s)\n", - auth_dat[i].userid, auth_dat[i].pass, - ip); - } - else - { - char pass[24]; - memcpy (pass, RFIFOP (fd, 26), 24); - pass[23] = '\0'; - remove_control_chars (pass); - login_log - ("'ladmin': Failure of password check (account: %s, proposed pass: %s, ip: %s)\n", - auth_dat[i].userid, pass, ip); - } - } - else - { - memcpy (WFIFOP (fd, 6), account_name, 24); - login_log - ("'ladmin': Attempt to check the password of an unknown account (account: %s, ip: %s)\n", - account_name, ip); - } - WFIFOSET (fd, 30); - RFIFOSKIP (fd, 50); - break; - - case 0x793c: // Request to modify sex - if (RFIFOREST (fd) < 27) - return; - WFIFOW (fd, 0) = 0x793d; - WFIFOL (fd, 2) = -1; - account_name = RFIFOP (fd, 2); - account_name[23] = '\0'; - remove_control_chars (account_name); - memcpy (WFIFOP (fd, 6), account_name, 24); - { - char sex; - sex = RFIFOB (fd, 26); - if (sex != 'F' && sex != 'M') - { - if (sex > 31) - login_log - ("'ladmin': Attempt to give an invalid sex (account: %s, received sex: %c, ip: %s)\n", - account_name, sex, ip); - else - login_log - ("'ladmin': Attempt to give an invalid sex (account: %s, received sex: 'control char', ip: %s)\n", - account_name, ip); - } - else - { - i = search_account_index (account_name); - if (i != -1) - { - memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); - if (auth_dat[i].sex != - ((sex == 'S' || sex == 's') ? 2 : (sex == 'M' - || sex == - 'm'))) - { - unsigned char buf[16]; - WFIFOL (fd, 2) = auth_dat[i].account_id; - for (j = 0; j < AUTH_FIFO_SIZE; j++) - if (auth_fifo[j].account_id == - auth_dat[i].account_id) - auth_fifo[j].login_id1++; // to avoid reconnection error when come back from map-server (char-server will ask again the authentification) - auth_dat[i].sex = (sex == 'S' - || sex == - 's') ? 2 : (sex == 'M' - || sex == 'm'); - login_log - ("'ladmin': Modification of a sex (account: %s, new sex: %c, ip: %s)\n", - auth_dat[i].userid, sex, ip); - // send to all char-server the change - WBUFW (buf, 0) = 0x2723; - WBUFL (buf, 2) = auth_dat[i].account_id; - WBUFB (buf, 6) = auth_dat[i].sex; - charif_sendallwos (-1, buf, 7); - } - else - { - login_log - ("'ladmin': Modification of a sex, but the sex is already the good sex (account: %s, sex: %c, ip: %s)\n", - auth_dat[i].userid, sex, ip); - } - } - else - { - login_log - ("'ladmin': Attempt to modify the sex of an unknown account (account: %s, received sex: %c, ip: %s)\n", - account_name, sex, ip); - } - } - } - WFIFOSET (fd, 30); - RFIFOSKIP (fd, 27); - break; - - case 0x793e: // Request to modify GM level - if (RFIFOREST (fd) < 27) - return; - WFIFOW (fd, 0) = 0x793f; - WFIFOL (fd, 2) = -1; - account_name = RFIFOP (fd, 2); - account_name[23] = '\0'; - remove_control_chars (account_name); - memcpy (WFIFOP (fd, 6), account_name, 24); - { - char new_gm_level; - new_gm_level = RFIFOB (fd, 26); - if (new_gm_level < 0 || new_gm_level > 99) - { - login_log - ("'ladmin': Attempt to give an invalid GM level (account: %s, received GM level: %d, ip: %s)\n", - account_name, (int) new_gm_level, ip); - } - else - { - i = search_account_index (account_name); - if (i != -1) - { - int acc = auth_dat[i].account_id; - memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); - if (isGM (acc) != new_gm_level) - { - // modification of the file - FILE *fp, *fp2; - int lock; - char line[512]; - int GM_account, GM_level; - int modify_flag; - char tmpstr[24]; - struct timeval tv; - if ((fp2 = - lock_fopen (GM_account_filename, - &lock)) != NULL) - { - if ((fp = - fopen_ (GM_account_filename, - "r")) != NULL) - { - gettimeofday (&tv, NULL); - strftime (tmpstr, 23, date_format, - gmtime (&(tv.tv_sec))); - modify_flag = 0; - // read/write GM file - while (fgets - (line, sizeof (line) - 1, fp)) - { - while (line[0] != '\0' - && (line[strlen (line) - 1] - == '\n' - || line[strlen (line) - - 1] == '\r')) - line[strlen (line) - 1] = - '\0'; - if ((line[0] == '/' - && line[1] == '/') - || line[0] == '\0') - fprintf (fp2, "%s\n", - line); - else - { - if (sscanf - (line, "%d %d", - &GM_account, - &GM_level) != 2 - && sscanf (line, "%d: %d", - &GM_account, - &GM_level) != - 2) - fprintf (fp2, - "%s\n", - line); - else if (GM_account != acc) - fprintf (fp2, - "%s\n", - line); - else if (new_gm_level < 1) - { - fprintf (fp2, - "// %s: 'ladmin' GM level removed on account %d '%s' (previous level: %d)\n//%d %d\n", - tmpstr, - acc, - auth_dat - [i].userid, - GM_level, acc, - new_gm_level); - modify_flag = 1; - } - else - { - fprintf (fp2, - "// %s: 'ladmin' GM level on account %d '%s' (previous level: %d)\n%d %d\n", - tmpstr, - acc, - auth_dat - [i].userid, - GM_level, acc, - new_gm_level); - modify_flag = 1; - } - } - } - if (modify_flag == 0) - fprintf (fp2, - "// %s: 'ladmin' GM level on account %d '%s' (previous level: 0)\n%d %d\n", - tmpstr, acc, - auth_dat[i].userid, acc, - new_gm_level); - fclose_ (fp); - } - else - { - login_log - ("'ladmin': Attempt to modify of a GM level - impossible to read GM accounts file (account: %s (%d), received GM level: %d, ip: %s)\n", - auth_dat[i].userid, acc, - (int) new_gm_level, ip); - } - lock_fclose(fp2, GM_account_filename, &lock); - WFIFOL (fd, 2) = acc; - login_log - ("'ladmin': Modification of a GM level (account: %s (%d), new GM level: %d, ip: %s)\n", - auth_dat[i].userid, acc, - (int) new_gm_level, ip); - // read and send new GM informations - read_gm_account (); - send_GM_accounts (); - } - else - { - login_log - ("'ladmin': Attempt to modify of a GM level - impossible to write GM accounts file (account: %s (%d), received GM level: %d, ip: %s)\n", - auth_dat[i].userid, acc, - (int) new_gm_level, ip); - } - } - else - { - login_log - ("'ladmin': Attempt to modify of a GM level, but the GM level is already the good GM level (account: %s (%d), GM level: %d, ip: %s)\n", - auth_dat[i].userid, acc, - (int) new_gm_level, ip); - } - } - else - { - login_log - ("'ladmin': Attempt to modify the GM level of an unknown account (account: %s, received GM level: %d, ip: %s)\n", - account_name, (int) new_gm_level, - ip); - } - } - } - WFIFOSET (fd, 30); - RFIFOSKIP (fd, 27); - break; - - case 0x7940: // Request to modify e-mail - if (RFIFOREST (fd) < 66) - return; - WFIFOW (fd, 0) = 0x7941; - WFIFOL (fd, 2) = -1; - account_name = RFIFOP (fd, 2); - account_name[23] = '\0'; - remove_control_chars (account_name); - memcpy (WFIFOP (fd, 6), account_name, 24); - { - char email[40]; - memcpy (email, RFIFOP (fd, 26), 40); - if (e_mail_check (email) == 0) - { - login_log - ("'ladmin': Attempt to give an invalid e-mail (account: %s, ip: %s)\n", - account_name, ip); - } - else - { - remove_control_chars (email); - i = search_account_index (account_name); - if (i != -1) - { - memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); - memcpy (auth_dat[i].email, email, 40); - WFIFOL (fd, 2) = auth_dat[i].account_id; - login_log - ("'ladmin': Modification of an email (account: %s, new e-mail: %s, ip: %s)\n", - auth_dat[i].userid, email, ip); - } - else - { - login_log - ("'ladmin': Attempt to modify the e-mail of an unknown account (account: %s, received e-mail: %s, ip: %s)\n", - account_name, email, ip); - } - } - } - WFIFOSET (fd, 30); - RFIFOSKIP (fd, 66); - break; - - case 0x7942: // Request to modify memo field - if (RFIFOREST (fd) < 28 - || RFIFOREST (fd) < (28 + RFIFOW (fd, 26))) - return; - WFIFOW (fd, 0) = 0x7943; - WFIFOL (fd, 2) = -1; - account_name = RFIFOP (fd, 2); - account_name[23] = '\0'; - remove_control_chars (account_name); - i = search_account_index (account_name); - if (i != -1) - { - int size_of_memo = sizeof (auth_dat[i].memo); - memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); - memset (auth_dat[i].memo, '\0', size_of_memo); - if (RFIFOW (fd, 26) == 0) - { - strncpy (auth_dat[i].memo, "!", size_of_memo); - } - else if (RFIFOW (fd, 26) > size_of_memo - 1) - { - memcpy (auth_dat[i].memo, RFIFOP (fd, 28), - size_of_memo - 1); - } - else - { - memcpy (auth_dat[i].memo, RFIFOP (fd, 28), - RFIFOW (fd, 26)); - } - auth_dat[i].memo[size_of_memo - 1] = '\0'; - remove_control_chars (auth_dat[i].memo); - WFIFOL (fd, 2) = auth_dat[i].account_id; - login_log - ("'ladmin': Modification of a memo field (account: %s, new memo: %s, ip: %s)\n", - auth_dat[i].userid, auth_dat[i].memo, ip); - } - else - { - memcpy (WFIFOP (fd, 6), account_name, 24); - login_log - ("'ladmin': Attempt to modify the memo field of an unknown account (account: %s, ip: %s)\n", - account_name, ip); - } - WFIFOSET (fd, 30); - RFIFOSKIP (fd, 28 + RFIFOW (fd, 26)); - break; - - case 0x7944: // Request to found an account id - if (RFIFOREST (fd) < 26) - return; - WFIFOW (fd, 0) = 0x7945; - WFIFOL (fd, 2) = -1; - account_name = RFIFOP (fd, 2); - account_name[23] = '\0'; - remove_control_chars (account_name); - i = search_account_index (account_name); - if (i != -1) - { - memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); - WFIFOL (fd, 2) = auth_dat[i].account_id; - login_log - ("'ladmin': Request (by the name) of an account id (account: %s, id: %d, ip: %s)\n", - auth_dat[i].userid, auth_dat[i].account_id, - ip); - } - else - { - memcpy (WFIFOP (fd, 6), account_name, 24); - login_log - ("'ladmin': ID request (by the name) of an unknown account (account: %s, ip: %s)\n", - account_name, ip); - } - WFIFOSET (fd, 30); - RFIFOSKIP (fd, 26); - break; - - case 0x7946: // Request to found an account name - if (RFIFOREST (fd) < 6) - return; - WFIFOW (fd, 0) = 0x7947; - WFIFOL (fd, 2) = RFIFOL (fd, 2); - memset (WFIFOP (fd, 6), '\0', 24); - for (i = 0; i < auth_num; i++) - { - if (auth_dat[i].account_id == RFIFOL (fd, 2)) - { - strncpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); - login_log - ("'ladmin': Request (by id) of an account name (account: %s, id: %d, ip: %s)\n", - auth_dat[i].userid, RFIFOL (fd, 2), ip); - break; - } - } - if (i == auth_num) - { - login_log - ("'ladmin': Name request (by id) of an unknown account (id: %d, ip: %s)\n", - RFIFOL (fd, 2), ip); - strncpy (WFIFOP (fd, 6), "", 24); - } - WFIFOSET (fd, 30); - RFIFOSKIP (fd, 6); - break; - - case 0x7948: // Request to change the validity limit (timestamp) (absolute value) - if (RFIFOREST (fd) < 30) - return; - { - time_t timestamp; - char tmpstr[2048]; - WFIFOW (fd, 0) = 0x7949; - WFIFOL (fd, 2) = -1; - account_name = RFIFOP (fd, 2); - account_name[23] = '\0'; - remove_control_chars (account_name); - timestamp = (time_t) RFIFOL (fd, 26); - strftime (tmpstr, 24, date_format, gmtime (×tamp)); - i = search_account_index (account_name); - if (i != -1) - { - memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); - login_log - ("'ladmin': Change of a validity limit (account: %s, new validity: %d (%s), ip: %s)\n", - auth_dat[i].userid, timestamp, - (timestamp == 0 ? "unlimited" : tmpstr), ip); - auth_dat[i].connect_until_time = timestamp; - WFIFOL (fd, 2) = auth_dat[i].account_id; - } - else - { - memcpy (WFIFOP (fd, 6), account_name, 24); - login_log - ("'ladmin': Attempt to change the validity limit of an unknown account (account: %s, received validity: %d (%s), ip: %s)\n", account_name, timestamp, - (timestamp == 0 ? "unlimited" : tmpstr), ip); - } - WFIFOL (fd, 30) = timestamp; - } - WFIFOSET (fd, 34); - RFIFOSKIP (fd, 30); - break; - - case 0x794a: // Request to change the final date of a banishment (timestamp) (absolute value) - if (RFIFOREST (fd) < 30) - return; - { - time_t timestamp; - char tmpstr[2048]; - WFIFOW (fd, 0) = 0x794b; - WFIFOL (fd, 2) = -1; - account_name = RFIFOP (fd, 2); - account_name[23] = '\0'; - remove_control_chars (account_name); - timestamp = (time_t) RFIFOL (fd, 26); - if (timestamp <= time (NULL)) - timestamp = 0; - strftime (tmpstr, 24, date_format, gmtime (×tamp)); - i = search_account_index (account_name); - if (i != -1) - { - memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); - WFIFOL (fd, 2) = auth_dat[i].account_id; - login_log - ("'ladmin': Change of the final date of a banishment (account: %s, new final date of banishment: %d (%s), ip: %s)\n", - auth_dat[i].userid, timestamp, - (timestamp == 0 ? "no banishment" : tmpstr), ip); - if (auth_dat[i].ban_until_time != timestamp) - { - if (timestamp != 0) - { - unsigned char buf[16]; - WBUFW (buf, 0) = 0x2731; - WBUFL (buf, 2) = auth_dat[i].account_id; - WBUFB (buf, 6) = 1; // 0: change of statut, 1: ban - WBUFL (buf, 7) = timestamp; // status or final date of a banishment - charif_sendallwos (-1, buf, 11); - for (j = 0; j < AUTH_FIFO_SIZE; j++) - if (auth_fifo[j].account_id == - auth_dat[i].account_id) - auth_fifo[j].login_id1++; // to avoid reconnection error when come back from map-server (char-server will ask again the authentification) - } - auth_dat[i].ban_until_time = timestamp; - } - } - else - { - memcpy (WFIFOP (fd, 6), account_name, 24); - login_log - ("'ladmin': Attempt to change the final date of a banishment of an unknown account (account: %s, received final date of banishment: %d (%s), ip: %s)\n", - account_name, timestamp, - (timestamp == 0 ? "no banishment" : tmpstr), ip); - } - WFIFOL (fd, 30) = timestamp; - } - WFIFOSET (fd, 34); - RFIFOSKIP (fd, 30); - break; - - case 0x794c: // Request to change the final date of a banishment (timestamp) (relative change) - if (RFIFOREST (fd) < 38) - return; - { - time_t timestamp; - struct tm *tmtime; - char tmpstr[2048]; - WFIFOW (fd, 0) = 0x794d; - WFIFOL (fd, 2) = -1; - account_name = RFIFOP (fd, 2); - account_name[23] = '\0'; - remove_control_chars (account_name); - i = search_account_index (account_name); - if (i != -1) - { - WFIFOL (fd, 2) = auth_dat[i].account_id; - memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); - if (auth_dat[i].ban_until_time == 0 - || auth_dat[i].ban_until_time < time (NULL)) - timestamp = time (NULL); - else - timestamp = auth_dat[i].ban_until_time; - tmtime = gmtime (×tamp); - tmtime->tm_year = - tmtime->tm_year + (short) RFIFOW (fd, 26); - tmtime->tm_mon = - tmtime->tm_mon + (short) RFIFOW (fd, 28); - tmtime->tm_mday = - tmtime->tm_mday + (short) RFIFOW (fd, 30); - tmtime->tm_hour = - tmtime->tm_hour + (short) RFIFOW (fd, 32); - tmtime->tm_min = - tmtime->tm_min + (short) RFIFOW (fd, 34); - tmtime->tm_sec = - tmtime->tm_sec + (short) RFIFOW (fd, 36); - timestamp = mktime (tmtime); - if (timestamp != -1) - { - if (timestamp <= time (NULL)) - timestamp = 0; - strftime (tmpstr, 24, date_format, - gmtime (×tamp)); - login_log - ("'ladmin': Adjustment of a final date of a banishment (account: %s, (%+d y %+d m %+d d %+d h %+d mn %+d s) -> new validity: %d (%s), ip: %s)\n", - auth_dat[i].userid, - (short) RFIFOW (fd, 26), (short) RFIFOW (fd, - 28), - (short) RFIFOW (fd, 30), (short) RFIFOW (fd, - 32), - (short) RFIFOW (fd, 34), (short) RFIFOW (fd, - 36), - timestamp, - (timestamp == 0 ? "no banishment" : tmpstr), - ip); - if (auth_dat[i].ban_until_time != timestamp) - { - if (timestamp != 0) - { - unsigned char buf[16]; - WBUFW (buf, 0) = 0x2731; - WBUFL (buf, 2) = auth_dat[i].account_id; - WBUFB (buf, 6) = 1; // 0: change of statut, 1: ban - WBUFL (buf, 7) = timestamp; // status or final date of a banishment - charif_sendallwos (-1, buf, 11); - for (j = 0; j < AUTH_FIFO_SIZE; j++) - if (auth_fifo[j].account_id == - auth_dat[i].account_id) - auth_fifo[j].login_id1++; // to avoid reconnection error when come back from map-server (char-server will ask again the authentification) - } - auth_dat[i].ban_until_time = timestamp; - } - } - else - { - strftime (tmpstr, 24, date_format, - gmtime (&auth_dat[i].ban_until_time)); - login_log - ("'ladmin': Impossible to adjust the final date of a banishment (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", - auth_dat[i].userid, - auth_dat[i].ban_until_time, - (auth_dat[i].ban_until_time == - 0 ? "no banishment" : tmpstr), - (short) RFIFOW (fd, 26), (short) RFIFOW (fd, - 28), - (short) RFIFOW (fd, 30), (short) RFIFOW (fd, - 32), - (short) RFIFOW (fd, 34), (short) RFIFOW (fd, - 36), - ip); - } - WFIFOL (fd, 30) = - (unsigned long) auth_dat[i].ban_until_time; - } - else - { - memcpy (WFIFOP (fd, 6), account_name, 24); - login_log - ("'ladmin': Attempt to adjust the final date of a banishment of an unknown account (account: %s, ip: %s)\n", - account_name, ip); - WFIFOL (fd, 30) = 0; - } - } - WFIFOSET (fd, 34); - RFIFOSKIP (fd, 38); - break; - - case 0x794e: // Request to send a broadcast message - if (RFIFOREST (fd) < 8 - || RFIFOREST (fd) < (8 + RFIFOL (fd, 4))) - return; - WFIFOW (fd, 0) = 0x794f; - WFIFOW (fd, 2) = -1; - if (RFIFOL (fd, 4) < 1) - { - login_log - ("'ladmin': Receiving a message for broadcast, but message is void (ip: %s)\n", - ip); - } - else - { - // at least 1 char-server - for (i = 0; i < MAX_SERVERS; i++) - if (server_fd[i] >= 0) - break; - if (i == MAX_SERVERS) - { - login_log - ("'ladmin': Receiving a message for broadcast, but no char-server is online (ip: %s)\n", - ip); - } - else - { - char buf[32000]; - char message[32000]; - WFIFOW (fd, 2) = 0; - memset (message, '\0', sizeof (message)); - memcpy (message, RFIFOP (fd, 8), RFIFOL (fd, 4)); - message[sizeof (message) - 1] = '\0'; - remove_control_chars (message); - if (RFIFOW (fd, 2) == 0) - login_log - ("'ladmin': Receiving a message for broadcast (message (in yellow): %s, ip: %s)\n", - message, ip); - else - login_log - ("'ladmin': Receiving a message for broadcast (message (in blue): %s, ip: %s)\n", - message, ip); - // send same message to all char-servers (no answer) - memcpy (WBUFP (buf, 0), RFIFOP (fd, 0), - 8 + RFIFOL (fd, 4)); - WBUFW (buf, 0) = 0x2726; - charif_sendallwos (-1, buf, 8 + RFIFOL (fd, 4)); - } - } - WFIFOSET (fd, 4); - RFIFOSKIP (fd, 8 + RFIFOL (fd, 4)); - break; - - case 0x7950: // Request to change the validity limite (timestamp) (relative change) - if (RFIFOREST (fd) < 38) - return; - { - time_t timestamp; - struct tm *tmtime; - char tmpstr[2048]; - char tmpstr2[2048]; - WFIFOW (fd, 0) = 0x7951; - WFIFOL (fd, 2) = -1; - account_name = RFIFOP (fd, 2); - account_name[23] = '\0'; - remove_control_chars (account_name); - i = search_account_index (account_name); - if (i != -1) - { - WFIFOL (fd, 2) = auth_dat[i].account_id; - memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); - timestamp = auth_dat[i].connect_until_time; - if (add_to_unlimited_account == 0 && timestamp == 0) - { - login_log - ("'ladmin': Attempt to adjust the validity limit of an unlimited account (account: %s, ip: %s)\n", - auth_dat[i].userid, ip); - WFIFOL (fd, 30) = 0; - } - else - { - if (timestamp == 0 || timestamp < time (NULL)) - timestamp = time (NULL); - tmtime = gmtime (×tamp); - tmtime->tm_year = - tmtime->tm_year + (short) RFIFOW (fd, 26); - tmtime->tm_mon = - tmtime->tm_mon + (short) RFIFOW (fd, 28); - tmtime->tm_mday = - tmtime->tm_mday + (short) RFIFOW (fd, 30); - tmtime->tm_hour = - tmtime->tm_hour + (short) RFIFOW (fd, 32); - tmtime->tm_min = - tmtime->tm_min + (short) RFIFOW (fd, 34); - tmtime->tm_sec = - tmtime->tm_sec + (short) RFIFOW (fd, 36); - timestamp = mktime (tmtime); - if (timestamp != -1) - { - strftime (tmpstr, 24, date_format, - gmtime (&auth_dat - [i].connect_until_time)); - strftime (tmpstr2, 24, date_format, - gmtime (×tamp)); - login_log - ("'ladmin': Adjustment of a validity limit (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> new validity: %d (%s), ip: %s)\n", - auth_dat[i].userid, - auth_dat[i].connect_until_time, - (auth_dat[i].connect_until_time == - 0 ? "unlimited" : tmpstr), - (short) RFIFOW (fd, 26), - (short) RFIFOW (fd, 28), - (short) RFIFOW (fd, 30), - (short) RFIFOW (fd, 32), - (short) RFIFOW (fd, 34), - (short) RFIFOW (fd, 36), timestamp, - (timestamp == 0 ? "unlimited" : tmpstr2), - ip); - auth_dat[i].connect_until_time = timestamp; - WFIFOL (fd, 30) = - (unsigned long) - auth_dat[i].connect_until_time; - } - else - { - strftime (tmpstr, 24, date_format, - gmtime (&auth_dat - [i].connect_until_time)); - login_log - ("'ladmin': Impossible to adjust a validity limit (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", - auth_dat[i].userid, - auth_dat[i].connect_until_time, - (auth_dat[i].connect_until_time == - 0 ? "unlimited" : tmpstr), - (short) RFIFOW (fd, 26), - (short) RFIFOW (fd, 28), - (short) RFIFOW (fd, 30), - (short) RFIFOW (fd, 32), - (short) RFIFOW (fd, 34), - (short) RFIFOW (fd, 36), ip); - WFIFOL (fd, 30) = 0; - } - } - } - else - { - memcpy (WFIFOP (fd, 6), account_name, 24); - login_log - ("'ladmin': Attempt to adjust the validity limit of an unknown account (account: %s, ip: %s)\n", - account_name, ip); - WFIFOL (fd, 30) = 0; - } - } - WFIFOSET (fd, 34); - RFIFOSKIP (fd, 38); - break; - - case 0x7952: // Request about informations of an account (by account name) - if (RFIFOREST (fd) < 26) - return; - WFIFOW (fd, 0) = 0x7953; - WFIFOL (fd, 2) = -1; - account_name = RFIFOP (fd, 2); - account_name[23] = '\0'; - remove_control_chars (account_name); - i = search_account_index (account_name); - if (i != -1) - { - WFIFOL (fd, 2) = auth_dat[i].account_id; - WFIFOB (fd, 6) = - (unsigned char) isGM (auth_dat[i].account_id); - memcpy (WFIFOP (fd, 7), auth_dat[i].userid, 24); - WFIFOB (fd, 31) = auth_dat[i].sex; - WFIFOL (fd, 32) = auth_dat[i].logincount; - WFIFOL (fd, 36) = auth_dat[i].state; - memcpy (WFIFOP (fd, 40), auth_dat[i].error_message, 20); - memcpy (WFIFOP (fd, 60), auth_dat[i].lastlogin, 24); - memcpy (WFIFOP (fd, 84), auth_dat[i].last_ip, 16); - memcpy (WFIFOP (fd, 100), auth_dat[i].email, 40); - WFIFOL (fd, 140) = - (unsigned long) auth_dat[i].connect_until_time; - WFIFOL (fd, 144) = - (unsigned long) auth_dat[i].ban_until_time; - WFIFOW (fd, 148) = strlen (auth_dat[i].memo); - if (auth_dat[i].memo[0]) - { - memcpy (WFIFOP (fd, 150), auth_dat[i].memo, - strlen (auth_dat[i].memo)); - } - login_log - ("'ladmin': Sending information of an account (request by the name; account: %s, id: %d, ip: %s)\n", - auth_dat[i].userid, auth_dat[i].account_id, - ip); - WFIFOSET (fd, 150 + strlen (auth_dat[i].memo)); - } - else - { - memcpy (WFIFOP (fd, 7), account_name, 24); - WFIFOW (fd, 148) = 0; - login_log - ("'ladmin': Attempt to obtain information (by the name) of an unknown account (account: %s, ip: %s)\n", - account_name, ip); - WFIFOSET (fd, 150); - } - RFIFOSKIP (fd, 26); - break; - - case 0x7954: // Request about information of an account (by account id) - if (RFIFOREST (fd) < 6) - return; - WFIFOW (fd, 0) = 0x7953; - WFIFOL (fd, 2) = RFIFOL (fd, 2); - memset (WFIFOP (fd, 7), '\0', 24); - for (i = 0; i < auth_num; i++) - { - if (auth_dat[i].account_id == RFIFOL (fd, 2)) - { - login_log - ("'ladmin': Sending information of an account (request by the id; account: %s, id: %d, ip: %s)\n", - auth_dat[i].userid, RFIFOL (fd, 2), ip); - WFIFOB (fd, 6) = - (unsigned char) isGM (auth_dat[i].account_id); - memcpy (WFIFOP (fd, 7), auth_dat[i].userid, 24); - WFIFOB (fd, 31) = auth_dat[i].sex; - WFIFOL (fd, 32) = auth_dat[i].logincount; - WFIFOL (fd, 36) = auth_dat[i].state; - memcpy (WFIFOP (fd, 40), auth_dat[i].error_message, - 20); - memcpy (WFIFOP (fd, 60), auth_dat[i].lastlogin, 24); - memcpy (WFIFOP (fd, 84), auth_dat[i].last_ip, 16); - memcpy (WFIFOP (fd, 100), auth_dat[i].email, 40); - WFIFOL (fd, 140) = - (unsigned long) auth_dat[i].connect_until_time; - WFIFOL (fd, 144) = - (unsigned long) auth_dat[i].ban_until_time; - WFIFOW (fd, 148) = strlen (auth_dat[i].memo); - if (auth_dat[i].memo[0]) - { - memcpy (WFIFOP (fd, 150), auth_dat[i].memo, - strlen (auth_dat[i].memo)); - } - WFIFOSET (fd, 150 + strlen (auth_dat[i].memo)); - break; - } - } - if (i == auth_num) - { - login_log - ("'ladmin': Attempt to obtain information (by the id) of an unknown account (id: %d, ip: %s)\n", - RFIFOL (fd, 2), ip); - strncpy (WFIFOP (fd, 7), "", 24); - WFIFOW (fd, 148) = 0; - WFIFOSET (fd, 150); - } - RFIFOSKIP (fd, 6); - break; - - case 0x7955: // Request to reload GM file (no answer) - login_log - ("'ladmin': Request to re-load GM configuration file (ip: %s).\n", - ip); - read_gm_account (); - // send GM accounts to all char-servers - send_GM_accounts (); - RFIFOSKIP (fd, 2); - break; - - default: - { - FILE *logfp; - char tmpstr[24]; - struct timeval tv; - logfp = fopen_ (login_log_unknown_packets_filename, "a"); - if (logfp) - { - gettimeofday (&tv, NULL); - strftime (tmpstr, 23, date_format, gmtime (&(tv.tv_sec))); - fprintf (logfp, - "%s.%03d: receiving of an unknown packet -> disconnection\n", - tmpstr, (int) tv.tv_usec / 1000); - fprintf (logfp, - "parse_admin: connection #%d (ip: %s), packet: 0x%x (with being read: %d).\n", - fd, ip, RFIFOW (fd, 0), RFIFOREST (fd)); - fprintf (logfp, "Detail (in hex):\n"); - fprintf (logfp, - "---- 00-01-02-03-04-05-06-07 08-09-0A-0B-0C-0D-0E-0F\n"); - memset (tmpstr, '\0', sizeof (tmpstr)); - for (i = 0; i < RFIFOREST (fd); i++) - { - if ((i & 15) == 0) - fprintf (logfp, "%04X ", i); - fprintf (logfp, "%02x ", RFIFOB (fd, i)); - if (RFIFOB (fd, i) > 0x1f) - tmpstr[i % 16] = RFIFOB (fd, i); - else - tmpstr[i % 16] = '.'; - if ((i - 7) % 16 == 0) // -8 + 1 - fprintf (logfp, " "); - else if ((i + 1) % 16 == 0) - { - fprintf (logfp, " %s\n", tmpstr); - memset (tmpstr, '\0', sizeof (tmpstr)); - } - } - if (i % 16 != 0) - { - for (j = i; j % 16 != 0; j++) - { - fprintf (logfp, " "); - if ((j - 7) % 16 == 0) // -8 + 1 - fprintf (logfp, " "); - } - fprintf (logfp, " %s\n", tmpstr); - } - fprintf (logfp, "\n"); - fclose_ (logfp); - } - } - login_log - ("'ladmin': End of connection, unknown packet (ip: %s)\n", - ip); - session[fd]->eof = 1; - printf - ("Remote administration has been disconnected (unknown packet).\n"); - return; - } - //WFIFOW(fd,0) = 0x791f; - //WFIFOSET(fd,2); - } - return; -} - -//-------------------------------------------- -// Test to know if an IP come from LAN or WAN. -//-------------------------------------------- -int lan_ip_check (unsigned char *p) -{ - int i; - int lancheck = 1; - -// printf("lan_ip_check: to compare: %d.%d.%d.%d, network: %d.%d.%d.%d/%d.%d.%d.%d\n", -// p[0], p[1], p[2], p[3], -// subneti[0], subneti[1], subneti[2], subneti[3], -// subnetmaski[0], subnetmaski[1], subnetmaski[2], subnetmaski[3]); - for (i = 0; i < 4; i++) - { - if ((subneti[i] & subnetmaski[i]) != (p[i] & subnetmaski[i])) - { - lancheck = 0; - break; - } - } - printf ("LAN test (result): %s source\033[0m.\n", - (lancheck) ? "\033[1;36mLAN" : "\033[1;32mWAN"); - return lancheck; -} - -//---------------------------------------------------------------------------------------- -// Default packet parsing (normal players or administation/char-server connexion requests) -//---------------------------------------------------------------------------------------- -void parse_login (int fd) -{ - struct mmo_account account; - int result, i, j; - unsigned char *p = (unsigned char *) &session[fd]->client_addr.sin_addr; - char ip[16]; - int host_len; - - sprintf (ip, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); - - if (session[fd]->eof) - { - close (fd); - delete_session (fd); - return; - } - - while (RFIFOREST (fd) >= 2) - { - if (display_parse_login == 1) - { - if (RFIFOW (fd, 0) == 0x64 || RFIFOW (fd, 0) == 0x01dd) - { - if (RFIFOREST (fd) >= ((RFIFOW (fd, 0) == 0x64) ? 55 : 47)) - printf - ("parse_login: connection #%d, packet: 0x%x (with being read: %d), account: %s.\n", - fd, RFIFOW (fd, 0), RFIFOREST (fd), RFIFOP (fd, 6)); - } - else if (RFIFOW (fd, 0) == 0x2710) - { - if (RFIFOREST (fd) >= 86) - printf - ("parse_login: connection #%d, packet: 0x%x (with being read: %d), server: %s.\n", - fd, RFIFOW (fd, 0), RFIFOREST (fd), RFIFOP (fd, 60)); - } - else - printf - ("parse_login: connection #%d, packet: 0x%x (with being read: %d).\n", - fd, RFIFOW (fd, 0), RFIFOREST (fd)); - } - - switch (RFIFOW (fd, 0)) - { - case 0x200: // New alive packet: structure: 0x200 .24B. used to verify if client is always alive. - if (RFIFOREST (fd) < 26) - return; - RFIFOSKIP (fd, 26); - break; - - case 0x204: // New alive packet: structure: 0x204 .16B. (new ragexe from 22 june 2004) - if (RFIFOREST (fd) < 18) - return; - RFIFOSKIP (fd, 18); - break; - - case 0x64: // Ask connection of a client - case 0x01dd: // Ask connection of a client (encryption mode) - if (RFIFOREST (fd) < ((RFIFOW (fd, 0) == 0x64) ? 55 : 47)) - return; - - account.userid = RFIFOP (fd, 6); - account.userid[23] = '\0'; - remove_control_chars (account.userid); - account.passwd = RFIFOP (fd, 30); - if (RFIFOW (fd, 0) == 0x64) - { - account.passwd[23] = '\0'; - remove_control_chars (account.passwd); - } -#ifdef PASSWORDENC - account.passwdenc = - (RFIFOW (fd, 0) == 0x64) ? 0 : PASSWORDENC; -#else - account.passwdenc = 0; -#endif - - if (RFIFOW (fd, 0) == 0x64) - { - login_log - ("Request for connection (non encryption mode) of %s (ip: %s).\n", - account.userid, ip); - } - else - { - login_log - ("Request for connection (encryption mode) of %s (ip: %s).\n", - account.userid, ip); - } - - if (!check_ip (session[fd]->client_addr.sin_addr.s_addr)) - { - login_log - ("Connection refused: IP isn't authorised (deny/allow, ip: %s).\n", - ip); - WFIFOW (fd, 0) = 0x6a; - WFIFOB (fd, 2) = 0x03; - WFIFOSET (fd, 3); - RFIFOSKIP (fd, (RFIFOW (fd, 0) == 0x64) ? 55 : 47); - break; - } - - result = mmo_auth (&account, fd); - if (result == -1) - { - int gm_level = isGM (account.account_id); - if (min_level_to_connect > gm_level) - { - login_log - ("Connection refused: the minimum GM level for connection is %d (account: %s, GM level: %d, ip: %s).\n", - min_level_to_connect, account.userid, - gm_level, ip); - WFIFOW (fd, 0) = 0x81; - WFIFOL (fd, 2) = 1; // 01 = Server closed - WFIFOSET (fd, 3); - } - else - { - int version_2 = RFIFOB (fd, 54); // version 2 - - if (gm_level) - printf - ("Connection of the GM (level:%d) account '%s' accepted.\n", - gm_level, account.userid); - else - printf - ("Connection of the account '%s' accepted.\n", - account.userid); - - /* - * Add a 0x0063 packet, which contains the name of the update host. The packet will only - * be sent if login_athena.conf contains a non-null entry for "update_host:" - * - * Because older clients cannot handle the 0x63 packet, we check the "version 2" value - * from the incoming 0x64 packet (the byte at offset 54). If bit 0 of this is set, - * then the client can safely accept the 0x63 packet. The "version 2" value is not - * otherwise used by eAthena. - */ - if ((RFIFOW (fd, 0) == 0x64) - && (version_2 & VERSION_2_UPDATEHOST)) - { - host_len = (int) strlen (update_host); - if (host_len > 0) - { - WFIFOW (fd, 0) = 0x63; - WFIFOW (fd, 2) = 4 + host_len; - memcpy (WFIFOP (fd, 4), update_host, - host_len); - WFIFOSET (fd, 4 + host_len); - } - } - - // Load list of char servers into outbound packet - server_num = 0; - if (version_2 && VERSION_2_SERVERORDER) - for (i = 0; i < MAX_SERVERS; i++) - { - if (server_fd[i] >= 0) - { - if (lan_ip_check (p)) - WFIFOL (fd, 47 + server_num * 32) = - inet_addr (lan_char_ip); - else - WFIFOL (fd, 47 + server_num * 32) = - server[i].ip; - WFIFOW (fd, 47 + server_num * 32 + 4) = - server[i].port; - memcpy (WFIFOP - (fd, 47 + server_num * 32 + 6), - server[i].name, 20); - WFIFOW (fd, 47 + server_num * 32 + 26) = - server[i].users; - WFIFOW (fd, 47 + server_num * 32 + 28) = - server[i].maintenance; - WFIFOW (fd, 47 + server_num * 32 + 30) = - server[i].is_new; - server_num++; - } - } - else // Send them in reverse, as the client defaults to the second (!) one - for (i = MAX_SERVERS - 1; i >= 0; i--) - { - if (server_fd[i] >= 0) - { - if (lan_ip_check (p)) - WFIFOL (fd, 47 + server_num * 32) = - inet_addr (lan_char_ip); - else - WFIFOL (fd, 47 + server_num * 32) = - server[i].ip; - WFIFOW (fd, 47 + server_num * 32 + 4) = - server[i].port; - memcpy (WFIFOP - (fd, 47 + server_num * 32 + 6), - server[i].name, 20); - WFIFOW (fd, 47 + server_num * 32 + 26) = - server[i].users; - WFIFOW (fd, 47 + server_num * 32 + 28) = - server[i].maintenance; - WFIFOW (fd, 47 + server_num * 32 + 30) = - server[i].is_new; - server_num++; - } - } - // if at least 1 char-server - if (server_num > 0) - { - WFIFOW (fd, 0) = 0x69; - WFIFOW (fd, 2) = 47 + 32 * server_num; - WFIFOL (fd, 4) = account.login_id1; - WFIFOL (fd, 8) = account.account_id; - WFIFOL (fd, 12) = account.login_id2; - WFIFOL (fd, 16) = 0; // in old version, that was for ip (not more used) - memcpy (WFIFOP (fd, 20), account.lastlogin, 24); // in old version, that was for name (not more used) - WFIFOB (fd, 46) = account.sex; - WFIFOSET (fd, 47 + 32 * server_num); - if (auth_fifo_pos >= AUTH_FIFO_SIZE) - auth_fifo_pos = 0; - auth_fifo[auth_fifo_pos].account_id = - account.account_id; - auth_fifo[auth_fifo_pos].login_id1 = - account.login_id1; - auth_fifo[auth_fifo_pos].login_id2 = - account.login_id2; - auth_fifo[auth_fifo_pos].sex = account.sex; - auth_fifo[auth_fifo_pos].delflag = 0; - auth_fifo[auth_fifo_pos].ip = - session[fd]->client_addr.sin_addr.s_addr; - auth_fifo_pos++; - // if no char-server, don't send void list of servers, just disconnect the player with proper message - } - else - { - login_log - ("Connection refused: there is no char-server online (account: %s, ip: %s).\n", - account.userid, ip); - WFIFOW (fd, 0) = 0x81; - WFIFOL (fd, 2) = 1; // 01 = Server closed - WFIFOSET (fd, 3); - } - } - } - else - { - memset (WFIFOP (fd, 0), '\0', 23); - WFIFOW (fd, 0) = 0x6a; - WFIFOB (fd, 2) = result; - if (result == 6) - { // 6 = Your are Prohibited to log in until %s - i = search_account_index (account.userid); - if (i != -1) - { - if (auth_dat[i].ban_until_time != 0) - { // if account is banned, we send ban timestamp - char tmpstr[256]; - strftime (tmpstr, 20, date_format, - gmtime (&auth_dat - [i].ban_until_time)); - tmpstr[19] = '\0'; - memcpy (WFIFOP (fd, 3), tmpstr, 20); - } - else - { // we send error message - memcpy (WFIFOP (fd, 3), - auth_dat[i].error_message, 20); - } - } - } - WFIFOSET (fd, 23); - } - RFIFOSKIP (fd, (RFIFOW (fd, 0) == 0x64) ? 55 : 47); - break; - - case 0x01db: // Sending request of the coding key - case 0x791a: // Sending request of the coding key (administration packet) - { - struct login_session_data *ld; - if (session[fd]->session_data) - { - printf - ("login: abnormal request of MD5 key (already opened session).\n"); - session[fd]->eof = 1; - return; - } - CREATE (ld, struct login_session_data, 1); - session[fd]->session_data = ld; - if (!ld) - { - printf - ("login: Request for md5 key: memory allocation failure (malloc)!\n"); - session[fd]->eof = 1; - return; - } - if (RFIFOW (fd, 0) == 0x01db) - { - login_log ("Sending request of the coding key (ip: %s)\n", - ip); - } - else - { - login_log - ("'ladmin': Sending request of the coding key (ip: %s)\n", - ip); - } - // Creation of the coding key - memset (ld->md5key, '\0', sizeof (ld->md5key)); - ld->md5keylen = rand () % 4 + 12; - for (i = 0; i < ld->md5keylen; i++) - ld->md5key[i] = rand () % 255 + 1; - - RFIFOSKIP (fd, 2); - WFIFOW (fd, 0) = 0x01dc; - WFIFOW (fd, 2) = 4 + ld->md5keylen; - memcpy (WFIFOP (fd, 4), ld->md5key, ld->md5keylen); - WFIFOSET (fd, WFIFOW (fd, 2)); - } - break; - - case 0x2710: // Connection request of a char-server - if (RFIFOREST (fd) < 86) - return; - { - int GM_value, len; - unsigned char *server_name; - account.userid = RFIFOP (fd, 2); - account.userid[23] = '\0'; - remove_control_chars (account.userid); - account.passwd = RFIFOP (fd, 26); - account.passwd[23] = '\0'; - remove_control_chars (account.passwd); - account.passwdenc = 0; - server_name = RFIFOP (fd, 60); - server_name[19] = '\0'; - remove_control_chars (server_name); - login_log - ("Connection request of the char-server '%s' @ %d.%d.%d.%d:%d (ip: %s)\n", - server_name, RFIFOB (fd, 54), RFIFOB (fd, 55), - RFIFOB (fd, 56), RFIFOB (fd, 57), RFIFOW (fd, 58), - ip); - result = mmo_auth (&account, fd); - - if (result == -1 && account.sex == 2) - { - // If this is the main server, and we don't already have a main server - if (server_fd[0] <= 0 - && strcasecmp (server_name, main_server) == 0) - { - account.account_id = 0; - } - else - { - int i; - for (i = 1; i < MAX_SERVERS; i++) - { - if (server_fd[i] <= 0) - { - account.account_id = i; - break; - } - } - } - } - - if (result == -1 && account.sex == 2 - && account.account_id < MAX_SERVERS - && server_fd[account.account_id] == -1) - { - login_log - ("Connection of the char-server '%s' accepted (account: %s, pass: %s, ip: %s)\n", - server_name, account.userid, - account.passwd, ip); - printf - ("Connection of the char-server '%s' accepted.\n", - server_name); - memset (&server[account.account_id], 0, - sizeof (struct mmo_char_server)); - server[account.account_id].ip = RFIFOL (fd, 54); - server[account.account_id].port = RFIFOW (fd, 58); - memcpy (server[account.account_id].name, server_name, - 20); - server[account.account_id].users = 0; - server[account.account_id].maintenance = - RFIFOW (fd, 82); - server[account.account_id].is_new = RFIFOW (fd, 84); - server_fd[account.account_id] = fd; - if (anti_freeze_enable) - server_freezeflag[account.account_id] = 5; // Char-server anti-freeze system. Counter. 5 ok, 4...0 freezed - WFIFOW (fd, 0) = 0x2711; - WFIFOB (fd, 2) = 0; - WFIFOSET (fd, 3); - session[fd]->func_parse = parse_fromchar; - realloc_fifo (fd, FIFOSIZE_SERVERLINK, - FIFOSIZE_SERVERLINK); - // send GM account to char-server - len = 4; - WFIFOW (fd, 0) = 0x2732; - for (i = 0; i < auth_num; i++) - // send only existing accounts. We can not create a GM account when server is online. - if ((GM_value = - isGM (auth_dat[i].account_id)) > 0) - { - WFIFOL (fd, len) = auth_dat[i].account_id; - WFIFOB (fd, len + 4) = - (unsigned char) GM_value; - len += 5; - } - WFIFOW (fd, 2) = len; - WFIFOSET (fd, len); - } - else - { - login_log - ("Connexion of the char-server '%s' REFUSED (account: %s, pass: %s, ip: %s)\n", - server_name, account.userid, - account.passwd, ip); - WFIFOW (fd, 0) = 0x2711; - WFIFOB (fd, 2) = 3; - WFIFOSET (fd, 3); - } - } - RFIFOSKIP (fd, 86); - return; - - case 0x7530: // Request of the server version - login_log ("Sending of the server version (ip: %s)\n", - ip); - WFIFOW (fd, 0) = 0x7531; - WFIFOB (fd, 2) = -1; - WFIFOB (fd, 3) = 'T'; - WFIFOB (fd, 4) = 'M'; - WFIFOB (fd, 5) = 'W'; - WFIFOL (fd, 6) = new_account_flag ? 1 : 0; - WFIFOSET (fd, 10); - RFIFOSKIP (fd, 2); - break; - - case 0x7532: // Request to end connection - login_log ("End of connection (ip: %s)\n", ip); - session[fd]->eof = 1; - return; - - case 0x7918: // Request for administation login - if (RFIFOREST (fd) < 4 - || RFIFOREST (fd) < ((RFIFOW (fd, 2) == 0) ? 28 : 20)) - return; - WFIFOW (fd, 0) = 0x7919; - WFIFOB (fd, 2) = 1; - if (!check_ladminip - (session[fd]->client_addr.sin_addr.s_addr)) - { - login_log - ("'ladmin'-login: Connection in administration mode refused: IP isn't authorised (ladmin_allow, ip: %s).\n", - ip); - } - else - { - struct login_session_data *ld = (struct login_session_data *)session[fd]->session_data; - if (RFIFOW (fd, 2) == 0) - { // non encrypted password - unsigned char *password; - password = RFIFOP (fd, 4); - password[23] = '\0'; - remove_control_chars (password); - // If remote administration is enabled and password sent by client matches password read from login server configuration file - if ((admin_state == 1) - && (strcmp (password, admin_pass) == 0)) - { - login_log - ("'ladmin'-login: Connection in administration mode accepted (non encrypted password: %s, ip: %s)\n", - password, ip); - printf - ("Connection of a remote administration accepted (non encrypted password).\n"); - WFIFOB (fd, 2) = 0; - session[fd]->func_parse = parse_admin; - } - else if (admin_state != 1) - login_log - ("'ladmin'-login: Connection in administration mode REFUSED - remote administration is disabled (non encrypted password: %s, ip: %s)\n", - password, ip); - else - login_log - ("'ladmin'-login: Connection in administration mode REFUSED - invalid password (non encrypted password: %s, ip: %s)\n", - password, ip); - } - else - { // encrypted password - if (!ld) - printf - ("'ladmin'-login: error! MD5 key not created/requested for an administration login.\n"); - else - { - char md5str[64] = "", md5bin[32]; - if (RFIFOW (fd, 2) == 1) - { - strncpy (md5str, ld->md5key, sizeof (ld->md5key)); // 20 - strcat (md5str, admin_pass); // 24 - } - else if (RFIFOW (fd, 2) == 2) - { - strncpy (md5str, admin_pass, sizeof (admin_pass)); // 24 - strcat (md5str, ld->md5key); // 20 - } - MD5_to_bin(MD5_from_cstring(md5str), md5bin); - // If remote administration is enabled and password hash sent by client matches hash of password read from login server configuration file - if ((admin_state == 1) - && (memcmp (md5bin, RFIFOP (fd, 4), 16) == 0)) - { - login_log - ("'ladmin'-login: Connection in administration mode accepted (encrypted password, ip: %s)\n", - ip); - printf - ("Connection of a remote administration accepted (encrypted password).\n"); - WFIFOB (fd, 2) = 0; - session[fd]->func_parse = parse_admin; - } - else if (admin_state != 1) - login_log - ("'ladmin'-login: Connection in administration mode REFUSED - remote administration is disabled (encrypted password, ip: %s)\n", - ip); - else - login_log - ("'ladmin'-login: Connection in administration mode REFUSED - invalid password (encrypted password, ip: %s)\n", - ip); - } - } - } - WFIFOSET (fd, 3); - RFIFOSKIP (fd, (RFIFOW (fd, 2) == 0) ? 28 : 20); - break; - - default: - if (save_unknown_packets) - { - FILE *logfp; - char tmpstr[24]; - struct timeval tv; - logfp = fopen_ (login_log_unknown_packets_filename, "a"); - if (logfp) - { - gettimeofday (&tv, NULL); - strftime (tmpstr, 23, date_format, - gmtime (&(tv.tv_sec))); - fprintf (logfp, - "%s.%03d: receiving of an unknown packet -> disconnection\n", - tmpstr, (int) tv.tv_usec / 1000); - fprintf (logfp, - "parse_login: connection #%d (ip: %s), packet: 0x%x (with being read: %d).\n", - fd, ip, RFIFOW (fd, 0), - RFIFOREST (fd)); - fprintf (logfp, "Detail (in hex):\n"); - fprintf (logfp, - "---- 00-01-02-03-04-05-06-07 08-09-0A-0B-0C-0D-0E-0F\n"); - memset (tmpstr, '\0', sizeof (tmpstr)); - for (i = 0; i < RFIFOREST (fd); i++) - { - if ((i & 15) == 0) - fprintf (logfp, "%04X ", i); - fprintf (logfp, "%02x ", RFIFOB (fd, i)); - if (RFIFOB (fd, i) > 0x1f) - tmpstr[i % 16] = RFIFOB (fd, i); - else - tmpstr[i % 16] = '.'; - if ((i - 7) % 16 == 0) // -8 + 1 - fprintf (logfp, " "); - else if ((i + 1) % 16 == 0) - { - fprintf (logfp, " %s\n", tmpstr); - memset (tmpstr, '\0', sizeof (tmpstr)); - } - } - if (i % 16 != 0) - { - for (j = i; j % 16 != 0; j++) - { - fprintf (logfp, " "); - if ((j - 7) % 16 == 0) // -8 + 1 - fprintf (logfp, " "); - } - fprintf (logfp, " %s\n", tmpstr); - } - fprintf (logfp, "\n"); - fclose_ (logfp); - } - } - login_log ("End of connection, unknown packet (ip: %s)\n", ip); - session[fd]->eof = 1; - return; - } - } - return; -} - -//------------------------------------------------- -// Return numerical value of a switch configuration -// on/off, english, français, deutsch, español -//------------------------------------------------- -int config_switch (const char *str) -{ - if (strcasecmp (str, "on") == 0 || strcasecmp (str, "yes") == 0 - || strcasecmp (str, "oui") == 0 || strcasecmp (str, "ja") == 0 - || strcasecmp (str, "si") == 0) - return 1; - if (strcasecmp (str, "off") == 0 || strcasecmp (str, "no") == 0 - || strcasecmp (str, "non") == 0 || strcasecmp (str, "nein") == 0) - return 0; - - return atoi (str); -} - -//---------------------------------- -// Reading Lan Support configuration -//---------------------------------- -int login_lan_config_read (const char *lancfgName) -{ - int j; - struct hostent *h = NULL; - char line[1024], w1[1024], w2[1024]; - FILE *fp; - - // set default configuration - strncpy (lan_char_ip, "127.0.0.1", sizeof (lan_char_ip)); - subneti[0] = 127; - subneti[1] = 0; - subneti[2] = 0; - subneti[3] = 1; - for (j = 0; j < 4; j++) - subnetmaski[j] = 255; - - fp = fopen_ (lancfgName, "r"); - - if (fp == NULL) - { - printf - ("***WARNING: LAN Support configuration file is not found: %s\n", - lancfgName); - return 1; - } - - printf ("---Start reading Lan Support configuration file\n"); - - while (fgets (line, sizeof (line) - 1, fp)) - { - if (line[0] == '/' && line[1] == '/') - continue; - - line[sizeof (line) - 1] = '\0'; - if (sscanf (line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - remove_control_chars (w1); - remove_control_chars (w2); - if (strcasecmp (w1, "lan_char_ip") == 0) - { // Read Char-Server Lan IP Address - h = gethostbyname (w2); - if (h != NULL) - { - sprintf (lan_char_ip, "%d.%d.%d.%d", - (unsigned char) h->h_addr[0], - (unsigned char) h->h_addr[1], - (unsigned char) h->h_addr[2], - (unsigned char) h->h_addr[3]); - } - else - { - strncpy (lan_char_ip, w2, sizeof (lan_char_ip)); - lan_char_ip[sizeof (lan_char_ip) - 1] = '\0'; - } - printf ("LAN IP of char-server: %s.\n", lan_char_ip); - } - else if (strcasecmp (w1, "subnet") == 0) - { // Read Subnetwork - for (j = 0; j < 4; j++) - subneti[j] = 0; - h = gethostbyname (w2); - if (h != NULL) - { - for (j = 0; j < 4; j++) - subneti[j] = (unsigned char) h->h_addr[j]; - } - else - { - sscanf (w2, "%d.%d.%d.%d", &subneti[0], &subneti[1], - &subneti[2], &subneti[3]); - } - printf ("Sub-network of the char-server: %d.%d.%d.%d.\n", - subneti[0], subneti[1], subneti[2], subneti[3]); - } - else if (strcasecmp (w1, "subnetmask") == 0) - { // Read Subnetwork Mask - for (j = 0; j < 4; j++) - subnetmaski[j] = 255; - h = gethostbyname (w2); - if (h != NULL) - { - for (j = 0; j < 4; j++) - subnetmaski[j] = (unsigned char) h->h_addr[j]; - } - else - { - sscanf (w2, "%d.%d.%d.%d", &subnetmaski[0], &subnetmaski[1], - &subnetmaski[2], &subnetmaski[3]); - } - printf ("Sub-network mask of the char-server: %d.%d.%d.%d.\n", - subnetmaski[0], subnetmaski[1], subnetmaski[2], - subnetmaski[3]); - } - } - fclose_ (fp); - - // log the LAN configuration - login_log ("The LAN configuration of the server is set:\n"); - login_log ("- with LAN IP of char-server: %s.\n", lan_char_ip); - login_log - ("- with the sub-network of the char-server: %d.%d.%d.%d/%d.%d.%d.%d.\n", - subneti[0], subneti[1], subneti[2], subneti[3], - subnetmaski[0], subnetmaski[1], subnetmaski[2], subnetmaski[3]); - - // sub-network check of the char-server - { - unsigned int a0, a1, a2, a3; - unsigned char p[4]; - sscanf (lan_char_ip, "%d.%d.%d.%d", &a0, &a1, &a2, &a3); - p[0] = a0; - p[1] = a1; - p[2] = a2; - p[3] = a3; - printf ("LAN test of LAN IP of the char-server: "); - if (lan_ip_check (p) == 0) - { - printf - ("\033[1;31m***ERROR: LAN IP of the char-server doesn't belong to the specified Sub-network\033[0m\n"); - login_log - ("***ERROR: LAN IP of the char-server doesn't belong to the specified Sub-network.\n"); - } - } - - printf ("---End reading of Lan Support configuration file\n"); - - return 0; -} - -//----------------------------------- -// Reading general configuration file -//----------------------------------- -int login_config_read (const char *cfgName) -{ - char line[1024], w1[1024], w2[1024]; - FILE *fp; - - fp = fopen_ (cfgName, "r"); - if (fp == NULL) - { - printf ("Configuration file (%s) not found.\n", cfgName); - return 1; - } - - printf ("---Start reading of Login Server configuration file (%s)\n", - cfgName); - while (fgets (line, sizeof (line) - 1, fp)) - { - if (line[0] == '/' && line[1] == '/') - continue; - - line[sizeof (line) - 1] = '\0'; - if (sscanf (line, "%[^:]: %[^\r\n]", w1, w2) == 2) - { - remove_control_chars (w1); - remove_control_chars (w2); - - if (strcasecmp (w1, "admin_state") == 0) - { - admin_state = config_switch (w2); - } - else if (strcasecmp (w1, "admin_pass") == 0) - { - strncpy (admin_pass, w2, sizeof (admin_pass)); - admin_pass[sizeof (admin_pass) - 1] = '\0'; - } - else if (strcasecmp (w1, "ladminallowip") == 0) - { - if (strcasecmp (w2, "clear") == 0) - { - if (access_ladmin_allow) - free (access_ladmin_allow); - access_ladmin_allow = NULL; - access_ladmin_allownum = 0; - } - else - { - if (strcasecmp (w2, "all") == 0) - { - // reset all previous values - if (access_ladmin_allow) - free (access_ladmin_allow); - // set to all - CREATE (access_ladmin_allow, char, ACO_STRSIZE); - access_ladmin_allownum = 1; - } - else if (w2[0] - && !(access_ladmin_allownum == 1 - && access_ladmin_allow[0] == '\0')) - { // don't add IP if already 'all' - if (access_ladmin_allow) - RECREATE (access_ladmin_allow, char, (access_ladmin_allownum + 1) * ACO_STRSIZE); - else - CREATE (access_ladmin_allow, char, ACO_STRSIZE); - strncpy (access_ladmin_allow + - (access_ladmin_allownum++) * ACO_STRSIZE, w2, - ACO_STRSIZE); - access_ladmin_allow[access_ladmin_allownum * - ACO_STRSIZE - 1] = '\0'; - } - } - } - else if (strcasecmp (w1, "gm_pass") == 0) - { - strncpy (gm_pass, w2, sizeof (gm_pass)); - gm_pass[sizeof (gm_pass) - 1] = '\0'; - } - else if (strcasecmp (w1, "level_new_gm") == 0) - { - level_new_gm = atoi (w2); - } - else if (strcasecmp (w1, "new_account") == 0) - { - new_account_flag = config_switch (w2); - } - else if (strcasecmp (w1, "login_port") == 0) - { - login_port = atoi (w2); - } - else if (strcasecmp (w1, "account_filename") == 0) - { - strncpy (account_filename, w2, sizeof (account_filename)); - account_filename[sizeof (account_filename) - 1] = '\0'; - } - else if (strcasecmp (w1, "gm_account_filename") == 0) - { - strncpy (GM_account_filename, w2, - sizeof (GM_account_filename)); - GM_account_filename[sizeof (GM_account_filename) - 1] = '\0'; - } - else if (strcasecmp (w1, "gm_account_filename_check_timer") == 0) - { - gm_account_filename_check_timer = atoi (w2); - } - else if (strcasecmp (w1, "login_log_filename") == 0) - { - strncpy (login_log_filename, w2, sizeof (login_log_filename)); - login_log_filename[sizeof (login_log_filename) - 1] = '\0'; - } - else if (strcasecmp (w1, "login_log_unknown_packets_filename") == 0) - { - strncpy (login_log_unknown_packets_filename, w2, - sizeof (login_log_unknown_packets_filename)); - login_log_unknown_packets_filename[sizeof - (login_log_unknown_packets_filename) - - 1] = '\0'; - } - else if (strcasecmp (w1, "save_unknown_packets") == 0) - { - save_unknown_packets = config_switch (w2); - } - else if (strcasecmp (w1, "display_parse_login") == 0) - { - display_parse_login = config_switch (w2); // 0: no, 1: yes - } - else if (strcasecmp (w1, "display_parse_admin") == 0) - { - display_parse_admin = config_switch (w2); // 0: no, 1: yes - } - else if (strcasecmp (w1, "display_parse_fromchar") == 0) - { - display_parse_fromchar = config_switch (w2); // 0: no, 1: yes (without packet 0x2714), 2: all packets - } - else if (strcasecmp (w1, "date_format") == 0) - { // note: never have more than 19 char for the date! - switch (atoi (w2)) - { - case 0: - strcpy (date_format, "%d-%m-%Y %H:%M:%S"); // 31-12-2004 23:59:59 - break; - case 1: - strcpy (date_format, "%m-%d-%Y %H:%M:%S"); // 12-31-2004 23:59:59 - break; - case 2: - strcpy (date_format, "%Y-%d-%m %H:%M:%S"); // 2004-31-12 23:59:59 - break; - case 3: - strcpy (date_format, "%Y-%m-%d %H:%M:%S"); // 2004-12-31 23:59:59 - break; - } - } - else if (strcasecmp (w1, "min_level_to_connect") == 0) - { - min_level_to_connect = atoi (w2); - } - else if (strcasecmp (w1, "add_to_unlimited_account") == 0) - { - add_to_unlimited_account = config_switch (w2); - } - else if (strcasecmp (w1, "start_limited_time") == 0) - { - start_limited_time = atoi (w2); - } - else if (strcasecmp (w1, "check_ip_flag") == 0) - { - check_ip_flag = config_switch (w2); - } - else if (strcasecmp (w1, "order") == 0) - { - access_order = atoi (w2); - if (strcasecmp (w2, "deny,allow") == 0 || - strcasecmp (w2, "deny, allow") == 0) - access_order = ACO_DENY_ALLOW; - if (strcasecmp (w2, "allow,deny") == 0 || - strcasecmp (w2, "allow, deny") == 0) - access_order = ACO_ALLOW_DENY; - if (strcasecmp (w2, "mutual-failture") == 0 || - strcasecmp (w2, "mutual-failure") == 0) - access_order = ACO_MUTUAL_FAILTURE; - } - else if (strcasecmp (w1, "allow") == 0) - { - if (strcasecmp (w2, "clear") == 0) - { - if (access_allow) - free (access_allow); - access_allow = NULL; - access_allownum = 0; - } - else - { - if (strcasecmp (w2, "all") == 0) - { - // reset all previous values - if (access_allow) - free (access_allow); - // set to all - CREATE (access_allow, char, ACO_STRSIZE); - access_allownum = 1; - } - else if (w2[0] - && !(access_allownum == 1 - && access_allow[0] == '\0')) - { // don't add IP if already 'all' - if (access_allow) - RECREATE (access_allow, char, (access_allownum + 1) * ACO_STRSIZE); - else - CREATE (access_allow, char, ACO_STRSIZE); - strncpy (access_allow + - (access_allownum++) * ACO_STRSIZE, w2, - ACO_STRSIZE); - access_allow[access_allownum * ACO_STRSIZE - 1] = - '\0'; - } - } - } - else if (strcasecmp (w1, "deny") == 0) - { - if (strcasecmp (w2, "clear") == 0) - { - if (access_deny) - free (access_deny); - access_deny = NULL; - access_denynum = 0; - } - else - { - if (strcasecmp (w2, "all") == 0) - { - // reset all previous values - if (access_deny) - free (access_deny); - // set to all - CREATE (access_deny, char, ACO_STRSIZE); - access_denynum = 1; - } - else if (w2[0] - && !(access_denynum == 1 - && access_deny[0] == '\0')) - { // don't add IP if already 'all' - if (access_deny) - RECREATE (access_deny, char, (access_denynum + 1) * ACO_STRSIZE); - else - CREATE (access_deny, char, ACO_STRSIZE); - strncpy (access_deny + - (access_denynum++) * ACO_STRSIZE, w2, - ACO_STRSIZE); - access_deny[access_denynum * ACO_STRSIZE - 1] = '\0'; - } - } - } - else if (strcasecmp (w1, "anti_freeze_enable") == 0) - { - anti_freeze_enable = config_switch (w2); - } - else if (strcasecmp (w1, "anti_freeze_interval") == 0) - { - ANTI_FREEZE_INTERVAL = atoi (w2); - if (ANTI_FREEZE_INTERVAL < 5) - ANTI_FREEZE_INTERVAL = 5; // minimum 5 seconds - } - else if (strcasecmp (w1, "import") == 0) - { - login_config_read (w2); - } - else if (strcasecmp (w1, "update_host") == 0) - { - strncpy (update_host, w2, sizeof (update_host)); - update_host[sizeof (update_host) - 1] = '\0'; - } - else if (strcasecmp (w1, "main_server") == 0) - { - strncpy (main_server, w2, sizeof (main_server)); - main_server[sizeof (main_server) - 1] = '\0'; - } - } - } - fclose_ (fp); - - printf ("---End reading of Login Server configuration file.\n"); - - return 0; -} - -//------------------------------------- -// Displaying of configuration warnings -//------------------------------------- -void display_conf_warnings (void) -{ - if (admin_state != 0 && admin_state != 1) - { - printf - ("***WARNING: Invalid value for admin_state parameter -> set to 0 (no remote admin).\n"); - admin_state = 0; - } - - if (admin_state == 1) - { - if (admin_pass[0] == '\0') - { - printf - ("***WARNING: Administrator password is void (admin_pass).\n"); - } - else if (strcmp (admin_pass, "admin") == 0) - { - printf - ("***WARNING: You are using the default administrator password (admin_pass).\n"); - printf (" We highly recommend that you change it.\n"); - } - } - - if (gm_pass[0] == '\0') - { - printf ("***WARNING: 'To GM become' password is void (gm_pass).\n"); - printf - (" We highly recommend that you set one password.\n"); - } - else if (strcmp (gm_pass, "gm") == 0) - { - printf - ("***WARNING: You are using the default GM password (gm_pass).\n"); - printf (" We highly recommend that you change it.\n"); - } - - if (level_new_gm < 0 || level_new_gm > 99) - { - printf - ("***WARNING: Invalid value for level_new_gm parameter -> set to 60 (default).\n"); - level_new_gm = 60; - } - - if (new_account_flag != 0 && new_account_flag != 1) - { - printf - ("***WARNING: Invalid value for new_account parameter -> set to 0 (no new account).\n"); - new_account_flag = 0; - } - - if (login_port < 1024 || login_port > 65535) - { - printf - ("***WARNING: Invalid value for login_port parameter -> set to 6900 (default).\n"); - login_port = 6900; - } - - if (gm_account_filename_check_timer < 0) - { - printf - ("***WARNING: Invalid value for gm_account_filename_check_timer parameter.\n"); - printf (" -> set to 15 sec (default).\n"); - gm_account_filename_check_timer = 15; - } - else if (gm_account_filename_check_timer == 1) - { - printf - ("***WARNING: Invalid value for gm_account_filename_check_timer parameter.\n"); - printf (" -> set to 2 sec (minimum value).\n"); - gm_account_filename_check_timer = 2; - } - - if (save_unknown_packets != 0 && save_unknown_packets != 1) - { - printf - ("WARNING: Invalid value for save_unknown_packets parameter -> set to 0-no save.\n"); - save_unknown_packets = 0; - } - - if (display_parse_login != 0 && display_parse_login != 1) - { // 0: no, 1: yes - printf - ("***WARNING: Invalid value for display_parse_login parameter\n"); - printf (" -> set to 0 (no display).\n"); - display_parse_login = 0; - } - - if (display_parse_admin != 0 && display_parse_admin != 1) - { // 0: no, 1: yes - printf - ("***WARNING: Invalid value for display_parse_admin parameter\n"); - printf (" -> set to 0 (no display).\n"); - display_parse_admin = 0; - } - - if (display_parse_fromchar < 0 || display_parse_fromchar > 2) - { // 0: no, 1: yes (without packet 0x2714), 2: all packets - printf - ("***WARNING: Invalid value for display_parse_fromchar parameter\n"); - printf (" -> set to 0 (no display).\n"); - display_parse_fromchar = 0; - } - - if (min_level_to_connect < 0) - { // 0: all players, 1-99 at least gm level x - printf - ("***WARNING: Invalid value for min_level_to_connect (%d) parameter\n", - min_level_to_connect); - printf (" -> set to 0 (any player).\n"); - min_level_to_connect = 0; - } - else if (min_level_to_connect > 99) - { // 0: all players, 1-99 at least gm level x - printf - ("***WARNING: Invalid value for min_level_to_connect (%d) parameter\n", - min_level_to_connect); - printf (" -> set to 99 (only GM level 99).\n"); - min_level_to_connect = 99; - } - - if (add_to_unlimited_account != 0 && add_to_unlimited_account != 1) - { // 0: no, 1: yes - printf - ("***WARNING: Invalid value for add_to_unlimited_account parameter\n"); - printf - (" -> set to 0 (impossible to add a time to an unlimited account).\n"); - add_to_unlimited_account = 0; - } - - if (start_limited_time < -1) - { // -1: create unlimited account, 0 or more: additionnal sec from now to create limited time - printf - ("***WARNING: Invalid value for start_limited_time parameter\n"); - printf - (" -> set to -1 (new accounts are created with unlimited time).\n"); - start_limited_time = -1; - } - - if (check_ip_flag != 0 && check_ip_flag != 1) - { // 0: no, 1: yes - printf ("***WARNING: Invalid value for check_ip_flag parameter\n"); - printf - (" -> set to 1 (check players ip between login-server & char-server).\n"); - check_ip_flag = 1; - } - - if (access_order == ACO_DENY_ALLOW) - { - if (access_denynum == 1 && access_deny[0] == '\0') - { - printf - ("***WARNING: The IP security order is 'deny,allow' (allow if not deny).\n"); - printf (" And you refuse ALL IP.\n"); - } - } - else if (access_order == ACO_ALLOW_DENY) - { - if (access_allownum == 0) - { - printf - ("***WARNING: The IP security order is 'allow,deny' (deny if not allow).\n"); - printf (" But, NO IP IS AUTHORISED!\n"); - } - } - else - { // ACO_MUTUAL_FAILTURE - if (access_allownum == 0) - { - printf - ("***WARNING: The IP security order is 'mutual-failture'\n"); - printf - (" (allow if in the allow list and not in the deny list).\n"); - printf (" But, NO IP IS AUTHORISED!\n"); - } - else if (access_denynum == 1 && access_deny[0] == '\0') - { - printf ("***WARNING: The IP security order is mutual-failture\n"); - printf - (" (allow if in the allow list and not in the deny list).\n"); - printf (" But, you refuse ALL IP!\n"); - } - } - - return; -} - -//------------------------------- -// Save configuration in log file -//------------------------------- -void save_config_in_log (void) -{ - int i; - - // a newline in the log... - login_log (""); - login_log ("The login-server starting...\n"); - - // save configuration in log file - login_log ("The configuration of the server is set:\n"); - - if (admin_state != 1) - login_log ("- with no remote administration.\n"); - else if (admin_pass[0] == '\0') - login_log ("- with a remote administration with a VOID password.\n"); - else if (strcmp (admin_pass, "admin") == 0) - login_log ("- with a remote administration with the DEFAULT password.\n"); - else - login_log - ("- with a remote administration with the password of %d character(s).\n", - strlen (admin_pass)); - if (access_ladmin_allownum == 0 - || (access_ladmin_allownum == 1 && access_ladmin_allow[0] == '\0')) - { - login_log ("- to accept any IP for remote administration\n"); - } - else - { - login_log ("- to accept following IP for remote administration:\n"); - for (i = 0; i < access_ladmin_allownum; i++) - login_log (" %s\n", - (char *) (access_ladmin_allow + i * ACO_STRSIZE)); - } - - if (gm_pass[0] == '\0') - login_log ("- with a VOID 'To GM become' password (gm_pass).\n"); - else if (strcmp (gm_pass, "gm") == 0) - login_log ("- with the DEFAULT 'To GM become' password (gm_pass).\n"); - else - login_log - ("- with a 'To GM become' password (gm_pass) of %d character(s).\n", - strlen (gm_pass)); - if (level_new_gm == 0) - login_log ("- to refuse any creation of GM with @gm.\n"); - else - login_log ("- to create GM with level '%d' when @gm is used.\n", - level_new_gm); - - if (new_account_flag == 1) - login_log ("- to ALLOW new users (with _F/_M).\n"); - else - login_log ("- to NOT ALLOW new users (with _F/_M).\n"); - login_log ("- with port: %d.\n", login_port); - login_log ("- with the accounts file name: '%s'.\n", - account_filename); - login_log ("- with the GM accounts file name: '%s'.\n", - GM_account_filename); - if (gm_account_filename_check_timer == 0) - login_log ("- to NOT check GM accounts file modifications.\n"); - else - login_log - ("- to check GM accounts file modifications every %d seconds.\n", - gm_account_filename_check_timer); - - // not necessary to log the 'login_log_filename', we are inside :) - - login_log ("- with the unknown packets file name: '%s'.\n", - login_log_unknown_packets_filename); - if (save_unknown_packets) - login_log ("- to SAVE all unkown packets.\n"); - else - login_log - ("- to SAVE only unkown packets sending by a char-server or a remote administration.\n"); - if (display_parse_login) - login_log ("- to display normal parse packets on console.\n"); - else - login_log ("- to NOT display normal parse packets on console.\n"); - if (display_parse_admin) - login_log ("- to display administration parse packets on console.\n"); - else - login_log ("- to NOT display administration parse packets on console.\n"); - if (display_parse_fromchar) - login_log ("- to display char-server parse packets on console.\n"); - else - login_log ("- to NOT display char-server parse packets on console.\n"); - - if (min_level_to_connect == 0) // 0: all players, 1-99 at least gm level x - login_log ("- with no minimum level for connection.\n"); - else if (min_level_to_connect == 99) - login_log ("- to accept only GM with level 99.\n"); - else - login_log ("- to accept only GM with level %d or more.\n", - min_level_to_connect); - - if (add_to_unlimited_account) - login_log - ("- to authorize adjustment (with timeadd ladmin) on an unlimited account.\n"); - else - login_log - ("- to refuse adjustment (with timeadd ladmin) on an unlimited account. You must use timeset (ladmin command) before.\n"); - - if (start_limited_time < 0) - login_log ("- to create new accounts with an unlimited time.\n"); - else if (start_limited_time == 0) - login_log - ("- to create new accounts with a limited time: time of creation.\n"); - else - login_log - ("- to create new accounts with a limited time: time of creation + %d second(s).\n", - start_limited_time); - - if (check_ip_flag) - login_log - ("- with control of players IP between login-server and char-server.\n"); - else - login_log - ("- to not check players IP between login-server and char-server.\n"); - - if (access_order == ACO_DENY_ALLOW) - { - if (access_denynum == 0) - { - login_log - ("- with the IP security order: 'deny,allow' (allow if not deny). You refuse no IP.\n"); - } - else if (access_denynum == 1 && access_deny[0] == '\0') - { - login_log - ("- with the IP security order: 'deny,allow' (allow if not deny). You refuse ALL IP.\n"); - } - else - { - login_log - ("- with the IP security order: 'deny,allow' (allow if not deny). Refused IP are:\n"); - for (i = 0; i < access_denynum; i++) - login_log (" %s\n", - (char *) (access_deny + i * ACO_STRSIZE)); - } - } - else if (access_order == ACO_ALLOW_DENY) - { - if (access_allownum == 0) - { - login_log - ("- with the IP security order: 'allow,deny' (deny if not allow). But, NO IP IS AUTHORISED!\n"); - } - else if (access_allownum == 1 && access_allow[0] == '\0') - { - login_log - ("- with the IP security order: 'allow,deny' (deny if not allow). You authorise ALL IP.\n"); - } - else - { - login_log - ("- with the IP security order: 'allow,deny' (deny if not allow). Authorised IP are:\n"); - for (i = 0; i < access_allownum; i++) - login_log (" %s\n", - (char *) (access_allow + i * ACO_STRSIZE)); - } - } - else - { // ACO_MUTUAL_FAILTURE - login_log - ("- with the IP security order: 'mutual-failture' (allow if in the allow list and not in the deny list).\n"); - if (access_allownum == 0) - { - login_log (" But, NO IP IS AUTHORISED!\n"); - } - else if (access_denynum == 1 && access_deny[0] == '\0') - { - login_log (" But, you refuse ALL IP!\n"); - } - else - { - if (access_allownum == 1 && access_allow[0] == '\0') - { - login_log (" You authorise ALL IP.\n"); - } - else - { - login_log (" Authorised IP are:\n"); - for (i = 0; i < access_allownum; i++) - login_log (" %s\n", - (char *) (access_allow + i * ACO_STRSIZE)); - } - login_log (" Refused IP are:\n"); - for (i = 0; i < access_denynum; i++) - login_log (" %s\n", - (char *) (access_deny + i * ACO_STRSIZE)); - } - } -} - -//-------------------------------------- -// Function called at exit of the server -//-------------------------------------- -void term_func (void) -{ - int i, fd; - - mmo_auth_sync (); - - free (auth_dat); - free (gm_account_db); - for (i = 0; i < MAX_SERVERS; i++) - { - if ((fd = server_fd[i]) >= 0) - delete_session (fd); - } - delete_session (login_fd); - - login_log - ("----End of login-server (normal end with closing of all files).\n"); -} - -//------------------------------ -// Main function of login-server -//------------------------------ -int do_init (int argc, char **argv) -{ - int i, j; - - // read login-server configuration - login_config_read ((argc > 1) ? argv[1] : LOGIN_CONF_NAME); - display_conf_warnings (); // not in login_config_read, because we can use 'import' option, and display same message twice or more - save_config_in_log (); // not before, because log file name can be changed - login_lan_config_read ((argc > 1) ? argv[1] : LAN_CONF_NAME); - - for (i = 0; i < AUTH_FIFO_SIZE; i++) - auth_fifo[i].delflag = 1; - for (i = 0; i < MAX_SERVERS; i++) - server_fd[i] = -1; - - gm_account_db = numdb_init (); - - read_gm_account (); - mmo_auth_init (); -// set_termfunc (mmo_auth_sync); - set_defaultparse (parse_login); - login_fd = make_listen_port (login_port); - -// add_timer_func_list (check_auth_sync, "check_auth_sync"); - - // Trigger auth sync every 5 minutes - i = add_timer_interval (gettick () + 300000, check_auth_sync, 0, 0, 300000); - - if (anti_freeze_enable > 0) - { -// add_timer_func_list (char_anti_freeze_system, "char_anti_freeze_system"); - i = add_timer_interval (gettick () + 1000, char_anti_freeze_system, 0, - 0, ANTI_FREEZE_INTERVAL * 1000); - } - - // add timer to check GM accounts file modification - j = gm_account_filename_check_timer; - if (j == 0) // if we would not to check, we check every 60 sec, just to have timer (if we change timer, is was not necessary to check if timer already exists) - j = 60; -// add_timer_func_list (check_GM_file, "check_GM_file"); - i = add_timer_interval (gettick () + j * 1000, check_GM_file, 0, 0, j * 1000); // every x sec we check if gm file has been changed - - login_log - ("The login-server is ready (Server is listening on the port %d).\n", - login_port); - - printf - ("The login-server is \033[1;32mready\033[0m (Server is listening on the port %d).\n\n", - login_port); - - return 0; -} diff --git a/src/login/login.cpp b/src/login/login.cpp new file mode 100644 index 0000000..543f32f --- /dev/null +++ b/src/login/login.cpp @@ -0,0 +1,5038 @@ +// $Id: login.c,v 1.1.1.1 2004/09/10 17:26:53 MagicalTux Exp $ +// new version of the login-server by [Yor] + +#include +#include +#include +#include +#include +#include +#include +#include +#include // for stat/lstat/fstat +#include +#include +#include +#include +#include +#include +#include + +#include "../common/core.hpp" +#include "../common/socket.hpp" +#include "../common/timer.hpp" +#include "login.hpp" +#include "../common/mmo.hpp" +#include "../common/version.hpp" +#include "../common/db.hpp" +#include "../common/lock.hpp" +#include "../common/mt_rand.hpp" + +#include "../common/md5calc.hpp" + +#ifdef MEMWATCH +#include "memwatch.hpp" +#endif + +int account_id_count = START_ACCOUNT_NUM; +int server_num; +int new_account_flag = 0; +int login_port = 6900; +char lan_char_ip[16]; +int subneti[4]; +int subnetmaski[4]; +char update_host[128] = ""; +char main_server[20] = ""; + +char account_filename[1024] = "save/account.txt"; +char GM_account_filename[1024] = "conf/GM_account.txt"; +char login_log_filename[1024] = "log/login.log"; +char login_log_unknown_packets_filename[1024] = + "log/login_unknown_packets.log"; +char date_format[32] = "%Y-%m-%d %H:%M:%S"; +int save_unknown_packets = 0; +long creation_time_GM_account_file; +int gm_account_filename_check_timer = 15; // Timer to check if GM_account file has been changed and reload GM account automaticaly (in seconds; default: 15) + +int display_parse_login = 0; // 0: no, 1: yes +int display_parse_admin = 0; // 0: no, 1: yes +int display_parse_fromchar = 0; // 0: no, 1: yes (without packet 0x2714), 2: all packets + +struct mmo_char_server server[MAX_SERVERS]; +int server_fd[MAX_SERVERS]; +int server_freezeflag[MAX_SERVERS]; // Char-server anti-freeze system. Counter. 5 ok, 4...0 freezed +int anti_freeze_enable = 0; +int ANTI_FREEZE_INTERVAL = 15; + +int login_fd; + +enum +{ + ACO_DENY_ALLOW = 0, + ACO_ALLOW_DENY, + ACO_MUTUAL_FAILTURE, + ACO_STRSIZE = 128, +}; + +int access_order = ACO_DENY_ALLOW; +int access_allownum = 0; +int access_denynum = 0; +char *access_allow = NULL; +char *access_deny = NULL; + +int access_ladmin_allownum = 0; +char *access_ladmin_allow = NULL; + +int min_level_to_connect = 0; // minimum level of player/GM (0: player, 1-99: gm) to connect on the server +int add_to_unlimited_account = 0; // Give possibility or not to adjust (ladmin command: timeadd) the time of an unlimited account. +int start_limited_time = -1; // Starting additional sec from now for the limited time at creation of accounts (-1: unlimited time, 0 or more: additional sec from now) +int check_ip_flag = 1; // It's to check IP of a player between login-server and char-server (part of anti-hacking system) + +struct login_session_data +{ + int md5keylen; + char md5key[20]; +}; + +#define AUTH_FIFO_SIZE 256 +struct +{ + int account_id, login_id1, login_id2; + int ip, sex, delflag; +} auth_fifo[AUTH_FIFO_SIZE]; +int auth_fifo_pos = 0; + +struct auth_dat +{ + int account_id, sex; + char userid[24], pass[40], lastlogin[24]; + int logincount; + int state; // packet 0x006a value + 1 (0: compte OK) + char email[40]; // e-mail (by default: a@a.com) + char error_message[20]; // Message of error code #6 = Your are Prohibited to log in until %s (packet 0x006a) + time_t ban_until_time; // # of seconds 1/1/1970 (timestamp): ban time limit of the account (0 = no ban) + time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) + char last_ip[16]; // save of last IP of connection + char memo[255]; // a memo field + int account_reg2_num; + struct global_reg account_reg2[ACCOUNT_REG2_NUM]; +} *auth_dat; + +int auth_num = 0, auth_max = 0; + +int admin_state = 0; +char admin_pass[24] = ""; +char gm_pass[64] = ""; +int level_new_gm = 60; + +static struct dbt *gm_account_db; + +pid_t pid = 0; // For forked DB writes + + +#define VERSION_2_UPDATEHOST 0x01 // client supports updatehost +#define VERSION_2_SERVERORDER 0x02 // send servers in forward order +//------------------------------ +// Writing function of logs file +//------------------------------ +int login_log (char *fmt, ...) +{ + FILE *logfp; + va_list ap; + struct timeval tv; + char tmpstr[2048]; + + va_start (ap, fmt); + + logfp = fopen_ (login_log_filename, "a"); + if (logfp) + { + if (fmt[0] == '\0') // jump a line if no message + fprintf (logfp, "\n"); + else + { + gettimeofday (&tv, NULL); + strftime (tmpstr, 24, date_format, gmtime (&(tv.tv_sec))); + sprintf (tmpstr + strlen (tmpstr), ".%03d: %s", + (int) tv.tv_usec / 1000, fmt); + vfprintf (logfp, tmpstr, ap); + } + fclose_ (logfp); + } + + va_end (ap); + return 0; +} + +//---------------------------------------------------------------------- +// Determine if an account (id) is a GM account +// and returns its level (or 0 if it isn't a GM account or if not found) +//---------------------------------------------------------------------- +int isGM (int account_id) +{ + struct gm_account *p = (struct gm_account*) numdb_search (gm_account_db, account_id); + if (p == NULL) + return 0; + return p->level; +} + +//------------------------------------------------------- +// Reading function of GM accounts file (and their level) +//------------------------------------------------------- +int read_gm_account (void) +{ + char line[512]; + struct gm_account *p; + FILE *fp; + int c = 0; + int GM_level; + struct stat file_stat; + + free (gm_account_db); + gm_account_db = numdb_init (); + + // get last modify time/date + if (stat (GM_account_filename, &file_stat)) + creation_time_GM_account_file = 0; // error + else + creation_time_GM_account_file = file_stat.st_mtime; + + if ((fp = fopen_ (GM_account_filename, "r")) == NULL) + { + printf ("read_gm_account: GM accounts file [%s] not found.\n", + GM_account_filename); + printf + (" Actually, there is no GM accounts on the server.\n"); + login_log ("read_gm_account: GM accounts file [%s] not found.\n", + GM_account_filename); + login_log + (" Actually, there is no GM accounts on the server.\n"); + return 1; + } + // limited to 4000, because we send information to char-servers (more than 4000 GM accounts???) + // int (id) + int (level) = 8 bytes * 4000 = 32k (limit of packets in windows) + while (fgets (line, sizeof (line) - 1, fp) && c < 4000) + { + if ((line[0] == '/' && line[1] == '/') || line[0] == '\0' + || line[0] == '\n' || line[0] == '\r') + continue; + CREATE (p, struct gm_account, 1); + if (sscanf (line, "%d %d", &p->account_id, &p->level) != 2 + && sscanf (line, "%d: %d", &p->account_id, &p->level) != 2) + printf + ("read_gm_account: file [%s], invalid 'id_acount level' format.\n", + GM_account_filename); + else if (p->level <= 0) + printf + ("read_gm_account: file [%s] %dth account (invalid level [0 or negative]: %d).\n", + GM_account_filename, c + 1, p->level); + else + { + if (p->level > 99) + { + printf + ("read_gm_account: file [%s] %dth account (invalid level, but corrected: %d->99).\n", + GM_account_filename, c + 1, p->level); + p->level = 99; + } + if ((GM_level = isGM (p->account_id)) > 0) + { // if it's not a new account + if (GM_level == p->level) + printf + ("read_gm_account: GM account %d defined twice (same level: %d).\n", + p->account_id, p->level); + else + printf + ("read_gm_account: GM account %d defined twice (levels: %d and %d).\n", + p->account_id, GM_level, p->level); + } + if (GM_level != p->level) + { // if new account or new level + numdb_insert (gm_account_db, p->account_id, p); + //printf("GM account:%d, level: %d->%d\n", p->account_id, GM_level, p->level); + if (GM_level == 0) + { // if new account + c++; + if (c >= 4000) + { + printf + ("***WARNING: 4000 GM accounts found. Next GM accounts are not readed.\n"); + login_log + ("***WARNING: 4000 GM accounts found. Next GM accounts are not readed.\n"); + } + } + } + } + } + fclose_ (fp); + + printf ("read_gm_account: file '%s' readed (%d GM accounts found).\n", + GM_account_filename, c); + login_log ("read_gm_account: file '%s' readed (%d GM accounts found).\n", + GM_account_filename, c); + + return 0; +} + +//-------------------------------------------------------------- +// Test of the IP mask +// (ip: IP to be tested, str: mask x.x.x.x/# or x.x.x.x/y.y.y.y) +//-------------------------------------------------------------- +int check_ipmask (unsigned int ip, const unsigned char *str) +{ + unsigned int mask = 0, i = 0, m, ip2, a0, a1, a2, a3; + unsigned char *p = (unsigned char *) &ip2, *p2 = (unsigned char *) &mask; + + if (sscanf (str, "%d.%d.%d.%d/%n", &a0, &a1, &a2, &a3, &i) != 4 || i == 0) + return 0; + p[0] = a0; + p[1] = a1; + p[2] = a2; + p[3] = a3; + + if (sscanf (str + i, "%d.%d.%d.%d", &a0, &a1, &a2, &a3) == 4) + { + p2[0] = a0; + p2[1] = a1; + p2[2] = a2; + p2[3] = a3; + mask = ntohl (mask); + } + else if (sscanf (str + i, "%d", &m) == 1 && m >= 0 && m <= 32) + { + for (i = 0; i < m && i < 32; i++) + mask = (mask >> 1) | 0x80000000; + } + else + { + printf ("check_ipmask: invalid mask [%s].\n", str); + return 0; + } + +// printf("Tested IP: %08x, network: %08x, network mask: %08x\n", +// (unsigned int)ntohl(ip), (unsigned int)ntohl(ip2), (unsigned int)mask); + return ((ntohl (ip) & mask) == (ntohl (ip2) & mask)); +} + +//--------------------- +// Access control by IP +//--------------------- +int check_ip (unsigned int ip) +{ + int i; + unsigned char *p = (unsigned char *) &ip; + char buf[32]; + enum + { ACF_DEF, ACF_ALLOW, ACF_DENY } flag = ACF_DEF; + + if (access_allownum == 0 && access_denynum == 0) + return 1; // When there is no restriction, all IP are authorised. + +// + 012.345.: front match form, or +// all: all IP are matched, or +// 012.345.678.901/24: network form (mask with # of bits), or +// 012.345.678.901/255.255.255.0: network form (mask with ip mask) +// + Note about the DNS resolution (like www.ne.jp, etc.): +// There is no guarantee to have an answer. +// If we have an answer, there is no guarantee to have a 100% correct value. +// And, the waiting time (to check) can be long (over 1 minute to a timeout). That can block the software. +// So, DNS notation isn't authorised for ip checking. + sprintf (buf, "%d.%d.%d.%d.", p[0], p[1], p[2], p[3]); + + for (i = 0; i < access_allownum; i++) + { + const char *p = access_allow + i * ACO_STRSIZE; + if (memcmp (p, buf, strlen (p)) == 0 || check_ipmask (ip, p)) + { + flag = ACF_ALLOW; + if (access_order == ACO_ALLOW_DENY) + return 1; // With 'allow, deny' (deny if not allow), allow has priority + break; + } + } + + for (i = 0; i < access_denynum; i++) + { + const char *p = access_deny + i * ACO_STRSIZE; + if (memcmp (p, buf, strlen (p)) == 0 || check_ipmask (ip, p)) + { + flag = ACF_DENY; + return 0; // At this point, if it's 'deny', we refuse connection. + break; + } + } + + return (flag == ACF_ALLOW || access_order == ACO_DENY_ALLOW) ? 1 : 0; + // With 'mutual-failture', only 'allow' and non 'deny' IP are authorised. + // A non 'allow' (even non 'deny') IP is not authorised. It's like: if allowed and not denied, it's authorised. + // So, it's disapproval if you have no description at the time of 'mutual-failture'. + // With 'deny,allow' (allow if not deny), because here it's not deny, we authorise. +} + +//-------------------------------- +// Access control by IP for ladmin +//-------------------------------- +int check_ladminip (unsigned int ip) +{ + int i; + unsigned char *p = (unsigned char *) &ip; + char buf[32]; + + if (access_ladmin_allownum == 0) + return 1; // When there is no restriction, all IP are authorised. + +// + 012.345.: front match form, or +// all: all IP are matched, or +// 012.345.678.901/24: network form (mask with # of bits), or +// 012.345.678.901/255.255.255.0: network form (mask with ip mask) +// + Note about the DNS resolution (like www.ne.jp, etc.): +// There is no guarantee to have an answer. +// If we have an answer, there is no guarantee to have a 100% correct value. +// And, the waiting time (to check) can be long (over 1 minute to a timeout). That can block the software. +// So, DNS notation isn't authorised for ip checking. + sprintf (buf, "%d.%d.%d.%d.", p[0], p[1], p[2], p[3]); + + for (i = 0; i < access_ladmin_allownum; i++) + { + const char *p = access_ladmin_allow + i * ACO_STRSIZE; + if (memcmp (p, buf, strlen (p)) == 0 || check_ipmask (ip, p)) + { + return 1; + } + } + + return 0; +} + +//----------------------------------------------------- +// Function to suppress control characters in a string. +//----------------------------------------------------- +int remove_control_chars (unsigned char *str) +{ + int i; + int change = 0; + + for (i = 0; str[i]; i++) + { + if (str[i] < 32) + { + str[i] = '_'; + change = 1; + } + } + + return change; +} + +//--------------------------------------------------- +// E-mail check: return 0 (not correct) or 1 (valid). +//--------------------------------------------------- +int e_mail_check (unsigned char *email) +{ + char ch; + unsigned char *last_arobas; + + // athena limits + if (strlen (email) < 3 || strlen (email) > 39) + return 0; + + // part of RFC limits (official reference of e-mail description) + if (strchr (email, '@') == NULL || email[strlen (email) - 1] == '@') + return 0; + + if (email[strlen (email) - 1] == '.') + return 0; + + last_arobas = strrchr (email, '@'); + + if (strstr (last_arobas, "@.") != NULL || + strstr (last_arobas, "..") != NULL) + return 0; + + for (ch = 1; ch < 32; ch++) + { + if (strchr (last_arobas, ch) != NULL) + { + return 0; + break; + } + } + + if (strchr (last_arobas, ' ') != NULL || + strchr (last_arobas, ';') != NULL) + return 0; + + // all correct + return 1; +} + +//----------------------------------------------- +// Search an account id +// (return account index or -1 (if not found)) +// If exact account name is not found, +// the function checks without case sensitive +// and returns index if only 1 account is found +// and similar to the searched name. +//----------------------------------------------- +int search_account_index (char *account_name) +{ + int i, quantity, index; + + quantity = 0; + index = -1; + for (i = 0; i < auth_num; i++) + { + // Without case sensitive check (increase the number of similar account names found) + if (strcasecmp (auth_dat[i].userid, account_name) == 0) + { + // Strict comparison (if found, we finish the function immediatly with correct value) + if (strcmp (auth_dat[i].userid, account_name) == 0) + return i; + quantity++; + index = i; + } + } + // Here, the exact account name is not found + // We return the found index of a similar account ONLY if there is 1 similar account + if (quantity == 1) + return index; + + // Exact account name is not found and 0 or more than 1 similar accounts have been found ==> we say not found + return -1; +} + +//-------------------------------------------------------- +// Create a string to save the account in the account file +//-------------------------------------------------------- +int mmo_auth_tostr (char *str, struct auth_dat *p) +{ + int i; + char *str_p = str; + + str_p += sprintf (str_p, "%d\t%s\t%s\t%s\t%c\t%d\t%d\t" + "%s\t%s\t%ld\t%s\t%s\t%ld\t", + p->account_id, p->userid, p->pass, p->lastlogin, + (p->sex == 2) ? 'S' : (p->sex ? 'M' : 'F'), + p->logincount, p->state, + p->email, p->error_message, + p->connect_until_time, p->last_ip, p->memo, + p->ban_until_time); + + for (i = 0; i < p->account_reg2_num; i++) + if (p->account_reg2[i].str[0]) + str_p += + sprintf (str_p, "%s,%d ", p->account_reg2[i].str, + p->account_reg2[i].value); + + return 0; +} + +//--------------------------------- +// Reading of the accounts database +//--------------------------------- +int mmo_auth_init (void) +{ + FILE *fp; + int account_id, logincount, state, n, i, j, v; + char line[2048], *p, userid[2048], pass[2048], lastlogin[2048], sex, + email[2048], error_message[2048], last_ip[2048], memo[2048]; + time_t ban_until_time; + time_t connect_until_time; + char str[2048]; + int GM_count = 0; + int server_count = 0; + + CREATE (auth_dat, struct auth_dat, 256); + auth_max = 256; + + fp = fopen_ (account_filename, "r"); + if (fp == NULL) + { + // no account file -> no account -> no login, including char-server (ERROR) + printf + ("\033[1;31mmmo_auth_init: Accounts file [%s] not found.\033[0m\n", + account_filename); + return 0; + } + + while (fgets (line, sizeof (line) - 1, fp) != NULL) + { + if (line[0] == '/' && line[1] == '/') + continue; + line[sizeof (line) - 1] = '\0'; + p = line; + + // database version reading (v2) + if (((i = sscanf (line, "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%d\t" + "%[^\t]\t%[^\t]\t%ld\t%[^\t]\t%[^\t]\t%ld%n", + &account_id, userid, pass, lastlogin, &sex, + &logincount, &state, email, error_message, + &connect_until_time, last_ip, memo, &ban_until_time, + &n)) == 13 && line[n] == '\t') + || + ((i = + sscanf (line, + "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%d\t" + "%[^\t]\t%[^\t]\t%ld\t%[^\t]\t%[^\t]%n", &account_id, + userid, pass, lastlogin, &sex, &logincount, &state, + email, error_message, &connect_until_time, last_ip, + memo, &n)) == 12 && line[n] == '\t')) + { + n = n + 1; + + // Some checks + if (account_id > END_ACCOUNT_NUM) + { + printf + ("\033[1;31mmmo_auth_init: ******Error: an account has an id higher than %d\n", + END_ACCOUNT_NUM); + printf + (" account id #%d -> account not read (saved in log file).\033[0m\n", + account_id); + login_log + ("mmmo_auth_init: ******Error: an account has an id higher than %d.\n", + END_ACCOUNT_NUM); + login_log + (" account id #%d -> account not read (saved in next line):\n", + account_id); + login_log ("%s", line); + continue; + } + userid[23] = '\0'; + remove_control_chars (userid); + for (j = 0; j < auth_num; j++) + { + if (auth_dat[j].account_id == account_id) + { + printf + ("\033[1;31mmmo_auth_init: ******Error: an account has an identical id to another.\n"); + printf + (" account id #%d -> new account not read (saved in log file).\033[0m\n", + account_id); + login_log + ("mmmo_auth_init: ******Error: an account has an identical id to another.\n"); + login_log + (" account id #%d -> new account not read (saved in next line):\n", + account_id); + login_log ("%s", line); + break; + } + else if (strcmp (auth_dat[j].userid, userid) == 0) + { + printf + ("\033[1;31mmmo_auth_init: ******Error: account name already exists.\n"); + printf (" account name '%s' -> new account not read.\n", userid); // 2 lines, account name can be long. + printf + (" Account saved in log file.\033[0m\n"); + login_log + ("mmmo_auth_init: ******Error: an account has an identical id to another.\n"); + login_log + (" account id #%d -> new account not read (saved in next line):\n", + account_id); + login_log ("%s", line); + break; + } + } + if (j != auth_num) + continue; + + if (auth_num >= auth_max) + { + auth_max += 256; + RECREATE (auth_dat, struct auth_dat, auth_max); + } + + memset (&auth_dat[auth_num], '\0', sizeof (struct auth_dat)); + + auth_dat[auth_num].account_id = account_id; + + strncpy (auth_dat[auth_num].userid, userid, 24); + + memo[254] = '\0'; + remove_control_chars (memo); + strncpy (auth_dat[auth_num].memo, memo, 255); + + pass[39] = '\0'; + remove_control_chars (pass); + // If a password is not encrypted, we encrypt it now. + // A password beginning with ! and - in the memo field is our magic + if (pass[0] != '!' && memo[0] == '-') { + strcpy(auth_dat[auth_num].pass, MD5_saltcrypt(pass, make_salt())); + auth_dat[auth_num].memo[0] = '!'; + printf("encrypting pass: %s %s\n", pass, auth_dat[auth_num].pass); + } + else + strcpy(auth_dat[auth_num].pass, pass); + + lastlogin[23] = '\0'; + remove_control_chars (lastlogin); + strncpy (auth_dat[auth_num].lastlogin, lastlogin, 24); + + auth_dat[auth_num].sex = (sex == 'S' + || sex == 's') ? 2 : (sex == 'M' + || sex == 'm'); + + if (logincount >= 0) + auth_dat[auth_num].logincount = logincount; + else + auth_dat[auth_num].logincount = 0; + + if (state > 255) + auth_dat[auth_num].state = 100; + else if (state < 0) + auth_dat[auth_num].state = 0; + else + auth_dat[auth_num].state = state; + + if (e_mail_check (email) == 0) + { + printf + ("Account %s (%d): invalid e-mail (replaced par a@a.com).\n", + auth_dat[auth_num].userid, + auth_dat[auth_num].account_id); + strncpy (auth_dat[auth_num].email, "a@a.com", 40); + } + else + { + remove_control_chars (email); + strncpy (auth_dat[auth_num].email, email, 40); + } + + error_message[19] = '\0'; + remove_control_chars (error_message); + if (error_message[0] == '\0' || state != 7) + { // 7, because state is packet 0x006a value + 1 + strncpy (auth_dat[auth_num].error_message, "-", 20); + } + else + { + strncpy (auth_dat[auth_num].error_message, error_message, 20); + } + + if (i == 13) + auth_dat[auth_num].ban_until_time = ban_until_time; + else + auth_dat[auth_num].ban_until_time = 0; + + auth_dat[auth_num].connect_until_time = connect_until_time; + + last_ip[15] = '\0'; + remove_control_chars (last_ip); + strncpy (auth_dat[auth_num].last_ip, last_ip, 16); + + for (j = 0; j < ACCOUNT_REG2_NUM; j++) + { + p += n; + if (sscanf (p, "%[^\t,],%d %n", str, &v, &n) != 2) + { + // We must check if a str is void. If it's, we can continue to read other REG2. + // Account line will have something like: str2,9 ,9 str3,1 (here, ,9 is not good) + if (p[0] == ',' && sscanf (p, ",%d %n", &v, &n) == 1) + { + j--; + continue; + } + else + break; + } + str[31] = '\0'; + remove_control_chars (str); + strncpy (auth_dat[auth_num].account_reg2[j].str, str, 32); + auth_dat[auth_num].account_reg2[j].value = v; + } + auth_dat[auth_num].account_reg2_num = j; + + if (isGM (account_id) > 0) + GM_count++; + if (auth_dat[auth_num].sex == 2) + server_count++; + + auth_num++; + if (account_id >= account_id_count) + account_id_count = account_id + 1; + + // Old athena database version reading (v1) + } + else if ((i = + sscanf (line, "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%d\t%n", + &account_id, userid, pass, lastlogin, &sex, + &logincount, &state, &n)) >= 5) + { + if (account_id > END_ACCOUNT_NUM) + { + printf + ("\033[1;31mmmo_auth_init: ******Error: an account has an id higher than %d\n", + END_ACCOUNT_NUM); + printf + (" account id #%d -> account not read (saved in log file).\033[0m\n", + account_id); + login_log + ("mmmo_auth_init: ******Error: an account has an id higher than %d.\n", + END_ACCOUNT_NUM); + login_log + (" account id #%d -> account not read (saved in next line):\n", + account_id); + login_log ("%s", line); + continue; + } + userid[23] = '\0'; + remove_control_chars (userid); + for (j = 0; j < auth_num; j++) + { + if (auth_dat[j].account_id == account_id) + { + printf + ("\033[1;31mmmo_auth_init: ******Error: an account has an identical id to another.\n"); + printf + (" account id #%d -> new account not read (saved in log file).\033[0m\n", + account_id); + login_log + ("mmmo_auth_init: ******Error: an account has an identical id to another.\n"); + login_log + (" account id #%d -> new account not read (saved in next line):\n", + account_id); + login_log ("%s", line); + break; + } + else if (strcmp (auth_dat[j].userid, userid) == 0) + { + printf + ("\033[1;31mmmo_auth_init: ******Error: account name already exists.\n"); + printf (" account name '%s' -> new account not read.\n", userid); // 2 lines, account name can be long. + printf + (" Account saved in log file.\033[0m\n"); + login_log + ("mmmo_auth_init: ******Error: an account has an identical id to another.\n"); + login_log + (" account id #%d -> new account not read (saved in next line):\n", + account_id); + login_log ("%s", line); + break; + } + } + if (j != auth_num) + continue; + + if (auth_num >= auth_max) + { + auth_max += 256; + RECREATE (auth_dat, struct auth_dat, auth_max); + } + + memset (&auth_dat[auth_num], '\0', sizeof (struct auth_dat)); + + auth_dat[auth_num].account_id = account_id; + + strncpy (auth_dat[auth_num].userid, userid, 24); + + lastlogin[23] = '\0'; + remove_control_chars (lastlogin); + strncpy (auth_dat[auth_num].lastlogin, lastlogin, 24); + + auth_dat[auth_num].sex = (sex == 'S' + || sex == 's') ? 2 : (sex == 'M' + || sex == 'm'); + + if (i >= 6) + { + if (logincount >= 0) + auth_dat[auth_num].logincount = logincount; + else + auth_dat[auth_num].logincount = 0; + } + else + auth_dat[auth_num].logincount = 0; + + if (i >= 7) + { + if (state > 255) + auth_dat[auth_num].state = 100; + else if (state < 0) + auth_dat[auth_num].state = 0; + else + auth_dat[auth_num].state = state; + } + else + auth_dat[auth_num].state = 0; + + // Initialization of new data + strncpy (auth_dat[auth_num].email, "a@a.com", 40); + strncpy (auth_dat[auth_num].error_message, "-", 20); + auth_dat[auth_num].ban_until_time = 0; + auth_dat[auth_num].connect_until_time = 0; + strncpy (auth_dat[auth_num].last_ip, "-", 16); + strncpy (auth_dat[auth_num].memo, "!", 255); + + for (j = 0; j < ACCOUNT_REG2_NUM; j++) + { + p += n; + if (sscanf (p, "%[^\t,],%d %n", str, &v, &n) != 2) + { + // We must check if a str is void. If it's, we can continue to read other REG2. + // Account line will have something like: str2,9 ,9 str3,1 (here, ,9 is not good) + if (p[0] == ',' && sscanf (p, ",%d %n", &v, &n) == 1) + { + j--; + continue; + } + else + break; + } + str[31] = '\0'; + remove_control_chars (str); + strncpy (auth_dat[auth_num].account_reg2[j].str, str, 32); + auth_dat[auth_num].account_reg2[j].value = v; + } + auth_dat[auth_num].account_reg2_num = j; + + if (isGM (account_id) > 0) + GM_count++; + if (auth_dat[auth_num].sex == 2) + server_count++; + + auth_num++; + if (account_id >= account_id_count) + account_id_count = account_id + 1; + + } + else + { + i = 0; + if (sscanf (line, "%d\t%%newid%%\n%n", &account_id, &i) == 1 && + i > 0 && account_id > account_id_count) + account_id_count = account_id; + } + } + fclose_ (fp); + + if (auth_num == 0) + { + printf ("mmo_auth_init: No account found in %s.\n", account_filename); + sprintf (line, "No account found in %s.", account_filename); + } + else + { + if (auth_num == 1) + { + printf ("mmo_auth_init: 1 account read in %s,\n", + account_filename); + sprintf (line, "1 account read in %s,", account_filename); + } + else + { + printf ("mmo_auth_init: %d accounts read in %s,\n", auth_num, + account_filename); + sprintf (line, "%d accounts read in %s,", auth_num, + account_filename); + } + if (GM_count == 0) + { + printf (" of which is no GM account, and "); + sprintf (str, "%s of which is no GM account and", line); + } + else if (GM_count == 1) + { + printf (" of which is 1 GM account, and "); + sprintf (str, "%s of which is 1 GM account and", line); + } + else + { + printf (" of which is %d GM accounts, and ", + GM_count); + sprintf (str, "%s of which is %d GM accounts and", line, + GM_count); + } + if (server_count == 0) + { + printf ("no server account ('S').\n"); + sprintf (line, "%s no server account ('S').", str); + } + else if (server_count == 1) + { + printf ("1 server account ('S').\n"); + sprintf (line, "%s 1 server account ('S').", str); + } + else + { + printf ("%d server accounts ('S').\n", server_count); + sprintf (line, "%s %d server accounts ('S').", str, server_count); + } + } + login_log ("%s\n", line); + + return 0; +} + +//------------------------------------------ +// Writing of the accounts database file +// (accounts are sorted by id before save) +//------------------------------------------ +void mmo_auth_sync (void) +{ + FILE *fp; + int i, j, k, lock; + int id[auth_num]; + char line[65536]; + + // Sorting before save + for (i = 0; i < auth_num; i++) + { + id[i] = i; + for (j = 0; j < i; j++) + { + if (auth_dat[i].account_id < auth_dat[id[j]].account_id) + { + for (k = i; k > j; k--) + id[k] = id[k - 1]; + id[j] = i; // id[i] + break; + } + } + } + + // Data save + fp = lock_fopen (account_filename, &lock); + if (fp == NULL) + return; + fprintf (fp, + "// Accounts file: here are saved all information about the accounts.\n"); + fprintf (fp, + "// Structure: ID, account name, password, last login time, sex, # of logins, state, email, error message for state 7, validity time, last (accepted) login ip, memo field, ban timestamp, repeated(register text, register value)\n"); + fprintf (fp, "// Some explanations:\n"); + fprintf (fp, + "// account name : between 4 to 23 char for a normal account (standard client can't send less than 4 char).\n"); + fprintf (fp, "// account password: between 4 to 23 char\n"); + fprintf (fp, + "// sex : M or F for normal accounts, S for server accounts\n"); + fprintf (fp, + "// state : 0: account is ok, 1 to 256: error code of packet 0x006a + 1\n"); + fprintf (fp, + "// email : between 3 to 39 char (a@a.com is like no email)\n"); + fprintf (fp, + "// error message : text for the state 7: 'Your are Prohibited to login until '. Max 19 char\n"); + fprintf (fp, + "// valitidy time : 0: unlimited account, : date calculated by addition of 1/1/1970 + value (number of seconds since the 1/1/1970)\n"); + fprintf (fp, "// memo field : max 254 char\n"); + fprintf (fp, + "// ban time : 0: no ban, : banned until the date: date calculated by addition of 1/1/1970 + value (number of seconds since the 1/1/1970)\n"); + for (i = 0; i < auth_num; i++) + { + k = id[i]; // use of sorted index + if (auth_dat[k].account_id < 0) + continue; + + mmo_auth_tostr (line, &auth_dat[k]); + fprintf (fp, "%s\n", line); + } + fprintf (fp, "%d\t%%newid%%\n", account_id_count); + + lock_fclose (fp, account_filename, &lock); + + return; +} + +// We want to sync the DB to disk as little as possible as it's fairly +// resource intensive. therefore most player-triggerable events that +// update the account DB will not immideately trigger a save. Instead +// we save periodicly on a timer. +//----------------------------------------------------- +void check_auth_sync (timer_id tid, tick_t tick, custom_id_t id, custom_data_t data) +{ + if (pid != 0) + { + int status; + pid_t temp = waitpid (pid, &status, WNOHANG); + + // Need to check status too? + if (temp == 0) + { + return; + } + } + + // This can take a lot of time. Fork a child to handle the work and return at once + // If we're unable to fork just continue running the function normally + if ((pid = fork ()) > 0) + return; + + mmo_auth_sync (); + + // If we're a child we should suicide now. + if (pid == 0) + _exit (0); + + return; +} + +//-------------------------------------------------------------------- +// Packet send to all char-servers, except one (wos: without our self) +//-------------------------------------------------------------------- +int charif_sendallwos (int sfd, unsigned char *buf, unsigned int len) +{ + int i, c; + + for (i = 0, c = 0; i < MAX_SERVERS; i++) + { + int fd; + if ((fd = server_fd[i]) >= 0 && fd != sfd) + { + memcpy (WFIFOP (fd, 0), buf, len); + WFIFOSET (fd, len); + c++; + } + } + return c; +} + +//----------------------------------------------------- +// Send GM accounts to all char-server +//----------------------------------------------------- +void send_GM_accounts (void) +{ + int i; + char buf[32000]; + int GM_value; + int len; + + len = 4; + WBUFW (buf, 0) = 0x2732; + for (i = 0; i < auth_num; i++) + // send only existing accounts. We can not create a GM account when server is online. + if ((GM_value = isGM (auth_dat[i].account_id)) > 0) + { + WBUFL (buf, len) = auth_dat[i].account_id; + WBUFB (buf, len + 4) = (unsigned char) GM_value; + len += 5; + } + WBUFW (buf, 2) = len; + charif_sendallwos (-1, buf, len); + + return; +} + +//----------------------------------------------------- +// Check if GM file account have been changed +//----------------------------------------------------- +void check_GM_file (timer_id tid, tick_t tick, custom_id_t id, custom_data_t data) +{ + struct stat file_stat; + long new_time; + + // if we would not check + if (gm_account_filename_check_timer < 1) + return; + + // get last modify time/date + if (stat (GM_account_filename, &file_stat)) + new_time = 0; // error + else + new_time = file_stat.st_mtime; + + if (new_time != creation_time_GM_account_file) + { + read_gm_account (); + send_GM_accounts (); + } +} + +//------------------------------------- +// Account creation (with e-mail check) +//------------------------------------- +int mmo_auth_new (struct mmo_account *account, char sex, char *email) +{ + time_t timestamp, timestamp_temp; + struct tm *tmtime; + int i = auth_num; + + if (auth_num >= auth_max) + { + auth_max += 256; + RECREATE (auth_dat, struct auth_dat, auth_max); + } + + memset (&auth_dat[i], '\0', sizeof (struct auth_dat)); + + while (isGM (account_id_count) > 0) + account_id_count++; + + auth_dat[i].account_id = account_id_count++; + + strncpy (auth_dat[i].userid, account->userid, 24); + auth_dat[i].userid[23] = '\0'; + + strcpy(auth_dat[i].pass, MD5_saltcrypt(account->passwd, make_salt())); + auth_dat[i].pass[39] = '\0'; + + memcpy (auth_dat[i].lastlogin, "-", 2); + + auth_dat[i].sex = (sex == 'M'); + + auth_dat[i].logincount = 0; + + auth_dat[i].state = 0; + + if (e_mail_check (email) == 0) + strncpy (auth_dat[i].email, "a@a.com", 40); + else + strncpy (auth_dat[i].email, email, 40); + + strncpy (auth_dat[i].error_message, "-", 20); + + auth_dat[i].ban_until_time = 0; + + if (start_limited_time < 0) + auth_dat[i].connect_until_time = 0; // unlimited + else + { // limited time + timestamp = time (NULL) + start_limited_time; + // double conversion to be sure that it is possible + tmtime = gmtime (×tamp); + timestamp_temp = mktime (tmtime); + if (timestamp_temp != -1 && (timestamp_temp + 3600) >= timestamp) // check possible value and overflow (and avoid summer/winter hour) + auth_dat[i].connect_until_time = timestamp_temp; + else + auth_dat[i].connect_until_time = 0; // unlimited + } + + strncpy (auth_dat[i].last_ip, "-", 16); + + strncpy (auth_dat[i].memo, "!", 255); + + auth_dat[i].account_reg2_num = 0; + + auth_num++; + + return (account_id_count - 1); +} + +//--------------------------------------- +// Check/authentification of a connection +//--------------------------------------- +int mmo_auth (struct mmo_account *account, int fd) +{ + int i; + struct timeval tv; + char tmpstr[256]; + int len, newaccount = 0; +#ifdef PASSWDENC + char md5str[64], md5bin[32]; +#endif + char ip[16]; + unsigned char *sin_addr = + (unsigned char *) &session[fd]->client_addr.sin_addr; + + sprintf (ip, "%d.%d.%d.%d", sin_addr[0], sin_addr[1], sin_addr[2], + sin_addr[3]); + + len = strlen (account->userid) - 2; + // Account creation with _M/_F + if (account->passwdenc == 0 && account->userid[len] == '_' && + (account->userid[len + 1] == 'F' || account->userid[len + 1] == 'M') + && new_account_flag == 1 && account_id_count <= END_ACCOUNT_NUM + && len >= 4 && strlen (account->passwd) >= 4) + { + if (new_account_flag == 1) + newaccount = 1; + account->userid[len] = '\0'; + } + + // Strict account search + for (i = 0; i < auth_num; i++) + { + if (strcmp (account->userid, auth_dat[i].userid) == 0) + break; + } + // if there is no creation request and strict account search fails, we do a no sensitive case research for index + if (newaccount == 0 && i == auth_num) + { + i = search_account_index (account->userid); + if (i == -1) + i = auth_num; + else + memcpy (account->userid, auth_dat[i].userid, 24); // for the possible tests/checks afterwards (copy correcte sensitive case). + } + + if (i != auth_num) + { + int encpasswdok = 0; + struct login_session_data *ld; + if (newaccount) + { + login_log + ("Attempt of creation of an already existant account (account: %s_%c, ip: %s)\n", + account->userid, account->userid[len + 1], ip); + return 9; // 9 = Account already exists + } + ld = (struct login_session_data*) session[fd]->session_data; +#ifdef PASSWORDENC + if (account->passwdenc > 0) + { + int j = account->passwdenc; + if (!ld) + { + login_log ("Md5 key not created (account: %s, ip: %s)\n", + account->userid, ip); + return 1; // 1 = Incorrect Password + } + if (j > 2) + j = 1; + do + { + if (j == 1) + { + strncpy (md5str, ld->md5key, sizeof (ld->md5key)); // 20 + strcat (md5str, auth_dat[i].pass); // 24 + } + else if (j == 2) + { + strncpy (md5str, auth_dat[i].pass, sizeof (auth_dat[i].pass)); // 24 + strcat (md5str, ld->md5key); // 20 + } + else + md5str[0] = '\0'; + md5str[sizeof (md5str) - 1] = '\0'; // 64 + MD5_String2binary (md5str, md5bin); + encpasswdok = (memcmp (account->passwd, md5bin, 16) == 0); + } + while (j < 2 && !encpasswdok && (j++) != account->passwdenc); +// printf("key[%s] md5 [%s] ", md5key, md5); +// printf("client [%s] accountpass [%s]\n", account->passwd, auth_dat[i].pass); + } +#endif + if ((!pass_ok (account->passwd, auth_dat[i].pass)) && !encpasswdok) + { + if (account->passwdenc == 0) + login_log + ("Invalid password (account: %s, ip: %s)\n", + account->userid, ip); + +#ifdef PASSWORDENC + else + { + char logbuf[512], *p = logbuf; + int j; + p += sprintf (p, + "Invalid password (account: %s, received md5[", + account->userid); + for (j = 0; j < 16; j++) + p += sprintf (p, "%02x", + ((unsigned char *) account->passwd)[j]); + p += sprintf (p, "] calculated md5["); + for (j = 0; j < 16; j++) + p += sprintf (p, "%02x", ((unsigned char *) md5bin)[j]); + p += sprintf (p, "] md5 key["); + for (j = 0; j < ld->md5keylen; j++) + p += sprintf (p, "%02x", + ((unsigned char *) ld->md5key)[j]); + p += sprintf (p, "], ip: %s)\n", ip); + login_log (logbuf); + } +#endif + return 1; // 1 = Incorrect Password + } + + if (auth_dat[i].state) + { + login_log + ("Connection refused (account: %s, state: %d, ip: %s)\n", + account->userid, auth_dat[i].state, + ip); + switch (auth_dat[i].state) + { // packet 0x006a value + 1 + case 1: // 0 = Unregistered ID + case 2: // 1 = Incorrect Password + case 3: // 2 = This ID is expired + case 4: // 3 = Rejected from Server + case 5: // 4 = You have been blocked by the GM Team + case 6: // 5 = Your Game's EXE file is not the latest version + case 7: // 6 = Your are Prohibited to log in until %s + case 8: // 7 = Server is jammed due to over populated + case 9: // 8 = No MSG (actually, all states after 9 except 99 are No MSG, use only this) + case 100: // 99 = This ID has been totally erased + return auth_dat[i].state - 1; + break; + default: + return 99; // 99 = ID has been totally erased + break; + } + } + + if (auth_dat[i].ban_until_time != 0) + { // if account is banned + strftime (tmpstr, 20, date_format, + gmtime (&auth_dat[i].ban_until_time)); + tmpstr[19] = '\0'; + if (auth_dat[i].ban_until_time > time (NULL)) + { // always banned + login_log + ("Connection refused (account: %s, banned until %s, ip: %s)\n", + account->userid, tmpstr, ip); + return 6; // 6 = Your are Prohibited to log in until %s + } + else + { // ban is finished + login_log + ("End of ban (account: %s, previously banned until %s -> not more banned, ip: %s)\n", + account->userid, tmpstr, ip); + auth_dat[i].ban_until_time = 0; // reset the ban time + } + } + + if (auth_dat[i].connect_until_time != 0 + && auth_dat[i].connect_until_time < time (NULL)) + { + login_log + ("Connection refused (account: %s, expired ID, ip: %s)\n", + account->userid, ip); + return 2; // 2 = This ID is expired + } + + login_log ("Authentification accepted (account: %s (id: %d), ip: %s)\n", + account->userid, auth_dat[i].account_id, ip); + } + else + { + if (newaccount == 0) + { + login_log + ("Unknown account (account: %s, ip: %s)\n", + account->userid, ip); + return 0; // 0 = Unregistered ID + } + else + { + int new_id = + mmo_auth_new (account, account->userid[len + 1], "a@a.com"); + login_log + ("Account creation and authentification accepted (account %s (id: %d), sex: %c, connection with _F/_M, ip: %s)\n", + account->userid, new_id, + account->userid[len + 1], ip); + } + } + + gettimeofday (&tv, NULL); + strftime (tmpstr, 24, date_format, gmtime (&(tv.tv_sec))); + sprintf (tmpstr + strlen (tmpstr), ".%03d", (int) tv.tv_usec / 1000); + + account->account_id = auth_dat[i].account_id; + account->login_id1 = mt_random (); + account->login_id2 = mt_random (); + memcpy (account->lastlogin, auth_dat[i].lastlogin, 24); + memcpy (auth_dat[i].lastlogin, tmpstr, 24); + account->sex = auth_dat[i].sex; + strncpy (auth_dat[i].last_ip, ip, 16); + auth_dat[i].logincount++; + + return -1; // account OK +} + +//------------------------------- +// Char-server anti-freeze system +//------------------------------- +void char_anti_freeze_system (timer_id tid, tick_t tick, custom_id_t id, custom_data_t data) +{ + int i; + + //printf("Entering in char_anti_freeze_system function to check freeze of servers.\n"); + for (i = 0; i < MAX_SERVERS; i++) + { + if (server_fd[i] >= 0) + { // if char-server is online + //printf("char_anti_freeze_system: server #%d '%s', flag: %d.\n", i, server[i].name, server_freezeflag[i]); + if (server_freezeflag[i]-- < 1) + { // Char-server anti-freeze system. Counter. 5 ok, 4...0 freezed + printf + ("Char-server anti-freeze system: char-server #%d '%s' is freezed -> disconnection.\n", + i, server[i].name); + login_log + ("Char-server anti-freeze system: char-server #%d '%s' is freezed -> disconnection.\n", + i, server[i].name); + session[server_fd[i]]->eof = 1; + } + } + } +} + +//-------------------------------- +// Packet parsing for char-servers +//-------------------------------- +void parse_fromchar (int fd) +{ + int i, j, id; + unsigned char *p = (unsigned char *) &session[fd]->client_addr.sin_addr; + char ip[16]; + + sprintf (ip, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); + + for (id = 0; id < MAX_SERVERS; id++) + if (server_fd[id] == fd) + break; + if (id == MAX_SERVERS || session[fd]->eof) + { + if (id < MAX_SERVERS) + { + printf ("Char-server '%s' has disconnected.\n", server[id].name); + login_log ("Char-server '%s' has disconnected (ip: %s).\n", + server[id].name, ip); + server_fd[id] = -1; + memset (&server[id], 0, sizeof (struct mmo_char_server)); + } + close (fd); + delete_session (fd); + return; + } + + while (RFIFOREST (fd) >= 2) + { + if (display_parse_fromchar == 2 || (display_parse_fromchar == 1 && RFIFOW (fd, 0) != 0x2714)) // 0x2714 is done very often (number of players) + printf + ("parse_fromchar: connection #%d, packet: 0x%x (with being read: %d bytes).\n", + fd, RFIFOW (fd, 0), RFIFOREST (fd)); + + switch (RFIFOW (fd, 0)) + { + // request from map-server via char-server to reload GM accounts (by Yor). + case 0x2709: + login_log + ("Char-server '%s': Request to re-load GM configuration file (ip: %s).\n", + server[id].name, ip); + read_gm_account (); + // send GM accounts to all char-servers + send_GM_accounts (); + RFIFOSKIP (fd, 2); + break; + + case 0x2712: // request from char-server to authentify an account + if (RFIFOREST (fd) < 19) + return; + { + int acc; + acc = RFIFOL (fd, 2); // speed up + for (i = 0; i < AUTH_FIFO_SIZE; i++) + { + if (auth_fifo[i].account_id == acc && + auth_fifo[i].login_id1 == RFIFOL (fd, 6) && +#if CMP_AUTHFIFO_LOGIN2 != 0 + auth_fifo[i].login_id2 == RFIFOL (fd, 10) && // relate to the versions higher than 18 +#endif + auth_fifo[i].sex == RFIFOB (fd, 14) && + (!check_ip_flag + || auth_fifo[i].ip == RFIFOL (fd, 15)) + && !auth_fifo[i].delflag) + { + int p, k; + auth_fifo[i].delflag = 1; + login_log + ("Char-server '%s': authentification of the account %d accepted (ip: %s).\n", + server[id].name, acc, ip); +// printf("%d\n", i); + for (k = 0; k < auth_num; k++) + { + if (auth_dat[k].account_id == acc) + { + WFIFOW (fd, 0) = 0x2729; // Sending of the account_reg2 + WFIFOL (fd, 4) = acc; + for (p = 8, j = 0; + j < auth_dat[k].account_reg2_num; + p += 36, j++) + { + memcpy (WFIFOP (fd, p), + auth_dat[k]. + account_reg2[j].str, 32); + WFIFOL (fd, p + 32) = + auth_dat[k].account_reg2[j].value; + } + WFIFOW (fd, 2) = p; + WFIFOSET (fd, p); +// printf("parse_fromchar: Sending of account_reg2: login->char (auth fifo)\n"); + WFIFOW (fd, 0) = 0x2713; + WFIFOL (fd, 2) = acc; + WFIFOB (fd, 6) = 0; + memcpy (WFIFOP (fd, 7), auth_dat[k].email, + 40); + WFIFOL (fd, 47) = + (unsigned long) + auth_dat[k].connect_until_time; + WFIFOSET (fd, 51); + break; + } + } + break; + } + } + // authentification not found + if (i == AUTH_FIFO_SIZE) + { + login_log + ("Char-server '%s': authentification of the account %d REFUSED (ip: %s).\n", + server[id].name, acc, ip); + WFIFOW (fd, 0) = 0x2713; + WFIFOL (fd, 2) = acc; + WFIFOB (fd, 6) = 1; + // It is unnecessary to send email + // It is unnecessary to send validity date of the account + WFIFOSET (fd, 51); + } + } + RFIFOSKIP (fd, 19); + break; + + case 0x2714: + if (RFIFOREST (fd) < 6) + return; + //printf("parse_fromchar: Receiving of the users number of the server '%s': %d\n", server[id].name, RFIFOL(fd,2)); + server[id].users = RFIFOL (fd, 2); + if (anti_freeze_enable) + server_freezeflag[id] = 5; // Char anti-freeze system. Counter. 5 ok, 4...0 freezed + RFIFOSKIP (fd, 6); + break; + + // we receive a e-mail creation of an account with a default e-mail (no answer) + case 0x2715: + { + int acc; + char email[40]; + if (RFIFOREST (fd) < 46) + return; + acc = RFIFOL (fd, 2); // speed up + memcpy (email, RFIFOP (fd, 6), 40); + email[39] = '\0'; + remove_control_chars (email); + //printf("parse_fromchar: an e-mail creation of an account with a default e-mail: server '%s', account: %d, e-mail: '%s'.\n", server[id].name, acc, RFIFOP(fd,6)); + if (e_mail_check (email) == 0) + login_log + ("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - e-mail is invalid (account: %d, ip: %s)\n", + server[id].name, acc, ip); + else + { + for (i = 0; i < auth_num; i++) + { + if (auth_dat[i].account_id == acc + && (strcmp (auth_dat[i].email, "a@a.com") == 0 + || auth_dat[i].email[0] == '\0')) + { + memcpy (auth_dat[i].email, email, 40); + login_log + ("Char-server '%s': Create an e-mail on an account with a default e-mail (account: %d, new e-mail: %s, ip: %s).\n", + server[id].name, acc, email, ip); + break; + } + } + if (i == auth_num) + login_log + ("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - account doesn't exist or e-mail of account isn't default e-mail (account: %d, ip: %s).\n", + server[id].name, acc, ip); + } + RFIFOSKIP (fd, 46); + break; + + // We receive an e-mail/limited time request, because a player comes back from a map-server to the char-server + } + case 0x2716: + if (RFIFOREST (fd) < 6) + return; + //printf("parse_fromchar: E-mail/limited time request from '%s' server (concerned account: %d)\n", server[id].name, RFIFOL(fd,2)); + for (i = 0; i < auth_num; i++) + { + if (auth_dat[i].account_id == RFIFOL (fd, 2)) + { + login_log + ("Char-server '%s': e-mail of the account %d found (ip: %s).\n", + server[id].name, RFIFOL (fd, 2), ip); + WFIFOW (fd, 0) = 0x2717; + WFIFOL (fd, 2) = RFIFOL (fd, 2); + memcpy (WFIFOP (fd, 6), auth_dat[i].email, 40); + WFIFOL (fd, 46) = + (unsigned long) auth_dat[i].connect_until_time; + WFIFOSET (fd, 50); + break; + } + } + if (i == auth_num) + { + login_log + ("Char-server '%s': e-mail of the account %d NOT found (ip: %s).\n", + server[id].name, RFIFOL (fd, 2), ip); + } + RFIFOSKIP (fd, 6); + break; + + case 0x2720: // To become GM request + if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) + return; + { + int acc; + unsigned char buf[10]; + FILE *fp; + acc = RFIFOL (fd, 4); + //printf("parse_fromchar: Request to become a GM acount from %d account.\n", acc); + WBUFW (buf, 0) = 0x2721; + WBUFL (buf, 2) = acc; + WBUFL (buf, 6) = 0; + if (strcmp (RFIFOP (fd, 8), gm_pass) == 0) + { + // only non-GM can become GM + if (isGM (acc) == 0) + { + // if we autorise creation + if (level_new_gm > 0) + { + // if we can open the file to add the new GM + if ((fp = + fopen_ (GM_account_filename, + "a")) != NULL) + { + char tmpstr[24]; + struct timeval tv; + gettimeofday (&tv, NULL); + strftime (tmpstr, 23, date_format, + gmtime (&(tv.tv_sec))); + fprintf (fp, + "\n// %s: @GM command on account %d\n%d %d\n", + tmpstr, + acc, acc, level_new_gm); + fclose_ (fp); + WBUFL (buf, 6) = level_new_gm; + read_gm_account (); + send_GM_accounts (); + printf + ("GM Change of the account %d: level 0 -> %d.\n", + acc, level_new_gm); + login_log + ("Char-server '%s': GM Change of the account %d: level 0 -> %d (ip: %s).\n", + server[id].name, acc, + level_new_gm, ip); + } + else + { + printf + ("Error of GM change (suggested account: %d, correct password, unable to add a GM account in GM accounts file)\n", + acc); + login_log + ("Char-server '%s': Error of GM change (suggested account: %d, correct password, unable to add a GM account in GM accounts file, ip: %s).\n", + server[id].name, acc, ip); + } + } + else + { + printf + ("Error of GM change (suggested account: %d, correct password, but GM creation is disable (level_new_gm = 0))\n", + acc); + login_log + ("Char-server '%s': Error of GM change (suggested account: %d, correct password, but GM creation is disable (level_new_gm = 0), ip: %s).\n", + server[id].name, acc, ip); + } + } + else + { + printf + ("Error of GM change (suggested account: %d (already GM), correct password).\n", + acc); + login_log + ("Char-server '%s': Error of GM change (suggested account: %d (already GM), correct password, ip: %s).\n", + server[id].name, acc, ip); + } + } + else + { + printf + ("Error of GM change (suggested account: %d, invalid password).\n", + acc); + login_log + ("Char-server '%s': Error of GM change (suggested account: %d, invalid password, ip: %s).\n", + server[id].name, acc, ip); + } + charif_sendallwos (-1, buf, 10); + } + RFIFOSKIP (fd, RFIFOW (fd, 2)); + return; + + // Map server send information to change an email of an account via char-server + case 0x2722: // 0x2722 .L .40B .40B + if (RFIFOREST (fd) < 86) + return; + { + int acc; + char actual_email[40], new_email[40]; + acc = RFIFOL (fd, 2); + memcpy (actual_email, RFIFOP (fd, 6), 40); + actual_email[39] = '\0'; + remove_control_chars (actual_email); + memcpy (new_email, RFIFOP (fd, 46), 40); + new_email[39] = '\0'; + remove_control_chars (new_email); + if (e_mail_check (actual_email) == 0) + login_log + ("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual email is invalid (account: %d, ip: %s)\n", + server[id].name, acc, ip); + else if (e_mail_check (new_email) == 0) + login_log + ("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a invalid new e-mail (account: %d, ip: %s)\n", + server[id].name, acc, ip); + else if (strcasecmp (new_email, "a@a.com") == 0) + login_log + ("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a default e-mail (account: %d, ip: %s)\n", + server[id].name, acc, ip); + else + { + for (i = 0; i < auth_num; i++) + { + if (auth_dat[i].account_id == acc) + { + if (strcasecmp (auth_dat[i].email, actual_email) + == 0) + { + memcpy (auth_dat[i].email, new_email, 40); + login_log + ("Char-server '%s': Modify an e-mail on an account (@email GM command) (account: %d (%s), new e-mail: %s, ip: %s).\n", + server[id].name, acc, + auth_dat[i].userid, new_email, ip); + } + else + login_log + ("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual e-mail is incorrect (account: %d (%s), actual e-mail: %s, proposed e-mail: %s, ip: %s).\n", + server[id].name, acc, + auth_dat[i].userid, + auth_dat[i].email, actual_email, ip); + break; + } + } + if (i == auth_num) + login_log + ("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but account doesn't exist (account: %d, ip: %s).\n", + server[id].name, acc, ip); + } + } + RFIFOSKIP (fd, 86); + break; + + // Receiving of map-server via char-server a status change resquest (by Yor) + case 0x2724: + if (RFIFOREST (fd) < 10) + return; + { + int acc, statut; + acc = RFIFOL (fd, 2); + statut = RFIFOL (fd, 6); + for (i = 0; i < auth_num; i++) + { + if (auth_dat[i].account_id == acc) + { + if (auth_dat[i].state != statut) + { + login_log + ("Char-server '%s': Status change (account: %d, new status %d, ip: %s).\n", + server[id].name, acc, statut, + ip); + if (statut != 0) + { + unsigned char buf[16]; + WBUFW (buf, 0) = 0x2731; + WBUFL (buf, 2) = acc; + WBUFB (buf, 6) = 0; // 0: change of statut, 1: ban + WBUFL (buf, 7) = statut; // status or final date of a banishment + charif_sendallwos (-1, buf, 11); + for (j = 0; j < AUTH_FIFO_SIZE; j++) + if (auth_fifo[j].account_id == acc) + auth_fifo[j].login_id1++; // to avoid reconnection error when come back from map-server (char-server will ask again the authentification) + } + auth_dat[i].state = statut; + } + else + login_log + ("Char-server '%s': Error of Status change - actual status is already the good status (account: %d, status %d, ip: %s).\n", + server[id].name, acc, statut, + ip); + break; + } + } + if (i == auth_num) + { + login_log + ("Char-server '%s': Error of Status change (account: %d not found, suggested status %d, ip: %s).\n", + server[id].name, acc, statut, ip); + } + RFIFOSKIP (fd, 10); + } + return; + + case 0x2725: // Receiving of map-server via char-server a ban resquest (by Yor) + if (RFIFOREST (fd) < 18) + return; + { + int acc; + acc = RFIFOL (fd, 2); + for (i = 0; i < auth_num; i++) + { + if (auth_dat[i].account_id == acc) + { + time_t timestamp; + struct tm *tmtime; + if (auth_dat[i].ban_until_time == 0 + || auth_dat[i].ban_until_time < time (NULL)) + timestamp = time (NULL); + else + timestamp = auth_dat[i].ban_until_time; + tmtime = gmtime (×tamp); + tmtime->tm_year = + tmtime->tm_year + (short) RFIFOW (fd, 6); + tmtime->tm_mon = + tmtime->tm_mon + (short) RFIFOW (fd, 8); + tmtime->tm_mday = + tmtime->tm_mday + (short) RFIFOW (fd, 10); + tmtime->tm_hour = + tmtime->tm_hour + (short) RFIFOW (fd, 12); + tmtime->tm_min = + tmtime->tm_min + (short) RFIFOW (fd, 14); + tmtime->tm_sec = + tmtime->tm_sec + (short) RFIFOW (fd, 16); + timestamp = timegm (tmtime); + if (timestamp != -1) + { + if (timestamp <= time (NULL)) + timestamp = 0; + if (auth_dat[i].ban_until_time != timestamp) + { + if (timestamp != 0) + { + unsigned char buf[16]; + char tmpstr[2048]; + strftime (tmpstr, 24, date_format, + gmtime (×tamp)); + login_log + ("Char-server '%s': Ban request (account: %d, new final date of banishment: %d (%s), ip: %s).\n", + server[id].name, acc, + timestamp, + (timestamp == + 0 ? "no banishment" : tmpstr), + ip); + WBUFW (buf, 0) = 0x2731; + WBUFL (buf, 2) = + auth_dat[i].account_id; + WBUFB (buf, 6) = 1; // 0: change of statut, 1: ban + WBUFL (buf, 7) = timestamp; // status or final date of a banishment + charif_sendallwos (-1, buf, 11); + for (j = 0; j < AUTH_FIFO_SIZE; j++) + if (auth_fifo[j].account_id == + acc) + auth_fifo[j].login_id1++; // to avoid reconnection error when come back from map-server (char-server will ask again the authentification) + } + else + { + login_log + ("Char-server '%s': Error of ban request (account: %d, new date unbans the account, ip: %s).\n", + server[id].name, acc, + ip); + } + auth_dat[i].ban_until_time = timestamp; + } + else + { + login_log + ("Char-server '%s': Error of ban request (account: %d, no change for ban date, ip: %s).\n", + server[id].name, acc, ip); + } + } + else + { + login_log + ("Char-server '%s': Error of ban request (account: %d, invalid date, ip: %s).\n", + server[id].name, acc, ip); + } + break; + } + } + if (i == auth_num) + { + login_log + ("Char-server '%s': Error of ban request (account: %d not found, ip: %s).\n", + server[id].name, acc, ip); + } + RFIFOSKIP (fd, 18); + } + return; + + case 0x2727: // Change of sex (sex is reversed) + if (RFIFOREST (fd) < 6) + return; + { + int acc, sex; + acc = RFIFOL (fd, 2); + for (i = 0; i < auth_num; i++) + { +// printf("%d,", auth_dat[i].account_id); + if (auth_dat[i].account_id == acc) + { + if (auth_dat[i].sex == 2) + login_log + ("Char-server '%s': Error of sex change - Server account (suggested account: %d, actual sex %d (Server), ip: %s).\n", + server[id].name, acc, + auth_dat[i].sex, ip); + else + { + unsigned char buf[16]; + if (auth_dat[i].sex == 0) + sex = 1; + else + sex = 0; + login_log + ("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n", + server[id].name, acc, + (sex == 2) ? 'S' : (sex ? 'M' : 'F'), + ip); + for (j = 0; j < AUTH_FIFO_SIZE; j++) + if (auth_fifo[j].account_id == acc) + auth_fifo[j].login_id1++; // to avoid reconnection error when come back from map-server (char-server will ask again the authentification) + auth_dat[i].sex = sex; + WBUFW (buf, 0) = 0x2723; + WBUFL (buf, 2) = acc; + WBUFB (buf, 6) = sex; + charif_sendallwos (-1, buf, 7); + } + break; + } + } + if (i == auth_num) + { + login_log + ("Char-server '%s': Error of sex change (account: %d not found, sex would be reversed, ip: %s).\n", + server[id].name, acc, ip); + } + RFIFOSKIP (fd, 6); + } + return; + + case 0x2728: // We receive account_reg2 from a char-server, and we send them to other char-servers. + if (RFIFOREST (fd) < 4 || RFIFOREST (fd) < RFIFOW (fd, 2)) + return; + { + int acc, p; + acc = RFIFOL (fd, 4); + for (i = 0; i < auth_num; i++) + { + if (auth_dat[i].account_id == acc) + { + unsigned char buf[RFIFOW (fd, 2) + 1]; + login_log + ("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d, ip: %s).\n", + server[id].name, acc, ip); + for (p = 8, j = 0; + p < RFIFOW (fd, 2) && j < ACCOUNT_REG2_NUM; + p += 36, j++) + { + memcpy (auth_dat[i].account_reg2[j].str, + RFIFOP (fd, p), 32); + auth_dat[i].account_reg2[j].str[31] = '\0'; + remove_control_chars (auth_dat[i].account_reg2 + [j].str); + auth_dat[i].account_reg2[j].value = + RFIFOL (fd, p + 32); + } + auth_dat[i].account_reg2_num = j; + // Sending information towards the other char-servers. + memcpy (WBUFP (buf, 0), RFIFOP (fd, 0), + RFIFOW (fd, 2)); + WBUFW (buf, 0) = 0x2729; + charif_sendallwos (fd, buf, WBUFW (buf, 2)); +// printf("parse_fromchar: receiving (from the char-server) of account_reg2 (account id: %d).\n", acc); + break; + } + } + if (i == auth_num) + { +// printf("parse_fromchar: receiving (from the char-server) of account_reg2 (unknwon account id: %d).\n", acc); + login_log + ("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d not found, ip: %s).\n", + server[id].name, acc, ip); + } + } + RFIFOSKIP (fd, RFIFOW (fd, 2)); + break; + + case 0x272a: // Receiving of map-server via char-server a unban resquest (by Yor) + if (RFIFOREST (fd) < 6) + return; + { + int acc; + acc = RFIFOL (fd, 2); + for (i = 0; i < auth_num; i++) + { + if (auth_dat[i].account_id == acc) + { + if (auth_dat[i].ban_until_time != 0) + { + auth_dat[i].ban_until_time = 0; + login_log + ("Char-server '%s': UnBan request (account: %d, ip: %s).\n", + server[id].name, acc, ip); + } + else + { + login_log + ("Char-server '%s': Error of UnBan request (account: %d, no change for unban date, ip: %s).\n", + server[id].name, acc, ip); + } + break; + } + } + if (i == auth_num) + { + login_log + ("Char-server '%s': Error of UnBan request (account: %d not found, ip: %s).\n", + server[id].name, acc, ip); + } + RFIFOSKIP (fd, 6); + } + return; + + // request from char-server to change account password + case 0x2740: // 0x2740 .L .24B .24B + if (RFIFOREST (fd) < 54) + return; + { + int acc; + char actual_pass[24], new_pass[24]; + acc = RFIFOL (fd, 2); + memcpy (actual_pass, RFIFOP (fd, 6), 24); + actual_pass[23] = '\0'; + remove_control_chars (actual_pass); + memcpy (new_pass, RFIFOP (fd, 30), 24); + new_pass[23] = '\0'; + remove_control_chars (new_pass); + + int status = 0; + + for (i = 0; i < auth_num; i++) + { + if (auth_dat[i].account_id == acc) + { + if (pass_ok (actual_pass, auth_dat[i].pass)) + { + if (strlen (new_pass) < 4) + status = 3; + else + { + status = 1; + strcpy (auth_dat[i].pass, MD5_saltcrypt(new_pass, make_salt())); + login_log + ("Char-server '%s': Change pass success (account: %d (%s), ip: %s.\n", + server[id].name, acc, + auth_dat[i].userid, ip); + } + } + else + { + status = 2; + login_log + ("Char-server '%s': Attempt to modify a pass failed, wrong password. (account: %d (%s), ip: %s).\n", + server[id].name, acc, + auth_dat[i].userid, ip); + } + break; + } + } + WFIFOW (fd, 0) = 0x2741; + WFIFOL (fd, 2) = acc; + WFIFOB (fd, 6) = status; // 0: acc not found, 1: success, 2: password mismatch, 3: pass too short + WFIFOSET (fd, 7); + } + + RFIFOSKIP (fd, 54); + break; + + default: + { + FILE *logfp; + char tmpstr[24]; + struct timeval tv; + logfp = fopen_ (login_log_unknown_packets_filename, "a"); + if (logfp) + { + gettimeofday (&tv, NULL); + strftime (tmpstr, 23, date_format, gmtime (&(tv.tv_sec))); + fprintf (logfp, + "%s.%03d: receiving of an unknown packet -> disconnection\n", + tmpstr, (int) tv.tv_usec / 1000); + fprintf (logfp, + "parse_fromchar: connection #%d (ip: %s), packet: 0x%x (with being read: %d).\n", + fd, ip, RFIFOW (fd, 0), RFIFOREST (fd)); + fprintf (logfp, "Detail (in hex):\n"); + fprintf (logfp, + "---- 00-01-02-03-04-05-06-07 08-09-0A-0B-0C-0D-0E-0F\n"); + memset (tmpstr, '\0', sizeof (tmpstr)); + for (i = 0; i < RFIFOREST (fd); i++) + { + if ((i & 15) == 0) + fprintf (logfp, "%04X ", i); + fprintf (logfp, "%02x ", RFIFOB (fd, i)); + if (RFIFOB (fd, i) > 0x1f) + tmpstr[i % 16] = RFIFOB (fd, i); + else + tmpstr[i % 16] = '.'; + if ((i - 7) % 16 == 0) // -8 + 1 + fprintf (logfp, " "); + else if ((i + 1) % 16 == 0) + { + fprintf (logfp, " %s\n", tmpstr); + memset (tmpstr, '\0', sizeof (tmpstr)); + } + } + if (i % 16 != 0) + { + for (j = i; j % 16 != 0; j++) + { + fprintf (logfp, " "); + if ((j - 7) % 16 == 0) // -8 + 1 + fprintf (logfp, " "); + } + fprintf (logfp, " %s\n", tmpstr); + } + fprintf (logfp, "\n"); + fclose_ (logfp); + } + } + printf + ("parse_fromchar: Unknown packet 0x%x (from a char-server)! -> disconnection.\n", + RFIFOW (fd, 0)); + session[fd]->eof = 1; + printf + ("Char-server has been disconnected (unknown packet).\n"); + return; + } + } + return; +} + +//--------------------------------------- +// Packet parsing for administation login +//--------------------------------------- +void parse_admin (int fd) +{ + int i, j; + unsigned char *p = (unsigned char *) &session[fd]->client_addr.sin_addr; + char *account_name; + char ip[16]; + + sprintf (ip, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); + + if (session[fd]->eof) + { + close (fd); + delete_session (fd); + printf ("Remote administration has disconnected (session #%d).\n", + fd); + return; + } + + while (RFIFOREST (fd) >= 2) + { + if (display_parse_admin == 1) + printf + ("parse_admin: connection #%d, packet: 0x%x (with being read: %d).\n", + fd, RFIFOW (fd, 0), RFIFOREST (fd)); + + switch (RFIFOW (fd, 0)) + { + case 0x7530: // Request of the server version + login_log ("'ladmin': Sending of the server version (ip: %s)\n", + ip); + WFIFOW (fd, 0) = 0x7531; + WFIFOB (fd, 2) = ATHENA_MAJOR_VERSION; + WFIFOB (fd, 3) = ATHENA_MINOR_VERSION; + WFIFOB (fd, 4) = ATHENA_REVISION; + WFIFOB (fd, 5) = ATHENA_RELEASE_FLAG; + WFIFOB (fd, 6) = ATHENA_OFFICIAL_FLAG; + WFIFOB (fd, 7) = ATHENA_SERVER_LOGIN; + WFIFOW (fd, 8) = ATHENA_MOD_VERSION; + WFIFOSET (fd, 10); + RFIFOSKIP (fd, 2); + break; + + case 0x7532: // Request of end of connection + login_log ("'ladmin': End of connection (ip: %s)\n", + ip); + RFIFOSKIP (fd, 2); + session[fd]->eof = 1; + break; + + case 0x7920: // Request of an accounts list + if (RFIFOREST (fd) < 10) + return; + { + int st, ed, len; + int id[auth_num]; + st = RFIFOL (fd, 2); + ed = RFIFOL (fd, 6); + RFIFOSKIP (fd, 10); + WFIFOW (fd, 0) = 0x7921; + if (st < 0) + st = 0; + if (ed > END_ACCOUNT_NUM || ed < st || ed <= 0) + ed = END_ACCOUNT_NUM; + login_log + ("'ladmin': Sending an accounts list (ask: from %d to %d, ip: %s)\n", + st, ed, ip); + // Sort before send + for (i = 0; i < auth_num; i++) + { + int k; + id[i] = i; + for (j = 0; j < i; j++) + { + if (auth_dat[id[i]].account_id < + auth_dat[id[j]].account_id) + { + for (k = i; k > j; k--) + { + id[k] = id[k - 1]; + } + id[j] = i; // id[i] + break; + } + } + } + // Sending accounts information + len = 4; + for (i = 0; i < auth_num && len < 30000; i++) + { + int account_id = auth_dat[id[i]].account_id; // use sorted index + if (account_id >= st && account_id <= ed) + { + j = id[i]; + WFIFOL (fd, len) = account_id; + WFIFOB (fd, len + 4) = + (unsigned char) isGM (account_id); + memcpy (WFIFOP (fd, len + 5), auth_dat[j].userid, + 24); + WFIFOB (fd, len + 29) = auth_dat[j].sex; + WFIFOL (fd, len + 30) = auth_dat[j].logincount; + if (auth_dat[j].state == 0 && auth_dat[j].ban_until_time != 0) // if no state and banished + WFIFOL (fd, len + 34) = 7; // 6 = Your are Prohibited to log in until %s + else + WFIFOL (fd, len + 34) = auth_dat[j].state; + len += 38; + } + } + WFIFOW (fd, 2) = len; + WFIFOSET (fd, len); + } + break; + + case 0x7924: + { // [Fate] Itemfrob package: change item IDs + if (RFIFOREST (fd) < 10) + return; + charif_sendallwos (-1, RFIFOP (fd, 0), 10); // forward package to char servers + RFIFOSKIP (fd, 10); + WFIFOW (fd, 0) = 0x7925; + WFIFOSET (fd, 2); + break; + } + + case 0x7930: // Request for an account creation + if (RFIFOREST (fd) < 91) + return; + { + struct mmo_account ma; + ma.userid = RFIFOP (fd, 2); + ma.passwd = RFIFOP (fd, 26); + memcpy (ma.lastlogin, "-", 2); + ma.sex = RFIFOB (fd, 50); + WFIFOW (fd, 0) = 0x7931; + WFIFOL (fd, 2) = -1; + memcpy (WFIFOP (fd, 6), RFIFOP (fd, 2), 24); + if (strlen (ma.userid) > 23 || strlen (ma.passwd) > 23) + { + login_log + ("'ladmin': Attempt to create an invalid account (account or pass is too long, ip: %s)\n", + ip); + } + else if (strlen (ma.userid) < 4 || strlen (ma.passwd) < 4) + { + login_log + ("'ladmin': Attempt to create an invalid account (account or pass is too short, ip: %s)\n", + ip); + } + else if (ma.sex != 'F' && ma.sex != 'M') + { + login_log + ("'ladmin': Attempt to create an invalid account (account: %s, invalid sex, ip: %s)\n", + ma.userid, ip); + } + else if (account_id_count > END_ACCOUNT_NUM) + { + login_log + ("'ladmin': Attempt to create an account, but there is no more available id number (account: %s, sex: %c, ip: %s)\n", + ma.userid, ma.sex, ip); + } + else + { + remove_control_chars (ma.userid); + remove_control_chars (ma.passwd); + for (i = 0; i < auth_num; i++) + { + if (strncmp (auth_dat[i].userid, ma.userid, 24) == + 0) + { + login_log + ("'ladmin': Attempt to create an already existing account (account: %s ip: %s)\n", + auth_dat[i].userid, ip); + break; + } + } + if (i == auth_num) + { + int new_id; + char email[40]; + memcpy (email, RFIFOP (fd, 51), 40); + email[39] = '\0'; + remove_control_chars (email); + new_id = mmo_auth_new (&ma, ma.sex, email); + login_log + ("'ladmin': Account creation (account: %s (id: %d), sex: %c, email: %s, ip: %s)\n", + ma.userid, new_id, + ma.sex, auth_dat[i].email, ip); + WFIFOL (fd, 2) = new_id; + } + } + WFIFOSET (fd, 30); + RFIFOSKIP (fd, 91); + } + break; + + case 0x7932: // Request for an account deletion + if (RFIFOREST (fd) < 26) + return; + WFIFOW (fd, 0) = 0x7933; + WFIFOL (fd, 2) = -1; + account_name = RFIFOP (fd, 2); + account_name[23] = '\0'; + remove_control_chars (account_name); + i = search_account_index (account_name); + if (i != -1) + { + // Char-server is notified of deletion (for characters deletion). + unsigned char buf[65535]; + WBUFW (buf, 0) = 0x2730; + WBUFL (buf, 2) = auth_dat[i].account_id; + charif_sendallwos (-1, buf, 6); + // send answer + memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); + WFIFOL (fd, 2) = auth_dat[i].account_id; + // save deleted account in log file + login_log + ("'ladmin': Account deletion (account: %s, id: %d, ip: %s) - saved in next line:\n", + auth_dat[i].userid, auth_dat[i].account_id, + ip); + mmo_auth_tostr (buf, &auth_dat[i]); + login_log ("%s\n", buf); + // delete account + memset (auth_dat[i].userid, '\0', + sizeof (auth_dat[i].userid)); + auth_dat[i].account_id = -1; + } + else + { + memcpy (WFIFOP (fd, 6), account_name, 24); + login_log + ("'ladmin': Attempt to delete an unknown account (account: %s, ip: %s)\n", + account_name, ip); + } + WFIFOSET (fd, 30); + RFIFOSKIP (fd, 26); + break; + + case 0x7934: // Request to change a password + if (RFIFOREST (fd) < 50) + return; + WFIFOW (fd, 0) = 0x7935; + WFIFOL (fd, 2) = -1; + account_name = RFIFOP (fd, 2); + account_name[23] = '\0'; + remove_control_chars (account_name); + i = search_account_index (account_name); + if (i != -1) + { + memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); + strcpy (auth_dat[i].pass, MD5_saltcrypt(RFIFOP (fd, 26), make_salt())); + auth_dat[i].pass[39] = '\0'; + WFIFOL (fd, 2) = auth_dat[i].account_id; + login_log + ("'ladmin': Modification of a password (account: %s, new password: %s, ip: %s)\n", + auth_dat[i].userid, auth_dat[i].pass, ip); + } + else + { + memcpy (WFIFOP (fd, 6), account_name, 24); + login_log + ("'ladmin': Attempt to modify the password of an unknown account (account: %s, ip: %s)\n", + account_name, ip); + } + WFIFOSET (fd, 30); + RFIFOSKIP (fd, 50); + break; + + case 0x7936: // Request to modify a state + if (RFIFOREST (fd) < 50) + return; + { + char error_message[20]; + int statut; + WFIFOW (fd, 0) = 0x7937; + WFIFOL (fd, 2) = -1; + account_name = RFIFOP (fd, 2); + account_name[23] = '\0'; + remove_control_chars (account_name); + statut = RFIFOL (fd, 26); + memcpy (error_message, RFIFOP (fd, 30), 20); + error_message[19] = '\0'; + remove_control_chars (error_message); + if (statut != 7 || error_message[0] == '\0') + { // 7: // 6 = Your are Prohibited to log in until %s + strcpy (error_message, "-"); + } + i = search_account_index (account_name); + if (i != -1) + { + memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); + WFIFOL (fd, 2) = auth_dat[i].account_id; + if (auth_dat[i].state == statut + && strcmp (auth_dat[i].error_message, + error_message) == 0) + login_log + ("'ladmin': Modification of a state, but the state of the account is already the good state (account: %s, received state: %d, ip: %s)\n", + account_name, statut, ip); + else + { + if (statut == 7) + login_log + ("'ladmin': Modification of a state (account: %s, new state: %d - prohibited to login until '%s', ip: %s)\n", + auth_dat[i].userid, statut, + error_message, ip); + else + login_log + ("'ladmin': Modification of a state (account: %s, new state: %d, ip: %s)\n", + auth_dat[i].userid, statut, ip); + if (auth_dat[i].state == 0) + { + unsigned char buf[16]; + WBUFW (buf, 0) = 0x2731; + WBUFL (buf, 2) = auth_dat[i].account_id; + WBUFB (buf, 6) = 0; // 0: change of statut, 1: ban + WBUFL (buf, 7) = statut; // status or final date of a banishment + charif_sendallwos (-1, buf, 11); + for (j = 0; j < AUTH_FIFO_SIZE; j++) + if (auth_fifo[j].account_id == + auth_dat[i].account_id) + auth_fifo[j].login_id1++; // to avoid reconnection error when come back from map-server (char-server will ask again the authentification) + } + auth_dat[i].state = statut; + memcpy (auth_dat[i].error_message, error_message, + 20); + } + } + else + { + memcpy (WFIFOP (fd, 6), account_name, 24); + login_log + ("'ladmin': Attempt to modify the state of an unknown account (account: %s, received state: %d, ip: %s)\n", + account_name, statut, ip); + } + WFIFOL (fd, 30) = statut; + } + WFIFOSET (fd, 34); + RFIFOSKIP (fd, 50); + break; + + case 0x7938: // Request for servers list and # of online players + login_log ("'ladmin': Sending of servers list (ip: %s)\n", ip); + server_num = 0; + for (i = 0; i < MAX_SERVERS; i++) + { + if (server_fd[i] >= 0) + { + WFIFOL (fd, 4 + server_num * 32) = server[i].ip; + WFIFOW (fd, 4 + server_num * 32 + 4) = server[i].port; + memcpy (WFIFOP (fd, 4 + server_num * 32 + 6), + server[i].name, 20); + WFIFOW (fd, 4 + server_num * 32 + 26) = + server[i].users; + WFIFOW (fd, 4 + server_num * 32 + 28) = + server[i].maintenance; + WFIFOW (fd, 4 + server_num * 32 + 30) = server[i].is_new; + server_num++; + } + } + WFIFOW (fd, 0) = 0x7939; + WFIFOW (fd, 2) = 4 + 32 * server_num; + WFIFOSET (fd, 4 + 32 * server_num); + RFIFOSKIP (fd, 2); + break; + + case 0x793a: // Request to password check + if (RFIFOREST (fd) < 50) + return; + WFIFOW (fd, 0) = 0x793b; + WFIFOL (fd, 2) = -1; + account_name = RFIFOP (fd, 2); + account_name[23] = '\0'; + remove_control_chars (account_name); + i = search_account_index (account_name); + if (i != -1) + { + memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); + if ( pass_ok(RFIFOP (fd, 26), auth_dat[i].pass) ) + { + WFIFOL (fd, 2) = auth_dat[i].account_id; + login_log + ("'ladmin': Check of password OK (account: %s, password: %s, ip: %s)\n", + auth_dat[i].userid, auth_dat[i].pass, + ip); + } + else + { + char pass[24]; + memcpy (pass, RFIFOP (fd, 26), 24); + pass[23] = '\0'; + remove_control_chars (pass); + login_log + ("'ladmin': Failure of password check (account: %s, proposed pass: %s, ip: %s)\n", + auth_dat[i].userid, pass, ip); + } + } + else + { + memcpy (WFIFOP (fd, 6), account_name, 24); + login_log + ("'ladmin': Attempt to check the password of an unknown account (account: %s, ip: %s)\n", + account_name, ip); + } + WFIFOSET (fd, 30); + RFIFOSKIP (fd, 50); + break; + + case 0x793c: // Request to modify sex + if (RFIFOREST (fd) < 27) + return; + WFIFOW (fd, 0) = 0x793d; + WFIFOL (fd, 2) = -1; + account_name = RFIFOP (fd, 2); + account_name[23] = '\0'; + remove_control_chars (account_name); + memcpy (WFIFOP (fd, 6), account_name, 24); + { + char sex; + sex = RFIFOB (fd, 26); + if (sex != 'F' && sex != 'M') + { + if (sex > 31) + login_log + ("'ladmin': Attempt to give an invalid sex (account: %s, received sex: %c, ip: %s)\n", + account_name, sex, ip); + else + login_log + ("'ladmin': Attempt to give an invalid sex (account: %s, received sex: 'control char', ip: %s)\n", + account_name, ip); + } + else + { + i = search_account_index (account_name); + if (i != -1) + { + memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); + if (auth_dat[i].sex != + ((sex == 'S' || sex == 's') ? 2 : (sex == 'M' + || sex == + 'm'))) + { + unsigned char buf[16]; + WFIFOL (fd, 2) = auth_dat[i].account_id; + for (j = 0; j < AUTH_FIFO_SIZE; j++) + if (auth_fifo[j].account_id == + auth_dat[i].account_id) + auth_fifo[j].login_id1++; // to avoid reconnection error when come back from map-server (char-server will ask again the authentification) + auth_dat[i].sex = (sex == 'S' + || sex == + 's') ? 2 : (sex == 'M' + || sex == 'm'); + login_log + ("'ladmin': Modification of a sex (account: %s, new sex: %c, ip: %s)\n", + auth_dat[i].userid, sex, ip); + // send to all char-server the change + WBUFW (buf, 0) = 0x2723; + WBUFL (buf, 2) = auth_dat[i].account_id; + WBUFB (buf, 6) = auth_dat[i].sex; + charif_sendallwos (-1, buf, 7); + } + else + { + login_log + ("'ladmin': Modification of a sex, but the sex is already the good sex (account: %s, sex: %c, ip: %s)\n", + auth_dat[i].userid, sex, ip); + } + } + else + { + login_log + ("'ladmin': Attempt to modify the sex of an unknown account (account: %s, received sex: %c, ip: %s)\n", + account_name, sex, ip); + } + } + } + WFIFOSET (fd, 30); + RFIFOSKIP (fd, 27); + break; + + case 0x793e: // Request to modify GM level + if (RFIFOREST (fd) < 27) + return; + WFIFOW (fd, 0) = 0x793f; + WFIFOL (fd, 2) = -1; + account_name = RFIFOP (fd, 2); + account_name[23] = '\0'; + remove_control_chars (account_name); + memcpy (WFIFOP (fd, 6), account_name, 24); + { + char new_gm_level; + new_gm_level = RFIFOB (fd, 26); + if (new_gm_level < 0 || new_gm_level > 99) + { + login_log + ("'ladmin': Attempt to give an invalid GM level (account: %s, received GM level: %d, ip: %s)\n", + account_name, (int) new_gm_level, ip); + } + else + { + i = search_account_index (account_name); + if (i != -1) + { + int acc = auth_dat[i].account_id; + memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); + if (isGM (acc) != new_gm_level) + { + // modification of the file + FILE *fp, *fp2; + int lock; + char line[512]; + int GM_account, GM_level; + int modify_flag; + char tmpstr[24]; + struct timeval tv; + if ((fp2 = + lock_fopen (GM_account_filename, + &lock)) != NULL) + { + if ((fp = + fopen_ (GM_account_filename, + "r")) != NULL) + { + gettimeofday (&tv, NULL); + strftime (tmpstr, 23, date_format, + gmtime (&(tv.tv_sec))); + modify_flag = 0; + // read/write GM file + while (fgets + (line, sizeof (line) - 1, fp)) + { + while (line[0] != '\0' + && (line[strlen (line) - 1] + == '\n' + || line[strlen (line) - + 1] == '\r')) + line[strlen (line) - 1] = + '\0'; + if ((line[0] == '/' + && line[1] == '/') + || line[0] == '\0') + fprintf (fp2, "%s\n", + line); + else + { + if (sscanf + (line, "%d %d", + &GM_account, + &GM_level) != 2 + && sscanf (line, "%d: %d", + &GM_account, + &GM_level) != + 2) + fprintf (fp2, + "%s\n", + line); + else if (GM_account != acc) + fprintf (fp2, + "%s\n", + line); + else if (new_gm_level < 1) + { + fprintf (fp2, + "// %s: 'ladmin' GM level removed on account %d '%s' (previous level: %d)\n//%d %d\n", + tmpstr, + acc, + auth_dat + [i].userid, + GM_level, acc, + new_gm_level); + modify_flag = 1; + } + else + { + fprintf (fp2, + "// %s: 'ladmin' GM level on account %d '%s' (previous level: %d)\n%d %d\n", + tmpstr, + acc, + auth_dat + [i].userid, + GM_level, acc, + new_gm_level); + modify_flag = 1; + } + } + } + if (modify_flag == 0) + fprintf (fp2, + "// %s: 'ladmin' GM level on account %d '%s' (previous level: 0)\n%d %d\n", + tmpstr, acc, + auth_dat[i].userid, acc, + new_gm_level); + fclose_ (fp); + } + else + { + login_log + ("'ladmin': Attempt to modify of a GM level - impossible to read GM accounts file (account: %s (%d), received GM level: %d, ip: %s)\n", + auth_dat[i].userid, acc, + (int) new_gm_level, ip); + } + lock_fclose(fp2, GM_account_filename, &lock); + WFIFOL (fd, 2) = acc; + login_log + ("'ladmin': Modification of a GM level (account: %s (%d), new GM level: %d, ip: %s)\n", + auth_dat[i].userid, acc, + (int) new_gm_level, ip); + // read and send new GM informations + read_gm_account (); + send_GM_accounts (); + } + else + { + login_log + ("'ladmin': Attempt to modify of a GM level - impossible to write GM accounts file (account: %s (%d), received GM level: %d, ip: %s)\n", + auth_dat[i].userid, acc, + (int) new_gm_level, ip); + } + } + else + { + login_log + ("'ladmin': Attempt to modify of a GM level, but the GM level is already the good GM level (account: %s (%d), GM level: %d, ip: %s)\n", + auth_dat[i].userid, acc, + (int) new_gm_level, ip); + } + } + else + { + login_log + ("'ladmin': Attempt to modify the GM level of an unknown account (account: %s, received GM level: %d, ip: %s)\n", + account_name, (int) new_gm_level, + ip); + } + } + } + WFIFOSET (fd, 30); + RFIFOSKIP (fd, 27); + break; + + case 0x7940: // Request to modify e-mail + if (RFIFOREST (fd) < 66) + return; + WFIFOW (fd, 0) = 0x7941; + WFIFOL (fd, 2) = -1; + account_name = RFIFOP (fd, 2); + account_name[23] = '\0'; + remove_control_chars (account_name); + memcpy (WFIFOP (fd, 6), account_name, 24); + { + char email[40]; + memcpy (email, RFIFOP (fd, 26), 40); + if (e_mail_check (email) == 0) + { + login_log + ("'ladmin': Attempt to give an invalid e-mail (account: %s, ip: %s)\n", + account_name, ip); + } + else + { + remove_control_chars (email); + i = search_account_index (account_name); + if (i != -1) + { + memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); + memcpy (auth_dat[i].email, email, 40); + WFIFOL (fd, 2) = auth_dat[i].account_id; + login_log + ("'ladmin': Modification of an email (account: %s, new e-mail: %s, ip: %s)\n", + auth_dat[i].userid, email, ip); + } + else + { + login_log + ("'ladmin': Attempt to modify the e-mail of an unknown account (account: %s, received e-mail: %s, ip: %s)\n", + account_name, email, ip); + } + } + } + WFIFOSET (fd, 30); + RFIFOSKIP (fd, 66); + break; + + case 0x7942: // Request to modify memo field + if (RFIFOREST (fd) < 28 + || RFIFOREST (fd) < (28 + RFIFOW (fd, 26))) + return; + WFIFOW (fd, 0) = 0x7943; + WFIFOL (fd, 2) = -1; + account_name = RFIFOP (fd, 2); + account_name[23] = '\0'; + remove_control_chars (account_name); + i = search_account_index (account_name); + if (i != -1) + { + int size_of_memo = sizeof (auth_dat[i].memo); + memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); + memset (auth_dat[i].memo, '\0', size_of_memo); + if (RFIFOW (fd, 26) == 0) + { + strncpy (auth_dat[i].memo, "!", size_of_memo); + } + else if (RFIFOW (fd, 26) > size_of_memo - 1) + { + memcpy (auth_dat[i].memo, RFIFOP (fd, 28), + size_of_memo - 1); + } + else + { + memcpy (auth_dat[i].memo, RFIFOP (fd, 28), + RFIFOW (fd, 26)); + } + auth_dat[i].memo[size_of_memo - 1] = '\0'; + remove_control_chars (auth_dat[i].memo); + WFIFOL (fd, 2) = auth_dat[i].account_id; + login_log + ("'ladmin': Modification of a memo field (account: %s, new memo: %s, ip: %s)\n", + auth_dat[i].userid, auth_dat[i].memo, ip); + } + else + { + memcpy (WFIFOP (fd, 6), account_name, 24); + login_log + ("'ladmin': Attempt to modify the memo field of an unknown account (account: %s, ip: %s)\n", + account_name, ip); + } + WFIFOSET (fd, 30); + RFIFOSKIP (fd, 28 + RFIFOW (fd, 26)); + break; + + case 0x7944: // Request to found an account id + if (RFIFOREST (fd) < 26) + return; + WFIFOW (fd, 0) = 0x7945; + WFIFOL (fd, 2) = -1; + account_name = RFIFOP (fd, 2); + account_name[23] = '\0'; + remove_control_chars (account_name); + i = search_account_index (account_name); + if (i != -1) + { + memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); + WFIFOL (fd, 2) = auth_dat[i].account_id; + login_log + ("'ladmin': Request (by the name) of an account id (account: %s, id: %d, ip: %s)\n", + auth_dat[i].userid, auth_dat[i].account_id, + ip); + } + else + { + memcpy (WFIFOP (fd, 6), account_name, 24); + login_log + ("'ladmin': ID request (by the name) of an unknown account (account: %s, ip: %s)\n", + account_name, ip); + } + WFIFOSET (fd, 30); + RFIFOSKIP (fd, 26); + break; + + case 0x7946: // Request to found an account name + if (RFIFOREST (fd) < 6) + return; + WFIFOW (fd, 0) = 0x7947; + WFIFOL (fd, 2) = RFIFOL (fd, 2); + memset (WFIFOP (fd, 6), '\0', 24); + for (i = 0; i < auth_num; i++) + { + if (auth_dat[i].account_id == RFIFOL (fd, 2)) + { + strncpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); + login_log + ("'ladmin': Request (by id) of an account name (account: %s, id: %d, ip: %s)\n", + auth_dat[i].userid, RFIFOL (fd, 2), ip); + break; + } + } + if (i == auth_num) + { + login_log + ("'ladmin': Name request (by id) of an unknown account (id: %d, ip: %s)\n", + RFIFOL (fd, 2), ip); + strncpy (WFIFOP (fd, 6), "", 24); + } + WFIFOSET (fd, 30); + RFIFOSKIP (fd, 6); + break; + + case 0x7948: // Request to change the validity limit (timestamp) (absolute value) + if (RFIFOREST (fd) < 30) + return; + { + time_t timestamp; + char tmpstr[2048]; + WFIFOW (fd, 0) = 0x7949; + WFIFOL (fd, 2) = -1; + account_name = RFIFOP (fd, 2); + account_name[23] = '\0'; + remove_control_chars (account_name); + timestamp = (time_t) RFIFOL (fd, 26); + strftime (tmpstr, 24, date_format, gmtime (×tamp)); + i = search_account_index (account_name); + if (i != -1) + { + memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); + login_log + ("'ladmin': Change of a validity limit (account: %s, new validity: %d (%s), ip: %s)\n", + auth_dat[i].userid, timestamp, + (timestamp == 0 ? "unlimited" : tmpstr), ip); + auth_dat[i].connect_until_time = timestamp; + WFIFOL (fd, 2) = auth_dat[i].account_id; + } + else + { + memcpy (WFIFOP (fd, 6), account_name, 24); + login_log + ("'ladmin': Attempt to change the validity limit of an unknown account (account: %s, received validity: %d (%s), ip: %s)\n", account_name, timestamp, + (timestamp == 0 ? "unlimited" : tmpstr), ip); + } + WFIFOL (fd, 30) = timestamp; + } + WFIFOSET (fd, 34); + RFIFOSKIP (fd, 30); + break; + + case 0x794a: // Request to change the final date of a banishment (timestamp) (absolute value) + if (RFIFOREST (fd) < 30) + return; + { + time_t timestamp; + char tmpstr[2048]; + WFIFOW (fd, 0) = 0x794b; + WFIFOL (fd, 2) = -1; + account_name = RFIFOP (fd, 2); + account_name[23] = '\0'; + remove_control_chars (account_name); + timestamp = (time_t) RFIFOL (fd, 26); + if (timestamp <= time (NULL)) + timestamp = 0; + strftime (tmpstr, 24, date_format, gmtime (×tamp)); + i = search_account_index (account_name); + if (i != -1) + { + memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); + WFIFOL (fd, 2) = auth_dat[i].account_id; + login_log + ("'ladmin': Change of the final date of a banishment (account: %s, new final date of banishment: %d (%s), ip: %s)\n", + auth_dat[i].userid, timestamp, + (timestamp == 0 ? "no banishment" : tmpstr), ip); + if (auth_dat[i].ban_until_time != timestamp) + { + if (timestamp != 0) + { + unsigned char buf[16]; + WBUFW (buf, 0) = 0x2731; + WBUFL (buf, 2) = auth_dat[i].account_id; + WBUFB (buf, 6) = 1; // 0: change of statut, 1: ban + WBUFL (buf, 7) = timestamp; // status or final date of a banishment + charif_sendallwos (-1, buf, 11); + for (j = 0; j < AUTH_FIFO_SIZE; j++) + if (auth_fifo[j].account_id == + auth_dat[i].account_id) + auth_fifo[j].login_id1++; // to avoid reconnection error when come back from map-server (char-server will ask again the authentification) + } + auth_dat[i].ban_until_time = timestamp; + } + } + else + { + memcpy (WFIFOP (fd, 6), account_name, 24); + login_log + ("'ladmin': Attempt to change the final date of a banishment of an unknown account (account: %s, received final date of banishment: %d (%s), ip: %s)\n", + account_name, timestamp, + (timestamp == 0 ? "no banishment" : tmpstr), ip); + } + WFIFOL (fd, 30) = timestamp; + } + WFIFOSET (fd, 34); + RFIFOSKIP (fd, 30); + break; + + case 0x794c: // Request to change the final date of a banishment (timestamp) (relative change) + if (RFIFOREST (fd) < 38) + return; + { + time_t timestamp; + struct tm *tmtime; + char tmpstr[2048]; + WFIFOW (fd, 0) = 0x794d; + WFIFOL (fd, 2) = -1; + account_name = RFIFOP (fd, 2); + account_name[23] = '\0'; + remove_control_chars (account_name); + i = search_account_index (account_name); + if (i != -1) + { + WFIFOL (fd, 2) = auth_dat[i].account_id; + memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); + if (auth_dat[i].ban_until_time == 0 + || auth_dat[i].ban_until_time < time (NULL)) + timestamp = time (NULL); + else + timestamp = auth_dat[i].ban_until_time; + tmtime = gmtime (×tamp); + tmtime->tm_year = + tmtime->tm_year + (short) RFIFOW (fd, 26); + tmtime->tm_mon = + tmtime->tm_mon + (short) RFIFOW (fd, 28); + tmtime->tm_mday = + tmtime->tm_mday + (short) RFIFOW (fd, 30); + tmtime->tm_hour = + tmtime->tm_hour + (short) RFIFOW (fd, 32); + tmtime->tm_min = + tmtime->tm_min + (short) RFIFOW (fd, 34); + tmtime->tm_sec = + tmtime->tm_sec + (short) RFIFOW (fd, 36); + timestamp = mktime (tmtime); + if (timestamp != -1) + { + if (timestamp <= time (NULL)) + timestamp = 0; + strftime (tmpstr, 24, date_format, + gmtime (×tamp)); + login_log + ("'ladmin': Adjustment of a final date of a banishment (account: %s, (%+d y %+d m %+d d %+d h %+d mn %+d s) -> new validity: %d (%s), ip: %s)\n", + auth_dat[i].userid, + (short) RFIFOW (fd, 26), (short) RFIFOW (fd, + 28), + (short) RFIFOW (fd, 30), (short) RFIFOW (fd, + 32), + (short) RFIFOW (fd, 34), (short) RFIFOW (fd, + 36), + timestamp, + (timestamp == 0 ? "no banishment" : tmpstr), + ip); + if (auth_dat[i].ban_until_time != timestamp) + { + if (timestamp != 0) + { + unsigned char buf[16]; + WBUFW (buf, 0) = 0x2731; + WBUFL (buf, 2) = auth_dat[i].account_id; + WBUFB (buf, 6) = 1; // 0: change of statut, 1: ban + WBUFL (buf, 7) = timestamp; // status or final date of a banishment + charif_sendallwos (-1, buf, 11); + for (j = 0; j < AUTH_FIFO_SIZE; j++) + if (auth_fifo[j].account_id == + auth_dat[i].account_id) + auth_fifo[j].login_id1++; // to avoid reconnection error when come back from map-server (char-server will ask again the authentification) + } + auth_dat[i].ban_until_time = timestamp; + } + } + else + { + strftime (tmpstr, 24, date_format, + gmtime (&auth_dat[i].ban_until_time)); + login_log + ("'ladmin': Impossible to adjust the final date of a banishment (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", + auth_dat[i].userid, + auth_dat[i].ban_until_time, + (auth_dat[i].ban_until_time == + 0 ? "no banishment" : tmpstr), + (short) RFIFOW (fd, 26), (short) RFIFOW (fd, + 28), + (short) RFIFOW (fd, 30), (short) RFIFOW (fd, + 32), + (short) RFIFOW (fd, 34), (short) RFIFOW (fd, + 36), + ip); + } + WFIFOL (fd, 30) = + (unsigned long) auth_dat[i].ban_until_time; + } + else + { + memcpy (WFIFOP (fd, 6), account_name, 24); + login_log + ("'ladmin': Attempt to adjust the final date of a banishment of an unknown account (account: %s, ip: %s)\n", + account_name, ip); + WFIFOL (fd, 30) = 0; + } + } + WFIFOSET (fd, 34); + RFIFOSKIP (fd, 38); + break; + + case 0x794e: // Request to send a broadcast message + if (RFIFOREST (fd) < 8 + || RFIFOREST (fd) < (8 + RFIFOL (fd, 4))) + return; + WFIFOW (fd, 0) = 0x794f; + WFIFOW (fd, 2) = -1; + if (RFIFOL (fd, 4) < 1) + { + login_log + ("'ladmin': Receiving a message for broadcast, but message is void (ip: %s)\n", + ip); + } + else + { + // at least 1 char-server + for (i = 0; i < MAX_SERVERS; i++) + if (server_fd[i] >= 0) + break; + if (i == MAX_SERVERS) + { + login_log + ("'ladmin': Receiving a message for broadcast, but no char-server is online (ip: %s)\n", + ip); + } + else + { + char buf[32000]; + char message[32000]; + WFIFOW (fd, 2) = 0; + memset (message, '\0', sizeof (message)); + memcpy (message, RFIFOP (fd, 8), RFIFOL (fd, 4)); + message[sizeof (message) - 1] = '\0'; + remove_control_chars (message); + if (RFIFOW (fd, 2) == 0) + login_log + ("'ladmin': Receiving a message for broadcast (message (in yellow): %s, ip: %s)\n", + message, ip); + else + login_log + ("'ladmin': Receiving a message for broadcast (message (in blue): %s, ip: %s)\n", + message, ip); + // send same message to all char-servers (no answer) + memcpy (WBUFP (buf, 0), RFIFOP (fd, 0), + 8 + RFIFOL (fd, 4)); + WBUFW (buf, 0) = 0x2726; + charif_sendallwos (-1, buf, 8 + RFIFOL (fd, 4)); + } + } + WFIFOSET (fd, 4); + RFIFOSKIP (fd, 8 + RFIFOL (fd, 4)); + break; + + case 0x7950: // Request to change the validity limite (timestamp) (relative change) + if (RFIFOREST (fd) < 38) + return; + { + time_t timestamp; + struct tm *tmtime; + char tmpstr[2048]; + char tmpstr2[2048]; + WFIFOW (fd, 0) = 0x7951; + WFIFOL (fd, 2) = -1; + account_name = RFIFOP (fd, 2); + account_name[23] = '\0'; + remove_control_chars (account_name); + i = search_account_index (account_name); + if (i != -1) + { + WFIFOL (fd, 2) = auth_dat[i].account_id; + memcpy (WFIFOP (fd, 6), auth_dat[i].userid, 24); + timestamp = auth_dat[i].connect_until_time; + if (add_to_unlimited_account == 0 && timestamp == 0) + { + login_log + ("'ladmin': Attempt to adjust the validity limit of an unlimited account (account: %s, ip: %s)\n", + auth_dat[i].userid, ip); + WFIFOL (fd, 30) = 0; + } + else + { + if (timestamp == 0 || timestamp < time (NULL)) + timestamp = time (NULL); + tmtime = gmtime (×tamp); + tmtime->tm_year = + tmtime->tm_year + (short) RFIFOW (fd, 26); + tmtime->tm_mon = + tmtime->tm_mon + (short) RFIFOW (fd, 28); + tmtime->tm_mday = + tmtime->tm_mday + (short) RFIFOW (fd, 30); + tmtime->tm_hour = + tmtime->tm_hour + (short) RFIFOW (fd, 32); + tmtime->tm_min = + tmtime->tm_min + (short) RFIFOW (fd, 34); + tmtime->tm_sec = + tmtime->tm_sec + (short) RFIFOW (fd, 36); + timestamp = mktime (tmtime); + if (timestamp != -1) + { + strftime (tmpstr, 24, date_format, + gmtime (&auth_dat + [i].connect_until_time)); + strftime (tmpstr2, 24, date_format, + gmtime (×tamp)); + login_log + ("'ladmin': Adjustment of a validity limit (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> new validity: %d (%s), ip: %s)\n", + auth_dat[i].userid, + auth_dat[i].connect_until_time, + (auth_dat[i].connect_until_time == + 0 ? "unlimited" : tmpstr), + (short) RFIFOW (fd, 26), + (short) RFIFOW (fd, 28), + (short) RFIFOW (fd, 30), + (short) RFIFOW (fd, 32), + (short) RFIFOW (fd, 34), + (short) RFIFOW (fd, 36), timestamp, + (timestamp == 0 ? "unlimited" : tmpstr2), + ip); + auth_dat[i].connect_until_time = timestamp; + WFIFOL (fd, 30) = + (unsigned long) + auth_dat[i].connect_until_time; + } + else + { + strftime (tmpstr, 24, date_format, + gmtime (&auth_dat + [i].connect_until_time)); + login_log + ("'ladmin': Impossible to adjust a validity limit (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", + auth_dat[i].userid, + auth_dat[i].connect_until_time, + (auth_dat[i].connect_until_time == + 0 ? "unlimited" : tmpstr), + (short) RFIFOW (fd, 26), + (short) RFIFOW (fd, 28), + (short) RFIFOW (fd, 30), + (short) RFIFOW (fd, 32), + (short) RFIFOW (fd, 34), + (short) RFIFOW (fd, 36), ip); + WFIFOL (fd, 30) = 0; + } + } + } + else + { + memcpy (WFIFOP (fd, 6), account_name, 24); + login_log + ("'ladmin': Attempt to adjust the validity limit of an unknown account (account: %s, ip: %s)\n", + account_name, ip); + WFIFOL (fd, 30) = 0; + } + } + WFIFOSET (fd, 34); + RFIFOSKIP (fd, 38); + break; + + case 0x7952: // Request about informations of an account (by account name) + if (RFIFOREST (fd) < 26) + return; + WFIFOW (fd, 0) = 0x7953; + WFIFOL (fd, 2) = -1; + account_name = RFIFOP (fd, 2); + account_name[23] = '\0'; + remove_control_chars (account_name); + i = search_account_index (account_name); + if (i != -1) + { + WFIFOL (fd, 2) = auth_dat[i].account_id; + WFIFOB (fd, 6) = + (unsigned char) isGM (auth_dat[i].account_id); + memcpy (WFIFOP (fd, 7), auth_dat[i].userid, 24); + WFIFOB (fd, 31) = auth_dat[i].sex; + WFIFOL (fd, 32) = auth_dat[i].logincount; + WFIFOL (fd, 36) = auth_dat[i].state; + memcpy (WFIFOP (fd, 40), auth_dat[i].error_message, 20); + memcpy (WFIFOP (fd, 60), auth_dat[i].lastlogin, 24); + memcpy (WFIFOP (fd, 84), auth_dat[i].last_ip, 16); + memcpy (WFIFOP (fd, 100), auth_dat[i].email, 40); + WFIFOL (fd, 140) = + (unsigned long) auth_dat[i].connect_until_time; + WFIFOL (fd, 144) = + (unsigned long) auth_dat[i].ban_until_time; + WFIFOW (fd, 148) = strlen (auth_dat[i].memo); + if (auth_dat[i].memo[0]) + { + memcpy (WFIFOP (fd, 150), auth_dat[i].memo, + strlen (auth_dat[i].memo)); + } + login_log + ("'ladmin': Sending information of an account (request by the name; account: %s, id: %d, ip: %s)\n", + auth_dat[i].userid, auth_dat[i].account_id, + ip); + WFIFOSET (fd, 150 + strlen (auth_dat[i].memo)); + } + else + { + memcpy (WFIFOP (fd, 7), account_name, 24); + WFIFOW (fd, 148) = 0; + login_log + ("'ladmin': Attempt to obtain information (by the name) of an unknown account (account: %s, ip: %s)\n", + account_name, ip); + WFIFOSET (fd, 150); + } + RFIFOSKIP (fd, 26); + break; + + case 0x7954: // Request about information of an account (by account id) + if (RFIFOREST (fd) < 6) + return; + WFIFOW (fd, 0) = 0x7953; + WFIFOL (fd, 2) = RFIFOL (fd, 2); + memset (WFIFOP (fd, 7), '\0', 24); + for (i = 0; i < auth_num; i++) + { + if (auth_dat[i].account_id == RFIFOL (fd, 2)) + { + login_log + ("'ladmin': Sending information of an account (request by the id; account: %s, id: %d, ip: %s)\n", + auth_dat[i].userid, RFIFOL (fd, 2), ip); + WFIFOB (fd, 6) = + (unsigned char) isGM (auth_dat[i].account_id); + memcpy (WFIFOP (fd, 7), auth_dat[i].userid, 24); + WFIFOB (fd, 31) = auth_dat[i].sex; + WFIFOL (fd, 32) = auth_dat[i].logincount; + WFIFOL (fd, 36) = auth_dat[i].state; + memcpy (WFIFOP (fd, 40), auth_dat[i].error_message, + 20); + memcpy (WFIFOP (fd, 60), auth_dat[i].lastlogin, 24); + memcpy (WFIFOP (fd, 84), auth_dat[i].last_ip, 16); + memcpy (WFIFOP (fd, 100), auth_dat[i].email, 40); + WFIFOL (fd, 140) = + (unsigned long) auth_dat[i].connect_until_time; + WFIFOL (fd, 144) = + (unsigned long) auth_dat[i].ban_until_time; + WFIFOW (fd, 148) = strlen (auth_dat[i].memo); + if (auth_dat[i].memo[0]) + { + memcpy (WFIFOP (fd, 150), auth_dat[i].memo, + strlen (auth_dat[i].memo)); + } + WFIFOSET (fd, 150 + strlen (auth_dat[i].memo)); + break; + } + } + if (i == auth_num) + { + login_log + ("'ladmin': Attempt to obtain information (by the id) of an unknown account (id: %d, ip: %s)\n", + RFIFOL (fd, 2), ip); + strncpy (WFIFOP (fd, 7), "", 24); + WFIFOW (fd, 148) = 0; + WFIFOSET (fd, 150); + } + RFIFOSKIP (fd, 6); + break; + + case 0x7955: // Request to reload GM file (no answer) + login_log + ("'ladmin': Request to re-load GM configuration file (ip: %s).\n", + ip); + read_gm_account (); + // send GM accounts to all char-servers + send_GM_accounts (); + RFIFOSKIP (fd, 2); + break; + + default: + { + FILE *logfp; + char tmpstr[24]; + struct timeval tv; + logfp = fopen_ (login_log_unknown_packets_filename, "a"); + if (logfp) + { + gettimeofday (&tv, NULL); + strftime (tmpstr, 23, date_format, gmtime (&(tv.tv_sec))); + fprintf (logfp, + "%s.%03d: receiving of an unknown packet -> disconnection\n", + tmpstr, (int) tv.tv_usec / 1000); + fprintf (logfp, + "parse_admin: connection #%d (ip: %s), packet: 0x%x (with being read: %d).\n", + fd, ip, RFIFOW (fd, 0), RFIFOREST (fd)); + fprintf (logfp, "Detail (in hex):\n"); + fprintf (logfp, + "---- 00-01-02-03-04-05-06-07 08-09-0A-0B-0C-0D-0E-0F\n"); + memset (tmpstr, '\0', sizeof (tmpstr)); + for (i = 0; i < RFIFOREST (fd); i++) + { + if ((i & 15) == 0) + fprintf (logfp, "%04X ", i); + fprintf (logfp, "%02x ", RFIFOB (fd, i)); + if (RFIFOB (fd, i) > 0x1f) + tmpstr[i % 16] = RFIFOB (fd, i); + else + tmpstr[i % 16] = '.'; + if ((i - 7) % 16 == 0) // -8 + 1 + fprintf (logfp, " "); + else if ((i + 1) % 16 == 0) + { + fprintf (logfp, " %s\n", tmpstr); + memset (tmpstr, '\0', sizeof (tmpstr)); + } + } + if (i % 16 != 0) + { + for (j = i; j % 16 != 0; j++) + { + fprintf (logfp, " "); + if ((j - 7) % 16 == 0) // -8 + 1 + fprintf (logfp, " "); + } + fprintf (logfp, " %s\n", tmpstr); + } + fprintf (logfp, "\n"); + fclose_ (logfp); + } + } + login_log + ("'ladmin': End of connection, unknown packet (ip: %s)\n", + ip); + session[fd]->eof = 1; + printf + ("Remote administration has been disconnected (unknown packet).\n"); + return; + } + //WFIFOW(fd,0) = 0x791f; + //WFIFOSET(fd,2); + } + return; +} + +//-------------------------------------------- +// Test to know if an IP come from LAN or WAN. +//-------------------------------------------- +int lan_ip_check (unsigned char *p) +{ + int i; + int lancheck = 1; + +// printf("lan_ip_check: to compare: %d.%d.%d.%d, network: %d.%d.%d.%d/%d.%d.%d.%d\n", +// p[0], p[1], p[2], p[3], +// subneti[0], subneti[1], subneti[2], subneti[3], +// subnetmaski[0], subnetmaski[1], subnetmaski[2], subnetmaski[3]); + for (i = 0; i < 4; i++) + { + if ((subneti[i] & subnetmaski[i]) != (p[i] & subnetmaski[i])) + { + lancheck = 0; + break; + } + } + printf ("LAN test (result): %s source\033[0m.\n", + (lancheck) ? "\033[1;36mLAN" : "\033[1;32mWAN"); + return lancheck; +} + +//---------------------------------------------------------------------------------------- +// Default packet parsing (normal players or administation/char-server connexion requests) +//---------------------------------------------------------------------------------------- +void parse_login (int fd) +{ + struct mmo_account account; + int result, i, j; + unsigned char *p = (unsigned char *) &session[fd]->client_addr.sin_addr; + char ip[16]; + int host_len; + + sprintf (ip, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); + + if (session[fd]->eof) + { + close (fd); + delete_session (fd); + return; + } + + while (RFIFOREST (fd) >= 2) + { + if (display_parse_login == 1) + { + if (RFIFOW (fd, 0) == 0x64 || RFIFOW (fd, 0) == 0x01dd) + { + if (RFIFOREST (fd) >= ((RFIFOW (fd, 0) == 0x64) ? 55 : 47)) + printf + ("parse_login: connection #%d, packet: 0x%x (with being read: %d), account: %s.\n", + fd, RFIFOW (fd, 0), RFIFOREST (fd), RFIFOP (fd, 6)); + } + else if (RFIFOW (fd, 0) == 0x2710) + { + if (RFIFOREST (fd) >= 86) + printf + ("parse_login: connection #%d, packet: 0x%x (with being read: %d), server: %s.\n", + fd, RFIFOW (fd, 0), RFIFOREST (fd), RFIFOP (fd, 60)); + } + else + printf + ("parse_login: connection #%d, packet: 0x%x (with being read: %d).\n", + fd, RFIFOW (fd, 0), RFIFOREST (fd)); + } + + switch (RFIFOW (fd, 0)) + { + case 0x200: // New alive packet: structure: 0x200 .24B. used to verify if client is always alive. + if (RFIFOREST (fd) < 26) + return; + RFIFOSKIP (fd, 26); + break; + + case 0x204: // New alive packet: structure: 0x204 .16B. (new ragexe from 22 june 2004) + if (RFIFOREST (fd) < 18) + return; + RFIFOSKIP (fd, 18); + break; + + case 0x64: // Ask connection of a client + case 0x01dd: // Ask connection of a client (encryption mode) + if (RFIFOREST (fd) < ((RFIFOW (fd, 0) == 0x64) ? 55 : 47)) + return; + + account.userid = RFIFOP (fd, 6); + account.userid[23] = '\0'; + remove_control_chars (account.userid); + account.passwd = RFIFOP (fd, 30); + if (RFIFOW (fd, 0) == 0x64) + { + account.passwd[23] = '\0'; + remove_control_chars (account.passwd); + } +#ifdef PASSWORDENC + account.passwdenc = + (RFIFOW (fd, 0) == 0x64) ? 0 : PASSWORDENC; +#else + account.passwdenc = 0; +#endif + + if (RFIFOW (fd, 0) == 0x64) + { + login_log + ("Request for connection (non encryption mode) of %s (ip: %s).\n", + account.userid, ip); + } + else + { + login_log + ("Request for connection (encryption mode) of %s (ip: %s).\n", + account.userid, ip); + } + + if (!check_ip (session[fd]->client_addr.sin_addr.s_addr)) + { + login_log + ("Connection refused: IP isn't authorised (deny/allow, ip: %s).\n", + ip); + WFIFOW (fd, 0) = 0x6a; + WFIFOB (fd, 2) = 0x03; + WFIFOSET (fd, 3); + RFIFOSKIP (fd, (RFIFOW (fd, 0) == 0x64) ? 55 : 47); + break; + } + + result = mmo_auth (&account, fd); + if (result == -1) + { + int gm_level = isGM (account.account_id); + if (min_level_to_connect > gm_level) + { + login_log + ("Connection refused: the minimum GM level for connection is %d (account: %s, GM level: %d, ip: %s).\n", + min_level_to_connect, account.userid, + gm_level, ip); + WFIFOW (fd, 0) = 0x81; + WFIFOL (fd, 2) = 1; // 01 = Server closed + WFIFOSET (fd, 3); + } + else + { + int version_2 = RFIFOB (fd, 54); // version 2 + + if (gm_level) + printf + ("Connection of the GM (level:%d) account '%s' accepted.\n", + gm_level, account.userid); + else + printf + ("Connection of the account '%s' accepted.\n", + account.userid); + + /* + * Add a 0x0063 packet, which contains the name of the update host. The packet will only + * be sent if login_athena.conf contains a non-null entry for "update_host:" + * + * Because older clients cannot handle the 0x63 packet, we check the "version 2" value + * from the incoming 0x64 packet (the byte at offset 54). If bit 0 of this is set, + * then the client can safely accept the 0x63 packet. The "version 2" value is not + * otherwise used by eAthena. + */ + if ((RFIFOW (fd, 0) == 0x64) + && (version_2 & VERSION_2_UPDATEHOST)) + { + host_len = (int) strlen (update_host); + if (host_len > 0) + { + WFIFOW (fd, 0) = 0x63; + WFIFOW (fd, 2) = 4 + host_len; + memcpy (WFIFOP (fd, 4), update_host, + host_len); + WFIFOSET (fd, 4 + host_len); + } + } + + // Load list of char servers into outbound packet + server_num = 0; + if (version_2 && VERSION_2_SERVERORDER) + for (i = 0; i < MAX_SERVERS; i++) + { + if (server_fd[i] >= 0) + { + if (lan_ip_check (p)) + WFIFOL (fd, 47 + server_num * 32) = + inet_addr (lan_char_ip); + else + WFIFOL (fd, 47 + server_num * 32) = + server[i].ip; + WFIFOW (fd, 47 + server_num * 32 + 4) = + server[i].port; + memcpy (WFIFOP + (fd, 47 + server_num * 32 + 6), + server[i].name, 20); + WFIFOW (fd, 47 + server_num * 32 + 26) = + server[i].users; + WFIFOW (fd, 47 + server_num * 32 + 28) = + server[i].maintenance; + WFIFOW (fd, 47 + server_num * 32 + 30) = + server[i].is_new; + server_num++; + } + } + else // Send them in reverse, as the client defaults to the second (!) one + for (i = MAX_SERVERS - 1; i >= 0; i--) + { + if (server_fd[i] >= 0) + { + if (lan_ip_check (p)) + WFIFOL (fd, 47 + server_num * 32) = + inet_addr (lan_char_ip); + else + WFIFOL (fd, 47 + server_num * 32) = + server[i].ip; + WFIFOW (fd, 47 + server_num * 32 + 4) = + server[i].port; + memcpy (WFIFOP + (fd, 47 + server_num * 32 + 6), + server[i].name, 20); + WFIFOW (fd, 47 + server_num * 32 + 26) = + server[i].users; + WFIFOW (fd, 47 + server_num * 32 + 28) = + server[i].maintenance; + WFIFOW (fd, 47 + server_num * 32 + 30) = + server[i].is_new; + server_num++; + } + } + // if at least 1 char-server + if (server_num > 0) + { + WFIFOW (fd, 0) = 0x69; + WFIFOW (fd, 2) = 47 + 32 * server_num; + WFIFOL (fd, 4) = account.login_id1; + WFIFOL (fd, 8) = account.account_id; + WFIFOL (fd, 12) = account.login_id2; + WFIFOL (fd, 16) = 0; // in old version, that was for ip (not more used) + memcpy (WFIFOP (fd, 20), account.lastlogin, 24); // in old version, that was for name (not more used) + WFIFOB (fd, 46) = account.sex; + WFIFOSET (fd, 47 + 32 * server_num); + if (auth_fifo_pos >= AUTH_FIFO_SIZE) + auth_fifo_pos = 0; + auth_fifo[auth_fifo_pos].account_id = + account.account_id; + auth_fifo[auth_fifo_pos].login_id1 = + account.login_id1; + auth_fifo[auth_fifo_pos].login_id2 = + account.login_id2; + auth_fifo[auth_fifo_pos].sex = account.sex; + auth_fifo[auth_fifo_pos].delflag = 0; + auth_fifo[auth_fifo_pos].ip = + session[fd]->client_addr.sin_addr.s_addr; + auth_fifo_pos++; + // if no char-server, don't send void list of servers, just disconnect the player with proper message + } + else + { + login_log + ("Connection refused: there is no char-server online (account: %s, ip: %s).\n", + account.userid, ip); + WFIFOW (fd, 0) = 0x81; + WFIFOL (fd, 2) = 1; // 01 = Server closed + WFIFOSET (fd, 3); + } + } + } + else + { + memset (WFIFOP (fd, 0), '\0', 23); + WFIFOW (fd, 0) = 0x6a; + WFIFOB (fd, 2) = result; + if (result == 6) + { // 6 = Your are Prohibited to log in until %s + i = search_account_index (account.userid); + if (i != -1) + { + if (auth_dat[i].ban_until_time != 0) + { // if account is banned, we send ban timestamp + char tmpstr[256]; + strftime (tmpstr, 20, date_format, + gmtime (&auth_dat + [i].ban_until_time)); + tmpstr[19] = '\0'; + memcpy (WFIFOP (fd, 3), tmpstr, 20); + } + else + { // we send error message + memcpy (WFIFOP (fd, 3), + auth_dat[i].error_message, 20); + } + } + } + WFIFOSET (fd, 23); + } + RFIFOSKIP (fd, (RFIFOW (fd, 0) == 0x64) ? 55 : 47); + break; + + case 0x01db: // Sending request of the coding key + case 0x791a: // Sending request of the coding key (administration packet) + { + struct login_session_data *ld; + if (session[fd]->session_data) + { + printf + ("login: abnormal request of MD5 key (already opened session).\n"); + session[fd]->eof = 1; + return; + } + CREATE (ld, struct login_session_data, 1); + session[fd]->session_data = ld; + if (!ld) + { + printf + ("login: Request for md5 key: memory allocation failure (malloc)!\n"); + session[fd]->eof = 1; + return; + } + if (RFIFOW (fd, 0) == 0x01db) + { + login_log ("Sending request of the coding key (ip: %s)\n", + ip); + } + else + { + login_log + ("'ladmin': Sending request of the coding key (ip: %s)\n", + ip); + } + // Creation of the coding key + memset (ld->md5key, '\0', sizeof (ld->md5key)); + ld->md5keylen = rand () % 4 + 12; + for (i = 0; i < ld->md5keylen; i++) + ld->md5key[i] = rand () % 255 + 1; + + RFIFOSKIP (fd, 2); + WFIFOW (fd, 0) = 0x01dc; + WFIFOW (fd, 2) = 4 + ld->md5keylen; + memcpy (WFIFOP (fd, 4), ld->md5key, ld->md5keylen); + WFIFOSET (fd, WFIFOW (fd, 2)); + } + break; + + case 0x2710: // Connection request of a char-server + if (RFIFOREST (fd) < 86) + return; + { + int GM_value, len; + unsigned char *server_name; + account.userid = RFIFOP (fd, 2); + account.userid[23] = '\0'; + remove_control_chars (account.userid); + account.passwd = RFIFOP (fd, 26); + account.passwd[23] = '\0'; + remove_control_chars (account.passwd); + account.passwdenc = 0; + server_name = RFIFOP (fd, 60); + server_name[19] = '\0'; + remove_control_chars (server_name); + login_log + ("Connection request of the char-server '%s' @ %d.%d.%d.%d:%d (ip: %s)\n", + server_name, RFIFOB (fd, 54), RFIFOB (fd, 55), + RFIFOB (fd, 56), RFIFOB (fd, 57), RFIFOW (fd, 58), + ip); + result = mmo_auth (&account, fd); + + if (result == -1 && account.sex == 2) + { + // If this is the main server, and we don't already have a main server + if (server_fd[0] <= 0 + && strcasecmp (server_name, main_server) == 0) + { + account.account_id = 0; + } + else + { + int i; + for (i = 1; i < MAX_SERVERS; i++) + { + if (server_fd[i] <= 0) + { + account.account_id = i; + break; + } + } + } + } + + if (result == -1 && account.sex == 2 + && account.account_id < MAX_SERVERS + && server_fd[account.account_id] == -1) + { + login_log + ("Connection of the char-server '%s' accepted (account: %s, pass: %s, ip: %s)\n", + server_name, account.userid, + account.passwd, ip); + printf + ("Connection of the char-server '%s' accepted.\n", + server_name); + memset (&server[account.account_id], 0, + sizeof (struct mmo_char_server)); + server[account.account_id].ip = RFIFOL (fd, 54); + server[account.account_id].port = RFIFOW (fd, 58); + memcpy (server[account.account_id].name, server_name, + 20); + server[account.account_id].users = 0; + server[account.account_id].maintenance = + RFIFOW (fd, 82); + server[account.account_id].is_new = RFIFOW (fd, 84); + server_fd[account.account_id] = fd; + if (anti_freeze_enable) + server_freezeflag[account.account_id] = 5; // Char-server anti-freeze system. Counter. 5 ok, 4...0 freezed + WFIFOW (fd, 0) = 0x2711; + WFIFOB (fd, 2) = 0; + WFIFOSET (fd, 3); + session[fd]->func_parse = parse_fromchar; + realloc_fifo (fd, FIFOSIZE_SERVERLINK, + FIFOSIZE_SERVERLINK); + // send GM account to char-server + len = 4; + WFIFOW (fd, 0) = 0x2732; + for (i = 0; i < auth_num; i++) + // send only existing accounts. We can not create a GM account when server is online. + if ((GM_value = + isGM (auth_dat[i].account_id)) > 0) + { + WFIFOL (fd, len) = auth_dat[i].account_id; + WFIFOB (fd, len + 4) = + (unsigned char) GM_value; + len += 5; + } + WFIFOW (fd, 2) = len; + WFIFOSET (fd, len); + } + else + { + login_log + ("Connexion of the char-server '%s' REFUSED (account: %s, pass: %s, ip: %s)\n", + server_name, account.userid, + account.passwd, ip); + WFIFOW (fd, 0) = 0x2711; + WFIFOB (fd, 2) = 3; + WFIFOSET (fd, 3); + } + } + RFIFOSKIP (fd, 86); + return; + + case 0x7530: // Request of the server version + login_log ("Sending of the server version (ip: %s)\n", + ip); + WFIFOW (fd, 0) = 0x7531; + WFIFOB (fd, 2) = -1; + WFIFOB (fd, 3) = 'T'; + WFIFOB (fd, 4) = 'M'; + WFIFOB (fd, 5) = 'W'; + WFIFOL (fd, 6) = new_account_flag ? 1 : 0; + WFIFOSET (fd, 10); + RFIFOSKIP (fd, 2); + break; + + case 0x7532: // Request to end connection + login_log ("End of connection (ip: %s)\n", ip); + session[fd]->eof = 1; + return; + + case 0x7918: // Request for administation login + if (RFIFOREST (fd) < 4 + || RFIFOREST (fd) < ((RFIFOW (fd, 2) == 0) ? 28 : 20)) + return; + WFIFOW (fd, 0) = 0x7919; + WFIFOB (fd, 2) = 1; + if (!check_ladminip + (session[fd]->client_addr.sin_addr.s_addr)) + { + login_log + ("'ladmin'-login: Connection in administration mode refused: IP isn't authorised (ladmin_allow, ip: %s).\n", + ip); + } + else + { + struct login_session_data *ld = (struct login_session_data *)session[fd]->session_data; + if (RFIFOW (fd, 2) == 0) + { // non encrypted password + unsigned char *password; + password = RFIFOP (fd, 4); + password[23] = '\0'; + remove_control_chars (password); + // If remote administration is enabled and password sent by client matches password read from login server configuration file + if ((admin_state == 1) + && (strcmp (password, admin_pass) == 0)) + { + login_log + ("'ladmin'-login: Connection in administration mode accepted (non encrypted password: %s, ip: %s)\n", + password, ip); + printf + ("Connection of a remote administration accepted (non encrypted password).\n"); + WFIFOB (fd, 2) = 0; + session[fd]->func_parse = parse_admin; + } + else if (admin_state != 1) + login_log + ("'ladmin'-login: Connection in administration mode REFUSED - remote administration is disabled (non encrypted password: %s, ip: %s)\n", + password, ip); + else + login_log + ("'ladmin'-login: Connection in administration mode REFUSED - invalid password (non encrypted password: %s, ip: %s)\n", + password, ip); + } + else + { // encrypted password + if (!ld) + printf + ("'ladmin'-login: error! MD5 key not created/requested for an administration login.\n"); + else + { + char md5str[64] = "", md5bin[32]; + if (RFIFOW (fd, 2) == 1) + { + strncpy (md5str, ld->md5key, sizeof (ld->md5key)); // 20 + strcat (md5str, admin_pass); // 24 + } + else if (RFIFOW (fd, 2) == 2) + { + strncpy (md5str, admin_pass, sizeof (admin_pass)); // 24 + strcat (md5str, ld->md5key); // 20 + } + MD5_to_bin(MD5_from_cstring(md5str), md5bin); + // If remote administration is enabled and password hash sent by client matches hash of password read from login server configuration file + if ((admin_state == 1) + && (memcmp (md5bin, RFIFOP (fd, 4), 16) == 0)) + { + login_log + ("'ladmin'-login: Connection in administration mode accepted (encrypted password, ip: %s)\n", + ip); + printf + ("Connection of a remote administration accepted (encrypted password).\n"); + WFIFOB (fd, 2) = 0; + session[fd]->func_parse = parse_admin; + } + else if (admin_state != 1) + login_log + ("'ladmin'-login: Connection in administration mode REFUSED - remote administration is disabled (encrypted password, ip: %s)\n", + ip); + else + login_log + ("'ladmin'-login: Connection in administration mode REFUSED - invalid password (encrypted password, ip: %s)\n", + ip); + } + } + } + WFIFOSET (fd, 3); + RFIFOSKIP (fd, (RFIFOW (fd, 2) == 0) ? 28 : 20); + break; + + default: + if (save_unknown_packets) + { + FILE *logfp; + char tmpstr[24]; + struct timeval tv; + logfp = fopen_ (login_log_unknown_packets_filename, "a"); + if (logfp) + { + gettimeofday (&tv, NULL); + strftime (tmpstr, 23, date_format, + gmtime (&(tv.tv_sec))); + fprintf (logfp, + "%s.%03d: receiving of an unknown packet -> disconnection\n", + tmpstr, (int) tv.tv_usec / 1000); + fprintf (logfp, + "parse_login: connection #%d (ip: %s), packet: 0x%x (with being read: %d).\n", + fd, ip, RFIFOW (fd, 0), + RFIFOREST (fd)); + fprintf (logfp, "Detail (in hex):\n"); + fprintf (logfp, + "---- 00-01-02-03-04-05-06-07 08-09-0A-0B-0C-0D-0E-0F\n"); + memset (tmpstr, '\0', sizeof (tmpstr)); + for (i = 0; i < RFIFOREST (fd); i++) + { + if ((i & 15) == 0) + fprintf (logfp, "%04X ", i); + fprintf (logfp, "%02x ", RFIFOB (fd, i)); + if (RFIFOB (fd, i) > 0x1f) + tmpstr[i % 16] = RFIFOB (fd, i); + else + tmpstr[i % 16] = '.'; + if ((i - 7) % 16 == 0) // -8 + 1 + fprintf (logfp, " "); + else if ((i + 1) % 16 == 0) + { + fprintf (logfp, " %s\n", tmpstr); + memset (tmpstr, '\0', sizeof (tmpstr)); + } + } + if (i % 16 != 0) + { + for (j = i; j % 16 != 0; j++) + { + fprintf (logfp, " "); + if ((j - 7) % 16 == 0) // -8 + 1 + fprintf (logfp, " "); + } + fprintf (logfp, " %s\n", tmpstr); + } + fprintf (logfp, "\n"); + fclose_ (logfp); + } + } + login_log ("End of connection, unknown packet (ip: %s)\n", ip); + session[fd]->eof = 1; + return; + } + } + return; +} + +//------------------------------------------------- +// Return numerical value of a switch configuration +// on/off, english, français, deutsch, español +//------------------------------------------------- +int config_switch (const char *str) +{ + if (strcasecmp (str, "on") == 0 || strcasecmp (str, "yes") == 0 + || strcasecmp (str, "oui") == 0 || strcasecmp (str, "ja") == 0 + || strcasecmp (str, "si") == 0) + return 1; + if (strcasecmp (str, "off") == 0 || strcasecmp (str, "no") == 0 + || strcasecmp (str, "non") == 0 || strcasecmp (str, "nein") == 0) + return 0; + + return atoi (str); +} + +//---------------------------------- +// Reading Lan Support configuration +//---------------------------------- +int login_lan_config_read (const char *lancfgName) +{ + int j; + struct hostent *h = NULL; + char line[1024], w1[1024], w2[1024]; + FILE *fp; + + // set default configuration + strncpy (lan_char_ip, "127.0.0.1", sizeof (lan_char_ip)); + subneti[0] = 127; + subneti[1] = 0; + subneti[2] = 0; + subneti[3] = 1; + for (j = 0; j < 4; j++) + subnetmaski[j] = 255; + + fp = fopen_ (lancfgName, "r"); + + if (fp == NULL) + { + printf + ("***WARNING: LAN Support configuration file is not found: %s\n", + lancfgName); + return 1; + } + + printf ("---Start reading Lan Support configuration file\n"); + + while (fgets (line, sizeof (line) - 1, fp)) + { + if (line[0] == '/' && line[1] == '/') + continue; + + line[sizeof (line) - 1] = '\0'; + if (sscanf (line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; + + remove_control_chars (w1); + remove_control_chars (w2); + if (strcasecmp (w1, "lan_char_ip") == 0) + { // Read Char-Server Lan IP Address + h = gethostbyname (w2); + if (h != NULL) + { + sprintf (lan_char_ip, "%d.%d.%d.%d", + (unsigned char) h->h_addr[0], + (unsigned char) h->h_addr[1], + (unsigned char) h->h_addr[2], + (unsigned char) h->h_addr[3]); + } + else + { + strncpy (lan_char_ip, w2, sizeof (lan_char_ip)); + lan_char_ip[sizeof (lan_char_ip) - 1] = '\0'; + } + printf ("LAN IP of char-server: %s.\n", lan_char_ip); + } + else if (strcasecmp (w1, "subnet") == 0) + { // Read Subnetwork + for (j = 0; j < 4; j++) + subneti[j] = 0; + h = gethostbyname (w2); + if (h != NULL) + { + for (j = 0; j < 4; j++) + subneti[j] = (unsigned char) h->h_addr[j]; + } + else + { + sscanf (w2, "%d.%d.%d.%d", &subneti[0], &subneti[1], + &subneti[2], &subneti[3]); + } + printf ("Sub-network of the char-server: %d.%d.%d.%d.\n", + subneti[0], subneti[1], subneti[2], subneti[3]); + } + else if (strcasecmp (w1, "subnetmask") == 0) + { // Read Subnetwork Mask + for (j = 0; j < 4; j++) + subnetmaski[j] = 255; + h = gethostbyname (w2); + if (h != NULL) + { + for (j = 0; j < 4; j++) + subnetmaski[j] = (unsigned char) h->h_addr[j]; + } + else + { + sscanf (w2, "%d.%d.%d.%d", &subnetmaski[0], &subnetmaski[1], + &subnetmaski[2], &subnetmaski[3]); + } + printf ("Sub-network mask of the char-server: %d.%d.%d.%d.\n", + subnetmaski[0], subnetmaski[1], subnetmaski[2], + subnetmaski[3]); + } + } + fclose_ (fp); + + // log the LAN configuration + login_log ("The LAN configuration of the server is set:\n"); + login_log ("- with LAN IP of char-server: %s.\n", lan_char_ip); + login_log + ("- with the sub-network of the char-server: %d.%d.%d.%d/%d.%d.%d.%d.\n", + subneti[0], subneti[1], subneti[2], subneti[3], + subnetmaski[0], subnetmaski[1], subnetmaski[2], subnetmaski[3]); + + // sub-network check of the char-server + { + unsigned int a0, a1, a2, a3; + unsigned char p[4]; + sscanf (lan_char_ip, "%d.%d.%d.%d", &a0, &a1, &a2, &a3); + p[0] = a0; + p[1] = a1; + p[2] = a2; + p[3] = a3; + printf ("LAN test of LAN IP of the char-server: "); + if (lan_ip_check (p) == 0) + { + printf + ("\033[1;31m***ERROR: LAN IP of the char-server doesn't belong to the specified Sub-network\033[0m\n"); + login_log + ("***ERROR: LAN IP of the char-server doesn't belong to the specified Sub-network.\n"); + } + } + + printf ("---End reading of Lan Support configuration file\n"); + + return 0; +} + +//----------------------------------- +// Reading general configuration file +//----------------------------------- +int login_config_read (const char *cfgName) +{ + char line[1024], w1[1024], w2[1024]; + FILE *fp; + + fp = fopen_ (cfgName, "r"); + if (fp == NULL) + { + printf ("Configuration file (%s) not found.\n", cfgName); + return 1; + } + + printf ("---Start reading of Login Server configuration file (%s)\n", + cfgName); + while (fgets (line, sizeof (line) - 1, fp)) + { + if (line[0] == '/' && line[1] == '/') + continue; + + line[sizeof (line) - 1] = '\0'; + if (sscanf (line, "%[^:]: %[^\r\n]", w1, w2) == 2) + { + remove_control_chars (w1); + remove_control_chars (w2); + + if (strcasecmp (w1, "admin_state") == 0) + { + admin_state = config_switch (w2); + } + else if (strcasecmp (w1, "admin_pass") == 0) + { + strncpy (admin_pass, w2, sizeof (admin_pass)); + admin_pass[sizeof (admin_pass) - 1] = '\0'; + } + else if (strcasecmp (w1, "ladminallowip") == 0) + { + if (strcasecmp (w2, "clear") == 0) + { + if (access_ladmin_allow) + free (access_ladmin_allow); + access_ladmin_allow = NULL; + access_ladmin_allownum = 0; + } + else + { + if (strcasecmp (w2, "all") == 0) + { + // reset all previous values + if (access_ladmin_allow) + free (access_ladmin_allow); + // set to all + CREATE (access_ladmin_allow, char, ACO_STRSIZE); + access_ladmin_allownum = 1; + } + else if (w2[0] + && !(access_ladmin_allownum == 1 + && access_ladmin_allow[0] == '\0')) + { // don't add IP if already 'all' + if (access_ladmin_allow) + RECREATE (access_ladmin_allow, char, (access_ladmin_allownum + 1) * ACO_STRSIZE); + else + CREATE (access_ladmin_allow, char, ACO_STRSIZE); + strncpy (access_ladmin_allow + + (access_ladmin_allownum++) * ACO_STRSIZE, w2, + ACO_STRSIZE); + access_ladmin_allow[access_ladmin_allownum * + ACO_STRSIZE - 1] = '\0'; + } + } + } + else if (strcasecmp (w1, "gm_pass") == 0) + { + strncpy (gm_pass, w2, sizeof (gm_pass)); + gm_pass[sizeof (gm_pass) - 1] = '\0'; + } + else if (strcasecmp (w1, "level_new_gm") == 0) + { + level_new_gm = atoi (w2); + } + else if (strcasecmp (w1, "new_account") == 0) + { + new_account_flag = config_switch (w2); + } + else if (strcasecmp (w1, "login_port") == 0) + { + login_port = atoi (w2); + } + else if (strcasecmp (w1, "account_filename") == 0) + { + strncpy (account_filename, w2, sizeof (account_filename)); + account_filename[sizeof (account_filename) - 1] = '\0'; + } + else if (strcasecmp (w1, "gm_account_filename") == 0) + { + strncpy (GM_account_filename, w2, + sizeof (GM_account_filename)); + GM_account_filename[sizeof (GM_account_filename) - 1] = '\0'; + } + else if (strcasecmp (w1, "gm_account_filename_check_timer") == 0) + { + gm_account_filename_check_timer = atoi (w2); + } + else if (strcasecmp (w1, "login_log_filename") == 0) + { + strncpy (login_log_filename, w2, sizeof (login_log_filename)); + login_log_filename[sizeof (login_log_filename) - 1] = '\0'; + } + else if (strcasecmp (w1, "login_log_unknown_packets_filename") == 0) + { + strncpy (login_log_unknown_packets_filename, w2, + sizeof (login_log_unknown_packets_filename)); + login_log_unknown_packets_filename[sizeof + (login_log_unknown_packets_filename) + - 1] = '\0'; + } + else if (strcasecmp (w1, "save_unknown_packets") == 0) + { + save_unknown_packets = config_switch (w2); + } + else if (strcasecmp (w1, "display_parse_login") == 0) + { + display_parse_login = config_switch (w2); // 0: no, 1: yes + } + else if (strcasecmp (w1, "display_parse_admin") == 0) + { + display_parse_admin = config_switch (w2); // 0: no, 1: yes + } + else if (strcasecmp (w1, "display_parse_fromchar") == 0) + { + display_parse_fromchar = config_switch (w2); // 0: no, 1: yes (without packet 0x2714), 2: all packets + } + else if (strcasecmp (w1, "date_format") == 0) + { // note: never have more than 19 char for the date! + switch (atoi (w2)) + { + case 0: + strcpy (date_format, "%d-%m-%Y %H:%M:%S"); // 31-12-2004 23:59:59 + break; + case 1: + strcpy (date_format, "%m-%d-%Y %H:%M:%S"); // 12-31-2004 23:59:59 + break; + case 2: + strcpy (date_format, "%Y-%d-%m %H:%M:%S"); // 2004-31-12 23:59:59 + break; + case 3: + strcpy (date_format, "%Y-%m-%d %H:%M:%S"); // 2004-12-31 23:59:59 + break; + } + } + else if (strcasecmp (w1, "min_level_to_connect") == 0) + { + min_level_to_connect = atoi (w2); + } + else if (strcasecmp (w1, "add_to_unlimited_account") == 0) + { + add_to_unlimited_account = config_switch (w2); + } + else if (strcasecmp (w1, "start_limited_time") == 0) + { + start_limited_time = atoi (w2); + } + else if (strcasecmp (w1, "check_ip_flag") == 0) + { + check_ip_flag = config_switch (w2); + } + else if (strcasecmp (w1, "order") == 0) + { + access_order = atoi (w2); + if (strcasecmp (w2, "deny,allow") == 0 || + strcasecmp (w2, "deny, allow") == 0) + access_order = ACO_DENY_ALLOW; + if (strcasecmp (w2, "allow,deny") == 0 || + strcasecmp (w2, "allow, deny") == 0) + access_order = ACO_ALLOW_DENY; + if (strcasecmp (w2, "mutual-failture") == 0 || + strcasecmp (w2, "mutual-failure") == 0) + access_order = ACO_MUTUAL_FAILTURE; + } + else if (strcasecmp (w1, "allow") == 0) + { + if (strcasecmp (w2, "clear") == 0) + { + if (access_allow) + free (access_allow); + access_allow = NULL; + access_allownum = 0; + } + else + { + if (strcasecmp (w2, "all") == 0) + { + // reset all previous values + if (access_allow) + free (access_allow); + // set to all + CREATE (access_allow, char, ACO_STRSIZE); + access_allownum = 1; + } + else if (w2[0] + && !(access_allownum == 1 + && access_allow[0] == '\0')) + { // don't add IP if already 'all' + if (access_allow) + RECREATE (access_allow, char, (access_allownum + 1) * ACO_STRSIZE); + else + CREATE (access_allow, char, ACO_STRSIZE); + strncpy (access_allow + + (access_allownum++) * ACO_STRSIZE, w2, + ACO_STRSIZE); + access_allow[access_allownum * ACO_STRSIZE - 1] = + '\0'; + } + } + } + else if (strcasecmp (w1, "deny") == 0) + { + if (strcasecmp (w2, "clear") == 0) + { + if (access_deny) + free (access_deny); + access_deny = NULL; + access_denynum = 0; + } + else + { + if (strcasecmp (w2, "all") == 0) + { + // reset all previous values + if (access_deny) + free (access_deny); + // set to all + CREATE (access_deny, char, ACO_STRSIZE); + access_denynum = 1; + } + else if (w2[0] + && !(access_denynum == 1 + && access_deny[0] == '\0')) + { // don't add IP if already 'all' + if (access_deny) + RECREATE (access_deny, char, (access_denynum + 1) * ACO_STRSIZE); + else + CREATE (access_deny, char, ACO_STRSIZE); + strncpy (access_deny + + (access_denynum++) * ACO_STRSIZE, w2, + ACO_STRSIZE); + access_deny[access_denynum * ACO_STRSIZE - 1] = '\0'; + } + } + } + else if (strcasecmp (w1, "anti_freeze_enable") == 0) + { + anti_freeze_enable = config_switch (w2); + } + else if (strcasecmp (w1, "anti_freeze_interval") == 0) + { + ANTI_FREEZE_INTERVAL = atoi (w2); + if (ANTI_FREEZE_INTERVAL < 5) + ANTI_FREEZE_INTERVAL = 5; // minimum 5 seconds + } + else if (strcasecmp (w1, "import") == 0) + { + login_config_read (w2); + } + else if (strcasecmp (w1, "update_host") == 0) + { + strncpy (update_host, w2, sizeof (update_host)); + update_host[sizeof (update_host) - 1] = '\0'; + } + else if (strcasecmp (w1, "main_server") == 0) + { + strncpy (main_server, w2, sizeof (main_server)); + main_server[sizeof (main_server) - 1] = '\0'; + } + } + } + fclose_ (fp); + + printf ("---End reading of Login Server configuration file.\n"); + + return 0; +} + +//------------------------------------- +// Displaying of configuration warnings +//------------------------------------- +void display_conf_warnings (void) +{ + if (admin_state != 0 && admin_state != 1) + { + printf + ("***WARNING: Invalid value for admin_state parameter -> set to 0 (no remote admin).\n"); + admin_state = 0; + } + + if (admin_state == 1) + { + if (admin_pass[0] == '\0') + { + printf + ("***WARNING: Administrator password is void (admin_pass).\n"); + } + else if (strcmp (admin_pass, "admin") == 0) + { + printf + ("***WARNING: You are using the default administrator password (admin_pass).\n"); + printf (" We highly recommend that you change it.\n"); + } + } + + if (gm_pass[0] == '\0') + { + printf ("***WARNING: 'To GM become' password is void (gm_pass).\n"); + printf + (" We highly recommend that you set one password.\n"); + } + else if (strcmp (gm_pass, "gm") == 0) + { + printf + ("***WARNING: You are using the default GM password (gm_pass).\n"); + printf (" We highly recommend that you change it.\n"); + } + + if (level_new_gm < 0 || level_new_gm > 99) + { + printf + ("***WARNING: Invalid value for level_new_gm parameter -> set to 60 (default).\n"); + level_new_gm = 60; + } + + if (new_account_flag != 0 && new_account_flag != 1) + { + printf + ("***WARNING: Invalid value for new_account parameter -> set to 0 (no new account).\n"); + new_account_flag = 0; + } + + if (login_port < 1024 || login_port > 65535) + { + printf + ("***WARNING: Invalid value for login_port parameter -> set to 6900 (default).\n"); + login_port = 6900; + } + + if (gm_account_filename_check_timer < 0) + { + printf + ("***WARNING: Invalid value for gm_account_filename_check_timer parameter.\n"); + printf (" -> set to 15 sec (default).\n"); + gm_account_filename_check_timer = 15; + } + else if (gm_account_filename_check_timer == 1) + { + printf + ("***WARNING: Invalid value for gm_account_filename_check_timer parameter.\n"); + printf (" -> set to 2 sec (minimum value).\n"); + gm_account_filename_check_timer = 2; + } + + if (save_unknown_packets != 0 && save_unknown_packets != 1) + { + printf + ("WARNING: Invalid value for save_unknown_packets parameter -> set to 0-no save.\n"); + save_unknown_packets = 0; + } + + if (display_parse_login != 0 && display_parse_login != 1) + { // 0: no, 1: yes + printf + ("***WARNING: Invalid value for display_parse_login parameter\n"); + printf (" -> set to 0 (no display).\n"); + display_parse_login = 0; + } + + if (display_parse_admin != 0 && display_parse_admin != 1) + { // 0: no, 1: yes + printf + ("***WARNING: Invalid value for display_parse_admin parameter\n"); + printf (" -> set to 0 (no display).\n"); + display_parse_admin = 0; + } + + if (display_parse_fromchar < 0 || display_parse_fromchar > 2) + { // 0: no, 1: yes (without packet 0x2714), 2: all packets + printf + ("***WARNING: Invalid value for display_parse_fromchar parameter\n"); + printf (" -> set to 0 (no display).\n"); + display_parse_fromchar = 0; + } + + if (min_level_to_connect < 0) + { // 0: all players, 1-99 at least gm level x + printf + ("***WARNING: Invalid value for min_level_to_connect (%d) parameter\n", + min_level_to_connect); + printf (" -> set to 0 (any player).\n"); + min_level_to_connect = 0; + } + else if (min_level_to_connect > 99) + { // 0: all players, 1-99 at least gm level x + printf + ("***WARNING: Invalid value for min_level_to_connect (%d) parameter\n", + min_level_to_connect); + printf (" -> set to 99 (only GM level 99).\n"); + min_level_to_connect = 99; + } + + if (add_to_unlimited_account != 0 && add_to_unlimited_account != 1) + { // 0: no, 1: yes + printf + ("***WARNING: Invalid value for add_to_unlimited_account parameter\n"); + printf + (" -> set to 0 (impossible to add a time to an unlimited account).\n"); + add_to_unlimited_account = 0; + } + + if (start_limited_time < -1) + { // -1: create unlimited account, 0 or more: additionnal sec from now to create limited time + printf + ("***WARNING: Invalid value for start_limited_time parameter\n"); + printf + (" -> set to -1 (new accounts are created with unlimited time).\n"); + start_limited_time = -1; + } + + if (check_ip_flag != 0 && check_ip_flag != 1) + { // 0: no, 1: yes + printf ("***WARNING: Invalid value for check_ip_flag parameter\n"); + printf + (" -> set to 1 (check players ip between login-server & char-server).\n"); + check_ip_flag = 1; + } + + if (access_order == ACO_DENY_ALLOW) + { + if (access_denynum == 1 && access_deny[0] == '\0') + { + printf + ("***WARNING: The IP security order is 'deny,allow' (allow if not deny).\n"); + printf (" And you refuse ALL IP.\n"); + } + } + else if (access_order == ACO_ALLOW_DENY) + { + if (access_allownum == 0) + { + printf + ("***WARNING: The IP security order is 'allow,deny' (deny if not allow).\n"); + printf (" But, NO IP IS AUTHORISED!\n"); + } + } + else + { // ACO_MUTUAL_FAILTURE + if (access_allownum == 0) + { + printf + ("***WARNING: The IP security order is 'mutual-failture'\n"); + printf + (" (allow if in the allow list and not in the deny list).\n"); + printf (" But, NO IP IS AUTHORISED!\n"); + } + else if (access_denynum == 1 && access_deny[0] == '\0') + { + printf ("***WARNING: The IP security order is mutual-failture\n"); + printf + (" (allow if in the allow list and not in the deny list).\n"); + printf (" But, you refuse ALL IP!\n"); + } + } + + return; +} + +//------------------------------- +// Save configuration in log file +//------------------------------- +void save_config_in_log (void) +{ + int i; + + // a newline in the log... + login_log (""); + login_log ("The login-server starting...\n"); + + // save configuration in log file + login_log ("The configuration of the server is set:\n"); + + if (admin_state != 1) + login_log ("- with no remote administration.\n"); + else if (admin_pass[0] == '\0') + login_log ("- with a remote administration with a VOID password.\n"); + else if (strcmp (admin_pass, "admin") == 0) + login_log ("- with a remote administration with the DEFAULT password.\n"); + else + login_log + ("- with a remote administration with the password of %d character(s).\n", + strlen (admin_pass)); + if (access_ladmin_allownum == 0 + || (access_ladmin_allownum == 1 && access_ladmin_allow[0] == '\0')) + { + login_log ("- to accept any IP for remote administration\n"); + } + else + { + login_log ("- to accept following IP for remote administration:\n"); + for (i = 0; i < access_ladmin_allownum; i++) + login_log (" %s\n", + (char *) (access_ladmin_allow + i * ACO_STRSIZE)); + } + + if (gm_pass[0] == '\0') + login_log ("- with a VOID 'To GM become' password (gm_pass).\n"); + else if (strcmp (gm_pass, "gm") == 0) + login_log ("- with the DEFAULT 'To GM become' password (gm_pass).\n"); + else + login_log + ("- with a 'To GM become' password (gm_pass) of %d character(s).\n", + strlen (gm_pass)); + if (level_new_gm == 0) + login_log ("- to refuse any creation of GM with @gm.\n"); + else + login_log ("- to create GM with level '%d' when @gm is used.\n", + level_new_gm); + + if (new_account_flag == 1) + login_log ("- to ALLOW new users (with _F/_M).\n"); + else + login_log ("- to NOT ALLOW new users (with _F/_M).\n"); + login_log ("- with port: %d.\n", login_port); + login_log ("- with the accounts file name: '%s'.\n", + account_filename); + login_log ("- with the GM accounts file name: '%s'.\n", + GM_account_filename); + if (gm_account_filename_check_timer == 0) + login_log ("- to NOT check GM accounts file modifications.\n"); + else + login_log + ("- to check GM accounts file modifications every %d seconds.\n", + gm_account_filename_check_timer); + + // not necessary to log the 'login_log_filename', we are inside :) + + login_log ("- with the unknown packets file name: '%s'.\n", + login_log_unknown_packets_filename); + if (save_unknown_packets) + login_log ("- to SAVE all unkown packets.\n"); + else + login_log + ("- to SAVE only unkown packets sending by a char-server or a remote administration.\n"); + if (display_parse_login) + login_log ("- to display normal parse packets on console.\n"); + else + login_log ("- to NOT display normal parse packets on console.\n"); + if (display_parse_admin) + login_log ("- to display administration parse packets on console.\n"); + else + login_log ("- to NOT display administration parse packets on console.\n"); + if (display_parse_fromchar) + login_log ("- to display char-server parse packets on console.\n"); + else + login_log ("- to NOT display char-server parse packets on console.\n"); + + if (min_level_to_connect == 0) // 0: all players, 1-99 at least gm level x + login_log ("- with no minimum level for connection.\n"); + else if (min_level_to_connect == 99) + login_log ("- to accept only GM with level 99.\n"); + else + login_log ("- to accept only GM with level %d or more.\n", + min_level_to_connect); + + if (add_to_unlimited_account) + login_log + ("- to authorize adjustment (with timeadd ladmin) on an unlimited account.\n"); + else + login_log + ("- to refuse adjustment (with timeadd ladmin) on an unlimited account. You must use timeset (ladmin command) before.\n"); + + if (start_limited_time < 0) + login_log ("- to create new accounts with an unlimited time.\n"); + else if (start_limited_time == 0) + login_log + ("- to create new accounts with a limited time: time of creation.\n"); + else + login_log + ("- to create new accounts with a limited time: time of creation + %d second(s).\n", + start_limited_time); + + if (check_ip_flag) + login_log + ("- with control of players IP between login-server and char-server.\n"); + else + login_log + ("- to not check players IP between login-server and char-server.\n"); + + if (access_order == ACO_DENY_ALLOW) + { + if (access_denynum == 0) + { + login_log + ("- with the IP security order: 'deny,allow' (allow if not deny). You refuse no IP.\n"); + } + else if (access_denynum == 1 && access_deny[0] == '\0') + { + login_log + ("- with the IP security order: 'deny,allow' (allow if not deny). You refuse ALL IP.\n"); + } + else + { + login_log + ("- with the IP security order: 'deny,allow' (allow if not deny). Refused IP are:\n"); + for (i = 0; i < access_denynum; i++) + login_log (" %s\n", + (char *) (access_deny + i * ACO_STRSIZE)); + } + } + else if (access_order == ACO_ALLOW_DENY) + { + if (access_allownum == 0) + { + login_log + ("- with the IP security order: 'allow,deny' (deny if not allow). But, NO IP IS AUTHORISED!\n"); + } + else if (access_allownum == 1 && access_allow[0] == '\0') + { + login_log + ("- with the IP security order: 'allow,deny' (deny if not allow). You authorise ALL IP.\n"); + } + else + { + login_log + ("- with the IP security order: 'allow,deny' (deny if not allow). Authorised IP are:\n"); + for (i = 0; i < access_allownum; i++) + login_log (" %s\n", + (char *) (access_allow + i * ACO_STRSIZE)); + } + } + else + { // ACO_MUTUAL_FAILTURE + login_log + ("- with the IP security order: 'mutual-failture' (allow if in the allow list and not in the deny list).\n"); + if (access_allownum == 0) + { + login_log (" But, NO IP IS AUTHORISED!\n"); + } + else if (access_denynum == 1 && access_deny[0] == '\0') + { + login_log (" But, you refuse ALL IP!\n"); + } + else + { + if (access_allownum == 1 && access_allow[0] == '\0') + { + login_log (" You authorise ALL IP.\n"); + } + else + { + login_log (" Authorised IP are:\n"); + for (i = 0; i < access_allownum; i++) + login_log (" %s\n", + (char *) (access_allow + i * ACO_STRSIZE)); + } + login_log (" Refused IP are:\n"); + for (i = 0; i < access_denynum; i++) + login_log (" %s\n", + (char *) (access_deny + i * ACO_STRSIZE)); + } + } +} + +//-------------------------------------- +// Function called at exit of the server +//-------------------------------------- +void term_func (void) +{ + int i, fd; + + mmo_auth_sync (); + + free (auth_dat); + free (gm_account_db); + for (i = 0; i < MAX_SERVERS; i++) + { + if ((fd = server_fd[i]) >= 0) + delete_session (fd); + } + delete_session (login_fd); + + login_log + ("----End of login-server (normal end with closing of all files).\n"); +} + +//------------------------------ +// Main function of login-server +//------------------------------ +int do_init (int argc, char **argv) +{ + int i, j; + + // read login-server configuration + login_config_read ((argc > 1) ? argv[1] : LOGIN_CONF_NAME); + display_conf_warnings (); // not in login_config_read, because we can use 'import' option, and display same message twice or more + save_config_in_log (); // not before, because log file name can be changed + login_lan_config_read ((argc > 1) ? argv[1] : LAN_CONF_NAME); + + for (i = 0; i < AUTH_FIFO_SIZE; i++) + auth_fifo[i].delflag = 1; + for (i = 0; i < MAX_SERVERS; i++) + server_fd[i] = -1; + + gm_account_db = numdb_init (); + + read_gm_account (); + mmo_auth_init (); +// set_termfunc (mmo_auth_sync); + set_defaultparse (parse_login); + login_fd = make_listen_port (login_port); + +// add_timer_func_list (check_auth_sync, "check_auth_sync"); + + // Trigger auth sync every 5 minutes + i = add_timer_interval (gettick () + 300000, check_auth_sync, 0, 0, 300000); + + if (anti_freeze_enable > 0) + { +// add_timer_func_list (char_anti_freeze_system, "char_anti_freeze_system"); + i = add_timer_interval (gettick () + 1000, char_anti_freeze_system, 0, + 0, ANTI_FREEZE_INTERVAL * 1000); + } + + // add timer to check GM accounts file modification + j = gm_account_filename_check_timer; + if (j == 0) // if we would not to check, we check every 60 sec, just to have timer (if we change timer, is was not necessary to check if timer already exists) + j = 60; +// add_timer_func_list (check_GM_file, "check_GM_file"); + i = add_timer_interval (gettick () + j * 1000, check_GM_file, 0, 0, j * 1000); // every x sec we check if gm file has been changed + + login_log + ("The login-server is ready (Server is listening on the port %d).\n", + login_port); + + printf + ("The login-server is \033[1;32mready\033[0m (Server is listening on the port %d).\n\n", + login_port); + + return 0; +} diff --git a/src/login/login.h b/src/login/login.h deleted file mode 100644 index a1f8fef..0000000 --- a/src/login/login.h +++ /dev/null @@ -1,41 +0,0 @@ -// $Id: login.h,v 1.1.1.1 2004/09/10 17:26:53 MagicalTux Exp $ -#ifndef _LOGIN_H_ -#define _LOGIN_H_ - -#define MAX_SERVERS 30 - -#define LOGIN_CONF_NAME "conf/login_athena.conf" -#define LAN_CONF_NAME "conf/lan_support.conf" -// It seems we don't need to emulate RO's "password encryption" - MC/TMW -//#define PASSWORDENC 3 // A definition is given when making an encryption password correspond. - // It is 1 at the time of passwordencrypt. - // It is made into 2 at the time of passwordencrypt2. - // When it is made 3, it corresponds to both. -#define START_ACCOUNT_NUM 2000000 -#define END_ACCOUNT_NUM 100000000 - -struct mmo_account -{ - char *userid; - char *passwd; - int passwdenc; - - long account_id; - long login_id1; - long login_id2; - long char_id; - char lastlogin[24]; - int sex; -}; - -struct mmo_char_server -{ - char name[20]; - long ip; - short port; - int users; - int maintenance; - int is_new; -}; - -#endif diff --git a/src/login/login.hpp b/src/login/login.hpp new file mode 100644 index 0000000..49d1c12 --- /dev/null +++ b/src/login/login.hpp @@ -0,0 +1,41 @@ +// $Id: login.h,v 1.1.1.1 2004/09/10 17:26:53 MagicalTux Exp $ +#ifndef LOGIN_HPP +#define LOGIN_HPP + +#define MAX_SERVERS 30 + +#define LOGIN_CONF_NAME "conf/login_athena.conf" +#define LAN_CONF_NAME "conf/lan_support.conf" +// It seems we don't need to emulate RO's "password encryption" - MC/TMW +//#define PASSWORDENC 3 // A definition is given when making an encryption password correspond. + // It is 1 at the time of passwordencrypt. + // It is made into 2 at the time of passwordencrypt2. + // When it is made 3, it corresponds to both. +#define START_ACCOUNT_NUM 2000000 +#define END_ACCOUNT_NUM 100000000 + +struct mmo_account +{ + char *userid; + char *passwd; + int passwdenc; + + long account_id; + long login_id1; + long login_id2; + long char_id; + char lastlogin[24]; + int sex; +}; + +struct mmo_char_server +{ + char name[20]; + long ip; + short port; + int users; + int maintenance; + int is_new; +}; + +#endif diff --git a/src/map/atcommand.c b/src/map/atcommand.c deleted file mode 100644 index 88e756d..0000000 --- a/src/map/atcommand.c +++ /dev/null @@ -1,8728 +0,0 @@ -// $Id: atcommand.c 148 2004-09-30 14:05:37Z MouseJstr $ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../common/socket.h" -#include "../common/timer.h" -#include "../common/nullpo.h" -#include "../common/mt_rand.h" - -#include "atcommand.h" -#include "battle.h" -#include "clif.h" -#include "chrif.h" -#include "guild.h" -#include "intif.h" -#include "itemdb.h" -#include "map.h" -#include "mob.h" -#include "npc.h" -#include "pc.h" -#include "party.h" -#include "script.h" -#include "skill.h" -#include "trade.h" - -#include "../common/core.h" -#include "tmw.h" - -#define STATE_BLIND 0x10 - -static char command_symbol = '@'; // first char of the commands (by [Yor]) - -static char msg_table[1000][1024]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others) - -#define ATCOMMAND_FUNC(x) int atcommand_ ## x (const int fd, struct map_session_data* sd, const char* command, const char* message) -ATCOMMAND_FUNC (setup); -ATCOMMAND_FUNC (broadcast); -ATCOMMAND_FUNC (localbroadcast); -ATCOMMAND_FUNC (charwarp); -ATCOMMAND_FUNC (warp); -ATCOMMAND_FUNC (where); -ATCOMMAND_FUNC (goto); -ATCOMMAND_FUNC (jump); -ATCOMMAND_FUNC (who); -ATCOMMAND_FUNC (whogroup); -ATCOMMAND_FUNC (whomap); -ATCOMMAND_FUNC (whomapgroup); -ATCOMMAND_FUNC (whogm); // by Yor -ATCOMMAND_FUNC (save); -ATCOMMAND_FUNC (load); -ATCOMMAND_FUNC (speed); -ATCOMMAND_FUNC (storage); -ATCOMMAND_FUNC (guildstorage); -ATCOMMAND_FUNC (option); -ATCOMMAND_FUNC (hide); -ATCOMMAND_FUNC (die); -ATCOMMAND_FUNC (kill); -ATCOMMAND_FUNC (alive); -ATCOMMAND_FUNC (kami); -ATCOMMAND_FUNC (heal); -ATCOMMAND_FUNC (item); -ATCOMMAND_FUNC (itemreset); -ATCOMMAND_FUNC (itemcheck); -ATCOMMAND_FUNC (baselevelup); -ATCOMMAND_FUNC (joblevelup); -ATCOMMAND_FUNC (help); -ATCOMMAND_FUNC (gm); -ATCOMMAND_FUNC (pvpoff); -ATCOMMAND_FUNC (pvpon); -ATCOMMAND_FUNC (gvgoff); -ATCOMMAND_FUNC (gvgon); -ATCOMMAND_FUNC (model); -ATCOMMAND_FUNC (go); -ATCOMMAND_FUNC (spawn); -ATCOMMAND_FUNC (killmonster); -ATCOMMAND_FUNC (killmonster2); -ATCOMMAND_FUNC (refine); -ATCOMMAND_FUNC (produce); -ATCOMMAND_FUNC (memo); -ATCOMMAND_FUNC (gat); -ATCOMMAND_FUNC (packet); -ATCOMMAND_FUNC (statuspoint); -ATCOMMAND_FUNC (skillpoint); -ATCOMMAND_FUNC (zeny); -ATCOMMAND_FUNC (param); -ATCOMMAND_FUNC (guildlevelup); -ATCOMMAND_FUNC (recall); -ATCOMMAND_FUNC (recallall); -ATCOMMAND_FUNC (revive); -ATCOMMAND_FUNC (character_stats); -ATCOMMAND_FUNC (character_stats_all); -ATCOMMAND_FUNC (character_option); -ATCOMMAND_FUNC (character_save); -ATCOMMAND_FUNC (night); -ATCOMMAND_FUNC (day); -ATCOMMAND_FUNC (doom); -ATCOMMAND_FUNC (doommap); -ATCOMMAND_FUNC (raise); -ATCOMMAND_FUNC (raisemap); -ATCOMMAND_FUNC (character_baselevel); -ATCOMMAND_FUNC (character_joblevel); -ATCOMMAND_FUNC (kick); -ATCOMMAND_FUNC (kickall); -ATCOMMAND_FUNC (allskills); -ATCOMMAND_FUNC (questskill); -ATCOMMAND_FUNC (charquestskill); -ATCOMMAND_FUNC (lostskill); -ATCOMMAND_FUNC (charlostskill); -ATCOMMAND_FUNC (party); -ATCOMMAND_FUNC (guild); -ATCOMMAND_FUNC (charskreset); -ATCOMMAND_FUNC (charstreset); -ATCOMMAND_FUNC (charreset); -ATCOMMAND_FUNC (charstpoint); -ATCOMMAND_FUNC (charmodel); -ATCOMMAND_FUNC (charskpoint); -ATCOMMAND_FUNC (charzeny); -ATCOMMAND_FUNC (agitstart); -ATCOMMAND_FUNC (agitend); -ATCOMMAND_FUNC (reloaditemdb); -ATCOMMAND_FUNC (reloadmobdb); -ATCOMMAND_FUNC (reloadskilldb); -ATCOMMAND_FUNC (reloadscript); -ATCOMMAND_FUNC (reloadgmdb); // by Yor -ATCOMMAND_FUNC (mapexit); -ATCOMMAND_FUNC (idsearch); -ATCOMMAND_FUNC (mapinfo); -ATCOMMAND_FUNC (dye); //** by fritz -ATCOMMAND_FUNC (hair_style); //** by fritz -ATCOMMAND_FUNC (hair_color); //** by fritz -ATCOMMAND_FUNC (all_stats); //** by fritz -ATCOMMAND_FUNC (char_change_sex); // by Yor -ATCOMMAND_FUNC (char_block); // by Yor -ATCOMMAND_FUNC (char_ban); // by Yor -ATCOMMAND_FUNC (char_unblock); // by Yor -ATCOMMAND_FUNC (char_unban); // by Yor -ATCOMMAND_FUNC (mount_peco); // by Valaris -ATCOMMAND_FUNC (char_mount_peco); // by Yor -ATCOMMAND_FUNC (guildspy); // [Syrus22] -ATCOMMAND_FUNC (partyspy); // [Syrus22] -ATCOMMAND_FUNC (guildrecall); // by Yor -ATCOMMAND_FUNC (partyrecall); // by Yor -ATCOMMAND_FUNC (enablenpc); -ATCOMMAND_FUNC (disablenpc); -ATCOMMAND_FUNC (servertime); // by Yor -ATCOMMAND_FUNC (chardelitem); // by Yor -ATCOMMAND_FUNC (jail); // by Yor -ATCOMMAND_FUNC (unjail); // by Yor -ATCOMMAND_FUNC (disguise); // [Valaris] -ATCOMMAND_FUNC (undisguise); // by Yor -ATCOMMAND_FUNC (ignorelist); // by Yor -ATCOMMAND_FUNC (charignorelist); // by Yor -ATCOMMAND_FUNC (inall); // by Yor -ATCOMMAND_FUNC (exall); // by Yor -ATCOMMAND_FUNC (chardisguise); // Kalaspuff -ATCOMMAND_FUNC (charundisguise); // Kalaspuff -ATCOMMAND_FUNC (email); // by Yor -ATCOMMAND_FUNC (effect); //by Apple -ATCOMMAND_FUNC (character_item_list); // by Yor -ATCOMMAND_FUNC (character_storage_list); // by Yor -ATCOMMAND_FUNC (character_cart_list); // by Yor -ATCOMMAND_FUNC (addwarp); // by MouseJstr -ATCOMMAND_FUNC (follow); // by MouseJstr -ATCOMMAND_FUNC (skillon); // by MouseJstr -ATCOMMAND_FUNC (skilloff); // by MouseJstr -ATCOMMAND_FUNC (killer); // by MouseJstr -ATCOMMAND_FUNC (npcmove); // by MouseJstr -ATCOMMAND_FUNC (killable); // by MouseJstr -ATCOMMAND_FUNC (charkillable); // by MouseJstr -ATCOMMAND_FUNC (chareffect); // by MouseJstr -ATCOMMAND_FUNC (chardye); // by MouseJstr -ATCOMMAND_FUNC (charhairstyle); // by MouseJstr -ATCOMMAND_FUNC (charhaircolor); // by MouseJstr -ATCOMMAND_FUNC (dropall); // by MouseJstr -ATCOMMAND_FUNC (chardropall); // by MouseJstr -ATCOMMAND_FUNC (storeall); // by MouseJstr -ATCOMMAND_FUNC (charstoreall); // by MouseJstr -ATCOMMAND_FUNC (skillid); // by MouseJstr -ATCOMMAND_FUNC (useskill); // by MouseJstr -ATCOMMAND_FUNC (summon); -ATCOMMAND_FUNC (rain); -ATCOMMAND_FUNC (snow); -ATCOMMAND_FUNC (sakura); -ATCOMMAND_FUNC (fog); -ATCOMMAND_FUNC (leaves); -ATCOMMAND_FUNC (adjgmlvl); // by MouseJstr -ATCOMMAND_FUNC (adjcmdlvl); // by MouseJstr -ATCOMMAND_FUNC (trade); // by MouseJstr -ATCOMMAND_FUNC (unmute); // [Valaris] -ATCOMMAND_FUNC (char_wipe); // [Fate] -ATCOMMAND_FUNC (set_magic); // [Fate] -ATCOMMAND_FUNC (magic_info); // [Fate] -ATCOMMAND_FUNC (log); // [Fate] -ATCOMMAND_FUNC (tee); // [Fate] -ATCOMMAND_FUNC (invisible); // [Fate] -ATCOMMAND_FUNC (visible); // [Fate] -ATCOMMAND_FUNC (list_nearby); // [Fate] -ATCOMMAND_FUNC (iterate_forward_over_players); // [Fate] -ATCOMMAND_FUNC (iterate_backwards_over_players); // [Fate] -ATCOMMAND_FUNC (skillpool_info); // [Fate] -ATCOMMAND_FUNC (skillpool_focus); // [Fate] -ATCOMMAND_FUNC (skillpool_unfocus); // [Fate] -ATCOMMAND_FUNC (skill_learn); // [Fate] -ATCOMMAND_FUNC (wgm); -ATCOMMAND_FUNC (ipcheck); -ATCOMMAND_FUNC (doomspot); - -/*========================================== - *AtCommandInfo atcommand_info[]構造体の定義 - *------------------------------------------ - */ - -// First char of commands is configured in atcommand_athena.conf. Leave @ in this list for default value. -// to set default level, read atcommand_athena.conf first please. -static AtCommandInfo atcommand_info[] = { - {AtCommand_Setup, "@setup", 40, atcommand_setup}, - {AtCommand_CharWarp, "@charwarp", 60, atcommand_charwarp}, - {AtCommand_Warp, "@warp", 40, atcommand_warp}, - {AtCommand_Where, "@where", 1, atcommand_where}, - {AtCommand_Goto, "@goto", 20, atcommand_goto}, - {AtCommand_Jump, "@jump", 40, atcommand_jump}, - {AtCommand_Who, "@who", 20, atcommand_who}, - {AtCommand_WhoGroup, "@whogroup", 20, atcommand_whogroup}, - {AtCommand_WhoMap, "@whomap", 20, atcommand_whomap}, - {AtCommand_WhoMapGroup, "@whomapgroup", 20, atcommand_whomapgroup}, - {AtCommand_WhoGM, "@whogm", 20, atcommand_whogm}, // by Yor - {AtCommand_Save, "@save", 40, atcommand_save}, - {AtCommand_Load, "@return", 40, atcommand_load}, - {AtCommand_Load, "@load", 40, atcommand_load}, - {AtCommand_Speed, "@speed", 40, atcommand_speed}, - {AtCommand_Storage, "@storage", 1, atcommand_storage}, - {AtCommand_GuildStorage, "@gstorage", 50, atcommand_guildstorage}, - {AtCommand_Option, "@option", 40, atcommand_option}, - {AtCommand_Hide, "@hide", 40, atcommand_hide}, // + /hide - {AtCommand_Die, "@die", 1, atcommand_die}, - {AtCommand_Kill, "@kill", 60, atcommand_kill}, - {AtCommand_Alive, "@alive", 60, atcommand_alive}, - {AtCommand_Kami, "@kami", 40, atcommand_kami}, - {AtCommand_Heal, "@heal", 40, atcommand_heal}, - {AtCommand_Item, "@item", 60, atcommand_item}, - {AtCommand_ItemReset, "@itemreset", 40, atcommand_itemreset}, - {AtCommand_ItemCheck, "@itemcheck", 60, atcommand_itemcheck}, - {AtCommand_BaseLevelUp, "@blvl", 60, atcommand_baselevelup}, - {AtCommand_JobLevelUp, "@jlvl", 60, atcommand_joblevelup}, - {AtCommand_Help, "@help", 20, atcommand_help}, - {AtCommand_GM, "@gm", 100, atcommand_gm}, - {AtCommand_PvPOff, "@pvpoff", 40, atcommand_pvpoff}, - {AtCommand_PvPOn, "@pvpon", 40, atcommand_pvpon}, - {AtCommand_GvGOff, "@gvgoff", 40, atcommand_gvgoff}, - {AtCommand_GvGOff, "@gpvpoff", 40, atcommand_gvgoff}, - {AtCommand_GvGOn, "@gvgon", 40, atcommand_gvgon}, - {AtCommand_GvGOn, "@gpvpon", 40, atcommand_gvgon}, - {AtCommand_Model, "@model", 20, atcommand_model}, - {AtCommand_Go, "@go", 10, atcommand_go}, - {AtCommand_Spawn, "@spawn", 50, atcommand_spawn}, - {AtCommand_KillMonster, "@killmonster", 60, atcommand_killmonster}, - {AtCommand_KillMonster2, "@killmonster2", 40, atcommand_killmonster2}, - {AtCommand_Produce, "@produce", 60, atcommand_produce}, - {AtCommand_Memo, "@memo", 40, atcommand_memo}, - {AtCommand_GAT, "@gat", 99, atcommand_gat}, // debug function - {AtCommand_Packet, "@packet", 99, atcommand_packet}, // debug function - {AtCommand_StatusPoint, "@stpoint", 60, atcommand_statuspoint}, - {AtCommand_SkillPoint, "@skpoint", 60, atcommand_skillpoint}, - {AtCommand_Zeny, "@zeny", 60, atcommand_zeny}, - {AtCommand_Strength, "@str", 60, atcommand_param}, - {AtCommand_Agility, "@agi", 60, atcommand_param}, - {AtCommand_Vitality, "@vit", 60, atcommand_param}, - {AtCommand_Intelligence, "@int", 60, atcommand_param}, - {AtCommand_Dexterity, "@dex", 60, atcommand_param}, - {AtCommand_Luck, "@luk", 60, atcommand_param}, - {AtCommand_GuildLevelUp, "@guildlvl", 60, atcommand_guildlevelup}, - {AtCommand_Recall, "@recall", 60, atcommand_recall}, // + /recall - {AtCommand_Revive, "@revive", 60, atcommand_revive}, - {AtCommand_CharacterStats, "@charstats", 40, atcommand_character_stats}, - {AtCommand_CharacterStatsAll, "@charstatsall", 40, - atcommand_character_stats_all}, - {AtCommand_CharacterOption, "@charoption", 60, - atcommand_character_option}, - {AtCommand_CharacterSave, "@charsave", 60, atcommand_character_save}, - {AtCommand_Night, "@night", 80, atcommand_night}, - {AtCommand_Day, "@day", 80, atcommand_day}, - {AtCommand_Doom, "@doom", 80, atcommand_doom}, - {AtCommand_DoomMap, "@doommap", 80, atcommand_doommap}, - {AtCommand_Raise, "@raise", 80, atcommand_raise}, - {AtCommand_RaiseMap, "@raisemap", 80, atcommand_raisemap}, - {AtCommand_CharacterBaseLevel, "@charbaselvl", 60, - atcommand_character_baselevel}, - {AtCommand_CharacterJobLevel, "@charjlvl", 60, - atcommand_character_joblevel}, - {AtCommand_Kick, "@kick", 20, atcommand_kick}, // + right click menu for GM "(name) force to quit" - {AtCommand_KickAll, "@kickall", 99, atcommand_kickall}, - {AtCommand_AllSkills, "@allskills", 60, atcommand_allskills}, - {AtCommand_QuestSkill, "@questskill", 40, atcommand_questskill}, - {AtCommand_CharQuestSkill, "@charquestskill", 60, - atcommand_charquestskill}, - {AtCommand_LostSkill, "@lostskill", 40, atcommand_lostskill}, - {AtCommand_CharLostSkill, "@charlostskill", 60, atcommand_charlostskill}, - {AtCommand_Party, "@party", 1, atcommand_party}, - {AtCommand_Guild, "@guild", 50, atcommand_guild}, - {AtCommand_AgitStart, "@agitstart", 60, atcommand_agitstart}, - {AtCommand_AgitEnd, "@agitend", 60, atcommand_agitend}, - {AtCommand_MapExit, "@mapexit", 99, atcommand_mapexit}, - {AtCommand_IDSearch, "@idsearch", 60, atcommand_idsearch}, - {AtCommand_MapMove, "@mapmove", 40, atcommand_warp}, // /mm command - {AtCommand_Broadcast, "@broadcast", 40, atcommand_broadcast}, // /b and /nb command - {AtCommand_LocalBroadcast, "@localbroadcast", 40, atcommand_localbroadcast}, // /lb and /nlb command - {AtCommand_RecallAll, "@recallall", 80, atcommand_recallall}, - {AtCommand_CharSkReset, "@charskreset", 60, atcommand_charskreset}, - {AtCommand_CharStReset, "@charstreset", 60, atcommand_charstreset}, - {AtCommand_ReloadItemDB, "@reloaditemdb", 99, atcommand_reloaditemdb}, // admin command - {AtCommand_ReloadMobDB, "@reloadmobdb", 99, atcommand_reloadmobdb}, // admin command - {AtCommand_ReloadSkillDB, "@reloadskilldb", 99, atcommand_reloadskilldb}, // admin command - {AtCommand_ReloadScript, "@reloadscript", 99, atcommand_reloadscript}, // admin command - {AtCommand_ReloadGMDB, "@reloadgmdb", 99, atcommand_reloadgmdb}, // admin command - {AtCommand_CharReset, "@charreset", 60, atcommand_charreset}, - {AtCommand_CharModel, "@charmodel", 50, atcommand_charmodel}, - {AtCommand_CharSKPoint, "@charskpoint", 60, atcommand_charskpoint}, - {AtCommand_CharSTPoint, "@charstpoint", 60, atcommand_charstpoint}, - {AtCommand_CharZeny, "@charzeny", 60, atcommand_charzeny}, - {AtCommand_MapInfo, "@mapinfo", 99, atcommand_mapinfo}, - {AtCommand_Dye, "@dye", 40, atcommand_dye}, // by fritz - {AtCommand_Dye, "@ccolor", 40, atcommand_dye}, // by fritz - {AtCommand_HairStyle, "@hairstyle", 40, atcommand_hair_style}, // by fritz - {AtCommand_HairColor, "@haircolor", 40, atcommand_hair_color}, // by fritz - {AtCommand_AllStats, "@allstats", 60, atcommand_all_stats}, // by fritz - {AtCommand_CharChangeSex, "@charchangesex", 60, atcommand_char_change_sex}, // by Yor - {AtCommand_CharBlock, "@block", 60, atcommand_char_block}, // by Yor - {AtCommand_CharUnBlock, "@unblock", 60, atcommand_char_unblock}, // by Yor - {AtCommand_CharBan, "@ban", 60, atcommand_char_ban}, // by Yor - {AtCommand_CharUnBan, "@unban", 60, atcommand_char_unban}, // by Yor - {AtCommand_MountPeco, "@mountpeco", 20, atcommand_mount_peco}, // by Valaris - {AtCommand_CharMountPeco, "@charmountpeco", 50, atcommand_char_mount_peco}, // by Yor - {AtCommand_GuildSpy, "@guildspy", 60, atcommand_guildspy}, // [Syrus22] - {AtCommand_PartySpy, "@partyspy", 60, atcommand_partyspy}, // [Syrus22] - {AtCommand_GuildRecall, "@guildrecall", 60, atcommand_guildrecall}, // by Yor - {AtCommand_PartyRecall, "@partyrecall", 60, atcommand_partyrecall}, // by Yor - {AtCommand_Enablenpc, "@enablenpc", 80, atcommand_enablenpc}, // [] - {AtCommand_Disablenpc, "@disablenpc", 80, atcommand_disablenpc}, // [] - {AtCommand_ServerTime, "@servertime", 0, atcommand_servertime}, // by Yor - {AtCommand_CharDelItem, "@chardelitem", 60, atcommand_chardelitem}, // by Yor - {AtCommand_ListNearby, "@listnearby", 40, atcommand_list_nearby}, // by Yor - {AtCommand_Jail, "@jail", 60, atcommand_jail}, // by Yor - {AtCommand_UnJail, "@unjail", 60, atcommand_unjail}, // by Yor - {AtCommand_Disguise, "@disguise", 20, atcommand_disguise}, // [Valaris] - {AtCommand_UnDisguise, "@undisguise", 20, atcommand_undisguise}, // by Yor - {AtCommand_IgnoreList, "@ignorelist", 0, atcommand_ignorelist}, // by Yor - {AtCommand_CharIgnoreList, "@charignorelist", 20, atcommand_charignorelist}, // by Yor - {AtCommand_IgnoreList, "@inall", 20, atcommand_inall}, // by Yor - {AtCommand_ExAll, "@exall", 20, atcommand_exall}, // by Yor - {AtCommand_CharDisguise, "@chardisguise", 60, atcommand_chardisguise}, // Kalaspuff - {AtCommand_CharUnDisguise, "@charundisguise", 60, atcommand_charundisguise}, // Kalaspuff - {AtCommand_EMail, "@email", 0, atcommand_email}, // by Yor - {AtCommand_Effect, "@effect", 40, atcommand_effect}, // by Apple - {AtCommand_Char_Item_List, "@charitemlist", 40, atcommand_character_item_list}, // by Yor - {AtCommand_Char_Storage_List, "@charstoragelist", 40, atcommand_character_storage_list}, // by Yor - {AtCommand_Char_Cart_List, "@charcartlist", 40, atcommand_character_cart_list}, // by Yor - {AtCommand_Follow, "@follow", 10, atcommand_follow}, // by MouseJstr - {AtCommand_AddWarp, "@addwarp", 20, atcommand_addwarp}, // by MouseJstr - {AtCommand_SkillOn, "@skillon", 20, atcommand_skillon}, // by MouseJstr - {AtCommand_SkillOff, "@skilloff", 20, atcommand_skilloff}, // by MouseJstr - {AtCommand_Killer, "@killer", 60, atcommand_killer}, // by MouseJstr - {AtCommand_NpcMove, "@npcmove", 20, atcommand_npcmove}, // by MouseJstr - {AtCommand_Killable, "@killable", 40, atcommand_killable}, // by MouseJstr - {AtCommand_CharKillable, "@charkillable", 40, atcommand_charkillable}, // by MouseJstr - {AtCommand_Chareffect, "@chareffect", 40, atcommand_chareffect}, // MouseJstr - //{ AtCommand_Chardye, "@chardye", 40, atcommand_chardye }, // MouseJstr - //{ AtCommand_Charhairstyle, "@charhairstyle", 40, atcommand_charhairstyle }, // MouseJstr - //{ AtCommand_Charhaircolor, "@charhaircolor", 40, atcommand_charhaircolor }, // MouseJstr - {AtCommand_Dropall, "@dropall", 40, atcommand_dropall}, // MouseJstr - {AtCommand_Chardropall, "@chardropall", 40, atcommand_chardropall}, // MouseJstr - {AtCommand_Storeall, "@storeall", 40, atcommand_storeall}, // MouseJstr - {AtCommand_Charstoreall, "@charstoreall", 40, atcommand_charstoreall}, // MouseJstr - {AtCommand_Skillid, "@skillid", 40, atcommand_skillid}, // MouseJstr - {AtCommand_Useskill, "@useskill", 40, atcommand_useskill}, // MouseJstr - {AtCommand_Rain, "@rain", 99, atcommand_rain}, - {AtCommand_Snow, "@snow", 99, atcommand_snow}, - {AtCommand_Sakura, "@sakura", 99, atcommand_sakura}, - {AtCommand_Fog, "@fog", 99, atcommand_fog}, - {AtCommand_Leaves, "@leaves", 99, atcommand_leaves}, - //{ AtCommand_Shuffle, "@shuffle", 99, atcommand_shuffle }, - //{ AtCommand_Maintenance, "@maintenance", 99, atcommand_maintenance }, - //{ AtCommand_Misceffect, "@misceffect", 60, atcommand_misceffect }, - {AtCommand_Summon, "@summon", 60, atcommand_summon}, - {AtCommand_AdjGmLvl, "@adjgmlvl", 99, atcommand_adjgmlvl}, - {AtCommand_AdjCmdLvl, "@adjcmdlvl", 99, atcommand_adjcmdlvl}, - {AtCommand_Trade, "@trade", 60, atcommand_trade}, - {AtCommand_UnMute, "@unmute", 60, atcommand_unmute}, // [Valaris] - {AtCommand_UnMute, "@charwipe", 60, atcommand_char_wipe}, // [Fate] - {AtCommand_SetMagic, "@setmagic", 99, atcommand_set_magic}, // [Fate] - {AtCommand_MagicInfo, "@magicinfo", 60, atcommand_magic_info}, // [Fate] - {AtCommand_Log, "@log", 60, atcommand_log}, // [Fate] - {AtCommand_Log, "@l", 60, atcommand_log}, // [Fate] - {AtCommand_Tee, "@tee", 60, atcommand_tee}, // [Fate] - {AtCommand_Tee, "@t", 60, atcommand_tee}, // [Fate] - {AtCommand_Invisible, "@invisible", 60, atcommand_invisible}, // [Fate] - {AtCommand_Visible, "@visible", 60, atcommand_visible}, // [Fate] - {AtCommand_IterateForward, "@hugo", 60, atcommand_iterate_forward_over_players}, // [Fate] - {AtCommand_IterateBackward, "@linus", 60, atcommand_iterate_backwards_over_players}, // [Fate] - {AtCommand_IterateBackward, "@sp-info", 40, atcommand_skillpool_info}, // [Fate] - {AtCommand_IterateBackward, "@sp-focus", 80, atcommand_skillpool_focus}, // [Fate] - {AtCommand_IterateBackward, "@sp-unfocus", 80, atcommand_skillpool_unfocus}, // [Fate] - {AtCommand_IterateBackward, "@skill-learn", 80, atcommand_skill_learn}, // [Fate] - {AtCommand_Wgm, "@wgm", 0, atcommand_wgm}, - {AtCommand_IpCheck, "@ipcheck", 60, atcommand_ipcheck}, - {AtCommand_DoomSpot, "@doomspot", 60, atcommand_doomspot}, - -// add new commands before this line - {AtCommand_Unknown, NULL, 1, NULL} -}; - -/*==================================================== - * This function return the name of the job (by [Yor]) - *---------------------------------------------------- - */ -const char *job_name (int pc_class) -{ - switch (pc_class) - { - case 0: - return "Novice"; - case 1: - return "Swordsman"; - case 2: - return "Mage"; - case 3: - return "Archer"; - case 4: - return "Acolyte"; - case 5: - return "Merchant"; - case 6: - return "Thief"; - case 7: - return "Knight"; - case 8: - return "Priest"; - case 9: - return "Wizard"; - case 10: - return "Blacksmith"; - case 11: - return "Hunter"; - case 12: - return "Assassin"; - case 13: - return "Knight 2"; - case 14: - return "Crusader"; - case 15: - return "Monk"; - case 16: - return "Sage"; - case 17: - return "Rogue"; - case 18: - return "Alchemist"; - case 19: - return "Bard"; - case 20: - return "Dancer"; - case 21: - return "Crusader 2"; - case 22: - return "Wedding"; - case 23: - return "Super Novice"; - case 4001: - return "Novice High"; - case 4002: - return "Swordsman High"; - case 4003: - return "Mage High"; - case 4004: - return "Archer High"; - case 4005: - return "Acolyte High"; - case 4006: - return "Merchant High"; - case 4007: - return "Thief High"; - case 4008: - return "Lord Knight"; - case 4009: - return "High Priest"; - case 4010: - return "High Wizard"; - case 4011: - return "Whitesmith"; - case 4012: - return "Sniper"; - case 4013: - return "Assassin Cross"; - case 4014: - return "Peko Knight"; - case 4015: - return "Paladin"; - case 4016: - return "Champion"; - case 4017: - return "Professor"; - case 4018: - return "Stalker"; - case 4019: - return "Creator"; - case 4020: - return "Clown"; - case 4021: - return "Gypsy"; - case 4022: - return "Peko Paladin"; - case 4023: - return "Baby Novice"; - case 4024: - return "Baby Swordsman"; - case 4025: - return "Baby Mage"; - case 4026: - return "Baby Archer"; - case 4027: - return "Baby Acolyte"; - case 4028: - return "Baby Merchant"; - case 4029: - return "Baby Thief"; - case 4030: - return "Baby Knight"; - case 4031: - return "Baby Priest"; - case 4032: - return "Baby Wizard"; - case 4033: - return "Baby Blacksmith"; - case 4034: - return "Baby Hunter"; - case 4035: - return "Baby Assassin"; - case 4036: - return "Baby Peco Knight"; - case 4037: - return "Baby Crusader"; - case 4038: - return "Baby Monk"; - case 4039: - return "Baby Sage"; - case 4040: - return "Baby Rogue"; - case 4041: - return "Baby Alchemist"; - case 4042: - return "Baby Bard"; - case 4043: - return "Baby Dancer"; - case 4044: - return "Baby Peco Crusader"; - case 4045: - return "Super Baby"; - } - return "Unknown Job"; -} - -//----------------------------------------------------------- -// Return the message string of the specified number by [Yor] -//----------------------------------------------------------- -char *msg_txt (int msg_number) -{ - if (msg_number >= 0 - && msg_number < (int) (sizeof (msg_table) / sizeof (msg_table[0])) - && msg_table[msg_number] != NULL && msg_table[msg_number][0] != '\0') - return msg_table[msg_number]; - - return "??"; -} - -//------------------------------------------------------------ -// E-mail check: return 0 (not correct) or 1 (valid). by [Yor] -//------------------------------------------------------------ -int e_mail_check (unsigned char *email) -{ - char ch; - unsigned char *last_arobas; - - // athena limits - if (strlen (email) < 3 || strlen (email) > 39) - return 0; - - // part of RFC limits (official reference of e-mail description) - if (strchr (email, '@') == NULL || email[strlen (email) - 1] == '@') - return 0; - - if (email[strlen (email) - 1] == '.') - return 0; - - last_arobas = strrchr (email, '@'); - - if (strstr (last_arobas, "@.") != NULL || - strstr (last_arobas, "..") != NULL) - return 0; - - for (ch = 1; ch < 32; ch++) - { - if (strchr (last_arobas, ch) != NULL) - { - return 0; - break; - } - } - - if (strchr (last_arobas, ' ') != NULL || - strchr (last_arobas, ';') != NULL) - return 0; - - // all correct - return 1; -} - -/*========================================== - * get_atcommand_level @コマンドの必要レベルを取得 - *------------------------------------------ - */ -int get_atcommand_level (const AtCommandType type) -{ - int i; - - for (i = 0; atcommand_info[i].type != AtCommand_None; i++) - if (atcommand_info[i].type == type) - return atcommand_info[i].level; - - return 100; // 100: command can not be used -} - -/*======================================== - * At-command logging - */ -void log_atcommand (struct map_session_data *sd, const char *fmt, ...) -{ - char message[512]; - va_list ap; - - va_start (ap, fmt); - vsnprintf (message, 511, fmt, ap); - va_end (ap); - - gm_log ("%s(%d,%d) %s(%d) : %s", map[sd->bl.m].name, sd->bl.x, - sd->bl.y, sd->status.name, sd->status.account_id, message); -} - -char *gm_logfile_name = NULL; -/*========================================== - * Log a timestamped line to GM log file - *------------------------------------------ - */ -void gm_log (const char *fmt, ...) -{ - static int last_logfile_nr = 0; - static FILE *gm_logfile = NULL; - time_t time_v; - struct tm ctime; - int month, year, logfile_nr; - char message[512]; - va_list ap; - - if (!gm_logfile_name) - return; - - va_start (ap, fmt); - vsnprintf (message, 511, fmt, ap); - va_end (ap); - - time (&time_v); - gmtime_r (&time_v, &ctime); - - year = ctime.tm_year + 1900; - month = ctime.tm_mon + 1; - logfile_nr = (year * 12) + month; - - if (logfile_nr != last_logfile_nr) - { - char *fullname = (char *)malloc (strlen (gm_logfile_name) + 10); - sprintf (fullname, "%s.%04d-%02d", gm_logfile_name, year, month); - - if (gm_logfile) - fclose_ (gm_logfile); - - gm_logfile = fopen_ (fullname, "a"); - free (fullname); - - if (!gm_logfile) - { - perror ("GM log file"); - gm_logfile_name = NULL; - } - last_logfile_nr = logfile_nr; - } - - fprintf (gm_logfile, "[%04d-%02d-%02d %02d:%02d:%02d] %s\n", - year, month, ctime.tm_mday, ctime.tm_hour, - ctime.tm_min, ctime.tm_sec, message); - - fflush (gm_logfile); -} - -/*========================================== - *is_atcommand @コマンドに存在するかどうか確認する - *------------------------------------------ - */ -AtCommandType -is_atcommand (const int fd, struct map_session_data *sd, const char *message, - int gmlvl) -{ - AtCommandInfo info; - AtCommandType type; - - nullpo_retr (AtCommand_None, sd); - - if (!message || !*message) - return AtCommand_None; - - memset (&info, 0, sizeof (info)); - - type = atcommand (gmlvl > 0 ? gmlvl : pc_isGM (sd), message, &info); - if (type != AtCommand_None) - { - char command[100]; - char output[200]; - const char *str = message; - const char *p = message; - memset (command, '\0', sizeof (command)); - memset (output, '\0', sizeof (output)); - while (*p && !isspace (*p)) - p++; - if (p - str >= sizeof (command)) // too long - return AtCommand_Unknown; - strncpy (command, str, p - str); - while (isspace (*p)) - p++; - - if (type == AtCommand_Unknown || info.proc == NULL) - { - sprintf (output, msg_table[153], command); // %s is Unknown Command. - clif_displaymessage (fd, output); - } - else - { - if (info.proc (fd, sd, command, p) != 0) - { - // Command can not be executed - sprintf (output, msg_table[154], command); // %s failed. - clif_displaymessage (fd, output); - } - else - { - if (get_atcommand_level (type) != 0) // Don't log level 0 commands - log_atcommand (sd, "%s %s", command, p); - } - } - - return info.type; - } - - return AtCommand_None; -} - -/*========================================== - * - *------------------------------------------ - */ -AtCommandType atcommand (const int level, const char *message, - struct AtCommandInfo * info) -{ - char *p = (char *) message; // it's 'char' and not 'const char' to have possibility to modify the first character if necessary - - if (!info) - return AtCommand_None; - if (battle_config.atc_gmonly != 0 && !level) // level = pc_isGM(sd) - return AtCommand_None; - if (!p || !*p) - { - fprintf (stderr, "at command message is empty\n"); - return AtCommand_None; - } - - if (*p == command_symbol) - { // check first char. - char command[101]; - int i = 0; - memset (info, 0, sizeof (AtCommandInfo)); - sscanf (p, "%100s", command); - command[sizeof (command) - 1] = '\0'; - - while (atcommand_info[i].type != AtCommand_Unknown) - { - if (strcasecmp (command + 1, atcommand_info[i].command + 1) == 0 - && level >= atcommand_info[i].level) - { - p[0] = atcommand_info[i].command[0]; // set correct first symbol for after. - break; - } - i++; - } - - if (atcommand_info[i].type == AtCommand_Unknown) - { - // doesn't return Unknown if player is normal player (display the text, not display: unknown command) - if (level == 0) - return AtCommand_None; - else - return AtCommand_Unknown; - } - memcpy (info, &atcommand_info[i], sizeof atcommand_info[i]); - } - else - { - return AtCommand_None; - } - - return info->type; -} - -/*========================================== - * - *------------------------------------------ - */ -static int atkillmonster_sub (struct block_list *bl, va_list ap) -{ - int flag = va_arg (ap, int); - - nullpo_retr (0, bl); - - if (flag) - mob_damage (NULL, (struct mob_data *) bl, - ((struct mob_data *) bl)->hp, 2); - else - mob_delete ((struct mob_data *) bl); - - return 0; -} - -/*========================================== - * Read Message Data - *------------------------------------------ - */ -int msg_config_read (const char *cfgName) -{ - int msg_number; - char line[1024], w1[1024], w2[1024]; - FILE *fp; - - if ((fp = fopen_ (cfgName, "r")) == NULL) - { - printf ("Messages file not found: %s\n", cfgName); - return 1; - } - - while (fgets (line, sizeof (line) - 1, fp)) - { - if (line[0] == '/' && line[1] == '/') - continue; - if (sscanf (line, "%[^:]: %[^\r\n]", w1, w2) == 2) - { - if (strcasecmp (w1, "import") == 0) - { - msg_config_read (w2); - } - else - { - msg_number = atoi (w1); - if (msg_number >= 0 - && msg_number < - (int) (sizeof (msg_table) / sizeof (msg_table[0]))) - strcpy (msg_table[msg_number], w2); - // printf("message #%d: '%s'.\n", msg_number, msg_table[msg_number]); - } - } - } - fclose_ (fp); - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -static AtCommandInfo *get_atcommandinfo_byname (const char *name) -{ - int i; - - for (i = 0; atcommand_info[i].type != AtCommand_Unknown; i++) - if (strcasecmp (atcommand_info[i].command + 1, name) == 0) - return &atcommand_info[i]; - - return NULL; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_config_read (const char *cfgName) -{ - char line[1024], w1[1024], w2[1024]; - AtCommandInfo *p; - FILE *fp; - - if ((fp = fopen_ (cfgName, "r")) == NULL) - { - printf ("At commands configuration file not found: %s\n", cfgName); - return 1; - } - - while (fgets (line, sizeof (line) - 1, fp)) - { - if (line[0] == '/' && line[1] == '/') - continue; - - if (sscanf (line, "%1023[^:]:%1023s", w1, w2) != 2) - continue; - p = get_atcommandinfo_byname (w1); - if (p != NULL) - { - p->level = atoi (w2); - if (p->level > 100) - p->level = 100; - else if (p->level < 0) - p->level = 0; - } - - if (strcasecmp (w1, "import") == 0) - atcommand_config_read (w2); - else if (strcasecmp (w1, "command_symbol") == 0 && w2[0] > 31 && w2[0] != '/' && // symbol of standard ragnarok GM commands - w2[0] != '%') // symbol of party chat speaking - command_symbol = w2[0]; - } - fclose_ (fp); - - return 0; -} - -/*========================================== -// @ command processing functions - *------------------------------------------ - */ - -/*========================================== - * @setup - Safely set a chars levels and warp them to a special place - * TAW Specific - *------------------------------------------ - */ -int atcommand_setup (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char buf[256]; - char character[100]; - int level = 1; - - memset (character, '\0', sizeof (character)); - - if (!message || !*message - || sscanf (message, "%d %99[^\n]", &level, character) < 2) - { - clif_displaymessage (fd, "Usage: @setup "); - return -1; - } - level--; - - snprintf (buf, 255, "-255 %s", character); - atcommand_character_baselevel (fd, sd, "@charbaselvl", buf); - - snprintf (buf, 255, "%d %s", level, character); - atcommand_character_baselevel (fd, sd, "@charbaselvl", buf); - - // Emote skill - snprintf (buf, 255, "1 1 %s", character); - atcommand_skill_learn(fd, sd, "@skill-learn", buf); - - // Trade skill - snprintf (buf, 255, "2 1 %s", character); - atcommand_skill_learn(fd, sd, "@skill-learn", buf); - - // Party skill - snprintf (buf, 255, "2 2 %s", character); - atcommand_skill_learn(fd, sd, "@skill-learn", buf); - - snprintf (buf, 255, "018-1.gat 24 98 %s", character); - atcommand_charwarp (fd, sd, "@charwarp", buf); - - return (0); - -} - -/*========================================== - * @rura+ - *------------------------------------------ - */ -int atcommand_charwarp (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char map_name[100]; - char character[100]; - int x = 0, y = 0; - struct map_session_data *pl_sd; - int m; - - memset (map_name, '\0', sizeof (map_name)); - memset (character, '\0', sizeof (character)); - - if (!message || !*message - || sscanf (message, "%99s %d %d %99[^\n]", map_name, &x, &y, - character) < 4) - { - clif_displaymessage (fd, - "Usage: @charwarp/@rura+ "); - return -1; - } - - if (x <= 0) - x = MRAND (399) + 1; - if (y <= 0) - y = MRAND (399) + 1; - if (strstr (map_name, ".gat") == NULL && strstr (map_name, ".afm") == NULL && strlen (map_name) < 13) // 16 - 4 (.gat) - strcat (map_name, ".gat"); - - if ((pl_sd = map_nick2sd (character)) != NULL) - { - if (pc_isGM (sd) >= pc_isGM (pl_sd)) - { // you can rura+ only lower or same GM level - if (x > 0 && x < 800 && y > 0 && y < 800) - { - m = map_mapname2mapid (map_name); - if (m >= 0 && map[m].flag.nowarpto - && battle_config.any_warp_GM_min_level > pc_isGM (sd)) - { - clif_displaymessage (fd, - "You are not authorised to warp someone to this map."); - return -1; - } - if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp - && battle_config.any_warp_GM_min_level > pc_isGM (sd)) - { - clif_displaymessage (fd, - "You are not authorised to warp this player from its actual map."); - return -1; - } - if (pc_setpos (pl_sd, map_name, x, y, 3) == 0) - { - clif_displaymessage (pl_sd->fd, msg_table[0]); // Warped. - clif_displaymessage (fd, msg_table[15]); // Player warped (message sends to player too). - } - else - { - clif_displaymessage (fd, msg_table[1]); // Map not found. - return -1; - } - } - else - { - clif_displaymessage (fd, msg_table[2]); // Coordinates out of range. - return -1; - } - } - else - { - clif_displaymessage (fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player. - return -1; - } - } - else - { - clif_displaymessage (fd, msg_table[3]); // Character not found. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_warp (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char map_name[100]; - int x = 0, y = 0; - int m; - - memset (map_name, '\0', sizeof (map_name)); - - if (!message || !*message - || sscanf (message, "%99s %d %d", map_name, &x, &y) < 1) - { - clif_displaymessage (fd, - "Please, enter a map (usage: @warp )."); - return -1; - } - - if (x <= 0) - x = MRAND (399) + 1; - if (y <= 0) - y = MRAND (399) + 1; - - if (strstr (map_name, ".gat") == NULL && strstr (map_name, ".afm") == NULL && strlen (map_name) < 13) // 16 - 4 (.gat) - strcat (map_name, ".gat"); - - if (x > 0 && x < 800 && y > 0 && y < 800) - { - m = map_mapname2mapid (map_name); - if (m >= 0 && map[m].flag.nowarpto - && battle_config.any_warp_GM_min_level > pc_isGM (sd)) - { - clif_displaymessage (fd, - "You are not authorised to warp you to this map."); - return -1; - } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp - && battle_config.any_warp_GM_min_level > pc_isGM (sd)) - { - clif_displaymessage (fd, - "You are not authorised to warp you from your actual map."); - return -1; - } - if (pc_setpos (sd, map_name, x, y, 3) == 0) - clif_displaymessage (fd, msg_table[0]); // Warped. - else - { - clif_displaymessage (fd, msg_table[1]); // Map not found. - return -1; - } - } - else - { - clif_displaymessage (fd, msg_table[2]); // Coordinates out of range. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_where (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char character[100]; - char output[200]; - struct map_session_data *pl_sd; - - memset (character, '\0', sizeof (character)); - memset (output, '\0', sizeof (output)); - - if (sscanf (message, "%99[^\n]", character) < 1) - strcpy (character, sd->status.name); - - if ((pl_sd = map_nick2sd (character)) != NULL && - !((battle_config.hide_GM_session - || (pl_sd->status.option & OPTION_HIDE)) - && (pc_isGM (pl_sd) > pc_isGM (sd)))) - { // you can look only lower or same level - sprintf (output, "%s: %s (%d,%d)", pl_sd->status.name, pl_sd->mapname, - pl_sd->bl.x, pl_sd->bl.y); - clif_displaymessage (fd, output); - } - else - { - clif_displaymessage (fd, msg_table[3]); // Character not found. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_goto (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char character[100]; - char output[200]; - struct map_session_data *pl_sd; - - memset (character, '\0', sizeof (character)); - memset (output, '\0', sizeof (output)); - - if (!message || !*message || sscanf (message, "%99[^\n]", character) < 1) - { - clif_displaymessage (fd, - "Please, enter a player name (usage: @jumpto/@warpto/@goto )."); - return -1; - } - - if ((pl_sd = map_nick2sd (character)) != NULL) - { - if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarpto - && battle_config.any_warp_GM_min_level > pc_isGM (sd)) - { - clif_displaymessage (fd, - "You are not authorised to warp you to the map of this player."); - return -1; - } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp - && battle_config.any_warp_GM_min_level > pc_isGM (sd)) - { - clif_displaymessage (fd, - "You are not authorised to warp you from your actual map."); - return -1; - } - pc_setpos (sd, pl_sd->mapname, pl_sd->bl.x, pl_sd->bl.y, 3); - sprintf (output, msg_table[4], character); // Jump to %s - clif_displaymessage (fd, output); - } - else - { - clif_displaymessage (fd, msg_table[3]); // Character not found. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_jump (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char output[200]; - int x = 0, y = 0; - - memset (output, '\0', sizeof (output)); - - sscanf (message, "%d %d", &x, &y); - - if (x <= 0) - x = MRAND (399) + 1; - if (y <= 0) - y = MRAND (399) + 1; - if (x > 0 && x < 800 && y > 0 && y < 800) - { - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto - && battle_config.any_warp_GM_min_level > pc_isGM (sd)) - { - clif_displaymessage (fd, - "You are not authorised to warp you to your actual map."); - return -1; - } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp - && battle_config.any_warp_GM_min_level > pc_isGM (sd)) - { - clif_displaymessage (fd, - "You are not authorised to warp you from your actual map."); - return -1; - } - pc_setpos (sd, sd->mapname, x, y, 3); - sprintf (output, msg_table[5], x, y); // Jump to %d %d - clif_displaymessage (fd, output); - } - else - { - clif_displaymessage (fd, msg_table[2]); // Coordinates out of range. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_who (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char output[200]; - struct map_session_data *pl_sd; - int i, j, count; - int pl_GM_level, GM_level; - char match_text[100]; - char player_name[24]; - - memset (output, '\0', sizeof (output)); - memset (match_text, '\0', sizeof (match_text)); - memset (player_name, '\0', sizeof (player_name)); - - if (sscanf (message, "%99[^\n]", match_text) < 1) - strcpy (match_text, ""); - for (j = 0; match_text[j]; j++) - match_text[j] = tolower (match_text[j]); - - count = 0; - GM_level = pc_isGM (sd); - for (i = 0; i < fd_max; i++) - { - if (session[i] && (pl_sd = (struct map_session_data *)session[i]->session_data) - && pl_sd->state.auth) - { - pl_GM_level = pc_isGM (pl_sd); - if (! - ((battle_config.hide_GM_session - || (pl_sd->status.option & OPTION_HIDE)) - && (pl_GM_level > GM_level))) - { // you can look only lower or same level - memcpy (player_name, pl_sd->status.name, 24); - for (j = 0; player_name[j]; j++) - player_name[j] = tolower (player_name[j]); - if (strstr (player_name, match_text) != NULL) - { // search with no case sensitive - if (pl_GM_level > 0) - sprintf (output, - "Name: %s (GM:%d) | Location: %s %d %d", - pl_sd->status.name, pl_GM_level, - pl_sd->mapname, pl_sd->bl.x, pl_sd->bl.y); - else - sprintf (output, "Name: %s | Location: %s %d %d", - pl_sd->status.name, pl_sd->mapname, - pl_sd->bl.x, pl_sd->bl.y); - clif_displaymessage (fd, output); - count++; - } - } - } - } - - if (count == 0) - clif_displaymessage (fd, msg_table[28]); // No player found. - else if (count == 1) - clif_displaymessage (fd, msg_table[29]); // 1 player found. - else - { - sprintf (output, msg_table[30], count); // %d players found. - clif_displaymessage (fd, output); - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_whogroup (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char temp0[100]; - char temp1[100]; - char output[200]; - struct map_session_data *pl_sd; - int i, j, count; - int pl_GM_level, GM_level; - char match_text[100]; - char player_name[24]; - struct guild *g; - struct party *p; - - memset (temp0, '\0', sizeof (temp0)); - memset (temp1, '\0', sizeof (temp1)); - memset (output, '\0', sizeof (output)); - memset (match_text, '\0', sizeof (match_text)); - memset (player_name, '\0', sizeof (player_name)); - - if (sscanf (message, "%99[^\n]", match_text) < 1) - strcpy (match_text, ""); - for (j = 0; match_text[j]; j++) - match_text[j] = tolower (match_text[j]); - - count = 0; - GM_level = pc_isGM (sd); - for (i = 0; i < fd_max; i++) - { - if (session[i] && (pl_sd = (struct map_session_data *)session[i]->session_data) - && pl_sd->state.auth) - { - pl_GM_level = pc_isGM (pl_sd); - if (! - ((battle_config.hide_GM_session - || (pl_sd->status.option & OPTION_HIDE)) - && (pl_GM_level > GM_level))) - { // you can look only lower or same level - memcpy (player_name, pl_sd->status.name, 24); - for (j = 0; player_name[j]; j++) - player_name[j] = tolower (player_name[j]); - if (strstr (player_name, match_text) != NULL) - { // search with no case sensitive - g = guild_search (pl_sd->status.guild_id); - if (g == NULL) - sprintf (temp1, "None"); - else - sprintf (temp1, "%s", g->name); - p = party_search (pl_sd->status.party_id); - if (p == NULL) - sprintf (temp0, "None"); - else - sprintf (temp0, "%s", p->name); - if (pl_GM_level > 0) - sprintf (output, - "Name: %s (GM:%d) | Party: '%s' | Guild: '%s'", - pl_sd->status.name, pl_GM_level, temp0, - temp1); - else - sprintf (output, - "Name: %s | Party: '%s' | Guild: '%s'", - pl_sd->status.name, temp0, temp1); - clif_displaymessage (fd, output); - count++; - } - } - } - } - - if (count == 0) - clif_displaymessage (fd, msg_table[28]); // No player found. - else if (count == 1) - clif_displaymessage (fd, msg_table[29]); // 1 player found. - else - { - sprintf (output, msg_table[30], count); // %d players found. - clif_displaymessage (fd, output); - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_whomap (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char output[200]; - struct map_session_data *pl_sd; - int i, count; - int pl_GM_level, GM_level; - int map_id; - char map_name[100]; - - memset (output, '\0', sizeof (output)); - memset (map_name, '\0', sizeof (map_name)); - - if (!message || !*message) - map_id = sd->bl.m; - else - { - sscanf (message, "%99s", map_name); - if (strstr (map_name, ".gat") == NULL && strstr (map_name, ".afm") == NULL && strlen (map_name) < 13) // 16 - 4 (.gat) - strcat (map_name, ".gat"); - if ((map_id = map_mapname2mapid (map_name)) < 0) - map_id = sd->bl.m; - } - - count = 0; - GM_level = pc_isGM (sd); - for (i = 0; i < fd_max; i++) - { - if (session[i] && (pl_sd = (struct map_session_data *)session[i]->session_data) - && pl_sd->state.auth) - { - pl_GM_level = pc_isGM (pl_sd); - if (! - ((battle_config.hide_GM_session - || (pl_sd->status.option & OPTION_HIDE)) - && (pl_GM_level > GM_level))) - { // you can look only lower or same level - if (pl_sd->bl.m == map_id) - { - if (pl_GM_level > 0) - sprintf (output, - "Name: %s (GM:%d) | Location: %s %d %d", - pl_sd->status.name, pl_GM_level, - pl_sd->mapname, pl_sd->bl.x, pl_sd->bl.y); - else - sprintf (output, "Name: %s | Location: %s %d %d", - pl_sd->status.name, pl_sd->mapname, - pl_sd->bl.x, pl_sd->bl.y); - clif_displaymessage (fd, output); - count++; - } - } - } - } - - if (count == 0) - sprintf (output, msg_table[54], map[map_id].name); // No player found in map '%s'. - else if (count == 1) - sprintf (output, msg_table[55], map[map_id].name); // 1 player found in map '%s'. - else - { - sprintf (output, msg_table[56], count, map[map_id].name); // %d players found in map '%s'. - } - clif_displaymessage (fd, output); - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_whomapgroup (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char temp0[100]; - char temp1[100]; - char output[200]; - struct map_session_data *pl_sd; - int i, count; - int pl_GM_level, GM_level; - int map_id = 0; - char map_name[100]; - struct guild *g; - struct party *p; - - memset (temp0, '\0', sizeof (temp0)); - memset (temp1, '\0', sizeof (temp1)); - memset (output, '\0', sizeof (output)); - memset (map_name, '\0', sizeof (map_name)); - - if (!message || !*message) - map_id = sd->bl.m; - else - { - sscanf (message, "%99s", map_name); - if (strstr (map_name, ".gat") == NULL && strstr (map_name, ".afm") == NULL && strlen (map_name) < 13) // 16 - 4 (.gat) - strcat (map_name, ".gat"); - if ((map_id = map_mapname2mapid (map_name)) < 0) - map_id = sd->bl.m; - } - - count = 0; - GM_level = pc_isGM (sd); - for (i = 0; i < fd_max; i++) - { - if (session[i] && (pl_sd = (struct map_session_data *)session[i]->session_data) - && pl_sd->state.auth) - { - pl_GM_level = pc_isGM (pl_sd); - if (! - ((battle_config.hide_GM_session - || (pl_sd->status.option & OPTION_HIDE)) - && (pl_GM_level > GM_level))) - { // you can look only lower or same level - if (pl_sd->bl.m == map_id) - { - g = guild_search (pl_sd->status.guild_id); - if (g == NULL) - sprintf (temp1, "None"); - else - sprintf (temp1, "%s", g->name); - p = party_search (pl_sd->status.party_id); - if (p == NULL) - sprintf (temp0, "None"); - else - sprintf (temp0, "%s", p->name); - if (pl_GM_level > 0) - sprintf (output, - "Name: %s (GM:%d) | Party: '%s' | Guild: '%s'", - pl_sd->status.name, pl_GM_level, temp0, - temp1); - else - sprintf (output, - "Name: %s | Party: '%s' | Guild: '%s'", - pl_sd->status.name, temp0, temp1); - clif_displaymessage (fd, output); - count++; - } - } - } - } - - if (count == 0) - sprintf (output, msg_table[54], map[map_id].name); // No player found in map '%s'. - else if (count == 1) - sprintf (output, msg_table[55], map[map_id].name); // 1 player found in map '%s'. - else - { - sprintf (output, msg_table[56], count, map[map_id].name); // %d players found in map '%s'. - } - clif_displaymessage (fd, output); - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_whogm (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char temp0[100]; - char temp1[100]; - char output[200]; - struct map_session_data *pl_sd; - int i, j, count; - int pl_GM_level, GM_level; - char match_text[100]; - char player_name[24]; - struct guild *g; - struct party *p; - - memset (temp0, '\0', sizeof (temp0)); - memset (temp1, '\0', sizeof (temp1)); - memset (output, '\0', sizeof (output)); - memset (match_text, '\0', sizeof (match_text)); - memset (player_name, '\0', sizeof (player_name)); - - if (sscanf (message, "%99[^\n]", match_text) < 1) - strcpy (match_text, ""); - for (j = 0; match_text[j]; j++) - match_text[j] = tolower (match_text[j]); - - count = 0; - GM_level = pc_isGM (sd); - for (i = 0; i < fd_max; i++) - { - if (session[i] && (pl_sd = (struct map_session_data *)session[i]->session_data) - && pl_sd->state.auth) - { - pl_GM_level = pc_isGM (pl_sd); - if (pl_GM_level > 0) - { - if (! - ((battle_config.hide_GM_session - || (pl_sd->status.option & OPTION_HIDE)) - && (pl_GM_level > GM_level))) - { // you can look only lower or same level - memcpy (player_name, pl_sd->status.name, 24); - for (j = 0; player_name[j]; j++) - player_name[j] = tolower (player_name[j]); - if (strstr (player_name, match_text) != NULL) - { // search with no case sensitive - sprintf (output, - "Name: %s (GM:%d) | Location: %s %d %d", - pl_sd->status.name, pl_GM_level, - pl_sd->mapname, pl_sd->bl.x, pl_sd->bl.y); - clif_displaymessage (fd, output); - sprintf (output, - " BLvl: %d | Job: %s (Lvl: %d)", - pl_sd->status.base_level, - job_name (pl_sd->status.pc_class), - pl_sd->status.job_level); - clif_displaymessage (fd, output); - g = guild_search (pl_sd->status.guild_id); - if (g == NULL) - sprintf (temp1, "None"); - else - sprintf (temp1, "%s", g->name); - p = party_search (pl_sd->status.party_id); - if (p == NULL) - sprintf (temp0, "None"); - else - sprintf (temp0, "%s", p->name); - sprintf (output, " Party: '%s' | Guild: '%s'", - temp0, temp1); - clif_displaymessage (fd, output); - count++; - } - } - } - } - } - - if (count == 0) - clif_displaymessage (fd, msg_table[150]); // No GM found. - else if (count == 1) - clif_displaymessage (fd, msg_table[151]); // 1 GM found. - else - { - sprintf (output, msg_table[152], count); // %d GMs found. - clif_displaymessage (fd, output); - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_save (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - nullpo_retr (-1, sd); - - pc_setsavepoint (sd, sd->mapname, sd->bl.x, sd->bl.y); - pc_makesavestatus (sd); - chrif_save (sd); - clif_displaymessage (fd, msg_table[6]); // Character data respawn point saved. - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_load (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - int m; - - m = map_mapname2mapid (sd->status.save_point.map); - if (m >= 0 && map[m].flag.nowarpto - && battle_config.any_warp_GM_min_level > pc_isGM (sd)) - { - clif_displaymessage (fd, - "You are not authorised to warp you to your save map."); - return -1; - } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp - && battle_config.any_warp_GM_min_level > pc_isGM (sd)) - { - clif_displaymessage (fd, - "You are not authorised to warp you from your actual map."); - return -1; - } - - pc_setpos (sd, sd->status.save_point.map, sd->status.save_point.x, - sd->status.save_point.y, 0); - clif_displaymessage (fd, msg_table[7]); // Warping to respawn point. - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_speed (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char output[200]; - int speed; - - memset (output, '\0', sizeof (output)); - - if (!message || !*message) - { - sprintf (output, - "Please, enter a speed value (usage: @speed <%d-%d>).", - MIN_WALK_SPEED, MAX_WALK_SPEED); - clif_displaymessage (fd, output); - return -1; - } - - speed = atoi (message); - if (speed >= MIN_WALK_SPEED && speed <= MAX_WALK_SPEED) - { - sd->speed = speed; - //sd->walktimer = x; - //この文を追加 by れ - clif_updatestatus (sd, SP_SPEED); - clif_displaymessage (fd, msg_table[8]); // Speed changed. - } - else - { - sprintf (output, - "Please, enter a valid speed value (usage: @speed <%d-%d>).", - MIN_WALK_SPEED, MAX_WALK_SPEED); - clif_displaymessage (fd, output); - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_storage (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - struct storage *stor; //changes from Freya/Yor - nullpo_retr (-1, sd); - - if (sd->state.storage_flag) - { - clif_displaymessage (fd, msg_table[250]); - return -1; - } - - if ((stor = account2storage2 (sd->status.account_id)) != NULL - && stor->storage_status == 1) - { - clif_displaymessage (fd, msg_table[250]); - return -1; - } - - storage_storageopen (sd); - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_guildstorage (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - struct storage *stor; //changes from Freya/Yor - nullpo_retr (-1, sd); - - if (sd->status.guild_id > 0) - { - if (sd->state.storage_flag) - { - clif_displaymessage (fd, msg_table[251]); - return -1; - } - if ((stor = account2storage2 (sd->status.account_id)) != NULL - && stor->storage_status == 1) - { - clif_displaymessage (fd, msg_table[251]); - return -1; - } - storage_guild_storageopen (sd); - } - else - { - clif_displaymessage (fd, msg_table[252]); - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_option (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - int param1 = 0, param2 = 0, param3 = 0; - nullpo_retr (-1, sd); - - if (!message || !*message - || sscanf (message, "%d %d %d", ¶m1, ¶m2, ¶m3) < 1 - || param1 < 0 || param2 < 0 || param3 < 0) - { - clif_displaymessage (fd, - "Please, enter at least a option (usage: @option )."); - return -1; - } - - sd->opt1 = param1; - sd->opt2 = param2; - if (!(sd->status.option & CART_MASK) && param3 & CART_MASK) - { - clif_cart_itemlist (sd); - clif_cart_equiplist (sd); - clif_updatestatus (sd, SP_CARTINFO); - } - sd->status.option = param3; - // fix pecopeco display - if (sd->status.pc_class == 13 || sd->status.pc_class == 21 - || sd->status.pc_class == 4014 || sd->status.pc_class == 4022) - { - if (!pc_isriding (sd)) - { // sd have the new value... - if (sd->status.pc_class == 13) - sd->status.pc_class = sd->view_class = 7; - else if (sd->status.pc_class == 21) - sd->status.pc_class = sd->view_class = 14; - else if (sd->status.pc_class == 4014) - sd->status.pc_class = sd->view_class = 4008; - else if (sd->status.pc_class == 4022) - sd->status.pc_class = sd->view_class = 4015; - } - } - else - { - if (pc_isriding (sd)) - { // sd have the new value... - if (sd->disguise > 0) - { // temporary prevention of crash caused by peco + disguise, will look into a better solution [Valaris] (code added by [Yor]) - sd->status.option &= ~0x0020; - } - else - { - if (sd->status.pc_class == 7) - sd->status.pc_class = sd->view_class = 13; - else if (sd->status.pc_class == 14) - sd->status.pc_class = sd->view_class = 21; - else if (sd->status.pc_class == 4008) - sd->status.pc_class = sd->view_class = 4014; - else if (sd->status.pc_class == 4015) - sd->status.pc_class = sd->view_class = 4022; - else - sd->status.option &= ~0x0020; - } - } - } - - clif_changeoption (&sd->bl); - pc_calcstatus (sd, 0); - clif_displaymessage (fd, msg_table[9]); // Options changed. - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_hide (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - if (sd->status.option & OPTION_HIDE) - { - sd->status.option &= ~OPTION_HIDE; - clif_displaymessage (fd, msg_table[10]); // Invisible: Off - } - else - { - sd->status.option |= OPTION_HIDE; - clif_displaymessage (fd, msg_table[11]); // Invisible: On - } - clif_changeoption (&sd->bl); - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_die (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - pc_damage (NULL, sd, sd->status.hp + 1); - clif_displaymessage (fd, msg_table[13]); // A pity! You've died. - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_kill (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char character[100]; - struct map_session_data *pl_sd; - - memset (character, '\0', sizeof (character)); - - if (!message || !*message || sscanf (message, "%99[^\n]", character) < 1) - { - clif_displaymessage (fd, - "Please, enter a player name (usage: @kill )."); - return -1; - } - - if ((pl_sd = map_nick2sd (character)) != NULL) - { - if (pc_isGM (sd) >= pc_isGM (pl_sd)) - { // you can kill only lower or same level - pc_damage (NULL, pl_sd, pl_sd->status.hp + 1); - clif_displaymessage (fd, msg_table[14]); // Character killed. - } - else - { - clif_displaymessage (fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player. - return -1; - } - } - else - { - clif_displaymessage (fd, msg_table[3]); // Character not found. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_alive (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - sd->status.hp = sd->status.max_hp; - sd->status.sp = sd->status.max_sp; - pc_setstand (sd); - if (battle_config.pc_invincible_time > 0) - pc_setinvincibletimer (sd, battle_config.pc_invincible_time); - clif_updatestatus (sd, SP_HP); - clif_updatestatus (sd, SP_SP); - clif_resurrection (&sd->bl, 1); - clif_displaymessage (fd, msg_table[16]); // You've been revived! It's a miracle! - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_kami (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char output[200]; - - memset (output, '\0', sizeof (output)); - - if (!message || !*message) - { - clif_displaymessage (fd, - "Please, enter a message (usage: @kami )."); - return -1; - } - - sscanf (message, "%199[^\n]", output); - intif_GMmessage (output, strlen (output) + 1, 0); - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_heal (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - int hp = 0, sp = 0; // [Valaris] thanks to fov - - sscanf (message, "%d %d", &hp, &sp); - - if (hp == 0 && sp == 0) - { - hp = sd->status.max_hp - sd->status.hp; - sp = sd->status.max_sp - sd->status.sp; - } - else - { - if (hp > 0 && (hp > sd->status.max_hp || hp > (sd->status.max_hp - sd->status.hp))) // fix positiv overflow - hp = sd->status.max_hp - sd->status.hp; - else if (hp < 0 && (hp < -sd->status.max_hp || hp < (1 - sd->status.hp))) // fix negativ overflow - hp = 1 - sd->status.hp; - if (sp > 0 && (sp > sd->status.max_sp || sp > (sd->status.max_sp - sd->status.sp))) // fix positiv overflow - sp = sd->status.max_sp - sd->status.sp; - else if (sp < 0 && (sp < -sd->status.max_sp || sp < (1 - sd->status.sp))) // fix negativ overflow - sp = 1 - sd->status.sp; - } - - if (hp > 0) // display like heal - clif_heal (fd, SP_HP, hp); - else if (hp < 0) // display like damage - clif_damage (&sd->bl, &sd->bl, gettick (), 0, 0, -hp, 0, 4, 0); - if (sp > 0) // no display when we lost SP - clif_heal (fd, SP_SP, sp); - - if (hp != 0 || sp != 0) - { - pc_heal (sd, hp, sp); - if (hp >= 0 && sp >= 0) - clif_displaymessage (fd, msg_table[17]); // HP, SP recovered. - else - clif_displaymessage (fd, msg_table[156]); // HP or/and SP modified. - } - else - { - clif_displaymessage (fd, msg_table[157]); // HP and SP are already with the good value. - return -1; - } - - return 0; -} - -/*========================================== - * @item command (usage: @item ) - *------------------------------------------ - */ -int atcommand_item (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char item_name[100]; - int number = 0, item_id, flag; - struct item item_tmp; - struct item_data *item_data; - int get_count, i; - - memset (item_name, '\0', sizeof (item_name)); - - if (!message || !*message - || sscanf (message, "%99s %d", item_name, &number) < 1) - { - clif_displaymessage (fd, - "Please, enter an item name/id (usage: @item [quantity])."); - return -1; - } - - if (number <= 0) - number = 1; - - item_id = 0; - if ((item_data = itemdb_searchname (item_name)) != NULL || - (item_data = itemdb_exists (atoi (item_name))) != NULL) - item_id = item_data->nameid; - - if (item_id >= 500) - { - get_count = number; - if (item_data->type == 4 || item_data->type == 5 || - item_data->type == 7 || item_data->type == 8) - { - get_count = 1; - } - for (i = 0; i < number; i += get_count) - { - memset (&item_tmp, 0, sizeof (item_tmp)); - item_tmp.nameid = item_id; - item_tmp.identify = 1; - if ((flag = - pc_additem ((struct map_session_data *) sd, &item_tmp, - get_count))) - clif_additem ((struct map_session_data *) sd, 0, 0, flag); - } - clif_displaymessage (fd, msg_table[18]); // Item created. - } - else - { - clif_displaymessage (fd, msg_table[19]); // Invalid item ID or name. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_itemreset (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - int i; - - for (i = 0; i < MAX_INVENTORY; i++) - { - if (sd->status.inventory[i].amount - && sd->status.inventory[i].equip == 0) - pc_delitem (sd, i, sd->status.inventory[i].amount, 0); - } - clif_displaymessage (fd, msg_table[20]); // All of your items have been removed. - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_itemcheck (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - pc_checkitem (sd); - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_baselevelup (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - int level, i; - - if (!message || !*message || (level = atoi (message)) == 0) - { - clif_displaymessage (fd, - "Please, enter a level adjustement (usage: @blvl )."); - return -1; - } - - if (level > 0) - { - if (sd->status.base_level == battle_config.maximum_level) - { // check for max level by Valaris - clif_displaymessage (fd, msg_table[47]); // Base level can't go any higher. - return -1; - } // End Addition - if (level > battle_config.maximum_level || level > (battle_config.maximum_level - sd->status.base_level)) // fix positiv overflow - level = battle_config.maximum_level - sd->status.base_level; - for (i = 1; i <= level; i++) - sd->status.status_point += (sd->status.base_level + i + 14) / 4; - sd->status.base_level += level; - clif_updatestatus (sd, SP_BASELEVEL); - clif_updatestatus (sd, SP_NEXTBASEEXP); - clif_updatestatus (sd, SP_STATUSPOINT); - pc_calcstatus (sd, 0); - pc_heal (sd, sd->status.max_hp, sd->status.max_sp); - clif_misceffect (&sd->bl, 0); - clif_displaymessage (fd, msg_table[21]); // Base level raised. - } - else - { - if (sd->status.base_level == 1) - { - clif_displaymessage (fd, msg_table[158]); // Base level can't go any lower. - return -1; - } - if (level < -battle_config.maximum_level || level < (1 - sd->status.base_level)) // fix negativ overflow - level = 1 - sd->status.base_level; - if (sd->status.status_point > 0) - { - for (i = 0; i > level; i--) - sd->status.status_point -= - (sd->status.base_level + i + 14) / 4; - if (sd->status.status_point < 0) - sd->status.status_point = 0; - clif_updatestatus (sd, SP_STATUSPOINT); - } // to add: remove status points from stats - sd->status.base_level += level; - clif_updatestatus (sd, SP_BASELEVEL); - clif_updatestatus (sd, SP_NEXTBASEEXP); - pc_calcstatus (sd, 0); - clif_displaymessage (fd, msg_table[22]); // Base level lowered. - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_joblevelup (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - int up_level = 50, level; - - if (!message || !*message || (level = atoi (message)) == 0) - { - clif_displaymessage (fd, - "Please, enter a level adjustement (usage: @jlvl )."); - return -1; - } - - if (sd->status.pc_class == 0 || sd->status.pc_class == 4001) - up_level -= 40; - else if ((sd->status.pc_class > 4007 && sd->status.pc_class < 4024) - || sd->status.pc_class == 23) - up_level += 20; - - if (level > 0) - { - if (sd->status.job_level == up_level) - { - clif_displaymessage (fd, msg_table[23]); // Job level can't go any higher. - return -1; - } - if (level > up_level || level > (up_level - sd->status.job_level)) // fix positiv overflow - level = up_level - sd->status.job_level; - sd->status.job_level += level; - clif_updatestatus (sd, SP_JOBLEVEL); - clif_updatestatus (sd, SP_NEXTJOBEXP); - sd->status.skill_point += level; - clif_updatestatus (sd, SP_SKILLPOINT); - pc_calcstatus (sd, 0); - clif_misceffect (&sd->bl, 1); - clif_displaymessage (fd, msg_table[24]); // Job level raised. - } - else - { - if (sd->status.job_level == 1) - { - clif_displaymessage (fd, msg_table[159]); // Job level can't go any lower. - return -1; - } - if (level < -up_level || level < (1 - sd->status.job_level)) // fix negativ overflow - level = 1 - sd->status.job_level; - sd->status.job_level += level; - clif_updatestatus (sd, SP_JOBLEVEL); - clif_updatestatus (sd, SP_NEXTJOBEXP); - if (sd->status.skill_point > 0) - { - sd->status.skill_point += level; - if (sd->status.skill_point < 0) - sd->status.skill_point = 0; - clif_updatestatus (sd, SP_SKILLPOINT); - } // to add: remove status points from skills - pc_calcstatus (sd, 0); - clif_displaymessage (fd, msg_table[25]); // Job level lowered. - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_help (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char buf[2048], w1[2048], w2[2048]; - int i, gm_level; - FILE *fp; - - memset (buf, '\0', sizeof (buf)); - - if ((fp = fopen_ (help_txt, "r")) != NULL) - { - clif_displaymessage (fd, msg_table[26]); // Help commands: - gm_level = pc_isGM (sd); - while (fgets (buf, sizeof (buf) - 1, fp) != NULL) - { - if (buf[0] == '/' && buf[1] == '/') - continue; - for (i = 0; buf[i] != '\0'; i++) - { - if (buf[i] == '\r' || buf[i] == '\n') - { - buf[i] = '\0'; - break; - } - } - if (sscanf (buf, "%2047[^:]:%2047[^\n]", w1, w2) < 2) - clif_displaymessage (fd, buf); - else if (gm_level >= atoi (w1)) - clif_displaymessage (fd, w2); - } - fclose_ (fp); - } - else - { - clif_displaymessage (fd, msg_table[27]); // File help.txt not found. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_gm (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char password[100]; - - memset (password, '\0', sizeof (password)); - - if (!message || !*message || sscanf (message, "%99[^\n]", password) < 1) - { - clif_displaymessage (fd, - "Please, enter a password (usage: @gm )."); - return -1; - } - - if (pc_isGM (sd)) - { // a GM can not use this function. only a normal player (become gm is not for gm!) - clif_displaymessage (fd, msg_table[50]); // You already have some GM powers. - return -1; - } - else - chrif_changegm (sd->status.account_id, password, - strlen (password) + 1); - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_pvpoff (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - struct map_session_data *pl_sd; - int i; - - if (battle_config.pk_mode) - { //disable command if server is in PK mode [Valaris] - clif_displaymessage (fd, msg_table[52]); // This option cannot be used in PK Mode. - return -1; - } - - if (map[sd->bl.m].flag.pvp) - { - map[sd->bl.m].flag.pvp = 0; - clif_send0199 (sd->bl.m, 0); - for (i = 0; i < fd_max; i++) - { //人数分ループ - if (session[i] && (pl_sd = (struct map_session_data *)session[i]->session_data) - && pl_sd->state.auth) - { - if (sd->bl.m == pl_sd->bl.m) - { - clif_pvpset (pl_sd, 0, 0, 2); - if (pl_sd->pvp_timer != -1) - { - delete_timer (pl_sd->pvp_timer, - pc_calc_pvprank_timer); - pl_sd->pvp_timer = -1; - } - } - } - } - clif_displaymessage (fd, msg_table[31]); // PvP: Off. - } - else - { - clif_displaymessage (fd, msg_table[160]); // PvP is already Off. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_pvpon (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - struct map_session_data *pl_sd; - int i; - - if (battle_config.pk_mode) - { //disable command if server is in PK mode [Valaris] - clif_displaymessage (fd, msg_table[52]); // This option cannot be used in PK Mode. - return -1; - } - - if (!map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.nopvp) - { - map[sd->bl.m].flag.pvp = 1; - clif_send0199 (sd->bl.m, 1); - for (i = 0; i < fd_max; i++) - { - if (session[i] && (pl_sd = (struct map_session_data *)session[i]->session_data) - && pl_sd->state.auth) - { - if (sd->bl.m == pl_sd->bl.m && pl_sd->pvp_timer == -1) - { - pl_sd->pvp_timer = add_timer (gettick () + 200, - pc_calc_pvprank_timer, - pl_sd->bl.id, 0); - pl_sd->pvp_rank = 0; - pl_sd->pvp_lastusers = 0; - pl_sd->pvp_point = 5; - } - } - } - clif_displaymessage (fd, msg_table[32]); // PvP: On. - } - else - { - clif_displaymessage (fd, msg_table[161]); // PvP is already On. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_gvgoff (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - if (map[sd->bl.m].flag.gvg) - { - map[sd->bl.m].flag.gvg = 0; - clif_send0199 (sd->bl.m, 0); - clif_displaymessage (fd, msg_table[33]); // GvG: Off. - } - else - { - clif_displaymessage (fd, msg_table[162]); // GvG is already Off. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_gvgon (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - if (!map[sd->bl.m].flag.gvg) - { - map[sd->bl.m].flag.gvg = 1; - clif_send0199 (sd->bl.m, 3); - clif_displaymessage (fd, msg_table[34]); // GvG: On. - } - else - { - clif_displaymessage (fd, msg_table[163]); // GvG is already On. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_model (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - int hair_style = 0, hair_color = 0, cloth_color = 0; - char output[200]; - - memset (output, '\0', sizeof (output)); - - if (!message || !*message - || sscanf (message, "%d %d %d", &hair_style, &hair_color, - &cloth_color) < 1) - { - sprintf (output, - "Please, enter at least a value (usage: @model ).", - MIN_HAIR_STYLE, MAX_HAIR_STYLE, MIN_HAIR_COLOR, - MAX_HAIR_COLOR, MIN_CLOTH_COLOR, MAX_CLOTH_COLOR); - clif_displaymessage (fd, output); - return -1; - } - - if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE && - hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR && - cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) - { - //服の色変更 - if (cloth_color != 0 && sd->status.sex == 1 - && (sd->status.pc_class == 12 || sd->status.pc_class == 17)) - { - //服の色未実装職の判定 - clif_displaymessage (fd, msg_table[35]); // You can't use this command with this class. - return -1; - } - else - { - pc_changelook (sd, LOOK_HAIR, hair_style); - pc_changelook (sd, LOOK_HAIR_COLOR, hair_color); - pc_changelook (sd, LOOK_CLOTHES_COLOR, cloth_color); - clif_displaymessage (fd, msg_table[36]); // Appearence changed. - } - } - else - { - clif_displaymessage (fd, msg_table[37]); // An invalid number was specified. - return -1; - } - - return 0; -} - -/*========================================== - * @dye && @ccolor - *------------------------------------------ - */ -int atcommand_dye (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - int cloth_color = 0; - char output[200]; - - memset (output, '\0', sizeof (output)); - - if (!message || !*message || sscanf (message, "%d", &cloth_color) < 1) - { - sprintf (output, - "Please, enter a clothes color (usage: @dye/@ccolor ).", - MIN_CLOTH_COLOR, MAX_CLOTH_COLOR); - clif_displaymessage (fd, output); - return -1; - } - - if (cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) - { - if (cloth_color != 0 && sd->status.sex == 1 - && (sd->status.pc_class == 12 || sd->status.pc_class == 17)) - { - clif_displaymessage (fd, msg_table[35]); // You can't use this command with this class. - return -1; - } - else - { - pc_changelook (sd, LOOK_CLOTHES_COLOR, cloth_color); - clif_displaymessage (fd, msg_table[36]); // Appearence changed. - } - } - else - { - clif_displaymessage (fd, msg_table[37]); // An invalid number was specified. - return -1; - } - - return 0; -} - -/*========================================== - * @chardye by [MouseJstr] - *------------------------------------------ - */ -int -atcommand_chardye (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - return 0; -} - -/*========================================== - * @hairstyle && @hstyle - *------------------------------------------ - */ -int atcommand_hair_style (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - int hair_style = 0; - char output[200]; - - memset (output, '\0', sizeof (output)); - - if (!message || !*message || sscanf (message, "%d", &hair_style) < 1) - { - sprintf (output, - "Please, enter a hair style (usage: @hairstyle/@hstyle ).", - MIN_HAIR_STYLE, MAX_HAIR_STYLE); - clif_displaymessage (fd, output); - return -1; - } - - if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE) - { - if (hair_style != 0 && sd->status.sex == 1 - && (sd->status.pc_class == 12 || sd->status.pc_class == 17)) - { - clif_displaymessage (fd, msg_table[35]); // You can't use this command with this class. - return -1; - } - else - { - pc_changelook (sd, LOOK_HAIR, hair_style); - clif_displaymessage (fd, msg_table[36]); // Appearence changed. - } - } - else - { - clif_displaymessage (fd, msg_table[37]); // An invalid number was specified. - return -1; - } - - return 0; -} - -/*========================================== - * @charhairstyle by [MouseJstr] - *------------------------------------------ - */ -int -atcommand_charhairstyle (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - return 0; -} - -/*========================================== - * @haircolor && @hcolor - *------------------------------------------ - */ -int atcommand_hair_color (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - int hair_color = 0; - char output[200]; - - memset (output, '\0', sizeof (output)); - - if (!message || !*message || sscanf (message, "%d", &hair_color) < 1) - { - sprintf (output, - "Please, enter a hair color (usage: @haircolor/@hcolor ).", - MIN_HAIR_COLOR, MAX_HAIR_COLOR); - clif_displaymessage (fd, output); - return -1; - } - - if (hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR) - { - if (hair_color != 0 && sd->status.sex == 1 - && (sd->status.pc_class == 12 || sd->status.pc_class == 17)) - { - clif_displaymessage (fd, msg_table[35]); // You can't use this command with this class. - return -1; - } - else - { - pc_changelook (sd, LOOK_HAIR_COLOR, hair_color); - clif_displaymessage (fd, msg_table[36]); // Appearence changed. - } - } - else - { - clif_displaymessage (fd, msg_table[37]); // An invalid number was specified. - return -1; - } - - return 0; -} - -/*========================================== - * @charhaircolor by [MouseJstr] - *------------------------------------------ - */ -int -atcommand_charhaircolor (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - return 0; -} - -/*========================================== - * @go [city_number/city_name]: improved by [yor] to add city names and help - *------------------------------------------ - */ -int atcommand_go (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - int i; - int town; - char map_name[100]; - char output[200]; - int m; - - struct - { - char map[16]; - int x, y; - } data[] = - { - { - "prontera.gat", 156, 191}, // 0=Prontera - { - "morocc.gat", 156, 93}, // 1=Morroc - { - "geffen.gat", 119, 59}, // 2=Geffen - { - "payon.gat", 162, 233}, // 3=Payon - { - "alberta.gat", 192, 147}, // 4=Alberta - { - "izlude.gat", 128, 114}, // 5=Izlude - { - "aldebaran.gat", 140, 131}, // 6=Al de Baran - { - "xmas.gat", 147, 134}, // 7=Lutie - { - "comodo.gat", 209, 143}, // 8=Comodo - { - "yuno.gat", 157, 51}, // 9=Yuno - { - "amatsu.gat", 198, 84}, // 10=Amatsu - { - "gonryun.gat", 160, 120}, // 11=Gon Ryun - { - "umbala.gat", 89, 157}, // 12=Umbala - { - "niflheim.gat", 21, 153}, // 13=Niflheim - { - "louyang.gat", 217, 40}, // 14=Lou Yang - { - "new_1-1.gat", 53, 111}, // 15=Start point - { - "sec_pri.gat", 23, 61}, // 16=Prison - }; - - memset (map_name, '\0', sizeof (map_name)); - memset (output, '\0', sizeof (output)); - - // get the number - town = atoi (message); - - // if no value, display all value - if (!message || !*message || sscanf (message, "%99s", map_name) < 1 - || town < -3 || town >= (int) (sizeof (data) / sizeof (data[0]))) - { - clif_displaymessage (fd, msg_table[38]); // Invalid location number or name. - clif_displaymessage (fd, msg_table[82]); // Please, use one of this number/name: - clif_displaymessage (fd, - "-3=(Memo point 2) 4=Alberta 11=Gon Ryun"); - clif_displaymessage (fd, - "-2=(Memo point 1) 5=Izlude 12=Umbala"); - clif_displaymessage (fd, - "-1=(Memo point 0) 6=Al de Baran 13=Niflheim"); - clif_displaymessage (fd, - " 0=Prontera 7=Lutie 14=Lou Yang"); - clif_displaymessage (fd, - " 1=Morroc 8=Comodo 15=Start point"); - clif_displaymessage (fd, - " 2=Geffen 9=Yuno 16=Prison"); - clif_displaymessage (fd, " 3=Payon 10=Amatsu"); - return -1; - } - else - { - // get possible name of the city and add .gat if not in the name - map_name[sizeof (map_name) - 1] = '\0'; - for (i = 0; map_name[i]; i++) - map_name[i] = tolower (map_name[i]); - if (strstr (map_name, ".gat") == NULL && strstr (map_name, ".afm") == NULL && strlen (map_name) < 13) // 16 - 4 (.gat) - strcat (map_name, ".gat"); - // try to see if it's a name, and not a number (try a lot of possibilities, write errors and abbreviations too) - if (strncmp (map_name, "prontera.gat", 3) == 0) - { // 3 first characters - town = 0; - } - else if (strncmp (map_name, "morocc.gat", 3) == 0) - { // 3 first characters - town = 1; - } - else if (strncmp (map_name, "geffen.gat", 3) == 0) - { // 3 first characters - town = 2; - } - else if (strncmp (map_name, "payon.gat", 3) == 0 || // 3 first characters - strncmp (map_name, "paion.gat", 3) == 0) - { // writing error (3 first characters) - town = 3; - } - else if (strncmp (map_name, "alberta.gat", 3) == 0) - { // 3 first characters - town = 4; - } - else if (strncmp (map_name, "izlude.gat", 3) == 0 || // 3 first characters - strncmp (map_name, "islude.gat", 3) == 0) - { // writing error (3 first characters) - town = 5; - } - else if (strncmp (map_name, "aldebaran.gat", 3) == 0 || // 3 first characters - strcmp (map_name, "al.gat") == 0) - { // al (de baran) - town = 6; - } - else if (strncmp (map_name, "lutie.gat", 3) == 0 || // name of the city, not name of the map (3 first characters) - strcmp (map_name, "christmas.gat") == 0 || // name of the symbol - strncmp (map_name, "xmas.gat", 3) == 0 || // 3 first characters - strncmp (map_name, "x-mas.gat", 3) == 0) - { // writing error (3 first characters) - town = 7; - } - else if (strncmp (map_name, "comodo.gat", 3) == 0) - { // 3 first characters - town = 8; - } - else if (strncmp (map_name, "yuno.gat", 3) == 0) - { // 3 first characters - town = 9; - } - else if (strncmp (map_name, "amatsu.gat", 3) == 0 || // 3 first characters - strncmp (map_name, "ammatsu.gat", 3) == 0) - { // writing error (3 first characters) - town = 10; - } - else if (strncmp (map_name, "gonryun.gat", 3) == 0) - { // 3 first characters - town = 11; - } - else if (strncmp (map_name, "umbala.gat", 3) == 0) - { // 3 first characters - town = 12; - } - else if (strncmp (map_name, "niflheim.gat", 3) == 0) - { // 3 first characters - town = 13; - } - else if (strncmp (map_name, "louyang.gat", 3) == 0) - { // 3 first characters - town = 14; - } - else if (strncmp (map_name, "new_1-1.gat", 3) == 0 || // 3 first characters (or "newbies") - strncmp (map_name, "startpoint.gat", 3) == 0 || // name of the position (3 first characters) - strncmp (map_name, "begining.gat", 3) == 0) - { // name of the position (3 first characters) - town = 15; - } - else if (strncmp (map_name, "sec_pri.gat", 3) == 0 || // 3 first characters - strncmp (map_name, "prison.gat", 3) == 0 || // name of the position (3 first characters) - strncmp (map_name, "jails.gat", 3) == 0) - { // name of the position - town = 16; - } - - if (town >= -3 && town <= -1) - { - if (sd->status.memo_point[-town - 1].map[0]) - { - m = map_mapname2mapid (sd->status.memo_point[-town - 1].map); - if (m >= 0 && map[m].flag.nowarpto - && battle_config.any_warp_GM_min_level > pc_isGM (sd)) - { - clif_displaymessage (fd, - "You are not authorised to warp you to this memo map."); - return -1; - } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp - && battle_config.any_warp_GM_min_level > pc_isGM (sd)) - { - clif_displaymessage (fd, - "You are not authorised to warp you from your actual map."); - return -1; - } - if (pc_setpos - (sd, sd->status.memo_point[-town - 1].map, - sd->status.memo_point[-town - 1].x, - sd->status.memo_point[-town - 1].y, 3) == 0) - { - clif_displaymessage (fd, msg_table[0]); // Warped. - } - else - { - clif_displaymessage (fd, msg_table[1]); // Map not found. - return -1; - } - } - else - { - sprintf (output, msg_table[164], -town - 1); // Your memo point #%d doesn't exist. - clif_displaymessage (fd, output); - return -1; - } - } - else if (town >= 0 && town < (int) (sizeof (data) / sizeof (data[0]))) - { - m = map_mapname2mapid (data[town].map); - if (m >= 0 && map[m].flag.nowarpto - && battle_config.any_warp_GM_min_level > pc_isGM (sd)) - { - clif_displaymessage (fd, - "You are not authorised to warp you to this destination map."); - return -1; - } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp - && battle_config.any_warp_GM_min_level > pc_isGM (sd)) - { - clif_displaymessage (fd, - "You are not authorised to warp you from your actual map."); - return -1; - } - if (pc_setpos (sd, data[town].map, data[town].x, data[town].y, 3) - == 0) - { - clif_displaymessage (fd, msg_table[0]); // Warped. - } - else - { - clif_displaymessage (fd, msg_table[1]); // Map not found. - return -1; - } - } - else - { // if you arrive here, you have an error in town variable when reading of names - clif_displaymessage (fd, msg_table[38]); // Invalid location number or name. - return -1; - } - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_spawn (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char monster[100]; - char output[200]; - int mob_id; - int number = 0; - int x = 0, y = 0; - int count; - int i, j, k; - int mx, my, range; - - memset (monster, '\0', sizeof (monster)); - memset (output, '\0', sizeof (output)); - - if (!message || !*message - || sscanf (message, "%99s %d %d %d", monster, &number, &x, &y) < 1) - { - clif_displaymessage (fd, msg_table[143]); // Give a monster name/id please. - return -1; - } - - // If monster identifier/name argument is a name - if ((mob_id = mobdb_searchname (monster)) == 0) // check name first (to avoid possible name begining by a number) - mob_id = mobdb_checkid (atoi (monster)); - - if (mob_id == 0) - { - clif_displaymessage (fd, msg_table[40]); // Invalid monster ID or name. - return -1; - } - - if (mob_id == 1288) - { - clif_displaymessage (fd, msg_table[83]); // Cannot spawn emperium. - return -1; - } - - if (number <= 0) - number = 1; - - // If value of atcommand_spawn_quantity_limit directive is greater than or equal to 1 and quantity of monsters is greater than value of the directive - if (battle_config.atc_spawn_quantity_limit >= 1 - && number > battle_config.atc_spawn_quantity_limit) - number = battle_config.atc_spawn_quantity_limit; - - if (battle_config.etc_log) - printf ("%s monster='%s' id=%d count=%d (%d,%d)\n", command, monster, - mob_id, number, x, y); - - count = 0; - range = sqrt (number) / 2; - range = range * 2 + 5; // calculation of an odd number (+ 4 area around) - for (i = 0; i < number; i++) - { - j = 0; - k = 0; - while (j++ < 8 && k == 0) - { // try 8 times to spawn the monster (needed for close area) - if (x <= 0) - mx = sd->bl.x + (MRAND (range) - (range / 2)); - else - mx = x; - if (y <= 0) - my = sd->bl.y + (MRAND (range) - (range / 2)); - else - my = y; - k = mob_once_spawn ((struct map_session_data *) sd, "this", mx, - my, "", mob_id, 1, ""); - } - count += (k != 0) ? 1 : 0; - } - - if (count != 0) - if (number == count) - clif_displaymessage (fd, msg_table[39]); // All monster summoned! - else - { - sprintf (output, msg_table[240], count); // %d monster(s) summoned! - clif_displaymessage (fd, output); - } - else - { - clif_displaymessage (fd, msg_table[40]); // Invalid monster ID or name. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -void atcommand_killmonster_sub (const int fd, struct map_session_data *sd, - const char *message, const int drop) -{ - int map_id; - char map_name[100]; - - memset (map_name, '\0', sizeof (map_name)); - - if (!message || !*message || sscanf (message, "%99s", map_name) < 1) - map_id = sd->bl.m; - else - { - if (strstr (map_name, ".gat") == NULL && strstr (map_name, ".afm") == NULL && strlen (map_name) < 13) // 16 - 4 (.gat) - strcat (map_name, ".gat"); - if ((map_id = map_mapname2mapid (map_name)) < 0) - map_id = sd->bl.m; - } - - map_foreachinarea (atkillmonster_sub, map_id, 0, 0, map[map_id].xs, - map[map_id].ys, BL_MOB, drop); - - clif_displaymessage (fd, msg_table[165]); // All monsters killed! - - return; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_killmonster (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - atcommand_killmonster_sub (fd, sd, message, 1); - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -static int atlist_nearby_sub (struct block_list *bl, va_list ap) -{ - char buf[32]; - int fd = va_arg (ap, int); - nullpo_retr (0, bl); - - sprintf (buf, " - \"%s\"", ((struct map_session_data *) bl)->status.name); - clif_displaymessage (fd, buf); - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_list_nearby (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - clif_displaymessage (fd, "Nearby players:"); - map_foreachinarea (atlist_nearby_sub, sd->bl.m, sd->bl.x - 1, - sd->bl.y - 1, sd->bl.x + 1, sd->bl.x + 1, BL_PC, fd); - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_killmonster2 (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - atcommand_killmonster_sub (fd, sd, message, 0); - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_produce (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char item_name[100]; - int item_id, attribute = 0, star = 0; - int flag = 0; - struct item_data *item_data; - struct item tmp_item; - char output[200]; - - memset (output, '\0', sizeof (output)); - memset (item_name, '\0', sizeof (item_name)); - - if (!message || !*message - || sscanf (message, "%99s %d %d", item_name, &attribute, &star) < 1) - { - clif_displaymessage (fd, - "Please, enter at least an item name/id (usage: @produce <# of very's>)."); - return -1; - } - - item_id = 0; - if ((item_data = itemdb_searchname (item_name)) != NULL || - (item_data = itemdb_exists (atoi (item_name))) != NULL) - item_id = item_data->nameid; - - if (itemdb_exists (item_id) && - (item_id <= 500 || item_id > 1099) && - (item_id < 4001 || item_id > 4148) && - (item_id < 7001 || item_id > 10019) && itemdb_isequip (item_id)) - { - if (attribute < MIN_ATTRIBUTE || attribute > MAX_ATTRIBUTE) - attribute = ATTRIBUTE_NORMAL; - if (star < MIN_STAR || star > MAX_STAR) - star = 0; - memset (&tmp_item, 0, sizeof tmp_item); - tmp_item.nameid = item_id; - tmp_item.amount = 1; - tmp_item.identify = 1; - tmp_item.card[0] = 0x00ff; - tmp_item.card[1] = ((star * 5) << 8) + attribute; - *((unsigned long *) (&tmp_item.card[2])) = sd->char_id; - clif_produceeffect (sd, 0, item_id); // 製造エフェクトパケット - clif_misceffect (&sd->bl, 3); // 他人にも成功を通知 - if ((flag = pc_additem (sd, &tmp_item, 1))) - clif_additem (sd, 0, 0, flag); - } - else - { - if (battle_config.error_log) - printf ("@produce NOT WEAPON [%d]\n", item_id); - if (item_id != 0 && itemdb_exists (item_id)) - sprintf (output, msg_table[169], item_id, item_data->name); // This item (%d: '%s') is not an equipment. - else - sprintf (output, "%s", msg_table[170]); // This item is not an equipment. - clif_displaymessage (fd, output); - return -1; - } - - return 0; -} - -/*========================================== - * Sub-function to display actual memo points - *------------------------------------------ - */ -void atcommand_memo_sub (struct map_session_data *sd) -{ - int i; - char output[200]; - - memset (output, '\0', sizeof (output)); - - clif_displaymessage (sd->fd, - "Your actual memo positions are (except respawn point):"); - for (i = MIN_PORTAL_MEMO; i <= MAX_PORTAL_MEMO; i++) - { - if (sd->status.memo_point[i].map[0]) - sprintf (output, "%d - %s (%d,%d)", i, - sd->status.memo_point[i].map, sd->status.memo_point[i].x, - sd->status.memo_point[i].y); - else - sprintf (output, msg_table[171], i); // %d - void - clif_displaymessage (sd->fd, output); - } - - return; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_memo (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - int position = 0; - char output[200]; - - memset (output, '\0', sizeof (output)); - - if (!message || !*message || sscanf (message, "%d", &position) < 1) - atcommand_memo_sub (sd); - else - { - if (position >= MIN_PORTAL_MEMO && position <= MAX_PORTAL_MEMO) - { - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto - && battle_config.any_warp_GM_min_level > pc_isGM (sd)) - { - clif_displaymessage (fd, - "You are not authorised to memo this map."); - return -1; - } - if (sd->status.memo_point[position].map[0]) - { - sprintf (output, msg_table[172], position, sd->status.memo_point[position].map, sd->status.memo_point[position].x, sd->status.memo_point[position].y); // You replace previous memo position %d - %s (%d,%d). - clif_displaymessage (fd, output); - } - memcpy (sd->status.memo_point[position].map, map[sd->bl.m].name, - 24); - sd->status.memo_point[position].x = sd->bl.x; - sd->status.memo_point[position].y = sd->bl.y; - clif_skill_memo (sd, 0); - if (pc_checkskill (sd, AL_WARP) <= (position + 1)) - clif_displaymessage (fd, msg_table[173]); // Note: you don't have the 'Warp' skill level to use it. - atcommand_memo_sub (sd); - } - else - { - sprintf (output, - "Please, enter a valid position (usage: @memo ).", - MIN_PORTAL_MEMO, MAX_PORTAL_MEMO); - clif_displaymessage (fd, output); - atcommand_memo_sub (sd); - return -1; - } - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_gat (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char output[200]; - int y; - - memset (output, '\0', sizeof (output)); - - for (y = 2; y >= -2; y--) - { - sprintf (output, "%s (x= %d, y= %d) %02X %02X %02X %02X %02X", - map[sd->bl.m].name, sd->bl.x - 2, sd->bl.y + y, - map_getcell (sd->bl.m, sd->bl.x - 2, sd->bl.y + y), - map_getcell (sd->bl.m, sd->bl.x - 1, sd->bl.y + y), - map_getcell (sd->bl.m, sd->bl.x, sd->bl.y + y), - map_getcell (sd->bl.m, sd->bl.x + 1, sd->bl.y + y), - map_getcell (sd->bl.m, sd->bl.x + 2, sd->bl.y + y)); - clif_displaymessage (fd, output); - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_packet (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - int x = 0, y = 0; - - if (!message || !*message || sscanf (message, "%d %d", &x, &y) < 2) - { - clif_displaymessage (fd, - "Please, enter a status type/flag (usage: @packet )."); - return -1; - } - - clif_status_change (&sd->bl, x, y); - - return 0; -} - -/*========================================== - * @stpoint (Rewritten by [Yor]) - *------------------------------------------ - */ -int atcommand_statuspoint (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - int point, new_status_point; - - if (!message || !*message || (point = atoi (message)) == 0) - { - clif_displaymessage (fd, - "Please, enter a number (usage: @stpoint )."); - return -1; - } - - new_status_point = (int) sd->status.status_point + point; - if (point > 0 && (point > 0x7FFF || new_status_point > 0x7FFF)) // fix positiv overflow - new_status_point = 0x7FFF; - else if (point < 0 && (point < -0x7FFF || new_status_point < 0)) // fix negativ overflow - new_status_point = 0; - - if (new_status_point != (int) sd->status.status_point) - { - sd->status.status_point = (short) new_status_point; - clif_updatestatus (sd, SP_STATUSPOINT); - clif_displaymessage (fd, msg_table[174]); // Number of status points changed! - } - else - { - if (point < 0) - clif_displaymessage (fd, msg_table[41]); // Impossible to decrease the number/value. - else - clif_displaymessage (fd, msg_table[149]); // Impossible to increase the number/value. - return -1; - } - - return 0; -} - -/*========================================== - * @skpoint (Rewritten by [Yor]) - *------------------------------------------ - */ -int atcommand_skillpoint (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - int point, new_skill_point; - - if (!message || !*message || (point = atoi (message)) == 0) - { - clif_displaymessage (fd, - "Please, enter a number (usage: @skpoint )."); - return -1; - } - - new_skill_point = (int) sd->status.skill_point + point; - if (point > 0 && (point > 0x7FFF || new_skill_point > 0x7FFF)) // fix positiv overflow - new_skill_point = 0x7FFF; - else if (point < 0 && (point < -0x7FFF || new_skill_point < 0)) // fix negativ overflow - new_skill_point = 0; - - if (new_skill_point != (int) sd->status.skill_point) - { - sd->status.skill_point = (short) new_skill_point; - clif_updatestatus (sd, SP_SKILLPOINT); - clif_displaymessage (fd, msg_table[175]); // Number of skill points changed! - } - else - { - if (point < 0) - clif_displaymessage (fd, msg_table[41]); // Impossible to decrease the number/value. - else - clif_displaymessage (fd, msg_table[149]); // Impossible to increase the number/value. - return -1; - } - - return 0; -} - -/*========================================== - * @zeny (Rewritten by [Yor]) - *------------------------------------------ - */ -int atcommand_zeny (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - int zeny, new_zeny; - - if (!message || !*message || (zeny = atoi (message)) == 0) - { - clif_displaymessage (fd, - "Please, enter an amount (usage: @zeny )."); - return -1; - } - - new_zeny = sd->status.zeny + zeny; - if (zeny > 0 && (zeny > MAX_ZENY || new_zeny > MAX_ZENY)) // fix positiv overflow - new_zeny = MAX_ZENY; - else if (zeny < 0 && (zeny < -MAX_ZENY || new_zeny < 0)) // fix negativ overflow - new_zeny = 0; - - if (new_zeny != sd->status.zeny) - { - sd->status.zeny = new_zeny; - clif_updatestatus (sd, SP_ZENY); - clif_displaymessage (fd, msg_table[176]); // Number of zenys changed! - } - else - { - if (zeny < 0) - clif_displaymessage (fd, msg_table[41]); // Impossible to decrease the number/value. - else - clif_displaymessage (fd, msg_table[149]); // Impossible to increase the number/value. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_param (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - int i, index, value = 0, new_value; - const char *param[] = - { "@str", "@agi", "@vit", "@int", "@dex", "@luk", NULL }; - short *status[] = { - &sd->status.str, &sd->status.agi, &sd->status.vit, - &sd->status.int_, &sd->status.dex, &sd->status.luk - }; - char output[200]; - - memset (output, '\0', sizeof (output)); - - if (!message || !*message || sscanf (message, "%d", &value) < 1 - || value == 0) - { - sprintf (output, - "Please, enter a valid value (usage: @str,@agi,@vit,@int,@dex,@luk <+/-adjustement>)."); - clif_displaymessage (fd, output); - return -1; - } - - index = -1; - for (i = 0; param[i] != NULL; i++) - { - if (strcasecmp (command, param[i]) == 0) - { - index = i; - break; - } - } - if (index < 0 || index > MAX_STATUS_TYPE) - { // normaly impossible... - sprintf (output, - "Please, enter a valid value (usage: @str,@agi,@vit,@int,@dex,@luk <+/-adjustement>)."); - clif_displaymessage (fd, output); - return -1; - } - - new_value = (int) *status[index] + value; - if (value > 0 && (value > battle_config.max_parameter || new_value > battle_config.max_parameter)) // fix positiv overflow - new_value = battle_config.max_parameter; - else if (value < 0 && (value < -battle_config.max_parameter || new_value < 1)) // fix negativ overflow - new_value = 1; - - if (new_value != (int) *status[index]) - { - *status[index] = new_value; - clif_updatestatus (sd, SP_STR + index); - clif_updatestatus (sd, SP_USTR + index); - pc_calcstatus (sd, 0); - clif_displaymessage (fd, msg_table[42]); // Stat changed. - } - else - { - if (value < 0) - clif_displaymessage (fd, msg_table[41]); // Impossible to decrease the number/value. - else - clif_displaymessage (fd, msg_table[149]); // Impossible to increase the number/value. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -//** Stat all by fritz (rewritten by [Yor]) -int atcommand_all_stats (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - int index, count, value = 0, new_value; - short *status[] = { - &sd->status.str, &sd->status.agi, &sd->status.vit, - &sd->status.int_, &sd->status.dex, &sd->status.luk - }; - - if (!message || !*message || sscanf (message, "%d", &value) < 1 - || value == 0) - value = battle_config.max_parameter; - - count = 0; - for (index = 0; index < (int) (sizeof (status) / sizeof (status[0])); - index++) - { - - new_value = (int) *status[index] + value; - if (value > 0 && (value > battle_config.max_parameter || new_value > battle_config.max_parameter)) // fix positiv overflow - new_value = battle_config.max_parameter; - else if (value < 0 && (value < -battle_config.max_parameter || new_value < 1)) // fix negativ overflow - new_value = 1; - - if (new_value != (int) *status[index]) - { - *status[index] = new_value; - clif_updatestatus (sd, SP_STR + index); - clif_updatestatus (sd, SP_USTR + index); - pc_calcstatus (sd, 0); - count++; - } - } - - if (count > 0) // if at least 1 stat modified - clif_displaymessage (fd, msg_table[84]); // All stats changed! - else - { - if (value < 0) - clif_displaymessage (fd, msg_table[177]); // Impossible to decrease a stat. - else - clif_displaymessage (fd, msg_table[178]); // Impossible to increase a stat. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_guildlevelup (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - int level = 0; - short added_level; - struct guild *guild_info; - - if (!message || !*message || sscanf (message, "%d", &level) < 1 - || level == 0) - { - clif_displaymessage (fd, - "Please, enter a valid level (usage: @guildlvl <# of levels>)."); - return -1; - } - - if (sd->status.guild_id <= 0 - || (guild_info = guild_search (sd->status.guild_id)) == NULL) - { - clif_displaymessage (fd, msg_table[43]); // You're not in a guild. - return -1; - } - if (strcmp (sd->status.name, guild_info->master) != 0) - { - clif_displaymessage (fd, msg_table[44]); // You're not the master of your guild. - return -1; - } - - added_level = (short) level; - if (level > 0 && (level > MAX_GUILDLEVEL || added_level > ((short) MAX_GUILDLEVEL - guild_info->guild_lv))) // fix positiv overflow - added_level = (short) MAX_GUILDLEVEL - guild_info->guild_lv; - else if (level < 0 && (level < -MAX_GUILDLEVEL || added_level < (1 - guild_info->guild_lv))) // fix negativ overflow - added_level = 1 - guild_info->guild_lv; - - if (added_level != 0) - { - intif_guild_change_basicinfo (guild_info->guild_id, GBI_GUILDLV, - &added_level, 2); - clif_displaymessage (fd, msg_table[179]); // Guild level changed. - } - else - { - clif_displaymessage (fd, msg_table[45]); // Guild level change failed. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_recall (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char character[100]; - char output[200]; - struct map_session_data *pl_sd; - - memset (character, '\0', sizeof (character)); - memset (output, '\0', sizeof (output)); - - if (!message || !*message || sscanf (message, "%99[^\n]", character) < 1) - { - clif_displaymessage (fd, - "Please, enter a player name (usage: @recall )."); - return -1; - } - - if ((pl_sd = map_nick2sd (character)) != NULL) - { - if (pc_isGM (sd) >= pc_isGM (pl_sd)) - { // you can recall only lower or same level - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto - && battle_config.any_warp_GM_min_level > pc_isGM (sd)) - { - clif_displaymessage (fd, - "You are not authorised to warp somenone to your actual map."); - return -1; - } - if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp - && battle_config.any_warp_GM_min_level > pc_isGM (sd)) - { - clif_displaymessage (fd, - "You are not authorised to warp this player from its actual map."); - return -1; - } - pc_setpos (pl_sd, sd->mapname, sd->bl.x, sd->bl.y, 2); - sprintf (output, msg_table[46], character); // %s recalled! - clif_displaymessage (fd, output); - } - else - { - clif_displaymessage (fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player. - return -1; - } - } - else - { - clif_displaymessage (fd, msg_table[3]); // Character not found. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_revive (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char character[100]; - struct map_session_data *pl_sd; - - memset (character, '\0', sizeof (character)); - - if (!message || !*message || sscanf (message, "%99[^\n]", character) < 1) - { - clif_displaymessage (fd, - "Please, enter a player name (usage: @revive )."); - return -1; - } - - if ((pl_sd = map_nick2sd (character)) != NULL) - { - pl_sd->status.hp = pl_sd->status.max_hp; - pc_setstand (pl_sd); - if (battle_config.pc_invincible_time > 0) - pc_setinvincibletimer (sd, battle_config.pc_invincible_time); - clif_updatestatus (pl_sd, SP_HP); - clif_updatestatus (pl_sd, SP_SP); - clif_resurrection (&pl_sd->bl, 1); - clif_displaymessage (fd, msg_table[51]); // Character revived. - } - else - { - clif_displaymessage (fd, msg_table[3]); // Character not found. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_character_stats (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char character[100]; - char job_jobname[100]; - char output[200]; - struct map_session_data *pl_sd; - int i; - - memset (character, '\0', sizeof (character)); - memset (job_jobname, '\0', sizeof (job_jobname)); - memset (output, '\0', sizeof (output)); - - if (!message || !*message || sscanf (message, "%99[^\n]", character) < 1) - { - clif_displaymessage (fd, - "Please, enter a player name (usage: @charstats )."); - return -1; - } - - if ((pl_sd = map_nick2sd (character)) != NULL) - { - struct - { - const char *format; - int value; - } output_table[] = - { - { - "Base Level - %d", pl_sd->status.base_level}, - { - job_jobname, pl_sd->status.job_level}, - { - "Hp - %d", pl_sd->status.hp}, - { - "MaxHp - %d", pl_sd->status.max_hp}, - { - "Sp - %d", pl_sd->status.sp}, - { - "MaxSp - %d", pl_sd->status.max_sp}, - { - "Str - %3d", pl_sd->status.str}, - { - "Agi - %3d", pl_sd->status.agi}, - { - "Vit - %3d", pl_sd->status.vit}, - { - "Int - %3d", pl_sd->status.int_}, - { - "Dex - %3d", pl_sd->status.dex}, - { - "Luk - %3d", pl_sd->status.luk}, - { - "Zeny - %d", pl_sd->status.zeny}, - { - NULL, 0} - }; - sprintf (job_jobname, "Job - %s %s", job_name (pl_sd->status.pc_class), - "(level %d)"); - sprintf (output, msg_table[53], pl_sd->status.name); // '%s' stats: - clif_displaymessage (fd, output); - for (i = 0; output_table[i].format != NULL; i++) - { - sprintf (output, output_table[i].format, output_table[i].value); - clif_displaymessage (fd, output); - } - } - else - { - clif_displaymessage (fd, msg_table[3]); // Character not found. - return -1; - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -//** Character Stats All by fritz -int atcommand_character_stats_all (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char output[1024], gmlevel[1024]; - int i; - int count; - struct map_session_data *pl_sd; - - memset (output, '\0', sizeof (output)); - memset (gmlevel, '\0', sizeof (gmlevel)); - - count = 0; - for (i = 0; i < fd_max; i++) - { - if (session[i] && (pl_sd = (struct map_session_data *)session[i]->session_data) - && pl_sd->state.auth) - { - - if (pc_isGM (pl_sd) > 0) - sprintf (gmlevel, "| GM Lvl: %d", pc_isGM (pl_sd)); - else - sprintf (gmlevel, " "); - - sprintf (output, - "Name: %s | BLvl: %d | Job: %s (Lvl: %d) | HP: %d/%d | SP: %d/%d", - pl_sd->status.name, pl_sd->status.base_level, - job_name (pl_sd->status.pc_class), pl_sd->status.job_level, - pl_sd->status.hp, pl_sd->status.max_hp, pl_sd->status.sp, - pl_sd->status.max_sp); - clif_displaymessage (fd, output); - sprintf (output, - "STR: %d | AGI: %d | VIT: %d | INT: %d | DEX: %d | LUK: %d | Zeny: %d %s", - pl_sd->status.str, pl_sd->status.agi, pl_sd->status.vit, - pl_sd->status.int_, pl_sd->status.dex, pl_sd->status.luk, - pl_sd->status.zeny, gmlevel); - clif_displaymessage (fd, output); - clif_displaymessage (fd, "--------"); - count++; - } - } - - if (count == 0) - clif_displaymessage (fd, msg_table[28]); // No player found. - else if (count == 1) - clif_displaymessage (fd, msg_table[29]); // 1 player found. - else - { - sprintf (output, msg_table[30], count); // %d players found. - clif_displaymessage (fd, output); - } - - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -int atcommand_character_option (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char character[100]; - int opt1 = 0, opt2 = 0, opt3 = 0; - struct map_session_data *pl_sd; - - memset (character, '\0', sizeof (character)); - - if (!message || !*message - || sscanf (message, "%d %d %d %99[^\n]", &opt1, &opt2, &opt3, - character) < 4 || opt1 < 0 || opt2 < 0 || opt3 < 0) - { - clif_displaymessage (fd, - "Please, enter valid options and a player name (usage: @charoption )."); - return -1; - } - - if ((pl_sd = map_nick2sd (character)) != NULL) - { - if (pc_isGM (sd) >= pc_isGM (pl_sd)) - { // you can change option only to lower or same level - pl_sd->opt1 = opt1; - pl_sd->opt2 = opt2; - pl_sd->status.option = opt3; - // fix pecopeco display - if (pl_sd->status.pc_class == 13 || pl_sd->status.pc_class == 21 - || pl_sd->status.pc_class == 4014 || pl_sd->status.pc_class == 4022) - { - if (!pc_isriding (pl_sd)) - { // pl_sd have the new value... - if (pl_sd->status.pc_class == 13) - pl_sd->status.pc_class = pl_sd->view_class = 7; - else if (pl_sd->status.pc_class == 21) - pl_sd->status.pc_class = pl_sd->view_class = 14; - else if (pl_sd->status.pc_class == 4014) - pl_sd->status.pc_class = pl_sd->view_class = 4008; - else if (pl_sd->status.pc_class == 4022) - pl_sd->status.pc_class = pl_sd->view_class = 4015; - } - } - else - { - if (pc_isriding (pl_sd)) - { // pl_sd have the new value... - if (pl_sd->disguise > 0) - { // temporary prevention of crash caused by peco + disguise, will look into a better solution [Valaris] (code added by [Yor]) - pl_sd->status.option &= ~0x0020; - } - else - { - if (pl_sd->status.pc_class == 7) - pl_sd->status.pc_class = pl_sd->view_class = 13; - else if (pl_sd->status.pc_class == 14) - pl_sd->status.pc_class = pl_sd->view_class = 21; - else if (pl_sd->status.pc_class == 4008) - pl_sd->status.pc_class = pl_sd->view_class = 4014; - else if (pl_sd->status.pc_class == 4015) - pl_sd->status.pc_class = pl_sd->view_class = 4022; - else - pl_sd->status.option &= ~0x0020; - } - } - } - clif_changeoption (&pl_sd->bl); - pc_calcstatus (pl_sd, 0); - clif_displaymessage (fd, msg_table[58]); // Character's options changed. - } - else - { - clif_displaymessage (fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player. - return -1; - } - } - else - { - clif_displaymessage (fd, msg_table[3]); // Character not found. - return -1; - } - - return 0; -} - -/*========================================== - * charchangesex command (usage: charchangesex ) - *------------------------------------------ - */ -int atcommand_char_change_sex (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char character[100]; - - memset (character, '\0', sizeof (character)); - - if (!message || !*message || sscanf (message, "%99[^\n]", character) < 1) - { - clif_displaymessage (fd, - "Please, enter a player name (usage: @charchangesex )."); - return -1; - } - - // check player name - if (strlen (character) < 4) - { - clif_displaymessage (fd, msg_table[86]); // Sorry, but a player name have at least 4 characters. - return -1; - } - else if (strlen (character) > 23) - { - clif_displaymessage (fd, msg_table[87]); // Sorry, but a player name have 23 characters maximum. - return -1; - } - else - { - chrif_char_ask_name (sd->status.account_id, character, 5, 0, 0, 0, 0, 0, 0); // type: 5 - changesex - clif_displaymessage (fd, msg_table[88]); // Character name sends to char-server to ask it. - } - - return 0; -} - -/*========================================== - * charblock command (usage: charblock ) - * This command do a definitiv ban on a player - *------------------------------------------ - */ -int atcommand_char_block (const int fd, struct map_session_data *sd, - const char *command, const char *message) -{ - char character[100]; - - memset (character, '\0', sizeof (character)); - - if (!message || !*message || sscanf (message, "%99[^\n]", character) < 1) - { - clif_displaymessage (fd, - "Please, enter a player name (usage: @block )."); - return -1; - } - - // check player name - if (strlen (character) < 4) - { - clif_displaymessage (fd, msg_table[86]); // Sorry, but a player name have at least 4 characters. - return -1; - } - else if (strlen (character) > 23) - { - clif_displaymessage (fd, msg_table[87]); // Sorry, but a player name have 23 characters maximum. - return -1; - } - else - { - chrif_char_ask_name (sd->status.account_id, character, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block - clif_displaymessage (fd, msg_table[88]); // Character name sends to char-server to ask it. - } - - return 0; -} - -/*========================================== - * charban command (usage: charban