Flesh out the remainder of the manager + http changes and create a sample application to partially

demonstrate the capability of manager over http.


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@16850 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Mark Spencer
2006-04-01 08:49:54 +00:00
parent 46a1b7c73b
commit bfba044b5f
11 changed files with 3165 additions and 39 deletions

215
static-http/ajamdemo.html Normal file
View File

@@ -0,0 +1,215 @@
<script src="prototype.js"></script>
<script src="astman.js"></script>
<link href="astman.css" media="all" rel="Stylesheet" type="text/css" />
<script>
var logins = new Object;
var logoffs = new Object;
var channels = new Object;
var pongs = new Object;
var loggedon = 0;
var selectedchan = null;
var hungupchan = "";
var transferedchan = "";
var demo = new Object;
function loggedOn() {
if (loggedon)
return;
loggedon = 1;
updateButtons();
$('statusbar').innerHTML = "<i>Retrieving channel status...</i>";
astmanEngine.pollEvents();
astmanEngine.sendRequest('action=status', demo.channels);
}
function clearChannelList() {
$('channellist').innerHTML = "<i class='light'>Not connected</i>";
}
function loggedOff() {
if (!loggedon)
return;
loggedon = 0;
selectedchan = null;
updateButtons();
astmanEngine.channelClear();
clearChannelList();
}
function updateButtons()
{
if ($(selectedchan)) {
$('transfer').disabled = 0;
$('hangup').disabled = 0;
} else {
$('transfer').disabled = 1;
$('hangup').disabled = 1;
selectedchan = null;
}
if (loggedon) {
$('logoff').disabled = 0;
$('login').disabled = 1;
$('refresh').disabled = 0;
} else {
$('logoff').disabled = 1;
$('login').disabled = 0;
$('refresh').disabled = 1;
}
}
demo.channelCallback = function(target) {
selectedchan = target;
updateButtons();
}
demo.channels = function(msgs) {
resp = msgs[0].headers['response'];
if (resp == "Success") {
loggedOn();
} else
loggedOff();
for (i=1;i<msgs.length - 1;i++)
astmanEngine.channelUpdate(msgs[i]);
$('channellist').innerHTML = astmanEngine.channelTable(demo.channelCallback);
$('statusbar').innerHTML = "Ready";
}
demo.logins = function(msgs) {
$('statusbar').innerHTML = msgs[0].headers['message'];
resp = msgs[0].headers['response'];
if (resp == "Success")
loggedOn();
else
loggedOff();
};
demo.logoffs = function(msgs) {
$('statusbar').innerHTML = msgs[0].headers['message'];
loggedOff();
};
demo.hungup = function(msgs) {
$('statusbar').innerHTML = "Hungup " + hungupchan;
}
demo.transferred = function(msgs) {
$('statusbar').innerHTML = "Transferred " + transferredchan;
}
function doHangup() {
hungupchan = selectedchan;
astmanEngine.sendRequest('action=hangup&channel=' + selectedchan, demo.hungup);
}
function doStatus() {
$('statusbar').innerHTML = "<i>Updating channel status...</i>";
astmanEngine.channelClear();
astmanEngine.sendRequest('action=status', demo.channels);
}
function doLogin() {
$('statusbar').innerHTML = "<i>Logging in...</i>";
astmanEngine.sendRequest('action=login&username=' + $('username').value + "&secret=" + $('secret').value, demo.logins);
}
function doTransfer() {
var channel = astmanEngine.channelInfo(selectedchan);
var exten = prompt("Enter new extension for " + selectedchan);
var altchan;
if (exten) {
if (channel.link) {
if (confirm("Transfer " + channel.link + " too?"))
altchan = channel.link;
}
if (altchan) {
transferredchan = selectedchan + " and " + altchan + " to " + exten;
astmanEngine.sendRequest('action=redirect&channel=' + selectedchan + "&priority=1&extrachannel=" + altchan + "&exten=" + exten, demo.transferred);
} else {
transferredchan = selectedchan + " to " + exten;
astmanEngine.sendRequest('action=redirect&channel=' + selectedchan + "&priority=1&exten=" + exten, demo.transferred);
}
}
}
function doLogoff() {
$('statusbar').innerHTML = "<i>Logging off...</i>";
astmanEngine.sendRequest('action=logoff', demo.logoffs);
}
demo.pongs = function(msgs) {
resp = msgs[0].headers['response'];
if (resp == "Pong") {
$('statusbar').innerHTML = "<i>Already connected...</i>";
loggedOn();
} else {
$('statusbar').innerHTML = "<i>Please login...</i>";
loggedOff();
}
}
demo.eventcb = function(msgs) {
var x;
if (loggedon) {
for (i=1;i<msgs.length - 1;i++) {
astmanEngine.channelUpdate(msgs[i]);
}
$('channellist').innerHTML = astmanEngine.channelTable(demo.channelCallback);
astmanEngine.pollEvents();
}
updateButtons();
}
function localajaminit() {
astmanEngine.setURL('../rawman');
astmanEngine.setEventCallback(demo.eventcb);
//astmanEngine.setDebug($('ditto'));
clearChannelList();
astmanEngine.sendRequest('action=ping', demo.pongs);
}
</script>
<title>Asterisk&trade; AJAM Demo</title>
<body onload="localajaminit()">
<table align="center" width=600>
<tr valign="top"><td>
<table align="left">
<tr><td colspan="2"><h2>Asterisk&trade; AJAM Demo</h2></td>
<tr><td>Username:</td><td><input id="username"></td></tr>
<tr><td>Secret:</td><td><input type="password" id="secret"></td></tr>
<tr><td colspan=2 align="center">
<div id="statusbar">
<span style="margin-left: 4px;font-weight:bold">&nbsp;</span>
</div>
</td></tr>
<tr><td><input type="submit" id="login" value="Login" onClick="doLogin()"></td>
<td><input type="submit" id="logoff" value="Logoff" disabled=1 onClick="doLogoff()"></td></tr>
</table>
</td><td valign='bottom'>
<table>
<div style="margin-left:10;margin-right:50;margin-top:10;margin-bottom:20">
<i>This is a demo of the Asynchronous Javascript Asterisk Manager interface. You can login with a
valid, appropriately permissioned manager username and secret.</i>
</div>
<tr>
<td><input type="submit" onClick="doStatus()" id="refresh" value="Refresh"></td>
<td><input type="submit" onClick="doTransfer()" id="transfer" value="Transfer..."></td>
<td><input type="submit" onClick="doHangup()" id="hangup" value="Hangup"></td>
</tr>
</table>
</td></tr>
<tr><td colspan=2>
<div id="channellist" class="chanlist">
</div>
</td></tr>
<tr><td align="center" colspan=2>
<font size=-1><i>
Copyright (C) 2006 Digium, Inc. Asterisk and Digium are trademarks of Digium, Inc.
</i></font>
</td></tr>
</table>
</body>

