diff --git a/mnet/xmlrpc/client.php b/mnet/xmlrpc/client.php index c45c1546502..0c34724fcf7 100644 --- a/mnet/xmlrpc/client.php +++ b/mnet/xmlrpc/client.php @@ -293,7 +293,7 @@ class mnet_xmlrpc_client { global $DB, $CFG; // Executing any system method is permitted. - $system_methods = array('system/listMethods', 'system/methodSignature', 'system/methodHelp', 'system/listServices'); + $system_methods = array('system/listMethods', 'system/methodSignature', 'system/methodHelp', 'system/listServices', 'system/listFiles', 'system/retrieveFile'); if (in_array($this->method, $system_methods) ) { return true; } diff --git a/mnet/xmlrpc/server.php b/mnet/xmlrpc/server.php index 64b1e3ce39b..4b09b340228 100644 --- a/mnet/xmlrpc/server.php +++ b/mnet/xmlrpc/server.php @@ -415,6 +415,12 @@ function mnet_server_dispatch($payload) { xmlrpc_server_register_method($xmlrpcserver, 'system.listServices', 'mnet_system'); xmlrpc_server_register_method($xmlrpcserver, 'system/listServices', 'mnet_system'); + xmlrpc_server_register_method($xmlrpcserver, 'system.listFiles', 'mnet_system'); + xmlrpc_server_register_method($xmlrpcserver, 'system/listFiles', 'mnet_system'); + + xmlrpc_server_register_method($xmlrpcserver, 'system.retrieveFile', 'mnet_system'); + xmlrpc_server_register_method($xmlrpcserver, 'system/retrieveFile', 'mnet_system'); + xmlrpc_server_register_method($xmlrpcserver, 'system.keyswap', 'mnet_keyswap'); xmlrpc_server_register_method($xmlrpcserver, 'system/keyswap', 'mnet_keyswap'); @@ -424,9 +430,13 @@ function mnet_server_dispatch($payload) { $method == 'system/methodSignature' || $method == 'system.methodHelp' || $method == 'system/methodHelp' || - $method == 'system.listServices' || - $method == 'system/listServices' || - $method == 'system.keyswap' || + $method == 'system.listServices' || + $method == 'system/listServices' || + $method == 'system.listFiles' || + $method == 'system/listFiles' || + $method == 'system.retrieveFile' || + $method == 'system/retrieveFile' || + $method == 'system.keyswap' || $method == 'system/keyswap') { $response = xmlrpc_server_call_method($xmlrpcserver, $payload, $MNET_REMOTE_CLIENT, array("encoding" => "utf-8")); @@ -688,10 +698,168 @@ function mnet_system($method, $params, $hostinfo) { } return $services; + } elseif ('system/retrieveFile' == $method) { + global $DB, $USER; + + $USER = $DB->get_record('user',array('username' => $params[0], 'mnethostid' => $hostinfo->id)); + $pathnamehash = $params[1]; + $fs = get_file_storage(); + + $sf = $fs->get_file_by_hash($pathnamehash); + + $contents = base64_encode($sf->get_content()); + + return array($contents, $sf->get_filename()); + } elseif ('system/listFiles' == $method) { + + global $DB, $USER; + + $USER = $DB->get_record('user',array('username' => $params[0], 'mnethostid' => $hostinfo->id)); + + $ret = array(); + $search = ''; + // no login required + $ret['nologin'] = true; + // todo: link to file manager + $ret['manage'] = $CFG->wwwroot .'/files/index.php'; // temporary + + $browser = get_file_browser(); + $itemid = null; + $filename = null; + $filearea = null; + $path = '/'; + $ret['dynload'] = false; + + if ($fileinfo = $browser->get_file_info(get_system_context(), $filearea, $itemid, $path, $filename)) { + + $ret['path'] = array(); + $params = $fileinfo->get_params(); + $filearea = $params['filearea']; + //todo: fix this call, and similar ones here and in build_tree - encoding path works only for real folders + $ret['path'][] = _encode_path($filearea, $path, $fileinfo->get_visible_name()); + if ($fileinfo->is_directory()) { + $level = $fileinfo->get_parent(); + while ($level) { + $params = $level->get_params(); + $ret['path'][] = _encode_path($params['filearea'], $params['filepath'], $level->get_visible_name()); + $level = $level->get_parent(); + } + } + $filecount = build_tree($fileinfo, $search, $ret['dynload'], $ret['list']); + $ret['path'] = array_reverse($ret['path']); + } else { + // throw some "context/filearea/item/path/file not found" exception? + } + + if (empty($ret['list'])) { + throw new repository_exception('emptyfilelist', 'repository_local'); + } else { + return $ret; + } } exit(mnet_server_fault(7019, 'nosuchfunction')); } + /** + * + * @param $filearea + * @param $path + * @param $visiblename + * @return + */ + function _encode_path($filearea, $path, $visiblename) { + return array('path'=>serialize(array($filearea, $path)), 'name'=>$visiblename); + } + + /** + * Builds a tree of files, to be used by get_listing(). This function is + * then called recursively. + * + * @param $fileinfo an object returned by file_browser::get_file_info() + * @param $search searched string + * @param $dynamicmode bool no recursive call is done when in dynamic mode + * @param $list - the array containing the files under the passed $fileinfo + * @returns int the number of files found + * + * todo: take $search into account, and respect a threshold for dynamic loading + */ + function build_tree($fileinfo, $search, $dynamicmode, &$list) { + global $CFG; + + $filecount = 0; + $children = $fileinfo->get_children(); + + foreach ($children as $child) { + $filename = $child->get_visible_name(); + $filesize = $child->get_filesize(); + $filesize = $filesize ? display_size($filesize) : ''; + $filedate = $child->get_timemodified(); + $filedate = $filedate ? userdate($filedate) : ''; + $filetype = $child->get_mimetype(); + + if ($child->is_directory()) { + $path = array(); + $level = $child->get_parent(); + while ($level) { + $params = $level->get_params(); + $path[] = _encode_path($params['filearea'], $params['filepath'], $level->get_visible_name()); + $level = $level->get_parent(); + } + + $tmp = array( + 'title' => $child->get_visible_name(), + 'size' => 0, + 'date' => $filedate, + 'path' => array_reverse($path), + 'thumbnail' => $CFG->pixpath .'/f/folder.gif' + ); + + + $_search = $search; + if ($search && stristr($tmp['title'], $search) !== false) { + $_search = false; + } + $tmp['children'] = array(); + $_filecount = build_tree($child, $_search, $dynamicmode, $tmp['children']); + if ($search && $_filecount) { + $tmp['expanded'] = 1; + } + + + + if (!$search || $_filecount || (stristr($tmp['title'], $search) !== false)) { + $list[] = $tmp; + $filecount += $_filecount; + } + + } else { // not a directory + // skip the file, if we're in search mode and it's not a match + if ($search && (stristr($filename, $search) === false)) { + continue; + } + + //retrieve the stored file id + $fs = get_file_storage(); + $params = $child->get_params(); + + $pathnamehash = $fs->get_pathname_hash($params['contextid'], $params['filearea'], $params['itemid'], $params['filepath'], $params['filename']); + + + $list[] = array( + 'title' => $filename, + 'size' => $filesize, + 'date' => $filedate, + 'source' => $pathnamehash, + 'thumbnail' => $CFG->pixpath .'/f/'. mimeinfo_from_type("icon", $filetype) + ); + + $filecount++; + } + } + + return $filecount; + } + /** * Initialize the object (if necessary), execute the method or function, and * return the response diff --git a/repository/remotemoodle/icon.png b/repository/remotemoodle/icon.png new file mode 100644 index 00000000000..e3f217403dc Binary files /dev/null and b/repository/remotemoodle/icon.png differ diff --git a/repository/remotemoodle/repository.class.php b/repository/remotemoodle/repository.class.php new file mode 100644 index 00000000000..6e042d67169 --- /dev/null +++ b/repository/remotemoodle/repository.class.php @@ -0,0 +1,323 @@ + $SESSION + * @global $action + * @global $CFG + * @param $repositoryid + * @param $context + * @param $options + */ + public function __construct($repositoryid, $context = SITEID, $options = array()) { + global $SESSION, $action, $CFG; + parent::__construct($repositoryid, $context, $options); + // TODO: + // get the parameter from client side + // $this->context can be used here. + // When user upload a file, $action == 'upload' + // You can use $_FILES to find that file + } + + /** + * + * @global $SESSION + * @param $ajax + * @return + */ + public function print_login($ajax = true) { + global $SESSION; + // TODO + // Return file list in moodle + return $this->get_listing(); + } + + /** + * + * @param $filearea + * @param $path + * @param $visiblename + * @return + */ + private function _encode_path($filearea, $path, $visiblename) { + return array('path'=>serialize(array($filearea, $path)), 'name'=>$visiblename); + } + + /** + * + * @param $path + * @return + */ + private function _decode_path($path) { + $filearea = ''; + $path = ''; + if (($file = unserialize($path)) !== false) { + $filearea = $file[0]; + $path = $file[1]; + } + return array('filearea' => $filearea, 'path' => $path); + } + + /** + * + * @param $search_text + * @return + */ + public function search($search_text) { + return $this->get_listing('', $search_text); + } + + private function ensure_environment() { + global $MNET; + + if (empty($MNET)) { + $MNET = new mnet_environment(); + $MNET->init(); + } + } + + /** + * + * @global $CFG + * @param $encodedpath + * @param $search + * @return + */ + public function get_listing($encodedpath = '', $search = '') { + global $CFG, $DB, $USER; + $ret = array( + 'path'=>'/var/repo/', + 'manage'=>'http://webmgr.moodle.com', + 'list'=> array( + array('title'=>'filename1', 'date'=>'01/01/2009', 'size'=>'10MB', 'source'=>'http://www.moodle.com/dl.rar'), + array('title'=>'folder2', 'date'=>'01/01/2009', 'size'=>'0', 'children'=>array()) + ) + ); + + $ret['nologin'] = true; + + require_once($CFG->dirroot . '/mnet/xmlrpc/client.php'); + //retrieve the host url + $this->ensure_environment(); + + $host = $DB->get_record('mnet_host',array('id' => $this->options['peer'])); + + + $mnetauth = get_auth_plugin('mnet'); + $url = $mnetauth->start_jump_session($host->id, ''); + + $mnet_peer = new mnet_peer(); + $mnet_peer->set_wwwroot($host->wwwroot); + + //connect to the remote moodle and retrieve the list of files + $client = new mnet_xmlrpc_client(); + + $client->set_method('system/listFiles'); + $client->add_param($USER->username); + + + $client->send($mnet_peer); + + $services = $client->response; + + return $services; + } + + /** + * Builds a tree of files, to be used by get_listing(). This function is + * then called recursively. + * + * @param $fileinfo an object returned by file_browser::get_file_info() + * @param $search searched string + * @param $dynamicmode bool no recursive call is done when in dynamic mode + * @param $list - the array containing the files under the passed $fileinfo + * @returns int the number of files found + * + * todo: take $search into account, and respect a threshold for dynamic loading + */ + private function build_tree($fileinfo, $search, $dynamicmode, &$list) { + global $CFG; + + $filecount = 0; + $children = $fileinfo->get_children(); + + foreach ($children as $child) { + $filename = $child->get_visible_name(); + $filesize = $child->get_filesize(); + $filesize = $filesize ? display_size($filesize) : ''; + $filedate = $child->get_timemodified(); + $filedate = $filedate ? userdate($filedate) : ''; + $filetype = $child->get_mimetype(); + + if ($child->is_directory()) { + $path = array(); + $level = $child->get_parent(); + while ($level) { + $params = $level->get_params(); + $path[] = $this->_encode_path($params['filearea'], $params['filepath'], $level->get_visible_name()); + $level = $level->get_parent(); + } + + $tmp = array( + 'title' => $child->get_visible_name(), + 'size' => 0, + 'date' => $filedate, + 'path' => array_reverse($path), + 'thumbnail' => $CFG->pixpath .'/f/folder.gif' + ); + + //if ($dynamicmode && $child->is_writable()) { + // $tmp['children'] = array(); + //} else { + // if folder name matches search, we send back all files contained. + $_search = $search; + if ($search && stristr($tmp['title'], $search) !== false) { + $_search = false; + } + $tmp['children'] = array(); + $_filecount = $this->build_tree($child, $_search, $dynamicmode, $tmp['children']); + if ($search && $_filecount) { + $tmp['expanded'] = 1; + } + + //} + + if (!$search || $_filecount || (stristr($tmp['title'], $search) !== false)) { + $list[] = $tmp; + $filecount += $_filecount; + } + + } else { // not a directory + // skip the file, if we're in search mode and it's not a match + if ($search && (stristr($filename, $search) === false)) { + continue; + } + $list[] = array( + 'title' => $filename, + 'size' => $filesize, + 'date' => $filedate, + 'source' => $child->get_url(), + 'thumbnail' => $CFG->pixpath .'/f/'. mimeinfo_from_type("icon", $filetype) + ); + $filecount++; + } + } + + return $filecount; + } + + /** + * Download a file + * @global object $CFG + * @param string $url the url of file + * @param string $file save location + * @return string the location of the file + * @see curl package + */ + public function get_file($url, $file = '') { + global $CFG, $DB, $USER; + require_once($CFG->dirroot . '/mnet/xmlrpc/client.php'); + //retrieve the host url + $this->ensure_environment(); + + $host = $DB->get_record('mnet_host',array('id' => $this->options['peer'])); + $mnetauth = get_auth_plugin('mnet'); + $mnetauth->start_jump_session($host->id, ''); + + $mnet_peer = new mnet_peer(); + $mnet_peer->set_wwwroot($host->wwwroot); + + //connect to the remote moodle and retrieve the list of files + $client = new mnet_xmlrpc_client(); + + $client->set_method('system/retrieveFile'); + $client->add_param($USER->username); + $client->add_param($url); + + $client->send($mnet_peer); + + $services = $client->response; + $content = base64_decode($services[0]); + $file = $services[1]; + + if (!file_exists($CFG->dataroot.'/temp/download')) { + mkdir($CFG->dataroot.'/temp/download/', 0777, true); + } + if (is_dir($CFG->dataroot.'/temp/download')) { + $dir = $CFG->dataroot.'/temp/download/'; + } + if (empty($file)) { + $file = uniqid('repo').'_'.time().'.tmp'; + } + if (file_exists($dir.$file)) { + $file = uniqid('m').$file; + } + + $fp = fopen($dir.$file, 'w'); + fwrite($fp,$content); + fclose($fp); + + return $dir.$file; + + } + + /** + * Add Instance settings input to Moodle form + * @param $ + */ + public function instance_config_form(&$mform) { + global $CFG, $DB; + + //retrieve all peers + $hosts = $DB->get_records_sql(' SELECT + h.id, + h.wwwroot, + h.ip_address, + h.name, + h.public_key, + h.public_key_expires, + h.transport, + h.portno, + h.last_connect_time, + h.last_log_id, + h.applicationid, + a.name as app_name, + a.display_name as app_display_name, + a.xmlrpc_server_url + FROM {mnet_host} h + JOIN {mnet_application} a ON h.applicationid=a.id + WHERE + h.id <> ? AND + h.deleted = 0 AND + a.name = ?', + array($CFG->mnet_localhost_id, 'moodle')); + $peers = array(); + foreach($hosts as $host) { + $peers[$host->id] = $host->name; + } + + $mform->addElement('select', 'peer', get_string('peer', 'repository_remotemoodle'),$peers); + $mform->addRule('peer', get_string('required'), 'required', null, 'client'); + } + + /** + * Names of the instance settings + * @return + */ + public static function get_instance_option_names() { + return array('peer'); + } +} +?> \ No newline at end of file