mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-31 11:09:04 +01:00
Merge branch 'master' into web-components
This commit is contained in:
commit
fbbc466c78
@ -696,10 +696,16 @@ class addressbook_groupdav extends Api\CalDAV\Handler
|
|||||||
{
|
{
|
||||||
trim($attribute);
|
trim($attribute);
|
||||||
list($key, $value) = explode('=', $attribute);
|
list($key, $value) = explode('=', $attribute);
|
||||||
|
// check if value is enclosed in quotes
|
||||||
|
if (in_array($value[0], ['"', "'"], true) && $value[0] === substr($value, -1))
|
||||||
|
{
|
||||||
|
$value = substr($value,1,-1);
|
||||||
|
}
|
||||||
switch (strtolower($key))
|
switch (strtolower($key))
|
||||||
{
|
{
|
||||||
case 'charset':
|
case 'charset':
|
||||||
$charset = strtoupper(substr($value,1,-1));
|
$charset = strtoupper($value);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,41 +291,8 @@ class addressbook_hooks
|
|||||||
|
|
||||||
if ($GLOBALS['egw_info']['user']['apps']['filemanager'])
|
if ($GLOBALS['egw_info']['user']['apps']['filemanager'])
|
||||||
{
|
{
|
||||||
$settings['default_document'] = array(
|
$merge = new Api\Contacts\Merge();
|
||||||
'type' => 'vfs_file',
|
$settings += $merge->merge_preferences();
|
||||||
'size' => 60,
|
|
||||||
'label' => 'Default document to insert contacts',
|
|
||||||
'name' => 'default_document',
|
|
||||||
'help' => lang('If you specify a document (full vfs path) here, %1 displays an extra document icon for each entry. That icon allows to download the specified document with the data inserted.', lang('addressbook')).' '.
|
|
||||||
lang('The document can contain placeholder like {{%1}}, to be replaced with the data.','n_fn').' '.
|
|
||||||
lang('The following document-types are supported:'). implode(',',Api\Storage\Merge::get_file_extensions()),
|
|
||||||
'run_lang' => false,
|
|
||||||
'xmlrpc' => True,
|
|
||||||
'admin' => False,
|
|
||||||
);
|
|
||||||
$settings['document_dir'] = array(
|
|
||||||
'type' => 'vfs_dirs',
|
|
||||||
'size' => 60,
|
|
||||||
'label' => 'Directory with documents to insert contacts',
|
|
||||||
'name' => 'document_dir',
|
|
||||||
'help' => lang('If you specify a directory (full vfs path) here, %1 displays an action for each document. That action allows to download the specified document with the data inserted.', lang('addressbook')) . ' ' .
|
|
||||||
lang('The document can contain placeholder like {{%1}}, to be replaced with the data.', 'n_fn') . ' ' .
|
|
||||||
lang('The following document-types are supported:') . implode(',', Api\Storage\Merge::get_file_extensions()),
|
|
||||||
'run_lang' => false,
|
|
||||||
'xmlrpc' => True,
|
|
||||||
'admin' => False,
|
|
||||||
'default' => '/templates/addressbook',
|
|
||||||
);
|
|
||||||
$settings[Api\Storage\Merge::PREF_DOCUMENT_FILENAME] = array(
|
|
||||||
'type' => 'taglist',
|
|
||||||
'label' => 'Document download filename',
|
|
||||||
'name' => 'document_download_name',
|
|
||||||
'values' => Api\Storage\Merge::DOCUMENT_FILENAME_OPTIONS,
|
|
||||||
'help' => 'Choose the default filename for downloaded documents.',
|
|
||||||
'xmlrpc' => True,
|
|
||||||
'admin' => False,
|
|
||||||
'default' => 'document',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($GLOBALS['egw_info']['user']['apps']['felamimail'] || $GLOBALS['egw_info']['user']['apps']['mail'])
|
if ($GLOBALS['egw_info']['user']['apps']['felamimail'] || $GLOBALS['egw_info']['user']['apps']['mail'])
|
||||||
|
@ -273,7 +273,7 @@ class admin_acl
|
|||||||
{
|
{
|
||||||
$rows['sel_options']['filter2'][] = array(
|
$rows['sel_options']['filter2'][] = array(
|
||||||
'value' => $appname,
|
'value' => $appname,
|
||||||
'label' => lang(Api\Link::get_registry($appname, 'entries')) ?? lang($appname)
|
'label' => lang(Api\Link::get_registry($appname, 'entries') ?: $appname)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
usort($rows['sel_options']['filter2'], function($a,$b) {
|
usort($rows['sel_options']['filter2'], function($a,$b) {
|
||||||
|
@ -87,7 +87,7 @@ class admin_cmd_category extends admin_cmd
|
|||||||
unset($set['old_parent'], $set['base_url'], $set['last_mod'], $set['all_cats'], $set['no_private']);
|
unset($set['old_parent'], $set['base_url'], $set['last_mod'], $set['all_cats'], $set['no_private']);
|
||||||
foreach($set as $key => $value)
|
foreach($set as $key => $value)
|
||||||
{
|
{
|
||||||
if(array_key_exists($key, $old) && $old[$key] == $value)
|
if ($old && array_key_exists($key, $old) && $old[$key] == $value)
|
||||||
{
|
{
|
||||||
unset($set[$key]);
|
unset($set[$key]);
|
||||||
unset($old[$key]);
|
unset($old[$key]);
|
||||||
|
@ -128,10 +128,10 @@ class admin_customfields
|
|||||||
public function index($content = array())
|
public function index($content = array())
|
||||||
{
|
{
|
||||||
// determine appname
|
// determine appname
|
||||||
$this->appname = $this->appname ? $this->appname : ($_GET['appname'] ? $_GET['appname'] : ($content['appname'] ? $content['appname'] : false));
|
$this->appname = $this->appname ?: (!empty($_GET['appname']) ? $_GET['appname'] : (!empty($content['appname']) ? $content['appname'] : false));
|
||||||
if(!$this->appname) die(lang('Error! No appname found'));
|
if(!$this->appname) die(lang('Error! No appname found'));
|
||||||
|
|
||||||
$this->use_private = !isset($_GET['use_private']) || (boolean)$_GET['use_private'] || $content['use_private'];
|
$this->use_private = !empty($_GET['use_private']) && $_GET['use_private'] !== 'undefined' || !empty($content['use_private']);
|
||||||
|
|
||||||
// Read fields, constructor doesn't always know appname
|
// Read fields, constructor doesn't always know appname
|
||||||
$this->fields = Api\Storage\Customfields::get($this->appname,true);
|
$this->fields = Api\Storage\Customfields::get($this->appname,true);
|
||||||
@ -323,10 +323,10 @@ class admin_customfields
|
|||||||
*/
|
*/
|
||||||
function edit($content = null)
|
function edit($content = null)
|
||||||
{
|
{
|
||||||
$cf_id = $_GET['cf_id'] ? (int)$_GET['cf_id'] : (int)$content['cf_id'];
|
$cf_id = isset($_GET['cf_id']) ? (int)$_GET['cf_id'] : (int)$content['cf_id'];
|
||||||
|
|
||||||
// determine appname
|
// determine appname
|
||||||
$this->appname = $this->appname ? $this->appname : ($_GET['appname'] ? $_GET['appname'] : ($content['cf_app'] ? $content['cf_app'] : false));
|
$this->appname = $this->appname ?: (isset($_GET['appname']) ? $_GET['appname'] : (!empty($content['cf_app']) ? $content['cf_app'] : false));
|
||||||
if(!$this->appname)
|
if(!$this->appname)
|
||||||
{
|
{
|
||||||
if($cf_id && $this->so)
|
if($cf_id && $this->so)
|
||||||
@ -339,7 +339,7 @@ class admin_customfields
|
|||||||
{
|
{
|
||||||
die(lang('Error! No appname found'));
|
die(lang('Error! No appname found'));
|
||||||
}
|
}
|
||||||
$this->use_private = !isset($_GET['use_private']) || (boolean)$_GET['use_private'] || $content['use_private'];
|
$this->use_private = !isset($_GET['use_private']) || (boolean)$_GET['use_private'] || !empty($content['use_private']);
|
||||||
|
|
||||||
// Read fields, constructor doesn't always know appname
|
// Read fields, constructor doesn't always know appname
|
||||||
$this->fields = Api\Storage\Customfields::get($this->appname,true);
|
$this->fields = Api\Storage\Customfields::get($this->appname,true);
|
||||||
@ -347,7 +347,7 @@ class admin_customfields
|
|||||||
// Update based on info returned from template
|
// Update based on info returned from template
|
||||||
if (is_array($content))
|
if (is_array($content))
|
||||||
{
|
{
|
||||||
$action = @key($content['button']);
|
$action = key($content['button'] ?? []);
|
||||||
switch($action)
|
switch($action)
|
||||||
{
|
{
|
||||||
case 'delete':
|
case 'delete':
|
||||||
@ -422,7 +422,7 @@ class admin_customfields
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$content['use_private'] = !isset($_GET['use_private']) || (boolean)$_GET['use_private'];
|
$content['use_private'] = !empty($_GET['use_private']) && $_GET['use_private'] !== 'undefined';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -474,11 +474,11 @@ class admin_customfields
|
|||||||
// Show sub-type row, and get types
|
// Show sub-type row, and get types
|
||||||
if($this->manage_content_types)
|
if($this->manage_content_types)
|
||||||
{
|
{
|
||||||
if(count($this->content_types) == 0)
|
if(empty($this->content_types))
|
||||||
{
|
{
|
||||||
$this->content_types = Api\Config::get_content_types($this->appname);
|
$this->content_types = Api\Config::get_content_types($this->appname);
|
||||||
}
|
}
|
||||||
if (count($this->content_types)==0)
|
if (empty($this->content_types))
|
||||||
{
|
{
|
||||||
// if you define your default types of your app with the search_link hook, they are available here, if no types were found
|
// if you define your default types of your app with the search_link hook, they are available here, if no types were found
|
||||||
$this->content_types = (array)Api\Link::get_registry($this->appname, 'default_types');
|
$this->content_types = (array)Api\Link::get_registry($this->appname, 'default_types');
|
||||||
@ -592,7 +592,7 @@ class admin_customfields
|
|||||||
*/
|
*/
|
||||||
function create_field(&$content)
|
function create_field(&$content)
|
||||||
{
|
{
|
||||||
$new_name = trim($content['fields'][count($content['fields'])-1]['name']);
|
$new_name = trim($content['fields'][count((array)$content['fields'])-1]['name']);
|
||||||
if (empty($new_name) || isset($this->fields[$new_name]))
|
if (empty($new_name) || isset($this->fields[$new_name]))
|
||||||
{
|
{
|
||||||
$content['error_msg'] .= empty($new_name) ?
|
$content['error_msg'] .= empty($new_name) ?
|
||||||
@ -601,7 +601,7 @@ class admin_customfields
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$this->fields[$new_name] = $content['fields'][count($content['fields'])-1];
|
$this->fields[$new_name] = $content['fields'][count((array)$content['fields'])-1];
|
||||||
if(!$this->fields[$new_name]['label']) $this->fields[$new_name]['label'] = $this->fields[$new_name]['name'];
|
if(!$this->fields[$new_name]['label']) $this->fields[$new_name]['label'] = $this->fields[$new_name]['name'];
|
||||||
$this->save_repository();
|
$this->save_repository();
|
||||||
}
|
}
|
||||||
|
@ -1258,7 +1258,7 @@ class admin_mail
|
|||||||
if ($content['ident_id'] != $content['old_ident_id'] &&
|
if ($content['ident_id'] != $content['old_ident_id'] &&
|
||||||
($content['old_ident_id'] || $content['ident_id'] != $content['std_ident_id']))
|
($content['old_ident_id'] || $content['ident_id'] != $content['std_ident_id']))
|
||||||
{
|
{
|
||||||
if ($content['ident_id'] > 0)
|
if ((int)$content['ident_id'] > 0)
|
||||||
{
|
{
|
||||||
$identity = Mail\Account::read_identity($content['ident_id'], false, $content['called_for']);
|
$identity = Mail\Account::read_identity($content['ident_id'], false, $content['called_for']);
|
||||||
unset($identity['account_id']);
|
unset($identity['account_id']);
|
||||||
@ -1285,7 +1285,7 @@ class admin_mail
|
|||||||
{
|
{
|
||||||
$sel_options['ident_email_alias'] = array_merge(
|
$sel_options['ident_email_alias'] = array_merge(
|
||||||
array('' => $content['mailLocalAddress'].' ('.lang('Default').')'),
|
array('' => $content['mailLocalAddress'].' ('.lang('Default').')'),
|
||||||
array_combine($content['mailAlternateAddress'], $content['mailAlternateAddress']));
|
array_combine($content['mailAlternateAddress'] ?? [], $content['mailAlternateAddress'] ?? []));
|
||||||
// if admin explicitly set a non-alias, we need to add it to aliases to keep it after storing signature by user
|
// if admin explicitly set a non-alias, we need to add it to aliases to keep it after storing signature by user
|
||||||
if ($content['ident_email'] !== $content['mailLocalAddress'] && !isset($sel_options['ident_email_alias'][$content['ident_email']]))
|
if ($content['ident_email'] !== $content['mailLocalAddress'] && !isset($sel_options['ident_email_alias'][$content['ident_email']]))
|
||||||
{
|
{
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<description value="Category owner" for="owner"/>
|
<description value="Category owner" for="owner"/>
|
||||||
<taglist statustext="Limit global category to members of a certain group" id="owner" needed="1" height="190" class="et2_fullWidth" rows="4" />
|
<taglist-account statustext="Limit global category to members of a certain group" id="owner" needed="1" class="et2_fullWidth" />
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
</rows>
|
</rows>
|
||||||
|
@ -227,8 +227,9 @@ export class et2_placeholder_select extends et2_inputWidget
|
|||||||
app.onchange = (node, widget) =>
|
app.onchange = (node, widget) =>
|
||||||
{
|
{
|
||||||
preview.set_value("");
|
preview.set_value("");
|
||||||
if(['user'].indexOf(widget.get_value()) >= 0)
|
if(['user', 'filemanager'].indexOf(widget.get_value()) >= 0)
|
||||||
{
|
{
|
||||||
|
// These ones don't let you select an entry for preview (they don't work)
|
||||||
entry.set_disabled(true);
|
entry.set_disabled(true);
|
||||||
entry.app_select.val('user');
|
entry.app_select.val('user');
|
||||||
entry.set_value({app: 'user', id: '', query: ''});
|
entry.set_value({app: 'user', id: '', query: ''});
|
||||||
@ -338,7 +339,7 @@ export class et2_placeholder_select extends et2_inputWidget
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
options[key].push({
|
options[this.egw().lang(key)].push({
|
||||||
value: key + '-' + sub,
|
value: key + '-' + sub,
|
||||||
label: this.egw().lang(sub)
|
label: this.egw().lang(sub)
|
||||||
});
|
});
|
||||||
|
@ -50,6 +50,22 @@ export class et2_toolbar extends et2_DOMWidget implements et2_IInput
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "more",
|
"default": "more",
|
||||||
"description": "Define a style for list header (more ...), which can get short 3dots with no caption or bigger button with caption more ..."
|
"description": "Define a style for list header (more ...), which can get short 3dots with no caption or bigger button with caption more ..."
|
||||||
|
},
|
||||||
|
"preference_id": {
|
||||||
|
"name": "Preference id",
|
||||||
|
"type": "string",
|
||||||
|
"default": false,
|
||||||
|
"description": "Define a custom preference id for saving the toolbar preferences." +
|
||||||
|
"This is useful when you have the same toolbar and you use it in a pop up but also in a tab, which have different dom ids" +
|
||||||
|
"When not set it defaults to the dom id of the form."
|
||||||
|
},
|
||||||
|
"preference_app": {
|
||||||
|
"name": "Preference application",
|
||||||
|
"type": "string",
|
||||||
|
"default": false,
|
||||||
|
"description": "Define a custom preference application for saving the toolbar preferences." +
|
||||||
|
"This is useful when you have the same toolbar and you use it in a pop up but also in a tab, wich have different application names" +
|
||||||
|
"When not set it defaults to the result of this.egw().app_name();"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -94,6 +110,13 @@ export class et2_toolbar extends et2_DOMWidget implements et2_IInput
|
|||||||
// Set proper id and dom_id for the widget
|
// Set proper id and dom_id for the widget
|
||||||
this.set_id(this.id);
|
this.set_id(this.id);
|
||||||
|
|
||||||
|
if(!this.options.preference_id){
|
||||||
|
this.options.preference_id = this.dom_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!this.options.preference_app){
|
||||||
|
this.options.preference_app = this.egw().app_name();
|
||||||
|
}
|
||||||
|
|
||||||
this.actionbox = jQuery(document.createElement('div'))
|
this.actionbox = jQuery(document.createElement('div'))
|
||||||
.addClass("et2_toolbar_more")
|
.addClass("et2_toolbar_more")
|
||||||
@ -232,7 +255,7 @@ export class et2_toolbar extends et2_DOMWidget implements et2_IInput
|
|||||||
{
|
{
|
||||||
this.actionbox.find('.toolbar-admin-pref').click(function(e){
|
this.actionbox.find('.toolbar-admin-pref').click(function(e){
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
egw.json('EGroupware\\Api\\Etemplate\\Widget\\Toolbar::ajax_get_default_prefs', [egw.app_name(), that.dom_id], function(_prefs){
|
egw.json('EGroupware\\Api\\Etemplate\\Widget\\Toolbar::ajax_get_default_prefs', [that.options.preference_app, that.options.preference_id], function(_prefs){
|
||||||
let prefs = [];
|
let prefs = [];
|
||||||
for (let p in _prefs)
|
for (let p in _prefs)
|
||||||
{
|
{
|
||||||
@ -242,7 +265,8 @@ export class et2_toolbar extends et2_DOMWidget implements et2_IInput
|
|||||||
}).sendRequest(true);
|
}).sendRequest(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let pref = (!egwIsMobile())? egw.preference(this.dom_id, this.egw().app_name()): undefined;
|
|
||||||
|
let pref = (!egwIsMobile())? egw.preference(this.options.preference_id, this.options.preference_app): undefined;
|
||||||
if (pref && !jQuery.isArray(pref)) this.preference = pref;
|
if (pref && !jQuery.isArray(pref)) this.preference = pref;
|
||||||
|
|
||||||
//Set the default actions for the first time
|
//Set the default actions for the first time
|
||||||
@ -461,7 +485,7 @@ export class et2_toolbar extends et2_DOMWidget implements et2_IInput
|
|||||||
if (that.actionlist.find(".ui-draggable").length == 0)
|
if (that.actionlist.find(".ui-draggable").length == 0)
|
||||||
{
|
{
|
||||||
that.preference = {};
|
that.preference = {};
|
||||||
egw.set_preference(that.egw().app_name(),that.dom_id,that.preference);
|
egw.set_preference(that.options.preference_app,that.options.preference_id,that.preference);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tolerance:"touch"
|
tolerance:"touch"
|
||||||
@ -525,7 +549,7 @@ export class et2_toolbar extends et2_DOMWidget implements et2_IInput
|
|||||||
{
|
{
|
||||||
this.preference[_action] = _state;
|
this.preference[_action] = _state;
|
||||||
if (egwIsMobile()) return;
|
if (egwIsMobile()) return;
|
||||||
egw.set_preference(this.egw().app_name(),this.dom_id,this.preference);
|
egw.set_preference(this.options.preference_app,this.options.preference_id,this.preference);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -773,7 +797,7 @@ export class et2_toolbar extends et2_DOMWidget implements et2_IInput
|
|||||||
id:child,
|
id:child,
|
||||||
value: child,
|
value: child,
|
||||||
label: _actions[key]['children'][child]['caption'],
|
label: _actions[key]['children'][child]['caption'],
|
||||||
app: egw.app_name(),
|
app: self.options.preference_app,
|
||||||
icon: _actions[key]['children'][child]['iconUrl']
|
icon: _actions[key]['children'][child]['iconUrl']
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -784,7 +808,7 @@ export class et2_toolbar extends et2_DOMWidget implements et2_IInput
|
|||||||
id:key,
|
id:key,
|
||||||
value: key,
|
value: key,
|
||||||
label: _actions[key]['caption'],
|
label: _actions[key]['caption'],
|
||||||
app: egw.app_name(),
|
app: self.options.preference_app,
|
||||||
icon: _actions[key]['iconUrl']
|
icon: _actions[key]['iconUrl']
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -808,12 +832,12 @@ export class et2_toolbar extends et2_DOMWidget implements et2_IInput
|
|||||||
_value.actions = pref;
|
_value.actions = pref;
|
||||||
}
|
}
|
||||||
egw.json('EGroupware\\Api\\Etemplate\\Widget\\Toolbar::ajax_setAdminSettings',
|
egw.json('EGroupware\\Api\\Etemplate\\Widget\\Toolbar::ajax_setAdminSettings',
|
||||||
[_value, self.dom_id, egw.app_name()],function(_result){
|
[_value, self.options.preference_id, self.options.preference_app],function(_result){
|
||||||
egw.message(_result);
|
egw.message(_result);
|
||||||
}).sendRequest(true);
|
}).sendRequest(true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
title: egw.lang('admin settings for %1', this.dom_id),
|
title: egw.lang('admin settings for %1', this.options.preference_id),
|
||||||
buttons: buttons,
|
buttons: buttons,
|
||||||
minWidth: 600,
|
minWidth: 600,
|
||||||
minHeight: 300,
|
minHeight: 300,
|
||||||
|
@ -744,20 +744,24 @@ export abstract class EgwApp
|
|||||||
// Find what we need
|
// Find what we need
|
||||||
let nm = null;
|
let nm = null;
|
||||||
let action = _action;
|
let action = _action;
|
||||||
let as_pdf = false;
|
let as_pdf = null;
|
||||||
|
|
||||||
// Find Select all
|
// Find Select all
|
||||||
while(nm == null && action != null)
|
while(nm == null && action.parent != null)
|
||||||
{
|
{
|
||||||
if(action.data != null && action.data.nextmatch)
|
if(action.data != null && action.data.nextmatch)
|
||||||
{
|
{
|
||||||
nm = action.data.nextmatch;
|
nm = action.data.nextmatch;
|
||||||
}
|
}
|
||||||
|
if(as_pdf === null && action.getActionById('as_pdf') !== null)
|
||||||
|
{
|
||||||
|
as_pdf = action.getActionById('as_pdf').checked;
|
||||||
|
}
|
||||||
action = action.parent;
|
action = action.parent;
|
||||||
}
|
}
|
||||||
let all = nm?.getSelection().all || false;
|
let all = nm?.getSelection().all || false;
|
||||||
|
|
||||||
as_pdf = action.getActionById('as_pdf')?.checked || false;
|
as_pdf = as_pdf || false;
|
||||||
|
|
||||||
// Get list of entry IDs
|
// Get list of entry IDs
|
||||||
let ids = [];
|
let ids = [];
|
||||||
|
@ -274,6 +274,7 @@ choose a background style. common de Wählen Sie einen Hintergrundstil.
|
|||||||
choose a text color for the icons common de Wählen Sie eine Textfarbe für die Symbole
|
choose a text color for the icons common de Wählen Sie eine Textfarbe für die Symbole
|
||||||
choose file... common de Dateien wählen...
|
choose file... common de Dateien wählen...
|
||||||
choose the category common de Kategorie auswählen
|
choose the category common de Kategorie auswählen
|
||||||
|
choose the default filename for merged documents. preferences de Wählen Sie den Standard-Dateinamen für zusammengeführte Platzhalter-Dokumente.
|
||||||
choose the parent category common de Wählen der übergeordneten Kategorie
|
choose the parent category common de Wählen der übergeordneten Kategorie
|
||||||
choose time common de Uhrzeit auswählen
|
choose time common de Uhrzeit auswählen
|
||||||
chosen parent category no longer exists common de Die ausgewählte Elternkategorie existiert nicht (mehr).
|
chosen parent category no longer exists common de Die ausgewählte Elternkategorie existiert nicht (mehr).
|
||||||
@ -378,6 +379,7 @@ december common de Dezember
|
|||||||
deck common de Deck (intern)
|
deck common de Deck (intern)
|
||||||
default common de Vorgabe
|
default common de Vorgabe
|
||||||
default category common de Standard-Kategorie
|
default category common de Standard-Kategorie
|
||||||
|
default document to insert entries preferences de Standarddokument für Einfügen in Dokument
|
||||||
default height for the windows common de Vorgabewert für Höhe des Fensters
|
default height for the windows common de Vorgabewert für Höhe des Fensters
|
||||||
default visible actions common de standardmäßig sichtbare Aktionen
|
default visible actions common de standardmäßig sichtbare Aktionen
|
||||||
default width for the windows common de Vorgabewert für Breite des Fensters
|
default width for the windows common de Vorgabewert für Breite des Fensters
|
||||||
@ -417,6 +419,8 @@ diable the execution a bugfixscript for internet explorer 5.5 and higher to show
|
|||||||
direction left to right common de Richtung von links nach rechts
|
direction left to right common de Richtung von links nach rechts
|
||||||
directory common de Verzeichnis
|
directory common de Verzeichnis
|
||||||
directory does not exist, is not readable by the webserver or is not relative to the document root! common de Verzeichnis existiert nicht, ist nicht vom Webserver lesbar oder ist nicht entsprechend zur Dokumentroot!
|
directory does not exist, is not readable by the webserver or is not relative to the document root! common de Verzeichnis existiert nicht, ist nicht vom Webserver lesbar oder ist nicht entsprechend zur Dokumentroot!
|
||||||
|
directory for storing merged documents preferences de Verzeichnis für zusammengeführte Platzhalter-Dokumente
|
||||||
|
directory with documents to insert entries preferences de Vorlagen-Verzeichnis für Einfügen in Dokument
|
||||||
disable internet explorer png-image-bugfix common de Internet Explorer PNG-Bilder-Bugfix abschalten
|
disable internet explorer png-image-bugfix common de Internet Explorer PNG-Bilder-Bugfix abschalten
|
||||||
disable slider effects common de Schwebeeffekte des Navigationsmenüs abschalten
|
disable slider effects common de Schwebeeffekte des Navigationsmenüs abschalten
|
||||||
disable the animated slider effects when showing or hiding menus in the page? opera and konqueror users will probably must want this. common de Die animierten Schwebeeffekte beim Anzeigen oder Verstecken des Navigationsmenüs in der Seite abschalten? Benutzer von Opera oder Konquerer müssen diese Funktion abschalten.
|
disable the animated slider effects when showing or hiding menus in the page? opera and konqueror users will probably must want this. common de Die animierten Schwebeeffekte beim Anzeigen oder Verstecken des Navigationsmenüs in der Seite abschalten? Benutzer von Opera oder Konquerer müssen diese Funktion abschalten.
|
||||||
@ -1500,6 +1504,7 @@ western sahara common de WEST SAHARA
|
|||||||
what color should all the blank space on the desktop have common de Welche Farbe soll der freie Platz auf der Arbeitsfläche haben
|
what color should all the blank space on the desktop have common de Welche Farbe soll der freie Platz auf der Arbeitsfläche haben
|
||||||
what happens with overflowing content: visible (default), hidden, scroll, auto (browser decides) common de was passiert mit überbreitem Inhalt: sichtbar (standard), versteckt, rollend, automatisch (der Browser entscheidet)
|
what happens with overflowing content: visible (default), hidden, scroll, auto (browser decides) common de was passiert mit überbreitem Inhalt: sichtbar (standard), versteckt, rollend, automatisch (der Browser entscheidet)
|
||||||
what style would you like the image to have? common de Welchen Stil soll das Bild haben?
|
what style would you like the image to have? common de Welchen Stil soll das Bild haben?
|
||||||
|
when you merge entries into documents, they will be stored here. If no directory is provided, they will be stored in your home directory (%1) preferences de Wenn Sie Einträge mit Platzhalter-Dokumenten zusammenführen, werden diese hier gespeichert. Wenn Sie kein Verzeichnis angeben, werden diese in Ihrem Homeverzeichnis gespeichert (%1)
|
||||||
when you say yes the home and logout buttons are presented as applications in the main top applcation bar. common de Wenn Sie dies aktivieren, werden die Start und Abmelde Symbole als Anwendungen im oberen Anwendungsbalken angezeigt.
|
when you say yes the home and logout buttons are presented as applications in the main top applcation bar. common de Wenn Sie dies aktivieren, werden die Start und Abmelde Symbole als Anwendungen im oberen Anwendungsbalken angezeigt.
|
||||||
where and how will the egroupware links like preferences, about and logout be displayed. common de Wo und wie werden die EGroupware Verknüpfungen wie Einstellungen, Über ..., und Abmelden angezeigt.
|
where and how will the egroupware links like preferences, about and logout be displayed. common de Wo und wie werden die EGroupware Verknüpfungen wie Einstellungen, Über ..., und Abmelden angezeigt.
|
||||||
which groups common de Welche Gruppen
|
which groups common de Welche Gruppen
|
||||||
|
@ -274,6 +274,7 @@ choose a background style. common en Choose a background style
|
|||||||
choose a text color for the icons common en Choose a text color for the icons
|
choose a text color for the icons common en Choose a text color for the icons
|
||||||
choose file... common en Choose file...
|
choose file... common en Choose file...
|
||||||
choose the category common en Choose the category
|
choose the category common en Choose the category
|
||||||
|
choose the default filename for merged documents. preferences en Choose the default filename for merged documents.
|
||||||
choose the parent category common en Choose the parent category
|
choose the parent category common en Choose the parent category
|
||||||
choose time common en Choose Time
|
choose time common en Choose Time
|
||||||
chosen parent category no longer exists common en Chosen parent category no longer exists
|
chosen parent category no longer exists common en Chosen parent category no longer exists
|
||||||
@ -378,6 +379,7 @@ december common en December
|
|||||||
deck common en Deck (internal)
|
deck common en Deck (internal)
|
||||||
default common en Default
|
default common en Default
|
||||||
default category common en Default category
|
default category common en Default category
|
||||||
|
default document to insert entries preferences en Default document to insert entries
|
||||||
default height for the windows common en Default height for the windows
|
default height for the windows common en Default height for the windows
|
||||||
default visible actions common en Default visible actions
|
default visible actions common en Default visible actions
|
||||||
default width for the windows common en Default width for the windows
|
default width for the windows common en Default width for the windows
|
||||||
@ -417,6 +419,8 @@ diable the execution a bugfixscript for internet explorer 5.5 and higher to show
|
|||||||
direction left to right common en Direction left to right
|
direction left to right common en Direction left to right
|
||||||
directory common en Directory
|
directory common en Directory
|
||||||
directory does not exist, is not readable by the webserver or is not relative to the document root! common en Directory does not exist, is not readable by the web server or is not relative to the document root!
|
directory does not exist, is not readable by the webserver or is not relative to the document root! common en Directory does not exist, is not readable by the web server or is not relative to the document root!
|
||||||
|
directory for storing merged documents preferences en Directory for storing merged documents
|
||||||
|
directory with documents to insert entries preferences en Directory with documents to insert entries
|
||||||
disable internet explorer png-image-bugfix common en Disable Internet Explorer png image bugfix
|
disable internet explorer png-image-bugfix common en Disable Internet Explorer png image bugfix
|
||||||
disable slider effects common en Disable slider effects
|
disable slider effects common en Disable slider effects
|
||||||
disable the animated slider effects when showing or hiding menus in the page? opera and konqueror users will probably must want this. common en Disable the animated slider effects when showing or hiding menus in the page.
|
disable the animated slider effects when showing or hiding menus in the page? opera and konqueror users will probably must want this. common en Disable the animated slider effects when showing or hiding menus in the page.
|
||||||
@ -857,6 +861,7 @@ maybe common en Maybe
|
|||||||
mayotte common en MAYOTTE
|
mayotte common en MAYOTTE
|
||||||
medium common en Medium
|
medium common en Medium
|
||||||
menu common en Menu
|
menu common en Menu
|
||||||
|
merged document filename preferences en Merged document filename
|
||||||
message common en Message
|
message common en Message
|
||||||
message ... common en Message ...
|
message ... common en Message ...
|
||||||
message prepared for sending. common en Message prepared for sending.
|
message prepared for sending. common en Message prepared for sending.
|
||||||
@ -1501,6 +1506,7 @@ western sahara common en WESTERN SAHARA
|
|||||||
what color should all the blank space on the desktop have common en What color should all the blank space on the desktop have?
|
what color should all the blank space on the desktop have common en What color should all the blank space on the desktop have?
|
||||||
what happens with overflowing content: visible (default), hidden, scroll, auto (browser decides) common en What happens with overflowing content: visible (default), hidden, scroll, auto (browser decides)
|
what happens with overflowing content: visible (default), hidden, scroll, auto (browser decides) common en What happens with overflowing content: visible (default), hidden, scroll, auto (browser decides)
|
||||||
what style would you like the image to have? common en Image style
|
what style would you like the image to have? common en Image style
|
||||||
|
when you merge entries into documents, they will be stored here. If no directory is provided, they will be stored in your home directory (%1) preferences en When you merge entries into documents, they will be stored here. If no directory is provided, they will be stored in your home directory (%1)
|
||||||
when you say yes the home and logout buttons are presented as applications in the main top applcation bar. common en If you say yes, the Home and Log out buttons are presented as applications in the main top application bar.
|
when you say yes the home and logout buttons are presented as applications in the main top applcation bar. common en If you say yes, the Home and Log out buttons are presented as applications in the main top application bar.
|
||||||
where and how will the egroupware links like preferences, about and logout be displayed. common en Where and how will the EGroupware links like Preferences, About and Log out be displayed.
|
where and how will the egroupware links like preferences, about and logout be displayed. common en Where and how will the EGroupware links like Preferences, About and Log out be displayed.
|
||||||
which groups common en Which groups
|
which groups common en Which groups
|
||||||
|
@ -468,7 +468,7 @@ class Accounts
|
|||||||
$data = self::cache_read($id);
|
$data = self::cache_read($id);
|
||||||
|
|
||||||
// add default description for Admins and Default group
|
// add default description for Admins and Default group
|
||||||
if ($data['account_type'] === 'g')
|
if ($data && $data['account_type'] === 'g')
|
||||||
{
|
{
|
||||||
self::add_default_group_description($data);
|
self::add_default_group_description($data);
|
||||||
}
|
}
|
||||||
@ -595,11 +595,15 @@ class Accounts
|
|||||||
/**
|
/**
|
||||||
* Return formatted username for a given account_id
|
* Return formatted username for a given account_id
|
||||||
*
|
*
|
||||||
* @param int $account_id account id
|
* @param ?int $account_id account id, default current user
|
||||||
* @return string full name of user or "#$account_id" if user not found
|
* @return string full name of user or "#$account_id" if user not found
|
||||||
*/
|
*/
|
||||||
static function username(int $account_id)
|
static function username(int $account_id=null)
|
||||||
{
|
{
|
||||||
|
if (empty($account_id))
|
||||||
|
{
|
||||||
|
$account_id = $GLOBALS['egw_info']['user']['account_id'];
|
||||||
|
}
|
||||||
if (!($account = self::cache_read($account_id)))
|
if (!($account = self::cache_read($account_id)))
|
||||||
{
|
{
|
||||||
return '#'.$account_id;
|
return '#'.$account_id;
|
||||||
@ -985,7 +989,7 @@ class Accounts
|
|||||||
$ret = $just_id && $data['memberships'] ? array_keys($data['memberships']) : $data['memberships'];
|
$ret = $just_id && $data['memberships'] ? array_keys($data['memberships']) : $data['memberships'];
|
||||||
}
|
}
|
||||||
//error_log(__METHOD__."($account_id, $just_id) data=".array2string($data)." returning ".array2string($ret));
|
//error_log(__METHOD__."($account_id, $just_id) data=".array2string($data)." returning ".array2string($ret));
|
||||||
return $ret;
|
return $ret ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,8 +15,7 @@
|
|||||||
namespace EGroupware\Api;
|
namespace EGroupware\Api;
|
||||||
|
|
||||||
// allow to set an application depending authentication type (eg. for syncml, groupdav, ...)
|
// allow to set an application depending authentication type (eg. for syncml, groupdav, ...)
|
||||||
if (isset($GLOBALS['egw_info']['server']['auth_type_'.$GLOBALS['egw_info']['flags']['currentapp']]) &&
|
if (!empty($GLOBALS['egw_info']['server']['auth_type_'.$GLOBALS['egw_info']['flags']['currentapp']]))
|
||||||
$GLOBALS['egw_info']['server']['auth_type_'.$GLOBALS['egw_info']['flags']['currentapp']])
|
|
||||||
{
|
{
|
||||||
$GLOBALS['egw_info']['server']['auth_type'] = $GLOBALS['egw_info']['server']['auth_type_'.$GLOBALS['egw_info']['flags']['currentapp']];
|
$GLOBALS['egw_info']['server']['auth_type'] = $GLOBALS['egw_info']['server']['auth_type_'.$GLOBALS['egw_info']['flags']['currentapp']];
|
||||||
}
|
}
|
||||||
@ -223,11 +222,11 @@ class Auth
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (is_null($passwordAgeBorder) && $GLOBALS['egw_info']['server']['change_pwd_every_x_days'])
|
if (is_null($passwordAgeBorder) && !empty($GLOBALS['egw_info']['server']['change_pwd_every_x_days']))
|
||||||
{
|
{
|
||||||
$passwordAgeBorder = (DateTime::to('now','ts')-($GLOBALS['egw_info']['server']['change_pwd_every_x_days']*86400));
|
$passwordAgeBorder = (DateTime::to('now','ts')-($GLOBALS['egw_info']['server']['change_pwd_every_x_days']*86400));
|
||||||
}
|
}
|
||||||
if (is_null($daysLeftUntilChangeReq) && $GLOBALS['egw_info']['server']['warn_about_upcoming_pwd_change'])
|
if (is_null($daysLeftUntilChangeReq) && !empty($GLOBALS['egw_info']['server']['warn_about_upcoming_pwd_change']))
|
||||||
{
|
{
|
||||||
// maxage - passwordage = days left until change is required
|
// maxage - passwordage = days left until change is required
|
||||||
$daysLeftUntilChangeReq = ($GLOBALS['egw_info']['server']['change_pwd_every_x_days'] - ((DateTime::to('now','ts')-($alpwchange_val?$alpwchange_val:0))/86400));
|
$daysLeftUntilChangeReq = ($GLOBALS['egw_info']['server']['change_pwd_every_x_days'] - ((DateTime::to('now','ts')-($alpwchange_val?$alpwchange_val:0))/86400));
|
||||||
@ -235,9 +234,9 @@ class Auth
|
|||||||
if ($alpwchange_val == 0 || // admin requested password change
|
if ($alpwchange_val == 0 || // admin requested password change
|
||||||
$passwordAgeBorder > $alpwchange_val || // change password every N days policy requests change
|
$passwordAgeBorder > $alpwchange_val || // change password every N days policy requests change
|
||||||
// user should be warned N days in advance about change and is not yet
|
// user should be warned N days in advance about change and is not yet
|
||||||
$GLOBALS['egw_info']['server']['change_pwd_every_x_days'] &&
|
!empty($GLOBALS['egw_info']['server']['change_pwd_every_x_days']) &&
|
||||||
$GLOBALS['egw_info']['user']['apps']['preferences'] &&
|
!empty($GLOBALS['egw_info']['user']['apps']['preferences']) &&
|
||||||
$GLOBALS['egw_info']['server']['warn_about_upcoming_pwd_change'] &&
|
!empty($GLOBALS['egw_info']['server']['warn_about_upcoming_pwd_change']) &&
|
||||||
$GLOBALS['egw_info']['server']['warn_about_upcoming_pwd_change'] > $daysLeftUntilChangeReq &&
|
$GLOBALS['egw_info']['server']['warn_about_upcoming_pwd_change'] > $daysLeftUntilChangeReq &&
|
||||||
$UserKnowsAboutPwdChange !== true)
|
$UserKnowsAboutPwdChange !== true)
|
||||||
{
|
{
|
||||||
@ -255,8 +254,8 @@ class Auth
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// login page does not inform user about passwords about to expire
|
// login page does not inform user about passwords about to expire
|
||||||
if ($GLOBALS['egw_info']['flags']['currentapp'] != 'login' &&
|
if ($GLOBALS['egw_info']['flags']['currentapp'] !== 'login' &&
|
||||||
($GLOBALS['egw_info']['flags']['currentapp'] != 'home' ||
|
($GLOBALS['egw_info']['flags']['currentapp'] !== 'home' ||
|
||||||
strpos($_SERVER['SCRIPT_NAME'], '/home/') !== false))
|
strpos($_SERVER['SCRIPT_NAME'], '/home/') !== false))
|
||||||
{
|
{
|
||||||
$UserKnowsAboutPwdChange = true;
|
$UserKnowsAboutPwdChange = true;
|
||||||
|
@ -853,7 +853,7 @@ class Categories
|
|||||||
|
|
||||||
if (is_null(self::$cache)) self::init_cache();
|
if (is_null(self::$cache)) self::init_cache();
|
||||||
|
|
||||||
$cat = self::$cache[$cat_id];
|
$cat = self::$cache[$cat_id] ?? null;
|
||||||
if ($item == 'path')
|
if ($item == 'path')
|
||||||
{
|
{
|
||||||
if ($cat['parent'])
|
if ($cat['parent'])
|
||||||
@ -864,7 +864,7 @@ class Categories
|
|||||||
}
|
}
|
||||||
if ($item == 'data')
|
if ($item == 'data')
|
||||||
{
|
{
|
||||||
return $cat['data'] ? json_php_unserialize($cat['data'], true) : array();
|
return !empty($cat['data']) ? json_php_unserialize($cat['data'], true) : array();
|
||||||
}
|
}
|
||||||
elseif ($cat[$item])
|
elseif ($cat[$item])
|
||||||
{
|
{
|
||||||
|
@ -210,7 +210,7 @@ class Config
|
|||||||
{
|
{
|
||||||
self::init_static();
|
self::init_static();
|
||||||
}
|
}
|
||||||
return (array)self::$configs[$app];
|
return self::$configs[$app] ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -238,7 +238,7 @@ class Config
|
|||||||
{
|
{
|
||||||
$config = self::read($app);
|
$config = self::read($app);
|
||||||
|
|
||||||
return is_array($config['types']) ? $config['types'] : array();
|
return !empty($config['types']) && is_array($config['types']) ? $config['types'] : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -202,9 +202,9 @@ class Contacts extends Contacts\Storage
|
|||||||
$this->prefs['hide_accounts'] = '0';
|
$this->prefs['hide_accounts'] = '0';
|
||||||
}
|
}
|
||||||
// get the default addressbook from the users prefs
|
// get the default addressbook from the users prefs
|
||||||
$this->default_addressbook = $GLOBALS['egw_info']['user']['preferences']['addressbook']['add_default'] ?
|
$this->default_addressbook = !empty($GLOBALS['egw_info']['user']['preferences']['addressbook']['add_default']) ?
|
||||||
(int)$GLOBALS['egw_info']['user']['preferences']['addressbook']['add_default'] : $this->user;
|
(int)$GLOBALS['egw_info']['user']['preferences']['addressbook']['add_default'] : $this->user;
|
||||||
$this->default_private = substr($GLOBALS['egw_info']['user']['preferences']['addressbook']['add_default'],-1) == 'p';
|
$this->default_private = substr($GLOBALS['egw_info']['user']['preferences']['addressbook']['add_default'] ?? '',-1) == 'p';
|
||||||
if ($this->default_addressbook > 0 && $this->default_addressbook != $this->user &&
|
if ($this->default_addressbook > 0 && $this->default_addressbook != $this->user &&
|
||||||
($this->default_private ||
|
($this->default_private ||
|
||||||
$this->default_addressbook == (int)$GLOBALS['egw']->preferences->forced['addressbook']['add_default'] ||
|
$this->default_addressbook == (int)$GLOBALS['egw']->preferences->forced['addressbook']['add_default'] ||
|
||||||
@ -312,14 +312,14 @@ class Contacts extends Contacts\Storage
|
|||||||
'adr_two_countryname' => lang('country').' ('.lang('business').')',
|
'adr_two_countryname' => lang('country').' ('.lang('business').')',
|
||||||
);
|
);
|
||||||
//_debug_array($this->contact_fields);
|
//_debug_array($this->contact_fields);
|
||||||
$this->own_account_acl = $GLOBALS['egw_info']['server']['own_account_acl'];
|
$this->own_account_acl = $GLOBALS['egw_info']['server']['own_account_acl'] ?? null;
|
||||||
if (!is_array($this->own_account_acl)) $this->own_account_acl = json_php_unserialize($this->own_account_acl, true);
|
if (!is_array($this->own_account_acl)) $this->own_account_acl = json_php_unserialize($this->own_account_acl, true);
|
||||||
// we have only one acl (n_fn) for the whole name, as not all backends store every part in an own field
|
// we have only one acl (n_fn) for the whole name, as not all backends store every part in an own field
|
||||||
if ($this->own_account_acl && in_array('n_fn',$this->own_account_acl))
|
if ($this->own_account_acl && in_array('n_fn',$this->own_account_acl))
|
||||||
{
|
{
|
||||||
$this->own_account_acl = array_merge($this->own_account_acl,array('n_prefix','n_given','n_middle','n_family','n_suffix'));
|
$this->own_account_acl = array_merge($this->own_account_acl,array('n_prefix','n_given','n_middle','n_family','n_suffix'));
|
||||||
}
|
}
|
||||||
if ($GLOBALS['egw_info']['server']['org_fileds_to_update'])
|
if (!empty($GLOBALS['egw_info']['server']['org_fileds_to_update']))
|
||||||
{
|
{
|
||||||
$this->org_fields = $GLOBALS['egw_info']['server']['org_fileds_to_update'];
|
$this->org_fields = $GLOBALS['egw_info']['server']['org_fileds_to_update'];
|
||||||
if (!is_array($this->org_fields)) $this->org_fields = unserialize($this->org_fields);
|
if (!is_array($this->org_fields)) $this->org_fields = unserialize($this->org_fields);
|
||||||
@ -337,7 +337,7 @@ class Contacts extends Contacts\Storage
|
|||||||
}
|
}
|
||||||
$this->categories = new Categories($this->user,'addressbook');
|
$this->categories = new Categories($this->user,'addressbook');
|
||||||
|
|
||||||
$this->delete_history = $GLOBALS['egw_info']['server']['history'];
|
$this->delete_history = $GLOBALS['egw_info']['server']['history'] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -155,119 +155,6 @@ class Merge extends Api\Storage\Merge
|
|||||||
return $replacements;
|
return $replacements;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate table with replacements for the preferences
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public function show_replacements()
|
|
||||||
{
|
|
||||||
$GLOBALS['egw_info']['flags']['app_header'] = lang('Addressbook').' - '.lang('Replacements for inserting contacts into documents');
|
|
||||||
$GLOBALS['egw_info']['flags']['nonavbar'] = (bool)$_GET['nonavbar'];
|
|
||||||
|
|
||||||
ob_start();
|
|
||||||
echo "<table width='90%' align='center'>\n";
|
|
||||||
echo '<tr><td colspan="4"><h3>'.lang('Contact fields:')."</h3></td></tr>";
|
|
||||||
|
|
||||||
$n = 0;
|
|
||||||
foreach($this->contacts->contact_fields as $name => $label)
|
|
||||||
{
|
|
||||||
if (in_array($name,array('tid','label','geo'))) continue; // dont show them, as they are not used in the UI atm.
|
|
||||||
|
|
||||||
if (in_array($name,array('email','org_name','tel_work','url')) && $n&1) // main values, which should be in the first column
|
|
||||||
{
|
|
||||||
echo "</tr>\n";
|
|
||||||
$n++;
|
|
||||||
}
|
|
||||||
if (!($n&1)) echo '<tr>';
|
|
||||||
echo '<td>{{'.$name.'}}</td><td>'.$label.'</td>';
|
|
||||||
if($name == 'cat_id')
|
|
||||||
{
|
|
||||||
if ($n&1) echo "</tr>\n";
|
|
||||||
echo '<td>{{categories}}</td><td>'.lang('Category path').'</td>';
|
|
||||||
$n++;
|
|
||||||
}
|
|
||||||
if ($n&1) echo "</tr>\n";
|
|
||||||
$n++;
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '<tr><td colspan="4"><h3>'.lang('Custom fields').":</h3></td></tr>";
|
|
||||||
foreach($this->contacts->customfields as $name => $field)
|
|
||||||
{
|
|
||||||
echo '<tr><td>{{#'.$name.'}}</td><td colspan="3">'.$field['label']."</td></tr>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '<tr><td colspan="4"><h3>'.lang('General fields:')."</h3></td></tr>";
|
|
||||||
foreach(array(
|
|
||||||
'link' => lang('HTML link to the current record'),
|
|
||||||
'links' => lang('Titles of any entries linked to the current record, excluding attached files'),
|
|
||||||
'attachments' => lang('List of files linked to the current record'),
|
|
||||||
'links_attachments' => lang('Links and attached files'),
|
|
||||||
'links/[appname]' => lang('Links to specified application. Example: {{links/infolog}}'),
|
|
||||||
'date' => lang('Date'),
|
|
||||||
'user/n_fn' => lang('Name of current user, all other contact fields are valid too'),
|
|
||||||
'user/account_lid' => lang('Username'),
|
|
||||||
'pagerepeat' => lang('For serial letter use this tag. Put the content, you want to repeat between two Tags.'),
|
|
||||||
'label' => lang('Use this tag for addresslabels. Put the content, you want to repeat, between two tags.'),
|
|
||||||
'labelplacement' => lang('Tag to mark positions for address labels'),
|
|
||||||
'IF fieldname' => lang('Example {{IF n_prefix~Mr~Hello Mr.~Hello Ms.}} - search the field "n_prefix", for "Mr", if found, write Hello Mr., else write Hello Ms.'),
|
|
||||||
'NELF' => lang('Example {{NELF role}} - if field role is not empty, you will get a new line with the value of field role'),
|
|
||||||
'NENVLF' => lang('Example {{NENVLF role}} - if field role is not empty, set a LF without any value of the field'),
|
|
||||||
'LETTERPREFIX' => lang('Example {{LETTERPREFIX}} - Gives a letter prefix without double spaces, if the title is empty for example'),
|
|
||||||
'LETTERPREFIXCUSTOM' => lang('Example {{LETTERPREFIXCUSTOM n_prefix title n_family}} - Example: Mr Dr. James Miller'),
|
|
||||||
) as $name => $label)
|
|
||||||
{
|
|
||||||
echo '<tr><td>{{'.$name.'}}</td><td colspan="3">'.$label."</td></tr>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '<tr><td colspan="4"><h3>'.lang('EPL Only').":</h3></td></tr>";
|
|
||||||
echo '<tr><td>{{share}}</td><td colspan="3">'.lang('Public sharing URL')."</td></tr>\n";
|
|
||||||
|
|
||||||
Api\Translation::add_app('calendar');
|
|
||||||
echo '<tr><td colspan="4"><h3>'.lang('Calendar fields:')." # = 1, 2, ..., 20, -1</h3></td></tr>";
|
|
||||||
foreach(array(
|
|
||||||
'title' => lang('Title'),
|
|
||||||
'description' => lang('Description'),
|
|
||||||
'participants' => lang('Participants'),
|
|
||||||
'location' => lang('Location'),
|
|
||||||
'start' => lang('Start').': '.lang('Date').'+'.lang('Time'),
|
|
||||||
'startday' => lang('Start').': '.lang('Weekday'),
|
|
||||||
'startdate'=> lang('Start').': '.lang('Date'),
|
|
||||||
'starttime'=> lang('Start').': '.lang('Time'),
|
|
||||||
'end' => lang('End').': '.lang('Date').'+'.lang('Time'),
|
|
||||||
'endday' => lang('End').': '.lang('Weekday'),
|
|
||||||
'enddate' => lang('End').': '.lang('Date'),
|
|
||||||
'endtime' => lang('End').': '.lang('Time'),
|
|
||||||
'duration' => lang('Duration'),
|
|
||||||
'category' => lang('Category'),
|
|
||||||
'priority' => lang('Priority'),
|
|
||||||
'updated' => lang('Updated'),
|
|
||||||
'recur_type' => lang('Repetition'),
|
|
||||||
'access' => lang('Access').': '.lang('public').', '.lang('private'),
|
|
||||||
'owner' => lang('Owner'),
|
|
||||||
) as $name => $label)
|
|
||||||
{
|
|
||||||
if(in_array($name, array('start',
|
|
||||||
'end')) && $n & 1) // main values, which should be in the first column
|
|
||||||
{
|
|
||||||
echo "</tr>\n";
|
|
||||||
$n++;
|
|
||||||
}
|
|
||||||
if(!($n & 1))
|
|
||||||
{
|
|
||||||
echo '<tr>';
|
|
||||||
}
|
|
||||||
echo '<td>{{calendar/#/' . $name . '}}</td><td>' . $label . '</td>';
|
|
||||||
if($n & 1)
|
|
||||||
{
|
|
||||||
echo "</tr>\n";
|
|
||||||
}
|
|
||||||
$n++;
|
|
||||||
}
|
|
||||||
echo "</table>\n";
|
|
||||||
|
|
||||||
$GLOBALS['egw']->framework->render(ob_get_clean());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of placeholders provided.
|
* Get a list of placeholders provided.
|
||||||
*
|
*
|
||||||
@ -352,10 +239,58 @@ class Merge extends Api\Storage\Merge
|
|||||||
'label' => "Formatted private address"
|
'label' => "Formatted private address"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$placeholders['EPL only'][] = [
|
||||||
|
'value' => $this->prefix($prefix, 'share', '{'),
|
||||||
|
'label' => 'Public sharing URL'
|
||||||
|
];
|
||||||
|
|
||||||
$this->add_customfield_placeholders($placeholders, $prefix);
|
$this->add_customfield_placeholders($placeholders, $prefix);
|
||||||
|
|
||||||
|
// Don't add any linked placeholders if we're not at the top level
|
||||||
|
// This avoids potential recursion
|
||||||
|
if(!$prefix)
|
||||||
|
{
|
||||||
|
$this->add_calendar_placeholders($placeholders, $prefix);
|
||||||
|
}
|
||||||
|
|
||||||
return $placeholders;
|
return $placeholders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function add_calendar_placeholders(&$placeholders, $prefix)
|
||||||
|
{
|
||||||
|
Api\Translation::add_app('calendar');
|
||||||
|
|
||||||
|
// NB: The -1 is actually ‑1, a non-breaking hyphen to avoid UI issues where we split on -
|
||||||
|
$group = lang('Calendar fields:') . " # = 1, 2, ..., 20, ‑1";
|
||||||
|
foreach(array(
|
||||||
|
'title' => lang('Title'),
|
||||||
|
'description' => lang('Description'),
|
||||||
|
'participants' => lang('Participants'),
|
||||||
|
'location' => lang('Location'),
|
||||||
|
'start' => lang('Start') . ': ' . lang('Date') . '+' . lang('Time'),
|
||||||
|
'startday' => lang('Start') . ': ' . lang('Weekday'),
|
||||||
|
'startdate' => lang('Start') . ': ' . lang('Date'),
|
||||||
|
'starttime' => lang('Start') . ': ' . lang('Time'),
|
||||||
|
'end' => lang('End') . ': ' . lang('Date') . '+' . lang('Time'),
|
||||||
|
'endday' => lang('End') . ': ' . lang('Weekday'),
|
||||||
|
'enddate' => lang('End') . ': ' . lang('Date'),
|
||||||
|
'endtime' => lang('End') . ': ' . lang('Time'),
|
||||||
|
'duration' => lang('Duration'),
|
||||||
|
'category' => lang('Category'),
|
||||||
|
'priority' => lang('Priority'),
|
||||||
|
'updated' => lang('Updated'),
|
||||||
|
'recur_type' => lang('Repetition'),
|
||||||
|
'access' => lang('Access') . ': ' . lang('public') . ', ' . lang('private'),
|
||||||
|
'owner' => lang('Owner'),
|
||||||
|
) as $name => $label)
|
||||||
|
{
|
||||||
|
$placeholders[$group][] = array(
|
||||||
|
'value' => $this->prefix(($prefix ? $prefix . '/' : '') . 'calendar/#', $name, '{'),
|
||||||
|
'label' => $label
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get insert-in-document action with optional default document on top
|
* Get insert-in-document action with optional default document on top
|
||||||
*
|
*
|
||||||
|
@ -77,15 +77,15 @@ class Sql extends Api\Storage
|
|||||||
// Get custom fields from addressbook instead of api
|
// Get custom fields from addressbook instead of api
|
||||||
$this->customfields = Api\Storage\Customfields::get('addressbook');
|
$this->customfields = Api\Storage\Customfields::get('addressbook');
|
||||||
|
|
||||||
if ($GLOBALS['egw_info']['server']['account_repository'])
|
if (!empty($GLOBALS['egw_info']['server']['account_repository']))
|
||||||
{
|
{
|
||||||
$this->account_repository = $GLOBALS['egw_info']['server']['account_repository'];
|
$this->account_repository = $GLOBALS['egw_info']['server']['account_repository'];
|
||||||
}
|
}
|
||||||
elseif ($GLOBALS['egw_info']['server']['auth_type'])
|
elseif (!empty($GLOBALS['egw_info']['server']['auth_type']))
|
||||||
{
|
{
|
||||||
$this->account_repository = $GLOBALS['egw_info']['server']['auth_type'];
|
$this->account_repository = $GLOBALS['egw_info']['server']['auth_type'];
|
||||||
}
|
}
|
||||||
if ($GLOBALS['egw_info']['server']['contact_repository'])
|
if (!empty($GLOBALS['egw_info']['server']['contact_repository']))
|
||||||
{
|
{
|
||||||
$this->contact_repository = $GLOBALS['egw_info']['server']['contact_repository'];
|
$this->contact_repository = $GLOBALS['egw_info']['server']['contact_repository'];
|
||||||
}
|
}
|
||||||
@ -742,7 +742,7 @@ class Sql extends Api\Storage
|
|||||||
$cat_filter = array();
|
$cat_filter = array();
|
||||||
foreach(is_array($cats) ? $cats : (is_numeric($cats) ? array($cats) : explode(',',$cats)) as $cat)
|
foreach(is_array($cats) ? $cats : (is_numeric($cats) ? array($cats) : explode(',',$cats)) as $cat)
|
||||||
{
|
{
|
||||||
if (is_numeric($cat)) $cat_filter[] = $this->db->concat("','",cat_id,"','")." LIKE '%,$cat,%'";
|
if (is_numeric($cat)) $cat_filter[] = $this->db->concat("','", 'cat_id', "','")." LIKE '%,$cat,%'";
|
||||||
}
|
}
|
||||||
return $cat_filter;
|
return $cat_filter;
|
||||||
}
|
}
|
||||||
|
@ -256,7 +256,7 @@ class Storage
|
|||||||
}
|
}
|
||||||
$this->customfields = Api\Storage\Customfields::get('addressbook');
|
$this->customfields = Api\Storage\Customfields::get('addressbook');
|
||||||
// contacts backend (contacts in LDAP require accounts in LDAP!)
|
// contacts backend (contacts in LDAP require accounts in LDAP!)
|
||||||
if($GLOBALS['egw_info']['server']['contact_repository'] == 'ldap' && $this->account_repository == 'ldap')
|
if (($GLOBALS['egw_info']['server']['contact_repository']??null) === 'ldap' && $this->account_repository === 'ldap')
|
||||||
{
|
{
|
||||||
$this->contact_repository = 'ldap';
|
$this->contact_repository = 'ldap';
|
||||||
$this->somain = new Ldap();
|
$this->somain = new Ldap();
|
||||||
@ -264,7 +264,7 @@ class Storage
|
|||||||
}
|
}
|
||||||
else // sql or sql->ldap
|
else // sql or sql->ldap
|
||||||
{
|
{
|
||||||
if ($GLOBALS['egw_info']['server']['contact_repository'] == 'sql-ldap')
|
if (($GLOBALS['egw_info']['server']['contact_repository']??null) === 'sql-ldap')
|
||||||
{
|
{
|
||||||
$this->contact_repository = 'sql-ldap';
|
$this->contact_repository = 'sql-ldap';
|
||||||
}
|
}
|
||||||
@ -347,9 +347,9 @@ class Storage
|
|||||||
if ($user)
|
if ($user)
|
||||||
{
|
{
|
||||||
// contacts backend (contacts in LDAP require accounts in LDAP!)
|
// contacts backend (contacts in LDAP require accounts in LDAP!)
|
||||||
if($GLOBALS['egw_info']['server']['contact_repository'] == 'ldap' && $this->account_repository == 'ldap')
|
if(($GLOBALS['egw_info']['server']['contact_repository']??null) === 'ldap' && $this->account_repository === 'ldap')
|
||||||
{
|
{
|
||||||
// static grants from ldap: all rights for the own personal addressbook and the group ones of the meberships
|
// static grants from ldap: all rights for the own personal addressbook and the group ones of the memberships
|
||||||
$grants = array($user => ~0);
|
$grants = array($user => ~0);
|
||||||
foreach($GLOBALS['egw']->accounts->memberships($user,true) as $gid)
|
foreach($GLOBALS['egw']->accounts->memberships($user,true) as $gid)
|
||||||
{
|
{
|
||||||
@ -415,9 +415,9 @@ class Storage
|
|||||||
*/
|
*/
|
||||||
function allow_account_edit($user=null)
|
function allow_account_edit($user=null)
|
||||||
{
|
{
|
||||||
return $GLOBALS['egw_info']['server']['allow_account_edit'] &&
|
return !empty($GLOBALS['egw_info']['server']['allow_account_edit']) &&
|
||||||
array_intersect($GLOBALS['egw_info']['server']['allow_account_edit'],
|
array_intersect($GLOBALS['egw_info']['server']['allow_account_edit'],
|
||||||
$GLOBALS['egw']->accounts->memberships($user ? $user : $this->user, true));
|
$GLOBALS['egw']->accounts->memberships($user ?: $this->user, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -591,7 +591,7 @@ class Db
|
|||||||
$this->setupType = $this->Type;
|
$this->setupType = $this->Type;
|
||||||
$this->Type = 'mysql';
|
$this->Type = 'mysql';
|
||||||
}
|
}
|
||||||
if ($new_connection)
|
if (!empty($new_connection))
|
||||||
{
|
{
|
||||||
foreach(get_included_files() as $file)
|
foreach(get_included_files() as $file)
|
||||||
{
|
{
|
||||||
@ -1599,7 +1599,7 @@ class Db
|
|||||||
{
|
{
|
||||||
return $array;
|
return $array;
|
||||||
}
|
}
|
||||||
if (!$column_definitions)
|
if (empty($column_definitions))
|
||||||
{
|
{
|
||||||
$column_definitions = $this->column_definitions;
|
$column_definitions = $this->column_definitions;
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ class Pdo
|
|||||||
// Exception reveals password, so we ignore the exception and connect again without pw, to get the right exception without pw
|
// Exception reveals password, so we ignore the exception and connect again without pw, to get the right exception without pw
|
||||||
self::$pdo = new \PDO($dsn,$egw_db->User,'$egw_db->Password');
|
self::$pdo = new \PDO($dsn,$egw_db->User,'$egw_db->Password');
|
||||||
}
|
}
|
||||||
if ($query)
|
if (!empty($query))
|
||||||
{
|
{
|
||||||
self::$pdo->exec($query);
|
self::$pdo->exec($query);
|
||||||
}
|
}
|
||||||
|
@ -117,22 +117,22 @@ class Etemplate extends Etemplate\Widget\Template
|
|||||||
|
|
||||||
foreach(count(array_filter(array_keys($extras), 'is_int')) ? $extras : array($extras) as $extra)
|
foreach(count(array_filter(array_keys($extras), 'is_int')) ? $extras : array($extras) as $extra)
|
||||||
{
|
{
|
||||||
if ($extra['data'] && is_array($extra['data']))
|
if (!empty($extra['data']) && is_array($extra['data']))
|
||||||
{
|
{
|
||||||
$content = array_merge($content, $extra['data']);
|
$content = array_merge($content, $extra['data']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($extra['preserve'] && is_array($extra['preserve']))
|
if (!empty($extra['preserve']) && is_array($extra['preserve']))
|
||||||
{
|
{
|
||||||
$preserv = array_merge($preserv, $extra['preserve']);
|
$preserv = array_merge($preserv, $extra['preserve']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($extra['readonlys'] && is_array($extra['readonlys']))
|
if (!empty($extra['readonlys']) && is_array($extra['readonlys']))
|
||||||
{
|
{
|
||||||
$readonlys = array_merge($readonlys, $extra['readonlys']);
|
$readonlys = array_merge($readonlys, $extra['readonlys']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($extra['sel_options'] && is_array($extra['sel_options']))
|
if (!empty($extra['sel_options']) && is_array($extra['sel_options']))
|
||||||
{
|
{
|
||||||
$sel_options = array_merge($sel_options, $extra['sel_options']);
|
$sel_options = array_merge($sel_options, $extra['sel_options']);
|
||||||
}
|
}
|
||||||
@ -177,7 +177,7 @@ class Etemplate extends Etemplate\Widget\Template
|
|||||||
}
|
}
|
||||||
|
|
||||||
// some apps (eg. InfoLog) set app_header only in get_rows depending on filter settings
|
// some apps (eg. InfoLog) set app_header only in get_rows depending on filter settings
|
||||||
self::$request->app_header = $GLOBALS['egw_info']['flags']['app_header'];
|
self::$request->app_header = $GLOBALS['egw_info']['flags']['app_header'] ?? null;
|
||||||
|
|
||||||
// compile required translations translations
|
// compile required translations translations
|
||||||
$currentapp = $GLOBALS['egw_info']['flags']['currentapp'];
|
$currentapp = $GLOBALS['egw_info']['flags']['currentapp'];
|
||||||
@ -209,7 +209,7 @@ class Etemplate extends Etemplate\Widget\Template
|
|||||||
'currentapp' => $currentapp,
|
'currentapp' => $currentapp,
|
||||||
);
|
);
|
||||||
|
|
||||||
if($data['content']['nm']['rows'] && is_array($data['content']['nm']['rows']))
|
if (!empty($data['content']['nm']['rows']) && is_array($data['content']['nm']['rows']))
|
||||||
{
|
{
|
||||||
// Deep copy rows so we don't lose them when request is set to null
|
// Deep copy rows so we don't lose them when request is set to null
|
||||||
// (some content by reference)
|
// (some content by reference)
|
||||||
@ -420,7 +420,7 @@ class Etemplate extends Etemplate\Widget\Template
|
|||||||
}
|
}
|
||||||
|
|
||||||
$tcontent = is_array($content) ? $content :
|
$tcontent = is_array($content) ? $content :
|
||||||
self::complete_array_merge(self::$request->preserv, $validated);
|
self::complete_array_merge(self::$request->preserv ?? [], $validated);
|
||||||
|
|
||||||
$hook_data = Hooks::process(
|
$hook_data = Hooks::process(
|
||||||
array(
|
array(
|
||||||
|
@ -428,9 +428,9 @@ class Request
|
|||||||
* @param string $var
|
* @param string $var
|
||||||
* @param mixed $val
|
* @param mixed $val
|
||||||
*/
|
*/
|
||||||
public function __set($var,$val)
|
public function __set($var, $val)
|
||||||
{
|
{
|
||||||
if ($this->data[$var] !== $val)
|
if (!isset($this->data[$var]) || $this->data[$var] !== $val)
|
||||||
{
|
{
|
||||||
$this->data[$var] = $val;
|
$this->data[$var] = $val;
|
||||||
//error_log(__METHOD__."('$var', ...) data of id=$this->id changed ...");
|
//error_log(__METHOD__."('$var', ...) data of id=$this->id changed ...");
|
||||||
|
@ -97,9 +97,10 @@ class Files extends Etemplate\Request
|
|||||||
* Factory method to get a new request object or the one for an existing request
|
* Factory method to get a new request object or the one for an existing request
|
||||||
*
|
*
|
||||||
* @param string $id =null
|
* @param string $id =null
|
||||||
* @return ?Etemplate\Request|false the object or false if $id is not found
|
* @param bool $handle_not_found =true true: handle not found by trying to redirect, false: just return null
|
||||||
|
* @return Request|null null if Request not found and $handle_not_found === false
|
||||||
*/
|
*/
|
||||||
static function read($id=null)
|
public static function read($id=null, $handle_not_found=true)
|
||||||
{
|
{
|
||||||
$request = new Files($id);
|
$request = new Files($id);
|
||||||
|
|
||||||
|
@ -83,9 +83,10 @@ class Session extends Etemplate\Request
|
|||||||
* Factory method to get a new request object or the one for an existing request
|
* Factory method to get a new request object or the one for an existing request
|
||||||
*
|
*
|
||||||
* @param string $id =null
|
* @param string $id =null
|
||||||
* @return ?Etemplate\request|false the object or false if $id is not found
|
* @param bool $handle_not_found =true true: handle not found by trying to redirect, false: just return null
|
||||||
|
* @return Request|null null if Request not found and $handle_not_found === false
|
||||||
*/
|
*/
|
||||||
static function read($id=null)
|
public static function read($id=null, $handle_not_found=true)
|
||||||
{
|
{
|
||||||
$request = new Session($id);
|
$request = new Session($id);
|
||||||
|
|
||||||
|
@ -553,12 +553,21 @@ class Widget
|
|||||||
$method = new ReflectionMethod($this, $method_name);
|
$method = new ReflectionMethod($this, $method_name);
|
||||||
foreach($method->getParameters() as $index => $param)
|
foreach($method->getParameters() as $index => $param)
|
||||||
{
|
{
|
||||||
if(!$param->isOptional() && !array_key_exists($index,$params))
|
if(!$param->isOptional() && !array_key_exists($index, $params))
|
||||||
{
|
{
|
||||||
error_log("Missing required parameter {$param->getPosition()}: {$param->getName()}");
|
error_log("Missing required parameter {$param->getPosition()}: {$param->getName()}");
|
||||||
$call = false;
|
$call = false;
|
||||||
}
|
}
|
||||||
if($param->isArray() && !is_array($params[$index]))
|
// Check to see if method wants an array, and we're providing it
|
||||||
|
$paramType = $param->getType();
|
||||||
|
if(!$paramType)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$types = $paramType instanceof \ReflectionUnionType
|
||||||
|
? $paramType->getTypes()
|
||||||
|
: [$paramType];
|
||||||
|
if(in_array('array', array_map(fn(\ReflectionNamedType $t) => $t->getName(), $types)) && !is_array($params[$index]))
|
||||||
{
|
{
|
||||||
error_log("$method_name expects an array for {$param->getPosition()}: {$param->getName()}");
|
error_log("$method_name expects an array for {$param->getPosition()}: {$param->getName()}");
|
||||||
$params[$index] = (array)$params[$index];
|
$params[$index] = (array)$params[$index];
|
||||||
@ -1044,6 +1053,10 @@ class Widget
|
|||||||
*/
|
*/
|
||||||
public static function &setElementAttribute($name,$attr,$val)
|
public static function &setElementAttribute($name,$attr,$val)
|
||||||
{
|
{
|
||||||
|
if (!isset(self::$request))
|
||||||
|
{
|
||||||
|
throw new \Exception(__METHOD__."('$name', '$attr', ".json_encode($val)." called before instanciating Api\Etemplate!");
|
||||||
|
}
|
||||||
//error_log(__METHOD__."('$name', '$attr', ...) request=".get_class(self::$request).", response=".get_class(self::$response).function_backtrace());
|
//error_log(__METHOD__."('$name', '$attr', ...) request=".get_class(self::$request).", response=".get_class(self::$response).function_backtrace());
|
||||||
$ref =& self::$request->modifications[$name][$attr];
|
$ref =& self::$request->modifications[$name][$attr];
|
||||||
if(self::$request && self::$response)
|
if(self::$request && self::$response)
|
||||||
|
@ -50,7 +50,7 @@ class Box extends Etemplate\Widget
|
|||||||
$old_expand = $params[1];
|
$old_expand = $params[1];
|
||||||
|
|
||||||
if ($this->id && $this->type != 'groupbox') $cname = self::form_name($cname, $this->id, $params[1]);
|
if ($this->id && $this->type != 'groupbox') $cname = self::form_name($cname, $this->id, $params[1]);
|
||||||
if (!empty($expand['cname']) && $expand['cname'] !== $cname && trim($cname))
|
if (($expand['cname'] ?? null) !== $cname && trim($cname))
|
||||||
{
|
{
|
||||||
$expand['cont'] =& self::get_array(self::$request->content, $cname);
|
$expand['cont'] =& self::get_array(self::$request->content, $cname);
|
||||||
$expand['cname'] = $cname;
|
$expand['cname'] = $cname;
|
||||||
|
@ -98,7 +98,7 @@ class Customfields extends Transformer
|
|||||||
$form_name = self::form_name($cname, $this->id, $expand);
|
$form_name = self::form_name($cname, $this->id, $expand);
|
||||||
|
|
||||||
// Store properties at top level, so all customfield widgets can share
|
// Store properties at top level, so all customfield widgets can share
|
||||||
if($this->attrs['app'])
|
if (!empty($this->attrs['app']))
|
||||||
{
|
{
|
||||||
$app = $this->attrs['app'];
|
$app = $this->attrs['app'];
|
||||||
}
|
}
|
||||||
@ -141,12 +141,12 @@ class Customfields extends Transformer
|
|||||||
// app changed
|
// app changed
|
||||||
$customfields = Api\Storage\Customfields::get($app);
|
$customfields = Api\Storage\Customfields::get($app);
|
||||||
}
|
}
|
||||||
if($this->attrs['customfields'])
|
if (!empty($this->attrs['customfields']))
|
||||||
{
|
{
|
||||||
$customfields = $this->attrs['customfields'];
|
$customfields = $this->attrs['customfields'];
|
||||||
}
|
}
|
||||||
// Filter fields
|
// Filter fields
|
||||||
if($this->attrs['field-names'])
|
if (!empty($this->attrs['field-names']))
|
||||||
{
|
{
|
||||||
$fields_name = explode(',', $this->attrs['field-names']);
|
$fields_name = explode(',', $this->attrs['field-names']);
|
||||||
foreach($fields_name as &$f)
|
foreach($fields_name as &$f)
|
||||||
@ -162,8 +162,8 @@ class Customfields extends Transformer
|
|||||||
|
|
||||||
$fields = $customfields;
|
$fields = $customfields;
|
||||||
|
|
||||||
$use_private = self::expand_name($this->attrs['use-private'],0,0,'','',self::$cont);
|
$use_private = self::expand_name($this->attrs['use-private'] ?? null,0,0,'','',self::$cont);
|
||||||
$this->attrs['sub-type'] = self::expand_name($this->attrs['sub-type'],0,0,'','',self::$cont);
|
$this->attrs['sub-type'] = self::expand_name($this->attrs['sub-type'] ?? null,0,0,'','',self::$cont);
|
||||||
|
|
||||||
foreach((array)$fields as $key => $field)
|
foreach((array)$fields as $key => $field)
|
||||||
{
|
{
|
||||||
@ -174,7 +174,7 @@ class Customfields extends Transformer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove filtered fields
|
// Remove filtered fields
|
||||||
if($field_filters && in_array($key, $negate_fields) && in_array($key, $field_filters))
|
if (!empty($field_filters) && in_array($key, $negate_fields) && in_array($key, $field_filters))
|
||||||
{
|
{
|
||||||
unset($fields[$key]);
|
unset($fields[$key]);
|
||||||
}
|
}
|
||||||
@ -284,7 +284,7 @@ class Customfields extends Transformer
|
|||||||
|
|
||||||
$type = $field['type'];
|
$type = $field['type'];
|
||||||
// Link-tos needs to change from appname to link-to
|
// Link-tos needs to change from appname to link-to
|
||||||
if($link_types[$field['type']])
|
if (!empty($link_types[$field['type']]))
|
||||||
{
|
{
|
||||||
if($type == 'filemanager')
|
if($type == 'filemanager')
|
||||||
{
|
{
|
||||||
@ -314,8 +314,8 @@ class Customfields extends Transformer
|
|||||||
{
|
{
|
||||||
$widget->attrs['data_format'] = $type == 'date' ? 'Y-m-d' : 'Y-m-d H:i:s';
|
$widget->attrs['data_format'] = $type == 'date' ? 'Y-m-d' : 'Y-m-d H:i:s';
|
||||||
}
|
}
|
||||||
if($field['values']['min']) $widget->attrs['min'] = $field['values']['min'];
|
if (isset($field['values']['min'])) $widget->attrs['min'] = $field['values']['min'];
|
||||||
if($field['values']['max']) $widget->attrs['min'] = $field['values']['max'];
|
if (isset($field['values']['max'])) $widget->attrs['min'] = $field['values']['max'];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'vfs-upload':
|
case 'vfs-upload':
|
||||||
@ -355,7 +355,7 @@ class Customfields extends Transformer
|
|||||||
$field['values'] = Api\Storage\Customfields::get_options_from_file($field['values']['@']);
|
$field['values'] = Api\Storage\Customfields::get_options_from_file($field['values']['@']);
|
||||||
}
|
}
|
||||||
// keep extra values set by app code, eg. addressbook advanced search
|
// keep extra values set by app code, eg. addressbook advanced search
|
||||||
if (is_array(self::$request->sel_options[self::$prefix.$fname]))
|
if (!empty(self::$request->sel_options[self::$prefix.$fname]) && is_array(self::$request->sel_options[self::$prefix.$fname]))
|
||||||
{
|
{
|
||||||
self::$request->sel_options[self::$prefix.$fname] += (array)$field['values'];
|
self::$request->sel_options[self::$prefix.$fname] += (array)$field['values'];
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ class Description extends Etemplate\Widget
|
|||||||
*/
|
*/
|
||||||
public function beforeSendToClient($cname, array $expand=null)
|
public function beforeSendToClient($cname, array $expand=null)
|
||||||
{
|
{
|
||||||
if ($this->attrs['activate_links'])
|
if (!empty($this->attrs['activate_links']))
|
||||||
{
|
{
|
||||||
$form_name = self::form_name($cname, $this->id, $expand);
|
$form_name = self::form_name($cname, $this->id, $expand);
|
||||||
$value =& self::get_array(self::$request->content, $form_name);
|
$value =& self::get_array(self::$request->content, $form_name);
|
||||||
|
@ -88,8 +88,11 @@ class Grid extends Box
|
|||||||
return false; // return
|
return false; // return
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->id && $this->type !== 'row') $cname = self::form_name($cname, $this->id, $expand);
|
if($this->id && $this->type !== 'row')
|
||||||
if (!empty($expand['cname']) && $expand['cname'] !== $cname && $cname)
|
{
|
||||||
|
$cname = self::form_name($cname, $this->id, $expand);
|
||||||
|
}
|
||||||
|
if($cname && (!empty($expand['cname']) && $expand['cname'] !== $cname || !$expand['cname']))
|
||||||
{
|
{
|
||||||
$expand['cont'] =& self::get_array(self::$request->content, $cname);
|
$expand['cont'] =& self::get_array(self::$request->content, $cname);
|
||||||
$expand['cname'] = $cname;
|
$expand['cname'] = $cname;
|
||||||
|
@ -36,17 +36,17 @@ class Image extends Etemplate\Widget
|
|||||||
|
|
||||||
$image = $value != '' ? $value : $this->attrs['src'];
|
$image = $value != '' ? $value : $this->attrs['src'];
|
||||||
|
|
||||||
if (is_string($image)) list($app,$img) = explode('/',$image,2);
|
if (is_string($image)) list($app,$img) = explode('/',$image,2)+[null,null];
|
||||||
if (!$app || !$img || !is_dir(EGW_SERVER_ROOT.'/'.$app) || strpos($img,'/')!==false)
|
if (empty($app) || empty($img) || !is_dir(EGW_SERVER_ROOT.'/'.$app) || strpos($img,'/')!==false)
|
||||||
{
|
{
|
||||||
$img = $image;
|
$img = $image;
|
||||||
list($app) = explode('.',$form_name);
|
list($app) = explode('.',$form_name);
|
||||||
}
|
}
|
||||||
$src = Api\Image::find($app, $img);
|
$src = Api\Image::find($app, $img);
|
||||||
if(!$this->id)
|
/*if(!$this->id)
|
||||||
{
|
{
|
||||||
// self::setElementAttribute($this->attrs['src'], 'id', $this->attrs['src']);
|
// self::setElementAttribute($this->attrs['src'], 'id', $this->attrs['src']);
|
||||||
}
|
}*/
|
||||||
self::setElementAttribute($this->attrs['src'], 'src', $src);
|
self::setElementAttribute($this->attrs['src'], 'src', $src);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,13 +130,13 @@ class Nextmatch extends Etemplate\Widget
|
|||||||
$send_value = $value;
|
$send_value = $value;
|
||||||
|
|
||||||
list($app) = explode('.',$value['get_rows']);
|
list($app) = explode('.',$value['get_rows']);
|
||||||
if(!$GLOBALS['egw_info']['apps'][$app])
|
if (empty($GLOBALS['egw_info']['apps'][$app]))
|
||||||
{
|
{
|
||||||
list($app) = explode('.',$this->attrs['template']);
|
list($app) = explode('.',$this->attrs['template']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for a favorite in URL
|
// Check for a favorite in URL
|
||||||
if($_GET['favorite'] && $value['favorites'])
|
if (!empty($_GET['favorite']) && !empty($value['favorites']))
|
||||||
{
|
{
|
||||||
$safe_name = preg_replace('/[^A-Za-z0-9-_]/','_',strip_tags($_GET['favorite']));
|
$safe_name = preg_replace('/[^A-Za-z0-9-_]/','_',strip_tags($_GET['favorite']));
|
||||||
$pref_name = "favorite_" .$safe_name;
|
$pref_name = "favorite_" .$safe_name;
|
||||||
@ -210,7 +210,7 @@ class Nextmatch extends Etemplate\Widget
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Favorite group for admins
|
// Favorite group for admins
|
||||||
if($GLOBALS['egw_info']['apps']['admin'] && $value['favorites'])
|
if (!empty($GLOBALS['egw_info']['apps']['admin']) && !empty($value['favorites']))
|
||||||
{
|
{
|
||||||
self::$request->sel_options[$form_name]['favorite']['group'] = array('all' => lang('All users')) +
|
self::$request->sel_options[$form_name]['favorite']['group'] = array('all' => lang('All users')) +
|
||||||
Select::typeOptions('select-account',',groups');
|
Select::typeOptions('select-account',',groups');
|
||||||
@ -894,7 +894,7 @@ class Nextmatch extends Etemplate\Widget
|
|||||||
if ($default_attrs) $action += $default_attrs;
|
if ($default_attrs) $action += $default_attrs;
|
||||||
|
|
||||||
// Add 'Select All' after first group
|
// Add 'Select All' after first group
|
||||||
if ($first_level && $group !== false && $action['group'] != $group && empty($egw_actions[$prefix.'select_all']))
|
if ($first_level && $group !== false && ($action['group']??null) != $group && empty($egw_actions[$prefix.'select_all']))
|
||||||
{
|
{
|
||||||
|
|
||||||
$egw_actions[$prefix.'select_all'] = array(
|
$egw_actions[$prefix.'select_all'] = array(
|
||||||
|
@ -49,7 +49,8 @@ class Password extends Etemplate\Widget\Textbox
|
|||||||
{
|
{
|
||||||
$form_name = self::form_name($cname, $this->id, $expand);
|
$form_name = self::form_name($cname, $this->id, $expand);
|
||||||
$value =& self::get_array(self::$request->content, $form_name);
|
$value =& self::get_array(self::$request->content, $form_name);
|
||||||
$plaintext = !in_array(self::expand_name($this->attrs['plaintext'],$expand['c'], $expand['row'], $expand['c_'], $expand['row_'], $expand['cont']),
|
$plaintext = !empty($this->attrs['plaintext']) && !in_array(
|
||||||
|
self::expand_name($this->attrs['plaintext'], $expand['c'] ?? null, $expand['row'] ?? null, $expand['c_'] ?? null, $expand['row_'] ?? null, $expand['cont']),
|
||||||
['false', '0']);
|
['false', '0']);
|
||||||
|
|
||||||
if (!empty($value))
|
if (!empty($value))
|
||||||
|
@ -64,9 +64,13 @@ class Placeholder extends Etemplate\Widget
|
|||||||
|
|
||||||
if(is_null($apps))
|
if(is_null($apps))
|
||||||
{
|
{
|
||||||
$apps = ['addressbook', 'user', 'general'] +
|
$apps = array_merge(
|
||||||
|
['addressbook', 'user', 'general'],
|
||||||
// We use linking for preview, so limit to apps that support links
|
// We use linking for preview, so limit to apps that support links
|
||||||
array_keys(Api\Link::app_list('query'));
|
array_keys(Api\Link::app_list('query')),
|
||||||
|
// Filemanager doesn't support links, but add it anyway
|
||||||
|
['filemanager']
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($apps as $appname)
|
foreach($apps as $appname)
|
||||||
@ -86,6 +90,8 @@ class Placeholder extends Etemplate\Widget
|
|||||||
// Looks like app doesn't support merging
|
// Looks like app doesn't support merging
|
||||||
continue 2;
|
continue 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Api\Translation::load_app($appname, $GLOBALS['egw_info']['user']['preferences']['common']['lang']);
|
||||||
$list = method_exists($merge, 'get_placeholder_list') ? $merge->get_placeholder_list() : [];
|
$list = method_exists($merge, 'get_placeholder_list') ? $merge->get_placeholder_list() : [];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -109,14 +109,14 @@ class Select extends Etemplate\Widget
|
|||||||
{
|
{
|
||||||
parent::set_attrs($xml, $cloned);
|
parent::set_attrs($xml, $cloned);
|
||||||
|
|
||||||
if ($this->attrs['multiple'] !== 'dynamic')
|
if (!isset($this->attrs['multiple']) || $this->attrs['multiple'] !== 'dynamic')
|
||||||
{
|
{
|
||||||
$this->attrs['multiple'] = !isset($this->attrs['multiple']) ? false :
|
$this->attrs['multiple'] = !isset($this->attrs['multiple']) ? false :
|
||||||
!(!$this->attrs['multiple'] || $this->attrs['multiple'] === 'false');
|
!(!$this->attrs['multiple'] || $this->attrs['multiple'] === 'false');
|
||||||
}
|
}
|
||||||
|
|
||||||
// set attrs[multiple] from attrs[options], unset options only if it just contains number or rows
|
// set attrs[multiple] from attrs[options], unset options only if it just contains number or rows
|
||||||
if ($this->attrs['options'] > 1)
|
if (isset($this->attrs['options']) && $this->attrs['options'] > 1)
|
||||||
{
|
{
|
||||||
$this->attrs['multiple'] = (int)$this->attrs['options'];
|
$this->attrs['multiple'] = (int)$this->attrs['options'];
|
||||||
if ((string)$this->attrs['multiple'] == $this->attrs['options'])
|
if ((string)$this->attrs['multiple'] == $this->attrs['options'])
|
||||||
@ -124,7 +124,7 @@ class Select extends Etemplate\Widget
|
|||||||
unset($this->attrs['options']);
|
unset($this->attrs['options']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elseif($this->attrs['rows'] > 1)
|
elseif(isset($this->attrs['rows']) && $this->attrs['rows'] > 1)
|
||||||
{
|
{
|
||||||
$this->attrs['multiple'] = true;
|
$this->attrs['multiple'] = true;
|
||||||
}
|
}
|
||||||
@ -311,8 +311,8 @@ class Select extends Etemplate\Widget
|
|||||||
{
|
{
|
||||||
$form_name = self::form_name($cname, $this->id, $expand);
|
$form_name = self::form_name($cname, $this->id, $expand);
|
||||||
}
|
}
|
||||||
if (!is_array(self::$request->sel_options[$form_name])) self::$request->sel_options[$form_name] = array();
|
if (empty(self::$request->sel_options[$form_name]) || !is_array(self::$request->sel_options[$form_name])) self::$request->sel_options[$form_name] = [];
|
||||||
$type = $this->attrs['type'] ? $this->attrs['type'] : $this->type;
|
$type = $this->attrs['type'] ?? $this->type;
|
||||||
if ($type != 'select' && $type != 'menupopup')
|
if ($type != 'select' && $type != 'menupopup')
|
||||||
{
|
{
|
||||||
// Check selection preference, we may be able to skip reading some data
|
// Check selection preference, we may be able to skip reading some data
|
||||||
@ -335,8 +335,8 @@ class Select extends Etemplate\Widget
|
|||||||
if (!isset($form_names_done[$form_name]) &&
|
if (!isset($form_names_done[$form_name]) &&
|
||||||
($type_options = self::typeOptions($this,
|
($type_options = self::typeOptions($this,
|
||||||
// typeOptions thinks # of rows is the first thing in options
|
// typeOptions thinks # of rows is the first thing in options
|
||||||
($this->attrs['rows'] && strpos($this->attrs['options'], $this->attrs['rows']) !== 0 ? $this->attrs['rows'].','.$this->attrs['options'] : $this->attrs['options']),
|
(!empty($this->attrs['rows']) && !empty($this->attrs['options']) && strpos($this->attrs['options'], $this->attrs['rows']) !== 0 ? $this->attrs['rows'].','.$this->attrs['options'] : $this->attrs['options']),
|
||||||
$no_lang, $this->attrs['readonly'], self::get_array(self::$request->content, $form_name), $form_name)))
|
$no_lang, $this->attrs['readonly'] ?? false, self::get_array(self::$request->content, $form_name), $form_name)))
|
||||||
{
|
{
|
||||||
self::fix_encoded_options($type_options);
|
self::fix_encoded_options($type_options);
|
||||||
|
|
||||||
@ -356,7 +356,7 @@ class Select extends Etemplate\Widget
|
|||||||
$options = (isset(self::$request->sel_options[$form_name]) ? $form_name : $this->id);
|
$options = (isset(self::$request->sel_options[$form_name]) ? $form_name : $this->id);
|
||||||
if(is_array(self::$request->sel_options[$options]))
|
if(is_array(self::$request->sel_options[$options]))
|
||||||
{
|
{
|
||||||
if(in_array($this->attrs['type'], self::$cached_types) && !isset($form_names_done[$options]))
|
if (isset($this->attrs['type']) && in_array($this->attrs['type'], self::$cached_types) && !isset($form_names_done[$options]))
|
||||||
{
|
{
|
||||||
// Fix any custom options from application
|
// Fix any custom options from application
|
||||||
self::fix_encoded_options(self::$request->sel_options[$options],true);
|
self::fix_encoded_options(self::$request->sel_options[$options],true);
|
||||||
@ -561,7 +561,7 @@ class Select extends Etemplate\Widget
|
|||||||
$field = self::expand_name($field, 0, 0,'','',self::$cont);
|
$field = self::expand_name($field, 0, 0,'','',self::$cont);
|
||||||
}
|
}
|
||||||
|
|
||||||
list($rows,$type,$type2,$type3,$type4,$type5) = $legacy_options;
|
list($rows,$type,$type2,$type3,$type4,$type5) = $legacy_options+[null,null,null,null,null,null];
|
||||||
$no_lang = false;
|
$no_lang = false;
|
||||||
$options = array();
|
$options = array();
|
||||||
switch ($widget_type)
|
switch ($widget_type)
|
||||||
@ -644,7 +644,7 @@ class Select extends Etemplate\Widget
|
|||||||
// These are extra info for easy dealing with categories
|
// These are extra info for easy dealing with categories
|
||||||
// client side, without extra loading
|
// client side, without extra loading
|
||||||
'main' => (int)$cat['main'],
|
'main' => (int)$cat['main'],
|
||||||
'children' => $cat['children'],
|
'children' => $cat['children'] ?? null,
|
||||||
//add different class per level to allow different styling for each category level:
|
//add different class per level to allow different styling for each category level:
|
||||||
'class' => "cat_level". $cat['level']
|
'class' => "cat_level". $cat['level']
|
||||||
);
|
);
|
||||||
@ -839,7 +839,7 @@ class Select extends Etemplate\Widget
|
|||||||
}
|
}
|
||||||
foreach((array)$options as $right => $name)
|
foreach((array)$options as $right => $name)
|
||||||
{
|
{
|
||||||
if(!!($value & $right))
|
if (!!((int)$value & (int)$right))
|
||||||
{
|
{
|
||||||
$new_value[] = $right;
|
$new_value[] = $right;
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ class Template extends Etemplate\Widget
|
|||||||
list($name) = explode('?', $_name); // remove optional cache-buster
|
list($name) = explode('?', $_name); // remove optional cache-buster
|
||||||
if (isset(self::$cache[$name]) || !($path = self::relPath($name, $template_set, $version, $load_via)))
|
if (isset(self::$cache[$name]) || !($path = self::relPath($name, $template_set, $version, $load_via)))
|
||||||
{
|
{
|
||||||
if ((!$path || self::read($load_via, $template_set)) && isset(self::$cache[$name]))
|
if ((empty($path) || self::read($load_via, $template_set)) && isset(self::$cache[$name]))
|
||||||
{
|
{
|
||||||
//error_log(__METHOD__."('$name', '$template_set', '$version', '$load_via') read from cache");
|
//error_log(__METHOD__."('$name', '$template_set', '$version', '$load_via') read from cache");
|
||||||
return self::$cache[$name];
|
return self::$cache[$name];
|
||||||
@ -146,7 +146,7 @@ class Template extends Etemplate\Widget
|
|||||||
{
|
{
|
||||||
static $prefixes = null;
|
static $prefixes = null;
|
||||||
unset($version); // not used currently
|
unset($version); // not used currently
|
||||||
list($app, $rest) = explode('.', $load_via ?: $name, 2);
|
list($app, $rest) = explode('.', $load_via ?: $name, 2)+[null,null];
|
||||||
|
|
||||||
if (empty($template_set))
|
if (empty($template_set))
|
||||||
{
|
{
|
||||||
@ -184,7 +184,7 @@ class Template extends Etemplate\Widget
|
|||||||
$path = $prefix.$path;
|
$path = $prefix.$path;
|
||||||
}
|
}
|
||||||
//error_log(__METHOD__."('$name', '$template_set') returning ".array2string($path));
|
//error_log(__METHOD__."('$name', '$template_set') returning ".array2string($path));
|
||||||
return $path;
|
return $path ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -230,16 +230,16 @@ class Template extends Etemplate\Widget
|
|||||||
{
|
{
|
||||||
$cname =& $params[0];
|
$cname =& $params[0];
|
||||||
$old_cname = $params[0];
|
$old_cname = $params[0];
|
||||||
if ($this->attrs['content']) $cname = self::form_name($cname, $this->attrs['content'], $params[1]);
|
if (!empty($this->attrs['content'])) $cname = self::form_name($cname, $this->attrs['content'], $params[1]);
|
||||||
|
|
||||||
// Check for template from content, and run over it
|
// Check for template from content, and run over it
|
||||||
// templates included via template tag have their name to load them from in attribute "template"
|
// templates included via template tag have their name to load them from in attribute "template"
|
||||||
$expand_name = self::expand_name($this->id ? $this->id : $this->attrs['template'], '','','','',self::$request->content);
|
$expand_name = self::expand_name($this->id ?: $this->attrs['template'], '','','','',self::$request->content);
|
||||||
if(!$expand_name && $this->id && $this->attrs['template'])
|
if(!$expand_name && $this->id && $this->attrs['template'])
|
||||||
{
|
{
|
||||||
$expand_name = $this->attrs['template'];
|
$expand_name = $this->attrs['template'];
|
||||||
}
|
}
|
||||||
if($this->original_name)
|
if (!empty($this->original_name))
|
||||||
{
|
{
|
||||||
$expand_name = self::expand_name($this->original_name, '','','','',self::$request->content);
|
$expand_name = self::expand_name($this->original_name, '','','','',self::$request->content);
|
||||||
}
|
}
|
||||||
|
@ -62,14 +62,14 @@ class Textbox extends Etemplate\Widget
|
|||||||
parent::set_attrs($xml, $cloned);
|
parent::set_attrs($xml, $cloned);
|
||||||
|
|
||||||
// Legacy handling only
|
// Legacy handling only
|
||||||
// A negative size triggered the HTML readonly attibute, but not etemplate readonly,
|
// A negative size triggered the HTML readonly attribute, but not etemplate readonly,
|
||||||
// so you got an input element, but it was not editable.
|
// so you got an input element, but it was not editable.
|
||||||
if ($this->attrs['size'] < 0)
|
if (isset($this->attrs['size']) && $this->attrs['size'] < 0)
|
||||||
{
|
{
|
||||||
self::setElementAttribute($this->id, 'size', abs($this->attrs['size']));
|
self::setElementAttribute($this->id, 'size', abs($this->attrs['size']));
|
||||||
self::$request->readonlys[$this->id] = false;
|
self::$request->readonlys[$this->id] = false;
|
||||||
self::setElementAttribute($this->id, 'readonly', true);
|
self::setElementAttribute($this->id, 'readonly', true);
|
||||||
trigger_error("Using a negative size to set textbox readonly. " .$this, E_USER_DEPRECATED);
|
//trigger_error("Using a negative size to set textbox readonly. " .$this, E_USER_DEPRECATED);
|
||||||
}
|
}
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ class Tree extends Etemplate\Widget
|
|||||||
parent::set_attrs($xml, $cloned);
|
parent::set_attrs($xml, $cloned);
|
||||||
|
|
||||||
// set attrs[multiple] from attrs[options]
|
// set attrs[multiple] from attrs[options]
|
||||||
if ($this->attrs['options'] > 1)
|
if (isset($this->attrs['options']) && (int)$this->attrs['options'] > 1)
|
||||||
{
|
{
|
||||||
self::setElementAttribute($this->id, 'multiple', true);
|
self::setElementAttribute($this->id, 'multiple', true);
|
||||||
}
|
}
|
||||||
@ -297,21 +297,21 @@ class Tree extends Etemplate\Widget
|
|||||||
{
|
{
|
||||||
$form_name = self::form_name($cname, $this->id);
|
$form_name = self::form_name($cname, $this->id);
|
||||||
|
|
||||||
if (($templated_path = self::templateImagePath($this->attrs['image_path'])) != $this->attrs['image_path'])
|
if (($templated_path = self::templateImagePath($this->attrs['image_path'] ?? null)) !== ($this->attrs['image_path'] ?? null))
|
||||||
{
|
{
|
||||||
self::setElementAttribute($form_name, 'image_path', $this->attrs['image_path'] = $templated_path);
|
self::setElementAttribute($form_name, 'image_path', $this->attrs['image_path'] = $templated_path);
|
||||||
//error_log(__METHOD__."() setting templated image-path for $form_name: $templated_path");
|
//error_log(__METHOD__."() setting templated image-path for $form_name: $templated_path");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_array(self::$request->sel_options[$form_name])) self::$request->sel_options[$form_name] = array();
|
if (empty(self::$request->sel_options[$form_name])) self::$request->sel_options[$form_name] = [];
|
||||||
if ($this->attrs['type'])
|
if (!empty($this->attrs['type']))
|
||||||
{
|
{
|
||||||
// += to keep further options set by app code
|
// += to keep further options set by app code
|
||||||
self::$request->sel_options[$form_name] += self::typeOptions($this->attrs['type'], $this->attrs['options'],
|
self::$request->sel_options[$form_name] += self::typeOptions($this->attrs['type'], $this->attrs['options'] ?? null,
|
||||||
$no_lang, $this->attrs['readonly'], self::get_array(self::$request->content, $form_name), $form_name);
|
$no_lang, $this->attrs['readonly'] ?? null, self::get_array(self::$request->content, $form_name), $form_name);
|
||||||
|
|
||||||
// if no_lang was modified, forward modification to the client
|
// if no_lang was modified, forward modification to the client
|
||||||
if ($no_lang != $this->attr['no_lang'])
|
if (!isset($this->attr['no_lang']) || $no_lang != $this->attr['no_lang'])
|
||||||
{
|
{
|
||||||
self::setElementAttribute($form_name, 'no_lang', $no_lang);
|
self::setElementAttribute($form_name, 'no_lang', $no_lang);
|
||||||
}
|
}
|
||||||
@ -440,7 +440,7 @@ class Tree extends Etemplate\Widget
|
|||||||
*/
|
*/
|
||||||
public static function typeOptions($widget_type, $legacy_options, &$no_lang=false, $readonly=false, $value=null, $form_name=null)
|
public static function typeOptions($widget_type, $legacy_options, &$no_lang=false, $readonly=false, $value=null, $form_name=null)
|
||||||
{
|
{
|
||||||
list($rows,$type,$type2,$type3) = explode(',',$legacy_options);
|
list($rows,$type,$type2,$type3) = explode(',', $legacy_options)+[null,null,null,null];
|
||||||
|
|
||||||
$no_lang = false;
|
$no_lang = false;
|
||||||
$options = array();
|
$options = array();
|
||||||
|
@ -37,10 +37,10 @@ class Vfs extends File
|
|||||||
*/
|
*/
|
||||||
public function beforeSendToClient($cname, $expand = array())
|
public function beforeSendToClient($cname, $expand = array())
|
||||||
{
|
{
|
||||||
if($this->type == 'vfs-upload' || $this->attrs['type'] == 'vfs-upload')
|
if ($this->type === 'vfs-upload' || !empty($this->attrs['type']) && $this->attrs['type'] === 'vfs-upload')
|
||||||
{
|
{
|
||||||
$form_name = self::form_name($cname, $this->id, $expand ? $expand : array('cont'=>self::$request->content));
|
$form_name = self::form_name($cname, $this->id, $expand ? $expand : array('cont'=>self::$request->content));
|
||||||
if($this->attrs['path'])
|
if (!empty($this->attrs['path']))
|
||||||
{
|
{
|
||||||
$path = self::expand_name($this->attrs['path'],$expand['c'], $expand['row'], $expand['c_'], $expand['row_'], $expand['cont']);
|
$path = self::expand_name($this->attrs['path'],$expand['c'], $expand['row'], $expand['c_'], $expand['row_'], $expand['cont']);
|
||||||
}
|
}
|
||||||
@ -226,7 +226,7 @@ class Vfs extends File
|
|||||||
foreach($links as $link)
|
foreach($links as $link)
|
||||||
{
|
{
|
||||||
$matches = null;
|
$matches = null;
|
||||||
if (is_array($link) && preg_match('|^'.preg_quote(Api\Vfs::PREFIX,'|').'('.preg_quote(self::get_temp_dir($app, ''), '|').'[^/]+)/|', $link['id']['tmp_name'], $matches))
|
if (is_array($link) && !empty($link['id']['tmp_name']) && preg_match('|^'.preg_quote(Api\Vfs::PREFIX,'|').'('.preg_quote(self::get_temp_dir($app, ''), '|').'[^/]+)/|', $link['id']['tmp_name'], $matches))
|
||||||
{
|
{
|
||||||
$replace[substr($link['id']['tmp_name'], strlen(Api\Vfs::PREFIX))] =
|
$replace[substr($link['id']['tmp_name'], strlen(Api\Vfs::PREFIX))] =
|
||||||
Api\Link::vfs_path($app, $id, Api\Vfs::basename($link['id']['tmp_name']), true);
|
Api\Link::vfs_path($app, $id, Api\Vfs::basename($link['id']['tmp_name']), true);
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
/**
|
/**
|
||||||
* EGroupware - Framework for Ajax based templates: jdots & Pixelegg
|
* EGroupware - Framework for Ajax based templates: jdots & Pixelegg
|
||||||
*
|
*
|
||||||
* @link http://www.stylite.de
|
* @link https://www.egroupware.org
|
||||||
* @package api
|
* @package api
|
||||||
* @subpackage framework
|
* @subpackage framework
|
||||||
* @author Andreas Stöckel <as@stylite.de>
|
* @author Andreas Stöckel
|
||||||
* @author Ralf Becker <rb@stylite.de>
|
* @author Ralf Becker <rb@egroupware.org>
|
||||||
* @author Nathan Gray <ng@stylite.de>
|
* @author Nathan Gray <ng@egroupware.org>
|
||||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ namespace EGroupware\Api\Framework;
|
|||||||
use EGroupware\Api;
|
use EGroupware\Api;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stylite jdots template
|
* Framework for Ajax based templates
|
||||||
*/
|
*/
|
||||||
abstract class Ajax extends Api\Framework
|
abstract class Ajax extends Api\Framework
|
||||||
{
|
{
|
||||||
@ -88,13 +88,13 @@ abstract class Ajax extends Api\Framework
|
|||||||
$width = self::DEFAULT_SIDEBAR_WIDTH;
|
$width = self::DEFAULT_SIDEBAR_WIDTH;
|
||||||
|
|
||||||
//Check whether the width had been stored explicitly for the jdots template, use that value
|
//Check whether the width had been stored explicitly for the jdots template, use that value
|
||||||
if ($GLOBALS['egw_info']['user']['preferences'][$app]['jdotssideboxwidth'])
|
if (!empty($GLOBALS['egw_info']['user']['preferences'][$app]['jdotssideboxwidth']))
|
||||||
{
|
{
|
||||||
$width = (int)$GLOBALS['egw_info']['user']['preferences'][$app]['jdotssideboxwidth'];
|
$width = (int)$GLOBALS['egw_info']['user']['preferences'][$app]['jdotssideboxwidth'];
|
||||||
// error_log(__METHOD__.__LINE__."($app):$width --> reading jdotssideboxwidth");
|
// error_log(__METHOD__.__LINE__."($app):$width --> reading jdotssideboxwidth");
|
||||||
}
|
}
|
||||||
//Otherwise use the legacy "idotssideboxwidth" value
|
//Otherwise use the legacy "idotssideboxwidth" value
|
||||||
else if ($GLOBALS['egw_info']['user']['preferences'][$app]['idotssideboxwidth'])
|
elseif (!empty($GLOBALS['egw_info']['user']['preferences'][$app]['idotssideboxwidth']))
|
||||||
{
|
{
|
||||||
$width = (int)$GLOBALS['egw_info']['user']['preferences'][$app]['idotssideboxwidth'];
|
$width = (int)$GLOBALS['egw_info']['user']['preferences'][$app]['idotssideboxwidth'];
|
||||||
// error_log(__METHOD__.__LINE__."($app):$width --> reading idotssideboxwidth");
|
// error_log(__METHOD__.__LINE__."($app):$width --> reading idotssideboxwidth");
|
||||||
@ -249,7 +249,7 @@ abstract class Ajax extends Api\Framework
|
|||||||
{
|
{
|
||||||
if (empty($GLOBALS['egw_info']['flags']['java_script'])) $GLOBALS['egw_info']['flags']['java_script']='';
|
if (empty($GLOBALS['egw_info']['flags']['java_script'])) $GLOBALS['egw_info']['flags']['java_script']='';
|
||||||
// eT2 sets $GLOBALS['egw_info']['flags']['nonavbar'] === 'popup' for popups, Etemplate::exec($outputmode === 2)
|
// eT2 sets $GLOBALS['egw_info']['flags']['nonavbar'] === 'popup' for popups, Etemplate::exec($outputmode === 2)
|
||||||
$extra['check-framework'] = $_GET['cd'] !== 'no' && $GLOBALS['egw_info']['flags']['nonavbar'] !== 'popup';
|
$extra['check-framework'] = (!isset($_GET['cd']) || $_GET['cd'] !== 'no') && $GLOBALS['egw_info']['flags']['nonavbar'] !== 'popup';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1047,16 +1047,16 @@ abstract class Ajax extends Api\Framework
|
|||||||
if (self::$footer_done) return; // prevent (multiple) footers
|
if (self::$footer_done) return; // prevent (multiple) footers
|
||||||
self::$footer_done = true;
|
self::$footer_done = true;
|
||||||
|
|
||||||
if (!isset($GLOBALS['egw_info']['flags']['nofooter']) || !$GLOBALS['egw_info']['flags']['nofooter'])
|
if (empty($GLOBALS['egw_info']['flags']['nofooter']))
|
||||||
{
|
{
|
||||||
if ($no_framework && $GLOBALS['egw_info']['user']['preferences']['common']['show_generation_time'])
|
if ($no_framework && !empty($GLOBALS['egw_info']['user']['preferences']['common']['show_generation_time']))
|
||||||
{
|
{
|
||||||
$vars = $this->_get_footer();
|
$vars = $this->_get_footer();
|
||||||
$footer = "\n".$vars['page_generation_time']."\n";
|
$footer = "\n".$vars['page_generation_time']."\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $footer.
|
return ($footer??'').
|
||||||
$GLOBALS['egw_info']['flags']['need_footer']."\n". // eg. javascript, which need to be at the end of the page
|
($GLOBALS['egw_info']['flags']['need_footer']??'')."\n". // eg. javascript, which need to be at the end of the page
|
||||||
"</body>\n</html>\n";
|
"</body>\n</html>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,12 +49,12 @@ class Bundle
|
|||||||
unset($GLOBALS['egw_info']['server']['debug_minify']);
|
unset($GLOBALS['egw_info']['server']['debug_minify']);
|
||||||
|
|
||||||
$file2bundle = array();
|
$file2bundle = array();
|
||||||
if ($GLOBALS['egw_info']['server']['debug_minify'] !== 'True')
|
if (!isset($GLOBALS['egw_info']['server']['debug_minify']) || $GLOBALS['egw_info']['server']['debug_minify'] !== 'True')
|
||||||
{
|
{
|
||||||
// get used bundles and cache them on tree-level for 2h
|
// get used bundles and cache them on tree-level for 2h
|
||||||
//$bundles = self::all(); Cache::setTree(__CLASS__, 'bundles', $bundles, 7200);
|
//$bundles = self::all(); Cache::setTree(__CLASS__, 'bundles', $bundles, 7200);
|
||||||
$bundles = Cache::getTree(__CLASS__, 'bundles', array(__CLASS__, 'all'), array(), 7200);
|
$bundles = Cache::getTree(__CLASS__, 'bundles', array(__CLASS__, 'all'), array(), 7200);
|
||||||
$bundles_ts = $bundles['.ts'];
|
$bundles_ts = $bundles['.ts'] ?? null;
|
||||||
unset($bundles['.ts']);
|
unset($bundles['.ts']);
|
||||||
foreach($bundles as $name => $files)
|
foreach($bundles as $name => $files)
|
||||||
{
|
{
|
||||||
@ -83,13 +83,13 @@ class Bundle
|
|||||||
|
|
||||||
if (!isset($to_include[$file]))
|
if (!isset($to_include[$file]))
|
||||||
{
|
{
|
||||||
if (($bundle = $file2bundle[$file]))
|
if (($bundle = $file2bundle[$file] ?? false))
|
||||||
{
|
{
|
||||||
//error_log(__METHOD__."() requiring bundle $bundle for $file");
|
//error_log(__METHOD__."() requiring bundle $bundle for $file");
|
||||||
if (!in_array($bundle, $included_bundles))
|
if (!in_array($bundle, $included_bundles))
|
||||||
{
|
{
|
||||||
$included_bundles[] = $bundle;
|
$included_bundles[] = $bundle;
|
||||||
$minurl = self::$bundle2minurl[$bundle];
|
$minurl = self::$bundle2minurl[$bundle] ?? null;
|
||||||
if (!isset($minurl) && isset($GLOBALS['egw_info']['apps'][$bundle]))
|
if (!isset($minurl) && isset($GLOBALS['egw_info']['apps'][$bundle]))
|
||||||
{
|
{
|
||||||
$minurl = '/'.$bundle.'/js/app.min.js';
|
$minurl = '/'.$bundle.'/js/app.min.js';
|
||||||
@ -108,10 +108,10 @@ class Bundle
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
unset($query);
|
unset($query);
|
||||||
list($path, $query) = explode('?', $file, 2);
|
list($path, $query) = explode('?', $file, 2)+[null,null];
|
||||||
$mod = filemtime(EGW_SERVER_ROOT.$path);
|
$mod = filemtime(EGW_SERVER_ROOT.$path);
|
||||||
// check if we have a more recent minified version of the file and use it
|
// check if we have a more recent minified version of the file and use it
|
||||||
if ($GLOBALS['egw_info']['server']['debug_minify'] !== 'True' &&
|
if ((!isset($GLOBALS['egw_info']['server']['debug_minify']) || $GLOBALS['egw_info']['server']['debug_minify'] !== 'True') &&
|
||||||
substr($path, -3) == '.js' && file_exists(EGW_SERVER_ROOT.($min_path = substr($path, 0, -3).'.min.js')) &&
|
substr($path, -3) == '.js' && file_exists(EGW_SERVER_ROOT.($min_path = substr($path, 0, -3).'.min.js')) &&
|
||||||
(($min_mod = filemtime(EGW_SERVER_ROOT.$min_path)) >= $mod))
|
(($min_mod = filemtime(EGW_SERVER_ROOT.$min_path)) >= $mod))
|
||||||
{
|
{
|
||||||
@ -148,7 +148,7 @@ class Bundle
|
|||||||
*/
|
*/
|
||||||
protected static function urls(array $js_includes, &$max_modified=null, $minurl=null)
|
protected static function urls(array $js_includes, &$max_modified=null, $minurl=null)
|
||||||
{
|
{
|
||||||
$debug_minify = $GLOBALS['egw_info']['server']['debug_minify'] === 'True';
|
$debug_minify = !empty($GLOBALS['egw_info']['server']['debug_minify']) && $GLOBALS['egw_info']['server']['debug_minify'] === 'True';
|
||||||
// ignore not existing minurl
|
// ignore not existing minurl
|
||||||
if (!empty($minurl) && !file_exists(EGW_SERVER_ROOT.$minurl)) $minurl = null;
|
if (!empty($minurl) && !file_exists(EGW_SERVER_ROOT.$minurl)) $minurl = null;
|
||||||
$to_include_first = $to_include = $to_minify = array();
|
$to_include_first = $to_include = $to_minify = array();
|
||||||
@ -158,7 +158,7 @@ class Bundle
|
|||||||
{
|
{
|
||||||
if ($path == '/api/js/jsapi/egw.js') continue; // Leave egw.js out of bundle
|
if ($path == '/api/js/jsapi/egw.js') continue; // Leave egw.js out of bundle
|
||||||
unset($query);
|
unset($query);
|
||||||
list($path,$query) = explode('?',$path,2);
|
list($path,$query) = explode('?',$path,2)+[null,null];
|
||||||
$mod = filemtime(EGW_SERVER_ROOT.$path);
|
$mod = filemtime(EGW_SERVER_ROOT.$path);
|
||||||
if ($mod > $max_modified) $max_modified = $mod;
|
if ($mod > $max_modified) $max_modified = $mod;
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ class CssIncludes
|
|||||||
{
|
{
|
||||||
foreach(self::resolve_css_includes($path) as $path)
|
foreach(self::resolve_css_includes($path) as $path)
|
||||||
{
|
{
|
||||||
list($file,$query) = explode('?',$path,2);
|
list($file,$query) = explode('?',$path,2)+[null,null];
|
||||||
if (($mod = filemtime(EGW_SERVER_ROOT.$file)) > $max_modified) $max_modified = $mod;
|
if (($mod = filemtime(EGW_SERVER_ROOT.$file)) > $max_modified) $max_modified = $mod;
|
||||||
|
|
||||||
// do NOT include app.css or categories.php, as it changes from app to app
|
// do NOT include app.css or categories.php, as it changes from app to app
|
||||||
|
@ -100,6 +100,7 @@ class Html
|
|||||||
// use preg_replace_callback as we experienced problems with links such as <www.example.tld/pfad/zu/einer/pdf-Datei.pdf>
|
// use preg_replace_callback as we experienced problems with links such as <www.example.tld/pfad/zu/einer/pdf-Datei.pdf>
|
||||||
$result4 = preg_replace_callback( $Expr, function ($match) {
|
$result4 = preg_replace_callback( $Expr, function ($match) {
|
||||||
//error_log(__METHOD__.__LINE__.array2string($match));
|
//error_log(__METHOD__.__LINE__.array2string($match));
|
||||||
|
$match += [null,null,null,null];
|
||||||
if ($match[4]==';' && (strlen($match[3])-4) >=0 && strpos($match[3],'>',strlen($match[3])-4)!==false)
|
if ($match[4]==';' && (strlen($match[3])-4) >=0 && strpos($match[3],'>',strlen($match[3])-4)!==false)
|
||||||
{
|
{
|
||||||
$match[3] = substr($match[3],0,strpos($match[3],'>',strlen($match[3])-4));
|
$match[3] = substr($match[3],0,strpos($match[3],'>',strlen($match[3])-4));
|
||||||
@ -111,7 +112,7 @@ class Html
|
|||||||
$match[4] = ">";
|
$match[4] = ">";
|
||||||
}
|
}
|
||||||
//error_log(__METHOD__.__LINE__.array2string($match));
|
//error_log(__METHOD__.__LINE__.array2string($match));
|
||||||
return $match[1]."<a href=\"http://www".$match[2].$match[3]."\" target=\"_blank\">"."www".$match[2].$match[3]."</a>".$match[4];
|
return $match[1]."<a href=\"https://www".$match[2].$match[3]."\" target=\"_blank\">"."www".$match[2].$match[3]."</a>".$match[4];
|
||||||
}, $result3 );
|
}, $result3 );
|
||||||
}
|
}
|
||||||
return $result4;
|
return $result4;
|
||||||
@ -755,7 +756,7 @@ tinymce.init({
|
|||||||
{
|
{
|
||||||
parse_str($vars,$vars);
|
parse_str($vars,$vars);
|
||||||
}
|
}
|
||||||
list($url,$v) = explode('?', $_url); // url may contain additional vars
|
list($url,$v) = explode('?', $_url)+[null,null]; // url may contain additional vars
|
||||||
if ($v)
|
if ($v)
|
||||||
{
|
{
|
||||||
parse_str($v,$v);
|
parse_str($v,$v);
|
||||||
|
@ -391,7 +391,7 @@ function hl_email_tag_transform($element, $attribute_array=0)
|
|||||||
// $GLOBALS['egw_info']['user']['preferences']['mail']['allowExternalIMGs'] ? '' : 'match' => '/^cid:.*/'),
|
// $GLOBALS['egw_info']['user']['preferences']['mail']['allowExternalIMGs'] ? '' : 'match' => '/^cid:.*/'),
|
||||||
if (isset($attribute_array['src']))
|
if (isset($attribute_array['src']))
|
||||||
{
|
{
|
||||||
if (!(strlen($attribute_array['src'])>4 && strlen($attribute_array['src'])<400))
|
if (!(strlen($attribute_array['src'])>4 && strlen($attribute_array['src'])<800))
|
||||||
{
|
{
|
||||||
$attribute_array['alt']= $attribute_array['alt'].' [blocked (reason: url length):'.$attribute_array['src'].']';
|
$attribute_array['alt']= $attribute_array['alt'].' [blocked (reason: url length):'.$attribute_array['src'].']';
|
||||||
if (!isset($attribute_array['title'])) $attribute_array['title']=$attribute_array['alt'];
|
if (!isset($attribute_array['title'])) $attribute_array['title']=$attribute_array['alt'];
|
||||||
|
@ -471,7 +471,7 @@ class Link extends Link\Storage
|
|||||||
*/
|
*/
|
||||||
static function temp_link_id($app,$id)
|
static function temp_link_id($app,$id)
|
||||||
{
|
{
|
||||||
return $app.':'.(!in_array($app, array(self::VFS_APPNAME,self::VFS_LINK, self::DATA_APPNAME)) ? $id : $id['name']);
|
return $app.':'.(!in_array($app, array(self::VFS_APPNAME,self::VFS_LINK, self::DATA_APPNAME)) || !is_array($id) ? $id : $id['name']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -683,15 +683,15 @@ class Link extends Link\Storage
|
|||||||
{
|
{
|
||||||
echo "<p>Link::unlink('$link_id','$app',".array2string($id).",'$owner','$app2','$id2', $hold_for_purge)</p>\n";
|
echo "<p>Link::unlink('$link_id','$app',".array2string($id).",'$owner','$app2','$id2', $hold_for_purge)</p>\n";
|
||||||
}
|
}
|
||||||
if ($link_id < 0) // vfs-link?
|
if ((int)$link_id < 0) // vfs-link?
|
||||||
{
|
{
|
||||||
return self::delete_attached(-$link_id);
|
return self::delete_attached(-$link_id);
|
||||||
}
|
}
|
||||||
elseif ($app == self::VFS_APPNAME)
|
elseif ($app === self::VFS_APPNAME)
|
||||||
{
|
{
|
||||||
return self::delete_attached($app2,$id2,$id);
|
return self::delete_attached($app2,$id2,$id);
|
||||||
}
|
}
|
||||||
elseif ($app2 == self::VFS_APPNAME)
|
elseif ($app2 === self::VFS_APPNAME)
|
||||||
{
|
{
|
||||||
return self::delete_attached($app,$id,$id2);
|
return self::delete_attached($app,$id,$id2);
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ class Storage
|
|||||||
{
|
{
|
||||||
echo "<p>solink.get_links($app,".print_r($id,true).",$only_app,$order,$deleted)</p>\n";
|
echo "<p>solink.get_links($app,".print_r($id,true).",$only_app,$order,$deleted)</p>\n";
|
||||||
}
|
}
|
||||||
if (($not_only = $only_app[0] == '!'))
|
if (!empty($only_app) && ($not_only = $only_app[0] == '!'))
|
||||||
{
|
{
|
||||||
$only_app = substr($only_app,1);
|
$only_app = substr($only_app,1);
|
||||||
}
|
}
|
||||||
@ -173,7 +173,7 @@ class Storage
|
|||||||
catch(Api\Db\Exception $e) {
|
catch(Api\Db\Exception $e) {
|
||||||
_egw_log_exception($e);
|
_egw_log_exception($e);
|
||||||
}
|
}
|
||||||
return is_array($id) ? $links : ($links[$id] ? $links[$id] : array());
|
return is_array($id) ? $links : ($links[$id] ?? []);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function _add2links($row,$left,$only_app,$not_only,array &$links)
|
private static function _add2links($row,$left,$only_app,$not_only,array &$links)
|
||||||
|
@ -414,14 +414,10 @@ class Mail
|
|||||||
{
|
{
|
||||||
//error_log(__METHOD__." Session restore ".function_backtrace());
|
//error_log(__METHOD__." Session restore ".function_backtrace());
|
||||||
$this->restoreSessionData();
|
$this->restoreSessionData();
|
||||||
$lv_mailbox = $this->sessionData['mailbox'];
|
|
||||||
$firstMessage = $this->sessionData['previewMessage'];
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$this->restoreSessionData();
|
$this->restoreSessionData();
|
||||||
$lv_mailbox = $this->sessionData['mailbox'];
|
|
||||||
$firstMessage = $this->sessionData['previewMessage'];
|
|
||||||
$this->sessionData = array();
|
$this->sessionData = array();
|
||||||
}
|
}
|
||||||
if (!$_reuseCache) $this->forcePrefReload($_profileID,!$_reuseCache);
|
if (!$_reuseCache) $this->forcePrefReload($_profileID,!$_reuseCache);
|
||||||
@ -1000,9 +996,7 @@ class Mail
|
|||||||
*/
|
*/
|
||||||
static function getTimeOut($_use='IMAP')
|
static function getTimeOut($_use='IMAP')
|
||||||
{
|
{
|
||||||
$timeout = $GLOBALS['egw_info']['user']['preferences']['mail']['connectionTimeout'];
|
return $_use=='SIEVE' ? 10 : 20; // this is the default value
|
||||||
if (empty($timeout)) $timeout = ($_use=='SIEVE'?10:20); // this is the default value
|
|
||||||
return $timeout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3211,7 +3205,7 @@ class Mail
|
|||||||
}
|
}
|
||||||
//error_log(__METHOD__.__LINE__.array2string($autoFolderObjects));
|
//error_log(__METHOD__.__LINE__.array2string($autoFolderObjects));
|
||||||
if (!$isGoogleMail) {
|
if (!$isGoogleMail) {
|
||||||
$folders = array_merge($inboxFolderObject,$autoFolderObjects,(array)$inboxSubFolderObjects,(array)$folders,(array)$typeFolderObject['others'] ?? [],(array)$typeFolderObject['shared'] ?? []);
|
$folders = array_merge($inboxFolderObject,$autoFolderObjects,(array)$inboxSubFolderObjects,(array)$folders,(array)($typeFolderObject['others'] ?? []),(array)($typeFolderObject['shared'] ?? []));
|
||||||
} else {
|
} else {
|
||||||
// avoid calling sortByAutoFolder as it is not regarding subfolders
|
// avoid calling sortByAutoFolder as it is not regarding subfolders
|
||||||
$gAutoFolderObjectsTmp = $googleAutoFolderObjects;
|
$gAutoFolderObjectsTmp = $googleAutoFolderObjects;
|
||||||
@ -5589,10 +5583,10 @@ class Mail
|
|||||||
if (empty($_folder)) $_folder = $this->sessionData['mailbox']?: $this->icServer->getCurrentMailbox();
|
if (empty($_folder)) $_folder = $this->sessionData['mailbox']?: $this->icServer->getCurrentMailbox();
|
||||||
$_uid = !(is_object($_uid) || is_array($_uid)) ? (array)$_uid : $_uid;
|
$_uid = !(is_object($_uid) || is_array($_uid)) ? (array)$_uid : $_uid;
|
||||||
|
|
||||||
if (!$_stream && isset($rawBody[$this->icServer->ImapServerId][$_folder][$_uid[0]][(empty($_partID)?'NIL':$_partID)]))
|
if (!$_stream && isset($rawBody[$this->icServer->ImapServerId][(string)$_folder][$_uid[0]][(empty($_partID)?'NIL':$_partID)]))
|
||||||
{
|
{
|
||||||
//error_log(__METHOD__.' ('.__LINE__.') '." Using Cache for raw Body $_uid, $_partID in Folder $_folder");
|
//error_log(__METHOD__.' ('.__LINE__.') '." Using Cache for raw Body $_uid, $_partID in Folder $_folder");
|
||||||
return $rawBody[$this->icServer->ImapServerId][$_folder][$_uid[0]][(empty($_partID)?'NIL':$_partID)];
|
return $rawBody[$this->icServer->ImapServerId][(string)$_folder][$_uid[0]][(empty($_partID)?'NIL':$_partID)];
|
||||||
}
|
}
|
||||||
|
|
||||||
$uidsToFetch = new Horde_Imap_Client_Ids();
|
$uidsToFetch = new Horde_Imap_Client_Ids();
|
||||||
@ -5629,7 +5623,7 @@ class Mail
|
|||||||
if (!$_stream)
|
if (!$_stream)
|
||||||
{
|
{
|
||||||
//error_log(__METHOD__.' ('.__LINE__.') '."[{$this->icServer->ImapServerId}][$_folder][$_uid][".(empty($_partID)?'NIL':$_partID)."]");
|
//error_log(__METHOD__.' ('.__LINE__.') '."[{$this->icServer->ImapServerId}][$_folder][$_uid][".(empty($_partID)?'NIL':$_partID)."]");
|
||||||
$rawBody[$this->icServer->ImapServerId][$_folder][$_uid[0]][(empty($_partID)?'NIL':$_partID)] = $body;
|
$rawBody[$this->icServer->ImapServerId][(string)$_folder][$_uid[0]][(empty($_partID)?'NIL':$_partID)] = $body;
|
||||||
}
|
}
|
||||||
return $body;
|
return $body;
|
||||||
}
|
}
|
||||||
@ -6775,6 +6769,8 @@ class Mail
|
|||||||
//error_log(__METHOD__."()");
|
//error_log(__METHOD__."()");
|
||||||
$imageC = 0;
|
$imageC = 0;
|
||||||
$images = null;
|
$images = null;
|
||||||
|
$attachments = null;
|
||||||
|
|
||||||
if (preg_match_all("/(src|background)=\"(.*)\"/Ui", $_html2parse, $images) && isset($images[2]))
|
if (preg_match_all("/(src|background)=\"(.*)\"/Ui", $_html2parse, $images) && isset($images[2]))
|
||||||
{
|
{
|
||||||
foreach($images[2] as $i => $url)
|
foreach($images[2] as $i => $url)
|
||||||
@ -6782,18 +6778,18 @@ class Mail
|
|||||||
//$isData = false;
|
//$isData = false;
|
||||||
$basedir = $data = '';
|
$basedir = $data = '';
|
||||||
$needTempFile = true;
|
$needTempFile = true;
|
||||||
|
$attachmentData = ['name' => '', 'type' => '', 'file' => '', 'tmp_name' => ''];
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// do not change urls for absolute images (thanks to corvuscorax)
|
// do not change urls for absolute images (thanks to corvuscorax)
|
||||||
if (substr($url, 0, 5) !== 'data:')
|
if (!str_starts_with($url, 'data:'))
|
||||||
{
|
{
|
||||||
$filename = basename($url); // need to resolve all sort of url
|
$attachmentData['name'] = basename($url); // need to resolve all sort of url
|
||||||
if (($directory = dirname($url)) == '.') $directory = '';
|
if (($directory = dirname($url)) == '.') $directory = '';
|
||||||
$ext = pathinfo($filename, PATHINFO_EXTENSION);
|
$ext = pathinfo($attachmentData['name'], PATHINFO_EXTENSION);
|
||||||
$mimeType = MimeMagic::ext2mime($ext);
|
$attachmentData['type'] = MimeMagic::ext2mime($ext);
|
||||||
if ( strlen($directory) > 1 && substr($directory,-1) != '/') { $directory .= '/'; }
|
if ( strlen($directory) > 1 && !str_ends_with($directory, '/')) { $directory .= '/'; }
|
||||||
$myUrl = $directory.$filename;
|
$myUrl = $directory.$attachmentData['name'];
|
||||||
if ($myUrl[0]=='/') // local path -> we only allow path's that are available via http/https (or vfs)
|
if ($myUrl[0]=='/') // local path -> we only allow path's that are available via http/https (or vfs)
|
||||||
{
|
{
|
||||||
$basedir = Framework::getUrl('/');
|
$basedir = Framework::getUrl('/');
|
||||||
@ -6801,7 +6797,7 @@ class Mail
|
|||||||
// use vfs instead of url containing webdav.php
|
// use vfs instead of url containing webdav.php
|
||||||
// ToDo: we should test if the webdav url is of our own scope, as we cannot handle foreign
|
// ToDo: we should test if the webdav url is of our own scope, as we cannot handle foreign
|
||||||
// webdav.php urls as vfs
|
// webdav.php urls as vfs
|
||||||
if (strpos($myUrl,'/webdav.php') !== false) // we have a webdav link, so we build a vfs/sqlfs link of it.
|
if (str_contains($myUrl, '/webdav.php')) // we have a webdav link, so we build a vfs/sqlfs link of it.
|
||||||
{
|
{
|
||||||
Vfs::load_wrapper('vfs');
|
Vfs::load_wrapper('vfs');
|
||||||
list(,$myUrl) = explode('/webdav.php',$myUrl,2);
|
list(,$myUrl) = explode('/webdav.php',$myUrl,2);
|
||||||
@ -6811,7 +6807,7 @@ class Mail
|
|||||||
|
|
||||||
// If it is an inline image url, we need to fetch the actuall attachment
|
// If it is an inline image url, we need to fetch the actuall attachment
|
||||||
// content and later on to be able to store its content as temp file
|
// content and later on to be able to store its content as temp file
|
||||||
if (strpos($myUrl, '/index.php?menuaction=mail.mail_ui.displayImage') !== false && $mail_bo)
|
if ($mail_bo && str_contains($myUrl, '/index.php?menuaction=mail.mail_ui.displayImage'))
|
||||||
{
|
{
|
||||||
$URI_params = array();
|
$URI_params = array();
|
||||||
// Strips the url and store it into a temp for further procss
|
// Strips the url and store it into a temp for further procss
|
||||||
@ -6826,50 +6822,50 @@ class Mail
|
|||||||
if ($attachment)
|
if ($attachment)
|
||||||
{
|
{
|
||||||
$data = $attachment->getContents();
|
$data = $attachment->getContents();
|
||||||
$mimeType = $attachment->getType();
|
$attachmentData['type'] = $attachment->getType();
|
||||||
$filename = $attachment->getDispositionParameter('filename');
|
$attachmentData['name'] = $attachment->getDispositionParameter('filename');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( strlen($basedir) > 1 && substr($basedir,-1) != '/' && $myUrl[0]!='/') { $basedir .= '/'; }
|
if ( $myUrl[0]!='/' && strlen($basedir) > 1 && !str_ends_with($basedir, '/')) { $basedir .= '/'; }
|
||||||
if ($needTempFile && !$attachment && substr($myUrl,0,4) !== "http") $data = file_get_contents($basedir.urldecode($myUrl));
|
if ($needTempFile && !$attachment && !str_starts_with($myUrl, "http")) $data = file_get_contents($basedir.urldecode($myUrl));
|
||||||
}
|
}
|
||||||
if (substr($url,0,strlen('data:'))=='data:')
|
if (str_starts_with($url, 'data:'))
|
||||||
{
|
{
|
||||||
//error_log(__METHOD__.' ('.__LINE__.') '.' -> '.$i.': '.array2string($images[$i]));
|
//error_log(__METHOD__.' ('.__LINE__.') '.' -> '.$i.': '.array2string($images[$i]));
|
||||||
// we only support base64 encoded data
|
// we only support base64 encoded data
|
||||||
$tmp = substr($url,strlen('data:'));
|
$tmp = substr($url,strlen('data:'));
|
||||||
list($mimeType,$data_base64) = explode(';base64,',$tmp);
|
list($attachmentData['type'],$data_base64) = explode(';base64,',$tmp);
|
||||||
$data = base64_decode($data_base64);
|
$data = base64_decode($data_base64);
|
||||||
// FF currently does NOT add any mime-type
|
// FF currently does NOT add any mime-type
|
||||||
if (strtolower(substr($mimeType, 0, 6)) != 'image/')
|
if (strtolower(substr($attachmentData['type'], 0, 6)) != 'image/')
|
||||||
{
|
{
|
||||||
$mimeType = MimeMagic::analyze_data($data);
|
$attachmentData['type'] = MimeMagic::analyze_data($data);
|
||||||
}
|
}
|
||||||
list($what,$exactly) = explode('/',$mimeType);
|
list($what,$exactly) = explode('/',$attachmentData['type']);
|
||||||
$needTempFile = true;
|
$needTempFile = true;
|
||||||
$filename = ($what?$what:'data').$imageC++.'.'.$exactly;
|
$attachmentData['name'] = ($what ?: 'data').$imageC++.'.'.$exactly;
|
||||||
}
|
}
|
||||||
if ($data || $needTempFile === false)
|
if ($data || $needTempFile === false)
|
||||||
{
|
{
|
||||||
if ($needTempFile)
|
if ($needTempFile)
|
||||||
{
|
{
|
||||||
$attachment_file =tempnam($GLOBALS['egw_info']['server']['temp_dir'],$GLOBALS['egw_info']['flags']['currentapp']."_");
|
$attachmentData['file'] =tempnam($GLOBALS['egw_info']['server']['temp_dir'],$GLOBALS['egw_info']['flags']['currentapp']."_");
|
||||||
$tmpfile = fopen($attachment_file,'w');
|
$tmpfile = fopen($attachmentData['file'],'w');
|
||||||
fwrite($tmpfile,$data);
|
fwrite($tmpfile,$data);
|
||||||
fclose($tmpfile);
|
fclose($tmpfile);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$attachment_file = $basedir.urldecode($myUrl);
|
$attachmentData['file'] = $basedir.urldecode($myUrl);
|
||||||
}
|
}
|
||||||
// we use $attachment_file as base for cid instead of filename, as it may be image.png
|
// we use $attachmentData['file'] as base for cid instead of filename, as it may be image.png
|
||||||
// (or similar) in all cases (when cut&paste). This may lead to more attached files, in case
|
// (or similar) in all cases (when cut&paste). This may lead to more attached files, in case
|
||||||
// we use the same image multiple times, but, if we do this, we should try to detect that
|
// we use the same image multiple times, but, if we do this, we should try to detect that
|
||||||
// on upload. filename itself is not sufficient to determine the sameness of images
|
// on upload. filename itself is not sufficient to determine the sameness of images
|
||||||
$cid = 'cid:' . md5($attachment_file);
|
$cid = 'cid:' . md5($attachmentData['file']);
|
||||||
if ($_mailObject->AddEmbeddedImage($attachment_file, substr($cid, 4), urldecode($filename), $mimeType) !== null)
|
if ($_mailObject->AddEmbeddedImage($attachmentData['file'], substr($cid, 4), urldecode($attachmentData['file']), $attachmentData['type']) !== null)
|
||||||
{
|
{
|
||||||
//$_html2parse = preg_replace("/".$images[1][$i]."=\"".preg_quote($url, '/')."\"/Ui", $images[1][$i]."=\"".$cid."\"", $_html2parse);
|
//$_html2parse = preg_replace("/".$images[1][$i]."=\"".preg_quote($url, '/')."\"/Ui", $images[1][$i]."=\"".$cid."\"", $_html2parse);
|
||||||
$_html2parse = str_replace($images[0][$i], $images[1][$i].'="'.$cid.'"', $_html2parse);
|
$_html2parse = str_replace($images[0][$i], $images[1][$i].'="'.$cid.'"', $_html2parse);
|
||||||
@ -6882,12 +6878,8 @@ class Mail
|
|||||||
error_log("Error adding inline attachment. " . $e->getMessage());
|
error_log("Error adding inline attachment. " . $e->getMessage());
|
||||||
error_log($e->getTraceAsString());
|
error_log($e->getTraceAsString());
|
||||||
}
|
}
|
||||||
$attachments [] = array(
|
$attachmentData['tmp_name'] = $attachmentData['file'];
|
||||||
'name' => $filename,
|
$attachments [] = $attachmentData;
|
||||||
'type' => $mimeType,
|
|
||||||
'file' => $attachment_file,
|
|
||||||
'tmp_name' => $attachment_file
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return is_array($attachments) ? $attachments : null;
|
return is_array($attachments) ? $attachments : null;
|
||||||
}
|
}
|
||||||
|
@ -549,7 +549,7 @@ class Account implements \ArrayAccess
|
|||||||
$row = array_merge($row, Credentials::from_session($row));
|
$row = array_merge($row, Credentials::from_session($row));
|
||||||
}
|
}
|
||||||
// fill an empty ident_realname or ident_email of current user with data from user account
|
// fill an empty ident_realname or ident_email of current user with data from user account
|
||||||
if ($replace_placeholders && (!isset($user) || $user == $GLOBALS['egw_info']['user']['acount_id']))
|
if ($replace_placeholders && (!isset($user) || $user == $GLOBALS['egw_info']['user']['account_id']))
|
||||||
{
|
{
|
||||||
if (empty($row['ident_realname'])) $row['ident_realname'] = $GLOBALS['egw_info']['user']['account_fullname'];
|
if (empty($row['ident_realname'])) $row['ident_realname'] = $GLOBALS['egw_info']['user']['account_fullname'];
|
||||||
if (empty($row['ident_email'])) $row['ident_email'] = $GLOBALS['egw_info']['user']['account_email'];
|
if (empty($row['ident_email'])) $row['ident_email'] = $GLOBALS['egw_info']['user']['account_email'];
|
||||||
@ -737,13 +737,13 @@ class Account implements \ArrayAccess
|
|||||||
|
|
||||||
if (empty($data['ident_email']) && $is_current_user)
|
if (empty($data['ident_email']) && $is_current_user)
|
||||||
{
|
{
|
||||||
$data['ident_email'] = $GLOBALS['egw_info']['user']['account_email'];
|
$data['ident_email'] = $GLOBALS['egw_info']['user']['account_email'] ?? null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (empty($data['ident_realname']))
|
if (empty($data['ident_realname']))
|
||||||
{
|
{
|
||||||
$data['ident_realname'] = $account->ident_realname || !$is_current_user ?
|
$data['ident_realname'] = $account->ident_realname || !$is_current_user ?
|
||||||
$account->ident_realname : $GLOBALS['egw_info']['user']['account_fullname'];
|
$account->ident_realname : ($GLOBALS['egw_info']['user']['account_fullname'] ?? null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1414,7 +1414,7 @@ class Account implements \ArrayAccess
|
|||||||
{
|
{
|
||||||
// for current user prefer account with ident_email matching user email or domain
|
// for current user prefer account with ident_email matching user email or domain
|
||||||
// (this also helps notifications to account allowing to send with from address of current user / account_email)
|
// (this also helps notifications to account allowing to send with from address of current user / account_email)
|
||||||
if ($only_current_user && $GLOBALS['egw_info']['user']['account_email'])
|
if ($only_current_user && !empty($GLOBALS['egw_info']['user']['account_email']))
|
||||||
{
|
{
|
||||||
list(,$domain) = explode('@', $account_email = $GLOBALS['egw_info']['user']['account_email']);
|
list(,$domain) = explode('@', $account_email = $GLOBALS['egw_info']['user']['account_email']);
|
||||||
// empty ident_email will be replaced with account_email!
|
// empty ident_email will be replaced with account_email!
|
||||||
|
@ -265,10 +265,10 @@ class Credentials
|
|||||||
throw new Api\Exception\WrongParameter("Unknown data[acc_imap_logintype]=".array2string($data['acc_imap_logintype']).'!');
|
throw new Api\Exception\WrongParameter("Unknown data[acc_imap_logintype]=".array2string($data['acc_imap_logintype']).'!');
|
||||||
}
|
}
|
||||||
$password = base64_decode(Api\Cache::getSession('phpgwapi', 'password'));
|
$password = base64_decode(Api\Cache::getSession('phpgwapi', 'password'));
|
||||||
$realname = !$set_identity || $data['ident_realname'] ? $data['ident_realname'] :
|
$realname = !$set_identity || !empty($data['ident_realname']) ? $data['ident_realname'] :
|
||||||
$GLOBALS['egw_info']['user']['account_fullname'];
|
($GLOBALS['egw_info']['user']['account_fullname'] ?? null);
|
||||||
$email = !$set_identity || $data['ident_email'] ? $data['ident_email'] :
|
$email = !$set_identity || !empty($data['ident_email']) ? $data['ident_email'] :
|
||||||
$GLOBALS['egw_info']['user']['account_email'];
|
($GLOBALS['egw_info']['user']['account_email'] ?? null);
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'ident_realname' => $realname,
|
'ident_realname' => $realname,
|
||||||
|
@ -169,7 +169,7 @@ class Html
|
|||||||
if ($addbracesforendtag === true )
|
if ($addbracesforendtag === true )
|
||||||
{
|
{
|
||||||
if (stripos($_body,'<'.$tag)!==false) $ct = preg_match_all('#<'.$tag.'(?:\s.*)?>(.+)</'.$endtag.'>#isU', $_body, $found);
|
if (stripos($_body,'<'.$tag)!==false) $ct = preg_match_all('#<'.$tag.'(?:\s.*)?>(.+)</'.$endtag.'>#isU', $_body, $found);
|
||||||
if ($ct>0)
|
if (isset($ct) && $ct>0)
|
||||||
{
|
{
|
||||||
//error_log(__METHOD__.__LINE__.array2string($found[0]));
|
//error_log(__METHOD__.__LINE__.array2string($found[0]));
|
||||||
// only replace what we have found
|
// only replace what we have found
|
||||||
@ -495,7 +495,7 @@ class Html
|
|||||||
$html = preg_replace('/&(?!#?[a-zA-Z0-9]+;)/', '&', $html);
|
$html = preg_replace('/&(?!#?[a-zA-Z0-9]+;)/', '&', $html);
|
||||||
|
|
||||||
$dom = new \DOMDocument('1.0','UTF-8');
|
$dom = new \DOMDocument('1.0','UTF-8');
|
||||||
if(!$dom->loadHTML(
|
if (!@$dom->loadHTML(
|
||||||
'<?xml encoding="UTF-8">'. Api\Translation::convert($html,preg_match('/<meta[^>]+content="[^>"]+charset=([^;"]+)/i', $html, $matches) ? $matches[1] : false, 'utf8'),
|
'<?xml encoding="UTF-8">'. Api\Translation::convert($html,preg_match('/<meta[^>]+content="[^>"]+charset=([^;"]+)/i', $html, $matches) ? $matches[1] : false, 'utf8'),
|
||||||
LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_NOBLANKS
|
LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_NOBLANKS
|
||||||
))
|
))
|
||||||
|
@ -360,9 +360,7 @@ class Imap extends Horde_Imap_Client_Socket implements Imap\PushIface
|
|||||||
*/
|
*/
|
||||||
static function getTimeOut($_use='IMAP')
|
static function getTimeOut($_use='IMAP')
|
||||||
{
|
{
|
||||||
$timeout = $GLOBALS['egw_info']['user']['preferences']['mail']['connectionTimeout'];
|
return $_use == 'SIEVE' ? 10 : 20; // this is the default value
|
||||||
if (empty($timeout) || !($timeout > 0)) $timeout = $_use == 'SIEVE' ? 10 : 20; // this is the default value
|
|
||||||
return $timeout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -742,7 +740,7 @@ class Imap extends Horde_Imap_Client_Socket implements Imap\PushIface
|
|||||||
* @param string $returnAttributes true means return an assoc array containing mailbox names and mailbox attributes
|
* @param string $returnAttributes true means return an assoc array containing mailbox names and mailbox attributes
|
||||||
* false - the default - means return an array of mailboxes with only selected attributes like delimiter
|
* false - the default - means return an array of mailboxes with only selected attributes like delimiter
|
||||||
*
|
*
|
||||||
* @return mixed array of mailboxes
|
* @return ?array array of mailboxes or null
|
||||||
*/
|
*/
|
||||||
function listSubscribedMailboxes($reference = '' , $restriction_search = 0, $returnAttributes = false)
|
function listSubscribedMailboxes($reference = '' , $restriction_search = 0, $returnAttributes = false)
|
||||||
{
|
{
|
||||||
@ -794,10 +792,10 @@ class Imap extends Horde_Imap_Client_Socket implements Imap\PushIface
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$ret[$k]=array('MAILBOX'=>$k,'ATTRIBUTES'=>$box['attributes'],'delimiter'=>($box['delimiter']?$box['delimiter']:$this->getDelimiter('personal')),'SUBSCRIBED'=>true);
|
$ret[$k]=array('MAILBOX'=>$k,'ATTRIBUTES'=>$box['attributes'],'delimiter'=>($box['delimiter']?:$this->getDelimiter('personal')),'SUBSCRIBED'=>true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $ret;
|
return $ret ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1376,6 +1374,7 @@ class Imap extends Horde_Imap_Client_Socket implements Imap\PushIface
|
|||||||
case 'retrieveRules':
|
case 'retrieveRules':
|
||||||
case 'getVacation':
|
case 'getVacation':
|
||||||
case 'setVacation':
|
case 'setVacation':
|
||||||
|
case 'getExtensions':
|
||||||
if (is_null($this->sieve))
|
if (is_null($this->sieve))
|
||||||
{
|
{
|
||||||
$this->sieve = new Sieve($this);
|
$this->sieve = new Sieve($this);
|
||||||
|
@ -73,7 +73,7 @@ class Notifications
|
|||||||
$account_specific = 0;
|
$account_specific = 0;
|
||||||
foreach($rows as $row)
|
foreach($rows as $row)
|
||||||
{
|
{
|
||||||
if ($row['account_id'])
|
if (!empty($row['account_id']))
|
||||||
{
|
{
|
||||||
$account_specific = $row['account_id'];
|
$account_specific = $row['account_id'];
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ class Notifications
|
|||||||
{
|
{
|
||||||
self::$cache[$acc_id][$row['account_id']][] = $row['notif_folder'];
|
self::$cache[$acc_id][$row['account_id']][] = $row['notif_folder'];
|
||||||
} // make sure set the account_specific correctly when notify_folder gets removed
|
} // make sure set the account_specific correctly when notify_folder gets removed
|
||||||
elseif (!$row['account_id'] && !is_array($account_id) && is_array($rows[$account_id]))
|
elseif (empty($row['account_id']) && !is_array($account_id) && is_array($rows[$account_id]))
|
||||||
{
|
{
|
||||||
$account_specific = $account_id;
|
$account_specific = $account_id;
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ class Script
|
|||||||
var $emailNotification; /* email notification settings. */
|
var $emailNotification; /* email notification settings. */
|
||||||
var $pcount; /* highest priority value in ruleset. */
|
var $pcount; /* highest priority value in ruleset. */
|
||||||
var $errstr; /* error text. */
|
var $errstr; /* error text. */
|
||||||
|
var $extensions; /* contains extensions status*/
|
||||||
/**
|
/**
|
||||||
* Body transform content types
|
* Body transform content types
|
||||||
*
|
*
|
||||||
@ -69,6 +70,21 @@ class Script
|
|||||||
$this->emailNotification = array(); // Added email notifications
|
$this->emailNotification = array(); // Added email notifications
|
||||||
$this->pcount = 0;
|
$this->pcount = 0;
|
||||||
$this->errstr = '';
|
$this->errstr = '';
|
||||||
|
$this->extensions = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function _setExtensionsStatus(Sieve $connection)
|
||||||
|
{
|
||||||
|
$this->extensions = [
|
||||||
|
'vacation' => $connection->hasExtension('vacation'),
|
||||||
|
'regex' => $connection->hasExtension('regex'),
|
||||||
|
'enotify' => $connection->hasExtension('enotify'),
|
||||||
|
'body' => $connection->hasExtension('body'),
|
||||||
|
'variables' => $connection->hasExtension('variables'),
|
||||||
|
'date' => $connection->hasExtension('date'),
|
||||||
|
'imap4flags' => $connection->hasExtension('imap4flags'),
|
||||||
|
'relational' => $connection->hasExtension('relational'),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// get sieve script rules for this user
|
// get sieve script rules for this user
|
||||||
@ -86,6 +102,7 @@ class Script
|
|||||||
$anyofbit = 4;
|
$anyofbit = 4;
|
||||||
$keepbit = 8;
|
$keepbit = 8;
|
||||||
$regexbit = 128;
|
$regexbit = 128;
|
||||||
|
$this->_setExtensionsStatus($connection);
|
||||||
|
|
||||||
if (!isset($this->name)){
|
if (!isset($this->name)){
|
||||||
$this->errstr = 'retrieveRules: no script name specified';
|
$this->errstr = 'retrieveRules: no script name specified';
|
||||||
@ -150,10 +167,10 @@ class Script
|
|||||||
$rule['anyof'] = ($bits[8] & $anyofbit);
|
$rule['anyof'] = ($bits[8] & $anyofbit);
|
||||||
$rule['keep'] = ($bits[8] & $keepbit);
|
$rule['keep'] = ($bits[8] & $keepbit);
|
||||||
$rule['regexp'] = ($bits[8] & $regexbit);
|
$rule['regexp'] = ($bits[8] & $regexbit);
|
||||||
$rule['bodytransform'] = ($bits[12]);
|
$rule['bodytransform'] = ($bits[12]??null);
|
||||||
$rule['field_bodytransform'] = ($bits[13]);
|
$rule['field_bodytransform'] = ($bits[13]??null);
|
||||||
$rule['ctype'] = ($bits[14]);
|
$rule['ctype'] = ($bits[14]??null);
|
||||||
$rule['field_ctype_val'] = ($bits[15]);
|
$rule['field_ctype_val'] = ($bits[15]??null);
|
||||||
$rule['unconditional'] = 0;
|
$rule['unconditional'] = 0;
|
||||||
if (!$rule['from'] && !$rule['to'] && !$rule['subject'] &&
|
if (!$rule['from'] && !$rule['to'] && !$rule['subject'] &&
|
||||||
!$rule['field'] && !$rule['size'] && $rule['action']) {
|
!$rule['field'] && !$rule['size'] && $rule['action']) {
|
||||||
@ -188,7 +205,7 @@ class Script
|
|||||||
}
|
}
|
||||||
$vacation['addresses'] = &$vaddresses;
|
$vacation['addresses'] = &$vaddresses;
|
||||||
|
|
||||||
$vacation['forwards'] = $bits[5];
|
$vacation['forwards'] = $bits[5]??null;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "notify":
|
case "notify":
|
||||||
@ -236,7 +253,6 @@ class Script
|
|||||||
|
|
||||||
$activerules = 0;
|
$activerules = 0;
|
||||||
$regexused = 0;
|
$regexused = 0;
|
||||||
$regexsupported = true;
|
|
||||||
$rejectused = 0;
|
$rejectused = 0;
|
||||||
$vacation_active = false;
|
$vacation_active = false;
|
||||||
|
|
||||||
@ -245,13 +261,10 @@ class Script
|
|||||||
|
|
||||||
//include "$default->lib_dir/version.php";
|
//include "$default->lib_dir/version.php";
|
||||||
|
|
||||||
// lets generate the main body of the script from our rules
|
// set extensions status
|
||||||
$enotify = $variables= $supportsbody = false;
|
$this->_setExtensionsStatus($connection);
|
||||||
if ($connection->hasExtension('enotify')) $enotify = true;
|
|
||||||
if ($connection->hasExtension('variables')) $variables = true;
|
if (!$this->extensions['vacation']) $this->vacation = false;
|
||||||
if ($connection->hasExtension('body')) $supportsbody = true;
|
|
||||||
if (!$connection->hasExtension('vacation')) $this->vacation = false;
|
|
||||||
if (!$connection->hasExtension('regex')) $regexsupported = false;
|
|
||||||
|
|
||||||
$newscriptbody = "";
|
$newscriptbody = "";
|
||||||
$continue = 1;
|
$continue = 1;
|
||||||
@ -334,7 +347,7 @@ class Script
|
|||||||
$newruletext .= "size " . $xthan . $rule['size'] . "K";
|
$newruletext .= "size " . $xthan . $rule['size'] . "K";
|
||||||
$started = 1;
|
$started = 1;
|
||||||
}
|
}
|
||||||
if ($supportsbody){
|
if ($this->extensions['body']){
|
||||||
if (!empty($rule['field_bodytransform'])){
|
if (!empty($rule['field_bodytransform'])){
|
||||||
if ($started) $newruletext .= ", ";
|
if ($started) $newruletext .= ", ";
|
||||||
$btransform = " :raw ";
|
$btransform = " :raw ";
|
||||||
@ -379,6 +392,9 @@ class Script
|
|||||||
if (preg_match("/discard/i",$rule['action'])) {
|
if (preg_match("/discard/i",$rule['action'])) {
|
||||||
$newruletext .= "discard;";
|
$newruletext .= "discard;";
|
||||||
}
|
}
|
||||||
|
if (preg_match("/flags/i",$rule['action'])) {
|
||||||
|
$newruletext .= "addflag \"".$rule['action_arg']."\";";
|
||||||
|
}
|
||||||
if ($rule['keep']) $newruletext .= "\n\tkeep;";
|
if ($rule['keep']) $newruletext .= "\n\tkeep;";
|
||||||
if (!$rule['unconditional']) $newruletext .= "\n}";
|
if (!$rule['unconditional']) $newruletext .= "\n}";
|
||||||
|
|
||||||
@ -417,7 +433,7 @@ class Script
|
|||||||
$vacation_active = true;
|
$vacation_active = true;
|
||||||
if ($vacation['text'])
|
if ($vacation['text'])
|
||||||
{
|
{
|
||||||
if ($regexsupported)
|
if ($this->extensions['regex'])
|
||||||
{
|
{
|
||||||
$newscriptbody .= "if header :regex ".'"X-Spam-Status" '.'"\\\\bYES\\\\b"'."{\n\tstop;\n}\n"; //stop vacation reply if it is spam
|
$newscriptbody .= "if header :regex ".'"X-Spam-Status" '.'"\\\\bYES\\\\b"'."{\n\tstop;\n}\n"; //stop vacation reply if it is spam
|
||||||
$regexused = 1;
|
$regexused = 1;
|
||||||
@ -441,17 +457,17 @@ class Script
|
|||||||
}
|
}
|
||||||
$newscriptbody .= "\tkeep;\n}\n";
|
$newscriptbody .= "\tkeep;\n}\n";
|
||||||
}
|
}
|
||||||
$newscriptbody .= "vacation :days " . $vacation['days'];
|
$vac_rule = "vacation :days " . $vacation['days'];
|
||||||
$first = 1;
|
$first = 1;
|
||||||
if (!empty($vacation['addresses'][0]))
|
if (!empty($vacation['addresses'][0]))
|
||||||
{
|
{
|
||||||
$newscriptbody .= " :addresses [";
|
$vac_rule .= " :addresses [";
|
||||||
foreach ($vacation['addresses'] as $vaddress) {
|
foreach ($vacation['addresses'] as $vaddress) {
|
||||||
if (!$first) $newscriptbody .= ", ";
|
if (!$first) $vac_rule .= ", ";
|
||||||
$newscriptbody .= "\"" . trim($vaddress) . "\"";
|
$vac_rule .= "\"" . trim($vaddress) . "\"";
|
||||||
$first = 0;
|
$first = 0;
|
||||||
}
|
}
|
||||||
$newscriptbody .= "] ";
|
$vac_rule .= "] ";
|
||||||
}
|
}
|
||||||
$message = $vacation['text'];
|
$message = $vacation['text'];
|
||||||
if ($vacation['start_date'] || $vacation['end_date'])
|
if ($vacation['start_date'] || $vacation['end_date'])
|
||||||
@ -463,7 +479,20 @@ class Script
|
|||||||
date($format_date,$vacation['end_date']),
|
date($format_date,$vacation['end_date']),
|
||||||
),$message);
|
),$message);
|
||||||
}
|
}
|
||||||
$newscriptbody .= " text:\n" . $message . "\n.\n;\n\n";
|
$vac_rule .= " text:\n" . $message . "\n.\n;\n\n";
|
||||||
|
if ($this->extensions['date'] && $vacation['start_date'] && $vacation['end_date'])
|
||||||
|
{
|
||||||
|
$newscriptbody .= "if allof (\n".
|
||||||
|
"currentdate :value \"ge\" \"date\" \"". date('Y-m-d', $vacation['start_date']) ."\",\n".
|
||||||
|
"currentdate :value \"le\" \"date\" \"". date('Y-m-d', $vacation['end_date']) ."\")\n".
|
||||||
|
"{\n".
|
||||||
|
$vac_rule."\n".
|
||||||
|
"}\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$newscriptbody .= $vac_rule;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update with any changes.
|
// update with any changes.
|
||||||
@ -476,10 +505,10 @@ class Script
|
|||||||
|
|
||||||
// format notification body
|
// format notification body
|
||||||
$egw_site_title = $GLOBALS['egw_info']['server']['site_title'];
|
$egw_site_title = $GLOBALS['egw_info']['server']['site_title'];
|
||||||
if ($enotify==true)
|
if ($this->extensions['enotify']==true)
|
||||||
{
|
{
|
||||||
$notification_body = lang("You have received a new message on the")." {$egw_site_title}";
|
$notification_body = lang("You have received a new message on the")." {$egw_site_title}";
|
||||||
if ($variables)
|
if ($this->extensions['variables'])
|
||||||
{
|
{
|
||||||
$notification_body .= ", ";
|
$notification_body .= ", ";
|
||||||
$notification_body .= 'From: ${from}';
|
$notification_body .= 'From: ${from}';
|
||||||
@ -522,13 +551,18 @@ class Script
|
|||||||
|
|
||||||
if ($activerules) {
|
if ($activerules) {
|
||||||
$newscripthead .= "require [\"fileinto\"";
|
$newscripthead .= "require [\"fileinto\"";
|
||||||
if ($regexsupported && $regexused) $newscripthead .= ",\"regex\"";
|
if ($this->extensions['regex'] && $regexused) $newscripthead .= ",\"regex\"";
|
||||||
if ($rejectused) $newscripthead .= ",\"reject\"";
|
if ($rejectused) $newscripthead .= ",\"reject\"";
|
||||||
if ($this->vacation && $vacation_active) {
|
if ($this->vacation && $vacation_active) {
|
||||||
$newscripthead .= ",\"vacation\"";
|
$newscripthead .= ",\"vacation\"";
|
||||||
}
|
}
|
||||||
if ($supportsbody) $newscripthead .= ",\"body\"";
|
if ($this->extensions['body']) $newscripthead .= ",\"body\"";
|
||||||
if ($this->emailNotification && $this->emailNotification['status'] == 'on') $newscripthead .= ',"'.($enotify?'e':'').'notify"'.($variables?',"variables"':''); // Added email notifications
|
if ($this->extensions['date']) $newscripthead .= ",\"date\"";
|
||||||
|
if ($this->extensions['relational']) $newscripthead .= ",\"relational\"";
|
||||||
|
if ($this->extensions['variables']) $newscripthead .= ",\"variables\"";
|
||||||
|
if ($this->extensions['imap4flags']) $newscripthead .= ",\"imap4flags\"";
|
||||||
|
|
||||||
|
if ($this->emailNotification && $this->emailNotification['status'] == 'on') $newscripthead .= ',"'.($this->extensions['enotify']?'e':'').'notify"'.($this->extensions['variables']?',"variables"':''); // Added email notifications
|
||||||
$newscripthead .= "];\n\n";
|
$newscripthead .= "];\n\n";
|
||||||
} else {
|
} else {
|
||||||
// no active rules, but might still have an active vacation rule
|
// no active rules, but might still have an active vacation rule
|
||||||
@ -536,18 +570,21 @@ class Script
|
|||||||
if ($this->vacation && $vacation_active)
|
if ($this->vacation && $vacation_active)
|
||||||
{
|
{
|
||||||
$newscripthead .= "require [\"vacation\"";
|
$newscripthead .= "require [\"vacation\"";
|
||||||
if ($regexsupported && $regexused) $newscripthead .= ",\"regex\"";
|
if ($this->extensions['regex'] && $regexused) $newscripthead .= ",\"regex\"";
|
||||||
|
if ($this->extensions['date']) $newscripthead .= ",\"date\"";
|
||||||
|
if ($this->extensions['relational']) $newscripthead .= ",\"relational\"";
|
||||||
|
|
||||||
$closeRequired=true;
|
$closeRequired=true;
|
||||||
}
|
}
|
||||||
if ($this->emailNotification && $this->emailNotification['status'] == 'on')
|
if ($this->emailNotification && $this->emailNotification['status'] == 'on')
|
||||||
{
|
{
|
||||||
if ($this->vacation && $vacation_active)
|
if ($this->vacation && $vacation_active)
|
||||||
{
|
{
|
||||||
$newscripthead .= ",\"".($enotify?'e':'')."notify\"".($variables?',"variables"':'')."];\n\n"; // Added email notifications
|
$newscripthead .= ",\"".($this->extensions['enotify']?'e':'')."notify\"".($this->extensions['variables']?',"variables"':'')."];\n\n"; // Added email notifications
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$newscripthead .= "require [\"".($enotify?'e':'')."notify\"".($variables?',"variables"':'')."];\n\n"; // Added email notifications
|
$newscripthead .= "require [\"".($this->extensions['enotify']?'e':'')."notify\"".($this->extensions['variables']?',"variables"':'')."];\n\n"; // Added email notifications
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($closeRequired) $newscripthead .= "];\n\n";
|
if ($closeRequired) $newscripthead .= "];\n\n";
|
||||||
@ -570,7 +607,7 @@ class Script
|
|||||||
$newscriptfoot .= "#rule&&" . $rule['priority'] . "&&" . $rule['status'] . "&&" .
|
$newscriptfoot .= "#rule&&" . $rule['priority'] . "&&" . $rule['status'] . "&&" .
|
||||||
addslashes($rule['from']) . "&&" . addslashes($rule['to']) . "&&" . addslashes($rule['subject']) . "&&" . $rule['action'] . "&&" .
|
addslashes($rule['from']) . "&&" . addslashes($rule['to']) . "&&" . addslashes($rule['subject']) . "&&" . $rule['action'] . "&&" .
|
||||||
$rule['action_arg'] . "&&" . $rule['flg'] . "&&" . addslashes($rule['field']) . "&&" . addslashes($rule['field_val']) . "&&" . $rule['size'];
|
$rule['action_arg'] . "&&" . $rule['flg'] . "&&" . addslashes($rule['field']) . "&&" . addslashes($rule['field_val']) . "&&" . $rule['size'];
|
||||||
if ($supportsbody && (!empty($rule['field_bodytransform']) || ($rule['ctype']!= '0' && !empty($rule['ctype'])))) $newscriptfoot .= "&&" . $rule['bodytransform'] . "&&" . $rule['field_bodytransform']. "&&" . $rule['ctype'] . "&&" . $rule['field_ctype_val'];
|
if ($this->extensions['body'] && (!empty($rule['field_bodytransform']) || ($rule['ctype']!= '0' && !empty($rule['ctype'])))) $newscriptfoot .= "&&" . $rule['bodytransform'] . "&&" . $rule['field_bodytransform']. "&&" . $rule['ctype'] . "&&" . $rule['field_ctype_val'];
|
||||||
$newscriptfoot .= "\n";
|
$newscriptfoot .= "\n";
|
||||||
$pcount = $pcount+2;
|
$pcount = $pcount+2;
|
||||||
//error_log(__CLASS__."::".__METHOD__.__LINE__.array2string($newscriptfoot));
|
//error_log(__CLASS__."::".__METHOD__.__LINE__.array2string($newscriptfoot));
|
||||||
@ -616,7 +653,7 @@ class Script
|
|||||||
}
|
}
|
||||||
catch (\Exception $e) {
|
catch (\Exception $e) {
|
||||||
$this->errstr = 'updateScript: putscript failed: ' . $e->getMessage().($e->details?': '.$e->details:'');
|
$this->errstr = 'updateScript: putscript failed: ' . $e->getMessage().($e->details?': '.$e->details:'');
|
||||||
if ($regexused&&!$regexsupported) $this->errstr .= " REGEX is not an supported CAPABILITY";
|
if ($regexused && !$this->extensions['regex']) $this->errstr .= " REGEX is not an supported CAPABILITY";
|
||||||
error_log(__METHOD__.__LINE__.' # Error: ->'.$this->errstr);
|
error_log(__METHOD__.__LINE__.' # Error: ->'.$this->errstr);
|
||||||
error_log(__METHOD__.__LINE__.' # ScriptName:'.$this->name.' Script:'.$newscript);
|
error_log(__METHOD__.__LINE__.' # ScriptName:'.$this->name.' Script:'.$newscript);
|
||||||
error_log(__METHOD__.__LINE__.' # Instance='.$GLOBALS['egw_info']['user']['domain'].', User='.$GLOBALS['egw_info']['user']['account_lid']);
|
error_log(__METHOD__.__LINE__.' # Instance='.$GLOBALS['egw_info']['user']['domain'].', User='.$GLOBALS['egw_info']['user']['account_lid']);
|
||||||
|
@ -94,7 +94,7 @@ class Sql extends Mail\Smtp
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($this->debug) error_log(__METHOD__."('$_accountName') returning ".array2string($emailAddresses));
|
if (!empty($this->debug)) error_log(__METHOD__."('$_accountName') returning ".array2string($emailAddresses));
|
||||||
|
|
||||||
return $emailAddresses;
|
return $emailAddresses;
|
||||||
}
|
}
|
||||||
@ -191,7 +191,7 @@ class Sql extends Mail\Smtp
|
|||||||
case self::TYPE_MAILBOX:
|
case self::TYPE_MAILBOX:
|
||||||
$userData['mailMessageStore'] = $row['mail_value'];
|
$userData['mailMessageStore'] = $row['mail_value'];
|
||||||
//error_log(__METHOD__."('$user') row=".array2string($row).', enabled[$row[account_id]]='.array2string($enabled[$row['account_id']]).', forwardOnly[$row[account_id]]='.array2string($forwardOnly[$row['account_id']]));
|
//error_log(__METHOD__."('$user') row=".array2string($row).', enabled[$row[account_id]]='.array2string($enabled[$row['account_id']]).', forwardOnly[$row[account_id]]='.array2string($forwardOnly[$row['account_id']]));
|
||||||
if ($row['account_id'] > 0 && $enabled[$row['account_id']] && !$forwardOnly[$row['account_id']])
|
if ($row['account_id'] > 0 && !empty($enabled[$row['account_id']]) && empty($forwardOnly[$row['account_id']]))
|
||||||
{
|
{
|
||||||
$userData['uid'][] = $this->accounts->id2name($row['account_id'], 'account_lid');
|
$userData['uid'][] = $this->accounts->id2name($row['account_id'], 'account_lid');
|
||||||
$userData['mailbox'][] = $row['mail_value'];
|
$userData['mailbox'][] = $row['mail_value'];
|
||||||
@ -218,7 +218,7 @@ class Sql extends Mail\Smtp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($this->debug) error_log(__METHOD__."('$user') returning ".array2string($userData));
|
if (!empty($this->debug)) error_log(__METHOD__."('$user') returning ".array2string($userData));
|
||||||
|
|
||||||
return $userData;
|
return $userData;
|
||||||
}
|
}
|
||||||
@ -240,7 +240,7 @@ class Sql extends Mail\Smtp
|
|||||||
function setUserData($_uidnumber, array $_mailAlternateAddress, array $_mailForwardingAddress, $_deliveryMode,
|
function setUserData($_uidnumber, array $_mailAlternateAddress, array $_mailForwardingAddress, $_deliveryMode,
|
||||||
$_accountStatus, $_mailLocalAddress, $_quota, $_forwarding_only=false, $_setMailbox=null)
|
$_accountStatus, $_mailLocalAddress, $_quota, $_forwarding_only=false, $_setMailbox=null)
|
||||||
{
|
{
|
||||||
if ($this->debug) error_log(__METHOD__."($_uidnumber, ".array2string($_mailAlternateAddress).', '.array2string($_mailForwardingAddress).", '$_deliveryMode', '$_accountStatus', '$_mailLocalAddress', $_quota, forwarding_only=".array2string($_forwarding_only).') '.function_backtrace());
|
if (!empty($this->debug)) error_log(__METHOD__."($_uidnumber, ".array2string($_mailAlternateAddress).', '.array2string($_mailForwardingAddress).", '$_deliveryMode', '$_accountStatus', '$_mailLocalAddress', $_quota, forwarding_only=".array2string($_forwarding_only).') '.function_backtrace());
|
||||||
|
|
||||||
if (!$_forwarding_only && $this->accounts->id2name($_uidnumber, 'account_email') !== $_mailLocalAddress)
|
if (!$_forwarding_only && $this->accounts->id2name($_uidnumber, 'account_email') !== $_mailLocalAddress)
|
||||||
{
|
{
|
||||||
|
@ -564,7 +564,7 @@ class Mailer extends Horde_Mime_Mail
|
|||||||
if (!isset($flowed)) $flowed = $this->_body && !in_array($this->_body->getType(), array('multipart/encrypted', 'multipart/signed'));
|
if (!isset($flowed)) $flowed = $this->_body && !in_array($this->_body->getType(), array('multipart/encrypted', 'multipart/signed'));
|
||||||
|
|
||||||
// check if flowed is disabled in mail site configuration
|
// check if flowed is disabled in mail site configuration
|
||||||
if (($config = Config::read('mail')) && $config['disable_rfc3676_flowed'])
|
if (($config = Config::read('mail')) && !empty($config['disable_rfc3676_flowed']))
|
||||||
{
|
{
|
||||||
$flowed = false;
|
$flowed = false;
|
||||||
}
|
}
|
||||||
@ -616,7 +616,7 @@ class Mailer extends Horde_Mime_Mail
|
|||||||
}
|
}
|
||||||
|
|
||||||
// log mails to file specified in $GLOBALS['egw_info']['server']['log_mail'] or error_log for true
|
// log mails to file specified in $GLOBALS['egw_info']['server']['log_mail'] or error_log for true
|
||||||
if ($GLOBALS['egw_info']['server']['log_mail'])
|
if (!empty($GLOBALS['egw_info']['server']['log_mail']))
|
||||||
{
|
{
|
||||||
$msg = $GLOBALS['egw_info']['server']['log_mail'] !== true ? date('Y-m-d H:i:s')."\n" : '';
|
$msg = $GLOBALS['egw_info']['server']['log_mail'] !== true ? date('Y-m-d H:i:s')."\n" : '';
|
||||||
$msg .= (!isset($e) ? 'Mail send' : 'Mail NOT send').
|
$msg .= (!isset($e) ? 'Mail send' : 'Mail NOT send').
|
||||||
@ -732,7 +732,7 @@ class Mailer extends Horde_Mime_Mail
|
|||||||
$recipients->add($h->getAddressList());
|
$recipients->add($h->getAddressList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($this->_bcc) {
|
if (!empty($this->_bcc)) {
|
||||||
$recipients->add($this->_bcc);
|
$recipients->add($this->_bcc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1538,7 +1538,7 @@ class Session
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check if the url already contains a query and ensure that vars is an array and all strings are in extravars
|
// check if the url already contains a query and ensure that vars is an array and all strings are in extravars
|
||||||
if (strpos($ret_url=$url, '?') !== false) list($ret_url,$othervars) = explode('?', $url, 2)+[null,null];
|
list($ret_url,$othervars) = explode('?', $url, 2)+[null,null];
|
||||||
if ($extravars && is_array($extravars))
|
if ($extravars && is_array($extravars))
|
||||||
{
|
{
|
||||||
$vars += $extravars;
|
$vars += $extravars;
|
||||||
|
@ -674,7 +674,7 @@ class Storage extends Storage\Base
|
|||||||
elseif (is_string($name) && $val!=null && in_array($name, $this->db_cols))
|
elseif (is_string($name) && $val!=null && in_array($name, $this->db_cols))
|
||||||
{
|
{
|
||||||
$extra_columns = $this->db->get_table_definitions($this->app, $this->extra_table);
|
$extra_columns = $this->db->get_table_definitions($this->app, $this->extra_table);
|
||||||
if ($extra_columns['fd'][array_search($name, $this->db_cols)])
|
if (!empty($extra_columns['fd'][array_search($name, $this->db_cols)]))
|
||||||
{
|
{
|
||||||
$filter[] = $this->db->expression($this->table_name,$this->table_name.'.',array(
|
$filter[] = $this->db->expression($this->table_name,$this->table_name.'.',array(
|
||||||
array_search($name, $this->db_cols) => $val,
|
array_search($name, $this->db_cols) => $val,
|
||||||
|
@ -1034,14 +1034,14 @@ class Base
|
|||||||
$this->total = $this->db->select($this->table_name,$colums,$query,__LINE__,__FILE__,false,$order_by,false,0,$join)->NumRows();
|
$this->total = $this->db->select($this->table_name,$colums,$query,__LINE__,__FILE__,false,$order_by,false,0,$join)->NumRows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$rs = $this->db->select($this->table_name,$mysql_calc_rows.$colums,$query,__LINE__,__FILE__,
|
$rs = $this->db->select($this->table_name,($mysql_calc_rows??'').$colums,$query,__LINE__,__FILE__,
|
||||||
$start,$order_by,$this->app,$num_rows,$join);
|
$start,$order_by,$this->app,$num_rows,$join);
|
||||||
if ($this->debug) error_log(__METHOD__."() ".$this->db->Query_ID->sql);
|
if ($this->debug) error_log(__METHOD__."() ".$this->db->Query_ID->sql);
|
||||||
$cols = $this->_get_columns($only_keys,$extra_cols);
|
$cols = $this->_get_columns($only_keys,$extra_cols);
|
||||||
}
|
}
|
||||||
if ((int) $this->debug >= 4) echo "<p>sql='{$this->db->Query_ID->sql}'</p>\n";
|
if ((int) $this->debug >= 4) echo "<p>sql='{$this->db->Query_ID->sql}'</p>\n";
|
||||||
|
|
||||||
if ($mysql_calc_rows)
|
if (!empty($mysql_calc_rows))
|
||||||
{
|
{
|
||||||
$this->total = $this->db->query('SELECT FOUND_ROWS()')->fetchColumn();
|
$this->total = $this->db->query('SELECT FOUND_ROWS()')->fetchColumn();
|
||||||
}
|
}
|
||||||
@ -1157,8 +1157,8 @@ class Base
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_array($query) && $op != 'AND') $query = $this->db->column_data_implode(' '.$op.' ',$query);
|
if (!empty($query) && is_array($query) && $op != 'AND') $query = $this->db->column_data_implode(' '.$op.' ',$query);
|
||||||
return $query;
|
return $query ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -190,7 +190,7 @@ class Customfields implements \IteratorAggregate
|
|||||||
/**
|
/**
|
||||||
* Format a single custom field value as string
|
* Format a single custom field value as string
|
||||||
*
|
*
|
||||||
* @param array $field field defintion incl. type
|
* @param array $field field definition incl. type
|
||||||
* @param string $value field value
|
* @param string $value field value
|
||||||
* @return string formatted value
|
* @return string formatted value
|
||||||
*/
|
*/
|
||||||
@ -204,7 +204,7 @@ class Customfields implements \IteratorAggregate
|
|||||||
$values = array();
|
$values = array();
|
||||||
foreach($field['rows'] > 1 ? explode(',', $value) : (array) $value as $value)
|
foreach($field['rows'] > 1 ? explode(',', $value) : (array) $value as $value)
|
||||||
{
|
{
|
||||||
$values[] = Api\Accounts::username($value);
|
$values[] = is_numeric($value) ? Api\Accounts::username($value) : $value;
|
||||||
}
|
}
|
||||||
$value = implode(', ',$values);
|
$value = implode(', ',$values);
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -283,7 +283,7 @@ abstract class Tracking
|
|||||||
//error_log(__METHOD__."() $name: data['#$name']=".array2string($data['#'.$name]).", field[values]=".array2string($field['values']));
|
//error_log(__METHOD__."() $name: data['#$name']=".array2string($data['#'.$name]).", field[values]=".array2string($field['values']));
|
||||||
$details['#'.$name] = array(
|
$details['#'.$name] = array(
|
||||||
'label' => $field['label'],
|
'label' => $field['label'],
|
||||||
'value' => Customfields::format($field, $data['#'.$name]),
|
'value' => Customfields::format($field, $data['#'.$name] ?? null),
|
||||||
);
|
);
|
||||||
//error_log("--> details['#$name']=".array2string($details['#'.$name]));
|
//error_log("--> details['#$name']=".array2string($details['#'.$name]));
|
||||||
}
|
}
|
||||||
@ -636,13 +636,13 @@ abstract class Tracking
|
|||||||
{
|
{
|
||||||
//error_log(__METHOD__."() data[$this->assigned_field]=".print_r($data[$this->assigned_field],true).", old[$this->assigned_field]=".print_r($old[$this->assigned_field],true));
|
//error_log(__METHOD__."() data[$this->assigned_field]=".print_r($data[$this->assigned_field],true).", old[$this->assigned_field]=".print_r($old[$this->assigned_field],true));
|
||||||
$old_assignees = array();
|
$old_assignees = array();
|
||||||
$assignees = $assigned ? $assigned : array();
|
$assignees = $assigned ?? array();
|
||||||
if ($data[$this->assigned_field]) // current assignments
|
if (!empty($data[$this->assigned_field])) // current assignments
|
||||||
{
|
{
|
||||||
$assignees = is_array($data[$this->assigned_field]) ?
|
$assignees = is_array($data[$this->assigned_field]) ?
|
||||||
$data[$this->assigned_field] : explode(',',$data[$this->assigned_field]);
|
$data[$this->assigned_field] : explode(',',$data[$this->assigned_field]);
|
||||||
}
|
}
|
||||||
if ($old && $old[$this->assigned_field])
|
if ($old && !empty($old[$this->assigned_field]))
|
||||||
{
|
{
|
||||||
$old_assignees = is_array($old[$this->assigned_field]) ?
|
$old_assignees = is_array($old[$this->assigned_field]) ?
|
||||||
$old[$this->assigned_field] : explode(',',$old[$this->assigned_field]);
|
$old[$this->assigned_field] : explode(',',$old[$this->assigned_field]);
|
||||||
@ -1050,7 +1050,7 @@ abstract class Tracking
|
|||||||
// remove the session-id in the notification mail!
|
// remove the session-id in the notification mail!
|
||||||
$link = preg_replace('/(sessionid|kp3|domain)=[^&]+&?/','',$link);
|
$link = preg_replace('/(sessionid|kp3|domain)=[^&]+&?/','',$link);
|
||||||
|
|
||||||
if ($popup) $link .= '&nopopup=1';
|
if (!empty($popup)) $link .= '&nopopup=1';
|
||||||
}
|
}
|
||||||
//error_log(__METHOD__."(..., $allow_popup, $receiver) returning ".array2string($allow_popup ? array($link,$popup) : $link));
|
//error_log(__METHOD__."(..., $allow_popup, $receiver) returning ".array2string($allow_popup ? array($link,$popup) : $link));
|
||||||
return $allow_popup ? array($link,$popup) : $link;
|
return $allow_popup ? array($link,$popup) : $link;
|
||||||
@ -1123,22 +1123,22 @@ abstract class Tracking
|
|||||||
{
|
{
|
||||||
// if there's no old entry, the entry is not modified by definition
|
// if there's no old entry, the entry is not modified by definition
|
||||||
// if both values are '', 0 or null, we count them as equal too
|
// if both values are '', 0 or null, we count them as equal too
|
||||||
$modified = $old && $data[$name] != $old[$name] && !(!$data[$name] && !$old[$name]);
|
$modified = $old && ($data[$name] ?? null) != ($old[$name] ?? null) && !(empty($data[$name]) && empty($old[$name]));
|
||||||
//if ($modified) error_log("data[$name]=".print_r($data[$name],true).", old[$name]=".print_r($old[$name],true)." --> modified=".(int)$modified);
|
//if ($modified) error_log("data[$name]=".print_r($data[$name],true).", old[$name]=".print_r($old[$name],true)." --> modified=".(int)$modified);
|
||||||
if (empty($detail['value']) && !$modified) continue; // skip unchanged, empty values
|
if (empty($detail['value']) && !$modified) continue; // skip unchanged, empty values
|
||||||
|
|
||||||
$body .= $this->format_line($html_email,$detail['type'],$modified,
|
$body .= $this->format_line($html_email, $detail['type'] ?? null, $modified,
|
||||||
$detail['label'] ? $detail['label'] : '', $detail['value']);
|
$detail['label'] ?? '', $detail['value']);
|
||||||
}
|
}
|
||||||
if ($html_email)
|
if ($html_email)
|
||||||
{
|
{
|
||||||
$body .= "</table>\n";
|
$body .= "</table>\n";
|
||||||
}
|
}
|
||||||
if(($sig = $this->get_signature($data,$old,$receiver)))
|
if (($sig = $this->get_signature($data,$old,$receiver)))
|
||||||
{
|
{
|
||||||
$body .= ($html_email ? '<br />':'') . "\n$sig";
|
$body .= ($html_email ? '<br />':'') . "\n$sig";
|
||||||
}
|
}
|
||||||
if (!$html_email && $data['tr_edit_mode'] == 'html')
|
if (!$html_email && isset($data['tr_edit_mode']) && $data['tr_edit_mode'] === 'html')
|
||||||
{
|
{
|
||||||
$body = Api\Mail\Html::convertHTMLToText($body);
|
$body = Api\Mail\Html::convertHTMLToText($body);
|
||||||
}
|
}
|
||||||
@ -1271,7 +1271,7 @@ abstract class Tracking
|
|||||||
$merge_class = $this->app.'_merge';
|
$merge_class = $this->app.'_merge';
|
||||||
$merge = new $merge_class();
|
$merge = new $merge_class();
|
||||||
$error = null;
|
$error = null;
|
||||||
$sig = $merge->merge_string($config['signature'], array($data[$this->id_field]), $error, 'text/html');
|
$sig = $merge->merge_string($config['signature']??null, array($data[$this->id_field]), $error, 'text/html');
|
||||||
if($error)
|
if($error)
|
||||||
{
|
{
|
||||||
error_log($error);
|
error_log($error);
|
||||||
|
@ -335,21 +335,20 @@ class Base
|
|||||||
$url = str_replace($matches[0], $matches[1] . Vfs::concat($matches[2], substr($parts['path'], strlen($mounted))), $url);
|
$url = str_replace($matches[0], $matches[1] . Vfs::concat($matches[2], substr($parts['path'], strlen($mounted))), $url);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($replace_user_pass_host)
|
if ($replace_user_pass_host)
|
||||||
{
|
{
|
||||||
$url = str_replace(array('$user',
|
$url = strtr($url, [
|
||||||
'$pass',
|
'$user' => $parts['user'],
|
||||||
'$host',
|
'$pass' => $parts['pass'],
|
||||||
'$home'), array($parts['user'],
|
'$host' => $parts['host'],
|
||||||
$parts['pass'],
|
'$home' => $parts['home'],
|
||||||
$parts['host'],
|
]);
|
||||||
$parts['home']), $url);
|
|
||||||
}
|
}
|
||||||
if($parts['query'])
|
if (isset($parts['query']))
|
||||||
{
|
{
|
||||||
$url .= '?' . $parts['query'];
|
$url .= '?' . $parts['query'];
|
||||||
}
|
}
|
||||||
if($parts['fragment'])
|
if (isset($parts['fragment']))
|
||||||
{
|
{
|
||||||
$url .= '#' . $parts['fragment'];
|
$url .= '#' . $parts['fragment'];
|
||||||
}
|
}
|
||||||
@ -657,7 +656,7 @@ class Base
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$k = (string)Vfs::parse_url($url, PHP_URL_SCHEME);
|
$k = (string)Vfs::parse_url($url, PHP_URL_SCHEME);
|
||||||
if(!(is_array($scheme2urls[$k])))
|
if (!isset($scheme2urls[$k]))
|
||||||
{
|
{
|
||||||
$scheme2urls[$k] = array();
|
$scheme2urls[$k] = array();
|
||||||
}
|
}
|
||||||
|
@ -798,11 +798,11 @@ class StreamWrapper extends Base implements StreamWrapperIface
|
|||||||
{
|
{
|
||||||
$stat['url'] = $url;
|
$stat['url'] = $url;
|
||||||
}
|
}
|
||||||
if (($stat['mode'] & 0222) && self::url_is_readonly($stat['url']))
|
if ($stat && ($stat['mode'] & 0222) && self::url_is_readonly($stat['url']))
|
||||||
{
|
{
|
||||||
$stat['mode'] &= ~0222;
|
$stat['mode'] &= ~0222;
|
||||||
}
|
}
|
||||||
if($stat['url'] && $query && strpos($stat['url'],'?'.$query)===false)
|
if ($stat && $stat['url'] && $query && strpos($stat['url'],'?'.$query) === false)
|
||||||
{
|
{
|
||||||
$stat['url'] .= '?'.$query;
|
$stat['url'] .= '?'.$query;
|
||||||
}
|
}
|
||||||
@ -998,7 +998,7 @@ class StreamWrapper extends Base implements StreamWrapperIface
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$vfs_fstab = $GLOBALS['egw_info']['user']['preferences']['common']['vfs_fstab'];
|
$vfs_fstab = $GLOBALS['egw_info']['user']['preferences']['common']['vfs_fstab'] ?? [];
|
||||||
}
|
}
|
||||||
if (!empty($vfs_fstab) && is_array($vfs_fstab))
|
if (!empty($vfs_fstab) && is_array($vfs_fstab))
|
||||||
{
|
{
|
||||||
|
@ -71,6 +71,7 @@ function _egw_log_exception($e,&$headline=null)
|
|||||||
{
|
{
|
||||||
error_log($headline.($e instanceof egw_exception_warning ? ': ' : ' ('.get_class($e).'): ').
|
error_log($headline.($e instanceof egw_exception_warning ? ': ' : ' ('.get_class($e).'): ').
|
||||||
$e->getMessage().(!empty($e->details) ? ': '.$e->details : ''));
|
$e->getMessage().(!empty($e->details) ? ': '.$e->details : ''));
|
||||||
|
error_log('File: '.str_replace(EGW_SERVER_ROOT, '', $e->getFile()).', Line: '.$e->getLine());
|
||||||
foreach($trace as $line)
|
foreach($trace as $line)
|
||||||
{
|
{
|
||||||
error_log($line);
|
error_log($line);
|
||||||
@ -103,6 +104,7 @@ function egw_exception_handler($e)
|
|||||||
if(!isset($_SERVER['HTTP_HOST']) || $GLOBALS['egw_info']['flags']['no_exception_handler'] == 'cli')
|
if(!isset($_SERVER['HTTP_HOST']) || $GLOBALS['egw_info']['flags']['no_exception_handler'] == 'cli')
|
||||||
{
|
{
|
||||||
echo ($headline ? $headline.': ' : '').$e->getMessage()."\n";
|
echo ($headline ? $headline.': ' : '').$e->getMessage()."\n";
|
||||||
|
echo $e->getFile().' ('.$e->getLine().")\n";
|
||||||
if ($GLOBALS['egw_info']['server']['exception_show_trace'])
|
if ($GLOBALS['egw_info']['server']['exception_show_trace'])
|
||||||
{
|
{
|
||||||
echo $e->getTraceAsString()."\n";
|
echo $e->getTraceAsString()."\n";
|
||||||
@ -116,6 +118,8 @@ function egw_exception_handler($e)
|
|||||||
$message = '<h3>'.Api\Html::htmlspecialchars($headline)."</h3>\n".
|
$message = '<h3>'.Api\Html::htmlspecialchars($headline)."</h3>\n".
|
||||||
'<pre><b>'.Api\Html::htmlspecialchars($e->getMessage())."</b>\n\n";
|
'<pre><b>'.Api\Html::htmlspecialchars($e->getMessage())."</b>\n\n";
|
||||||
|
|
||||||
|
echo $e->getFile().' ('.$e->getLine().")\n";
|
||||||
|
|
||||||
// only show trace (incl. function arguments) if explicitly enabled, eg. on a development system
|
// only show trace (incl. function arguments) if explicitly enabled, eg. on a development system
|
||||||
if ($GLOBALS['egw_info']['server']['exception_show_trace'])
|
if ($GLOBALS['egw_info']['server']['exception_show_trace'])
|
||||||
{
|
{
|
||||||
@ -174,6 +178,7 @@ function egw_error_handler ($errno, $errstr, $errfile, $errline)
|
|||||||
{
|
{
|
||||||
case E_RECOVERABLE_ERROR:
|
case E_RECOVERABLE_ERROR:
|
||||||
case E_USER_ERROR:
|
case E_USER_ERROR:
|
||||||
|
error_log(__METHOD__."($errno, '$errstr', '$errfile', $errline)");
|
||||||
throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
|
throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
|
||||||
|
|
||||||
case E_WARNING:
|
case E_WARNING:
|
||||||
|
@ -175,6 +175,8 @@ function php_safe_unserialize($str)
|
|||||||
*/
|
*/
|
||||||
function json_php_unserialize($str, $allow_not_serialized=false)
|
function json_php_unserialize($str, $allow_not_serialized=false)
|
||||||
{
|
{
|
||||||
|
if (!isset($str)) return $str;
|
||||||
|
|
||||||
if ((in_array($str[0], array('a', 'i', 's', 'b', 'O', 'C')) && $str[1] == ':' || $str === 'N;') &&
|
if ((in_array($str[0], array('a', 'i', 's', 'b', 'O', 'C')) && $str[1] == ':' || $str === 'N;') &&
|
||||||
($arr = php_safe_unserialize($str)) !== false || $str === 'b:0;')
|
($arr = php_safe_unserialize($str)) !== false || $str === 'b:0;')
|
||||||
{
|
{
|
||||||
|
65
api/templates/default/show_replacements.xet
Normal file
65
api/templates/default/show_replacements.xet
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE overlay PUBLIC "-//EGroupware GmbH//eTemplate 2//EN" "http://www.egroupware.org/etemplate2.dtd">
|
||||||
|
<!-- $Id$ -->
|
||||||
|
<overlay>
|
||||||
|
<template id="api.show_replacements.placeholder_list">
|
||||||
|
<description id="title" class="title"/>
|
||||||
|
<grid id="placeholders" width="100%">
|
||||||
|
<columns>
|
||||||
|
<column width="30%"/>
|
||||||
|
<column/>
|
||||||
|
</columns>
|
||||||
|
<rows>
|
||||||
|
<row>
|
||||||
|
<description id="${row}[value]"/>
|
||||||
|
<description id="${row}[label]"/>
|
||||||
|
</row>
|
||||||
|
</rows>
|
||||||
|
</grid>
|
||||||
|
</template>
|
||||||
|
<template id="api.show_replacements" template="" lang="" group="0" version="21.1.001">
|
||||||
|
<vbox>
|
||||||
|
<description value="Placeholders" class="group title"/>
|
||||||
|
<box id="placeholders">
|
||||||
|
<box id="${row}">
|
||||||
|
<template template="api.show_replacements.placeholder_list"/>
|
||||||
|
</box>
|
||||||
|
</box>
|
||||||
|
<template template="@extra_template"/>
|
||||||
|
<details title="Common">
|
||||||
|
<description value="Common" class="group title"/>
|
||||||
|
<box id="common">
|
||||||
|
<box id="${row}">
|
||||||
|
<template template="api.show_replacements.placeholder_list"/>
|
||||||
|
</box>
|
||||||
|
</box>
|
||||||
|
</details>
|
||||||
|
<details title="Current user">
|
||||||
|
<description value="Current user" class="group title"/>
|
||||||
|
<box id="user">
|
||||||
|
<box id="${row}">
|
||||||
|
<template template="api.show_replacements.placeholder_list"/>
|
||||||
|
</box>
|
||||||
|
</box>
|
||||||
|
</details>
|
||||||
|
</vbox>
|
||||||
|
<styles>
|
||||||
|
.et2_details_title, .title {
|
||||||
|
display: inline-block;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 130%;
|
||||||
|
margin-top: 2ex;
|
||||||
|
|
||||||
|
}
|
||||||
|
.et2_details_title, .group {
|
||||||
|
margin-top: 3ex;
|
||||||
|
font-size: 150%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Cosmetics **/
|
||||||
|
#api-show_replacements_title:first-letter, .title {
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
</styles>
|
||||||
|
</template>
|
||||||
|
</overlay>
|
@ -1634,7 +1634,7 @@ class calendar_boupdate extends calendar_bo
|
|||||||
$memberships = $GLOBALS['egw']->accounts->memberships($uid,true);
|
$memberships = $GLOBALS['egw']->accounts->memberships($uid,true);
|
||||||
}
|
}
|
||||||
$memberships[] = $uid;
|
$memberships[] = $uid;
|
||||||
return array_intersect($memberships, array_keys($event['participants'])) && $this->check_perms(Acl::EDIT,0,$uid);
|
return array_intersect($memberships, array_keys($event['participants'] ?? [])) && $this->check_perms(Acl::EDIT,0,$uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -660,31 +660,8 @@ class calendar_hooks
|
|||||||
// Merge print
|
// Merge print
|
||||||
if ($GLOBALS['egw_info']['user']['apps']['filemanager'])
|
if ($GLOBALS['egw_info']['user']['apps']['filemanager'])
|
||||||
{
|
{
|
||||||
$settings['default_document'] = array(
|
$merge = new calendar_merge();
|
||||||
'type' => 'vfs_file',
|
$settings += $merge->merge_preferences();
|
||||||
'size' => 60,
|
|
||||||
'label' => 'Default document to insert entries',
|
|
||||||
'name' => 'default_document',
|
|
||||||
'help' => lang('If you specify a document (full vfs path) here, %1 displays an extra document icon for each entry. That icon allows to download the specified document with the data inserted.',lang('calendar')).' '.
|
|
||||||
lang('The document can contain placeholder like {{%1}}, to be replaced with the data.','calendar_title').' '.
|
|
||||||
lang('The following document-types are supported:'). implode(',',Api\Storage\Merge::get_file_extensions()),
|
|
||||||
'run_lang' => false,
|
|
||||||
'xmlrpc' => True,
|
|
||||||
'admin' => False,
|
|
||||||
);
|
|
||||||
$settings['document_dir'] = array(
|
|
||||||
'type' => 'vfs_dirs',
|
|
||||||
'size' => 60,
|
|
||||||
'label' => 'Directory with documents to insert entries',
|
|
||||||
'name' => 'document_dir',
|
|
||||||
'help' => lang('If you specify a directory (full vfs path) here, %1 displays an action for each document. That action allows to download the specified document with the data inserted.',lang('calendar')).' '.
|
|
||||||
lang('The document can contain placeholder like {{%1}}, to be replaced with the data.','calendar_title').' '.
|
|
||||||
lang('The following document-types are supported:'). implode(',',Api\Storage\Merge::get_file_extensions()),
|
|
||||||
'run_lang' => false,
|
|
||||||
'xmlrpc' => True,
|
|
||||||
'admin' => False,
|
|
||||||
'default' => '/templates/calendar',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$settings += array(
|
$settings += array(
|
||||||
|
@ -3082,7 +3082,7 @@ class calendar_ical extends calendar_boupdate
|
|||||||
// check if json_encoded attribute is to big for our table
|
// check if json_encoded attribute is to big for our table
|
||||||
if (($attributes['params'] || count($attributes['values']) > 1) &&
|
if (($attributes['params'] || count($attributes['values']) > 1) &&
|
||||||
strlen($event['##'.$attributes['name']]) >
|
strlen($event['##'.$attributes['name']]) >
|
||||||
Api\Db::get_column_attribute('cal_extra_value', 'egw_cal_extra', 'calendar', 'precision'))
|
$GLOBALS['egw']->db->get_column_attribute('cal_extra_value', 'egw_cal_extra', 'calendar', 'precision'))
|
||||||
{
|
{
|
||||||
// store content compressed (Outlook/Exchange HTML garbadge is very good compressable)
|
// store content compressed (Outlook/Exchange HTML garbadge is very good compressable)
|
||||||
if (function_exists('gzcompress'))
|
if (function_exists('gzcompress'))
|
||||||
@ -3093,7 +3093,7 @@ class calendar_ical extends calendar_boupdate
|
|||||||
}
|
}
|
||||||
// if that's not enough --> unset it, as truncating the json gives nothing
|
// if that's not enough --> unset it, as truncating the json gives nothing
|
||||||
if (strlen($event['##'.$attributes['name']]) >
|
if (strlen($event['##'.$attributes['name']]) >
|
||||||
Api\Db::get_column_attribute('cal_extra_value', 'egw_cal_extra', 'calendar', 'precision'))
|
$GLOBALS['egw']->db->get_column_attribute('cal_extra_value', 'egw_cal_extra', 'calendar', 'precision'))
|
||||||
{
|
{
|
||||||
unset($event['##'.$attributes['name']]);
|
unset($event['##'.$attributes['name']]);
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -878,7 +878,14 @@ class calendar_so
|
|||||||
$where[] = "$this->user_table.cal_recur_date=0";
|
$where[] = "$this->user_table.cal_recur_date=0";
|
||||||
$cols = str_replace(array('cal_start','cal_end'),array('range_start AS cal_start','(SELECT MIN(cal_end) FROM egw_cal_dates WHERE egw_cal.cal_id=egw_cal_dates.cal_id) AS cal_end'),$cols);
|
$cols = str_replace(array('cal_start','cal_end'),array('range_start AS cal_start','(SELECT MIN(cal_end) FROM egw_cal_dates WHERE egw_cal.cal_id=egw_cal_dates.cal_id) AS cal_end'),$cols);
|
||||||
// in case cal_start is used in a query, eg. calendar_ical::find_event
|
// in case cal_start is used in a query, eg. calendar_ical::find_event
|
||||||
$where = str_replace(array('cal_start','cal_end'), array('range_start','(SELECT MIN(cal_end) FROM egw_cal_dates WHERE egw_cal.cal_id=egw_cal_dates.cal_id)'), $where);
|
// in contrary to the docu on php.net, 3rd parameter can not be an array: https://3v4l.org/budKH
|
||||||
|
foreach($where as &$val)
|
||||||
|
{
|
||||||
|
if (!is_array($val))
|
||||||
|
{
|
||||||
|
$val = str_replace(array('cal_start','cal_end'), array('range_start','(SELECT MIN(cal_end) FROM egw_cal_dates WHERE egw_cal.cal_id=egw_cal_dates.cal_id)'), $val);
|
||||||
|
}
|
||||||
|
}
|
||||||
$params['order'] = str_replace('cal_start', 'range_start', $params['order']);
|
$params['order'] = str_replace('cal_start', 'range_start', $params['order']);
|
||||||
if ($end) $where[] = (int)$end.' > range_start';
|
if ($end) $where[] = (int)$end.' > range_start';
|
||||||
}
|
}
|
||||||
|
@ -642,16 +642,20 @@ class calendar_ui
|
|||||||
*
|
*
|
||||||
* @param int $event_id
|
* @param int $event_id
|
||||||
* @param Api\DateTime $recurrence_date
|
* @param Api\DateTime $recurrence_date
|
||||||
|
* @param array|bool|int|null $old_event
|
||||||
*
|
*
|
||||||
* @return boolean True if the event was updated, false if it could not be
|
* @return boolean True if the event was updated, false if it could not be
|
||||||
* updated or was removed.
|
* updated or was removed.
|
||||||
*/
|
*/
|
||||||
public function update_client($event_id, Api\DateTime $recurrence_date = null)
|
public function update_client($event_id, Api\DateTime $recurrence_date = null, $old_event = array())
|
||||||
{
|
{
|
||||||
if(!$event_id) return false;
|
if(!$event_id)
|
||||||
if(is_string($event_id) && strpos($event_id,':') !== FALSE)
|
|
||||||
{
|
{
|
||||||
list($event_id, $date) = explode(':',$event_id);
|
return false;
|
||||||
|
}
|
||||||
|
if(is_string($event_id) && strpos($event_id, ':') !== FALSE)
|
||||||
|
{
|
||||||
|
list($event_id, $date) = explode(':', $event_id);
|
||||||
$recurrence_date = new Api\DateTime($date);
|
$recurrence_date = new Api\DateTime($date);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -698,6 +702,21 @@ class calendar_ui
|
|||||||
else if($event['recur_type'] )
|
else if($event['recur_type'] )
|
||||||
{
|
{
|
||||||
$this_month = new Api\DateTime('next month');
|
$this_month = new Api\DateTime('next month');
|
||||||
|
$data = [];
|
||||||
|
if($old_event && ($old_event['start'] != $event['start'] || $old_event['recur_enddate'] != $event['recur_enddate']))
|
||||||
|
{
|
||||||
|
// Set up to clear old events in case recurrence start/end date changed
|
||||||
|
$old_rrule = calendar_rrule::event2rrule($old_event, true);
|
||||||
|
|
||||||
|
$old_rrule->rewind();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
$occurrence = $old_rrule->current();
|
||||||
|
$data['calendar::' . $old_event['id'] . ':' . $occurrence->format('ts')] = null;
|
||||||
|
$old_rrule->next();
|
||||||
|
}
|
||||||
|
while($old_rrule->valid() && $occurrence <= $this_month);
|
||||||
|
}
|
||||||
$rrule = calendar_rrule::event2rrule($event, true);
|
$rrule = calendar_rrule::event2rrule($event, true);
|
||||||
$rrule->rewind();
|
$rrule->rewind();
|
||||||
do
|
do
|
||||||
@ -705,10 +724,17 @@ class calendar_ui
|
|||||||
$occurrence = $rrule->current();
|
$occurrence = $rrule->current();
|
||||||
$converted = $this->bo->read($event['id'], $occurrence);
|
$converted = $this->bo->read($event['id'], $occurrence);
|
||||||
$this->to_client($converted);
|
$this->to_client($converted);
|
||||||
$response->generic('data', array('uid' => 'calendar::'.$converted['row_id'], 'data' => $converted));
|
$data['calendar::' . $converted['row_id']] = $converted;
|
||||||
$rrule->next();
|
$rrule->next();
|
||||||
}
|
}
|
||||||
while ($rrule->valid() && $occurrence <= $this_month );
|
while($rrule->valid() && $occurrence <= $this_month);
|
||||||
|
|
||||||
|
// Now we have to go through and send each one individually, since client side data can't handle more than one
|
||||||
|
foreach($data as $uid => $cal_data)
|
||||||
|
{
|
||||||
|
$response->apply('egw.dataStoreUID', [$uid, $cal_data]);
|
||||||
|
}
|
||||||
|
$response->apply('app.calendar.update_events', [array_keys($data)]);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1007,7 +1007,7 @@ class calendar_uiforms extends calendar_ui
|
|||||||
$response = Api\Json\Response::get();
|
$response = Api\Json\Response::get();
|
||||||
if($response && $update_type != 'delete' && !$client_updated)
|
if($response && $update_type != 'delete' && !$client_updated)
|
||||||
{
|
{
|
||||||
$client_updated = $this->update_client($event['id']);
|
$client_updated = $this->update_client($event['id'], null, is_array($old_event) ? $old_event : []);
|
||||||
}
|
}
|
||||||
|
|
||||||
$msg = $message . ($msg ? ', ' . $msg : '');
|
$msg = $message . ($msg ? ', ' . $msg : '');
|
||||||
@ -1267,8 +1267,6 @@ class calendar_uiforms extends calendar_ui
|
|||||||
Api\DateTime::to($as_of_date,'ts') < time()
|
Api\DateTime::to($as_of_date,'ts') < time()
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
unset($orig_event);
|
|
||||||
// copy event by unsetting the id(s)
|
// copy event by unsetting the id(s)
|
||||||
unset($event['id']);
|
unset($event['id']);
|
||||||
unset($event['uid']);
|
unset($event['uid']);
|
||||||
@ -1325,7 +1323,8 @@ class calendar_uiforms extends calendar_ui
|
|||||||
}
|
}
|
||||||
$last->setTime(0, 0, 0);
|
$last->setTime(0, 0, 0);
|
||||||
$old_event['recur_enddate'] = Api\DateTime::to($last, 'ts');
|
$old_event['recur_enddate'] = Api\DateTime::to($last, 'ts');
|
||||||
if (!$this->bo->update($old_event,true,true,false,true,$dummy=null,$no_notifications))
|
$dummy = null;
|
||||||
|
if (!$this->bo->update($old_event,true,true,false,true,$dummy, $no_notifications))
|
||||||
{
|
{
|
||||||
$msg .= ($msg ? ', ' : '') .lang('Error: the entry has been updated since you opened it for editing!').'<br />'.
|
$msg .= ($msg ? ', ' : '') .lang('Error: the entry has been updated since you opened it for editing!').'<br />'.
|
||||||
lang('Copy your changes to the clipboard, %1reload the entry%2 and merge them.','<a href="'.
|
lang('Copy your changes to the clipboard, %1reload the entry%2 and merge them.','<a href="'.
|
||||||
@ -1925,7 +1924,7 @@ class calendar_uiforms extends calendar_ui
|
|||||||
$sel_options['owner'][$uid] = $this->bo->participant_name($uid);
|
$sel_options['owner'][$uid] = $this->bo->participant_name($uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$content['no_add_alarm'] = !count($sel_options['owner']); // no rights to set any alarm
|
$content['no_add_alarm'] = empty($sel_options['owner']) || !count((array)$sel_options['owner']); // no rights to set any alarm
|
||||||
if (!$event['id'])
|
if (!$event['id'])
|
||||||
{
|
{
|
||||||
$etpl->set_cell_attribute('button[new_alarm]','type','checkbox');
|
$etpl->set_cell_attribute('button[new_alarm]','type','checkbox');
|
||||||
@ -2182,7 +2181,7 @@ class calendar_uiforms extends calendar_ui
|
|||||||
}
|
}
|
||||||
$user_and_memberships = $GLOBALS['egw']->accounts->memberships($user, true);
|
$user_and_memberships = $GLOBALS['egw']->accounts->memberships($user, true);
|
||||||
$user_and_memberships[] = $user;
|
$user_and_memberships[] = $user;
|
||||||
if (!array_intersect(array_keys($event['participants']), $user_and_memberships))
|
if (!array_intersect(array_keys($event['participants'] ?? []), $user_and_memberships))
|
||||||
{
|
{
|
||||||
$event['error'] .= ($event['error'] ? "\n" : '').lang('You are not invited to that event!');
|
$event['error'] .= ($event['error'] ? "\n" : '').lang('You are not invited to that event!');
|
||||||
if ($event['id'])
|
if ($event['id'])
|
||||||
|
@ -651,22 +651,34 @@ export class CalendarApp extends EgwApp
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Do we already have "fresh" data? Most user actions give fresh data in response
|
// Do we already have "fresh" data? Most user actions give fresh data in response
|
||||||
let existing = egw.dataGetUIDdata('calendar::'+pushData.id);
|
let existing = egw.dataGetUIDdata('calendar::' + pushData.id);
|
||||||
if(existing && Math.abs(existing.timestamp - new Date().valueOf()) < 1000)
|
if(existing && Math.abs(existing.timestamp - new Date().valueOf()) < 1000)
|
||||||
{
|
{
|
||||||
// Update directly
|
// Update directly
|
||||||
this._update_events(this.state, ['calendar::'+pushData.id]);
|
this._update_events(this.state, ['calendar::' + pushData.id]);
|
||||||
return;
|
return;
|
||||||
};
|
}
|
||||||
|
;
|
||||||
|
|
||||||
// Ask for the real data, we don't have it
|
// Ask for the real data, we don't have it
|
||||||
egw.request("calendar.calendar_ui.ajax_get", [[pushData.id]]).then((data) =>
|
let process_data = (data) =>
|
||||||
{
|
{
|
||||||
// Store it, which will call all registered listeners
|
// Store it, which will call all registered listeners
|
||||||
egw.dataStoreUID(data.uid, data.data);
|
egw.dataStoreUID(data.uid, data.data);
|
||||||
|
|
||||||
// Any existing events were updated. Run this to catch new events or events moved into view
|
// Any existing events were updated. Run this to catch new events or events moved into view
|
||||||
this._update_events(this.state, [data.uid]);
|
this._update_events(this.state, [data.uid]);
|
||||||
|
}
|
||||||
|
egw.request("calendar.calendar_ui.ajax_get", [[pushData.id]]).then((data) =>
|
||||||
|
{
|
||||||
|
if(typeof data.uid !== "undefined")
|
||||||
|
{
|
||||||
|
return process_data(data)
|
||||||
|
}
|
||||||
|
for(let e of data)
|
||||||
|
{
|
||||||
|
process_data(e);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3736,13 +3748,22 @@ export class CalendarApp extends EgwApp
|
|||||||
else if(typeof framework !== 'undefined')
|
else if(typeof framework !== 'undefined')
|
||||||
{
|
{
|
||||||
framework.applications.calendar.sidemenuEntry.hideAjaxLoader();
|
framework.applications.calendar.sidemenuEntry.hideAjaxLoader();
|
||||||
egw.loading_prompt('calendar',false)
|
egw.loading_prompt('calendar', false)
|
||||||
|
|
||||||
}
|
}
|
||||||
}, this,null
|
}, this, null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We have a list of calendar UIDs of events that need updating.
|
||||||
|
* Public wrapper for _update_events so we can call it from server
|
||||||
|
*/
|
||||||
|
update_events(uids : string[])
|
||||||
|
{
|
||||||
|
return this._update_events(this.state, uids);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We have a list of calendar UIDs of events that need updating.
|
* We have a list of calendar UIDs of events that need updating.
|
||||||
*
|
*
|
||||||
|
@ -46,6 +46,14 @@
|
|||||||
"type": "pear",
|
"type": "pear",
|
||||||
"url": "https://pear.horde.org"
|
"url": "https://pear.horde.org"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "vcs",
|
||||||
|
"url": "https://github.com/egroupware/Crypt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "vcs",
|
||||||
|
"url": "https://github.com/egroupware/Compress"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "vcs",
|
"type": "vcs",
|
||||||
"url": "https://github.com/IMSGlobal/lti-1-3-php-library"
|
"url": "https://github.com/IMSGlobal/lti-1-3-php-library"
|
||||||
@ -81,6 +89,8 @@
|
|||||||
"egroupware/adodb-php": "self.version",
|
"egroupware/adodb-php": "self.version",
|
||||||
"egroupware/bookmarks": "self.version",
|
"egroupware/bookmarks": "self.version",
|
||||||
"egroupware/collabora": "self.version",
|
"egroupware/collabora": "self.version",
|
||||||
|
"egroupware/compress": "^2.2.3",
|
||||||
|
"egroupware/crypt": "^2.7.13",
|
||||||
"egroupware/guzzlestream": "dev-master",
|
"egroupware/guzzlestream": "dev-master",
|
||||||
"egroupware/icalendar": "^2.1.9",
|
"egroupware/icalendar": "^2.1.9",
|
||||||
"egroupware/magicsuggest": "^2.1",
|
"egroupware/magicsuggest": "^2.1",
|
||||||
@ -99,8 +109,6 @@
|
|||||||
"npm-asset/as-jqplot": "1.0.*",
|
"npm-asset/as-jqplot": "1.0.*",
|
||||||
"npm-asset/gridster": "0.5.*",
|
"npm-asset/gridster": "0.5.*",
|
||||||
"oomphinc/composer-installers-extender": "^1.1",
|
"oomphinc/composer-installers-extender": "^1.1",
|
||||||
"pear-pear.horde.org/horde_compress": "^2.0.8",
|
|
||||||
"pear-pear.horde.org/horde_crypt": "^2.7.9",
|
|
||||||
"pear-pear.horde.org/horde_imap_client": "^2.30.3",
|
"pear-pear.horde.org/horde_imap_client": "^2.30.3",
|
||||||
"pear-pear.horde.org/horde_mail": "^2.1.2",
|
"pear-pear.horde.org/horde_mail": "^2.1.2",
|
||||||
"pear-pear.horde.org/horde_managesieve": "^1.0.2",
|
"pear-pear.horde.org/horde_managesieve": "^1.0.2",
|
||||||
|
956
composer.lock
generated
956
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -171,49 +171,19 @@ class filemanager_hooks
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
$settings[Api\Storage\Merge::PREF_STORE_LOCATION] = array(
|
$merge = new filemanager_merge();
|
||||||
'type' => 'vfs_dir',
|
$settings += $merge->merge_preferences();
|
||||||
'size' => 60,
|
|
||||||
'label' => 'Directory for storing merged documents',
|
|
||||||
'name' => Api\Storage\Merge::PREF_STORE_LOCATION,
|
|
||||||
'help' => lang('When you merge entries into documents, they will be stored here. If no directory is provided, they will be stored in %1', Vfs::get_home_dir())
|
|
||||||
);
|
|
||||||
$settings['default_document'] = array(
|
|
||||||
'type' => 'vfs_file',
|
|
||||||
'size' => 60,
|
|
||||||
'label' => 'Default document to insert entries',
|
|
||||||
'name' => 'default_document',
|
|
||||||
'help' => lang('If you specify a document (full vfs path) here, %1 displays an extra document icon for each entry. That icon allows to download the specified document with the data inserted.', lang('filemanager')) . ' ' .
|
|
||||||
lang('The document can contain placeholder like {{%1}}, to be replaced with the data.', 'name') . ' ' .
|
|
||||||
lang('The following document-types are supported:') . implode(',', Api\Storage\Merge::get_file_extensions()),
|
|
||||||
'run_lang' => false,
|
|
||||||
'xmlrpc' => True,
|
|
||||||
'admin' => False,
|
|
||||||
);
|
|
||||||
$settings['document_dir'] = array(
|
|
||||||
'type' => 'vfs_dirs',
|
|
||||||
'size' => 60,
|
|
||||||
'label' => 'Directory with documents to insert entries',
|
|
||||||
'name' => 'document_dir',
|
|
||||||
'help' => lang('If you specify a directory (full vfs path) here, %1 displays an action for each document. That action allows to download the specified document with the %1 data inserted.', lang('filemanager')).' '.
|
|
||||||
lang('The document can contain placeholder like {{%1}}, to be replaced with the data.','name').' '.
|
|
||||||
lang('The following document-types are supported:'). implode(',',Api\Storage\Merge::get_file_extensions()),
|
|
||||||
'run_lang' => false,
|
|
||||||
'xmlrpc' => True,
|
|
||||||
'admin' => False,
|
|
||||||
'default' => '/templates/filemanager',
|
|
||||||
);
|
|
||||||
|
|
||||||
$editorLink = self::getEditorLink();
|
$editorLink = self::getEditorLink();
|
||||||
$mimes = array('0' => lang('None'));
|
$mimes = array('0' => lang('None'));
|
||||||
|
|
||||||
foreach ((array)$editorLink['mime'] as $mime => $value)
|
foreach((array)$editorLink['mime'] as $mime => $value)
|
||||||
{
|
{
|
||||||
$mimes[$mime] = lang('%1 file', strtoupper($value['ext'])).' ('.$mime.')';
|
$mimes[$mime] = lang('%1 file', strtoupper($value['ext'])) . ' (' . $mime . ')';
|
||||||
|
|
||||||
if (!empty($value['extra_extensions']))
|
if(!empty($value['extra_extensions']))
|
||||||
{
|
{
|
||||||
$mimes[$mime] .= ', '.strtoupper(implode(', ', $value['extra_extensions']));
|
$mimes[$mime] .= ', ' . strtoupper(implode(', ', $value['extra_extensions']));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,8 +33,7 @@ class filemanager_merge extends Api\Storage\Merge
|
|||||||
/**
|
/**
|
||||||
* Fields that are numeric, for special numeric handling
|
* Fields that are numeric, for special numeric handling
|
||||||
*/
|
*/
|
||||||
protected $numeric_fields = array(
|
protected $numeric_fields = array();
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fields that are dates or timestamps
|
* Fields that are dates or timestamps
|
||||||
@ -74,12 +73,12 @@ class filemanager_merge extends Api\Storage\Merge
|
|||||||
* Get replacements
|
* Get replacements
|
||||||
*
|
*
|
||||||
* @param int $id id of entry
|
* @param int $id id of entry
|
||||||
* @param string &$content=null content to create some replacements only if they are use
|
* @param string &$content =null content to create some replacements only if they are use
|
||||||
* @return array|boolean
|
* @return array|boolean
|
||||||
*/
|
*/
|
||||||
protected function get_replacements($id,&$content=null)
|
protected function get_replacements($id, &$content = null)
|
||||||
{
|
{
|
||||||
if (!($replacements = $this->filemanager_replacements($id, '', $content)))
|
if(!($replacements = $this->filemanager_replacements($id, '', $content)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -90,35 +89,35 @@ class filemanager_merge extends Api\Storage\Merge
|
|||||||
* Get filemanager replacements
|
* Get filemanager replacements
|
||||||
*
|
*
|
||||||
* @param int $id id (vfs path) of entry
|
* @param int $id id (vfs path) of entry
|
||||||
* @param string $prefix='' prefix like eg. 'erole'
|
* @param string $prefix ='' prefix like eg. 'erole'
|
||||||
* @return array|boolean
|
* @return array|boolean
|
||||||
*/
|
*/
|
||||||
public function filemanager_replacements($id,$prefix='', &$content = null)
|
public function filemanager_replacements($id, $prefix = '', &$content = null)
|
||||||
{
|
{
|
||||||
$info = array();
|
$info = array();
|
||||||
$file = Vfs::lstat($id,true);
|
$file = Vfs::lstat($id, true);
|
||||||
|
|
||||||
$file['mtime'] = Api\DateTime::to($file['mtime']);
|
$file['mtime'] = Api\DateTime::to($file['mtime']);
|
||||||
$file['ctime'] = Api\DateTime::to($file['ctime']);
|
$file['ctime'] = Api\DateTime::to($file['ctime']);
|
||||||
|
|
||||||
$file['name'] = Vfs::basename($id);
|
$file['name'] = Vfs::basename($id);
|
||||||
$file['dir'] = ($dir = Vfs::dirname($id)) ? Vfs::decodePath($dir) : '';
|
$file['dir'] = ($dir = Vfs::dirname($id)) ? Vfs::decodePath($dir) : '';
|
||||||
$dirlist = explode('/',$file['dir']);
|
$dirlist = explode('/', $file['dir']);
|
||||||
$file['folder'] = array_pop($dirlist);
|
$file['folder'] = array_pop($dirlist);
|
||||||
$file['folder_file'] = $file['folder'] . '/'.$file['name'];
|
$file['folder_file'] = $file['folder'] . '/' . $file['name'];
|
||||||
$file['path'] = $id;
|
$file['path'] = $id;
|
||||||
$file['rel_path'] = str_replace($this->dir.'/', '', $id);
|
$file['rel_path'] = str_replace($this->dir . '/', '', $id);
|
||||||
$file['hsize'] = Vfs::hsize($file['size']);
|
$file['hsize'] = Vfs::hsize($file['size']);
|
||||||
$file['mime'] = Vfs::mime_content_type($id);
|
$file['mime'] = Vfs::mime_content_type($id);
|
||||||
$file['gid'] *= -1; // our widgets use negative gid's
|
$file['gid'] *= -1; // our widgets use negative gid's
|
||||||
if (($props = Vfs::propfind($id)))
|
if(($props = Vfs::propfind($id)))
|
||||||
{
|
{
|
||||||
foreach($props as $prop)
|
foreach($props as $prop)
|
||||||
{
|
{
|
||||||
$file[$prop['name']] = $prop['val'];
|
$file[$prop['name']] = $prop['val'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (($file['is_link'] = Vfs::is_link($id)))
|
if(($file['is_link'] = Vfs::is_link($id)))
|
||||||
{
|
{
|
||||||
$file['symlink'] = Vfs::readlink($id);
|
$file['symlink'] = Vfs::readlink($id);
|
||||||
}
|
}
|
||||||
@ -131,17 +130,17 @@ class filemanager_merge extends Api\Storage\Merge
|
|||||||
foreach(Api\Storage\Customfields::get('filemanager') as $name => $field)
|
foreach(Api\Storage\Customfields::get('filemanager') as $name => $field)
|
||||||
{
|
{
|
||||||
// Set any missing custom fields, or the marker will stay
|
// Set any missing custom fields, or the marker will stay
|
||||||
if(!$file['#'.$name])
|
if(!$file['#' . $name])
|
||||||
{
|
{
|
||||||
$file['#'.$name] = '';
|
$file['#' . $name] = '';
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format date cfs per user Api\Preferences
|
// Format date cfs per user Api\Preferences
|
||||||
if($field['type'] == 'date' || $field['type'] == 'date-time')
|
if($field['type'] == 'date' || $field['type'] == 'date-time')
|
||||||
{
|
{
|
||||||
$this->date_fields[] = '#'.$name;
|
$this->date_fields[] = '#' . $name;
|
||||||
$file['#'.$name] = Api\DateTime::to($file['#'.$name], $field['type'] == 'date' ? true : '');
|
$file['#' . $name] = Api\DateTime::to($file['#' . $name], $field['type'] == 'date' ? true : '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -150,17 +149,19 @@ class filemanager_merge extends Api\Storage\Merge
|
|||||||
if($dirlist[1] == 'apps' && count($dirlist) > 1)
|
if($dirlist[1] == 'apps' && count($dirlist) > 1)
|
||||||
{
|
{
|
||||||
// Try this first - a normal path /apps/appname/id/file
|
// Try this first - a normal path /apps/appname/id/file
|
||||||
list($app, $app_id) = explode('/', substr($file['path'], strpos($file['path'], 'apps/')+5));
|
list($app, $app_id) = explode('/', substr($file['path'], strpos($file['path'], 'apps/') + 5));
|
||||||
// Symlink?
|
// Symlink?
|
||||||
if(!$app || !(int)$app_id || !array_key_exists($app, $GLOBALS['egw_info']['user']['apps'])) {
|
if(!$app || !(int)$app_id || !array_key_exists($app, $GLOBALS['egw_info']['user']['apps']))
|
||||||
|
{
|
||||||
// Try resolving just app + ID - /apps/App Name/Record Title/file
|
// Try resolving just app + ID - /apps/App Name/Record Title/file
|
||||||
$resolved = Vfs::resolve_url_symlinks(implode('/',array_slice(explode('/',$file['dir']),0,4)));
|
$resolved = Vfs::resolve_url_symlinks(implode('/', array_slice(explode('/', $file['dir']), 0, 4)));
|
||||||
list($app, $app_id) = explode('/', substr($resolved, strpos($resolved, 'apps/')+5));
|
list($app, $app_id) = explode('/', substr($resolved, strpos($resolved, 'apps/') + 5));
|
||||||
|
|
||||||
if(!$app || !(int)$app_id || !array_key_exists($app, $GLOBALS['egw_info']['user']['apps'])) {
|
if(!$app || !(int)$app_id || !array_key_exists($app, $GLOBALS['egw_info']['user']['apps']))
|
||||||
|
{
|
||||||
// Get rid of any virtual folders (eg: All$) and symlinks
|
// Get rid of any virtual folders (eg: All$) and symlinks
|
||||||
$resolved = Vfs::resolve_url_symlinks($file['path']);
|
$resolved = Vfs::resolve_url_symlinks($file['path']);
|
||||||
list($app, $app_id) = explode('/', substr($resolved, strpos($resolved, 'apps/')+5));
|
list($app, $app_id) = explode('/', substr($resolved, strpos($resolved, 'apps/') + 5));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if($app && $app_id)
|
if($app && $app_id)
|
||||||
@ -170,7 +171,7 @@ class filemanager_merge extends Api\Storage\Merge
|
|||||||
$app_merge = null;
|
$app_merge = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$classname = $app .'_merge';
|
$classname = $app . '_merge';
|
||||||
if(class_exists($classname))
|
if(class_exists($classname))
|
||||||
{
|
{
|
||||||
$app_merge = new $classname();
|
$app_merge = new $classname();
|
||||||
@ -181,7 +182,8 @@ class filemanager_merge extends Api\Storage\Merge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Silently discard & continue
|
// Silently discard & continue
|
||||||
catch(Exception $e) {
|
catch (Exception $e)
|
||||||
|
{
|
||||||
unset($e); // not used
|
unset($e); // not used
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -211,7 +213,7 @@ class filemanager_merge extends Api\Storage\Merge
|
|||||||
foreach($file as $key => &$value)
|
foreach($file as $key => &$value)
|
||||||
{
|
{
|
||||||
if(!$value) $value = '';
|
if(!$value) $value = '';
|
||||||
$info['$$'.($prefix ? $prefix.'/':'').$key.'$$'] = $value;
|
$info['$$' . ($prefix ? $prefix . '/' : '') . $key . '$$'] = $value;
|
||||||
}
|
}
|
||||||
if($app_placeholders)
|
if($app_placeholders)
|
||||||
{
|
{
|
||||||
@ -239,14 +241,18 @@ class filemanager_merge extends Api\Storage\Merge
|
|||||||
{
|
{
|
||||||
return $session;
|
return $session;
|
||||||
}
|
}
|
||||||
else if (($session = \EGroupware\Api\Cache::getSession(Api\Sharing::class, "$app::$id")) &&
|
else
|
||||||
|
{
|
||||||
|
if(($session = \EGroupware\Api\Cache::getSession(Api\Sharing::class, "$app::$id")) &&
|
||||||
substr($session['share_path'], -strlen($path)) === $path)
|
substr($session['share_path'], -strlen($path)) === $path)
|
||||||
{
|
{
|
||||||
return $session;
|
return $session;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Need to create the share here.
|
// Need to create the share here.
|
||||||
// No way to know here if it should be writable, or who it's going to
|
// No way to know here if it should be writable, or who it's going to
|
||||||
$mode = /* ? ? Sharing::WRITABLE :*/ Api\Sharing::READONLY;
|
$mode = /* ? ? Sharing::WRITABLE :*/
|
||||||
|
Api\Sharing::READONLY;
|
||||||
$recipients = array();
|
$recipients = array();
|
||||||
$extra = array();
|
$extra = array();
|
||||||
|
|
||||||
@ -254,19 +260,27 @@ class filemanager_merge extends Api\Storage\Merge
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate table with replacements for the Api\Preferences
|
* Hook for extending apps to customise the replacements UI without having to override the whole method
|
||||||
*
|
*
|
||||||
|
* @param string $template_name
|
||||||
|
* @param $content
|
||||||
|
* @param $sel_options
|
||||||
|
* @param $readonlys
|
||||||
*/
|
*/
|
||||||
public function show_replacements()
|
protected function show_replacements_hook(&$template_name, &$content, &$sel_options, &$readonlys)
|
||||||
{
|
{
|
||||||
$GLOBALS['egw_info']['flags']['app_header'] = lang('filemanager').' - '.lang('Replacements for inserting entries into documents');
|
$content['extra_template'] = 'filemanager.replacements';
|
||||||
$GLOBALS['egw_info']['flags']['nonavbar'] = false;
|
}
|
||||||
echo $GLOBALS['egw']->framework->header();
|
|
||||||
|
|
||||||
echo "<table width='90%' align='center'>\n";
|
/**
|
||||||
echo '<tr><td colspan="4"><h3>'.lang('Filemanager fields:')."</h3></td></tr>";
|
* Get a list of placeholders provided.
|
||||||
|
*
|
||||||
|
* Placeholders are grouped logically. Group key should have a user-friendly translation.
|
||||||
|
*/
|
||||||
|
public function get_placeholder_list($prefix = '')
|
||||||
|
{
|
||||||
|
$placeholders = parent::get_placeholder_list($prefix);
|
||||||
|
|
||||||
$n = 0;
|
|
||||||
$fields = array(
|
$fields = array(
|
||||||
'name' => 'name',
|
'name' => 'name',
|
||||||
'path' => 'Absolute path',
|
'path' => 'Absolute path',
|
||||||
@ -283,43 +297,22 @@ class filemanager_merge extends Api\Storage\Merge
|
|||||||
'hsize' => 'Size',
|
'hsize' => 'Size',
|
||||||
'size' => 'Size (in bytes)',
|
'size' => 'Size (in bytes)',
|
||||||
);
|
);
|
||||||
|
$group = 'placeholders';
|
||||||
foreach($fields as $name => $label)
|
foreach($fields as $name => $label)
|
||||||
{
|
{
|
||||||
if (!($n&1)) echo '<tr>';
|
$marker = $this->prefix($prefix, $name, '{');
|
||||||
echo '<td>{{'.$name.'}}</td><td>'.lang($label).'</td>';
|
if(!array_filter($placeholders, function ($a) use ($marker)
|
||||||
if ($n&1) echo "</tr>\n";
|
|
||||||
$n++;
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '<tr><td colspan="4"><h3>'.lang('Custom fields').":</h3></td></tr>";
|
|
||||||
foreach(Api\Storage\Customfields::get('filemanager') as $name => $field)
|
|
||||||
{
|
{
|
||||||
echo '<tr><td>{{#'.$name.'}}</td><td colspan="3">'.$field['label']."</td></tr>\n";
|
return array_key_exists($marker, $a);
|
||||||
}
|
}))
|
||||||
|
|
||||||
echo '<tr><td colspan="4"><h3>'.lang('Application fields').":</h3></td></tr>";
|
|
||||||
echo '<tr><td colspan="4">'.lang('For files linked to an application entry (inside /apps/appname/id/) the placeholders for that application are also available. See the specific application for a list of available placeholders.').'</td></tr>';
|
|
||||||
|
|
||||||
echo '<tr><td colspan="4"><h3>'.lang('General fields:')."</h3></td></tr>";
|
|
||||||
foreach(array(
|
|
||||||
'date' => lang('Date'),
|
|
||||||
'user/n_fn' => lang('Name of current user, all other contact fields are valid too'),
|
|
||||||
'user/account_lid' => lang('Username'),
|
|
||||||
'pagerepeat' => lang('For serial letter use this tag. Put the content, you want to repeat between two Tags.'),
|
|
||||||
'label' => lang('Use this tag for addresslabels. Put the content, you want to repeat, between two tags.'),
|
|
||||||
'labelplacement' => lang('Tag to mark positions for address labels'),
|
|
||||||
'IF fieldname' => lang('Example {{IF n_prefix~Mr~Hello Mr.~Hello Ms.}} - search the field "n_prefix", for "Mr", if found, write Hello Mr., else write Hello Ms.'),
|
|
||||||
'NELF' => lang('Example {{NELF role}} - if field role is not empty, you will get a new line with the value of field role'),
|
|
||||||
'NENVLF' => lang('Example {{NENVLF role}} - if field role is not empty, set a LF without any value of the field'),
|
|
||||||
'LETTERPREFIX' => lang('Example {{LETTERPREFIX}} - Gives a letter prefix without double spaces, if the title is empty for example'),
|
|
||||||
'LETTERPREFIXCUSTOM' => lang('Example {{LETTERPREFIXCUSTOM n_prefix title n_family}} - Example: Mr Dr. James Miller'),
|
|
||||||
) as $name => $label)
|
|
||||||
{
|
{
|
||||||
echo '<tr><td>{{'.$name.'}}</td><td colspan="3">'.$label."</td></tr>\n";
|
$placeholders[$group][] = [
|
||||||
|
'value' => $marker,
|
||||||
|
'label' => $label
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "</table>\n";
|
return $placeholders;
|
||||||
|
|
||||||
echo $GLOBALS['egw']->framework->footer();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -684,7 +684,7 @@ class filemanager_ui
|
|||||||
*/
|
*/
|
||||||
static public function action($action,$selected,$dir=null,&$errs=null,&$files=null,&$dirs=null)
|
static public function action($action,$selected,$dir=null,&$errs=null,&$files=null,&$dirs=null)
|
||||||
{
|
{
|
||||||
if (!count($selected))
|
if (!count((array)$selected))
|
||||||
{
|
{
|
||||||
return lang('You need to select some files first!');
|
return lang('You need to select some files first!');
|
||||||
}
|
}
|
||||||
|
12
filemanager/templates/default/replacements.xet
Normal file
12
filemanager/templates/default/replacements.xet
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE overlay PUBLIC "-//EGroupware GmbH//eTemplate 2//EN" "http://www.egroupware.org/etemplate2.dtd">
|
||||||
|
<!-- This template adds the extra bits to the replacements list UI -->
|
||||||
|
<overlay>
|
||||||
|
<template id="filemanager.replacements">
|
||||||
|
<vbox>
|
||||||
|
<description class="title" value="Application fields"/>
|
||||||
|
<description
|
||||||
|
value="For files linked to an application entry (inside /apps/appname/id/) the placeholders for that application are also available. See the specific application for a list of available placeholders."/>
|
||||||
|
</vbox>
|
||||||
|
</template>
|
||||||
|
</overlay>
|
@ -126,7 +126,10 @@ class importexport_definitions_bo {
|
|||||||
$definition = $this->read($key);
|
$definition = $this->read($key);
|
||||||
if($definition['owner'] && $definition['owner'] == $GLOBALS['egw_info']['user']['account_id'] || $GLOBALS['egw_info']['user']['apps']['admin']) {
|
if($definition['owner'] && $definition['owner'] == $GLOBALS['egw_info']['user']['account_id'] || $GLOBALS['egw_info']['user']['apps']['admin']) {
|
||||||
// clear private cache
|
// clear private cache
|
||||||
unset($this->definitions[array_search($key,$this->definitions)]);
|
if(is_array($this->definitions))
|
||||||
|
{
|
||||||
|
unset($this->definitions[array_search($key, $this->definitions)]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
unset($keys[$index]);
|
unset($keys[$index]);
|
||||||
}
|
}
|
||||||
|
@ -279,7 +279,7 @@ class importexport_export_csv implements importexport_iface_export_record
|
|||||||
}
|
}
|
||||||
// Fall through for other settings
|
// Fall through for other settings
|
||||||
case 'select':
|
case 'select':
|
||||||
if (count($c_field['values']) == 1 && isset($c_field['values']['@']))
|
if (!empty($c_field['values']) && count($c_field['values']) == 1 && isset($c_field['values']['@']))
|
||||||
{
|
{
|
||||||
$c_field['values'] = Api\Storage\Customfields::get_options_from_file($c_field['values']['@']);
|
$c_field['values'] = Api\Storage\Customfields::get_options_from_file($c_field['values']['@']);
|
||||||
}
|
}
|
||||||
|
@ -183,18 +183,27 @@ class importexport_wizard_basic_export_csv
|
|||||||
$content['step'] = 'wizard_step40';
|
$content['step'] = 'wizard_step40';
|
||||||
|
|
||||||
// If editing an existing definition, these will be in plugin_options
|
// If editing an existing definition, these will be in plugin_options
|
||||||
if(!$content['delimiter'] && $content['plugin_options']['delimiter']) {
|
if(!$content['delimiter'] && $content['plugin_options']['delimiter'])
|
||||||
|
{
|
||||||
$content['delimiter'] = $content['plugin_options']['delimiter'];
|
$content['delimiter'] = $content['plugin_options']['delimiter'];
|
||||||
} elseif (!$content['delimiter']) {
|
}
|
||||||
|
elseif(!$content['delimiter'])
|
||||||
|
{
|
||||||
$content['delimiter'] = ';';
|
$content['delimiter'] = ';';
|
||||||
}
|
}
|
||||||
if(!$content['charset'] && $content['plugin_options']['charset']) {
|
if(!$content['charset'] && $content['plugin_options']['charset'])
|
||||||
|
{
|
||||||
$content['charset'] = $content['plugin_options']['charset'] ? $content['plugin_options']['charset'] : 'user';
|
$content['charset'] = $content['plugin_options']['charset'] ? $content['plugin_options']['charset'] : 'user';
|
||||||
}
|
}
|
||||||
if(!array_key_exists('begin_with_fieldnames', $content) && array_key_exists('begin_with_fieldnames', $content['plugin_options'])) {
|
if(!array_key_exists('begin_with_fieldnames', $content) &&
|
||||||
|
is_array($content['plugin_options']) &&
|
||||||
|
array_key_exists('begin_with_fieldnames', $content['plugin_options']))
|
||||||
|
{
|
||||||
$content['begin_with_fieldnames'] = $content['plugin_options']['begin_with_fieldnames'];
|
$content['begin_with_fieldnames'] = $content['plugin_options']['begin_with_fieldnames'];
|
||||||
}
|
}
|
||||||
if(!array_key_exists('convert', $content) && array_key_exists('convert', $content['plugin_options'])) {
|
if(!array_key_exists('convert', $content) &&
|
||||||
|
is_array($content['plugin_options']) && array_key_exists('convert', $content['plugin_options']))
|
||||||
|
{
|
||||||
$content['convert'] = $content['plugin_options']['convert'];
|
$content['convert'] = $content['plugin_options']['convert'];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +213,7 @@ class importexport_wizard_basic_export_csv
|
|||||||
1 => lang('Field names'),
|
1 => lang('Field names'),
|
||||||
'label' => lang('Field labels')
|
'label' => lang('Field labels')
|
||||||
);
|
);
|
||||||
$sel_options['charset'] = Api\Translation::get_installed_charsets()+
|
$sel_options['charset'] = Api\Translation::get_installed_charsets() +
|
||||||
array(
|
array(
|
||||||
'user' => lang('User preference'),
|
'user' => lang('User preference'),
|
||||||
);
|
);
|
||||||
@ -273,13 +282,20 @@ class importexport_wizard_basic_export_csv
|
|||||||
unset ($preserv['button']);
|
unset ($preserv['button']);
|
||||||
|
|
||||||
$content['set_filter']['fields'] = importexport_helper_functions::get_filter_fields(
|
$content['set_filter']['fields'] = importexport_helper_functions::get_filter_fields(
|
||||||
$content['application'],$content['plugin'],$this
|
$content['application'], $content['plugin'], $this
|
||||||
);
|
);
|
||||||
// Load existing filter from either content or definition
|
// Load existing filter from either content or definition
|
||||||
|
if(!array_key_exists('filter', $content) || !is_array($content['filter']))
|
||||||
|
{
|
||||||
|
$content['filter'] = [];
|
||||||
|
}
|
||||||
foreach($content['set_filter']['fields'] as $field => $settings)
|
foreach($content['set_filter']['fields'] as $field => $settings)
|
||||||
|
{
|
||||||
|
if(array_key_exists($field, $content['filter']))
|
||||||
{
|
{
|
||||||
$content['set_filter'][$field] = $content['filter'][$field];
|
$content['set_filter'][$field] = $content['filter'][$field];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(!$content['set_filter']['fields'])
|
if(!$content['set_filter']['fields'])
|
||||||
{
|
{
|
||||||
|
@ -228,7 +228,7 @@ class infolog_bo
|
|||||||
{
|
{
|
||||||
foreach(array_keys($config_data['status']) as $key)
|
foreach(array_keys($config_data['status']) as $key)
|
||||||
{
|
{
|
||||||
if (!is_array($this->status[$key]))
|
if (!isset($this->status[$key]) || !is_array($this->status[$key]))
|
||||||
{
|
{
|
||||||
$this->status[$key] = array();
|
$this->status[$key] = array();
|
||||||
}
|
}
|
||||||
@ -262,17 +262,17 @@ class infolog_bo
|
|||||||
$save_config = true;
|
$save_config = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($save_config) Api\Config::save_value('customfields',$this->customfields,'infolog');
|
if (!empty($save_config)) Api\Config::save_value('customfields',$this->customfields,'infolog');
|
||||||
}
|
}
|
||||||
if (is_array($config_data['responsible_edit']))
|
if (isset($config_data['responsible_edit']) && is_array($config_data['responsible_edit']))
|
||||||
{
|
{
|
||||||
$this->responsible_edit = array_merge($this->responsible_edit,$config_data['responsible_edit']);
|
$this->responsible_edit = array_merge($this->responsible_edit,$config_data['responsible_edit']);
|
||||||
}
|
}
|
||||||
if (is_array($config_data['copy_excludefields']))
|
if (isset($config_data['copy_excludefields']) && is_array($config_data['copy_excludefields']))
|
||||||
{
|
{
|
||||||
$this->copy_excludefields = array_merge($this->copy_excludefields,$config_data['copy_excludefields']);
|
$this->copy_excludefields = array_merge($this->copy_excludefields,$config_data['copy_excludefields']);
|
||||||
}
|
}
|
||||||
if (is_array($config_data['sub_excludefields']) && $config_data['sub_excludefields'])
|
if (!empty($config_data['sub_excludefields']) && is_array($config_data['sub_excludefields']))
|
||||||
{
|
{
|
||||||
$this->sub_excludefields = array_merge($this->sub_excludefields,$config_data['sub_excludefields']);
|
$this->sub_excludefields = array_merge($this->sub_excludefields,$config_data['sub_excludefields']);
|
||||||
}
|
}
|
||||||
@ -286,7 +286,7 @@ class infolog_bo
|
|||||||
}
|
}
|
||||||
$this->history = $config_data['history'];
|
$this->history = $config_data['history'];
|
||||||
|
|
||||||
$this->limit_modified_n_month = $config_data['limit_modified_n_month'];
|
$this->limit_modified_n_month = $config_data['limit_modified_n_month'] ?? null;
|
||||||
}
|
}
|
||||||
// sort types by there translation
|
// sort types by there translation
|
||||||
foreach($this->enums['type'] as $key => $val)
|
foreach($this->enums['type'] as $key => $val)
|
||||||
@ -629,12 +629,14 @@ class infolog_bo
|
|||||||
|
|
||||||
if (!$info_id || ($data = $this->so->read($info_id)) === False)
|
if (!$info_id || ($data = $this->so->read($info_id)) === False)
|
||||||
{
|
{
|
||||||
return null;
|
$null = null;
|
||||||
|
return $null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$ignore_acl && !$this->check_access($data,Acl::READ)) // check behind read, to prevent a double read
|
if (!$ignore_acl && !$this->check_access($data,Acl::READ)) // check behind read, to prevent a double read
|
||||||
{
|
{
|
||||||
return False;
|
$false = False;
|
||||||
|
return $false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($data['info_subject'] == $this->subject_from_des($data['info_des']))
|
if ($data['info_subject'] == $this->subject_from_des($data['info_des']))
|
||||||
@ -1092,10 +1094,14 @@ class infolog_bo
|
|||||||
* Checks for info_contact properly linked, project properly linked and
|
* Checks for info_contact properly linked, project properly linked and
|
||||||
* adds or removes to correct.
|
* adds or removes to correct.
|
||||||
*
|
*
|
||||||
* @param Array $values
|
* @param array $values
|
||||||
*/
|
*/
|
||||||
protected function write_check_links(&$values)
|
protected function write_check_links(array &$values)
|
||||||
{
|
{
|
||||||
|
if(!$this->check_access($values, Acl::EDIT))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
$old_link_id = (int)$values['info_link_id'];
|
$old_link_id = (int)$values['info_link_id'];
|
||||||
$from = $values['info_from'];
|
$from = $values['info_from'];
|
||||||
|
|
||||||
@ -1113,7 +1119,7 @@ class infolog_bo
|
|||||||
$id = (int)$values['info_contact']['id'];
|
$id = (int)$values['info_contact']['id'];
|
||||||
$from = $values['info_contact']['search'];
|
$from = $values['info_contact']['search'];
|
||||||
}
|
}
|
||||||
else if ($values['info_contact'])
|
else if($values['info_contact'])
|
||||||
{
|
{
|
||||||
list($app, $id) = explode(':', $values['info_contact'], 2);
|
list($app, $id) = explode(':', $values['info_contact'], 2);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* eGroupWare - Infolog - importexport
|
* EGroupware - InfoLog - importexport
|
||||||
*
|
*
|
||||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
* @package infolog
|
* @package infolog
|
||||||
@ -8,13 +8,12 @@
|
|||||||
* @link http://www.egroupware.org
|
* @link http://www.egroupware.org
|
||||||
* @author Nathan Gray
|
* @author Nathan Gray
|
||||||
* @copyright Nathan Gray
|
* @copyright Nathan Gray
|
||||||
* @version $Id$
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class infolog_egw_record
|
* class infolog_egw_record
|
||||||
*
|
*
|
||||||
* compability layer for iface_egw_record needet for importexport
|
* compatibility layer for iface_egw_record needed for importexport
|
||||||
*/
|
*/
|
||||||
class infolog_egw_record implements importexport_iface_egw_record
|
class infolog_egw_record implements importexport_iface_egw_record
|
||||||
{
|
{
|
||||||
@ -53,7 +52,7 @@ class infolog_egw_record implements importexport_iface_egw_record
|
|||||||
* @param string $_attribute_name
|
* @param string $_attribute_name
|
||||||
*/
|
*/
|
||||||
public function __get($_attribute_name) {
|
public function __get($_attribute_name) {
|
||||||
return $this->record[$_attribute_name];
|
return $this->record[$_attribute_name] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -458,41 +458,8 @@ class infolog_hooks
|
|||||||
// Merge print
|
// Merge print
|
||||||
if ($GLOBALS['egw_info']['user']['apps']['filemanager'])
|
if ($GLOBALS['egw_info']['user']['apps']['filemanager'])
|
||||||
{
|
{
|
||||||
$settings['default_document'] = array(
|
$merge = new infolog_merge();
|
||||||
'type' => 'vfs_file',
|
$settings += $merge->merge_preferences();
|
||||||
'size' => 60,
|
|
||||||
'label' => 'Default document to insert entries',
|
|
||||||
'name' => 'default_document',
|
|
||||||
'help' => lang('If you specify a document (full vfs path) here, %1 displays an extra document icon for each entry. That icon allows to download the specified document with the data inserted.',lang('infolog')).' '.
|
|
||||||
lang('The document can contain placeholder like {{%1}}, to be replaced with the data.','info_subject').' '.
|
|
||||||
lang('The following document-types are supported:').'*.rtf, *.txt',
|
|
||||||
'run_lang' => false,
|
|
||||||
'xmlrpc' => True,
|
|
||||||
'admin' => False,
|
|
||||||
);
|
|
||||||
$settings['document_dir'] = array(
|
|
||||||
'type' => 'vfs_dirs',
|
|
||||||
'size' => 60,
|
|
||||||
'label' => 'Directory with documents to insert entries',
|
|
||||||
'name' => 'document_dir',
|
|
||||||
'help' => lang('If you specify a directory (full vfs path) here, %1 displays an action for each document. That action allows to download the specified document with the data inserted.', lang('infolog')) . ' ' .
|
|
||||||
lang('The document can contain placeholder like {{%1}}, to be replaced with the data.', 'info_subject') . ' ' .
|
|
||||||
lang('The following document-types are supported:') . '*.rtf, *.txt',
|
|
||||||
'run_lang' => false,
|
|
||||||
'xmlrpc' => True,
|
|
||||||
'admin' => False,
|
|
||||||
'default' => '/templates/infolog',
|
|
||||||
);
|
|
||||||
$settings[Api\Storage\Merge::PREF_DOCUMENT_FILENAME] = array(
|
|
||||||
'type' => 'taglist',
|
|
||||||
'label' => 'Document download filename',
|
|
||||||
'name' => 'document_download_name',
|
|
||||||
'values' => Api\Storage\Merge::DOCUMENT_FILENAME_OPTIONS,
|
|
||||||
'help' => 'Choose the default filename for downloaded documents.',
|
|
||||||
'xmlrpc' => True,
|
|
||||||
'admin' => False,
|
|
||||||
'default' => 'document',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($GLOBALS['egw_info']['user']['apps']['calendar'])
|
if ($GLOBALS['egw_info']['user']['apps']['calendar'])
|
||||||
|
@ -138,7 +138,7 @@ class infolog_merge extends Api\Storage\Merge
|
|||||||
// Set any missing custom fields, or the marker will stay
|
// Set any missing custom fields, or the marker will stay
|
||||||
foreach($this->bo->customfields as $name => $field)
|
foreach($this->bo->customfields as $name => $field)
|
||||||
{
|
{
|
||||||
if(!$array['#'.$name])
|
if (empty($array['#'.$name]))
|
||||||
{
|
{
|
||||||
$array['#'.$name] = '';
|
$array['#'.$name] = '';
|
||||||
}
|
}
|
||||||
@ -183,9 +183,9 @@ class infolog_merge extends Api\Storage\Merge
|
|||||||
$info += $this->get_all_links('infolog', $id, $prefix, $content);
|
$info += $this->get_all_links('infolog', $id, $prefix, $content);
|
||||||
|
|
||||||
// Add contact fields
|
// Add contact fields
|
||||||
if($array['info_link'] && $array['info_link']['app'] && $array['info_link']['id'])
|
if($array['info_link'] && is_array($array['info_link']) && $array['info_link']['app'] && $array['info_link']['id'])
|
||||||
{
|
{
|
||||||
$info+=$this->get_app_replacements($array['info_link']['app'], $array['info_link']['id'], $content, 'info_contact');
|
$info += $this->get_app_replacements($array['info_link']['app'], $array['info_link']['id'], $content, 'info_contact');
|
||||||
}
|
}
|
||||||
// Add owner fields
|
// Add owner fields
|
||||||
$info += $this->contact_replacements(Api\Accounts::id2name($info_owner,'person_id'),'info_owner');
|
$info += $this->contact_replacements(Api\Accounts::id2name($info_owner,'person_id'),'info_owner');
|
||||||
@ -198,98 +198,20 @@ class infolog_merge extends Api\Storage\Merge
|
|||||||
return $info;
|
return $info;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate table with replacements for the Api\Preferences
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public function show_replacements()
|
|
||||||
{
|
|
||||||
$GLOBALS['egw_info']['flags']['app_header'] = lang('infolog').' - '.lang('Replacements for inserting entries into documents');
|
|
||||||
$GLOBALS['egw_info']['flags']['nonavbar'] = false;
|
|
||||||
echo $GLOBALS['egw']->framework->header();
|
|
||||||
|
|
||||||
echo "<table width='90%' align='center'>\n";
|
|
||||||
echo '<tr><td colspan="4"><h3>'.lang('Infolog fields:')."</h3></td></tr>";
|
|
||||||
|
|
||||||
$n = 0;
|
|
||||||
$tracking = new infolog_tracking($this->bo);
|
|
||||||
$fields = array('info_id' => lang('Infolog ID'), 'pm_id' => lang('Project ID'), 'project' => lang('Project name')) + $tracking->field2label + array('info_sum_timesheets' => lang('Used time'));
|
|
||||||
Api\Translation::add_app('projectmanager');
|
|
||||||
foreach($fields as $name => $label)
|
|
||||||
{
|
|
||||||
if (in_array($name,array('custom'))) continue; // dont show them
|
|
||||||
|
|
||||||
if (in_array($name,array('info_subject', 'info_des')) && $n&1) // main values, which should be in the first column
|
|
||||||
{
|
|
||||||
echo "</tr>\n";
|
|
||||||
$n++;
|
|
||||||
}
|
|
||||||
if (!($n&1)) echo '<tr>';
|
|
||||||
echo '<td>{{'.$name.'}}</td><td>'.lang($label).'</td>';
|
|
||||||
if ($n&1) echo "</tr>\n";
|
|
||||||
$n++;
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '<tr><td colspan="4"><h3>'.lang('Custom fields').":</h3></td></tr>";
|
|
||||||
$contact_custom = false;
|
|
||||||
foreach($this->bo->customfields as $name => $field)
|
|
||||||
{
|
|
||||||
echo '<tr><td>{{#'.$name.'}}</td><td colspan="3">'.$field['label'].($field['type'] == 'select-account' ? '*':'')."</td></tr>\n";
|
|
||||||
if($field['type'] == 'select-account') $contact_custom = true;
|
|
||||||
}
|
|
||||||
if($contact_custom)
|
|
||||||
{
|
|
||||||
echo '<tr><td /><td colspan="3">* '.lang('Addressbook placeholders available'). '</td></tr>';
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '<tr><td colspan="4"><h3>'.lang('Parent').":</h3></td></tr>";
|
|
||||||
echo '<tr><td>{{info_id_parent/info_subject}}</td><td colspan="3">'.lang('All other %1 fields are valid',lang('infolog'))."</td></tr>\n";
|
|
||||||
|
|
||||||
echo '<tr><td colspan="4"><h3>'.lang('Contact fields').':</h3></td></tr>';
|
|
||||||
$i = 0;
|
|
||||||
foreach($this->contacts->contact_fields as $name => $label)
|
|
||||||
{
|
|
||||||
if (in_array($name,array('tid','label','geo'))) continue; // dont show them, as they are not used in the UI atm.
|
|
||||||
|
|
||||||
if (in_array($name,array('email','org_name','tel_work','url')) && $n&1) // main values, which should be in the first column
|
|
||||||
{
|
|
||||||
echo "</tr>\n";
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
if (!($i&1)) echo '<tr>';
|
|
||||||
echo '<td>{{info_contact/'.$name.'}}</td><td>'.$label.'</td>';
|
|
||||||
if ($i&1) echo "</tr>\n";
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
echo '<tr><td colspan="4">'.lang('Owner contact fields also available under info_owner/...').'</td></tr>';
|
|
||||||
|
|
||||||
echo '<tr><td colspan="4"><h3>'.lang('Custom fields').":</h3></td></tr>";
|
|
||||||
foreach($this->contacts->customfields as $name => $field)
|
|
||||||
{
|
|
||||||
echo '<tr><td>{{info_contact/#'.$name.'}}</td><td colspan="3">'.$field['label']."</td></tr>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '<tr><td colspan="4"><h3>' . lang('General fields:') . "</h3></td></tr>";
|
|
||||||
foreach($this->get_common_replacements() as $name => $label)
|
|
||||||
{
|
|
||||||
echo '<tr><td>{{' . $name . '}}</td><td colspan="3">' . $label . "</td></tr>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "</table>\n";
|
|
||||||
|
|
||||||
echo $GLOBALS['egw']->framework->footer();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function get_placeholder_list($prefix = '')
|
public function get_placeholder_list($prefix = '')
|
||||||
{
|
{
|
||||||
$placeholders = parent::get_placeholder_list($prefix);
|
|
||||||
|
|
||||||
$tracking = new infolog_tracking($this->bo);
|
$tracking = new infolog_tracking($this->bo);
|
||||||
|
$placeholders = array(
|
||||||
|
'infolog' => [],
|
||||||
|
lang('parent') => [],
|
||||||
|
lang($tracking->field2label['info_from']) => []
|
||||||
|
) + parent::get_placeholder_list($prefix);
|
||||||
|
|
||||||
$fields = array('info_id' => lang('Infolog ID'), 'pm_id' => lang('Project ID'),
|
$fields = array('info_id' => lang('Infolog ID'), 'pm_id' => lang('Project ID'),
|
||||||
'project' => lang('Project name')) + $tracking->field2label + array('info_sum_timesheets' => lang('Used time'));
|
'project' => lang('Project name')) + $tracking->field2label + array('info_sum_timesheets' => lang('Used time'));
|
||||||
Api\Translation::add_app('projectmanager');
|
Api\Translation::add_app('projectmanager');
|
||||||
|
|
||||||
$group = 'placeholders';
|
$group = 'infolog';
|
||||||
foreach($fields as $name => $label)
|
foreach($fields as $name => $label)
|
||||||
{
|
{
|
||||||
if(in_array($name, array('custom')))
|
if(in_array($name, array('custom')))
|
||||||
@ -310,15 +232,27 @@ class infolog_merge extends Api\Storage\Merge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't add any linked placeholders if we're not at the top level
|
||||||
|
// This avoids potential recursion
|
||||||
|
if(!$prefix)
|
||||||
|
{
|
||||||
// Add contact placeholders
|
// Add contact placeholders
|
||||||
$insert_index = 1;
|
|
||||||
$placeholders = array_slice($placeholders, 0, $insert_index, true) +
|
|
||||||
[lang($tracking->field2label['info_from']) => []] +
|
|
||||||
array_slice($placeholders, $insert_index, count($placeholders) - $insert_index, true);
|
|
||||||
$contact_merge = new Api\Contacts\Merge();
|
$contact_merge = new Api\Contacts\Merge();
|
||||||
$contact = $contact_merge->get_placeholder_list('info_contact');
|
$contact = $contact_merge->get_placeholder_list($this->prefix($prefix, 'info_contact'));
|
||||||
$this->add_linked_placeholders($placeholders, lang($tracking->field2label['info_from']), $contact);
|
$this->add_linked_placeholders($placeholders, lang($tracking->field2label['info_from']), $contact);
|
||||||
|
|
||||||
|
// Add parent placeholders
|
||||||
|
$this->add_linked_placeholders(
|
||||||
|
$placeholders,
|
||||||
|
lang('parent'),
|
||||||
|
$this->get_placeholder_list(($prefix ? $prefix . '/' : '') . 'info_id_parent')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unset($placeholders[lang('parent')]);
|
||||||
|
unset($placeholders[lang($tracking->field2label['info_from'])]);
|
||||||
|
}
|
||||||
return $placeholders;
|
return $placeholders;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ class infolog_tracking extends Api\Storage\Tracking
|
|||||||
*/
|
*/
|
||||||
function get_subject($data, $old, $deleted = null, $receiver = null)
|
function get_subject($data, $old, $deleted = null, $receiver = null)
|
||||||
{
|
{
|
||||||
if ($data['prefix'])
|
if (!empty($data['prefix']))
|
||||||
{
|
{
|
||||||
$prefix = $data['prefix']; // async notification
|
$prefix = $data['prefix']; // async notification
|
||||||
}
|
}
|
||||||
@ -172,7 +172,7 @@ class infolog_tracking extends Api\Storage\Tracking
|
|||||||
*/
|
*/
|
||||||
function get_message($data, $old, $receiver = null)
|
function get_message($data, $old, $receiver = null)
|
||||||
{
|
{
|
||||||
if ($data['message']) return $data['message']; // async notification
|
if (!empty($data['message'])) return $data['message']; // async notification
|
||||||
|
|
||||||
if (!$old || $old['info_status'] == 'deleted')
|
if (!$old || $old['info_status'] == 'deleted')
|
||||||
{
|
{
|
||||||
@ -345,16 +345,16 @@ class infolog_tracking extends Api\Storage\Tracking
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
// Per-type notification
|
// Per-type notification
|
||||||
$type_config = $info_config[self::CUSTOM_NOTIFICATION][$data['info_type']];
|
$type_config = $info_config[self::CUSTOM_NOTIFICATION][$data['info_type']] ?? null;
|
||||||
$global = $info_config[self::CUSTOM_NOTIFICATION]['~global~'];
|
$global = $info_config[self::CUSTOM_NOTIFICATION]['~global~'];
|
||||||
|
|
||||||
// Disabled
|
// Disabled
|
||||||
if(!$type_config['use_custom'] && !$global['use_custom']) return '';
|
if(empty($type_config['use_custom']) && empty($global['use_custom'])) return '';
|
||||||
|
|
||||||
// Type or globabl
|
// Type or global
|
||||||
$config = trim(strip_tags($type_config['message'])) != '' && $type_config['use_custom'] ? $type_config['message'] : $global['message'];
|
$config = trim(strip_tags($type_config['message'])) != '' && $type_config['use_custom'] ? $type_config['message'] : $global['message'];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return $config;
|
return $config ?? null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1874,7 +1874,7 @@ class infolog_ui
|
|||||||
|
|
||||||
$content['link_to']['to_app'] = 'infolog';
|
$content['link_to']['to_app'] = 'infolog';
|
||||||
$content['link_to']['to_id'] = $info_id;
|
$content['link_to']['to_id'] = $info_id;
|
||||||
|
/* $info_link_id is never defined
|
||||||
if ($info_link_id && strpos($info_link_id,':') !== false) // updating info_link_id if necessary
|
if ($info_link_id && strpos($info_link_id,':') !== false) // updating info_link_id if necessary
|
||||||
{
|
{
|
||||||
list($app,$id) = explode(':',$info_link_id);
|
list($app,$id) = explode(':',$info_link_id);
|
||||||
@ -1903,7 +1903,7 @@ class infolog_ui
|
|||||||
// we need eg. the new modification date, for further updates
|
// we need eg. the new modification date, for further updates
|
||||||
$content = array_merge($content,$to_write);
|
$content = array_merge($content,$to_write);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
// Need to purge description history after encryption?
|
// Need to purge description history after encryption?
|
||||||
if($content['clean_history'])
|
if($content['clean_history'])
|
||||||
@ -2115,7 +2115,7 @@ class infolog_ui
|
|||||||
// remove types owned by groups the user has no edit grant (current type is made readonly)
|
// remove types owned by groups the user has no edit grant (current type is made readonly)
|
||||||
foreach($this->bo->group_owners as $type => $group)
|
foreach($this->bo->group_owners as $type => $group)
|
||||||
{
|
{
|
||||||
if (!($this->bo->grants[$group] & Acl::EDIT))
|
if (!(($this->bo->grants[$group]??0) & Acl::EDIT))
|
||||||
{
|
{
|
||||||
if ($type == $content['info_type'])
|
if ($type == $content['info_type'])
|
||||||
{
|
{
|
||||||
@ -2172,7 +2172,7 @@ class infolog_ui
|
|||||||
$readonlys['action'] = true;
|
$readonlys['action'] = true;
|
||||||
}
|
}
|
||||||
// ToDo: use the old status before the delete
|
// ToDo: use the old status before the delete
|
||||||
if ($info_id && $undelete)
|
if ($info_id && !empty($undelete))
|
||||||
{
|
{
|
||||||
$content['info_status'] = $this->bo->status['defaults'][$content['info_type']];
|
$content['info_status'] = $this->bo->status['defaults'][$content['info_type']];
|
||||||
$this->tmpl->setElementAttribute('button[save]', 'label', 'Un-Delete');
|
$this->tmpl->setElementAttribute('button[save]', 'label', 'Un-Delete');
|
||||||
@ -2187,7 +2187,7 @@ class infolog_ui
|
|||||||
// use a typ-specific template (infolog.edit.xyz), if one exists, otherwise fall back to the generic one
|
// use a typ-specific template (infolog.edit.xyz), if one exists, otherwise fall back to the generic one
|
||||||
if (!$this->tmpl->read('infolog.edit.'.$content['info_type']))
|
if (!$this->tmpl->read('infolog.edit.'.$content['info_type']))
|
||||||
{
|
{
|
||||||
$this->tmpl->read($print ? 'infolog.edit.print':'infolog.edit');
|
$this->tmpl->read(!empty($print) ? 'infolog.edit.print' : 'infolog.edit');
|
||||||
}
|
}
|
||||||
if ($this->bo->has_customfields($content['info_type']))
|
if ($this->bo->has_customfields($content['info_type']))
|
||||||
{
|
{
|
||||||
@ -2252,7 +2252,7 @@ class infolog_ui
|
|||||||
$tracking = new infolog_tracking($this);
|
$tracking = new infolog_tracking($this);
|
||||||
foreach($tracking->field2history as $field => $history)
|
foreach($tracking->field2history as $field => $history)
|
||||||
{
|
{
|
||||||
$history_stati[$history] = $tracking->field2label[$field];
|
$history_stati[$history] = $tracking->field2label[$field] ?? null;
|
||||||
}
|
}
|
||||||
// Modified date removed from field2history, we don't need that in the history
|
// Modified date removed from field2history, we don't need that in the history
|
||||||
$history_stati['Mo'] = $tracking->field2label['info_datemodified'];
|
$history_stati['Mo'] = $tracking->field2label['info_datemodified'];
|
||||||
@ -2276,20 +2276,20 @@ class infolog_ui
|
|||||||
'to_tracker' => array('label' => 'Tracker', 'title' => 'Convert to a ticket'),
|
'to_tracker' => array('label' => 'Tracker', 'title' => 'Convert to a ticket'),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if ($GLOBALS['egw_info']['user']['apps']['calendar'])
|
if (!empty($GLOBALS['egw_info']['user']['apps']['calendar']))
|
||||||
{
|
{
|
||||||
$sel_options['action']['schedule'] = array('label' => 'Schedule', 'title' => 'Schedule appointment');
|
$sel_options['action']['schedule'] = array('label' => 'Schedule', 'title' => 'Schedule appointment');
|
||||||
}
|
}
|
||||||
if ($GLOBALS['egw_info']['user']['apps']['stylite'] && !$GLOBALS['egw_info']['server']['disable_pgp_encryption'])
|
if (!empty($GLOBALS['egw_info']['user']['apps']['stylite']) && empty($GLOBALS['egw_info']['server']['disable_pgp_encryption']))
|
||||||
{
|
{
|
||||||
$content['encryption_ts'] = filemtime(EGW_SERVER_ROOT.'/stylite/js/app.js');
|
$content['encryption_ts'] = filemtime(EGW_SERVER_ROOT.'/stylite/js/app.js');
|
||||||
}
|
}
|
||||||
elseif ($GLOBALS['egw_info']['server']['disable_pgp_encryption'])
|
elseif (!empty($GLOBALS['egw_info']['server']['disable_pgp_encryption']))
|
||||||
{
|
{
|
||||||
$readonlys['encrypt'] = true;
|
$readonlys['encrypt'] = true;
|
||||||
}
|
}
|
||||||
$GLOBALS['egw_info']['flags']['app_header'] = lang('InfoLog').' - '.
|
$GLOBALS['egw_info']['flags']['app_header'] = lang('InfoLog').' - '.
|
||||||
($content['status_only'] ? lang('Edit Status') : lang('Edit'));
|
(!empty($content['status_only']) ? lang('Edit Status') : lang('Edit'));
|
||||||
$GLOBALS['egw_info']['flags']['params']['manual'] = array('page' => ($info_id ? 'ManualInfologEdit' : 'ManualInfologAdd'));
|
$GLOBALS['egw_info']['flags']['params']['manual'] = array('page' => ($info_id ? 'ManualInfologEdit' : 'ManualInfologAdd'));
|
||||||
//error_log(substr($content['info_des'],1793,10));
|
//error_log(substr($content['info_des'],1793,10));
|
||||||
//$content['info_des'] = substr($content['info_des'],0,1793);
|
//$content['info_des'] = substr($content['info_des'],0,1793);
|
||||||
|
1
json.php
1
json.php
@ -60,6 +60,7 @@ function ajax_exception_handler($e)
|
|||||||
$response = Json\Response::get();
|
$response = Json\Response::get();
|
||||||
$message .= ($message ? "\n\n" : '').$e->getMessage();
|
$message .= ($message ? "\n\n" : '').$e->getMessage();
|
||||||
|
|
||||||
|
$message .= "\n\n".$e->getFile().' ('.$e->getLine().')';
|
||||||
// only show trace (incl. function arguments) if explicitly enabled, eg. on a development system
|
// only show trace (incl. function arguments) if explicitly enabled, eg. on a development system
|
||||||
if ($GLOBALS['egw_info']['server']['exception_show_trace'])
|
if ($GLOBALS['egw_info']['server']['exception_show_trace'])
|
||||||
{
|
{
|
||||||
|
@ -216,7 +216,7 @@ class mail_compose
|
|||||||
|
|
||||||
);
|
);
|
||||||
$acc_smime = Mail\Smime::get_acc_smime($content['mailaccount']);
|
$acc_smime = Mail\Smime::get_acc_smime($content['mailaccount']);
|
||||||
if ($acc_smime['acc_smime_password'])
|
if ($acc_smime && !empty($acc_smime['acc_smime_password']))
|
||||||
{
|
{
|
||||||
$actions = array_merge($actions, array(
|
$actions = array_merge($actions, array(
|
||||||
'smime_sign' => array (
|
'smime_sign' => array (
|
||||||
@ -271,9 +271,9 @@ class mail_compose
|
|||||||
}
|
}
|
||||||
unset($actions['pgp']);
|
unset($actions['pgp']);
|
||||||
}
|
}
|
||||||
if ($GLOBALS['egw_info']['server']['disable_pgp_encryption']) unset($actions['pgp']);
|
if (!empty($GLOBALS['egw_info']['server']['disable_pgp_encryption'])) unset($actions['pgp']);
|
||||||
// remove vfs actions if the user has no run access to filemanager
|
// remove vfs actions if the user has no run access to filemanager
|
||||||
if (!$GLOBALS['egw_info']['user']['apps']['filemanager'])
|
if (empty($GLOBALS['egw_info']['user']['apps']['filemanager']))
|
||||||
{
|
{
|
||||||
unset($actions['save2vfs']);
|
unset($actions['save2vfs']);
|
||||||
unset($actions['selectFromVFSForCompose']);
|
unset($actions['selectFromVFSForCompose']);
|
||||||
@ -1242,16 +1242,16 @@ class mail_compose
|
|||||||
// address stuff like from, to, cc, replyto
|
// address stuff like from, to, cc, replyto
|
||||||
$destinationRows = 0;
|
$destinationRows = 0;
|
||||||
foreach(self::$destinations as $destination) {
|
foreach(self::$destinations as $destination) {
|
||||||
if (!is_array($content[$destination]))
|
if (!empty($content[$destination]) && !is_array($content[$destination]))
|
||||||
{
|
{
|
||||||
if (!empty($content[$destination])) $content[$destination] = (array)$content[$destination];
|
$content[$destination] = (array)$content[$destination];
|
||||||
}
|
}
|
||||||
$addr_content = $content[strtolower($destination)];
|
$addr_content = $content[strtolower($destination)] ?? [];
|
||||||
// we clear the given address array and rebuild it
|
// we clear the given address array and rebuild it
|
||||||
unset($content[strtolower($destination)]);
|
unset($content[strtolower($destination)]);
|
||||||
foreach((array)$addr_content as $key => $value) {
|
foreach($addr_content as $value) {
|
||||||
if ($value=="NIL@NIL") continue;
|
if ($value === "NIL@NIL") continue;
|
||||||
if ($destination=='replyto' && str_replace('"','',$value) ==
|
if ($destination === 'replyto' && str_replace('"','',$value) ===
|
||||||
str_replace('"','',$identities[$this->mail_bo->getDefaultIdentity()]))
|
str_replace('"','',$identities[$this->mail_bo->getDefaultIdentity()]))
|
||||||
{
|
{
|
||||||
// preserve/restore the value to content.
|
// preserve/restore the value to content.
|
||||||
@ -1261,7 +1261,7 @@ class mail_compose
|
|||||||
//error_log(__METHOD__.__LINE__.array2string(array('key'=>$key,'value'=>$value)));
|
//error_log(__METHOD__.__LINE__.array2string(array('key'=>$key,'value'=>$value)));
|
||||||
$value = str_replace("\"\"",'"', htmlspecialchars_decode($value, ENT_COMPAT));
|
$value = str_replace("\"\"",'"', htmlspecialchars_decode($value, ENT_COMPAT));
|
||||||
foreach(Mail::parseAddressList($value) as $addressObject) {
|
foreach(Mail::parseAddressList($value) as $addressObject) {
|
||||||
if ($addressObject->host == '.SYNTAX-ERROR.') continue;
|
if ($addressObject->host === '.SYNTAX-ERROR.') continue;
|
||||||
$address = imap_rfc822_write_address($addressObject->mailbox,$addressObject->host,$addressObject->personal);
|
$address = imap_rfc822_write_address($addressObject->mailbox,$addressObject->host,$addressObject->personal);
|
||||||
//$address = Mail::htmlentities($address, $this->displayCharset);
|
//$address = Mail::htmlentities($address, $this->displayCharset);
|
||||||
$content[strtolower($destination)][]=$address;
|
$content[strtolower($destination)][]=$address;
|
||||||
@ -1289,7 +1289,7 @@ class mail_compose
|
|||||||
$content['mail_'.($content['mimeType'] == 'html'?'html':'plain').'text'] =$content['body'];
|
$content['mail_'.($content['mimeType'] == 'html'?'html':'plain').'text'] =$content['body'];
|
||||||
$content['showtempname']=0;
|
$content['showtempname']=0;
|
||||||
//if (is_array($content['attachments']))error_log(__METHOD__.__LINE__.'before merging content with uploadforCompose:'.array2string($content['attachments']));
|
//if (is_array($content['attachments']))error_log(__METHOD__.__LINE__.'before merging content with uploadforCompose:'.array2string($content['attachments']));
|
||||||
$content['attachments']=(is_array($content['attachments'])&&is_array($content['uploadForCompose'])?array_merge($content['attachments'],(!empty($content['uploadForCompose'])?$content['uploadForCompose']:array())):(is_array($content['uploadForCompose'])?$content['uploadForCompose']:(is_array($content['attachments'])?$content['attachments']:null)));
|
$content['attachments'] = array_merge($content['attachments'] ?? [], $content['uploadForCompose'] ?? []);
|
||||||
//if (is_array($content['attachments'])) foreach($content['attachments'] as $k => &$file) $file['delete['.$file['tmp_name'].']']=0;
|
//if (is_array($content['attachments'])) foreach($content['attachments'] as $k => &$file) $file['delete['.$file['tmp_name'].']']=0;
|
||||||
$content['no_griddata'] = empty($content['attachments']);
|
$content['no_griddata'] = empty($content['attachments']);
|
||||||
$preserv['attachments'] = $content['attachments'];
|
$preserv['attachments'] = $content['attachments'];
|
||||||
@ -1297,21 +1297,21 @@ class mail_compose
|
|||||||
|
|
||||||
//if (is_array($content['attachments']))error_log(__METHOD__.__LINE__.' Attachments:'.array2string($content['attachments']));
|
//if (is_array($content['attachments']))error_log(__METHOD__.__LINE__.' Attachments:'.array2string($content['attachments']));
|
||||||
// if no filemanager -> no vfsFileSelector
|
// if no filemanager -> no vfsFileSelector
|
||||||
if (!$GLOBALS['egw_info']['user']['apps']['filemanager'])
|
if (empty($GLOBALS['egw_info']['user']['apps']['filemanager']))
|
||||||
{
|
{
|
||||||
$content['vfsNotAvailable'] = "mail_DisplayNone";
|
$content['vfsNotAvailable'] = "mail_DisplayNone";
|
||||||
}
|
}
|
||||||
// if no infolog -> no save as infolog
|
// if no infolog -> no save as infolog
|
||||||
if (!$GLOBALS['egw_info']['user']['apps']['infolog'])
|
if (empty($GLOBALS['egw_info']['user']['apps']['infolog']))
|
||||||
{
|
{
|
||||||
$content['noInfologAvailable'] = "mail_DisplayNone";
|
$content['noInfologAvailable'] = "mail_DisplayNone";
|
||||||
}
|
}
|
||||||
// if no tracker -> no save as tracker
|
// if no tracker -> no save as tracker
|
||||||
if (!$GLOBALS['egw_info']['user']['apps']['tracker'])
|
if (empty($GLOBALS['egw_info']['user']['apps']['tracker']))
|
||||||
{
|
{
|
||||||
$content['noTrackerAvailable'] = "mail_DisplayNone";
|
$content['noTrackerAvailable'] = "mail_DisplayNone";
|
||||||
}
|
}
|
||||||
if (!$GLOBALS['egw_info']['user']['apps']['infolog'] && !$GLOBALS['egw_info']['user']['apps']['tracker'])
|
if (empty($GLOBALS['egw_info']['user']['apps']['infolog']) && empty($GLOBALS['egw_info']['user']['apps']['tracker']))
|
||||||
{
|
{
|
||||||
$content['noSaveAsAvailable'] = "mail_DisplayNone";
|
$content['noSaveAsAvailable'] = "mail_DisplayNone";
|
||||||
}
|
}
|
||||||
@ -1324,12 +1324,12 @@ class mail_compose
|
|||||||
$sel_options['mimeType'] = self::$mimeTypes;
|
$sel_options['mimeType'] = self::$mimeTypes;
|
||||||
$sel_options['priority'] = self::$priorities;
|
$sel_options['priority'] = self::$priorities;
|
||||||
$sel_options['filemode'] = Vfs\Sharing::$modes;
|
$sel_options['filemode'] = Vfs\Sharing::$modes;
|
||||||
if (!isset($content['priority']) || empty($content['priority'])) $content['priority']=3;
|
if (empty($content['priority'])) $content['priority']=3;
|
||||||
//$GLOBALS['egw_info']['flags']['currentapp'] = 'mail';//should not be needed
|
//$GLOBALS['egw_info']['flags']['currentapp'] = 'mail';//should not be needed
|
||||||
$etpl = new Etemplate('mail.compose');
|
$etpl = new Etemplate('mail.compose');
|
||||||
|
|
||||||
$etpl->setElementAttribute('composeToolbar', 'actions', self::getToolbarActions($content));
|
$etpl->setElementAttribute('composeToolbar', 'actions', self::getToolbarActions($content));
|
||||||
if ($content['mimeType']=='html')
|
if ($content['mimeType'] == 'html')
|
||||||
{
|
{
|
||||||
//mode="$cont[rtfEditorFeatures]" validation_rules="$cont[validation_rules]" base_href="$cont[upload_dir]"
|
//mode="$cont[rtfEditorFeatures]" validation_rules="$cont[validation_rules]" base_href="$cont[upload_dir]"
|
||||||
$_htmlConfig = Mail::$htmLawed_config;
|
$_htmlConfig = Mail::$htmLawed_config;
|
||||||
@ -1340,7 +1340,7 @@ class mail_compose
|
|||||||
Mail::$htmLawed_config = $_htmlConfig;
|
Mail::$htmLawed_config = $_htmlConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($content['composeID'])&&!empty($content['composeID']))
|
if (!empty($content['composeID']))
|
||||||
{
|
{
|
||||||
$composeCache = $content;
|
$composeCache = $content;
|
||||||
unset($composeCache['body']);
|
unset($composeCache['body']);
|
||||||
@ -1348,21 +1348,21 @@ class mail_compose
|
|||||||
unset($composeCache['mail_plaintext']);
|
unset($composeCache['mail_plaintext']);
|
||||||
Api\Cache::setCache(Api\Cache::SESSION,'mail','composeCache'.trim($GLOBALS['egw_info']['user']['account_id']).'_'.$this->composeID,$composeCache,$expiration=60*60*2);
|
Api\Cache::setCache(Api\Cache::SESSION,'mail','composeCache'.trim($GLOBALS['egw_info']['user']['account_id']).'_'.$this->composeID,$composeCache,$expiration=60*60*2);
|
||||||
}
|
}
|
||||||
if (!isset($_content['serverID'])||empty($_content['serverID']))
|
if (empty($_content['serverID']))
|
||||||
{
|
{
|
||||||
$content['serverID'] = $this->mail_bo->profileID;
|
$content['serverID'] = $this->mail_bo->profileID;
|
||||||
}
|
}
|
||||||
$preserv['serverID'] = $content['serverID'];
|
$preserv['serverID'] = $content['serverID'];
|
||||||
$preserv['lastDrafted'] = $content['lastDrafted'];
|
$preserv['lastDrafted'] = $content['lastDrafted'] ?? null;
|
||||||
$preserv['processedmail_id'] = $content['processedmail_id'];
|
$preserv['processedmail_id'] = $content['processedmail_id'] ?? null;
|
||||||
$preserv['references'] = $content['references'];
|
$preserv['references'] = $content['references'] ?? null;
|
||||||
$preserv['in-reply-to'] = $content['in-reply-to'];
|
$preserv['in-reply-to'] = $content['in-reply-to'] ?? null;
|
||||||
// thread-topic is a proprietary microsoft header and deprecated with the current version
|
// thread-topic is a proprietary microsoft header and deprecated with the current version
|
||||||
// horde does not support the encoding of thread-topic, and probably will not no so in the future
|
// horde does not support the encoding of thread-topic, and probably will not no so in the future
|
||||||
//$preserv['thread-topic'] = $content['thread-topic'];
|
//$preserv['thread-topic'] = $content['thread-topic'];
|
||||||
$preserv['thread-index'] = $content['thread-index'];
|
$preserv['thread-index'] = $content['thread-index'] ?? null;
|
||||||
$preserv['list-id'] = $content['list-id'];
|
$preserv['list-id'] = $content['list-id'] ?? null;
|
||||||
$preserv['mode'] = $content['mode'];
|
$preserv['mode'] = $content['mode'] ?? null;
|
||||||
// convert it back to checkbox expectations
|
// convert it back to checkbox expectations
|
||||||
if($content['mimeType'] == 'html') {
|
if($content['mimeType'] == 'html') {
|
||||||
$content['mimeType']=1;
|
$content['mimeType']=1;
|
||||||
@ -1391,11 +1391,11 @@ class mail_compose
|
|||||||
// Resolve distribution list before send content to client
|
// Resolve distribution list before send content to client
|
||||||
foreach(array('to', 'cc', 'bcc', 'replyto') as $f)
|
foreach(array('to', 'cc', 'bcc', 'replyto') as $f)
|
||||||
{
|
{
|
||||||
if (is_array($content[$f])) $content[$f]= self::resolveEmailAddressList ($content[$f]);
|
if (isset($content[$f]) && is_array($content[$f])) $content[$f]= self::resolveEmailAddressList ($content[$f]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set filemode icons for all attachments
|
// set filemode icons for all attachments
|
||||||
if($content['attachments'] && is_array($content['attachments']))
|
if(!empty($content['attachments']))
|
||||||
{
|
{
|
||||||
foreach($content['attachments'] as &$attach)
|
foreach($content['attachments'] as &$attach)
|
||||||
{
|
{
|
||||||
@ -1407,9 +1407,9 @@ class mail_compose
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$content['to'] = self::resolveEmailAddressList($content['to']);
|
if (isset($content['to'])) $content['to'] = self::resolveEmailAddressList($content['to']);
|
||||||
$content['html_toolbar'] = empty(Mail::$mailConfig['html_toolbar']) ?
|
$content['html_toolbar'] = empty(Mail::$mailConfig['html_toolbar']) ?
|
||||||
join(',', Etemplate\Widget\HtmlArea::$toolbar_default_list) : join(',', Mail::$mailConfig['html_toolbar']);
|
implode(',', Etemplate\Widget\HtmlArea::$toolbar_default_list) : implode(',', Mail::$mailConfig['html_toolbar']);
|
||||||
//error_log(__METHOD__.__LINE__.array2string($content));
|
//error_log(__METHOD__.__LINE__.array2string($content));
|
||||||
$etpl->exec('mail.mail_compose.compose',$content,$sel_options,array(),$preserv,2);
|
$etpl->exec('mail.mail_compose.compose',$content,$sel_options,array(),$preserv,2);
|
||||||
}
|
}
|
||||||
@ -2022,7 +2022,7 @@ class mail_compose
|
|||||||
'size' => $_size,
|
'size' => $_size,
|
||||||
'folder' => $_folder,
|
'folder' => $_folder,
|
||||||
'winmailFlag' => $_is_winmail,
|
'winmailFlag' => $_is_winmail,
|
||||||
'tmp_name' => mail_ui::generateRowID($this->mail_bo->profileID, $_folder, $_uid).'_'.(!empty($_partID)?$_partID:count($this->sessionData['attachments'])+1),
|
'tmp_name' => mail_ui::generateRowID($this->mail_bo->profileID, $_folder, $_uid).'_'.(!empty($_partID)?$_partID:count($this->sessionData['attachments'] ?? [])+1),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2485,7 +2485,7 @@ class mail_compose
|
|||||||
if(!empty($_formData['list-id'])) {
|
if(!empty($_formData['list-id'])) {
|
||||||
$_mailObject->addHeader('List-Id', $_formData['list-id']);
|
$_mailObject->addHeader('List-Id', $_formData['list-id']);
|
||||||
}
|
}
|
||||||
if($_formData['disposition']=='on') {
|
if(isset($_formData['disposition']) && $_formData['disposition'] === 'on') {
|
||||||
$_mailObject->addHeader('Disposition-Notification-To', $_identity['ident_email']);
|
$_mailObject->addHeader('Disposition-Notification-To', $_identity['ident_email']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2522,6 +2522,8 @@ class mail_compose
|
|||||||
if ($_formData['attachments'] && $_formData['filemode'] != Vfs\Sharing::ATTACH && !$_autosaving)
|
if ($_formData['attachments'] && $_formData['filemode'] != Vfs\Sharing::ATTACH && !$_autosaving)
|
||||||
{
|
{
|
||||||
$attachment_links = $this->_getAttachmentLinks($_formData['attachments'], $_formData['filemode'],
|
$attachment_links = $this->_getAttachmentLinks($_formData['attachments'], $_formData['filemode'],
|
||||||
|
// @TODO: $content['mimeType'] could type string/boolean. At the moment we can't strictly check them :(.
|
||||||
|
// @TODO: This needs to be fixed in compose function to get the right type from the content.
|
||||||
$_formData['mimeType'] == 'html',
|
$_formData['mimeType'] == 'html',
|
||||||
array_unique(array_merge((array)$_formData['to'], (array)$_formData['cc'], (array)$_formData['bcc'])),
|
array_unique(array_merge((array)$_formData['to'], (array)$_formData['cc'], (array)$_formData['bcc'])),
|
||||||
$_formData['expiration'], $_formData['password']);
|
$_formData['expiration'], $_formData['password']);
|
||||||
@ -2530,7 +2532,7 @@ class mail_compose
|
|||||||
{
|
{
|
||||||
case 'html':
|
case 'html':
|
||||||
$body = $_formData['body'];
|
$body = $_formData['body'];
|
||||||
if ($attachment_links)
|
if (!empty($attachment_links))
|
||||||
{
|
{
|
||||||
if (strpos($body, '<!-- HTMLSIGBEGIN -->') !== false)
|
if (strpos($body, '<!-- HTMLSIGBEGIN -->') !== false)
|
||||||
{
|
{
|
||||||
@ -2567,7 +2569,7 @@ class mail_compose
|
|||||||
default:
|
default:
|
||||||
$body = $this->convertHTMLToText($_formData['body'],false, false, true, true);
|
$body = $this->convertHTMLToText($_formData['body'],false, false, true, true);
|
||||||
|
|
||||||
if ($attachment_links) $body .= $attachment_links;
|
if (!empty($attachment_links)) $body .= $attachment_links;
|
||||||
|
|
||||||
#$_mailObject->Body = $_formData['body'];
|
#$_mailObject->Body = $_formData['body'];
|
||||||
if(!empty($signature)) {
|
if(!empty($signature)) {
|
||||||
@ -2653,7 +2655,7 @@ class mail_compose
|
|||||||
}
|
}
|
||||||
if ($connection_opened) $mail_bo->closeConnection();
|
if ($connection_opened) $mail_bo->closeConnection();
|
||||||
}
|
}
|
||||||
return is_array($inline_images)?$inline_images:array();
|
return $inline_images ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2761,7 +2763,7 @@ class mail_compose
|
|||||||
$dmailbox = $dhA['folder'];
|
$dmailbox = $dhA['folder'];
|
||||||
// beware: do not delete the original mail as found in processedmail_id
|
// beware: do not delete the original mail as found in processedmail_id
|
||||||
$pMuid='';
|
$pMuid='';
|
||||||
if ($content['processedmail_id'])
|
if (!empty($content['processedmail_id']))
|
||||||
{
|
{
|
||||||
$pMhA = mail_ui::splitRowID($content['processedmail_id']);
|
$pMhA = mail_ui::splitRowID($content['processedmail_id']);
|
||||||
$pMuid = $pMhA['msgUID'];
|
$pMuid = $pMhA['msgUID'];
|
||||||
@ -3021,7 +3023,7 @@ class mail_compose
|
|||||||
// create the messages and store inline images
|
// create the messages and store inline images
|
||||||
$inline_images = $this->createMessage($mail, $_formData, $identity);
|
$inline_images = $this->createMessage($mail, $_formData, $identity);
|
||||||
// remember the identity
|
// remember the identity
|
||||||
if ($_formData['to_infolog'] == 'on' || $_formData['to_tracker'] == 'on') $fromAddress = $mail->From;//$mail->FromName.($mail->FromName?' <':'').$mail->From.($mail->FromName?'>':'');
|
if (!empty($mail->From) && ($_formData['to_infolog'] == 'on' || $_formData['to_tracker'] == 'on')) $fromAddress = $mail->From;//$mail->FromName.($mail->FromName?' <':'').$mail->From.($mail->FromName?'>':'');
|
||||||
#print "<pre>". $mail->getMessageHeader() ."</pre><hr><br>";
|
#print "<pre>". $mail->getMessageHeader() ."</pre><hr><br>";
|
||||||
#print "<pre>". $mail->getMessageBody() ."</pre><hr><br>";
|
#print "<pre>". $mail->getMessageBody() ."</pre><hr><br>";
|
||||||
#exit;
|
#exit;
|
||||||
@ -3317,14 +3319,14 @@ class mail_compose
|
|||||||
if (isset($lastDrafted['uid']) && !empty($lastDrafted['uid'])) $lastDrafted['uid']=trim($lastDrafted['uid']);
|
if (isset($lastDrafted['uid']) && !empty($lastDrafted['uid'])) $lastDrafted['uid']=trim($lastDrafted['uid']);
|
||||||
// manually drafted, do not delete
|
// manually drafted, do not delete
|
||||||
// will be handled later on IF mode was $_formData['mode']=='composefromdraft'
|
// will be handled later on IF mode was $_formData['mode']=='composefromdraft'
|
||||||
if (isset($lastDrafted['uid']) && (empty($lastDrafted['uid']) || $lastDrafted['uid'] == $this->sessionData['uid'])) $lastDrafted=false;
|
if (isset($lastDrafted['uid']) && (empty($lastDrafted['uid']) || $lastDrafted['uid'] == ($this->sessionData['uid']??null))) $lastDrafted=false;
|
||||||
//error_log(__METHOD__.__LINE__.array2string($lastDrafted));
|
//error_log(__METHOD__.__LINE__.array2string($lastDrafted));
|
||||||
}
|
}
|
||||||
if ($lastDrafted && is_array($lastDrafted) && $mail_bo->isDraftFolder($lastDrafted['folder']))
|
if ($lastDrafted && is_array($lastDrafted) && $mail_bo->isDraftFolder($lastDrafted['folder']))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if ($this->sessionData['lastDrafted'] != $this->sessionData['uid'] || !($_formData['mode']=='composefromdraft' &&
|
if ($this->sessionData['lastDrafted'] != ($this->sessionData['uid']??null) || !($_formData['mode']=='composefromdraft' &&
|
||||||
($_formData['to_infolog'] == 'on' || $_formData['to_tracker'] == 'on' || $_formData['to_calendar'] == 'on' )&&$this->sessionData['attachments']))
|
($_formData['to_infolog'] == 'on' || $_formData['to_tracker'] == 'on' || $_formData['to_calendar'] == 'on' )&&$this->sessionData['attachments']))
|
||||||
{
|
{
|
||||||
//error_log(__METHOD__.__LINE__."#".$lastDrafted['uid'].'#'.$lastDrafted['folder'].array2string($_formData));
|
//error_log(__METHOD__.__LINE__."#".$lastDrafted['uid'].'#'.$lastDrafted['folder'].array2string($_formData));
|
||||||
@ -3399,7 +3401,7 @@ class mail_compose
|
|||||||
}
|
}
|
||||||
if (is_array($this->sessionData['cc'])) $mailaddresses['cc'] = $this->sessionData['cc'];
|
if (is_array($this->sessionData['cc'])) $mailaddresses['cc'] = $this->sessionData['cc'];
|
||||||
if (is_array($this->sessionData['bcc'])) $mailaddresses['bcc'] = $this->sessionData['bcc'];
|
if (is_array($this->sessionData['bcc'])) $mailaddresses['bcc'] = $this->sessionData['bcc'];
|
||||||
if (!empty($mailaddresses)) $mailaddresses['from'] = Mail\Html::decodeMailHeader($fromAddress);
|
if (!empty($mailaddresses) && !empty($fromAddress)) $mailaddresses['from'] = Mail\Html::decodeMailHeader($fromAddress);
|
||||||
|
|
||||||
if ($_formData['to_infolog'] == 'on' || $_formData['to_tracker'] == 'on' || $_formData['to_calendar'] == 'on' )
|
if ($_formData['to_infolog'] == 'on' || $_formData['to_tracker'] == 'on' || $_formData['to_calendar'] == 'on' )
|
||||||
{
|
{
|
||||||
@ -3407,7 +3409,7 @@ class mail_compose
|
|||||||
|
|
||||||
foreach(array('to_infolog','to_tracker','to_calendar') as $app_key)
|
foreach(array('to_infolog','to_tracker','to_calendar') as $app_key)
|
||||||
{
|
{
|
||||||
$entryid = $_formData['to_integrate_ids'][0][$app_key];
|
$entryid = $_formData['to_integrate_ids'][0][$app_key] ?? null;
|
||||||
if ($_formData[$app_key] == 'on')
|
if ($_formData[$app_key] == 'on')
|
||||||
{
|
{
|
||||||
$app_name = substr($app_key,3);
|
$app_name = substr($app_key,3);
|
||||||
|
@ -252,6 +252,10 @@ class mail_sieve
|
|||||||
break;
|
break;
|
||||||
case 'reject':
|
case 'reject':
|
||||||
$content['action_reject_text'] = $rules['action_arg'];
|
$content['action_reject_text'] = $rules['action_arg'];
|
||||||
|
break;
|
||||||
|
case 'flags':
|
||||||
|
$content['action_flags_list'] = explode(' ', $rules['action_arg']);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
$content['anyof'] = $rules['anyof'] != 0?1:0;
|
$content['anyof'] = $rules['anyof'] != 0?1:0;
|
||||||
}
|
}
|
||||||
@ -302,10 +306,15 @@ class mail_sieve
|
|||||||
break;
|
break;
|
||||||
case 'reject':
|
case 'reject':
|
||||||
$newRule['action_arg'] = $content['action_reject_text'];
|
$newRule['action_arg'] = $content['action_reject_text'];
|
||||||
|
break;
|
||||||
|
case 'flags':
|
||||||
|
$newRule['action_arg'] = implode(' ', $content['action_flags_list']);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
unset($newRule['action_folder_text']);
|
unset($newRule['action_folder_text']);
|
||||||
unset($newRule['action_address_text']);
|
unset($newRule['action_address_text']);
|
||||||
unset($newRule['action_reject_text']);
|
unset($newRule['action_reject_text']);
|
||||||
|
unset($newRule['action_flags_list']);
|
||||||
|
|
||||||
$newRule['flg'] = 0 ;
|
$newRule['flg'] = 0 ;
|
||||||
if( $newRule['continue'] ) { $newRule['flg'] += 1; }
|
if( $newRule['continue'] ) { $newRule['flg'] += 1; }
|
||||||
@ -550,7 +559,7 @@ class mail_sieve
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ($icServer->acc_imap_administration)
|
if ($icServer->acc_imap_administration || (!empty($icServer->getExtensions()) && in_array('DATE', $icServer->getExtensions())))
|
||||||
{
|
{
|
||||||
$ByDate = array('by_date' => lang('By date'));
|
$ByDate = array('by_date' => lang('By date'));
|
||||||
}
|
}
|
||||||
@ -949,11 +958,11 @@ class mail_sieve
|
|||||||
break;
|
break;
|
||||||
case 'enable':
|
case 'enable':
|
||||||
$msg = lang('rule with priority ') . $checked . lang(' enabled!');
|
$msg = lang('rule with priority ') . $checked . lang(' enabled!');
|
||||||
$this->rules[$checked][status] = 'ENABLED';
|
$this->rules[$checked]['status'] = 'ENABLED';
|
||||||
break;
|
break;
|
||||||
case 'disable':
|
case 'disable':
|
||||||
$msg = lang('rule with priority ') . $checked . lang(' disabled!');
|
$msg = lang('rule with priority ') . $checked . lang(' disabled!');
|
||||||
$this->rules[$checked][status] = 'DISABLED';
|
$this->rules[$checked]['status'] = 'DISABLED';
|
||||||
break;
|
break;
|
||||||
case 'move':
|
case 'move':
|
||||||
break;
|
break;
|
||||||
|
@ -425,7 +425,7 @@ class mail_ui
|
|||||||
protected static function image_proxy()
|
protected static function image_proxy()
|
||||||
{
|
{
|
||||||
$configs = Api\Config::read('mail');
|
$configs = Api\Config::read('mail');
|
||||||
$image_proxy = $configs[self::IMAGE_PROXY_CONFIG] ?: self::DEFAULT_IMAGE_PROXY;
|
$image_proxy = $configs[self::IMAGE_PROXY_CONFIG] ?? self::DEFAULT_IMAGE_PROXY;
|
||||||
if (strpos(self::EGROUPWARE_IMAGE_PROXY, parse_url($image_proxy, PHP_URL_HOST)))
|
if (strpos(self::EGROUPWARE_IMAGE_PROXY, parse_url($image_proxy, PHP_URL_HOST)))
|
||||||
{
|
{
|
||||||
$image_proxy = self::EGROUPWARE_IMAGE_PROXY;
|
$image_proxy = self::EGROUPWARE_IMAGE_PROXY;
|
||||||
@ -565,7 +565,7 @@ class mail_ui
|
|||||||
$etpl->setElementAttribute(self::$nm_index.'[foldertree]','actions', $this->get_tree_actions());
|
$etpl->setElementAttribute(self::$nm_index.'[foldertree]','actions', $this->get_tree_actions());
|
||||||
|
|
||||||
// sending preview toolbar actions
|
// sending preview toolbar actions
|
||||||
if ($content['mailSplitter']) $etpl->setElementAttribute('mailPreview[toolbar]', 'actions', $this->get_toolbar_actions());
|
if (!empty($content['mailSplitter'])) $etpl->setElementAttribute('mailPreview[toolbar]', 'actions', $this->get_toolbar_actions());
|
||||||
|
|
||||||
// We need to send toolbar actions to client-side because view template needs them
|
// We need to send toolbar actions to client-side because view template needs them
|
||||||
if (Api\Header\UserAgent::mobile()) $sel_options['toolbar'] = $this->get_toolbar_actions();
|
if (Api\Header\UserAgent::mobile()) $sel_options['toolbar'] = $this->get_toolbar_actions();
|
||||||
@ -1827,7 +1827,7 @@ $filter['before']= date("d-M-Y", $cutoffdate2);
|
|||||||
// we have an own created rowID; prepend app=mail
|
// we have an own created rowID; prepend app=mail
|
||||||
array_unshift($res,'mail');
|
array_unshift($res,'mail');
|
||||||
}
|
}
|
||||||
return array('app'=>$res[0], 'accountID'=>$res[1], 'profileID'=>$res[2], 'folder'=>base64_decode($res[3]), 'msgUID'=>$res[4]);
|
return array('app'=>$res[0], 'accountID'=>$res[1]??null, 'profileID'=>$res[2]??null, 'folder'=>base64_decode($res[3]??null), 'msgUID'=>$res[4]??null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,6 +98,16 @@
|
|||||||
<radio label="Discard message" id="action" options="discard"/>
|
<radio label="Discard message" id="action" options="discard"/>
|
||||||
<description/>
|
<description/>
|
||||||
</row>
|
</row>
|
||||||
|
<row>
|
||||||
|
<radio label="set flags" id="action" options="flags"/>
|
||||||
|
<taglist id="action_flags_list">
|
||||||
|
<option value="\\Flagged">Flagged</option>
|
||||||
|
<option value="\\Deleted">Deleted</option>
|
||||||
|
<option value="\\Seen">Read</option>
|
||||||
|
<option value="\\Answered">Answered</option>
|
||||||
|
<option value="\\Draft">Draft</option>
|
||||||
|
</taglist>
|
||||||
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<description value="(*) Please consider, forward to multiple addresses will not work if number of addresses exceeds the Limit. For most mail Servers the limit is 4 by default, please contact your mail server administrator for further info."/>
|
<description value="(*) Please consider, forward to multiple addresses will not work if number of addresses exceeds the Limit. For most mail Servers the limit is 4 by default, please contact your mail server administrator for further info."/>
|
||||||
</row>
|
</row>
|
||||||
|
@ -160,7 +160,7 @@ class notifications_popup implements notifications_iface {
|
|||||||
foreach ($rs as $notification) {
|
foreach ($rs as $notification) {
|
||||||
$actions = null;
|
$actions = null;
|
||||||
$data = json_decode($notification['notify_data'], true);
|
$data = json_decode($notification['notify_data'], true);
|
||||||
if ($data['appname'] && $data['data'])
|
if (!empty($data['appname']) && !empty($data['data']))
|
||||||
{
|
{
|
||||||
$_actions = Api\Hooks::process (array(
|
$_actions = Api\Hooks::process (array(
|
||||||
'location' => 'notifications_actions',
|
'location' => 'notifications_actions',
|
||||||
@ -175,7 +175,7 @@ class notifications_popup implements notifications_iface {
|
|||||||
'created' => Api\DateTime::server2user($notification['notify_created']),
|
'created' => Api\DateTime::server2user($notification['notify_created']),
|
||||||
'current' => new Api\DateTime('now'),
|
'current' => new Api\DateTime('now'),
|
||||||
'actions' => is_array($actions)?$actions:NULL,
|
'actions' => is_array($actions)?$actions:NULL,
|
||||||
'extra_data' => ($data['data'] ? $data['data'] : array())
|
'extra_data' => $data['data'] ?? [],
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -85,13 +85,13 @@ class pixelegg_framework extends Api\Framework\Ajax
|
|||||||
{
|
{
|
||||||
$ret = parent::_get_css();
|
$ret = parent::_get_css();
|
||||||
// color to use
|
// color to use
|
||||||
$color = str_replace('custom',$GLOBALS['egw_info']['user']['preferences']['common']['template_custom_color'],
|
$color = str_replace('custom', $GLOBALS['egw_info']['user']['preferences']['common']['template_custom_color'] ?? null,
|
||||||
$GLOBALS['egw_info']['user']['preferences']['common']['template_color']);
|
$GLOBALS['egw_info']['user']['preferences']['common']['template_color'] ?? null);
|
||||||
|
|
||||||
// Create a dark variant of the color
|
// Create a dark variant of the color
|
||||||
$color_darker = empty($color) ? '' :$this->_color_shader($color, -30);
|
$color_darker = empty($color) ? '' :$this->_color_shader($color, -30);
|
||||||
|
|
||||||
if (preg_match('/^(#[0-9A-F]+|[A-Z]+)$/i', $GLOBALS['egw_info']['user']['preferences']['common']['sidebox_custom_color']))
|
if (!empty($GLOBALS['egw_info']['user']['preferences']['common']['sidebox_custom_color']) && preg_match('/^(#[0-9A-F]+|[A-Z]+)$/i', $GLOBALS['egw_info']['user']['preferences']['common']['sidebox_custom_color']))
|
||||||
{
|
{
|
||||||
$sidebox_color_hover = $GLOBALS['egw_info']['user']['preferences']['common']['sidebox_custom_color'];
|
$sidebox_color_hover = $GLOBALS['egw_info']['user']['preferences']['common']['sidebox_custom_color'];
|
||||||
$sidebox_color = $this->_color_shader($sidebox_color_hover, -30);
|
$sidebox_color = $this->_color_shader($sidebox_color_hover, -30);
|
||||||
@ -101,7 +101,7 @@ class pixelegg_framework extends Api\Framework\Ajax
|
|||||||
$sidebox_color_hover = $color;
|
$sidebox_color_hover = $color;
|
||||||
$sidebox_color = $color_darker;
|
$sidebox_color = $color_darker;
|
||||||
}
|
}
|
||||||
if (preg_match('/^(#[0-9A-F]+|[A-Z]+)$/i', $GLOBALS['egw_info']['user']['preferences']['common']['loginbox_custom_color']))
|
if (!empty($GLOBALS['egw_info']['user']['preferences']['common']['loginbox_custom_color']) && preg_match('/^(#[0-9A-F]+|[A-Z]+)$/i', $GLOBALS['egw_info']['user']['preferences']['common']['loginbox_custom_color']))
|
||||||
{
|
{
|
||||||
$loginbox_color = $GLOBALS['egw_info']['user']['preferences']['common']['loginbox_custom_color'];
|
$loginbox_color = $GLOBALS['egw_info']['user']['preferences']['common']['loginbox_custom_color'];
|
||||||
}
|
}
|
||||||
@ -109,8 +109,8 @@ class pixelegg_framework extends Api\Framework\Ajax
|
|||||||
{
|
{
|
||||||
$loginbox_color = $color_darker;
|
$loginbox_color = $color_darker;
|
||||||
}
|
}
|
||||||
//alway set header logo used in sharing regardless of custom color being set
|
//always set header logo used in sharing regardless of custom color being set
|
||||||
$header = $GLOBALS['egw_info']['server']['login_logo_header'] ? Api\Framework::get_login_logo_or_bg_url('login_logo_header', 'logo')
|
$header = !empty($GLOBALS['egw_info']['server']['login_logo_header']) ? Api\Framework::get_login_logo_or_bg_url('login_logo_header', 'logo')
|
||||||
: Api\Framework::get_login_logo_or_bg_url('login_logo_file', 'logo');
|
: Api\Framework::get_login_logo_or_bg_url('login_logo_file', 'logo');
|
||||||
$ret['app_css'] .= "
|
$ret['app_css'] .= "
|
||||||
/*
|
/*
|
||||||
|
@ -451,7 +451,7 @@ class timesheet_bo extends Api\Storage
|
|||||||
{
|
{
|
||||||
$extra_cols[] = $total_sql.' AS ts_total';
|
$extra_cols[] = $total_sql.' AS ts_total';
|
||||||
}
|
}
|
||||||
if (!isset($filter['ts_owner']) || !count($filter['ts_owner']))
|
if (!isset($filter['ts_owner']) || !count((array)$filter['ts_owner']))
|
||||||
{
|
{
|
||||||
$filter['ts_owner'] = array_keys($this->grants);
|
$filter['ts_owner'] = array_keys($this->grants);
|
||||||
}
|
}
|
||||||
|
@ -178,41 +178,8 @@ class timesheet_hooks
|
|||||||
// Merge print
|
// Merge print
|
||||||
if ($GLOBALS['egw_info']['user']['apps']['filemanager'])
|
if ($GLOBALS['egw_info']['user']['apps']['filemanager'])
|
||||||
{
|
{
|
||||||
$settings['default_document'] = array(
|
$merge = new timesheet_merge();
|
||||||
'type' => 'vfs_file',
|
$settings += $merge->merge_preferences();
|
||||||
'size' => 60,
|
|
||||||
'label' => 'Default document to insert entries',
|
|
||||||
'name' => 'default_document',
|
|
||||||
'help' => lang('If you specify a document (full vfs path) here, %1 displays an extra document icon for each entry. That icon allows to download the specified document with the data inserted.',lang('timesheet')).' '.
|
|
||||||
lang('The document can contain placeholder like {{%1}}, to be replaced with the data.', 'ts_title').' '.
|
|
||||||
lang('The following document-types are supported:'). implode(',',Api\Storage\Merge::get_file_extensions()),
|
|
||||||
'run_lang' => false,
|
|
||||||
'xmlrpc' => True,
|
|
||||||
'admin' => False,
|
|
||||||
);
|
|
||||||
$settings['document_dir'] = array(
|
|
||||||
'type' => 'vfs_dirs',
|
|
||||||
'size' => 60,
|
|
||||||
'label' => 'Directory with documents to insert entries',
|
|
||||||
'name' => 'document_dir',
|
|
||||||
'help' => lang('If you specify a directory (full vfs path) here, %1 displays an action for each document. That action allows to download the specified document with the %1 data inserted.', lang('timesheet')) . ' ' .
|
|
||||||
lang('The document can contain placeholder like {{%1}}, to be replaced with the data.', 'ts_title') . ' ' .
|
|
||||||
lang('The following document-types are supported:') . implode(',', Api\Storage\Merge::get_file_extensions()),
|
|
||||||
'run_lang' => false,
|
|
||||||
'xmlrpc' => True,
|
|
||||||
'admin' => False,
|
|
||||||
'default' => '/templates/timesheet',
|
|
||||||
);
|
|
||||||
$settings[Api\Storage\Merge::PREF_DOCUMENT_FILENAME] = array(
|
|
||||||
'type' => 'taglist',
|
|
||||||
'label' => 'Document download filename',
|
|
||||||
'name' => 'document_download_name',
|
|
||||||
'values' => Api\Storage\Merge::DOCUMENT_FILENAME_OPTIONS,
|
|
||||||
'help' => 'Choose the default filename for downloaded documents.',
|
|
||||||
'xmlrpc' => True,
|
|
||||||
'admin' => False,
|
|
||||||
'default' => 'document',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $settings;
|
return $settings;
|
||||||
|
@ -156,68 +156,6 @@ class timesheet_merge extends Api\Storage\Merge
|
|||||||
return $info;
|
return $info;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate table with replacements for the Api\Preferences
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public function show_replacements()
|
|
||||||
{
|
|
||||||
$GLOBALS['egw_info']['flags']['app_header'] = lang('timesheet').' - '.lang('Replacements for inserting entries into documents');
|
|
||||||
$GLOBALS['egw_info']['flags']['nonavbar'] = false;
|
|
||||||
echo $GLOBALS['egw']->framework->header();
|
|
||||||
|
|
||||||
echo "<table width='90%' align='center'>\n";
|
|
||||||
echo '<tr><td colspan="4"><h3>'.lang('Timesheet fields:')."</h3></td></tr>";
|
|
||||||
|
|
||||||
$n = 0;
|
|
||||||
$fields = array('ts_id' => lang('Timesheet ID')) + $this->bo->field2label + array(
|
|
||||||
'ts_total' => lang('total'),
|
|
||||||
'ts_created' => lang('Created'),
|
|
||||||
'ts_modified' => lang('Modified'),
|
|
||||||
);
|
|
||||||
foreach($fields as $name => $label)
|
|
||||||
{
|
|
||||||
if (in_array($name,array('pl_id','customfields'))) continue; // dont show them
|
|
||||||
|
|
||||||
if (in_array($name,array('ts_title', 'ts_description')) && $n&1) // main values, which should be in the first column
|
|
||||||
{
|
|
||||||
echo "</tr>\n";
|
|
||||||
$n++;
|
|
||||||
}
|
|
||||||
if (!($n&1)) echo '<tr>';
|
|
||||||
echo '<td>{{'.$name.'}}</td><td>'.lang($label).'</td>';
|
|
||||||
if ($n&1) echo "</tr>\n";
|
|
||||||
$n++;
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '<tr><td colspan="4"><h3>'.lang('Custom fields').":</h3></td></tr>";
|
|
||||||
foreach($this->bo->customfields as $name => $field)
|
|
||||||
{
|
|
||||||
echo '<tr><td>{{#'.$name.'}}</td><td colspan="3">'.$field['label']."</td></tr>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '<tr><td colspan="4"><h3>'.lang('Project fields').':</h3></td></tr>';
|
|
||||||
$pm_merge = new projectmanager_merge();
|
|
||||||
$i = 0;
|
|
||||||
foreach($pm_merge->projectmanager_fields as $name => $label)
|
|
||||||
{
|
|
||||||
if (!($i&1)) echo '<tr>';
|
|
||||||
echo '<td>{{ts_project/'.$name.'}}</td><td>'.$label.'</td>';
|
|
||||||
if ($i&1) echo "</tr>\n";
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '<tr><td colspan="4"><h3>' . lang('General fields:') . "</h3></td></tr>";
|
|
||||||
foreach($this->get_common_replacements() as $name => $label)
|
|
||||||
{
|
|
||||||
echo '<tr><td>{{' . $name . '}}</td><td colspan="3">' . $label . "</td></tr>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "</table>\n";
|
|
||||||
|
|
||||||
echo $GLOBALS['egw']->framework->footer();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of placeholders provided.
|
* Get a list of placeholders provided.
|
||||||
*
|
*
|
||||||
@ -256,10 +194,14 @@ class timesheet_merge extends Api\Storage\Merge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't add any linked placeholders if we're not at the top level
|
||||||
|
// This avoids potential recursion
|
||||||
|
if(!$prefix)
|
||||||
|
{
|
||||||
// Add project placeholders
|
// Add project placeholders
|
||||||
$pm_merge = new projectmanager_merge();
|
$pm_merge = new projectmanager_merge();
|
||||||
$this->add_linked_placeholders($placeholders, lang('Project'), $pm_merge->get_placeholder_list('ts_project'));
|
$this->add_linked_placeholders($placeholders, lang('Project'), $pm_merge->get_placeholder_list('ts_project'));
|
||||||
|
}
|
||||||
return $placeholders;
|
return $placeholders;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user