34
static-http/astman.css Normal file
View File

@@ -0,0 +1,34 @@
.chanlist {
border : 1px solid #1f669b;
height : 150px;
overflow : auto;
background-color : #f1f1f1;
width : 600;
}
.chantable {
border : 0px;
background-color : #f1f1f1;
width : 100%;
}
.labels {
background-color : #000000;
color : #ffffff;
}
.chanlisteven {
background-color : #fff8e4;
}
.chanlistodd {
background-color : #f0f5ff;
}
.chanlistselected {
background-color : #ffb13d;
}
.light {
color : #717171;
}

256
static-http/astman.js Normal file
View File

@@ -0,0 +1,256 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Javascript routines or accessing manager routines over HTTP.
*
* Copyright (C) 1999 - 2006, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*
*/
function Astman() {
var me = this;
var channels = new Array;
var lastselect;
var selecttarget;
this.setURL = function(url) {
this.url = url;
};
this.setEventCallback = function(callback) {
this.eventcallback = callback;
};
this.setDebug = function(debug) {
this.debug = debug;
};
this.clickChannel = function(ev) {
var target = ev.target;
// XXX This is icky, we statically use astmanEngine to call the callback XXX
if (me.selecttarget)
me.restoreTarget(me.selecttarget);
while(!target.id || !target.id.length)
target=target.parentNode;
me.selecttarget = target.id;
target.className = "chanlistselected";
me.chancallback(target.id);
};
this.restoreTarget = function(targetname) {
var other;
target = $(targetname);
if (!target)
return;
if (target.previousSibling) {
other = target.previousSibling.previousSibling.className;
} else if (target.nextSibling) {
other = target.nextSibling.nextSibling.className;
}
if (other) {
if (other == "chanlisteven")
target.className = "chanlistodd";
else
target.className = "chanlisteven";
} else
target.className = "chanlistodd";
};
this.channelUpdate = function(msg, channame) {
var fields = new Array("callerid", "calleridname", "context", "extension", "priority", "account", "state", "link", "uniqueid" );
if (!channame || !channame.length)
channame = msg.headers['channel'];
if (!channels[channame])
channels[channame] = new Array();
if (msg.headers.event) {
if (msg.headers.event == "Hangup") {
delete channels[channame];
} else if (msg.headers.event == "Link") {
var chan1 = msg.headers.channel1;
var chan2 = msg.headers.channel2;
if (chan1 && channels[chan1])
channels[chan1].link = chan2;
if (chan2 && channels[chan2])
channels[chan2].link = chan1;
} else if (msg.headers.event == "Unlink") {
var chan1 = msg.headers.channel1;
var chan2 = msg.headers.channel2;
if (chan1 && channels[chan1])
delete channels[chan1].link;
if (chan2 && channels[chan2])
delete channels[chan2].link;
} else if (msg.headers.event == "Rename") {
var oldname = msg.headers.oldname;
var newname = msg.headers.newname;
if (oldname && channels[oldname]) {
channels[newname] = channels[oldname];
delete channels[oldname];
}
} else {
channels[channame]['channel'] = channame;
for (x=0;x<fields.length;x++) {
if (msg.headers[fields[x]])
channels[channame][fields[x]] = msg.headers[fields[x]];
}
}
} else {
channels[channame]['channel'] = channame;
for (x=0;x<fields.length;x++) {
if (msg.headers[fields[x]])
channels[channame][fields[x]] = msg.headers[fields[x]];
}
}
};
this.channelClear = function() {
channels = new Array;
}
this.channelInfo = function(channame) {
return channels[channame];
};
this.channelTable = function(callback) {
var s, x;
var cclass, count=0;
var found = 0;
var fieldlist = new Array("channel", "callerid", "calleridname", "context", "extension", "priority");
me.chancallback = callback;
s = "<table class='chantable' align='center'>\n";
s = s + "\t<tr class='labels' id='labels'><td>Channel</td><td>State</td><td>Caller</td><td>Location</td><td>Link</td></tr>";
count=0;
for (x in channels) {
if (channels[x].channel) {
if (count % 2)
cclass = "chanlistodd";
else
cclass = "chanlisteven";
if (me.selecttarget && (me.selecttarget == x))
cclass = "chanlistselected";
count++;
s = s + "\t<tr class='" + cclass + "' id='" + channels[x].channel + "' onClick='astmanEngine.clickChannel(event)'>";
s = s + "<td>" + channels[x].channel + "</td>";
if (channels[x].state)
s = s + "<td>" + channels[x].state + "</td>";
else
s = s + "<td><i class='light'>unknown</i></td>";
if (channels[x].calleridname && channels[x].callerid && channels[x].calleridname != "<unknown>") {
cid = channels[x].calleridname.escapeHTML() + " &lt;" + channels[x].callerid.escapeHTML() + "&gt;";
} else if (channels[x].calleridname && (channels[x].calleridname != "<unknown>")) {
cid = channels[x].calleridname.escapeHTML();
} else if (channels[x].callerid) {
cid = channels[x].callerid.escapeHTML();
} else {
cid = "<i class='light'>Unknown</i>";
}
s = s + "<td>" + cid + "</td>";
if (channels[x].extension) {
s = s + "<td>" + channels[x].extension + "@" + channels[x].context + ":" + channels[x].priority + "</td>";
} else {
s = s + "<td><i class='light'>None</i></td>";
}
if (channels[x].link) {
s = s + "<td>" + channels[x].link + "</td>";
} else {
s = s + "<td><i class='light'>None</i></td>";
}
s = s + "</tr>\n";
found++;
}
}
if (!found)
s += "<tr><td colspan=" + fieldlist.length + "><i class='light'>No active channels</i></td>\n";
s += "</table>\n";
return s;
};
this.parseResponse = function(t, callback) {
var msgs = new Array();
var inmsg = 0;
var msgnum = 0;
var x,y;
var s = t.responseText;
var allheaders = s.split('\r\n');
if (me.debug)
me.debug.value = "\n";
for (x=0;x<allheaders.length;x++) {
if (allheaders[x].length) {
var fields = allheaders[x].split(': ');
if (!inmsg) {
msgs[msgnum] = new Object();
msgs[msgnum].headers = new Array();
msgs[msgnum].names = new Array();
y=0;
}
msgs[msgnum].headers[fields[0].toLowerCase()] = fields[1];
msgs[msgnum].names[y++] = fields[0].toLowerCase();
if (me.debug)
me.debug.value = me.debug.value + "field " + fields[0] + "/" + fields[1] + "\n";
inmsg=1;
} else {
if (inmsg) {
if (me.debug)
me.debug.value = me.debug.value + " new message\n";
inmsg = 0;
msgnum++;
}
}
}
if (me.debug) {
me.debug.value = me.debug.value + "msgnum is " + msgnum + " and array length is " + msgs.length + "\n";
me.debug.value = me.debug.value + "length is " + msgs.length + "\n";
var x, y;
for (x=0;x<msgs.length;x++) {
for (y=0;y<msgs[x].names.length;y++) {
me.debug.value = me.debug.value + "msg "+ (x + 1) + "/" + msgs[x].names[y] + "/" + msgs[x].headers[msgs[x].names[y]] + "\n";
}
}
}
callback(msgs);
};
this.managerResponse = function(t) {
me.parseResponse(t, me.callback);
};
this.doEvents = function(msgs) {
me.eventcallback(msgs);
};
this.eventResponse = function(t) {
me.parseResponse(t, me.doEvents);
};
this.sendRequest = function(request, callback) {
var tmp;
var opt = {
method: 'get',
asynchronous: true,
onSuccess: this.managerResponse,
onFailure: function(t) {
alert("Error: " + t.status + ": " + t.statusText);
},
};
me.callback = callback;
opt.parameters = request;
tmp = new Ajax.Request(this.url, opt);
};
this.pollEvents = function() {
var tmp;
var opt = {
method: 'get',
asynchronous: true,
onSuccess: this.eventResponse,
onFailure: function(t) {
alert("Event Error: " + t.status + ": " + t.statusText);
},
};
opt.parameters="action=waitevent";
tmp = new Ajax.Request(this.url, opt);
};
};
astmanEngine = new Astman();

1781
static-http/prototype.js vendored Normal file

File diff suppressed because it is too large Load Diff