diff --git a/phpgwapi/inc/class.egw_tail.inc.php b/phpgwapi/inc/class.egw_tail.inc.php
index 87c190acbd..dc6456ada6 100644
--- a/phpgwapi/inc/class.egw_tail.inc.php
+++ b/phpgwapi/inc/class.egw_tail.inc.php
@@ -50,6 +50,15 @@ class egw_tail
*/
protected $filename;
+ /**
+ * Methods allowed to call via menuaction
+ *
+ * @var array
+ */
+ public $public_functions = array(
+ 'download' => true,
+ );
+
/**
* Constructor
*
@@ -63,7 +72,7 @@ class egw_tail
{
$this->filename = $filename;
- if (!in_array($filename,$this->filenames)) $this->filenames[] = $filename;
+ if (!$this->filenames || !in_array($filename,$this->filenames)) $this->filenames[] = $filename;
}
}
@@ -72,6 +81,7 @@ class egw_tail
*
* @param string $filename
* @param int $start=0 last position in log-file
+ * @throws egw_exception_wrong_parameter
*/
public function ajax_chunk($filename,$start=0)
{
@@ -81,37 +91,87 @@ class egw_tail
}
if ($filename[0] != '/') $filename = $GLOBALS['egw_info']['server']['files_dir'].'/'.$filename;
- if (!$start || $start < 0)
+ if (file_exists($filename))
{
- $start = filesize($filename) - 4*self::MAX_CHUNK_SIZE;
- if ($start < 0) $start = 0;
+ $size = filesize($filename);
+ if (!$start || $start < 0 || $start > $size || $size-$start > 4*self::MAX_CHUNK_SIZE)
+ {
+ $start = $size - 4*self::MAX_CHUNK_SIZE;
+ if ($start < 0) $start = 0;
+ }
+ $size = egw_vfs::hsize($size);
+ $content = file_get_contents($filename, false, null, $start, self::MAX_CHUNK_SIZE);
+ $length = bytes($content);
+ $writable = is_writable($filename) || is_writable(dirname($filename));
+ }
+ else
+ {
+ $start = $length = 0;
+ $content = '';
+ $writable = $size = false;
}
- $content = file_get_contents($filename, false, null, $start, self::MAX_CHUNK_SIZE);
- $length = bytes($content);
-
$response = egw_json_response::get();
$response->data(array( // send all responses as data
+ 'size' => $size,
+ 'writable' => $writable,
'next' => $start + $length,
'length' => $length,
'content' => $content,
));
}
+ /**
+ * Ajax callback to delete log-file
+ *
+ * @param string $filename
+ * @param boolean $truncate=false true: truncate file, false: delete file
+ * @throws egw_exception_wrong_parameter
+ */
+ public function ajax_delete($filename,$truncate=false)
+ {
+ if (!in_array($filename,$this->filenames))
+ {
+ throw new egw_exception_wrong_parameter("Not allowed to view '$filename'!");
+ }
+ if ($filename[0] != '/') $filename = $GLOBALS['egw_info']['server']['files_dir'].'/'.$filename;
+ if ($truncate)
+ {
+ file_put_contents($filename, '');
+ }
+ else
+ {
+ unlink($filename);
+ }
+ }
+
/**
* Return html & javascript for logviewer
*
+ * @param string $header=null default $this->filename
* @param string $id='log'
* @return string
+ * @throws egw_exception_wrong_parameter
*/
- public function show($id='log')
+ public function show($header=null, $id='log')
{
if (!isset($this->filename))
{
throw new egw_exception_wrong_parameter("Must be instanciated with filename!");
}
+ if (is_null($header)) $header = $this->filename;
+
return '
-
';
+'.htmlspecialchars($header).'
+
+ '.html::form(
+ html::input('clear_'.$id,lang('Clear window'),'button','id="clear_'.$id.'" onClick="button_'.$id.'(this)"')."\n".
+ html::input('delete_'.$id,lang('Delete file'),'button','id="delete_'.$id.'" onClick="button_'.$id.'(this)"')."\n".
+ html::input('empty_'.$id,lang('Empty file'),'button','id="empty_'.$id.'" onClick="button_'.$id.'(this)"')."\n".
+ html::input('download_'.$id,lang('Download'),'submit','id="download_'.$id.'"'),
+ '','/index.php',array(
+ 'menuaction' => 'phpgwapi.egw_tail.download',
+ 'filename' => $this->filename,
+ )).'
+
+';
+ }
+
+ /**
+ * Download a file specified per GET parameter (must be in $this->filesnames!)
+ *
+ * @throws egw_exception_wrong_parameter
+ */
+ public function download()
+ {
+ $filename = $_GET['filename'];
+ if (!in_array($filename,$this->filenames))
+ {
+ throw new egw_exception_wrong_parameter("Not allowed to download '$filename'!");
+ }
+ html::content_header(basename($filename),'text/plain');
+ if ($filename[0] != '/') $filename = $GLOBALS['egw_info']['server']['files_dir'].'/'.$filename;
+ while(ob_get_level()) ob_end_clean(); // stop all output buffering, to NOT run into memory_limit
+ readfile($filename);
+ common::egw_exit();
}
}
-// some testcode, if this file is called via it's URL
-if (isset($_SERVER['SCRIPT_FILENAME']) && $_SERVER['SCRIPT_FILENAME'] == __FILE__)
+// some testcode, if this file is called via it's URL (you need to uncomment and adapt filename!)
+/*if (isset($_SERVER['SCRIPT_FILENAME']) && $_SERVER['SCRIPT_FILENAME'] == __FILE__)
{
$GLOBALS['egw_info'] = array(
'flags' => array(
'currentapp' => 'admin',
+ 'nonavbar' => true,
),
);
include_once '../../header.inc.php';
- $error_log = new egw_tail($file='/opt/local/apache2/logs/error_log');
- echo "$file
\n";
+ $error_log = new egw_tail('/opt/local/apache2/logs/error_log');
echo $error_log->show();
-}
\ No newline at end of file
+}*/
\ No newline at end of file
diff --git a/phpgwapi/inc/class.groupdav_hooks.inc.php b/phpgwapi/inc/class.groupdav_hooks.inc.php
index 5d129ce987..0d355cfaa6 100644
--- a/phpgwapi/inc/class.groupdav_hooks.inc.php
+++ b/phpgwapi/inc/class.groupdav_hooks.inc.php
@@ -16,6 +16,10 @@
*/
class groupdav_hooks
{
+ public $public_functions = array(
+ 'log' => true,
+ );
+
/**
* Show GroupDAV preferences link in preferences
*
@@ -69,23 +73,88 @@ class groupdav_hooks
}
}
+ $settings[] = array(
+ 'type' => 'section',
+ 'title' => 'Debuging',
+ );
$settings['debug_level'] = array(
'type' => 'select',
'label' => 'Debug level for Apache/PHP error-log',
'name' => 'debug_level',
'help' => 'Enables debug-messages to Apache/PHP error-log, allowing to diagnose problems on a per user basis.',
'values' => array(
- '0' => 'Off',
- 'r' => 'Requests and truncated responses',
- 'f' => 'Requests and full responses to files directory',
- '1' => 'Debug 1 - function calls',
- '2' => 'Debug 2 - more info',
- '3' => 'Debug 3 - complete $_SERVER array',
+ '0' => lang('Off'),
+ 'r' => lang('Requests and truncated responses'),
+ 'f' => lang('Requests and full responses to files directory'),
),
'xmlrpc' => true,
'admin' => false,
'default' => '0',
);
+ if ($GLOBALS['type'] === 'forced' || $GLOBALS['type'] === 'user' &&
+ $GLOBALS['egw_info']['user']['preferences']['groupdav']['debug-log'] !== 'never')
+ {
+ if ($GLOBALS['type'] === 'user')
+ {
+ $logs = array();
+ if (($files = scandir($log_dir=$GLOBALS['egw_info']['server']['files_dir'].'/groupdav')))
+ {
+ $account_lid_len = strlen($GLOBALS['egw_info']['user']['account_lid']);
+ foreach($files as $log)
+ {
+ if (substr($log,0,$account_lid_len+1) == $GLOBALS['egw_info']['user']['account_lid'].'-' &&
+ substr($log,-4) == '.log')
+ {
+ $logs['groupdav/'.$log] = egw_time::to(filemtime($log_dir.'/'.$log)).': '.
+ str_replace('!','/',substr($log,$account_lid_len+1,-4));
+ }
+ }
+ }
+ $link = egw::link('/index.php',array(
+ 'menuaction' => 'groupdav.groupdav_hooks.log',
+ 'filename' => '',
+ ));
+ $onchange = "egw_openWindowCentered('$link'+encodeURIComponent(this.value), '_blank', 1000, 500); this.value=''";
+ }
+ else // allow to force users to NOT be able to delete their profiles
+ {
+ $logs = array('never' => lang('Never'));
+ }
+ $settings['show-log'] = array(
+ 'type' => 'select',
+ 'label' => 'Show log of following device',
+ 'name' => 'show-log',
+ 'help' => lang('You need to set above debug-level to "%1" to create/update a log.',
+ lang('Requests and full responses to files directory')),
+ 'values' => $logs,
+ 'xmlrpc' => True,
+ 'admin' => False,
+ 'onchange' => $onchange,
+ );
+ }
return $settings;
}
+
+ /**
+ * Open log window for log-file specified in GET parameter filename (relative to files_dir)
+ *
+ * $_GET['filename'] has to be in groupdav sub-dir of files_dir and start with account_lid of current user
+ *
+ * @throws egw_exception_wrong_parameter
+ */
+ public function log()
+ {
+ $filename = $_GET['filename'];
+ if (!preg_match('|^groupdav/'.preg_quote($GLOBALS['egw_info']['user']['account_lid'],'|').'-[^/]+\.log$|',$filename))
+ {
+ throw new egw_exception_wrong_parameter("Access denied to file '$filename'!");
+ }
+ $GLOBALS['egw_info']['flags']['css'] = '
+body { background-color: #e0e0e0; }
+pre.tail { background-color: white; padding-left: 5px; margin-left: 5px; }
+';
+ $header = str_replace('!','/',substr($filename,10+strlen($GLOBALS['egw_info']['user']['account_lid']),-4));
+ $tail = new egw_tail($filename);
+ $GLOBALS['egw']->framework->render($tail->show($header),false,false);
+ }
}
\ No newline at end of file
diff --git a/preferences/inc/class.uisettings.inc.php b/preferences/inc/class.uisettings.inc.php
index 5a22c95ba3..7c14dde6d4 100755
--- a/preferences/inc/class.uisettings.inc.php
+++ b/preferences/inc/class.uisettings.inc.php
@@ -267,7 +267,8 @@ class uisettings
$valarray['help'],
$valarray['default'],
$valarray['run_lang'],
- $valarray['type'] == 'multiselect'
+ $valarray['type'] == 'multiselect',
+ $valarray['onchange']
);
break;
case 'check':
@@ -518,7 +519,7 @@ class uisettings
$this->t->fp('rows','section_row',True);
}
- function create_select_box($label,$name,$values,$help='',$default='',$run_lang=True,$multiple=false)
+ function create_select_box($label,$name,$values,$help='',$default='',$run_lang=True,$multiple=false,$onchange=null)
{
$_appname = $this->check_app();
if($this->is_forced_value($_appname,$name))
@@ -548,7 +549,8 @@ class uisettings
}
if (is_array($extra)) $values = $extra + (is_array($values)?$values:array($values));
- $select = html::select($GLOBALS['type'].'['.$name.']',$default,$values,true);
+ $select = html::select($GLOBALS['type'].'['.$name.']',$default,$values,true,
+ $onchange?'onchange="'.str_replace('"','\\"',htmlspecialchars($onchange)).'"':'');
}
else
{