1
+ # Copyright 2011 Omar Shammas
2
+ #
3
+ # This program is free software; you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation; either version 2 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program; if not, write to the Free Software
15
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
+
17
+ #Versions:
18
+ # 0.1 -- written by Omar Shammas (email : omar DOT shammas [a t ] g m ail DOT com)
19
+ # Initial version works with 0.7 version of the BBB API
20
+ # test comment
21
+
22
+ import urllib .request , urllib .parse , urllib .error , urllib .request , urllib .error , urllib .parse , socket
23
+ import hashlib , random
24
+ from xml .dom import minidom
25
+ from xml .dom .minidom import Node
26
+
27
+
28
+ def bbb_wrap_load_file (url ):
29
+ timeout = 10
30
+ socket .setdefaulttimeout (timeout )
31
+
32
+ try :
33
+ req = urllib .request .urlopen (url )
34
+ return minidom .parse (req )
35
+ except :
36
+ return False
37
+
38
+
39
+ def assign2Dict (xml ):
40
+ try :
41
+ mapping = {}
42
+ response = xml .firstChild
43
+ for child in response .childNodes :
44
+
45
+ if ( child .hasChildNodes () ):
46
+ mapping [child .tagName ] = child .firstChild .nodeValue
47
+ else :
48
+ mapping [child .tagName ] = None
49
+
50
+ return mapping
51
+ except :
52
+ return False
53
+
54
+ #------------------------------------------------GET URLs-------------------------------------------------
55
+ #
56
+ #This method returns the url to join the specified meeting.
57
+ #
58
+ #@param meetingID -- the unique meeting identifier used to store the meeting in the bigbluebutton server
59
+ #@param username -- the display name to be used when the user joins the meeting
60
+ #@param PW -- the attendee or moderator password of the meeting
61
+ #@param SALT -- the security salt of the bigbluebutton server
62
+ #@param URL -- the url of the bigbluebutton server
63
+ #
64
+ #@return The url to join the meeting
65
+
66
+ def joinMeetingURL (meetingID , username , PW , URL , SALT ):
67
+ url_join = URL + "api/join?"
68
+
69
+ parameters = {'meetingID' : meetingID ,
70
+ 'fullName' : username ,
71
+ 'password' : PW ,
72
+ }
73
+
74
+ parameters = urllib .parse .urlencode (parameters )
75
+ return url_join + parameters + '&checksum=' + hashlib .sha1 (("join" + parameters + SALT ).encode ('utf-8' )).hexdigest ()
76
+
77
+ #
78
+ #This method returns the url to join the specified meeting.
79
+ #
80
+ #@param name -- a name fot the meeting
81
+ #@param meetingID -- the unique meeting identifier used to store the meeting in the bigbluebutton server
82
+ #@param attendeePW -- the attendee of the meeting
83
+ #@param moderatorPW -- the moderator of the meeting
84
+ #@param welcome -- the welcome message that gets displayed on the chat window
85
+ #@param logoutURL -- the URL that the bbb client will go to after users logouut
86
+ #@param SALT -- the security salt of the bigbluebutton server
87
+ #@param URL -- the url of the bigbluebutton server
88
+ #
89
+ #@return The url to join the meeting
90
+
91
+ def createMeetingURL (name , meetingID , attendeePW , moderatorPW , welcome , logoutURL , URL , SALT ):
92
+ url_create = URL + "api/create?"
93
+ voiceBridge = 70000 + random .randint (0 , 9999 );
94
+ parameters = {'name' : name ,
95
+ 'meetingID' : meetingID ,
96
+ 'attendeePW' : attendeePW ,
97
+ 'moderatorPW' : moderatorPW ,
98
+ 'voiceBridge' : voiceBridge ,
99
+ 'logoutURL' : logoutURL ,
100
+ }
101
+
102
+ #if (welcome and welcome != ''):
103
+ # parameters.update({'welcome': welcome.strip()})
104
+
105
+ parameters = urllib .parse .urlencode (parameters )
106
+
107
+ return url_create + parameters + '&checksum=' + hashlib .sha1 (("create" + parameters + SALT ).encode ('utf-8' )).hexdigest ()
108
+
109
+
110
+ #
111
+ #This method returns the url to check if the specified meeting is running.
112
+ #
113
+ #@param meetingID -- the unique meeting identifier used to store the meeting in the bigbluebutton server
114
+ #@param SALT -- the security salt of the bigbluebutton server
115
+ #@param URL -- the url of the bigbluebutton server
116
+ #
117
+ #@return The url to check if the specified meeting is running.
118
+ #
119
+ def isMeetingRunningURL ( meetingID , URL , SALT ):
120
+ base_url = URL + "api/isMeetingRunning?"
121
+
122
+ parameters = {'meetingID' : meetingID ,}
123
+ parameters = urllib .parse .urlencode (parameters )
124
+
125
+ return base_url + parameters + '&checksum=' + hashlib .sha1 (("isMeetingRunning" + parameters + SALT ).encode ('utf-8' )).hexdigest ()
126
+
127
+
128
+ #
129
+ #This method returns the url to getMeetingInfo of the specified meeting.
130
+ #
131
+ #@param meetingID -- the unique meeting identifier used to store the meeting in the bigbluebutton server
132
+ #@param modPW -- the moderator password of the meeting
133
+ #@param SALT -- the security salt of the bigbluebutton server
134
+ #@param URL -- the url of the bigbluebutton server
135
+ #
136
+ #@return The url to check if the specified meeting is running.
137
+ #
138
+ def getMeetingInfoURL ( meetingID , modPW , URL , SALT ):
139
+ base_url = URL + "api/getMeetingInfo?"
140
+
141
+ parameters = {'meetingID' : meetingID ,
142
+ 'password' : modPW ,
143
+ }
144
+ parameters = urllib .parse .urlencode (parameters )
145
+
146
+ return base_url + parameters + '&checksum=' + hashlib .sha1 (("getMeetingInfo" + parameters + SALT ).encode ('utf-8' )).hexdigest ()
147
+
148
+
149
+ #
150
+ #This method returns the url for listing all meetings in the bigbluebutton server.
151
+ #
152
+ #@param SALT -- the security salt of the bigbluebutton server
153
+ #@param URL -- the url of the bigbluebutton server
154
+ #
155
+ #@return The url of getMeetings.
156
+ #
157
+ def getMeetingsURL (URL , SALT ):
158
+ base_url = URL + "api/getMeetings?"
159
+
160
+ parameters = {'random' : (random .random () * 1000 ),}
161
+ parameters = urllib .parse .urlencode (parameters )
162
+
163
+ return base_url + parameters + '&checksum=' + hashlib .sha1 (("getMeetings" + parameters + SALT ).encode ('utf-8' )).hexdigest ()
164
+
165
+
166
+ #
167
+ #This method returns the url to end the specified meeting.
168
+ #
169
+ #@param meetingID -- the unique meeting identifier used to store the meeting in the bigbluebutton server
170
+ #@param modPW -- the moderator password of the meeting
171
+ #@param SALT -- the security salt of the bigbluebutton server
172
+ #@param URL -- the url of the bigbluebutton server
173
+ #
174
+ #@return The url to end the specified meeting.
175
+ #
176
+ def endMeetingURL ( meetingID , modPW , URL , SALT ):
177
+ base_url = URL + "api/end?"
178
+
179
+ parameters = {'meetingID' : meetingID ,
180
+ 'password' : modPW ,
181
+ }
182
+ parameters = urllib .parse .urlencode (parameters )
183
+
184
+ return base_url + parameters + '&checksum=' + hashlib .sha1 (("end" + parameters + SALT ).encode ('utf-8' )).hexdigest ()
185
+
186
+
187
+
188
+
189
+ #-----------------------------------------------CREATE----------------------------------------------------
190
+ #
191
+ #This method creates a meeting and return an array of the xml packet
192
+ #
193
+ #@param username
194
+ #@param meetingID -- the unique meeting identifier used to store the meeting in the bigbluebutton server
195
+ #@param welcomeString -- the welcome message to be displayed when a user logs in to the meeting
196
+ #@param mPW -- the moderator password of the meeting
197
+ #@param aPW -- the attendee password of the meeting
198
+ #@param SALT -- the security salt of the bigbluebutton server
199
+ #@param URL -- the url of the bigbluebutton server
200
+ #@param logoutURL -- the url the user should be redirected to when they logout of bigbluebutton
201
+ #
202
+ #@return
203
+ # - Null if unable to reach the bigbluebutton server
204
+ # - False if an error occurs while parsing
205
+ # - Dictionary containing the values of the xml packet
206
+ #
207
+ def createMeeting (name , meeting_id , welcome_message , moderator_pw , attendee_pw , logout_url , url , secret ):
208
+
209
+ create_url = createMeetingURL (name , meeting_id , attendee_pw , moderator_pw , welcome_message , logout_url , url , secret )
210
+ xml = bbb_wrap_load_file ( create_url )
211
+
212
+ if (xml ):
213
+ return assign2Dict (xml )
214
+
215
+ #if unable to reach the server
216
+ return None
217
+
218
+
219
+ #-------------------------------------------getMeetingInfo---------------------------------------------------
220
+ #
221
+ #This method calls the getMeetingInfo on the bigbluebutton server and returns an array.
222
+ #
223
+ #@param meetingID -- the unique meeting identifier used to store the meeting in the bigbluebutton server
224
+ #@param modPW -- the moderator password of the meeting
225
+ #@param SALT -- the security salt of the bigbluebutton server
226
+ #@param URL -- the url of the bigbluebutton server
227
+ #
228
+ #@return
229
+ # - None if unable to reach the bigbluebutton server
230
+ # - Dictionary containing the values of the xml packet
231
+ # - If the returncode == 'FAILED' it returns a dictionary containing a returncode, messagekey, and message.
232
+ # - If the returncode == 'SUCCESS' it returns a dictionary containing a meetingID, moderatorPW, attendeePW,
233
+ # hasBeenForciblyEnded, running, startTime, endTime, participantCount, moderatorCount, and attendees.
234
+
235
+ def getMeetingInfo ( meetingID , modPW , URL , SALT ):
236
+ getMeetingInfo_url = getMeetingInfoURL (meetingID , modPW , URL , SALT )
237
+ xml = bbb_wrap_load_file ( getMeetingInfo_url )
238
+
239
+ if (xml ):
240
+ mapping = {}
241
+ response = xml .firstChild
242
+ for child in response .childNodes :
243
+
244
+ if ( child .hasChildNodes () ):
245
+ #Makes a dictionary for attendees inside mapping
246
+ if (child .tagName == "attendees" ):
247
+ attendees = {}
248
+ #Makes a dictionary for attendee inside attendees
249
+ for atnds in child .childNodes :
250
+ attendee = {}
251
+ #Adds the elements to the attendee dictionary
252
+ for atnd in atnds .childNodes :
253
+ if ( atnd .hasChildNodes () ):
254
+ attendee [atnd .tagName ] = atnd .firstChild .nodeValue
255
+ else :
256
+ attendee [atnd .tagName ] = None
257
+ #Updates the attendees dictionary with the attendee we just parsed
258
+ attendees [ attendee ["userID" ] ] = attendee
259
+
260
+ #Once completed parsing the attendees we add that dictionary to mapping
261
+ mapping [child .tagName ] = attendees
262
+ else :
263
+ mapping [child .tagName ] = child .firstChild .nodeValue
264
+ else :
265
+ mapping [child .tagName ] = None
266
+ return mapping
267
+
268
+ #if unable to reach the server
269
+ return None
270
+
271
+
272
+ #-----------------------------------------------getMeetings------------------------------------------------------
273
+ #
274
+ #This method calls getMeetings on the bigbluebutton server, then calls getMeetingInfo for each meeting and concatenates the result.
275
+ #
276
+ #@param URL -- the url of the bigbluebutton server
277
+ #@param SALT -- the security salt of the bigbluebutton server
278
+ #
279
+ #@return
280
+ # - None if unable to reach the bigbluebutton server
281
+ # - Dictionary containing the values of the xml packet
282
+ # - If the returncode == 'FAILED' it returns a dictionary containing a returncode, messagekey, and message.
283
+ # - If the returncode == 'SUCCESS' it returns a dictionary containing all the meetings. Each item meetingID, moderatorPW, attendeePW,
284
+ # hasBeenForciblyEnded, running, startTime, endTime, participantCount, moderatorCount, and attendees.
285
+
286
+ # - Null if the server is unreachable
287
+ # - If FAILED then returns an array containing a returncode, messageKey, message.
288
+ # - If SUCCESS then returns an array of all the meetings. Each element in the array is an array containing a meetingID,
289
+ # moderatorPW, attendeePW, hasBeenForciblyEnded, running.
290
+ #
291
+ def getMeetings ( URL , SALT ):
292
+ getMeetings_url = getMeetingsURL ( URL , SALT )
293
+ xml = bbb_wrap_load_file ( getMeetings_url )
294
+
295
+ if (xml ):
296
+ mapping = {}
297
+ response = xml .firstChild
298
+ for child in response .childNodes :
299
+
300
+ if ( child .hasChildNodes () ):
301
+
302
+ #Makes a dictionary for meetings inside mapping
303
+ if (child .tagName == "meetings" ):
304
+ meetings = {}
305
+
306
+ #Makes a dictionary for meeting inside meetings
307
+ for mtgs in child .childNodes :
308
+ meeting = {}
309
+
310
+ #Adds the elements to the meeting dictionary
311
+ for mtg in mtgs .childNodes :
312
+ if ( mtg .hasChildNodes () ):
313
+ meeting [mtg .tagName ] = mtg .firstChild .nodeValue
314
+ else :
315
+ meeting [mtg .tagName ] = None
316
+ #Updates the meetings dictionary with the meeting we just parsed
317
+ meetings [ meeting ["meetingID" ] ] = meeting
318
+ #Once completed parsing the meetings we add that dictionary to mapping
319
+ mapping [child .tagName ] = meetings
320
+
321
+ else :
322
+ mapping [child .tagName ] = child .firstChild .nodeValue
323
+ else :
324
+ mapping [child .tagName ] = None
325
+
326
+ return mapping
327
+
328
+ #if unable to reach the server
329
+ return None
330
+
331
+ #------------------------------------------------End Meeting------------------------------------
332
+ #
333
+ #This method calls end meeting on the specified meeting in the bigbluebutton server.
334
+ #
335
+ #@param meetingID -- the unique meeting identifier used to store the meeting in the bigbluebutton server
336
+ #@param modPW -- the moderator password of the meeting
337
+ #@param SALT -- the security salt of the bigbluebutton server
338
+ #@param URL -- the url of the bigbluebutton server
339
+ #
340
+ #@return
341
+ # - Null if the server is unreachable
342
+ # - A dictionary containing a returncode, messageKey, message.
343
+ #
344
+ def endMeeting ( meetingID , modPW , URL , SALT ):
345
+ endMeeting_url = endMeetingURL ( meetingID , modPW , URL , SALT )
346
+ xml = bbb_wrap_load_file ( endMeeting_url )
347
+
348
+ if (xml ):
349
+ return assign2Dict (xml )
350
+
351
+ #if unable to reach the server
352
+ return None
353
+
354
+ #------------------------------------------------isMeetingRunning------------------------------------
355
+ #
356
+ #This method check the BigBlueButton server to see if the meeting is running (i.e. there is someone in the meeting)
357
+ #
358
+ #@param meetingID -- the unique meeting identifier used to store the meeting in the bigbluebutton server
359
+ #@param SALT -- the security salt of the bigbluebutton server
360
+ #@param URL -- the url of the bigbluebutton server
361
+ #
362
+ #@return A boolean of true if the meeting is running and false if it is not running
363
+ #
364
+ def isMeetingRunning ( meetingID , URL , SALT ):
365
+ isMeetingRunning_url = isMeetingRunningURL ( meetingID , URL , SALT )
366
+ xml = bbb_wrap_load_file ( isMeetingRunning_url )
367
+
368
+ if (xml ):
369
+ return assign2Dict (xml )
370
+
371
+ #if unable to reach the server
372
+ return None
0 commit comments