From 4fc6102162bbe824227a896a2d25b31ef1dc1b8f Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 18 Jul 2014 08:48:37 +0000 Subject: [PATCH 01/49] removed not used setting of application via GET parameter --- etemplate/inc/class.db_tools.inc.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/etemplate/inc/class.db_tools.inc.php b/etemplate/inc/class.db_tools.inc.php index cff158005e..43a11240ac 100644 --- a/etemplate/inc/class.db_tools.inc.php +++ b/etemplate/inc/class.db_tools.inc.php @@ -115,10 +115,6 @@ class db_tools */ function edit(array $content=null,$msg = '') { - if (isset($_GET['app'])) - { - $this->app = $_GET['app']; - } if (is_array($content)) { if ($this->debug) From a2bac6e07acfd3ed2b160740f1fb109033dedd50 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Fri, 18 Jul 2014 09:16:41 +0000 Subject: [PATCH 02/49] Make sure _with value is not null when trying to replace it into url, it causes broken url while using _replace argument from refresh_opener --- phpgwapi/js/jsapi/egw_message.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpgwapi/js/jsapi/egw_message.js b/phpgwapi/js/jsapi/egw_message.js index 1627613aa3..7916a9bf37 100644 --- a/phpgwapi/js/jsapi/egw_message.js +++ b/phpgwapi/js/jsapi/egw_message.js @@ -273,7 +273,7 @@ egw.extend('message', egw.MODULE_WND_LOCAL, function(_app, _wnd) if (typeof _replace != 'undefined') { - href = href.replace(typeof _replace == 'string' ? new RegExp(_replace) : _replace, typeof _with != 'undefined' ? _with : ''); + href = href.replace(typeof _replace == 'string' ? new RegExp(_replace) : _replace, (typeof _with != 'undefined' && _with != null) ? _with : ''); } if (href.indexOf('msg=') != -1) From 08e4ecd69666b3d50063e1296a234225d0edfce3 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 18 Jul 2014 09:47:17 +0000 Subject: [PATCH 03/49] fixed typo --- admin/lang/egw_de.lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/lang/egw_de.lang b/admin/lang/egw_de.lang index 4ed5a2ca77..c0f764a825 100644 --- a/admin/lang/egw_de.lang +++ b/admin/lang/egw_de.lang @@ -644,7 +644,7 @@ url of the egroupware installation, eg. http://domain.com/egroupware admin de UR usage admin de Einsatz use cookies to pass sessionid admin de Sitzungs-ID in einem Cookie speichern use pure html compliant code (not fully working yet) admin de Vollständig HTML kompatiblen Code verwenden (nicht vollständig implementiert) -use secure cookies (transmitted only via https) admin de Benutzer sichere Cookies (werden nur per https übertragen) +use secure cookies (transmitted only via https) admin de Benutze sichere Cookies (werden nur per https übertragen) use theme admin de Benutztes Farbschema user accounts admin de Benutzerkonten user csv export admin de CSV Export von Benutzern From a8a5557aa7b8f24fcd3aac30c646e85bdee026ca Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Fri, 18 Jul 2014 09:49:17 +0000 Subject: [PATCH 04/49] * API/CKEditor: introduce new skins/themes --- .../inc/class.egw_ckeditor_config.inc.php | 35 +++++++++++++++---- .../inc/class.preferences_hooks.inc.php | 6 +--- preferences/lang/egw_de.lang | 10 +++--- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/phpgwapi/inc/class.egw_ckeditor_config.inc.php b/phpgwapi/inc/class.egw_ckeditor_config.inc.php index 05bb1bb8d2..4c7dc3988b 100644 --- a/phpgwapi/inc/class.egw_ckeditor_config.inc.php +++ b/phpgwapi/inc/class.egw_ckeditor_config.inc.php @@ -56,6 +56,21 @@ class egw_ckeditor_config 'px' => 'px: display pixels', ); + /** + * Get available CKEditor Skins + * @return array + */ + public static function getAvailableCKEditorSkins() + { + return array( + 'kama' => lang('kama theme'), + 'moono' => lang('moono theme (default)'), + 'moonocolor' => lang('moono color theme'), + 'moono-dark' => lang('dark moono theme'), + 'bootstrapck' => lang('bootstrap theme for ckeditor'), + ); + } + /** * Get font size from preferences * @@ -170,18 +185,24 @@ class egw_ckeditor_config //Convert old fckeditor skin names to new ones switch ($skin) { - case 'silver': - case 'office2003': - case 'moono': - $skin = "moono"; - break; case 'kama': - case 'default': + $skin = "kama"; + break; + case 'silver': + case 'bootstrapck': + $skin = "bootstrapck"; + break; + case 'moono-dark': + $skin = "moono-dark"; + break; + case 'office2003': case 'moonocolor': $skin = "moonocolor"; break; + case 'moono': + case 'default': default: - $skin = "moonocolor"; + $skin = "moono"; } //Check whether the skin actually exists, if not, switch to a default diff --git a/preferences/inc/class.preferences_hooks.inc.php b/preferences/inc/class.preferences_hooks.inc.php index 89e8913391..ff7d61c0fd 100644 --- a/preferences/inc/class.preferences_hooks.inc.php +++ b/preferences/inc/class.preferences_hooks.inc.php @@ -67,11 +67,7 @@ class preferences_hooks 'br' => lang('br') ); - $rich_text_editor_skins = array( - 'kama' => lang ('Default theme'), - 'moono' => lang('Moono theme'), - 'moonocolor' => lang('Moono color theme'), - ); + $rich_text_editor_skins = egw_ckeditor_config::getAvailableCKEditorSkins(); $account_sels = array( 'selectbox' => lang('Selectbox'), diff --git a/preferences/lang/egw_de.lang b/preferences/lang/egw_de.lang index 2e226e749e..2ddf379c20 100644 --- a/preferences/lang/egw_de.lang +++ b/preferences/lang/egw_de.lang @@ -11,6 +11,7 @@ any listing in egw will show you this number of entries or lines per page.
to are you sure you want to delete this category ? preferences de Sind sie sicher, dass sie diese Kategorie löschen wollen ? automatically start with this font preferences de Startet automatisch mit dieser Schrift automatically start with this font size preferences de Startet automatisch mit dieser Schriftgröße +bootstrap theme for ckeditor preferences de Bootstrap Schema für den CKEditor br preferences de br change a user password by passing the old and new passwords. returns true on success, false on failure. preferences de Ändern Sie Ihr Passwort, indem Sie Ihr altes und neues Passwort angeben. Es wird TRUE zurückgegeben für eine erfolgreiche Änderung und FALSE wenn es nicht erfolgreich war. change password preferences de Passwort ändern @@ -22,6 +23,7 @@ charset for the csv export/import preferences de Zeichensatz click to select a color preferences de Anklicken um eine Farbe auszuwählen color preferences de Farbe country preferences de Land +dark moono theme preferences de Dunkles Moono Schema data exchange settings preferences de Einstellungen für den Datenaustausch date format preferences de Datumsformat default preferences de Vorgabe @@ -29,7 +31,6 @@ default application preferences de Standard-Anwendung default font preferences de Standard-Schrift default font size preferences de Standard-Schriftgröße default preferences preferences de Voreinstellungen -default theme preferences de Vorgabe Farbschema delete categories preferences de Kategorie löschen deny following groups access to acl (grant access) admin de verweigere folgenden Gruppen den Zugriff in den ACL's deny following groups access to edit categories admin de verweigere folgenden Gruppen den Zugriff zum Ändern der Kategorien @@ -72,13 +73,14 @@ images linked to an entry can be displayed as thumbnails. you can turn this off in which country are you. this is used to set certain defaults for you. preferences de In welchen Land befinden Sie sich? Damit werden verschiedene Voreinstellungen für Sie vorgenommen. interface/template selection preferences de Auswahl der Benutzeroberfläche just clicking on the line, like a checkbox preferences de einfaches anklicken der Zeile, wie eine Checkbox +kama theme preferences de Kama Farbschema language preferences de Sprache look & feel preferences de Aussehen und Handhabung lowercase letters preferences de Kleinbuchstaben max matches per page preferences de maximale Treffer pro Seite max number of icons in navbar preferences de Maximale Anzahl von Icons in der Navigationsleiste -moono color theme preferences de Farbiges Schema (Mono) -moono theme preferences de Einfarbiges Schema (Mono) +moono color theme preferences de Farbiges Schema (Moono) +moono theme (default) preferences de Einfarbiges Schema (Moono) no default preferences de Keine Vorgabe no user-selection at all common de Überhaupt keine Benutzerauswahl note: this feature does *not* change your email password. this will preferences de Anmerkung: Diese Funktion ändert nicht Ihr E-Mail Passwort. @@ -86,7 +88,6 @@ note: this feature does *not* change your email password. this will need to be d notification settings preferences de Einstellungen der Benachrichtigungen number format preferences de Format von Zahlen numbers preferences de Zahlen -office 2003 theme preferences de Office 2003 old password and new password are the same. this is invalid. you must enter a new password preferences de Altes Passwort und Neues Passwort sind gleich. Dies ist ungültig. Sie müssen ein neues Passwort vergeben. p: paragraph preferences de p: Absatz password changed preferences de Ihr Password wurde geändert @@ -125,7 +126,6 @@ show navigation bar as preferences de Anzeige der Navigationsleiste show number of current users preferences de Anzahl gegenwärtiger Benutzer anzeigen show text on navigation icons preferences de Text zu Icons in der Navigationsleiste anzeigen show_more_apps common de Mehr Anwendungen anzeigen -silver theme preferences de Silbern special characters preferences de Sonderzeichen spellchecker language addressbook de Sprache Rechtschreibprüfung text editor settings preferences de Einstellungen des Texteditors From 9712e625db91a97d6685a3a7bddaf6185991f8a8 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 18 Jul 2014 10:02:51 +0000 Subject: [PATCH 05/49] * Admin/API: remove no longer fully supported method to not "store session-id in cookie", it is the safer default anyway --- admin/templates/default/config.tpl | 10 ---------- etemplate/inc/class.url_widget.inc.php | 10 ---------- phpgwapi/js/jsapi/egw_links.js | 8 -------- 3 files changed, 28 deletions(-) diff --git a/admin/templates/default/config.tpl b/admin/templates/default/config.tpl index 8eae450db2..d0a3101492 100644 --- a/admin/templates/default/config.tpl +++ b/admin/templates/default/config.tpl @@ -105,16 +105,6 @@  {lang_security} - - {lang_Use_cookies_to_pass_sessionid}: - - - - - {lang_Cookie_path_(allows_multiple_eGW_sessions_with_different_directories,_has_problemes_with_SiteMgr!)}: diff --git a/etemplate/inc/class.url_widget.inc.php b/etemplate/inc/class.url_widget.inc.php index 4ad3d35b3a..7407a95ec4 100644 --- a/etemplate/inc/class.url_widget.inc.php +++ b/etemplate/inc/class.url_widget.inc.php @@ -164,11 +164,6 @@ class url_widget if ($value) { $link = (strpos($value,'://') === false) ? 'http://'.$value : $value; - if (!$GLOBALS['egw_info']['server']['usecookies']) // if session-id is in url, use redirect.php to remove it from referrer - { - $link = $GLOBALS['egw_info']['server']['webserver_url'].'/redirect.php?go='.$link; - if ($link[0] == '/') $link = ($_SERVER['HTTPS'] ? 'https://' : 'http://').$_SERVER['HTTP_HOST'].$link; - } $cell['size'] = ','.$link.',,,_blank'; } if (substr($value,0,7) == 'http://') @@ -194,11 +189,6 @@ class url_widget if ($value) { $link = self::phone2link($value); - if (!$GLOBALS['egw_info']['server']['usecookies'] && substr($link,0,4) == 'http') // if session-id is in url, use redirect.php to remove it from referrer - { - $link = $GLOBALS['egw_info']['server']['webserver_url'].'/redirect.php?go='.$link; - if ($link[0] == '/') $link = ($_SERVER['HTTPS'] ? 'https://' : 'http://').$_SERVER['HTTP_HOST'].$link; - } $cell['size'] = ','.$link.($GLOBALS['egw_info']['server']['call_popup']=='none' ? '' : // 'none' = no target ',,,calling,'.$GLOBALS['egw_info']['server']['call_popup']); } diff --git a/phpgwapi/js/jsapi/egw_links.js b/phpgwapi/js/jsapi/egw_links.js index e217e7236c..f84f68849d 100644 --- a/phpgwapi/js/jsapi/egw_links.js +++ b/phpgwapi/js/jsapi/egw_links.js @@ -258,14 +258,6 @@ egw.extend('links', egw.MODULE_GLOBAL, function() { } var vars = {}; - /* not sure we still need to support that - // add session params if not using cookies - if (!$GLOBALS['egw_info']['server']['usecookies']) - { - $vars['sessionid'] = $GLOBALS['egw']->session->sessionid; - $vars['kp3'] = $GLOBALS['egw']->session->kp3; - $vars['domain'] = $GLOBALS['egw']->session->account_domain; - }*/ // check if the url already contains a query and ensure that vars is an array and all strings are in extravars var url_othervars = _url.split('?',2); From 609aa97d9ddfa3276f62c85ebaf03009f8055525 Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Fri, 18 Jul 2014 10:04:37 +0000 Subject: [PATCH 06/49] missing lang stuff --- preferences/lang/egw_en.lang | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/preferences/lang/egw_en.lang b/preferences/lang/egw_en.lang index 1206a4385e..5a8316d58a 100644 --- a/preferences/lang/egw_en.lang +++ b/preferences/lang/egw_en.lang @@ -11,6 +11,7 @@ any listing in egw will show you this number of entries or lines per page.
to are you sure you want to delete this category ? preferences en Are you sure you want to delete this category ? automatically start with this font preferences en Automatically start with this font automatically start with this font size preferences en Automatically start with this font size +bootstrap theme for ckeditor preferences en Bootstrap Theme for CKEditor br preferences en br change a user password by passing the old and new passwords. returns true on success, false on failure. preferences en Change a user password by passing the old and new passwords. Returns TRUE on success, FALSE on failure. change password preferences en Change password @@ -22,6 +23,7 @@ charset for the csv export/import preferences en Character set click to select a color preferences en Click to select a color color preferences en Color country preferences en Country +dark moono theme preferences en Dark Moono Theme data exchange settings preferences en Data exchange settings date format preferences en Date format default preferences en Default @@ -29,7 +31,6 @@ default application preferences en Default application default font preferences en Default font default font size preferences en Default font size default preferences preferences en Default preferences -default theme preferences en Default theme delete categories preferences en Delete categories deny following groups access to acl (grant access) admin en Deny following groups access to ACL (grant access) deny following groups access to edit categories admin en Deny following groups access to edit categories @@ -72,13 +73,14 @@ images linked to an entry can be displayed as thumbnails. you can turn this off in which country are you. this is used to set certain defaults for you. preferences en Select the country. It sets some defaults e.g. in Calendar. interface/template selection preferences en Interface | Template just clicking on the line, like a checkbox preferences en just clicking on the line, like a checkbox +kama theme preferences en Kama theme language preferences en Language look & feel preferences en Look & feel lowercase letters preferences en lowercase letters max matches per page preferences en Max matches per page max number of icons in navbar preferences en Max number of icons in navigation bar moono color theme preferences en Moono color theme -moono theme preferences en Moono theme +moono theme (default) preferences en Moono theme (Default) no default preferences en No default no user-selection at all common en No user selection at all note: this feature does *not* change your email password. this will preferences en note: This feature does *not* change your email password. This will @@ -86,7 +88,6 @@ note: this feature does *not* change your email password. this will need to be d notification settings preferences en Notification settings number format preferences en Number format numbers preferences en numbers -office 2003 theme preferences en Office 2003 theme old password and new password are the same. this is invalid. you must enter a new password preferences en Old password and new password are the same. You must enter a new password! p: paragraph preferences en p: Paragraph password changed preferences en Password changed. @@ -125,7 +126,6 @@ show navigation bar as preferences en Show navigation bar as show number of current users preferences en Current users show text on navigation icons preferences en Show text on navigation icons show_more_apps common en Show more applications -silver theme preferences en Silver theme special characters preferences en special characters spellchecker language addressbook en Spellchecker language text editor settings preferences en Text editor settings From 003f36afdbb5c773fecc25787044349a5296f7f3 Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Fri, 18 Jul 2014 11:14:33 +0000 Subject: [PATCH 07/49] avoid warning on unexpected accounts->memberships result --- phpgwapi/inc/class.preferences.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpgwapi/inc/class.preferences.inc.php b/phpgwapi/inc/class.preferences.inc.php index 58b9453c3f..45b1da1a91 100644 --- a/phpgwapi/inc/class.preferences.inc.php +++ b/phpgwapi/inc/class.preferences.inc.php @@ -412,7 +412,7 @@ class preferences if ($this->account_id > 0) { $primary_group = accounts::id2name($this->account_id, 'account_primary_group'); - foreach($GLOBALS['egw']->accounts->memberships($this->account_id, true) as $gid) + foreach((array)$GLOBALS['egw']->accounts->memberships($this->account_id, true) as $gid) { if ($gid != $primary_group) $to_read[] = $gid + self::DEFAULT_ID; // need to offset it with DEFAULT_ID = -2! } From 61dab2537573eafef80d1e07207b083c94fde881 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 18 Jul 2014 11:46:10 +0000 Subject: [PATCH 08/49] make account_id available for preferences hook --- .../inc/class.preferences_settings.inc.php | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/preferences/inc/class.preferences_settings.inc.php b/preferences/inc/class.preferences_settings.inc.php index 8bd2544066..5c6227802f 100644 --- a/preferences/inc/class.preferences_settings.inc.php +++ b/preferences/inc/class.preferences_settings.inc.php @@ -292,7 +292,7 @@ class preferences_settings */ function get_content($appname, $type, &$sel_options, &$readonlys, &$types, $tpl) { - if (!$this->call_hook($appname, $type)) + if (!$this->call_hook($appname, $type, $GLOBALS['egw']->preferences->get_account_id())) { throw new egw_exception_wrong_parameter("Could not find settings for application: ".$appname); } @@ -543,10 +543,11 @@ class preferences_settings * Sets $this->appname and $this->settings * * @param string $appname appname or 'common' - * @param string $type='user' 'default' or 'forced' + * @param string $type='user' 'default', 'forced', 'user' or 'group' + * @param int|string $account_id=null account_id for user or group prefs, or "forced" or "default" * @return boolean */ - protected function call_hook($appname, $type='user') + protected function call_hook($appname, $type='user', $account_id=null) { $this->appname = $appname == 'common' ? 'preferences' : $appname; @@ -559,10 +560,15 @@ class preferences_settings } // make type available, to hooks from applications can use it, eg. activesync - $GLOBALS['type'] = $type; + $hook_data = array( + 'location' => 'settings', + 'type' => $type, + 'account_id' => $account_id, + ); + $GLOBALS['type'] = $type; // old global variable // calling app specific settings hook - $settings = $GLOBALS['egw']->hooks->single('settings',$this->appname); + $settings = $GLOBALS['egw']->hooks->single($hook_data, $this->appname); // it either returns the settings or save it in $GLOBALS['settings'] (deprecated!) if (isset($settings) && is_array($settings) && $settings) { @@ -578,7 +584,8 @@ class preferences_settings } // calling settings hook all apps can answer (for a specific app) - foreach($GLOBALS['egw']->hooks->process('settings_'.$this->appname,$this->appname,true) as $settings) + $hook_data['location'] = 'settings_'.$this->appname; + foreach($GLOBALS['egw']->hooks->process($hook_data, $this->appname,true) as $settings) { if (isset($settings) && is_array($settings) && $settings) { From 3055fe6875969b9ca98ee2f4ee8e126d3be8ac36 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Fri, 18 Jul 2014 17:18:29 +0000 Subject: [PATCH 09/49] Try to catch PEAR_Exception over mail_ui and callWizard if there is an exception --- mail/inc/class.mail_ui.inc.php | 595 ++++++++++++++++----------------- 1 file changed, 295 insertions(+), 300 deletions(-) diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index c68163c1fa..36560a2ca5 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -165,7 +165,10 @@ class mail_ui $windowName = "editMailAccount".self::$icServerID; $response->call("egw.open_link", egw::link('/index.php', $linkData), $windowName, "600x480"); egw_framework::message($message, 'error'); - if ($_GET['menuaction'] == 'mail.mail_ui.index') $response->call('framework.setSidebox','mail',array(),'md5'); + if ($_GET['menuaction'] == 'mail.mail_ui.index') + { + $response->call('framework.setSidebox','mail',array(),'md5'); + } if ($exit) { common::egw_exit(); @@ -376,302 +379,301 @@ class mail_ui */ function index(array $content=null,$msg=null) { - //error_log(__METHOD__.__LINE__.function_backtrace()); - if (mail_bo::$debugTimes) $starttime = microtime (true); - $this->mail_bo->restoreSessionData(); - $sessionFolder = $this->mail_bo->sessionData['mailbox']; - if ($this->mail_bo->folderExists($sessionFolder)) - { - try - { - $this->mail_bo->reopen($sessionFolder); // needed to fetch full set of capabilities - } - catch (Exception $e) - { - self::callWizard($e->getMessage()); - } - } - else - { - $sessionFolder = $this->mail_bo->sessionData['mailbox'] = 'INBOX'; - } - //error_log(__METHOD__.__LINE__.' SessionFolder:'.$sessionFolder.' isToSchema:'.$toSchema); - if (!is_array($content)) - { - $content = array( - self::$nm_index => egw_session::appsession('index','mail'), - ); - if (!is_array($content[self::$nm_index])) - { - $content[self::$nm_index] = array( - 'get_rows' => 'mail.mail_ui.get_rows', // I method/callback to request the data for the rows eg. 'notes.bo.get_rows' - 'filter' => 'any', // filter is used to choose the mailbox - 'no_filter2' => false, // I disable the 2. filter (params are the same as for filter) - 'no_cat' => true, // I disable the cat-selectbox - //'cat_is_select' => 'no_lang', // true or no_lang - 'lettersearch' => false, // I show a lettersearch - 'searchletter' => false, // I0 active letter of the lettersearch or false for [all] - 'start' => 0, // IO position in list - 'order' => 'date', // IO name of the column to sort after (optional for the sortheaders) - 'sort' => 'DESC', // IO direction of the sort: 'ASC' or 'DESC' - //'default_cols' => 'status,attachments,subject,'.($toSchema?'toaddress':'fromaddress').',date,size', // I columns to use if there's no user or default pref (! as first char uses all but the named columns), default all columns - //'default_cols' => 'status,attachments,subject,address,date,size', // I columns to use if there's no user or default pref (! as first char uses all but the named columns), default all columns - //'csv_fields' => false, // I false=disable csv export, true or unset=enable it with auto-detected fieldnames, - //or array with name=>label or name=>array('label'=>label,'type'=>type) pairs (type is a eT widget-type) - 'actions' => self::get_actions(), - 'row_id' => 'row_id', // is a concatenation of trim($GLOBALS['egw_info']['user']['account_id']):profileID:base64_encode(FOLDERNAME):uid - 'placeholder_actions' => array('composeasnew') + try { + //error_log(__METHOD__.__LINE__.function_backtrace()); + if (mail_bo::$debugTimes) $starttime = microtime (true); + $this->mail_bo->restoreSessionData(); + $sessionFolder = $this->mail_bo->sessionData['mailbox']; + if ($this->mail_bo->folderExists($sessionFolder)) + { + $this->mail_bo->reopen($sessionFolder); // needed to fetch full set of capabilities + } + else + { + $sessionFolder = $this->mail_bo->sessionData['mailbox'] = 'INBOX'; + } + //error_log(__METHOD__.__LINE__.' SessionFolder:'.$sessionFolder.' isToSchema:'.$toSchema); + if (!is_array($content)) + { + $content = array( + self::$nm_index => egw_session::appsession('index','mail'), + ); + if (!is_array($content[self::$nm_index])) + { + $content[self::$nm_index] = array( + 'get_rows' => 'mail.mail_ui.get_rows', // I method/callback to request the data for the rows eg. 'notes.bo.get_rows' + 'filter' => 'any', // filter is used to choose the mailbox + 'no_filter2' => false, // I disable the 2. filter (params are the same as for filter) + 'no_cat' => true, // I disable the cat-selectbox + //'cat_is_select' => 'no_lang', // true or no_lang + 'lettersearch' => false, // I show a lettersearch + 'searchletter' => false, // I0 active letter of the lettersearch or false for [all] + 'start' => 0, // IO position in list + 'order' => 'date', // IO name of the column to sort after (optional for the sortheaders) + 'sort' => 'DESC', // IO direction of the sort: 'ASC' or 'DESC' + //'default_cols' => 'status,attachments,subject,'.($toSchema?'toaddress':'fromaddress').',date,size', // I columns to use if there's no user or default pref (! as first char uses all but the named columns), default all columns + //'default_cols' => 'status,attachments,subject,address,date,size', // I columns to use if there's no user or default pref (! as first char uses all but the named columns), default all columns + //'csv_fields' => false, // I false=disable csv export, true or unset=enable it with auto-detected fieldnames, + //or array with name=>label or name=>array('label'=>label,'type'=>type) pairs (type is a eT widget-type) + 'actions' => self::get_actions(), + 'row_id' => 'row_id', // is a concatenation of trim($GLOBALS['egw_info']['user']['account_id']):profileID:base64_encode(FOLDERNAME):uid + 'placeholder_actions' => array('composeasnew') + ); + } + } + $content[self::$nm_index]['default_cols'] = 'status,attachments,subject,address,date,size'; // I columns to use if there's no user or default pref (! as first char uses all but the named columns), default all columns + $content[self::$nm_index]['csv_fields'] = false; + if ($msg) + { + $content['msg'] = $msg; + } + else + { + unset($msg); + unset($content['msg']); + } + + $quota = $this->mail_bo->getQuotaRoot(); + + if($quota !== false && $quota['limit'] != 'NOT SET') { + $quotainfo = $this->quotaDisplay($quota['usage'], $quota['limit']); + $content[self::$nm_index]['quota'] = $sel_options[self::$nm_index]['quota'] = $quotainfo['text']; + $content[self::$nm_index]['quotainpercent'] = $sel_options[self::$nm_index]['quotainpercent'] = (string)$quotainfo['percent']; + $content[self::$nm_index]['quotaclass'] = $sel_options[self::$nm_index]['quotaclass'] = $quotainfo['class']; + $content[self::$nm_index]['quotanotsupported'] = $sel_options[self::$nm_index]['quotanotsupported'] = ""; + } else { + $content[self::$nm_index]['quota'] = $sel_options[self::$nm_index]['quota'] = lang("Quota not provided by server"); + $content[self::$nm_index]['quotaclass'] = $sel_options[self::$nm_index]['quotaclass'] = "mail_DisplayNone"; + $content[self::$nm_index]['quotanotsupported'] = $sel_options[self::$nm_index]['quotanotsupported'] = "mail_DisplayNone"; + } + + $vacation = $this->gatherVacation(); + //error_log(__METHOD__.__LINE__.' Server:'.self::$icServerID.' Sieve Enabled:'.array2string($vacation)); + if($vacation) { + if (is_array($vacation) && ($vacation['status'] == 'on' || $vacation['status']=='by_date')) + { + $dtfrmt = $GLOBALS['egw_info']['user']['preferences']['common']['dateformat']/*.' '.($GLOBALS['egw_info']['user']['preferences']['common']['timeformat']!='24'?'h:i a':'H:i')*/; + $content[self::$nm_index]['vacationnotice'] = $sel_options[self::$nm_index]['vacationnotice'] = lang('Vacation notice is active'); + $content[self::$nm_index]['vacationrange'] = $sel_options[self::$nm_index]['vacationrange'] = ($vacation['status']=='by_date'? common::show_date($vacation['start_date'],$dtfrmt,true).($vacation['end_date']>$vacation['start_date']?'->'.common::show_date($vacation['end_date']+ 24*3600-1,$dtfrmt,true):''):''); + } + } + if ($vacation==false) + { + $content[self::$nm_index]['vacationnotice'] = $sel_options[self::$nm_index]['vacationnotice'] = ''; + $content[self::$nm_index]['vacationrange'] = $sel_options[self::$nm_index]['vacationrange'] = ''; + } + //$zstarttime = microtime (true); + $sel_options[self::$nm_index]['foldertree'] = $this->getFolderTree('initial',null,!$this->mail_bo->mailPreferences['showAllFoldersInFolderPane']); + //$zendtime = microtime(true) - $zstarttime; + //error_log(__METHOD__.__LINE__. " time used: ".$zendtime); + $content[self::$nm_index]['selectedFolder'] = $this->mail_bo->profileID.self::$delimiter.(!empty($this->mail_bo->sessionData['mailbox'])?$this->mail_bo->sessionData['mailbox']:'INBOX'); + // since we are connected,(and selected the folder) we check for capabilities SUPPORTS_KEYWORDS to eventually add the keyword filters + if ( $this->mail_bo->icServer->hasCapability('SUPPORTS_KEYWORDS')) + { + $this->statusTypes = array_merge($this->statusTypes,array( + 'keyword1' => 'important',//lang('important'), + 'keyword2' => 'job', //lang('job'), + 'keyword3' => 'personal',//lang('personal'), + 'keyword4' => 'to do', //lang('to do'), + 'keyword5' => 'later', //lang('later'), + )); + } + else + { + $keywords = array('keyword1','keyword2','keyword3','keyword4','keyword5'); + foreach($keywords as &$k) + { + if (array_key_exists($k,$this->statusTypes)) unset($this->statusTypes[$k]); + } + } + + if (!isset($content[self::$nm_index]['foldertree'])) $content[self::$nm_index]['foldertree'] = $this->mail_bo->profileID.self::$delimiter.'INBOX'; + if (!isset($content[self::$nm_index]['selectedFolder'])) $content[self::$nm_index]['selectedFolder'] = $this->mail_bo->profileID.self::$delimiter.'INBOX'; + + $content[self::$nm_index]['foldertree'] = $content[self::$nm_index]['selectedFolder']; + + if (is_null(emailadmin_imapbase::$supportsORinQuery) || !isset(emailadmin_imapbase::$supportsORinQuery[$this->mail_bo->profileID])) + { + emailadmin_imapbase::$supportsORinQuery = egw_cache::getCache(egw_cache::INSTANCE, 'email', 'supportsORinQuery'.trim($GLOBALS['egw_info']['user']['account_id']), null, array(), 60*60*10); + if (!isset(emailadmin_imapbase::$supportsORinQuery[$this->mail_bo->profileID])) emailadmin_imapbase::$supportsORinQuery[$this->mail_bo->profileID]=true; + } + if (!emailadmin_imapbase::$supportsORinQuery[$this->mail_bo->profileID]) unset($this->searchTypes['quick']); + $sel_options['filter2'] = $this->searchTypes; + $sel_options['filter'] = $this->statusTypes; + + $etpl = new etemplate_new('mail.index'); + $group=0; + // Set tree actions + $tree_actions = array( + 'drop_move_mail' => array( + 'type' => 'drop', + 'acceptedTypes' => 'mail', + 'icon' => 'move', + 'caption' => 'Move to', + 'onExecute' => 'javaScript:app.mail.mail_move' + ), + 'drop_copy_mail' => array( + 'type' => 'drop', + 'acceptedTypes' => 'mail', + 'icon' => 'copy', + 'caption' => 'Copy to', + 'onExecute' => 'javaScript:app.mail.mail_copy' + ), + 'drop_cancel' => array( + 'icon' => 'cancel', + 'caption' => 'Cancel', + 'acceptedTypes' => 'mail', + 'type' => 'drop', + ), + 'drop_move_folder' => array( + 'caption' => 'Move folder', + 'hideOnDisabled' => true, + 'type' => 'drop', + 'acceptedTypes' => 'mailFolder', + 'onExecute' => 'javaScript:app.mail.mail_MoveFolder' + ), + // Tree does support this one + 'add' => array( + 'caption' => 'Add Folder', + 'onExecute' => 'javaScript:app.mail.mail_AddFolder', + 'enabled' => 'javaScript:app.mail.mail_CheckFolderNoSelect', + ), + 'edit' => array( + 'caption' => 'Rename Folder', + 'onExecute' => 'javaScript:app.mail.mail_RenameFolder', + 'enabled' => 'javaScript:app.mail.mail_CheckFolderNoSelect', + ), + 'move' => array( + 'caption' => 'Move Folder', + 'type' => 'drag', + 'enabled' => 'javaScript:app.mail.mail_CheckFolderNoSelect', + 'dragType' => array('mailFolder') + ), + 'delete' => array( + 'caption' => 'Delete Folder', + 'enabled' => 'javaScript:app.mail.mail_CheckFolderNoSelect', + 'onExecute' => 'javaScript:app.mail.mail_DeleteFolder', + ), + 'subscribe' => array( + 'caption' => 'Subscribe folder ...', + //'icon' => 'configure', + 'enabled' => 'javaScript:app.mail.mail_CheckFolderNoSelect', + 'onExecute' => 'javaScript:app.mail.edit_subscribe', + ), + 'unsubscribe' => array( + 'caption' => 'Unsubscribe folder', + 'enabled' => 'javaScript:app.mail.mail_CheckFolderNoSelect', + 'onExecute' => 'javaScript:app.mail.unsubscribe_folder', + ), + 'sieve' => array( + 'caption' => 'Mail filter', + 'onExecute' => 'javaScript:app.mail.edit_sieve', + 'group' => ++$group, // new group for filter + 'enabled' => 'javaScript:app.mail.sieve_enabled', + 'icon' => 'etemplate/fav_filter', // funnel + ), + 'vacation' => array( + 'caption' => 'Vacation notice', + 'icon' => 'mail/navbar', // mail as in admin + 'onExecute' => 'javaScript:app.mail.edit_vacation', + 'group' => $group, + 'enabled' => 'javaScript:app.mail.sieve_enabled', + ), + 'edit_account' => array( + 'caption' => 'Edit account ...', + 'icon' => 'configure', + 'onExecute' => 'javaScript:app.mail.edit_account', + 'group' => ++$group, // new groups for account & acl + ), + 'edit_acl' => array( + 'caption' => 'Edit folder ACL ...', + 'icon' => 'lock', + 'enabled' => 'javaScript:app.mail.acl_enabled', + 'onExecute' => 'javaScript:app.mail.edit_acl', + 'group' => $group, + ), ); - } - } - $content[self::$nm_index]['default_cols'] = 'status,attachments,subject,address,date,size'; // I columns to use if there's no user or default pref (! as first char uses all but the named columns), default all columns - $content[self::$nm_index]['csv_fields'] = false; - if ($msg) - { - $content['msg'] = $msg; - } - else - { - unset($msg); - unset($content['msg']); - } + // the preference prefaskformove controls actually if there is a popup on target or not + // if there are multiple options there is a popup on target, 0 for prefaskformove means + // that only move is available; 1 stands for move and cancel; 2 (should be the default if + // not set); so we are assuming this, when not set + if (isset($this->mail_bo->mailPreferences['prefaskformove'])) + { + switch ($this->mail_bo->mailPreferences['prefaskformove']) + { + case 0: + unset($tree_actions['drop_copy_mail']); + unset($tree_actions['drop_cancel']); + break; + case 1: + unset($tree_actions['drop_copy_mail']); + break; + default: + // everything is fine + } + } + //error_log(__METHOD__.__LINE__.' showAllFoldersInFolderPane:'.$this->mail_bo->mailPreferences['showAllFoldersInFolderPane'].'/'.$GLOBALS['egw_info']['user']['preferences']['mail']['showAllFoldersInFolderPane']); + if ($this->mail_bo->mailPreferences['showAllFoldersInFolderPane']) + { + unset($tree_actions['subscribe']); + unset($tree_actions['unsubscribe']); + } + ++$group; // put delete in own group + switch($GLOBALS['egw_info']['user']['preferences']['mail']['deleteOptions']) + { + case 'move_to_trash': + $tree_actions['empty_trash'] = array( + 'caption' => 'empty trash', + 'icon' => 'dhtmlxtree/MailFolderTrash', + 'onExecute' => 'javaScript:app.mail.mail_emptyTrash', + 'group' => $group, + ); + break; + case 'mark_as_deleted': + $tree_actions['compress_folder'] = array( + 'caption' => 'compress folder', + 'icon' => 'dhtmlxtree/MailFolderTrash', + 'onExecute' => 'javaScript:app.mail.mail_compressFolder', + 'group' => $group, + ); + break; + } - $quota = $this->mail_bo->getQuotaRoot(); + // enforce global (group-specific) ACL + if (!mail_hooks::access('aclmanagement')) + { + unset($tree_actions['edit_acl']); + } + if (!mail_hooks::access('editfilterrules')) + { + unset($tree_actions['sieve']); + } + if (!mail_hooks::access('absentnotice')) + { + unset($tree_actions['vacation']); + } + if (!mail_hooks::access('managefolders')) + { + unset($tree_actions['add']); + unset($tree_actions['move']); + unset($tree_actions['delete']); + // manage folders should not affect the ability to subscribe or unsubscribe + // to existing folders, it should only affect add/rename/move/delete + } - if($quota !== false && $quota['limit'] != 'NOT SET') { - $quotainfo = $this->quotaDisplay($quota['usage'], $quota['limit']); - $content[self::$nm_index]['quota'] = $sel_options[self::$nm_index]['quota'] = $quotainfo['text']; - $content[self::$nm_index]['quotainpercent'] = $sel_options[self::$nm_index]['quotainpercent'] = (string)$quotainfo['percent']; - $content[self::$nm_index]['quotaclass'] = $sel_options[self::$nm_index]['quotaclass'] = $quotainfo['class']; - $content[self::$nm_index]['quotanotsupported'] = $sel_options[self::$nm_index]['quotanotsupported'] = ""; - } else { - $content[self::$nm_index]['quota'] = $sel_options[self::$nm_index]['quota'] = lang("Quota not provided by server"); - $content[self::$nm_index]['quotaclass'] = $sel_options[self::$nm_index]['quotaclass'] = "mail_DisplayNone"; - $content[self::$nm_index]['quotanotsupported'] = $sel_options[self::$nm_index]['quotanotsupported'] = "mail_DisplayNone"; - } + $etpl->setElementAttribute(self::$nm_index.'[foldertree]','actions', $tree_actions); - $vacation = $this->gatherVacation(); - //error_log(__METHOD__.__LINE__.' Server:'.self::$icServerID.' Sieve Enabled:'.array2string($vacation)); - if($vacation) { - if (is_array($vacation) && ($vacation['status'] == 'on' || $vacation['status']=='by_date')) - { - $dtfrmt = $GLOBALS['egw_info']['user']['preferences']['common']['dateformat']/*.' '.($GLOBALS['egw_info']['user']['preferences']['common']['timeformat']!='24'?'h:i a':'H:i')*/; - $content[self::$nm_index]['vacationnotice'] = $sel_options[self::$nm_index]['vacationnotice'] = lang('Vacation notice is active'); - $content[self::$nm_index]['vacationrange'] = $sel_options[self::$nm_index]['vacationrange'] = ($vacation['status']=='by_date'? common::show_date($vacation['start_date'],$dtfrmt,true).($vacation['end_date']>$vacation['start_date']?'->'.common::show_date($vacation['end_date']+ 24*3600-1,$dtfrmt,true):''):''); - } - } - if ($vacation==false) - { - $content[self::$nm_index]['vacationnotice'] = $sel_options[self::$nm_index]['vacationnotice'] = ''; - $content[self::$nm_index]['vacationrange'] = $sel_options[self::$nm_index]['vacationrange'] = ''; - } - //$zstarttime = microtime (true); - $sel_options[self::$nm_index]['foldertree'] = $this->getFolderTree('initial',null,!$this->mail_bo->mailPreferences['showAllFoldersInFolderPane']); - //$zendtime = microtime(true) - $zstarttime; - //error_log(__METHOD__.__LINE__. " time used: ".$zendtime); - $content[self::$nm_index]['selectedFolder'] = $this->mail_bo->profileID.self::$delimiter.(!empty($this->mail_bo->sessionData['mailbox'])?$this->mail_bo->sessionData['mailbox']:'INBOX'); - // since we are connected,(and selected the folder) we check for capabilities SUPPORTS_KEYWORDS to eventually add the keyword filters - if ( $this->mail_bo->icServer->hasCapability('SUPPORTS_KEYWORDS')) - { - $this->statusTypes = array_merge($this->statusTypes,array( - 'keyword1' => 'important',//lang('important'), - 'keyword2' => 'job', //lang('job'), - 'keyword3' => 'personal',//lang('personal'), - 'keyword4' => 'to do', //lang('to do'), - 'keyword5' => 'later', //lang('later'), - )); - } - else - { - $keywords = array('keyword1','keyword2','keyword3','keyword4','keyword5'); - foreach($keywords as &$k) - { - if (array_key_exists($k,$this->statusTypes)) unset($this->statusTypes[$k]); - } - } + // sending preview toolbar actions + $etpl->setElementAttribute('mailPreview[toolbar]', 'actions', $this->get_toolbar_actions()); - if (!isset($content[self::$nm_index]['foldertree'])) $content[self::$nm_index]['foldertree'] = $this->mail_bo->profileID.self::$delimiter.'INBOX'; - if (!isset($content[self::$nm_index]['selectedFolder'])) $content[self::$nm_index]['selectedFolder'] = $this->mail_bo->profileID.self::$delimiter.'INBOX'; - - $content[self::$nm_index]['foldertree'] = $content[self::$nm_index]['selectedFolder']; - - if (is_null(emailadmin_imapbase::$supportsORinQuery) || !isset(emailadmin_imapbase::$supportsORinQuery[$this->mail_bo->profileID])) - { - emailadmin_imapbase::$supportsORinQuery = egw_cache::getCache(egw_cache::INSTANCE, 'email', 'supportsORinQuery'.trim($GLOBALS['egw_info']['user']['account_id']), null, array(), 60*60*10); - if (!isset(emailadmin_imapbase::$supportsORinQuery[$this->mail_bo->profileID])) emailadmin_imapbase::$supportsORinQuery[$this->mail_bo->profileID]=true; + if (empty($content[self::$nm_index]['filter2']) || empty($content[self::$nm_index]['search'])) $content[self::$nm_index]['filter2']=(emailadmin_imapbase::$supportsORinQuery[$this->mail_bo->profileID]?'quick':'subject'); + $readonlys = $preserv = array(); + if (mail_bo::$debugTimes) mail_bo::logRunTimes($starttime,null,'',__METHOD__.__LINE__); } - if (!emailadmin_imapbase::$supportsORinQuery[$this->mail_bo->profileID]) unset($this->searchTypes['quick']); - $sel_options['filter2'] = $this->searchTypes; - $sel_options['filter'] = $this->statusTypes; - - $etpl = new etemplate_new('mail.index'); - $group=0; - // Set tree actions - $tree_actions = array( - 'drop_move_mail' => array( - 'type' => 'drop', - 'acceptedTypes' => 'mail', - 'icon' => 'move', - 'caption' => 'Move to', - 'onExecute' => 'javaScript:app.mail.mail_move' - ), - 'drop_copy_mail' => array( - 'type' => 'drop', - 'acceptedTypes' => 'mail', - 'icon' => 'copy', - 'caption' => 'Copy to', - 'onExecute' => 'javaScript:app.mail.mail_copy' - ), - 'drop_cancel' => array( - 'icon' => 'cancel', - 'caption' => 'Cancel', - 'acceptedTypes' => 'mail', - 'type' => 'drop', - ), - 'drop_move_folder' => array( - 'caption' => 'Move folder', - 'hideOnDisabled' => true, - 'type' => 'drop', - 'acceptedTypes' => 'mailFolder', - 'onExecute' => 'javaScript:app.mail.mail_MoveFolder' - ), - // Tree does support this one - 'add' => array( - 'caption' => 'Add Folder', - 'onExecute' => 'javaScript:app.mail.mail_AddFolder', - 'enabled' => 'javaScript:app.mail.mail_CheckFolderNoSelect', - ), - 'edit' => array( - 'caption' => 'Rename Folder', - 'onExecute' => 'javaScript:app.mail.mail_RenameFolder', - 'enabled' => 'javaScript:app.mail.mail_CheckFolderNoSelect', - ), - 'move' => array( - 'caption' => 'Move Folder', - 'type' => 'drag', - 'enabled' => 'javaScript:app.mail.mail_CheckFolderNoSelect', - 'dragType' => array('mailFolder') - ), - 'delete' => array( - 'caption' => 'Delete Folder', - 'enabled' => 'javaScript:app.mail.mail_CheckFolderNoSelect', - 'onExecute' => 'javaScript:app.mail.mail_DeleteFolder', - ), - 'subscribe' => array( - 'caption' => 'Subscribe folder ...', - //'icon' => 'configure', - 'enabled' => 'javaScript:app.mail.mail_CheckFolderNoSelect', - 'onExecute' => 'javaScript:app.mail.edit_subscribe', - ), - 'unsubscribe' => array( - 'caption' => 'Unsubscribe folder', - 'enabled' => 'javaScript:app.mail.mail_CheckFolderNoSelect', - 'onExecute' => 'javaScript:app.mail.unsubscribe_folder', - ), - 'sieve' => array( - 'caption' => 'Mail filter', - 'onExecute' => 'javaScript:app.mail.edit_sieve', - 'group' => ++$group, // new group for filter - 'enabled' => 'javaScript:app.mail.sieve_enabled', - 'icon' => 'etemplate/fav_filter', // funnel - ), - 'vacation' => array( - 'caption' => 'Vacation notice', - 'icon' => 'mail/navbar', // mail as in admin - 'onExecute' => 'javaScript:app.mail.edit_vacation', - 'group' => $group, - 'enabled' => 'javaScript:app.mail.sieve_enabled', - ), - 'edit_account' => array( - 'caption' => 'Edit account ...', - 'icon' => 'configure', - 'onExecute' => 'javaScript:app.mail.edit_account', - 'group' => ++$group, // new groups for account & acl - ), - 'edit_acl' => array( - 'caption' => 'Edit folder ACL ...', - 'icon' => 'lock', - 'enabled' => 'javaScript:app.mail.acl_enabled', - 'onExecute' => 'javaScript:app.mail.edit_acl', - 'group' => $group, - ), - ); - // the preference prefaskformove controls actually if there is a popup on target or not - // if there are multiple options there is a popup on target, 0 for prefaskformove means - // that only move is available; 1 stands for move and cancel; 2 (should be the default if - // not set); so we are assuming this, when not set - if (isset($this->mail_bo->mailPreferences['prefaskformove'])) + catch (Exception $e) { - switch ($this->mail_bo->mailPreferences['prefaskformove']) - { - case 0: - unset($tree_actions['drop_copy_mail']); - unset($tree_actions['drop_cancel']); - break; - case 1: - unset($tree_actions['drop_copy_mail']); - break; - default: - // everything is fine - } + self::callWizard($e->getMessage()); } - //error_log(__METHOD__.__LINE__.' showAllFoldersInFolderPane:'.$this->mail_bo->mailPreferences['showAllFoldersInFolderPane'].'/'.$GLOBALS['egw_info']['user']['preferences']['mail']['showAllFoldersInFolderPane']); - if ($this->mail_bo->mailPreferences['showAllFoldersInFolderPane']) - { - unset($tree_actions['subscribe']); - unset($tree_actions['unsubscribe']); - } - ++$group; // put delete in own group - switch($GLOBALS['egw_info']['user']['preferences']['mail']['deleteOptions']) - { - case 'move_to_trash': - $tree_actions['empty_trash'] = array( - 'caption' => 'empty trash', - 'icon' => 'dhtmlxtree/MailFolderTrash', - 'onExecute' => 'javaScript:app.mail.mail_emptyTrash', - 'group' => $group, - ); - break; - case 'mark_as_deleted': - $tree_actions['compress_folder'] = array( - 'caption' => 'compress folder', - 'icon' => 'dhtmlxtree/MailFolderTrash', - 'onExecute' => 'javaScript:app.mail.mail_compressFolder', - 'group' => $group, - ); - break; - } - - // enforce global (group-specific) ACL - if (!mail_hooks::access('aclmanagement')) - { - unset($tree_actions['edit_acl']); - } - if (!mail_hooks::access('editfilterrules')) - { - unset($tree_actions['sieve']); - } - if (!mail_hooks::access('absentnotice')) - { - unset($tree_actions['vacation']); - } - if (!mail_hooks::access('managefolders')) - { - unset($tree_actions['add']); - unset($tree_actions['move']); - unset($tree_actions['delete']); - // manage folders should not affect the ability to subscribe or unsubscribe - // to existing folders, it should only affect add/rename/move/delete - } - - $etpl->setElementAttribute(self::$nm_index.'[foldertree]','actions', $tree_actions); - - // sending preview toolbar actions - $etpl->setElementAttribute('mailPreview[toolbar]', 'actions', $this->get_toolbar_actions()); - - if (empty($content[self::$nm_index]['filter2']) || empty($content[self::$nm_index]['search'])) $content[self::$nm_index]['filter2']=(emailadmin_imapbase::$supportsORinQuery[$this->mail_bo->profileID]?'quick':'subject'); - $readonlys = $preserv = array(); - if (mail_bo::$debugTimes) mail_bo::logRunTimes($starttime,null,'',__METHOD__.__LINE__); return $etpl->exec('mail.mail_ui.index',$content,$sel_options,$readonlys,$preserv); } @@ -2259,19 +2261,12 @@ class mail_ui $vacation = $this->mail_bo->icServer->acc_sieve_enabled && ($this->mail_bo->icServer->acc_sieve_host||$this->mail_bo->icServer->acc_imap_host); //error_log(__METHOD__.__LINE__.' Server:'.self::$icServerID.' Sieve Enabled:'.array2string($vacation)); - if ($vacation && (!($isSieveError = egw_cache::getCache(egw_cache::INSTANCE, 'email', - 'icServerSIEVE_connectionError'.trim($GLOBALS['egw_info']['user']['account_id']))) || !$isSieveError[self::$icServerID])) + if ($vacation) { $sieveServer = $this->mail_bo->icServer; - try { - $sieveServer->retrieveRules(); - $vacation = $sieveServer->getVacation(); - } - catch (Exception $e) - { - $vacation = false; - error_log(__METHOD__.__LINE__."Failed to retrive vacation rules because of ".$e->getMessage()); - } + + $sieveServer->retrieveRules(); + $vacation = $sieveServer->getVacation(); } //error_log(__METHOD__.__LINE__.' Server:'.self::$icServerID.' Vacation retrieved:'.array2string($vacation)); return $vacation; From 95e1fb860af256929f4ef9f3a26d20ee167c19a3 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Fri, 18 Jul 2014 17:22:28 +0000 Subject: [PATCH 10/49] Make sure et2 is availabe, because it could be not available over cases like when mail connection error. It Fixes error: "can not read getWidgetById of undefined" --- mail/js/app.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mail/js/app.js b/mail/js/app.js index edec6379ac..ea1d711f79 100644 --- a/mail/js/app.js +++ b/mail/js/app.js @@ -227,7 +227,7 @@ app.classes.mail = AppJS.extend( break; case 'emailadmin': // update tree with given mail account _id and _type - var tree = this.et2.getWidgetById(this.nm_index+'[foldertree]'); + var tree = this.et2 ? this.et2.getWidgetById(this.nm_index+'[foldertree]') : null; if (!tree) break; var node = tree.getNode(_id); switch(_type) @@ -1209,7 +1209,8 @@ app.classes.mail = AppJS.extend( * Object with the required data (KEY id, VALUE desc), or ID => {new data} */ mail_reloadNode: function(_status) { - var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]'); + var ftree = this.et2?this.et2.getWidgetById(this.nm_index+'[foldertree]'):null; + if (!ftree) return; var selectedNode = ftree.getSelectedNode(); for (var i in _status) { From 9f07b914907e08b79dbf2b36014b6f9c89744eca Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Mon, 21 Jul 2014 07:02:48 +0000 Subject: [PATCH 11/49] quiten open_basedir warnings, when minify tries to access docroot --- phpgwapi/inc/min/lib/Minify/CSS/UriRewriter.php | 2 +- phpgwapi/inc/min/lib/Minify/Controller/MinApp.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/phpgwapi/inc/min/lib/Minify/CSS/UriRewriter.php b/phpgwapi/inc/min/lib/Minify/CSS/UriRewriter.php index e670340e36..79f7d98e69 100755 --- a/phpgwapi/inc/min/lib/Minify/CSS/UriRewriter.php +++ b/phpgwapi/inc/min/lib/Minify/CSS/UriRewriter.php @@ -208,7 +208,7 @@ class Minify_CSS_UriRewriter { */ protected static function _realpath($path) { - $realPath = realpath($path); + $realPath = @realpath($path); if ($realPath !== false) { $path = $realPath; } diff --git a/phpgwapi/inc/min/lib/Minify/Controller/MinApp.php b/phpgwapi/inc/min/lib/Minify/Controller/MinApp.php index 7988526f26..54febee474 100755 --- a/phpgwapi/inc/min/lib/Minify/Controller/MinApp.php +++ b/phpgwapi/inc/min/lib/Minify/Controller/MinApp.php @@ -142,7 +142,7 @@ class Minify_Controller_MinApp extends Minify_Controller_Base { } $base_path = $_SERVER['DOCUMENT_ROOT'].$base; // check base against symlinks to support aliases configured via symlinks - if (!(file_exists($base_path) && is_dir($base_path) && realpath($base_path) !== false) && + if (!(file_exists($base_path) && is_dir($base_path) && @realpath($base_path) !== false) && isset($options['minifierOptions']['text/css']['symlinks'][$t='//'.trim($base, '/')]) && ($base_path = realpath($options['minifierOptions']['text/css']['symlinks'][$t]))) { $base_path .= '/'; From cdd295fd5ce78b7a053a71b44274886b7b939156 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Mon, 21 Jul 2014 08:22:11 +0000 Subject: [PATCH 12/49] quiten open_basedir warnings, when minify tries to access docroot --- phpgwapi/inc/min/lib/Minify/Controller/MinApp.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpgwapi/inc/min/lib/Minify/Controller/MinApp.php b/phpgwapi/inc/min/lib/Minify/Controller/MinApp.php index 54febee474..4def285e04 100755 --- a/phpgwapi/inc/min/lib/Minify/Controller/MinApp.php +++ b/phpgwapi/inc/min/lib/Minify/Controller/MinApp.php @@ -142,7 +142,7 @@ class Minify_Controller_MinApp extends Minify_Controller_Base { } $base_path = $_SERVER['DOCUMENT_ROOT'].$base; // check base against symlinks to support aliases configured via symlinks - if (!(file_exists($base_path) && is_dir($base_path) && @realpath($base_path) !== false) && + if (!(@file_exists($base_path) && is_dir($base_path) && realpath($base_path) !== false) && isset($options['minifierOptions']['text/css']['symlinks'][$t='//'.trim($base, '/')]) && ($base_path = realpath($options['minifierOptions']['text/css']['symlinks'][$t]))) { $base_path .= '/'; From 1960c8c7f7e147c1737c9c227ac9aa224da1794f Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Mon, 21 Jul 2014 09:38:35 +0000 Subject: [PATCH 13/49] Fix calendar Action->Infolog opens not as popup --- calendar/js/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calendar/js/app.js b/calendar/js/app.js index aa77fa5129..9c1e0b2193 100644 --- a/calendar/js/app.js +++ b/calendar/js/app.js @@ -698,7 +698,7 @@ app.classes.calendar = AppJS.extend( this.et2._inst.submit(); break; case 'infolog': - this.egw.open_link('infolog.infolog_ui.edit&action=calendar&action_id='+($j.isPlainObject(event)?event['id']:event),'_self','700x600','infolog'); + this.egw.open_link('infolog.infolog_ui.edit&action=calendar&action_id='+($j.isPlainObject(event)?event['id']:event),'_blank','700x600','infolog'); this.et2._inst.submit(); break; case 'ical': From 62498c91e73c36741f2ecd9c1e5ed9ded0a19577 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Mon, 21 Jul 2014 12:19:07 +0000 Subject: [PATCH 14/49] Add translation for global categories delete confirmation dialog --- admin/lang/egw_de.lang | 1 + 1 file changed, 1 insertion(+) diff --git a/admin/lang/egw_de.lang b/admin/lang/egw_de.lang index c0f764a825..c1f48f46e1 100644 --- a/admin/lang/egw_de.lang +++ b/admin/lang/egw_de.lang @@ -191,6 +191,7 @@ delete all records admin de Alle Einträge löschen delete application admin de Anwendung löschen delete category admin de Kategorie löschen delete group admin de Gruppe löschen +delete including sub-enteries common de Inklusive Untereinträge löschen delete peer server admin de Server von Serververbund löschen delete selected entries admin de Ausgewählte Einträge löschen delete the category admin de Kategorie löschen From 3c6130f7e664a465a6870c191b856d2beafded8c Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Mon, 21 Jul 2014 12:57:32 +0000 Subject: [PATCH 15/49] setting an (unlikely) custom delimiter, to allow to use "," in value, eg. folder-name, IF values are specified as array --- etemplate/js/et2_widget_tree.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/etemplate/js/et2_widget_tree.js b/etemplate/js/et2_widget_tree.js index ff039356c9..75b4616fb5 100644 --- a/etemplate/js/et2_widget_tree.js +++ b/etemplate/js/et2_widget_tree.js @@ -188,12 +188,15 @@ var et2_tree = et2_inputWidget.extend( image_path: widget.options.image_path, checkbox: widget.options.multiple }); + // to allow "," in value, eg. folder-names, IF value is specified as array + widget.input.dlmtr = ':}-*('; + if (widget.options.std_images) { widget.setImages.apply(widget, widget.options.std_images.split(',')); } // Add in the callback so we can keep the two in sync - widget.input.AJAX_callback = function(dxmlObject) { + widget.input.AJAX_callback = function(dxmlObject) { widget._dhtmlxtree_json_callback(JSON.parse(dxmlObject.xmlDoc.responseText), widget.input.lastLoadedXMLId); }; From f337b335023850957f17dd2c3fc2800c7f8bd564 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Mon, 21 Jul 2014 13:38:23 +0000 Subject: [PATCH 16/49] * eTemplate2: fixed popups eg. tracker open empty, not rendering popup content --- phpgwapi/js/jsapi/egw.js | 41 ++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/phpgwapi/js/jsapi/egw.js b/phpgwapi/js/jsapi/egw.js index 3caf158ee8..06d4e5f2f4 100644 --- a/phpgwapi/js/jsapi/egw.js +++ b/phpgwapi/js/jsapi/egw.js @@ -214,27 +214,28 @@ window.framework.setSidebox.apply(window.framework, JSON.parse(sidebox)); } - // load etemplate2 template(s) - $j('div.et2_container[data-etemplate]').each(function(index, node){ - var data = JSON.parse(node.getAttribute('data-etemplate')) || {}; - var currentapp = data.data.currentapp || window.egw_appName; - if(popup || window.opener) - { - // Resize popup when et2 load is done - jQuery(node).one("load",function() { - window.resizeTo(jQuery(document).width()+25,jQuery(document).height()+70); - }); - } - var et2 = new etemplate2(node, currentapp+".etemplate_new.ajax_process_content.etemplate"); - et2.load(data.name,data.url,data.data); - if (typeof data.response != 'undefined') - { - var json_request = egw(window).json(); - json_request.handleResponse({response: data.response}); - } - }); - + // rest needs DOM to be ready $j(function() { + // load etemplate2 template(s) + $j('div.et2_container[data-etemplate]').each(function(index, node){ + var data = JSON.parse(node.getAttribute('data-etemplate')) || {}; + var currentapp = data.data.currentapp || window.egw_appName; + if(popup || window.opener) + { + // Resize popup when et2 load is done + jQuery(node).one("load",function() { + window.resizeTo(jQuery(document).width()+25,jQuery(document).height()+70); + }); + } + var et2 = new etemplate2(node, currentapp+".etemplate_new.ajax_process_content.etemplate"); + et2.load(data.name,data.url,data.data); + if (typeof data.response != 'undefined') + { + var json_request = egw(window).json(); + json_request.handleResponse({response: data.response}); + } + }); + // set app-header if (window.framework && egw_script.getAttribute('data-app-header')) { From d6d627229954ae0ecc8588e0aae9d49fb36a09f8 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Mon, 21 Jul 2014 14:37:15 +0000 Subject: [PATCH 17/49] * Admin/LDAP: deactivated accounts could not be reactivated, as account popup was not showing selected account --- addressbook/inc/class.addressbook_ldap.inc.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/addressbook/inc/class.addressbook_ldap.inc.php b/addressbook/inc/class.addressbook_ldap.inc.php index 990de28da8..4a37e3dbd0 100644 --- a/addressbook/inc/class.addressbook_ldap.inc.php +++ b/addressbook/inc/class.addressbook_ldap.inc.php @@ -411,7 +411,7 @@ class addressbook_ldap $filter = $this->id_filter($contact_id); } $rows = $this->_searchLDAP($this->allContactsDN, - $filter, $this->all_attributes, ADDRESSBOOK_ALL); + $filter, $this->all_attributes, ADDRESSBOOK_ALL, array('_posixaccount2egw')); return $rows ? $rows[0] : false; } @@ -996,9 +996,10 @@ class addressbook_ldap * @param string $_filter * @param array $_attributes * @param int $_addressbooktype + * @param array $_skipPlugins=null schema-plugins to skip * @return array/boolean with eGW contacts or false on error */ - function _searchLDAP($_ldapContext, $_filter, $_attributes, $_addressbooktype) + function _searchLDAP($_ldapContext, $_filter, $_attributes, $_addressbooktype, array $_skipPlugins=null) { $this->total = 0; @@ -1046,7 +1047,7 @@ class addressbook_ldap } } $objectclass2egw = '_'.$objectclass.'2egw'; - if (method_exists($this,$objectclass2egw)) + if (!in_array($objectclass2egw, (array)$_skipPlugins) &&method_exists($this,$objectclass2egw)) { if (($ret=$this->$objectclass2egw($contact,$entry)) === false) { From 6a0c7e2c3de0daa565f499318e4c178daeccb831 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Mon, 21 Jul 2014 15:27:15 +0000 Subject: [PATCH 18/49] log not compiling PHP expressions as warning, as they are most likely caused by wired content, eg. filenames containing a $ --- etemplate/js/et2_core_phpExpressionCompiler.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/etemplate/js/et2_core_phpExpressionCompiler.js b/etemplate/js/et2_core_phpExpressionCompiler.js index 558f35a172..a60a055910 100644 --- a/etemplate/js/et2_core_phpExpressionCompiler.js +++ b/etemplate/js/et2_core_phpExpressionCompiler.js @@ -430,8 +430,8 @@ egw.debug("log", "Compiled PHP " + _expr + " --> " + js); } catch(e) { - // if expression does NOT compile use it literally and log an error, but not stop execution - egw.debug("error", "Error compiling PHP "+_expr+" --> using it literally ("+ + // if expression does NOT compile use it literally and log a warning, but not stop execution + egw.debug("warn", "Error compiling PHP "+_expr+" --> using it literally ("+ (typeof e == 'string' ? e : e.message)+")!"); return function(){ return _expr; }; } From bd4128878830784bf9cc99f96ff6902c544f14b3 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Mon, 21 Jul 2014 16:31:10 +0000 Subject: [PATCH 19/49] - Add special handling for ids like something[{$row}] to only send select options once - Don't need to process or send options for account, it is done client side now. --- .../class.etemplate_widget_menupopup.inc.php | 33 +++++-------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/etemplate/inc/class.etemplate_widget_menupopup.inc.php b/etemplate/inc/class.etemplate_widget_menupopup.inc.php index e38712913d..9587edf56d 100644 --- a/etemplate/inc/class.etemplate_widget_menupopup.inc.php +++ b/etemplate/inc/class.etemplate_widget_menupopup.inc.php @@ -184,6 +184,11 @@ class etemplate_widget_menupopup extends etemplate_widget { $form_name = $matches[2]; } + // happens in auto-repeat grids: $cname='', this->id='something[{$row}]' + elseif (preg_match('/([^[]+)\[({\$row})\]$/', $this->id, $matches)) + { + $form_name = $matches[1]; + } else { $form_name = self::form_name($cname, $this->id); @@ -224,6 +229,10 @@ class etemplate_widget_menupopup extends etemplate_widget { self::setElementAttribute($form_name, "search", true); } + if(!self::$request->sel_options[$options]) + { + unset(self::$request->sel_options[$options]); + } } } @@ -495,30 +504,6 @@ class etemplate_widget_menupopup extends etemplate_widget $no_lang = True; break; - case 'select-account': // options: #rows,{accounts(default)|both|groups|owngroups},{0(=lid)|1(default=name)|2(=lid+name),expand-multiselect-rows,not-to-show-accounts,...)} - // Get preference for selection display - - // Get important attributes in a non-legacy way - if($widget != null && $widget->attrs['account_type']) - { - $type = $widget->attrs['account_type']; - } - - $select_pref = $GLOBALS['egw_info']['user']['preferences']['common']['account_selection']; - // in case of readonly, we read/create only the needed entries, as reading accounts is expensive - if (!is_array($value) && strpos($value,',') !== false) $value = explode(',',$value); - if ($readonly || $select_pref == 'popup') - { - $no_lang = True; - foreach(is_array($value) ? $value : array($value) as $id) - { - $options[$id] = !$id && !is_numeric($rows) ? lang($rows) : - self::accountInfo($id, null, $type2, $type=='both'); - } - break; - } - break; - case 'select-year': // options: #rows,#before(default=3),#after(default=2) $options[''] = ''; if ($type <= 0) $type = 3; From 6c89d3a1b711a1863c5c27c077b6f4239d2e2555 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Mon, 21 Jul 2014 16:47:29 +0000 Subject: [PATCH 20/49] Fix unable to set EACL --- filemanager/inc/class.filemanager_ui.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filemanager/inc/class.filemanager_ui.inc.php b/filemanager/inc/class.filemanager_ui.inc.php index 4ee64ba526..751822797f 100644 --- a/filemanager/inc/class.filemanager_ui.inc.php +++ b/filemanager/inc/class.filemanager_ui.inc.php @@ -1058,7 +1058,7 @@ class filemanager_ui } else { - $msg .= egw_vfs::eacl($path,$content['rights'],$content['eacl_owner']) ? + $msg .= egw_vfs::eacl($path,$content['eacl']['rights'],$content['eacl_owner']) ? lang('ACL added.') : lang('Error adding the ACL!'); } } From ea6eb12cd4b841f7a01c681b014e10ac85809cb4 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Tue, 22 Jul 2014 08:05:42 +0000 Subject: [PATCH 21/49] Fix mail ACL popup dialog does not make delete button readonly for account owner --- mail/inc/class.mail_acl.inc.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mail/inc/class.mail_acl.inc.php b/mail/inc/class.mail_acl.inc.php index 4cc7e8d928..e1c3ba19a4 100644 --- a/mail/inc/class.mail_acl.inc.php +++ b/mail/inc/class.mail_acl.inc.php @@ -62,10 +62,10 @@ class mail_acl } /** - * Edit folder ACLs for account(s) + * Edit folder ACLs of account(s) * - * @param string $msg - * @param array $content + * @param string $content = null + * @param array $msg = '' * */ function edit(array $content=null ,$msg='') @@ -157,7 +157,7 @@ class mail_acl $msg .= "\n".lang("Error: Could not save ACL").' '.lang("reason!"); } //Send message - egw_framework::refresh_opener($msg, 'mail', 'update'); + egw_framework::refresh_opener($msg, 'mail',null, 'update'); if ($button == "apply") break; @@ -175,7 +175,7 @@ class mail_acl { error_log(__METHOD__.__LINE__. "()" . "The remove_acl suppose to return an array back, something is wrong there"); } - egw_framework::refresh_opener($msg, 'mail', 'update'); + egw_framework::refresh_opener($msg, 'mail', null,'update'); } } $readonlys = $sel_options = array(); @@ -184,8 +184,8 @@ class mail_acl //Make the delete buttons readonly for entry filed and account owner foreach($content['grid'] as $key => $field) { - if ($field['acc_id'] == $this->mail_bo->icServer->acc_name || - $field['acc_id'][0] == $this->mail_bo->icServer->acc_name) + if ($field['acc_id'] == $this->mail_bo->icServer->acc_imap_username || + $field['acc_id'][0] == $this->mail_bo->icServer->acc_imap_username) { $readonlys['grid']['delete['.$key.']'] = true; } From cd702481aff9c5975160a346015e67f78ca7d323 Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Tue, 22 Jul 2014 10:07:30 +0000 Subject: [PATCH 22/49] allow to call getAllIdentities for other users; used for Admin Calling eSync Prefs on Mail for other users --- mail/inc/class.mail_activesync.inc.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mail/inc/class.mail_activesync.inc.php b/mail/inc/class.mail_activesync.inc.php index 95b6c82f5c..b1fbab710e 100644 --- a/mail/inc/class.mail_activesync.inc.php +++ b/mail/inc/class.mail_activesync.inc.php @@ -157,7 +157,7 @@ class mail_activesync implements activesync_plugin_write, activesync_plugin_send */ function getAvailableProfiles($params = null) { - $allIdentities = mail_bo::getAllIdentities(); + $allIdentities = mail_bo::getAllIdentities(($params['account_id']?$params['account_id']:null)); $identities = array(); if (!isset($params['setup'])) { @@ -191,6 +191,7 @@ class mail_activesync implements activesync_plugin_write, activesync_plugin_send */ function settings($hook_data) { + //error_log(__METHOD__.__LINE__.array2string($hook_data)); $identities = array(); if (!isset($hook_data['setup'])) { From 9cfee0d9a4fcf82b296baeef8f417f010d3a5b0f Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Tue, 22 Jul 2014 10:44:03 +0000 Subject: [PATCH 23/49] fixed wired data-values created directly after migration to json, got semaphore working again and fixing all IDE warnings --- phpgwapi/inc/class.asyncservice.inc.php | 51 ++++++++++++++++--------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/phpgwapi/inc/class.asyncservice.inc.php b/phpgwapi/inc/class.asyncservice.inc.php index bbcfe774a3..4685178449 100644 --- a/phpgwapi/inc/class.asyncservice.inc.php +++ b/phpgwapi/inc/class.asyncservice.inc.php @@ -157,17 +157,17 @@ class asyncservice // as empty patterns get enumerated before the the last pattern and // get set to the minimum after // - $n = $first_set = $last_set = 0; + $i = $first_set = $last_set = 0; foreach($units as $u => $date_pattern) { - ++$n; + ++$i; if (isset($times[$u])) { - $last_set = $n; + $last_set = $i; if (!$first_set) { - $first_set = $n; + $first_set = $i; } } } @@ -261,6 +261,7 @@ class asyncservice // now we have the times enumerated, lets find the first not expired one // $found = array(); + $over = null; while (!isset($found['min'])) { $future = False; @@ -276,7 +277,7 @@ class asyncservice if ($this->debug) echo "--> already have a $u = ".$found[$u].", future='$future'
\n"; continue; // already set } - foreach($times[$u] as $unit_value => $nul) + foreach(array_keys($times[$u]) as $unit_value) { switch($u) { @@ -300,13 +301,13 @@ class asyncservice } if (!isset($found[$u])) // we have to try the next one, if it exists { - $next = array_keys($units); + $nexts = array_keys($units); if (!isset($next[count($found)-1])) { if ($this->debug) echo "

Nothing found, exiting !!!

\n"; return False; } - $next = $next[count($found)-1]; + $next = $nexts[count($found)-1]; $over = $found[$next]; unset($found[$next]); if ($this->debug) echo "

Have to try the next $next, $u's are over for $next=$over !!!

\n"; @@ -341,7 +342,7 @@ class asyncservice function last_check_run($semaphore=False,$release=False,$run_by='') { //echo "

last_check_run(semaphore=".($semaphore?'True':'False').",release=".($release?'True':'False').")

\n"; - if ($exists = $this->read('##last-check-run##')) + if (($exists = $this->read('##last-check-run##'))) { list(,$last_run) = each($exists); } @@ -379,7 +380,7 @@ class asyncservice if ($exists) $where = array('async_next=0 OR async_next<'.time()-600); } //echo "last_run=
"; print_r($last_run); echo "
\n"; - return $this->write($last_run,!!$exits,$where) > 0; + return $this->write($last_run, !!$exists, $where) > 0; } /** @@ -398,7 +399,7 @@ class asyncservice if (($jobs = $this->read())) { - foreach($jobs as $id => $job) + foreach($jobs as $job) { // checking / setting up egw_info/user // @@ -502,7 +503,16 @@ class asyncservice foreach($this->db->select($this->db_table,$cols,$where,__LINE__,__FILE__,$offset,$append,False,$num_rows) as $row) { $row['async_times'] = json_php_unserialize($row['async_times']); - $row['async_data'] = json_php_unserialize($row['async_data'], true); // allow non-serialized data + // check for broken value during migration + if ($row['async_data'][0] == '"' && substr($row['async_data'], 0, 7) == '"\\"\\\\\\"') + { + $row['async_data'] = null; + $this->write(egw_db::strip_array_keys($row,'async_'), true); + } + else + { + $row['async_data'] = json_php_unserialize($row['async_data'], true); // allow non-serialized data + } $jobs[$row['async_id']] = egw_db::strip_array_keys($row,'async_'); } if (!count($jobs)) @@ -520,7 +530,7 @@ class asyncservice * @param array $where additional where statemetn to update only if a certain condition is met, used for the semaphore * @return int affected rows, can be 0 if an additional where statement is given */ - function write($job,$exists = False,$where=array()) + function write($job, $exists = False, $where=array()) { if (!is_a($this->db, 'egw_db')) return 0; @@ -529,16 +539,17 @@ class asyncservice 'async_next' => $job['next'], 'async_times' => json_encode($job['times']), 'async_method' => $job['method'], - 'async_data' => json_encode($job['data']), + 'async_data' => $job['data'] ? json_encode($job['data']) : null, 'async_account_id'=> $job['account_id'], ); + $where['async_id'] = $job['id']; if ($exists) { - $this->db->update($this->db_table,$data,array('async_id' => $job['id']),__LINE__,__FILE__); + $this->db->update($this->db_table, $data, $where, __LINE__, __FILE__); } else { - $this->db->insert($this->db_table,$data,array('async_id' => $job['id']),__LINE__,__FILE__); + $this->db->insert($this->db_table, $data, $where, __LINE__, __FILE__); } return $this->db->affected_rows(); } @@ -562,7 +573,10 @@ class asyncservice { return; } - $run = True; + else + { + $run = True; + } if (substr(php_uname(), 0, 7) == "Windows") { @@ -592,12 +606,12 @@ class asyncservice $webserver = posix_getpwuid(posix_getuid ()); echo '

'.lang("You need to add the webserver user '%1' to the group '%2'.",$webserver['name'],$group['name'])."

\n"; } } - if ($fd = popen('/bin/sh -c "type -p '.$name.'"','r')) + if (($fd = popen('/bin/sh -c "type -p '.$name.'"','r'))) { $this->$name = fgets($fd,256); @pclose($fd); } - if ($pos = strpos($this->$name,"\n")) + if (($pos = strpos($this->$name,"\n"))) { $this->$name = substr($this->$name,0,$pos); } @@ -641,6 +655,7 @@ class asyncservice $this->other_cronlines = array(); if (($crontab = popen('/bin/sh -c "'.$this->crontab.' -l" 2>&1','r')) !== False) { + $n = 0; while ($line = fgets($crontab,256)) { if ($this->debug) echo 'line '.++$n.": $line
\n"; From be405e847c867019d98a395e276be5038fc685de Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Tue, 22 Jul 2014 11:11:28 +0000 Subject: [PATCH 24/49] allow all php serialized values, to fix integer timestamps in async table --- phpgwapi/inc/common_functions.inc.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpgwapi/inc/common_functions.inc.php b/phpgwapi/inc/common_functions.inc.php index 08c68c1bfc..4a78dd2efd 100755 --- a/phpgwapi/inc/common_functions.inc.php +++ b/phpgwapi/inc/common_functions.inc.php @@ -1601,8 +1601,8 @@ if (isset($_SERVER['SCRIPT_FILENAME']) && $_SERVER['SCRIPT_FILENAME'] == __FILE_ */ function json_php_unserialize($str, $allow_not_serialized=false) { - if (($str[0] == 'a' && $str[1] == ':' || $str === 'N;') && - ($arr = php_safe_unserialize($str)) !== false) + 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;') { return $arr; } From c07599aa27c9315c1f2cc1e15d7b599301394c20 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Tue, 22 Jul 2014 12:52:10 +0000 Subject: [PATCH 25/49] fixed async job was not removed, if facations was deactivated and only try to reschedule with increasing intervals for 2 days --- mail/inc/class.mail_sieve.inc.php | 33 +++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/mail/inc/class.mail_sieve.inc.php b/mail/inc/class.mail_sieve.inc.php index 0dc7f54d51..9606ec7470 100644 --- a/mail/inc/class.mail_sieve.inc.php +++ b/mail/inc/class.mail_sieve.inc.php @@ -48,14 +48,14 @@ class mail_sieve * @var boolean */ var $is_admin_vac = false; - + /** * siteConfigs * * @var array */ var $mailConfig = array(); - + /** * Constructor */ @@ -64,13 +64,13 @@ class mail_sieve $this->displayCharset = translation::charset(); $this->mail_admin = isset($GLOBALS['egw_info']['user']['apps']['emailadmin']); $this->mailConfig = config::read('mail'); - + $acc_id = isset($_GET['acc_id']) ? (int)$_GET['acc_id'] : egw_cache::getSession(__CLASS__, 'acc_id'); if ($acc_id > 0) { $this->account = emailadmin_account::read($acc_id); } - + $this->restoreSessionData(); } @@ -507,6 +507,7 @@ class mail_sieve elseif ($content['acc_id']) { $this->account = emailadmin_account::read($content['acc_id']); + $preserv['acc_id'] = $content['acc_id']; } $icServer = $this->account->imapServer($this->is_admin_vac ? $account_id : false); @@ -614,7 +615,8 @@ class mail_sieve // schedule job to switch message on/off, if request and not already in past else { - if ($newVacation['status'] == 'by_date' && $newVacation['end_date']+24*3600 > time()) + if ($newVacation['status'] == 'by_date' && $newVacation['end_date']+24*3600 > time() || + $vacRules && $vacRules['vacation']['status'] == 'by_date') { self::setAsyncJob($newVacation); } @@ -694,17 +696,22 @@ class mail_sieve $async->delete($async_id); $end_date = $_vacation['end_date'] + 24*3600; // end-date is inclusive, so we have to add 24h - if ($_vacation['status'] == 'by_date' && time() < $end_date && $_reschedule===false) + if ($_vacation['status'] == 'by_date' && time() < $end_date && !$_reschedule) { $time = time() < $_vacation['start_date'] ? $_vacation['start_date'] : $end_date; $async->set_timer($time,$async_id, 'mail_sieve::async_vacation', $_vacation, $_vacation['account_id']); } if ($_reschedule) { - $time = time() + 60*3; - unset($_vacation['next']); - unset($_vacation['times']); - $async->set_timer($time, $async_id, 'mail_sieve::async_vacation', $_vacation, $_vacation['account_id']); + $_vacation['rescheduled'] = $_vacation['rescheduled'] ? 2*$_vacation['rescheduled'] : 5; + // only try to reschedule for 2 days max + if ($_vacation['rescheduled'] <= 2 * 24 * 60) + { + $time = time() + 60*($_vacation['rescheduled']); + unset($_vacation['next']); + unset($_vacation['times']); + $async->set_timer($time, $async_id, 'mail_sieve::async_vacation', $_vacation, $_vacation['account_id']); + } } } @@ -728,6 +735,12 @@ class mail_sieve $ret = $icServer->setVacationUser($_vacation['account_id'], null, $_vacation); self::setAsyncJob($_vacation); } + // if mail account no longer exists --> remove async job + catch (egw_exception_not_found $e) + { + $_vacation['status'] = 'off'; + self::setAsyncJob($_vacation); + } catch (Exception $e) { error_log(__METHOD__.'('.array2string($_vacation).' failed '.$e->getMessage()); self::setAsyncJob($_vacation, true); // reschedule From a63cfe5aa1fb7151efb8911bbc9be42ae185fcd1 Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Tue, 22 Jul 2014 13:01:55 +0000 Subject: [PATCH 26/49] firefox does stumble on kama skin; use moonocolor instead --- phpgwapi/inc/class.egw_ckeditor_config.inc.php | 1 + 1 file changed, 1 insertion(+) diff --git a/phpgwapi/inc/class.egw_ckeditor_config.inc.php b/phpgwapi/inc/class.egw_ckeditor_config.inc.php index 4c7dc3988b..10891f4a6c 100644 --- a/phpgwapi/inc/class.egw_ckeditor_config.inc.php +++ b/phpgwapi/inc/class.egw_ckeditor_config.inc.php @@ -187,6 +187,7 @@ class egw_ckeditor_config { case 'kama': $skin = "kama"; + if (html::$user_agent=='firefox' || html::$user_agent=='msie') $skin='moonocolor'; break; case 'silver': case 'bootstrapck': From cf519cb66639b8e6c7f277a8cf9699d59bf6d0fa Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Tue, 22 Jul 2014 13:48:57 +0000 Subject: [PATCH 27/49] re-add "Deny access" to groups --- admin/inc/class.admin_ui.inc.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/admin/inc/class.admin_ui.inc.php b/admin/inc/class.admin_ui.inc.php index 13375eded1..71ec94f0b9 100644 --- a/admin/inc/class.admin_ui.inc.php +++ b/admin/inc/class.admin_ui.inc.php @@ -128,6 +128,17 @@ class admin_ui 'group' => 2, ), ); + if (!$GLOBALS['egw']->acl->check('account_access',64,'admin')) // no rights to set ACL-rights + { + $actions['deny'] = array( + 'caption' => 'Deny access', + 'enableId' => '^/groups/-\\d+', + 'url' => 'menuaction=admin.uiaclmanager.list_apps&account_id=$id', + 'onExecute' => 'javaScript:app.admin.group', + 'icon' => 'cancel', + 'group' => 2, + ); + } $group = 5; // allow to place actions in different groups by hook, this is the default // supporting both old way using $GLOBALS['menuData'] and new just returning data in hook $apps = array_unique(array_merge(array('admin'), $GLOBALS['egw']->hooks->hook_implemented('edit_group'))); From f2ca4d2762de095be09ea866ca41f9997c9911c2 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Tue, 22 Jul 2014 14:57:23 +0000 Subject: [PATCH 28/49] copy felamimail preferences to new mail app, if they still exist there --- mail/setup/default_records.inc.php | 20 +++++++++++- phpgwapi/inc/class.preferences.inc.php | 42 ++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/mail/setup/default_records.inc.php b/mail/setup/default_records.inc.php index e51c394d1f..613a776f48 100644 --- a/mail/setup/default_records.inc.php +++ b/mail/setup/default_records.inc.php @@ -27,4 +27,22 @@ if (!$GLOBALS['egw_setup']->db->affected_rows()) } // change common/default_app pref to mail, if it was felamimail -preferences::change_preference('common', 'default_app', 'mail', 'felamimail'); \ No newline at end of file +preferences::change_preference('common', 'default_app', 'mail', 'felamimail'); + +// copy felamimail preferences to new mail app, if they still exist there +preferences::copy_preferences('felamimail', 'mail', array( + 'htmlOptions', + 'allowExternalIMGs', + 'message_forwarding', + 'composeOptions', + 'replyOptions', + 'disableRulerForSignatureSeparation', + 'insertSignatureAtTopOffMessage', + 'attachVCardAtCompose', + 'deleteOptions', + 'sendOptions', + 'trustServerUnseenInfo', + 'showAllFoldersInFolderPane', + 'prefaskformove', + 'saveAsOptions', +)); \ No newline at end of file diff --git a/phpgwapi/inc/class.preferences.inc.php b/phpgwapi/inc/class.preferences.inc.php index 45b1da1a91..127475e776 100644 --- a/phpgwapi/inc/class.preferences.inc.php +++ b/phpgwapi/inc/class.preferences.inc.php @@ -801,6 +801,48 @@ class preferences self::change_preference($app, $name, null, null, $type); } + /** + * Copy preferences from one app to an other + * + * @param string $from_app + * @param string $to_app + * @param array $names=null array of names to copy or null for all + */ + public static function copy_preferences($from_app, $to_app, array $names=null) + { + $db = isset($GLOBALS['egw_setup']->db) ? $GLOBALS['egw_setup']->db : $GLOBALS['egw']->db; + + foreach($db->select(self::TABLE, '*', array('preference_app' => $from_app), __LINE__, __FILE__) as $row) + { + $prefs = self::unserialize($row['preference_value']); + + if ($names) + { + $prefs = array_intersect_key($prefs, array_flip($names)); + } + if (!$prefs) continue; // nothing to change, as nothing set + + $row['preference_app'] = $to_app; + unset($row['preference_value']); + + if (($values = $this->db->select(self::TABLE, 'preference_value', $row, __LINE__, __FILE__)->fetchColumn())) + { + $prefs = array_merge($values, $prefs); + } + + $this->db->insert(self::TABLE, array( + 'preference_value' => json_encode($prefs) + ), $row, __LINE__, __FILE__); + + // update instance-wide cache + if (($cached = egw_cache::getInstance(__CLASS__, $row['prefences_owner']))) + { + $cached[$from_app] = $prefs; + egw_cache::setInstance(__CLASS__, $row['preference_owner'], $cached); + } + } + } + /** * Save the the preferences to the repository * From b3c2bebd5f66f887dd517c88f85c324e87036d55 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Tue, 22 Jul 2014 16:52:22 +0000 Subject: [PATCH 29/49] fixe PHP Fatal error in preferences::copy_preferences() in mail install --- phpgwapi/inc/class.preferences.inc.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/phpgwapi/inc/class.preferences.inc.php b/phpgwapi/inc/class.preferences.inc.php index 127475e776..ddf919be52 100644 --- a/phpgwapi/inc/class.preferences.inc.php +++ b/phpgwapi/inc/class.preferences.inc.php @@ -810,6 +810,7 @@ class preferences */ public static function copy_preferences($from_app, $to_app, array $names=null) { + //error_log(__METHOD__."('$from_app', '$to_app', ".array2string($names).')'); $db = isset($GLOBALS['egw_setup']->db) ? $GLOBALS['egw_setup']->db : $GLOBALS['egw']->db; foreach($db->select(self::TABLE, '*', array('preference_app' => $from_app), __LINE__, __FILE__) as $row) @@ -825,12 +826,13 @@ class preferences $row['preference_app'] = $to_app; unset($row['preference_value']); - if (($values = $this->db->select(self::TABLE, 'preference_value', $row, __LINE__, __FILE__)->fetchColumn())) + if (($values = $db->select(self::TABLE, 'preference_value', $row, __LINE__, __FILE__)->fetchColumn())) { - $prefs = array_merge($values, $prefs); + $prefs = array_merge(self::unserialize($values), $prefs); } - $this->db->insert(self::TABLE, array( + //error_log(__LINE__.': '.__METHOD__."() inserting app=$row[preference_app], owner=$row[preference_owner]: ".array2string($prefs)); + $db->insert(self::TABLE, array( 'preference_value' => json_encode($prefs) ), $row, __LINE__, __FILE__); From 3176500c8318673a1b801ec0178bb9905ac5e516 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Tue, 22 Jul 2014 21:21:33 +0000 Subject: [PATCH 30/49] Refine select option searching when the id is like parent[selectbox]. - only search parents when the ID has multiple parts - fix case when selectbox was in the sel_options arrayMgr, but had no options, parent was used as select options --- etemplate/js/et2_widget_selectbox.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/etemplate/js/et2_widget_selectbox.js b/etemplate/js/et2_widget_selectbox.js index cce0683055..1a78c7810a 100644 --- a/etemplate/js/et2_widget_selectbox.js +++ b/etemplate/js/et2_widget_selectbox.js @@ -791,13 +791,21 @@ jQuery.extend(et2_selectbox, } // Try name like widget[$row] - if(!content_options || content_options.length == 0) + if(name_parts.length > 1 && (!content_options || content_options.length == 0 )) { var pop_that = jQuery.extend([],name_parts); while(pop_that.length > 0 && (!content_options || content_options.length == 0)) { - pop_that.pop(); + var last = pop_that.pop(); content_options = widget.getArrayMgr('sel_options').getEntry(pop_that.join('[')); + + // Double check, might have found a normal parent namespace ( eg subgrid in subgrid[selectbox] ) + // with an empty entry for the selecbox. If there were valid options here, + // we would have found them already, and keeping this would result in the ID as an option + if(content_options && typeof content_options[last] != 'undefined' && content_options[last] ) + { + content_options = content_options[last]; + } } } From 101eee1e1c28ad677ea6c44e9b2919793623c659 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Tue, 22 Jul 2014 21:26:03 +0000 Subject: [PATCH 31/49] Extend run() method for tabs: - Apply additional tabs once in run() before applying the method, instead of in each method - Apply tab readonlys to disable tabs, so they can be skipped --- .../inc/class.etemplate_widget_tabbox.inc.php | 75 ++++++++++--------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/etemplate/inc/class.etemplate_widget_tabbox.inc.php b/etemplate/inc/class.etemplate_widget_tabbox.inc.php index a67d8b85a5..e4471c4e94 100644 --- a/etemplate/inc/class.etemplate_widget_tabbox.inc.php +++ b/etemplate/inc/class.etemplate_widget_tabbox.inc.php @@ -27,28 +27,51 @@ class etemplate_widget_tabbox extends etemplate_widget { /** - * Fill additional tabs + * Run a given method on all children * - * @param string $cname + * Default implementation only calls method on itself and run on all children. + * Overridden here to apply readonlys for the tabbox to disabled on the tab + * content. This prevents running the method on disabled tabs. + * + * @param string $method_name + * @param array $params=array('') parameter(s) first parameter has to be the cname, second $expand! + * @param boolean $respect_disabled=false false (default): ignore disabled, true: method is NOT run for disabled widgets AND their children */ - public function beforeSendToClient($cname) + public function run($method_name, $params=array(''), $respect_disabled=false) { - unset($cname); - if($this->attrs['tabs']) + // add_tabs toggles replacing or adding to existing tabs + if(!$this->attrs['add_tabs']) { - // add_tabs toggles replacing or adding to existing tabs - if(!$this->attrs['add_tabs']) + $this->children[1]->children = array(); + } + + // Make sure additional tabs are processed for any method + foreach($this->attrs['tabs'] as $tab) + { + $template= clone etemplate_widget_template::instance($tab['template']); + if($tab['id']) $template->attrs['content'] = $tab['id']; + $this->children[1]->children[] = $template; + unset($template); + } + + // Check for disabled tabs set via readonly, and set them as disabled + $form_name = self::form_name($params[0], $this->id, $params[1]); + $readonlys = self::get_array(self::$request->readonlys, $form_name); + if($respect_disabled && $readonlys) + { + foreach($this->children[1]->children as $tab) { - $this->children[1]->children = array(); - } - foreach($this->attrs['tabs'] as $tab) - { - $template= clone etemplate_widget_template::instance($tab['template']); - if($tab['id']) $template->attrs['content'] = $tab['id']; - $this->children[1]->children[] = $template; - unset($template); + $ro_id = explode('.',$tab->template ? $tab->template : $tab->id); + $ro_id = $ro_id[count($ro_id)-1]; + if($readonlys[$ro_id]) + { + $tab->attrs['disabled'] = $readonlys[$ro_id]; + } } } + + // Tabs are set up now, continue as normal + parent::run($method_name, $params, $respect_disabled); } /** @@ -68,27 +91,7 @@ class etemplate_widget_tabbox extends etemplate_widget { $value = self::get_array($content, $form_name); $valid =& self::get_array($validated, $form_name, true); - if (true) $valid = $value; - - if(!$this->attrs['tabs']) - { - return; - } - - // Make sure additional tabs are processed - - // add_tabs toggles replacing or adding to existing tabs - if(!$this->attrs['add_tabs']) - { - $this->children[1]->children = array(); - } - foreach($this->attrs['tabs'] as $tab) - { - $template= clone etemplate_widget_template::instance($tab['template']); - if($tab['id'] && $content[$tab['id']]) $template->attrs['content'] = $tab['id']; - $this->children[1]->children[] = $template; - unset($template); - } + if (true) $valid = $value; } } } From 8f0513c99ec09b4bd0e7ad066b0c46ff02573f53 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Tue, 22 Jul 2014 21:33:41 +0000 Subject: [PATCH 32/49] Don't clear children if tabs attribute not provided --- .../inc/class.etemplate_widget_tabbox.inc.php | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/etemplate/inc/class.etemplate_widget_tabbox.inc.php b/etemplate/inc/class.etemplate_widget_tabbox.inc.php index e4471c4e94..b5a2448b0f 100644 --- a/etemplate/inc/class.etemplate_widget_tabbox.inc.php +++ b/etemplate/inc/class.etemplate_widget_tabbox.inc.php @@ -39,19 +39,23 @@ class etemplate_widget_tabbox extends etemplate_widget */ public function run($method_name, $params=array(''), $respect_disabled=false) { - // add_tabs toggles replacing or adding to existing tabs - if(!$this->attrs['add_tabs']) - { - $this->children[1]->children = array(); - } // Make sure additional tabs are processed for any method - foreach($this->attrs['tabs'] as $tab) + if($this->attrs['tabs']) { - $template= clone etemplate_widget_template::instance($tab['template']); - if($tab['id']) $template->attrs['content'] = $tab['id']; - $this->children[1]->children[] = $template; - unset($template); + // add_tabs toggles replacing or adding to existing tabs + if(!$this->attrs['add_tabs']) + { + $this->children[1]->children = array(); + } + + foreach($this->attrs['tabs'] as $tab) + { + $template= clone etemplate_widget_template::instance($tab['template']); + if($tab['id']) $template->attrs['content'] = $tab['id']; + $this->children[1]->children[] = $template; + unset($template); + } } // Check for disabled tabs set via readonly, and set them as disabled From b6b660ee1645b7ca834c4a8c4a69e7696a9e6704 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Tue, 22 Jul 2014 22:22:09 +0000 Subject: [PATCH 33/49] Fix detached date label --- etemplate/js/et2_widget_date.js | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/etemplate/js/et2_widget_date.js b/etemplate/js/et2_widget_date.js index 94878d5ed6..7373fde1d2 100644 --- a/etemplate/js/et2_widget_date.js +++ b/etemplate/js/et2_widget_date.js @@ -610,14 +610,14 @@ var et2_date_ro = et2_valueWidget.extend([et2_IDetachedDOM], */ init: function() { this._super.apply(this, arguments); - this.label_node = $j(document.createElement("label")) + this._labelContainer = $j(document.createElement("label")) .addClass("et2_label"); this.value = ""; this.span = $j(document.createElement(this._type == "date-since" || this._type == "date-time_today" ? "span" : "time")) .addClass("et2_date_ro et2_label") - .appendTo(this.label_node); + .appendTo(this._labelContainer); - this.setDOMNode(this.label_node[0]); + this.setDOMNode(this._labelContainer[0]); }, set_value: function(_value) { @@ -707,6 +707,18 @@ var et2_date_ro = et2_valueWidget.extend([et2_IDetachedDOM], this.span.attr("datetime", date("Y-m-d H:i:s",this.date)).text(display); }, + set_label: function(label) + { + // Remove current label + this._labelContainer.contents() + .filter(function(){ return this.nodeType == 3; }).remove(); + + var parts = et2_csvSplit(label, 2, "%s"); + this._labelContainer.prepend(parts[0]); + this._labelContainer.append(parts[1]); + this.label = label; + }, + /** * Creates a list of attributes which can be set when working in the * "detached" mode. The result is stored in the _attrs array which is provided @@ -725,7 +737,7 @@ var et2_date_ro = et2_valueWidget.extend([et2_IDetachedDOM], * @return {array} */ getDetachedNodes: function() { - return [this.label_node[0], this.span[0]]; + return [this._labelContainer[0], this.span[0]]; }, /** @@ -739,7 +751,7 @@ var et2_date_ro = et2_valueWidget.extend([et2_IDetachedDOM], * given values. */ setDetachedAttributes: function(_nodes, _values) { - this.label_node = jQuery(_nodes[0]); + this._labelContainer = jQuery(_nodes[0]); this.span = jQuery(_nodes[1]); this.set_value(_values["value"]); From eeafdea3130e63d7b1548a61fe97c2c6372a1ddc Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Wed, 23 Jul 2014 07:15:06 +0000 Subject: [PATCH 34/49] * Admin/Setup: restore of 14.1 backup was not working (backup file itself is correct) caused by typo in json_decode of schema --- phpgwapi/inc/class.db_backup.inc.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/phpgwapi/inc/class.db_backup.inc.php b/phpgwapi/inc/class.db_backup.inc.php index b118ea28a3..58a61d064a 100644 --- a/phpgwapi/inc/class.db_backup.inc.php +++ b/phpgwapi/inc/class.db_backup.inc.php @@ -457,15 +457,7 @@ class db_backup if (substr($line,0,8) == 'schema: ') { // create the tables in the backup set - $schema = trim(substr($line,8)); - if ($schema[0] == 'a' && $schema[1] == ':') - { - $this->schemas = php_safe_unserialize($schema); - } - else - { - $this->schema = json_decode($schema, true); - } + $this->schemas = json_php_unserialize(trim(substr($line,8))); foreach($this->schemas as $table_name => $schema) { // if column is longtext in current schema, convert text to longtext, in case user already updated column From 0e5747deb0dfb3a11312e95b00e07f5fc266dea0 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Wed, 23 Jul 2014 11:59:46 +0000 Subject: [PATCH 35/49] Make mail ACL account owner row readonly as the owner should not be able to delete/change his rights, he always has full-rights --- mail/inc/class.mail_acl.inc.php | 48 +++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/mail/inc/class.mail_acl.inc.php b/mail/inc/class.mail_acl.inc.php index e1c3ba19a4..402bd2f613 100644 --- a/mail/inc/class.mail_acl.inc.php +++ b/mail/inc/class.mail_acl.inc.php @@ -143,24 +143,20 @@ class mail_acl $tmpl->set_validation_error('grid['.$row.']'.'[acc_id]', "You must fill this field!"); } } - else - { - $msg .= lang("The Folder %1 's ACLs saved!", $content['mailbox']); - } + //Add new row at the end if ($content['grid'][count($content['grid'])]['acc_id']) array_push($content['grid'], array('acc_id'=>'')); - } else { $msg .= "\n".lang("Error: Could not save ACL").' '.lang("reason!"); } //Send message - egw_framework::refresh_opener($msg, 'mail',null, 'update'); + egw_framework::message($msg); if ($button == "apply") break; - + //Fall through case 'cancel': egw_framework::window_close(); common::egw_exit(); @@ -175,21 +171,29 @@ class mail_acl { error_log(__METHOD__.__LINE__. "()" . "The remove_acl suppose to return an array back, something is wrong there"); } - egw_framework::refresh_opener($msg, 'mail', null,'update'); + egw_framework::message($msg); } } $readonlys = $sel_options = array(); $sel_options['acl'] = $this->aclRightsAbbrvs; - //Make the delete buttons readonly for entry filed and account owner - foreach($content['grid'] as $key => $field) + //Make the account owner's fields all readonly as owner has all rights and should not be able to change them + foreach($content['grid'] as $key => $fields) { - if ($field['acc_id'] == $this->mail_bo->icServer->acc_imap_username || - $field['acc_id'][0] == $this->mail_bo->icServer->acc_imap_username) + if ($fields['acc_id'] == $this->mail_bo->icServer->acc_imap_username || + $fields['acc_id'][0] == $this->mail_bo->icServer->acc_imap_username) { + foreach ($fields as $index => $val) + { + $readonlys['grid'][$key][$index] = true; + } $readonlys['grid']['delete['.$key.']'] = true; + $readonlys['grid'][$key]['acl_recursive'] = true; + $preserv ['grid'][$key] = $fields; + $preserv['grid'][$key]['acl_recursive'] = false; } } + //Make entry row's delete button readonly $readonlys['grid']['delete['.count($content['grid']).']'] = true; $preserv ['mailbox'] = $content['mailbox']; @@ -210,7 +214,7 @@ class mail_acl function update_acl ($content, &$msg) { $validator = array(); - + foreach ($content['grid'] as $keys => $value) { $recursive = $value['acl_recursive']; @@ -229,7 +233,8 @@ class mail_acl $options['rights'] .= $right[1]; } } - $username = $content['grid'][$keys]['acc_id'][0]; + $username = $content['grid'][$keys]['acc_id'] == $this->mail_bo->icServer->acc_imap_username + ?$content['grid'][$keys]['acc_id']:$content['grid'][$keys]['acc_id'][0]; //error_log(__METHOD__."(".__LINE__.") setACL($content[mailbox], $username, ".array2string($options).", $recursive)"); if (is_numeric($username) && ($u = $this->mail_bo->icServer->getMailBoxUserName($username))) { @@ -238,7 +243,15 @@ class mail_acl if (!empty($username)) { //error_log(__METHOD__."() setACL($content[mailbox], $username, ".array2string($options).", $recursive)"); - $this->setACL($content['mailbox'], $username, $options, $recursive); + if (($ret=$this->setACL($content['mailbox'], $username, $options, $recursive, $msg))) + { + $msg = lang("The Folder %1 's ACLs saved!", $content['mailbox']); + + } + else + { + $msg = lang('Error while setting folder '.$content['mailbox']. $msg); + } } else { @@ -376,7 +389,7 @@ class mail_acl /** * Set ACL rights of a folder or including subfolders to an account * @param String $mailbox folder name that needs to be edited - * @param String $Identifier The identifier to set. + * @param String $identifier The identifier to set. * @param Array $options Additional options: * - rights: (string) The rights to alter or set. * - action: (string, optional) If 'add' or 'remove', adds or removes the @@ -387,7 +400,7 @@ class mail_acl * @return Boolean FALSE in case of any exceptions and TRUE in case of success, * */ - function setACL($mailbox, $identifier,$options, $recursive) + function setACL($mailbox, $identifier,$options, $recursive, &$msg) { if ($recursive) { @@ -405,6 +418,7 @@ class mail_acl } catch (Exception $e) { + $msg = $e->getMessage(); error_log(__METHOD__. "Could not set ACL rights on folder " . $mailbox . " for account ". $identifier . " because of " .$e->getMessage()); return false; } From 349630ffa78522304cddd09e9fe04c7530429c39 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Wed, 23 Jul 2014 12:30:39 +0000 Subject: [PATCH 36/49] show calendars and ressource-calendars for user whos preferences are displayed, for "default" and "forced" we only display all and primary group calendars, but ressources of current user --- .../inc/class.calendar_activesync.inc.php | 12 +++---- calendar/inc/class.calendar_bo.inc.php | 33 +++++++++++++------ calendar/inc/class.calendar_groupdav.inc.php | 16 ++++----- .../inc/class.groupdav_principals.inc.php | 5 +-- resources/inc/class.bo_acl.inc.php | 5 +-- resources/inc/class.resources_bo.inc.php | 13 +++++--- 6 files changed, 50 insertions(+), 34 deletions(-) diff --git a/calendar/inc/class.calendar_activesync.inc.php b/calendar/inc/class.calendar_activesync.inc.php index 06fedb3961..f7127bce8d 100644 --- a/calendar/inc/class.calendar_activesync.inc.php +++ b/calendar/inc/class.calendar_activesync.inc.php @@ -17,8 +17,8 @@ */ if (isset($_SERVER['SCRIPT_FILENAME']) && $_SERVER['SCRIPT_FILENAME'] == __FILE__) { - interface activesync_plugin_write {}; - interface activesync_plugin_meeting_requests {}; + interface activesync_plugin_write {} + interface activesync_plugin_meeting_requests {} } /** @@ -1576,14 +1576,12 @@ END:VTIMEZONE function settings($hook_data) { $cals = array(); - if (!$hook_data['setup']) + if (!$hook_data['setup'] && is_numeric($hook_data['account_id'])) { - if (!isset($this->calendar)) $this->calendar = new calendar_boupdate(); - - foreach ($this->calendar->list_cals() as $entry) + foreach (calendar_bo::list_calendars($hook_data['account_id']) as $entry) { $account_id = $entry['grantor']; - if ($account_id != $GLOBALS['egw_info']['user']['account_id']) + if ($account_id != $hook_data['account_id']) // skip current user { $cals[$account_id] = $entry['name']; } diff --git a/calendar/inc/class.calendar_bo.inc.php b/calendar/inc/class.calendar_bo.inc.php index eb6403d85c..770d3cde1e 100644 --- a/calendar/inc/class.calendar_bo.inc.php +++ b/calendar/inc/class.calendar_bo.inc.php @@ -1650,7 +1650,7 @@ class calendar_bo /** * This is called only by list_cals(). It was moved here to remove fatal error in php5 beta4 */ - function _list_cals_add($id,&$users,&$groups) + private static function _list_cals_add($id,&$users,&$groups) { $name = common::grab_owner_name($id); if (!($egw_name = $GLOBALS['egw']->accounts->id2name($id))) @@ -1680,28 +1680,41 @@ class calendar_bo */ function list_cals() { + return self::list_calendars($GLOBALS['egw_info']['user']['account_id'], $this->grants); + } + + /** + * generate list of user- / group-calendars or a given user + * + * @param int $user account_id of user to generate list for + * @param array $grants=null calendar grants from user, or null to query them from acl class + */ + public static function list_calendars($user, array $grants=null) + { + if (is_null($grants)) $grants = $GLOBALS['egw']->acl->get_grants('calendar', true, $user); + $users = $groups = array(); - foreach($this->grants as $id => $rights) + foreach(array_keys($grants) as $id) { - $this->_list_cals_add($id,$users,$groups); + self::_list_cals_add($id,$users,$groups); } - if (($memberships = $GLOBALS['egw']->accounts->membership($GLOBALS['egw_info']['user']['account_id']))) + if (($memberships = $GLOBALS['egw']->accounts->membership($user))) { foreach($memberships as $group_info) { - $this->_list_cals_add($group_info['account_id'],$users,$groups); + self::_list_cals_add($group_info['account_id'],$users,$groups); - if ($account_perms = $GLOBALS['egw']->acl->get_ids_for_location($group_info['account_id'],EGW_ACL_READ,'calendar')) + if (($account_perms = $GLOBALS['egw']->acl->get_ids_for_location($group_info['account_id'],EGW_ACL_READ,'calendar'))) { foreach($account_perms as $id) { - $this->_list_cals_add($id,$users,$groups); + self::_list_cals_add($id,$users,$groups); } } } } - usort($users,array($this,'name_cmp')); - usort($groups,array($this,'name_cmp')); + usort($users, array(__CLASS__, 'name_cmp')); + usort($groups, array(__CLASS__, 'name_cmp')); return array_merge($users, $groups); // users first and then groups, both alphabeticaly } @@ -1713,7 +1726,7 @@ class calendar_bo * @param array $b * @return int */ - function name_cmp(array $a, array $b) + public static function name_cmp(array $a, array $b) { return strnatcasecmp($a['name'], $b['name']); } diff --git a/calendar/inc/class.calendar_groupdav.inc.php b/calendar/inc/class.calendar_groupdav.inc.php index d5b524eae3..0d6089eb16 100644 --- a/calendar/inc/class.calendar_groupdav.inc.php +++ b/calendar/inc/class.calendar_groupdav.inc.php @@ -1536,21 +1536,19 @@ class calendar_groupdav extends groupdav_handler */ static function get_settings($hook_data) { - $calendars = array(); - if (!isset($hook_data['setup'])) + $calendars = array( + 'A' => lang('All'), + 'G' => lang('Primary Group'), + ); + if (!isset($hook_data['setup']) && in_array($hook_data['type'], array('user', 'group'))) { - $user = $GLOBALS['egw_info']['user']['account_id']; - $cal_bo = new calendar_bo(); - foreach ($cal_bo->list_cals() as $entry) + $user = $hook_data['account_id']; + foreach (calendar_bo::list_calendars($user) as $entry) { $calendars[$entry['grantor']] = $entry['name']; } unset($calendars[$user]); } - $calendars = array( - 'A' => lang('All'), - 'G' => lang('Primary Group'), - ) + $calendars; $settings = array(); $settings['calendar-home-set'] = array( diff --git a/phpgwapi/inc/class.groupdav_principals.inc.php b/phpgwapi/inc/class.groupdav_principals.inc.php index a526472f74..f8d3484e9f 100644 --- a/phpgwapi/inc/class.groupdav_principals.inc.php +++ b/phpgwapi/inc/class.groupdav_principals.inc.php @@ -1233,13 +1233,14 @@ class groupdav_principals extends groupdav_handler /** * Get all resources (we cache the resources here, to only query them once per request) * + * @param int $user=null account_if of user, or null for current user * @return array of array with values for res_id, cat_id and name (no other values1) */ - public static function get_resources() + public static function get_resources($user=null) { if (!isset(self::$all_resources)) { - if (!isset(self::$resources)) self::$resources = new resources_bo(); + if (!isset(self::$resources)) self::$resources = new resources_bo($user); self::$all_resources = array(); $query = array( diff --git a/resources/inc/class.bo_acl.inc.php b/resources/inc/class.bo_acl.inc.php index 03632aeb4e..adcfc65c94 100755 --- a/resources/inc/class.bo_acl.inc.php +++ b/resources/inc/class.bo_acl.inc.php @@ -37,15 +37,16 @@ class bo_acl /** * Constructor * + * @param int $user=null account_id of user whos rights to return, or null for current user * @param boolean $session */ - function __construct($session=False) + function __construct($session=False, $user=null) { define('EGW_ACL_CAT_ADMIN',64); define('EGW_ACL_DIRECT_BOOKING',128); define('EGW_ACL_CALREAD',256); - $this->egw_cats = new categories('','resources'); + $this->egw_cats = new categories($user, 'resources'); $this->debug = False; //all this is only needed when called from uiacl. diff --git a/resources/inc/class.resources_bo.inc.php b/resources/inc/class.resources_bo.inc.php index c2ea4a4709..1d10821177 100755 --- a/resources/inc/class.resources_bo.inc.php +++ b/resources/inc/class.resources_bo.inc.php @@ -66,10 +66,15 @@ class resources_bo 'accessory_of' => 'Accessory of' ); - function __construct() + /** + * Constructor + * + * @param int $user=null account_id of user to use for acl, default current user + */ + function __construct($user=null) { $this->so = new resources_so(); - $this->acl =& CreateObject('resources.bo_acl'); + $this->acl = CreateObject('resources.bo_acl', $user); $this->cats = $this->acl->egw_cats; $this->cal_right_transform = array( @@ -139,7 +144,7 @@ class resources_bo { $filter['deleted'] = null; } - + if ($query['filter']) { if (($children = $this->acl->get_cats(EGW_ACL_READ,$query['filter']))) @@ -393,7 +398,7 @@ class resources_bo $this->so->save(); } } - + $res_id = $this->so->save($resource); // History & notifications From 448241f5962903e778a9b3cd804b1fdf201261d7 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Wed, 23 Jul 2014 12:39:10 +0000 Subject: [PATCH 37/49] need to check type, not account_id to detected "default" or "forced" prefs --- calendar/inc/class.calendar_activesync.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calendar/inc/class.calendar_activesync.inc.php b/calendar/inc/class.calendar_activesync.inc.php index f7127bce8d..28d7b2b43e 100644 --- a/calendar/inc/class.calendar_activesync.inc.php +++ b/calendar/inc/class.calendar_activesync.inc.php @@ -1576,7 +1576,7 @@ END:VTIMEZONE function settings($hook_data) { $cals = array(); - if (!$hook_data['setup'] && is_numeric($hook_data['account_id'])) + if (!$hook_data['setup'] && in_array($hook_data['type'], array('user', 'group'))) { foreach (calendar_bo::list_calendars($hook_data['account_id']) as $entry) { From 1bda4f1337f36aeb0b209ba1b1f0af983e148c84 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Wed, 23 Jul 2014 13:14:23 +0000 Subject: [PATCH 38/49] Set display_format and hours_per_day for infolog used_time --- infolog/templates/default/edit.xet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infolog/templates/default/edit.xet b/infolog/templates/default/edit.xet index 577de50373..e593e866f1 100644 --- a/infolog/templates/default/edit.xet +++ b/infolog/templates/default/edit.xet @@ -60,7 +60,7 @@ - + From 7ed3f456490ecc11597c05df666b7862f2e61ccd Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Wed, 23 Jul 2014 13:16:01 +0000 Subject: [PATCH 39/49] skip current user only for users, not group(-preferences) --- calendar/inc/class.calendar_activesync.inc.php | 6 ++---- calendar/inc/class.calendar_groupdav.inc.php | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/calendar/inc/class.calendar_activesync.inc.php b/calendar/inc/class.calendar_activesync.inc.php index 28d7b2b43e..4cb3520dc7 100644 --- a/calendar/inc/class.calendar_activesync.inc.php +++ b/calendar/inc/class.calendar_activesync.inc.php @@ -1581,11 +1581,9 @@ END:VTIMEZONE foreach (calendar_bo::list_calendars($hook_data['account_id']) as $entry) { $account_id = $entry['grantor']; - if ($account_id != $hook_data['account_id']) // skip current user - { - $cals[$account_id] = $entry['name']; - } + $cals[$account_id] = $entry['name']; } + if ($hook_data['account_id'] > 0) unset($cals[$hook_data['account_id']]); // skip current user } $cals['G'] = lang('Primary group'); $cals['A'] = lang('All'); diff --git a/calendar/inc/class.calendar_groupdav.inc.php b/calendar/inc/class.calendar_groupdav.inc.php index 0d6089eb16..a3273242c0 100644 --- a/calendar/inc/class.calendar_groupdav.inc.php +++ b/calendar/inc/class.calendar_groupdav.inc.php @@ -1547,7 +1547,7 @@ class calendar_groupdav extends groupdav_handler { $calendars[$entry['grantor']] = $entry['name']; } - unset($calendars[$user]); + if ($user > 0) unset($calendars[$user]); // skip current user } $settings = array(); From fbf05c95f458d092cb0e70d01d144b7e0c2e2f9b Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Wed, 23 Jul 2014 14:00:20 +0000 Subject: [PATCH 40/49] show addressbooks for user whos preferences are displayed, for "default" and "forced" only show acl independent settings --- .../inc/class.addressbook_activesync.inc.php | 26 ++++++---- addressbook/inc/class.addressbook_bo.inc.php | 52 ++++++++++++++----- .../inc/class.addressbook_groupdav.inc.php | 27 +++++----- addressbook/inc/class.addressbook_so.inc.php | 10 ++-- 4 files changed, 75 insertions(+), 40 deletions(-) diff --git a/addressbook/inc/class.addressbook_activesync.inc.php b/addressbook/inc/class.addressbook_activesync.inc.php index 3dd9cb68e7..115442961a 100644 --- a/addressbook/inc/class.addressbook_activesync.inc.php +++ b/addressbook/inc/class.addressbook_activesync.inc.php @@ -803,33 +803,37 @@ class addressbook_activesync implements activesync_plugin_write, activesync_plug { $addressbooks = array(); - if (!isset($hook_data['setup'])) + if (!isset($hook_data['setup']) && in_array($hook_data['type'], array('user', 'group'))) { - $user = $GLOBALS['egw_info']['user']['account_id']; + $user = $hook_data['account_id']; $addressbook_bo = new addressbook_bo(); - $addressbooks = $addressbook_bo->get_addressbooks(EGW_ACL_READ); - unset($addressbooks[$user]); // personal addressbook is allways synced + $addressbooks = $addressbook_bo->get_addressbooks(EGW_ACL_READ, null, $user); + if ($user > 0) + { + unset($addressbooks[$user]); // personal addressbook is allways synced + if (isset($addressbooks[$user.'p'])) + { + $addressbooks[self::PRIVATE_AB] = lang('Private'); + } + } unset($addressbooks[$user.'p']);// private addressbook uses ID self::PRIVATE_AB - $fileas_options = array('0' => lang('use addressbooks "own sorting" attribute'))+$addressbook_bo->fileas_options(); } - if ($GLOBALS['egw_info']['user']['preferences']['addressbook']['private_addressbook']) - { - $addressbooks[self::PRIVATE_AB] = lang('Private'); - } $addressbooks += array( 'G' => lang('Primary Group'), 'U' => lang('Accounts'), 'A' => lang('All'), ); // allow to force "none", to not show the prefs to the users - if ($GLOBALS['type'] == 'forced') + if ($hook_data['type'] == 'forced') { $addressbooks['N'] = lang('None'); } // rewriting owner=0 to 'U', as 0 get's always selected by prefs - if (!isset($addressbooks[0])) + // not removing it for default or forced prefs based on current users pref + if (!isset($addressbooks[0]) && (in_array($hook_data['type'], array('user', 'group')) || + $GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts'])) { unset($addressbooks['U']); } diff --git a/addressbook/inc/class.addressbook_bo.inc.php b/addressbook/inc/class.addressbook_bo.inc.php index 9a55d20c92..8bb590ffd2 100755 --- a/addressbook/inc/class.addressbook_bo.inc.php +++ b/addressbook/inc/class.addressbook_bo.inc.php @@ -183,7 +183,7 @@ class addressbook_bo extends addressbook_so { $this->default_addressbook = $this->user; // admin set a default or forced pref for personal addressbook } - $this->private_addressbook = $this->contact_repository == 'sql' && $this->prefs['private_addressbook']; + $this->private_addressbook = self::private_addressbook($this->contact_repository == 'sql', $this->prefs); $this->contact_fields = array( 'id' => lang('Contact ID'), @@ -311,23 +311,51 @@ class addressbook_bo extends addressbook_so $this->delete_history = $GLOBALS['egw_info']['server']['history']; } + /** + * Do we use a private addressbook (in comparison to a personal one) + * + * Used to set $this->private_addressbook for current user. + * + * @param string $contact_repository + * @param array $prefs addressbook preferences + * @return boolean + */ + public static function private_addressbook($contact_repository, array $prefs) + { + return $contact_repository == 'sql' && $prefs['private_addressbook']; + } + /** * Get the availible addressbooks of the user * * @param int $required=EGW_ACL_READ required rights on the addressbook or multiple rights or'ed together, * to return only addressbooks fullfilling all the given rights * @param string $extra_label first label if given (already translated) + * @param int $user=null account_id or null for current user * @return array with owner => label pairs */ - function get_addressbooks($required=EGW_ACL_READ,$extra_label=null) + function get_addressbooks($required=EGW_ACL_READ,$extra_label=null,$user=null) { //echo "uicontacts::get_addressbooks($required,$include_all) grants="; _debug_array($this->grants); + if (is_null($user)) + { + $user = $this->user; + $preferences = $GLOBALS['egw_info']['user']['preferences']; + $grants = $this->grants; + } + else + { + $prefs_obj = new preferences($user); + $preferences = $prefs_obj->read_repository(); + $grants = $this->get_grants($user, 'addressbook', $preferences); + } + $addressbooks = $to_sort = array(); if ($extra_label) $addressbooks[''] = $extra_label; - $addressbooks[$this->user] = lang('Personal'); + $addressbooks[$user] = lang('Personal'); // add all group addressbooks the user has the necessary rights too - foreach($this->grants as $uid => $rights) + foreach($grants as $uid => $rights) { if (($rights & $required) == $required && $GLOBALS['egw']->accounts->get_type($uid) == 'g') { @@ -339,20 +367,20 @@ class addressbook_bo extends addressbook_so asort($to_sort); $addressbooks += $to_sort; } - if (!$GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts'] && ( - ($this->grants[0] & $required) == $required || - $GLOBALS['egw_info']['user']['preferences']['common']['account_selection'] == 'groupmembers' && + if (!$preferences['addressbook']['hide_accounts'] && ( + ($grants[0] & $required) == $required || + $preferences['common']['account_selection'] == 'groupmembers' && $this->account_repository != 'ldap' && ($required & EGW_ACL_READ))) { $addressbooks[0] = lang('Accounts'); } // add all other user addressbooks the user has the necessary rights too $to_sort = array(); - foreach($this->grants as $uid => $rights) + foreach($grants as $uid => $rights) { - if ($uid != $this->user && ($rights & $required) == $required && $GLOBALS['egw']->accounts->get_type($uid) == 'u') + if ($uid != $user && ($rights & $required) == $required && $GLOBALS['egw']->accounts->get_type($uid) == 'u') { - $to_sort[$uid] = $GLOBALS['egw']->common->grab_owner_name($uid); + $to_sort[$uid] = common::grab_owner_name($uid); } } if ($to_sort) @@ -360,9 +388,9 @@ class addressbook_bo extends addressbook_so asort($to_sort); $addressbooks += $to_sort; } - if ($this->private_addressbook) + if ($user > 0 && self::private_addressbook($this->contact_repository, $preferences['addressbook'])) { - $addressbooks[$this->user.'p'] = lang('Private'); + $addressbooks[$user.'p'] = lang('Private'); } //echo "

".__METHOD__."($required,'$extra_label')"; _debug_array($addressbooks); return $addressbooks; diff --git a/addressbook/inc/class.addressbook_groupdav.inc.php b/addressbook/inc/class.addressbook_groupdav.inc.php index 61a052b5bc..cfe67eecae 100644 --- a/addressbook/inc/class.addressbook_groupdav.inc.php +++ b/addressbook/inc/class.addressbook_groupdav.inc.php @@ -1067,36 +1067,37 @@ class addressbook_groupdav extends groupdav_handler /** * Return appliction specific settings * - * @param array $hook_data + * @param array $hook_data values for keys 'location', 'type' and 'account_id' * @return array of array with settings */ static function get_settings($hook_data) { - $addressbooks = array(); - if (!isset($hook_data['setup'])) - { - $user = $GLOBALS['egw_info']['user']['account_id']; - $addressbook_bo = new addressbook_bo(); - $addressbooks = $addressbook_bo->get_addressbooks(EGW_ACL_READ); - unset($addressbooks[$user]); // allways synced - unset($addressbooks[$user.'p']);// ignore (optional) private addressbook for now - } $addressbooks = array( 'A' => lang('All'), 'G' => lang('Primary Group'), 'U' => lang('Accounts'), 'O' => lang('Sync all selected into one'), 'D' => lang('Distribution lists as groups') - ) + $addressbooks; + ); + if (!isset($hook_data['setup']) && in_array($hook_data['type'], array('user', 'group'))) + { + $user = $hook_data['account_id']; + $addressbook_bo = new addressbook_bo(); + $addressbooks = $addressbook_bo->get_addressbooks(EGW_ACL_READ, null, $user); + if ($user > 0) unset($addressbooks[$user]); // allways synced + unset($addressbooks[$user.'p']);// ignore (optional) private addressbook for now + } // allow to force no other addressbooks - if ($GLOBALS['type'] === 'forced') + if ($hook_data['type'] === 'forced') { $addressbooks['N'] = lang('None'); } // rewriting owner=0 to 'U', as 0 get's always selected by prefs - if (!isset($addressbooks[0])) + // not removing it for default or forced prefs based on current users pref + if (!isset($addressbooks[0]) && (in_array($hook_data['type'], array('user', 'group')) || + $GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts'])) { unset($addressbooks['U']); } diff --git a/addressbook/inc/class.addressbook_so.inc.php b/addressbook/inc/class.addressbook_so.inc.php index e73c60ce48..7d24286934 100755 --- a/addressbook/inc/class.addressbook_so.inc.php +++ b/addressbook/inc/class.addressbook_so.inc.php @@ -313,8 +313,10 @@ class addressbook_so * @param string $contact_app='addressbook' * @return array */ - function get_grants($user,$contact_app='addressbook') + function get_grants($user, $contact_app='addressbook', $preferences=null) { + if (!isset($preferences)) $preferences = $GLOBALS['egw_info']['user']['preferences']; + if ($user) { // contacts backend (contacts in LDAP require accounts in LDAP!) @@ -336,12 +338,12 @@ class addressbook_so // add grants for accounts: if account_selection not in ('none','groupmembers'): everyone has read access, // if he has not set the hide_accounts preference // ToDo: be more specific for 'groupmembers', they should be able to see the groupmembers - if (!in_array($GLOBALS['egw_info']['user']['preferences']['common']['account_selection'], array('none','groupmembers'))) + if (!in_array($preferences['common']['account_selection'], array('none','groupmembers'))) { $grants[0] = EGW_ACL_READ; } - // add account grants for admins - if ($this->is_admin()) // admin rights can be limited by ACL! + // add account grants for admins (only for current user!) + if ($user == $this->user && $this->is_admin()) // admin rights can be limited by ACL! { $grants[0] = EGW_ACL_READ; // admins always have read-access if (!$GLOBALS['egw']->acl->check('account_access',16,'admin')) $grants[0] |= EGW_ACL_EDIT; From d2b6fd07949c01b5e4c85e8b1964dc26c6b84ad9 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Wed, 23 Jul 2014 16:40:19 +0000 Subject: [PATCH 41/49] pending translations from our translation server --- home/lang/egw_it.lang | 3 +++ infolog/lang/egw_en.lang | 12 ++++++++++++ infolog/lang/egw_it.lang | 15 +++++++++++++++ mail/lang/egw_de.lang | 2 +- mail/lang/egw_en.lang | 2 +- 5 files changed, 32 insertions(+), 2 deletions(-) diff --git a/home/lang/egw_it.lang b/home/lang/egw_it.lang index 459d750764..96a3249552 100644 --- a/home/lang/egw_it.lang +++ b/home/lang/egw_it.lang @@ -1,4 +1,7 @@ displays home home it Mostra home egroupware home it eGroupware +entry home it Voce home home it Home +show a list of entries home it Mostra una lista di voci +show one entry home it Visualizza una singola voce there is a new version of egroupware available home it C'è una nuova versione di eGroupWare disponibile diff --git a/infolog/lang/egw_en.lang b/infolog/lang/egw_en.lang index 2b316d122c..81454a409a 100644 --- a/infolog/lang/egw_en.lang +++ b/infolog/lang/egw_en.lang @@ -13,6 +13,7 @@ %1 you delegated is due at %2 infolog en %1 you delegated is due at %2 %1 you delegated is starting at %2 infolog en %1 you delegated is starting at %2 (and children) deleted infolog en (and children) deleted. +(no subject) infolog en (no subject) - subprojects from infolog en - Sub projects from 0% infolog en 0% 10% infolog en 10% @@ -49,6 +50,7 @@ added infolog en Added addressbook placeholders available infolog en Addressbook placeholders available all infolog en All all links and attachments infolog en All links and attachments +all other %1 fields are valid infolog en All other %1 fields are valid all projects infolog en All projects allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog en Allows to set the status of an entry, e.g. set a ToDo to done if it's finished. Values depend on entry type. alternatives infolog en Alternatives @@ -187,6 +189,10 @@ error: importing the ical infolog en Error: importing the iCal error: no mail (mailbox / uid) given! infolog en Error: no mail (Mailbox / UID) given! error: saving the entry infolog en Error saving the entry! error: the entry has been updated since you opened it for editing! infolog en Error: the entry has been updated since you opened it for editing! +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. infolog en 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. +example {{letterprefixcustom n_prefix title n_family}} - example: mr dr. james miller infolog en Example {{LETTERPREFIXCUSTOM n_prefix title n_family}} - Example: Mr Dr. James Miller +example {{nelf role}} - if field role is not empty, you will get a new line with the value of field role infolog en Example {{NELF role}} - if field role is not empty, you will get a new line with the value of field role +example {{nelfnv role}} - if field role is not empty, set a lf without any value of the field infolog en Example {{NELFNV role}} - if field role is not empty, set a LF without any value of the field execute a further action for this entry infolog en Execute a further action for this entry existing links infolog en Existing links exists infolog en Exists @@ -221,6 +227,9 @@ id infolog en ID id# infolog en ID# if a type has a group owner, all entries of that type will be owned by the given group and not the user who created it! infolog en If a type has a group owner, all entries of that type will be owned by the given group and NOT the user who created it! if not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences). infolog en If not set, the line with search and filters is hidden for less entries than "max matches per page", as defined in your common preferences. +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. infolog en 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. +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. infolog en 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. +if you specify an export definition, it will be used when you export infolog en If you specify an export definition, it will be used when you export import next set infolog en Import next set importance infolog en Importance imports entries into the infolog from a csv file. csv means 'comma seperated values'. however in the options tab you can also choose other seperators. infolog en Imports entries into the InfoLog from a CSV file. CSV means 'Comma Separated Values'. In the options tab you can also choose other separators. @@ -267,6 +276,7 @@ linked to %1 infolog en Linked to %1 links infolog en Links links and attached files infolog en Links and attached files links of this entry infolog en Links of this entry +links to specified application. example: {{links/infolog}} infolog en Links to specified application. Example: {{links/infolog}} links wrapped in an href tag with download link infolog en Links wrapped in an HREF tag with download link list all categories infolog en List all categories list no subs/childs infolog en List no subs/childs @@ -306,6 +316,7 @@ notification settings infolog en Notification settings number of records to read (%1) infolog en Number of records to read (%1) number of row for a multiline inputfield or line of a multi-select-box infolog en Number of row for a multi line input field or line of a multi select box offer infolog en Offer +old fixed definition infolog en Old fixed definition one day after infolog en One day after one day in advance infolog en One day in advance ongoing infolog en Ongoing @@ -450,6 +461,7 @@ task infolog en ToDo tasks of infolog en Tasks of template infolog en Template test import (show importable records only in browser) infolog en Test import . Show importable records only in browser. +the document can contain placeholder like {{%1}}, to be replaced with the data. infolog en The document can contain placeholder like {{%1}}, to be replaced with the data. the following document-types are supported: infolog en The following document-types are supported: the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog en The name used internally,<= 10 chars, changing it makes existing data unavailable. the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog en The name used internally, <= 20 chars, changing it makes existing data unavailable. diff --git a/infolog/lang/egw_it.lang b/infolog/lang/egw_it.lang index 183d88fdbd..bc1e022626 100644 --- a/infolog/lang/egw_it.lang +++ b/infolog/lang/egw_it.lang @@ -13,6 +13,7 @@ %1 you delegated is due at %2 infolog it %1 che hai delegato, scade il %2 %1 you delegated is starting at %2 infolog it %1 che hai delegato, inizia il %2 (and children) deleted infolog it (e figli) eliminati. +(no subject) infolog it (nessun oggetto) - subprojects from infolog it - Sottoprogetti da 0% infolog it 0% 10% infolog it 10% @@ -49,6 +50,7 @@ added infolog it Aggiunto addressbook placeholders available infolog it Variabili metasintattiche della rubrica disponibili all infolog it Tutte all links and attachments infolog it tutti i link links e gli allegati +all other %1 fields are valid infolog it Tutti gli altri %1 campi sono validi all projects infolog it Tutti i progetti allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog it pemette di impostare lo stato di una voce, es. impostare completato un ToDo finito (i valori dipendono dal tipo di voce) alternatives infolog it Alternative @@ -187,6 +189,10 @@ error: importing the ical infolog it Errore: importando iCal error: no mail (mailbox / uid) given! infolog it Errore: nessuna mail (casella/UID) data! error: saving the entry infolog it Errore: durante il salvataggio della voce error: the entry has been updated since you opened it for editing! infolog it Errore: la voce è stata aggiornata da quando l'hai aperta per la modifica! +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. infolog it Esempio {{IF n_prefix~Mr~Hello Mr.~Hello Ms.}} - cerca nel campo "n_prefix" il valore "Mr", se lo trova scrive "Hello Mr.", altrimenti scrive "Hello Ms." +example {{letterprefixcustom n_prefix title n_family}} - example: mr dr. james miller infolog it Esempio {{LETTERPREFIXCUSTOM n_prefix title n_family}} - Esempio: Mr Dr. James Miller +example {{nelf role}} - if field role is not empty, you will get a new line with the value of field role infolog it Esempio {{NELF role}} - se il campo "ruolo" non è vuoto, si otterrà una nuova riga con il valore del campo "ruolo" +example {{nelfnv role}} - if field role is not empty, set a lf without any value of the field infolog it Esempio {{NELFNV role}} - se il campo "ruolo" non è vuoto, inserisce una nuova riga senza il valore del campo execute a further action for this entry infolog it Esegui ancora una azione per questo inserimento existing links infolog it Collegamenti esistenti exists infolog it Esiste @@ -205,6 +211,7 @@ for infolog type %1, %2 is required infolog it Per schede attività di tipo %1, for serial letter use this tag. put the content, you want to repeat between two tags. infolog it Per una lettera seriale, utilizzare questo tag. Immettere il contenuto che si vuole ripetere tra due tag. for which types should this field be used infolog it per quali tipo devi usare questo campo from infolog it Da +full list of placeholder names infolog it Lista completa dei nomi dei segnaposto general fields: infolog it Campi generici general settings infolog it Impostazioni generali global categories infolog it Categorie Globali @@ -220,6 +227,9 @@ id infolog it ID id# infolog it ID # if a type has a group owner, all entries of that type will be owned by the given group and not the user who created it! infolog it Se un tipo di schede ha come proprietario un gruppo, tutte le voci di quel tipo saranno di quel gruppo e NON dell'utente che le ha create! if not set, the line with search and filters is hidden for less entries then "max matches per page" (as defined in your common preferences). infolog it Se non impostato, la linea con ricerca e filtri viene nascosta per meno voci di "massime occorrenze per pagina" (come definito nelle tue preferenze comuni). +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. infolog it Se qui viene specificata una directory (un percorso completo vfs), %1 visualizza una azione per ogni documento. Questa azione consente di scaricare lo specifico documento +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. infolog it Se qui viene specificato un documento (un percorso completo vfs), %1 visualizza una icona di documento aggiuntiva per ogni voce. Questa icona consente di scaricare lo specifico documento. +if you specify an export definition, it will be used when you export infolog it Se viene specificata un formato di esportazione, verrà utilizzato quando esporterai. import next set infolog it importa il prossimo set importance infolog it Importanza imports entries into the infolog from a csv file. csv means 'comma seperated values'. however in the options tab you can also choose other seperators. infolog it Importa le schede attività in un file CSV. Puoi selezionare separatori anche diversi dalla virgola nella scheda opzioni. @@ -266,6 +276,7 @@ linked to %1 infolog it Collegato a %1 links infolog it Links links and attached files infolog it Collegamenti e file allegati links of this entry infolog it Links della voce +links to specified application. example: {{links/infolog}} infolog it Collegamento (link) alla applicazione specifica. Esempio: {{links/infolog}} links wrapped in an href tag with download link infolog it Collegamenti fra tag HREF con link allo scaricamento list all categories infolog it Elenca tutte le categorie list no subs/childs infolog it Non elencare Sub/figli @@ -305,6 +316,7 @@ notification settings infolog it Impostazioni di notifica number of records to read (%1) infolog it Numero di record da leggere (%1) number of row for a multiline inputfield or line of a multi-select-box infolog it numeri di righe per la casella di inserimento multilinea o linee per una select-box multipla offer infolog it Offerta +old fixed definition infolog it Vecchia definizione fissa one day after infolog it Un giorno dopo one day in advance infolog it Un giorno in anticipo ongoing infolog it In corso @@ -325,6 +337,7 @@ own open and upcoming infolog it Proprie aperte prossime own overdue infolog it Proprie scaduti own upcoming infolog it Proprie in arrivo owner does not have edit rights infolog it Il proprietario non ha permessi di modifica +owner, responsible infolog it Proprietario, Responsabile parent infolog it Superiore parent infolog infolog it Scheda attività padre participants for scheduling an appointment infolog it Partecipanti per programmare un appuntamento @@ -448,6 +461,7 @@ task infolog it ToDo tasks of infolog it Task di template infolog it Template test import (show importable records only in browser) infolog it Test importazione (mostra solo record importabili nel browser) +the document can contain placeholder like {{%1}}, to be replaced with the data. infolog it Il documento puà contenere dei segnaposto come {{%1}}, che saranno sostituiti con i dati the following document-types are supported: infolog it I seguenti tipi di documento sono supportati the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog it il nome usato internamente (<= 10 caratteri), cambiandolo rende i dati esistenti indisponibili the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog it il nome usato internamente (<= 20 caratteri), cambiandolo rende i dati esistenti indisponibili @@ -475,6 +489,7 @@ upcoming infolog it Imminente urgency infolog it Urgenza urgent infolog it Urgente use all infolog it Usa tutti +use custom notification message infolog it Utilizza un messaggio di notifica personalizzato use field from csv if possible infolog it Usa i campi del CSV se possibile use search results infolog it Usa i risultati della ricerca use this tag for addresslabels. put the content, you want to repeat, between two tags. infolog it Usa questo tag per le etichette di indirizzo. Posiziona il contenuto da ripetere, tra due tag. diff --git a/mail/lang/egw_de.lang b/mail/lang/egw_de.lang index a306be8ebb..cc4bcce89e 100644 --- a/mail/lang/egw_de.lang +++ b/mail/lang/egw_de.lang @@ -93,7 +93,7 @@ display only when no plain text is available mail de nur anzeigen wenn kein Plai displaying html messages is disabled mail de Die Anzeige von HTML-E-Mails ist deaktiviert. displaying plain messages is disabled mail de Die Anzeige von reinen Text E-Mails ist deaktiviert. do not auto create folders mail de Automatische Ordnererstellung verhindern für -do you really want to apply %1 to all messages in current view? mail de Wollen Sie wirklich %1 auf alle Nachrichten in der aktuellen Ansicht anwenden? +do you really want to apply %1 to all messages in the current view? mail de Wollen Sie wirklich %1 auf alle Nachrichten in der aktuellen Ansicht anwenden? do you really want to delete folder %1 ? mail de Wollen Sie den Ordner %1 wirklich löschen? do you really want to toggle flag %1 for all messages in current view? mail de Wollen Sie wirklich den Wert für %1 für alle Nachrichten in der aktuellen Ansicht umschalten? do you want to be asked for confirmation before attaching selected messages to new mail? mail de Möchten Sie vor dem Anhängen von einer oder mehreren (ausgewählten) E-Mails an eine neue E-Mail gefragt werden? diff --git a/mail/lang/egw_en.lang b/mail/lang/egw_en.lang index b4430f458c..3d44c6f45c 100644 --- a/mail/lang/egw_en.lang +++ b/mail/lang/egw_en.lang @@ -93,7 +93,7 @@ display only when no plain text is available mail en display only when no plain displaying html messages is disabled mail en displaying html messages is disabled displaying plain messages is disabled mail en displaying plain messages is disabled do not auto create folders mail en do not auto create folders -do you really want to apply %1 to all messages in current view? mail en Do you really want to apply %1 to ALL messages in current view? +do you really want to apply %1 to all messages in the current view? mail en Do you really want to apply %1 to ALL messages in the current view? do you really want to delete folder %1 ? mail en Do you really want to DELETE Folder %1 ? do you really want to toggle flag %1 for all messages in current view? mail en Do you really want to toggle flag %1 for ALL messages in current view? do you want to be asked for confirmation before attaching selected messages to new mail? mail en Do you want to be asked for confirmation before attaching selected messages to new mail? From e60896f250607e378d4aea27c5d5b93e1db80c40 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 24 Jul 2014 07:04:59 +0000 Subject: [PATCH 42/49] fixed uncaught ErrorException in setup: Argument 2 passed to addressbook_bo::private_addressbook() must be of the type array, null given --- addressbook/inc/class.addressbook_bo.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addressbook/inc/class.addressbook_bo.inc.php b/addressbook/inc/class.addressbook_bo.inc.php index 8bb590ffd2..a7278877c5 100755 --- a/addressbook/inc/class.addressbook_bo.inc.php +++ b/addressbook/inc/class.addressbook_bo.inc.php @@ -320,7 +320,7 @@ class addressbook_bo extends addressbook_so * @param array $prefs addressbook preferences * @return boolean */ - public static function private_addressbook($contact_repository, array $prefs) + public static function private_addressbook($contact_repository, array $prefs=null) { return $contact_repository == 'sql' && $prefs['private_addressbook']; } From b3e4dbf265e952b6d032060922c27289ce40a922 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 24 Jul 2014 07:24:37 +0000 Subject: [PATCH 43/49] removed stray error_log --- infolog/inc/class.infolog_bo.inc.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/infolog/inc/class.infolog_bo.inc.php b/infolog/inc/class.infolog_bo.inc.php index 1336948d7a..6a331015b5 100644 --- a/infolog/inc/class.infolog_bo.inc.php +++ b/infolog/inc/class.infolog_bo.inc.php @@ -931,8 +931,6 @@ class infolog_bo $values['info_id'] = $info_id; $to_write['info_id'] = $info_id; - error_log(__LINE__); - error_log(array2string($values)); // if the info responbsible array is not passed, fetch it from old. if (!array_key_exists('info_responsible',$values)) $values['info_responsible'] = $old['info_responsible']; if (!is_array($values['info_responsible'])) // this should not happen, bug it does ;-) From 98692acb09bfe27b19a1b9341474b0494f36c2e2 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 24 Jul 2014 07:27:58 +0000 Subject: [PATCH 44/49] fixed sqlfs_stream_wrapper::dir_opendir("links://default/apps/$app/$id",0) links://default/apps/$app/$id is no directory! --- .../inc/class.links_stream_wrapper.inc.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/phpgwapi/inc/class.links_stream_wrapper.inc.php b/phpgwapi/inc/class.links_stream_wrapper.inc.php index ab973329d5..3a303a1a38 100644 --- a/phpgwapi/inc/class.links_stream_wrapper.inc.php +++ b/phpgwapi/inc/class.links_stream_wrapper.inc.php @@ -297,6 +297,25 @@ class links_stream_wrapper extends links_stream_wrapper_parent } return parent::stream_open($url,$mode,$options,$opened_path); } + + /** + * This method is called immediately when your stream object is created for examining directory contents with opendir(). + * + * Reimplemented to give no error, if entry directory does not exist. + * + * @param string $path URL that was passed to opendir() and that this object is expected to explore. + * @param $options + * @return booelan + */ + function dir_opendir ( $url, $options ) + { + if (!parent::url_stat($url, STREAM_URL_STAT_QUIET) && self::url_stat($url, STREAM_URL_STAT_QUIET)) + { + $this->opened_dir = array(); + return true; + } + return parent::dir_opendir($url, $options); + } } stream_register_wrapper(links_stream_wrapper::SCHEME ,'links_stream_wrapper'); From 1266aeb52a0e6181fb1c7a5692f6d22215cf96a4 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 24 Jul 2014 09:38:55 +0000 Subject: [PATCH 45/49] quiten permanennt error_log in etemplate_widget::run, if widget is disabled, and therefore not running --- etemplate/inc/class.etemplate_widget.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etemplate/inc/class.etemplate_widget.inc.php b/etemplate/inc/class.etemplate_widget.inc.php index b836f68668..aac416ef57 100644 --- a/etemplate/inc/class.etemplate_widget.inc.php +++ b/etemplate/inc/class.etemplate_widget.inc.php @@ -398,7 +398,7 @@ class etemplate_widget } if ($respect_disabled && ($disabled = $this->attrs['disabled'] && self::check_disabled($this->attrs['disabled'], $expand))) { - error_log(__METHOD__."('$method_name', ".array2string($params).', '.array2string($respect_disabled).") $this disabled='{$this->attrs['disabled']}'=".array2string($disabled).": NOT running"); + //error_log(__METHOD__."('$method_name', ".array2string($params).', '.array2string($respect_disabled).") $this disabled='{$this->attrs['disabled']}'=".array2string($disabled).": NOT running"); return; } if (method_exists($this, $method_name)) From 19651fcb9b478adf44a453b2c969716294bfa52d Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 24 Jul 2014 09:53:04 +0000 Subject: [PATCH 46/49] remove wrong settings definition, causing an illegal string offset in preferences --- mail/inc/class.mail_hooks.inc.php | 1 - preferences/inc/class.preferences_settings.inc.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/mail/inc/class.mail_hooks.inc.php b/mail/inc/class.mail_hooks.inc.php index 55e34a9e75..d18582f211 100644 --- a/mail/inc/class.mail_hooks.inc.php +++ b/mail/inc/class.mail_hooks.inc.php @@ -476,7 +476,6 @@ class mail_hooks 'admin' => False, 'default'=> 'text', ), - 'add_popup' => '870x800', ); if (!$GLOBALS['egw_info']['apps']['stylite']) unset($settingsArray['attachVCardAtCompose']); return $settingsArray; diff --git a/preferences/inc/class.preferences_settings.inc.php b/preferences/inc/class.preferences_settings.inc.php index 5c6227802f..566027753b 100644 --- a/preferences/inc/class.preferences_settings.inc.php +++ b/preferences/inc/class.preferences_settings.inc.php @@ -623,7 +623,7 @@ class preferences_settings // only set not yet set default prefs, so user is able to unset it again with "" // (only works with type vfs_*, other types delete empty values!) if (!isset($GLOBALS['egw']->preferences->default[$appname][$name]) && - ((string)$data['default'] !== '' || (string)$data['forced'] !== '')) + ((string)$data['default'] !== '' || (string)$data['forced'] !== '')) { $default = (string)$data['forced'] !== '' ? $data['forced'] : $data['default']; //echo "

".__METHOD__."($appname) $this->appname/$appname/$name=$default NOT yet set!

\n"; From c013b687726e539f848c1083f08130c20fc177cc Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Thu, 24 Jul 2014 12:00:17 +0000 Subject: [PATCH 47/49] add missing flags parameter on reopening exported messages --- mail/inc/class.mail_ui.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index 36560a2ca5..8d34dd236e 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -3146,7 +3146,7 @@ class mail_ui { $messageUid = $this->mail_bo->appendMessage($_folder, $Header.$mailObject->LE.$mailObject->LE, - $Body); + $Body,'\\Seen'); } catch (egw_exception_wrong_userinput $e) { From 3253a191b7e5a24cf0eba2af454c69a628b6acae Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 24 Jul 2014 15:58:20 +0000 Subject: [PATCH 48/49] fixed typo causing no next execution to be found, and therefore periodic jobs to be terminated --- phpgwapi/inc/class.asyncservice.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpgwapi/inc/class.asyncservice.inc.php b/phpgwapi/inc/class.asyncservice.inc.php index 4685178449..18c8d26d0d 100644 --- a/phpgwapi/inc/class.asyncservice.inc.php +++ b/phpgwapi/inc/class.asyncservice.inc.php @@ -302,7 +302,7 @@ class asyncservice if (!isset($found[$u])) // we have to try the next one, if it exists { $nexts = array_keys($units); - if (!isset($next[count($found)-1])) + if (!isset($nexts[count($found)-1])) { if ($this->debug) echo "

Nothing found, exiting !!!

\n"; return False; From 1912a14fe7ce1bc72b58e3676e8de284b102c02a Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Thu, 24 Jul 2014 17:13:46 +0000 Subject: [PATCH 49/49] Add login.js to phpgwapi in order to make it available for all templates. Implement socialMedia for jdots and idots templates too --- phpgwapi/inc/class.egw_framework.inc.php | 3 ++ phpgwapi/js/login.js | 54 ++++++++++++++++++++ phpgwapi/templates/default/login.tpl | 5 +- phpgwapi/templates/idots/css/traditional.css | 6 ++- 4 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 phpgwapi/js/login.js diff --git a/phpgwapi/inc/class.egw_framework.inc.php b/phpgwapi/inc/class.egw_framework.inc.php index 0b441209a8..67772c395d 100644 --- a/phpgwapi/inc/class.egw_framework.inc.php +++ b/phpgwapi/inc/class.egw_framework.inc.php @@ -444,6 +444,9 @@ abstract class egw_framework */ function login_screen($extra_vars) { + //allow to include JSONP file with social media urls from egroupware.org + self::csp_script_src_attrs('https://www.egroupware.org'); + //error_log(__METHOD__."() server[template_dir]=".array2string($GLOBALS['egw_info']['server']['template_dir']).", this->template=$this->template, this->template_dir=$this->template_dir, get_class(this)=".get_class($this)); $tmpl = new Template($GLOBALS['egw_info']['server']['template_dir']); diff --git a/phpgwapi/js/login.js b/phpgwapi/js/login.js new file mode 100644 index 0000000000..7d8cc4d366 --- /dev/null +++ b/phpgwapi/js/login.js @@ -0,0 +1,54 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + + +egw_LAB.wait(function() { + $j.ajax('https://www.egroupware.org/social.js', { + dataType: "jsonp", + jsonp: false, + jsonpCallback: "do_social", + cache: true + }).done(function(_data) + { + $j(document).ready(function() { + var social = $j(document.createElement('div')) + .attr({ + id: "socialMedia", + class: "socialMedia" + }) + .appendTo($j('#socialBox')); + + for(var i=0; i < _data.length; ++i) + { + var data = _data[i]; + var url = (data.lang ? data.lang[$j('meta[name="language"]').attr('content')] : null) || data.url; + $j(document.createElement('a')).attr({ + href: url, + target: '_blank' + }) + .appendTo(social) + .append($j(document.createElement('img')) + .attr('src', data.svg)); + } + }); + }); +}); + +// $j('img.bgfade').hide(); +//// var dg_H = $j(window).height(); +//// var dg_W = $j(window).width(); +//// $j('#wrap').css({'height':dg_H,'width':dg_W}); +// +// function anim() { +// $j("#wrap img.bgfade").first().appendTo('#wrap').fadeOut(3500); +// $j("#wrap img").first().fadeIn(3500); +// setTimeout(anim, 7000); +// } +//anim(); +//$j(window).resize(function(){window.location.href=window.location.href}); +// }); +// +//}); diff --git a/phpgwapi/templates/default/login.tpl b/phpgwapi/templates/default/login.tpl index ea008b86d0..038a446323 100644 --- a/phpgwapi/templates/default/login.tpl +++ b/phpgwapi/templates/default/login.tpl @@ -1,4 +1,4 @@ - +
@@ -61,6 +61,9 @@ + + +
diff --git a/phpgwapi/templates/idots/css/traditional.css b/phpgwapi/templates/idots/css/traditional.css index 2e044d328f..1abb9cdb15 100755 --- a/phpgwapi/templates/idots/css/traditional.css +++ b/phpgwapi/templates/idots/css/traditional.css @@ -468,7 +468,11 @@ body { position: relative; background-repeat: no-repeat; background-position: center 80px; - background-image: url(../images/login-background.jpg); + background-color: white; +} +#socialMedia { + left: 273px; + position: relative; } #loginScreenMessage { text-align: center;