From 9f94a17eacd85144a1aee14929688b33e9393fe1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20F=C3=BCrmann?= <michael@spicyweb.de>
Date: Tue, 17 Feb 2015 19:40:07 +0100
Subject: [PATCH] Server initialization and domain management (without ssl for
 now)

---
 install/apps/metronome-init                   |  62 +++
 .../mod_auth_external/authenticate_isp.php    |  65 +++
 .../mod_auth_external/authenticate_isp.sh     |  38 ++
 .../mod_auth_external/isuser_isp.php          |  44 ++
 .../mod_auth_external/mod_auth_external.lua   | 118 +++++
 .../apps/metronome_libs/mod_discoitems.lua    |  24 +
 .../mod_webpresence/icons/status_away.png     | Bin 0 -> 948 bytes
 .../mod_webpresence/icons/status_chat.png     | Bin 0 -> 920 bytes
 .../mod_webpresence/icons/status_dnd.png      | Bin 0 -> 822 bytes
 .../mod_webpresence/icons/status_offline.png  | Bin 0 -> 905 bytes
 .../mod_webpresence/icons/status_online.png   | Bin 0 -> 920 bytes
 .../mod_webpresence/icons/status_xa.png       | Bin 0 -> 954 bytes
 .../mod_webpresence/mod_webpresence.lua       | 118 +++++
 install/dist/conf/debian60.conf.php           |   4 +
 install/dist/lib/debian60.lib.php             |   4 +
 install/install.php                           |  19 +
 install/lib/installer_base.lib.php            |  64 ++-
 install/sql/incremental/upd_0081.sql          |  55 +++
 install/sql/ispconfig3.sql                    |  59 +++
 install/tpl/metronome_conf_global.master      |  65 +++
 install/tpl/metronome_conf_main.master        |   3 +
 install/tpl/server.ini.master                 |   9 +
 interface/web/admin/form/server.tform.php     |   6 +
 .../web/admin/form/server_config.tform.php    |  80 ++++
 interface/web/admin/lib/lang/en_server.lng    |   2 +
 .../web/admin/lib/lang/en_server_config.lng   |  14 +
 .../web/admin/lib/lang/en_server_list.lng     |   2 +
 interface/web/admin/list/server.list.php      |   9 +
 .../templates/server_config_xmpp_edit.htm     |  73 +++
 .../admin/templates/server_edit_services.htm  |   6 +
 interface/web/admin/templates/server_list.htm |   3 +
 interface/web/client/form/client.tform.php    | 100 ++++
 interface/web/client/lib/lang/en_client.lng   |  21 +
 .../client/templates/client_edit_limits.htm   |  64 +++
 interface/web/js/xmpp_domain_muc.js           |  26 ++
 interface/web/js/xmpp_domain_registration.js  |  25 +
 interface/web/mail/form/xmpp_domain.tform.php | 284 ++++++++++++
 .../web/mail/lib/lang/en_xmpp_domain.lng      |  28 ++
 .../lib/lang/en_xmpp_domain_admin_list.lng    |   8 +
 .../web/mail/lib/lang/en_xmpp_domain_list.lng |   7 +
 interface/web/mail/lib/module.conf.php        |  24 +
 interface/web/mail/list/xmpp_domain.list.php  | 109 +++++
 .../mail/templates/xmpp_domain_admin_list.htm |  60 +++
 .../web/mail/templates/xmpp_domain_edit.htm   | 124 +++++
 .../templates/xmpp_domain_edit_modules.htm    |  52 +++
 .../mail/templates/xmpp_domain_edit_muc.htm   |  87 ++++
 .../web/mail/templates/xmpp_domain_list.htm   |  74 +++
 interface/web/mail/xmpp_domain_del.php        | 102 ++++
 interface/web/mail/xmpp_domain_edit.php       | 436 ++++++++++++++++++
 interface/web/mail/xmpp_domain_list.php       |  28 ++
 server/conf/metronome_conf_global.master      |  48 ++
 server/conf/metronome_conf_host.master        | 138 ++++++
 server/conf/metronome_conf_main.master        |   3 +
 server/conf/metronome_conf_status.master      |  12 +
 server/mods-available/xmpp_module.inc.php     | 109 +++++
 server/plugins-available/xmpp_plugin.inc.php  | 232 ++++++++++
 server/server.sh                              |   1 +
 57 files changed, 3147 insertions(+), 1 deletion(-)
 create mode 100644 install/apps/metronome-init
 create mode 100644 install/apps/metronome_libs/mod_auth_external/authenticate_isp.php
 create mode 100644 install/apps/metronome_libs/mod_auth_external/authenticate_isp.sh
 create mode 100644 install/apps/metronome_libs/mod_auth_external/isuser_isp.php
 create mode 100644 install/apps/metronome_libs/mod_auth_external/mod_auth_external.lua
 create mode 100644 install/apps/metronome_libs/mod_discoitems.lua
 create mode 100644 install/apps/metronome_libs/mod_webpresence/icons/status_away.png
 create mode 100644 install/apps/metronome_libs/mod_webpresence/icons/status_chat.png
 create mode 100644 install/apps/metronome_libs/mod_webpresence/icons/status_dnd.png
 create mode 100644 install/apps/metronome_libs/mod_webpresence/icons/status_offline.png
 create mode 100644 install/apps/metronome_libs/mod_webpresence/icons/status_online.png
 create mode 100644 install/apps/metronome_libs/mod_webpresence/icons/status_xa.png
 create mode 100644 install/apps/metronome_libs/mod_webpresence/mod_webpresence.lua
 create mode 100644 install/sql/incremental/upd_0081.sql
 create mode 100644 install/tpl/metronome_conf_global.master
 create mode 100644 install/tpl/metronome_conf_main.master
 create mode 100644 interface/web/admin/templates/server_config_xmpp_edit.htm
 create mode 100644 interface/web/js/xmpp_domain_muc.js
 create mode 100644 interface/web/js/xmpp_domain_registration.js
 create mode 100644 interface/web/mail/form/xmpp_domain.tform.php
 create mode 100644 interface/web/mail/lib/lang/en_xmpp_domain.lng
 create mode 100644 interface/web/mail/lib/lang/en_xmpp_domain_admin_list.lng
 create mode 100644 interface/web/mail/lib/lang/en_xmpp_domain_list.lng
 create mode 100644 interface/web/mail/list/xmpp_domain.list.php
 create mode 100644 interface/web/mail/templates/xmpp_domain_admin_list.htm
 create mode 100644 interface/web/mail/templates/xmpp_domain_edit.htm
 create mode 100644 interface/web/mail/templates/xmpp_domain_edit_modules.htm
 create mode 100644 interface/web/mail/templates/xmpp_domain_edit_muc.htm
 create mode 100644 interface/web/mail/templates/xmpp_domain_list.htm
 create mode 100644 interface/web/mail/xmpp_domain_del.php
 create mode 100644 interface/web/mail/xmpp_domain_edit.php
 create mode 100644 interface/web/mail/xmpp_domain_list.php
 create mode 100644 server/conf/metronome_conf_global.master
 create mode 100644 server/conf/metronome_conf_host.master
 create mode 100644 server/conf/metronome_conf_main.master
 create mode 100644 server/conf/metronome_conf_status.master
 create mode 100644 server/mods-available/xmpp_module.inc.php
 create mode 100644 server/plugins-available/xmpp_plugin.inc.php

