2008-03-02 22:44:15 +01:00
< ? php
/**
2016-05-05 09:20:07 +02:00
* EGroupware - Filemanager - user interface
2008-03-02 22:44:15 +01:00
*
* @ link http :// www . egroupware . org
2008-03-03 08:53:43 +01:00
* @ package filemanager
2008-03-02 22:44:15 +01:00
* @ author Ralf Becker < RalfBecker - AT - outdoor - training . de >
2017-03-31 09:05:01 +02:00
* @ copyright ( c ) 2008 - 17 by Ralf Becker < RalfBecker - AT - outdoor - training . de >
2008-03-02 22:44:15 +01:00
* @ license http :// opensource . org / licenses / gpl - license . php GPL - GNU General Public License
* @ version $Id $
*/
2008-03-18 10:07:06 +01:00
2016-03-21 11:06:54 +01:00
use EGroupware\Api ;
2016-05-05 09:20:07 +02:00
use EGroupware\Api\Egw ;
use EGroupware\Api\Etemplate ;
2020-03-04 21:53:26 +01:00
use EGroupware\Api\Framework ;
use EGroupware\Api\Link ;
2016-03-21 11:06:54 +01:00
use EGroupware\Api\Vfs ;
2016-08-17 17:23:22 +02:00
2009-12-01 15:51:13 +01:00
/**
* Filemanage user interface class
*/
2008-03-02 22:44:15 +01:00
class filemanager_ui
{
/**
* Methods callable via menuaction
*
* @ var array
*/
var $public_functions = array (
'index' => true ,
2008-03-03 23:15:44 +01:00
'file' => true ,
2016-07-19 18:20:08 +02:00
'editor' => true
2008-03-02 22:44:15 +01:00
);
2010-12-28 04:12:57 +01:00
2010-10-15 21:42:38 +02:00
/**
* Views available from plugins
2010-12-28 04:12:57 +01:00
*
2010-10-15 21:42:38 +02:00
* @ var array
*/
public static $views = array (
'filemanager_ui::listview' => 'Listview' ,
);
public static $views_init = false ;
2013-04-09 18:20:06 +02:00
2012-10-27 13:38:47 +02:00
/**
* vfs namespace for document merge properties
*
*/
public static $merge_prop_namespace = '' ;
2020-03-25 03:34:04 +01:00
protected $etemplate ;
const LIST_TEMPLATE = 'filemanager.index' ;
2008-04-16 09:07:31 +02:00
2008-10-05 19:07:36 +02:00
/**
* Constructor
*
*/
function __construct ()
{
// strip slashes from _GET parameters, if someone still has magic_quotes_gpc on
2021-03-21 18:27:09 +01:00
if ( function_exists ( 'get_magic_quotes_gpc' ) && get_magic_quotes_gpc () && $_GET )
2008-10-05 19:07:36 +02:00
{
2016-05-05 09:20:07 +02:00
$_GET = array_stripslashes ( $_GET );
2008-10-05 19:07:36 +02:00
}
2008-11-09 17:33:09 +01:00
// do we have root rights
2016-03-21 11:06:54 +01:00
if ( Api\Cache :: getSession ( 'filemanager' , 'is_root' ))
2008-11-09 17:33:09 +01:00
{
2016-03-21 11:06:54 +01:00
Vfs :: $is_root = true ;
2008-11-09 17:33:09 +01:00
}
2010-12-28 04:12:57 +01:00
2014-11-18 13:55:32 +01:00
static :: init_views ();
2016-03-21 11:06:54 +01:00
static :: $merge_prop_namespace = Vfs :: DEFAULT_PROP_NAMESPACE . $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ];
2010-10-15 21:42:38 +02:00
}
2010-12-28 04:12:57 +01:00
2010-10-15 21:42:38 +02:00
/**
* Initialise and return available views
2010-12-28 04:12:57 +01:00
*
2010-10-15 21:42:38 +02:00
* @ return array with method => label pairs
*/
public static function init_views ()
{
2014-11-18 13:55:32 +01:00
if ( ! static :: $views_init )
2010-10-15 21:42:38 +02:00
{
// translate our labels
2014-11-18 13:55:32 +01:00
foreach ( static :: $views as & $label )
2010-10-15 21:42:38 +02:00
{
$label = lang ( $label );
}
// search for plugins with additional filemanager views
2016-05-05 09:20:07 +02:00
foreach ( Api\Hooks :: process ( 'filemanager_views' ) as $views )
2010-10-15 21:42:38 +02:00
{
2014-11-18 13:55:32 +01:00
if ( is_array ( $views )) static :: $views += $views ;
2010-10-15 21:42:38 +02:00
}
2014-11-18 13:55:32 +01:00
static :: $views_init = true ;
2010-10-15 21:42:38 +02:00
}
2014-11-18 13:55:32 +01:00
return static :: $views ;
2008-11-09 17:33:09 +01:00
}
/**
2010-10-15 21:42:38 +02:00
* Get active view
2008-11-09 17:33:09 +01:00
*
2010-10-15 21:42:38 +02:00
* @ return string
2008-11-09 17:33:09 +01:00
*/
2012-03-04 14:33:10 +01:00
public static function get_view ()
2008-11-09 17:33:09 +01:00
{
2016-03-21 11:06:54 +01:00
$view =& Api\Cache :: getSession ( 'filemanager' , 'view' );
2010-10-15 21:42:38 +02:00
if ( isset ( $_GET [ 'view' ]))
2008-11-09 17:33:09 +01:00
{
2010-10-15 21:42:38 +02:00
$view = $_GET [ 'view' ];
2008-11-09 17:33:09 +01:00
}
2014-11-18 13:55:32 +01:00
if ( ! isset ( static :: $views [ $view ]))
2008-11-09 17:33:09 +01:00
{
2014-11-18 13:55:32 +01:00
reset ( static :: $views );
$view = key ( static :: $views );
2008-11-09 17:33:09 +01:00
}
2010-10-15 21:42:38 +02:00
return $view ;
2008-10-05 19:07:36 +02:00
}
2017-09-26 18:41:57 +02:00
/**
* Method to build select options out of actions
* @ param type $actions
* @ return type
*/
public static function convertActionsToselOptions ( $actions )
{
$sel_options = array ();
foreach ( $actions as $action => $value )
{
2022-05-12 23:22:49 +02:00
$sel_options [] = array (
'value' => $action ,
2017-09-26 18:41:57 +02:00
'label' => $value [ 'caption' ],
2022-05-12 23:22:49 +02:00
'icon' => $value [ 'icon' ]
2017-09-26 18:41:57 +02:00
);
}
return $sel_options ;
}
2011-06-30 15:07:55 +02:00
/**
* Context menu
*
* @ return array
*/
2014-12-05 20:34:12 +01:00
public static function get_actions ()
2011-06-30 15:07:55 +02:00
{
2011-07-01 09:49:58 +02:00
$actions = array (
2021-10-27 19:55:31 +02:00
'open' => array (
'caption' => lang ( 'Open' ),
'icon' => '' ,
'group' => $group = 1 ,
2011-06-30 15:07:55 +02:00
'allowOnMultiple' => false ,
2021-10-27 19:55:31 +02:00
'onExecute' => 'javaScript:app.filemanager.open' ,
'default' => true
2011-06-30 15:07:55 +02:00
),
2021-10-27 19:55:31 +02:00
'new' => array (
'caption' => 'New' ,
'group' => $group ,
2017-10-23 12:08:33 +02:00
'disableClass' => 'noEdit' ,
2021-10-27 19:55:31 +02:00
'children' => array (
'document' => array (
'caption' => 'Document' ,
'icon' => 'new' ,
2017-09-26 18:41:57 +02:00
'onExecute' => 'javaScript:app.filemanager.create_new' ,
2016-07-20 16:44:37 +02:00
)
)
),
2021-10-27 19:55:31 +02:00
'mkdir' => array (
'caption' => lang ( 'Create directory' ),
'icon' => 'filemanager/button_createdir' ,
'group' => $group ,
2017-09-26 18:41:57 +02:00
'allowOnMultiple' => false ,
2021-10-27 19:55:31 +02:00
'disableClass' => 'noEdit' ,
'onExecute' => 'javaScript:app.filemanager.createdir'
2014-06-24 21:29:05 +02:00
),
2021-10-27 19:55:31 +02:00
'edit' => array (
'caption' => lang ( 'Edit settings' ),
'group' => $group ,
'allowOnMultiple' => false ,
'onExecute' => Api\Header\UserAgent :: mobile () ? 'javaScript:app.filemanager.viewEntry' : 'javaScript:app.filemanager.editprefs' ,
'mobileViewTemplate' => 'file?' . filemtime ( Api\Etemplate\Widget\Template :: rel2path ( '/filemanager/templates/mobile/file.xet' ))
2011-06-30 15:07:55 +02:00
),
2021-10-27 19:55:31 +02:00
'unlock' => array (
'caption' => lang ( 'Unlock' ),
'icon' => 'unlock' ,
'enableClass' => 'locked' ,
'group' => $group ,
2017-09-26 18:41:57 +02:00
'allowOnMultiple' => true ,
2021-10-27 19:55:31 +02:00
'hideOnDisabled' => true
),
'saveas' => array (
'caption' => lang ( 'Save as' ),
'group' => $group ,
'allowOnMultiple' => true ,
'icon' => 'filesave' ,
'onExecute' => 'javaScript:app.filemanager.force_download' ,
'disableClass' => 'isDir' ,
'enabled' => 'javaScript:app.filemanager.is_multiple_allowed' ,
'shortcut' => array ( 'ctrl' => true , 'shift' => true , 'keyCode' => 83 ,
'caption' => 'Ctrl + Shift + S' ),
2017-09-26 18:41:57 +02:00
),
'saveaszip' => array (
2021-10-27 19:55:31 +02:00
'caption' => lang ( 'Save as ZIP' ),
'group' => $group ,
2017-09-26 18:41:57 +02:00
'allowOnMultiple' => true ,
2021-10-27 19:55:31 +02:00
'icon' => 'save_zip' ,
'postSubmit' => true ,
'shortcut' => array ( 'ctrl' => true , 'shift' => true , 'keyCode' => 90 ,
'caption' => 'Ctrl + Shift + Z' ),
2017-09-26 18:41:57 +02:00
),
2016-08-24 22:28:34 +02:00
'egw_paste' => array (
'enabled' => false ,
'group' => $group + 0.5 ,
'hideOnDisabled' => true
),
'paste' => array (
'caption' => lang ( 'Paste' ),
'acceptedTypes' => 'file' ,
'group' => $group + 0.5 ,
'order' => 10 ,
2016-08-29 17:37:07 +02:00
'enabled' => 'javaScript:app.filemanager.paste_enabled' ,
2016-08-24 22:28:34 +02:00
'children' => array ()
),
2016-10-24 12:55:20 +02:00
'copylink' => array (
'caption' => lang ( 'Copy link address' ),
'group' => $group + 0.5 ,
'icon' => 'copy' ,
'allowOnMultiple' => false ,
'order' => 10 ,
'onExecute' => 'javaScript:app.filemanager.copy_link'
),
2020-03-25 18:39:22 +01:00
'share' => EGroupware\Api\Vfs\HiddenUploadSharing :: get_actions ( 'filemanager' , ++ $group )[ 'share' ],
2012-05-03 19:58:16 +02:00
'documents' => filemanager_merge :: document_action (
$GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'filemanager' ][ 'document_dir' ],
++ $group , 'Insert in document' , 'document_' ,
$GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'filemanager' ][ 'default_document' ]
),
2011-06-30 15:07:55 +02:00
'delete' => array (
'caption' => lang ( 'Delete' ),
'group' => ++ $group ,
'confirm' => 'Delete these files or directories?' ,
2013-04-11 12:46:39 +02:00
'onExecute' => 'javaScript:app.filemanager.action' ,
2017-11-07 12:19:57 +01:00
'disableClass' => 'noDelete'
2011-06-30 15:07:55 +02:00
),
2013-04-11 12:46:39 +02:00
// DRAG and DROP events
'file_drag' => array (
2014-09-23 23:25:46 +02:00
'dragType' => array ( 'file' , 'link' ),
2023-02-17 17:16:13 +01:00
'type' => 'drag'
2013-04-11 12:46:39 +02:00
),
2014-10-17 00:41:39 +02:00
'file_drop_mail' => array (
'type' => 'drop' ,
'acceptedTypes' => 'mail' ,
2014-11-19 18:58:02 +01:00
'onExecute' => 'javaScript:app.filemanager.drop' ,
'hideOnDisabled' => true
2014-10-17 00:41:39 +02:00
),
2013-04-11 12:46:39 +02:00
'file_drop_move' => array (
'icon' => 'stylite/move' ,
'acceptedTypes' => 'file' ,
'caption' => lang ( 'Move into folder' ),
'type' => 'drop' ,
'onExecute' => 'javaScript:app.filemanager.drop' ,
'default' => true
),
'file_drop_copy' => array (
2018-03-14 13:26:49 +01:00
'icon' => 'stylite/copy' ,
2013-04-11 12:46:39 +02:00
'acceptedTypes' => 'file' ,
'caption' => lang ( 'Copy into folder' ),
'type' => 'drop' ,
'onExecute' => 'javaScript:app.filemanager.drop'
2014-11-18 01:09:38 +01:00
),
'file_drop_symlink' => array (
'icon' => 'linkpaste' ,
'acceptedTypes' => 'file' ,
'caption' => lang ( 'Link into folder' ),
'type' => 'drop' ,
'onExecute' => 'javaScript:app.filemanager.drop'
2013-04-11 12:46:39 +02:00
)
2011-06-30 15:07:55 +02:00
);
2018-03-12 11:11:13 +01:00
2019-08-26 19:22:26 +02:00
// This one makes no sense in filemanager
unset ( $actions [ 'share' ][ 'children' ][ 'shareFilemanager' ]);
2018-03-12 11:11:13 +01:00
if ( isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'mail' ])) {
2019-07-16 21:44:20 +02:00
$actions [ 'share' ][ 'children' ][ 'share_mail' ] = array (
'caption' => lang ( 'Mail' ),
'icon' => 'mail' ,
'group' => 1 ,
'order' => 0 ,
2019-08-28 11:20:42 +02:00
'allowOnMultiple' => true ,
2019-07-16 21:44:20 +02:00
);
2016-03-21 11:06:54 +01:00
foreach ( Vfs\Sharing :: $modes as $mode => $data )
2014-12-03 17:25:10 +01:00
{
2019-07-16 21:44:20 +02:00
$actions [ 'share' ][ 'children' ][ 'share_mail' ][ 'children' ][ 'mail_' . $mode ] = array (
2014-12-03 17:25:10 +01:00
'caption' => $data [ 'label' ],
2014-12-04 10:19:03 +01:00
'hint' => $data [ 'title' ],
2019-07-16 21:44:20 +02:00
'icon' => $mode == Vfs\Sharing :: ATTACH ?
'mail/attach' : 'api/link' ,
2017-08-02 18:01:54 +02:00
'group' => 2 ,
2014-12-03 17:25:10 +01:00
'onExecute' => 'javaScript:app.filemanager.mail' ,
);
2017-06-29 14:33:53 +02:00
if ( $mode == Vfs\Sharing :: ATTACH || $mode == Vfs\Sharing :: LINK )
{
2019-07-16 21:44:20 +02:00
$actions [ 'share' ][ 'children' ][ 'share_mail' ][ 'children' ][ 'mail_' . $mode ][ 'disableClass' ] = 'isDir' ;
2017-06-29 14:33:53 +02:00
}
2014-12-03 17:25:10 +01:00
}
2020-03-26 20:20:20 +01:00
foreach ( Vfs\HiddenUploadSharing :: $modes as $mode => $data )
{
$actions [ 'share' ][ 'children' ][ 'share_mail' ][ 'children' ][ 'mail_shareUploadDir' ] = array (
'caption' => $data [ 'label' ],
'hint' => $data [ 'title' ],
2020-03-27 20:40:48 +01:00
'icon' => 'api/link' ,
2020-03-26 20:20:20 +01:00
'group' => 3 ,
'data' => [ 'share_writable' => $mode ],
'enabled' => 'javaScript:app.filemanager.hidden_upload_enabled' ,
'onExecute' => 'javaScript:app.filemanager.mail_share_link' ,
);
}
2014-12-03 17:25:10 +01:00
}
2018-03-12 11:11:13 +01:00
2016-08-24 22:28:34 +02:00
// This would be done automatically, but we're overriding
foreach ( $actions as $action_id => $action )
{
if ( $action [ 'type' ] == 'drop' && $action [ 'caption' ])
{
$action [ 'type' ] = 'popup' ;
if ( $action [ 'acceptedTypes' ] == 'file' )
{
2016-08-29 17:37:07 +02:00
$action [ 'enabled' ] = 'javaScript:app.filemanager.paste_enabled' ;
2016-08-24 22:28:34 +02:00
}
$actions [ 'paste' ][ 'children' ][ " { $action_id } _paste " ] = $action ;
}
}
2011-07-01 09:49:58 +02:00
return $actions ;
2011-06-30 15:07:55 +02:00
}
2013-04-09 18:20:06 +02:00
2012-10-27 13:38:47 +02:00
/**
* Get mergeapp property for given path
*
* @ param string $path
2014-05-27 09:30:33 +02:00
* @ param string $scope ( default ) or 'parents'
2012-10-27 13:38:47 +02:00
* $scope == 'self' query only the given path
* $scope == 'parents' query only path parents for property ( first parent in hierarchy upwards wins )
*
* @ return string merge application or NULL if no property found
*/
private static function get_mergeapp ( $path , $scope = 'self' )
{
$app = null ;
switch ( $scope )
{
case 'self' :
2016-03-21 11:06:54 +01:00
$props = Vfs :: propfind ( $path , static :: $merge_prop_namespace );
2012-10-27 13:38:47 +02:00
$app = empty ( $props ) ? null : $props [ 0 ][ 'val' ];
break ;
case 'parents' :
// search for props in parent directories
$currentpath = $path ;
2016-03-21 11:06:54 +01:00
while ( $dir = Vfs :: dirname ( $currentpath ))
2012-10-27 13:38:47 +02:00
{
2016-03-21 11:06:54 +01:00
$props = Vfs :: propfind ( $dir , static :: $merge_prop_namespace );
2012-10-27 13:38:47 +02:00
if ( ! empty ( $props ))
{
// found prop in parent directory
return $app = $props [ 0 ][ 'val' ];
}
$currentpath = $dir ;
}
break ;
}
2013-04-09 18:20:06 +02:00
2012-10-27 13:38:47 +02:00
return $app ;
}
2011-06-30 15:07:55 +02:00
2008-03-02 22:44:15 +01:00
/**
* Main filemanager page
*
2014-05-27 09:30:33 +02:00
* @ param array $content
* @ param string $msg
2008-03-02 22:44:15 +01:00
*/
2008-03-03 23:15:44 +01:00
function index ( array $content = null , $msg = null )
2008-03-02 22:44:15 +01:00
{
if ( ! is_array ( $content ))
{
$content = array (
2016-03-21 11:06:54 +01:00
'nm' => Api\Cache :: getSession ( 'filemanager' , 'index' ),
2008-03-02 22:44:15 +01:00
);
2013-04-11 12:46:39 +02:00
if ( ! is_array ( $content [ 'nm' ]))
2008-03-02 22:44:15 +01:00
{
$content [ 'nm' ] = array (
2022-11-07 21:20:29 +01:00
'get_rows' => 'filemanager.filemanager_ui.get_rows' ,
// I method/callback to request the data for the rows eg. 'notes.bo.get_rows'
'filter' => '' , // current dir only
'no_filter2' => True , // I disable the 2. filter (params are the same as for filter)
'no_cat' => True , // I disable the cat-selectbox
'lettersearch' => True , // I show a lettersearch
'searchletter' => false , // I0 active letter of the lettersearch or false for [all]
'start' => 0 , // IO position in list
'order' => 'mtime' , // IO name of the column to sort after (optional for the sortheaders)
'sort' => 'DESC' , // IO direction of the sort: 'ASC' or 'DESC'
'default_cols' => '!comment,ctime' ,
// I columns to use if there's no user or default pref (! as first char uses all but the named columns), default all columns
'csv_fields' => false ,
// I false=disable csv export, true or unset=enable it with auto-detected fieldnames,
//or array with name=>label or name=>array('label'=>label,'type'=>type) pairs (type is a eT widget-type)
'row_id' => 'path' ,
'row_modified' => 'mtime' ,
'parent_id' => 'dir' ,
'is_parent' => 'is_dir' ,
'favorites' => true
2008-03-02 22:44:15 +01:00
);
2014-11-18 13:55:32 +01:00
$content [ 'nm' ][ 'path' ] = static :: get_home_dir ();
2008-03-02 22:44:15 +01:00
}
2017-04-04 16:52:25 +02:00
$content [ 'nm' ][ 'actions' ] = static :: get_actions ();
2014-11-18 13:55:32 +01:00
$content [ 'nm' ][ 'home_dir' ] = static :: get_home_dir ();
2015-01-16 18:07:18 +01:00
$content [ 'nm' ][ 'view' ] = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'filemanager' ][ 'nm_view' ];
2023-07-12 23:47:54 +02:00
$content [ 'nm' ][ 'placeholder_actions' ] = array ( 'mkdir' , 'paste' , 'share' , 'file_drop_mail' , 'file_drop_move' ,
'file_drop_copy' , 'file_drop_symlink' );
2013-04-10 19:11:32 +02:00
2023-07-12 23:47:54 +02:00
// disable kanban column if we have no kanban
if ( empty ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'kanban' ]))
{
$content [ 'nm' ][ 'no_kanban' ] = true ;
}
if ( isset ( $_GET [ 'msg' ]))
{
$msg = $_GET [ 'msg' ];
}
2009-05-06 17:15:39 +02:00
2015-02-02 18:50:45 +01:00
// Blank favorite set via GET needs special handling for path
2023-07-12 23:47:54 +02:00
if ( isset ( $_GET [ 'favorite' ]) && $_GET [ 'favorite' ] == 'blank' )
2015-02-02 18:50:45 +01:00
{
$content [ 'nm' ][ 'path' ] = static :: get_home_dir ();
}
2009-05-06 17:15:39 +02:00
// switch to projectmanager folders
2023-07-12 23:47:54 +02:00
if ( isset ( $_GET [ 'pm_id' ]))
2009-05-06 17:15:39 +02:00
{
$_GET [ 'path' ] = '/apps/projectmanager' . (( int ) $_GET [ 'pm_id' ] ? '/' . ( int ) $_GET [ 'pm_id' ] : '' );
}
2008-09-04 08:44:48 +02:00
if ( isset ( $_GET [ 'path' ]) && ( $path = $_GET [ 'path' ]))
2008-08-27 13:17:00 +02:00
{
2009-04-30 10:09:50 +02:00
switch ( $path )
{
case '..' :
2016-03-21 11:06:54 +01:00
$path = Vfs :: dirname ( $content [ 'nm' ][ 'path' ]);
2009-04-30 10:09:50 +02:00
break ;
case '~' :
2014-11-18 13:55:32 +01:00
$path = static :: get_home_dir ();
2009-04-30 10:09:50 +02:00
break ;
}
2016-07-02 12:39:28 +02:00
if ( $path && $path [ 0 ] == '/' && Vfs :: stat ( $path , true ) && Vfs :: is_dir ( $path ) && Vfs :: check_access ( $path , Vfs :: READABLE ))
2008-09-04 08:44:48 +02:00
{
$content [ 'nm' ][ 'path' ] = $path ;
2008-10-05 19:07:36 +02:00
}
2008-09-04 08:44:48 +02:00
else
2008-08-27 13:17:00 +02:00
{
2016-07-02 14:02:13 +02:00
$msg .= lang ( 'The requested path %1 is not available.' , $path ? Vfs :: decodePath ( $path ) : " false " );
2008-08-27 13:17:00 +02:00
}
2009-04-23 08:05:48 +02:00
// reset lettersearch as it confuses users (they think the dir is empty)
$content [ 'nm' ][ 'searchletter' ] = false ;
// switch recusive display off
2014-04-08 00:46:00 +02:00
if ( ! $content [ 'nm' ][ 'filter' ]) $content [ 'nm' ][ 'filter' ] = '' ;
2008-03-02 22:44:15 +01:00
}
}
2014-11-18 13:55:32 +01:00
$view = static :: get_view ();
2010-10-15 21:42:38 +02:00
call_user_func ( $view , $content , $msg );
}
/**
* Make the current user ( vfs ) root
*
2021-09-13 16:16:36 +02:00
* The user / pw is either the " root_ " prefixed setup config user or a specially configured vfs_root user
2010-10-15 21:42:38 +02:00
*
2014-05-27 09:30:33 +02:00
* @ param string $user setup config user to become root or '' to log off as root
* @ param string $password setup config password to become root
2021-09-13 16:16:36 +02:00
* @ param string & $msg on return error or success message
* @ param bool $allow_setup = false true : allow " root_ " prefixed setup - config user / pw
2010-10-15 21:42:38 +02:00
* @ param boolean & $is_setup = null on return true if authenticated user is setup config user , false otherwise
* @ return boolean true is root user given , false otherwise ( including logout / empty $user )
*/
2021-09-13 16:16:36 +02:00
protected function sudo ( $user = '' , $password = '' , string & $msg = null , bool $allow_setup = false , & $is_setup = null )
2010-10-15 21:42:38 +02:00
{
2021-09-13 16:16:36 +02:00
$is_root = $is_setup = false ;
$msg = null ;
2010-10-15 21:42:38 +02:00
if ( ! $user )
{
2021-09-13 16:16:36 +02:00
$msg = lang ( 'Root access stopped.' );
}
// config user & password
elseif ( $allow_setup && substr ( $user , 0 , 5 ) === 'root_' )
{
if ( ! ( $msg = setup :: checkip ()))
{
2021-09-13 18:24:24 +02:00
$is_root = $is_setup = setup :: check_auth ( substr ( $user , 5 ), $password , $GLOBALS [ 'egw_info' ][ 'server' ][ 'header_admin_user' ],
$GLOBALS [ 'egw_info' ][ 'server' ][ 'header_admin_password' ]);
2021-09-13 16:16:36 +02:00
}
2010-10-15 21:42:38 +02:00
}
2021-09-13 16:16:36 +02:00
// or vfs root user from setup >> configuration
2010-10-15 21:42:38 +02:00
else
{
2021-09-13 16:16:36 +02:00
$is_root = $GLOBALS [ 'egw_info' ][ 'server' ][ 'vfs_root_user' ] &&
2010-10-15 21:42:38 +02:00
in_array ( $user , preg_split ( '/, */' , $GLOBALS [ 'egw_info' ][ 'server' ][ 'vfs_root_user' ])) &&
$GLOBALS [ 'egw' ] -> auth -> authenticate ( $user , $password , 'text' );
}
2021-09-13 16:16:36 +02:00
if ( empty ( $msg ))
{
$msg = $is_root ? lang ( 'Root access granted.' ) : lang ( 'Wrong username or password!' );
}
//error_log(__METHOD__."('$user', '$password', $is_setup, '$msg') --> returning ".array2string($is_root));
2016-03-21 11:06:54 +01:00
Api\Cache :: setSession ( 'filemanager' , 'is_setup' , $is_setup );
2016-05-30 18:02:57 +02:00
Api\Cache :: setSession ( 'filemanager' , 'is_root' , Vfs :: $is_root = $is_root );
2021-09-13 16:16:36 +02:00
2016-05-30 18:02:57 +02:00
return Vfs :: $is_root ;
2010-10-15 21:42:38 +02:00
}
/**
* Filemanager listview
*
2014-05-27 09:30:33 +02:00
* @ param array $content
* @ param string $msg
2010-10-15 21:42:38 +02:00
*/
function listview ( array $content = null , $msg = null )
{
2020-03-25 03:34:04 +01:00
$tpl = $this -> etemplate ? $this -> etemplate : new Etemplate ( static :: LIST_TEMPLATE );
2010-10-15 21:42:38 +02:00
2020-03-25 18:39:22 +01:00
if ( $msg )
{
Framework :: message ( $msg );
}
2008-03-02 22:44:15 +01:00
2011-12-27 12:08:41 +01:00
if (( $content [ 'nm' ][ 'action' ] || $content [ 'nm' ][ 'rows' ]) && ( empty ( $content [ 'button' ]) || ! isset ( $content [ 'button' ])))
2008-03-02 22:44:15 +01:00
{
2011-06-30 15:07:55 +02:00
if ( $content [ 'nm' ][ 'action' ])
2008-03-02 22:44:15 +01:00
{
2020-03-25 18:39:22 +01:00
$msg = static :: action ( $content [ 'nm' ][ 'action' ], $content [ 'nm' ][ 'selected' ], $content [ 'nm' ][ 'path' ]);
if ( $msg )
{
Framework :: message ( $msg );
}
2014-02-06 00:36:01 +01:00
2011-12-27 12:08:41 +01:00
// clean up after action
unset ( $content [ 'nm' ][ 'selected' ]);
// reset any occasion where action may be stored, as it may be ressurected out of the helpers by etemplate, which is quite unconvenient in case of action delete
2020-03-25 18:39:22 +01:00
if ( isset ( $content [ 'nm' ][ 'action' ]))
{
unset ( $content [ 'nm' ][ 'action' ]);
}
if ( isset ( $content [ 'nm' ][ 'nm_action' ]))
{
unset ( $content [ 'nm' ][ 'nm_action' ]);
}
if ( isset ( $content [ 'nm_action' ]))
{
unset ( $content [ 'nm_action' ]);
}
2011-12-27 12:08:41 +01:00
// we dont use ['nm']['rows']['delete'], so unset it, if it is present
2020-03-25 18:39:22 +01:00
if ( isset ( $content [ 'nm' ][ 'rows' ][ 'delete' ]))
{
unset ( $content [ 'nm' ][ 'rows' ][ 'delete' ]);
}
2008-03-02 22:44:15 +01:00
}
2020-03-25 18:39:22 +01:00
elseif ( $content [ 'nm' ][ 'rows' ][ 'delete' ])
2008-03-02 22:44:15 +01:00
{
2020-03-25 18:39:22 +01:00
$msg = static :: action ( 'delete' , array_keys ( $content [ 'nm' ][ 'rows' ][ 'delete' ]), $content [ 'nm' ][ 'path' ]);
if ( $msg )
{
Framework :: message ( $msg );
}
2014-02-06 00:36:01 +01:00
2011-12-27 12:08:41 +01:00
// clean up after action
unset ( $content [ 'nm' ][ 'rows' ][ 'delete' ]);
// reset any occasion where action may be stored, as we use ['nm']['rows']['delete'] anyhow
// we clean this up, as it may be ressurected out of the helpers by etemplate, which is quite unconvenient in case of action delete
2020-03-25 18:39:22 +01:00
if ( isset ( $content [ 'nm' ][ 'action' ]))
{
unset ( $content [ 'nm' ][ 'action' ]);
}
if ( isset ( $content [ 'nm' ][ 'nm_action' ]))
{
unset ( $content [ 'nm' ][ 'nm_action' ]);
}
if ( isset ( $content [ 'nm_action' ]))
{
unset ( $content [ 'nm_action' ]);
}
if ( isset ( $content [ 'nm' ][ 'selected' ]))
{
unset ( $content [ 'nm' ][ 'selected' ]);
}
2008-03-02 22:44:15 +01:00
}
unset ( $content [ 'nm' ][ 'rows' ]);
2020-03-25 18:39:22 +01:00
Api\Cache :: setSession ( 'filemanager' , 'index' , $content [ 'nm' ]);
2008-03-02 22:44:15 +01:00
}
2010-05-11 17:02:30 +02:00
// be tolerant with (in previous versions) not correct urlencoded pathes
2020-03-25 18:39:22 +01:00
if ( $content [ 'nm' ][ 'path' ][ 0 ] == '/' && ! Vfs :: stat ( $content [ 'nm' ][ 'path' ], true ) && Vfs :: stat ( urldecode ( $content [ 'nm' ][ 'path' ])))
2010-05-11 17:02:30 +02:00
{
$content [ 'nm' ][ 'path' ] = urldecode ( $content [ 'nm' ][ 'path' ]);
}
2021-10-06 16:07:47 +02:00
if ( ! empty ( $content [ 'button' ]))
2008-03-02 22:44:15 +01:00
{
2021-10-06 16:07:47 +02:00
$button = key ( $content [ 'button' ]);
unset ( $content [ 'button' ]);
2020-03-25 18:39:22 +01:00
switch ( $button )
2008-03-02 22:44:15 +01:00
{
case 'upload' :
2009-02-26 15:48:53 +01:00
if ( ! $content [ 'upload' ])
{
2020-03-25 18:39:22 +01:00
Framework :: message ( lang ( 'You need to select some files first!' ), 'error' );
2009-02-26 15:48:53 +01:00
break ;
}
$upload_success = $upload_failure = array ();
2020-03-25 18:39:22 +01:00
foreach ( isset ( $content [ 'upload' ][ 0 ]) ? $content [ 'upload' ] : array ( $content [ 'upload' ]) as $upload )
2008-03-02 22:44:15 +01:00
{
2010-05-11 17:02:30 +02:00
// encode chars which special meaning in url/vfs (some like / get removed!)
2020-03-25 18:39:22 +01:00
$to = Vfs :: concat ( $content [ 'nm' ][ 'path' ], Vfs :: encodePathComponent ( $upload [ 'name' ]));
2013-02-05 10:27:41 +01:00
if ( $upload &&
2020-03-25 18:39:22 +01:00
( Vfs :: is_writable ( $content [ 'nm' ][ 'path' ]) || Vfs :: is_writable ( $to )) &&
copy ( $upload [ 'tmp_name' ], Vfs :: PREFIX . $to ))
2009-02-26 15:48:53 +01:00
{
$upload_success [] = $upload [ 'name' ];
}
else
{
$upload_failure [] = $upload [ 'name' ];
}
2008-03-02 22:44:15 +01:00
}
2009-02-26 15:48:53 +01:00
$content [ 'nm' ][ 'msg' ] = '' ;
if ( $upload_success )
2008-03-02 22:44:15 +01:00
{
2020-03-25 18:39:22 +01:00
Framework :: message ( count ( $upload_success ) == 1 && ! $upload_failure ? lang ( 'File successful uploaded.' ) :
lang ( '%1 successful uploaded.' , implode ( ', ' , $upload_success )));
2009-02-26 15:48:53 +01:00
}
if ( $upload_failure )
{
2020-03-25 18:39:22 +01:00
Framework :: message ( lang ( 'Error uploading file!' ) . " \n " . etemplate :: max_upload_size_message (), 'error' );
2008-03-02 22:44:15 +01:00
}
break ;
}
}
2014-05-27 09:30:33 +02:00
$readonlys [ 'button[mailpaste]' ] = ! isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'mail' ]);
2008-04-16 09:07:31 +02:00
2008-03-03 13:16:11 +01:00
$sel_options [ 'filter' ] = array (
2020-03-25 18:39:22 +01:00
'' => 'Current directory' ,
'2' => 'Directories sorted in' ,
'3' => 'Show hidden files' ,
'4' => 'All subdirectories' ,
'5' => 'Files from links' ,
'0' => 'Files from subdirectories' ,
2008-03-03 13:16:11 +01:00
);
2017-09-26 18:41:57 +02:00
$sel_options [ 'new' ] = self :: convertActionsToselOptions ( $content [ 'nm' ][ 'actions' ][ 'new' ][ 'children' ]);
2014-12-09 13:08:00 +01:00
// sharing has no divAppbox, we need to set popupMainDiv instead, to be able to drop files everywhere
if ( substr ( $_SERVER [ 'SCRIPT_FILENAME' ], - 10 ) == '/share.php' )
{
2020-03-25 03:34:04 +01:00
$tpl -> setElementAttribute ( 'nm[upload]' , 'drop_target' , 'popupMainDiv' );
2014-12-09 13:08:00 +01:00
}
2015-01-13 22:56:54 +01:00
// Set view button to match current settings
2020-03-25 18:39:22 +01:00
if ( $content [ 'nm' ][ 'view' ] == 'tile' )
2015-01-13 22:56:54 +01:00
{
2020-03-25 18:39:22 +01:00
$tpl -> setElementAttribute ( 'nm[button][change_view]' , 'statustext' , lang ( 'List view' ));
$tpl -> setElementAttribute ( 'nm[button][change_view]' , 'image' , 'list_row' );
2015-01-13 22:56:54 +01:00
}
2014-12-10 11:32:47 +01:00
// if initial load is done via GET request (idots template or share.php)
// get_rows cant call app.filemanager.set_readonly, so we need to do that here
2020-03-25 18:39:22 +01:00
if ( ! array_key_exists ( 'initial_path_readonly' , $content ))
{
$content [ 'initial_path_readonly' ] = ! Vfs :: is_writable ( $content [ 'nm' ][ 'path' ]);
}
2014-12-10 11:32:47 +01:00
2008-03-02 22:44:15 +01:00
$tpl -> exec ( 'filemanager.filemanager_ui.index' , $content , $sel_options , $readonlys , array ( 'nm' => $content [ 'nm' ]));
}
2008-03-04 17:53:14 +01:00
2008-10-14 15:20:31 +02:00
/**
* Get the configured start directory for the current user
*
* @ return string
*/
static function get_home_dir ()
{
$start = '/home/' . $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_lid' ];
// check if user specified a valid startpath in his prefs --> use it
if (( $path = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'filemanager' ][ 'startfolder' ]) &&
2016-03-21 11:06:54 +01:00
$path [ 0 ] == '/' && Vfs :: is_dir ( $path ) && Vfs :: check_access ( $path , Vfs :: READABLE ))
2008-10-14 15:20:31 +02:00
{
$start = $path ;
}
2016-03-21 11:06:54 +01:00
elseif ( ! Vfs :: is_dir ( $start ) && Vfs :: check_access ( $start , Vfs :: READABLE ))
2014-11-18 13:55:32 +01:00
{
$start = '/' ;
}
2008-10-14 15:20:31 +02:00
return $start ;
}
2008-03-02 22:44:15 +01:00
/**
* Run a certain action with the selected file
*
* @ param string $action
* @ param array $selected selected pathes
2014-05-27 09:30:33 +02:00
* @ param mixed $dir current directory
2010-12-28 04:12:57 +01:00
* @ param int & $errs = null on return number of errors
* @ param int & $dirs = null on return number of dirs deleted
* @ param int & $files = null on return number of files deleted
2008-03-02 22:44:15 +01:00
* @ return string success or failure message displayed to the user
*/
2014-12-05 20:34:12 +01:00
static public function action ( $action , $selected , $dir = null , & $errs = null , & $files = null , & $dirs = null )
2008-03-02 22:44:15 +01:00
{
2021-10-07 18:30:59 +02:00
if ( ! count (( array ) $selected ))
2008-03-02 22:44:15 +01:00
{
return lang ( 'You need to select some files first!' );
}
$errs = $dirs = $files = 0 ;
2012-05-03 19:58:16 +02:00
2008-03-02 22:44:15 +01:00
switch ( $action )
{
2010-05-06 08:53:52 +02:00
2008-03-02 22:44:15 +01:00
case 'delete' :
2014-11-18 13:55:32 +01:00
return static :: do_delete ( $selected , $errs , $files , $dirs );
2010-05-06 08:53:52 +02:00
2014-12-09 17:29:00 +01:00
case 'mail' :
2008-03-02 22:44:15 +01:00
case 'copy' :
foreach ( $selected as $path )
{
2014-10-17 00:41:39 +02:00
if ( strpos ( $path , 'mail::' ) === 0 && $path = substr ( $path , 6 ))
{
// Support for dropping mail in filemanager - Pass mail back to mail app
2017-11-17 18:31:15 +01:00
if ( ExecMethod2 ( 'mail.mail_ui.vfsSaveMessages' , $path , $dir ))
2014-10-17 00:41:39 +02:00
{
++ $files ;
}
else
{
++ $errs ;
}
}
2016-03-21 11:06:54 +01:00
elseif ( ! Vfs :: is_dir ( $path ))
2008-03-02 22:44:15 +01:00
{
2016-03-21 11:06:54 +01:00
$to = Vfs :: concat ( $dir , Vfs :: basename ( $path ));
if ( $path != $to && Vfs :: copy ( $path , $to ))
2008-03-02 22:44:15 +01:00
{
++ $files ;
}
else
{
++ $errs ;
}
}
else
{
$len = strlen ( dirname ( $path ));
2016-03-21 11:06:54 +01:00
foreach ( Vfs :: find ( $path ) as $p )
2008-03-02 22:44:15 +01:00
{
$to = $dir . substr ( $p , $len );
2008-03-04 08:35:05 +01:00
if ( $to == $p ) // cant copy into itself!
{
++ $errs ;
continue ;
}
2016-03-21 11:06:54 +01:00
if (( $is_dir = Vfs :: is_dir ( $p )) && Vfs :: mkdir ( $to , null , STREAM_MKDIR_RECURSIVE ))
2008-03-02 22:44:15 +01:00
{
++ $dirs ;
}
2016-03-21 11:06:54 +01:00
elseif ( ! $is_dir && Vfs :: copy ( $p , $to ))
2008-03-02 22:44:15 +01:00
{
++ $files ;
}
else
{
++ $errs ;
}
}
}
}
if ( $errs )
{
return lang ( '%1 errors copying (%2 diretories and %3 files copied)!' , $errs , $dirs , $files );
}
return $dirs ? lang ( '%1 directories and %2 files copied.' , $dirs , $files ) : lang ( '%1 files copied.' , $files );
2008-04-16 09:07:31 +02:00
2010-12-28 04:12:57 +01:00
case 'move' :
2008-03-02 22:44:15 +01:00
foreach ( $selected as $path )
{
2016-03-21 11:06:54 +01:00
$to = Vfs :: is_dir ( $dir ) || count ( $selected ) > 1 ? Vfs :: concat ( $dir , Vfs :: basename ( $path )) : $dir ;
if ( $path != $to && Vfs :: rename ( $path , $to ))
2008-03-02 22:44:15 +01:00
{
++ $files ;
}
else
{
++ $errs ;
}
}
if ( $errs )
{
return lang ( '%1 errors moving (%2 files moved)!' , $errs , $files );
}
return lang ( '%1 files moved.' , $files );
2009-04-09 16:05:14 +02:00
2013-04-12 10:56:28 +02:00
case 'symlink' : // symlink given files to $dir
foreach (( array ) $selected as $target )
2009-04-09 16:05:14 +02:00
{
2016-03-21 11:06:54 +01:00
$link = Vfs :: concat ( $dir , Vfs :: basename ( $target ));
if ( ! Vfs :: stat ( $dir ) || ( $ok = Vfs :: mkdir ( $dir , 0 , true )))
2014-09-01 23:23:04 +02:00
{
if ( ! $ok )
{
$errs ++ ;
continue ;
}
}
2016-03-21 11:06:54 +01:00
if ( $target [ 0 ] != '/' ) $target = Vfs :: concat ( $dir , $target );
if ( ! Vfs :: stat ( $target ))
2013-04-12 10:56:28 +02:00
{
2016-03-21 11:06:54 +01:00
return lang ( 'Link target %1 not found!' , Vfs :: decodePath ( $target ));
2013-04-12 10:56:28 +02:00
}
2016-03-21 11:06:54 +01:00
if ( $target != $link && Vfs :: symlink ( $target , $link ))
2009-04-09 16:05:14 +02:00
{
++ $files ;
}
else
{
++ $errs ;
}
}
2013-04-12 10:56:28 +02:00
if ( count (( array ) $selected ) == 1 )
{
2016-03-21 11:06:54 +01:00
return $files ? lang ( 'Symlink to %1 created.' , Vfs :: decodePath ( $target )) :
lang ( 'Error creating symlink to target %1!' , Vfs :: decodePath ( $target ));
2013-04-12 10:56:28 +02:00
}
$ret = lang ( '%1 elements linked.' , $files );
2009-04-09 16:05:14 +02:00
if ( $errs )
{
2013-04-12 10:56:28 +02:00
$ret = lang ( '%1 errors linking (%2)!' , $errs , $ret );
2009-04-09 16:05:14 +02:00
}
2016-03-21 11:06:54 +01:00
return $ret ; //." Vfs::symlink('$target', '$link')";
2013-04-11 15:16:40 +02:00
case 'createdir' :
2016-03-21 11:06:54 +01:00
$dst = Vfs :: concat ( $dir , is_array ( $selected ) ? $selected [ 0 ] : $selected );
2021-10-27 19:55:31 +02:00
if ( Vfs :: mkdir ( $dst , null , STREAM_MKDIR_RECURSIVE ))
2013-04-11 15:16:40 +02:00
{
2013-04-12 10:07:26 +02:00
return lang ( " Directory successfully created. " );
2013-04-11 15:16:40 +02:00
}
2013-04-12 10:07:26 +02:00
return lang ( " Error while creating directory. " );
2013-04-11 15:16:40 +02:00
2014-06-24 21:29:05 +02:00
case 'saveaszip' :
2016-03-21 11:06:54 +01:00
Vfs :: download_zip ( $selected );
exit ;
2021-10-27 19:55:31 +02:00
case 'unlock' :
foreach (( array ) $selected as $target )
{
$link = Vfs :: concat ( $dir , Vfs :: basename ( $target ));
$lock = Vfs :: checkLock ( $link );
if ( $lock && Vfs :: unlock ( $link , $lock [ 'token' ]))
{
$files ++ ;
}
else
{
$errs ++ ;
}
}
return lang ( '%1 files unlocked.' , $files );
2012-05-11 12:30:52 +02:00
default :
list ( $action , $settings ) = explode ( '_' , $action , 2 );
switch ( $action )
{
case 'document' :
2021-10-27 19:55:31 +02:00
if ( ! $settings )
{
$settings = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'filemanager' ][ 'default_document' ];
}
2016-03-21 11:06:54 +01:00
$document_merge = new filemanager_merge ( Vfs :: decodePath ( $dir ));
2012-05-11 12:30:52 +02:00
$msg = $document_merge -> download ( $settings , $selected , '' , $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'filemanager' ][ 'document_dir' ]);
2021-10-27 19:55:31 +02:00
if ( $msg )
{
return $msg ;
}
2014-11-18 13:55:32 +01:00
$errs = count ( $selected );
2012-05-11 12:30:52 +02:00
return false ;
}
2008-03-02 22:44:15 +01:00
}
return " Unknown action ' $action '! " ;
}
2010-12-28 04:12:57 +01:00
2010-09-24 20:55:36 +02:00
/**
* Delete selected files and return success or error message
2010-12-28 04:12:57 +01:00
*
2010-09-24 20:55:36 +02:00
* @ param array $selected
2010-12-28 04:12:57 +01:00
* @ param int & $errs = null on return number of errors
* @ param int & $dirs = null on return number of dirs deleted
* @ param int & $files = null on return number of files deleted
2010-09-24 20:55:36 +02:00
* @ return string
*/
2010-12-28 04:12:57 +01:00
public static function do_delete ( array $selected , & $errs = null , & $dirs = null , & $files = null )
2010-09-24 20:55:36 +02:00
{
$dirs = $files = $errs = 0 ;
// we first delete all selected links (and files)
2016-03-21 11:06:54 +01:00
// feeding the links to dirs to Vfs::find() deletes the content of the dirs, not just the link!
2010-09-24 20:55:36 +02:00
foreach ( $selected as $key => $path )
{
2020-10-21 00:47:26 +02:00
if ( Vfs :: is_dir ( $path ) && $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'vfs_fstab' ][ $path ])
{
// Trying to delete a share. Unmount.
$root = Vfs :: $is_root ;
Vfs :: $is_root = true ;
Vfs :: umount ( $path );
Vfs :: $is_root = $root ;
++ $dirs ;
unset ( $selected [ $key ]);
}
else if ( ! Vfs :: is_dir ( $path ) || Vfs :: is_link ( $path ))
2010-09-24 20:55:36 +02:00
{
2016-03-21 11:06:54 +01:00
if ( Vfs :: unlink ( $path ))
2010-09-24 20:55:36 +02:00
{
++ $files ;
}
else
{
++ $errs ;
}
unset ( $selected [ $key ]);
}
}
if ( $selected ) // somethings left to delete
{
// some precaution to never allow to (recursivly) remove /, /apps or /home
foreach (( array ) $selected as $path )
{
2016-08-18 10:03:53 +02:00
if ( Vfs :: isProtectedDir ( $path ))
2010-09-24 20:55:36 +02:00
{
2010-12-28 04:12:57 +01:00
$errs ++ ;
2016-03-21 11:06:54 +01:00
return lang ( " Cautiously rejecting to remove folder '%1'! " , Vfs :: decodePath ( $path ));
2010-09-24 20:55:36 +02:00
}
}
// now we use find to loop through all files and dirs: (selected only contains dirs now)
// - depth=true to get first the files and then the dir containing it
// - hidden=true to also return hidden files (eg. Thumbs.db), as we cant delete non-empty dirs
2016-01-21 12:49:50 +01:00
// - show-deleted=false to not (finally) deleted versioned files
2016-03-21 11:06:54 +01:00
foreach ( Vfs :: find ( $selected , array ( 'depth' => true , 'hidden' => true , 'show-deleted' => false )) as $path )
2010-09-24 20:55:36 +02:00
{
2016-03-21 11:06:54 +01:00
if (( $is_dir = Vfs :: is_dir ( $path ) && ! Vfs :: is_link ( $path )) && Vfs :: rmdir ( $path , 0 ))
2010-09-24 20:55:36 +02:00
{
++ $dirs ;
}
2016-03-21 11:06:54 +01:00
elseif ( ! $is_dir && Vfs :: unlink ( $path ))
2010-09-24 20:55:36 +02:00
{
++ $files ;
}
else
{
++ $errs ;
}
}
}
if ( $errs )
{
return lang ( '%1 errors deleteting (%2 directories and %3 files deleted)!' , $errs , $dirs , $files );
}
if ( $dirs )
{
return lang ( '%1 directories and %2 files deleted.' , $dirs , $files );
}
return $files == 1 ? lang ( 'File deleted.' ) : lang ( '%1 files deleted.' , $files );
}
2008-03-02 22:44:15 +01:00
/**
* Callback to fetch the rows for the nextmatch widget
*
* @ param array $query
* @ param array & $rows
*/
2015-01-13 22:56:54 +01:00
function get_rows ( & $query , & $rows )
2008-03-02 22:44:15 +01:00
{
2020-06-08 18:18:15 +02:00
$old_session = Api\Cache :: getSession ( 'filemanager' , 'index' );
2013-04-20 14:24:45 +02:00
// do NOT store query, if hierarchical data / children are requested
2013-10-10 13:29:31 +02:00
if ( ! $query [ 'csv_export' ])
2013-04-20 14:24:45 +02:00
{
2021-05-07 18:27:27 +02:00
$store_query = array_diff_key ( $query , array_flip ( array ( 'rows' , 'actions' , 'action_links' , 'placeholder_actions' )));
// Don't store mime filter from expose, just in case user reloads and the UI can't remove it
unset ( $store_query [ 'col_filter' ][ 'mime' ]);
Api\Cache :: setSession ( 'filemanager' , 'index' , $store_query );
2013-04-20 14:24:45 +02:00
}
2014-11-18 13:55:32 +01:00
if ( ! $query [ 'path' ]) $query [ 'path' ] = static :: get_home_dir ();
2014-06-04 14:08:57 +02:00
2015-01-13 22:56:54 +01:00
// Change template to match selected view
if ( $query [ 'view' ])
{
$query [ 'template' ] = ( $query [ 'view' ] == 'row' ? 'filemanager.index.rows' : 'filemanager.tile' );
2015-01-16 18:07:18 +01:00
// Store as preference but only for index, not home
if ( $query [ 'get_rows' ] == 'filemanager.filemanager_ui.get_rows' )
{
$GLOBALS [ 'egw' ] -> preferences -> add ( 'filemanager' , 'nm_view' , $query [ 'view' ]);
$GLOBALS [ 'egw' ] -> preferences -> save_repository ();
}
2015-01-13 22:56:54 +01:00
}
2010-05-11 17:02:30 +02:00
// be tolerant with (in previous versions) not correct urlencoded pathes
2016-03-21 11:06:54 +01:00
if ( ! Vfs :: stat ( $query [ 'path' ], true ) && Vfs :: stat ( urldecode ( $query [ 'path' ])))
2010-05-11 17:02:30 +02:00
{
$query [ 'path' ] = urldecode ( $query [ 'path' ]);
}
2016-03-21 11:06:54 +01:00
if ( ! Vfs :: stat ( $query [ 'path' ], true ) || ! Vfs :: is_dir ( $query [ 'path' ]) || ! Vfs :: check_access ( $query [ 'path' ], Vfs :: READABLE ))
2008-03-02 22:44:15 +01:00
{
2014-11-18 13:55:32 +01:00
// only redirect, if it would be to some other location, gives redirect-loop otherwise
2020-06-08 18:18:15 +02:00
foreach ([ $old_session [ 'path' ], static :: get_home_dir ()] as $new_path )
2014-11-18 13:55:32 +01:00
{
2020-06-08 18:18:15 +02:00
if ( $new_path && Vfs :: stat ( $new_path ) && $query [ 'path' ] != $new_path )
{
// we will leave here, since we are not allowed, or the location does not exist. Index must handle that, and give
// an appropriate message
Egw :: redirect_link ( '/index.php' , array ( 'menuaction' => 'filemanager.filemanager_ui.index' ,
'path' => $new_path ,
'msg' => lang ( 'The requested path %1 is not available.' , Vfs :: decodePath ( $query [ 'path' ])),
'ajax' => 'true'
));
break ;
}
2014-11-18 13:55:32 +01:00
}
$rows = array ();
return 0 ;
2008-03-02 22:44:15 +01:00
}
2018-12-20 18:45:11 +01:00
$GLOBALS [ 'egw' ] -> session -> commit_session ();
2008-03-03 13:16:11 +01:00
$rows = $dir_is_writable = array ();
2018-04-09 22:01:36 +02:00
$vfs_options = $this -> get_vfs_options ( $query );
2022-11-04 23:28:01 +01:00
if ( $query [ 'col_filter' ][ 'path' ] && $vfs_options [ 'name' ])
{
// Query the requested path, in case it's nested
2023-06-08 22:14:41 +02:00
if ( ! is_array ( $query [ 'col_filter' ][ 'path' ]))
2023-06-08 21:37:38 +02:00
{
2023-06-08 22:14:41 +02:00
$query [ 'col_filter' ][ 'path' ] = $query [ 'col_filter' ][ 'path' ] ? [ $query [ 'col_filter' ][ 'path' ]] : [];
2023-06-08 21:37:38 +02:00
}
2023-06-08 21:58:46 +02:00
$query [ 'col_filter' ][ 'path' ][] = $query [ 'path' ];
2022-11-04 23:28:01 +01:00
foreach ( $query [ 'col_filter' ][ 'path' ] as $filter_path )
{
$query [ 'col_filter' ][ 'dir' ][] = Vfs :: is_dir ( $filter_path ) ? $filter_path : Vfs :: dirname ( $filter_path );
}
}
2021-10-28 21:08:31 +02:00
// query and cache locks for whole directory
$locks = [];
foreach ( ! empty ( $query [ 'col_filter' ][ 'dir' ]) ? ( array ) $query [ 'col_filter' ][ 'dir' ] : ( array ) $query [ 'path' ] as $path )
{
$locks += Vfs :: checkLock ( $path , 999 );
}
$n = 0 ;
2016-03-21 11:06:54 +01:00
foreach ( Vfs :: find ( ! empty ( $query [ 'col_filter' ][ 'dir' ]) ? $query [ 'col_filter' ][ 'dir' ] : $query [ 'path' ], $vfs_options , true ) as $path => $row )
2008-10-06 19:43:42 +02:00
{
//echo $path; _debug_array($row);
2008-10-05 19:07:36 +02:00
2008-10-06 19:43:42 +02:00
$dir = dirname ( $path );
if ( ! isset ( $dir_is_writable [ $dir ]))
2008-03-03 13:16:11 +01:00
{
2016-03-21 11:06:54 +01:00
$dir_is_writable [ $dir ] = Vfs :: is_writable ( $dir );
2008-03-03 13:16:11 +01:00
}
2016-03-21 11:06:54 +01:00
if ( Vfs :: is_dir ( $path ))
2011-08-29 10:40:22 +02:00
{
2016-08-29 17:37:07 +02:00
if ( ! isset ( $dir_is_writable [ $path ]))
{
$dir_is_writable [ $path ] = Vfs :: is_writable ( $path );
}
2017-10-30 18:25:12 +01:00
2016-08-29 17:37:07 +02:00
$row [ 'class' ] .= 'isDir ' ;
2016-08-29 19:49:20 +02:00
$row [ 'is_dir' ] = 1 ;
2018-01-30 12:26:45 +01:00
if ( ! $dir_is_writable [ $path ])
{
$row [ 'class' ] .= 'noEdit ' ;
}
2020-06-08 18:18:15 +02:00
if ( ! Vfs :: is_executable ( $path ))
{
$row [ 'class' ] .= 'noExecute' ;
}
2011-08-29 10:40:22 +02:00
}
2021-10-27 19:55:31 +02:00
elseif ( ! $dir_is_writable [ Vfs :: dirname ( $path )])
2017-10-30 18:25:12 +01:00
{
$row [ 'class' ] .= 'noEdit ' ;
}
2021-10-28 21:08:31 +02:00
if ( ! empty ( $lock = $locks [ $path ]))
2021-10-27 19:55:31 +02:00
{
$row [ 'locked' ] = 'lock' ;
2021-10-28 18:27:22 +02:00
$row [ 'locked_status' ] = lang (
" LOCK from %1, created %2 " ,
// Not sure why sometimes the lock is owned by a user ID, sometimes mailto:user@email
is_numeric ( $lock [ 'owner' ]) ? $GLOBALS [ 'egw' ] -> accounts -> username ( $lock [ 'owner' ]) : str_replace ( 'mailto:' , '' , $lock [ 'owner' ]),
Api\DateTime :: to ( APi\DateTime :: server2user ( $lock [ 'created' ]), '' )
);
2021-10-27 19:55:31 +02:00
if ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'admin' ] || Vfs :: $is_admin || Vfs :: $is_root ||
$lock [ 'owner' ] == $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ] ||
$lock [ 'owner' ] == 'mailto:' . $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_email' ]
)
{
$row [ 'class' ] .= ' locked ' ;
}
}
2018-03-12 11:11:13 +01:00
2017-11-07 12:19:57 +01:00
$row [ 'class' ] .= ! $dir_is_writable [ $dir ] ? 'noDelete' : '' ;
2016-03-21 11:06:54 +01:00
$row [ 'download_url' ] = Vfs :: download_url ( $path );
2021-10-27 19:55:31 +02:00
$row [ 'gid' ] = - abs ( $row [ 'gid' ]); // gid are positive, but we use negagive account_id for groups internal
2013-04-09 18:20:06 +02:00
2021-10-27 19:55:31 +02:00
foreach ([ 'mtime' , 'ctime' ] as $date_field )
2020-11-30 21:29:39 +01:00
{
2020-12-09 22:30:47 +01:00
$row [ $date_field ] = Api\DateTime :: server2user ( $row [ $date_field ]);
2020-11-30 21:29:39 +01:00
}
2024-08-06 14:00:55 +02:00
// do NOT send URL to client-side, it can contain passwords
unset ( $row [ 'url' ]);
2011-08-29 10:40:22 +02:00
$rows [ ++ $n ] = $row ;
$path2n [ $path ] = $n ;
2008-03-02 22:44:15 +01:00
}
2008-10-05 19:07:36 +02:00
// query comments and cf's for the displayed rows
$cols_to_show = explode ( ',' , $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'filemanager' ][ 'nextmatch-filemanager.index.rows' ]);
2015-03-27 10:28:46 +01:00
2015-01-16 17:50:52 +01:00
// Always include comment in tiles
if ( $query [ 'view' ] == 'tile' )
{
$cols_to_show [] = 'comment' ;
}
2008-10-05 19:07:36 +02:00
$all_cfs = in_array ( 'customfields' , $cols_to_show ) && $cols_to_show [ count ( $cols_to_show ) - 1 ][ 0 ] != '#' ;
if ( $path2n && ( in_array ( 'comment' , $cols_to_show ) || in_array ( 'customfields' , $cols_to_show )) &&
2016-03-21 11:06:54 +01:00
( $path2props = Vfs :: propfind ( array_keys ( $path2n ))))
2008-10-05 19:07:36 +02:00
{
foreach ( $path2props as $path => $props )
{
2008-10-21 11:08:37 +02:00
unset ( $row ); // fixes a weird problem with php5.1, does NOT happen with php5.2
2008-10-05 19:07:36 +02:00
$row =& $rows [ $path2n [ $path ]];
2009-02-27 11:22:28 +01:00
if ( ! is_array ( $props ) ) continue ;
2008-10-05 19:07:36 +02:00
foreach ( $props as $prop )
{
if ( ! $all_cfs && $prop [ 'name' ][ 0 ] == '#' && ! in_array ( $prop [ 'name' ], $cols_to_show )) continue ;
2008-10-05 21:01:49 +02:00
$row [ $prop [ 'name' ]] = strlen ( $prop [ 'val' ]) < 64 ? $prop [ 'val' ] : substr ( $prop [ 'val' ], 0 , 64 ) . ' ...' ;
2008-10-05 19:07:36 +02:00
}
}
}
2013-04-12 19:57:12 +02:00
// tell client-side if directory is writeable or not
2016-03-21 11:06:54 +01:00
$response = Api\Json\Response :: get ();
$response -> call ( 'app.filemanager.set_readonly' , $query [ 'path' ], ! Vfs :: is_writable ( $query [ 'path' ]));
2013-04-12 11:33:37 +02:00
2008-03-02 22:44:15 +01:00
//_debug_array($readonlys);
2009-05-06 17:15:39 +02:00
if ( $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ] == 'projectmanager' )
{
// we need our app.css file
if ( ! file_exists ( EGW_SERVER_ROOT . ( $css_file = '/filemanager/templates/' . $GLOBALS [ 'egw_info' ][ 'server' ][ 'template_set' ] . '/app.css' )))
{
$css_file = '/filemanager/templates/default/app.css' ;
}
$GLOBALS [ 'egw_info' ][ 'flags' ][ 'css' ] .= " \n \t \t </style> \n \t \t " . '<link href="' . $GLOBALS [ 'egw_info' ][ 'server' ][ 'webserver_url' ] .
$css_file . '?' . filemtime ( EGW_SERVER_ROOT . $css_file ) . '" type="text/css" rel="StyleSheet" />' . " \n \t \t <style> \n \t \t \t " ;
}
2016-03-21 11:06:54 +01:00
return Vfs :: $find_total ;
2008-03-02 22:44:15 +01:00
}
2008-04-16 09:07:31 +02:00
2018-04-09 22:01:36 +02:00
/**
* Get the VFS options ( for get rows )
*/
protected function get_vfs_options ( $query )
{
if ( $query [ 'searchletter' ] && ! empty ( $query [ 'search' ]))
{
$namefilter = '/^' . $query [ 'searchletter' ] . '.*' . str_replace ( array ( '\\?' , '\\*' ), array ( '.{1}' , '.*' ), preg_quote ( $query [ 'search' ])) . '/i' ;
if ( $query [ 'searchletter' ] == strtolower ( $query [ 'search' ][ 0 ]))
{
$namefilter = '/^(' . $query [ 'searchletter' ] . '.*' . str_replace ( array ( '\\?' , '\\*' ), array ( '.{1}' , '.*' ), preg_quote ( $query [ 'search' ])) . '|' .
str_replace ( array ( '\\?' , '\\*' ), array ( '.{1}' , '.*' ), preg_quote ( $query [ 'search' ])) . ')/i' ;
}
}
elseif ( $query [ 'searchletter' ])
{
$namefilter = '/^' . $query [ 'searchletter' ] . '/i' ;
}
elseif ( ! empty ( $query [ 'search' ]))
{
$namefilter = '/' . str_replace ( array ( '\\?' , '\\*' ), array ( '.{1}' , '.*' ), preg_quote ( $query [ 'search' ])) . '/i' ;
}
// Re-map so 'No filters' favorite ('') is depth 1
$filter = $query [ 'filter' ] === '' ? 1 : $query [ 'filter' ];
$maxdepth = $filter && $filter != 4 ? ( int )( boolean ) $filter : null ;
if ( $filter == 5 ) $maxdepth = 2 ;
$n = 0 ;
$vfs_options = array (
'mindepth' => 1 ,
'maxdepth' => $maxdepth ,
'dirsontop' => $filter <= 1 ,
'type' => $filter && $filter != 5 ? ( $filter == 4 ? 'd' : null ) : ( $filter == 5 ? 'F' : 'f' ),
'order' => $query [ 'order' ], 'sort' => $query [ 'sort' ],
'limit' => ( int ) $query [ 'num_rows' ] . ',' . ( int ) $query [ 'start' ],
'need_mime' => true ,
'name_preg' => $namefilter ,
'hidden' => $filter == 3 ,
'follow' => $filter == 5 ,
);
if ( $query [ 'col_filter' ][ 'mime' ])
{
$vfs_options [ 'mime' ] = $query [ 'col_filter' ][ 'mime' ];
}
2020-03-04 21:53:26 +01:00
if ( $namefilter )
{
$vfs_options [ 'name' ] = $query [ 'search' ];
}
2022-11-04 23:28:01 +01:00
if ( $query [ 'col_filter' ][ 'path' ])
{
$path = is_array ( $query [ 'col_filter' ][ 'path' ]) ? $query [ 'col_filter' ][ 'path' ][ 0 ] : $query [ 'col_filter' ][ 'path' ];
$vfs_options [ 'name' ] = Vfs :: basename ( $path );
}
2018-04-09 22:01:36 +02:00
return $vfs_options ;
}
2008-03-03 23:15:44 +01:00
/**
* Preferences of a file / directory
*
2014-05-27 09:30:33 +02:00
* @ param array $content
* @ param string $msg
2008-03-03 23:15:44 +01:00
*/
2008-04-14 07:54:10 +02:00
function file ( array $content = null , $msg = '' )
2008-03-03 23:15:44 +01:00
{
2016-05-05 09:20:07 +02:00
$tpl = new Etemplate ( 'filemanager.file' );
2008-04-16 09:07:31 +02:00
2008-03-03 23:15:44 +01:00
if ( ! is_array ( $content ))
{
2010-04-22 19:38:01 +02:00
if ( isset ( $_GET [ 'msg' ]))
{
$msg .= $_GET [ 'msg' ];
}
2011-09-05 12:25:28 +02:00
if ( ! ( $path = str_replace ( array ( '#' , '?' ), array ( '%23' , '%3F' ), $_GET [ 'path' ])) || // ?, # need to stay encoded!
// actions enclose pathes containing comma with "
( $path [ 0 ] == '"' && substr ( $path , - 1 ) == '"' && ! ( $path = substr ( str_replace ( '""' , '"' , $path ), 1 , - 1 ))) ||
2016-03-21 11:06:54 +01:00
! ( $stat = Vfs :: lstat ( $path )))
2008-03-03 23:15:44 +01:00
{
2011-09-05 12:25:28 +02:00
$msg .= lang ( 'File or directory not found!' ) . " path=' $path ', stat= " . array2string ( $stat );
2008-03-03 23:15:44 +01:00
}
else
{
$content = $stat ;
2024-08-06 14:00:55 +02:00
// do NOT send URL to client-side, it can contain passwords
unset ( $content [ 'url' ]);
2016-03-21 11:06:54 +01:00
$content [ 'name' ] = $content [ 'itempicker_merge' ][ 'name' ] = Vfs :: basename ( $path );
2016-07-02 12:39:28 +02:00
$content [ 'dir' ] = $content [ 'itempicker_merge' ][ 'dir' ] = ( $dir = Vfs :: dirname ( $path )) ? Vfs :: decodePath ( $dir ) : '' ;
2008-03-03 23:15:44 +01:00
$content [ 'path' ] = $path ;
2016-03-21 11:06:54 +01:00
$content [ 'hsize' ] = Vfs :: hsize ( $stat [ 'size' ]);
$content [ 'mime' ] = Vfs :: mime_content_type ( $path );
2008-03-03 23:15:44 +01:00
$content [ 'gid' ] *= - 1 ; // our widgets use negative gid's
2016-03-21 11:06:54 +01:00
if (( $props = Vfs :: propfind ( $path )))
2008-10-05 19:07:36 +02:00
{
2014-05-27 09:30:33 +02:00
foreach ( $props as $prop )
{
$content [ $prop [ 'name' ]] = $prop [ 'val' ];
}
2008-10-05 19:07:36 +02:00
}
2016-03-21 11:06:54 +01:00
if (( $content [ 'is_link' ] = Vfs :: is_link ( $path )))
2009-03-19 21:12:35 +01:00
{
2016-03-21 11:06:54 +01:00
$content [ 'symlink' ] = Vfs :: readlink ( $path );
2009-03-19 21:12:35 +01:00
}
2008-03-03 23:15:44 +01:00
}
2009-03-19 21:12:35 +01:00
$content [ 'tabs' ] = $_GET [ 'tabs' ];
2016-03-21 11:06:54 +01:00
if ( ! ( $content [ 'is_dir' ] = Vfs :: is_dir ( $path ) && ! Vfs :: is_link ( $path )))
2008-03-03 23:15:44 +01:00
{
$content [ 'perms' ][ 'executable' ] = ( int ) !! ( $content [ 'mode' ] & 0111 );
$mask = 6 ;
if ( preg_match ( '/^text/' , $content [ 'mime' ]) && $content [ 'size' ] < 100000 )
{
2016-03-21 11:06:54 +01:00
$content [ 'text_content' ] = file_get_contents ( Vfs :: PREFIX . $path );
2008-03-03 23:15:44 +01:00
}
}
else
{
2008-04-14 07:54:10 +02:00
//currently not implemented in backend $content['perms']['sticky'] = (int)!!($content['mode'] & 0x201);
2008-03-03 23:15:44 +01:00
$mask = 7 ;
}
foreach ( array ( 'owner' => 6 , 'group' => 3 , 'other' => 0 ) as $name => $shift )
{
$content [ 'perms' ][ $name ] = ( $content [ 'mode' ] >> $shift ) & $mask ;
}
2016-03-21 11:06:54 +01:00
$content [ 'is_owner' ] = Vfs :: has_owner_rights ( $path , $content );
2008-03-03 23:15:44 +01:00
}
else
{
2008-04-14 07:54:10 +02:00
//_debug_array($content);
2008-07-27 20:58:41 +02:00
$path =& $content [ 'path' ];
2008-04-16 09:07:31 +02:00
2021-09-27 17:28:41 +02:00
$button = @ key ( $content [ 'button' ] ? ? []);
2019-02-12 22:13:45 +01:00
unset ( $content [ 'button' ]);
2021-06-10 22:12:25 +02:00
if ( ! $button && $content [ 'sudo' ] && $content [ 'sudouser' ])
2013-12-16 19:46:48 +01:00
{
// Button to stop sudo is not in button namespace
$button = 'sudo' ;
2021-06-10 22:12:25 +02:00
unset ( $content [ 'sudo' ], $content [ 'sudouser' ]);
2013-12-16 19:46:48 +01:00
}
2010-05-11 17:02:30 +02:00
// need to check 'setup' button (submit button in sudo popup), as some browsers (eg. chrome) also fill the hidden field
2016-03-21 11:06:54 +01:00
if ( $button == 'sudo' && Vfs :: $is_root || $button == 'setup' && $content [ 'sudo' ][ 'user' ])
2008-11-09 17:33:09 +01:00
{
2021-09-13 16:16:36 +02:00
$this -> sudo ( $button === 'setup' ? $content [ 'sudo' ][ 'user' ] : '' , $content [ 'sudo' ][ 'passwd' ], $msg );
2008-11-09 17:33:09 +01:00
unset ( $content [ 'sudo' ]);
2016-03-21 11:06:54 +01:00
$content [ 'is_owner' ] = Vfs :: has_owner_rights ( $path );
2008-11-09 17:33:09 +01:00
}
2008-04-14 07:54:10 +02:00
if ( in_array ( $button , array ( 'save' , 'apply' )))
2008-03-03 23:15:44 +01:00
{
2008-10-05 19:07:36 +02:00
$props = array ();
2014-11-18 13:55:32 +01:00
$perm_changed = $perm_failed = 0 ;
2008-04-14 07:54:10 +02:00
foreach ( $content [ 'old' ] as $name => $old_value )
2008-03-03 23:15:44 +01:00
{
2009-06-14 15:26:07 +02:00
if ( isset ( $content [ $name ]) && ( $old_value != $content [ $name ] ||
// do not check for modification, if modify_subs is checked!
2009-12-01 10:07:18 +01:00
$content [ 'modify_subs' ] && in_array ( $name , array ( 'uid' , 'gid' , 'perms' ))) &&
2016-03-21 11:06:54 +01:00
( $name != 'uid' || Vfs :: $is_root ))
2008-03-03 23:15:44 +01:00
{
2008-10-05 19:07:36 +02:00
if ( $name == 'name' )
{
2016-07-02 12:39:28 +02:00
if ( ! ( $dir = Vfs :: dirname ( $path )))
{
$msg .= lang ( 'File or directory not found!' ) . " Vfs::dirname(' $path ')===false " ;
if ( $button == 'save' ) $button = 'apply' ;
continue ;
}
$to = Vfs :: concat ( $dir , $content [ 'name' ]);
2016-03-21 11:06:54 +01:00
if ( file_exists ( Vfs :: PREFIX . $to ) && $content [ 'confirm_overwrite' ] !== $to )
2008-11-16 11:18:19 +01:00
{
$tpl -> set_validation_error ( 'name' , lang ( " There's already a file with that name! " ) . '<br />' .
lang ( 'To overwrite the existing file store again.' , lang ( $button )));
$content [ 'confirm_overwrite' ] = $to ;
if ( $button == 'save' ) $button = 'apply' ;
continue ;
}
2016-03-21 11:06:54 +01:00
if ( Vfs :: rename ( $path , $to ))
2008-10-05 19:07:36 +02:00
{
2016-03-21 11:06:54 +01:00
$msg .= lang ( 'Renamed %1 to %2.' , Vfs :: decodePath ( basename ( $path )), Vfs :: decodePath ( basename ( $to ))) . ' ' ;
2008-10-05 19:07:36 +02:00
$content [ 'old' ][ 'name' ] = $content [ $name ];
$path = $to ;
2016-05-05 09:20:07 +02:00
$content [ 'mime' ] = Api\MimeMagic :: filename2mime ( $path ); // recheck mime type
2016-03-21 11:06:54 +01:00
$refresh_path = Vfs :: dirname ( $path ); // for renames, we have to refresh the parent
2008-10-05 19:07:36 +02:00
}
else
{
2016-03-21 11:06:54 +01:00
$msg .= lang ( 'Rename of %1 to %2 failed!' , Vfs :: decodePath ( basename ( $path )), Vfs :: decodePath ( basename ( $to ))) . ' ' ;
if ( Vfs :: deny_script ( $to ))
2009-03-31 13:30:12 +02:00
{
$msg .= lang ( 'You are NOT allowed to upload a script!' ) . ' ' ;
}
2008-10-05 19:07:36 +02:00
}
}
elseif ( $name [ 0 ] == '#' || $name == 'comment' )
2008-04-14 07:54:10 +02:00
{
2008-10-05 21:01:49 +02:00
$props [] = array ( 'name' => $name , 'val' => $content [ $name ] ? $content [ $name ] : null );
2008-04-14 07:54:10 +02:00
}
2012-10-27 13:38:47 +02:00
elseif ( $name == 'mergeapp' )
{
$mergeprop = array (
array (
2014-11-18 13:55:32 +01:00
'ns' => static :: $merge_prop_namespace ,
2012-10-27 13:38:47 +02:00
'name' => 'mergeapp' ,
'val' => ( ! empty ( $content [ $name ]) ? $content [ $name ] : null ),
),
);
2016-03-21 11:06:54 +01:00
if ( Vfs :: proppatch ( $path , $mergeprop ))
2012-10-27 13:38:47 +02:00
{
$content [ 'old' ][ $name ] = $content [ $name ];
$msg .= lang ( 'Setting for document merge saved.' );
}
else
{
$msg .= lang ( 'Saving setting for document merge failed!' );
}
}
2008-10-05 19:07:36 +02:00
else
{
static $name2cmd = array ( 'uid' => 'chown' , 'gid' => 'chgrp' , 'perms' => 'chmod' );
2017-03-31 09:05:01 +02:00
$cmd = array ( 'EGroupware\\Api\\Vfs' , $name2cmd [ $name ]);
2024-01-18 09:33:47 +01:00
$value = $name == 'perms' ? static :: perms2mode ( $content [ 'perms' ]) : ( $content [ $name ] ? ? '' );
if ( $value === '' ) continue ;
2008-11-09 17:33:09 +01:00
if ( $content [ 'modify_subs' ])
2008-10-05 19:07:36 +02:00
{
2008-11-09 17:33:09 +01:00
if ( $name == 'perms' )
{
2016-03-21 11:06:54 +01:00
$changed = Vfs :: find ( $path , array ( 'type' => 'd' ), $cmd , array ( $value ));
$changed += Vfs :: find ( $path , array ( 'type' => 'f' ), $cmd , array ( $value & 0666 )); // no execute for files
2008-11-09 17:33:09 +01:00
}
else
{
2016-03-21 11:06:54 +01:00
$changed = Vfs :: find ( $path , null , $cmd , array ( $value ));
2008-11-09 17:33:09 +01:00
}
$ok = $failed = 0 ;
2021-03-29 23:56:00 +02:00
foreach ( $changed as $sub_path => & $r )
2008-11-09 17:33:09 +01:00
{
if ( $r )
{
++ $ok ;
2021-03-29 23:56:00 +02:00
// Changing owner does not change mtime. Clear subs on UI so they get reloaded
if ( $sub_path == $path ) continue ;
Api\Json\Response :: get () -> apply ( 'egw.dataStoreUID' ,[ 'filemanager::' . $sub_path , null ]);
2008-11-09 17:33:09 +01:00
}
else
{
++ $failed ;
}
}
if ( $ok && ! $failed )
{
2009-06-14 15:26:07 +02:00
if ( ! $perm_changed ++ ) $msg .= lang ( 'Permissions of %1 changed.' , $path . ' ' . lang ( 'and all it\'s childeren' ));
2008-11-12 18:04:38 +01:00
$content [ 'old' ][ $name ] = $content [ $name ];
2008-11-09 17:33:09 +01:00
}
elseif ( $failed )
{
2009-06-14 15:26:07 +02:00
if ( ! $perm_failed ++ ) $msg .= lang ( 'Failed to change permissions of %1!' , $path . lang ( 'and all it\'s childeren' ) .
2008-11-09 17:33:09 +01:00
( $ok ? ' (' . lang ( '%1 failed, %2 succeded' , $failed , $ok ) . ')' : '' ));
}
2008-10-05 19:07:36 +02:00
}
2008-11-09 17:33:09 +01:00
elseif ( call_user_func_array ( $cmd , array ( $path , $value )))
2008-10-05 19:07:36 +02:00
{
2008-11-09 17:33:09 +01:00
$msg .= lang ( 'Permissions of %1 changed.' , $path );
2008-11-12 18:04:38 +01:00
$content [ 'old' ][ $name ] = $content [ $name ];
2008-10-05 19:07:36 +02:00
}
else
{
2008-11-09 17:33:09 +01:00
$msg .= lang ( 'Failed to change permissions of %1!' , $path );
2008-10-05 19:07:36 +02:00
}
}
}
}
if ( $props )
{
2016-03-21 11:06:54 +01:00
if ( Vfs :: proppatch ( $path , $props ))
2008-10-05 19:07:36 +02:00
{
foreach ( $props as $prop )
{
2008-10-05 21:01:49 +02:00
$content [ 'old' ][ $prop [ 'name' ]] = $prop [ 'val' ];
2008-10-05 19:07:36 +02:00
}
$msg .= lang ( 'Properties saved.' );
}
else
{
$msg .= lang ( 'Saving properties failed!' );
2008-04-14 07:54:10 +02:00
}
}
}
2021-10-06 16:07:47 +02:00
elseif ( ! empty ( $content [ 'eacl' ]) && ! empty ( $content [ 'is_owner' ]))
2008-04-14 07:54:10 +02:00
{
2021-10-06 16:07:47 +02:00
if ( ! empty ( $content [ 'eacl' ][ 'delete' ]))
2008-04-14 07:54:10 +02:00
{
2019-02-12 22:13:45 +01:00
$ino_owner = key ( $content [ 'eacl' ][ 'delete' ]);
2014-11-18 13:55:32 +01:00
list (, $owner ) = explode ( '-' , $ino_owner , 2 ); // $owner is a group and starts with a minus!
2016-03-21 11:06:54 +01:00
$msg .= Vfs :: eacl ( $path , null , $owner ) ? lang ( 'ACL deleted.' ) : lang ( 'Error deleting the ACL entry!' );
2008-04-14 07:54:10 +02:00
}
elseif ( $button == 'eacl' )
{
2014-04-23 21:49:17 +02:00
if ( ! $content [ 'eacl_owner' ])
2008-04-14 07:54:10 +02:00
{
$msg .= lang ( 'You need to select an owner!' );
}
else
{
2016-03-21 11:06:54 +01:00
$msg .= Vfs :: eacl ( $path , $content [ 'eacl' ][ 'rights' ], $content [ 'eacl_owner' ]) ?
2008-04-14 07:54:10 +02:00
lang ( 'ACL added.' ) : lang ( 'Error adding the ACL!' );
2008-03-03 23:15:44 +01:00
}
}
}
2016-05-05 09:20:07 +02:00
Framework :: refresh_opener ( $msg , 'filemanager' , $refresh_path ? $refresh_path : $path , 'edit' , null , '&path=[^&]*' );
if ( $button == 'save' ) Framework :: window_close ();
2008-03-03 23:15:44 +01:00
}
2016-03-21 11:06:54 +01:00
if ( $content [ 'is_link' ] && ! Vfs :: stat ( $path ))
2009-03-19 21:12:35 +01:00
{
$msg .= ( $msg ? " \n " : '' ) . lang ( 'Link target %1 not found!' , $content [ 'symlink' ]);
}
2016-05-05 09:20:07 +02:00
$content [ 'link' ] = Egw :: link ( Vfs :: download_url ( $path ));
2016-03-21 11:06:54 +01:00
$content [ 'icon' ] = Vfs :: mime_icon ( $content [ 'mime' ]);
2008-04-14 07:54:10 +02:00
$content [ 'msg' ] = $msg ;
2016-03-21 11:06:54 +01:00
if (( $readonlys [ 'uid' ] = ! Vfs :: $is_root ) && ! $content [ 'uid' ]) $content [ 'ro_uid_root' ] = 'root' ;
2008-03-03 23:15:44 +01:00
// only owner can change group & perms
2008-04-14 07:54:10 +02:00
if (( $readonlys [ 'gid' ] = ! $content [ 'is_owner' ] ||
2017-10-31 17:38:35 +01:00
Vfs :: parse_url ( Vfs :: resolve_url ( $content [ 'path' ]), PHP_URL_SCHEME ) == 'oldvfs' ) ||// no uid , gid or perms in oldvfs
! Vfs :: is_writable ( $path ))
2008-03-03 23:15:44 +01:00
{
if ( ! $content [ 'gid' ]) $content [ 'ro_gid_root' ] = 'root' ;
foreach ( $content [ 'perms' ] as $name => $value )
{
$readonlys [ 'perms[' . $name . ']' ] = true ;
}
}
2017-10-31 17:38:35 +01:00
$readonlys [ 'gid' ] = $readonlys [ 'gid' ] || ! Vfs :: is_writable ( $path );
2016-07-02 12:39:28 +02:00
$readonlys [ 'name' ] = $path == '/' || ! ( $dir = Vfs :: dirname ( $path )) || ! Vfs :: is_writable ( $dir );
2016-03-21 11:06:54 +01:00
$readonlys [ 'comment' ] = ! Vfs :: is_writable ( $path );
2014-04-23 21:49:17 +02:00
$readonlys [ 'tabs' ][ 'filemanager.file.preview' ] = $readonlys [ 'tabs' ][ 'filemanager.file.perms' ] = $content [ 'is_link' ];
2008-04-16 09:07:31 +02:00
2021-04-13 19:14:44 +02:00
// Don't allow permission changes for these, even for root - it causes too many problems.
// Use the CLI if you really need to make changes
if ( in_array ( $content [ 'path' ], [ '/' , '/home' , '/apps' ]))
{
foreach ( $content [ 'perms' ] as $name => $value )
{
$readonlys [ 'perms[' . $name . ']' ] = true ;
}
$readonlys [ 'gid' ] = true ;
$readonlys [ 'uid' ] = true ;
$readonlys [ 'modify_subs' ] = true ;
}
2008-11-09 17:33:09 +01:00
// if neither owner nor is writable --> disable save&apply
2016-03-21 11:06:54 +01:00
$readonlys [ 'button[save]' ] = $readonlys [ 'button[apply]' ] = ! $content [ 'is_owner' ] && ! Vfs :: is_writable ( $path );
2008-11-09 17:33:09 +01:00
2016-03-21 11:06:54 +01:00
if ( ! ( $cfs = Api\Storage\Customfields :: get ( 'filemanager' )))
2008-10-05 19:07:36 +02:00
{
2009-03-19 21:12:35 +01:00
$readonlys [ 'tabs' ][ 'custom' ] = true ;
2008-10-05 19:07:36 +02:00
}
2016-03-21 11:06:54 +01:00
elseif ( ! Vfs :: is_writable ( $path ))
2008-10-05 19:07:36 +02:00
{
foreach ( $cfs as $name => $data )
{
$readonlys [ '#' . $name ] = true ;
}
}
2014-04-23 21:49:17 +02:00
$readonlys [ 'tabs' ][ 'filemanager.file.eacl' ] = true ; // eacl off by default
2008-03-03 23:15:44 +01:00
if ( $content [ 'is_dir' ])
{
2014-04-23 21:49:17 +02:00
$readonlys [ 'tabs' ][ 'filemanager.file.preview' ] = true ; // no preview tab for dirs
2008-04-14 07:54:10 +02:00
$sel_options [ 'rights' ] = $sel_options [ 'owner' ] = $sel_options [ 'group' ] = $sel_options [ 'other' ] = array (
2008-03-03 23:15:44 +01:00
7 => lang ( 'Display and modification of content' ),
5 => lang ( 'Display of content' ),
0 => lang ( 'No access' ),
);
2017-11-06 14:52:12 +01:00
if (( $content [ 'eacl' ] = Vfs :: get_eacl ( $content [ 'path' ])) !== false && // backend supports eacl
$GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ] == Vfs :: $user ) // leave eACL tab disabled for sharing
2008-04-14 07:54:10 +02:00
{
2014-04-23 21:49:17 +02:00
unset ( $readonlys [ 'tabs' ][ 'filemanager.file.eacl' ]); // --> switch the tab on again
2008-04-14 07:54:10 +02:00
foreach ( $content [ 'eacl' ] as & $eacl )
{
2016-03-21 11:06:54 +01:00
$eacl [ 'path' ] = rtrim ( Vfs :: parse_url ( $eacl [ 'path' ], PHP_URL_PATH ), '/' );
2008-04-16 09:07:31 +02:00
$readonlys [ 'delete[' . $eacl [ 'ino' ] . '-' . $eacl [ 'owner' ] . ']' ] = $eacl [ 'ino' ] != $content [ 'ino' ] ||
2008-04-14 07:54:10 +02:00
$eacl [ 'path' ] != $content [ 'path' ] || ! $content [ 'is_owner' ];
}
array_unshift ( $content [ 'eacl' ], false ); // make the keys start with 1, not 0
2009-08-26 12:04:21 +02:00
$content [ 'eacl' ][ 'owner' ] = 0 ;
$content [ 'eacl' ][ 'rights' ] = 5 ;
2008-04-14 07:54:10 +02:00
}
2008-03-03 23:15:44 +01:00
}
else
{
2023-01-19 17:21:03 +01:00
$sel_options [ 'owner' ] = $sel_options [ 'group' ] = $sel_options [ 'other' ] = array (
2008-03-03 23:15:44 +01:00
6 => lang ( 'Read & write access' ),
4 => lang ( 'Read access only' ),
0 => lang ( 'No access' ),
2008-04-14 07:54:10 +02:00
);
2008-03-03 23:15:44 +01:00
}
2023-01-19 17:21:03 +01:00
// Use 'root' for ID 0
$sel_options [ 'gid' ] = $sel_options [ 'uid' ] = array (
[ 'value' => '0' , 'label' => lang ( " root " )]
);
2013-04-09 18:20:06 +02:00
2020-11-30 21:29:39 +01:00
// Times are in server time, convert to user timezone
2023-01-19 17:21:03 +01:00
foreach ([ 'mtime' , 'ctime' ] as $date_field )
2020-11-30 21:29:39 +01:00
{
2023-01-19 17:21:03 +01:00
$time = new Api\DateTime ( $content [ $date_field ], Api\DateTime :: $server_timezone );
2020-11-30 21:29:39 +01:00
$time -> setUser ();
$content [ $date_field ] = $time -> format ( 'ts' );
}
2012-10-27 13:38:47 +02:00
// mergeapp
2014-11-18 13:55:32 +01:00
$content [ 'mergeapp' ] = static :: get_mergeapp ( $path , 'self' );
$content [ 'mergeapp_parent' ] = static :: get_mergeapp ( $path , 'parents' );
2012-10-27 13:38:47 +02:00
if ( ! empty ( $content [ 'mergeapp' ]))
{
$content [ 'mergeapp_effective' ] = $content [ 'mergeapp' ];
}
elseif ( ! empty ( $content [ 'mergeapp_parent' ]))
{
$content [ 'mergeapp_effective' ] = $content [ 'mergeapp_parent' ];
}
else
{
$content [ 'mergeapp_effective' ] = null ;
}
// mergeapp select options
2016-05-05 09:20:07 +02:00
$mergeapp_list = Link :: app_list ( 'merge' );
2013-01-04 01:23:57 +01:00
unset ( $mergeapp_list [ $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ]]); // exclude filemanager from list
2012-10-27 13:38:47 +02:00
$mergeapp_empty = ! empty ( $content [ 'mergeapp_parent' ])
? $mergeapp_list [ $content [ 'mergeapp_parent' ]] . ' (parent setting)' : '' ;
$sel_options [ 'mergeapp' ] = array ( '' => $mergeapp_empty );
$sel_options [ 'mergeapp' ] = $sel_options [ 'mergeapp' ] + $mergeapp_list ;
// mergeapp other gui options
$content [ 'mergeapp_itempicker_disabled' ] = $content [ 'is_dir' ] || empty ( $content [ 'mergeapp_effective' ]);
2013-04-09 18:20:06 +02:00
2008-03-03 23:15:44 +01:00
$preserve = $content ;
if ( ! isset ( $preserve [ 'old' ]))
{
$preserve [ 'old' ] = array (
'perms' => $content [ 'perms' ],
'name' => $content [ 'name' ],
'uid' => $content [ 'uid' ],
'gid' => $content [ 'gid' ],
2008-10-05 19:07:36 +02:00
'comment' => ( string ) $content [ 'comment' ],
2012-10-27 13:38:47 +02:00
'mergeapp' => $content [ 'mergeapp' ]
2008-03-03 23:15:44 +01:00
);
2008-10-05 19:07:36 +02:00
if ( $cfs ) foreach ( $cfs as $name => $data )
{
$preserve [ 'old' ][ '#' . $name ] = ( string ) $content [ '#' . $name ];
}
2008-03-03 23:15:44 +01:00
}
2016-03-21 11:06:54 +01:00
if ( Vfs :: $is_root )
2008-11-09 17:33:09 +01:00
{
2014-07-31 19:45:57 +02:00
$tpl -> setElementAttribute ( 'sudouser' , 'label' , 'Logout' );
$tpl -> setElementAttribute ( 'sudouser' , 'help' , 'Log out as superuser' );
2013-12-16 19:46:48 +01:00
// Need a more complex submit because button type is buttononly, which doesn't submit
2014-07-31 19:45:57 +02:00
$tpl -> setElementAttribute ( 'sudouser' , 'onclick' , 'app.filemanager.set_sudoButton(widget,"login")' );
2013-12-16 19:46:48 +01:00
2008-11-09 17:33:09 +01:00
}
2014-07-31 19:45:57 +02:00
elseif ( $button == 'sudo' )
{
$tpl -> setElementAttribute ( 'sudouser' , 'label' , 'Superuser' );
$tpl -> setElementAttribute ( 'sudouser' , 'help' , 'Enter setup user and password to get root rights' );
$tpl -> setElementAttribute ( 'sudouser' , 'onclick' , 'app.filemanager.set_sudoButton(widget,"logout")' );
}
2017-10-31 17:38:35 +01:00
else if ( self :: is_anonymous ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]))
{
// Just hide sudo for anonymous users
$readonlys [ 'sudouser' ] = true ;
}
2016-03-21 11:06:54 +01:00
if (( $extra_tabs = Vfs :: getExtraInfo ( $path , $content )))
2010-03-23 21:44:17 +01:00
{
2013-12-16 19:46:48 +01:00
// add to existing tabs in template
$tpl -> setElementAttribute ( 'tabs' , 'add_tabs' , true );
2013-08-20 18:41:31 +02:00
2023-02-14 21:24:19 +01:00
$tabs =& $tpl -> getElementAttribute ( 'tabs' , 'extraTabs' );
2014-11-18 13:55:32 +01:00
if ( true ) $tabs = array ();
2012-07-09 23:23:21 +02:00
2011-06-23 20:34:47 +02:00
foreach ( isset ( $extra_tabs [ 0 ]) ? $extra_tabs : array ( $extra_tabs ) as $extra_tab )
2010-03-23 21:44:17 +01:00
{
2013-12-16 19:46:48 +01:00
$tabs [] = array (
'label' => $extra_tab [ 'label' ],
'template' => $extra_tab [ 'name' ]
);
2011-06-23 20:34:47 +02:00
if ( $extra_tab [ 'data' ] && is_array ( $extra_tab [ 'data' ]))
{
$content = array_merge ( $content , $extra_tab [ 'data' ]);
}
if ( $extra_tab [ 'preserve' ] && is_array ( $extra_tab [ 'preserve' ]))
{
$preserve = array_merge ( $preserve , $extra_tab [ 'preserve' ]);
}
if ( $extra_tab [ 'readonlys' ] && is_array ( $extra_tab [ 'readonlys' ]))
{
2011-06-24 18:45:11 +02:00
$readonlys = array_merge ( $readonlys , $extra_tab [ 'readonlys' ]);
2011-06-23 20:34:47 +02:00
}
2010-05-13 13:59:16 +02:00
}
2010-03-23 21:44:17 +01:00
}
2016-05-05 09:20:07 +02:00
Framework :: window_focus ();
2016-03-21 11:06:54 +01:00
$GLOBALS [ 'egw_info' ][ 'flags' ][ 'app_header' ] = lang ( 'Preferences' ) . ' ' . Vfs :: decodePath ( $path );
2008-03-03 23:15:44 +01:00
$tpl -> exec ( 'filemanager.filemanager_ui.file' , $content , $sel_options , $readonlys , $preserve , 2 );
}
2008-04-16 09:07:31 +02:00
2017-10-30 18:25:12 +01:00
/**
* Check if the user is anonymous user
2017-10-31 17:38:35 +01:00
* @ param integer $account_id
2017-10-30 18:25:12 +01:00
*/
2017-10-31 17:38:35 +01:00
protected static function is_anonymous ( $account_id )
2017-10-30 18:25:12 +01:00
{
2017-10-31 17:38:35 +01:00
$acl = new Api\Acl ( $account_id );
$acl -> read_repository ();
return $acl -> check ( 'anonymous' , 1 , 'phpgwapi' );
2017-10-30 18:25:12 +01:00
}
2010-12-28 04:12:57 +01:00
/**
* Run given action on given path ( es ) and return array / object with values for keys 'msg' , 'errs' , 'dirs' , 'files'
*
* @ param string $action eg . 'delete' , ...
2013-04-11 15:16:40 +02:00
* @ param array $selected selected path ( s )
* @ param string $dir = null current directory
2021-04-28 22:19:51 +02:00
* @ param string [] $props Properties for the file , eg : [ comment => 'Latest from Ralf' ]
2014-11-18 13:55:32 +01:00
* @ see static :: action ()
2010-12-28 04:12:57 +01:00
*/
2013-11-08 00:30:50 +01:00
public static function ajax_action ( $action , $selected , $dir = null , $props = null )
2010-12-28 04:12:57 +01:00
{
2014-10-13 19:23:33 +02:00
// do we have root rights, need to run here too, as method is static and therefore does NOT run __construct
2016-03-21 11:06:54 +01:00
if ( Api\Cache :: getSession ( 'filemanager' , 'is_root' ))
2014-10-13 19:23:33 +02:00
{
2016-03-21 11:06:54 +01:00
Vfs :: $is_root = true ;
2014-10-13 19:23:33 +02:00
}
2016-03-21 11:06:54 +01:00
$response = Api\Json\Response :: get ();
2011-03-21 17:14:43 +01:00
2010-12-28 04:12:57 +01:00
$arr = array (
'msg' => '' ,
2013-11-14 22:38:45 +01:00
'action' => $action ,
2010-12-28 04:12:57 +01:00
'errs' => 0 ,
'dirs' => 0 ,
'files' => 0 ,
);
2011-03-21 17:14:43 +01:00
2013-04-11 15:16:40 +02:00
if ( ! isset ( $dir )) $dir = array_pop ( $selected );
2011-03-21 17:14:43 +01:00
2013-04-20 21:23:36 +02:00
switch ( $action )
{
case 'upload' :
2020-03-25 03:34:04 +01:00
static :: handle_upload_action ( $action , $selected , $dir , $props , $arr );
2013-04-20 21:23:36 +02:00
break ;
2017-11-03 16:30:35 +01:00
case 'shareWritableLink' :
case 'shareReadonlyLink' :
if ( $action === 'shareWritableLink' )
{
$share = Vfs\Sharing :: create (
2020-03-25 03:34:04 +01:00
'' , $selected , Vfs\Sharing :: WRITABLE , basename ( $selected ), array (), array ( 'share_writable' => true )
2017-11-03 16:30:35 +01:00
);
}
else
{
$share = Vfs\Sharing :: create (
2020-03-25 03:34:04 +01:00
'' , $selected , Vfs\Sharing :: READONLY , basename ( $selected ), array ()
2017-11-03 16:30:35 +01:00
);
}
2017-08-01 15:25:33 +02:00
$arr [ " share_link " ] = $link = Vfs\Sharing :: share2link ( $share );
$arr [ " template " ] = Api\Etemplate\Widget\Template :: rel2url ( '/filemanager/templates/default/share_dialog.xet' );
break ;
2013-11-14 22:38:45 +01:00
// Upload, then link
case 'link' :
// First upload
2014-11-18 13:55:32 +01:00
$arr = static :: ajax_action ( 'upload' , $selected , $dir , $props );
2016-05-05 09:20:07 +02:00
$app_dir = Link :: vfs_path ( $props [ 'entry' ][ 'app' ], $props [ 'entry' ][ 'id' ], '' , true );
2013-11-14 22:38:45 +01:00
foreach ( $arr [ 'uploaded' ] as $file )
{
2016-03-21 11:06:54 +01:00
$target = Vfs :: concat ( $dir , Vfs :: encodePathComponent ( $file [ 'name' ]));
if ( Vfs :: file_exists ( $target ) && $app_dir )
2013-11-14 22:38:45 +01:00
{
2016-03-21 11:06:54 +01:00
if ( ! Vfs :: file_exists ( $app_dir )) Vfs :: mkdir ( $app_dir );
2013-11-14 22:38:45 +01:00
error_log ( " Symlinking $target to $app_dir " );
2016-03-21 11:06:54 +01:00
Vfs :: symlink ( $target , Vfs :: concat ( $app_dir , Vfs :: encodePathComponent ( $file [ 'name' ])));
2013-11-14 22:38:45 +01:00
}
}
// Must return to avoid adding to $response again
return ;
2013-04-20 21:23:36 +02:00
default :
2014-11-18 13:55:32 +01:00
$arr [ 'msg' ] = static :: action ( $action , $selected , $dir , $arr [ 'errs' ], $arr [ 'dirs' ], $arr [ 'files' ]);
2013-04-20 21:23:36 +02:00
}
2010-12-28 04:12:57 +01:00
$response -> data ( $arr );
2011-06-30 15:07:55 +02:00
//error_log(__METHOD__."('$action',".array2string($selected).') returning '.array2string($arr));
2013-11-14 22:38:45 +01:00
return $arr ;
2010-12-28 04:12:57 +01:00
}
2020-03-25 03:34:04 +01:00
/**
* Deal with an uploaded file
*
* @ param string $action Should be 'upload'
* @ param $selected Array of file information
* @ param string $dir Target directory
* @ param $props
* @ param string [] $arr Result
*
* @ throws Api\Exception\AssertionFailed
*/
protected static function handle_upload_action ( string $action , $selected , $dir , $props , & $arr )
{
$script_error = 0 ;
$conflict = $selected [ 'conflict' ];
unset ( $selected [ 'conflict' ]);
foreach ( $selected as $tmp_name => & $data )
{
2024-06-20 12:29:13 +02:00
$path = Vfs :: concat ( $dir , Vfs :: limitFilename ( Vfs :: encodePathComponent ( $data [ 'name' ])));
2020-03-25 03:34:04 +01:00
if ( Vfs :: deny_script ( $path ))
{
if ( ! isset ( $script_error ))
{
$arr [ 'msg' ] .= ( $arr [ 'msg' ] ? " \n " : '' ) . lang ( 'You are NOT allowed to upload a script!' );
}
++ $script_error ;
++ $arr [ 'errs' ];
unset ( $selected [ $tmp_name ]);
continue ;
}
elseif ( Vfs :: is_dir ( $path ))
{
$data [ 'confirm' ] = 'is_dir' ;
continue ;
}
elseif ( ! $data [ 'confirmed' ] && Vfs :: stat ( $path ))
{
// File exists, what to do?
switch ( $conflict )
{
case 'overwrite' :
unset ( $data [ 'confirm' ]);
$data [ 'confirmed' ] = true ;
break ;
case 'rename' :
// Find a unique name
$i = 1 ;
$info = pathinfo ( $path );
while ( Vfs :: file_exists ( $path ))
{
$path = $info [ 'dirname' ] . '/' . $info [ 'filename' ] . " ( $i ). " . $info [ 'extension' ];
$i ++ ;
}
break ;
case 'ask' :
default :
$data [ 'confirm' ] = true ;
}
}
if ( ! $data [ 'confirm' ])
{
if ( is_dir ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'temp_dir' ]) && is_writable ( $GLOBALS [ 'egw_info' ][ 'server' ][ 'temp_dir' ]))
{
$tmp_path = $GLOBALS [ 'egw_info' ][ 'server' ][ 'temp_dir' ] . '/' . basename ( $tmp_name );
}
else
{
$tmp_path = ini_get ( 'upload_tmp_dir' ) . '/' . basename ( $tmp_name );
}
2022-11-23 21:53:47 +01:00
try
2020-03-25 03:34:04 +01:00
{
2023-07-25 17:23:06 +02:00
$data [ 'path' ] = $path ;
2022-11-23 21:53:47 +01:00
if ( Vfs :: copy_uploaded ( $tmp_path , $path , $props , false ))
{
++ $arr [ 'files' ];
$uploaded [] = $data [ 'name' ];
}
else
{
++ $arr [ 'errs' ];
}
2020-03-25 03:34:04 +01:00
}
2022-11-23 21:53:47 +01:00
catch ( \EGroupware\Stylite\Vfs\QuotaExceededException $e )
2020-03-25 03:34:04 +01:00
{
2022-11-23 21:53:47 +01:00
// File was touched but not written. Might need to delete it
$stat = Vfs :: stat ( $path );
if ( $stat && $stat [ 'size' ] == 0 )
{
Vfs :: unlink ( $path );
}
// Send error
2020-03-25 03:34:04 +01:00
++ $arr [ 'errs' ];
2022-11-23 21:53:47 +01:00
++ $script_error ;
$arr [ 'msg' ] = $e -> getMessage ();
$arr [ 'msg' ] .= " \n " . lang ( " You can either delete some files or get in touch with your administrator to get more space " );
// No point continuing
break ;
2020-03-25 03:34:04 +01:00
}
}
}
if ( $arr [ 'errs' ] > $script_error )
{
$arr [ 'msg' ] .= ( $arr [ 'msg' ] ? " \n " : '' ) . lang ( 'Error uploading file!' );
}
if ( $arr [ 'files' ])
{
$arr [ 'msg' ] .= ( $arr [ 'msg' ] ? " \n " : '' ) . lang ( '%1 successful uploaded.' , implode ( ', ' , $uploaded ));
}
$arr [ 'uploaded' ] = $selected ;
$arr [ 'path' ] = $dir ;
$arr [ 'props' ] = $props ;
}
2008-03-03 23:15:44 +01:00
/**
* Convert perms array back to integer mode
*
* @ param array $perms with keys owner , group , other , executable , sticky
* @ return int
*/
private function perms2mode ( array $perms )
{
2008-11-09 17:33:09 +01:00
$mode = $perms [ 'owner' ] << 6 | $perms [ 'group' ] << 3 | $perms [ 'other' ];
2008-03-03 23:15:44 +01:00
if ( $mode [ 'executable' ])
{
$mode |= 0111 ;
}
if ( $mode [ 'sticky' ])
{
$mode |= 0x201 ;
}
return $mode ;
}
2020-10-21 00:47:26 +02:00
/**
* User just got a new share . Ask the questions , let them customize
*
* @ param array $content
*/
public function share_received ( $content = array ())
{
// Deal with returning data & changes
// Read info for display
$content [ 'mount_location' ] = $content [ 'share_path' ];
$sel_options = array ();
$readonlys = array ();
$preserve = $content ;
$template = new Api\Etemplate ( " api.file_share_received " );
$template -> exec ( __CLASS__ . '::' . __METHOD__ , $content , $sel_options , $readonlys , $preserve , 2 );
}
2024-01-18 09:33:47 +01:00
}