Mercurial > prosody-modules
changeset 6520:7eb114975cec
mod_admin_web2: Fork of admin_web for prosody 13.0. It is a fork because it changes access rights and might be insecure. Mark as alpha.
| author | Menel <menel@snikket.de> |
|---|---|
| date | Fri, 24 Apr 2026 12:40:13 +0200 |
| parents | 01d8bfbfc435 |
| children | 28e39dbf9d7b |
| files | mod_admin_web2/README.md mod_admin_web2/admin_web2/get_deps.sh mod_admin_web2/admin_web2/mod_admin_web2.lua mod_admin_web2/admin_web2/www_files/css/style.css mod_admin_web2/admin_web2/www_files/images/blue_orange.png mod_admin_web2/admin_web2/www_files/images/compressed.png mod_admin_web2/admin_web2/www_files/images/encrypted.png mod_admin_web2/admin_web2/www_files/images/prosody.png mod_admin_web2/admin_web2/www_files/images/secure.png mod_admin_web2/admin_web2/www_files/index.html mod_admin_web2/admin_web2/www_files/js/main.js |
| diffstat | 11 files changed, 881 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_admin_web2/README.md Fri Apr 24 12:40:13 2026 +0200 @@ -0,0 +1,67 @@ +--- +labels: +- 'Stage-Alpha' +summary: Web administration interface +rockspec: + build: + platforms: + unix: + type: command + build_command: cd admin_web2; sh get_deps.sh + install_command: | + cd admin_web2; + cp mod_admin_web2.lua $(LUADIR); + cp -r www_files $(PREFIX); +... + +Introduction +============ + +This module is a fork of [mod_admin_web], because that on is incompatible with prosody 13.0. +It was made with only small changes but also without much understanding of lua and the internal workigs of prosody. Use with care. Restrict access from the web. +Patches welcome. + +This module provides a basic web-administration interface. It currently +gives you access to Ad-Hoc commands on any virtual host or component. It +also provides a live list of S2S and C2S connections. (buggy, not showing all of them) + +**New:** You need to be the global instance operator to access this module. Smiplifying access rights. +**Known Issue:** If you define it on more then one host or globally, it might be nessesary to reload the module to have access to all hosts from within one interface. + +Installation +============ + +1. Copy the admin\_web directory into a directory Prosody will check + for plugins. (cf. [Installing + modules](http://prosody.im/doc/installing_modules)) +2. **Execute the contained `get_deps.sh` script from within the admin\_web + directory.** (Requires wget, tar, and a basic shell) + +Configuration Details +===================== + +"admin\_web" needs to be added to the modules\_enabled table of the host +you want to load this module on. + +By default the interface will then be reachable under +`http://example.com:5280/admin`, or `https://example.com:5281/admin`. + +The module will automatically enable two other modules if they aren't +already: mod\_bosh (used to connect to the server from the web), and +mod\_admin\_adhoc (which provides admin commands over XMPP). + + VirtualHost "example.com" + modules_enabled = { + ..... + "admin_web"; + ..... + } + +Compatibility +============= + + --------- ---------------------------------- + 13.0 Works + 0.12 not supported, use [mod_admin_web] + \<= 0.11 not supported + --------- ----------------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_admin_web2/admin_web2/get_deps.sh Fri Apr 24 12:40:13 2026 +0200 @@ -0,0 +1,23 @@ +#!/bin/sh +JQUERY_VERSION="1.10.2" +STROPHE_VERSION="1.1.2" +BOOTSTRAP_VERSION="1.4.0" +ADHOC_COMMITISH="87bfedccdb91e2ff7cfb165e989e5259c155b513" + +cd www_files/js + +rm -f jquery-$JQUERY_VERSION.min.js +wget http://code.jquery.com/jquery-$JQUERY_VERSION.min.js || exit 1 + +rm -f adhoc.js +wget -O adhoc.js "http://git.babelmonkeys.de/?p=adhocweb.git;a=blob_plain;f=js/adhoc.js;hb=$ADHOC_COMMITISH" || exit 1 + +rm -f strophe.min.js +wget https://raw.github.com/strophe/strophe.im/gh-pages/strophejs/downloads/strophejs-$STROPHE_VERSION.tar.gz && + tar xzf strophejs-$STROPHE_VERSION.tar.gz strophejs-$STROPHE_VERSION/strophe.min.js && + mv strophejs-$STROPHE_VERSION/strophe.min.js . && + rm -r strophejs-$STROPHE_VERSION strophejs-$STROPHE_VERSION.tar.gz || exit 1 + +cd ../css +rm -f bootstrap-$BOOTSTRAP_VERSION.min.css +wget https://raw.github.com/twbs/bootstrap/v$BOOTSTRAP_VERSION/bootstrap.min.css -O bootstrap-$BOOTSTRAP_VERSION.min.css || exit 1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_admin_web2/admin_web2/mod_admin_web2.lua Fri Apr 24 12:40:13 2026 +0200 @@ -0,0 +1,332 @@ +-- Copyright (C) 2010 Florian Zeitz +-- +-- This file is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- + +-- <session xmlns="http://prosody.im/streams/c2s" jid="alice@example.com/brussels"> +-- <encrypted/> +-- <compressed/> +-- </session> + +-- <session xmlns="http://prosody.im/streams/s2s" jid="example.com"> +-- <encrypted> +-- <valid/> / <invalid/> +-- </encrypted> +-- <compressed/> +-- <in/> / <out/> +-- </session> + +module:default_permission("prosody:operator", ":web-operator") + +local st = require "util.stanza"; +local uuid_generate = require "util.uuid".generate; +local pubsub = require "util.pubsub"; +local jid_bare = require "util.jid".bare; + +local hosts = prosody.hosts; +local incoming_s2s = prosody.incoming_s2s; + +module:set_global(); + +local service = {}; + +local xmlns_adminsub = "http://prosody.im/adminsub"; +local xmlns_c2s_session = "http://prosody.im/streams/c2s"; +local xmlns_s2s_session = "http://prosody.im/streams/s2s"; + +local idmap = {}; + +local function add_client(session, host) + local name = session.full_jid; + local id = idmap[name]; + if not id then + id = uuid_generate(); + idmap[name] = id; + end + local item = st.stanza("item", { id = id }):tag("session", {xmlns = xmlns_c2s_session, jid = name}):up(); + if session.secure then + local encrypted = item:tag("encrypted"); + local sock = session.conn and session.conn.socket and session.conn:socket() + local info = sock and sock.info and sock:info(); + for k, v in pairs(info or {}) do + encrypted:tag("info", { name = k }):text(tostring(v)):up(); + end + end + if session.compressed then + item:tag("compressed"):up(); + end + service[host]:publish(xmlns_c2s_session, host, id, item); + module:log("debug", "Added client %s", name); +end + +local function del_client(session, host) + local name = session.full_jid; + local id = idmap[name]; + if id then + local notifier = st.stanza("retract", { id = id }); + service[host]:retract(xmlns_c2s_session, host, id, notifier); + end +end + +local function add_host(session, type, host) + local name = (type == "out" and session.to_host) or (type == "in" and session.from_host); + local id = idmap[name.."_"..type]; + if not id then + id = uuid_generate(); + idmap[name.."_"..type] = id; + end + local item = st.stanza("item", { id = id }):tag("session", {xmlns = xmlns_s2s_session, jid = name}) + :tag(type):up(); + if session.secure then + local encrypted = item:tag("encrypted"); + + local sock = session.conn and session.conn.socket and session.conn:socket() + local info = sock and sock.info and sock:info(); + for k, v in pairs(info or {}) do + encrypted:tag("info", { name = k }):text(tostring(v)):up(); + end + + if session.cert_identity_status == "valid" then + encrypted:tag("valid"); + else + encrypted:tag("invalid"); + end + end + if session.compressed then + item:tag("compressed"):up(); + end + service[host]:publish(xmlns_s2s_session, host, id, item); + module:log("debug", "Added host %s s2s%s", name, type); +end + +local function del_host(session, type, host) + local name = (type == "out" and session.to_host) or (type == "in" and session.from_host); + local id = idmap[name.."_"..type]; + if id then + local notifier = st.stanza("retract", { id = id }); + service[host]:retract(xmlns_s2s_session, host, id, notifier); + end +end + +function module.add_host(module) + -- Dependencies + module:depends("bosh"); + module:depends("admin_adhoc"); + module:depends("http"); + + local http_files = require "net.http.files"; + local serve_file = http_files.serve { + path = module:get_directory() .. "/www_files"; + }; + + -- Setup HTTP server + module:provides("http", { + title = "Admin Interface"; + name = "admin"; + route = { + ["GET"] = function(event) + event.response.headers.location = event.request.path .. "/"; + return 301; + end; + ["GET /*"] = serve_file; + } + }); + + -- Setup adminsub service + local function simple_broadcast(kind, node, jids, item) + if item then + item = st.clone(item); + item.attr.xmlns = nil; -- Clear the pubsub namespace + end + local message = st.message({ from = module.host, type = "headline" }) + :tag("event", { xmlns = xmlns_adminsub .. "#event" }) + :tag(kind, { node = node }) + :add_child(item); + for jid in pairs(jids) do + module:log("debug", "Sending notification to %s", jid); + message.attr.to = jid; + module:send(message); + end + end + + service[module.host] = pubsub.new({ + broadcaster = simple_broadcast; + normalize_jid = jid_bare; +-- what was this for? prosody:operator has full rights everywhere, this shoud be fine? +-- get_affiliation = function(jid) return get_affiliation(jid, module.host) end; + get_affiliation = function() return "owner" end; + capabilities = { + member = { + create = false; + publish = false; + retract = false; + get_nodes = true; + + subscribe = true; + unsubscribe = true; + get_subscription = true; + get_subscriptions = true; + get_items = true; + + subscribe_other = false; + unsubscribe_other = false; + get_subscription_other = false; + get_subscriptions_other = false; + + be_subscribed = true; + be_unsubscribed = true; + + set_affiliation = false; + }; + + owner = { + create = true; + publish = true; + retract = true; + get_nodes = true; + + subscribe = true; + unsubscribe = true; + get_subscription = true; + get_subscriptions = true; + get_items = true; + + subscribe_other = true; + unsubscribe_other = true; + get_subscription_other = true; + get_subscriptions_other = true; + + be_subscribed = true; + be_unsubscribed = true; + + set_affiliation = true; + }; + }; + }); + + -- Create node for s2s sessions + local ok, err = service[module.host]:create(xmlns_s2s_session, true); + if not ok then + module:log("warn", "Could not create node %s: %s", xmlns_s2s_session, err); + else + service[module.host]:set_affiliation(xmlns_s2s_session, true, module.host, "owner") + end + + -- Add outgoing s2s sessions + for _, session in pairs(hosts[module.host].s2sout) do + if session.type ~= "s2sout_unauthed" then + add_host(session, "out", module.host); + end + end + + -- Add incoming s2s sessions + for session in pairs(incoming_s2s) do + if session.to_host == module.host then + add_host(session, "in", module.host); + end + end + + -- Create node for c2s sessions + ok, err = service[module.host]:create(xmlns_c2s_session, true); + if not ok then + module:log("warn", "Could not create node %s: %s", xmlns_c2s_session, tostring(err)); + else + service[module.host]:set_affiliation(xmlns_c2s_session, true, module.host, "owner") + end + + -- Add c2s sessions + for _, user in pairs(hosts[module.host].sessions or {}) do + for _, session in pairs(user.sessions or {}) do + add_client(session, module.host); + end + end + + -- Register adminsub handler + module:hook("iq/host/http://prosody.im/adminsub:adminsub", function(event) + -- luacheck: ignore 431/ok + local origin, stanza = event.origin, event.stanza; + local adminsub = stanza.tags[1]; + local action = adminsub.tags[1]; + local reply; + if action.name == "subscribe" then + local ok, ret = service[module.host]:add_subscription(action.attr.node, stanza.attr.from, stanza.attr.from); + if ok then + reply = st.reply(stanza) + :tag("adminsub", { xmlns = xmlns_adminsub }); + else + reply = st.error_reply(stanza, "cancel", ret); + end + elseif action.name == "unsubscribe" then + local ok, ret = service[module.host]:remove_subscription(action.attr.node, stanza.attr.from, stanza.attr.from); + if ok then + reply = st.reply(stanza) + :tag("adminsub", { xmlns = xmlns_adminsub }); + else + reply = st.error_reply(stanza, "cancel", ret); + end + elseif action.name == "items" then + local node = action.attr.node; + local ok, ret = service[module.host]:get_items(node, stanza.attr.from); + if not ok then + origin.send(st.error_reply(stanza, "cancel", ret)); + return true; + end + + local data = st.stanza("items", { node = node }); + for _, entry in pairs(ret) do + data:add_child(entry); + end + if data then + reply = st.reply(stanza) + :tag("adminsub", { xmlns = xmlns_adminsub }) + :add_child(data); + else + reply = st.error_reply(stanza, "cancel", "item-not-found"); + end + elseif action.name == "adminfor" then + local data = st.stanza("adminfor"); + for host_name in pairs(hosts) do + -- new Permission API: + if module:context(host_name):may(":web-operator", stanza.attr.from) then + data:tag("item"):text(host_name):up(); + end + end + reply = st.reply(stanza) + :tag("adminsub", { xmlns = xmlns_adminsub }) + :add_child(data); + else + reply = st.error_reply(stanza, "feature-not-implemented"); + end + origin.send(reply); + return true; + end); + + -- Add/remove c2s sessions + module:hook("resource-bind", function(event) + add_client(event.session, module.host); + end); + + module:hook("resource-unbind", function(event) + del_client(event.session, module.host); + service[module.host]:remove_subscription(xmlns_c2s_session, module.host, event.session.full_jid); + service[module.host]:remove_subscription(xmlns_s2s_session, module.host, event.session.full_jid); + end); + + -- Add/remove s2s sessions + module:hook("s2sout-established", function(event) + add_host(event.session, "out", module.host); + end); + + module:hook("s2sin-established", function(event) + add_host(event.session, "in", module.host); + end); + + module:hook("s2sout-destroyed", function(event) + del_host(event.session, "out", module.host); + end); + + module:hook("s2sin-destroyed", function(event) + del_host(event.session, "in", module.host); + end); +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_admin_web2/admin_web2/www_files/css/style.css Fri Apr 24 12:40:13 2026 +0200 @@ -0,0 +1,114 @@ +body { + margin: 0 +} + +a { + color: #0000FF +} + +#adhocCommands > ul { + margin: 0 +} + +.btn { + margin-right: 0.3em +} + +.btn:last-child { + margin-right: 0 +} + +#log_container { + clear: both; + display: none +} + +#adhocCommands { + border-right: solid 1px +} + +#adhocCommands li { + list-style: inside +} + +#login { + float: left; + margin: 1em 2em 0 1em; + padding-right: 1em; + border: solid 1px; + background: #eef0f2; + color: #000000 +} + +#main { + display: none; + margin: 1em +} + +#main p { + margin: 0 +} + +#top { + clear: both; + width: 100%; + padding: 0; +} + +@media screen and (min-width: 757px) { + #header { + background: url(../images/blue_orange.png) repeat-x + } +} + +#header img { + max-width: 100%; + height: auto +} + +#menu { + display: none; + color: #454748; + font-size: 1.1em; + background: #eef0f2; + width: 100%; +} + +#menu ul { + display: inline; + list-style-type: none; + margin: 0; + padding: 0.5em 0 +} + +#menu li { + display: inline; + padding: 0 0.5em +} + +#menu a { + color: #454748; + text-decoration: none +} + +#menu li a:hover { + color: #6197DF; + text-decoration: underline +} + +#selector { + display: inline-block +} + +#s2sList h2, #c2sList h2 { + color: #4b8ade; + margin: 0 +} + +#s2sList li, #c2sList li { + cursor: pointer +} + +#host { + margin: 0.25em; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_admin_web2/admin_web2/www_files/index.html Fri Apr 24 12:40:13 2026 +0200 @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>Prosody Webadmin</title> +<link rel="stylesheet" type="text/css" href="css/bootstrap-1.4.0.min.css" /> +<link rel="stylesheet" type="text/css" href="css/style.css" /> +<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" /> +<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script> +<script type="text/javascript" src="js/strophe.min.js"></script> +<script type="text/javascript" src="js/adhoc.js"></script> +<script type="text/javascript" src="js/main.js"></script> +</head> + +<body> +<div id='top'> + <div id='header'> + <img src="images/prosody.png" alt="Prosody"/> + </div> + <div id='menu'> + <ul> + <li><a id='adhocMenu' href="#adhoc">General</a></li> + <li><a id='serverMenu' href="#s2sList">Servers</a></li> + <li><a id='clientMenu' href="#c2sList">Clients</a></li> + <li><span id="selector">Host: <select id="host"></select></span></li> + <li><a href="#" id='logout'>Logout</a></li> + </ul> + </div> +</div> + +<div id='login'> + <form id='cred' name='cred' class='form-stacked'> + <fieldset> + <div class='clearfix'> + <label for='jid'>JID:</label> + <div class='input'> + <input type='text' id='jid' /> + </div> + </div> + <div class='clearfix'> + <label for='pass'>Password:</label> + <div class='input'> + <input type='password' id='pass' /> + </div> + </div> + <div class='clearfix'> + <div class='input'> + <input type='submit' id='connect' value='Login' class='btn' /> + </div> + </div> + </fieldset> + </form> +</div> + +<div id='main'> + <div id="adhoc"> + <div class="row"> + <div id="adhocCommands" class="span4"></div> + <div id="adhocDisplay" class="span12"></div> + </div> + </div> + <div id="s2sList" class="container"> + <div class="row"> + <div class="span8"> + <h2>Incoming S2S connections:</h2> + <ul id="s2sin"></ul> + </div> + <div class="span8"> + <h2>Outgoing S2S connections:</h2> + <ul id="s2sout"></ul> + </div> + </div> + </div> + <div id="c2sList" class="container"> + <div class="row"> + <div class="span16"> + <h2>Client connections:</h2> + <ul id="c2s"></ul> + </div> + </div> + </div> +</div> + +<div id='log_container'> + <a id='log_toggle' href='#'>Status Log :</a> + <div id='log'></div> +</div> +</body> +</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_admin_web2/admin_web2/www_files/js/main.js Fri Apr 24 12:40:13 2026 +0200 @@ -0,0 +1,255 @@ +var BOSH_SERVICE = '/http-bind/'; +var show_log = false; + +Strophe.addNamespace('C2SSTREAM', 'http://prosody.im/streams/c2s'); +Strophe.addNamespace('S2SSTREAM', 'http://prosody.im/streams/s2s'); +Strophe.addNamespace('ADMINSUB', 'http://prosody.im/adminsub'); +Strophe.addNamespace('CAPS', 'http://jabber.org/protocol/caps'); + +var localJID = null; +var connection = null; + +var adminsubHost = null; +var adhocControl = new Adhoc('#adhocDisplay', function() {}); + +function log(msg) { + var entry = $('<div></div>').append(document.createTextNode(msg)); + $('#log').append(entry); +} + +function rawInput(data) { + log('RECV: ' + data); +} + +function rawOutput(data) { + log('SENT: ' + data); +} + +function _cbNewS2S(e) { + var items, item, entry, tmp, retract, id, jid, infos, info, metadata; + items = e.getElementsByTagName('item'); + for (i = 0; i < items.length; i++) { + item = items[i]; + id = item.attributes.getNamedItem('id').value; + jid = item.getElementsByTagName('session')[0].attributes.getNamedItem('jid').value; + infos = item.getElementsByTagName('info'); + + entry = $('<li id="' + id + '">' + jid + '</li>'); + if (tmp = item.getElementsByTagName('encrypted')[0]) { + if (tmp.getElementsByTagName('valid')[0]) { + entry.append('<img src="images/secure.png" title="encrypted (certificate valid)" alt=" (secure) (encrypted)" />'); + } else { + entry.append('<img src="images/encrypted.png" title="encrypted (certificate invalid)" alt=" (encrypted)" />'); + } + } + if (item.getElementsByTagName('compressed')[0]) { + entry.append('<img src="images/compressed.png" title="compressed" alt=" (compressed)" />'); + } + metadata = $('<ul/>').css('display', 'none'); + entry.on('click', function() { + $(this).find("ul").slideToggle(); + }); + metadata.appendTo(entry); + for (j = 0; j < infos.length; j++) { + info = infos[j]; + metadata.append('<li><b>' + info.attributes.getNamedItem('name').value + ':</b> ' + info.textContent + '</li>'); + } + if (infos.length == 0) + metadata.append('<li>No information available</li>'); + + if (items[i].getElementsByTagName('out')[0]) { + entry.appendTo('#s2sout'); + } else { + entry.appendTo('#s2sin'); + } + } + retract = e.getElementsByTagName('retract')[0]; + if (retract) { + id = retract.attributes.getNamedItem('id').value; + $('#' + id).remove(); + } + return true; +} + +function _cbNewC2S(e) { + var items, item, entry, retract, id, jid, infos, info, metadata; + items = e.getElementsByTagName('item'); + for (i = 0; i < items.length; i++) { + item = items[i]; + id = item.attributes.getNamedItem('id').value; + jid = item.getElementsByTagName('session')[0].attributes.getNamedItem('jid').value; + infos = item.getElementsByTagName('info'); + entry = $('<li id="' + id + '">' + jid + '</li>'); + if (item.getElementsByTagName('encrypted')[0]) { + entry.append('<img src="images/encrypted.png" title="encrypted" alt=" (encrypted)" />'); + } + if (item.getElementsByTagName('compressed')[0]) { + entry.append('<img src="images/compressed.png" title="compressed" alt=" (compressed)" />'); + } + metadata = $('<ul/>').css('display', 'none'); + entry.on('click', function() { + $(this).find("ul").slideToggle(); + }); + metadata.appendTo(entry); + for (j = 0; j < infos.length; j++) { + info = infos[j]; + metadata.append('<li><b>' + info.attributes.getNamedItem('name').value + ':</b> ' + info.textContent + '</li>'); + } + if (infos.length == 0) + metadata.append('<li>No information available</li>'); + entry.appendTo('#c2s'); + } + retract = e.getElementsByTagName('retract')[0]; + if (retract) { + id = retract.attributes.getNamedItem('id').value; + $('#' + id).remove(); + } + return true; +} + +function _cbAdminSub(e) { + var node = e.getElementsByTagName('items')[0].attributes.getNamedItem('node').value; + if (node == Strophe.NS.C2SSTREAM) { + _cbNewC2S(e); + } else if (node == Strophe.NS.S2SSTREAM) { + _cbNewS2S(e); + } + + return true; +} + +function onConnect(status) { + if (status == Strophe.Status.CONNECTING) { + log('Strophe is connecting.'); + } else if (status == Strophe.Status.CONNFAIL) { + alert('Connection failed (Wrong host?)'); + log('Strophe failed to connect.'); + showConnect(); + } else if (status == Strophe.Status.DISCONNECTING) { + log('Strophe is disconnecting.'); + } else if (status == Strophe.Status.DISCONNECTED) { + log('Strophe is disconnected.'); + showConnect(); + } else if (status == Strophe.Status.AUTHFAIL) { + alert('Wrong username and/or password'); + log('Authentication failed'); + if (connection) { + connection.disconnect(); + } + } else if (status == Strophe.Status.CONNECTED) { + log('Strophe is connected.'); + connection.sendIQ($iq({to: connection.domain, type: 'get', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB}) + .c('adminfor'), function(e) { + var items; + var domainpart = Strophe.getDomainFromJid(connection.jid); + items = e.getElementsByTagName('item'); + if (items.length == 0) { + alert("You are not an administrator"); + connection.disconnect(); + return false; + } + for (i = 0; i < items.length; i++) { + var host = $(items[i]).text(); + $('<option/>').text(host).prop('selected', host == domainpart).appendTo('#host'); + } + showDisconnect(); + adminsubHost = $('#host').val(); + adhocControl.checkFeatures(adminsubHost, + function () { adhocControl.getCommandNodes(function (result) { $('#adhocDisplay').empty(); $('#adhocCommands').html(result); }) }, + function () { $('#adhocCommands').empty(); $('#adhocDisplay').html('<p>This host does not support commands</p>'); }); + connection.addHandler(_cbAdminSub, Strophe.NS.ADMINSUB + '#event', 'message'); + connection.send($iq({to: adminsubHost, type: 'set', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB}) + .c('subscribe', {node: Strophe.NS.C2SSTREAM})); + connection.send($iq({to: adminsubHost, type: 'set', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB}) + .c('subscribe', {node: Strophe.NS.S2SSTREAM})); + connection.sendIQ($iq({to: adminsubHost, type: 'get', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB}) + .c('items', {node: Strophe.NS.S2SSTREAM}), _cbNewS2S); + connection.sendIQ($iq({to: adminsubHost, type: 'get', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB}) + .c('items', {node: Strophe.NS.C2SSTREAM}), _cbNewC2S); + }); + } +} + +function showConnect() { + $('#login').show(); + $('#menu').hide(); + $('#main').hide(); + $('#s2sin').empty(); + $('#s2sout').empty(); + $('#c2s').empty(); + $('#host').empty(); +} + +function showDisconnect() { + $('#s2sList').hide(); + $('#c2sList').hide(); + $('#login').hide(); + + $('#menu').show(); + $('#main').show(); + $('#adhoc').show(); +} + +$(document).ready(function () { + connection = new Strophe.Connection(BOSH_SERVICE); + if (show_log) { + $('#log_container').show(); + connection.rawInput = rawInput; + connection.rawOutput = rawOutput; + } + + $("#log_toggle").click(function () { + $("#log").toggle(); + }); + + $('#cred').on('submit', function (event) { + var button = $('#connect').get(0); + var jid = $('#jid'); + var pass = $('#pass'); + localJID = jid.get(0).value; + + $('#log').empty(); + connection.connect(localJID, pass.get(0).value, onConnect); + event.preventDefault(); + }); + + $('#logout').click(function (event) { + connection.disconnect(); + event.preventDefault(); + }); + + $('#adhocMenu, #serverMenu, #clientMenu').click(function (event) { + event.preventDefault(); + var tab = $(this).attr('href'); + $('#main > div').hide(); + $(tab).fadeIn('fast'); + }); + + $('#host').on('change', function (event) { + connection.send($iq({to: adminsubHost, type: 'set', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB}) + .c('unsubscribe', {node: Strophe.NS.C2SSTREAM})); + connection.send($iq({to: adminsubHost, type: 'set', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB}) + .c('unsubscribe', {node: Strophe.NS.S2SSTREAM})); + adminsubHost = $(this).val(); + adhocControl.checkFeatures(adminsubHost, + function () { adhocControl.getCommandNodes(function (result) { $('#adhocDisplay').empty(); $('#adhocCommands').html(result); }) }, + function () { $('#adhocCommands').empty(); $('#adhocDisplay').html('<p>This host does not support commands</p>'); }); + $('#s2sin').empty(); + $('#s2sout').empty(); + $('#c2s').empty(); + connection.send($iq({to: adminsubHost, type: 'set', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB}) + .c('subscribe', {node: Strophe.NS.C2SSTREAM})); + connection.send($iq({to: adminsubHost, type: 'set', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB}) + .c('subscribe', {node: Strophe.NS.S2SSTREAM})); + connection.sendIQ($iq({to: adminsubHost, type: 'get', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB}) + .c('items', {node: Strophe.NS.S2SSTREAM}), _cbNewS2S); + connection.sendIQ($iq({to: adminsubHost, type: 'get', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB}) + .c('items', {node: Strophe.NS.C2SSTREAM}), _cbNewC2S); + }); +}); + +window.onunload = window.onbeforeunload = function() { + if (connection) { + connection.disconnect(); + } +}