diff --git a/install/apps/metronome-init b/install/apps/metronome-init
new file mode 100644
index 0000000000..e10ef3c32e
--- /dev/null
+++ b/install/apps/metronome-init
@@ -0,0 +1,62 @@
+#! /bin/sh
+#
+# metronome        Start/stop metronome server
+#
+
+### BEGIN INIT INFO
+# Provides:          metronome
+# Required-Start:    $remote_fs $network $named $time
+# Required-Stop:     $remote_fs $network $named $time
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Starts metronome server
+# Description:       Starts metronome server, an XMPP server written in Lua.
+### END INIT INFO
+
+METRONOME=/usr/bin/metronomectl
+PIDDIR=/var/run/metronome
+NAME=metronome
+
+test -e $METRONOME || exit 0
+
+start()
+{
+        mkdir $PIDDIR -p
+        chown metronome:metronome $PIDDIR
+        chmod 750 $PIDDIR
+
+    $METRONOME start >> /dev/null
+}
+
+stop()
+{
+    $METRONOME stop >> /dev/null
+}
+
+case "$1" in
+    start)
+        echo -n "Starting Metronome..."
+        start &
+    ;;
+    stop)
+        echo -n "Stopping Metronome..."
+        stop &
+    ;;
+    restart)
+        echo -n "Restarting Metronome..."
+        stop &
+        start &
+    ;;
+    *)
+        echo "Usage: $0 {start|stop|restart}" >&2
+        exit 1
+    ;;
+esac
+
+if [ $? -eq 0 ]; then
+    echo .
+else
+    echo " failed!"
+fi
+
+exit 0
diff --git a/install/apps/metronome_libs/mod_auth_external/authenticate_isp.php b/install/apps/metronome_libs/mod_auth_external/authenticate_isp.php
new file mode 100644
index 0000000000..7c59f3759b
--- /dev/null
+++ b/install/apps/metronome_libs/mod_auth_external/authenticate_isp.php
@@ -0,0 +1,65 @@
+<?php
+ini_set('display_errors', false);
+$username = 'prosody';
+$password = '23fm%4ks0';
+/*
+$soap_location = 'http://localhost:8080/ispconfig3/interface/web/remote/index.php';
+$soap_uri = 'http://localhost:8080/ispconfig3/interface/web/remote/';
+*/
+$soap_location = 'https://tepin.spicyweb.de:8080/remote/index.php';
+$soap_uri = 'https://tepin.spicyweb.de:8080/remote/';
+
+$auth_keys = array(
+    'iplay-esports.de' => 'f47kmm5Yh5hJzSws2KTS',
+    'weirdempire.de' => 'scNDcU37gQ7MCMeBgaJX'
+);
+
+$arg_email = '';
+$arg_password = '';
+
+if(count($argv) == 4){
+    $arg_email = $argv[1].'@'.$argv[2];
+    $arg_password = $argv[3];
+}
+$client = new SoapClient(null, array('location' => $soap_location, 'uri' => $soap_uri));
+try {
+    //* Login to the remote server
+    if($session_id = $client->login($username,$password)) {
+        //var_dump($client->mail_alias_get($session_id, array('source' => 'blablubb@divepage.net', 'type' => 'alias', 'active' => 'y')));
+        // Is Mail Alias?
+        $alias = $client->mail_alias_get($session_id, array('source' => $arg_email, 'type' => 'alias', 'active' => 'y'));
+        if(count($alias))
+            $arg_email = $alias[0]['destination'];
+        $mailbox = $client->mail_user_get($session_id, array('email' => $arg_email));
+        if(count($mailbox)){
+            $password = $mailbox[0]['password'];
+            echo checkAuth($argv[1], $argv[2], $arg_password, $password);//intval(crypt($arg_password, $password) == $password);
+        }
+        else
+            echo 0;
+        //* Logout
+        $client->logout($session_id);
+    }
+    else
+        echo 0;
+} catch (SoapFault $e) {
+    echo 0;
+}
+
+function checkAuth($user, $domain, $pw, $pw_mailbox){
+    global $auth_keys;
+    if(crypt($pw, $pw_mailbox) == $pw_mailbox)
+        return intval(1);
+
+    if(array_key_exists($domain, $auth_keys)){
+        $datetime = new DateTime();
+        $datetime->setTimezone(new DateTimeZone("UTC"));
+        for($t = $datetime->getTimestamp(); $t >= $datetime->getTimestamp()-30; $t--){
+            $pw_api = md5($domain.'@'.$auth_keys[$domain].'@'.$user.'@'.$t);
+            if($pw_api == $pw)
+                return intval(1);
+        }
+    }
+    return intval(0);
+}
+?>
\ No newline at end of file
diff --git a/install/apps/metronome_libs/mod_auth_external/authenticate_isp.sh b/install/apps/metronome_libs/mod_auth_external/authenticate_isp.sh
new file mode 100644
index 0000000000..c4832f4433
--- /dev/null
+++ b/install/apps/metronome_libs/mod_auth_external/authenticate_isp.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+IFS=":"
+AUTH_OK=1
+AUTH_FAILED=0
+LOGFILE="/var/log/metronome/auth.log"
+USELOG=true
+
+while read ACTION USER HOST PASS ; do
+
+    [ $USELOG == true ] && { echo "Date: $(date) Action: $ACTION User: $USER Host: $HOST" >> $LOGFILE; }
+
+    case $ACTION in
+        "auth")
+            if [ `/usr/bin/php /usr/lib/metronome/spicy-modules/mod_auth_external/authenticate_isp.php $USER $HOST $PASS` == 1 ] ; then
+                echo $AUTH_OK
+                [ $USELOG == true ] && { echo "AUTH OK" >> $LOGFILE; }
+            else
+                echo $AUTH_FAILED
+                [ $USELOG == true ] && { echo "AUTH FAILED" >> $LOGFILE; }
+            fi
+        ;;
+        "isuser")
+             if [ `/usr/bin/php /usr/lib/metronome/spicy-modules/mod_auth_external/isuser_isp.php $USER $HOST` == 1 ] ; then
+                echo $AUTH_OK
+                [ $USELOG == true ] && { echo "AUTH OK" >> $LOGFILE; }
+            else
+                echo $AUTH_FAILED
+                [ $USELOG == true ] && { echo "AUTH FAILED" >> $LOGFILE; }
+            fi
+        ;;
+        *)
+            echo $AUTH_FAILED
+            [ $USELOG == true ] && { echo "NO ACTION GIVEN" >> $LOGFILE; }
+        ;;
+    esac
+
+done
diff --git a/install/apps/metronome_libs/mod_auth_external/isuser_isp.php b/install/apps/metronome_libs/mod_auth_external/isuser_isp.php
new file mode 100644
index 0000000000..d37053270e
--- /dev/null
+++ b/install/apps/metronome_libs/mod_auth_external/isuser_isp.php
@@ -0,0 +1,44 @@
+<?php
+ini_set('display_errors', false);
+$username = 'prosody';
+$password = '23fm%4ks0';
+/*
+$soap_location = 'http://localhost:8080/ispconfig3/interface/web/remote/index.php';
+$soap_uri = 'http://localhost:8080/ispconfig3/interface/web/remote/';
+*/
+$soap_location = 'https://tepin.spicyweb.de:8080/remote/index.php';
+$soap_uri = 'https://tepin.spicyweb.de:8080/remote/';
+
+
+$arg_email = '';
+
+if(count($argv) == 3){
+    $arg_email = $argv[1].'@'.$argv[2];
+}
+
+$client = new SoapClient(null, array('location' => $soap_location, 'uri' => $soap_uri));
+try {
+    //* Login to the remote server
+    if($session_id = $client->login($username,$password)) {
+        //var_dump($client->mail_alias_get($session_id, array('source' => 'blablubb@divepage.net', 'type' => 'alias', 'active' => 'y')));
+        // Is Mail Alias?
+        $alias = $client->mail_alias_get($session_id, array('source' => $arg_email, 'type' => 'alias', 'active' => 'y'));
+        if(count($alias))
+            $arg_email = $alias[0]['destination'];
+        $mailbox = $client->mail_user_get($session_id, array('email' => $arg_email));
+        if(count($mailbox)){
+            echo 1;
+            //$password = $mailbox[0]['password'];
+            //echo intval(crypt($arg_password, $password) == $password);
+        }
+        else
+            echo 0;
+        //* Logout
+        $client->logout($session_id);
+    }
+    else
+        echo 0;
+} catch (SoapFault $e) {
+    echo 0;
+}
+?>
\ No newline at end of file
diff --git a/install/apps/metronome_libs/mod_auth_external/mod_auth_external.lua b/install/apps/metronome_libs/mod_auth_external/mod_auth_external.lua
new file mode 100644
index 0000000000..c86400610e
--- /dev/null
+++ b/install/apps/metronome_libs/mod_auth_external/mod_auth_external.lua
@@ -0,0 +1,118 @@
+local nodeprep = require "util.encodings".stringprep.nodeprep;
+local lpc = require "lpc";
+
+local config = require "core.configmanager";
+local log = module._log;
+local host = module.host;
+local script_type = config.get(host, "external_auth_protocol") or "generic";
+assert(script_type == "ejabberd" or script_type == "generic");
+local command = config.get(host, "external_auth_command") or "";
+assert(type(command) == "string");
+assert(not host:find(":"));
+local usermanager = require "core.usermanager";
+local jid_bare = require "util.jid".bare;
+local new_sasl = require "util.sasl".new;
+
+local pid;
+local readfile;
+local writefile;
+
+local function send_query(text)
+        if pid and lpc.wait(pid,1) ~= nil then
+            log("debug","error, process died, force reopen");
+            pid=nil;
+        end
+        if not pid then
+                log("debug", "Opening process " .. command);
+                pid, writefile, readfile = lpc.run(command);
+        end
+        if not pid then
+                log("debug", "Process failed to open");
+                return nil;
+        end
+
+        writefile:write(text);
+        writefile:flush();
+        if script_type == "ejabberd" then
+                return readfile:read(4);
+        elseif script_type == "generic" then
+                return readfile:read();
+        end
+end
+
+function do_query(kind, username, password)
+        if not username then return nil, "not-acceptable"; end
+        username = nodeprep(username);
+        if not username then return nil, "jid-malformed"; end
+
+        local query = (password and "%s:%s:%s:%s" or "%s:%s:%s"):format(kind, username, host, password);
+        local len = #query
+        if len > 1000 then return nil, "policy-violation"; end
+
+        if script_type == "ejabberd" then
+                local lo = len % 256;
+                local hi = (len - lo) / 256;
+                query = string.char(hi, lo)..query;
+        end
+        if script_type == "generic" then
+                query = query..'\n';
+        end
+
+        local response = send_query(query);
+        if (script_type == "ejabberd" and response == "\0\2\0\0") or
+                (script_type == "generic" and response == "0") then
+                        return nil, "not-authorized";
+        elseif (script_type == "ejabberd" and response == "\0\2\0\1") or
+                (script_type == "generic" and response == "1") then
+                        return true;
+        else
+                log("debug", "Nonsense back");
+                return nil, "internal-server-error";
+        end
+end
+
+function new_external_provider(host)
+        local provider = { name = "external" };
+
+        function provider.test_password(username, password)
+                return do_query("auth", username, password);
+        end
+
+        function provider.set_password(username, password)
+                return do_query("setpass", username, password);
+        end
+
+        function provider.user_exists(username)
+                return do_query("isuser", username);
+        end
+
+        function provider.create_user(username, password) return nil, "Account creation/modification not available."; end
+
+        function provider.get_sasl_handler()
+                local testpass_authentication_profile = {
+                        plain_test = function(sasl, username, password, realm)
+                                return usermanager.test_password(username, realm, password), true;
+                        end,
+                };
+                return new_sasl(module.host, testpass_authentication_profile);
+        end
+
+        function provider.is_admin(jid)
+                local admins = config.get(host, "admins");
+                if admins ~= config.get("*", "admins") then
+                        if type(admins) == "table" then
+                                jid = jid_bare(jid);
+                                for _,admin in ipairs(admins) do
+                                        if admin == jid then return true; end
+                                end
+                        elseif admins then
+                                log("error", "Option 'admins' for host '%s' is not a table", host);
+                        end
+                end
+                return usermanager.is_admin(jid);
+        end
+
+        return provider;
+end
+
+module:add_item("auth-provider", new_external_provider(host));
\ No newline at end of file
diff --git a/install/apps/metronome_libs/mod_discoitems.lua b/install/apps/metronome_libs/mod_discoitems.lua
new file mode 100644
index 0000000000..f05b904907
--- /dev/null
+++ b/install/apps/metronome_libs/mod_discoitems.lua
@@ -0,0 +1,24 @@
+-- * Metronome IM *
+--
+-- This file is part of the Metronome XMPP server and is released under the
+-- ISC License, please see the LICENSE file in this source package for more
+-- information about copyright and licensing.
+--
+-- As per the sublicensing clause, this file is also MIT/X11 Licensed.
+-- ** Copyright (c) 2009, Waqas Hussain
+
+local st = require "util.stanza";
+
+local result_query = st.stanza("query", {xmlns = "http://jabber.org/protocol/disco#items"});
+for _, item in ipairs(module:get_option("disco_items") or {}) do
+    result_query:tag("item", {jid = item[1], name = item[2]}):up();
+end
+
+module:hook("iq/host/http://jabber.org/protocol/disco#items:query", function(event)
+    local stanza = event.stanza;
+    local query = stanza.tags[1];
+    if stanza.attr.type == "get" and not query.attr.node then
+        event.origin.send(st.reply(stanza):add_child(result_query));
+        return true;
+    end
+end, 100);
diff --git a/install/apps/metronome_libs/mod_webpresence/icons/status_away.png b/install/apps/metronome_libs/mod_webpresence/icons/status_away.png
new file mode 100644
index 0000000000000000000000000000000000000000..0de5c6ab3d35e958b2c2c9fa9ee6e5876312b54b
GIT binary patch
literal 948
zcmV;l155mgP)<h;3K|Lk000e1NJLTq000jF000mO1^@s6$yOx<00004b3#c}2nYxW
zd<bNS00009a7bBm000fw000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^
zaAhuUa%Y?FJQ@H112IWNK~yM_RnuQgm308d@$dV4-}Aob98uvMM4Aa<bllA4)QoVJ
zSh`5@0%x)QT(Ib-HHWoftI1XxZT*?rg&9Rl7mn#gE<$ZAC%GWINXsb}!jvH3h=&87
z!#VGH&-;6SU672P>*sU#JepF9xjFpi<1dH&*($&0tPbjKK|H0#rd|Dym~9=~^ZBK-
zbGzC-yt{5wxNLFa=+nzG+x(``0F-p`vJReOGa7fjv$t};?MarraO%VvcNXui+Z2Ab
zc;a$-iMCXj7MgA_iya$jr;+Jt?!*%OIGopiF8Ofe)QK}n06Y?!`l`HGEfrP(JunY_
z-hA|64!S>xumT9vV)(9L$2UQWeX-IA18o4}z^<}w8;jE0HN%H6O@tM|2;`s#b7r8=
zL}~^f{FF=A#VfSjSk9W9k)5wRU;d~tReD!A;0c646FQn<ApCxG%a3LlXhNr{!=d5*
zW-QCX&7@enD5+bS*gj){k$DiMKzS(711a$w2b4ld$?4w`ELpRYb!F>$sd_VSuNx%j
zgRqfWCh{z|P)SKD<<Rm&6q&J+sU$L;WbmI!+IvI1@z%S1+|<ZZp{taJJOCC2vV|g<
za;4`w?C)@hF07>KWE7c7kVzzXr!C3B<~Dx5(8b^{$JrjSQPKrq%GQK2KCMN^V(Eo_
z69sgBc#zhk&AfN=5T4Sg-+LI>b@`<6HI7sz@EivvB>=b6zNitieFOPsCi3F)5%$!-
z%158J(5hf~=oafYJV{N}6YQ%PM|U$w#|A(ujS)LApodE$e};(HRTQN}bYzh4FaAw^
zLn9kDZf0-8>ud>LU_~g6m$Bi$H6Fi_uezgo^?L7LL!*bj{CdS>dE+Zr=GzSP_tAB2
zg7{>dp>qd#?x9Ik)&XYVU^2iL*9zKue!ae5Q%X@?vsEjyulLnPMoSm_GaS2`N6)au
zk!Qx3S@}$Q<3T?AJv0;#7Og(t*&UlbMs>|rL);l?tGqw9qhiUFurwD#%%I7v$#?zp
zRr}2ar~TpkYR`9e$Nu-Kds$nys?v{L`#_GpD%Z>wj!ye--@I#HmcrL@<x+3!-0r_D
WGj@dkENYYh0000<MNUMnLSTXg0LdT#

literal 0
HcmV?d00001

diff --git a/install/apps/metronome_libs/mod_webpresence/icons/status_chat.png b/install/apps/metronome_libs/mod_webpresence/icons/status_chat.png
new file mode 100644
index 0000000000000000000000000000000000000000..324f40baf379ec677e4b7b9791f94298481d7e86
GIT binary patch
literal 920
zcmV;J184k+P)<h;3K|Lk000e1NJLTq000jF000mO1^@s6$yOx<00004b3#c}2nYxW
zd<bNS00009a7bBm000fw000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^
zaAhuUa%Y?FJQ@H10~JX`K~yM_Rnvb=)O8%k@#p7r-}@oT;RV9oMDSp9sI74Yidi}{
zsbpnS%dOb#hcVY5{o|!IWR)%dsGDu#7-r0J<A=63J7z6!)7n~d*oasYHXC3})Q-FF
z9SrUc?!NE-qTu=W>+$DHi3p2pKey{piC67(I&w7*W4<stnZ7qQZ4FGuj8OBj8^15!
zss;Ss@p|v$TZ}KZJ(2&s)8Rl6kTfFGSYk3XoXma~wx9dt#Gh|3!N-o*dtYd<|N3b4
zD!)>0lyU(UA}K6MAl4+&=mayV7(EwVeII`~vKc@F)NSI^K=n$$(jK%fMr$ux`_Q@w
ztvrC6mKGZ=&2IMZjc+>e>c-Ci)aR|+cfYhRFZ_^awM}auHtj_z50J&OVp!IFPM^NP
zh7Ipv7!D$lCj6DT^rderD|C5T?!}b_hD~9hZ~)8Dx)7xbP|8Jrf1GHviiU>0^!9e~
z>~m@AcO_lv*+jEpw`Xg?LdXGGAcJKkfh@`76sJzzrnB=$x_iE2b?I-^)L4jQC@sy@
z8Y`A(%0)7Cca2b7JWc&GPL#|87Dtc%z{!(m85<j=Hyon<tdPsi1K=%5mm4!Pb93Y4
zCfBc*ke_cu=|6aSX9efa53ys%E38>l#>)q`(bi@lk^s^Gm<b%(Ol0pwA_;11w{zyq
z1-`#x(BA$F0|O2k8{Z-re3K(b=5V`b5Sa!nEK4zQ*Lg?Jrqs=Y2WJ@@>)`U`9$H&3
z5R26j3U$!g*}+=>Ab~&%%Ss?J1;DML72KVmkKp@tzR0zrl$ls1hYwfE)vI9<5g8sH
zlE%h$l1P?`nea&5R1!ClxQQHUD#`_F9^Q?J(DKpx(ESHmCS!T>+Uw;KiCmFAdmfR$
z#|tEGy8c6P6Y1(Mkag?Vek~#(B8UhdobdPE{>v`^M3H^_i{z)D^%4{}k)BI#*|OC)
z`s7n}-X&N>c%!MR?cz6{`Fjs+OVGezo&?`5l&X#8;RPrn|G#RX&08M}EYF(_R#ePZ
uFLPymqht2i$cXKxVRv2|?7#Kp;_bh*VwXTL_!Tn%0000<MNUMnLSTYjk*_@f

literal 0
HcmV?d00001

diff --git a/install/apps/metronome_libs/mod_webpresence/icons/status_dnd.png b/install/apps/metronome_libs/mod_webpresence/icons/status_dnd.png
new file mode 100644
index 0000000000000000000000000000000000000000..015f3da95dfe2a6c9dcdf414951c277104ae6b2e
GIT binary patch
literal 822
zcmV-61Ihe}P)<h;3K|Lk000e1NJLTq000jF000mO1^@s6$yOx<00004b3#c}2nYxW
zd<bNS00009a7bBm000fw000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^
zaAhuUa%Y?FJQ@H10<%d(K~yM_eUr^=TvZsxf9KqD?%X>`8bWHC5+ah88qqRn1%uG&
zQcS>)O<QnL=%y8m|AG`(ZbS%lRZ%F^Zdxiff?ZUE3hlzGP%WBlOf5;sB$=9-xp&UT
z>*AW4Ao#$6ck%vS9(bOkM1-CC@Ri0pd&=&tEz9Rq??+mg<*upy)XM9hfAsy2U+>&i
z+wkexqr=ZOmp_|ougzo%B?uu1u8fpLU^&=$`-y#57AFs$xO#csKZZ}w937ro{^Rb8
z;n8@SX%eFW@GjCTBSpv4X$LxO&$oL=7k)eP+@Y(N=fwaVXs%v(!L`O~eTJ-_U~L7v
zUPP%t41#xp>nW!Ge0XrJo?ilvC;sNOnU^;nelS>5Dz7KxeTI77VAJYAj6(2&_Yv;|
z?;>`qeCCrIU(OrT-a0!Nz1G^I6NNFFTAm<M+16U2H7Ko63Y3De)?bONHqV*7C=cA}
z3OCdMX`!jDD^jB|O3*O@9}yox2{8{u<!Q86>EG&1m_Fx5mtw+ua~GJNp2j(ca}MwQ
ze`fDJpPoO@#@rkOJvVB$0wDw;#)!2RYc2n$4Cn_QD5cG&N>*y68$5URT|Uk;v;veu
z0f-<1L_tJ|5!RaPoB>*?T`{dRTb%8=L$9tck=8WEYLY}DKn#NGRauwaK)2%&fv6Rm
zefeUt|M1iIv*x2yL!Cm$P_?Scw1Rp?pezDK5!i0>cl-9r{o$eam56Y>G5N(C_ZE(2
zI+7S&S>KiMzx`jU=UjYh?Aon+zrU#g%E^fn*C)mo)|2!fd(|t8xC?yHU+2om@KQQ9
za%$Jdc<b2frucR7Qe&n0_Ti0|PMv=Yb!sWM2M6TN(4Ol9Pwqc?^P5}EUGTP!ywrHj
zbc>TCouZNV+~{U%S69;Xu4MMBpMUt};?CW_0VwBr-clcF`v3p{07*qoM6N<$g4nQ!
A4FCWD

literal 0
HcmV?d00001

diff --git a/install/apps/metronome_libs/mod_webpresence/icons/status_offline.png b/install/apps/metronome_libs/mod_webpresence/icons/status_offline.png
new file mode 100644
index 0000000000000000000000000000000000000000..12db2af7dd86308f5abed00e3930d7f961e1ecc3
GIT binary patch
literal 905
zcmV;419tq0P)<h;3K|Lk000e1NJLTq000jF000mO1^@s6$yOx<00004b3#c}2nYxW
zd<bNS00009a7bBm000fw000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^
zaAhuUa%Y?FJQ@H10|rS%K~yM_Rg=w2V`mt}fA?PR&DC6!m|Hu7x~NmZL2#5Qbfayk
zOer%~EM#z|9qg1~Hlc`u3%6bPF9<?Gp)wtmN<pSjl&-ociqiPCY1&TGnq)*Leok^f
z-nXk*=fK&Wv-v&GQKXby*B4(7KUS5R0fg*9QQmePryv#iyO93;;?w1yu4k2M`N8Ky
zwrK?CqG9{Krqw6_LI^z1!*yLQFE7OD#j77wT|QcV_S^$dt3}HUZ#715447uE5(osS
z+As_N_V)JGP%s*I%X0s-;d{ze+0X*tM#9n7gM$M$Ha0K}1Jg7y3<F))+1c44l}eGx
zWC#Tt-n~4lJOxl6K91k74@N%C=ku7R$=KK!tE;O>DbaPEbUMxW_&6gYBRGzO@B5fW
zFg`H!@q0C%>wm55hMLJ_n4FwsaBz_J_I5@`N3m_2?(S~l@i?heist5KbX`YEsU04d
zzEKsFn*gy`jQRO_rlzLo=;&Z&Wrd!e9;T<KSz20Re}A9G#>W3iqqHf*4<DS_(MGEZ
zD4)-BdV0#-+#I1$h@+z;dV70`#bQ({70Tr@p6BuE<mg0o9LM)O@9HE?O-&SwMGA!i
z0Jd$DOeWdh-p2Dhgb)CDuB&QoH{bcH)~vGuq?GLL?vhHS=<DkvnM_itR7fNew6?ag
zu&{t-S!kNZ$!RI4`qIm|u8ZS1WV2biy1IzR<IK*^lFeqBnVDf?VuJqueij!O+1%X3
zbzOYnWt6-3KD-mqtlz?+h_=4I&f3}<rBaDRB0*<oC%*4fEEbVcQdd_;sZ;`0%9FF>
z0Yys5M|VH?-j3WD_B@YVE{CeBw6(RNX&S!oBZT1m{2br+sjV}4@y}mBZmp+>RDf{Q
zdUSYP_(M^krKJViwh=<$y6zPq%d!Xr3|{2^&P5vP6IbuK{Oq}Gc&q+a;qc$3*X0Xg
zS;04!CWOz+!-D)Xn^}oOt)5?g{`KgMRaJH8{o9`iUpz64z-?8jX>#4l%X0bkmRh5(
fq&N4zyPo|Isjz3R!I6nX00000NkvXXu0mjf4oJCl

literal 0
HcmV?d00001

diff --git a/install/apps/metronome_libs/mod_webpresence/icons/status_online.png b/install/apps/metronome_libs/mod_webpresence/icons/status_online.png
new file mode 100644
index 0000000000000000000000000000000000000000..fb257c3144736fd691d81ac82242f7d51f909679
GIT binary patch
literal 920
zcmV;J184k+P)<h;3K|Lk000e1NJLTq000jF000mO1^@s6$yOx<00004b3#c}2nYxW
zd<bNS00009a7bBm000fw000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^
zaAhuUa%Y?FJQ@H10~JX`K~yM_Rg+(6TXhu2KlgWU?oHA*HA}Z;Y+a!%v(#Z*b@fje
zMG7LDK1AGxQ0HVYhPbDKFIEtX)0e(jL1Bc|DU9K;Lv({_?ZeCj_up<7H`7())+BAZ
zCQWXV-g|%7hdXO`;K1Q<zUK?ybH0k}x~z^TKkDo^LzS0mTCLmi+3VDzmI+ji>vhH8
z7nhD)JG**T`48N8ct_-JduBA-GrtSJ*LNKkX-S-#gD>Ng8!xW^=Fz{}UK=}k#$EyU
zy}cun>iPR>;fZ3i&;>#j07zRRmnC-9#xWi2tj)%2(LcLV+qRCKJmU(0+16ZQv8&Lm
z8Y)^qL#um`K@HVVQFRq1uMi##GaJse-D*so01(^X@7|T|ntNGj0-+03zxohR=mLSD
zd9<0ypC{=U?;ySD-mAT@Kl_v@iPB*!WD7+oC_+JK!ecX36wT|^e_l^wFo9thl&vyL
zttEBN&3~X(0<|r;;JPljcp@!Jz^lc$VBeN~#Cl@%?dfBB_cRz#4w|jPs<Wcfk;t;d
zIqu-p9Bk9ZHf^kFi}oMd85$U3@Z&))cU(qp@D?vOSW!U<M_Q85ry=^ye)M4-yKG|@
zZ6Ze^oEkaB#Q6!1-8_c*jEU=br&UZvsNwC6Z!R^IA}!-BoIZY<KsG?~>m<GlK8_wd
zO4FJq;sbHA2eUYqgS0&6$n|hq3l#k+8I)V^Jb#A+0|!V9Cjgj9&(Is|B^Hm7ej|-^
zyk`LrQXyCfq_p+-*1ng!nSY_!y`+x)GDh&-AR`}+0C4D?L)?hnz^Qj|Dh@pO<fdfA
z_2>Mbs54XP*)KmE?U-*_*jCwG;dbga3l|qyyuZlsm0=3c6;{*-2+RkF{<!Yj$qQ3M
zitD<>_wH0Cjj3Dz^v<@`LN&rag)ycKGH+!-`QHe2cY{REu1UALo4Y5@CG#uBi0|F0
z{ZUSxn0q|`O5w4Buv8mV4`i4+4Zk+Hk6a3Uzo~J<{)uzR{6nr<vE<X8FILs+{_5Il
uXDw(&_4~e@p3|@D_`dt?%I{yTp8Xdmo@oJ(e(5Fv0000<MNUMnLSTZSlCmTK

literal 0
HcmV?d00001

diff --git a/install/apps/metronome_libs/mod_webpresence/icons/status_xa.png b/install/apps/metronome_libs/mod_webpresence/icons/status_xa.png
new file mode 100644
index 0000000000000000000000000000000000000000..321d35b5a3f1c832669154c1bc8f4f000c42e761
GIT binary patch
literal 954
zcmV;r14aCaP)<h;3K|Lk000e1NJLTq000jF000mO1^@s6$yOx<00004b3#c}2nYxW
zd<bNS00009a7bBm000fw000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^
zaAhuUa%Y?FJQ@H112;)TK~yM_Rg-N@RdoQyf9KqD&pnrOxi`Fs7^6%GZv(qS*n*X^
zYHba;6Ua$yLXfLyy|~ue{LqV~b49DBuKdt?aj}%ONo`4sENvhLt|&IMDSS{Yuh<1H
z_x0TK^6!J`@cI1v?fLNRk%SN|&z^?xHouW+b{j^uYFR~blxRlr{1Nx&9qJqV{k!F?
zbVKfK-WaTmML(}g{oABTNCJUv3rxeo$l640w==$S)zO(ydB@<ukabh;ZQ2;Di(Z<n
zwU<g&O~$3j09d9&&TyDdn(Rw!^rV*<Ei9fsUsF{vI4~q+fU?-!CmYOo=?EGhq`YXl
zg6>nu(-l<B#XfZvk=<|8Ur<Ed-~W`aI5%?`Kz_BMx@p7Gwa71yo2kl8H1FQej;I&Q
zBjfS9_&BT6xoa<-PjnO2{p2KAf9cAWj)&`O6(yB?A>df@P|izNq=lxIHp<q8c(!v3
z^<tj<M;@bfYdbGLwVl@3Wpo)z;t7|Si@ha#vqqT^u=lnM<9$1M^Ocua7rKWpj*lT4
zpXBwv_ZS>FLiWTEVPV4m<M@*4wbFr#;zX^L@aaA`UZ0E8wuj-uDn9)3EBt;xu~>}8
zntOR)j+04Pq>?7Nti#ytMR7T4W1BgLoMB^R9O`6)^u=kS(I^1HV34loc5sjYhUH+J
z*Q?W#B)e*Zfu1#~R1gV-fKLq{kvHDqflUp(*wck!7<4`T41rK3@BVO-yBFekfXTvw
zStYJ&Guez?0dU&!ptrTry0x9p4t_-5&)@UY$zdi&M%c6e0Cyh$k>>h(cFxCG)V(uO
z<e|En`=|aIuS_Rgy8<iudg2U=3k$rqxsm6S*RV{7GpPJpRgI?Wl#Y&)&i9J3($&q9
z5Q4|Up(C5mPPb=ehyJ_Dkz6vp7pGAjfo%yaOArMzvP{0_p?^)uH>b{CXi)%+(Ath;
z8KdUG*(>GS&R-zG^+k+jCnyFk=V=@*TrsPb6m7rd7_IG%O7`5$;qcX1+xmsLteVzM
zG3`+q59Eu90{^l6J63m}7(NxdMZS@m`@)YZnQV7aIve)p%;H7WJ$F@ACxzzzcIvl3
c`<Ju-0qPcLu<&ZF;s5{u07*qoM6N<$g22Gox&QzG

literal 0
HcmV?d00001

diff --git a/install/apps/metronome_libs/mod_webpresence/mod_webpresence.lua b/install/apps/metronome_libs/mod_webpresence/mod_webpresence.lua
new file mode 100644
index 0000000000..c1de0e0d37
--- /dev/null
+++ b/install/apps/metronome_libs/mod_webpresence/mod_webpresence.lua
@@ -0,0 +1,118 @@
+module:depends("http");
+
+local jid_split = require "util.jid".prepped_split;
+local b64 = require "util.encodings".base64.encode;
+local sha1 = require "util.hashes".sha1;
+local stanza = require "util.stanza".stanza;
+local json = require "util.json".encode_ordered;
+
+local function require_resource(name)
+    local icon_path = module:get_option_string("presence_icons", "icons");
+    local f, err  = module:load_resource(icon_path.."/"..name);
+    if f then
+        return f:read("*a");
+    end
+    module:log("warn", "Failed to open image file %s", icon_path..name);
+    return "";
+end
+
+local statuses = { online = {}, away = {}, xa = {}, dnd = {}, chat = {}, offline = {} };
+
+local function handle_request(event, path)
+  local status, message;
+  local jid, type = path:match("([^/]+)/?(.*)$");
+  if jid then
+    local user, host = jid_split(jid);
+    if host and not user then
+        user, host = host, event.request.headers.host;
+        if host then host = host:gsub(":%d+$", ""); end
+    end
+    if user and host then
+      local user_sessions = hosts[host] and hosts[host].sessions[user];
+      if user_sessions then
+        status = user_sessions.top_resources[1];
+        if status and status.presence then
+          message = status.presence:child_with_name("status");
+          status = status.presence:child_with_name("show");
+          if not status then
+            status = "online";
+          else
+            status = status:get_text();
+          end
+          if message then
+            message = message:get_text();
+          end
+        end
+      end
+    end
+  end
+  status = status or "offline";
+
+  statuses[status].image = function()
+    return { status_code = 200, headers = { content_type = "image/png" },
+      body =  require_resource("status_"..status..".png")
+    };
+  end;
+  statuses[status].html = function()
+    local jid_hash = sha1(jid, true);
+    return { status_code = 200, headers = { content_type = "text/html" },
+      body =  [[<!DOCTYPE html>]]..
+        tostring(
+          stanza("html")
+            :tag("head")
+            :tag("title"):text("XMPP Status Page for "..jid):up():up()
+            :tag("body")
+            :tag("div", { id = jid_hash.."_status", class = "xmpp_status" })
+            :tag("img", { id = jid_hash.."_img", class = "xmpp_status_image xmpp_status_"..status,
+              src = "data:image/png;base64,"..b64(require_resource("status_"..status..".png")) }):up()
+            :tag("span", { id = jid_hash.."_status_name", class = "xmpp_status_name" })
+              :text("\194\160"..status):up()
+            :tag("span", { id = jid_hash.."_status_message", class = "xmpp_status_message" })
+              :text(message and "\194\160"..message.."" or "")
+        )
+    };
+  end;
+  statuses[status].text = function()
+    return { status_code = 200, headers = { content_type = "text/plain" },
+      body = status
+    };
+  end;
+  statuses[status].message = function()
+    return { status_code = 200, headers = { content_type = "text/plain" },
+      body = (message and message or "")
+    };
+  end;
+  statuses[status].json = function()
+    return { status_code = 200, headers = { content_type = "application/json" },
+      body = json({
+        jid    = jid,
+        show   = status,
+        status = (message and message or "null")
+      })
+    };
+  end;
+  statuses[status].xml = function()
+    return { status_code = 200, headers = { content_type = "application/xml" },
+      body = [[<?xml version="1.0" encoding="utf-8"?>]]..
+        tostring(
+          stanza("result")
+            :tag("jid"):text(jid):up()
+            :tag("show"):text(status):up()
+            :tag("status"):text(message)
+        )
+      };
+  end
+
+  if ((type == "") or (not statuses[status][type])) then
+    type = "image"
+  end;
+
+  return statuses[status][type]();
+end
+
+module:provides("http", {
+    default_path = "/status";
+    route = {
+        ["GET /*"] = handle_request;
+    };
+});
diff --git a/install/dist/conf/debian60.conf.php b/install/dist/conf/debian60.conf.php
index a3819966b9..e18faa4967 100644
--- a/install/dist/conf/debian60.conf.php
+++ b/install/dist/conf/debian60.conf.php
@@ -222,5 +222,9 @@ $conf['cron']['init_script'] = 'cron';
 $conf['cron']['crontab_dir'] = '/etc/cron.d';
 $conf['cron']['wget'] = '/usr/bin/wget';
 
+//* Metronome XMPP
+$conf['xmpp']['installed'] = false;
+$conf['xmpp']['init_script'] = 'metronome';
+
 
 ?>
diff --git a/install/dist/lib/debian60.lib.php b/install/dist/lib/debian60.lib.php
index 584e6aa91c..fab5628a77 100644
--- a/install/dist/lib/debian60.lib.php
+++ b/install/dist/lib/debian60.lib.php
@@ -154,6 +154,10 @@ class installer extends installer_base {
 	*/
 	}
 
+    public function configure_xmpp() {
+        parent::configure_xmpp();
+    }
+
 }
 
 ?>
diff --git a/install/install.php b/install/install.php
index 91759f2284..3aedfefa85 100644
--- a/install/install.php
+++ b/install/install.php
@@ -347,6 +347,13 @@ if($install_mode == 'standard') {
 	}
 	*/
 
+    //* Configure XMPP
+    if($conf['xmpp']['installed'] == true){
+        $conf['services']['xmpp'] = true;
+        swriteln('Configuring Metronome XMPP Server');
+        $inst->configure_xmpp();
+    }
+
 	//* Configure ISPConfig
 	swriteln('Installing ISPConfig');
 
@@ -398,6 +405,7 @@ if($install_mode == 'standard') {
 	//if($conf['squid']['installed'] == true && $conf['squid']['init_script'] != '' && is_file($conf['init_scripts'].'/'.$conf['squid']['init_script']))     system($conf['init_scripts'].'/'.$conf['squid']['init_script'].' restart &> /dev/null');
 	if($conf['nginx']['installed'] == true && $conf['nginx']['init_script'] != '') system($inst->getinitcommand($conf['nginx']['init_script'], 'restart').' &> /dev/null');
 	if($conf['ufw']['installed'] == true && $conf['ufw']['init_script'] != '') system($inst->getinitcommand($conf['ufw']['init_script'], 'restart').' &> /dev/null');
+    if($conf['xmpp']['installed'] == true && $conf['xmpp']['init_script'] != '') system($inst->getinitcommand($conf['xmpp']['init_script'], 'restart').' &> /dev/null');
 
 } else {
 
@@ -408,6 +416,7 @@ if($install_mode == 'standard') {
 	$conf['services']['db'] = true;
 	$conf['services']['firewall'] = false;
 	$conf['services']['proxy'] = false;
+    $conf['services']['xmpp'] = false;
 
 
 	//** Get Server ID
@@ -639,6 +648,16 @@ if($install_mode == 'standard') {
 		$inst->configure_firewall();
 	}*/
 
+    //** Configure XMPP
+    if($conf['xmpp']['installed'] == true){
+        if(strtolower($inst->simple_query('Configure Metronome XMPP Server', array('y', 'n'), 'y', 'configure_xmpp')) == 'y'){
+            $conf['services']['xmpp'] = true;
+            swriteln('Configuring Metronome XMPP Server');
+            $inst->configure_xmpp();
+            if($conf['xmpp']['installed'] == true && $conf['xmpp']['init_script'] != '') system($inst->getinitcommand($conf['xmpp']['init_script'], 'restart').' &> /dev/null');
+        }
+    }
+
 	//** Configure ISPConfig :-)
 	$install_ispconfig_interface_default = ($conf['mysql']['master_slave_setup'] == 'y')?'n':'y';
 	if(strtolower($inst->simple_query('Install ISPConfig Web Interface', array('y', 'n'), $install_ispconfig_interface_default,'install_ispconfig_web_interface')) == 'y') {
diff --git a/install/lib/installer_base.lib.php b/install/lib/installer_base.lib.php
index ae64463c17..688cfdb6ef 100644
--- a/install/lib/installer_base.lib.php
+++ b/install/lib/installer_base.lib.php
@@ -155,6 +155,7 @@ class installer_base {
 		if(is_installed('fail2ban-server')) $conf['fail2ban']['installed'] = true;
 		if(is_installed('vzctl')) $conf['openvz']['installed'] = true;
 		if(is_dir("/etc/Bastille")) $conf['bastille']['installed'] = true;
+        if(is_installed('metronome') && is_installed('metronomectl')) $conf['xmpp']['installed'] = true;
 
 		if ($conf['services']['web'] && (($conf['apache']['installed'] && is_file($conf['apache']["vhost_conf_enabled_dir"]."/000-ispconfig.vhost")) || ($conf['nginx']['installed'] && is_file($conf['nginx']["vhost_conf_enabled_dir"]."/000-ispconfig.vhost")))) $this->ispconfig_interface_installed = true;
 	}
@@ -1308,6 +1309,66 @@ class installer_base {
 	}
 
 
+    public function configure_xmpp() {
+        global $conf;
+
+        if($conf['xmpp']['installed'] == false) return;
+        //* Create the logging directory for xmpp server
+        if(!@is_dir('/var/log/metronome')) mkdir('/var/log/metronome', 0755, true);
+        chown('/var/log/metronome', 'metronome');
+        if(!@is_dir('/var/run/metronome')) mkdir('/var/run/metronome', 0755, true);
+        chown('/var/run/metronome', 'metronome');
+        if(!@is_dir('/var/lib/metronome')) mkdir('/var/lib/metronome', 0755, true);
+        chown('/var/lib/metronome', 'metronome');
+        if(!@is_dir('/etc/metronome/hosts')) mkdir('/etc/metronome/hosts', 0755, true);
+        if(!@is_dir('/etc/metronome/status')) mkdir('/etc/metronome/status', 0755, true);
+        unlink('/etc/metronome/metronome.cfg.lua');
+
+        $row = $this->db->queryOneRecord("SELECT server_name FROM server WHERE server_id = ".$conf["server_id"]."");
+        $server_name = $row["server_name"];
+
+        $tpl = new tpl('metronome_conf_main.master');
+        wf('/etc/metronome/metronome.cfg.lua', $tpl->grab());
+        unset($tpl);
+
+        $tpl = new tpl('metronome_conf_global.master');
+        $tpl->setVar('xmpp_admins','');
+        wf('/etc/metronome/global.cfg.lua', $tpl->grab());
+        unset($tpl);
+
+        // Copy isp libs
+        if(!@is_dir('/usr/lib/metronome/isp-modules')) mkdir('/usr/lib/metronome/isp-modules', 0755, true);
+        caselog('cp -rf apps/metronome_libs/* /usr/lib/metronome/isp-modules/', __FILE__, __LINE__);
+
+        // Copy init script
+        caselog('cp -f apps/metronome-init /etc/init.d/metronome', __FILE__, __LINE__);
+        caselog('chmod u+x /etc/init.d/metronome', __FILE__, __LINE__);
+
+        exec($this->getinitcommand('xmpp', 'restart'));
+
+
+
+        /*// Dont just copy over the virtualhost template but add some custom settings
+        $tpl = new tpl('apache_apps.vhost.master');
+
+        $tpl->setVar('apps_vhost_port',$conf['web']['apps_vhost_port']);
+        $tpl->setVar('apps_vhost_dir',$conf['web']['website_basedir'].'/apps');
+        $tpl->setVar('apps_vhost_basedir',$conf['web']['website_basedir']);
+        $tpl->setVar('apps_vhost_servername',$apps_vhost_servername);
+        $tpl->setVar('apache_version',getapacheversion());
+
+
+        // comment out the listen directive if port is 80 or 443
+        if($conf['web']['apps_vhost_ip'] == 80 or $conf['web']['apps_vhost_ip'] == 443) {
+            $tpl->setVar('vhost_port_listen','#');
+        } else {
+            $tpl->setVar('vhost_port_listen','');
+        }
+
+        wf($vhost_conf_dir.'/apps.vhost', $tpl->grab());
+        unset($tpl);*/
+    }
+
 
 	public function configure_apache() {
 		global $conf;
@@ -1969,8 +2030,9 @@ class installer_base {
 		$vserver_server_enabled = ($conf['openvz']['installed'])?1:0;
 		$proxy_server_enabled = ($conf['services']['proxy'])?1:0;
 		$firewall_server_enabled = ($conf['services']['firewall'])?1:0;
+        $xmpp_server_enabled = ($conf['services']['xmpp'])?1:0;
 
-		$sql = "UPDATE `server` SET mail_server = '$mail_server_enabled', web_server = '$web_server_enabled', dns_server = '$dns_server_enabled', file_server = '$file_server_enabled', db_server = '$db_server_enabled', vserver_server = '$vserver_server_enabled', proxy_server = '$proxy_server_enabled', firewall_server = '$firewall_server_enabled' WHERE server_id = ".intval($conf['server_id']);
+		$sql = "UPDATE `server` SET mail_server = '$mail_server_enabled', web_server = '$web_server_enabled', dns_server = '$dns_server_enabled', file_server = '$file_server_enabled', db_server = '$db_server_enabled', vserver_server = '$vserver_server_enabled', proxy_server = '$proxy_server_enabled', firewall_server = '$firewall_server_enabled', xmpp_server = '.$xmpp_server_enabled.' WHERE server_id = ".intval($conf['server_id']);
 
 		if($conf['mysql']['master_slave_setup'] == 'y') {
 			$this->dbmaster->query($sql);
diff --git a/install/sql/incremental/upd_0081.sql b/install/sql/incremental/upd_0081.sql
new file mode 100644
index 0000000000..f525e7295f
--- /dev/null
+++ b/install/sql/incremental/upd_0081.sql
@@ -0,0 +1,55 @@
+ALTER TABLE `server` ADD COLUMN `xmpp_server` tinyint(1) NOT NULL default '0' AFTER `firewall_server`;
+
+ALTER TABLE `client`
+  ADD COLUMN `limit_xmpp_domain` int(11) NOT NULL DEFAULT '-1',
+  ADD COLUMN `limit_xmpp_user` int(11) NOT NULL DEFAULT '-1',
+  ADD COLUMN `limit_xmpp_muc` ENUM( 'n', 'y' ) NOT NULL default 'n',
+  ADD COLUMN `limit_xmpp_anon` ENUM( 'n', 'y' ) NOT NULL default 'n',
+  ADD COLUMN `limit_xmpp_auth_options` varchar(255) NOT NULL DEFAULT 'plain,hashed,isp',
+  ADD COLUMN `limit_xmpp_vjud` ENUM( 'n', 'y' ) NOT NULL default 'n',
+  ADD COLUMN `limit_xmpp_proxy` ENUM( 'n', 'y' ) NOT NULL default 'n',
+  ADD COLUMN `limit_xmpp_status` ENUM( 'n', 'y' ) NOT NULL default 'n',
+  ADD COLUMN `limit_xmpp_pastebin` ENUM( 'n', 'y' ) NOT NULL default 'n',
+  ADD COLUMN `limit_xmpp_httparchive` ENUM( 'n', 'y' ) NOT NULL default 'n';
+
+
+CREATE TABLE `xmpp_domain` (
+  `domain_id` int(11) unsigned NOT NULL auto_increment,
+  `sys_userid` int(11) unsigned NOT NULL default '0',
+  `sys_groupid` int(11) unsigned NOT NULL default '0',
+  `sys_perm_user` varchar(5) NOT NULL default '',
+  `sys_perm_group` varchar(5) NOT NULL default '',
+  `sys_perm_other` varchar(5) NOT NULL default '',
+  `server_id` int(11) unsigned NOT NULL default '0',
+  `domain` varchar(255) NOT NULL default '',
+
+  `auth_method` ENUM( 'isp', 'plain', 'hashed' ) NOT NULL default 'hashed',
+  `public_registration` ENUM( 'n', 'y' ) NOT NULL default 'n',
+  `registration_url` varchar(255) NOT NULL DEFAULT '',
+  `registration_message` varchar(255) NOT NULL DEFAULT '',
+  `domain_admins` text,
+
+  `use_pubsub` enum('n','y') NOT NULL DEFAULT 'n',
+  `use_proxy` enum('n','y') NOT NULL DEFAULT 'n',
+  `use_anon_host` enum('n','y') NOT NULL DEFAULT 'n',
+
+  `use_vjud` enum('n','y') NOT NULL DEFAULT 'n',
+  `vjud_opt_mode` enum('in', 'out') NOT NULL DEFAULT 'in',
+
+  `use_muc_host` enum('n','y') NOT NULL DEFAULT 'n',
+  `muc_name` varchar(30) NOT NULL DEFAULT ''
+  `muc_restrict_room_creation` enum('n', 'y', 'm') NOT NULL DEFAULT 'm',
+  `muc_admins` text,
+  `use_pastebin` enum('n','y') NOT NULL DEFAULT 'n',
+  `pastebin_expire_after` int(3) NOT NULL DEFAULT 48,
+  `pastebin_trigger` varchar(10) NOT NULL DEFAULT '!paste',
+  `use_http_archive` enum('n','y') NOT NULL DEFAULT 'n',
+  `http_archive_show_join` enum('n', 'y') NOT NULL DEFAULT 'n',
+  `http_archive_show_status` enum('n', 'y') NOT NULL DEFAULT 'n',
+  `use_status_host` enum('n','y') NOT NULL DEFAULT 'n',
+
+  `active` enum('n','y') NOT NULL DEFAULT 'n',
+  PRIMARY KEY  (`domain_id`),
+  KEY `server_id` (`server_id`,`domain`),
+  KEY `domain_active` (`domain`,`active`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
\ No newline at end of file
diff --git a/install/sql/ispconfig3.sql b/install/sql/ispconfig3.sql
index 8b791657f9..1f5b4180f9 100644
--- a/install/sql/ispconfig3.sql
+++ b/install/sql/ispconfig3.sql
@@ -184,6 +184,16 @@ CREATE TABLE `client` (
   `limit_spamfilter_wblist` int(11) NOT NULL DEFAULT '0',
   `limit_spamfilter_user` int(11) NOT NULL DEFAULT '0',
   `limit_spamfilter_policy` int(11) NOT NULL DEFAULT '0',
+  `limit_xmpp_domain` int(11) NOT NULL DEFAULT '-1',
+  `limit_xmpp_user` int(11) NOT NULL DEFAULT '-1',
+  `limit_xmpp_muc` ENUM( 'n', 'y' ) NOT NULL default 'n',
+  `limit_xmpp_anon` ENUM( 'n', 'y' ) NOT NULL default 'n',
+  `limit_xmpp_auth_options` varchar(255) NOT NULL DEFAULT 'plain,hashed,isp',
+  `limit_xmpp_vjud` ENUM( 'n', 'y' ) NOT NULL default 'n',
+  `limit_xmpp_proxy` ENUM( 'n', 'y' ) NOT NULL default 'n',
+  `limit_xmpp_status` ENUM( 'n', 'y' ) NOT NULL default 'n',
+  `limit_xmpp_pastebin` ENUM( 'n', 'y' ) NOT NULL default 'n',
+  `limit_xmpp_httparchive` ENUM( 'n', 'y' ) NOT NULL default 'n',
   `default_webserver` int(11) unsigned NOT NULL DEFAULT '1',
   `web_servers` blob,
   `limit_web_ip` text,
@@ -1201,6 +1211,7 @@ CREATE TABLE `server` (
   `vserver_server` tinyint(1) NOT NULL default '0',
   `proxy_server` tinyint(1) NOT NULL default '0',
   `firewall_server` tinyint(1) NOT NULL default '0',
+  `xmpp_server` tinyint(1) NOT NULL default '0',
   `config` text,
   `updated` bigint(20) unsigned NOT NULL default '0',
   `mirror_server_id` int(11) unsigned NOT NULL default '0',
@@ -1950,6 +1961,54 @@ CREATE TABLE `web_traffic` (
   PRIMARY KEY  (`hostname`,`traffic_date`)
 ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
 
+-- --------------------------------------------------------
+
+--
+-- Table structure for table  `xmpp_domain`
+--
+
+CREATE TABLE `xmpp_domain` (
+  `domain_id` int(11) unsigned NOT NULL auto_increment,
+  `sys_userid` int(11) unsigned NOT NULL default '0',
+  `sys_groupid` int(11) unsigned NOT NULL default '0',
+  `sys_perm_user` varchar(5) NOT NULL default '',
+  `sys_perm_group` varchar(5) NOT NULL default '',
+  `sys_perm_other` varchar(5) NOT NULL default '',
+  `server_id` int(11) unsigned NOT NULL default '0',
+  `domain` varchar(255) NOT NULL default '',
+
+  `auth_method` ENUM( 'isp', 'plain', 'hashed' ) NOT NULL default 'hashed',
+  `public_registration` ENUM( 'n', 'y' ) NOT NULL default 'n',
+  `registration_url` varchar(255) NOT NULL DEFAULT '',
+  `registration_message` varchar(255) NOT NULL DEFAULT '',
+  `domain_admins` text,
+
+  `use_pubsub` enum('n','y') NOT NULL DEFAULT 'n',
+  `use_proxy` enum('n','y') NOT NULL DEFAULT 'n',
+  `use_anon_host` enum('n','y') NOT NULL DEFAULT 'n',
+
+  `use_vjud` enum('n','y') NOT NULL DEFAULT 'n',
+  `vjud_opt_mode` enum('in', 'out') NOT NULL DEFAULT 'in',
+
+  `use_muc_host` enum('n','y') NOT NULL DEFAULT 'n',
+  `muc_name` varchar(30) NOT NULL DEFAULT '',
+  `muc_restrict_room_creation` enum('n', 'y', 'm') NOT NULL DEFAULT 'm',
+  `muc_admins` text,
+  `use_pastebin` enum('n','y') NOT NULL DEFAULT 'n',
+  `pastebin_expire_after` int(3) NOT NULL DEFAULT 48,
+  `pastebin_trigger` varchar(10) NOT NULL DEFAULT '!paste',
+  `use_http_archive` enum('n','y') NOT NULL DEFAULT 'n',
+  `http_archive_show_join` enum('n', 'y') NOT NULL DEFAULT 'n',
+  `http_archive_show_status` enum('n', 'y') NOT NULL DEFAULT 'n',
+  `use_status_host` enum('n','y') NOT NULL DEFAULT 'n',
+
+  `active` enum('n','y') NOT NULL DEFAULT 'n',
+  PRIMARY KEY  (`domain_id`),
+  KEY `server_id` (`server_id`,`domain`),
+  KEY `domain_active` (`domain`,`active`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
+
+
 -- --------------------------------------------------------
 -- --------------------------------------------------------
 -- DB-DATA
diff --git a/install/tpl/metronome_conf_global.master b/install/tpl/metronome_conf_global.master
new file mode 100644
index 0000000000..68f4c59b6b
--- /dev/null
+++ b/install/tpl/metronome_conf_global.master
@@ -0,0 +1,65 @@
+pidfile = "/var/run/metronome/metronome.pid";
+metronome_max_files_soft = 200000;
+metronome_max_files_hard = 300000;
+plugin_paths = {
+        "/usr/lib/metronome/isp-modules",
+};
+use_libevent = true;
+log = {
+        debug = "/var/log/metronome/metronome.dbg",
+        info = "/var/log/metronome/metronome.log",
+        error = "/var/log/metronome/metronome.err",
+};
+use_ipv6 = true;
+http_ports = {
+        5290,
+};
+https_ports = {
+        5291,
+};
+pastebin_ports = {
+        5292,
+};
+bosh_ports = {
+        5280,
+};
+admins = {
+        {tmpl_var xmpp_admins}
+};
+modules_enabled = {
+        "saslauth",
+        "tls",
+        "dialback",
+        "disco",
+        "discoitems",
+        "version",
+        "uptime",
+        "time",
+        "ping",
+        "admin_adhoc",
+        "admin_telnet",
+        "bosh",
+        "posix",
+        "announce",
+        "offline",
+        "webpresence",
+        "mam",
+        "stream_management",
+        "message_carbons"
+};
+modules_disabled = {
+};
+bosh_max_inactivity = 30;
+consider_bosh_secure = true;
+cross_domain_bosh = true;
+allow_registration = false;
+ssl = {
+        key = "/etc/metronome/certs/localhost.key",
+        certificate = "/etc/metronome/certs/localhost.cert",
+};
+c2s_require_encryption = false;
+s2s_secure = true;
+s2s_insecure_domains = {
+        "gmail.com",
+};
+authentication = "internal_plain";
diff --git a/install/tpl/metronome_conf_main.master b/install/tpl/metronome_conf_main.master
new file mode 100644
index 0000000000..f9c8fbdd65
--- /dev/null
+++ b/install/tpl/metronome_conf_main.master
@@ -0,0 +1,3 @@
+Include "/etc/metronome/global.cfg.lua"
+Include "/etc/metronome/hosts/*.lua"
+Include "/etc/metronome/status/*.lua"
diff --git a/install/tpl/server.ini.master b/install/tpl/server.ini.master
index 7805988a71..20dca2d42f 100644
--- a/install/tpl/server.ini.master
+++ b/install/tpl/server.ini.master
@@ -145,3 +145,12 @@ do_not_try_rescue_httpd=n
 do_not_try_rescue_mysql=n
 do_not_try_rescue_mail=n
 
+[xmpp]
+xmpp_use_ispv6=n
+xmpp_bosh_max_inactivity=30
+xmpp_server_admins=admin@service.com, superuser@service.com
+xmpp_modules_enabled=saslauth, tls, dialback, disco, discoitems, version, uptime, time, ping, admin_adhoc, admin_telnet, bosh, posix, announce, offline, webpresence, mam, stream_management, message_carbons
+xmpp_port_http=5290
+xmpp_port_https=5291
+xmpp_port_pastebin=5292
+xmpp_port_bosh=5280
diff --git a/interface/web/admin/form/server.tform.php b/interface/web/admin/form/server.tform.php
index a2eac6c3b7..1bf079e1b0 100644
--- a/interface/web/admin/form/server.tform.php
+++ b/interface/web/admin/form/server.tform.php
@@ -102,6 +102,12 @@ $form["tabs"]['services'] = array (
 			'default' => '0',
 			'value'  => array(0 => 0, 1 => 1)
 		),
+		'xmpp_server' => array (
+			'datatype' => 'INTEGER',
+			'formtype' => 'CHECKBOX',
+			'default' => '0',
+			'value'  => array(0 => 0, 1 => 1)
+		),
 		'mirror_server_id' => array (
 			'datatype' => 'INTEGER',
 			'formtype' => 'TEXT',
diff --git a/interface/web/admin/form/server_config.tform.php b/interface/web/admin/form/server_config.tform.php
index 6f1c889bb5..351d4de86c 100644
--- a/interface/web/admin/form/server_config.tform.php
+++ b/interface/web/admin/form/server_config.tform.php
@@ -1318,6 +1318,86 @@ $form["tabs"]['fastcgi'] = array(
 );
 
 
+$form["tabs"]['xmpp'] = array(
+    'title' => "XMPP",
+    'width' => 80,
+    'template' => "templates/server_config_xmpp_edit.htm",
+    'fields' => array(
+        //#################################
+        // Begin Datatable fields
+        //#################################
+        'xmpp_use_ipv6' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOX',
+            'default' => 'n',
+            'value' => array(0 => 'n', 1 => 'y')
+        ),
+        'xmpp_bosh_max_inactivity' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'TEXT',
+            'default' => '30',
+            'validators' => array(0 => array('type' => 'ISINT',
+                'errmsg' => 'ip_address_error_wrong'),
+                array('type'=>'RANGE', 'range'=>'15:360', 'errmsg' => 'xmpp_bosh_timeout_range_wrong')
+            ),
+            'value' => '',
+            'width' => '15'
+        ),
+
+        'xmpp_server_admins' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'TEXT',
+            'default' => 'admin@service.com, superuser@service.com',
+            'value' => '',
+            'width' => '15'
+        ),
+
+        'xmpp_modules_enabled' => array(
+            'datatype' => 'TEXT',
+            'formtype' => 'TEXT',
+            'default' => "saslauth, tls, dialback, disco, discoitems, version, uptime, time, ping, admin_adhoc, admin_telnet, bosh, posix, announce, offline, webpresence, mam, stream_management, message_carbons",
+            'value' => '',
+            'separator' => ","
+        ),
+
+        'xmpp_port_http' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'TEXT',
+            'default' => '5290',
+            'validators' => array(0 => array('type' => 'ISINT')),
+            'value' => '5290',
+            'width' => '15'
+        ),
+        'xmpp_port_https' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'TEXT',
+            'default' => '5291',
+            'validators' => array(0 => array('type' => 'ISINT')),
+            'value' => '5291',
+            'width' => '15'
+        ),
+        'xmpp_port_pastebin' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'TEXT',
+            'default' => '5292',
+            'validators' => array(0 => array('type' => 'ISINT')),
+            'value' => '5292',
+            'width' => '15'
+        ),
+        'xmpp_port_bosh' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'TEXT',
+            'default' => '5280',
+            'validators' => array(0 => array('type' => 'ISINT')),
+            'value' => '5280',
+            'width' => '15'
+        ),
+        //#################################
+        // ENDE Datatable fields
+        //#################################
+    )
+);
+
 $form["tabs"]['jailkit'] = array(
 	'title' => "Jailkit",
 	'width' => 80,
diff --git a/interface/web/admin/lib/lang/en_server.lng b/interface/web/admin/lib/lang/en_server.lng
index 4130201b7c..1f36bc718e 100644
--- a/interface/web/admin/lib/lang/en_server.lng
+++ b/interface/web/admin/lib/lang/en_server.lng
@@ -12,4 +12,6 @@ $wb["firewall_server_txt"] = 'Firewall-Server';
 $wb["active_txt"] = 'Active';
 $wb["mirror_server_id_txt"] = 'Is mirror of Server';
 $wb["- None -"] = '- None -';
+// New for XMPP
+$wb['xmpp_server_txt'] = 'XMPP Server';
 ?>
\ No newline at end of file
diff --git a/interface/web/admin/lib/lang/en_server_config.lng b/interface/web/admin/lib/lang/en_server_config.lng
index 8affba0c14..aac7390659 100644
--- a/interface/web/admin/lib/lang/en_server_config.lng
+++ b/interface/web/admin/lib/lang/en_server_config.lng
@@ -264,4 +264,18 @@ $wb['php_ini_check_minutes_txt'] = 'Check php.ini every X minutes for changes';
 $wb['php_ini_check_minutes_error_empty'] = 'Please specify a value how often php.ini should be checked for changes.';
 $wb['php_ini_check_minutes_info_txt'] = '0 = no check';
 $wb['enable_spdy_txt'] = 'Makes SPDY available';
+
+// New for XMPP
+$wb['xmpp_server_txt'] = 'XMPP Server';
+$wb['xmpp_use_ipv6_txt'] = 'Use IPv6';
+$wb['xmpp_bosh_max_inactivity_txt'] = 'Max. BOSH inactivity time';
+$wb['xmpp_bosh_timeout_range_wrong'] = 'Please enter a bosh timeout range between 15 - 360';
+$wb['xmpp_module_saslauth'] = 'saslauth';
+$wb['xmpp_server_admins_txt'] = 'Server Admins (JIDs)';
+$wb['xmpp_modules_enabled_txt'] = 'Serverwide enabled plugins (one per line)';
+$wb['xmpp_ports_txt'] = 'Component ports';
+$wb['xmpp_port_http_txt'] = 'HTTP';
+$wb['xmpp_port_https_txt'] = 'HTTPS';
+$wb['xmpp_port_pastebin_txt'] = 'Pastebin';
+$wb['xmpp_port_bosh_txt'] = 'BOSH';
 ?>
diff --git a/interface/web/admin/lib/lang/en_server_list.lng b/interface/web/admin/lib/lang/en_server_list.lng
index 164468e700..89a81fa43b 100644
--- a/interface/web/admin/lib/lang/en_server_list.lng
+++ b/interface/web/admin/lib/lang/en_server_list.lng
@@ -10,4 +10,6 @@ $wb["vserver_server_txt"] = 'VServer';
 $wb["proxy_server_txt"] = 'Proxy';
 $wb["firewall_server_txt"] = 'Firewall';
 $wb["add_new_record_txt"] = 'Add new Server';
+// New for XMPP
+$wb['xmpp_server_txt'] = 'XMPP';
 ?>
\ No newline at end of file
diff --git a/interface/web/admin/list/server.list.php b/interface/web/admin/list/server.list.php
index 0309b7a3c1..0290632405 100644
--- a/interface/web/admin/list/server.list.php
+++ b/interface/web/admin/list/server.list.php
@@ -110,4 +110,13 @@ $liste['item'][] = array( 'field'  => 'vserver_server',
 	'width'  => '',
 	'value'  => array('1' => "<div id=\"ir-Yes\" class=\"swap\"><span>Yes</span></div>", '0' => "<div class=\"swap\" id=\"ir-No\"><span>No</span></div>"));
 
+$liste['item'][] = array( 'field'  => 'xmpp_server',
+	'datatype' => 'VARCHAR',
+	'formtype' => 'SELECT',
+	'op'  => 'like',
+	'prefix' => '%',
+	'suffix' => '%',
+	'width'  => '',
+	'value'  => array('1' => "<div id=\"ir-Yes\" class=\"swap\"><span>Yes</span></div>", '0' => "<div class=\"swap\" id=\"ir-No\"><span>No</span></div>"));
+
 ?>
diff --git a/interface/web/admin/templates/server_config_xmpp_edit.htm b/interface/web/admin/templates/server_config_xmpp_edit.htm
new file mode 100644
index 0000000000..acf019b9ff
--- /dev/null
+++ b/interface/web/admin/templates/server_config_xmpp_edit.htm
@@ -0,0 +1,73 @@
+<div class='page-header'>
+	<h1><tmpl_var name="list_head_txt"></h1>
+</div>
+<p><tmpl_var name="list_desc_txt"></p>
+
+
+
+<div class="form-group">
+    <label class="col-sm-3 control-label">{tmpl_var name='xmpp_use_ipv6_txt'}</label>
+    <div class="col-sm-9">
+        {tmpl_var name='xmpp_use_ipv6'}
+    </div>
+</div>
+<div class="form-group">
+    <label class="col-sm-3 control-label">{tmpl_var name='xmpp_bosh_max_inactivity_txt'}</label>
+    <div class="col-sm-3">
+        <input type="number" name="xmpp_bosh_max_inactivity" id="xmpp_bosh_max_inactivity" value="{tmpl_var name='xmpp_bosh_max_inactivity'}" class="form-control" />
+    </div>
+</div>
+
+<div class="form-group">
+    <label class="col-sm-3 control-label">{tmpl_var name='xmpp_server_admins_txt'}</label>
+    <div class="col-sm-9">
+        <input type="text" name="xmpp_server_admins" id="xmpp_server_admins" value="{tmpl_var name='xmpp_server_admins'}" class="form-control" />
+    </div>
+</div>
+
+<div class="form-group">
+    <label class="col-sm-3 control-label">{tmpl_var name='xmpp_modules_enabled_txt'}</label>
+    <div class="col-sm-9"><textarea class="form-control" name="xmpp_modules_enabled" id="xmpp_modules_enabled" rows='3' cols='30'>{tmpl_var name='xmpp_modules_enabled'}</textarea></div>
+</div>
+<div class="col-sm-12">
+    <h4>{tmpl_var name='xmpp_ports_txt'}</h4>
+    <div class="col-sm-6">
+        <div class="form-group">
+            <label class="col-sm-6 control-label">{tmpl_var name='xmpp_port_http_txt'}</label>
+            <div class="col-sm-6">
+                <input type="number" name="xmpp_port_http" id="xmpp_port_http" value="{tmpl_var name='xmpp_port_http'}" class="form-control" />
+            </div>
+        </div>
+    </div>
+    <div class="col-sm-6">
+        <div class="form-group">
+            <label class="col-sm-6 control-label">{tmpl_var name='xmpp_port_https_txt'}</label>
+            <div class="col-sm-6">
+                <input type="number" name="xmpp_port_https" id="xmpp_port_https" value="{tmpl_var name='xmpp_port_https'}" class="form-control" />
+            </div>
+        </div>
+    </div>
+    <div class="col-sm-6">
+        <div class="form-group">
+            <label class="col-sm-6 control-label">{tmpl_var name='xmpp_port_pastebin_txt'}</label>
+            <div class="col-sm-6">
+                <input type="number" name="xmpp_port_pastebin" id="xmpp_port_pastebin" value="{tmpl_var name='xmpp_port_pastebin'}" class="form-control" />
+            </div>
+        </div>
+    </div>
+    <div class="col-sm-6">
+        <div class="form-group">
+            <label class="col-sm-6 control-label">{tmpl_var name='xmpp_port_bosh_txt'}</label>
+            <div class="col-sm-6">
+                <input type="number" name="xmpp_port_bosh" id="xmpp_port_bosh" value="{tmpl_var name='xmpp_port_bosh'}" class="form-control" />
+            </div>
+        </div>
+    </div>
+</div>
+
+<input type="hidden" name="id" value="{tmpl_var name='id'}">
+
+<div class="clear"><div class="right">
+    <button class="btn btn-default formbutton-success" type="button" value="{tmpl_var name='btn_save_txt'}" data-submit-form="pageForm" data-form-action="admin/server_config_edit.php">{tmpl_var name='btn_save_txt'}</button>
+    <button class="btn btn-default formbutton-default" type="button" value="{tmpl_var name='btn_cancel_txt'}" data-load-content="admin/server_config_list.php">{tmpl_var name='btn_cancel_txt'}</button>
+</div></div>
diff --git a/interface/web/admin/templates/server_edit_services.htm b/interface/web/admin/templates/server_edit_services.htm
index aca706a0f7..4a648f4591 100644
--- a/interface/web/admin/templates/server_edit_services.htm
+++ b/interface/web/admin/templates/server_edit_services.htm
@@ -44,6 +44,12 @@
                     {tmpl_var name='vserver_server'}
                 </div>
             </div>
+            <div class="form-group">
+                <label class="col-sm-3 control-label">{tmpl_var name='xmpp_server_txt'}</label>
+                <div class="col-sm-9">
+                    {tmpl_var name='xmpp_server'}
+                </div>
+            </div>
             <div class="form-group">
                 <label for="mirror_server_id" class="col-sm-3 control-label">{tmpl_var name='mirror_server_id_txt'}</label>
                 <div class="col-sm-9"><select name="mirror_server_id" id="server_id" class="form-control">
diff --git a/interface/web/admin/templates/server_list.htm b/interface/web/admin/templates/server_list.htm
index ce568b884e..016b0cd1df 100644
--- a/interface/web/admin/templates/server_list.htm
+++ b/interface/web/admin/templates/server_list.htm
@@ -16,6 +16,7 @@
                         <th data-column="file_server"><tmpl_var name="file_server_txt"></th>
                         <th data-column="db_server"><tmpl_var name="db_server_txt"></th>
                         <th data-column="vserver_server"><tmpl_var name="vserver_server_txt"></th>
+                        <th data-column="vserver_server"><tmpl_var name="xmpp_server_txt"></th>
                         <th class="small-col text-right">{tmpl_var name='search_limit'}</th>
                     </tr>
                     <tr>
@@ -26,6 +27,7 @@
                         <td><select class="form-control" name="search_active">{tmpl_var name='search_file_server'}</select></td>
                         <td><select class="form-control" name="search_active">{tmpl_var name='search_db_server'}</select></td>
                         <td><select class="form-control" name="search_active">{tmpl_var name='search_vserver_server'}</select></td>
+                        <td><select class="form-control" name="search_active">{tmpl_var name='search_xmpp_server'}</select></td>
                         <td class="text-right">
                             <button type="button" class="btn btn-default formbutton-default formbutton-narrow" name="Filter" id="Filter" value="{tmpl_var name="filter_txt"}" data-submit-form="pageForm" data-form-action="admin/server_list.php"><span class="icon icon-filter"></span></button>
                         </td>
@@ -41,6 +43,7 @@
                             <td>{tmpl_var name="file_server"}</td>
                             <td>{tmpl_var name="db_server"}</td>
                             <td>{tmpl_var name="vserver_server"}</td>
+                            <td>{tmpl_var name="xmpp_server"}</td>
                             <td class="text-right">
                                 <a class="btn btn-default formbutton-danger formbutton-narrow" href="javascript: ISPConfig.confirm_action('admin/server_del.php?id={tmpl_var name='id'}&phpsessid={tmpl_var name='phpsessid'}','{tmpl_var name='delete_confirmation'}');"><span class="icon icon-delete"></span></button>
                             </td>
diff --git a/interface/web/client/form/client.tform.php b/interface/web/client/form/client.tform.php
index 8d2ce89855..b5bf002b21 100644
--- a/interface/web/client/form/client.tform.php
+++ b/interface/web/client/form/client.tform.php
@@ -773,6 +773,106 @@ $form["tabs"]['limits'] = array (
 			'rows'  => '',
 			'cols'  => ''
 		),
+        'xmpp_servers' => array (
+            'datatype' => 'VARCHAR',
+            'formtype' => 'MULTIPLE',
+            'separator' => ',',
+            'default' => '1',
+            'datasource' => array (  'type' => 'CUSTOM',
+                'class'=> 'custom_datasource',
+                'function'=> 'client_servers'
+            ),
+            'validators'    => array (  0 => array (    'type'  => 'NOTEMPTY',
+                'errmsg'=> 'no_xmpp_server_error'),
+                1 => array ( 'type' => 'CUSTOM',
+                    'class' => 'validate_client',
+                    'function' => 'check_used_servers',
+                    'errmsg'=> 'xmpp_servers_used'),
+            ),
+            'value'  => '',
+            'name'  => 'xmpp_servers'
+        ),
+        'limit_xmpp_domain' => array(
+            'datatype' => 'INTEGER',
+            'formtype' => 'TEXT',
+            'validators' => array (  0 => array ( 'type' => 'ISINT',
+                'errmsg'=> 'limit_xmpp_domain_error_notint'),
+            ),
+            'default' => '-1',
+            'value'  => '',
+            'separator' => '',
+            'width'  => '10',
+            'maxlength' => '10',
+            'rows'  => '',
+            'cols'  => ''
+        ),
+        'limit_xmpp_user' => array(
+            'datatype' => 'INTEGER',
+            'formtype' => 'TEXT',
+            'validators' => array (  0 => array ( 'type' => 'ISINT',
+                'errmsg'=> 'limit_xmpp_user_error_notint'),
+            ),
+            'default' => '-1',
+            'value'  => '',
+            'separator' => '',
+            'width'  => '10',
+            'maxlength' => '10',
+            'rows'  => '',
+            'cols'  => ''
+        ),
+        'limit_xmpp_muc' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOX',
+            'default' => 'n',
+            'value'  => array(0 => 'n', 1 => 'y')
+        ),
+        'limit_xmpp_anon' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOX',
+            'default' => 'n',
+            'value'  => array(0 => 'n', 1 => 'y')
+        ),
+        'limit_xmpp_auth_options' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOXARRAY',
+            'validators' => array (  0 => array ( 'type' => 'NOTEMPTY',
+                'errmsg'=> 'xmpp_auth_options_notempty'),
+            ),
+            'default' => '',
+            'separator' => ',',
+            'valuelimit' => 'client:xmpp_auth_options',
+            'value'  => array('plain' => 'Plain', 'hashed' => 'Hashed', 'isp' => 'By Mail Account')
+        ),
+        'limit_xmpp_vjud' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOX',
+            'default' => 'n',
+            'value'  => array(0 => 'n', 1 => 'y')
+        ),
+        'limit_xmpp_proxy' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOX',
+            'default' => 'n',
+            'value'  => array(0 => 'n', 1 => 'y')
+        ),
+        'limit_xmpp_status' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOX',
+            'default' => 'n',
+            'value'  => array(0 => 'n', 1 => 'y')
+        ),
+        'limit_xmpp_pastebin' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOX',
+            'default' => 'n',
+            'value'  => array(0 => 'n', 1 => 'y')
+        ),
+        'limit_xmpp_httparchive' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOX',
+            'default' => 'n',
+            'value'  => array(0 => 'n', 1 => 'y')
+        ),
 		'default_webserver' => array (
 			'datatype' => 'INTEGER',
 			'formtype' => 'SELECT',
diff --git a/interface/web/client/lib/lang/en_client.lng b/interface/web/client/lib/lang/en_client.lng
index e7e634bf08..786bd7cae2 100644
--- a/interface/web/client/lib/lang/en_client.lng
+++ b/interface/web/client/lib/lang/en_client.lng
@@ -132,6 +132,7 @@ $wb["bank_account_iban_txt"] = 'IBAN';
 $wb["bank_account_swift_txt"] = 'BIC / Swift';
 $wb["web_limits_txt"] = 'Web Limits';
 $wb["email_limits_txt"] = 'Email Limits';
+$wb["xmpp_limits_txt"] = 'XMPP Limits';
 $wb["database_limits_txt"] = 'Database Limits';
 $wb["cron_job_limits_txt"] = 'Cron Job Limits';
 $wb["dns_limits_txt"] = 'DNS Limits';
@@ -170,6 +171,26 @@ $wb["mail_servers_txt"] = 'Mailservers';
 $wb["mail_servers_placeholder"] = 'Select mailservers';
 $wb['no_mail_server_error'] = 'At least one mailserver must be selected.';
 $wb['mail_servers_used'] = 'The server you are trying to remove from this client is used as a Mailserver. Be sure that this server is not used by this client before you remove it.';
+
+$wb["xmpp_servers_txt"] = 'XMPP Servers';
+$wb["xmpp_servers_placeholder"] = 'Select XMPP Servers';
+$wb['no_xmpp_server_error'] = 'At least one XMPP Server must be selected.';
+$wb['xmpp_servers_used'] = 'The server you are trying to remove from this client is used as a XMPP Server. Be sure that this server is not used by this client before you remove it.';
+$wb['limit_xmpp_domain_error_notint'] = 'The XMPP domain limit must be a number.';
+$wb['limit_xmpp_user_error_notint'] = 'The XMPP user limit must be a number.';
+$wb['xmpp_auth_options_notempty'] = 'At least one XMPP auth method must be selected.';
+$wb['limit_xmpp_domain_txt'] = 'Max. number of XMPP domains';
+$wb['limit_xmpp_user_txt'] = 'Max. number of XMPP accounts';
+$wb['xmpp_auth_options_txt'] = 'Available Auth options';
+$wb['limit_xmpp_muc_txt'] = 'Multiuser chat available';
+$wb['limit_xmpp_pastebin_txt'] = 'Pastebin for MUC available';
+$wb['limit_xmpp_httparchive_txt'] = 'HTTP archive for MUC available';
+$wb['limit_xmpp_anon_txt'] = 'Anonymous host available';
+$wb['limit_xmpp_vjud_txt'] = 'VJUD user directory available';
+$wb['limit_xmpp_proxy_txt'] = 'Bytestream proxy available';
+$wb['limit_xmpp_status_txt'] = 'Status host available';
+
+
 $wb['added_by_txt'] = 'Added by';
 $wb['added_date_txt'] = 'Added date';
 $wb['parent_client_id_txt'] = 'Client of reseller';
diff --git a/interface/web/client/templates/client_edit_limits.htm b/interface/web/client/templates/client_edit_limits.htm
index b0dc73c144..ffb1708adc 100644
--- a/interface/web/client/templates/client_edit_limits.htm
+++ b/interface/web/client/templates/client_edit_limits.htm
@@ -209,6 +209,70 @@
                     <label for="limit_spamfilter_policy" class="col-sm-3 control-label">{tmpl_var name='limit_spamfilter_policy_txt'}</label>
                     <div class="col-sm-9"><input type="text" name="limit_spamfilter_policy" id="limit_spamfilter_policy" value="{tmpl_var name='limit_spamfilter_policy'}" class="form-control" /></div></div>
             </div>
+            <div class="col-sm-3"></div><div class="col-sm-9"><button class="btn btn-default formbutton-default" type="button" data-toggle="collapse" data-target="#toggle-xmpp_limits" aria-expanded="false" aria-controls="toggle-xmpp_limits">{tmpl_var name='xmpp_limits_txt'}</button></div>
+            <div id="toggle-xmpp_limits" class="collapse">
+                <div class="form-group">
+                    <label for="xmpp_servers" class="col-sm-3 control-label">{tmpl_var name='xmpp_servers_txt'}</label>
+                    <div class="col-sm-9"><select data-placeholder="{tmpl_var name='xmpp_servers_placeholder'}" multiple name="xmpp_servers[]" id="xmpp_servers" class="form-control">
+                        {tmpl_var name='xmpp_servers'}
+                    </select></div>
+                </div>
+                <div class="form-group">
+                    <label for="limit_xmpp_domain" class="col-sm-3 control-label">{tmpl_var name='limit_xmpp_domain_txt'}</label>
+                    <div class="col-sm-9"><input type="text" name="limit_web_domain" id="limit_xmpp_domain" value="{tmpl_var name='limit_xmpp_domain'}" class="form-control" /></div></div>
+                <div class="form-group">
+                    <label for="limit_xmpp_user" class="col-sm-3 control-label">{tmpl_var name='limit_xmpp_user_txt'}</label>
+                    <div class="col-sm-9"><input type="text" name="limit_web_domain" id="limit_xmpp_user" value="{tmpl_var name='limit_xmpp_user'}" class="form-control" /></div></div>
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">{tmpl_var name='xmpp_auth_options_txt'}</label>
+                    <div class="col-sm-9">
+                        {tmpl_var name='xmpp_auth_options'}
+                    </div>
+                </div>
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">{tmpl_var name='limit_xmpp_muc_txt'}</label>
+                    <div class="col-sm-9">
+                        {tmpl_var name='limit_xmpp_muc'}
+                    </div>
+                </div>
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">{tmpl_var name='limit_xmpp_pastebin_txt'}</label>
+                    <div class="col-sm-9">
+                        {tmpl_var name='limit_xmpp_pastebin'}
+                    </div>
+                </div>
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">{tmpl_var name='limit_xmpp_httparchive_txt'}</label>
+                    <div class="col-sm-9">
+                        {tmpl_var name='limit_xmpp_httparchive'}
+                    </div>
+                </div>
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">{tmpl_var name='limit_xmpp_anon_txt'}</label>
+                    <div class="col-sm-9">
+                        {tmpl_var name='limit_xmpp_anon'}
+                    </div>
+                </div>
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">{tmpl_var name='limit_xmpp_vjud_txt'}</label>
+                    <div class="col-sm-9">
+                        {tmpl_var name='limit_xmpp_vjud'}
+                    </div>
+                </div>
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">{tmpl_var name='limit_xmpp_proxy_txt'}</label>
+                    <div class="col-sm-9">
+                        {tmpl_var name='limit_xmpp_proxy'}
+                    </div>
+                </div>
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">{tmpl_var name='limit_xmpp_status_txt'}</label>
+                    <div class="col-sm-9">
+                        {tmpl_var name='limit_xmpp_status'}
+                    </div>
+                </div>
+
+            </div>
             <div class="col-sm-3"></div><div class="col-sm-9"><button class="btn btn-default formbutton-default" type="button" data-toggle="collapse" data-target="#toggle-database_limits" aria-expanded="false" aria-controls="toggle-database_limits">{tmpl_var name='database_limits_txt'}</button></div>
             <div id="toggle-database_limits" class="collapse">
                 <div class="form-group">
diff --git a/interface/web/js/xmpp_domain_muc.js b/interface/web/js/xmpp_domain_muc.js
new file mode 100644
index 0000000000..90189288e8
--- /dev/null
+++ b/interface/web/js/xmpp_domain_muc.js
@@ -0,0 +1,26 @@
+$('document').ready(function(){
+    $('#use_muc_host').on('change', function(e){
+        if($(this).is(':checked')){
+            $('#toggle-use-muc').addClass('in');
+            $('#use_pastebin').trigger('change');
+            $('#use_http_archive').trigger('change');
+        }else{
+            $('#toggle-use-muc').removeClass('in');
+        }
+    });
+    $('#use_pastebin').on('change', function(e){
+        if($(this).is(':checked')){
+            $('#toggle-use-pastebin').addClass('in');
+        }else{
+            $('#toggle-use-pastebin').removeClass('in');
+        }
+    });
+    $('#use_http_archive').on('change', function(e){
+        if($(this).is(':checked')){
+            $('#toggle-use-archive').addClass('in');
+        }else{
+            $('#toggle-use-archive').removeClass('in');
+        }
+    });
+    $('#use_muc_host').trigger('change');
+})
\ No newline at end of file
diff --git a/interface/web/js/xmpp_domain_registration.js b/interface/web/js/xmpp_domain_registration.js
new file mode 100644
index 0000000000..bde0874dc7
--- /dev/null
+++ b/interface/web/js/xmpp_domain_registration.js
@@ -0,0 +1,25 @@
+$('document').ready(function(){
+    $('#auth_method').on('select2-selecting', function(e){
+        val = e.choice ? e.choice.id : e.target.selectedIndex;
+        if(val == 2){
+            //Mailbox
+            $('#toggle-auth-internal').removeClass('in');
+            $('#toggle-registration-closed').removeClass('in');
+        }else if(val != undefined){
+            $('#toggle-auth-internal').addClass('in');
+            $('#public_registration').trigger('change');
+        }else{
+            $('#toggle-auth-internal').removeClass('in');
+            $('#toggle-registration-closed').removeClass('in');
+        }
+    });
+    $('#public_registration').on('change', function(e){
+        if($(this).is(':checked')){
+            $('#toggle-registration-closed').removeClass('in');
+        }else{
+            $('#toggle-registration-closed').addClass('in');
+        }
+    });
+    $('#public_registration').trigger('change');
+    $('#auth_method').trigger('select2-selecting');
+})
\ No newline at end of file
diff --git a/interface/web/mail/form/xmpp_domain.tform.php b/interface/web/mail/form/xmpp_domain.tform.php
new file mode 100644
index 0000000000..cc1765f3cc
--- /dev/null
+++ b/interface/web/mail/form/xmpp_domain.tform.php
@@ -0,0 +1,284 @@
+<?php
+
+/*
+	Form Definition
+
+	Tabledefinition
+
+	Datatypes:
+	- INTEGER (Forces the input to Int)
+	- DOUBLE
+	- CURRENCY (Formats the values to currency notation)
+	- VARCHAR (no format check, maxlength: 255)
+	- TEXT (no format check)
+	- DATE (Dateformat, automatic conversion to timestamps)
+
+	Formtype:
+	- TEXT (Textfield)
+	- TEXTAREA (Textarea)
+	- PASSWORD (Password textfield, input is not shown when edited)
+	- SELECT (Select option field)
+	- RADIO
+	- CHECKBOX
+	- CHECKBOXARRAY
+	- FILE
+
+	VALUE:
+	- Wert oder Array
+
+	Hint:
+	The ID field of the database table is not part of the datafield definition.
+	The ID field must be always auto incement (int or bigint).
+
+	Search:
+	- searchable = 1 or searchable = 2 include the field in the search
+	- searchable = 1: this field will be the title of the search result
+	- searchable = 2: this field will be included in the description of the search result
+
+
+*/
+
+$form["title"]    = "XMPP Domain";
+$form["description"]  = "";
+$form["name"]    = "xmpp_domain";
+$form["action"]   = "xmpp_domain_edit.php";
+$form["db_table"]  = "xmpp_domain";
+$form["db_table_idx"] = "domain_id";
+$form["db_history"]  = "yes";
+$form["tab_default"] = "domain";
+$form["list_default"] = "xmpp_domain_list.php";
+$form["auth"]   = 'yes'; // yes / no
+
+$form["auth_preset"]["userid"]  = 0; // 0 = id of the user, > 0 id must match with id of current user
+$form["auth_preset"]["groupid"] = 0; // 0 = default groupid of the user, > 0 id must match with groupid of current user
+$form["auth_preset"]["perm_user"] = 'riud'; //r = read, i = insert, u = update, d = delete
+$form["auth_preset"]["perm_group"] = 'riud'; //r = read, i = insert, u = update, d = delete
+$form["auth_preset"]["perm_other"] = ''; //r = read, i = insert, u = update, d = delete
+
+$form["tabs"]['domain'] = array (
+	'title'  => "Domain",
+	'width'  => 100,
+	'template'  => "templates/xmpp_domain_edit.htm",
+	'fields'  => array (
+		//#################################
+		// Begin Datatable fields
+		//#################################
+		'server_id' => array (
+			'datatype' => 'INTEGER',
+			'formtype' => 'SELECT',
+			'default' => '',
+			'datasource' => array (  'type' => 'SQL',
+				'querystring' => 'SELECT server_id,server_name FROM server WHERE xmpp_server = 1 AND mirror_server_id = 0 AND {AUTHSQL} ORDER BY server_name',
+				'keyfield'=> 'server_id',
+				'valuefield'=> 'server_name'
+			),
+			'value'  => ''
+		),
+		'domain' => array (
+			'datatype' => 'VARCHAR',
+			'formtype' => 'TEXT',
+			'filters'   => array( 0 => array( 'event' => 'SAVE',
+					'type' => 'IDNTOASCII'),
+				1 => array( 'event' => 'SHOW',
+					'type' => 'IDNTOUTF8'),
+				2 => array( 'event' => 'SAVE',
+					'type' => 'TOLOWER')
+			),
+			'validators' => array (  0 => array ( 'type' => 'NOTEMPTY',
+					'errmsg'=> 'domain_error_empty'),
+				1 => array ( 'type' => 'UNIQUE',
+					'errmsg'=> 'domain_error_unique'),
+				2 => array ( 'type' => 'REGEX',
+					'regex' => '/^[\w\.\-]{2,255}\.[a-zA-Z0-9\-]{2,30}$/',
+					'errmsg'=> 'domain_error_regex'),
+			),
+			'default' => '',
+			'value'  => '',
+			'width'  => '30',
+			'maxlength' => '255',
+			'searchable' => 1
+		),
+		'auth_method' => array (
+			'datatype'      => 'VARCHAR',
+			'formtype'      => 'SELECT',
+			'default'       => '1',
+			'value'         => array(0 => 'Plain', 1 => 'Hashed', 2 => 'By Email Mailbox')
+		),
+        'public_registration' => array (
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOX',
+            'default' => 'y',
+            'value'  => array(0 => 'n', 1 => 'y')
+        ),
+        'registration_url' => array (
+            'datatype' => 'VARCHAR',
+            'validators' => array (  0 => array ( 'type' => 'REGEX',
+                'regex' => '@^(([\.]{0})|((ftp|https?)://([-\w\.]+)+(:\d+)?(/([\w/_\.\,\-\+\?\~!:%]*(\?\S+)?)?)?)|(\[scheme\]://([-\w\.]+)+(:\d+)?(/([\w/_\.\-\,\+\?\~!:%]*(\?\S+)?)?)?)|(/(?!.*\.\.)[\w/_\.\-]{1,255}/))$@',
+                'errmsg'=> 'redirect_error_regex'),
+            ),
+            'formtype' => 'TEXT',
+            'default' => '',
+            'value'  => '',
+            'width'  => '30',
+            'maxlength' => '255'
+        ),
+        'registration_message' => array(
+            'datatype' => 'TEXT',
+            'formtype' => 'TEXT',
+            'default' => "Please visit our website for information on registration.",
+            'value' => ''
+        ),
+        'domain_admins' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'TEXT',
+            'default' => 'admin@service.com, superuser@service.com',
+            'value' => '',
+            'width' => '15',
+            'maxlength' => '3'
+        ),
+
+		'active' => array (
+			'datatype' => 'VARCHAR',
+			'formtype' => 'CHECKBOX',
+			'default' => 'y',
+			'value'  => array(0 => 'n', 1 => 'y')
+		),
+		//#################################
+		// ENDE Datatable fields
+		//#################################
+	)
+);
+
+
+$form["tabs"]['features'] = array (
+    'title'  => "Modules",
+    'width'  => 100,
+    'template'  => "templates/xmpp_domain_edit_modules.htm",
+    'fields'  => array (
+        //#################################
+        // Begin Datatable fields
+        //#################################
+        'use_anon_host' => array (
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOX',
+            'default' => 'y',
+            'value'  => array(0 => 'n', 1 => 'y')
+        ),
+        'use_pubsub' => array (
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOX',
+            'default' => 'y',
+            'value'  => array(0 => 'n', 1 => 'y')
+        ),
+        'use_vjud' => array (
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOX',
+            'default' => 'y',
+            'value'  => array(0 => 'n', 1 => 'y')
+        ),
+        'vjud_opt_mode' => array (
+            'datatype'      => 'VARCHAR',
+            'formtype'      => 'SELECT',
+            'default'       => '0',
+            'value'         => array(0 => 'Opt-In', 1 => 'Opt-Out')
+        ),
+        'use_proxy' => array (
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOX',
+            'default' => 'y',
+            'value'  => array(0 => 'n', 1 => 'y')
+        ),
+        'use_status_host' => array (
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOX',
+            'default' => 'y',
+            'value'  => array(0 => 'n', 1 => 'y')
+        ),
+        //#################################
+        // ENDE Datatable fields
+        //#################################
+    )
+);
+
+$form["tabs"]['muc'] = array (
+    'title'  => "MUC",
+    'width'  => 100,
+    'template'  => "templates/xmpp_domain_edit_muc.htm",
+    'fields'  => array (
+        //#################################
+        // Begin Datatable fields
+        //#################################
+        'use_muc_host' => array (
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOX',
+            'default' => 'y',
+            'value'  => array(0 => 'n', 1 => 'y')
+        ),
+        'muc_name' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'TEXT',
+            'default' => ''
+        ),
+        'muc_restrict_room_creation' => array (
+            'datatype'      => 'VARCHAR',
+            'formtype'      => 'SELECT',
+            'default'       => '1',
+            'value'         => array(0 => 'Everyone', 1 => 'Members', 2 => 'Admins')
+        ),
+        'muc_admins' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'TEXT',
+            'default' => 'admin@service.com, superuser@service.com',
+            'value' => '',
+            'width' => '15',
+            'maxlength' => '3'
+        ),
+        'use_pastebin' => array (
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOX',
+            'default' => 'y',
+            'value'  => array(0 => 'n', 1 => 'y')
+        ),
+        'pastebin_expire_after' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'TEXT',
+            'default' => '48',
+            'validators' => array(0 => array('type' => 'ISINT'),
+                array('type'=>'RANGE', 'range'=>'1:168')
+            ),
+            'value' => '',
+            'width' => '15'
+        ),
+        'pastebin_trigger' => array(
+            'datatype' => 'VARCHAR',
+            'formtype' => 'TEXT',
+            'default' => '!paste',
+            'value' => '',
+            'width' => '15'
+        ),
+        'use_http_archive' => array (
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOX',
+            'default' => 'y',
+            'value'  => array(0 => 'n', 1 => 'y')
+        ),
+        'http_archive_show_join' => array (
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOX',
+            'default' => 'y',
+            'value'  => array(0 => 'n', 1 => 'y')
+        ),
+        'http_archive_show_status' => array (
+            'datatype' => 'VARCHAR',
+            'formtype' => 'CHECKBOX',
+            'default' => 'y',
+            'value'  => array(0 => 'n', 1 => 'y')
+        ),
+        //#################################
+        // ENDE Datatable fields
+        //#################################
+    )
+);
+
+
+?>
diff --git a/interface/web/mail/lib/lang/en_xmpp_domain.lng b/interface/web/mail/lib/lang/en_xmpp_domain.lng
new file mode 100644
index 0000000000..1151f5cd44
--- /dev/null
+++ b/interface/web/mail/lib/lang/en_xmpp_domain.lng
@@ -0,0 +1,28 @@
+<?php
+$wb["server_id_txt"] = 'Server';
+$wb["domain_txt"] = 'Domain';
+$wb["type_txt"] = 'Type';
+$wb["active_txt"] = 'Active';
+$wb["client_txt"] = 'Client';
+$wb["auth_method_txt"] = 'Authentication Method';
+$wb["public_registration_txt"] = 'Enable public registration';
+$wb["registration_url_txt"] = 'Registration URL';
+$wb["registration_message_txt"] = 'Registration Message';
+$wb["domain_admins_txt"] = 'Domain Admins (JIDs)';
+$wb["use_pubsub_txt"] = 'Enable Pubsub';
+$wb["use_proxy_txt"] = 'Enable Bytestream Proxy';
+$wb["use_anon_host_txt"] = 'Enable Anonymous Host';
+$wb["use_vjud_txt"] = 'Enable VJUD User Directory';
+$wb["vjud_opt_mode_txt"] = 'VJUD Opt Mode';
+$wb["use_muc_host_txt"] = 'Enable Multi User Chatrooms';
+$wb["muc_name_txt"] = 'Name in MUC Service Discovery';
+$wb["muc_restrict_room_creation_txt"] = 'Permission to create chatrooms';
+$wb["muc_admins_txt"] = 'MUC Admins (JIDs)';
+$wb["use_pastebin_txt"] = 'Enable Pastebin';
+$wb["pastebin_expire_after_txt"] = 'Pastes expire after (hours)';
+$wb["pastebin_trigger_txt"] = 'Pastebin trigger';
+$wb["use_http_archive_txt"] = 'Enable HTTP chatroom archive';
+$wb["http_archive_show_join_txt"] = 'Show join messages in archive';
+$wb["http_archive_show_status_txt"] = 'Show status changes in archive';
+$wb["use_status_host_txt"] = 'Enable XML Status host';
+?>
diff --git a/interface/web/mail/lib/lang/en_xmpp_domain_admin_list.lng b/interface/web/mail/lib/lang/en_xmpp_domain_admin_list.lng
new file mode 100644
index 0000000000..a3d1736d7b
--- /dev/null
+++ b/interface/web/mail/lib/lang/en_xmpp_domain_admin_list.lng
@@ -0,0 +1,8 @@
+<?php
+$wb["list_head_txt"] = 'XMPP Domain';
+$wb["server_id_txt"] = 'Server';
+$wb["domain_txt"] = 'Domain';
+$wb["add_new_record_txt"] = 'Add new Domain';
+$wb["active_txt"] = 'Active';
+$wb["sys_groupid_txt"] = 'Client';
+?>
\ No newline at end of file
diff --git a/interface/web/mail/lib/lang/en_xmpp_domain_list.lng b/interface/web/mail/lib/lang/en_xmpp_domain_list.lng
new file mode 100644
index 0000000000..f8c2fb9b8e
--- /dev/null
+++ b/interface/web/mail/lib/lang/en_xmpp_domain_list.lng
@@ -0,0 +1,7 @@
+<?php
+$wb["list_head_txt"] = 'XMPP Domain';
+$wb["server_id_txt"] = 'Server';
+$wb["domain_txt"] = 'Domain';
+$wb["add_new_record_txt"] = 'Add new Domain';
+$wb["active_txt"] = 'Active';
+?>
\ No newline at end of file
diff --git a/interface/web/mail/lib/module.conf.php b/interface/web/mail/lib/module.conf.php
index 2ca9b7aca9..7f828d1fc9 100644
--- a/interface/web/mail/lib/module.conf.php
+++ b/interface/web/mail/lib/module.conf.php
@@ -148,6 +148,30 @@ if($app->auth->get_client_limit($userid, 'fetchmail') != 0)
 		'items' => $items);
 }
 
+//**** XMPP Menu
+$items = array();
+
+if($app->auth->get_client_limit($userid, 'xmppdomain') != 0)
+{
+    $items[] = array( 'title'  => 'XMPP Domain',
+        'target'  => 'content',
+        'link' => 'mail/xmpp_domain_list.php',
+        'html_id' => 'xmpp_domain_list');
+}
+
+if($app->auth->get_client_limit($userid, 'xmppaccount') != 0)
+{
+    $items[] = array( 'title'  => 'XMPP Account',
+        'target'  => 'content',
+        'link' => 'mail/xmpp_account_list.php',
+        'html_id' => 'xmpp_account_list');
+}
+
+if(count($items))
+    $module['nav'][] = array( 'title' => 'Jabber / XMPP',
+        'open'  => 1,
+        'items' => $items);
+
 
 
 //**** Statistics menu
diff --git a/interface/web/mail/list/xmpp_domain.list.php b/interface/web/mail/list/xmpp_domain.list.php
new file mode 100644
index 0000000000..21257e4283
--- /dev/null
+++ b/interface/web/mail/list/xmpp_domain.list.php
@@ -0,0 +1,109 @@
+<?php
+
+/*
+	Datatypes:
+	- INTEGER
+	- DOUBLE
+	- CURRENCY
+	- VARCHAR
+	- TEXT
+	- DATE
+*/
+
+
+
+// Name of the list
+if($_SESSION['s']['user']['typ'] == 'admin') {
+	$liste["name"]     = "xmpp_domain_admin";
+} else {
+	$liste["name"]     = "xmpp_domain";
+}
+
+// Database table
+$liste["table"]    = "xmpp_domain";
+
+// Index index field of the database table
+$liste["table_idx"]   = "domain_id";
+
+// Search Field Prefix
+$liste["search_prefix"]  = "search_";
+
+// Records per page
+$liste["records_per_page"]  = "15";
+
+// Script File of the list
+$liste["file"]    = "xmpp_domain_list.php";
+
+// Script file of the edit form
+$liste["edit_file"]   = "xmpp_domain_edit.php";
+
+// Script File of the delete script
+$liste["delete_file"]  = "xmpp_domain_del.php";
+
+// Paging Template
+$liste["paging_tpl"]  = "templates/paging.tpl.htm";
+
+// Enable auth
+$liste["auth"]    = "yes";
+
+
+/*****************************************************
+* Suchfelder
+*****************************************************/
+
+
+$liste["item"][] = array( 'field'  => "active",
+	'datatype' => "VARCHAR",
+	'formtype' => "SELECT",
+	'op'  => "=",
+	'prefix' => "",
+	'suffix' => "",
+	'width'  => "",
+	'value'  => array('y' => "<div id=\"ir-Yes\" class=\"swap\"><span>Yes</span></div>", 'n' => "<div class=\"swap\" id=\"ir-No\"><span>No</span></div>"));
+
+
+if($_SESSION['s']['user']['typ'] == 'admin') {
+	$liste["item"][] = array( 'field'  => "sys_groupid",
+		'datatype' => "INTEGER",
+		'formtype' => "SELECT",
+		'op'  => "=",
+		'prefix' => "",
+		'suffix' => "",
+		'datasource' => array (  'type' => 'SQL',
+			'querystring' => 'SELECT groupid, name FROM sys_group WHERE groupid != 1 ORDER BY name',
+			'keyfield'=> 'groupid',
+			'valuefield'=> 'name'
+		),
+		'width'  => "",
+		'value'  => "");
+}
+
+
+$liste["item"][] = array( 'field'  => "server_id",
+	'datatype' => "INTEGER",
+	'formtype' => "SELECT",
+	'op'  => "like",
+	'prefix' => "",
+	'suffix' => "",
+	'datasource' => array (  'type' => 'SQL',
+		'querystring' => 'SELECT a.server_id, a.server_name FROM server a, xmpp_domain b WHERE (a.server_id = b.server_id) AND ({AUTHSQL-B}) ORDER BY a.server_name',
+		'keyfield'=> 'server_id',
+		'valuefield'=> 'server_name'
+	),
+	'width'  => "",
+	'value'  => "");
+
+$liste["item"][] = array( 'field'  => "domain",
+	'datatype' => "VARCHAR",
+	'filters'   => array( 0 => array( 'event' => 'SHOW',
+			'type' => 'IDNTOUTF8')
+	),
+	'formtype' => "TEXT",
+	'op'  => "like",
+	'prefix' => "%",
+	'suffix' => "%",
+	'width'  => "",
+	'value'  => "");
+
+
+?>
diff --git a/interface/web/mail/templates/xmpp_domain_admin_list.htm b/interface/web/mail/templates/xmpp_domain_admin_list.htm
new file mode 100644
index 0000000000..ccda2d5032
--- /dev/null
+++ b/interface/web/mail/templates/xmpp_domain_admin_list.htm
@@ -0,0 +1,60 @@
+<div class='page-header'>
+	<h1><tmpl_var name="list_head_txt"></h1>
+</div>
+
+
+        <p class="fieldset-legend">{tmpl_var name="toolsarea_head_txt"}</p>
+
+                <button class="btn btn-default formbutton-success" type="button" data-load-content="mail/xmpp_domain_edit.php">{tmpl_var name="add_new_record_txt"}</button>
+            
+        
+
+    
+        <p class="fieldset-legend"><tmpl_var name="list_head_txt"></p>
+            <div class="table-wrapper marginTop15">
+<table class="table">
+                <thead class="dark form-group-sm">
+                    <tr>
+                        <th class="tiny-col" data-column="active"><tmpl_var name="active_txt"></th>
+                        <th data-column="sys_groupid"><tmpl_var name="sys_groupid_txt"></th>
+                        <th data-column="server_id"><tmpl_var name="server_id_txt"></th>
+                        <th data-column="domain"><tmpl_var name="domain_txt"></th>
+                        <th class="small-col text-right">{tmpl_var name='search_limit'}</th>
+                    </tr>
+                    <tr>
+                        <td><select class="form-control" name="search_active">{tmpl_var name='search_active'}</select></td>
+                        <td><select class="form-control" name="search_sys_groupid">{tmpl_var name='search_sys_groupid'}</select></td>
+                        <td><select class="form-control" name="search_server_id">{tmpl_var name='search_server_id'}</select></td>
+                        <td><input class="form-control" type="text" name="search_domain" value="{tmpl_var name='search_domain'}" /></td>
+                        <td class="text-right">
+                            <button type="button" class="btn btn-default formbutton-default formbutton-narrow" name="Filter" id="Filter" value="{tmpl_var name="filter_txt"}" data-submit-form="pageForm" data-form-action="mail/xmpp_domain_list.php"><span class="icon icon-filter"></span></button>
+                        </td>
+                    </tr>
+                </thead>
+                <tbody>
+                    <tmpl_loop name="records">
+                        <tr>
+                            <td><a href="#" data-load-content="mail/xmpp_domain_edit.php?id={tmpl_var name='id'}">{tmpl_var name="active"}</a></td>
+                            <td><a href="#" data-load-content="mail/xmpp_domain_edit.php?id={tmpl_var name='id'}">{tmpl_var name="sys_groupid"}</a></td>
+                            <td><a href="#" data-load-content="mail/xmpp_domain_edit.php?id={tmpl_var name='id'}">{tmpl_var name="server_id"}</a></td>
+                            <td><a href="#" data-load-content="mail/xmpp_domain_edit.php?id={tmpl_var name='id'}">{tmpl_var name="domain"}</a></td>
+                            <td class="text-right">
+                                <a class="btn btn-default formbutton-danger formbutton-narrow" href="javascript: ISPConfig.confirm_action('mail/xmpp_domain_del.php?id={tmpl_var name='id'}&phpsessid={tmpl_var name='phpsessid'}','{tmpl_var name='delete_confirmation'}');"><span class="icon icon-delete"></span></button>
+                            </td>
+                        </tr>
+                    </tmpl_loop>
+                    <tmpl_unless name="records">
+                        <tr class="tbl_row_noresults tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
+                            <td colspan="5">{tmpl_var name='globalsearch_noresults_text_txt'}</td>
+                        </tr>
+                    </tmpl_unless>
+                </tbody>
+                <tfoot>
+                    <tr>
+                        <td colspan="5"><tmpl_var name="paging"></td>
+                    </tr>
+                </tfoot>
+            </table>
+</div>
+        
+    
\ No newline at end of file
diff --git a/interface/web/mail/templates/xmpp_domain_edit.htm b/interface/web/mail/templates/xmpp_domain_edit.htm
new file mode 100644
index 0000000000..c735eff94b
--- /dev/null
+++ b/interface/web/mail/templates/xmpp_domain_edit.htm
@@ -0,0 +1,124 @@
+<div class='page-header'>
+	<h1><tmpl_var name="list_head_txt"></h1>
+</div>
+<p><tmpl_var name="list_desc_txt"></p>
+
+
+        
+            <tmpl_if name="is_admin">
+                <div class="form-group">
+                    <tmpl_if name="edit_disabled">
+                        <label for="server_id_disabled" class="col-sm-3 control-label">{tmpl_var name='server_id_txt'}</label>
+                        <div class="col-sm-9"><select name="server_id_disabled" id="server_id_disabled" class="form-control" disabled="disabled">
+                            {tmpl_var name='server_id'}
+                        </select></div>
+                        <input type="hidden" name="server_id" value="{tmpl_var name='server_id_value'}" />
+                        <tmpl_else>
+                            <label for="server_id" class="col-sm-3 control-label">{tmpl_var name='server_id_txt'}</label>
+                            <div class="col-sm-9"><select name="server_id" id="server_id" class="form-control">
+                                {tmpl_var name='server_id'}
+                            </select></div>
+                    </tmpl_if>
+                </div>
+                <tmpl_unless name="domain_option">
+                    <div class="form-group">
+                        <label for="client_group_id" class="col-sm-3 control-label">{tmpl_var name='client_group_id_txt'}</label>
+                        <div class="col-sm-9"><select name="client_group_id" id="client_group_id" class="form-control">
+                            {tmpl_var name='client_group_id'}
+                        </select></div>
+                    </div>
+                </tmpl_unless>
+            <tmpl_else>
+                <tmpl_if name="only_one_server">
+                    <input type="hidden" id="server_id" name="server_id" value="{tmpl_var name='server_id_value'}" />
+                <tmpl_else>
+                    <div class="form-group">
+                        <tmpl_if name="edit_disabled">
+                            <label for="server_id_disabled" class="col-sm-3 control-label">{tmpl_var name='server_id_txt'}</label>
+                            <div class="col-sm-9"><select name="server_id_disabled" id="server_id_disabled" class="form-control" disabled="disabled">
+                                {tmpl_var name='client_server_id'}
+                            </select></div>
+                            <input type="hidden" name="server_id" value="{tmpl_var name='server_id_value'}" />
+                        <tmpl_else>
+                            <label for="server_id" class="col-sm-3 control-label">{tmpl_var name='server_id_txt'}</label>
+                            <div class="col-sm-9"><select name="server_id" id="server_id" class="form-control">
+                                {tmpl_var name='client_server_id'}
+                            </select></div>
+                        </tmpl_if>
+                    </div>
+                </tmpl_if>
+            </tmpl_if>
+
+            <tmpl_if name="is_reseller">
+                <tmpl_unless name="domain_option">
+                    <div class="form-group">
+                        <label for="client_group_id" class="col-sm-3 control-label">{tmpl_var name='client_group_id_txt'}</label>
+                        <div class="col-sm-9"><select name="client_group_id" id="client_group_id" class="form-control">
+                            {tmpl_var name='client_group_id'}
+                        </select></div>
+                    </div>
+                </tmpl_unless>
+            </tmpl_if>
+
+            <div class="form-group">
+                <label for="domain" class="col-sm-3 control-label">{tmpl_var name='domain_txt'}</label>
+                <tmpl_if name="domain_option">
+                    <div class="col-sm-9"><select name="domain" id="domain" class="form-control">
+                        {tmpl_var name='domain_option'}
+                    </select></div>
+                    <tmpl_else>
+                        <div class="col-sm-9"><input type="text" name="domain" id="domain" value="{tmpl_var name='domain'}" class="form-control" /></div></tmpl_if>
+            </div>
+
+
+
+
+
+<div class="form-group">
+    <label for="auth_method" class="col-sm-3 control-label">{tmpl_var name='auth_method_txt'}</label>
+    <div class="col-sm-9"><select name="auth_method" id="auth_method" class="form-control">
+        {tmpl_var name='auth_method'}
+    </select></div>
+</div>
+
+<div id="toggle-auth-internal" class="collapse">
+    <div class="form-group">
+        <label class="col-sm-3 control-label">{tmpl_var name='public_registration_txt'}</label>
+        <div class="col-sm-9">
+            {tmpl_var name='public_registration'}
+        </div>
+    </div>
+</div>
+<div id="toggle-registration-closed" class="collapse">
+    <div class="form-group">
+        <label for="registration_url" class="col-sm-3 control-label">{tmpl_var name='registration_url_txt'}</label>
+        <div class="col-sm-9">
+            <input type="text" name="registration_url" id="registration_url" value="{tmpl_var name='registration_url'}" class="form-control" />
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="col-sm-3 control-label">{tmpl_var name='registration_message_txt'}</label>
+        <div class="col-sm-9"><textarea class="form-control" name="registration_message" id="registration_message" rows='3' cols='30'>{tmpl_var name='registration_message'}</textarea></div>
+    </div>
+</div>
+
+<div class="form-group">
+    <label class="col-sm-3 control-label">{tmpl_var name='domain_admins_txt'}</label>
+    <div class="col-sm-9"><textarea class="form-control" name="domain_admins" id="domain_admins" rows='3' cols='30'>{tmpl_var name='domain_admins'}</textarea></div>
+</div>
+
+
+<div class="form-group">
+    <label class="col-sm-3 control-label">{tmpl_var name='active_txt'}</label>
+    <div class="col-sm-9">
+        {tmpl_var name='active'}
+    </div>
+</div>
+
+        <input type="hidden" name="id" value="{tmpl_var name='id'}">
+        <input type="hidden" name="type" value="domain">
+        <div class="clear"><div class="right">
+            <button class="btn btn-default formbutton-success" type="button" value="{tmpl_var name='btn_save_txt'}" data-submit-form="pageForm" data-form-action="mail/xmpp_domain_edit.php">{tmpl_var name='btn_save_txt'}</button>
+            <button class="btn btn-default formbutton-default" type="button" value="{tmpl_var name='btn_cancel_txt'}" data-load-content="mail/xmpp_domain_list.php">{tmpl_var name='btn_cancel_txt'}</button>
+        </div></div>
+<script language="JavaScript" type="text/javascript" src="js/xmpp_domain_registration.js"></script>
diff --git a/interface/web/mail/templates/xmpp_domain_edit_modules.htm b/interface/web/mail/templates/xmpp_domain_edit_modules.htm
new file mode 100644
index 0000000000..f6d988fea2
--- /dev/null
+++ b/interface/web/mail/templates/xmpp_domain_edit_modules.htm
@@ -0,0 +1,52 @@
+<div class='page-header'>
+	<h1><tmpl_var name="list_head_txt"></h1>
+</div>
+<p><tmpl_var name="list_desc_txt"></p>
+
+
+
+<div class="form-group">
+    <label class="col-sm-3 control-label">{tmpl_var name='use_anon_host_txt'}</label>
+    <div class="col-sm-9">
+        {tmpl_var name='use_anon_host'}
+    </div>
+</div>
+<div class="form-group">
+    <label class="col-sm-3 control-label">{tmpl_var name='use_pubsub_txt'}</label>
+    <div class="col-sm-9">
+        {tmpl_var name='use_pubsub'}
+    </div>
+</div>
+<div class="form-group">
+    <label class="col-sm-3 control-label">{tmpl_var name='use_vjud_txt'}</label>
+    <div class="col-sm-9">
+        {tmpl_var name='use_vjud'}
+    </div>
+</div>
+<div class="form-group">
+    <label for="vjud_opt_mode" class="col-sm-3 control-label">{tmpl_var name='vjud_opt_mode_txt'}</label>
+    <div class="col-sm-3"><select name="vjud_opt_mode" id="vjud_opt_mode" class="form-control">
+        {tmpl_var name='vjud_opt_mode'}
+    </select></div>
+</div>
+<div class="form-group">
+    <label class="col-sm-3 control-label">{tmpl_var name='use_proxy_txt'}</label>
+    <div class="col-sm-9">
+        {tmpl_var name='use_proxy'}
+    </div>
+</div>
+<div class="form-group">
+    <label class="col-sm-3 control-label">{tmpl_var name='use_status_host_txt'}</label>
+    <div class="col-sm-9">
+        {tmpl_var name='use_status_host'}
+    </div>
+</div>
+
+
+
+        <input type="hidden" name="id" value="{tmpl_var name='id'}">
+        <input type="hidden" name="type" value="modules" />
+        <div class="clear"><div class="right">
+            <button class="btn btn-default formbutton-success" type="button" value="{tmpl_var name='btn_save_txt'}" data-submit-form="pageForm" data-form-action="mail/xmpp_domain_edit.php">{tmpl_var name='btn_save_txt'}</button>
+            <button class="btn btn-default formbutton-default" type="button" value="{tmpl_var name='btn_cancel_txt'}" data-load-content="mail/xmpp_domain_list.php">{tmpl_var name='btn_cancel_txt'}</button>
+        </div></div>
diff --git a/interface/web/mail/templates/xmpp_domain_edit_muc.htm b/interface/web/mail/templates/xmpp_domain_edit_muc.htm
new file mode 100644
index 0000000000..533362df51
--- /dev/null
+++ b/interface/web/mail/templates/xmpp_domain_edit_muc.htm
@@ -0,0 +1,87 @@
+<div class='page-header'>
+	<h1><tmpl_var name="list_head_txt"></h1>
+</div>
+<p><tmpl_var name="list_desc_txt"></p>
+
+
+
+<div class="form-group">
+    <label class="col-sm-3 control-label">{tmpl_var name='use_muc_host_txt'}</label>
+    <div class="col-sm-9">
+        {tmpl_var name='use_muc_host'}
+    </div>
+</div>
+
+<div id="toggle-use-muc" class="collapse">
+    <div class="form-group">
+        <label for="muc_name" class="col-sm-3 control-label">{tmpl_var name='muc_name_txt'}</label>
+        <div class="col-sm-9">
+            <input type="text" name="muc_name" id="muc_name" value="{tmpl_var name='muc_name'}" class="form-control" maxlength="30" />
+        </div>
+    </div>
+
+    <div class="form-group">
+        <label for="muc_restrict_room_creation" class="col-sm-3 control-label">{tmpl_var name='muc_restrict_room_creation_txt'}</label>
+        <div class="col-sm-3"><select name="muc_restrict_room_creation" id="muc_restrict_room_creation" class="form-control">
+            {tmpl_var name='muc_restrict_room_creation'}
+        </select></div>
+    </div>
+    <div class="form-group">
+        <div class="form-group">
+            <label class="col-sm-3 control-label">{tmpl_var name='muc_admins_txt'}</label>
+            <div class="col-sm-9"><textarea class="form-control" name="muc_admins" id="muc_admins" rows='3' cols='30'>{tmpl_var name='muc_admins'}</textarea></div>
+        </div>
+    </div>
+
+    <div class="form-group">
+        <label class="col-sm-3 control-label">{tmpl_var name='use_pastebin_txt'}</label>
+        <div class="col-sm-9">
+            {tmpl_var name='use_pastebin'}
+        </div>
+    </div>
+    <div id="toggle-use-pastebin" class="collapse">
+        <div class="form-group">
+            <label class="col-sm-3 control-label">{tmpl_var name='pastebin_expire_after_txt'}</label>
+            <div class="col-sm-3">
+                <input type="number" name="pastebin_expire_after" id="pastebin_expire_after" value="{tmpl_var name='pastebin_expire_after'}" class="form-control" />
+            </div>
+        </div>
+        <div class="form-group">
+            <label class="col-sm-3 control-label">{tmpl_var name='pastebin_trigger_txt'}</label>
+            <div class="col-sm-3">
+                <input type="text" name="pastebin_trigger" id="pastebin_trigger" value="{tmpl_var name='pastebin_trigger'}" class="form-control" />
+            </div>
+        </div>
+    </div>
+
+    <div class="form-group">
+        <label class="col-sm-3 control-label">{tmpl_var name='use_http_archive_txt'}</label>
+        <div class="col-sm-9">
+            {tmpl_var name='use_http_archive'}
+        </div>
+    </div>
+    <div id="toggle-use-archive" class="collapse">
+        <div class="form-group">
+            <label class="col-sm-3 control-label">{tmpl_var name='http_archive_show_join_txt'}</label>
+            <div class="col-sm-9">
+                {tmpl_var name='http_archive_show_join'}
+            </div>
+        </div>
+        <div class="form-group">
+            <label class="col-sm-3 control-label">{tmpl_var name='http_archive_show_status_txt'}</label>
+            <div class="col-sm-9">
+                {tmpl_var name='http_archive_show_status'}
+            </div>
+        </div>
+    </div>
+
+</div>
+
+
+        <input type="hidden" name="id" value="{tmpl_var name='id'}">
+        <input type="hidden" name="type" value="muc" />
+        <div class="clear"><div class="right">
+            <button class="btn btn-default formbutton-success" type="button" value="{tmpl_var name='btn_save_txt'}" data-submit-form="pageForm" data-form-action="mail/xmpp_domain_edit.php">{tmpl_var name='btn_save_txt'}</button>
+            <button class="btn btn-default formbutton-default" type="button" value="{tmpl_var name='btn_cancel_txt'}" data-load-content="mail/xmpp_domain_list.php">{tmpl_var name='btn_cancel_txt'}</button>
+        </div></div>
+<script language="JavaScript" type="text/javascript" src="js/xmpp_domain_muc.js"></script>
diff --git a/interface/web/mail/templates/xmpp_domain_list.htm b/interface/web/mail/templates/xmpp_domain_list.htm
new file mode 100644
index 0000000000..79579142d7
--- /dev/null
+++ b/interface/web/mail/templates/xmpp_domain_list.htm
@@ -0,0 +1,74 @@
+<div class='page-header'>
+	<h1><tmpl_var name="list_head_txt"></h1>
+</div>
+<p><tmpl_var name="list_desc_txt"></p>
+
+
+        <tmpl_if name='datalog_changes_count' op='>' value='0'>
+        <div>
+            <div class="systemmonitor-state state-info">
+                <div class="status"></div>
+                <div class="statusMsg">
+                    {tmpl_var name="datalog_changes_txt"}
+                    <ul>
+                    <tmpl_loop name="datalog_changes">
+                        <li><strong>{tmpl_var name="text"}:</strong> {tmpl_var name="count"}</li>
+                    </tmpl_loop>
+                    </ul>
+                    {tmpl_var name="datalog_changes_end_txt"}
+                </div>
+            </div><br />
+        </div>
+        </tmpl_if>
+        <p class="fieldset-legend">{tmpl_var name="toolsarea_head_txt"}</p>
+            
+                <button class="btn btn-default formbutton-success" type="button" data-load-content="mail/xmpp_domain_edit.php">{tmpl_var name="add_new_record_txt"}</button>
+            
+        
+
+    
+        <p class="fieldset-legend"><tmpl_var name="list_head_txt"></p>
+            <div class="table-wrapper marginTop15">
+<table class="table">
+                <thead class="dark form-group-sm">
+                    <tr>
+                        <th class="tiny-col" data-column="active"><tmpl_var name="active_txt"></th>
+                        <th data-column="server_id"><tmpl_var name="server_id_txt"></th>
+                        <th data-column="domain"><tmpl_var name="domain_txt"></th>
+                        <th class="small-col text-right">{tmpl_var name='search_limit'}</th>
+                    </tr>
+                    <tr>
+                        <td><select class="form-control" name="search_active">{tmpl_var name='search_active'}</select></td>
+                        <td><select class="form-control" name="search_server_id">{tmpl_var name='search_server_id'}</select></td>
+                        <td><input class="form-control" type="text" name="search_domain" value="{tmpl_var name='search_domain'}" /></td>
+                        <td class="text-right">
+                            <button type="button" class="btn btn-default formbutton-default formbutton-narrow" name="Filter" id="Filter" value="{tmpl_var name="filter_txt"}" data-submit-form="pageForm" data-form-action="mail/xmpp_domain_list.php"><span class="icon icon-filter"></span></button>
+                        </td>
+                    </tr>
+                </thead>
+                <tbody>
+                    <tmpl_loop name="records">
+                        <tr>
+                            <td><a href="#" data-load-content="mail/xmpp_domain_edit.php?id={tmpl_var name='id'}">{tmpl_var name="active"}</a></td>
+                            <td><a href="#" data-load-content="mail/xmpp_domain_edit.php?id={tmpl_var name='id'}">{tmpl_var name="server_id"}</a></td>
+                            <td><a href="#" data-load-content="mail/xmpp_domain_edit.php?id={tmpl_var name='id'}">{tmpl_var name="domain"}</a></td>
+                            <td class="text-right">
+                                <a class="btn btn-default formbutton-danger formbutton-narrow" href="javascript: ISPConfig.confirm_action('mail/xmpp_domain_del.php?id={tmpl_var name='id'}&phpsessid={tmpl_var name='phpsessid'}','{tmpl_var name='delete_confirmation'}');"><span class="icon icon-delete"></span></button>
+                            </td>
+                        </tr>
+                    </tmpl_loop>
+                    <tmpl_unless name="records">
+                        <tr class="tbl_row_noresults tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
+                            <td colspan="4">{tmpl_var name='globalsearch_noresults_text_txt'}</td>
+                        </tr>
+                    </tmpl_unless>
+                </tbody>
+                <tfoot>
+                    <tr>
+                        <td colspan="4"><tmpl_var name="paging"></td>
+                    </tr>
+                </tfoot>
+            </table>
+</div>
+        
+    
\ No newline at end of file
diff --git a/interface/web/mail/xmpp_domain_del.php b/interface/web/mail/xmpp_domain_del.php
new file mode 100644
index 0000000000..3dcc859764
--- /dev/null
+++ b/interface/web/mail/xmpp_domain_del.php
@@ -0,0 +1,102 @@
+<?php
+
+/*
+Copyright (c) 2005, Till Brehm, projektfarm Gmbh
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+    * Neither the name of ISPConfig nor the names of its contributors
+      may be used to endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/******************************************
+* Begin Form configuration
+******************************************/
+
+$list_def_file = "list/xmpp_domain.list.php";
+$tform_def_file = "form/xmpp_domain.tform.php";
+
+/******************************************
+* End Form configuration
+******************************************/
+
+require_once '../../lib/config.inc.php';
+require_once '../../lib/app.inc.php';
+
+//* Check permissions for module
+$app->auth->check_module_permissions('mail');
+
+// Loading classes
+$app->uses('tpl,tform,tform_actions');
+$app->load('tform_actions');
+
+class page_action extends tform_actions {
+
+	function onBeforeDelete() {
+		global $app; $conf;
+
+		$domain = $this->dataRecord['domain'];
+
+		// Before we delete the email domain,
+		// we will delete all depending records.
+        // TODO: Delete xmpp accounts in filesystem
+        // TODO: Delete xmpp accounts in isp
+        // TODO: Delete DNS Records
+/*
+		// Delete all forwardings where the source or destination belongs to this domain
+		$records = $app->db->queryAllRecords("SELECT forwarding_id as id FROM mail_forwarding WHERE source like '%@".$app->db->quote($domain)."' OR (destination like '%@".$app->db->quote($domain)."' AND type != 'forward')");
+		foreach($records as $rec) {
+			$app->db->datalogDelete('mail_forwarding', 'forwarding_id', $rec['id']);
+		}
+
+		// Delete all fetchmail accounts where destination belongs to this domain
+		$records = $app->db->queryAllRecords("SELECT mailget_id as id FROM mail_get WHERE destination like '%@".$app->db->quote($domain)."'");
+		foreach($records as $rec) {
+			$app->db->datalogDelete('mail_get', 'mailget_id', $rec['id']);
+		}
+
+		// Delete all mailboxes where destination belongs to this domain
+		$records = $app->db->queryAllRecords("SELECT mailuser_id as id FROM mail_user WHERE email like '%@".$app->db->quote($domain)."'");
+		foreach($records as $rec) {
+			$app->db->datalogDelete('mail_user', 'mailuser_id', $rec['id']);
+		}
+
+		// Delete all spamfilters that belong to this domain
+		$records = $app->db->queryAllRecords("SELECT id FROM spamfilter_users WHERE email = '%@".$app->db->quote($domain)."'");
+		foreach($records as $rec) {
+			$app->db->datalogDelete('spamfilter_users', 'id', $rec['id']);
+		}
+
+		// Delete all mailinglists that belong to this domain
+		$records = $app->db->queryAllRecords("SELECT mailinglist_id FROM mail_mailinglist WHERE domain = '".$app->db->quote($domain)."'");
+		foreach($records as $rec) {
+			$app->db->datalogDelete('mail_mailinglist', 'mailinglist_id', $rec['id']);
+		}
+*/
+	}
+
+}
+
+$page = new page_action;
+$page->onDelete();
+
+?>
diff --git a/interface/web/mail/xmpp_domain_edit.php b/interface/web/mail/xmpp_domain_edit.php
new file mode 100644
index 0000000000..d87778d110
--- /dev/null
+++ b/interface/web/mail/xmpp_domain_edit.php
@@ -0,0 +1,436 @@
+<?php
+/*
+Copyright (c) 2007, Till Brehm, projektfarm Gmbh
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+    * Neither the name of ISPConfig nor the names of its contributors
+      may be used to endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+/******************************************
+* Begin Form configuration
+******************************************/
+
+$tform_def_file = "form/xmpp_domain.tform.php";
+
+/******************************************
+* End Form configuration
+******************************************/
+
+require_once '../../lib/config.inc.php';
+require_once '../../lib/app.inc.php';
+
+//* Check permissions for module
+$app->auth->check_module_permissions('mail');
+
+// Loading classes
+$app->uses('tpl,tform,tform_actions,tools_sites');
+$app->load('tform_actions');
+
+class page_action extends tform_actions {
+    var $_xmpp_type = 'domain';
+
+    function onLoad() {
+        $show_type = 'server';
+        if(isset($_GET['type']) && $_GET['type'] == 'modules') {
+            $show_type = 'modules';
+        } elseif(isset($_GET['type']) && $_GET['type'] == 'muc') {
+            $show_type = 'muc';
+        }
+
+        $_SESSION['s']['var']['xmpp_type'] = $show_type;
+        $this->_xmpp_type = $show_type;
+
+        parent::onLoad();
+    }
+
+	function onShowNew() {
+		global $app, $conf;
+
+		// we will check only users, not admins
+		if($_SESSION["s"]["user"]["typ"] == 'user') {
+			if(!$app->tform->checkClientLimit('limit_xmppdomain')) {
+				$app->error($app->tform->wordbook["limit_xmppdomain_txt"]);
+			}
+			if(!$app->tform->checkResellerLimit('limit_xmppdomain')) {
+				$app->error('Reseller: '.$app->tform->wordbook["limit_xmppdomain_txt"]);
+			}
+		} else {
+			$settings = $app->getconf->get_global_config('xmpp');
+			$app->tform->formDef['tabs']['domain']['fields']['server_id']['default'] = intval($settings['default_xmppserver']);
+		}
+
+		parent::onShowNew();
+	}
+
+	function onShowEnd() {
+		global $app, $conf;
+
+		$app->uses('ini_parser,getconf');
+		$settings = $app->getconf->get_global_config('domains');
+
+		if($_SESSION["s"]["user"]["typ"] == 'admin' && $settings['use_domain_module'] != 'y') {
+			// Getting Clients of the user
+			$sql = "SELECT sys_group.groupid, sys_group.name, CONCAT(IF(client.company_name != '', CONCAT(client.company_name, ' :: '), ''), client.contact_name, ' (', client.username, IF(client.customer_no != '', CONCAT(', ', client.customer_no), ''), ')') as contactname FROM sys_group, client WHERE sys_group.client_id = client.client_id AND sys_group.client_id > 0 ORDER BY client.company_name, client.contact_name, sys_group.name";
+
+			$clients = $app->db->queryAllRecords($sql);
+			$client_select = '';
+			if($_SESSION["s"]["user"]["typ"] == 'admin') $client_select .= "<option value='0'></option>";
+			//$tmp_data_record = $app->tform->getDataRecord($this->id);
+			if(is_array($clients)) {
+				foreach( $clients as $client) {
+					$selected = @(is_array($this->dataRecord) && ($client["groupid"] == $this->dataRecord['client_group_id'] || $client["groupid"] == $this->dataRecord['sys_groupid']))?'SELECTED':'';
+					$client_select .= "<option value='$client[groupid]' $selected>$client[contactname]</option>\r\n";
+				}
+			}
+			$app->tpl->setVar("client_group_id", $client_select);
+
+		} elseif ($_SESSION["s"]["user"]["typ"] != 'admin' && $app->auth->has_clients($_SESSION['s']['user']['userid'])) {
+
+			// Get the limits of the client
+			$client_group_id = $_SESSION["s"]["user"]["default_group"];
+			$client = $app->db->queryOneRecord("SELECT client.client_id, client.contact_name, client.default_xmppserver, CONCAT(IF(client.company_name != '', CONCAT(client.company_name, ' :: '), ''), client.contact_name, ' (', client.username, IF(client.customer_no != '', CONCAT(', ', client.customer_no), ''), ')') as contactname, sys_group.name FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id order by client.contact_name");
+
+			// Set the xmppserver to the default server of the client
+			$tmp = $app->db->queryOneRecord("SELECT server_name FROM server WHERE server_id = $client[default_xmppserver]");
+			$app->tpl->setVar("server_id", "<option value='$client[default_xmppserver]'>$tmp[server_name]</option>");
+			unset($tmp);
+
+			if ($settings['use_domain_module'] != 'y') {
+				// Fill the client select field
+				$sql = "SELECT sys_group.groupid, sys_group.name, CONCAT(IF(client.company_name != '', CONCAT(client.company_name, ' :: '), ''), client.contact_name, ' (', client.username, IF(client.customer_no != '', CONCAT(', ', client.customer_no), ''), ')') as contactname FROM sys_group, client WHERE sys_group.client_id = client.client_id AND client.parent_client_id = ".$app->functions->intval($client['client_id'])." ORDER BY client.company_name, client.contact_name, sys_group.name";
+				$clients = $app->db->queryAllRecords($sql);
+				$tmp = $app->db->queryOneRecord("SELECT groupid FROM sys_group WHERE client_id = ".$app->functions->intval($client['client_id']));
+				$client_select = '<option value="'.$tmp['groupid'].'">'.$client['contactname'].'</option>';
+				//$tmp_data_record = $app->tform->getDataRecord($this->id);
+				if(is_array($clients)) {
+					foreach( $clients as $client) {
+						$selected = @(is_array($this->dataRecord) && ($client["groupid"] == $this->dataRecord['client_group_id'] || $client["groupid"] == $this->dataRecord['sys_groupid']))?'SELECTED':'';
+						$client_select .= "<option value='$client[groupid]' $selected>$client[contactname]</option>\r\n";
+					}
+				}
+				$app->tpl->setVar("client_group_id", $client_select);
+			}
+		}
+
+		if($_SESSION["s"]["user"]["typ"] != 'admin')
+		{
+			$client_group_id = $_SESSION["s"]["user"]["default_group"];
+			$client_xmpp = $app->db->queryOneRecord("SELECT xmpp_servers FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
+
+			$client_xmpp['xmpp_servers_ids'] = explode(',', $client_xmpp['xmpp_servers']);
+
+			$only_one_server = count($client_xmpp['xmpp_servers_ids']) === 1;
+			$app->tpl->setVar('only_one_server', $only_one_server);
+
+			if ($only_one_server) {
+				$app->tpl->setVar('server_id_value', $client_xmpp['xmpp_servers_ids'][0]);
+			}
+
+			$sql = "SELECT server_id, server_name FROM server WHERE server_id IN (" . $client_xmpp['xmpp_servers'] . ");";
+			$xmpp_servers = $app->db->queryAllRecords($sql);
+
+			$options_xmpp_servers = "";
+
+			foreach ($xmpp_servers as $xmpp_server) {
+				$options_xmpp_servers .= "<option value='$xmpp_server[server_id]'>$xmpp_server[server_name]</option>";
+			}
+
+			$app->tpl->setVar("client_server_id", $options_xmpp_servers);
+			unset($options_xmpp_servers);
+
+		}
+
+		/*
+		 * Now we have to check, if we should use the domain-module to select the domain
+		 * or not
+		 */
+		if ($settings['use_domain_module'] == 'y') {
+			/*
+			 * The domain-module is in use.
+			*/
+			$domains = $app->tools_sites->getDomainModuleDomains("xmpp_domain", $this->dataRecord["domain"]);
+			$domain_select = '';
+			if(is_array($domains) && sizeof($domains) > 0) {
+				/* We have domains in the list, so create the drop-down-list */
+				foreach( $domains as $domain) {
+					$domain_select .= "<option value=" . $domain['domain_id'] ;
+					if ($domain['domain'] == $this->dataRecord["domain"]) {
+						$domain_select .= " selected";
+					}
+					$domain_select .= ">" . $app->functions->idn_decode($domain['domain']) . "</option>\r\n";
+				}
+			}
+			else {
+				/*
+				 * We have no domains in the domain-list. This means, we can not add ANY new domain.
+				 * To avoid, that the variable "domain_option" is empty and so the user can
+				 * free enter a domain, we have to create a empty option!
+				*/
+				$domain_select .= "<option value=''></option>\r\n";
+			}
+			$app->tpl->setVar("domain_option", $domain_select);
+			$app->tpl->setVar("domain_module", 1);
+		} else {
+			$app->tpl->setVar("domain_module", 0);
+		}
+
+
+		if($this->id > 0) {
+			//* we are editing a existing record
+			$app->tpl->setVar("edit_disabled", 1);
+			$app->tpl->setVar("server_id_value", $this->dataRecord["server_id"]);
+		} else {
+			$app->tpl->setVar("edit_disabled", 0);
+		}
+
+
+		parent::onShowEnd();
+	}
+
+	function onSubmit() {
+		global $app, $conf;
+
+		/* check if the domain module is used - and check if the selected domain can be used! */
+		$app->uses('ini_parser,getconf');
+		$settings = $app->getconf->get_global_config('domains');
+		if ($settings['use_domain_module'] == 'y') {
+			if ($_SESSION["s"]["user"]["typ"] == 'admin' || $app->auth->has_clients($_SESSION['s']['user']['userid'])) {
+				$this->dataRecord['client_group_id'] = $app->tools_sites->getClientIdForDomain($this->dataRecord['domain']);
+			}
+			$domain_check = $app->tools_sites->checkDomainModuleDomain($this->dataRecord['domain']);
+			if(!$domain_check) {
+				// invalid domain selected
+				$app->tform->errorMessage .= $app->tform->lng("domain_error_empty")."<br />";
+			} else {
+				$this->dataRecord['domain'] = $domain_check;
+			}
+		}
+
+		if($_SESSION["s"]["user"]["typ"] != 'admin') {
+			// Get the limits of the client
+			$client_group_id = $app->functions->intval($_SESSION["s"]["user"]["default_group"]);
+			$client = $app->db->queryOneRecord("SELECT limit_xmppdomain, default_xmppserver FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
+			// When the record is updated
+			if($this->id > 0) {
+				// restore the server ID if the user is not admin and record is edited
+				$tmp = $app->db->queryOneRecord("SELECT server_id FROM xmpp_domain WHERE domain_id = ".$app->functions->intval($this->id));
+				$this->dataRecord["server_id"] = $tmp["server_id"];
+				unset($tmp);
+				// When the record is inserted
+			} else {
+				$client['xmpp_servers_ids'] = explode(',', $client['xmpp_servers']);
+
+				// Check if chosen server is in authorized servers for this client
+				if (!(is_array($client['xmpp_servers_ids']) && in_array($this->dataRecord["server_id"], $client['xmpp_servers_ids']))) {
+					$app->error($app->tform->wordbook['error_not_allowed_server_id']);
+				}
+
+				if($client["limit_xmppdomain"] >= 0) {
+					$tmp = $app->db->queryOneRecord("SELECT count(domain_id) as number FROM xmpp_domain WHERE sys_groupid = $client_group_id");
+					if($tmp["number"] >= $client["limit_xmppdomain"]) {
+						$app->error($app->tform->wordbook["limit_xmppdomain_txt"]);
+					}
+				}
+			}
+
+			// Clients may not set the client_group_id, so we unset them if user is not a admin
+			if(!$app->auth->has_clients($_SESSION['s']['user']['userid'])) unset($this->dataRecord["client_group_id"]);
+		}
+
+		//* make sure that the xmpp domain is lowercase
+		if(isset($this->dataRecord["domain"])) $this->dataRecord["domain"] = strtolower($this->dataRecord["domain"]);
+
+        // Read auth method
+        if(isset($this->dataRecord["auth_method"]))
+            switch($this->dataRecord["auth_method"]){
+                case 0:
+                    $this->dataRecord["auth_method"] = 'plain';
+                    break;
+                case 1:
+                    $this->dataRecord["auth_method"] = 'hashed';
+                    break;
+                case 2:
+                    $this->dataRecord["auth_method"] = 'isp';
+                    break;
+            }
+        // vjud opt mode
+        if(isset($this->dataRecord["vjud_opt_mode"]))
+            $this->dataRecord["vjud_opt_mode"] = $this->dataRecord["vjud_opt_mode"] == 0 ? 'in' : 'out';
+        if(isset($this->dataRecord["muc_restrict_room_creation"])){
+            switch($this->dataRecord["muc_restrict_room_creation"]){
+                case 0:
+                    $this->dataRecord["muc_restrict_room_creation"] = 'false';
+                    break;
+                case 1:
+                    $this->dataRecord["muc_restrict_room_creation"] = 'member';
+                    break;
+                case 2:
+                    $this->dataRecord["muc_restrict_room_creation"] = 'true';
+                    break;
+            }
+        }
+
+		parent::onSubmit();
+	}
+
+	function onAfterInsert() {
+        global $app, $conf;
+
+        // make sure that the record belongs to the client group and not the admin group when admin inserts it
+        // also make sure that the user can not delete domain created by a admin
+        if($_SESSION["s"]["user"]["typ"] == 'admin' && isset($this->dataRecord["client_group_id"])) {
+            $client_group_id = $app->functions->intval($this->dataRecord["client_group_id"]);
+            $app->db->query("UPDATE xmpp_domain SET sys_groupid = $client_group_id, sys_perm_group = 'ru' WHERE domain_id = ".$this->id);
+        }
+        if($app->auth->has_clients($_SESSION['s']['user']['userid']) && isset($this->dataRecord["client_group_id"])) {
+            $client_group_id = $app->functions->intval($this->dataRecord["client_group_id"]);
+            $app->db->query("UPDATE xmpp_domain SET sys_groupid = $client_group_id, sys_perm_group = 'riud' WHERE domain_id = ".$this->id);
+        }
+
+        //* make sure that the xmpp domain is lowercase
+        if(isset($this->dataRecord["domain"])) $this->dataRecord["domain"] = strtolower($this->dataRecord["domain"]);
+
+        // Insert DNS Records
+        $soa = $app->db->queryOneRecord("SELECT id AS zone, sys_userid, sys_groupid, sys_perm_user, sys_perm_group, sys_perm_other, server_id, ttl, serial FROM dns_soa WHERE active = 'Y' AND origin = ?", $this->dataRecord['domain'].'.');
+        if ( isset($soa) && !empty($soa) ) $this->update_dns($this->dataRecord, $soa);
+	}
+
+	function onBeforeUpdate() {
+        global $app, $conf;
+
+        if($this->_xmpp_type == 'server') {
+            //* Check if the server has been changed
+            // We do this only for the admin or reseller users, as normal clients can not change the server ID anyway
+            if($_SESSION["s"]["user"]["typ"] == 'admin' || $app->auth->has_clients($_SESSION['s']['user']['userid'])) {
+                if (isset($this->dataRecord["server_id"])) {
+                    $rec = $app->db->queryOneRecord("SELECT server_id from xmpp_domain WHERE domain_id = ".$this->id);
+                    if($rec['server_id'] != $this->dataRecord["server_id"]) {
+                        //* Add a error message and switch back to old server
+                        $app->tform->errorMessage .= $app->lng('The Server can not be changed.');
+                        $this->dataRecord["server_id"] = $rec['server_id'];
+                    }
+                    unset($rec);
+                }
+                //* If the user is neither admin nor reseller
+            } else {
+                //* We do not allow users to change a domain which has been created by the admin
+                $rec = $app->db->queryOneRecord("SELECT sys_perm_group, domainfrom xmpp_domain WHERE domain_id = ".$this->id);
+                if(isset($this->dataRecord["domain"]) && $rec['domain'] != $this->dataRecord["domain"] && $app->tform->checkPerm($this->id, 'u')) {
+                    //* Add a error message and switch back to old server
+                    $app->tform->errorMessage .= $app->lng('The Domain can not be changed. Please ask your Administrator if you want to change the domain name.');
+                    $this->dataRecord["domain"] = $rec['domain'];
+                }
+                unset($rec);
+            }
+        }
+
+        //* make sure that the xmpp domain is lowercase
+        if(isset($this->dataRecord["domain"])) $this->dataRecord["domain"] = strtolower($this->dataRecord["domain"]);
+
+	}
+
+	function onAfterUpdate() {
+		global $app, $conf;
+
+        // Update DNS Records
+        // TODO: Update gets only triggered from main form. WHY?
+        // TODO: if(in_array($this->_xmpp_type, array('muc', 'modules'))){
+            $soa = $app->db->queryOneRecord("SELECT id AS zone, sys_userid, sys_groupid, sys_perm_user, sys_perm_group, sys_perm_other, server_id, ttl, serial FROM dns_soa WHERE active = 'Y' AND origin = ?", $this->dataRecord['domain'].'.');
+            if ( isset($soa) && !empty($soa) ) $this->update_dns($this->dataRecord, $soa);
+        //}
+	}
+
+
+
+    private function update_dns($dataRecord, $new_rr) {
+        global $app, $conf;
+
+        $rec = $app->db->queryOneRecord("SELECT use_pubsub, use_proxy, use_anon_host, use_vjud, use_muc_host from xmpp_domain WHERE domain_id = ".$this->id);
+        $required_hosts = array('xmpp');
+        if($rec['use_pubsub']=='y')
+            $required_hosts[] = 'pubsub';
+        if($rec['use_proxy']=='y')
+            $required_hosts[] = 'proxy';
+        if($rec['use_anon_host']=='y')
+            $required_hosts[] = 'anon';
+        if($rec['use_vjud']=='y')
+            $required_hosts[] = 'vjud';
+        if($rec['use_muc_host']=='y')
+            $required_hosts[] = 'muc';
+
+        // purge old rr-record
+        $sql = "SELECT * FROM dns_rr WHERE zone = ? AND (name IN ? AND type = 'CNAME' OR name LIKE ? AND type = 'SRV')  AND ? ORDER BY serial DESC";
+        $rec = $app->db->queryAllRecords($sql, $new_rr['zone'], array('xmpp', 'pubsub', 'proxy', 'anon', 'vjud', 'muc'), '_xmpp-%', $app->tform->getAuthSQL('r'));
+        if (is_array($rec[1])) {
+            for ($i=0; $i < count($rec); ++$i)
+                $app->db->datalogDelete('dns_rr', 'id', $rec[$i]['id']);
+        }
+
+        // create new cname rr-records
+        foreach($required_hosts AS $h){
+            $rr = $new_rr;
+            $rr['name'] = $h;
+            $rr['type'] = 'CNAME';
+            $rr['data'] = 'jalapeno.spicyweb.de.';
+            $rr['aux'] = 0;
+            $rr['active'] = 'Y';
+            $rr['stamp'] = date('Y-m-d H:i:s');
+            $rr['serial'] = $app->validate_dns->increase_serial($new_rr['serial']);
+            $app->db->datalogInsert('dns_rr', $rr, 'id', $rr['zone']);
+        }
+
+        //create new srv rr-records
+        $rr = $new_rr;
+        $rr['name'] = '_xmpp-client._tcp.'.$dataRecord['domain'].'.';
+        $rr['type'] = 'SRV';
+        $rr['data'] = '5 5222 jalapeno.spicyweb.de.';
+        $rr['aux'] = 0;
+        $rr['active'] = 'Y';
+        $rr['stamp'] = date('Y-m-d H:i:s');
+        $rr['serial'] = $app->validate_dns->increase_serial($new_rr['serial']);
+        $app->db->datalogInsert('dns_rr', $rr, 'id', $rr['zone']);
+        $rr = $new_rr;
+        $rr['name'] = '_xmpp-server._tcp.'.$dataRecord['domain'].'.';
+        $rr['type'] = 'SRV';
+        $rr['data'] = '5 5269 jalapeno.spicyweb.de.';
+        $rr['aux'] = 0;
+        $rr['active'] = 'Y';
+        $rr['stamp'] = date('Y-m-d H:i:s');
+        $rr['serial'] = $app->validate_dns->increase_serial($new_rr['serial']);
+        $app->db->datalogInsert('dns_rr', $rr, 'id', $rr['zone']);
+
+        // Refresh zone
+        $zone = $app->db->queryOneRecord("SELECT id, serial FROM dns_soa WHERE active = 'Y' AND id = ?", $new_rr['zone']);
+        $new_serial = $app->validate_dns->increase_serial($zone['serial']);
+        $app->db->datalogUpdate('dns_soa', "serial = '".$new_serial."'", 'id', $zone['id']);
+    }
+
+
+}
+
+$page = new page_action;
+$page->onLoad();
+
+?>
diff --git a/interface/web/mail/xmpp_domain_list.php b/interface/web/mail/xmpp_domain_list.php
new file mode 100644
index 0000000000..ff632e38ca
--- /dev/null
+++ b/interface/web/mail/xmpp_domain_list.php
@@ -0,0 +1,28 @@
+<?php
+require_once '../../lib/config.inc.php';
+require_once '../../lib/app.inc.php';
+
+/******************************************
+* Begin Form configuration
+******************************************/
+
+$list_def_file = "list/xmpp_domain.list.php";
+
+/******************************************
+* End Form configuration
+******************************************/
+
+
+//* Check permissions for module
+$app->auth->check_module_permissions('mail');
+
+$app->uses('listform_actions');
+
+// Limit the results to alias domains
+// $app->listform_actions->SQLExtWhere = "type = 'local'";
+
+$app->listform_actions->SQLOrderBy = 'ORDER BY xmpp_domain.domain';
+$app->listform_actions->onLoad();
+
+
+?>
diff --git a/server/conf/metronome_conf_global.master b/server/conf/metronome_conf_global.master
new file mode 100644
index 0000000000..71920caea1
--- /dev/null
+++ b/server/conf/metronome_conf_global.master
@@ -0,0 +1,48 @@
+pidfile = "/var/run/metronome/metronome.pid";
+metronome_max_files_soft = 200000;
+metronome_max_files_hard = 300000;
+plugin_paths = {
+        "/usr/lib/metronome/isp-modules",
+};
+use_libevent = true;
+log = {
+        debug = "/var/log/metronome/metronome.dbg",
+        info = "/var/log/metronome/metronome.log",
+        error = "/var/log/metronome/metronome.err",
+};
+use_ipv6 = {tmpl_var name='ipv6'};
+http_ports = {
+        {tmpl_var name='port_http'},
+};
+https_ports = {
+        {tmpl_var name='port_https'},
+};
+pastebin_ports = {
+        {tmpl_var name='port_pastebin'},
+};
+bosh_ports = {
+        {tmpl_var name='port_bosh'},
+};
+admins = {
+{tmpl_var name='server_admins'}
+};
+modules_enabled = {
+{tmpl_var name='modules_enabled'}
+};
+modules_disabled = {
+};
+bosh_max_inactivity = {tmpl_var name='bosh_timeout'};
+consider_bosh_secure = true;
+cross_domain_bosh = true;
+allow_registration = true;
+-- TODO generate ssl key during setup
+ssl = {
+        key = "/etc/metronome/certs/localhost.key",
+        certificate = "/etc/metronome/certs/localhost.cert",
+};
+c2s_require_encryption = false;
+s2s_secure = true;
+s2s_insecure_domains = {
+        "gmail.com",
+};
+authentication = "internal_plain";
\ No newline at end of file
diff --git a/server/conf/metronome_conf_host.master b/server/conf/metronome_conf_host.master
new file mode 100644
index 0000000000..66cbf0b60b
--- /dev/null
+++ b/server/conf/metronome_conf_host.master
@@ -0,0 +1,138 @@
+VirtualHost "{tmpl_var name='domain'}"
+        enabled = {tmpl_var name='active'};
+        authentication = "{tmpl_var name='auth_method'}";
+    <tmpl_if name='auth_method' op='==' value='external'>
+        external_auth_command = "/usr/lib/metronome/isp-modules/mod_auth_external/authenticate_isp.sh";
+    <tmpl_else>
+        allow_registration = {tmpl_var name='public_registration'};
+    </tmpl_if>
+    <tmpl_if name='registration_url' op='!=' value=''>
+        registration_url = "{tmpl_var name='registration_url'}";
+        registration_text = "{tmpl_var name='registration_message'}";
+    </tmpl_if>
+        no_registration_whitelist = true;
+
+        modules_enabled = {
+                "roster",
+                "private",
+                "vcard",
+                "privacy",
+                "pep",
+<tmpl_if name='public_registration' op='==' value='true'>
+                "register",
+<tmpl_elseif name='registration_url' op='!=' value=''>
+                "register_redirect",
+</tmpl_if>
+                "admin_adhoc",
+        };
+        disco_items = {
+<tmpl_if name='use_muc' op='==' value='true'>
+                {
+                        "muc.{tmpl_var name='domain'}",
+                        "{tmpl_var name='muc_name'}",
+                },
+</tmpl_if>
+<tmpl_if name='use_pubsub' op='==' value='true'>
+                {
+                        "pubsub.{tmpl_var name='domain'}",
+                        "{tmpl_var name='domain'} Publish/Subscribe",
+                },
+</tmpl_if>
+<tmpl_if name='use_proxy' op='==' value='true'>
+                {
+                        "proxy.{tmpl_var name='domain'}",
+                        "{tmpl_var name='domain'} Bytestream Proxy",
+                },
+</tmpl_if>
+<tmpl_if name='use_vjud' op='==' value='true'>
+                {
+                        "vjud.{tmpl_var name='domain'}",
+                        "{tmpl_var name='domain'} User Directory",
+                },
+</tmpl_if>
+        };
+
+        admins = {
+{tmpl_var name='domain_admins'}
+        };
+-- TODO: SSL Certs for Hosts
+--        ssl = {
+--                key = "/var/lib/metronome/iplay-esports.de.key",
+--                certificate = "/var/lib/metronome/iplay-esports.de.crt",
+--        };
+
+
+<tmpl_if name='use_proxy' op='==' value='true'>
+VirtualHost "anon.{tmpl_var name='domain'}"
+        enabled = true;
+        authentication = "anonymous";
+        allow_anonymous_multiresourcing = true;
+        anonymous_jid_gentoken = "{tmpl_var name='domain'} Anonymous User";
+        admins = {
+        };
+</tmpl_if>
+
+
+<tmpl_if name='use_muc' op='==' value='true'>
+Component "muc.{tmpl_var name='domain'}" "muc"
+        modules_enabled = {
+                "muc_limits",
+                "muc_log",
+<tmpl_if name='use_archive' op='==' value='true'>
+                "muc_log_http",
+</tmpl_if>
+<tmpl_if name='use_pastebin' op='==' value='true'>
+                "pastebin",
+</tmpl_if>
+        };
+        muc_event_rate = 0.7;
+        muc_burst_factor = 13;
+        muc_log_presences = false;
+<tmpl_if name='use_archive' op='==' value='true'>
+        muc_log_http_config = {
+                show_join = {tmpl_var name='archive_join'},
+                show_status = {tmpl_var name='archive_status'},
+                theme = "metronome",
+                url_base = "logs",
+        };
+</tmpl_if>
+<tmpl_if name='use_pastebin' op='==' value='true'>
+        pastebin_path = "/pastes/";
+        pastebin_expire_after = {tmpl_var name='pastebin_expire'};
+        pastebin_trigger = "{tmpl_var name='pastebin_trigger'}";
+</tmpl_if>
+        name = "{tmpl_var name='muc_name'}";
+        restrict_room_creation = "{tmpl_var name='muc_restrict_room_creation'}";
+        admins = {
+{tmpl_var name='muc_admins'}
+        };
+</tmpl_if>
+
+
+<tmpl_if name='use_pubsub' op='==' value='true'>
+Component "pubsub.{tmpl_var name='domain'}" "pubsub"
+        name = "{tmpl_var name='domain'} Publish/Subscribe";
+        unrestricted_node_creation = false;
+</tmpl_if>
+
+<tmpl_if name='use_proxy' op='==' value='true'>
+Component "proxy.{tmpl_var name='domain'}" "proxy65"
+        proxy65_acl = {
+                "{tmpl_var name='domain'}",
+        };
+        proxy65_interfaces = {
+                "*",
+                "::",
+        };
+        proxy65_ports = {
+                5000,
+        };
+</tmpl_if>
+
+
+<tmpl_if name='use_vjud' op='==' value='true'>
+Component "vjud.{tmpl_var name='domain'}" "vjud"
+        ud_disco_name = "{tmpl_var name='domain'} User Directory";
+        synchronize_to_host_vcards = "{tmpl_var name='domain'}";
+        vjud_mode = "{tmpl_var name='vjud_opt_mode'}";
+</tmpl_if>
\ No newline at end of file
diff --git a/server/conf/metronome_conf_main.master b/server/conf/metronome_conf_main.master
new file mode 100644
index 0000000000..1103ca4d9c
--- /dev/null
+++ b/server/conf/metronome_conf_main.master
@@ -0,0 +1,3 @@
+Include "/etc/metronome/global.cfg.lua"
+Include "/etc/metronome/hosts/*.lua"
+Include "/etc/metronome/status.cfg.lua"
diff --git a/server/conf/metronome_conf_status.master b/server/conf/metronome_conf_status.master
new file mode 100644
index 0000000000..daa8205491
--- /dev/null
+++ b/server/conf/metronome_conf_status.master
@@ -0,0 +1,12 @@
+Component "xmpp.{tmpl_var name='domain'}" "http"
+        modules_enabled = {
+                "server_status",
+                "webpresence"
+        };
+        server_status_basepath = "/xmppd/";
+        server_status_show_hosts = {
+{tmpl_var name='status_hosts'}
+        };
+        server_status_show_comps = {
+{tmpl_var name='status_comps'}
+        };
\ No newline at end of file
diff --git a/server/mods-available/xmpp_module.inc.php b/server/mods-available/xmpp_module.inc.php
new file mode 100644
index 0000000000..145b7f0f58
--- /dev/null
+++ b/server/mods-available/xmpp_module.inc.php
@@ -0,0 +1,109 @@
+<?php
+
+/*
+Copyright (c) 2007, Till Brehm, projektfarm Gmbh
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+    * Neither the name of ISPConfig nor the names of its contributors
+      may be used to endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+class xmpp_module {
+
+    var $module_name = 'xmpp_module';
+    var $class_name = 'xmpp_module';
+    var $actions_available = array(
+        'xmpp_domain_insert',
+        'xmpp_domain_update',
+        'xmpp_domain_delete',
+        'xmpp_user_insert',
+        'xmpp_user_update',
+        'xmpp_user_delete'
+    );
+
+    //* This function is called during ispconfig installation to determine
+    //  if a symlink shall be created for this plugin.
+    function onInstall() {
+        global $conf;
+
+        if($conf['services']['xmpp'] == true) {
+            return true;
+        } else {
+            return false;
+        }
+
+    }
+
+    /*
+         This function is called when the module is loaded
+    */
+
+    function onLoad() {
+        global $app;
+
+        /*
+        Annonce the actions that where provided by this module, so plugins
+        can register on them.
+        */
+
+        $app->plugins->announceEvents($this->module_name, $this->actions_available);
+
+        /*
+        As we want to get notified of any changes on several database tables,
+        we register for them.
+
+        The following function registers the function "functionname"
+         to be executed when a record for the table "dbtable" is
+         processed in the sys_datalog. "classname" is the name of the
+         class that contains the function functionname.
+        */
+
+        $app->modules->registerTableHook('xmpp_domain', 'xmpp_module', 'process');
+
+    }
+
+    /*
+     This function is called when a change in one of the registered tables is detected.
+     The function then raises the events for the plugins.
+    */
+
+    function process($tablename, $action, $data) {
+        global $app;
+
+        switch ($tablename) {
+            case 'xmpp_domain':
+                if($action == 'i') $app->plugins->raiseEvent('xmpp_domain_insert', $data);
+                if($action == 'u') $app->plugins->raiseEvent('xmpp_domain_update', $data);
+                if($action == 'd') $app->plugins->raiseEvent('xmpp_domain_delete', $data);
+                break;
+            case 'xmpp_user':
+                if($action == 'i') $app->plugins->raiseEvent('xmpp_user_insert', $data);
+                if($action == 'u') $app->plugins->raiseEvent('xmpp_user_update', $data);
+                if($action == 'd') $app->plugins->raiseEvent('xmpp_user_delete', $data);
+                break;
+        } // end switch
+    } // end function
+
+} // end class
+
+?>
diff --git a/server/plugins-available/xmpp_plugin.inc.php b/server/plugins-available/xmpp_plugin.inc.php
new file mode 100644
index 0000000000..c4f70e30dd
--- /dev/null
+++ b/server/plugins-available/xmpp_plugin.inc.php
@@ -0,0 +1,232 @@
+<?php
+
+
+// TODO Plugin bei Installation symlinken in plugins-enabled!
+/*
+Copyright (c) 2007, Till Brehm, projektfarm Gmbh
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+    * Neither the name of ISPConfig nor the names of its contributors
+      may be used to endorse or promote products derived from this software without
+      specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+class xmpp_plugin {
+
+    var $plugin_name = 'xmpp_server_plugin';
+    var $class_name = 'xmpp_server_plugin';
+
+
+    var $xmpp_config_dir = '/etc/metronome';
+
+    //* This function is called during ispconfig installation to determine
+    //  if a symlink shall be created for this plugin.
+    function onInstall() {
+        global $conf;
+
+        if($conf['services']['xmpp'] == true) {
+            return true;
+        } else {
+            return false;
+        }
+
+    }
+
+    /*
+         This function is called when the plugin is loaded
+    */
+
+    function onLoad() {
+        global $app;
+
+        /*
+        Register for the events
+        */
+
+        $app->plugins->registerEvent('server_insert', 'xmpp_plugin', 'insert');
+        $app->plugins->registerEvent('server_update', 'xmpp_plugin', 'update');
+        $app->plugins->registerEvent('xmpp_domain_insert', 'xmpp_plugin', 'domainInsert');
+        $app->plugins->registerEvent('xmpp_domain_update', 'xmpp_plugin', 'domainUpdate');
+        $app->plugins->registerEvent('xmpp_domain_delete', 'xmpp_plugin', 'domainDelete');
+
+    }
+
+    function insert($event_name, $data) {
+        global $app, $conf;
+
+        $this->update($event_name, $data);
+
+    }
+
+    // The purpose of this plugin is to rewrite the main.cf file
+    function update($event_name, $data) {
+        global $app, $conf;
+
+        // get the config
+        $app->uses("getconf,system,tpl");
+
+
+        $old_ini_data = $app->ini_parser->parse_ini_string($data['old']['config']);
+        $xmpp_config = $app->getconf->get_server_config($conf['server_id'], 'xmpp');
+
+        $tpl = new tpl();
+        $tpl->newTemplate('metronome_conf_global.master');
+
+        $tpl->setVar('ipv6', $xmpp_config['xmpp_use_ipv6']=='y'?'true':'false');
+        $tpl->setVar('bosh_timeout', intval($xmpp_config['xmpp_bosh_max_inactivity']));
+        $tpl->setVar('port_http', intval($xmpp_config['xmpp_port_http']));
+        $tpl->setVar('port_https', intval($xmpp_config['xmpp_port_https']));
+        $tpl->setVar('port_pastebin', intval($xmpp_config['xmpp_port_pastebin']));
+        $tpl->setVar('port_bosh', intval($xmpp_config['xmpp_port_bosh']));
+        $admins = '';
+        foreach(explode(',', $xmpp_config['xmpp_server_admins']) AS $a)
+            $admins.= "\t\"".trim($a)."\",\n";
+        $tpl->setVar('server_admins', $admins);
+        unset($admins);
+        $modules = '';
+        foreach(explode(',', $xmpp_config['xmpp_modules_enabled']) AS $m)
+            $modules.= "\t\"".trim($m)."\",\n";
+        $tpl->setVar('modules_enabled', $modules);
+        unset($modules);
+        $app->system->file_put_contents($this->xmpp_config_dir.'/global.cfg.lua', $tpl->grab());
+        unset($tpl);
+
+        return;
+    }
+
+    function domainInsert($event_name, $data) {
+        global $app, $conf;
+
+        $this->domainUpdate($event_name, $data);
+
+    }
+
+    function domainUpdate($event_name, $data){
+        global $app, $conf;
+
+        // get the config
+        $app->uses("getconf,system,tpl");
+
+        // Collections
+        $status_hosts = array($data['new']['domain']);
+        $status_comps = array();
+
+        // Create main host file
+        $tpl = new tpl();
+        $tpl->newTemplate('metronome_conf_host.master');
+        $tpl->setVar('domain', $data['new']['domain']);
+        $tpl->setVar('active', $data['new']['active'] == 'y' ? 'true' : 'false');
+        $tpl->setVar('auth_method', $data['new']['auth_method'] == 'isp' ? 'external' : 'internal_'.$data['new']['auth_method']);
+        $tpl->setVar('public_registration', $data['new']['public_registration'] == 'y' ? 'true' : 'false');
+
+        $admins = array();
+        foreach(explode(',',$data['new']['domain_admins']) AS $adm){
+            $admins[] = trim($adm);
+        }
+        $tpl->setVar('domain_admins', "\t\t\"".implode("\",\n\t\t\"",$admins)."\"\n");
+
+        if($data['new']['use_pubsub']=='y'){
+            $tpl->setVar('use_pubsub', 'true');
+            $status_comps[] = 'pubsub.'.$data['new']['domain'];
+        }else{
+            $tpl->setVar('use_pubsub', 'false');
+        }
+        if($data['new']['use_proxy']=='y'){
+            $tpl->setVar('use_proxy', 'true');
+            $status_comps[] = 'proxy.'.$data['new']['domain'];
+        }else{
+            $tpl->setVar('use_proxy', 'false');
+        }
+
+        if($data['new']['use_anon_host']=='y'){
+            $tpl->setVar('use_anon_host', 'true');
+            $status_hosts[] = 'anon.'.$data['new']['domain'];
+        }else{
+            $tpl->setVar('use_anon_host', 'false');
+        }
+        if($data['new']['use_vjud']=='y'){
+            $tpl->setVar('use_vjud', 'true');
+            $tpl->setVar('vjud_opt_mode', 'opt-'.$data['new']['vjud_opt_mode']);
+            $status_comps[] = 'vjud.'.$data['new']['domain'];
+        }else{
+            $tpl->setVar('use_vjud', 'false');
+        }
+
+        $tpl->setVar('use_muc', $data['new']['use_muc_host']=='y'?'true':'false');
+        if($data['new']['use_muc_host'] == 'y'){
+            $status_comps[] = 'muc.'.$data['new']['domain'];
+            $tpl->setVar('muc_restrict_room_creation', $data['new']['muc_restrict_room_creation']);
+            $tpl->setVar('muc_name', strlen($data['new']['muc_name']) ? $data['new']['muc_name'] : $data['new']['domain'].' Chatrooms');
+            $admins = array();
+            foreach(explode(',',$data['new']['muc_admins']) AS $adm){
+                $admins[] = trim($adm);
+            }
+            $tpl->setVar('muc_admins', "\t\t\"".implode("\",\n\t\t\"",$admins)."\"\n");
+            $tpl->setVar('use_pastebin', $data['new']['use_pastebin']=='y'?'true':'false');
+            $tpl->setVar('pastebin_expire', intval($data['new']['pastebin_expire_after']));
+            $tpl->setVar('pastebin_trigger', $data['new']['pastebin_trigger']);
+            $tpl->setVar('use_archive', $data['new']['use_http_archive']=='y'?'true':'false');
+            $tpl->setVar('archive_join', $data['new']['http_archive_show_join']=='y'?'true':'false');
+            $tpl->setVar('archive_status', $data['new']['http_archive_show_status']=='y'?'true':'false');
+
+        }
+
+        $app->system->file_put_contents($this->xmpp_config_dir.'/hosts/'.$data['new']['domain'].'.cfg.lua', $tpl->grab());
+        unset($tpl);
+
+        // Create status host file
+        if($data['new']['use_status_host']=='y'){
+            $tpl = new tpl;
+            $tpl->newTemplate('metronome_conf_status.master');
+            $tpl->setVar('domain', $data['new']['domain']);
+            $tpl->setVar('status_hosts', "\t\t\"".implode("\",\n\t\t\"",$status_hosts)."\"\n");
+            $tpl->setVar('status_comps', "\t\t\"".implode("\",\n\t\t\"",$status_comps)."\"\n");
+            $app->system->file_put_contents($this->xmpp_config_dir.'/status/'.$data['new']['domain'].'.cfg.lua', $tpl->grab());
+            unset($tpl);
+        }
+    }
+
+    function domainDelete($event_name, $data){
+        global $app, $conf;
+
+        // get the config
+        $app->uses("system");
+        $domain = $data['old']['domain'];
+        $folder = str_replace('-', '%2d', str_replace('.', '%2e', $str = urlencode($domain)));
+
+        // Remove config files
+        $app->system->unlink("/etc/metronome/hosts/$domain.cfg.lua");
+        $app->system->unlink("/etc/metronome/status/$domain.cfg.lua");
+        $app->system->unlink("/etc/metronome/certs/$domain.cert");
+        $app->system->unlink("/etc/metronome/certs/$domain.key");
+        $app->system->unlink("/etc/metronome/certs/$domain.csr");
+        // Remove all stored data
+        var_dump('rm -rf /var/lib/metronome/'.$folder);
+        exec('rm -rf /var/lib/metronome/'.$folder);
+        exec('rm -rf /var/lib/metronome/*%2e'.$folder);
+
+        $app->services->restartServiceDelayed('metronome', 'restart');
+    }
+
+} // end class
+
+?>
diff --git a/server/server.sh b/server/server.sh
index 522e0d5f74..2f3d2fbb82 100755
--- a/server/server.sh
+++ b/server/server.sh
@@ -1,5 +1,6 @@
 #!/bin/sh
 
+
 PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/X11R6/bin
 
 . /etc/profile
-- 
GitLab