diff --git a/lib/util.php b/lib/util.php
new file mode 100644
--- /dev/null
+++ b/lib/util.php
@@ -0,0 +1,266 @@
+
+// Sponsored by WIEDENMANN SEILE GMBH, http://www.wiedenmannseile.de
+//
+// This file is part of Wiedenmann Vacation.
+//
+// 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 ,
+// or write to
+
+// $_REQUEST['_DEBUG_'] = 1;
+// $_REQUEST['_DEBUG_TEST_'] = 1;
+require_once(dirname(__FILE__) . '/../lib/config.php');
+require_once(dirname(__FILE__) . '/../lib/language.php');
+
+// --------------------------------------------------
+// |||:sec:||| Benutzer
+// --------------------------------------------------
+
+function get_users()
+{
+ global $PASSWD_FILE;
+ global $USER_ID_MIN;
+ global $USER_ID_MAX;
+ global $ALLOWED_USERS;
+ global $INVALID_USERS;
+ global $HOME_PFX;
+
+ $passwd = file_get_contents($PASSWD_FILE);
+ $lines = explode("\n", $passwd);
+ $users = Array();
+ //var_dump($lines);
+ foreach ($lines as $line) {
+ if (empty($line)) {
+ continue;
+ }
+ $fields = explode(':', $line);
+ $user = $fields[0];
+ $uid = $fields[2];
+ $home = $fields[5];
+
+ // uncoditionally accept allowed users
+ if (!in_array($user, $ALLOWED_USERS)) {
+ if ($uid < $USER_ID_MIN || $uid > $USER_ID_MAX) {
+ // skip users with a user id outside the allowed range
+ continue;
+ }
+ $home_pos = strpos($home, $HOME_PFX);
+ if ($home_pos === false || $home_pos > 0) {
+ // skip users without a HOME directory
+ continue;
+ }
+ if (in_array($user, $INVALID_USERS)) {
+ // skip invalid users
+ continue;
+ }
+ }
+ $users[$user] = Array($user, $home);
+ }
+ ksort($users);
+ return $users;
+}
+
+function make_htpasswd()
+{
+ global $SHADOW_FILE;
+ global $HTPASSWD_FILE;
+ $users = get_users();
+ $user_names = array_keys($users);
+ $shadow = file_get_contents($SHADOW_FILE);
+ $lines = explode("\n", $shadow);
+ $pw_ent = Array();
+ //var_dump($lines);
+ foreach ($lines as $line) {
+ if (empty($line)) {
+ continue;
+ }
+ $fields = explode(':', $line);
+ $user = $fields[0];
+ $pass = $fields[1];
+ if (in_array($user, $user_names)) {
+ $pw_ent[] = sprintf('%s:%s', $user, $pass);
+ }
+ }
+ $htpwd = fopen($HTPASSWD_FILE, 'w');
+ fwrite($htpwd, implode($pw_ent, "\n"));
+ fclose($htpwd);
+}
+
+// --------------------------------------------------
+// |||:sec:||| substitute_elements
+// --------------------------------------------------
+
+// |:check:| syntax error on PHP 5.2.x (mecki)
+// class substitute_elements_check
+// {
+// const _doc_ = <<<'DOC'
+// Markierungen in String ersetzen.
+
+// function substitute_elements ($string, $substitutions=array(), $keep_unknown=NULL, $pfx='@', $sfx=NULL)
+
+// Falls eine Markierung gefunden wurde, die nicht in $substitutions
+// enthalten ist, wird sie durch einen leeren String ersetzt, falls
+// $keep_unknown == false, andernfalls wird die Markierung
+// unverändert beibehalten.
+
+// Ist $keep_unknown == NULL (Standardwert), dann wird es auf
+// isset($_REQUEST['_DEBUG_']) gesetzt. Im Debug-Modus werden die
+// Markierungen also beibehalten im Normal-Modus nicht.
+// DOC;
+// const _check_ = <<<'CHECK'
+// global $BRNL;
+
+// $string = 'Eine @Ersetzung@ an @dieser@ Stelle.' . $BRNL;
+
+// $substitutions = array(
+// 'Ersetzung' => 'neue Sache',
+// );
+
+// echo substitute_elements($string, $substitutions, True);
+// echo substitute_elements($string, $substitutions, False);
+// CHECK;
+// static $_check_output_;
+// }
+
+function substitute_elements (
+ $string, $substitutions=array(), $keep_unknown=NULL, $pfx='@', $sfx=NULL)
+{
+ if ( !isset($keep_unknown) )
+ {
+ $keep_unknown = isset($_REQUEST['_DEBUG_']);
+ }
+
+ if ( !isset($sfx) )
+ {
+ $sfx = $pfx;
+ }
+
+ $subst_rx = $pfx . '([^' . substr($sfx, 0, 1) . ']+)' .$sfx;
+
+ $parts = preg_split('/' . $subst_rx . '/', $string);
+ //hline();
+ //$d->c()->kva($parts)->p();
+
+ $subst_keys = Array();
+ preg_match_all('/' . $subst_rx . '/', $string,
+ $subst_keys, PREG_PATTERN_ORDER);
+ $subst_keys = $subst_keys[1];
+ //hline();
+ //$d->c()->kva($subst_keys)->p();
+
+ $result = Array();
+ $indx = 0;
+ foreach ($parts as $part)
+ {
+ // pdkv('// $part '."$indx", $part);
+ $result[] = $part;
+ if ( array_key_exists($indx, $subst_keys))
+ {
+ $subst_key = $subst_keys[$indx];
+ if (array_key_exists($subst_key, $substitutions))
+ {
+ $result[] = $substitutions[$subst_key];
+ }
+ else if ( $keep_unknown )
+ {
+ $result[] = $pfx . $subst_key . $sfx;
+ }
+ // pdkv('// $subst_key', $subst_key);
+ }
+ $indx += 1;
+ }
+ $result = implode('', $result);
+ return $result;
+}
+
+// --------------------------------------------------
+// |||:sec:||| Language Support
+// --------------------------------------------------
+
+if (!array_key_exists($LANGUAGE, $LC_LANGUAGES)) {
+ $LANGUAGE = 'en';
+}
+$LC_MESSAGES_EN = $LC_LANGUAGES['en'];
+$LC_MESSAGES = $LC_LANGUAGES[$LANGUAGE];
+
+if ( isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
+{
+ $accept_language = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
+ $accept_language = preg_replace('/;[^,;]*/', '', $accept_language);
+ $preferred_languages = explode(',', $accept_language);
+ // if (isset($_REQUEST['_DEBUG_'])) {
+ // var_dump($preferred_languages);
+ // }
+ foreach ($preferred_languages as $plang) {
+ if (array_key_exists($plang, $LC_LANGUAGES)) {
+ $LC_MESSAGES = $LC_LANGUAGES[$plang];
+ break;
+ }
+ }
+}
+
+function get_text($text)
+{
+ global $LC_MESSAGES_EN;
+ global $LC_MESSAGES;
+ if ( !array_key_exists($text, $LC_MESSAGES))
+ {
+ if ( array_key_exists($text, $LC_MESSAGES_EN) )
+ {
+ return $LC_MESSAGES_EN[$text];
+ }
+ return $text;
+ }
+ return $LC_MESSAGES[$text];
+}
+
+// --------------------------------------------------
+// |||:sec:||| Ăberschrift/Fehlermeldung
+// --------------------------------------------------
+
+function shl($message)
+{
+ return sprintf('%s
', $message);
+}
+
+function hl($message)
+{
+ echo shl($message)."\n";
+}
+
+function error_msg($message)
+{
+ echo sprintf('%s'."\n", $message);
+}
+
+//
+// :ide-menu: Emacs IDE Menu - Buffer @BUFFER@
+// . M-x `eIDE-menu' ()(eIDE-menu "z")
+// :ide: COMPILE: PHP _DEBUG_=2 _DEBUG_TEST_=2
+// . (compile (concat "php " (file-name-nondirectory (buffer-file-name)) " _DEBUG_=2 _DEBUG_TEST_=2"))
+
+// :ide: QUO: $this->
+// . (insert "$this->" )
+
+// :ide: COMPILE: PHP w/o args
+// . (compile (concat "php " (file-name-nondirectory (buffer-file-name)) ""))
+
+// :ide: COMPILE: PHP _DEBUG_=1 _DEBUG_TEST_=1
+// . (compile (concat "php " (file-name-nondirectory (buffer-file-name)) " _DEBUG_=1 _DEBUG_TEST_=1"))
+
+//
+// Local Variables:
+// mode: php
+// End:
+?>