using log4net;
using System;
using System.Web;
using System.Security.Cryptography;
using System.Web.Security;
using System.Xml;
using System.Net;
using System.Net.Cache;
using System.IO;
// Do-what-you-want license.
namespace BBB.Web
{
public class BBBAPI
{
// This is the security salt that must match the value set in the BigBlueButton server
string salt = "...";
// This is the URL for the BigBlueButton server
string BigBlueButtonURL = "http://...";
log4net.ILog logger = log4net.LogManager.GetLogger("bbb.web");
public BBBAPI ()
{
}
//
// Create a meeting with specific
// - meetingID
// - welcome message
// - moderator password
// - viewer password
// - voiceBridge
// - logoutURL
//
public string createMeeting(string meetingID, string welcome, string moderatorPassword, string viewerPassword, int voiceBridge, string logoutURL) {
string base_url_create = BigBlueButtonURL + "api/create?";
string base_url_join = BigBlueButtonURL + "api/join?";
string welcome_param = "";
string checksum = "";
string attendee_password_param = "&attendeePW=ap";
string moderator_password_param = "&moderatorPW=mp";
string voice_bridge_param = "";
string logoutURL_param = "";
if ( (welcome != null) && ! welcome.Equals("")) {
welcome_param = "&welcome=" + urlEncode(welcome);
}
if ( (moderatorPassword != null) && ! moderatorPassword.Equals("")) {
moderator_password_param = "&moderatorPW=" + urlEncode(moderatorPassword);
}
if ( (viewerPassword != null) && ! viewerPassword.Equals("")) {
attendee_password_param = "&attendeePW=" + urlEncode(viewerPassword);
}
if ( voiceBridge > 0 ) {
voice_bridge_param = "&voiceBridge=" + urlEncode(voiceBridge + "");
} else {
// No voice bridge number passed, so we'll generate a random one for this meeting
int n = 70000 + (new Random()).Next(9999);
voice_bridge_param = "&voiceBridge=" + n;
}
if ( (logoutURL != null) && ! logoutURL.Equals("")) {
logoutURL_param = "&logoutURL=" + urlEncode(logoutURL);
}
//
// Now create the URL
//
string create_parameters = "name=" + urlEncode(meetingID) + "&meetingID=" + urlEncode(meetingID)
+ welcome_param + attendee_password_param + moderator_password_param + voice_bridge_param + logoutURL_param;
XmlDocument doc = null;
try {
// Attempt to create a meeting using meetingID
string xml = getURL(base_url_create + create_parameters + "&checksum=" + Checksum(create_parameters + salt) );
doc = parseXml(xml);
} catch (Exception e) {
logger.Debug(e.Message);
}
if (doc.GetElementsByTagName("returncode").Item(0).InnerText
.Trim().Equals("SUCCESS")) {
string meetingToken = "";
if (doc.GetElementsByTagName("meetingToken").Item(0) != null) {
return doc.GetElementsByTagName("meetingToken").Item(0)
.InnerText.Trim();
}
}
return "Error " + doc.GetElementsByTagName("messageKey").Item(0).InnerText.Trim()
+ ": " + doc.GetElementsByTagName("message").Item(0).InnerText.Trim();
}
//
// isMeetingRunning() -- check the BigBlueButton server to see if the meeting is running (i.e. there is someone in the meeting)
//
public String isMeetingRunning(string meetingToken, string meetingID) {
string base_main = "meetingToken=" + meetingToken + "&meetingID=" + urlEncode(meetingID);
string base_url = BigBlueButtonURL + "api/isMeetingRunning?";
string checksum ="";
try {
checksum = FormsAuthentication.HashPasswordForStoringInConfigFile(base_main + salt, "sha1");
} catch (Exception e) {
log4net.LogManager.GetLogger("bbb.web").Debug(e.StackTrace);
}
string xml = getURL(base_url + base_main + "&checksum=" + checksum);
XmlDocument doc = null;
try {
doc = parseXml(xml);
} catch (Exception e) {
log4net.LogManager.GetLogger("bbb.web").Debug(e.StackTrace);
}
if (doc.GetElementsByTagName("returncode").Item(0).InnerText.Trim().Equals("SUCCESS") ){
return doc.GetElementsByTagName("running").Item(0).InnerText.Trim();
}
return "false";
}
//
// getURLisMeetingRunning() -- return a URL that the client can use to poll for whether the given meeting is running
//
public string getURLisMeetingRunning(string meetingToken, string meetingID) {
string base_main = "meetingToken=" + meetingToken + "&meetingID=" + urlEncode(meetingID);
string base_url = BigBlueButtonURL + "api/isMeetingRunning?";
string checksum = "";
try {
checksum = FormsAuthentication.HashPasswordForStoringInConfigFile(base_main + salt, "sha1");
} catch (Exception e) {
log4net.LogManager.GetLogger("bbb.web").Debug(e.StackTrace);
}
return base_url + base_main + "&checksum=" + checksum;
}
//
// getJoinMeetingURL() -- get join meeting URL for both viewer and moderator
//
public string getJoinMeetingURL(string username, string meetingToken, string password) {
string base_url_join = BigBlueButtonURL + "api/join?";
string join_parameters = "meetingToken=" + meetingToken + "&fullName=" + urlEncode(username)
+ "&password=" + urlEncode(password);
return base_url_join + join_parameters + "&checksum=" + Checksum(join_parameters + salt);
}
//
// Create a meeting and return a URL to join it as moderator
//
public string getJoinURL(string username, string meetingID, string welcome) {
string base_url_create = BigBlueButtonURL + "api/create?";
string base_url_join = BigBlueButtonURL + "api/join?";
string welcome_param = "";
string checksum = "";
int voiceBridge = 7000 + new Random().Next(9999);
if ( (welcome != null) && ! welcome.Equals("")) {
welcome_param = "&welcome=" + urlEncode(welcome);
}
//
// When creating a meeting, the 'name' parameter is the name of the meeting (not to be confused with
// the username). For example, the name could be "Fred's meeting" and the meetingID could be "ID-1234312".
//
// While name and meetinID could be different, we'll keep them the same. Why? Because calling api/create?
// with a previously used meetingID will return same meetingToken (regardless if the meeting is running or not).
//
// This means the first person to call getJoinURL with meetingID="Demo Meeting" will actually create the
// meeting. Subsequent calls will return the same meetingToken and thus subsequent users will join the same
// meeting.
//
// Note: We're hard-coding the password for moderator and attendee (viewer) for purposes of demo.
//
string create_parameters = "name=" + urlEncode(meetingID) + "&meetingID=" + urlEncode(meetingID)
+ welcome_param + "&attendeePW=ap&moderatorPW=mp&voiceBridge="+voiceBridge;
XmlDocument doc = null;
try {
// Attempt to create a meeting using meetingID
string xml = getURL(base_url_create + create_parameters + "&checksum=" + Checksum(create_parameters + salt) );
doc = parseXml(xml);
} catch (Exception e) {
logger.Debug(e.Message);
}
if (doc.GetElementsByTagName("returncode").Item(0).InnerText.Trim().Equals("SUCCESS")) {
string meetingToken = "";
if (doc.GetElementsByTagName("meetingToken").Item(0) != null) {
meetingToken = doc.GetElementsByTagName("meetingToken").Item(0).InnerText.Trim();
}
//
// Now create a URL to join that meeting
//
string join_parameters = "meetingToken=" + meetingToken + "&fullName=" + urlEncode(username)
+ "&password=mp";
return base_url_join + join_parameters + "&checksum=" + Checksum(join_parameters + salt);
}
return doc.GetElementsByTagName("messageKey").Item(0).InnerText.Trim()
+ ": " + doc.GetElementsByTagName("message").Item(0).InnerText.Trim();
}
//
// getJoinURLViewer() -- Get the URL to join a meeting as viewer
//
public string getJoinURLViewer(string username, string meetingToken) {
string base_url_join = BigBlueButtonURL + "api/join?";
string join_parameters = "meetingToken=" + meetingToken + "&fullName=" + urlEncode(username)
+ "&password=ap";
return base_url_join + join_parameters + "&checksum=" + Checksum(join_parameters + salt);
}
//
// checksum() -- create a hash based on the shared salt (located in bbb_api_conf.jsp)
//
public static string Checksum(string s) {
string checksum = "";
try {
checksum = FormsAuthentication.HashPasswordForStoringInConfigFile(s, "SHA1");
checksum = checksum.ToLower(); // BBB is case sensitive here.
} catch (Exception e) {
log4net.LogManager.GetLogger("bbb.web").Debug(e.StackTrace);
}
return checksum;
}
//
// getURL() -- fetch a URL and return its contents as a string
//
public static string getURL(string url) {
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
request.CachePolicy = new HttpRequestCachePolicy(System.Net.Cache.HttpRequestCacheLevel.NoCacheNoStore);
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if( response.StatusCode.Equals(HttpStatusCode.OK) ) {
StreamReader input = new StreamReader(response.GetResponseStream());
return input.ReadToEnd();
}
return "";
}
public string getMeetingInfoURL(string meetingID, string password) {
string meetingParameters = "meetingID=" + urlEncode(meetingID) + "&password=" + password;
return BigBlueButtonURL + "api/getMeetingInfo?" + meetingParameters + "&checksum=" + Checksum(meetingParameters + salt);
}
public string getMeetingsURL() {
string meetingParameters = "random=" + new Random().Next(9999);
return BigBlueButtonURL + "api/getMeetings?" + meetingParameters + "&checksum=" + Checksum(meetingParameters + salt);
}
public string getMeetingInfo(string meetingID, string password) {
try {
HttpWebRequest hpCon = (HttpWebRequest)HttpWebRequest.Create(getMeetingInfoURL(meetingID, password));
string data = (new StreamReader(hpCon.GetResponse().GetResponseStream())).ReadToEnd();
return data;
} catch (Exception e) {
logger.Debug(e.Message);
return "";
}
}
//
// urlEncode() -- URL encode the string
//
public static string urlEncode(string s) {
try {
return HttpUtility.UrlEncode(s);
} catch (Exception e) {
log4net.LogManager.GetLogger("bbb.web").Debug(e.StackTrace);
}
return "";
}
//
// parseXml() -- return a DOM of the XML
//
public static XmlDocument parseXml(string xml) {
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
return doc;
}
//
// Calls getMeetings to obtain the list of meetings, then calls getMeetingInfo for each meeting
// and concatenates the result.
//
public string getMeetings() {
try {
// Call the API and get the result
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(getMeetingsURL());
string data = (new StreamReader(request.GetResponse().GetResponseStream())).ReadToEnd();
XmlDocument doc = parseXml(data);
// tags needed for parsing xml documents
const string startTag = "";
const string endTag = "";
const string startResponse = "";
const string endResponse = "";
// if the request succeeded, then calculate the checksum of each meeting and insert it into the document
XmlNodeList meetingsList = doc.GetElementsByTagName("meeting");
string newXMldocument = startTag;
foreach(XmlElement element in meetingsList) {
string meetingID = element.GetElementsByTagName("meetingID")[0].InnerText;
string password = element.GetElementsByTagName("moderatorPW")[0].InnerText;
data = getMeetingInfoURL(meetingID, password);
if( data.IndexOf("") != -1) {
int startIndex = data.IndexOf(startResponse) + startTag.Length;
int endIndex = data.IndexOf(endResponse);
newXMldocument += "" + data.Substring(startIndex, endIndex) + "";
}
}
newXMldocument += endTag;
return newXMldocument;
} catch (Exception e) {
log4net.LogManager.GetLogger("bbb.web").Debug(e.StackTrace);
return null;
}
}
}
}