diff --git a/main/img/icons/22/om_integration.png b/main/img/icons/22/om_integration.png
new file mode 100644
index 0000000000..f941effceb
Binary files /dev/null and b/main/img/icons/22/om_integration.png differ
diff --git a/main/img/icons/64/openmeetings.png b/main/img/icons/64/openmeetings.png
new file mode 100644
index 0000000000..b746bd6105
Binary files /dev/null and b/main/img/icons/64/openmeetings.png differ
diff --git a/main/img/icons/64/openmeetings_na.png b/main/img/icons/64/openmeetings_na.png
new file mode 100644
index 0000000000..5b6c0a0427
Binary files /dev/null and b/main/img/icons/64/openmeetings_na.png differ
diff --git a/plugin/openmeetings/config.php b/plugin/openmeetings/config.php
new file mode 100644
index 0000000000..957d9ed380
--- /dev/null
+++ b/plugin/openmeetings/config.php
@@ -0,0 +1,13 @@
+install();
\ No newline at end of file
diff --git a/plugin/openmeetings/lang/english.php b/plugin/openmeetings/lang/english.php
new file mode 100644
index 0000000000..930f54e77f
--- /dev/null
+++ b/plugin/openmeetings/lang/english.php
@@ -0,0 +1,54 @@
+
+ */
+
+//Needed in order to show the plugin title
+$strings['plugin_title'] = "OpenMeetings";
+$strings['plugin_comment'] = "Add a videoconference room in a Chamilo course using OpenMeetings";
+
+$strings['Videoconference'] = "Videoconference";
+$strings['MeetingOpened'] = "Meeting opened";
+$strings['MeetingClosed'] = "Meeting closed";
+$strings['MeetingClosedComment'] = "If you have asked for your sessions to be recorded, the recording will be available in the list below when it has been completely generated.";
+$strings['CloseMeeting'] = "Close meeting";
+
+$strings['VideoConferenceXCourseX'] = "Videoconference #%s course %s";
+$strings['VideoConferenceAddedToTheCalendar'] = "Videoconference added to the calendar";
+$strings['VideoConferenceAddedToTheLinkTool'] = "Videoconference added to the link tool";
+
+$strings['GoToTheVideoConference'] = "Go to the videoconference";
+
+$strings['Records'] = "Recording";
+$strings['Meeting'] = "Meeting";
+
+$strings['ViewRecord'] = "View recording";
+$strings['CopyToLinkTool'] = "Copy to link tool";
+
+$strings['EnterConference'] = "Enter the videoconference";
+$strings['RecordList'] = "Recording list";
+$strings['ServerIsNotRunning'] = "Videoconference server is not running";
+$strings['ServerIsNotConfigured'] = "Videoconference server is not configured";
+
+$strings['XUsersOnLine'] = "%s user(s) online";
+
+$strings['host'] = 'OpenMeetings host';
+$strings['host_help'] = 'This is the full address of your OpenMeeetings server interface. Might be http://localhost:5080/openmeetings, an IP address (e.g. http://192.168.13.54:5080/openmeetings) or a domain name (e.g. http://my.video.com:5080/openmeetings).';
+
+$strings['salt'] = 'OpenMeetings salt';
+$strings['salt_help'] = 'This is the security key of your OpenMeetings server, which will allow your server to authentify the Chamilo installation. Refer to the OpenMeetings documentation to locate it.';
+
+$strings['tool_enable'] = 'OpenMeetings videoconference tool enabled';
+$strings['tool_enable_help'] = 'Choose whether you want to enable the OpenMeetings videoconference tool. Once enabled, it will show as an additional course tool in all courses homepage, and teachers will be able to launch a conference at any time. Students will not be able to launch a conference, only join one. If you don\'t have an OpenMeetings server, please set one up or ask the Chamilo official providers for a quote. OpenMeetings is a free (as in freedom *and* beer), but its installation requires a set of technical skills that might not be immediately available to all. You can install it on your own or seek professional help to assist you or do it for you. This help, however, will generate a certain cost. In the pure logic of the free software, we offer you the tools to make your work easier and recommend professionals (the Chamilo Official Providers) that will be able to help you if this were too difficult.
';
+
+$strings['openmeetings_welcome_message'] = 'Welcome message';
+$strings['openmeetings_record_and_store'] = 'Record and store sessions';
+
+$strings['plugin_tool_openmeetings'] = 'Video';
+
+$strings['ThereAreNotRecordingsForTheMeetings'] = 'There are not recording for the meeting sessions';
+$strings['NoRecording'] = 'No recording';
+
diff --git a/plugin/openmeetings/lang/french.php b/plugin/openmeetings/lang/french.php
new file mode 100644
index 0000000000..8d2708dd46
--- /dev/null
+++ b/plugin/openmeetings/lang/french.php
@@ -0,0 +1,47 @@
+en installer un avant de poursuivre, ou demander un devis à l'un des fournisseurs officiels de Chamilo. OpenMeetings est un outil de logiciel libre (et gratuit), mais son installation pourrait présenter une certaine complexité et demander des compétences qui ne sont peut-être pas à la portée de tous. Vous pouvez l'installer vous-même à partir de la documentation (disponible publiquement) de OpenMeetings, ou recherchez un soutien professionnel. Ce soutien pourrait générer certains coûts (au moins le temps de la personne qui vous assiste dans l'opération). Dans le plus pur esprit du logiciel libre, nous vous fournissons les outils pour simplifier votre travail dans la mesure de nos possibilités, et nous vous recommandons des professionnels (les fournisseurs officiels de Chamilo) pour vous venir en aide au cas où ceux-ci seraient insuffisants.
";
+
+$strings['openmeetings_welcome_message'] = 'Message de bienvenue de OpenMeetings';
+$strings['openmeetings_record_and_store'] = 'Enregistrer les sessions de vidéoconférence';
+
+$strings['plugin_tool_openmeetings'] = 'Vidéo';
+
+$strings['ThereAreNotRecordingsForTheMeetings'] = 'Aucun enregistrement disponible';
+$strings['NoRecording'] = "Pas d'enregistrement";
+
diff --git a/plugin/openmeetings/lang/spanish.php b/plugin/openmeetings/lang/spanish.php
new file mode 100644
index 0000000000..7692aa729f
--- /dev/null
+++ b/plugin/openmeetings/lang/spanish.php
@@ -0,0 +1,50 @@
+configure uno antes de seguir, o pida una cotización a uno de los proveedores oficiales de Chamilo. OpenMeetings es una herramienta de software libre (y gratuita), pero su instalación requiere de competencias que quizás no sean inmediatamente disponibles para todos. Puede instalarla usted mismo o buscar ayuda profesional. Esta ayuda podría no obstante generar algunos costos (por lo menos el tiempo de la persona quien lo ayude). En el puro espíritu del software libre, le ofrecemos las herramientas para hacer su trabajo más simple, en la medida de nuestras posibilidades, y le recomendamos profesionales (los proveedores oficiales de Chamilo) para ayudarlo en caso esto fuera demasiado complicado.
';
+
+$strings['openmeetings_welcome_message'] = 'Mensaje de bienvenida de ';
+$strings['openmeetings_record_and_store'] = 'Grabar las sesiones de videoconferencia';
+
+$strings['plugin_tool_openmeetings'] = 'Video';
+
+$strings['ThereAreNotRecordingsForTheMeetings'] = 'No hay grabaciones de sesiones de videoconferencia';
+$strings['NoRecording'] = 'No hay grabación';
+
diff --git a/plugin/openmeetings/lib/openmeetings.class.php b/plugin/openmeetings/lib/openmeetings.class.php
new file mode 100644
index 0000000000..6b7d741bb7
--- /dev/null
+++ b/plugin/openmeetings/lib/openmeetings.class.php
@@ -0,0 +1,546 @@
+get('tool_enable');
+ $om_host = $plugin->get('host');
+ $om_user = $plugin->get('user');
+ $om_pass = $plugin->get('pass');
+ global $_configuration;
+ $accessUrl = api_get_access_url($_configuration['access_url']);
+ $this->externalType = substr($accessUrl['url'],strpos($accessUrl['url'],'://')+3,-1);
+ if (strcmp($this->externalType,'localhost') == 0) {
+ $this->externalType = substr(api_get_path(WEB_PATH),strpos(api_get_path(WEB_PATH),'://')+3,-1);
+ }
+ $this->externalType = 'chamilolms.'.$this->externalType;
+
+ $this->table = \Database::get_main_table('plugin_openmeetings');
+
+ if ($om_plugin) {
+ $user_info = api_get_user_info();
+ $this->user_complete_name = $user_info['complete_name'];
+ $this->user = $om_user;
+ $this->pass = $om_pass;
+ $this->url = $om_host;
+
+ // Setting OM api
+ define('CONFIG_OPENMEETINGS_USER', $this->user);
+ define('CONFIG_OPENMEETINGS_PASS', $this->pass);
+ define('CONFIG_OPENMEETINGS_SERVER_URL', $this->url);
+
+ $this->gateway = new \OpenMeetingsGateway($this->url, $this->user, $this->pass);
+ $this->plugin_enabled = $om_plugin;
+ // The room has a name composed of C + course ID + '-' + session ID
+ $this->chamiloCourseId = api_get_course_int_id();
+ $this->chamiloSessionId = api_get_session_id();
+ $this->roomName = 'C'.$this->chamiloCourseId.'-'.$this->chamiloSessionId;
+ $return = $this->gateway->loginUser();
+ if ($return == 0) {
+ $msg = 'Could not initiate session with server through OpenMeetingsGateway::loginUser()';
+ error_log(__FILE__.'+'.__LINE__.': '.$msg);
+ die($msg);
+ }
+ $this->sessionId = $this->gateway->sessionId;
+ }
+ }
+ /**
+ * Checks whether a user is teacher in the current course
+ * @return bool True if the user can be considered a teacher in this course, false otherwise
+ */
+ function isTeacher()
+ {
+ return api_is_course_admin() || api_is_coach() || api_is_platform_admin();
+ }
+ /**
+ * Login the user with OM Server. This generates a session ID that is
+ * specific to the current user, but that does not require specific user data
+ *
+ * It is similar to opening a PHP session. In fact, the session ID is kept
+ * inside the $_SESSION['openmeetings_session'] session variable
+ * @return bool True if the user is correct and false when is incorrect
+ * @deprecated loginUser now called at object instanciation
+ */
+ /**
+ function loginUser()
+ {
+ try {
+ //Verifying if there is already an active session
+ if (empty($_SESSION['openmeetings_session'])) {
+ // Login user returns either 0 or >0, depending on the results
+ // Technically, as long as the SOAP user has been configured in OpenMeetings and OpenMeetings is on, this should always succeed.
+ if ($this->gateway->loginUser()) {
+ $this->sessionId = $_SESSION['openmeetings_session'] = $this->gateway->session_id;
+ return true;
+ } else {
+ error_log('loginUser did not succeed');
+ return false;
+ }
+ } else {
+ $this->sessionId = $_SESSION['openmeetings_session'];
+ return true;
+ }
+ } catch (SoapFault $e) {
+ error_log(__FILE__.'+'.__LINE__.' Warning: We have detected some problems. Fault: '.$e->faultstring);
+ return false;
+ }
+ }
+ */
+ /*
+ * Creating a Room for the meeting
+ * @return bool True if the user is correct and false when is incorrect
+ */
+ function createMeeting($params)
+ {
+ //$id = \Database::insert($this->table, $params);
+ // First, try to see if there is an active room for this course and session
+ $roomId = null;
+ $meetingData = \Database::select('*', $this->table, array('where' => array('c_id = ?' => $this->chamiloCourseId, ' AND session_id = ? ' => $this->chamiloSessionId)), 'first');
+ if ($meetingData != false && count($meetingData) > 0) {
+ //error_log(print_r($meetingData,1));
+ //error_log('Found previous room reference - reusing');
+ // There has been a room in the past for this course. It should
+ // still be on the server, so update (instead of creating a new one)
+ // This fills the following attributes: status, name, comment, chamiloCourseId, chamiloSessionId
+ $room = new Room();
+ $room->loadRoomId($meetingData['room_id']);
+ $roomArray = (array)$room;
+ $roomArray['SID'] = $this->sessionId;
+ $roomId = $this->gateway->updateRoomWithModeration($room);
+ if ($roomId != $meetingData['room_id']) {
+ $msg = 'Something went wrong: the updated room ID ('.$roomId.') is not the same as the one we had ('.$meetingData['room_id'].')';
+ error_log($msg);
+ die($msg);
+ }
+
+ } else {
+ //error_log('Found no previous room - creating');
+ $room = new Room();
+ $room->SID = $this->sessionId;
+ $room->name = $this->roomName;
+ $room->roomtypes_id = $room->roomtypes_id;
+ $room->comment = urlencode(get_lang('Course').': ' . $params['meeting_name'] . ' Plugin for Chamilo');
+ $room->numberOfPartizipants = $room->numberOfPartizipants;
+ $room->ispublic = $room->getString('isPublic');
+ $room->appointment = $room->getString('appointment');
+ $room->isDemoRoom = $room->getString('isDemoRoom');
+ $room->demoTime = $room->demoTime;
+ $room->isModeratedRoom = $room->getString('isModeratedRoom');
+ $roomId = $this->gateway->createRoomWithModAndType($room);
+ }
+
+ if (!empty($roomId)) {
+ /*
+ // Find the biggest room_id so far, and create a new one
+ if (empty($roomId)) {
+ $roomData = \Database::select('MAX(room_id) as room_id', $this->table, array(), 'first');
+ $roomId = $roomData['room_id'] + 1;
+ }*/
+
+ $params['status'] = '1';
+ $params['meeting_name'] = $room->name;
+ $params['created_at'] = api_get_utc_datetime();
+ $params['room_id'] = $roomId;
+ $params['c_id'] = api_get_course_int_id();
+ $params['session_id'] = api_get_session_id();
+
+ $id = \Database::insert($this->table, $params);
+
+ $this->joinMeeting($id);
+ } else {
+ return -1;
+ }
+ }
+ /**
+ * Returns a meeting "join" URL
+ * @param string The name of the meeting (usually the course code)
+ * @return mixed The URL to join the meeting, or false on error
+ * @todo implement moderator pass
+ * @assert ('') === false
+ * @assert ('abcdefghijklmnopqrstuvwxyzabcdefghijklmno') === false
+ */
+ function joinMeeting($meetingId)
+ {
+ if (empty($meetingId)) {
+ return false;
+ }
+ $meetingData = \Database::select('*', $this->table, array('where' => array('id = ? AND status = 1 ' => $meetingId)), 'first');
+
+ if (empty($meetingData)) {
+ if ($this->debug) error_log("meeting does not exist: $meetingId ");
+ return false;
+ }
+ $params = array( 'room_id' => $meetingData['room_id'] );
+
+ $returnVal = $this->setUserObjectAndGenerateRoomHashByURLAndRecFlag( $params );
+ //$urlWithoutProtocol = str_replace("http://", CONFIG_OPENMEETINGS_SERVER_URL);
+ //$imgWithoutProtocol = str_replace("http://", $_SESSION['_user']['avatar'] );
+
+ $iframe = $this->url . "/?" .
+ "secureHash=" . $returnVal;
+
+ printf("", $iframe, "100%", 640);
+ }
+ /**
+ * Checks if the videoconference server is running.
+ * Function currently disabled (always returns 1)
+ * @return bool True if server is running, false otherwise
+ * @assert () === false
+ */
+ function isServerRunning()
+ {
+ // Always return true for now as this requires the openmeetings object
+ // to have been instanciated and this includes a loginUser() which
+ // connects to the server
+ return true;
+ }
+ /**
+ * Gets the password for a specific meeting for the current user
+ * @return string A moderator password if user is teacher, or the course code otherwise
+ */
+ function getMeetingUserPassword()
+ {
+ if ($this->isTeacher()) {
+ return $this->getMeetingModerationPassword();
+ } else {
+ return api_get_course_id();
+ }
+ }
+ /**
+ * Generated a moderator password for the meeting
+ * @return string A password for the moderation of the video conference
+ */
+ function getMeetingModerationPassword()
+ {
+ return api_get_course_id().'mod';
+ }
+ /**
+ * Get information about the given meeting
+ * @param array ...?
+ * @return mixed Array of information on success, false on error
+ * @assert (array()) === false
+ */
+ function getMeetingInfo($params)
+ {
+ try {
+ $result = $this->api->getMeetingInfoArray($params);
+ if ($result == null) {
+ if ($this->debug) error_log(__FILE__.'+'.__LINE__." Failed to get any response. Maybe we can't contact the OpenMeetings server.");
+ } else {
+ return $result;
+ }
+ } catch (Exception $e) {
+ if ($this->debug) error_log(__FILE__.'+'.__LINE__.' Caught exception: ', $e->getMessage(), "\n");
+ }
+ return false;
+ }
+
+ /**
+ * @param array $params Array of parameters
+ * @return mixed
+ */
+ function setUserObjectAndGenerateRecordingHashByURL( $params )
+ {
+ $username = $_SESSION['_user']['username'];
+ $firstname = $_SESSION['_user']['firstname'];
+ $lastname = $_SESSION['_user']['lastname'];
+ $userId = $_SESSION['_user']['user_id'];
+ $systemType = 'chamilo';
+ $room_id = $params['room_id'];
+
+ $urlWsdl = $this->url . "/services/UserService?wsdl";
+ $omServices = new \SoapClient( $urlWsdl );
+ $objRec = new User();
+
+ $objRec->SID = $this->sessionId;
+ $objRec->username = $username;
+ $objRec->firstname = $firstname;
+ $objRec->lastname = $lastname;
+ $objRec->externalUserId = $userId;
+ $objRec->externalUserType = $systemType;
+ $objRec->recording_id = $recording_id;
+
+ $orFn = $omServices->setUserObjectAndGenerateRecordingHashByURL( $objRec );
+ return $orFn->return;
+ }
+
+ /**
+ * @param Array $params Array of parameters
+ * @return mixed
+ */
+ function setUserObjectAndGenerateRoomHashByURLAndRecFlag( $params )
+ {
+
+ $username = $_SESSION['_user']['username'];
+ $firstname = $_SESSION['_user']['firstname'];
+ $lastname = $_SESSION['_user']['lastname'];
+ $profilePictureUrl = $_SESSION['_user']['avatar'];
+ $email = $_SESSION['_user']['mail'];
+ $userId = $_SESSION['_user']['user_id'];
+ $systemType = 'Chamilo';
+ $room_id = $params['room_id'];
+ $becomeModerator = ( $this->isTeacher() ? 1 : 0 );
+ $allowRecording = 1; //Provisional
+
+ $urlWsdl = $this->url . "/services/UserService?wsdl";
+ $omServices = new \SoapClient( $urlWsdl );
+ $objRec = new User();
+
+ $objRec->SID = $this->sessionId;
+ $objRec->username = $username;
+ $objRec->firstname = $firstname;
+ $objRec->lastname = $lastname;
+ $objRec->profilePictureUrl = $profilePictureUrl;
+ $objRec->email = $email;
+ $objRec->externalUserId = $userId;
+ $objRec->externalUserType = $systemType;
+ $objRec->room_id = $room_id;
+ $objRec->becomeModeratorAsInt = $becomeModerator;
+ $objRec->showAudioVideoTestAsInt = 1;
+ $objRec->allowRecording = $allowRecording;
+
+ $rcFn = $omServices->setUserObjectAndGenerateRoomHashByURLAndRecFlag( $objRec );
+
+ return $rcFn->return;
+ }
+
+ /**
+ * Gets all the course meetings saved in the plugin_openmeetings table
+ * @return array Array of current open meeting rooms
+ */
+ function getCourseMeetings()
+ {
+ $newMeetingsList = array();
+ $openMeeting = false;
+ $item = array();
+ $meetingsList = \Database::select('*', $this->table, array('where' => array('c_id = ? ' => api_get_course_int_id(), ' AND session_id = ? ' => api_get_session_id())));
+
+ //error_log(__FILE__.'+'.__LINE__.' Meetings found: '.print_r($meetingsList,1));
+
+ $urlWsdl = $this->url . "/services/RoomService?wsdl";
+ $omServices = new \SoapClient($urlWsdl);
+ $room = new Room();
+ /*
+ try {
+ $rooms = $this->gateway->getRoomsWithCurrentUsersByType();
+ //$rooms = $omServices->getRoomsPublic(array(
+ //'SID' => $this->sessionId,
+ //'start' => 0,
+ //'max' => 10,
+ //'orderby' => 'name',
+ //'asc' => 'true',
+ //'externalRoomType' => 'chamilo',
+ //'roomtypes_id' => 'chamilo',
+ //)
+ //);
+ } catch (SoapFault $e) {
+ error_log(__FILE__.'+'.__LINE__.' '.$e->faultstring);
+ //error_log($rooms->getDebug());
+ return false;
+ }
+ */
+ $room->SID = $this->sessionId;
+ //error_log(__FILE__.'+'.__LINE__.' Meetings found: '.print_r($room->SID,1));
+
+ foreach ($meetingsList as $meetingDb) {
+ //$room->rooms_id = $meetingDb['room_id'];
+ //error_log(__FILE__.'+'.__LINE__.' Meetings found: '.print_r($meetingDb['room_id'],1));
+ $remoteMeeting = array();
+ $meetingDb['created_at'] = api_get_local_time($meetingDb['created_at']);
+ $meetingDb['closed_at'] = (!empty($meetingDb['closed_at'])?api_get_local_time($meetingDb['closed_at']):'');
+ // Fixed value for now
+ $meetingDb['participantCount'] = 40;
+
+ // The following code is currently commented because the web service
+ // says this is not allowed by the SOAP user.
+ /*
+ try {
+ // Get the conference room object from OpenMeetings server - requires SID and rooms_id to be defined
+ $objRoomId = $this->gateway->getRoomById($meetingDb['room_id']);
+ if (empty($objRoomId->return)) {
+ error_log(__FILE__.'+'.__LINE__.' Emptyyyyy ');
+ //\Database::delete($this->table, "id = {$meetingDb['id']}");
+ // Don't delete expired rooms, just mark as closed
+ \Database::update($this->table, array('status' => 0, 'closed_at' => api_get_utc_datetime()), array('id = ? ' => $meetingDb['id']));
+ continue;
+ }
+ //$objCurUs = $omServices->getRoomWithCurrentUsersById($objCurrentUsers);
+ } catch (SoapFault $e) {
+ error_log(__FILE__.'+'.__LINE__.' '.$e->faultstring);
+ exit;
+ }
+ //if( empty($objCurUs->returnMeetingID) ) continue;
+
+ $current_room = array(
+ 'roomtype' => $objRoomId->return->roomtype->roomtypes_id,
+ 'meetingName' => $objRoomId->return->name,
+ 'meetingId' => $objRoomId->return->meetingID,
+ 'createTime' => $objRoomId->return->rooms_id,
+ 'showMicrophoneStatus' => $objRoomId->return->showMicrophoneStatus,
+ 'attendeePw' => $objRoomId->return->attendeePW,
+ 'moderatorPw' => $objRoomId->return->moderators,
+ 'isClosed' => $objRoomId->return->isClosed,
+ 'allowRecording' => $objRoomId->return->allowRecording,
+ 'startTime' => $objRoomId->return->startTime,
+ 'endTime' => $objRoomId->return->updatetime,
+ 'participantCount' => count($objRoomId->return->currentusers),
+ 'maxUsers' => $objRoomId->return->numberOfPartizipants,
+ 'moderatorCount' => count($objRoomId->return->moderators)
+ );
+ // Then interate through attendee results and return them as part of the array:
+ if (!empty($objRoomId->return->currentusers)) {
+ foreach ($objRoomId->return->currentusers as $a)
+ $current_room[] = array(
+ 'userId' => $a->username,
+ 'fullName' => $a->firstname . " " . $a->lastname,
+ 'isMod' => $a->isMod
+ );
+ }
+
+ $remoteMeeting = $current_room;
+ */
+
+ if (empty( $remoteMeeting )) {
+ /*
+ error_log(__FILE__.'+'.__LINE__.' Empty remote Meeting for now');
+ if ($meetingDb['status'] == 1 && $this->isTeacher()) {
+ $this->endMeeting($meetingDb['id']);
+ }
+ */
+ } else {
+ $remoteMeeting['add_to_calendar_url'] = api_get_self().'?action=add_to_calendar&id='.$meetingDb['id'].'&start='.api_strtotime($meetingDb['startTime']);
+ }
+ $remoteMeeting['end_url'] = api_get_self().'?action=end&id='.$meetingDb['id'];
+
+ //$record_array = array();
+
+// if ($meetingDb['record'] == 1) {
+// $recordingParams = array(
+// 'meetingId' => $meetingDb['id'], //-- OPTIONAL - comma separate if multiple ids
+// );
+//
+// $records = $this->api->getRecordingsWithXmlResponseArray($recordingParams);
+// if (!empty($records)) {
+// $count = 1;
+// if (isset($records['message']) && !empty($records['message'])) {
+// if ($records['messageKey'] == 'noRecordings') {
+// $record_array[] = get_lang('NoRecording');
+// } else {
+// //$record_array[] = $records['message'];
+// }
+// } else {
+// foreach ($records as $record) {
+// if (is_array($record) && isset($record['recordId'])) {
+// $url = Display::url(get_lang('ViewRecord'), $record['playbackFormatUrl'], array('target' => '_blank'));
+// if ($this->is_teacher()) {
+// $url .= Display::url(Display::return_icon('link.gif',get_lang('CopyToLinkTool')), api_get_self().'?action=copy_record_to_link_tool&id='.$meetingDb['id'].'&record_id='.$record['recordId']);
+// $url .= Display::url(Display::return_icon('agenda.png',get_lang('AddToCalendar')), api_get_self().'?action=add_to_calendar&id='.$meetingDb['id'].'&start='.api_strtotime($meetingDb['created_at']).'&url='.$record['playbackFormatUrl']);
+// $url .= Display::url(Display::return_icon('delete.png',get_lang('Delete')), api_get_self().'?action=delete_record&id='.$record['recordId']);
+// }
+// //$url .= api_get_self().'?action=publish&id='.$record['recordID'];
+// $count++;
+// $record_array[] = $url;
+// } else {
+//
+// }
+// }
+// }
+// }
+// //var_dump($record_array);
+// $item['show_links'] = implode('
', $record_array);
+//
+// }
+//
+ //$item['created_at'] = api_convert_and_format_date($meetingDb['created_at']);
+// //created_at
+//
+// $item['publish_url'] = api_get_self().'?action=publish&id='.$meetingDb['id'];
+// $item['unpublish_url'] = api_get_self().'?action=unpublish&id='.$meetingDb['id'];
+//
+ //if ($meetingDb['status'] == 1) {
+// $joinParams = array(
+// 'meetingId' => $meetingDb['id'], //-- REQUIRED - A unique id for the meeting
+// 'username' => $this->user_complete_name, //-- REQUIRED - The name that will display for the user in the meeting
+// 'password' => $pass, //-- REQUIRED - The attendee or moderator password, depending on what's passed here
+// 'createTime' => '', //-- OPTIONAL - string. Leave blank ('') unless you set this correctly.
+// 'userID' => '', // -- OPTIONAL - string
+// 'webVoiceConf' => '' // -- OPTIONAL - string
+// );
+// $returnVal = $this->setUserObjectAndGenerateRoomHashByURLAndRecFlag( array('room_id' => $meetingDb['id']) );
+// $joinUrl = CONFIG_OPENMEETINGS_SERVER_URL . "?" .
+// "secureHash=" . $returnVal;
+//
+// $item['go_url'] = $joinUrl;
+ //}
+ $item = array_merge($item, $meetingDb, $remoteMeeting);
+ //error_log(__FILE__.'+'.__LINE__.' Item: '.print_r($item,1));
+ $newMeetingsList[] = $item;
+ } //end foreach $meetingsList
+ return $newMeetingsList;
+ }
+
+ /**
+ * Send a command to the OpenMeetings server to close the meeting
+ * @param $meetingId
+ * @return int
+ */
+ function endMeeting($meetingId)
+ {
+ try {
+ $urlWsdl = $this->url . "/services/RoomService?wsdl";
+ $ws = new \SoapClient( $urlWsdl );
+ $room = new Room($meetingId);
+ $room->SID = $this->sessionId;
+ $room->room_id = intval($meetingId);
+ $room->status = false;
+ $roomClosed = $ws->closeRoom($room);
+ if ($roomClosed > 0) {
+ //error_log(__FILE__.'+'.__LINE__.' Closing returned '.print_r($roomClosed,1));
+ \Database::update($this->table, array('status' => 0, 'closed_at' => api_get_utc_datetime()), array('id = ? ' => $meetingId));
+ }
+ //error_log(__FILE__.'+'.__LINE__.' Finished closing');
+ } catch (SoapFault $e) {
+ error_log(__FILE__.'+'.__LINE__.' Warning: We have detected some problems: Fault: '.$e->faultstring);
+ exit;
+ return -1;
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugin/openmeetings/lib/openmeetings_api.php b/plugin/openmeetings/lib/openmeetings_api.php
new file mode 100644
index 0000000000..f3f395ec1b
--- /dev/null
+++ b/plugin/openmeetings/lib/openmeetings_api.php
@@ -0,0 +1,26 @@
+_user = CONFIG_OPENMEETINGS_USER;
+ $this->_pass = CONFIG_OPENMEETINGS_PASS;
+ $this->_serverBaseUrl = CONFIG_OPENMEETINGS_SERVER_URL;
+ }
+
+
+}
diff --git a/plugin/openmeetings/lib/openmeetings_gateway.php b/plugin/openmeetings/lib/openmeetings_gateway.php
new file mode 100644
index 0000000000..e40561b90a
--- /dev/null
+++ b/plugin/openmeetings/lib/openmeetings_gateway.php
@@ -0,0 +1,404 @@
+_user = urlencode($user);
+ $this->_pass = urlencode($pass);
+ $this->_url = $host;
+ if (substr($this->_url, -1, 1) == '/') {
+ $this->_url = substr($this->_url, 0, -1);
+ }
+ $this->rest = new OpenMeetingsRestService();
+ $err = $this->rest->getError();
+ if ($err) {
+ error_log('Constructor error: ' . $err);
+ error_log('Debug: ' . $this->rest->getDebug());;
+ exit();
+ }
+
+ }
+
+ function getRestUrl($name)
+ {
+ return $this->getUrl() . "/services/" . $name . "/";
+ }
+
+ function getUrl()
+ {
+ return $this->_url;
+ }
+
+ function var_to_str($in)
+ {
+ if (is_bool($in)) {
+ return $in ? "true" : "false";
+ } else {
+ return $in;
+ }
+ }
+
+ /**
+ * TODO: Get Error Service and show detailed Error Message
+ */
+ function loginUser()
+ {
+ $returnValue = 0;
+ $response = $this->rest->call($this->getRestUrl("UserService") . "getSession", "session_id");
+
+ if ($this->rest->getError()) {
+ error_log('Fault (Expect - The request contains an invalid SOAP body) '.print_r($response,1));
+
+ } else {
+ $err = $this->rest->getError();
+ if ($err) {
+ error_log('Error: ' . $err);
+ } else {
+ //error_log('getSession returned '.$response. ' - Storing as sessionId');
+ $this->sessionId = $response;
+
+ $url = $this->getRestUrl("UserService")
+ . "loginUser?"
+ . "SID=" . $this->sessionId
+ . "&username=" . $this->_user
+ . "&userpass=" . $this->_pass;
+ $result = $this->rest->call($url);
+ //error_log(__FILE__.'+'.__LINE__.': '.$url);
+ if ($this->rest->getError()) {
+ error_log('Fault (Expect - The request contains an invalid SOAP body) '.print_r($result,1));
+ } else {
+ $err = $this->rest->getError();
+ if ($err) {
+ error_log('Error '. $err);
+ } else {
+ $returnValue = $result;
+ }
+ }
+ }
+ }
+
+ if ($returnValue > 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ function updateRoomWithModeration($room)
+ {
+ $err = $this->rest->getError();
+ if ($err) {
+ error_log('Constructor error: ' . $err);
+ error_log('Debug: ' . $this->rest->getDebug());
+ exit();
+ }
+
+ $isModeratedRoom = false;
+ if ($room->isModeratedRoom == 1) {
+ $isModeratedRoom = true;
+ }
+
+ $url = $this->getRestUrl($this->getRestUrl("RoomService")
+ . "updateRoomWithModeration?SID=" . $this->sessionId
+ . "&room_id=" . $room->room_id
+ . "&name=" . urlencode($room->name)
+ . "&roomtypes_id=" . $room->roomtypes_id
+ . "&comment=" . $room->comment
+ . "&numberOfPartizipants=" . $room->numberOfPartizipants
+ . "&ispublic=false"
+ . "&appointment=false"
+ . "&isDemoRoom=false"
+ . "&demoTime=0"
+ . "&isModeratedRoom=" . $this->var_to_str($isModeratedRoom));
+ //error_log($url);
+ $result = $this->rest->call($url);
+
+ if ($result->fault) {
+ error_log('Fault (Expect - The request contains an invalid SOAP body) '.print_r($result,1));
+ } else {
+ $err = $this->rest->getError();
+ if ($err) {
+ error_log('Error: ' . $err);
+ } else {
+ // echo '
'; print_r($result["return"]); echo ''; + //error_log('Room updated successfully '.print_r($result,1)); + return $result; + } + } + return - 1; + } + + /* + * public String setUserObjectAndGenerateRecordingHashByURL(String SID, String username, String firstname, String lastname, Long externalUserId, String externalUserType, Long recording_id) + */ + function setUserObjectAndGenerateRecordingHashByURL($username, $firstname, $lastname, $userId, $systemType, $recording_id) + { + $result = $this->rest->call($this->getRestUrl("UserService") + . 'setUserObjectAndGenerateRecordingHashByURL?' + . 'SID=' . $this->sessionId + . '&username=' . urlencode($username) + . '&firstname=' . urlencode($firstname) + . '&lastname=' . urlencode($lastname) + . '&externalUserId=' . $userId + . '&externalUserType=' . urlencode($systemType) + . '&recording_id=' . $recording_id, 'return'); + + if ($result->fault) { + error_log('Fault (Expect - The request contains an invalid SOAP body) '.print_r($result,1)); + } else { + $err = $this->rest->getError(); + if ($err) { + error_log('Error: '.$err); + } else { + return $result; + } + } + return - 1; + } + function setUserObjectAndGenerateRoomHashByURLAndRecFlag($username, $firstname, $lastname, $profilePictureUrl, $email, $userId, $systemType, $room_id, $becomeModerator, $allowRecording) + { + $err = $this->rest->getError(); + if ($err) { + error_log('Constructor error: ' . $err); + error_log('Debug: ' . $this->rest->getDebug());; + exit(); + } + + $result = $this->rest->call($this->getRestUrl("UserService") + . "setUserObjectAndGenerateRoomHashByURLAndRecFlag?" + . "SID=" . $this->sessionId + . "&username=" . urlencode($username) + . "&firstname=" . urlencode($firstname) + . "&lastname=" . urlencode($lastname) + . "&profilePictureUrl=" . urlencode($profilePictureUrl) + . "&email=" . urlencode($email) + . "&externalUserId=" . urlencode($userId) + . "&externalUserType=" . urlencode($systemType) + . "&room_id=" . urlencode($room_id) + . "&becomeModeratorAsInt=" . $becomeModerator + . "&showAudioVideoTestAsInt=1" + . "&allowRecording=" . $this->var_to_str($allowRecording)); + + if ($result->fault) { + error_log('Fault (Expect - The request contains an invalid SOAP body) '.print_r($result,1)); + } else { + $err = $this->rest->getError(); + if ($err) { + error_log('Error: '.$err); + } else { + // echo '
'; print_r($result["return"]); echo ''; + return $result; + } + } + return - 1; + } + function deleteRoom($openmeetings) + { + $err = $this->rest->getError(); + if ($err) { + error_log('Constructor error: ' . $err); + error_log('Debug: ' . $this->rest->getDebug());; + exit(); + } + + $result = $this->rest->call($this->getRestUrl("RoomService") . "deleteRoom?SID=" . $this->sessionId + . "&rooms_id=" . $openmeetings->room_id); + + if ($result->fault) { + error_log('Fault (Expect - The request contains an invalid SOAP body) '.print_r($result,1)); + } else { + $err = $this->rest->getError(); + if ($err) { + error_log('Error: '.$err); + } else { + // echo '
'; print_r($result["return"]); echo ''; + // return $result["return"]; + return $result; + } + } + return - 1; + } + + /** + * Generate a new room hash for entering a conference room + */ + function setUserObjectAndGenerateRoomHash($username, $firstname, $lastname, $profilePictureUrl, $email, $externalUserId, $externalUserType, $room_id, $becomeModeratorAsInt, $showAudioVideoTestAsInt) + { + $result = $this->rest->call($this->getRestUrl("UserService") + . "setUserObjectAndGenerateRoomHash?" + . "SID=" . $this->sessionId + . "&username=" . urlencode($username) + . "&firstname=" . urlencode($firstname) + . "&lastname=" . urlencode($lastname) + . "&profilePictureUrl=" . urlencode($profilePictureUrl) + . "&email=" . urlencode($email) + . "&externalUserId=" . urlencode($externalUserId) + . "&externalUserType=" . urlencode($externalUserType) + . "&room_id=" . $room_id + . "&becomeModeratorAsInt=" . $becomeModeratorAsInt + . "&showAudioVideoTestAsInt=" . $showAudioVideoTestAsInt); + + if ($result->getError()) { + error_log('Fault (Expect - The request contains an invalid SOAP body) '.print_r($result,1)); + } else { + $err = $this->rest->getError(); + if ($err) { + error_log('Error: '.$err); + } else { + // echo '
'; print_r($result["return"]); echo ''; + return $result; + } + } + return - 1; + } + + /** + * Create a new conference room + */ + function createRoomWithModAndType($room) + { + $url = $this->getRestUrl("RoomService") + . 'addRoomWithModerationAndExternalType?' + . 'SID=' . $room->SID + . '&name=' . $room->roomname + . '&roomtypes_id=' . $room->roomtypes_id + . '&comment='. $room->comment + . '&numberOfPartizipants=' . $room->numberOfPartizipants + . '&ispublic=' . $room->ispublic + . '&appointment=' . $room->appointment + . '&isDemoRoom=' . $room->isDemoRoom + . '&demoTime=' . $room->demoTime + . '&isModeratedRoom=' . $room->isModeratedRoom + . '&externalRoomType=' . $room->externalRoomType; + //error_log($url); + $result = $this->rest->call($url); + + if ($this->rest->fault) { + error_log('Fault (Expect - The request contains an invalid SOAP body) '.print_r($result,1)); + } else { + $err = $this->rest->getError(); + if ($err) { + error_log('Error: '.$err); + } else { + //error_log('Creation of a new room succeeded: ID '.print_r($result,1)); + return $result; + } + } + return - 1; + } + + /** + * Gets the list of open rooms of type "Chamilo" + * @param string $type The type of external system connecting to OpenMeetings + */ + public function getRoomsWithCurrentUsersByType($type = 'chamilolms') + { + //$this->loginUser(); + if (empty($this->sessionId)) { + return false; + } + + $url = $this->getRestUrl("RoomService") . "getRoomsWithCurrentUsersByListAndType?SID=" . $this->sessionId + . "&start=1&max=1000&orderby=name&asc=true&externalRoomType=chamilolms"; + //$url = $this->getRestUrl("RoomService") + // . "getRoomTypes?" + // . "SID=" . $this->sessionId; + //$url = $this->getRestUrl('JabberService') . 'getAvailableRooms?SID=' . $this->sessionId; + error_log(__FILE__.'+'.__LINE__.' Calling WS: '.$url); + $result = $this->rest->call($url, "return"); + $rooms = array(); + foreach ($result as $room) { + error_log(__FILE__.'+'.__LINE__.': one room found on remote: '.print_r($room,1)); + if ($room['externalRoomType'] == $type && count($room['currentusers']) > 0 ) { + $rooms[] = $room; + } + } + return $result; + } + + /** + * Gets details of a remote room by room ID + * @param int $roomId The ID of the room, as of plugin_openmeetings.room_id + * @return mixed Room object + */ + public function getRoomById($roomId = 0) + { + //$this->loginUser(); + if (empty($this->sessionId) or empty($roomId)) { + return false; + } + $roomId = intval($roomId); + + $url = $this->getRestUrl("RoomService") + . "getRoomById?" + . "SID=" . $this->sessionId + . "&rooms_id=".$roomId; + //error_log(__FILE__.'+'.__LINE__.' Calling WS: '.$url); + $result = $this->rest->call($url, "return"); + return $result; + } + + /** + * Get list of available recordings made by this instance + */ + function getRecordingsByExternalRooms() + { + $url = $this->getRestUrl("RoomService") + . "getFlvRecordingByExternalRoomType?" + . "SID=" . $this->sessionId + . "&externalRoomType=" . urlencode($this->config["moduleKey"]); + + $result = $this->rest->call($url, "return"); + + return $result; + } + + /** + * Get list of available recordings made by user + */ + function getRecordingsByExternalUser($id) + { + $url = $this->getRestUrl("RoomService") + . "getFlvRecordingByExternalUserId?" + . "SID=" . $this->sessionId + . "&externalUserId=" . $id; + + $result = $this->rest->call($url, "return"); + + return $result; + } +} diff --git a/plugin/openmeetings/lib/openmeetings_plugin.class.php b/plugin/openmeetings/lib/openmeetings_plugin.class.php new file mode 100644 index 0000000000..ac536bf62c --- /dev/null +++ b/plugin/openmeetings/lib/openmeetings_plugin.class.php @@ -0,0 +1,86 @@ + 'openmeetings_record_and_store', 'type' => 'checkbox') + ); + + static function create() + { + static $result = null; + return $result ? $result : $result = new self(); + } + + protected function __construct() + { + parent::__construct('2.0', 'Francis Gonzales', array('tool_enable' => 'boolean', 'host' =>'text', 'user' => 'text', 'pass' => 'text')); + } + + function install() + { + $table = Database::get_main_table('plugin_openmeetings'); + // id is the internal unique ID (keeps track of historical sessions + // status is 0 for closed, 1 for open (available) + // room_id is a reference to the meeting ID on the OpenMeetings server. + // Any c_id + session_id occurence gets a unique new meeting ID to avoid issues with the number of rooms, as indicated in https://issues.apache.org/jira/browse/OPENMEETINGS-802#comment-13860340 + $sql = "CREATE TABLE IF NOT EXISTS $table ( + id INT unsigned NOT NULL auto_increment PRIMARY KEY, + c_id INT unsigned NOT NULL DEFAULT 0, + session_id INT unsigned NOT NULL DEFAULT 0, + room_id INT unsigned NOT NULL DEFAULT 0, + meeting_name VARCHAR(255) NOT NULL DEFAULT '', + attendee_pw VARCHAR(255) NOT NULL DEFAULT '', + moderator_pw VARCHAR(255) NOT NULL DEFAULT '', + record INT NOT NULL DEFAULT 0, + status INT NOT NULL DEFAULT 0, + created_at DATETIME NOT NULL, + closed_at DATETIME, + calendar_id INT DEFAULT 0, + welcome_msg TEXT NOT NULL DEFAULT '')"; + Database::query($sql); + + //Installing course settings + $this->install_course_fields_in_all_courses(); + } + + function uninstall() + { + $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT); + $t_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS); + $t_tool = Database::get_course_table(TABLE_TOOL_LIST); + + //New settings + + $sql = "DELETE FROM $t_settings WHERE variable = 'openmeetings_tool_enable'"; + Database::query($sql); + $sql = "DELETE FROM $t_settings WHERE variable = 'openmeetings_pass'"; + Database::query($sql); + $sql = "DELETE FROM $t_settings WHERE variable = 'openmeetings_user'"; + Database::query($sql); + $sql = "DELETE FROM $t_settings WHERE variable = 'openmeetings_host'"; + Database::query($sql); + + //Old settings deleting just in case + $sql = "DELETE FROM $t_settings WHERE variable = 'openmeetings_plugin'"; + Database::query($sql); + $sql = "DELETE FROM $t_options WHERE variable = 'openmeetings_plugin'"; + Database::query($sql); +// $sql = "DELETE FROM $t_settings WHERE variable = 'openmeetings_plugin_host'"; +// Database::query($sql); +// $sql = "DELETE FROM $t_settings WHERE variable = 'openmeetings_plugin_salt'"; +// Database::query($sql); + + //hack to get rid of Database::query warning (please add c_id...) + $sql = "DELETE FROM $t_tool WHERE name = 'openmeetings' AND c_id = c_id"; + Database::query($sql); + + $sql = "DROP TABLE IF EXISTS plugin_openmeetings"; + Database::query($sql); + + //Deleting course settings + $this->uninstall_course_fields_in_all_courses(); + } +} \ No newline at end of file diff --git a/plugin/openmeetings/lib/openmeetings_rest_service.php b/plugin/openmeetings/lib/openmeetings_rest_service.php new file mode 100644 index 0000000000..57db66015f --- /dev/null +++ b/plugin/openmeetings/lib/openmeetings_rest_service.php @@ -0,0 +1,181 @@ +loadXML($xml); + + if ($returnAttribute == "") { + //echo "XML".$xml."
| # | +{{ 'CreatedAt'|get_lang }} | +{{ 'Status'|get_lang }} | +{{ 'Records'|get_lang }} | + + {% if allow_to_edit %} +{{ 'Actions'|get_lang }} | + {% endif %} + +
|---|---|---|---|---|
| {{ meeting.id }} | +{{ meeting.created_at }} | ++ {% if meeting.status == 1 %} + {{ 'MeetingOpened'|get_lang }} + {% else %} + {{ 'MeetingClosed'|get_lang }} + {% endif %} + | ++ {% if meeting.record == 1 %} + {# Record list #} + {{ meeting.show_links }} + {% endif %} + | + + {% if allow_to_edit %} ++ {% if meeting.status == 1 %} + {{ 'CloseMeeting'|get_lang }} + {% endif %} + | + {% endif %} + +