Commit f2485476 authored by Dele Olajide's avatar Dele Olajide Committed by dele

Further work Jitsi videobridge. see changelog

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@13988 b35dd754-fafc-0310-a699-88a17e54d16e
parent f66df28d
...@@ -43,11 +43,20 @@ ...@@ -43,11 +43,20 @@
Jitsi Video Bridge Plugin Changelog Jitsi Video Bridge Plugin Changelog
</h1> </h1>
<p><b>1.3.0</b> -- Feb 19th, 2014</p> <p><b>1.3.0</b> -- March 13th, 2014</p>
<ul> <ul>
<li>Added username/password protection on web applications</li>
<li>OF-749: Upgraded bouncy castle libraries from 1.49 to 1.50</li> <li>OF-749: Upgraded bouncy castle libraries from 1.49 to 1.50</li>
<li>Jisti Videobridge plugin: Added latest jitmeet web conference application</li>
<li>Jisti Videobridge plugin: Implememted SIP registration and outgoing calls</li>
<li>Jisti Videobridge plugin: Implememted media recording</li>
<li>Ofmeet: Implememted feature to invite telphone user to conference</li>
</ul>
<p><b>1.2.2</b> -- Feb 18th, 2014</p>
<ul>
<li>Added username/password protection on web applications</li>
</ul> </ul>
<p><b>1.2.1</b> -- Feb 17th, 2014</p> <p><b>1.2.1</b> -- Feb 17th, 2014</p>
......
...@@ -17,7 +17,7 @@ var Chat = (function (my) { ...@@ -17,7 +17,7 @@ var Chat = (function (my) {
} }
$('#nickinput').keydown(function(event) { $('#nickinput').keydown(function(event) {
if (event.keyCode == 13) { if (event.keyCode === 13) {
event.preventDefault(); event.preventDefault();
var val = Util.escapeHtml(this.value); var val = Util.escapeHtml(this.value);
this.value = ''; this.value = '';
...@@ -36,7 +36,7 @@ var Chat = (function (my) { ...@@ -36,7 +36,7 @@ var Chat = (function (my) {
}); });
$('#usermsg').keydown(function(event) { $('#usermsg').keydown(function(event) {
if (event.keyCode == 13) { if (event.keyCode === 13) {
event.preventDefault(); event.preventDefault();
var message = Util.escapeHtml(this.value); var message = Util.escapeHtml(this.value);
$('#usermsg').val('').trigger('autosize.resize'); $('#usermsg').val('').trigger('autosize.resize');
...@@ -64,7 +64,7 @@ var Chat = (function (my) { ...@@ -64,7 +64,7 @@ var Chat = (function (my) {
my.updateChatConversation = function (from, displayName, message) { my.updateChatConversation = function (from, displayName, message) {
var divClassName = ''; var divClassName = '';
if (connection.emuc.myroomjid == from) { if (connection.emuc.myroomjid === from) {
divClassName = "localuser"; divClassName = "localuser";
} }
else { else {
...@@ -124,7 +124,7 @@ var Chat = (function (my) { ...@@ -124,7 +124,7 @@ var Chat = (function (my) {
} }
// Request the focus in the nickname field or the chat input field. // Request the focus in the nickname field or the chat input field.
if ($('#nickname').css('visibility') == 'visible') if ($('#nickname').css('visibility') === 'visible')
$('#nickinput').focus(); $('#nickinput').focus();
else { else {
$('#usermsg').focus(); $('#usermsg').focus();
...@@ -171,7 +171,7 @@ var Chat = (function (my) { ...@@ -171,7 +171,7 @@ var Chat = (function (my) {
$('#chatconversation').width($('#chatspace').width() - 10); $('#chatconversation').width($('#chatspace').width() - 10);
$('#chatconversation') $('#chatconversation')
.height(window.innerHeight - 50 - parseInt(usermsgHeight)); .height(window.innerHeight - 50 - parseInt(usermsgHeight));
}; }
/** /**
* Shows/hides a visual notification, indicating that a message has arrived. * Shows/hides a visual notification, indicating that a message has arrived.
......
...@@ -4,8 +4,8 @@ Strophe.addConnectionPlugin('logger', { ...@@ -4,8 +4,8 @@ Strophe.addConnectionPlugin('logger', {
log: [], log: [],
init: function (conn) { init: function (conn) {
this.connection = conn; this.connection = conn;
this.connection.rawInput = this.log_incoming.bind(this);; this.connection.rawInput = this.log_incoming.bind(this);
this.connection.rawOutput = this.log_outgoing.bind(this);; this.connection.rawOutput = this.log_outgoing.bind(this);
}, },
log_incoming: function (stanza) { log_incoming: function (stanza) {
this.log.push([new Date().getTime(), 'incoming', stanza]); this.log.push([new Date().getTime(), 'incoming', stanza]);
......
...@@ -40,7 +40,7 @@ var Etherpad = (function (my) { ...@@ -40,7 +40,7 @@ var Etherpad = (function (my) {
else else
largeVideo = $('#largeVideo'); largeVideo = $('#largeVideo');
if ($('#etherpad>iframe').css('visibility') == 'hidden') { if ($('#etherpad>iframe').css('visibility') === 'hidden') {
largeVideo.fadeOut(300, function () { largeVideo.fadeOut(300, function () {
if (isPresentationVisible()) if (isPresentationVisible())
largeVideo.css({opacity:'0'}); largeVideo.css({opacity:'0'});
...@@ -123,7 +123,7 @@ var Etherpad = (function (my) { ...@@ -123,7 +123,7 @@ var Etherpad = (function (my) {
if (!config.etherpad_base) if (!config.etherpad_base)
return; return;
if (etherpadIFrame && etherpadIFrame.style.visibility != 'hidden') if (etherpadIFrame && etherpadIFrame.style.visibility !== 'hidden')
Etherpad.toggleEtherpad(isPresentation); Etherpad.toggleEtherpad(isPresentation);
}); });
......
...@@ -2,8 +2,13 @@ ...@@ -2,8 +2,13 @@
<head> <head>
<title>WebRTC, meet the Jitsi Videobridge</title> <title>WebRTC, meet the Jitsi Videobridge</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="libs/strophejingle.bundle.js?v=7"></script><!-- strophe.jingle bundle --> <script src="libs/strophe/strophe.jingle.adapter.js?v=1"></script><!-- strophe.jingle bundles -->
<script src="libs/colibri.js?v=7"></script><!-- colibri focus implementation --> <script src="libs/strophe/strophe.jingle.bundle.js?v=8"></script>
<script src="libs/strophe/strophe.jingle.js?v=1"></script>
<script src="libs/strophe/strophe.jingle.sdp.js?v=1"></script>
<script src="libs/strophe/strophe.jingle.session.js?v=1"></script>
<script src="libs/colibri/colibri.focus.js?v=8"></script><!-- colibri focus implementation -->
<script src="libs/colibri/colibri.session.js?v=1"></script>
<script src="//code.jquery.com/ui/1.10.4/jquery-ui.js"></script> <script src="//code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
<script src="muc.js?v=9"></script><!-- simple MUC library --> <script src="muc.js?v=9"></script><!-- simple MUC library -->
<script src="estos_log.js?v=2"></script><!-- simple stanza logger --> <script src="estos_log.js?v=2"></script><!-- simple stanza logger -->
......
...@@ -13,26 +13,26 @@ ...@@ -13,26 +13,26 @@
* https://jitsi.org/Projects/JitsiVideobridge * https://jitsi.org/Projects/JitsiVideobridge
*/ */
/* /*
Copyright (c) 2013 ESTOS GmbH Copyright (c) 2013 ESTOS GmbH
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software. all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
/* jshint -W117 */ /* jshint -W117 */
function ColibriFocus(connection, bridgejid) { function ColibriFocus(connection, bridgejid) {
this.connection = connection; this.connection = connection;
...@@ -322,9 +322,6 @@ ColibriFocus.prototype.createdConference = function (result) { ...@@ -322,9 +322,6 @@ ColibriFocus.prototype.createdConference = function (result) {
localSDP.TransportToJingle(channel, elem); localSDP.TransportToJingle(channel, elem);
elem.up(); // end of channel elem.up(); // end of channel
for (j = 0; j < self.peers.length; j++) {
elem.c('channel', {initiator: 'true', expire:'15' }).up();
}
elem.up(); // end of content elem.up(); // end of content
}); });
...@@ -934,55 +931,3 @@ ColibriFocus.prototype.hardMuteVideo = function (muted) { ...@@ -934,55 +931,3 @@ ColibriFocus.prototype.hardMuteVideo = function (muted) {
track.enabled = !muted; track.enabled = !muted;
}); });
}; };
// A colibri session is similar to a jingle session, it just implements some things differently
// FIXME: inherit jinglesession, see https://github.com/legastero/Jingle-RTCPeerConnection/blob/master/index.js
function ColibriSession(me, sid, connection) {
this.me = me;
this.sid = sid;
this.connection = connection;
//this.peerconnection = null;
//this.mychannel = null;
//this.channels = null;
this.peerjid = null;
this.colibri = null;
}
// implementation of JingleSession interface
ColibriSession.prototype.initiate = function (peerjid, isInitiator) {
this.peerjid = peerjid;
};
ColibriSession.prototype.sendOffer = function (offer) {
console.log('ColibriSession.sendOffer');
};
ColibriSession.prototype.accept = function () {
console.log('ColibriSession.accept');
};
ColibriSession.prototype.terminate = function (reason) {
this.colibri.terminate(this, reason);
};
ColibriSession.prototype.active = function () {
console.log('ColibriSession.active');
};
ColibriSession.prototype.setRemoteDescription = function (elem, desctype) {
this.colibri.setRemoteDescription(this, elem, desctype);
};
ColibriSession.prototype.addIceCandidate = function (elem) {
this.colibri.addIceCandidate(this, elem);
};
ColibriSession.prototype.sendAnswer = function (sdp, provisional) {
console.log('ColibriSession.sendAnswer');
};
ColibriSession.prototype.sendTerminate = function (reason, text) {
console.log('ColibriSession.sendTerminate');
};
/* colibri.js -- a COLIBRI focus
* The colibri spec has been submitted to the XMPP Standards Foundation
* for publications as a XMPP extensions:
* http://xmpp.org/extensions/inbox/colibri.html
*
* colibri.js is a participating focus, i.e. the focus participates
* in the conference. The conference itself can be ad-hoc, through a
* MUC, through PubSub, etc.
*
* colibri.js relies heavily on the strophe.jingle library available
* from https://github.com/ESTOS/strophe.jingle
* and interoperates with the Jitsi videobridge available from
* https://jitsi.org/Projects/JitsiVideobridge
*/
/*
Copyright (c) 2013 ESTOS GmbH
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// A colibri session is similar to a jingle session, it just implements some things differently
// FIXME: inherit jinglesession, see https://github.com/legastero/Jingle-RTCPeerConnection/blob/master/index.js
function ColibriSession(me, sid, connection) {
this.me = me;
this.sid = sid;
this.connection = connection;
//this.peerconnection = null;
//this.mychannel = null;
//this.channels = null;
this.peerjid = null;
this.colibri = null;
}
// implementation of JingleSession interface
ColibriSession.prototype.initiate = function (peerjid, isInitiator) {
this.peerjid = peerjid;
};
ColibriSession.prototype.sendOffer = function (offer) {
console.log('ColibriSession.sendOffer');
};
ColibriSession.prototype.accept = function () {
console.log('ColibriSession.accept');
};
ColibriSession.prototype.terminate = function (reason) {
this.colibri.terminate(this, reason);
};
ColibriSession.prototype.active = function () {
console.log('ColibriSession.active');
};
ColibriSession.prototype.setRemoteDescription = function (elem, desctype) {
this.colibri.setRemoteDescription(this, elem, desctype);
};
ColibriSession.prototype.addIceCandidate = function (elem) {
this.colibri.addIceCandidate(this, elem);
};
ColibriSession.prototype.sendAnswer = function (sdp, provisional) {
console.log('ColibriSession.sendAnswer');
};
ColibriSession.prototype.sendTerminate = function (reason, text) {
console.log('ColibriSession.sendTerminate');
};
...@@ -64,6 +64,5 @@ function smilify(body) ...@@ -64,6 +64,5 @@ function smilify(body)
body = body.replace(/(:-\0|\(shocked\))/gi, "<img src="+smiley19+ ">"); body = body.replace(/(:-\0|\(shocked\))/gi, "<img src="+smiley19+ ">");
body = body.replace(/(\(oops\))/gi, "<img src="+smiley20+ ">"); body = body.replace(/(\(oops\))/gi, "<img src="+smiley20+ ">");
return body return body;
}; }
...@@ -40,7 +40,9 @@ ...@@ -40,7 +40,9 @@
<div class="header_button_separator"></div> <div class="header_button_separator"></div>
<a class="button" onclick='openPDFDialog();'><i id="pdf" title="Share PDF" class="fa fa-file fa-lg"></i></a> <a class="button" onclick='openPDFDialog();'><i id="pdf" title="Share PDF" class="fa fa-file fa-lg"></i></a>
<div class="header_button_separator"></div> <div class="header_button_separator"></div>
<a class="button" onclick='goFullScreen();'><i id="pdf" title="Full Screen" class="fa fa-arrows-alt fa-lg"></i></a> <a class="button" onclick='goFullScreen();'><i id="fullscreen" title="Full Screen" class="fa fa-arrows-alt fa-lg"></i></a>
<div class="header_button_separator"></div>
<a class="button" onclick='inviteParticipant();'><i id="invite" title="Invite Participant" class="fa fa-phone fa-lg"></i></a>
<!-- <!--
<div class="header_button_separator"></div> <div class="header_button_separator"></div>
<a class="button" onclick='goAltView();'><i id="altview" title="Alternate View" class="fa fa-stop fa-lg"></i></a> <a class="button" onclick='goAltView();'><i id="altview" title="Alternate View" class="fa fa-stop fa-lg"></i></a>
......
...@@ -8,6 +8,7 @@ var pdfShare = null; ...@@ -8,6 +8,7 @@ var pdfShare = null;
var pdfFrame = null; var pdfFrame = null;
var pdfPage = "1"; var pdfPage = "1";
var altView = false; var altView = false;
var sipUri = null;
$(document).ready(function () $(document).ready(function ()
{ {
...@@ -1255,6 +1256,71 @@ function goFullScreen() ...@@ -1255,6 +1256,71 @@ function goFullScreen()
} }
} }
function inviteParticipant()
{
if (sipUri == null)
{
$.prompt('<h2>Enter SIP address or Telephone number to invite a person by phone</h2><input id="sipUri" type="text" placeholder="sip:name@domain or tel:nnnnnnnn" autofocus >',
{
title: "Invite Participant by Phone",
persistent: false,
buttons: { "Invite": true , "Cancel": false},
defaultButton: 1,
loaded: function(event) {
document.getElementById('sipUri').select();
},
submit: function(e,v,m,f)
{
if(v)
{
sipUri = document.getElementById('sipUri').value;
$("#invite").addClass("fa-border");
connection.sendIQ($iq({to: connection.domain, type: 'set'}).c('colibri', {xmlns: 'urn:xmpp:rayo:colibri:1', action: 'invite', muc: roomjid, from: "sip:" + roomjid, to: sipUri}),
function (res) {
console.log('rayo colibri invite ok');
$("#invite").removeClass("fa-spin");
},
function (err) {
console.log('rayo colibri invite error', err);
}
);
}
}
});
} else {
$.prompt("Are you sure you would like to remove the Phone Participant?",
{
title: "Remove Participant by Phone",
buttons: { "Remove": true, "Cancel": false},
defaultButton: 1,
submit: function(e,v,m,f)
{
if(v)
{
$("#invite").removeClass("fa-border fa-spin");
connection.sendIQ($iq({to: connection.domain, type: 'set'}).c('colibri', {xmlns: 'urn:xmpp:rayo:colibri:1', action: 'uninvite', muc: roomjid, callId: sipUri}),
function (res) {
console.log('rayo colibri uninvite ok');
sipUri = null;
},
function (err) {
console.log('rayo colibri uninvite error', err);
sipUri = null;
}
);
}
}
});
}
}
function setEmoticons(body) function setEmoticons(body)
{ {
if (body) if (body)
......
plugin.title=Jitsi Videobridge plugin.title=Jitsi Videobridge
plugin.title.description=Jitsi Videobridge Settings plugin.title.description=Jitsi Videobridge Settings
config.page.title=Jitsi Videobridge Settings Page config.page.title=Jitsi Videobridge Settings Page
config.page.configuration.title=Configuration config.page.configuration.media.title=Configuration
config.page.configuration.security.title=Security
config.page.configuration.recording.title=Recordings
config.page.configuration.telephone.title=SIP Registration
config.page.configuration.min.port=Min port used for media config.page.configuration.min.port=Min port used for media
config.page.configuration.max.port=Max port used for media config.page.configuration.max.port=Max port used for media
config.page.configuration.submit=Save
config.page.configuration.error.minport=Invalid min port value config.page.configuration.error.minport=Invalid min port value
config.page.configuration.error.maxport=Invalid max port value config.page.configuration.error.maxport=Invalid max port value
config.page.configuration.username=Username for web applications config.page.configuration.username=Username for web applications
...@@ -13,3 +15,10 @@ config.page.configuration.record.enabled=Enabled ...@@ -13,3 +15,10 @@ config.page.configuration.record.enabled=Enabled
config.page.configuration.record.enabled_description=Audio and Video Recording enabled config.page.configuration.record.enabled_description=Audio and Video Recording enabled
config.page.configuration.record.disabled=Disabled config.page.configuration.record.disabled=Disabled
config.page.configuration.record.disabled_description=Audio and Video Recording disabled config.page.configuration.record.disabled_description=Audio and Video Recording disabled
config.page.configuration.authusername=Username
config.page.configuration.sippassword=Password
config.page.configuration.server=Registration Server
config.page.configuration.outboundproxy=Outbound Proxy
config.page.configuration.save.title=Save Settings
config.page.configuration.submit=Save
config.page.configuration.restart.warning=Changes to any of these parameters requires a restart of Openfire.
package com.rayo.core.verb;
import java.net.URI;
import javax.validation.constraints.NotNull;
import com.rayo.core.validation.Messages;
import org.xmpp.packet.*;
public class InviteCommand extends AbstractVerbCommand {
@NotNull(message=Messages.MISSING_TO)
private URI to;
@NotNull(message=Messages.MISSING_FROM)
private URI from;
private JID muc;
public InviteCommand(JID muc, URI from, URI to)
{
this.muc = muc;
this.to = to;
this.from = from;
}
public JID getMuc() {
return muc;
}
public void setMuc(JID muc) {
this.muc = muc;
}
public URI getTo() {
return to;
}
public void setTo(URI to) {
this.to = to;
}
public URI getFrom() {
return from;
}
public void setFrom(URI from) {
this.from = from;
}
}
package com.rayo.core.verb;
import org.xmpp.packet.*;
public class UnInviteCommand extends AbstractVerbCommand {
private JID muc;
private String callId;
public UnInviteCommand(JID muc, String callId)
{
this.muc = muc;
this.callId = callId;
}
public JID getMuc() {
return muc;
}
public void setMuc(JID muc) {
this.muc = muc;
}
public String getCallId() {
return callId;
}
public void setCallId(String callId) {
this.callId = callId;
}
}
...@@ -59,6 +59,13 @@ public class ColibriProvider extends BaseProvider { ...@@ -59,6 +59,13 @@ public class ColibriProvider extends BaseProvider {
} else if ("expire".equals(action)) { } else if ("expire".equals(action)) {
command = new ColibriExpireCommand(new JID(element.attributeValue("muc"))); command = new ColibriExpireCommand(new JID(element.attributeValue("muc")));
} else if ("invite".equals(action)) {
command = new InviteCommand(new JID(element.attributeValue("muc")), toURI(element.attributeValue("from")), toURI(element.attributeValue("to")));
} else if ("uninvite".equals(action)) {
command = new UnInviteCommand(new JID(element.attributeValue("muc")), element.attributeValue("callid"));
} }
return command; return command;
......
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.attribute;
import de.javawi.jstun.util.*;
public class ChangeRequest extends MessageAttribute {
/*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 A B 0|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
boolean changeIP = false;
boolean changePort = false;
public ChangeRequest() {
super(MessageAttribute.MessageAttributeType.ChangeRequest);
}
public boolean isChangeIP() {
return changeIP;
}
public boolean isChangePort() {
return changePort;
}
public void setChangeIP() {
changeIP = true;
}
public void setChangePort() {
changePort = true;
}
public byte[] getBytes() throws UtilityException {
byte[] result = new byte[8];
// message attribute header
// type
System.arraycopy(Utility.integerToTwoBytes(typeToInteger(type)), 0, result, 0, 2);
// length
System.arraycopy(Utility.integerToTwoBytes(4), 0, result, 2, 2);
// change request header
if (changeIP) result[7] = Utility.integerToOneByte(4);
if (changePort) result[7] = Utility.integerToOneByte(2);
if (changeIP && changePort) result[7] = Utility.integerToOneByte(6);
return result;
}
public static ChangeRequest parse(byte[] data) throws MessageAttributeParsingException {
try {
if (data.length < 4) {
throw new MessageAttributeParsingException("Data array too short");
}
ChangeRequest cr = new ChangeRequest();
int status = Utility.oneByteToInteger(data[3]);
switch (status) {
case 0: break;
case 2: cr.setChangePort(); break;
case 4: cr.setChangeIP(); break;
case 6: cr.setChangeIP(); cr.setChangePort(); break;
default: throw new MessageAttributeParsingException("Status parsing error");
}
return cr;
} catch (UtilityException ue) {
throw new MessageAttributeParsingException("Parsing error");
}
}
}
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.attribute;
import java.util.logging.Logger;
public class ChangedAddress extends MappedResponseChangedSourceAddressReflectedFrom {
private static Logger logger = Logger.getLogger("de.javawi.stun.attribute.ChangedAddress");
public ChangedAddress() {
super(MessageAttribute.MessageAttributeType.ChangedAddress);
}
public static MessageAttribute parse(byte[] data) throws MessageAttributeParsingException {
ChangedAddress ca = new ChangedAddress();
MappedResponseChangedSourceAddressReflectedFrom.parse(ca, data);
logger.finer("Message Attribute: Changed Address parsed: " + ca.toString() + ".");
return ca;
}
}
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.attribute;
import de.javawi.jstun.util.Utility;
import de.javawi.jstun.util.UtilityException;
public class Dummy extends MessageAttribute {
int lengthValue;
public Dummy() {
super(MessageAttributeType.Dummy);
}
public void setLengthValue(int length) {
this.lengthValue = length;
}
public byte[] getBytes() throws UtilityException {
byte[] result = new byte[lengthValue + 4];
// message attribute header
// type
System.arraycopy(Utility.integerToTwoBytes(typeToInteger(type)), 0, result, 0, 2);
// length
System.arraycopy(Utility.integerToTwoBytes(lengthValue), 0, result, 2, 2);
return result;
}
public static Dummy parse(byte[] data) {
Dummy dummy = new Dummy();
dummy.setLengthValue(data.length);
return dummy;
}
}
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.attribute;
import de.javawi.jstun.util.Utility;
import de.javawi.jstun.util.UtilityException;
public class ErrorCode extends MessageAttribute {
/*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | 0 |Class| Number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reason Phrase (variable) ..
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
int responseCode;
String reason;
public ErrorCode() {
super(MessageAttribute.MessageAttributeType.ErrorCode);
}
public void setResponseCode(int responseCode) throws MessageAttributeException {
switch (responseCode) {
case 400: reason = "Bad Request"; break;
case 401: reason = "Unauthorized"; break;
case 420: reason = "Unkown Attribute"; break;
case 430: reason = "Stale Credentials"; break;
case 431: reason = "Integrity Check Failure"; break;
case 432: reason = "Missing Username"; break;
case 433: reason = "Use TLS"; break;
case 500: reason = "Server Error"; break;
case 600: reason = "Global Failure"; break;
default: throw new MessageAttributeException("Response Code is not valid");
}
this.responseCode = responseCode;
}
public int getResponseCode() {
return responseCode;
}
public String getReason() {
return reason;
}
public byte[] getBytes() throws UtilityException {
int length = reason.length();
// length adjustment
if ((length % 4) != 0) {
length += 4 - (length % 4);
}
// message attribute header
length += 4;
byte[] result = new byte[length];
// message attribute header
// type
System.arraycopy(Utility.integerToTwoBytes(typeToInteger(type)), 0, result, 0, 2);
// length
System.arraycopy(Utility.integerToTwoBytes(length-4), 0, result, 2, 2);
// error code header
int classHeader = (int) Math.floor(((double)responseCode)/100);
result[6] = Utility.integerToOneByte(classHeader);
result[7] = Utility.integerToOneByte(responseCode%100);
byte[] reasonArray = reason.getBytes();
System.arraycopy(reasonArray, 0, result, 8, reasonArray.length);
return result;
}
public static ErrorCode parse(byte[] data) throws MessageAttributeParsingException {
try {
if (data.length < 4) {
throw new MessageAttributeParsingException("Data array too short");
}
byte classHeaderByte = data[3];
int classHeader = Utility.oneByteToInteger(classHeaderByte);
if ((classHeader < 1) || (classHeader > 6)) throw new MessageAttributeParsingException("Class parsing error");
byte numberByte = data[4];
int number = Utility.oneByteToInteger(numberByte);
if ((number < 0) || (number > 99)) throw new MessageAttributeParsingException("Number parsing error");
int responseCode = (classHeader * 100) + number;
ErrorCode result = new ErrorCode();
result.setResponseCode(responseCode);
return result;
} catch (UtilityException ue) {
throw new MessageAttributeParsingException("Parsing error");
} catch (MessageAttributeException mae) {
throw new MessageAttributeParsingException("Parsing error");
}
}
}
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.attribute;
import java.util.logging.Logger;
public class MappedAddress extends MappedResponseChangedSourceAddressReflectedFrom {
private static Logger logger = Logger.getLogger("de.javawi.stun.attribute.MappedAddress");
public MappedAddress() {
super(MessageAttribute.MessageAttributeType.MappedAddress);
}
public static MessageAttribute parse(byte[] data) throws MessageAttributeParsingException {
MappedAddress ma = new MappedAddress();
MappedResponseChangedSourceAddressReflectedFrom.parse(ma, data);
logger.finer("Message Attribute: Mapped Address parsed: " + ma.toString() + ".");
return ma;
}
}
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.attribute;
import de.javawi.jstun.util.*;
public class MappedResponseChangedSourceAddressReflectedFrom extends MessageAttribute {
int port;
Address address;
/*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |x x x x x x x x| Family | Port |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Address |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public MappedResponseChangedSourceAddressReflectedFrom() {
super();
try {
port = 0;
address = new Address("0.0.0.0");
} catch (UtilityException ue) {
ue.getMessage();
ue.printStackTrace();
}
}
public MappedResponseChangedSourceAddressReflectedFrom(MessageAttribute.MessageAttributeType type) {
super(type);
}
public int getPort() {
return port;
}
public Address getAddress() {
return address;
}
public void setPort(int port) throws MessageAttributeException {
if ((port > 65536) || (port < 0)) {
throw new MessageAttributeException("Port value " + port + " out of range.");
}
this.port = port;
}
public void setAddress(Address address) {
this.address = address;
}
public byte[] getBytes() throws UtilityException {
byte[] result = new byte[12];
// message attribute header
// type
System.arraycopy(Utility.integerToTwoBytes(typeToInteger(type)), 0, result, 0, 2);
// length
System.arraycopy(Utility.integerToTwoBytes(8), 0, result, 2, 2);
// mappedaddress header
// family
result[5] = Utility.integerToOneByte(0x01);
// port
System.arraycopy(Utility.integerToTwoBytes(port), 0, result, 6, 2);
// address
System.arraycopy(address.getBytes(), 0, result, 8, 4);
return result;
}
protected static MappedResponseChangedSourceAddressReflectedFrom parse(MappedResponseChangedSourceAddressReflectedFrom ma, byte[] data) throws MessageAttributeParsingException {
try {
if (data.length < 8) {
throw new MessageAttributeParsingException("Data array too short");
}
int family = Utility.oneByteToInteger(data[1]);
if (family != 0x01) throw new MessageAttributeParsingException("Family " + family + " is not supported");
byte[] portArray = new byte[2];
System.arraycopy(data, 2, portArray, 0, 2);
ma.setPort(Utility.twoBytesToInteger(portArray));
int firstOctet = Utility.oneByteToInteger(data[4]);
int secondOctet = Utility.oneByteToInteger(data[5]);
int thirdOctet = Utility.oneByteToInteger(data[6]);
int fourthOctet = Utility.oneByteToInteger(data[7]);
ma.setAddress(new Address(firstOctet, secondOctet, thirdOctet, fourthOctet));
return ma;
} catch (UtilityException ue) {
throw new MessageAttributeParsingException("Parsing error");
} catch (MessageAttributeException mae) {
throw new MessageAttributeParsingException("Port parsing error");
}
}
public String toString() {
return "Address " +address.toString() + ", Port " + port;
}
}
\ No newline at end of file
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.attribute;
import java.util.logging.*;
import de.javawi.jstun.util.*;
public abstract class MessageAttribute implements MessageAttributeInterface {
private static Logger logger = Logger.getLogger("de.javawi.stun.util.MessageAttribute");
MessageAttributeType type;
public MessageAttribute() {
}
public MessageAttribute(MessageAttributeType type) {
setType(type);
}
public void setType(MessageAttributeType type) {
this.type = type;
}
public MessageAttribute.MessageAttributeType getType() {
return type;
}
public static int typeToInteger(MessageAttributeType type) {
if (type == MessageAttributeType.MappedAddress) return MAPPEDADDRESS;
if (type == MessageAttributeType.ResponseAddress) return RESPONSEADDRESS;
if (type == MessageAttributeType.ChangeRequest) return CHANGEREQUEST;
if (type == MessageAttributeType.SourceAddress) return SOURCEADDRESS;
if (type == MessageAttributeType.ChangedAddress) return CHANGEDADDRESS;
if (type == MessageAttributeType.Username) return USERNAME;
if (type == MessageAttributeType.Password) return PASSWORD;
if (type == MessageAttributeType.MessageIntegrity) return MESSAGEINTEGRITY;
if (type == MessageAttributeType.ErrorCode) return ERRORCODE;
if (type == MessageAttributeType.UnknownAttribute) return UNKNOWNATTRIBUTE;
if (type == MessageAttributeType.ReflectedFrom) return REFLECTEDFROM;
if (type == MessageAttributeType.Dummy) return DUMMY;
return -1;
}
public static MessageAttributeType intToType(long type) {
if (type == MAPPEDADDRESS) return MessageAttributeType.MappedAddress;
if (type == RESPONSEADDRESS) return MessageAttributeType.ResponseAddress;
if (type == CHANGEREQUEST) return MessageAttributeType.ChangeRequest;
if (type == SOURCEADDRESS) return MessageAttributeType.SourceAddress;
if (type == CHANGEDADDRESS) return MessageAttributeType.ChangedAddress;
if (type == USERNAME) return MessageAttributeType.Username;
if (type == PASSWORD) return MessageAttributeType.Password;
if (type == MESSAGEINTEGRITY) return MessageAttributeType.MessageIntegrity;
if (type == ERRORCODE) return MessageAttributeType.ErrorCode;
if (type == UNKNOWNATTRIBUTE) return MessageAttributeType.UnknownAttribute;
if (type == REFLECTEDFROM) return MessageAttributeType.ReflectedFrom;
if (type == DUMMY) return MessageAttributeType.Dummy;
return null;
}
abstract public byte[] getBytes() throws UtilityException;
//abstract public MessageAttribute parse(byte[] data) throws MessageAttributeParsingException;
public int getLength() throws UtilityException {
int length = getBytes().length;
return length;
}
public static MessageAttribute parseCommonHeader(byte[] data) throws MessageAttributeParsingException {
try {
byte[] typeArray = new byte[2];
System.arraycopy(data, 0, typeArray, 0, 2);
int type = Utility.twoBytesToInteger(typeArray);
byte[] lengthArray = new byte[2];
System.arraycopy(data, 2, lengthArray, 0, 2);
int lengthValue = Utility.twoBytesToInteger(lengthArray);
byte[] valueArray = new byte[lengthValue];
System.arraycopy(data, 4, valueArray, 0, lengthValue);
MessageAttribute ma;
switch (type) {
case MAPPEDADDRESS: ma = MappedAddress.parse(valueArray); break;
case RESPONSEADDRESS: ma = ResponseAddress.parse(valueArray); break;
case CHANGEREQUEST: ma = ChangeRequest.parse(valueArray); break;
case SOURCEADDRESS: ma = SourceAddress.parse(valueArray); break;
case CHANGEDADDRESS: ma = ChangedAddress.parse(valueArray); break;
case USERNAME: ma = Username.parse(valueArray); break;
case PASSWORD: ma = Password.parse(valueArray); break;
case MESSAGEINTEGRITY: ma = MessageIntegrity.parse(valueArray); break;
case ERRORCODE: ma = ErrorCode.parse(valueArray); break;
case UNKNOWNATTRIBUTE: ma = UnknownAttribute.parse(valueArray); break;
case REFLECTEDFROM: ma = ReflectedFrom.parse(valueArray); break;
default:
if (type <= 0x7fff) {
throw new UnknownMessageAttributeException("Unkown mandatory message attribute", intToType(type));
} else {
logger.finer("MessageAttribute with type " + type + " unkown.");
ma = Dummy.parse(valueArray);
break;
}
}
return ma;
} catch (UtilityException ue) {
throw new MessageAttributeParsingException("Parsing error");
}
}
}
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.attribute;
public class MessageAttributeException extends Exception {
private static final long serialVersionUID = 3258131345099404850L;
public MessageAttributeException(String mesg) {
super(mesg);
}
}
\ No newline at end of file
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.attribute;
public interface MessageAttributeInterface {
public enum MessageAttributeType { MappedAddress, ResponseAddress, ChangeRequest, SourceAddress, ChangedAddress, Username, Password, MessageIntegrity, ErrorCode, UnknownAttribute, ReflectedFrom, Dummy };
final static int MAPPEDADDRESS = 0x0001;
final static int RESPONSEADDRESS = 0x0002;
final static int CHANGEREQUEST = 0x0003;
final static int SOURCEADDRESS = 0x0004;
final static int CHANGEDADDRESS = 0x0005;
final static int USERNAME = 0x0006;
final static int PASSWORD = 0x0007;
final static int MESSAGEINTEGRITY = 0x0008;
final static int ERRORCODE = 0x0009;
final static int UNKNOWNATTRIBUTE = 0x000a;
final static int REFLECTEDFROM = 0x000b;
final static int DUMMY = 0x0000;
}
\ No newline at end of file
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.attribute;
public class MessageAttributeParsingException extends MessageAttributeException {
private static final long serialVersionUID = 3258409534426263605L;
public MessageAttributeParsingException(String mesg) {
super(mesg);
}
}
\ No newline at end of file
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.attribute;
public class MessageIntegrity extends MessageAttribute {
// incomplete message integrity implementation
public MessageIntegrity() {
super(MessageAttribute.MessageAttributeType.MessageIntegrity);
}
public byte[] getBytes() {
return new byte[0];
}
public static MessageIntegrity parse(byte[] data) {
return new MessageIntegrity();
}
}
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.attribute;
import de.javawi.jstun.util.Utility;
import de.javawi.jstun.util.UtilityException;
public class Password extends MessageAttribute {
String password;
public Password() {
super(MessageAttribute.MessageAttributeType.Password);
}
public Password(String password) {
super(MessageAttribute.MessageAttributeType.Password);
setPassword(password);
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public byte[] getBytes() throws UtilityException {
int length = password.length();
// password header
if ((length % 4) != 0) {
length += 4 - (length % 4);
}
// message attribute header
length += 4;
byte[] result = new byte[length];
// message attribute header
// type
System.arraycopy(Utility.integerToTwoBytes(typeToInteger(type)), 0, result, 0, 2);
// length
System.arraycopy(Utility.integerToTwoBytes(length - 4), 0, result, 2, 2);
// password header
byte[] temp = password.getBytes();
System.arraycopy(temp, 0, result, 4, temp.length);
return result;
}
public static Password parse(byte[] data) {
Password result = new Password();
String password = new String(data);
result.setPassword(password);
return result;
}
}
\ No newline at end of file
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.attribute;
import java.util.logging.Logger;
public class ReflectedFrom extends MappedResponseChangedSourceAddressReflectedFrom {
private static Logger logger = Logger.getLogger("de.javawi.stun.attribute.ReflectedFrom");
public ReflectedFrom() {
super(MessageAttribute.MessageAttributeType.ReflectedFrom);
}
public static ReflectedFrom parse(byte[] data) throws MessageAttributeParsingException {
ReflectedFrom result = new ReflectedFrom();
MappedResponseChangedSourceAddressReflectedFrom.parse(result, data);
logger.finer("Message Attribute: ReflectedFrom parsed: " + result.toString() + ".");
return result;
}
}
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.attribute;
import java.util.logging.Logger;
public class ResponseAddress extends MappedResponseChangedSourceAddressReflectedFrom {
private static Logger logger = Logger.getLogger("de.javawi.stun.attribute.ResponseAddress");
public ResponseAddress() {
super(MessageAttribute.MessageAttributeType.ResponseAddress);
}
public static MessageAttribute parse(byte[] data) throws MessageAttributeParsingException {
ResponseAddress ra = new ResponseAddress();
MappedResponseChangedSourceAddressReflectedFrom.parse(ra, data);
logger.finer("Message Attribute: Response Address parsed: " + ra.toString() + ".");
return ra;
}
}
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.attribute;
import java.util.logging.Logger;
public class SourceAddress extends MappedResponseChangedSourceAddressReflectedFrom {
private static Logger logger = Logger.getLogger("de.javawi.stun.attribute.SourceAddress");
public SourceAddress() {
super(MessageAttribute.MessageAttributeType.SourceAddress);
}
public static MessageAttribute parse(byte[] data) throws MessageAttributeParsingException {
SourceAddress sa = new SourceAddress();
MappedResponseChangedSourceAddressReflectedFrom.parse(sa, data);
logger.finer("Message Attribute: Source Address parsed: " + sa.toString() + ".");
return sa;
}
}
\ No newline at end of file
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.attribute;
import java.util.*;
import de.javawi.jstun.util.Utility;
import de.javawi.jstun.util.UtilityException;
public class UnknownAttribute extends MessageAttribute {
/*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Attribute 1 Type | Attribute 2 Type |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Attribute 3 Type | Attribute 4 Type ...
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
Vector<MessageAttributeType> unkown = new Vector<MessageAttributeType>();
public UnknownAttribute() {
super(MessageAttribute.MessageAttributeType.UnknownAttribute);
}
public void addAttribute(MessageAttributeType attribute) {
unkown.add(attribute);
}
public byte[] getBytes() throws UtilityException {
int length = 0;
if (unkown.size()%2 == 1) {
length = 2 * (unkown.size() + 1) + 4;
} else {
length = 2 * unkown.size() + 4;
}
byte[] result = new byte[length];
// message attribute header
// type
System.arraycopy(Utility.integerToTwoBytes(typeToInteger(type)), 0, result, 0, 2);
// length
System.arraycopy(Utility.integerToTwoBytes(length - 4), 0, result, 2, 2);
// unkown attribute header
Iterator<MessageAttributeType> it = unkown.iterator();
while(it.hasNext()) {
MessageAttributeType attri = it.next();
System.arraycopy(Utility.integerToTwoBytes(typeToInteger(attri)), 0, result, 4, 2);
}
// padding
if (unkown.size()%2 == 1) {
System.arraycopy(Utility.integerToTwoBytes(typeToInteger(unkown.elementAt(1))), 0, result, 4, 2);
}
return result;
}
public static UnknownAttribute parse(byte[] data) throws MessageAttributeParsingException {
try {
UnknownAttribute result = new UnknownAttribute();
if (data.length % 4 != 0) throw new MessageAttributeParsingException("Data array too short");
for (int i = 0; i < data.length; i += 4) {
byte[] temp = new byte[4];
System.arraycopy(data, i, temp, 0, 4);
long attri = Utility.fourBytesToLong(temp);
result.addAttribute(MessageAttribute.intToType(attri));
}
return result;
} catch (UtilityException ue) {
throw new MessageAttributeParsingException("Parsing error");
}
}
}
\ No newline at end of file
package de.javawi.jstun.attribute;
import de.javawi.jstun.attribute.MessageAttributeInterface.MessageAttributeType;
public class UnknownMessageAttributeException extends MessageAttributeParsingException {
private static final long serialVersionUID = 5375193544145543299L;
private MessageAttributeType type;
public UnknownMessageAttributeException(String mesg, MessageAttributeType type) {
super(mesg);
this.type = type;
}
public MessageAttributeType getType() {
return type;
}
}
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.attribute;
import de.javawi.jstun.util.Utility;
import de.javawi.jstun.util.UtilityException;
public class Username extends MessageAttribute {
String username;
public Username() {
super(MessageAttribute.MessageAttributeType.Username);
}
public Username(String username) {
super(MessageAttribute.MessageAttributeType.Username);
setUsername(username);
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public byte[] getBytes() throws UtilityException {
int length = username.length();
// username header
if ((length % 4) != 0) {
length += 4 - (length % 4);
}
// message attribute header
length += 4;
byte[] result = new byte[length];
// message attribute header
// type
System.arraycopy(Utility.integerToTwoBytes(typeToInteger(type)), 0, result, 0, 2);
// length
System.arraycopy(Utility.integerToTwoBytes(length-4), 0, result, 2, 2);
// username header
byte[] temp = username.getBytes();
System.arraycopy(temp, 0, result, 4, temp.length);
return result;
}
public static Username parse(byte[] data) {
Username result = new Username();
String username = new String(data);
result.setUsername(username);
return result;
}
}
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.header;
import de.javawi.jstun.attribute.*;
import de.javawi.jstun.util.*;
import java.util.*;
import java.util.logging.*;
public class MessageHeader implements MessageHeaderInterface {
/*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | STUN Message Type | Message Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* Transaction ID
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
private static Logger logger = Logger.getLogger("de.javawi.stun.header.MessageHeader");
MessageHeaderType type;
byte[] id = new byte[16];
TreeMap<MessageAttribute.MessageAttributeType, MessageAttribute> ma = new TreeMap<MessageAttribute.MessageAttributeType, MessageAttribute>();
public MessageHeader() {
super();
}
public MessageHeader(MessageHeaderType type) {
super();
setType(type);
}
public void setType(MessageHeaderType type) {
this.type = type;
}
public MessageHeaderType getType() {
return type;
}
public static int typeToInteger(MessageHeaderType type) {
if (type == MessageHeaderType.BindingRequest) return BINDINGREQUEST;
if (type == MessageHeaderType.BindingResponse) return BINDINGRESPONSE;
if (type == MessageHeaderType.BindingErrorResponse) return BINDINGERRORRESPONSE;
if (type == MessageHeaderType.SharedSecretRequest) return SHAREDSECRETREQUEST;
if (type == MessageHeaderType.SharedSecretResponse) return SHAREDSECRETRESPONSE;
if (type == MessageHeaderType.SharedSecretErrorResponse) return SHAREDSECRETERRORRESPONSE;
return -1;
}
public void setTransactionID(byte[] id) {
System.arraycopy(id, 0, this.id, 0, 16);
}
public void generateTransactionID() throws UtilityException {
System.arraycopy(Utility.integerToTwoBytes((int)(Math.random() * 65536)), 0, id, 0, 2);
System.arraycopy(Utility.integerToTwoBytes((int)(Math.random() * 65536)), 0, id, 2, 2);
System.arraycopy(Utility.integerToTwoBytes((int)(Math.random() * 65536)), 0, id, 4, 2);
System.arraycopy(Utility.integerToTwoBytes((int)(Math.random() * 65536)), 0, id, 6, 2);
System.arraycopy(Utility.integerToTwoBytes((int)(Math.random() * 65536)), 0, id, 8, 2);
System.arraycopy(Utility.integerToTwoBytes((int)(Math.random() * 65536)), 0, id, 10, 2);
System.arraycopy(Utility.integerToTwoBytes((int)(Math.random() * 65536)), 0, id, 12, 2);
System.arraycopy(Utility.integerToTwoBytes((int)(Math.random() * 65536)), 0, id, 14, 2);
}
public byte[] getTransactionID() {
byte[] idCopy = new byte[id.length];
System.arraycopy(id, 0, idCopy, 0, id.length);
return idCopy;
}
public boolean equalTransactionID(MessageHeader header) {
byte[] idHeader = header.getTransactionID();
if (idHeader.length != 16) return false;
if ((idHeader[0] == id[0]) && (idHeader[1] == id[1]) && (idHeader[2] == id[2]) && (idHeader[3] == id[3]) &&
(idHeader[4] == id[4]) && (idHeader[5] == id[5]) && (idHeader[6] == id[6]) && (idHeader[7] == id[7]) &&
(idHeader[8] == id[8]) && (idHeader[9] == id[9]) && (idHeader[10] == id[10]) && (idHeader[11] == id[11]) &&
(idHeader[12] == id[12]) && (idHeader[13] == id[13]) && (idHeader[14] == id[14]) && (idHeader[15] == id[15])) {
return true;
} else {
return false;
}
}
public void addMessageAttribute(MessageAttribute attri) {
ma.put(attri.getType(), attri);
}
public MessageAttribute getMessageAttribute(MessageAttribute.MessageAttributeType type) {
return ma.get(type);
}
public byte[] getBytes() throws UtilityException {
int length = 20;
Iterator<MessageAttribute.MessageAttributeType> it = ma.keySet().iterator();
while (it.hasNext()) {
MessageAttribute attri = ma.get(it.next());
length += attri.getLength();
}
// add attribute size + attributes.getSize();
byte[] result = new byte[length];
System.arraycopy(Utility.integerToTwoBytes(typeToInteger(type)), 0, result, 0, 2);
System.arraycopy(Utility.integerToTwoBytes(length-20), 0, result, 2, 2);
System.arraycopy(id, 0, result, 4, 16);
// arraycopy of attributes
int offset = 20;
it = ma.keySet().iterator();
while (it.hasNext()) {
MessageAttribute attri = ma.get(it.next());
System.arraycopy(attri.getBytes(), 0, result, offset, attri.getLength());
offset += attri.getLength();
}
return result;
}
public int getLength() throws UtilityException {
return getBytes().length;
}
public void parseAttributes(byte[] data) throws MessageAttributeParsingException {
try {
byte[] lengthArray = new byte[2];
System.arraycopy(data, 2, lengthArray, 0, 2);
int length = Utility.twoBytesToInteger(lengthArray);
System.arraycopy(data, 4, id, 0, 16);
byte[] cuttedData;
int offset = 20;
while (length > 0) {
cuttedData = new byte[length];
System.arraycopy(data, offset, cuttedData, 0, length);
MessageAttribute ma = MessageAttribute.parseCommonHeader(cuttedData);
addMessageAttribute(ma);
length -= ma.getLength();
offset += ma.getLength();
}
} catch (UtilityException ue) {
throw new MessageAttributeParsingException("Parsing error");
}
}
public static MessageHeader parseHeader(byte[] data) throws MessageHeaderParsingException {
try {
MessageHeader mh = new MessageHeader();
byte[] typeArray = new byte[2];
System.arraycopy(data, 0, typeArray, 0, 2);
int type = Utility.twoBytesToInteger(typeArray);
switch (type) {
case BINDINGREQUEST: mh.setType(MessageHeaderType.BindingRequest); logger.finer("Binding Request received."); break;
case BINDINGRESPONSE: mh.setType(MessageHeaderType.BindingResponse); logger.finer("Binding Response received."); break;
case BINDINGERRORRESPONSE: mh.setType(MessageHeaderType.BindingErrorResponse); logger.finer("Binding Error Response received."); break;
case SHAREDSECRETREQUEST: mh.setType(MessageHeaderType.SharedSecretRequest); logger.finer("Shared Secret Request received."); break;
case SHAREDSECRETRESPONSE: mh.setType(MessageHeaderType.SharedSecretResponse); logger.finer("Shared Secret Response received."); break;
case SHAREDSECRETERRORRESPONSE: mh.setType(MessageHeaderType.SharedSecretErrorResponse); logger.finer("Shared Secret Error Response received.");break;
default: throw new MessageHeaderParsingException("Message type " + type + "is not supported");
}
return mh;
} catch (UtilityException ue) {
throw new MessageHeaderParsingException("Parsing error");
}
}
}
\ No newline at end of file
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.header;
public class MessageHeaderException extends Exception {
private static final long serialVersionUID = 3689066248944103737L;
public MessageHeaderException(String mesg) {
super(mesg);
}
}
\ No newline at end of file
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.header;
public interface MessageHeaderInterface {
public enum MessageHeaderType { BindingRequest, BindingResponse, BindingErrorResponse, SharedSecretRequest, SharedSecretResponse, SharedSecretErrorResponse };
final static int BINDINGREQUEST = 0x0001;
final static int BINDINGRESPONSE = 0x0101;
final static int BINDINGERRORRESPONSE = 0x0111;
final static int SHAREDSECRETREQUEST = 0x0002;
final static int SHAREDSECRETRESPONSE = 0x0102;
final static int SHAREDSECRETERRORRESPONSE = 0x0112;
}
\ No newline at end of file
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.header;
public class MessageHeaderParsingException extends MessageHeaderException {
private static final long serialVersionUID = 3544393617029607478L;
public MessageHeaderParsingException(String mesg) {
super(mesg);
}
}
\ No newline at end of file
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.util;
import java.util.*;
import java.net.*;
public class Address {
int firstOctet;
int secondOctet;
int thirdOctet;
int fourthOctet;
public Address(int firstOctet, int secondOctet, int thirdOctet, int fourthOctet) throws UtilityException {
if ((firstOctet < 0) || (firstOctet > 255) || (secondOctet < 0) || (secondOctet > 255) || (thirdOctet < 0) || (thirdOctet > 255) || (fourthOctet < 0) || (fourthOctet > 255)) {
throw new UtilityException("Address is malformed.");
}
this.firstOctet = firstOctet;
this.secondOctet = secondOctet;
this.thirdOctet = thirdOctet;
this.fourthOctet = fourthOctet;
}
public Address(String address) throws UtilityException {
StringTokenizer st = new StringTokenizer(address, ".");
if (st.countTokens() != 4) {
throw new UtilityException("4 octets in address string are required.");
}
int i = 0;
while (st.hasMoreTokens()) {
int temp = Integer.parseInt(st.nextToken());
if ((temp < 0) || (temp > 255)) {
throw new UtilityException("Address is in incorrect format.");
}
switch (i) {
case 0: firstOctet = temp; ++i; break;
case 1: secondOctet = temp; ++i; break;
case 2: thirdOctet = temp; ++i; break;
case 3: fourthOctet = temp; ++i; break;
}
}
}
public Address(byte[] address) throws UtilityException {
if (address.length < 4) {
throw new UtilityException("4 bytes are required.");
}
firstOctet = Utility.oneByteToInteger(address[0]);
secondOctet = Utility.oneByteToInteger(address[1]);
thirdOctet = Utility.oneByteToInteger(address[2]);
fourthOctet = Utility.oneByteToInteger(address[3]);
}
public String toString() {
return firstOctet + "." + secondOctet + "." + thirdOctet + "." + fourthOctet;
}
public byte[] getBytes() throws UtilityException {
byte[] result = new byte[4];
result[0] = Utility.integerToOneByte(firstOctet);
result[1] = Utility.integerToOneByte(secondOctet);
result[2] = Utility.integerToOneByte(thirdOctet);
result[3] = Utility.integerToOneByte(fourthOctet);
return result;
}
public InetAddress getInetAddress() throws UtilityException, UnknownHostException {
byte[] address = new byte[4];
address[0] = Utility.integerToOneByte(firstOctet);
address[1] = Utility.integerToOneByte(secondOctet);
address[2] = Utility.integerToOneByte(thirdOctet);
address[3] = Utility.integerToOneByte(fourthOctet);
return InetAddress.getByAddress(address);
}
public boolean equals(Object obj) {
if (obj == null) return false;
try {
byte[] data1 = this.getBytes();
byte[] data2 = ((Address) obj).getBytes();
if ((data1[0] == data2[0]) && (data1[1] == data2[1]) &&
(data1[2] == data2[2]) && (data1[3] == data2[3])) return true;
return false;
} catch (UtilityException ue) {
return false;
}
}
public int hashCode() {
return (firstOctet << 24) + (secondOctet << 16) + (thirdOctet << 8) + fourthOctet;
}
}
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.util;
public class Utility {
public static final byte integerToOneByte(int value) throws UtilityException {
if ((value > Math.pow(2,15)) || (value < 0)) {
throw new UtilityException("Integer value " + value + " is larger than 2^15");
}
return (byte)(value & 0xFF);
}
public static final byte[] integerToTwoBytes(int value) throws UtilityException {
byte[] result = new byte[2];
if ((value > Math.pow(2,31)) || (value < 0)) {
throw new UtilityException("Integer value " + value + " is larger than 2^31");
}
result[0] = (byte)((value >>> 8) & 0xFF);
result[1] = (byte)(value & 0xFF);
return result;
}
public static final byte[] integerToFourBytes(int value) throws UtilityException {
byte[] result = new byte[4];
if ((value > Math.pow(2,63)) || (value < 0)) {
throw new UtilityException("Integer value " + value + " is larger than 2^63");
}
result[0] = (byte)((value >>> 24) & 0xFF);
result[1] = (byte)((value >>> 16) & 0xFF);
result[2] = (byte)((value >>> 8) & 0xFF);
result[3] = (byte)(value & 0xFF);
return result;
}
public static final int oneByteToInteger(byte value) throws UtilityException {
return (int)value & 0xFF;
}
public static final int twoBytesToInteger(byte[] value) throws UtilityException {
if (value.length < 2) {
throw new UtilityException("Byte array too short!");
}
int temp0 = value[0] & 0xFF;
int temp1 = value[1] & 0xFF;
return ((temp0 << 8) + temp1);
}
public static final long fourBytesToLong(byte[] value) throws UtilityException {
if (value.length < 4) {
throw new UtilityException("Byte array too short!");
}
int temp0 = value[0] & 0xFF;
int temp1 = value[1] & 0xFF;
int temp2 = value[2] & 0xFF;
int temp3 = value[3] & 0xFF;
return (((long)temp0 << 24) + (temp1 << 16) + (temp2 << 8) + temp3);
}
}
/*
* This file is part of JSTUN.
*
* Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
* reserved.
*
* This software is licensed under either the GNU Public License (GPL),
* or the Apache 2.0 license. Copies of both license agreements are
* included in this distribution.
*/
package de.javawi.jstun.util;
public class UtilityException extends Exception {
private static final long serialVersionUID = 3545800974716581680L;
UtilityException(String mesg) {
super(mesg);
}
}
/**
* Copyright 2012 Voxbone SA/NV
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ifsoft.sip;
/**
* Class used to generate RFC2833 DTMF events
*
*/
public class DtmfEvent
{
byte event;
short duration;
byte [] rtpPacket = new byte[16];
public DtmfEvent(char dtmf, long startTime, byte [] ssrc)
{
if (dtmf == '*')
{
event = 10;
}
else if (dtmf == '#')
{
event = 11;
}
else if (dtmf == 'A')
{
event = 12;
}
else if (dtmf == 'B')
{
event = 13;
}
else if (dtmf == 'C')
{
event = 14;
}
else if (dtmf == 'D')
{
event = 15;
}
else
{
event = Byte.parseByte("" + dtmf);
}
RtpUtil.buildRtpHeader(rtpPacket, 101, (short) 0, startTime, ssrc);
rtpPacket[12] = this.event;
rtpPacket[13] = 10;
duration = 0;
}
public byte [] startPacket()
{
RtpUtil.setMarker(rtpPacket, true);
duration += 160;
rtpPacket[15] = (byte) (duration & 0xFF);
rtpPacket[14] = (byte) ((duration >> 8) & 0xFF);
return rtpPacket;
}
public byte [] continuationPacket()
{
RtpUtil.setMarker(rtpPacket, false);
duration += 160;
rtpPacket[15] = (byte) (duration & 0xFF);
rtpPacket[14] = (byte) ((duration >> 8) & 0xFF);
return rtpPacket;
}
public byte [] endPacket()
{
rtpPacket[13] |= (byte) (1<<7);
return rtpPacket;
}
}
/**
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ifsoft.sip;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* The class takes standard Http Authentication details and returns a response
* according to the MD5 algorithm
*
* @author Emil Ivov < emcho@dev.java.net >
* @version 1.0
*/
public class MessageDigestAlgorithm {
/**
* Calculates a response an http authentication response in accordance with
* rfc2617.
*
* @param algorithm MD5 or MD5-sess)
* @param username_value username_value (see rfc2617)
* @param realm_value realm_value
* @param passwd passwd
* @param nonce_value nonce_value
* @param cnonce_value cnonce_value
* @param Method method
* @param digest_uri_value uri_value
* @param entity_body entity_body
* @param qop_value qop
* @return a digest response as defined in rfc2617
* @throws NullPointerException in case of incorrectly null parameters.
*/
public static String calculateResponse(String algorithm, String username_value,
String realm_value, String passwd, String nonce_value,
String nc_value, String cnonce_value, String Method,
String digest_uri_value, String entity_body, String qop_value) {
if (username_value == null || realm_value == null || passwd == null
|| Method == null || digest_uri_value == null
|| nonce_value == null)
throw new NullPointerException(
"Null parameter to MessageDigestAlgorithm.calculateResponse()");
// The following follows closely the algorithm for generating a response
// digest as specified by rfc2617
String A1 = null;
if (algorithm == null || algorithm.trim().length() == 0
|| algorithm.trim().equalsIgnoreCase("MD5")) {
A1 = username_value + ":" + realm_value + ":" + passwd;
}
else {
if (cnonce_value == null || cnonce_value.length() == 0)
throw new NullPointerException(
"cnonce_value may not be absent for MD5-Sess algorithm.");
A1 = MessageDigestAlgorithm.H(username_value + ":" + realm_value + ":" + passwd) + ":"
+ nonce_value + ":" + cnonce_value;
}
String A2 = null;
if (qop_value == null || qop_value.trim().length() == 0
|| qop_value.trim().equalsIgnoreCase("auth")) {
A2 = Method + ":" + digest_uri_value;
}
else {
if (entity_body == null)
entity_body = "";
A2 = Method + ":" + digest_uri_value + ":" + MessageDigestAlgorithm.H(entity_body);
}
String request_digest = null;
if (cnonce_value != null && qop_value != null
&& (qop_value.equals("auth") || (qop_value.equals("auth-int")))) {
request_digest = MessageDigestAlgorithm.KD(MessageDigestAlgorithm.H(A1), nonce_value + ":" + nc_value + ":"
+ cnonce_value + ":" + qop_value + ":" + MessageDigestAlgorithm.H(A2));
}
else {
request_digest = MessageDigestAlgorithm.KD(MessageDigestAlgorithm.H(A1), nonce_value + ":" + MessageDigestAlgorithm.H(A2));
}
return request_digest;
}
/**
* Defined in rfc 2617 as H(data) = MD5(data);
*
* @param data data
* @return MD5(data)
*/
private static String H(String data) {
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
return MessageDigestAlgorithm.toHexString(digest.digest(data.getBytes()));
}
catch (NoSuchAlgorithmException ex) {
// shouldn't happen
return null;
}
}
/**
* Defined in rfc 2617 as KD(secret, data) = H(concat(secret, ":", data))
*
* @param data data
* @param secret secret
* @return H(concat(secret, ":", data));
*/
private static String KD(String secret, String data) {
return MessageDigestAlgorithm.H(secret + ":" + data);
}
// the following code was copied from the NIST-SIP instant
// messenger (its author is Olivier Deruelle). Thanks for making it public!
/**
* to hex converter
*/
private static final char[] toHex = {'0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/**
* Converts b[] to hex string.
*
* @param b
* the bte array to convert
* @return a Hex representation of b.
*/
private static String toHexString(byte b[]) {
int pos = 0;
char[] c = new char[b.length * 2];
for (int i = 0; i < b.length; i++) {
c[pos++] = MessageDigestAlgorithm.toHex[(b[i] >> 4) & 0x0F];
c[pos++] = MessageDigestAlgorithm.toHex[b[i] & 0x0f];
}
return new String(c);
}
}
/**
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ifsoft.sip;
public class ProxyCredentials
{
private String xmppUserName = null;
private String userName = null;
private String userDisplay = null;
private char[] password = null;
private String authUserName = null;
private String realm = null;
private String proxy = null;
private String host = null;
private String name = null;
public void setUserName(String userName)
{
this.userName = userName;
}
public void setAuthUserName(String userName)
{
this.authUserName = userName;
}
public void setXmppUserName(String xmppUserName)
{
this.xmppUserName = xmppUserName;
}
public void setRealm(String realm)
{
this.realm = realm;
}
public void setProxy(String proxy)
{
this.proxy = proxy;
}
public void setHost(String host)
{
this.host = host;
}
public void setName(String name)
{
this.name = name;
}
public void setUserDisplay(String userDisplay)
{
this.userDisplay = userDisplay;
}
public void setPassword(char[] passwd) {
this.password = passwd;
}
public String getUserDisplay()
{
return userDisplay;
}
public String getUserName()
{
return this.userName;
}
public String getRealm()
{
return realm;
}
public String getProxy()
{
return proxy;
}
public String getHost()
{
return host;
}
public String getName()
{
return name;
}
public String getAuthUserName()
{
return this.authUserName;
}
public String getXmppUserName()
{
return this.xmppUserName;
}
public char[] getPassword() {
return password;
}
}
...@@ -71,6 +71,18 @@ ...@@ -71,6 +71,18 @@
String enabled = request.getParameter("enabled"); String enabled = request.getParameter("enabled");
JiveGlobals.setProperty(PluginImpl.RECORD_PROPERTY_NAME, enabled); JiveGlobals.setProperty(PluginImpl.RECORD_PROPERTY_NAME, enabled);
String authusername = request.getParameter("authusername");
JiveGlobals.setProperty("voicebridge.default.proxy.sipauthuser", authusername);
String sippassword = request.getParameter("sippassword");
JiveGlobals.setProperty("voicebridge.default.proxy.sippassword", sippassword);
String server = request.getParameter("server");
JiveGlobals.setProperty("voicebridge.default.proxy.sipserver", server);
String outboundproxy = request.getParameter("outboundproxy");
JiveGlobals.setProperty("voicebridge.default.proxy.outboundproxy", outboundproxy);
} }
%> %>
...@@ -93,12 +105,12 @@ ...@@ -93,12 +105,12 @@
<table class="jive-table" cellpadding="0" cellspacing="0" border="0" width="50%"> <table class="jive-table" cellpadding="0" cellspacing="0" border="0" width="50%">
<thead> <thead>
<tr> <tr>
<th colspan="2"><fmt:message key="config.page.configuration.title"/></th> <th colspan="2"><fmt:message key="config.page.configuration.media.title"/></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td><label class="jive-label"><fmt:message key="config.page.configuration.min.port"/>:</label><br> <td><fmt:message key="config.page.configuration.min.port"/><br>
</td> </td>
<td align="left"> <td align="left">
<input name="minport" type="text" maxlength="5" size="5" <input name="minport" type="text" maxlength="5" size="5"
...@@ -106,15 +118,25 @@ ...@@ -106,15 +118,25 @@
</td> </td>
</tr> </tr>
<tr> <tr>
<td><label class="jive-label"><fmt:message key="config.page.configuration.max.port"/>:</label><br> <td><fmt:message key="config.page.configuration.max.port"/><br>
</td> </td>
<td align="left"> <td align="left">
<input name="maxport" type="text" maxlength="5" size="5" <input name="maxport" type="text" maxlength="5" size="5"
value="<%=plugin.getMaxPort()%>"/> value="<%=plugin.getMaxPort()%>"/>
</td> </td>
</tr> </tr>
</tbody>
</table>
<p/>
<table class="jive-table" cellpadding="0" cellspacing="0" border="0" width="50%">
<thead>
<tr>
<th colspan="2"><fmt:message key="config.page.configuration.security.title"/></th>
</tr>
</thead>
<tbody>
<tr> <tr>
<td><label class="jive-label"><fmt:message key="config.page.configuration.username"/>:</label><br> <td><fmt:message key="config.page.configuration.username"/><br>
</td> </td>
<td align="left"> <td align="left">
<input name="username" type="text" maxlength="16" size="16" <input name="username" type="text" maxlength="16" size="16"
...@@ -122,13 +144,23 @@ ...@@ -122,13 +144,23 @@
</td> </td>
</tr> </tr>
<tr> <tr>
<td><label class="jive-label"><fmt:message key="config.page.configuration.password"/>:</label><br> <td><fmt:message key="config.page.configuration.password"/><br>
</td> </td>
<td align="left"> <td align="left">
<input name="password" type="password" maxlength="16" size="16" <input name="password" type="password" maxlength="16" size="16"
value="<%=JiveGlobals.getProperty(PluginImpl.PASSWORD_PROPERTY_NAME, "jitsi")%>"/> value="<%=JiveGlobals.getProperty(PluginImpl.PASSWORD_PROPERTY_NAME, "jitsi")%>"/>
</td> </td>
</tr> </tr>
</tbody>
</table>
<p/>
<table class="jive-table" cellpadding="0" cellspacing="0" border="0" width="50%">
<thead>
<tr>
<th colspan="2"><fmt:message key="config.page.configuration.recording.title"/></th>
</tr>
</thead>
<tbody>
<tr> <tr>
<td nowrap colspan="2"> <td nowrap colspan="2">
<input type="radio" value="false" name="enabled" <%= ("false".equals(JiveGlobals.getProperty(PluginImpl.RECORD_PROPERTY_NAME, "false")) ? "checked" : "") %>> <input type="radio" value="false" name="enabled" <%= ("false".equals(JiveGlobals.getProperty(PluginImpl.RECORD_PROPERTY_NAME, "false")) ? "checked" : "") %>>
...@@ -141,9 +173,63 @@ ...@@ -141,9 +173,63 @@
<b><fmt:message key="config.page.configuration.record.enabled" /></b> - <fmt:message key="config.page.configuration.record.enabled_description" /> <b><fmt:message key="config.page.configuration.record.enabled" /></b> - <fmt:message key="config.page.configuration.record.enabled_description" />
</td> </td>
</tr> </tr>
</tbody>
</table>
<p/>
<table class="jive-table" cellpadding="0" cellspacing="0" border="0" width="50%">
<thead>
<tr>
<th><fmt:message key="config.page.configuration.telephone.title"/></th>
<th><%= plugin.sipRegisterStatus %></th>
</tr>
</thead>
<tbody>
<tr>
<td align="left" width="150">
<fmt:message key="config.page.configuration.authusername"/>
</td>
<td><input type="text" size="20" maxlength="100" name="authusername"
value="<%= JiveGlobals.getProperty("voicebridge.default.proxy.sipauthuser", "") %>">
</td>
</tr>
<tr>
<td align="left" width="150">
<fmt:message key="config.page.configuration.sippassword"/>
</td>
<td><input type="password" size="20" maxlength="100" name="sippassword"
value="<%= JiveGlobals.getProperty("voicebridge.default.proxy.sippassword", "") %>">
</td>
</tr>
<tr>
<td align="left" width="150">
<fmt:message key="config.page.configuration.server"/>
</td>
<td><input type="text" size="20" maxlength="100" name="server"
value="<%= JiveGlobals.getProperty("voicebridge.default.proxy.sipserver", "") %>">
</td>
</tr>
<tr>
<td align="left" width="150">
<fmt:message key="config.page.configuration.outboundproxy"/>
</td>
<td><input type="text" size="20" maxlength="100" name="outboundproxy"
value="<%= JiveGlobals.getProperty("voicebridge.default.proxy.outboundproxy", "") %>">
</td>
</tr>
</table>
<p/>
<table class="jive-table" cellpadding="0" cellspacing="0" border="0" width="50%">
<thead>
<tr>
<th colspan="2"><fmt:message key="config.page.configuration.save.title"/></th>
</tr>
</thead>
<tbody>
<tr> <tr>
<th colspan="2"><input type="submit" name="update" <th colspan="2"><input type="submit" name="update" value="<fmt:message key="config.page.configuration.submit" />"><fmt:message key="config.page.configuration.restart.warning"/></th>
value="<fmt:message key="config.page.configuration.submit" />"></th>
</tr> </tr>
</tbody> </tbody>
</table> </table>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment