';
+
+///
+/// End of main process, where everything is deployed
+///
+
+/// Print the footer of the page
+ print_footer();
+
+///
+/// Common and useful functions used by the body of the script
+///
+
+ /*** This function will return an ordered and nested array of items
+ * that is a perfect representation of the prefered organization
+ */
+ function ims_process_organizations($data) {
+ global $CFG;
+
+ /// Get the default organization
+ $default_organization = $data['@']['default'];
+ if ($CFG->debug) print_object('default_organization: '.$default_organization);
+
+ /// Iterate (reverse) over organizations until we find the default one
+ $count_organizations = count($data['#']['organization']);
+ if ($CFG->debug) print_object('count_organizations: '.$count_organizations);
+
+ $current_organization = $count_organizations - 1;
+ while ($current_organization >= 0) {
+ /// Load organization and check it
+ $organization = $data['#']['organization'][$current_organization];
+ if ($organization['@']['identifier'] == $default_organization) {
+ $current_organization = -1; //Match, so exit.
+ }
+ $current_organization--;
+ }
+
+ /// At this point we MUST have the final organization
+ if ($CFG->debug) print_object('final organization: '.$organization['#']['title'][0]['#']);
+ if (empty($organization)) {
+ return false; //Error, no organization found
+ }
+
+ /// Extract items map from organization
+ $items = $organization['#']['item'];
+ if (!$itemmap = ims_process_items($items)) {
+ return false; //Error, no items found
+ }
+ return $itemmap;
+ }
+
+ /*** This function gets the xmlized representation of the items
+ * and returns an array of items, ordered, with level and info
+ */
+ function ims_process_items($items, $level = 1, &$id = 1, $parent = 0) {
+ global $CFG;
+
+ $itemmap = array();
+
+ /// Iterate over items from start to end
+ $count_items = count($items);
+ if ($CFG->debug) print_object('level '.$level.'-count_items: '.$count_items);
+
+ $current_item = 0;
+ while ($current_item < $count_items) {
+ /// Load item
+ $item = $items[$current_item];
+ $obj_item = new stdClass;
+ $obj_item->title = $item['#']['title'][0]['#'];
+ $obj_item->identifier = $item['@']['identifier'];
+ $obj_item->identifierref = $item['@']['identifierref'];
+ $obj_item->id = $id;
+ $obj_item->level = $level;
+ $obj_item->parent = $parent;
+ /// Only if the item has everything
+ if (!empty($obj_item->title) &&
+ !empty($obj_item->identifier)) {
+ /// Add to itemmap
+ $itemmap[$id] = $obj_item;
+ if ($CFG->debug) print_object('level '.$level.'-id '.$id.'-parent '.$parent.'-'.$obj_item->title);
+ /// Counters go up
+ $id++;
+ /// Check for subitems recursively
+ $subitems = $item['#']['item'];
+ if (count($subitems)) {
+ /// Recursive call
+ $subitemmap = ims_process_items($subitems, $level+1, $id, $obj_item->id);
+ /// Add at the end and counters if necessary
+ if ($count_subitems = count($subitemmap)) {
+ foreach ($subitemmap as $subitem) {
+ /// Add the subitem to the main items array
+ $itemmap[$subitem->id] = $subitem;
+ }
+ }
+ }
+ }
+ $current_item++;
+ }
+ return $itemmap;
+ }
+
+ /*** This function will load an array of resources to be used later.
+ * Keys are identifiers
+ */
+ function ims_load_resources($data) {
+ global $CFG;
+
+ $resources = array();
+
+ $count_resources = count($data);
+ if ($CFG->debug) print_object('count_resources: '.$count_resources);
+
+ $current_resource = 0;
+ while ($current_resource < $count_resources) {
+ /// Load resource
+ $resource = $data[$current_resource];
+ $obj_resource = new stdClass;
+ $obj_resource->identifier = $resource['@']['identifier'];
+ $obj_resource->href = $resource['@']['href'];
+ if (empty($obj_resource->href)) {
+ $obj_resource->href = $resource['#']['file'][0]['@']['href'];
+ }
+ /// Only if the resource has everything
+ if (!empty($obj_resource->identifier) &&
+ !empty($obj_resource->href)) {
+ /// Add to resources (identifier as key)
+ $resources[$obj_resource->identifier] = $obj_resource->href;
+ }
+ /// Counters go up
+ $current_resource++;
+ }
+ return $resources;
+ }
+
+?>
diff --git a/mod/resource/type/ims/ims.html b/mod/resource/type/ims/ims.html
new file mode 100644
index 00000000000..724de7f67f4
--- /dev/null
+++ b/mod/resource/type/ims/ims.html
@@ -0,0 +1,205 @@
+
+
+
+
+
diff --git a/mod/resource/type/ims/resource.class.php b/mod/resource/type/ims/resource.class.php
new file mode 100644
index 00000000000..63ae9a3c63d
--- /dev/null
+++ b/mod/resource/type/ims/resource.class.php
@@ -0,0 +1,757 @@
+resource->alltext)) {
+ $this->resource->alltext='';
+ }
+ /// set own attributes
+ $this->parameters = $this->alltext2parameters($this->resource->alltext);
+ }
+
+ /***
+ * This function converts parameters stored in the alltext field to the proper
+ * this->parameters object storing the special configuration of this resource type
+ */
+ function alltext2parameters($alltext) {
+ /// set parameter defaults
+ $alltextfield = new stdClass();
+ $alltextfield->tableofcontents=0;
+ $alltextfield->navigationbuttons=0;
+
+ /// load up any stored parameters
+ if (!empty($alltext)) {
+ $parray = explode(',', $alltext);
+ foreach ($parray as $key => $fieldstring) {
+ $field = explode('=', $fieldstring);
+ $alltextfield->$field[0] = $field[1];
+ }
+ }
+
+ return $alltextfield;
+ }
+
+ /***
+ * This function converts the this->parameters attribute (object) to the format
+ * needed to save them in the alltext field to store all the special configuration
+ * of this resource type
+ */
+ function parameters2alltext($parameters) {
+ $optionlist = array();
+
+ $optionlist[] = 'tableofcontents='.$parameters->tableofcontents;
+ $optionlist[] = 'navigationbuttons='.$parameters->navigationbuttons;
+
+ return implode(',', $optionlist);
+ }
+
+ /***
+ * This function will convert all the parameters configured in the resource form
+ * to a this->parameter attribute (object)
+ */
+ function form2parameters($resource) {
+ $parameters = new stdClass;
+ $parameters->tableofcontents = $resource->param_tableofcontents;
+ $parameters->navigationbuttons = $resource->param_navigationbuttons;
+
+ return $parameters;
+ }
+
+ /*** This function checks for errors in the status or deployment of the IMS
+ * Content Package returning an error code:
+ * 1 = Not a .zip file.
+ * 2 = Zip file doesn't exist
+ * 3 = Package not deployed.
+ * 4 = Package has changed since deployed.
+ */
+ function check4errors($file, $course, $resource) {
+
+ global $CFG;
+
+ $mimetype = mimeinfo("type", $file);
+ if ($mimetype != "application/zip") {
+ return 1; //Error
+ }
+
+ /// Check if the uploaded file exists
+ if (!file_exists($CFG->dataroot.'/'.$course->id.'/'.$file)) {
+ return 2; //Error
+ }
+
+ /// Calculate the path were the IMS package must be deployed
+ $deploydir = $CFG->dataroot.'/'.$course->id.'/'.$CFG->moddata.'/resource/'.$resource->id;
+
+ /// Confirm that the IMS package has been deployed. These files must exist if
+ /// the package is deployed: moodle_index.ser and moodle_hash.ser
+ if (!file_exists($deploydir.'/moodle_inx.ser') ||
+ !file_exists($deploydir.'/moodle_hash.ser')) {
+ return 3; //Error
+ }
+
+ /// If teacheredit, make, hash check. It's the md5 of the name of the file
+ /// plus its size and modification date
+ if (isteacheredit($course->id)) {
+ if (!$this->checkpackagehash($file, $course, $resource)) {
+ return 4;
+ }
+ }
+
+ /// We've arrived here. Everything is ok
+ return 0;
+ }
+
+ /*** This function will check that the ims package (zip file) uploaded
+ * isn't changed since it was deployed.
+ */
+ function checkpackagehash($file, $course, $resource) {
+ global $CFG;
+
+ /// Calculate paths
+ $zipfile = $CFG->dataroot.'/'.$course->id.'/'.$file;
+ $hashfile= $CFG->dataroot.'/'.$course->id.'/'.$CFG->moddata.'/resource/'.$resource->id.'/moodle_hash.ser';
+ /// Get deloyed hash value
+ $f = fopen ($hashfile,'r');
+ $deployedhash = fread($f, filesize($hashfile));
+ fclose ($f);
+ /// Unserialize the deployed hash
+ $deployedhash = unserialize($deployedhash);
+ /// Calculate uploaded file hash value
+ $uploadedhash = $this->calculatefilehash($zipfile);
+
+ /// Compare them
+ return ($deployedhash == $uploadedhash);
+ }
+
+ /*** This function will calculate the hash of any file passes as argument.
+ * It's based in a md5 of the filename, filesize and 20 first bytes (it includes
+ * the zip CRC at byte 15).
+ */
+ function calculatefilehash($filefullpath) {
+
+ /// Name and size
+ $filename = basename($filefullpath);
+ $filesize = filesize($filefullpath);
+ /// Read first 20cc
+ $f = fopen ($filefullpath,'r');
+ $data = fread($f, 20);
+ fclose ($f);
+
+ return md5($filename.'-'.$filesize.'-'.$data);
+ }
+
+ /**
+ * Add new instance of file resource
+ *
+ * Create alltext field before calling base class function.
+ *
+ * @param resource object
+ */
+ function add_instance($resource) {
+
+ /// Load parameters to this->parameters
+ $this->parameters = $this->form2parameters($resource);
+ /// Save parameters into the alltext field
+ $resource->alltext = $this->parameters2alltext($this->parameters);
+
+ return parent::add_instance($resource);
+ }
+
+
+ /**
+ * Update instance of file resource
+ *
+ * Create alltext field before calling base class function.
+ *
+ * @param resource object
+ */
+ function update_instance($resource) {
+
+ /// Load parameters to this->parameters
+ $this->parameters = $this->form2parameters($resource);
+ /// Save parameters into the alltext field
+ $resource->alltext = $this->parameters2alltext($this->parameters);
+
+ return parent::update_instance($resource);
+ }
+
+
+ /**
+ * Display the file resource
+ *
+ * Displays a file resource embedded, in a frame, or in a popup.
+ * Output depends on type of file resource.
+ *
+ * @param CFG global object
+ */
+ function display() {
+ global $CFG, $THEME, $USER;
+
+ require_once($CFG->libdir.'/filelib.php');
+
+ /// Set up generic stuff first, including checking for access
+ parent::display();
+
+ /// Set up some shorthand variables
+ $cm = $this->cm;
+ $course = $this->course;
+ $resource = $this->resource;
+
+ /// Fetch parameters
+ $inpopup = optional_param('inpopup', 0, PARAM_BOOL);
+ $page = optional_param('page', 0, PARAM_INT);
+ $frameset= optional_param('frameset', '', PARAM_ALPHA);
+
+ /// Init some variables
+ $errorcode = 0;
+ $buttontext = 0;
+ $querystring = '';
+ $resourcetype = '';
+ $mimetype = mimeinfo("type", $resource->reference);
+ $pagetitle = strip_tags($course->shortname.': '.format_string($resource->name));
+
+ /// Cache this per request
+ static $items;
+
+ /// Check for errors
+ $errorcode = $this->check4errors($resource->reference, $course, $resource);
+
+ /// If there are any error, show it instead of the resource page
+ if ($errorcode) {
+ if (!isteacheredit($course->id)) {
+ /// Resource not available page
+ $errortext = get_string('resourcenotavailable','resource');
+ } else {
+ /// Depending of the error, show different messages and pages
+ if ($errorcode ==1) {
+ $errortext = get_string('invalidfiletype','resource');
+ } else if ($errorcode == 2) {
+ $errortext = get_string('filenotexists','resource');
+ } else if ($errorcode == 3) {
+ $errortext = get_string('packagenotdeplyed','resource');
+ } else if ($errorcode == 4) {
+ $errortext = get_string('packagechanged','resource');
+ }
+ }
+ /// Display the error and exit
+ if ($inpopup) {
+ print_header($pagetitle, $course->fullname.' : '.$resource->name);
+ } else {
+ print_header($pagetitle, $course->fullname, "$this->navigation ".format_string($resource->name), "", "", true, update_module_button($cm->id, $course->id, $this->strresource), navmenu($course, $cm));
+ }
+ print_simple_box_start('center', '60%');
+ echo '
'.$errortext.'
';
+ /// If errors were 3 or 4 and isteacheredit(), show the deploy button
+ if (isteacheredit($course->id) && ($errorcode = 3 || $errorcode ==4)) {
+ $link = 'type/ims/deploy.php';
+ $options['courseid'] = $course->id;
+ $options['cmid'] = $cm->id;
+ $options['file'] = $resource->reference;
+ $options['sesskey'] = $USER->sesskey;
+ $options['inpopup'] = $inpopup;
+ if ($errorcode == 3) {
+ $label = get_string ('deploy', 'resource');
+ } else if ($errorcode == 4) {
+ $label = get_string ('redeploy', 'resource');
+ }
+ $method='post';
+ /// Let's go with the button
+ echo '