summaryrefslogtreecommitdiff
path: root/src/high
diff options
context:
space:
mode:
authorBen Longbons <b.r.longbons@gmail.com>2014-10-25 15:24:26 -0700
committerBen Longbons <b.r.longbons@gmail.com>2014-10-26 14:21:48 -0700
commit86395f53634b3ef1ce76a7f1e5edfdb61f8ffd80 (patch)
tree2710c62fe71d5e0d2e228fba9c951a040c4dcddf /src/high
parent6800761863dd45b6055768febc6ace6a20120dc7 (diff)
downloadtmwa-86395f53634b3ef1ce76a7f1e5edfdb61f8ffd80.tar.gz
tmwa-86395f53634b3ef1ce76a7f1e5edfdb61f8ffd80.tar.bz2
tmwa-86395f53634b3ef1ce76a7f1e5edfdb61f8ffd80.tar.xz
tmwa-86395f53634b3ef1ce76a7f1e5edfdb61f8ffd80.zip
Fix header ranking
Diffstat (limited to 'src/high')
-rw-r--r--src/high/core.cpp161
-rw-r--r--src/high/core.hpp47
-rw-r--r--src/high/extract_mmo.cpp95
-rw-r--r--src/high/extract_mmo.hpp32
-rw-r--r--src/high/fwd.hpp39
-rw-r--r--src/high/md5more.cpp159
-rw-r--r--src/high/md5more.hpp44
-rw-r--r--src/high/mmo.hpp71
-rw-r--r--src/high/utils.cpp86
-rw-r--r--src/high/utils.hpp29
10 files changed, 763 insertions, 0 deletions
diff --git a/src/high/core.cpp b/src/high/core.cpp
new file mode 100644
index 0000000..a45db18
--- /dev/null
+++ b/src/high/core.cpp
@@ -0,0 +1,161 @@
+#include "core.hpp"
+// core.cpp - The main loop.
+//
+// Copyright © ????-2004 Athena Dev Teams
+// Copyright © 2004-2011 The Mana World Development Team
+// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include <sys/wait.h>
+
+#include <alloca.h>
+
+#include <csignal>
+#include <cstdlib>
+
+#include <tmwa/shared.hpp>
+
+#include "../strings/zstring.hpp"
+#include "../strings/literal.hpp"
+
+#include "../io/cxxstdio.hpp"
+
+#include "../net/socket.hpp"
+#include "../net/timer.hpp"
+
+#include "../poison.hpp"
+
+
+namespace tmwa
+{
+// 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);
+static
+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)
+ {
+ DIAG_PUSH();
+ DIAG_I(old_style_cast);
+ return SIG_ERR;
+ DIAG_POP();
+ }
+
+ return oact.sa_handler;
+}
+
+volatile
+bool runflag = true;
+
+static
+void chld_proc(int)
+{
+ wait(nullptr);
+}
+static
+void sig_proc(int)
+{
+ for (int i = 1; i < 31; ++i)
+ {
+ DIAG_PUSH();
+ DIAG_I(old_style_cast);
+ compat_signal(i, SIG_IGN);
+ DIAG_POP();
+ }
+ runflag = false;
+}
+
+/*
+ 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.
+ */
+} // namespace tmwa
+
+int tmwa_main(int argc, char **argv)
+{
+ using namespace tmwa;
+
+ check_paths();
+
+ // ZString args[argc]; is (deliberately!) not supported by clang yet
+ ZString *args = static_cast<ZString *>(alloca(argc * sizeof(ZString)));
+ for (int i = 0; i < argc; ++i)
+ args[i] = ZString(strings::really_construct_from_a_pointer, argv[i], nullptr);
+ do_init(Slice<ZString>(args, argc));
+
+ if (!runflag)
+ {
+ PRINTF("Fatal error during startup; exiting\n"_fmt);
+ return 1;
+ }
+ // set up exit handlers *after* the initialization has happened.
+ // This is because term_func is likely to depend on successful init.
+
+ DIAG_PUSH();
+ DIAG_I(old_style_cast);
+ compat_signal(SIGPIPE, SIG_IGN);
+ DIAG_POP();
+ compat_signal(SIGTERM, sig_proc);
+ compat_signal(SIGINT, sig_proc);
+ compat_signal(SIGCHLD, chld_proc);
+
+ // Signal to create coredumps by system when necessary (crash)
+ DIAG_PUSH();
+ DIAG_I(old_style_cast);
+ DIAG_I(zero_as_null_pointer_constant);
+ 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);
+ DIAG_POP();
+
+ atexit(term_func);
+
+ while (runflag)
+ {
+ // TODO - if timers take a long time to run, this
+ // may wait too long in sendrecv
+ tick_t now = milli_clock::now();
+ interval_t next = do_timer(now);
+ runflag &= do_sendrecv(next);
+ runflag &= do_parsepacket();
+ }
+
+ return 0;
+}
diff --git a/src/high/core.hpp b/src/high/core.hpp
new file mode 100644
index 0000000..0ded246
--- /dev/null
+++ b/src/high/core.hpp
@@ -0,0 +1,47 @@
+#pragma once
+// core.hpp - The main loop.
+//
+// Copyright © ????-2004 Athena Dev Teams
+// Copyright © 2004-2011 The Mana World Development Team
+// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "fwd.hpp"
+
+#include "../range/slice.hpp"
+
+
+namespace tmwa
+{
+/// core.c contains a server-independent main() function
+/// and then runs a do_sendrecv loop
+
+/// When this is cleared, the server exits gracefully.
+extern volatile bool runflag;
+
+/// This is an external function defined by each server
+/// This function must register stuff for the parse loop
+extern int do_init(Slice<ZString>);
+
+/// Cleanup function called whenever a signal kills us
+/// or when if we manage to exit() gracefully.
+extern void term_func(void);
+} // namespace tmwa
+
+/// grumble grumble stupid intertwined includes mumble mumble
+__attribute__((warn_unused_result))
+extern int tmwa_main(int argc, char **argv);
diff --git a/src/high/extract_mmo.cpp b/src/high/extract_mmo.cpp
new file mode 100644
index 0000000..a674656
--- /dev/null
+++ b/src/high/extract_mmo.cpp
@@ -0,0 +1,95 @@
+#include "extract_mmo.hpp"
+// extract_mmo.cpp - a simple, hierarchical, tokenizer
+//
+// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include <algorithm>
+
+#include "../io/extract.hpp"
+
+#include "../mmo/extract_enums.hpp"
+
+#include "mmo.hpp"
+
+#include "../poison.hpp"
+
+
+// TODO also pass an io::LineSpan around.
+namespace tmwa
+{
+bool extract(XString str, GlobalReg *var)
+{
+ return extract(str,
+ record<','>(&var->str, &var->value));
+}
+
+bool extract(XString str, Item *it)
+{
+ XString ignored;
+ XString corruption_hack_amount;
+ bool rv = extract(str,
+ record<',', 11>(
+ &ignored,
+ &it->nameid,
+ &corruption_hack_amount,
+ &it->equip,
+ &ignored,
+ &ignored,
+ &ignored,
+ &ignored,
+ &ignored,
+ &ignored,
+ &ignored,
+ &ignored));
+ if (rv)
+ {
+ if (corruption_hack_amount == "-1"_s)
+ it->amount = 0;
+ else
+ rv = extract(corruption_hack_amount, &it->amount);
+ }
+ return rv;
+}
+
+bool extract(XString str, MapName *m)
+{
+ XString::iterator it = std::find(str.begin(), str.end(), '.');
+ str = str.xislice_h(it);
+ VString<15> tmp;
+ bool rv = extract(str, &tmp);
+ *m = tmp;
+ return rv;
+}
+
+bool extract(XString str, CharName *out)
+{
+ VString<23> tmp;
+ if (extract(str, &tmp))
+ {
+ *out = CharName(tmp);
+ return true;
+ }
+ return false;
+}
+
+bool extract(XString str, NpcEvent *ev)
+{
+ XString mid;
+ return extract(str, record<':'>(&ev->npc, &mid, &ev->label)) && !mid;
+}
+} // namespace tmwa
diff --git a/src/high/extract_mmo.hpp b/src/high/extract_mmo.hpp
new file mode 100644
index 0000000..0c18090
--- /dev/null
+++ b/src/high/extract_mmo.hpp
@@ -0,0 +1,32 @@
+#pragma once
+// extract_mmo.hpp - a simple, hierarchical, tokenizer
+//
+// Copyright © 2012-2013 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "fwd.hpp"
+
+
+namespace tmwa
+{
+bool extract(XString str, GlobalReg *var);
+bool extract(XString str, Item *it);
+bool extract(XString str, MapName *m);
+bool extract(XString str, CharName *out);
+
+bool extract(XString str, NpcEvent *ev);
+} // namespace tmwa
diff --git a/src/high/fwd.hpp b/src/high/fwd.hpp
new file mode 100644
index 0000000..1a46b4b
--- /dev/null
+++ b/src/high/fwd.hpp
@@ -0,0 +1,39 @@
+#pragma once
+// high/fwd.hpp - list of type names for mmo lib
+//
+// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "../sanity.hpp"
+
+#include "../range/fwd.hpp" // rank 1
+#include "../strings/fwd.hpp" // rank 1
+#include "../compat/fwd.hpp" // rank 2
+#include "../generic/fwd.hpp" // rank 3
+#include "../io/fwd.hpp" // rank 4
+#include "../net/fwd.hpp" // rank 5
+#include "../mmo/fwd.hpp" // rank 6
+#include "../proto2/fwd.hpp" // rank 8
+// high/fwd.hpp is rank 9
+
+
+namespace tmwa
+{
+class CharPair;
+class PartyPair;
+// meh, add more when I feel like it
+} // namespace tmwa
diff --git a/src/high/md5more.cpp b/src/high/md5more.cpp
new file mode 100644
index 0000000..05149ac
--- /dev/null
+++ b/src/high/md5more.cpp
@@ -0,0 +1,159 @@
+#include "md5more.hpp"
+// md5more.cpp - Non-basic MD5 functions.
+//
+// Copyright © ????-2004 Athena Dev Teams
+// Copyright © 2004-2011 The Mana World Development Team
+// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include <algorithm>
+
+#include "../compat/rawmem.hpp"
+
+#include "../generic/random.hpp"
+
+#include "../io/cxxstdio.hpp"
+#include "../io/read.hpp"
+
+#include "../net/ip.hpp"
+
+#include "mmo.hpp"
+
+#include "../poison.hpp"
+
+
+namespace tmwa
+{
+#define X block.data
+
+// TODO - refactor MD5 into a stream, and merge the implementations
+// I once implemented an ostream that does it ...
+MD5_state MD5_from_FILE(io::ReadFile& 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 = in.get(sign_cast<char *>(buf + block_len), 0x40 - block_len);
+ 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;
+ really_memset0(buf + block_len + 1, 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)
+ {
+ really_memset0(buf, 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
+AccountCrypt MD5_saltcrypt(AccountPass key, SaltString salt)
+{
+ char cbuf[64] {};
+
+ // hash the key then the salt
+ // buf ends up as a 64-char NUL-terminated string
+ md5_string tbuf, tbuf2;
+ MD5_to_str(MD5_from_string(key), tbuf);
+ MD5_to_str(MD5_from_string(salt), tbuf2);
+ const auto it = std::copy(tbuf.begin(), tbuf.end(), std::begin(cbuf));
+ auto it2 = std::copy(tbuf2.begin(), tbuf2.end(), it);
+ assert(it2 == std::end(cbuf));
+
+ md5_string tbuf3;
+ MD5_to_str(MD5_from_string(XString(std::begin(cbuf), it2, nullptr)), tbuf3);
+
+ VString<31> obuf;
+
+ // This truncates the string, but we have to keep it like that for compatibility
+ SNPRINTF(obuf, 32, "!%s$%s"_fmt, salt, tbuf3);
+ return stringish<AccountCrypt>(obuf);
+}
+
+SaltString make_salt(void)
+{
+ char salt[5];
+ for (int i = 0; i < 5; i++)
+ // 126 would probably actually be okay
+ salt[i] = random_::in(48, 125);
+ return stringish<SaltString>(XString(salt + 0, salt + 5, nullptr));
+}
+
+bool pass_ok(AccountPass password, AccountCrypt crypted)
+{
+ // crypted is like !salt$hash
+ auto begin = crypted.begin() + 1;
+ auto end = std::find(begin, crypted.end(), '$');
+ SaltString salt = stringish<SaltString>(crypted.xislice(begin, end));
+
+ return crypted == MD5_saltcrypt(password, salt);
+}
+
+// [M|h]ashes up an IP address and a secret key
+// to return a hopefully unique masked IP.
+IP4Address MD5_ip(IP4Address ip)
+{
+ static SaltString secret = make_salt();
+
+ // MD5sum a secret + the IP address
+ VString<31> ipbuf;
+ SNPRINTF(ipbuf, 32, "%s %s"_fmt, ip, secret);
+ md5_binary obuf;
+ MD5_to_bin(MD5_from_string(ipbuf), obuf);
+
+ // Fold the md5sum to 32 bits, pack the bytes to an in_addr
+ return IP4Address({
+ static_cast<uint8_t>(obuf[0] ^ obuf[1] ^ obuf[8] ^ obuf[9]),
+ static_cast<uint8_t>(obuf[2] ^ obuf[3] ^ obuf[10] ^ obuf[11]),
+ static_cast<uint8_t>(obuf[4] ^ obuf[5] ^ obuf[12] ^ obuf[13]),
+ static_cast<uint8_t>(obuf[6] ^ obuf[7] ^ obuf[14] ^ obuf[15]),
+ });
+}
+} // namespace tmwa
diff --git a/src/high/md5more.hpp b/src/high/md5more.hpp
new file mode 100644
index 0000000..33ebe24
--- /dev/null
+++ b/src/high/md5more.hpp
@@ -0,0 +1,44 @@
+#pragma once
+// md5more.hpp - Non-basic MD5 functions.
+//
+// Copyright © ????-2004 Athena Dev Teams
+// Copyright © 2004-2011 The Mana World Development Team
+// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "fwd.hpp"
+
+#include "../generic/md5.hpp"
+
+
+namespace tmwa
+{
+MD5_state MD5_from_FILE(io::ReadFile& in);
+
+// whoever wrote this fails basic understanding of
+AccountCrypt MD5_saltcrypt(AccountPass key, SaltString salt);
+
+/// return some random characters
+// Currently, returns a 5-char string
+SaltString make_salt(void);
+
+/// check plaintext password against saved saltcrypt
+bool pass_ok(AccountPass password, AccountCrypt crypted);
+
+/// This returns an IP4Address because it is configurable whether it gets called at all
+IP4Address MD5_ip(IP4Address ip);
+} // namespace tmwa
diff --git a/src/high/mmo.hpp b/src/high/mmo.hpp
new file mode 100644
index 0000000..b5bcac8
--- /dev/null
+++ b/src/high/mmo.hpp
@@ -0,0 +1,71 @@
+#pragma once
+// mmo.hpp - Huge mess of structures.
+//
+// Copyright © ????-2004 Athena Dev Teams
+// Copyright © 2004-2011 The Mana World Development Team
+// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "fwd.hpp"
+
+#include "../compat/borrow.hpp"
+#include "../compat/memory.hpp"
+
+#include "../proto2/net-CharData.hpp"
+#include "../proto2/net-CharKey.hpp"
+#include "../proto2/net-PartyMost.hpp"
+#include "../proto2/net-SkillValue.hpp"
+
+
+namespace tmwa
+{
+inline
+bool operator == (const SkillValue& l, const SkillValue& r)
+{
+ return l.lv == r.lv && l.flags == r.flags;
+}
+inline
+bool operator != (const SkillValue& l, const SkillValue& r)
+{
+ return !(l == r);
+}
+
+struct CharPair
+{
+ CharKey key;
+ std::unique_ptr<CharData> data;
+
+ CharPair()
+ : key{}, data(make_unique<CharData>())
+ {}
+};
+
+struct GM_Account
+{
+ AccountId account_id;
+ GmLevel level;
+};
+
+struct PartyPair
+{
+ PartyId party_id;
+ Borrowed<PartyMost> party_most;
+
+ PartyMost& operator *() const { return *party_most; }
+ Borrowed<PartyMost> operator->() const { return party_most; }
+};
+} // namespace tmwa
diff --git a/src/high/utils.cpp b/src/high/utils.cpp
new file mode 100644
index 0000000..9b89c31
--- /dev/null
+++ b/src/high/utils.cpp
@@ -0,0 +1,86 @@
+#include "utils.hpp"
+// utils.cpp - Useful stuff that hasn't been categorized.
+//
+// Copyright © ????-2004 Athena Dev Teams
+// Copyright © 2004-2011 The Mana World Development Team
+// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include <sys/time.h>
+
+#include <algorithm>
+
+#include "../strings/zstring.hpp"
+#include "../strings/xstring.hpp"
+
+#include "../io/cxxstdio.hpp"
+#include "../io/extract.hpp"
+
+#include "../poison.hpp"
+
+
+namespace tmwa
+{
+//---------------------------------------------------
+// E-mail check: return 0 (not correct) or 1 (valid).
+//---------------------------------------------------
+bool e_mail_check(XString email)
+{
+ // athena limits
+ if (email.size() < 3 || email.size() > 39)
+ return 0;
+
+ // part of RFC limits (official reference of e-mail description)
+ XString::iterator at = std::find(email.begin(), email.end(), '@');
+ if (at == email.end())
+ return 0;
+ XString username = email.xislice_h(at);
+ XString hostname = email.xislice_t(at + 1);
+ if (!username || !hostname)
+ return 0;
+ if (hostname.contains('@'))
+ return 0;
+ if (hostname.front() == '.' || hostname.back() == '.')
+ return 0;
+ if (hostname.contains_seq(".."_s))
+ return 0;
+ if (email.contains_any(" ;"_s))
+ return 0;
+ return email.is_print();
+}
+
+//-------------------------------------------------
+// Return numerical value of a switch configuration
+// on/off, english, français, deutsch, español
+//-------------------------------------------------
+int config_switch(ZString str)
+{
+ if (str == "true"_s || str == "on"_s || str == "yes"_s
+ || str == "oui"_s || str == "ja"_s
+ || str == "si"_s)
+ return 1;
+ if (str == "false"_s || str == "off"_s || str == "no"_s
+ || str == "non"_s || str == "nein"_s)
+ return 0;
+
+ int rv;
+ if (extract(str, &rv))
+ return rv;
+ FPRINTF(stderr, "Fatal: bad option value %s"_fmt, str);
+ abort();
+}
+} // namespace tmwa
diff --git a/src/high/utils.hpp b/src/high/utils.hpp
new file mode 100644
index 0000000..c815e03
--- /dev/null
+++ b/src/high/utils.hpp
@@ -0,0 +1,29 @@
+#pragma once
+// utils.hpp - Useful stuff that hasn't been categorized.
+//
+// Copyright © ????-2004 Athena Dev Teams
+// Copyright © 2004-2011 The Mana World Development Team
+// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "fwd.hpp"
+
+namespace tmwa
+{
+bool e_mail_check(XString email);
+int config_switch(ZString str);
+} // namespace tmwa