diff --git a/api/src/Html/CkEditorConfig.php b/api/src/Html/CkEditorConfig.php
index a891c4f50e..5000df0860 100644
--- a/api/src/Html/CkEditorConfig.php
+++ b/api/src/Html/CkEditorConfig.php
@@ -258,6 +258,14 @@ class CkEditorConfig
*/
private static function get_filebrowserBrowseUrl($start_path = '')
{
+ // Still need to treat old etemplate app to use filemanager_select.
+ // @TODO: this should be removed when we don't have any old etemplate app anymore.
+ if (in_array($GLOBALS['app'], array('phpbrain', 'sitemgr')))
+ {
+ return $GLOBALS['egw_info']['server']['webserver_url'].'/index.php?menuaction=filemanager.filemanager_select.select&mode=open&method=ckeditor_return'
+ .($start_path != '' ? '&path='.$start_path : '');
+ }
+
return \EGroupware\Api\Egw::link('/index.php',array(
'menuaction' => 'api.EGroupware\\Api\\Html\\CkEditorConfig.vfsSelectHelper',
'path' => $start_path
diff --git a/filemanager/inc/class.filemanager_select.inc.php b/filemanager/inc/class.filemanager_select.inc.php
new file mode 100644
index 0000000000..fc84a91ac2
--- /dev/null
+++ b/filemanager/inc/class.filemanager_select.inc.php
@@ -0,0 +1,366 @@
+
+ * @copyright (c) 2009-2016 by Ralf Becker
+ * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
+ * @version $Id$
+ */
+
+use EGroupware\Api;
+use EGroupware\Api\Link;
+use EGroupware\Api\Framework;
+use EGroupware\Api\Egw;
+use EGroupware\Api\Vfs;
+use EGroupware\Api\Etemplate;
+
+/**
+ * Select file to open or save dialog
+ *
+ * This dialog can be called from applications to open or store files from the VFS.
+ *
+ * There are the following ($_GET) parameters:
+ * - menuaction=filemanager.filemanager_select.select (required)
+ * - mode=(open|open-multiple|saveas|select-dir) (required)
+ * - method=app.class.method (required callback, gets called with id and selected file(s))
+ * - id=... (optional parameter passed to callback)
+ * - path=... (optional start path in VFS)
+ * - mime=... (optional mime-type to limit display to given type)
+ * - label=... (optional label for submit button, default "Open")
+ *
+ * The application calls this method in a popup with size: 640x580 px
+ * After the user selected one or more files (depending on the mode parameter), the "method" callback gets
+ * called on server (!) side. Parameters are the id plus the selected files as 1. and 2. parameter.
+ * The callback returns javascript to eg. update it's UI AND (!) to close the current popup ("window.close();").
+ */
+class filemanager_select
+{
+ /**
+ * Methods callable via menuaction
+ *
+ * @var array
+ */
+ var $public_functions = array(
+ 'select' => true,
+ );
+
+ /**
+ * Constructor
+ *
+ */
+ function __construct()
+ {
+ // strip slashes from _GET parameters, if someone still has magic_quotes_gpc on
+ if (get_magic_quotes_gpc() && $_GET)
+ {
+ $_GET = array_stripslashes($_GET);
+ }
+ }
+
+ /**
+ * File selector
+ *
+ * @param array $content
+ */
+ function select(array $content=null)
+ {
+ if (!is_array($content))
+ {
+ $content = array();
+ // recover from a failed upload in CkEditor, eg. > max_uploadsize
+ if ($_GET['failed_upload'] && $_GET['msg'])
+ {
+ $content['msg'] = $_GET['msg'];
+ $_GET['mode'] = 'open';
+ $_GET['method'] = 'ckeditor_return';
+ $_GET['CKEditorFuncNum'] = Api\Cache::getSession('filemanager','ckeditorfuncnum');
+ }
+ $content['mode'] = $_GET['mode'];
+ if (!in_array($content['mode'],array('open','open-multiple','saveas','select-dir')))
+ {
+ throw new Api\Exception\WrongParameter("Wrong or unset required mode parameter!");
+ }
+ $content['path'] = $_GET['path'];
+ if (empty($content['path']))
+ {
+ $content['path'] = Api\Cache::getSession('filemanger', 'select_path');
+ }
+ $content['name'] = (string)$_GET['name'];
+ $content['method'] = $_GET['method'];
+ if ($content['method'] == 'ckeditor_return')
+ {
+ if (isset($_GET['CKEditorFuncNum']) && is_numeric($_GET['CKEditorFuncNum']))
+ {
+ Api\Cache::setSession('filemanager','ckeditorfuncnum',
+ $content['ckeditorfuncnum'] = $_GET['CKEditorFuncNum']);
+ }
+ else
+ {
+ throw new Api\Exception\WrongParameter("chkeditor_return has been specified as a method but some parameters are missing or invalid.");
+ }
+ }
+ $content['id'] = $_GET['id'];
+ $content['label'] = isset($_GET['label']) ? $_GET['label'] : lang('Open');
+ if (($content['options-mime'] = isset($_GET['mime'])))
+ {
+ $sel_options['mime'] = array();
+ foreach((array)$_GET['mime'] as $key => $value)
+ {
+ if (is_numeric($key))
+ {
+ $sel_options['mime'][$value] = lang('%1 files',strtoupper(Api\MimeMagic::mime2ext($value))).' ('.$value.')';
+ }
+ else
+ {
+ $sel_options['mime'][$key] = lang('%1 files',strtoupper($value)).' ('.$key.')';
+ }
+ }
+
+ list($content['mime']) = each($sel_options['mime']);
+ error_log(array2string($content['options-mime']));
+ }
+ }
+ elseif(isset($content['button']))
+ {
+ list($button) = each($content['button']);
+ unset($content['button']);
+ switch($button)
+ {
+ case 'home':
+ $content['path'] = filemanager_ui::get_home_dir();
+ break;
+ case 'ok':
+ $copy_result = null;
+ if (isset($content['file_upload']['name']) && file_exists($content['file_upload']['tmp_name']))
+ {
+ //Set the "content" name filed accordingly to the uploaded file
+ // encode chars which special meaning in url/vfs (some like / get removed!)
+ $content['name'] = Vfs::encodePathComponent($content['file_upload']['name']);
+ $to_path = Vfs::concat($content['path'],$content['name']);
+
+ $copy_result = (Vfs::is_writable($content['path']) || Vfs::is_writable($to_path)) &&
+ copy($content['file_upload']['tmp_name'],Vfs::PREFIX.$to_path);
+ }
+
+ //Break on an error condition
+ if ((($content['mode'] == 'open' || $content['mode'] == 'saveas') && ($content['name'] == '')) || ($copy_result === false))
+ {
+ if ($copy_result === false)
+ {
+ $content['msg'] = lang('Error uploading file!');
+ }
+ else
+ {
+ $content['msg'] = lang('Filename must not be empty!');
+ }
+ $content['name'] = '';
+
+ break;
+ }
+
+ switch($content['mode'])
+ {
+ case 'open-multiple':
+ foreach((array)$content['dir']['selected'] as $name)
+ {
+ $files[] = Vfs::concat($content['path'],$name);
+ }
+ //Add an uploaded file to the files result array2string
+ if ($copy_result === true) $files[] = $to_path;
+ break;
+
+ case 'select-dir':
+ $files = $content['path'];
+ break;
+
+ case 'saveas':
+ // Don't trust the name the user gives, encode it
+ $content['name'] = Vfs::encodePathComponent($content['name']);
+ // Fall through
+
+ default:
+ $files = Vfs::concat($content['path'],$content['name']);
+ break;
+ }
+
+ if ($content['method'] && $content['method'] != 'ckeditor_return')
+ {
+ $js = ExecMethod2($content['method'],$content['id'],$files);
+ }
+ else if ($content['method'] == 'ckeditor_return')
+ {
+ $download_url = Vfs::download_url(Vfs::concat($content['path'],$content['name']));
+ if ($download_url[0] == '/') $download_url = Egw::link($download_url);
+
+ $response = Api\Json\Response::get();
+ $response->apply('window.opener.CKEDITOR.tools.callFunction', array(
+ $content['ckeditorfuncnum'],
+ str_replace("'", "\\'", $download_url)
+ ));
+ Framework::window_close();
+ exit();
+ }
+ if(Api\Json\Response::isJSONResponse())
+ {
+ $response = Api\Json\Response::get();
+ if($js)
+ {
+ $response->script($js);
+ }
+ // Ahh!
+ // The vfs-select widget looks for this
+ $response->script('this.selected_files = '.json_encode($files) . ';');
+ Framework::window_close();
+ }
+ else
+ {
+ header('Content-type: text/html; charset='.Api\Translation::charset());
+ echo "\n\n\n\n\n";
+ }
+ exit();
+ }
+
+ $sel_options['mime'] = $content['options-mime'];
+ }
+ elseif(isset($content['apps']))
+ {
+ list($app) = each($content['apps']);
+ if ($app == 'home') $content['path'] = filemanager_ui::get_home_dir();
+ }
+
+ //Deactivate the opload field if the current directory is not writeable or
+ //we're currently not in the single file open mode.
+ $content['no_upload'] = !Vfs::is_writable($content['path']) ||
+ !in_array($content['mode'],array('open'));
+
+ $content['apps'] = array_keys(self::get_apps());
+
+ if (isset($app))
+ {
+ $content['path'] = '/apps/'.(isset($content['apps'][$app]) ? $content['apps'][$app] : $app);
+ }
+
+ // Set a flag for easy detection as we go
+ $favorites_flag = substr($content['path'],0,strlen('/apps/favorites')) == '/apps/favorites';
+
+ if (!$favorites_flag && (!$content['path'] || !Vfs::is_dir($content['path'])))
+ {
+ $content['path'] = filemanager_ui::get_home_dir();
+ }
+ $tpl = new Etemplate('filemanager.select');
+
+ if ($favorites_flag)
+ {
+ // Display favorites as if they were folders
+ $files = array();
+ $favorites = Framework\Favorites::get_favorites('filemanager');
+ $n = 0;
+ foreach($favorites as $favorite)
+ {
+ $path = $favorite['state']['path'];
+ // Just directories
+ if(!$path) continue;
+ if ($path == $content['path']) continue; // remove directory itself
+
+ $mime = Vfs::mime_content_type($path);
+ $content['dir'][$n] = array(
+ 'name' => $favorite['name'],
+ 'path' => $path,
+ 'mime' => $mime,
+ 'is_dir' => true
+ );
+ if ($content['mode'] == 'open-multiple')
+ {
+ $readonlys['selected['.$favorite['name'].']'] = true;
+ }
+ ++$n;
+ }
+ }
+ else if (!($files = Vfs::find($content['path'],array(
+ 'dirsontop' => true,
+ 'order' => 'name',
+ 'sort' => 'ASC',
+ 'maxdepth' => 1,
+ ))))
+ {
+ $content['msg'] = lang("Can't open directory %1!",$content['path']);
+ }
+ else
+ {
+ $n = 0;
+ $content['dir'] = array('mode' => $content['mode']);
+ foreach($files as $path)
+ {
+ if ($path == $content['path']) continue; // remove directory itself
+
+ $name = Vfs::basename($path);
+ $is_dir = Vfs::is_dir($path);
+ $mime = Vfs::mime_content_type($path);
+ if ($content['mime'] && !$is_dir && $mime != $content['mime'])
+ {
+ continue; // does not match mime-filter --> ignore
+ }
+ $content['dir'][$n] = array(
+ 'name' => $name,
+ 'path' => $path,
+ 'mime' => $mime,
+ 'is_dir' => $is_dir
+ );
+ if ($is_dir && $content['mode'] == 'open-multiple')
+ {
+ $readonlys['selected['.$name.']'] = true;
+ }
+ ++$n;
+ }
+ if (!$n) $readonlys['selected[]'] = true; // remove checkbox from empty line
+ }
+ $readonlys['button[createdir]'] = !Vfs::is_writable($content['path']);
+
+ //_debug_array($readonlys);
+ Api\Cache::setSession('filemanger', 'select_path', $content['path']);
+ $preserve = array(
+ 'mode' => $content['mode'],
+ 'method' => $content['method'],
+ 'id' => $content['id'],
+ 'label' => $content['label'],
+ 'mime' => $content['mime'],
+ 'options-mime' => $sel_options['mime'],
+ 'old_path' => $content['path'],
+ );
+
+ if (isset($content['ckeditorfuncnum']))
+ {
+ $preserve['ckeditorfuncnum'] = $content['ckeditorfuncnum'];
+ $preserve['ckeditor'] = $content['ckeditor'];
+ }
+
+ // tell framework we need inline javascript for ckeditor_return
+ if ($content['method'] == 'ckeditor_return')
+ {
+ Api\Header\ContentSecurityPolicy::add('script-src', 'unsafe-inline');
+ }
+ $tpl->exec('filemanager.filemanager_select.select',$content,$sel_options,$readonlys,$preserve,2);
+ }
+
+ /**
+ * Get a list off all apps having an application directory in VFS
+ *
+ * @return array
+ */
+ static function get_apps()
+ {
+ $apps = array(false); // index starting from 1
+ if (isset($GLOBALS['egw_info']['apps']['stylite'])) $apps = array('favorites' => lang('Favorites'));
+ $apps += Link::app_list('query');
+
+ unset($apps['mydms']); // they do NOT support adding files to VFS
+ unset($apps['wiki']);
+ unset($apps['api-accounts']);
+ unset($apps['addressbook-email']);
+
+ return $apps;
+ }
+}
diff --git a/filemanager/templates/default/select.xet b/filemanager/templates/default/select.xet
new file mode 100644
index 0000000000..2b1df6525c
--- /dev/null
+++ b/filemanager/templates/default/select.xet
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+