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; } } } }