Commit b98a92ce authored by Dele Olajide's avatar Dele Olajide

Version 0.0.3

parent a1671c3f
......@@ -49,12 +49,14 @@
Openfire Meetings Plugin Changelog
</h1>
<p><b>0.0.3</b> -- Dec 2nd, 2014</p>
<p><b>0.0.3</b> -- Dec 6th, 2014</p>
<ul>
<li>Changed version to 3.9.9 to overcome bug in openfire version control</li>
<li>Added recording parameters to admin web page</li>
<li>Latest version of Jitsi Meet</li>
<li>Updated Jitsi Meet and Jitsi Videobridge</li>
<li>Added Spark plugin</li>
<li>Added support for Openfire vCard avatars</li>
</ul>
<p><b>0.0.2</b> -- Nov 30th, 2014</p>
......
......@@ -54,8 +54,29 @@
Openfire Meetings
</p>
<h2>Installation</h2>
<div>
<p>Ignite Realtime is pleased to announce "Openfire Meeting", a new plugin for Openfire that continues the development of the ofmeet web application which was part of the deprecated <a href="https://community.igniterealtime.org/community/support/jitsi_videobridge_plugin">Jitsi-videobridge plugin</a>.</p>
<p style="min-height: 8pt; padding: 0px;">&nbsp;</p><p><strong>PLEASE NOTE</strong> - You will need latest Openfire 3.10.0 to use this plugin. Use a nightly build or wait for the imminent official release.</p>
<p><a href="https://community.igniterealtime.org/servlet/JiveServlet/showImage/38-1730-22181/ofmeet1.png"><img alt="ofmeet1.png" height="272" src="https://community.igniterealtime.org/servlet/JiveServlet/downloadImage/38-1730-22181/432-272/ofmeet1.png" style="width:432px; height: 272.438709677419px;" width="432"/></a></p>
<p style="min-height: 8pt; padding: 0px;">&nbsp;</p><p>Openfire Meetings is a complete standalone plugin powered by Jitsi Videobridge. It does not depend on any other plugins</p><p style="min-height: 8pt; padding: 0px;">&nbsp;</p>
<p><a href="https://community.igniterealtime.org/servlet/JiveServlet/showImage/38-1730-22275/ofmeet3.png"><img alt="ofmeet3.png" height="160" src="https://community.igniterealtime.org/servlet/JiveServlet/downloadImage/38-1730-22275/428-160/ofmeet3.png" style="width:428px; height: 160.325732899023px;" width="428"/></a></p>
<p style="min-height: 8pt; padding: 0px;">&nbsp;</p><p>The front-end we application is a combination of Candy and Jitsi Meet and enables the following features</p>
<ul>
<li>Openfire user authentication directly from web browser for both Candy and Jitsi Meet</li>
<li>Audio, Video and Telephone (SIP) conferencing directly with Jitsi Meet and from Candy</li>
<li>Desktop sharing (screen and applications) using the Openfire Meeting Chrome extension</li>
<li>Fastpath user agent with audio and video using the Candy and Jitsi Meet web applications. It also requires Fastpath plugin to be installed.</li>
<li>Configuration directly from Openfire admin web pages.</li>
</ul>
<p style="min-height: 8pt; padding: 0px;">&nbsp;</p><p><a href="https://community.igniterealtime.org/servlet/JiveServlet/showImage/38-1730-22276/ofmeet2.png"><img alt="ofmeet2.png" height="224" src="https://community.igniterealtime.org/servlet/JiveServlet/downloadImage/38-1730-22276/397-224/ofmeet2.png" style="width:397px; height: 223.661971830986px;" width="397"/></a></p>
<p><strong>How to use</strong></p>
<p><span>Jitsi Meet - </span>https://your-server.com:7443/ofmeet</p>
<p><span>Spark Plugin - </span>https://your-server.com:7443/ofmeet/spark/ofmeet-plugin.jar</p>
<p>Candy - https://your-server.com:7443/ofmeet/candy.html</p>
<p style="min-height: 8pt; padding: 0px;">&nbsp;</p><p><a href="https://community.igniterealtime.org/servlet/JiveServlet/showImage/38-1730-22278/ofmeet5.png"><img alt="ofmeet5.png" height="93" src="https://community.igniterealtime.org/servlet/JiveServlet/downloadImage/38-1730-22278/ofmeet5.png" style="height: auto;" width="300"/></a></p>
<p>Discussion place is in the <a href="https://community.igniterealtime.org/community/plugins/commplugins/openfire-meetings/activity">community plugins, here</a></p>
</div>
</body>
</html>
......@@ -283,6 +283,7 @@ function doJoin() {
roomjid += '/' + tmpJid;
}
connection.ofmuc.roomJid = roomName; // BAO
connection.emuc.doJoin(roomjid);
}
......
......@@ -14,7 +14,7 @@ var Avatar = (function(my) {
}
users[jid] = id;
}
var url = getGravatarUrl(users[jid] || jid);
var url = getGravatarUrl(users[jid] || jid, 100, jid); // BAO
var resourceJid = Strophe.getResourceFromJid(jid);
var thumbnail = $('#participant_' + resourceJid);
var avatar = $('#avatar_' + resourceJid);
......@@ -102,7 +102,7 @@ var Avatar = (function(my) {
}
var avatar = $("#activeSpeakerAvatar")[0];
var url = getGravatarUrl(users[jid],
interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE);
interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE, jid); // BAO
if(jid === activeSpeakerJid && avatar.src === url) {
return;
}
......@@ -137,16 +137,22 @@ var Avatar = (function(my) {
return mediaStreams[jid][MediaStream.VIDEO_TYPE].muted;
}
function getGravatarUrl(id, size) {
function getGravatarUrl(id, size, jid) {
if (connection.emuc.myroomjid == jid && config.userAvatar && config.userAvatar != "null")
{
return config.userAvatar; // BAO openfire avatars
} else if (connection.ofmuc.members[jid]) {
return connection.ofmuc.members[jid].avatar;
}
if(id === connection.emuc.myroomjid || !id) {
id = SettingsMenu.getUID();
}
if (config.userAvatar && config.userAvatar != "null") return config.userAvatar; // BAO
return 'https://www.gravatar.com/avatar/' +
MD5.hexdigest(id.trim().toLowerCase()) +
"?d=retro&size=" + (size || "30");
return '//www.gravatar.com/avatar/' + MD5.hexdigest(id.trim().toLowerCase()) + "?d=mm&size=" + (size || "30");
}
return my;
......
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Forbidden</title>
</head>
<body>
<h1>Forbidden</h1>
<h4>This is a private folder</h4>
</body>
</html>
\ No newline at end of file
......@@ -53,7 +53,7 @@ var ContactList = (function (my) {
}
};
newContact.appendChild(createAvatar(id));
newContact.appendChild(createAvatar(id, peerJid)); // BAO
newContact.appendChild(createDisplayNameParagraph("Participant"));
var clElement = contactlist.get(0);
......@@ -136,11 +136,22 @@ var ContactList = (function (my) {
*
* @return the newly created avatar element
*/
function createAvatar(id) {
function createAvatar(id, peerJid) { // BAO
var avatar = document.createElement('img');
avatar.className = "icon-avatar avatar";
avatar.src = "https://www.gravatar.com/avatar/" + id + "?d=retro&size=30";
if (connection.emuc.myroomjid == peerJid && config.userAvatar && config.userAvatar != "null")
{
avatar.src = config.userAvatar;
} else if (connection.ofmuc.members[peerJid] && connection.ofmuc.members[peerJid].avatar) {
avatar.src = connection.ofmuc.members[peerJid].avatar;
} else {
avatar.src = "//www.gravatar.com/avatar/" + id + "?d=mm&size=30";
}
return avatar;
}
......
......@@ -340,7 +340,7 @@
</div>
<div id="settingsmenu" class="right-panel">
<div class="icon-settings"> SETTINGS</div>
<img id="avatar" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEBLAEsAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAgACADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD6E+LPjLUNIuoPD2izLbaldQ+cbl4wwijyVG0EY3EgnJyBt5BzXkFl4k1u08YbLy6+1Xsrgx3vCyR/Lg5CDDD2469cZpnxy8ZWWs+O0l0XfjT4TZSTk7TK6yNu2jOCoPAPUlm7AZr/AApv7S5vr2+v42eUBMeYBuQfMDx2ydtfEZti5yru0tFt5Hv5c6Ps1H7TPVE8Ya3F5Miasblo2HmQSQJFvHocqCoPTNehaFr1vqllBdQnCzoHCsMEZHSvAvGWsW9rBPfwyiAIMI5HGTnHQ1u/BrxWNWsUUFUkt2Ecsa5wvGRjPPT9QR2r0OH8TWrSm5yvHpfv/kGa4JU6SqRjbuec+Ofhb4r0PWbtYbZryxHzQ3aFAsi5OAVLZDAAZGMdwTzXEWN7PpmpGVPkuomKvjg7u6ntkdK+5NasFvLZkPGVIrxXxl8INKu72a+imubaSQgsI9hUnjnDIcH6V9NleEweEqznUhzcys76o+XxVOpOzpys0eS/FLVtP1PxTJY6YJF0yNkjgkJMhb5Qd4Dcg5bp7YrqPgbZ3NhCLyVgTdRptUfwqC5HPvv6emKkf4WWqThpbm5mVT90xxKG9jhBXoHhDw99nMSLGkaJgAAYwOa7MS8K4xjh4W5fK33muGq4qMZxqTupWb9Uf//Z"/> <!-- BAO -->
<img id="avatar" src="//www.gravatar.com/avatar/00000000000000000000000000000000?d=mm&size=30"/> <!-- BAO -->
<div class="arrow-up"></div>
<input type="text" id="setDisplayName" placeholder="Name">
<input type="text" id="setEmail" placeholder="E-Mail">
......
/*
* Jitsi Videobridge, OpenSource video conferencing.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jitsi.jigasi.openfire;
import java.io.File;
import org.jivesoftware.util.*;
import org.jivesoftware.openfire.container.Plugin;
import org.jivesoftware.openfire.container.PluginManager;
import org.slf4j.*;
import org.slf4j.Logger;
import org.xmpp.component.*;
import org.xmpp.packet.*;
/**
* SIP gateway for Jitsi Videobridge conferences.
*/
public class JigasiPlugin
{
/**
* The Log.
*/
private static final Logger Log = LoggerFactory.getLogger(JigasiPlugin.class);
private CallControlComponent component;
private ComponentManager componentManager;
private String subdomain;
private File pluginDirectory;
public void initializePlugin(PluginManager manager, File pluginDirectory)
{
Log.info("JigasiPlugin - initializePlugin");
this.pluginDirectory = pluginDirectory;
ComponentManager componentManager = ComponentManagerFactory.getComponentManager();
String subdomain = "ofmeet-call-control";
CallControlComponent component = new CallControlComponent(pluginDirectory);
boolean added = false;
try
{
componentManager.addComponent(subdomain, component);
added = true;
}
catch (ComponentException ce)
{
ce.printStackTrace(System.err);
}
if (added)
{
this.componentManager = componentManager;
this.subdomain = subdomain;
this.component = component;
}
else
{
this.componentManager = null;
this.subdomain = null;
this.component = null;
}
}
public void destroyPlugin()
{
Log.info("JigasiPlugin - destroyPlugin");
if ((componentManager != null) && (subdomain != null))
{
try
{
component.stop();
componentManager.removeComponent(subdomain);
}
catch (ComponentException ce)
{
// TODO Auto-generated method stub
}
componentManager = null;
subdomain = null;
component = null;
}
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -46,9 +46,9 @@ Strophe.addConnectionPlugin('rayo',
console.info('Dial result ', result);
var resource = $(result).find('ref').attr('uri');
this.call_resource = resource.substr('xmpp:'.length);
self.call_resource = resource.substr('xmpp:'.length); // BAO
console.info(
"Received call resource: " + this.call_resource);
"Received call resource: " + self.call_resource);
},
function (error)
{
......
/* global $, $iq, config, connection, Etherpad, hangUp, roomName, Strophe,
Toolbar, Util, VideoLayout */
/**
* Contains logic responsible for enabling/disabling functionality available
* only to moderator users.
*/
var Moderator = (function (my) {
var getNextTimeout = Util.createExpBackoffTimer(1000);
var getNextErrorTimeout = Util.createExpBackoffTimer(1000);
my.isModerator = function () {
return connection.emuc.isModerator();
};
my.onModeratorStatusChanged = function (isModerator) {
Toolbar.showSipCallButton(isModerator);
Toolbar.showRecordingButton(
isModerator); //&&
// FIXME:
// Recording visible if
// there are at least 2(+ 1 focus) participants
//Object.keys(connection.emuc.members).length >= 3);
if (isModerator && config.etherpad_base) {
Etherpad.init();
}
$(document).trigger('local.role.moderator', [isModerator]);
};
my.init = function () {
$(document).bind(
'role.changed.muc',
function (event, jid, info, pres) {
console.info(
"Role changed for " + jid + ", new role: " + info.role);
VideoLayout.showModeratorIndicator();
}
);
$(document).bind(
'local.role.changed.muc',
function (event, jid, info, pres) {
console.info("My role changed, new role: " + info.role);
VideoLayout.showModeratorIndicator();
Moderator.onModeratorStatusChanged(Moderator.isModerator());
}
);
$(document).bind(
'left.muc',
function (event, jid) {
console.info("Someone left is it focus ? " + jid);
var resource = Strophe.getResourceFromJid(jid);
if (resource === 'focus') {
console.info(
"Focus has left the room - leaving conference");
//hangUp();
// We'd rather reload to have everything re-initialized
// FIXME: show some message before reload
location.reload();
}
}
);
};
my.createConferenceIq = function () {
var elem = $iq({to: config.hosts.focus, type: 'set'});
elem.c('conference', {
xmlns: 'http://jitsi.org/protocol/focus',
room: roomName
});
if (config.channelLastN !== undefined)
{
elem.c(
'property',
{ name: 'channelLastN', value: config.channelLastN})
.up();
}
if (config.adaptiveLastN !== undefined)
{
elem.c(
'property',
{ name: 'adaptiveLastN', value: config.adaptiveLastN})
.up();
}
if (config.adaptiveSimulcast !== undefined)
{
elem.c(
'property',
{ name: 'adaptiveSimulcast', value: config.adaptiveSimulcast})
.up();
}
elem.up();
return elem;
};
// FIXME: we need to show the fact that we're waiting for the focus
// to the user(or that focus is not available)
my.allocateConferenceFocus = function (roomName, callback) {
var iq = Moderator.createConferenceIq();
connection.sendIQ(
iq,
function (result) {
if ('true' === $(result).find('conference').attr('ready')) {
// Reset both timers
getNextTimeout(true);
getNextErrorTimeout(true);
callback();
} else {
var waitMs = getNextTimeout();
console.info("Waiting for the focus... " + waitMs);
// Reset error timeout
getNextErrorTimeout(true);
window.setTimeout(
function () {
Moderator.allocateConferenceFocus(
roomName, callback);
}, waitMs);
}
},
function (error) {
var waitMs = getNextErrorTimeout();
console.error("Focus error, retry after " + waitMs, error);
// Reset response timeout
getNextTimeout(true);
window.setTimeout(
function () {
Moderator.allocateConferenceFocus(roomName, callback);
}, waitMs);
}
);
};
return my;
}(Moderator || {}));
......@@ -79,7 +79,7 @@ Strophe.addConnectionPlugin('ofmuc', {
var type = pres.getAttribute('type');
if (type != null) {
return true;
return true;
}
if (!this.roomJid || Strophe.getBareJidFromJid(from) != this.roomJid) return true;
......@@ -95,6 +95,11 @@ Strophe.addConnectionPlugin('ofmuc', {
} else if (this.members[from] === undefined) {
this.members[from] = member;
if (config.userAvatar && config.userAvatar != "null")
{
this.avatarShare(config.userAvatar);
}
if (this.sharePDF)
{
......@@ -139,6 +144,12 @@ Strophe.addConnectionPlugin('ofmuc', {
that.handlePdfShare(action, url);
});
$(msg).find('avatarshare').each(function()
{
that.members[from].avatar = $(this).text();
Avatar.setUserAvatar(from);
});
return true;
},
......@@ -180,7 +191,7 @@ Strophe.addConnectionPlugin('ofmuc', {
{
var callId = Strophe.getNodeFromJid(from);
console.log("onRayo callid", callId, jid);
//console.log("onRayo callid", callId, jid);
if (jid)
{
......@@ -201,7 +212,7 @@ Strophe.addConnectionPlugin('ofmuc', {
{
var callId = Strophe.getNodeFromJid(from);
console.log("onRayo callid", callId, jid);
//console.log("onRayo callid", callId, jid);
if (jid)
{
......@@ -266,6 +277,12 @@ Strophe.addConnectionPlugin('ofmuc', {
this.connection.send(msg);
},
avatarShare: function(avatar) {
//console.log("ofmuc.avatarShare", avatar)
var msg = $msg({to: this.roomJid, type: 'groupchat'});
msg.c('avatarshare', {xmlns: 'http://igniterealtime.org/protocol/avatarshare'}).t(avatar).up();
this.connection.send(msg);
},
pdfStart: function(url) {
//console.log("pdfStart", url);
......
/* global $, $iq, config, connection, focusJid, messageHandler, Moderator,
Toolbar, Util */
var Recording = (function (my) {
var recordingToken = null;
var recordingEnabled;
my.setRecordingToken = function (token) {
recordingToken = token;
};
// Sends a COLIBRI message which enables or disables (according to 'state')
// the recording on the bridge. Waits for the result IQ and calls 'callback'
// with the new recording state, according to the IQ.
my.setRecording = function (state, token, callback) {
var self = this;
var elem = $iq({to: focusJid, type: 'set'});
elem.c('conference', {
xmlns: 'http://jitsi.org/protocol/colibri'
});
elem.c('recording', {state: state, token: token});
elem.up();
connection.sendIQ(elem,
function (result) {
console.log('Set recording "', state, '". Result:', result);
var recordingElem = $(result).find('>conference>recording');
var newState = ('true' === recordingElem.attr('state'));
recordingEnabled = newState;
callback(newState);
},
function (error) {
console.warn(error);
}
);
};
my.toggleRecording = function () {
if (!Moderator.isModerator()) {
console.log(
'non-focus, or conference not yet organized:' +
' not enabling recording');
return;
}
if (!recordingToken)
{
messageHandler.openTwoButtonDialog(null,
'<h2>Enter recording token</h2>' +
'<input id="recordingToken" type="text" placeholder="token" autofocus>',
false,
"Save",
function (e, v, m, f) {
if (v) {
var token = document.getElementById('recordingToken');
if (token.value) {
my.setRecordingToken(
Util.escapeHtml(token.value));
my.toggleRecording();
}
}
},
function (event) {
document.getElementById('recordingToken').focus();
}
);
return;
}
var oldState = recordingEnabled;
Toolbar.setRecordingButtonState(!oldState);
my.setRecording(!oldState,
recordingToken,
function (state) {
console.log("New recording state: ", state);
if (state === oldState)
{
// FIXME: new focus:
// this will not work when moderator changes
// during active session. Then it will assume that
// recording status has changed to true, but it might have
// been already true(and we only received actual status from
// the focus).
//
// SO we start with status null, so that it is initialized
// here and will fail only after second click, so if invalid
// token was used we have to press the button twice before
// current status will be fetched and token will be reset.
//
// Reliable way would be to return authentication error.
// Or status update when moderator connects.
// Or we have to stop recording session when current
// moderator leaves the room.
// Failed to change, reset the token because it might
// have been wrong
my.setRecordingToken(null);
}
// Update with returned status
Toolbar.setRecordingButtonState(state);
}
);
};
return my;
}(Recording || {}));
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Forbidden</title>
</head>
<body>
<h1>Forbidden</h1>
<h4>This is a private folder</h4>
</body>
</html>
\ No newline at end of file
#OfMeet Settings
server=btg199251
port=7443
protocol=https://
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