Michael Fürmann
2015-02-17 9f94a17eacd85144a1aee14929688b33e9393fe1
Server initialization and domain management (without ssl for now)
19 files modified
38 files added
3148 ■■■■■ changed files
install/apps/metronome-init 62 ●●●●● patch | view | raw | blame | history
install/apps/metronome_libs/mod_auth_external/authenticate_isp.php 65 ●●●●● patch | view | raw | blame | history
install/apps/metronome_libs/mod_auth_external/authenticate_isp.sh 38 ●●●●● patch | view | raw | blame | history
install/apps/metronome_libs/mod_auth_external/isuser_isp.php 44 ●●●●● patch | view | raw | blame | history
install/apps/metronome_libs/mod_auth_external/mod_auth_external.lua 118 ●●●●● patch | view | raw | blame | history
install/apps/metronome_libs/mod_discoitems.lua 24 ●●●●● patch | view | raw | blame | history
install/apps/metronome_libs/mod_webpresence/icons/status_away.png patch | view | raw | blame | history
install/apps/metronome_libs/mod_webpresence/icons/status_chat.png patch | view | raw | blame | history
install/apps/metronome_libs/mod_webpresence/icons/status_dnd.png patch | view | raw | blame | history
install/apps/metronome_libs/mod_webpresence/icons/status_offline.png patch | view | raw | blame | history
install/apps/metronome_libs/mod_webpresence/icons/status_online.png patch | view | raw | blame | history
install/apps/metronome_libs/mod_webpresence/icons/status_xa.png patch | view | raw | blame | history
install/apps/metronome_libs/mod_webpresence/mod_webpresence.lua 118 ●●●●● patch | view | raw | blame | history
install/dist/conf/debian60.conf.php 4 ●●●● patch | view | raw | blame | history
install/dist/lib/debian60.lib.php 4 ●●●● patch | view | raw | blame | history
install/install.php 19 ●●●●● patch | view | raw | blame | history
install/lib/installer_base.lib.php 64 ●●●●● patch | view | raw | blame | history
install/sql/incremental/upd_0081.sql 55 ●●●●● patch | view | raw | blame | history
install/sql/ispconfig3.sql 59 ●●●●● patch | view | raw | blame | history
install/tpl/metronome_conf_global.master 65 ●●●●● patch | view | raw | blame | history
install/tpl/metronome_conf_main.master 3 ●●●●● patch | view | raw | blame | history
install/tpl/server.ini.master 9 ●●●●● patch | view | raw | blame | history
interface/web/admin/form/server.tform.php 6 ●●●●● patch | view | raw | blame | history
interface/web/admin/form/server_config.tform.php 80 ●●●●● patch | view | raw | blame | history
interface/web/admin/lib/lang/en_server.lng 2 ●●●●● patch | view | raw | blame | history
interface/web/admin/lib/lang/en_server_config.lng 14 ●●●●● patch | view | raw | blame | history
interface/web/admin/lib/lang/en_server_list.lng 2 ●●●●● patch | view | raw | blame | history
interface/web/admin/list/server.list.php 9 ●●●●● patch | view | raw | blame | history
interface/web/admin/templates/server_config_xmpp_edit.htm 73 ●●●●● patch | view | raw | blame | history
interface/web/admin/templates/server_edit_services.htm 6 ●●●●● patch | view | raw | blame | history
interface/web/admin/templates/server_list.htm 3 ●●●●● patch | view | raw | blame | history
interface/web/client/form/client.tform.php 100 ●●●●● patch | view | raw | blame | history
interface/web/client/lib/lang/en_client.lng 21 ●●●●● patch | view | raw | blame | history
interface/web/client/templates/client_edit_limits.htm 64 ●●●●● patch | view | raw | blame | history
interface/web/js/xmpp_domain_muc.js 26 ●●●●● patch | view | raw | blame | history
interface/web/js/xmpp_domain_registration.js 25 ●●●●● patch | view | raw | blame | history
interface/web/mail/form/xmpp_domain.tform.php 284 ●●●●● patch | view | raw | blame | history
interface/web/mail/lib/lang/en_xmpp_domain.lng 28 ●●●●● patch | view | raw | blame | history
interface/web/mail/lib/lang/en_xmpp_domain_admin_list.lng 8 ●●●●● patch | view | raw | blame | history
interface/web/mail/lib/lang/en_xmpp_domain_list.lng 7 ●●●●● patch | view | raw | blame | history
interface/web/mail/lib/module.conf.php 24 ●●●●● patch | view | raw | blame | history
interface/web/mail/list/xmpp_domain.list.php 109 ●●●●● patch | view | raw | blame | history
interface/web/mail/templates/xmpp_domain_admin_list.htm 60 ●●●●● patch | view | raw | blame | history
interface/web/mail/templates/xmpp_domain_edit.htm 124 ●●●●● patch | view | raw | blame | history
interface/web/mail/templates/xmpp_domain_edit_modules.htm 52 ●●●●● patch | view | raw | blame | history
interface/web/mail/templates/xmpp_domain_edit_muc.htm 87 ●●●●● patch | view | raw | blame | history
interface/web/mail/templates/xmpp_domain_list.htm 74 ●●●●● patch | view | raw | blame | history
interface/web/mail/xmpp_domain_del.php 102 ●●●●● patch | view | raw | blame | history
interface/web/mail/xmpp_domain_edit.php 436 ●●●●● patch | view | raw | blame | history
interface/web/mail/xmpp_domain_list.php 28 ●●●●● patch | view | raw | blame | history
server/conf/metronome_conf_global.master 48 ●●●●● patch | view | raw | blame | history
server/conf/metronome_conf_host.master 138 ●●●●● patch | view | raw | blame | history
server/conf/metronome_conf_main.master 3 ●●●●● patch | view | raw | blame | history
server/conf/metronome_conf_status.master 12 ●●●●● patch | view | raw | blame | history
server/mods-available/xmpp_module.inc.php 109 ●●●●● patch | view | raw | blame | history
server/plugins-available/xmpp_plugin.inc.php 232 ●●●●● patch | view | raw | blame | history
server/server.sh 1 ●●●● patch | view | raw | blame | history
install/apps/metronome-init
New file
@@ -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
install/apps/metronome_libs/mod_auth_external/authenticate_isp.php
New file
@@ -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);
}
?>
install/apps/metronome_libs/mod_auth_external/authenticate_isp.sh
New file
@@ -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
install/apps/metronome_libs/mod_auth_external/isuser_isp.php
New file
@@ -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;
}
?>
install/apps/metronome_libs/mod_auth_external/mod_auth_external.lua
New file
@@ -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));
install/apps/metronome_libs/mod_discoitems.lua
New file
@@ -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);
install/apps/metronome_libs/mod_webpresence/icons/status_away.png
install/apps/metronome_libs/mod_webpresence/icons/status_chat.png
install/apps/metronome_libs/mod_webpresence/icons/status_dnd.png
install/apps/metronome_libs/mod_webpresence/icons/status_offline.png
install/apps/metronome_libs/mod_webpresence/icons/status_online.png
install/apps/metronome_libs/mod_webpresence/icons/status_xa.png
install/apps/metronome_libs/mod_webpresence/mod_webpresence.lua
New file
@@ -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;
    };
});
install/dist/conf/debian60.conf.php
@@ -222,5 +222,9 @@
$conf['cron']['crontab_dir'] = '/etc/cron.d';
$conf['cron']['wget'] = '/usr/bin/wget';
//* Metronome XMPP
$conf['xmpp']['installed'] = false;
$conf['xmpp']['init_script'] = 'metronome';
?>
install/dist/lib/debian60.lib.php
@@ -154,6 +154,10 @@
    */
    }
    public function configure_xmpp() {
        parent::configure_xmpp();
    }
}
?>
install/install.php
@@ -347,6 +347,13 @@
    }
    */
    //* 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($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 @@
    $conf['services']['db'] = true;
    $conf['services']['firewall'] = false;
    $conf['services']['proxy'] = false;
    $conf['services']['xmpp'] = false;
    //** Get Server ID
@@ -639,6 +648,16 @@
        $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') {
install/lib/installer_base.lib.php
@@ -155,6 +155,7 @@
        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 @@
    }
    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 @@
        $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);
install/sql/incremental/upd_0081.sql
New file
@@ -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 ;
install/sql/ispconfig3.sql
@@ -184,6 +184,16 @@
  `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 @@
  `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',
@@ -1951,6 +1962,54 @@
) 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
-- --------------------------------------------------------
install/tpl/metronome_conf_global.master
New file
@@ -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";
install/tpl/metronome_conf_main.master
New file
@@ -0,0 +1,3 @@
Include "/etc/metronome/global.cfg.lua"
Include "/etc/metronome/hosts/*.lua"
Include "/etc/metronome/status/*.lua"
install/tpl/server.ini.master
@@ -145,3 +145,12 @@
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
interface/web/admin/form/server.tform.php
@@ -102,6 +102,12 @@
            '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',
interface/web/admin/form/server_config.tform.php
@@ -1318,6 +1318,86 @@
);
$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,
interface/web/admin/lib/lang/en_server.lng
@@ -12,4 +12,6 @@
$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';
?>
interface/web/admin/lib/lang/en_server_config.lng
@@ -264,4 +264,18 @@
$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';
?>
interface/web/admin/lib/lang/en_server_list.lng
@@ -10,4 +10,6 @@
$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';
?>
interface/web/admin/list/server.list.php
@@ -110,4 +110,13 @@
    '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>"));
?>
interface/web/admin/templates/server_config_xmpp_edit.htm
New file
@@ -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>
interface/web/admin/templates/server_edit_services.htm
@@ -45,6 +45,12 @@
                </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">
                    {tmpl_var name='mirror_server_id'}
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>
interface/web/client/form/client.tform.php
@@ -773,6 +773,106 @@
            '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',
interface/web/client/lib/lang/en_client.lng
@@ -132,6 +132,7 @@
$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_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';
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">
interface/web/js/xmpp_domain_muc.js
New file
@@ -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');
})
interface/web/js/xmpp_domain_registration.js
New file
@@ -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');
})
interface/web/mail/form/xmpp_domain.tform.php
New file
@@ -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
        //#################################
    )
);
?>
interface/web/mail/lib/lang/en_xmpp_domain.lng
New file
@@ -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';
?>
interface/web/mail/lib/lang/en_xmpp_domain_admin_list.lng
New file
@@ -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';
?>
interface/web/mail/lib/lang/en_xmpp_domain_list.lng
New file
@@ -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';
?>
interface/web/mail/lib/module.conf.php
@@ -148,6 +148,30 @@
        '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
interface/web/mail/list/xmpp_domain.list.php
New file
@@ -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'  => "");
?>
interface/web/mail/templates/xmpp_domain_admin_list.htm
New file
@@ -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>
interface/web/mail/templates/xmpp_domain_edit.htm
New file
@@ -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>
interface/web/mail/templates/xmpp_domain_edit_modules.htm
New file
@@ -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>
interface/web/mail/templates/xmpp_domain_edit_muc.htm
New file
@@ -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>
interface/web/mail/templates/xmpp_domain_list.htm
New file
@@ -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>
interface/web/mail/xmpp_domain_del.php
New file
@@ -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();
?>
interface/web/mail/xmpp_domain_edit.php
New file
@@ -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();
?>
interface/web/mail/xmpp_domain_list.php
New file
@@ -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();
?>
server/conf/metronome_conf_global.master
New file
@@ -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";
server/conf/metronome_conf_host.master
New file
@@ -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>
server/conf/metronome_conf_main.master
New file
@@ -0,0 +1,3 @@
Include "/etc/metronome/global.cfg.lua"
Include "/etc/metronome/hosts/*.lua"
Include "/etc/metronome/status.cfg.lua"
server/conf/metronome_conf_status.master
New file
@@ -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'}
        };
server/mods-available/xmpp_module.inc.php
New file
@@ -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
?>
server/plugins-available/xmpp_plugin.inc.php
New file
@@ -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
?>
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