From 872fa0b72b94c5ef886ce012f456782b40606e07 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Sun, 14 Feb 2010 06:11:28 +0000 Subject: [PATCH 001/334] fixed stupid windows path: moved aspell_path config to setup, vor obvious reasons --- setup/inc/class.setup_process.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/inc/class.setup_process.inc.php b/setup/inc/class.setup_process.inc.php index 4f9f64be5f..628d668c30 100755 --- a/setup/inc/class.setup_process.inc.php +++ b/setup/inc/class.setup_process.inc.php @@ -249,7 +249,7 @@ class setup_process } $current_config['files_dir'] = 'C:\\Program Files\\'.$egroupwareDirName.'\\'.$GLOBALS['egw_setup']->ConfigDomain.'\\files'; $current_config['backup_dir'] = 'C:\\Program Files\\'.$egroupwareDirName.'\\'.$GLOBALS['egw_setup']->ConfigDomain.'\\backup'; - $current_config['aspell_path'] = 'C:\Program Files\Aspell\bin\aspell.exe'; + $current_config['aspell_path'] = 'C:\\Program Files\\Aspell\\bin\\aspell.exe'; } // only set aspell path, if it's installed if (!is_executable($current_config['aspell_path'])) From 0c640ed171fed220aa6609835835dbd52303d548 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Sun, 14 Feb 2010 06:27:54 +0000 Subject: [PATCH 002/334] support for 1.6.003 --- phpgwapi/setup/tables_update.inc.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/phpgwapi/setup/tables_update.inc.php b/phpgwapi/setup/tables_update.inc.php index e8ffd70766..aa3e4ef4cb 100644 --- a/phpgwapi/setup/tables_update.inc.php +++ b/phpgwapi/setup/tables_update.inc.php @@ -33,6 +33,11 @@ function phpgwapi_upgrade1_6_002() return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.7.001'; } +function phpgwapi_upgrade1_6_003() +{ + return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.7.001'; +} + function phpgwapi_upgrade1_7_001() { $GLOBALS['egw_setup']->oProc->AddColumn('egw_sqlfs','fs_link',array( From 0affaddfb286e5c21d8216cffafa0a5a9e8292bc Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Mon, 15 Feb 2010 02:58:58 +0000 Subject: [PATCH 003/334] fix for Debian Bug#569677: egroupware-core: base configuration fails with php error if egroupware-emailadmin is not installed --- setup/inc/hook_config_validate.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/inc/hook_config_validate.inc.php b/setup/inc/hook_config_validate.inc.php index 35e0d102ed..57cd5dac6a 100644 --- a/setup/inc/hook_config_validate.inc.php +++ b/setup/inc/hook_config_validate.inc.php @@ -43,7 +43,7 @@ function mail_server($settings) { $GLOBALS['config_error'] = lang('Missing or uncomplete mailserver configuration'); } - if (@file_exists('../emailadmin/inc/class.emailadmin_bo.inc.php') && $GLOBALS['egw_setup']->table_exist(array('egw_emailadmin')) || true) + if (@file_exists('../emailadmin/inc/class.emailadmin_bo.inc.php') && $GLOBALS['egw_setup']->table_exist(array('egw_emailadmin'))) { $emailadmin = new emailadmin_bo(-1,false); // false=no session stuff if (is_object($emailadmin)) From dbeb104ed5ff852e7acba9d9a1ec52b6a1f613eb Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Mon, 15 Feb 2010 04:35:32 +0000 Subject: [PATCH 004/334] changed rename to also rename in-active versions and made mkdir_recursive private, as it is only a helper and no exported method --- phpgwapi/inc/class.sqlfs_stream_wrapper.inc.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/phpgwapi/inc/class.sqlfs_stream_wrapper.inc.php b/phpgwapi/inc/class.sqlfs_stream_wrapper.inc.php index eb6f818869..4b0d3cedae 100644 --- a/phpgwapi/inc/class.sqlfs_stream_wrapper.inc.php +++ b/phpgwapi/inc/class.sqlfs_stream_wrapper.inc.php @@ -548,12 +548,14 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper if (self::LOG_LEVEL > 1) error_log(__METHOD__."($url_from,$url_to)"); $path_from = parse_url($url_from,PHP_URL_PATH); + $from_dir = dirname($path_from); $path_to = parse_url($url_to,PHP_URL_PATH); $to_dir = dirname($path_to); $operation = self::url2operation($url_from); // we have to use array($class,'url_stat'), as $class.'::url_stat' requires PHP 5.2.3 and we currently only require 5.2+ - if (!($from_stat = call_user_func(array($class,'url_stat'),$path_from,0)) || !egw_vfs::check_access(dirname($path_from),egw_vfs::WRITABLE)) + if (!($from_stat = call_user_func(array($class,'url_stat'),$path_from,0)) || + !egw_vfs::check_access($from_dir,egw_vfs::WRITABLE,$from_dir_stat = call_user_func(array($class,'url_stat'),$from_dir,0))) { self::_remove_password($url_from); self::_remove_password($url_to); @@ -588,11 +590,12 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper unset(self::$stat_cache[$path_from]); unset(self::$stat_cache[$path_to]); - $stmt = self::$pdo->prepare('UPDATE '.self::TABLE.' SET fs_dir=:fs_dir,fs_name=:fs_name WHERE fs_id=:fs_id'); + $stmt = self::$pdo->prepare('UPDATE '.self::TABLE.' SET fs_dir=:fs_dir,fs_name=:fs_name WHERE fs_dir=:old_dir AND fs_name=:old_name'); $ok = $stmt->execute(array( - 'fs_dir' => $to_dir_stat['ino'], - 'fs_name' => egw_vfs::basename($path_to), - 'fs_id' => $from_stat['ino'], + 'fs_dir' => $to_dir_stat['ino'], + 'fs_name' => egw_vfs::basename($path_to), + 'old_dir' => $from_dir_stat['ino'], + 'old_name' => $from_stat['name'], )); unset($stmt); @@ -614,7 +617,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper /** * due to problems with recursive directory creation, we have our own here */ - function mkdir_recursive($pathname, $mode, $depth=0) + private static function mkdir_recursive($pathname, $mode, $depth=0) { $maxdepth=10; $depth2propagate = (int)$depth + 1; From c70ff2e069dcc29beeb20cc584d55b4825ca2528 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Mon, 15 Feb 2010 06:02:36 +0000 Subject: [PATCH 005/334] fixed a strange PHP5.3 problem, it seems call_user_func_array fails returning NULL for a static method with a var parameter --- phpgwapi/inc/class.sqlfs_stream_wrapper.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpgwapi/inc/class.sqlfs_stream_wrapper.inc.php b/phpgwapi/inc/class.sqlfs_stream_wrapper.inc.php index 4b0d3cedae..10cd385577 100644 --- a/phpgwapi/inc/class.sqlfs_stream_wrapper.inc.php +++ b/phpgwapi/inc/class.sqlfs_stream_wrapper.inc.php @@ -1679,7 +1679,7 @@ class sqlfs_stream_wrapper implements iface_stream_wrapper * @param array $props array or array with values for keys 'name', 'ns', 'val' (null to delete the prop) * @return boolean true if props are updated, false otherwise (eg. ressource not found) */ - static function proppatch($path,array &$props) + static function proppatch($path,array $props) { if (self::LOG_LEVEL > 1) error_log(__METHOD__."(".array2string($path).','.array2string($props)); if (!is_numeric($path)) From 8d0c656df89fc072a9118fde500f889d03cf93f1 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Mon, 15 Feb 2010 20:40:34 +0000 Subject: [PATCH 006/334] Javascript fix for ajax select widget on IE --- etemplate/js/ajax_select.js | 44 ++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/etemplate/js/ajax_select.js b/etemplate/js/ajax_select.js index 25c461f03a..1a1ed1b991 100644 --- a/etemplate/js/ajax_select.js +++ b/etemplate/js/ajax_select.js @@ -26,6 +26,8 @@ var current_app = 'etemplate'; var ajax_select_timer_id = 0; var ajax_select_timeout = 300; +var ajax_select_event = null; + // These keys will not trigger a search if the results box is currently displayed var no_search_keys = [ '9', // Tab @@ -212,6 +214,12 @@ function timer_change(e, value) { if ( ajax_select_timer_id != 0) { clearTimeout(ajax_select_timer_id); } + if(!e) { + var e = cloneObject(window.event); + } else { + var e = cloneObject(e); + } + ajax_select_event = e; ajax_select_timer_id = setTimeout( function() { change(e, value); @@ -224,18 +232,27 @@ function change(e, value) { if(!e) { var e = window.event; } + if(e.target) { var target = e.target; + } else if (ajax_select_event) { + var e = ajax_select_event; + ajax_select_event = null; + if(e.target) { + var target = e.target; + } else if (e.srcElement) { + var target = e.srcElement; + } } else if (e.srcElement) { var target = e.srcElement; - } + } if(target) { if (target.nodeType == 3) { // defeat Safari bug target = target.parentNode; } var id = target.id; var value = target.value; - } else if (e) { + } else if (typeof(e) == 'string' ) { var id = e; if(value) { var value = value; @@ -243,6 +260,9 @@ function change(e, value) { var value = e.value; } var set_id = id.substr(0, id.lastIndexOf('[')); + } else { + alert('Error in events'); + return; } var base_id = id.substr(0, id.lastIndexOf('[')); @@ -254,8 +274,14 @@ function change(e, value) { * We check for Tab, Up and Down */ var interested = false; + var keycode = ''; for(var i = 0; i < no_search_keys.length; i++) { - if(e.keyCode == no_search_keys[i]) { + if(e.which) { + keycode = e.which; + } else if(e && e.keyCode) { + keycode = e.keyCode; + } + if(keycode == no_search_keys[i]) { interested = true; break; } @@ -285,6 +311,18 @@ function change(e, value) { } +/** +* Deep copy an object +* Used because IE thinks its a good idea to use a global var for events +*/ +function cloneObject(obj) { + var clone = {}; + for(var i in obj) { + clone[i] = obj[i]; + } + return clone; +} + /* Remove options from a results box * @param id - The id of the select */ From ea5535284fba82a0c87d6ed4cf53c0e58ec81fde Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Tue, 16 Feb 2010 10:42:27 +0000 Subject: [PATCH 007/334] fix for addressbook hook_home problem; birthdays where not displayed correctly anymore in home view --- addressbook/inc/class.addressbook_bo.inc.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/addressbook/inc/class.addressbook_bo.inc.php b/addressbook/inc/class.addressbook_bo.inc.php index 1461aa0862..7f01d79a53 100755 --- a/addressbook/inc/class.addressbook_bo.inc.php +++ b/addressbook/inc/class.addressbook_bo.inc.php @@ -146,8 +146,7 @@ class addressbook_bo extends addressbook_so function __construct($contact_app='addressbook') { parent::__construct($contact_app); - - $this->now_su = new egw_time('now'); + $this->now_su = egw_time::to('now','ts'); $this->prefs =& $GLOBALS['egw_info']['user']['preferences']['addressbook']; // get the default addressbook from the users prefs From 9d39f2ec989a670ed12c7b601a71047a7040d753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Lehrke?= Date: Tue, 16 Feb 2010 15:09:52 +0000 Subject: [PATCH 008/334] Fix newline issue --- phpgwapi/inc/horde/Horde/String.php | 45 +++++++++++++++++++------- phpgwapi/inc/horde/Horde/iCalendar.php | 2 +- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/phpgwapi/inc/horde/Horde/String.php b/phpgwapi/inc/horde/Horde/String.php index 1ff4021c21..237541a418 100644 --- a/phpgwapi/inc/horde/Horde/String.php +++ b/phpgwapi/inc/horde/Horde/String.php @@ -6,9 +6,9 @@ $GLOBALS['_HORDE_STRING_CHARSET'] = 'iso-8859-1'; * The String:: class provides static methods for charset and locale safe * string manipulation. * - * $Horde: framework/Util/String.php,v 1.43.6.31 2008/10/23 21:28:38 jan Exp $ + * $Horde: framework/Util/String.php,v 1.43.6.38 2009-09-15 16:36:14 jan Exp $ * - * Copyright 2003-2008 The Horde Project (http://www.horde.org/) + * Copyright 2003-2009 The Horde Project (http://www.horde.org/) * * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. @@ -86,6 +86,9 @@ class String { } /* If the from and to character sets are identical, return now. */ + if ($from == $to) { + return $input; + } $from = String::lower($from); $to = String::lower($to); if ($from == $to) { @@ -94,6 +97,7 @@ class String { if (is_array($input)) { $tmp = array(); + reset($input); while (list($key, $val) = each($input)) { $tmp[String::_convertCharset($key, $from, $to)] = String::convertCharset($val, $from, $to); } @@ -317,20 +321,40 @@ class String { if (is_null($length)) { $length = String::length($string, $charset) - $start; } + if ($length == 0) { return ''; } + + /* Try mbstring. */ if (String::extensionExists('mbstring')) { + if (is_null($charset)) { + $charset = $GLOBALS['_HORDE_STRING_CHARSET']; + } + $old_error = error_reporting(0); + $ret = mb_substr($string, $start, $length, String::_mbstringCharset($charset)); + error_reporting($old_error); + /* mb_substr() returns empty string on failure. */ + if (strlen($ret)) { + return $ret; + } + } + + /* Try iconv. */ + if (function_exists('iconv_substr')) { if (is_null($charset)) { $charset = $GLOBALS['_HORDE_STRING_CHARSET']; } + $old_error = error_reporting(0); - $ret = mb_substr($string, $start, $length, String::_mbstringCharset($charset)); + $ret = iconv_substr($string, $start, $length, $charset); error_reporting($old_error); - if (!empty($ret)) { + /* iconv_substr() returns false on failure. */ + if ($ret !== false) { return $ret; } } + return substr($string, $start, $length); } @@ -349,9 +373,6 @@ class String { $charset = $GLOBALS['_HORDE_STRING_CHARSET']; } $charset = String::lower($charset); - if ($charset == 'utf-8' || $charset == 'utf8') { - return strlen(utf8_decode($string)); - } if (String::extensionExists('mbstring')) { $old_error = error_reporting(0); $ret = mb_strlen($string, String::_mbstringCharset($charset)); @@ -360,6 +381,9 @@ class String { return $ret; } } + if ($charset == 'utf-8' || $charset == 'utf8') { + return strlen(utf8_decode($string)); + } return strlen($string); } @@ -482,9 +506,9 @@ class String { $line = String::substr($string, 0, $width, 'utf-8'); $string = String::substr($string, String::length($line, 'utf-8'), null, 'utf-8'); // Make sure didn't cut a word, unless we want hard breaks anyway. - if (!$cut && preg_match('/^(.+?)(\s|\r?\n)/u', $string, $match)) { + if (!$cut && preg_match('/^(.+?)((\s|\r?\n).*)/us', $string, $match)) { $line .= $match[1]; - $string = String::substr($string, String::length($match[1], 'utf-8'), null, 'utf-8'); + $string = $match[2]; } // Wrap at existing line breaks. if (preg_match('/^(.*?)(\r?\n)(.*)$/u', $line, $match)) { @@ -513,8 +537,7 @@ class String { } // Hard wrap if necessary. if ($cut) { - $wrapped .= String::substr($line, 0, $width, 'utf-8') . $break; - $string = String::substr($line, $width, null, 'utf-8') . $string; + $wrapped .= $line . $break; continue; } $wrapped .= $line; diff --git a/phpgwapi/inc/horde/Horde/iCalendar.php b/phpgwapi/inc/horde/Horde/iCalendar.php index b6140700a7..f6e99fd9df 100644 --- a/phpgwapi/inc/horde/Horde/iCalendar.php +++ b/phpgwapi/inc/horde/Horde/iCalendar.php @@ -1180,7 +1180,7 @@ class Horde_iCalendar { case 'QUOTED-PRINTABLE': if (!$this->isOldFormat()) { - $enconding = false; + $encoding = false; break; } $params_str .= ';ENCODING=' . $params['ENCODING']; From 39666ba03b854e36474164de3c31613aa009e4bc Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Tue, 16 Feb 2010 23:23:24 +0000 Subject: [PATCH 009/334] let link-entry display "appname: #id" for entries no link title is available (eg. because they got deleted), makes sense eg. for history logging --- etemplate/inc/class.link_widget.inc.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/etemplate/inc/class.link_widget.inc.php b/etemplate/inc/class.link_widget.inc.php index e900d6ccec..9595f705b4 100644 --- a/etemplate/inc/class.link_widget.inc.php +++ b/etemplate/inc/class.link_widget.inc.php @@ -371,8 +371,12 @@ class link_widget $titles = array(); foreach(explode(',',$id) as $id) { - if ($id && ($title = egw_link::title($app,$id))) + if ($id) { + if (!($title = egw_link::title($app,$id))) + { + $title = $app.': #'.$id; + } $titles[$id] = $title; } } From ab598b8fcbf6943cf74ed3c28a810128fc780d29 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Wed, 17 Feb 2010 00:55:43 +0000 Subject: [PATCH 010/334] fix for user changing the timezone while having an edit popup open (unfixed the timestamps would change by the differenz of the two timezones). This fix does eg. NOT fix history logging (depending on the entry read before saving it), so it is better to handle the situation in the UI code, thought this is better then not handling it at all --- etemplate/inc/class.so_sql.inc.php | 50 +++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/etemplate/inc/class.so_sql.inc.php b/etemplate/inc/class.so_sql.inc.php index 4b54746a24..edd36a1cf8 100644 --- a/etemplate/inc/class.so_sql.inc.php +++ b/etemplate/inc/class.so_sql.inc.php @@ -166,7 +166,8 @@ class so_sql * @param string $colum_prefix='' column prefix to automatic remove from the column-name, if the column name starts with it * @param boolean $no_clone=false can we avoid to clone the db-object, default no * new code using appnames and foreach(select(...,$app) can set it to avoid an extra instance of the db object - * @param string $timestamp_type=null default null=leave them as is, 'ts'|'integer' use integer unix timestamps, 'object' use egw_time objects + * @param string $timestamp_type=null default null=leave them as is, 'ts'|'integer' use integer unix timestamps, + * 'object' use egw_time objects or 'string' use DB timestamp (Y-m-d H:i:s) string * * @return so_sql */ @@ -197,8 +198,22 @@ class so_sql echo "

so_sql('$app','$table')

\n"; _debug_array($this); } - // set timestampt type and current time - switch(($this->timestamp_type = $timestamp_type)) + $this->set_times($timestamp_type); + } + + /** + * Set class vars timestamp_type, now and tz_offset_s + * + * @param string|boolean $timestamp_type=false default false do NOT set time_stamptype, + * null=leave them as is, 'ts'|'integer' use integer unix timestamps, 'object' use egw_time objects, + * 'string' use DB timestamp (Y-m-d H:i:s) string + */ + public function set_times($timestamp_type=false) + { + if ($timestamp_type !== false) $this->timestamp_type = $timestamp_type; + + // set current time + switch($this->timestamp_type) { case 'object': $this->now = new egw_time('now'); @@ -320,6 +335,10 @@ class so_sql $this->data[$col] = $new[$col]; } } + if (isset($new[self::USER_TIMEZONE_READ])) + { + $this->data[self::USER_TIMEZONE_READ] = $new[self::USER_TIMEZONE_READ]; + } if ((int) $this->debug >= 4) _debug_array($this->data); } @@ -419,6 +438,11 @@ class so_sql return $this->data; } + + /** + * Name of automatically set user timezone field from read + */ + const USER_TIMEZONE_READ = 'user_timezone_read'; /** * reads row matched by key and puts all cols in the data array @@ -514,6 +538,9 @@ class so_sql } $this->db2data(); + // store user timezone used for reading + $this->data[self::USER_TIMEZONE_READ] = egw_time::$user_timezone->getName(); + if ((int) $this->debug >= 4) { echo "data =\n"; _debug_array($this->data); @@ -527,7 +554,7 @@ class so_sql if ((int) $this->debug >= 4) echo "nothing found !!!

\n"; $this->db2data(); - + return False; } @@ -541,7 +568,20 @@ class so_sql function save($keys=null,$extra_where=null) { if (is_array($keys) && count($keys)) $this->data_merge($keys); - + + // check if data contains user timezone during read AND user changed timezone since then + // --> load old timezone for the rest of this request + // this only a grude hack, better handle this situation in app code: + // history logging eg. depends on old data read before calling save, which is then in new timezone! + // anyway it's better fixing it here then not fixing it at all ;-) + if (isset($this->data[self::USER_TIMEZONE_READ]) && $this->data[self::USER_TIMEZONE_READ] != egw_time::$user_timezone->getName()) + { + //echo "

".__METHOD__."() User change TZ since read! tz-read=".$this->data[self::USER_TIMEZONE_READ].' != current-tz='.egw_time::$user_timezone->getName()." --> fixing

\n"; + error_log(__METHOD__."() User changed TZ since read! tz-read=".$this->data[self::USER_TIMEZONE_READ].' != current-tz='.egw_time::$user_timezone->getName()." --> fixing

"); + $GLOBALS['egw_info']['user']['preferences']['common']['tz'] = $this->data[self::USER_TIMEZONE_READ]; + egw_time::setUserPrefs($this->data[self::USER_TIMEZONE_READ]); + $this->set_times(); + } $this->data2db(); if ((int) $this->debug >= 4) { echo "so_sql::save(".print_r($keys,true).") autoinc_id='$this->autoinc_id', data="; _debug_array($this->data); } From d2d64a73fe20c1c14989e972af2aa64696a1968f Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Wed, 17 Feb 2010 12:03:37 +0000 Subject: [PATCH 011/334] get rid of comma in full-emailadresses, as imap_rfc_address_list assumes a new address to come after comma --- addressbook/inc/class.addressbook_ui.inc.php | 1 + 1 file changed, 1 insertion(+) diff --git a/addressbook/inc/class.addressbook_ui.inc.php b/addressbook/inc/class.addressbook_ui.inc.php index 986544ad88..3fb0538cd5 100644 --- a/addressbook/inc/class.addressbook_ui.inc.php +++ b/addressbook/inc/class.addressbook_ui.inc.php @@ -686,6 +686,7 @@ class addressbook_ui extends addressbook_bo } if($email) { + $contact['n_fn'] = str_replace(',',' ',$contact['n_fn']); $GLOBALS['egw']->js->set_onload("addEmail('".addslashes( $contact['n_fn'] ? $contact['n_fn'].' <'.$email.'>' : $email)."');"); $Ok = true; From 8204d84ca501920c192297b5418939d3f3d106d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Lehrke?= Date: Wed, 17 Feb 2010 13:28:00 +0000 Subject: [PATCH 012/334] Enable proper 'refresh from server' again --- phpgwapi/inc/horde/Horde/SyncML/Command/Alert.php | 1 + 1 file changed, 1 insertion(+) diff --git a/phpgwapi/inc/horde/Horde/SyncML/Command/Alert.php b/phpgwapi/inc/horde/Horde/SyncML/Command/Alert.php index 89c2c0eac5..61e057ea3c 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Command/Alert.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Command/Alert.php @@ -255,6 +255,7 @@ class Horde_SyncML_Command_Alert extends Horde_SyncML_Command { case ALERT_REFRESH_FROM_SERVER: $synctype = ALERT_REFRESH_FROM_SERVER; $response = $anchormatch ? RESPONSE_OK : RESPONSE_REFRESH_REQUIRED; + $anchormatch = false; break; case ALERT_RESUME: From 21ccdd5f288e11ef83577da78e83e39f5135bb56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Lehrke?= Date: Wed, 17 Feb 2010 13:29:28 +0000 Subject: [PATCH 013/334] Fix various synchronization issues (SyncML & CalDAV) --- calendar/inc/class.calendar_bo.inc.php | 4 + calendar/inc/class.calendar_boupdate.inc.php | 74 ++++++---- calendar/inc/class.calendar_groupdav.inc.php | 66 ++++++--- calendar/inc/class.calendar_ical.inc.php | 138 +++++++++++++----- calendar/inc/class.calendar_sif.inc.php | 10 +- calendar/inc/class.calendar_so.inc.php | 102 ++++++++----- calendar/inc/class.calendar_ui.inc.php | 3 +- calendar/templates/default/images/forward.gif | Bin 0 -> 319 bytes calendar/templates/default/images/forward.png | Bin 0 -> 494 bytes 9 files changed, 264 insertions(+), 133 deletions(-) create mode 100644 calendar/templates/default/images/forward.gif create mode 100644 calendar/templates/default/images/forward.png diff --git a/calendar/inc/class.calendar_bo.inc.php b/calendar/inc/class.calendar_bo.inc.php index 08d45f45c6..9b759b0d6d 100644 --- a/calendar/inc/class.calendar_bo.inc.php +++ b/calendar/inc/class.calendar_bo.inc.php @@ -95,6 +95,7 @@ class calendar_bo 'R' => 'Rejected', 'T' => 'Tentative', 'U' => 'No Response', + 'D' => 'Delegated', 'G' => 'Group invitation', ); /** @@ -1349,6 +1350,9 @@ class calendar_bo case 'U': // no response = unknown $status = html::image('calendar','cnr-pending',$this->verbose_status[$status]); break; + case 'D': // delegated + $status = html::image('calendar','forward',$this->verbose_status[$status]); + break; case 'G': // group invitation // Todo: Image, seems not to be used $status = '('.$this->verbose_status[$status].')'; diff --git a/calendar/inc/class.calendar_boupdate.inc.php b/calendar/inc/class.calendar_boupdate.inc.php index e4fe7a1639..c6cdc212a1 100644 --- a/calendar/inc/class.calendar_boupdate.inc.php +++ b/calendar/inc/class.calendar_boupdate.inc.php @@ -20,6 +20,7 @@ define('MSG_TENTATIVE',4); define('MSG_ACCEPTED',5); define('MSG_ALARM',6); define('MSG_DISINVITE',7); +define('MSG_DELEGATED',8); /** * Class to access AND manipulate all calendar data (business object) @@ -493,7 +494,7 @@ class calendar_boupdate extends calendar_bo // the following switch falls through all cases, as each included the following too // - $msg_is_response = $msg_type == MSG_REJECTED || $msg_type == MSG_ACCEPTED || $msg_type == MSG_TENTATIVE; + $msg_is_response = $msg_type == MSG_REJECTED || $msg_type == MSG_ACCEPTED || $msg_type == MSG_TENTATIVE || $msg_type == MSG_DELEGATED; switch($ru = $part_prefs['calendar']['receive_updates']) { @@ -619,6 +620,12 @@ class calendar_boupdate extends calendar_bo $msgtype = '"calendar";'; $method = 'REPLY'; break; + case MSG_DELEGATED: + $action = lang('Delegated'); + $msg = 'Response'; + $msgtype = '"calendar";'; + $method = 'REPLY'; + break; case MSG_ALARM: $action = lang('Alarm'); $msg = 'Alarm'; @@ -825,8 +832,16 @@ class calendar_boupdate extends calendar_bo return false; } - // invalidate the read-cache if it contains the event we store now - if ($event['id'] && $event['id'] == self::$cached_event['id']) self::$cached_event = array(); + if ($event['id']) + { + // invalidate the read-cache if it contains the event we store now + if ($event['id'] == self::$cached_event['id']) self::$cached_event = array(); + $old_event = $this->read($event['id'], $event['recurrence'], false, 'server'); + } + else + { + $old_event = null; + } $save_event = $event; // we run all dates through date2ts, to adjust to server-time and the possible date-formats @@ -858,8 +873,6 @@ class calendar_boupdate extends calendar_bo } $set_recurrences = false; $set_recurrences_start = 0; - $old_event = $this->read($event['id'], $event['recurrence']); - if (($cal_id = $this->so->save($event,$set_recurrences,$set_recurrences_start,0,$event['etag'])) && $set_recurrences && $event['recur_type'] != MCAL_RECUR_NONE) { $save_event['id'] = $cal_id; @@ -1062,7 +1075,7 @@ class calendar_boupdate extends calendar_bo error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. "($cal_id, $uid, $status, $recur_date)"); } - $old_event = $this->read($cal_id, $recur_date); + $old_event = $this->read($cal_id, $recur_date, false, 'server'); if (($Ok = $this->so->set_status($cal_id,is_numeric($uid)?'u':$uid[0],is_numeric($uid)?$uid:substr($uid,1),$status,$recur_date ? $this->date2ts($recur_date,true) : 0,$role))) { if ($updateTS) $GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id,'modify',time()); @@ -1071,6 +1084,7 @@ class calendar_boupdate extends calendar_bo 'R' => MSG_REJECTED, 'T' => MSG_TENTATIVE, 'A' => MSG_ACCEPTED, + 'D' => MSG_DELEGATED, ); if (isset($status2msg[$status])) { @@ -1080,7 +1094,7 @@ class calendar_boupdate extends calendar_bo } // Update history - if (!is_array($event)) $event = $this->read($cal_id); + $event = $this->read($cal_id, $recur_date, false, 'server'); $tracking = new calendar_tracking($this); $tracking->track($event, $old_event); @@ -1098,8 +1112,6 @@ class calendar_boupdate extends calendar_bo */ function delete($cal_id,$recur_date=0,$ignore_acl=false) { - $event = $this->read($cal_id,$recur_date); - if (!($event = $this->read($cal_id,$recur_date)) || !$ignore_acl && !$this->check_perms(EGW_ACL_DELETE,$event)) { @@ -1111,10 +1123,6 @@ class calendar_boupdate extends calendar_bo { $this->so->delete($cal_id); $GLOBALS['egw']->contenthistory->updateTimeStamp('calendar',$cal_id,'delete',time()); - - // Update history - $tracking = new calendar_tracking($this); - $tracking->track($event, $event, null, true); // delete all links to the event egw_link::unlink(0,'calendar',$cal_id); @@ -1448,6 +1456,7 @@ class calendar_boupdate extends calendar_bo { $matchingEvents = array(); $query = array(); + $recur_date = 0; if ($this->log) { @@ -1459,17 +1468,12 @@ class calendar_boupdate extends calendar_bo { if (isset($event['recurrence'])) { - $recur_date = $event['recurrence']; + $recur_date = $this->date2usertime($event['recurrence']); } - else + elseif (isset($event['start'])) { - $recur_date = $event['start']; + $recur_date = $this->date2usertime($event['start']); } - $recur_date = $this->date2usertime($recur_date); - } - else - { - $recur_date = 0; } if ($event['id']) @@ -1501,13 +1505,14 @@ class calendar_boupdate extends calendar_bo return $matchingEvents; } } - if ($filter == 'exact' || $filter == 'check') return array(); + if ($filter == 'exact') return array(); } unset($event['id']); if ($filter == 'master') { $query[] = 'recur_type!='. MCAL_RECUR_NONE; + $query['cal_recurrence'] = 0; } // only query calendars of users, we have READ-grants from @@ -1611,7 +1616,7 @@ class calendar_boupdate extends calendar_bo error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. '(' . $event['uid'] . ')[EventUID]'); } - if (isset($event['recurrence'])) + if ($filter != 'master' && isset($event['recurrence'])) { $query['cal_recurrence'] = $event['recurrence']; } @@ -1637,17 +1642,17 @@ class calendar_boupdate extends calendar_bo foreach($foundEvents as $egwEvent) { - if (in_array($egwEvent['id'], $matchingEvents)) continue; - if ($this->log) { error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. '[FOUND]: ' . array2string($egwEvent)); } + if (in_array($egwEvent['id'], $matchingEvents)) continue; - if ($filter == 'chec' && !empty($event['uid'])) + if (in_array($filter, array('exact', 'master')) && !empty($event['uid'])) { $matchingEvents[] = $egwEvent['id']; // UID found + if ($filter = 'master') break; continue; } @@ -1849,6 +1854,7 @@ class calendar_boupdate extends calendar_bo } } $matchingEvents[] = $egwEvent['id']; // exact match + if ($filter = 'master') break; } // append pseudos as last entries $matchingEvents = array_merge($matchingEvents, $pseudos); @@ -1942,20 +1948,24 @@ class calendar_boupdate extends calendar_bo in_array($event['recurrence'], $master_event['recur_exception'])) { $type = 'SERIES-PSEUDO-EXCEPTION'; // could also be a real one - $recurrence_event = $event; + $recurrence_event = $master_event; + $recurrence_event['start'] = $event['recurrence']; + $recurrence_event['end'] -= $master_event['start'] - $event['recurrence']; break; } elseif (in_array($event['start'], $master_event['recur_exception'])) { $type='SERIES-PSEUDO-EXCEPTION'; // new pseudo exception? - $recurrence_event = $event; + $recurrence_event = $master_event; + $recurrence_event['start'] = $event['start']; + $recurrence_event['end'] -= $master_event['start'] - $event['start']; break; } else { // try to find a suitable pseudo exception date $egw_rrule = calendar_rrule::event2rrule($master_event, false); - $egw_rrule->rewind(); + $egw_rrule->current = clone $egw_rrule->time; while ($egw_rrule->valid()) { $occurrence = egw_time::to($egw_rrule->current(), 'server'); @@ -1967,7 +1977,9 @@ class calendar_boupdate extends calendar_bo if ($event['start'] == $occurrence) { $type = 'SERIES-PSEUDO-EXCEPTION'; // let's try a pseudo exception - $recurrence_event = $event; + $recurrence_event = $master_event; + $recurrence_event['start'] = $occurrence; + $recurrence_event['end'] -= $master_event['start'] - $occurrence; break 2; } if (isset($event['recurrence']) && $event['recurrence'] == $occurrence) @@ -2077,4 +2089,4 @@ class calendar_boupdate extends calendar_bo } } } -} +} \ No newline at end of file diff --git a/calendar/inc/class.calendar_groupdav.inc.php b/calendar/inc/class.calendar_groupdav.inc.php index 32d170f64d..5883a74643 100644 --- a/calendar/inc/class.calendar_groupdav.inc.php +++ b/calendar/inc/class.calendar_groupdav.inc.php @@ -110,10 +110,12 @@ class calendar_groupdav extends groupdav_handler 'daywise' => false, 'date_format' => 'server', ); + /* if ($this->client_shared_uid_exceptions) { $cal_filters['query']['cal_reference'] = 0; } + */ // process REPORT filters or multiget href's if (($id || $options['root']['name'] != 'propfind') && !$this->_report_filters($options,$cal_filters,$id)) { @@ -137,8 +139,17 @@ class calendar_groupdav extends groupdav_handler if ($events) { // get all max user modified times at once - foreach($events as &$event) + foreach($events as $k => &$event) { + if ($this->client_shared_uid_exceptions && + $event['reference'] && + ($master = $this->bo->read($event['reference'], 0, false, 'server')) && + array_search($event['recurrence'], $master['recur_exception']) !== false) + { + // this exception will be handled with the series master + unset($events[$k]); + continue; + } $ids[] = $event['id']; } $max_user_modified = $this->bo->so->max_user_modified($ids); @@ -350,22 +361,28 @@ class calendar_groupdav extends groupdav_handler */ private static function &get_series($uid,calendar_bo $bo=null) { - if (is_null($bo)) $bo = new calendar_bo(); + if (is_null($bo)) $bo = new calendar_bopdate(); + + if (!($masterId = array_shift($bo->find_event(array('uid' => $uid), 'master'))) + || !($master = $bo->read($masterId, 0, false, 'server'))) + { + return array(); // should never happen + } + + $exceptions = $master['recur_exception']; $events =& $bo->search(array( 'query' => array('cal_uid' => $uid), 'daywise' => false, 'date_format' => 'server', )); - $master = null; + $events = array_merge(array($master), $events); foreach($events as $k => &$recurrence) { - if (!isset($master)) // first event is always the series master - { - $master =& $events[$k]; - //error_log('master: '.array2string($master)); - continue; // nothing to change - } + //error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. + // "($uid)[$k]:" . array2string($recurrence)); + if (!$k) continue; // nothing to change + if ($recurrence['id'] != $master['id']) // real exception { //error_log('real exception: '.array2string($recurrence)); @@ -373,9 +390,9 @@ class calendar_groupdav extends groupdav_handler // at least Lightning "understands" EXDATE as exception from what's included // in the whole resource / VCALENDAR component // not removing it causes Lightning to remove the exception itself - if (($k = array_search($recurrence['recurrence'],$master['recur_exception'])) !== false) + if (($e = array_search($recurrence['recurrence'],$exceptions)) !== false) { - unset($master['recur_exception'][$k]); + unset($exceptions[$e]); } continue; // nothing to change } @@ -386,13 +403,14 @@ class calendar_groupdav extends groupdav_handler unset($events[$k]); // no exception --> remove it continue; } - // this is a virtual excetion now (no extra event/cal_id in DB) + // this is a virtual exception now (no extra event/cal_id in DB) //error_log('virtual exception: '.array2string($recurrence)); $recurrence['recurrence'] = $recurrence['start']; $recurrence['reference'] = $master['id']; $recurrence['recur_type'] = MCAL_RECUR_NONE; // is set, as this is a copy of the master // not for included exceptions (Lightning): $master['recur_exception'][] = $recurrence['start']; } + $events[0]['recur_exception'] = $exceptions; return $events; } @@ -416,10 +434,12 @@ class calendar_groupdav extends groupdav_handler return $event; } $handler = $this->_get_handler(); - if (!is_numeric($id) && ($foundEntries = $handler->find_event($options['content'], 'check'))) + + if (!is_numeric($id) && ($foundEntries = $handler->find_event($options['content'], 'exact'))) { $id = array_shift($foundEntries); } + if (!($cal_id = $handler->importVCal($options['content'],is_numeric($id) ? $id : -1, self::etag2value($this->http_if_match)))) { @@ -448,14 +468,15 @@ class calendar_groupdav extends groupdav_handler static function fix_series(array &$events) { foreach($events as $n => $event) error_log(__METHOD__." $n before: ".array2string($event)); - $master =& $events[0]; + //$master =& $events[0]; $bo = new calendar_boupdate(); // get array with orginal recurrences indexed by recurrence-id - $org_recurrences = array(); - foreach(self::get_series($master['uid'],$bo) as $event) + $org_recurrences = $exceptions = array(); + foreach(self::get_series($events[0]['uid'],$bo) as $k => $event) { + if (!$k) $master = $event; if ($event['recurrence']) { $org_recurrences[$event['recurrence']] = $event; @@ -463,9 +484,15 @@ class calendar_groupdav extends groupdav_handler } // assign cal_id's to already existing recurrences and evtl. re-add recur_exception to master - foreach($events as &$recurrence) + foreach($events as $k => &$recurrence) { - if ($recurrence['id'] || !$recurrence['recurrence']) continue; // master + if (!$recurrence['recurrence']) + { + // master + $recurrence['id'] = $master['id']; + $master =& $events[$k]; + continue; + } // from now on we deal with exceptions $org_recurrence = $org_recurrences[$recurrence['recurrence']]; @@ -478,12 +505,13 @@ class calendar_groupdav extends groupdav_handler if ($recurrence['id'] != $master['id']) { error_log(__METHOD__.'() re-adding recur_exception '.$recurrence['recurrence'].' = '.date('Y-m-d H:i:s',$recurrence['recurrence'])); - $master['recur_exception'][] = $recurrence['recurrence']; + $exceptions[] = $recurrence['recurrence']; } // remove recurrence to be able to detect deleted exceptions unset($org_recurrences[$recurrence['recurrence']]); } } + $master['recur_exception'] = array_merge($exceptions, $master['recur_exception']); // delete not longer existing recurrences foreach($org_recurrences as $org_recurrence) diff --git a/calendar/inc/class.calendar_ical.inc.php b/calendar/inc/class.calendar_ical.inc.php index 7a62111d79..167731fe1e 100644 --- a/calendar/inc/class.calendar_ical.inc.php +++ b/calendar/inc/class.calendar_ical.inc.php @@ -41,6 +41,7 @@ class calendar_ical extends calendar_boupdate 'A' => 'ACCEPTED', 'R' => 'DECLINED', 'T' => 'TENTATIVE', + 'D' => 'DELEGATED' ); /** * @var array conversation of the participant status ical => egw @@ -51,6 +52,7 @@ class calendar_ical extends calendar_boupdate 'ACCEPTED' => 'A', 'DECLINED' => 'R', 'TENTATIVE' => 'T', + 'DELEGATED' => 'D', ); /** @@ -227,7 +229,7 @@ class calendar_ical extends calendar_boupdate if ($this->log) { error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. - "() User does not have the permission to read event $_id.\n", + '() User does not have the permission to read event ' . $event['id']. "\n", 3,$this->logfile); } return -1; // Permission denied @@ -238,8 +240,8 @@ class calendar_ical extends calendar_boupdate if ($this->log) { error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. - "() Event $_id not found.\n", - 3,$this->logfile); + "() Event $event not found.\n", + 3, $this->logfile); } } continue; @@ -342,15 +344,21 @@ class calendar_ical extends calendar_boupdate $horde_vtimezone->parsevCalendar($vtimezone,'VTIMEZONE'); // DTSTART must be in local time! $standard = $horde_vtimezone->findComponent('STANDARD'); - $dtstart = $standard->getAttribute('DTSTART'); - $dtstart = new egw_time($dtstart, egw_time::$server_timezone); - $dtstart->setTimezone(self::$tz_cache[$tzid]); - $standard->setAttribute('DTSTART', $dtstart->format('Ymd\THis'), array(), false); + if (is_a($standard, 'Horde_iCalendar')) + { + $dtstart = $standard->getAttribute('DTSTART'); + $dtstart = new egw_time($dtstart, egw_time::$server_timezone); + $dtstart->setTimezone(self::$tz_cache[$tzid]); + $standard->setAttribute('DTSTART', $dtstart->format('Ymd\THis'), array(), false); + } $daylight = $horde_vtimezone->findComponent('DAYLIGHT'); - $dtstart = $daylight->getAttribute('DTSTART'); - $dtstart = new egw_time($dtstart, egw_time::$server_timezone); - $dtstart->setTimezone(self::$tz_cache[$tzid]); - $daylight->setAttribute('DTSTART', $dtstart->format('Ymd\THis'), array(), false); + if (is_a($daylight, 'Horde_iCalendar')) + { + $dtstart = $daylight->getAttribute('DTSTART'); + $dtstart = new egw_time($dtstart, egw_time::$server_timezone); + $dtstart->setTimezone(self::$tz_cache[$tzid]); + $daylight->setAttribute('DTSTART', $dtstart->format('Ymd\THis'), array(), false); + } $vcal->addComponent($horde_vtimezone); $vtimezones_added[] = $tzid; } @@ -396,6 +404,7 @@ class calendar_ical extends calendar_boupdate sort($exceptions); } $event['recur_exception'] = $exceptions; + /* // Adjust the event start -- must not be an exception $length = $event['end'] - $event['start']; $rriter = calendar_rrule::event2rrule($event, false, $tzid); @@ -415,13 +424,21 @@ class calendar_ical extends calendar_boupdate { // the series dissolved completely into exceptions continue; - } + }*/ } foreach ($egwSupportedFields as $icalFieldName => $egwFieldName) { - if (!isset($this->supportedFields[$egwFieldName])) continue; - + if (!isset($this->supportedFields[$egwFieldName])) + { + if ($this->log) + { + error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. + '(' . $event['id'] . ") [$icalFieldName] not supported\n", + 3,$this->logfile); + } + continue; + } $values[$icalFieldName] = array(); switch ($icalFieldName) { @@ -928,11 +945,30 @@ class calendar_ical extends calendar_boupdate { if (!is_array($this->supportedFields)) $this->setSupportedFields(); - if (!($events = $this->icaltoegw($_vcalData,$cal_id,$etag,$recur_date))) + if (!($events = $this->icaltoegw($_vcalData))) { return false; } + if ($cal_id > 0) + { + if (count($events) == 1) + { + $events[0]['id'] = $cal_id; + if (!is_null($etag)) $events[0]['etag'] = (int) $etag; + if ($recur_date) $events[0]['recurrence'] = $recur_date; + } + elseif (($foundEvent = $this->find_event(array('id' => $cal_id), 'exact')) && + ($eventId = array_shift($foundEvent)) && + ($egwEvent = $this->read($eventId))) + { + foreach ($events as $k => $event) + { + if (!isset($event['uid'])) $events[$k]['uid'] = $egwEvent['uid']; + } + } + } + // check if we are importing an event series with exceptions in CalDAV // only first event / series master get's cal_id from URL // other events are exceptions and need to be checked if they are new @@ -947,13 +983,18 @@ class calendar_ical extends calendar_boupdate foreach ($events as $event) { if ($this->so->isWholeDay($event)) $event['whole_day'] = true; - + if (is_array($event['category'])) + { + $event['category'] = $this->find_or_add_categories($event['category'], + isset($event['id']) ? $event['id'] : -1); + } if ($this->log) { error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" . array2string($event)."\n",3,$this->logfile); } + /* if ($event['recur_type'] != MCAL_RECUR_NONE) { // Adjust the event start -- no exceptions before and at the start @@ -987,7 +1028,7 @@ class calendar_ical extends calendar_boupdate } $event['recur_exception'] = $exceptions; } - + */ $updated_id = false; $event_info = $this->get_event_info($event); @@ -1066,11 +1107,11 @@ class calendar_ical extends calendar_boupdate error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. "() Restore status for $uid\n",3,$this->logfile); } - $event['participants']['uid'] = $event_info['stored_event']['participants'][$uid]; + $event['participants'][$uid] = $event_info['stored_event']['participants'][$uid]; } else { - $event['participants']['uid'] = calendar_so::combine_status('U'); + $event['participants'][$uid] = calendar_so::combine_status('U'); } } } @@ -1271,7 +1312,7 @@ class calendar_ical extends calendar_boupdate if (is_array($days)) { $recur_exceptions = array(); - + /* if (!isset($days[$event_info['stored_event']['start']]) && $event_info['stored_event']['start'] < $event['start']) { @@ -1318,7 +1359,7 @@ class calendar_ical extends calendar_boupdate $event['start'] = $startdate; $event['end'] = $startdate + $length; - } + } */ foreach ($event['recur_exception'] as $recur_exception) { @@ -1363,7 +1404,7 @@ class calendar_ical extends calendar_boupdate $event_info['master_event']['recur_exception'] = array_unique(array_merge($event_info['master_event']['recur_exception'], array($event['recurrence']))); - + /* // Adjust the event start -- must not be an exception $length = $event_info['master_event']['end'] - $event_info['master_event']['start']; $rriter = calendar_rrule::event2rrule($event_info['master_event'], false); @@ -1376,6 +1417,21 @@ class calendar_ical extends calendar_boupdate // remove leading exceptions if ($day < $newstart) { + if (($foundEvents = $this->find_event( + array('uid' => $event_info['master_event']['uid'], + 'recurrence' => $day), 'exact')) && + ($eventId = array_shift($foundEvents)) && + ($exception = read($eventId, 0, 'server'))) + { + // Unlink this exception + unset($exception['uid']); + $this->update($exception, true); + } + if ($event['recurrence'] == $day) + { + // Unlink this exception + unset($event['uid']); + } unset($event_info['master_event']['recur_exception'][$key]); } } @@ -1384,14 +1440,14 @@ class calendar_ical extends calendar_boupdate { $event_info['master_event']['start'] = $newstart; $event_info['master_event']['end'] = $newstart + $length; - $event_to_store = $event_info['master_event']; // prevent the master_event from being changed by the update method - $this->server2usertime($event_to_store); - $this->update($event_to_store, true); - unset($event_to_store); - } + }*/ $event['reference'] = $event_info['master_event']['id']; $event['category'] = $event_info['master_event']['category']; $event['owner'] = $event_info['master_event']['owner']; + $event_to_store = $event_info['master_event']; // prevent the master_event from being changed by the update method + $this->server2usertime($event_to_store); + $this->update($event_to_store, true); + unset($event_to_store); } $event_to_store = $event; // prevent $event from being changed by update method @@ -1864,7 +1920,7 @@ class calendar_ical extends calendar_boupdate } } - function icaltoegw($_vcalData, $cal_id=-1, $etag=null, $recur_date=0) + function icaltoegw($_vcalData) { if ($this->log) { @@ -1906,7 +1962,7 @@ class calendar_ical extends calendar_boupdate { if (is_a($component, 'Horde_iCalendar_vevent')) { - if (($event = $this->vevent2egw($component, $version, $this->supportedFields, $cal_id))) + if (($event = $this->vevent2egw($component, $version, $this->supportedFields))) { //common adjustments if ($this->productManufacturer == '' && $this->productName == '' @@ -1943,11 +1999,6 @@ class calendar_ical extends calendar_boupdate date_default_timezone_set($GLOBALS['egw_info']['server']['server_timezone']); - // if cal_id, etag or recur_date is given, use/set it for 1. event - if ($cal_id > 0) $events[0]['id'] = $cal_id; - if (!is_null($etag)) $events[0]['etag'] = (int) $etag; - if ($recur_date) $events[0]['recurrence'] = $recur_date; - return $events; } @@ -1957,11 +2008,10 @@ class calendar_ical extends calendar_boupdate * @param array $component VEVENT * @param string $version vCal version (1.0/2.0) * @param array $supportedFields supported fields of the device - * @param int $cal_id id of existing event in the content (only used to merge categories) * * @return array|boolean event on success, false on failure */ - function vevent2egw(&$component, $version, $supportedFields, $cal_id=-1) + function vevent2egw(&$component, $version, $supportedFields) { if (!is_a($component, 'Horde_iCalendar_vevent')) return false; @@ -2353,7 +2403,7 @@ class calendar_ical extends calendar_boupdate case 'CATEGORIES': if ($attributes['value']) { - $vcardData['category'] = $this->find_or_add_categories(explode(',',$attributes['value']), $cal_id); + $vcardData['category'] = explode(',', $attributes['value']); } else { @@ -2369,6 +2419,7 @@ class calendar_ical extends calendar_boupdate if (isset($attributes['params']['STATUS'])) { $status = $this->status_ical2egw[strtoupper($attributes['params']['STATUS'])]; + if (empty($status)) $status = 'X'; } else { @@ -2599,8 +2650,6 @@ class calendar_ical extends calendar_boupdate if ($this->calendarOwner) $event['owner'] = $this->calendarOwner; - if ($cal_id > 0) $event['id'] = $cal_id; - if ($this->log) { error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n" . @@ -2613,7 +2662,15 @@ class calendar_ical extends calendar_boupdate function search($_vcalData, $contentID=null, $relax=false) { - if (($events = $this->icaltoegw($_vcalData,!is_null($contentID) ? $contentID : -1))) + if (is_null($contentID)) + { + $eventId = -1; + } + else + { + $eventId = $contentID; + } + if (($events = $this->icaltoegw($_vcalData))) { // this function only supports searching a single event if (count($events) == 1) @@ -2621,6 +2678,7 @@ class calendar_ical extends calendar_boupdate $filter = $relax ? 'relax' : 'check'; $event = array_shift($events); if ($this->so->isWholeDay($event)) $event['whole_day'] = true; + $event['category'] = $this->find_or_add_categories($event['category'], $eventId); if ($contentID) $event['id'] = $contentID; return $this->find_event($event, $filter); } diff --git a/calendar/inc/class.calendar_sif.inc.php b/calendar/inc/class.calendar_sif.inc.php index d5c70c8942..6551ebd2f9 100644 --- a/calendar/inc/class.calendar_sif.inc.php +++ b/calendar/inc/class.calendar_sif.inc.php @@ -430,6 +430,7 @@ class calendar_sif extends calendar_boupdate return false; } + /* if ($event['recur_type'] != MCAL_RECUR_NONE) { // Adjust the event start -- no exceptions before and at the start @@ -462,7 +463,7 @@ class calendar_sif extends calendar_boupdate } } $event['recur_exception'] = $exceptions; - } + } */ if ($recur_date) $event['recurrence'] = $recur_date; $event_info = $this->get_event_info($event); @@ -684,7 +685,7 @@ class calendar_sif extends calendar_boupdate $event_info['master_event']['recur_exception'] = array_unique(array_merge($event_info['master_event']['recur_exception'], array($event['recurrence']))); - + /* // Adjust the event start -- must not be an exception $length = $event_info['master_event']['end'] - $event_info['master_event']['start']; $rriter = calendar_rrule::event2rrule($event_info['master_event'], false); @@ -709,7 +710,7 @@ class calendar_sif extends calendar_boupdate $this->server2usertime($event_to_store); $this->update($event_to_store, true); unset($event_to_store); - } + } */ $event['reference'] = $event_info['master_event']['id']; $event['category'] = $event_info['master_event']['category']; $event['owner'] = $event_info['master_event']['owner']; @@ -914,6 +915,7 @@ class calendar_sif extends calendar_boupdate array2string($exceptions)."\n",3,$this->logfile); } $event['recur_exception'] = $exceptions; + /* // Adjust the event start -- must not be an exception $length = $event['end'] - $event['start']; $rriter = calendar_rrule::event2rrule($event, false, $tzid); @@ -927,7 +929,7 @@ class calendar_sif extends calendar_boupdate // remove leading exceptions if ($day <= $event['start']) unset($exceptions[$key]); } - $event['recur_exception'] = $exceptions; + $event['recur_exception'] = $exceptions; */ } if ($this->uidExtension) diff --git a/calendar/inc/class.calendar_so.inc.php b/calendar/inc/class.calendar_so.inc.php index 1a5094a132..b198599cd0 100644 --- a/calendar/inc/class.calendar_so.inc.php +++ b/calendar/inc/class.calendar_so.inc.php @@ -44,6 +44,7 @@ define('REJECTED',0); define('NO_RESPONSE',1); define('TENTATIVE',2); define('ACCEPTED',3); +define('DELEGATED',4); define('HOUR_s',60*60); define('DAY_s',24*HOUR_s); @@ -188,6 +189,18 @@ class calendar_so $this->db->update($this->cal_table, array('cal_uid' => $event['uid']), array('cal_id' => $event['id']),__LINE__,__FILE__,'calendar'); } + if ((int) $recur_date == 0 && + $event['recur_type'] != MCAL_RECUR_NONE && + !empty($event['recur_exception'])) + { + sort($event['recur_exception']); + if ($event['recur_exception'][0] < $event['start']) + { + // leading exceptions => move start and end + $event['end'] -= $event['start'] - $event['recur_exception'][0]; + $event['start'] = $event['recur_exception'][0]; + } + } } // check if we have a real recurance, if not set $recur_date=0 @@ -377,6 +390,8 @@ class calendar_so $where[] = "cal_status='T'"; break; case 'rejected': $where[] = "cal_status='R'"; break; + case 'delegated': + $where[] = "cal_status='D'"; break; case 'all': case 'owner': break; @@ -649,6 +664,8 @@ ORDER BY cal_user_type, cal_usre_id $minimum_uid_length = 8; } + $old_min = $old_duration = 0; + //echo '

'.__METHOD__.'('.array2string($event).",$change_since) event="; _debug_array($event); //error_log(__METHOD__.'('.array2string($event).",$set_recurrences,$change_since,$etag)"); @@ -827,7 +844,7 @@ ORDER BY cal_user_type, cal_usre_id // update start- and endtime if present in the event-array, evtl. we need to move all recurrences if (isset($event['cal_start']) && isset($event['cal_end'])) { - $this->move($cal_id,$event['cal_start'],$event['cal_end'],!$cal_id ? false : $change_since); + $this->move($cal_id,$event['cal_start'],$event['cal_end'],!$cal_id ? false : $change_since, $old_min, $old_min + $old_duration); } // update participants if present in the event-array if (isset($event['cal_participants'])) @@ -1157,7 +1174,8 @@ ORDER BY cal_user_type, cal_usre_id REJECTED => 'R', NO_RESPONSE => 'U', TENTATIVE => 'T', - ACCEPTED => 'A' + ACCEPTED => 'A', + DELEGATED => 'D' ); if (!(int)$cal_id || !(int)$user_id && $user_type != 'e') { @@ -1581,7 +1599,7 @@ ORDER BY cal_user_type, cal_usre_id * @param int $start=0 if != 0: startdate of the search/list (servertime) * @param int $end=0 if != 0: enddate of the search/list (servertime) * @param string $filter='all' string filter-name: all (not rejected), - * accepted, unknown, tentative, rejected, + * accepted, unknown, tentative, rejected, delegated * rrule return array of remote exceptions in servertime * tz_rrule/tz_only, return (only by) timezone transition affected entries * map return array of dates with no pseudo exception @@ -1607,15 +1625,46 @@ ORDER BY cal_user_type, cal_usre_id $remote = in_array($filter, array('tz_rrule', 'rrule')); $egw_rrule = calendar_rrule::event2rrule($event, false); - $egw_rrule->rewind(); + $egw_rrule->current = clone $egw_rrule->time; if ($expand_all) { unset($event['recur_excpetion']); $remote_rrule = calendar_rrule::event2rrule($event, false, $tz_id); - $remote_rrule->rewind(); + $remote_rrule->current = clone $remote_rrule->time; } while ($egw_rrule->valid()) { + while ($egw_rrule->exceptions && + in_array($egw_rrule->current->format('Ymd'),$egw_rrule->exceptions)) + { + if (in_array($filter, array('map','tz_map','rrule','tz_rrule'))) + { + // real exception + $locts = (int)egw_time::to($egw_rrule->current(),'server'); + if ($expand_all) + { + $remts = (int)egw_time::to($remote_rrule->current(),'server'); + if ($remote) + { + $days[$locts]= $remts; + } + else + { + $days[$remts]= $locts; + } + } + else + { + $days[$locts]= $locts; + } + } + if ($expand_all) + { + $remote_rrule->next_no_exception(); + } + $egw_rrule->next_no_exception(); + if (!$egw_rrule->valid()) return $days; + } $day = $egw_rrule->current(); $locts = (int)egw_time::to($day,'server'); $tz_exception = ($filter == 'tz_rrule'); @@ -1659,7 +1708,6 @@ ORDER BY cal_user_type, cal_usre_id // '() status exception: ' . $day->format('Ymd\THis')); if ($expand_all) { - $remts = (int)egw_time::to($remote_day,'server'); if ($filter == 'tz_only') { unset($days[$remts]); @@ -1699,40 +1747,11 @@ ORDER BY cal_user_type, cal_usre_id } } } - do + if ($expand_all) { - $egw_rrule->next_no_exception(); - $day = $egw_rrule->current(); - if ($expand_all) - { - $remote_rrule->next_no_exception(); - $remts = (int)egw_time::to($remote_rrule->current(),'server'); - } - $exception = $egw_rrule->exceptions && - in_array($day->format('Ymd'),$egw_rrule->exceptions); - if (in_array($filter, array('map','tz_map','rrule','tz_rrule')) - && $exception) - { - // real exception - $locts = (int)egw_time::to($day,'ts'); - if ($expand_all) - { - if ($remote) - { - $days[$locts]= $remts; - } - else - { - $days[$remts]= $locts; - } - } - else - { - $days[$locts]= $locts; - } - } + $remote_rrule->next_no_exception(); } - while ($exception); + $egw_rrule->next_no_exception(); } return $days; } @@ -1831,6 +1850,13 @@ ORDER BY cal_user_type, cal_usre_id continue; } break; + case 'delegated': + if ($status != 'D') + { + unset($participants[$uid]); + continue; + } + break; case 'default': if ($status == 'R') { diff --git a/calendar/inc/class.calendar_ui.inc.php b/calendar/inc/class.calendar_ui.inc.php index 2092dd515e..e9346b659d 100644 --- a/calendar/inc/class.calendar_ui.inc.php +++ b/calendar/inc/class.calendar_ui.inc.php @@ -146,7 +146,7 @@ class calendar_ui $this->accountsel = $GLOBALS['egw']->uiaccountsel; $this->categories = new categories($this->user,'calendar'); - + $this->common_prefs = &$GLOBALS['egw_info']['user']['preferences']['common']; $this->cal_prefs = &$GLOBALS['egw_info']['user']['preferences']['calendar']; $this->bo->check_set_default_prefs(); @@ -708,6 +708,7 @@ class calendar_ui 'accepted' => array(lang('Accepted'), lang('Show only accepted events')), 'unknown' => array(lang('Invitations'), lang('Show only invitations, not yet accepted or rejected')), 'tentative' => array(lang('Tentative'), lang('Show only tentative accepted events')), + 'delegated' => array(lang('Delegated'), lang('Show only delegated events')), 'rejected' => array(lang('Rejected'),lang('Show only rejected events')), 'owner' => array(lang('Owner too'),lang('Show also events just owned by selected user')), 'all' => array(lang('All incl. rejected'),lang('Show all status incl. rejected events')), diff --git a/calendar/templates/default/images/forward.gif b/calendar/templates/default/images/forward.gif new file mode 100644 index 0000000000000000000000000000000000000000..7a5df0b7572acce25f3050e3e3c17a6d2601a9e8 GIT binary patch literal 319 zcmZ?wbhEHb6E|9J%5>F;abPSbsh!FJPVdN z6|HkFTIXK8#;bI#TiJTQ^3}c->-}ps2h?o~YuXXpvOTV4Yi#Sb#EzZm6AxufI+Qo% zP|nmN|49dm{{)?jQWHy3QxwWGOEMJPJ$(Zh6o0ZXaxvI5=r8~Q$fFEw?g!=iq?Ap%+k(md=bD>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2igJ= z3mz`%)+>Sl00C}EL_t(2&yA74OB-<%z(3#bosCk|4)GT>L=Y*62qFo%Sm{y>mWG0p zNVhKj1ByZxF@w7}b?)NeqP7UGZE+}~MG%6av>caK)1G(9d%1lD zFgCX?Pm>A$xd9+ol0tzPrcyl}tsI{e0^2^HHUXk~9mlEQc(oh1h=_`Jw(-}wr1ZP| zMQi=p1gQD}Eri4$YeYaRP%SY$KP2=k93K_;9%*yBu(RNs0Ipk^IXpTIX)ILJusoI; z84s#1#b5S&jhZj)EcpGIeB Date: Thu, 18 Feb 2010 23:32:25 +0000 Subject: [PATCH 014/334] Fix so sitemgr contact form shows contact's address instead of current user --- addressbook/inc/class.addressbook_tracking.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addressbook/inc/class.addressbook_tracking.inc.php b/addressbook/inc/class.addressbook_tracking.inc.php index 26b6d57926..b649412825 100644 --- a/addressbook/inc/class.addressbook_tracking.inc.php +++ b/addressbook/inc/class.addressbook_tracking.inc.php @@ -59,7 +59,7 @@ class addressbook_tracking extends bo_tracking * * @var boolean */ - var $prefer_user_as_sender = true; + var $prefer_user_as_sender = false; /** * Instance of the bocontacts class calling us * From 7304df7dcd00305d8e278e4c1621d13a9180892d Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Fri, 19 Feb 2010 14:53:24 +0000 Subject: [PATCH 015/334] fix for a problem with IE7 and IE8(Compatibilitymode) displaying Icons and text in Navbar --- phpgwapi/templates/idots/css/traditional.css | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/phpgwapi/templates/idots/css/traditional.css b/phpgwapi/templates/idots/css/traditional.css index 277a42b00a..1e3f3eb87d 100755 --- a/phpgwapi/templates/idots/css/traditional.css +++ b/phpgwapi/templates/idots/css/traditional.css @@ -322,7 +322,13 @@ body { border:solid 1px #9c9c9c; background-image: url(../images/background-icon-bar.png); background-repeat: repeat-x; - height: 45px; + overflow:visible; + height: 45px; /* prevents text line to show in IE7+8(Compatibilitymode) */ +} +/* Star-Plus-HTML Hack fix for the above */ +*:first-child+html #divAppIconBar +{ + height: 60px; } #divAppTextBar From ce7324f12fa35d2bf58a2733d9162b7a0d7e7dc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Lehrke?= Date: Fri, 19 Feb 2010 17:10:15 +0000 Subject: [PATCH 016/334] Fix daywise search --- calendar/inc/class.calendar_bo.inc.php | 8 ++++++-- calendar/inc/class.calendar_so.inc.php | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/calendar/inc/class.calendar_bo.inc.php b/calendar/inc/class.calendar_bo.inc.php index 9b759b0d6d..c229773809 100644 --- a/calendar/inc/class.calendar_bo.inc.php +++ b/calendar/inc/class.calendar_bo.inc.php @@ -16,6 +16,10 @@ if (!defined('ACL_TYPE_IDENTIFER')) // used to mark ACL-values for the debug_mes define('ACL_TYPE_IDENTIFER','***ACL***'); } +define('HOUR_s',60*60); +define('DAY_s',24*HOUR_s); +define('WEEK_s',7*DAY_s); + /** * Gives read access to the calendar, but all events the user is not participating are private! * Used by addressbook. @@ -292,9 +296,9 @@ class calendar_bo * filter string all (not rejected), accepted, unknown, tentative, rejected or hideprivate * query string pattern so search for, if unset or empty all matching entries are returned (no search) * Please Note: a search never returns repeating events more then once AND does not honor start+end date !!! - * dayswise boolean on True it returns an array with YYYYMMDD strings as keys and an array with events + * daywise boolean on True it returns an array with YYYYMMDD strings as keys and an array with events * (events spanning multiple days are returned each day again (!)) otherwise it returns one array with - * the events (default), not honored in a search ==> always returns an array of events ! + * the events (default), not honored in a search ==> always returns an array of events! * date_format string date-formats: 'ts'=timestamp (default), 'array'=array, or string with format for date * offset boolean/int false (default) to return all entries or integer offset to return only a limited result * enum_recuring boolean if true or not set (default) or daywise is set, each recurence of a recuring events is returned, diff --git a/calendar/inc/class.calendar_so.inc.php b/calendar/inc/class.calendar_so.inc.php index b198599cd0..f5cf124b7b 100644 --- a/calendar/inc/class.calendar_so.inc.php +++ b/calendar/inc/class.calendar_so.inc.php @@ -1912,7 +1912,7 @@ ORDER BY cal_user_type, cal_usre_id } /** - * Moves a datetime to the beginning og the day within timezone + * Moves a datetime to the beginning of the day within timezone * * @param egw_time &time the datetime entry * @param string tz_id timezone From e362a5b451cb61571988cd5f739f91ae839a9db6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Lehrke?= Date: Fri, 19 Feb 2010 17:42:02 +0000 Subject: [PATCH 017/334] Use category names for history-log --- calendar/inc/class.calendar_boupdate.inc.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/calendar/inc/class.calendar_boupdate.inc.php b/calendar/inc/class.calendar_boupdate.inc.php index c6cdc212a1..e5e8822722 100644 --- a/calendar/inc/class.calendar_boupdate.inc.php +++ b/calendar/inc/class.calendar_boupdate.inc.php @@ -884,6 +884,8 @@ class calendar_boupdate extends calendar_bo // Update history $tracking = new calendar_tracking($this); + $event['category'] = implode(',', $this->get_categories($event['category'])); + $old_event['category'] = implode(',', $this->get_categories($old_event['category'])); $tracking->track($event, $old_event); return $cal_id; From 3aa96a4a34c31f556f9bdd94ac7a683f01fc1838 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Sun, 21 Feb 2010 23:15:05 +0000 Subject: [PATCH 018/334] for xml: decode all entities, remove all non-decodable entities, remove all html tags and encode <, > and & as entities --- etemplate/inc/class.bo_merge.inc.php | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/etemplate/inc/class.bo_merge.inc.php b/etemplate/inc/class.bo_merge.inc.php index 476597e010..b08207e6d0 100644 --- a/etemplate/inc/class.bo_merge.inc.php +++ b/etemplate/inc/class.bo_merge.inc.php @@ -5,7 +5,7 @@ * @link http://www.egroupware.org * @author Ralf Becker * @package addressbook - * @copyright (c) 2007-9 by Ralf Becker + * @copyright (c) 2007-10 by Ralf Becker * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @version $Id$ */ @@ -479,9 +479,30 @@ abstract class bo_merge { $replacements = $GLOBALS['egw']->translation->convert($replacements,$GLOBALS['egw']->translation->charset(),$charset); } - if ($is_xml) // zip'ed xml document (eg. OO) --> need to encode &,<,> to not mess up xml + if ($is_xml) // zip'ed xml document (eg. OO) { - $replacements = str_replace(array('&','&','<','>'),array('&','&','<','>'),$replacements); + // clean replacements from html or html-entities, which mess up xml + foreach($replacements as $name => &$value) + { + // decode html entities back to utf-8 + if (strpos($value,'&') !== false) + { + $value = html_entity_decode($value,ENT_QUOTES,$charset); + + // remove all non-decodable entities + if (strpos($value,'&') !== false) + { + $value = preg_replace('/&[^; ]+;/','',$value); + } + } + // remove all html tags, evtl. included + if (strpos($value,'<') !== false) + { + $value = strip_tags($value); + } + } + // now decode &, < and >, which need to be encoded as entities in xml + $replacements = str_replace(array('&','<','>'),array('&','<','>'),$replacements); } return str_replace(array_keys($replacements),array_values($replacements),$content); } From 08dbf52b66f57a629a652df5bbeee4c0e8a04d1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Lehrke?= Date: Mon, 22 Feb 2010 10:02:33 +0000 Subject: [PATCH 019/334] Fix typos and code cleanup --- calendar/inc/class.calendar_bo.inc.php | 19 +++++++++---------- calendar/inc/class.calendar_boupdate.inc.php | 15 +++++---------- calendar/inc/class.calendar_ical.inc.php | 2 +- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/calendar/inc/class.calendar_bo.inc.php b/calendar/inc/class.calendar_bo.inc.php index c229773809..dfb3111216 100644 --- a/calendar/inc/class.calendar_bo.inc.php +++ b/calendar/inc/class.calendar_bo.inc.php @@ -639,7 +639,7 @@ class calendar_bo $old_horizont = $this->config['horizont']; $this->config['horizont'] = $new_horizont; - // create further recurrences for all recuring and not yet (at the old horizont) ended events + // create further recurrences for all recurring and not yet (at the old horizont) ended events if (($recuring = $this->so->unfinished_recuring($old_horizont))) { foreach($this->read(array_keys($recuring)) as $cal_id => $event) @@ -660,7 +660,7 @@ class calendar_bo } /** - * set all recurrences for an event until defined horizont $this->config['horizont'] + * set all recurrences for an event until the defined horizont $this->config['horizont'] * * This methods operates in usertime, while $this->config['horizont'] is in servertime! * @@ -715,7 +715,7 @@ class calendar_bo function db2data(&$events,$date_format='ts') { if (!is_array($events)) echo "

bocal::db2data(\$events,$date_format) \$events is no array
\n".function_backtrace()."

\n"; - foreach($events as $id => &$event) + foreach($events as &$event) { // convert timezone id of event to tzid (iCal id like 'Europe/Berlin') if (!$event['tz_id'] || !($event['tzid'] = calendar_timezones::id2tz($event['tz_id']))) @@ -732,7 +732,7 @@ class calendar_bo // same with the recur exceptions if (isset($event['recur_exception']) && is_array($event['recur_exception'])) { - foreach($event['recur_exception'] as $n => &$date) + foreach($event['recur_exception'] as &$date) { $date = $this->date2usertime($date,$date_format); } @@ -740,7 +740,7 @@ class calendar_bo // same with the alarms if (isset($event['alarm']) && is_array($event['alarm'])) { - foreach($event['alarm'] as $n => &$alarm) + foreach($event['alarm'] as &$alarm) { $alarm['time'] = $this->date2usertime($alarm['time'],$date_format); } @@ -769,7 +769,7 @@ class calendar_bo * @param mixed $date=null date to specify a single event of a series * @param boolean $ignore_acl should we ignore the acl, default False for a single id, true for multiple id's * @param string $date_format='ts' date-formats: 'ts'=timestamp, 'server'=timestamp in servertime, 'array'=array, or string with date-format - * @return boolean/array event or array of id => event pairs, false if the acl-check went wrong, null if $ids not found + * @return boolean|array event or array of id => event pairs, false if the acl-check went wrong, null if $ids not found */ function read($ids,$date=null,$ignore_acl=False,$date_format='ts') { @@ -985,7 +985,6 @@ class calendar_bo $owner = $event['owner']; $private = !$event['public']; } - $user = $GLOBALS['egw_info']['user']['account_id']; $grants = $this->grants[$owner]; if (is_array($event) && $needed == EGW_ACL_READ) { @@ -996,11 +995,11 @@ class calendar_bo { foreach($event['participants'] as $uid => $accept) { - if ($uid == $user || $uid < 0 && in_array($user,$GLOBALS['egw']->accounts->members($uid,true))) + if ($uid == $this->user || $uid < 0 && in_array($this->user,$GLOBALS['egw']->accounts->members($uid,true))) { // if we are a participant, we have an implicite READ and PRIVAT grant // exept the group gives its members only EGW_ACL_FREEBUSY and the participant is not the current user - if ($this->grants[$uid] == EGW_ACL_FREEBUSY && $uid != $user) continue; + if ($this->grants[$uid] == EGW_ACL_FREEBUSY && $uid != $this->user) continue; $grants |= EGW_ACL_READ | EGW_ACL_PRIVATE; break; @@ -1028,7 +1027,7 @@ class calendar_bo } else { - $access = $user == $owner || $grants & $needed && (!$private || $grants & EGW_ACL_PRIVATE); + $access = $this->user == $owner || $grants & $needed && (!$private || $grants & EGW_ACL_PRIVATE); } if ($this->debug && ($this->debug > 2 || $this->debug == 'check_perms')) { diff --git a/calendar/inc/class.calendar_boupdate.inc.php b/calendar/inc/class.calendar_boupdate.inc.php index e5e8822722..aa67f173b1 100644 --- a/calendar/inc/class.calendar_boupdate.inc.php +++ b/calendar/inc/class.calendar_boupdate.inc.php @@ -1607,7 +1607,7 @@ class calendar_boupdate extends calendar_bo $matchFields = array('priority', 'public', 'non_blocking', 'recurrence'); foreach ($matchFields as $key) { - if (!empty($event[$key])) $query['cal_'.$key] = $event[$key]; + if (isset($event[$key])) $query['cal_'.$key] = $event[$key]; } } if (!empty($event['uid'])) @@ -1803,14 +1803,9 @@ class calendar_boupdate extends calendar_bo // check exceptions // $exceptions[$remote_ts] = $egw_ts $exceptions = $this->so->get_recurrence_exceptions($egwEvent, $event['$tzid'], 0, 0, 'map'); - // remove leading exceptions - foreach ($exceptions as $key => $day) + if (is_array($event['recur_exception'])) { - if ($day <= $event['start']) unset($exceptions['key']); - } - if (is_array($event['recur_excpetion'])) - { - foreach ($event['recur_excpetion'] as $key => $day) + foreach ($event['recur_exception'] as $key => $day) { if (isset($exceptions[$day])) { @@ -1832,14 +1827,14 @@ class calendar_boupdate extends calendar_bo { error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. '() missing event[recur_exception]: ' . - array2string($event['recur_excpetion'])); + array2string($event['recur_exception'])); } continue; } } // check recurrence information - foreach (array('recur_type', 'recur_interval') as $key) + foreach (array('recur_type', 'recur_interval', 'recur_enddate') as $key) { if (isset($event[$key]) && $event[$key] != $egwEvent[$key]) diff --git a/calendar/inc/class.calendar_ical.inc.php b/calendar/inc/class.calendar_ical.inc.php index 167731fe1e..04834cc128 100644 --- a/calendar/inc/class.calendar_ical.inc.php +++ b/calendar/inc/class.calendar_ical.inc.php @@ -2370,7 +2370,7 @@ class calendar_ical extends calendar_boupdate } break; case 'SUMMARY': - $vcardData['title'] = str_replace("\r\n", "\n", $attributes['value']); + $vcardData['title'] = str_replace("\r\n", "\n", $attributes['value']); break; case 'UID': if (strlen($attributes['value']) >= $minimum_uid_length) From fc3228806aa97c83ad21f989753feb6af37c8c0a Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Mon, 22 Feb 2010 18:18:38 +0000 Subject: [PATCH 020/334] Fix infolog print view to only display the custom fields allowed for that infolog type --- infolog/setup/etemplates.inc.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/infolog/setup/etemplates.inc.php b/infolog/setup/etemplates.inc.php index 5061508752..007e164feb 100644 --- a/infolog/setup/etemplates.inc.php +++ b/infolog/setup/etemplates.inc.php @@ -2,7 +2,7 @@ /** * eGroupWare - eTemplates for Application infolog * http://www.egroupware.org - * generated by soetemplate::dump4setup() 2009-12-14 09:58 + * generated by soetemplate::dump4setup() 2010-02-22 11:17 * * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @package infolog @@ -39,9 +39,9 @@ $templ_data[] = array('name' => 'infolog.edit.history','template' => '','lang' = $templ_data[] = array('name' => 'infolog.edit.links','template' => '','lang' => '','group' => '0','version' => '1.3.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:6:{i:0;a:7:{s:1:"A";s:3:"100";s:2:"h1";s:13:",@status_only";s:2:"h2";s:13:",@status_only";s:2:"c1";s:2:"th";s:2:"c2";s:3:"row";s:2:"c4";s:2:"th";s:2:"c5";s:11:"row_off,top";}i:1;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"span";s:3:"all";s:5:"label";s:16:"Create new links";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:2;a:2:{s:1:"A";a:3:{s:4:"type";s:7:"link-to";s:4:"span";s:3:"all";s:4:"name";s:7:"link_to";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:3;a:2:{s:1:"A";a:3:{s:4:"type";s:8:"link-add";s:4:"span";s:3:"all";s:4:"name";s:7:"link_to";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:4;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"span";s:3:"all";s:5:"label";s:14:"Existing links";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:5;a:2:{s:1:"A";a:3:{s:4:"type";s:9:"link-list";s:4:"span";s:3:"all";s:4:"name";s:7:"link_to";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}}s:4:"rows";i:5;s:4:"cols";i:2;s:4:"size";s:17:"100%,245,,,,,auto";s:7:"options";a:3:{i:0;s:4:"100%";i:1;s:3:"245";i:6;s:4:"auto";}}}','size' => '100%,245,,,,,auto','style' => '','modified' => '1075977056',); -$templ_data[] = array('name' => 'infolog.edit.print','template' => '','lang' => '','group' => '0','version' => '1.7.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:22:{i:0;a:20:{s:1:"A";s:3:"103";s:1:"B";s:3:"260";s:1:"C";s:3:"140";s:2:"c3";s:3:"row";s:2:"c4";s:3:"row";s:2:"c5";s:3:"row";s:2:"c2";s:2:"th";s:2:"h2";s:2:"28";s:2:"h1";s:6:",!@msg";s:1:"D";s:3:"27%";s:3:"c18";s:6:"row_on";s:3:"c19";s:3:"row";s:3:"c20";s:3:"row";s:3:"c17";s:2:"th";s:2:"c7";s:2:"th";s:2:"h7";s:2:"10";s:3:"c21";s:3:"row";s:3:"h21";s:13:",!@info_owner";s:3:"h17";s:2:"10";s:3:"c10";s:2:"th";}i:1;a:4:{s:1:"A";a:5:{s:4:"type";s:4:"html";s:4:"span";s:13:"all,redItalic";s:5:"align";s:6:"center";s:4:"name";s:3:"msg";s:7:"no_lang";s:1:"1";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:2;a:4:{s:1:"A";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:3:{s:4:"type";s:5:"image";s:4:"name";s:5:"print";s:7:"onclick";s:15:"window.print();";}i:2;a:4:{s:4:"type";s:5:"label";s:5:"label";s:4:"Type";s:4:"size";s:12:",,,info_type";s:8:"readonly";s:1:"1";}}s:1:"B";a:5:{s:4:"type";s:4:"hbox";s:4:"span";s:3:"all";s:4:"size";s:6:"2,,0,0";i:1;a:6:{s:4:"type";s:6:"select";s:4:"name";s:9:"info_type";s:8:"onchange";i:1;s:4:"help";s:46:"Type of the log-entry: Note, Phonecall or ToDo";s:7:"no_lang";s:1:"1";s:8:"readonly";s:1:"1";}i:2;a:4:{s:4:"type";s:3:"int";s:4:"name";s:11:"info_number";s:4:"span";s:7:",infoId";s:8:"readonly";s:1:"1";}}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:3;a:4:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:5:"label";s:8:"Category";s:4:"size";s:11:",,,info_cat";}s:1:"B";a:5:{s:4:"type";s:10:"select-cat";s:4:"size";s:4:"None";s:4:"name";s:8:"info_cat";s:4:"help";s:32:"select a category for this entry";s:8:"readonly";s:1:"1";}s:1:"C";a:5:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:6:"Parent";}i:2;a:6:{s:4:"type";s:10:"link-entry";s:4:"size";s:7:"infolog";s:4:"name";s:14:"info_id_parent";s:5:"align";s:5:"right";s:4:"span";s:7:",noWrap";s:8:"readonly";s:1:"1";}s:4:"span";s:3:"all";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:4;a:4:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:5:"label";s:7:"Contact";s:4:"size";s:12:",,,info_from";}s:1:"B";a:38:{s:4:"type";s:4:"vbox";s:4:"size";s:6:"2,,0,0";i:1;a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,0,0";i:1;a:4:{s:4:"type";s:10:"link-entry";s:4:"name";s:12:"info_contact";s:4:"span";s:7:",noWrap";s:8:"readonly";s:1:"1";}i:2;a:5:{s:4:"type";s:8:"checkbox";s:4:"name";s:16:"info_custom_from";s:8:"onchange";s:91:"document.getElementById(form::name(\'info_from\')).style.display=this.checked?\'block\':\'none\';";s:4:"help";s:31:"Check to specify custom contact";s:8:"readonly";s:1:"1";}}i:2;a:7:{s:4:"type";s:4:"text";s:4:"size";s:6:"36,255";s:4:"name";s:9:"info_from";s:4:"help";s:80:"Custom contact-information, leave emtpy to use information from most recent link";s:4:"blur";s:11:"@blur_title";s:4:"span";s:21:",$cont[hide_from_css]";s:8:"readonly";s:1:"1";}i:3;a:1:{s:4:"type";s:5:"label";}i:4;a:1:{s:4:"type";s:5:"label";}i:5;a:1:{s:4:"type";s:5:"label";}i:6;a:1:{s:4:"type";s:5:"label";}i:7;a:1:{s:4:"type";s:5:"label";}i:8;a:1:{s:4:"type";s:5:"label";}i:9;a:1:{s:4:"type";s:5:"label";}i:10;a:1:{s:4:"type";s:5:"label";}i:11;a:1:{s:4:"type";s:5:"label";}i:12;a:1:{s:4:"type";s:5:"label";}i:13;a:1:{s:4:"type";s:5:"label";}i:14;a:1:{s:4:"type";s:5:"label";}i:15;a:1:{s:4:"type";s:5:"label";}i:16;a:1:{s:4:"type";s:5:"label";}i:17;a:1:{s:4:"type";s:5:"label";}i:18;a:1:{s:4:"type";s:5:"label";}i:19;a:1:{s:4:"type";s:5:"label";}i:20;a:1:{s:4:"type";s:5:"label";}i:21;a:1:{s:4:"type";s:5:"label";}i:22;a:1:{s:4:"type";s:5:"label";}i:23;a:1:{s:4:"type";s:5:"label";}i:24;a:1:{s:4:"type";s:5:"label";}i:25;a:1:{s:4:"type";s:5:"label";}i:26;a:1:{s:4:"type";s:5:"label";}i:27;a:1:{s:4:"type";s:5:"label";}i:28;a:1:{s:4:"type";s:5:"label";}i:29;a:1:{s:4:"type";s:5:"label";}i:30;a:1:{s:4:"type";s:5:"label";}i:31;a:1:{s:4:"type";s:5:"label";}i:32;a:1:{s:4:"type";s:5:"label";}i:33;a:1:{s:4:"type";s:5:"label";}i:34;a:1:{s:4:"type";s:5:"label";}i:35;a:1:{s:4:"type";s:5:"label";}i:36;a:1:{s:4:"type";s:5:"label";}}s:1:"C";a:3:{s:4:"type";s:5:"label";s:4:"size";s:12:",,,info_addr";s:5:"label";s:11:"Phone/Email";}s:1:"D";a:6:{s:4:"type";s:4:"text";s:4:"size";s:6:"30,255";s:4:"name";s:9:"info_addr";s:4:"help";s:76:"Custom contact-address, leave empty to use information from most recent link";s:4:"span";s:15:",inputFullWidth";s:8:"readonly";s:1:"1";}}i:5;a:4:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:5:"label";s:7:"Subject";s:4:"size";s:15:",,,info_subject";}s:1:"B";a:6:{s:4:"type";s:4:"text";s:4:"size";s:6:"80,255";s:4:"span";s:5:"all,b";s:4:"name";s:12:"info_subject";s:4:"help";s:29:"a short subject for the entry";s:8:"readonly";s:1:"1";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:6;a:4:{s:1:"A";a:1:{s:4:"type";s:5:"label";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:7;a:4:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"span";s:3:"all";s:5:"label";s:11:"Description";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:8;a:4:{s:1:"A";a:6:{s:4:"type";s:8:"textarea";s:7:"no_lang";s:1:"1";s:4:"name";s:8:"info_des";s:4:"help";s:44:"enter a textual description of the log-entry";s:4:"span";s:15:"all,description";s:8:"readonly";s:1:"1";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:9;a:4:{s:1:"A";a:1:{s:4:"type";s:5:"label";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:10;a:4:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"span";s:3:"all";s:5:"label";s:12:"customfields";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:11;a:4:{s:1:"A";a:3:{s:4:"type";s:12:"customfields";s:4:"span";s:3:"all";s:8:"readonly";s:1:"1";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:12;a:4:{s:1:"A";a:3:{s:4:"type";s:8:"template";s:4:"span";s:3:"all";s:4:"name";s:26:"infolog.edit.print.project";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:13;a:4:{s:1:"A";a:3:{s:4:"type";s:8:"template";s:4:"name";s:24:"infolog.edit.print.links";s:4:"span";s:3:"all";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:14;a:4:{s:1:"A";a:1:{s:4:"type";s:5:"label";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:15;a:4:{s:1:"A";a:3:{s:4:"type";s:8:"template";s:4:"name";s:29:"infolog.edit.print.delegation";s:4:"span";s:3:"all";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:16;a:4:{s:1:"A";a:1:{s:4:"type";s:5:"label";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:17;a:4:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"span";s:3:"all";s:5:"label";s:21:"Dates, Status, Access";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:18;a:4:{s:1:"A";a:4:{s:4:"type";s:5:"label";s:5:"label";s:9:"Startdate";s:4:"size";s:17:",,,info_startdate";s:8:"readonly";s:1:"1";}s:1:"B";a:5:{s:4:"type";s:9:"date-time";s:4:"size";s:2:",2";s:4:"name";s:14:"info_startdate";s:4:"help";s:115:"when should the ToDo or Phonecall be started, it shows up from that date in the filter open or own open (startpage)";s:8:"readonly";s:1:"1";}s:1:"C";a:3:{s:4:"type";s:5:"label";s:5:"label";s:7:"Enddate";s:4:"size";s:15:",,,info_enddate";}s:1:"D";a:4:{s:4:"type";s:4:"date";s:4:"name";s:12:"info_enddate";s:4:"help";s:49:"til when should the ToDo or Phonecall be finished";s:8:"readonly";s:1:"1";}}i:19;a:4:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:5:"label";s:6:"Status";s:4:"size";s:14:",,,info_status";}s:1:"B";a:5:{s:4:"type";s:6:"select";s:4:"name";s:11:"info_status";s:4:"help";s:12:"@status_help";s:8:"onchange";s:183:"if (this.value==\'done\' || this.value==\'billed\') set_element(this.form,\'exec[info_percent]\',\'100\'); else if (this.value==\'not-started\') set_element(this.form,\'exec[info_percent]\',\'0\');";s:8:"readonly";s:1:"1";}s:1:"C";a:3:{s:4:"type";s:5:"label";s:5:"label";s:9:"Completed";s:4:"size";s:15:",,,info_percent";}s:1:"D";a:5:{s:4:"type";s:14:"select-percent";s:4:"name";s:12:"info_percent";s:4:"help";s:17:"Percent completed";s:8:"onchange";s:570:"if (this.value==100 && this.form[\'exec[info_status]\'].value != \'done\' && this.form[\'exec[info_status]\'].value != \'billed\' && this.form[\'exec[info_status]\'].value != \'cancelled\') this.form[\'exec[info_status]\'].value=\'done\'; else if (this.value != 100 && this.form[\'exec[info_status]\'].value != \'cancelled\') this.form[\'exec[info_status]\'].value=this.value != 0 ? \'ongoing\' : \'not-started\'; else if (this.value==0 && this.form[\'exec[info_status]\'].value != \'cancelled\' && this.form[\'exec[info_status]\'].value != \'offer\') this.form[\'exec[info_status]\'].value=\'not-started\'; ";s:8:"readonly";s:1:"1";}}i:20;a:4:{s:1:"A";a:4:{s:4:"type";s:5:"label";s:4:"size";s:21:",,,info_datecompleted";s:5:"label";s:14:"Date completed";s:8:"readonly";s:1:"1";}s:1:"B";a:4:{s:4:"type";s:9:"date-time";s:4:"name";s:18:"info_datecompleted";s:4:"help";s:84:"Date completed (leave it empty to have it automatic set if status is done or billed)";s:8:"readonly";s:1:"1";}s:1:"C";a:3:{s:4:"type";s:5:"label";s:5:"label";s:7:"Private";s:4:"size";s:14:",,,info_access";}s:1:"D";a:5:{s:4:"type";s:8:"checkbox";s:4:"size";s:14:"private,public";s:4:"name";s:11:"info_access";s:4:"help";s:87:"should this entry only be visible to you and people you grant privat access via the ACL";s:8:"readonly";s:1:"1";}}i:21;a:4:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:5:"Owner";}s:1:"B";a:3:{s:4:"type";s:14:"select-account";s:4:"name";s:10:"info_owner";s:8:"readonly";s:1:"1";}s:1:"C";a:2:{s:4:"type";s:5:"label";s:5:"label";s:13:"Last modified";}s:1:"D";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:5:"2,0,0";i:1;a:3:{s:4:"type";s:14:"select-account";s:4:"name";s:13:"info_modifier";s:8:"readonly";s:1:"1";}i:2;a:4:{s:4:"type";s:9:"date-time";s:4:"span";s:10:",lpadding5";s:4:"name";s:17:"info_datemodified";s:8:"readonly";s:1:"1";}}}}s:4:"rows";i:21;s:4:"cols";i:4;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '.hideFrom input { display: none; } +$templ_data[] = array('name' => 'infolog.edit.print','template' => '','lang' => '','group' => '0','version' => '1.7.002','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:22:{i:0;a:20:{s:1:"A";s:3:"103";s:1:"B";s:3:"260";s:1:"C";s:3:"140";s:2:"c3";s:3:"row";s:2:"c4";s:3:"row";s:2:"c5";s:3:"row";s:2:"c2";s:2:"th";s:2:"h2";s:2:"28";s:2:"h1";s:6:",!@msg";s:1:"D";s:3:"27%";s:3:"c18";s:6:"row_on";s:3:"c19";s:3:"row";s:3:"c20";s:3:"row";s:3:"c17";s:2:"th";s:2:"c7";s:2:"th";s:2:"h7";s:2:"10";s:3:"c21";s:3:"row";s:3:"h21";s:13:",!@info_owner";s:3:"h17";s:2:"10";s:3:"c10";s:2:"th";}i:1;a:4:{s:1:"A";a:5:{s:4:"type";s:4:"html";s:4:"span";s:13:"all,redItalic";s:5:"align";s:6:"center";s:4:"name";s:3:"msg";s:7:"no_lang";s:1:"1";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:2;a:4:{s:1:"A";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:3:{s:4:"type";s:5:"image";s:4:"name";s:5:"print";s:7:"onclick";s:15:"window.print();";}i:2;a:4:{s:4:"type";s:5:"label";s:5:"label";s:4:"Type";s:4:"size";s:12:",,,info_type";s:8:"readonly";s:1:"1";}}s:1:"B";a:5:{s:4:"type";s:4:"hbox";s:4:"span";s:3:"all";s:4:"size";s:6:"2,,0,0";i:1;a:6:{s:4:"type";s:6:"select";s:4:"name";s:9:"info_type";s:8:"onchange";i:1;s:4:"help";s:46:"Type of the log-entry: Note, Phonecall or ToDo";s:7:"no_lang";s:1:"1";s:8:"readonly";s:1:"1";}i:2;a:4:{s:4:"type";s:3:"int";s:4:"name";s:11:"info_number";s:4:"span";s:7:",infoId";s:8:"readonly";s:1:"1";}}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:3;a:4:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:5:"label";s:8:"Category";s:4:"size";s:11:",,,info_cat";}s:1:"B";a:5:{s:4:"type";s:10:"select-cat";s:4:"size";s:4:"None";s:4:"name";s:8:"info_cat";s:4:"help";s:32:"select a category for this entry";s:8:"readonly";s:1:"1";}s:1:"C";a:5:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:6:"Parent";}i:2;a:6:{s:4:"type";s:10:"link-entry";s:4:"size";s:7:"infolog";s:4:"name";s:14:"info_id_parent";s:5:"align";s:5:"right";s:4:"span";s:7:",noWrap";s:8:"readonly";s:1:"1";}s:4:"span";s:3:"all";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:4;a:4:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:5:"label";s:7:"Contact";s:4:"size";s:12:",,,info_from";}s:1:"B";a:38:{s:4:"type";s:4:"vbox";s:4:"size";s:6:"2,,0,0";i:1;a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,0,0";i:1;a:4:{s:4:"type";s:10:"link-entry";s:4:"name";s:12:"info_contact";s:4:"span";s:7:",noWrap";s:8:"readonly";s:1:"1";}i:2;a:5:{s:4:"type";s:8:"checkbox";s:4:"name";s:16:"info_custom_from";s:8:"onchange";s:91:"document.getElementById(form::name(\'info_from\')).style.display=this.checked?\'block\':\'none\';";s:4:"help";s:31:"Check to specify custom contact";s:8:"readonly";s:1:"1";}}i:2;a:7:{s:4:"type";s:4:"text";s:4:"size";s:6:"36,255";s:4:"name";s:9:"info_from";s:4:"help";s:80:"Custom contact-information, leave emtpy to use information from most recent link";s:4:"blur";s:11:"@blur_title";s:4:"span";s:21:",$cont[hide_from_css]";s:8:"readonly";s:1:"1";}i:3;a:1:{s:4:"type";s:5:"label";}i:4;a:1:{s:4:"type";s:5:"label";}i:5;a:1:{s:4:"type";s:5:"label";}i:6;a:1:{s:4:"type";s:5:"label";}i:7;a:1:{s:4:"type";s:5:"label";}i:8;a:1:{s:4:"type";s:5:"label";}i:9;a:1:{s:4:"type";s:5:"label";}i:10;a:1:{s:4:"type";s:5:"label";}i:11;a:1:{s:4:"type";s:5:"label";}i:12;a:1:{s:4:"type";s:5:"label";}i:13;a:1:{s:4:"type";s:5:"label";}i:14;a:1:{s:4:"type";s:5:"label";}i:15;a:1:{s:4:"type";s:5:"label";}i:16;a:1:{s:4:"type";s:5:"label";}i:17;a:1:{s:4:"type";s:5:"label";}i:18;a:1:{s:4:"type";s:5:"label";}i:19;a:1:{s:4:"type";s:5:"label";}i:20;a:1:{s:4:"type";s:5:"label";}i:21;a:1:{s:4:"type";s:5:"label";}i:22;a:1:{s:4:"type";s:5:"label";}i:23;a:1:{s:4:"type";s:5:"label";}i:24;a:1:{s:4:"type";s:5:"label";}i:25;a:1:{s:4:"type";s:5:"label";}i:26;a:1:{s:4:"type";s:5:"label";}i:27;a:1:{s:4:"type";s:5:"label";}i:28;a:1:{s:4:"type";s:5:"label";}i:29;a:1:{s:4:"type";s:5:"label";}i:30;a:1:{s:4:"type";s:5:"label";}i:31;a:1:{s:4:"type";s:5:"label";}i:32;a:1:{s:4:"type";s:5:"label";}i:33;a:1:{s:4:"type";s:5:"label";}i:34;a:1:{s:4:"type";s:5:"label";}i:35;a:1:{s:4:"type";s:5:"label";}i:36;a:1:{s:4:"type";s:5:"label";}}s:1:"C";a:3:{s:4:"type";s:5:"label";s:4:"size";s:12:",,,info_addr";s:5:"label";s:11:"Phone/Email";}s:1:"D";a:6:{s:4:"type";s:4:"text";s:4:"size";s:6:"30,255";s:4:"name";s:9:"info_addr";s:4:"help";s:76:"Custom contact-address, leave empty to use information from most recent link";s:4:"span";s:15:",inputFullWidth";s:8:"readonly";s:1:"1";}}i:5;a:4:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:5:"label";s:7:"Subject";s:4:"size";s:15:",,,info_subject";}s:1:"B";a:6:{s:4:"type";s:4:"text";s:4:"size";s:6:"80,255";s:4:"span";s:5:"all,b";s:4:"name";s:12:"info_subject";s:4:"help";s:29:"a short subject for the entry";s:8:"readonly";s:1:"1";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:6;a:4:{s:1:"A";a:1:{s:4:"type";s:5:"label";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:7;a:4:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"span";s:3:"all";s:5:"label";s:11:"Description";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:8;a:4:{s:1:"A";a:6:{s:4:"type";s:8:"textarea";s:7:"no_lang";s:1:"1";s:4:"name";s:8:"info_des";s:4:"help";s:44:"enter a textual description of the log-entry";s:4:"span";s:15:"all,description";s:8:"readonly";s:1:"1";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:9;a:4:{s:1:"A";a:1:{s:4:"type";s:5:"label";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:10;a:4:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"span";s:3:"all";s:5:"label";s:12:"customfields";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:11;a:4:{s:1:"A";a:4:{s:4:"type";s:12:"customfields";s:4:"span";s:3:"all";s:8:"readonly";s:1:"1";s:4:"size";s:10:"@info_type";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:12;a:4:{s:1:"A";a:3:{s:4:"type";s:8:"template";s:4:"span";s:3:"all";s:4:"name";s:26:"infolog.edit.print.project";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:13;a:4:{s:1:"A";a:3:{s:4:"type";s:8:"template";s:4:"name";s:24:"infolog.edit.print.links";s:4:"span";s:3:"all";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:14;a:4:{s:1:"A";a:1:{s:4:"type";s:5:"label";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:15;a:4:{s:1:"A";a:3:{s:4:"type";s:8:"template";s:4:"name";s:29:"infolog.edit.print.delegation";s:4:"span";s:3:"all";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:16;a:4:{s:1:"A";a:1:{s:4:"type";s:5:"label";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:17;a:4:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"span";s:3:"all";s:5:"label";s:21:"Dates, Status, Access";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}s:1:"D";a:1:{s:4:"type";s:5:"label";}}i:18;a:4:{s:1:"A";a:4:{s:4:"type";s:5:"label";s:5:"label";s:9:"Startdate";s:4:"size";s:17:",,,info_startdate";s:8:"readonly";s:1:"1";}s:1:"B";a:5:{s:4:"type";s:9:"date-time";s:4:"size";s:2:",2";s:4:"name";s:14:"info_startdate";s:4:"help";s:115:"when should the ToDo or Phonecall be started, it shows up from that date in the filter open or own open (startpage)";s:8:"readonly";s:1:"1";}s:1:"C";a:3:{s:4:"type";s:5:"label";s:5:"label";s:7:"Enddate";s:4:"size";s:15:",,,info_enddate";}s:1:"D";a:4:{s:4:"type";s:4:"date";s:4:"name";s:12:"info_enddate";s:4:"help";s:49:"til when should the ToDo or Phonecall be finished";s:8:"readonly";s:1:"1";}}i:19;a:4:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:5:"label";s:6:"Status";s:4:"size";s:14:",,,info_status";}s:1:"B";a:5:{s:4:"type";s:6:"select";s:4:"name";s:11:"info_status";s:4:"help";s:12:"@status_help";s:8:"onchange";s:183:"if (this.value==\'done\' || this.value==\'billed\') set_element(this.form,\'exec[info_percent]\',\'100\'); else if (this.value==\'not-started\') set_element(this.form,\'exec[info_percent]\',\'0\');";s:8:"readonly";s:1:"1";}s:1:"C";a:3:{s:4:"type";s:5:"label";s:5:"label";s:9:"Completed";s:4:"size";s:15:",,,info_percent";}s:1:"D";a:5:{s:4:"type";s:14:"select-percent";s:4:"name";s:12:"info_percent";s:4:"help";s:17:"Percent completed";s:8:"onchange";s:570:"if (this.value==100 && this.form[\'exec[info_status]\'].value != \'done\' && this.form[\'exec[info_status]\'].value != \'billed\' && this.form[\'exec[info_status]\'].value != \'cancelled\') this.form[\'exec[info_status]\'].value=\'done\'; else if (this.value != 100 && this.form[\'exec[info_status]\'].value != \'cancelled\') this.form[\'exec[info_status]\'].value=this.value != 0 ? \'ongoing\' : \'not-started\'; else if (this.value==0 && this.form[\'exec[info_status]\'].value != \'cancelled\' && this.form[\'exec[info_status]\'].value != \'offer\') this.form[\'exec[info_status]\'].value=\'not-started\'; ";s:8:"readonly";s:1:"1";}}i:20;a:4:{s:1:"A";a:4:{s:4:"type";s:5:"label";s:4:"size";s:21:",,,info_datecompleted";s:5:"label";s:14:"Date completed";s:8:"readonly";s:1:"1";}s:1:"B";a:4:{s:4:"type";s:9:"date-time";s:4:"name";s:18:"info_datecompleted";s:4:"help";s:84:"Date completed (leave it empty to have it automatic set if status is done or billed)";s:8:"readonly";s:1:"1";}s:1:"C";a:3:{s:4:"type";s:5:"label";s:5:"label";s:7:"Private";s:4:"size";s:14:",,,info_access";}s:1:"D";a:5:{s:4:"type";s:8:"checkbox";s:4:"size";s:14:"private,public";s:4:"name";s:11:"info_access";s:4:"help";s:87:"should this entry only be visible to you and people you grant privat access via the ACL";s:8:"readonly";s:1:"1";}}i:21;a:4:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:5:"Owner";}s:1:"B";a:3:{s:4:"type";s:14:"select-account";s:4:"name";s:10:"info_owner";s:8:"readonly";s:1:"1";}s:1:"C";a:2:{s:4:"type";s:5:"label";s:5:"label";s:13:"Last modified";}s:1:"D";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:5:"2,0,0";i:1;a:3:{s:4:"type";s:14:"select-account";s:4:"name";s:13:"info_modifier";s:8:"readonly";s:1:"1";}i:2;a:4:{s:4:"type";s:9:"date-time";s:4:"span";s:10:",lpadding5";s:4:"name";s:17:"info_datemodified";s:8:"readonly";s:1:"1";}}}}s:4:"rows";i:21;s:4:"cols";i:4;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '.hideFrom input { display: none; } .link_select select { width: 250px; } -.description textarea { width: 98%; }','modified' => '1260711082',); +.description textarea { width: 98%; }','modified' => '1266862572',); $templ_data[] = array('name' => 'infolog.edit.print.delegation','template' => '','lang' => '','group' => '0','version' => '1.7.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:7:{i:0;a:10:{s:1:"A";s:3:"100";s:2:"c1";s:2:"th";s:2:"c2";s:3:"row";s:2:"c3";s:3:"row";s:2:"c4";s:2:"th";s:2:"c5";s:7:"row,top";s:2:"c6";s:3:"row";s:2:"h6";s:2:",1";s:2:"h1";s:2:"10";s:2:"h4";s:2:"10";}i:1;a:2:{s:1:"A";a:3:{s:4:"span";s:3:"all";s:4:"type";s:5:"label";s:5:"label";s:7:"General";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:2;a:2:{s:1:"A";a:3:{s:4:"size";s:16:",,,info_priority";s:4:"type";s:5:"label";s:5:"label";s:8:"Priority";}s:1:"B";a:4:{s:4:"name";s:13:"info_priority";s:4:"type";s:6:"select";s:4:"help";s:31:"select a priority for this task";s:8:"readonly";s:1:"1";}}i:3;a:2:{s:1:"A";a:4:{s:4:"size";s:16:",,,info_location";s:4:"type";s:5:"label";s:5:"label";s:8:"Location";s:8:"readonly";s:1:"1";}s:1:"B";a:4:{s:4:"size";s:6:"80,255";s:4:"name";s:13:"info_location";s:4:"type";s:4:"text";s:8:"readonly";s:1:"1";}}i:4;a:2:{s:1:"A";a:3:{s:4:"span";s:3:"all";s:4:"type";s:5:"label";s:5:"label";s:10:"Delegation";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:5;a:2:{s:1:"A";a:4:{s:4:"size";s:19:",,,info_responsible";s:4:"type";s:5:"label";s:5:"label";s:11:"Responsible";s:8:"readonly";s:1:"1";}s:1:"B";a:5:{s:4:"type";s:14:"select-account";s:4:"name";s:16:"info_responsible";s:4:"size";s:7:"10,both";s:4:"help";s:66:"select a responsible user: a person you want to delegate this task";s:8:"readonly";s:1:"1";}}i:6;a:2:{s:1:"A";a:3:{s:4:"size";s:15:",,,info_confirm";s:4:"type";s:5:"label";s:5:"label";s:7:"Confirm";}s:1:"B";a:4:{s:4:"name";s:12:"info_confirm";s:4:"type";s:6:"select";s:4:"help";s:87:"do you want a confirmation of the responsible on: accepting, finishing the task or both";s:8:"readonly";s:1:"1";}}}s:4:"cols";i:2;s:4:"rows";i:6;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '','modified' => '1260707728',); From 48886af55c6ff5da4c8dc560875b0d1e87b34423 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Mon, 22 Feb 2010 20:56:59 +0000 Subject: [PATCH 021/334] Blur text can affect regular searches, not just array searches --- etemplate/inc/class.ajax_select_widget.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etemplate/inc/class.ajax_select_widget.inc.php b/etemplate/inc/class.ajax_select_widget.inc.php index 71dc0ba16d..c35965b2fe 100644 --- a/etemplate/inc/class.ajax_select_widget.inc.php +++ b/etemplate/inc/class.ajax_select_widget.inc.php @@ -254,7 +254,7 @@ class ajax_select_widget $value_in = $extension_data['old_value']; } // Check for blur text left in - if($extension_data['options']['id_field'] == self::ARRAY_KEY && $value_in['search'] == lang('Search...') ) { + if($value_in['search'] == lang('Search...') ) { $value_in['search'] = ''; } From 5e2d3f47396bacc668f16dca8563afb6ac4d1669 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Mon, 22 Feb 2010 21:25:00 +0000 Subject: [PATCH 022/334] Fix for lost links when copying. All links get copied now, including the one in the header. --- infolog/inc/class.infolog_ui.inc.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/infolog/inc/class.infolog_ui.inc.php b/infolog/inc/class.infolog_ui.inc.php index e3f5c64845..09e29c6ed3 100644 --- a/infolog/inc/class.infolog_ui.inc.php +++ b/infolog/inc/class.infolog_ui.inc.php @@ -854,7 +854,15 @@ class infolog_ui unset($content['info_id']); unset ($info_id); unset($content['info_datemodified']); - unset($contentt['info_modifier']); + unset($content['info_modifier']); + + // Get links to be copied + $content['link_to']['to_id'] = egw_link::get_links($content['link_to']['to_app'], $content['link_to']['to_id']); + if($content['info_link_id']) { + $info_link_id = $content['info_link_id']; + unset($content['info_link_id']); + } + $content['info_owner'] = !(int)$this->owner || !$this->bo->check_perms(EGW_ACL_ADD,0,$this->owner) ? $this->user : $this->owner; $content['msg'] = lang('Infolog copied - the copy can now be edited'); $content['info_subject'] = lang('Copy of:').' '.$content['info_subject']; From 4424d49c304f67fbeb28cb6f9c8b607daf3face9 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Mon, 22 Feb 2010 22:46:17 +0000 Subject: [PATCH 023/334] Handle case when ID is missing, happens the time after clearing the cf search --- etemplate/inc/class.nextmatch_widget.inc.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/etemplate/inc/class.nextmatch_widget.inc.php b/etemplate/inc/class.nextmatch_widget.inc.php index ba640fb36f..ceaf1fa62a 100644 --- a/etemplate/inc/class.nextmatch_widget.inc.php +++ b/etemplate/inc/class.nextmatch_widget.inc.php @@ -970,7 +970,14 @@ class nextmatch_widget } foreach($this->cfs as $name => $field) { if($GLOBALS['egw_info']['apps'][$field['type']]) { - if ((string)$value_in[self::CF_PREFIX.$name] != (string)$extension_data['old_value'][self::CF_PREFIX.$name]) + if(is_array($value_in[self::CF_PREFIX.$name])) { + list($old_app, $old_id) = explode(':', $extension_data['old_value'][self::CF_PREFIX.$name]); + if($value_in[self::CF_PREFIX.$name]['id'] != '' && $value_in[self::CF_PREFIX.$name]['id'] != $old_id) { + $nm_global['filter'][self::CF_PREFIX.$name] = $value_in[self::CF_PREFIX.$name]['id']; + } + + } + elseif ((string)$value_in[self::CF_PREFIX.$name] != (string)$extension_data['old_value'][self::CF_PREFIX.$name]) { $nm_global['filter'][self::CF_PREFIX.$name] = $value_in[self::CF_PREFIX.$name]['id']; } From 0b79a0466d018a7e1ff920e7c20d66febf12ebe0 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Mon, 22 Feb 2010 23:02:25 +0000 Subject: [PATCH 024/334] Make changing status for whole query work --- timesheet/inc/class.timesheet_ui.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/timesheet/inc/class.timesheet_ui.inc.php b/timesheet/inc/class.timesheet_ui.inc.php index cf5bb95259..6889615907 100644 --- a/timesheet/inc/class.timesheet_ui.inc.php +++ b/timesheet/inc/class.timesheet_ui.inc.php @@ -759,7 +759,7 @@ class timesheet_ui extends timesheet_bo else { if ($this->action($content['action'],$content['nm']['rows']['checked'],$content['use_all'], - $success,$failed,$action_msg,$content['action'],$msg)) + $success,$failed,$action_msg,'index',$msg)) { $msg .= lang('%1 timesheets(s) %2',$success,$action_msg); } From de840a1fcc52721d8d0bf12f8b70085d31eaf9ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Lehrke?= Date: Tue, 23 Feb 2010 18:18:10 +0000 Subject: [PATCH 025/334] Fix empty field issue --- phpgwapi/inc/horde/Horde/iCalendar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpgwapi/inc/horde/Horde/iCalendar.php b/phpgwapi/inc/horde/Horde/iCalendar.php index f6e99fd9df..6c5454d473 100644 --- a/phpgwapi/inc/horde/Horde/iCalendar.php +++ b/phpgwapi/inc/horde/Horde/iCalendar.php @@ -1222,7 +1222,7 @@ class Horde_iCalendar { $attr_string = $name . $params_str; if (strlen($value) > 0) { $attr_string .= ':' . $value; - } elseif ($name != 'RRULE') { + } elseif ($name != 'RRULE' && $name != 'ATTENDEE' && $name != 'ORGANIZER') { $attr_string .= ':'; } if (!$this->isOldFormat()) { From 85b6ba5ef0d130be1abce3957d6a1cb8ccb6b7af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Lehrke?= Date: Tue, 23 Feb 2010 18:19:12 +0000 Subject: [PATCH 026/334] Cleanup issues found during backport --- calendar/inc/class.calendar_groupdav.inc.php | 25 ++++++++++++------ calendar/inc/class.calendar_ical.inc.php | 27 +++++++++----------- calendar/inc/class.calendar_sif.inc.php | 14 +++++----- calendar/inc/class.calendar_so.inc.php | 9 ++++--- 4 files changed, 42 insertions(+), 33 deletions(-) diff --git a/calendar/inc/class.calendar_groupdav.inc.php b/calendar/inc/class.calendar_groupdav.inc.php index 5883a74643..8d89eb15f3 100644 --- a/calendar/inc/class.calendar_groupdav.inc.php +++ b/calendar/inc/class.calendar_groupdav.inc.php @@ -98,8 +98,11 @@ class calendar_groupdav extends groupdav_handler */ function propfind($path,$options,&$files,$user,$id='') { - if ($this->debug) error_log(__METHOD__."($path,".array2string($options).",,$user,$id)"); - $starttime = microtime(true); + if ($this->debug) + { + error_log(__METHOD__."($path,".array2string($options).",,$user,$id)"); + $starttime = microtime(true); + } // ToDo: add parameter to only return id & etag $cal_filters = array( @@ -121,7 +124,11 @@ class calendar_groupdav extends groupdav_handler { return false; } - if ($this->debug > 1) error_log(__METHOD__."($path,,,$user,$id) cal_filters=".array2string($cal_filters)); + if ($this->debug > 1) + { + error_log(__METHOD__."($path,,,$user,$id) cal_filters=". + array2string($cal_filters)); + } // check if we have to return the full calendar data or just the etag's if (!($calendar_data = $options['props'] == 'all' && $options['root']['ns'] == groupdav::CALDAV) && is_array($options['props'])) @@ -183,7 +190,11 @@ class calendar_groupdav extends groupdav_handler ); } } - if ($this->debug) error_log(__METHOD__."($path) took ".(microtime(true) - $starttime).' to return '.count($files['files']).' items'); + if ($this->debug) + { + error_log(__METHOD__."($path) took ".(microtime(true) - $starttime). + ' to return '.count($files['files']).' items'); + } return true; } @@ -284,11 +295,9 @@ class calendar_groupdav extends groupdav_handler { foreach($options['other'] as $option) { - if ($option['name'] == 'href') { $parts = explode('/',$option['data']); - if (is_numeric($id = basename(array_pop($parts),'.ics'))) $ids[] = $id; } } @@ -424,13 +433,13 @@ class calendar_groupdav extends groupdav_handler */ function put(&$options,$id,$user=null) { - if($this->debug) error_log(__METHOD__."($id, $user)".print_r($options,true)); + if ($this->debug) error_log(__METHOD__."($id, $user)".print_r($options,true)); $return_no_access=true; // as handled by importVCal anyway and allows it to set the status for participants $event = $this->_common_get_put_delete('PUT',$options,$id,$return_no_access); if (!is_null($event) && !is_array($event)) { - if($this->debug) error_log(__METHOD__.print_r($event,true).function_backtrace()); + if ($this->debug) error_log(__METHOD__.print_r($event,true).function_backtrace()); return $event; } $handler = $this->_get_handler(); diff --git a/calendar/inc/class.calendar_ical.inc.php b/calendar/inc/class.calendar_ical.inc.php index 04834cc128..3c9f0b1948 100644 --- a/calendar/inc/class.calendar_ical.inc.php +++ b/calendar/inc/class.calendar_ical.inc.php @@ -196,6 +196,7 @@ class calendar_ical extends calendar_boupdate 'UID' => 'uid', 'RECURRENCE-ID' => 'recurrence', 'SEQUENCE' => 'etag', + 'STATUS' => 'status', ); if (!is_array($this->supportedFields)) $this->setSupportedFields(); @@ -218,7 +219,7 @@ class calendar_ical extends calendar_boupdate { $mailtoOrganizer = false; $organizerCN = false; - $recurrence = $recur_date; + $recurrence = $this->date2usertime($recur_date); $tzid = null; if (!is_array($event) @@ -622,6 +623,10 @@ class calendar_ical extends calendar_boupdate } break; + case 'STATUS': + $attributes['STATUS'] = 'CONFIRMED'; + break; + case 'CATEGORIES': if ($event['category'] && ($values['CATEGORIES'] = $this->get_categories($event['category']))) { @@ -641,12 +646,12 @@ class calendar_ical extends calendar_boupdate { $icalFieldName = 'X-RECURRENCE-ID'; } - if ($recurrence) + if ($recur_date) { // We handle a pseudo exception if (isset($event['whole_day'])) { - $time = new egw_time($recurrence,egw_time::$server_timezone); + $time = new egw_time($recur_date,egw_time::$server_timezone); $time->setTimezone(self::$tz_cache[$event['tzid']]); $arr = egw_time::to($time,'array'); $vevent->setAttribute($icalFieldName, array( @@ -658,7 +663,7 @@ class calendar_ical extends calendar_boupdate } else { - $attributes[$icalFieldName] = self::getDateTime($recurrence,$tzid,$parameters[$icalFieldName]); + $attributes[$icalFieldName] = self::getDateTime($recur_date,$tzid,$parameters[$icalFieldName]); } } elseif ($event['recurrence'] && $event['reference']) @@ -734,7 +739,6 @@ class calendar_ical extends calendar_boupdate { $attributes[$icalFieldName] = $value; } - break; } } @@ -1089,8 +1093,8 @@ class calendar_ical extends calendar_boupdate // If this is an updated meeting, and the client doesn't support // participants OR the event no longer contains participants, add them back - $event['participants'] = $event_info['stored_event']['participants']; - $event['participant_types'] = $event_info['stored_event']['participant_types']; + unset($event['participants']); + unset($event['participant_types']); } else { @@ -1748,6 +1752,7 @@ class calendar_ical extends calendar_boupdate $defaultFields['basic'] = $defaultFields['minimal'] + array( 'recur_exception' => 'recur_exception', 'priority' => 'priority', + 'status' => 'status', ); $defaultFields['nexthaus'] = $defaultFields['basic'] + array( @@ -2662,14 +2667,6 @@ class calendar_ical extends calendar_boupdate function search($_vcalData, $contentID=null, $relax=false) { - if (is_null($contentID)) - { - $eventId = -1; - } - else - { - $eventId = $contentID; - } if (($events = $this->icaltoegw($_vcalData))) { // this function only supports searching a single event diff --git a/calendar/inc/class.calendar_sif.inc.php b/calendar/inc/class.calendar_sif.inc.php index 6551ebd2f9..f75ffd2a6e 100644 --- a/calendar/inc/class.calendar_sif.inc.php +++ b/calendar/inc/class.calendar_sif.inc.php @@ -312,10 +312,7 @@ class calendar_sif extends calendar_boupdate if ($this->event['recur_noenddate'] == 0) { $recur_enddate = $this->vCalendar->_parseDateTime($this->event['recur_enddate']); - $finalEvent['recur_enddate'] = mktime( - date('H', 23), - date('i', 59), - date('s', 59), + $finalEvent['recur_enddate'] = mktime(0, 0, 0, date('m', $recur_enddate), date('d', $recur_enddate), date('Y', $recur_enddate)); @@ -480,6 +477,11 @@ class calendar_sif extends calendar_boupdate // overwrite with server data for merge foreach ($event_info['stored_event'] as $key => $value) { + if (in_array($key, array('participants', 'participant_types'))) + { + unset($event[$key]); + continue; + } if (!empty($value)) $event[$key] = $value; } } @@ -487,8 +489,8 @@ class calendar_sif extends calendar_boupdate { // not merge // SIF clients do not support participants => add them back - $event['participants'] = $event_info['stored_event']['participants']; - $event['participant_types'] = $event_info['stored_event']['participant_types']; + unset($event['participants']); + unset($event['participant_types']); if ($event['whole_day'] && $event['tzid'] != $event_info['stored_event']['tzid']) { if (!isset(self::$tz_cache[$event_info['stored_event']['tzid']])) diff --git a/calendar/inc/class.calendar_so.inc.php b/calendar/inc/class.calendar_so.inc.php index f5cf124b7b..001aed31d3 100644 --- a/calendar/inc/class.calendar_so.inc.php +++ b/calendar/inc/class.calendar_so.inc.php @@ -1491,16 +1491,14 @@ ORDER BY cal_user_type, cal_usre_id * get stati of all recurrences of an event for a specific participant * * @param int $cal_id - * @param int $uid participant uid + * @param int $uid=null participant uid; if == null return only the recur dates * @param int $start=0 if != 0: startdate of the search/list (servertime) * @param int $end=0 if != 0: enddate of the search/list (servertime) * * @return array recur_date => status pairs (index 0 => main status) */ - function get_recurrences($cal_id, $uid, $start=0, $end=0) + function get_recurrences($cal_id, $uid=null, $start=0, $end=0) { - $user_type = $user_id = null; - self::split_user($uid, $user_type, $user_id); $participant_status = array(); $where = array('cal_id' => $cal_id); if ($start != 0 && $end == 0) $where[] = '(cal_recur_date = 0 OR cal_recur_date >= ' . (int)$start . ')'; @@ -1515,6 +1513,9 @@ ORDER BY cal_user_type, cal_usre_id // inititalize the array $participant_status[$row['cal_recur_date']] = null; } + if (is_null($uid)) return $participant_status; + $user_type = $user_id = null; + self::split_user($uid, $user_type, $user_id); $where = array( 'cal_id' => $cal_id, 'cal_user_type' => $user_type ? $user_type : 'u', From b2b8b353832f6b80397ca4a958ee974b142af210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Lehrke?= Date: Wed, 24 Feb 2010 15:05:00 +0000 Subject: [PATCH 027/334] Fix various recurring event issues --- calendar/inc/class.calendar_ical.inc.php | 135 +++++++++++--------- calendar/inc/class.calendar_sif.inc.php | 3 +- calendar/inc/class.calendar_uiforms.inc.php | 17 +-- 3 files changed, 83 insertions(+), 72 deletions(-) diff --git a/calendar/inc/class.calendar_ical.inc.php b/calendar/inc/class.calendar_ical.inc.php index 3c9f0b1948..0d30209d9c 100644 --- a/calendar/inc/class.calendar_ical.inc.php +++ b/calendar/inc/class.calendar_ical.inc.php @@ -211,6 +211,7 @@ class calendar_ical extends calendar_boupdate strtoupper($GLOBALS['egw_info']['user']['preferences']['common']['lang'])); $vcal->setAttribute('VERSION', $version); $vcal->setAttribute('METHOD', $method); + $events_exported = false; if (!is_array($events)) $events = array($events); @@ -893,9 +894,10 @@ class calendar_ical extends calendar_boupdate } } $vcal->addComponent($vevent); + $events_exported = true; } - $retval = $vcal->exportvCalendar(); + $retval = $events_exported ? $vcal->exportvCalendar() : false; if ($this->log) { error_log(__FILE__.'['.__LINE__.'] '.__METHOD__ . @@ -1070,7 +1072,7 @@ class calendar_ical extends calendar_boupdate if (!isset($event['participants'][$uid])) { // Add it back in - $event['participants'][$uid] = $event['participant_types']['r'][substr($uid,1)] = $status; + $event['participants'][$uid] = $status; } } break; @@ -1083,7 +1085,14 @@ class calendar_ical extends calendar_boupdate else { // no merge - if (!isset($this->supportedFields['participants']) || !count($event['participants'])) + if(!isset($this->supportedFields['category'])) + { + $event['category'] = $event_info['stored_event']['category']; + } + if (!isset($this->supportedFields['participants']) + || !$event['participants'] + || !is_array($event['participants']) + || !count($event['participants'])) { if ($this->log) { @@ -1094,7 +1103,6 @@ class calendar_ical extends calendar_boupdate // If this is an updated meeting, and the client doesn't support // participants OR the event no longer contains participants, add them back unset($event['participants']); - unset($event['participant_types']); } else { @@ -1119,20 +1127,19 @@ class calendar_ical extends calendar_boupdate } } } - } - - foreach ($event_info['stored_event']['participants'] as $uid => $status) - { - // Is it a resource and no longer present in the event? - if ($uid[0] == 'r' && !isset($event['participants'][$uid])) + foreach ($event_info['stored_event']['participants'] as $uid => $status) { - if ($this->log) + // Is it a resource and no longer present in the event? + if ($uid[0] == 'r' && !isset($event['participants'][$uid])) { - error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. - "() Restore resource $uid to status $status\n",3,$this->logfile); + if ($this->log) + { + error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. + "() Restore resource $uid to status $status\n",3,$this->logfile); + } + // Add it back in + $event['participants'][$uid] = $status; } - // Add it back in - $event['participants'][$uid] = $event['participant_types']['r'][substr($uid,1)] = $status; } } @@ -1188,7 +1195,9 @@ class calendar_ical extends calendar_boupdate $event['owner'] = $this->user; } - if (!is_array($event['participants']) || !count($event['participants'])) + if (!$event['participants'] + || !is_array($event['participants']) + || !count($event['participants'])) { $status = $event['owner'] == $this->user ? 'A' : 'U'; $status = calendar_so::combine_status($status, 1, 'CHAIR'); @@ -1198,7 +1207,7 @@ class calendar_ical extends calendar_boupdate { foreach ($event['participants'] as $uid => $status) { - // Is it a resource and no longer present in the event? + // if the client did not give us a proper status => set default if ($status[0] == 'X') { if ($uid == $event['owner']) @@ -1499,46 +1508,49 @@ class calendar_ical extends calendar_boupdate $event_info['stored_event'] = $this->read($updated_id, 0, false, 'server'); } - // update status depending on the given event type - switch ($event_info['type']) + if (isset($event['participants'])) { - case 'SINGLE': - case 'SERIES-MASTER': - case 'SERIES-EXCEPTION': - case 'SERIES-EXCEPTION-PROPAGATE': - if (is_array($event_info['stored_event'])) // status update requires a stored event - { - if ($event_info['acl_edit']) + // update status depending on the given event type + switch ($event_info['type']) + { + case 'SINGLE': + case 'SERIES-MASTER': + case 'SERIES-EXCEPTION': + case 'SERIES-EXCEPTION-PROPAGATE': + if (is_array($event_info['stored_event'])) // status update requires a stored event { - // update all participants if we have the right to do that - $this->update_status($event, $event_info['stored_event']); + if ($event_info['acl_edit']) + { + // update all participants if we have the right to do that + $this->update_status($event, $event_info['stored_event']); + } + elseif (isset($event['participants'][$this->user]) || isset($event_info['stored_event']['participants'][$this->user])) + { + // update the users status only + $this->set_status($event_info['stored_event']['id'], $this->user, + ($event['participants'][$this->user] ? $event['participants'][$this->user] : 'R'), 0, true); + } } - elseif (isset($event['participants'][$this->user]) || isset($event_info['stored_event']['participants'][$this->user])) - { - // update the users status only - $this->set_status($event_info['stored_event']['id'], $this->user, - ($event['participants'][$this->user] ? $event['participants'][$this->user] : 'R'), 0, true); - } - } - break; + break; - case 'SERIES-PSEUDO-EXCEPTION': - if (is_array($event_info['master_event'])) // status update requires a stored master event - { - $recurrence = $this->date2usertime($event['recurrence']); - if ($event_info['acl_edit']) + case 'SERIES-PSEUDO-EXCEPTION': + if (is_array($event_info['master_event'])) // status update requires a stored master event { - // update all participants if we have the right to do that - $this->update_status($event, $event_info['stored_event'], $recurrence); + $recurrence = $this->date2usertime($event['recurrence']); + if ($event_info['acl_edit']) + { + // update all participants if we have the right to do that + $this->update_status($event, $event_info['stored_event'], $recurrence); + } + elseif (isset($event['participants'][$this->user]) || isset($event_info['master_event']['participants'][$this->user])) + { + // update the users status only + $this->set_status($event_info['master_event']['id'], $this->user, + ($event['participants'][$this->user] ? $event['participants'][$this->user] : 'R'), $recurrence, true); + } } - elseif (isset($event['participants'][$this->user]) || isset($event_info['master_event']['participants'][$this->user])) - { - // update the users status only - $this->set_status($event_info['master_event']['id'], $this->user, - ($event['participants'][$this->user] ? $event['participants'][$this->user] : 'R'), $recurrence, true); - } - } - break; + break; + } } // choose which id to return to the client @@ -1864,6 +1876,7 @@ class calendar_ical extends calendar_boupdate case 'd750i': case 'p910i': case 'g705i': + case 'w890i': $this->supportedFields = $defaultFields['basic']; break; default: @@ -2491,7 +2504,7 @@ class calendar_ical extends calendar_boupdate { //Horde::logMessage("vevent2egw: set status to " . $status, // __FILE__, __LINE__, PEAR_LOG_DEBUG); - $event['participants'][$this->user] = + $vcardData['participants'][$this->user] = calendar_so::combine_status($status); } $status = 'U'; // keep the group @@ -2532,12 +2545,12 @@ class calendar_ical extends calendar_boupdate { $attributes['params']['ROLE'] = 'CHAIR'; } - if (!isset($event['participants'][$uid]) || - $event['participants'][$uid][0] != 'A') + if (!isset($vcardData['participants'][$uid]) || + $vcardData['participants'][$uid][0] != 'A') { // for multiple entries the ACCEPT wins // add quantity and role - $event['participants'][$uid] = + $vcardData['participants'][$uid] = calendar_so::combine_status($status, $attributes['params']['X-EGROUPWARE-QUANTITY'], $attributes['params']['ROLE']); @@ -2545,11 +2558,11 @@ class calendar_ical extends calendar_boupdate break; case 'ORGANIZER': - if (isset($event['participants'][$uid])) + if (isset($vcardData['participants'][$uid])) { - $status = $event['participants'][$uid]; + $status = $vcardData['participants'][$uid]; calendar_so::split_status($status, $quantity, $role); - $event['participants'][$uid] = + $vcardData['participants'][$uid] = calendar_so::combine_status($status, $quantity, 'CHAIR'); } if (is_numeric($uid) && ($uid == $this->calendarOwner || !$this->calendarOwner)) @@ -2561,10 +2574,10 @@ class calendar_ical extends calendar_boupdate { // we must insert a CHAIR participant to keep the ORGANIZER $event['owner'] = $this->user; - if (!isset($event['participants'][$uid])) + if (!isset($vcardData['participants'][$uid])) { // save the ORGANIZER as event CHAIR - $event['participants'][$uid] = + $vcardData['participants'][$uid] = calendar_so::combine_status('U', 1, 'CHAIR'); } } @@ -2781,6 +2794,8 @@ class calendar_ical extends calendar_boupdate */ function update_status($new_event, $old_event , $recur_date=0) { + if (!isset($new_event['participants'])) return; + // check the old list against the new list foreach ($old_event['participants'] as $userid => $status) { diff --git a/calendar/inc/class.calendar_sif.inc.php b/calendar/inc/class.calendar_sif.inc.php index f75ffd2a6e..12f45b2b7a 100644 --- a/calendar/inc/class.calendar_sif.inc.php +++ b/calendar/inc/class.calendar_sif.inc.php @@ -477,7 +477,7 @@ class calendar_sif extends calendar_boupdate // overwrite with server data for merge foreach ($event_info['stored_event'] as $key => $value) { - if (in_array($key, array('participants', 'participant_types'))) + if ($key == 'participants') { unset($event[$key]); continue; @@ -490,7 +490,6 @@ class calendar_sif extends calendar_boupdate // not merge // SIF clients do not support participants => add them back unset($event['participants']); - unset($event['participant_types']); if ($event['whole_day'] && $event['tzid'] != $event_info['stored_event']['tzid']) { if (!isset(self::$tz_cache[$event_info['stored_event']['tzid']])) diff --git a/calendar/inc/class.calendar_uiforms.inc.php b/calendar/inc/class.calendar_uiforms.inc.php index 3514e2204e..3086131594 100644 --- a/calendar/inc/class.calendar_uiforms.inc.php +++ b/calendar/inc/class.calendar_uiforms.inc.php @@ -238,7 +238,7 @@ class calendar_uiforms extends calendar_ui $event['end']['hour'] = 23; $event['end']['minute'] = $event['end']['second'] = 59; unset($event['end']['raw']); $event['end'] = $this->bo->date2ts($event['end']); } - // some checks for recurances, if you give a date, make it a weekly repeating event and visa versa + // some checks for recurrences, if you give a date, make it a weekly repeating event and visa versa if ($event['recur_type'] == MCAL_RECUR_NONE && $event['recur_data']) $event['recur_type'] = MCAL_RECUR_WEEKLY; if ($event['recur_type'] == MCAL_RECUR_WEEKLY && !$event['recur_data']) { @@ -833,14 +833,11 @@ class calendar_uiforms extends calendar_ui // check if we should create an exception if ($_GET['exception']) { - // exception: preserv participants of this event and merge it with the 0-recurrence - $participants = array('participants' => $event['participants'],'participant_types' => $event['participant_types']); - $event = array_merge($this->bo->read($cal_id,0,true),$participants); $msg = $this->_create_exception($event,$preserv); } else { - $event = $this->bo->read($cal_id,0,true); // read the 0-recurrence + $event = $this->bo->read($cal_id,0,true); } } } @@ -1077,12 +1074,12 @@ class calendar_uiforms extends calendar_ui $GLOBALS['egw']->js->set_onload("set_style_by_class('table','end_hide','display','".($content['duration'] && isset($sel_options['duration'][$content['duration']]) ? 'none' : 'block')."');"); $readonlys['recur_exception'] = !count($content['recur_exception']); // otherwise we get a delete button - + if ($event['recur_type'] != MCAL_RECUR_NONE) { $onclick =& $etpl->get_cell_attribute('button[delete]','onclick'); $onclick = str_replace('Delete this event','Delete this series of recuring events',$onclick); - + // some fundamental values of an existing series should not be changed by the user $readonlys['start'] = $readonlys['whole_day'] = true; $readonlys['recur_type'] = $readonlys['recur_data'] = true; @@ -1746,7 +1743,7 @@ class calendar_uiforms extends calendar_ui 'owner' => 'select-account', 'cat_id' => 'select-cat', 'non_blocking' => array(''=>lang('No'), 1=>lang('Yes')), - + 'start' => 'date-time', 'end' => 'date-time', @@ -1770,11 +1767,11 @@ class calendar_uiforms extends calendar_ui if($content['recur_type'] || $content['recurrence']) { $content['history']['filter'] = array( '(history_status NOT LIKE \'participants%\' OR (history_status LIKE \'participants%\' AND ( - history_new_value LIKE \'%' . bo_tracking::ONE2N_SEPERATOR . $content['recurrence'] . '\' OR + history_new_value LIKE \'%' . bo_tracking::ONE2N_SEPERATOR . $content['recurrence'] . '\' OR history_old_value LIKE \'%' . bo_tracking::ONE2N_SEPERATOR . $content['recurrence'] . '\')))' ); } - + // Translate labels $tracking = new calendar_tracking(); foreach($tracking->field2label as $field => $label) { From c9ab7e557b85049f3c0147fde8f641fd9860e070 Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Thu, 25 Feb 2010 13:42:27 +0000 Subject: [PATCH 028/334] fixing issue: failed add to organisation from org-view, when colon in org_unit/org_location/organisation --- 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 7f01d79a53..f77ad5561e 100755 --- a/addressbook/inc/class.addressbook_bo.inc.php +++ b/addressbook/inc/class.addressbook_bo.inc.php @@ -878,7 +878,7 @@ class addressbook_bo extends addressbook_so $org = array(); foreach(explode('|||',$org_id) as $part) { - list($name,$value) = explode(':',$part); + list($name,$value) = explode(':',$part,2); $org[$name] = $value; } $csvs = array('cat_id'); // fields with comma-separated-values From 8211aef3ff11121ab0293e1625ec35cdbd868331 Mon Sep 17 00:00:00 2001 From: Christian Binder Date: Thu, 25 Feb 2010 17:05:24 +0000 Subject: [PATCH 029/334] fixed wrong series event end times for whole day events when events occur or span over a daylight saving date, fixed typos --- calendar/inc/class.calendar_bo.inc.php | 29 ++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/calendar/inc/class.calendar_bo.inc.php b/calendar/inc/class.calendar_bo.inc.php index dfb3111216..62af9b9b3f 100644 --- a/calendar/inc/class.calendar_bo.inc.php +++ b/calendar/inc/class.calendar_bo.inc.php @@ -853,9 +853,30 @@ class calendar_bo //echo "

".$time." --> ignored as $ts < $start-$event_length

\n"; continue; // to early or original event (returned by interator too) } - //echo "

".$time." --> adding recurrence

\n"; + + $ts_end = $ts + $event_length; + + // adjust ts_end for whole day events in case it does not fit due to + // spans over summer/wintertime adjusted days + if($event['whole_day'] && ($arr_end = $this->date2array($ts_end)) && + !($arr_end['hour'] == 23 && $arr_end['minute'] == 59 && $arr_end['second'] == 59)) + { + $arr_end['hour'] = 23; + $arr_end['minute'] = 59; + $arr_end['second'] = 59; + $ts_end_guess = $this->date2ts($arr_end); + if($ts_end_guess - $ts_end > DAY_s/2) + { + $ts_end = $ts_end_guess - DAY_s; // $ts_end_guess was one day too far in the future + } + else + { + $ts_end = $ts_end_guess; // $ts_end_guess was ok + } + } + $event['start'] = $ts; - $event['end'] = $ts + $event_length; + $event['end'] = $ts_end; $events[] = $event; } if ($this->debug && ((int) $this->debug > 2 || $this->debug == 'set_recurrences' || $this->debug == 'check_move_horizont' || $this->debug == 'insert_all_recurrences')) @@ -1037,7 +1058,7 @@ class calendar_bo } /** - * Converts several date-types to a timestamp and optionaly converts user- to server-time + * Converts several date-types to a timestamp and optionally converts user- to server-time * * @param mixed $date date to convert, should be one of the following types * string (!) in form YYYYMMDD or iso8601 YYYY-MM-DDThh:mm:ss or YYYYMMDDThhmmss @@ -1051,7 +1072,7 @@ class calendar_bo } /** - * Converts a date to an array and optionaly converts server- to user-time + * Converts a date to an array and optionally converts server- to user-time * * @param mixed $date date to convert * @param boolean $server2user_time conversation between user- and server-time default False == Off From 731abfd2a3836561ae8e6c4c03d32a359ae9cc5b Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Thu, 25 Feb 2010 23:13:18 +0000 Subject: [PATCH 030/334] Some more work toward completion: - Wizard now works to define input definitions; you can define the mapping, translations and conditions using the UI. - Added ability to schedule imports / export using async services Still a lot of work to be done... --- importexport/inc/class.bodefinitions.inc.php | 11 ++ .../inc/class.iface_import_plugin.inc.php | 11 ++ ...ass.import_export_helper_functions.inc.php | 5 +- ...rtexport_admin_prefs_sidebox_hooks.inc.php | 5 +- importexport/inc/class.uidefinitions.inc.php | 33 +++-- importexport/inc/class.uiexport.inc.php | 123 ++++++++++++++---- importexport/js/export_dialog.js | 11 +- importexport/setup/etemplates.inc.php | 28 ++-- 8 files changed, 171 insertions(+), 56 deletions(-) diff --git a/importexport/inc/class.bodefinitions.inc.php b/importexport/inc/class.bodefinitions.inc.php index 77221d0200..d37dbbf04a 100644 --- a/importexport/inc/class.bodefinitions.inc.php +++ b/importexport/inc/class.bodefinitions.inc.php @@ -70,6 +70,17 @@ class bodefinitions { } } + /** + * Save a definition + * + * @param definition $definition + */ + public function save(Array $data) { + $definition = new definition(); + $definition->set_record($data); + $definition->save($data['definition_id']); + } + /** * checkes if user if permitted to access given definition * diff --git a/importexport/inc/class.iface_import_plugin.inc.php b/importexport/inc/class.iface_import_plugin.inc.php index a0744129cc..a168af8bea 100644 --- a/importexport/inc/class.iface_import_plugin.inc.php +++ b/importexport/inc/class.iface_import_plugin.inc.php @@ -31,6 +31,7 @@ interface iface_import_plugin { * * @param stram $_stram * @param definition $_definition + * @return int number of successful imports */ public function import( $_stream, definition $_definition ); @@ -76,5 +77,15 @@ interface iface_import_plugin { */ public function get_selectors_etpl(); + /** + * Returns errors that were encountered during importing + * Maximum of one error message per record, but you can concatenate them if you need to + * + * @return Array ( + * record_# => error message + * ) + */ + public function get_errors(); + } // end of iface_export_plugin ?> diff --git a/importexport/inc/class.import_export_helper_functions.inc.php b/importexport/inc/class.import_export_helper_functions.inc.php index b2cfe66684..4de42606bf 100755 --- a/importexport/inc/class.import_export_helper_functions.inc.php +++ b/importexport/inc/class.import_export_helper_functions.inc.php @@ -184,7 +184,7 @@ class import_export_helper_functions { $CntlPre = '|TC{'; // Filter all cntl-chars \x01-\x1f and trim $CntlnCLPre = '|TCnCL{'; // Like |C{ but allowes CR and LF $INE = '|INE{'; // Only insert if stuff in ^^ is not empty - + foreach ( $_conversion as $idx => $conversion_string ) { if ( empty( $conversion_string ) ) continue; @@ -221,7 +221,7 @@ class import_export_helper_functions { } // clean each field $val = preg_replace_callback("/(\|T\{|\|TC\{|\|TCnCL\{|\|INE\{)(.*)\}/", array( self, 'strclean'), $val ); - + $_record[$idx] = $val; } return $_record; @@ -249,7 +249,6 @@ class import_export_helper_functions { } private static function strclean( $_matches ) { - //print_r($_matches); switch( $_matches[1] ) { case '|T{' : return trim( $_matches[2] ); case '|TC{' : return trim( preg_replace( '/[\x01-\x1F]+/', '', $_matches[2] ) ); diff --git a/importexport/inc/class.importexport_admin_prefs_sidebox_hooks.inc.php b/importexport/inc/class.importexport_admin_prefs_sidebox_hooks.inc.php index ea5f1b35d9..7e5961a235 100644 --- a/importexport/inc/class.importexport_admin_prefs_sidebox_hooks.inc.php +++ b/importexport/inc/class.importexport_admin_prefs_sidebox_hooks.inc.php @@ -62,6 +62,9 @@ class importexport_admin_prefs_sidebox_hooks 'Define {im|ex}ports' => $GLOBALS['egw']->link('/index.php',array( 'menuaction' => 'importexport.uidefinitions.index', )), + 'Schedule' => $GLOBALS['egw']->link('/index.php', array( + 'menuaction' => 'importexport.importexport_schedule_ui.index' + )), ); if ($location == 'admin') { @@ -114,4 +117,4 @@ class importexport_admin_prefs_sidebox_hooks $GLOBALS['egw']->preferences->save_repository(False,'default'); } } -} \ No newline at end of file +} diff --git a/importexport/inc/class.uidefinitions.inc.php b/importexport/inc/class.uidefinitions.inc.php index a6c648a875..14eacbc923 100644 --- a/importexport/inc/class.uidefinitions.inc.php +++ b/importexport/inc/class.uidefinitions.inc.php @@ -19,7 +19,7 @@ require_once('class.bodefinitions.inc.php'); */ class uidefinitions { - const _debug = true; + const _debug = false; const _appname = 'importexport'; @@ -64,12 +64,12 @@ class uidefinitions $this->steps = array( 'wizzard_step10' => lang('Choose an application'), 'wizzard_step20' => lang('Choose a plugin'), - 'wizzard_step80' => lang('Which useres are allowed for this definition'), + 'wizzard_step80' => lang('Which users are allowed to use this definition'), 'wizzard_step90' => lang('Choose a name for this definition'), 'wizzard_finish' => '', ); - //register plugins (depricated) - //$this->plugins = bodefinitions::plugins(); + //register plugins + $this->plugins = import_export_helper_functions::get_plugins(); } /** @@ -134,7 +134,7 @@ class uidefinitions } $definition = array('name' => $_definition); $bodefinitions = new bodefinitions(); - $bodefinitions->read($definition); + $definition = $bodefinitions->read($definition); $definition['edit'] = true; $this->wizzard($definition); } @@ -160,8 +160,9 @@ class uidefinitions if($content['plugin'] && $content['application']) { // we need to deal with the wizzard object if exists - if (file_exists(EGW_SERVER_ROOT . '/'. $content['application'].'/inc/class.wizzard_'. $content['plugin'].'.inc.php')) + if (file_exists(EGW_SERVER_ROOT . '/'. $content['application'].'/importexport/class.wizzard_'. $content['plugin'].'.inc.php')) { + require_once(EGW_SERVER_ROOT . '/'. $content['application'].'/importexport/class.wizzard_'. $content['plugin'].'.inc.php'); $wizzard_plugin = 'wizzard_'.$content['plugin']; } else @@ -169,7 +170,10 @@ class uidefinitions $wizzard_plugin = $content['plugin']; } $this->plugin = is_object($GLOBALS['egw']->$wizzard_plugin) ? $GLOBALS['egw']->$wizzard_plugin : new $wizzard_plugin; - if(!is_object($GLOBALS['egw']->uidefinitions)) $GLOBALS['egw']->uidefinitions =& $this; + + // Global object needs to be the same, or references to plugin don't work + if(!is_object($GLOBALS['egw']->uidefinitions) || $GLOBALS['egw']->uidefinitions !== $this) + $GLOBALS['egw']->uidefinitions =& $this; } // deal with buttons even if we are not on ajax if(isset($content['button']) && array_search('pressed',$content['button']) === false && count($content['button']) == 1) @@ -273,7 +277,7 @@ class uidefinitions $plugin_definition = $this->plugins[$content['application']][$content['plugin']]['definition']; if($plugin_definition) $this->plugin = new $plugin_definition; }*/ - if(is_object($this->plugin)) + if(is_object($this->plugin) && is_array($this->plugin->steps)) { $steps = array_merge($this->steps,$this->plugin->steps); $steps = array_flip($steps); asort($steps); $steps = array_flip($steps); @@ -331,7 +335,7 @@ class uidefinitions switch (array_search('pressed', $content['button'])) { case 'next': - $content['type'] = $this->plugin->plugin_info['type']; + $content['type'] = $this->plugin instanceof iface_import_plugin ? 'import' : 'export'; return $this->get_step($content['step'],1); case 'previous' : unset ($content['plugin']); @@ -347,7 +351,11 @@ class uidefinitions else { $content['msg'] = $this->steps['wizzard_step20']; - foreach ($this->plugins[$content['application']] as $plugin => $info) $sel_options['plugin'][$plugin] = $info['name']; + foreach ($this->plugins[$content['application']] as $type => $plugins) { + foreach($plugins as $plugin => $name) { + $sel_options['plugin'][$plugin] = $name; + } + } $content['step'] = 'wizzard_step20'; $preserv = $content; unset ($preserv['button']); @@ -427,6 +435,11 @@ class uidefinitions function wizzard_finish(&$content) { if(self::_debug) error_log('importexport.uidefinitions::wizzard_finish->$content '.print_r($content,true)); + // Take out some UI leavings + unset($content['msg']); + unset($content['step']); + unset($content['button']); + $bodefinitions = new bodefinitions(); $bodefinitions->save($content); // This message is displayed if browser cant close window diff --git a/importexport/inc/class.uiexport.inc.php b/importexport/inc/class.uiexport.inc.php index 211e6a46c1..87cbbd68c8 100644 --- a/importexport/inc/class.uiexport.inc.php +++ b/importexport/inc/class.uiexport.inc.php @@ -57,7 +57,8 @@ class uiexport { if(empty($_content)) { $et = new etemplate(self::_appname. '.export_dialog'); $_appname = $_GET['appname']; - $_definition =$_GET['definition'] = 'expert'; + //$_definition = $_GET['definition'] = 'expert'; + $_definition = $_GET['definition']; $_plugin = $_GET['plugin']; // NOTE: definition _must_ be 'expert' if for plugin to be used! $_selection = $_GET['selection']; @@ -67,6 +68,7 @@ class uiexport { $content['appname'] = $_appname; $preserv['appname'] = $_appname; $readonlys['appname'] = true; + $this->js->set_onload("export_dialog.appname = '$_appname';"); $this->js->set_onload("set_style_by_class('tr','select_appname','display','none');"); // fill definitions @@ -84,8 +86,9 @@ class uiexport { } unset($definitions); $sel_options['definition']['expert'] = lang('Expert options'); + - if(isset($_definition) && array_key_exists($_definition,$sel_options)) { + if(isset($_definition) && array_key_exists($_definition,$sel_options['definition'])) { $content['definition'] = $_definition; } else { @@ -98,16 +101,17 @@ class uiexport { $sel_options['plugin'] = $this->export_plugins[$_appname]['export']; // show definitions or plugins in ui? - if($content['defintion'] == 'expert') { + if($content['definition'] == 'expert') { if(isset($_plugin) && array_key_exists($_plugin,$sel_options['plugin'])) { $content['plugin'] = $_plugin; $selected_plugin = $_plugin; - error_log('hallo'); } else { - $plugins_classnames = array_keys($plugins); +/* + $plugins_classnames = array_keys($sel_options['plugin']); $selected_plugin = $plugins_classnames[0]; $sel_options['plugin'] = $plugins; +*/ } $this->js->set_onload("set_style_by_class('tr','select_definition','display','none');"); } @@ -120,15 +124,17 @@ class uiexport { } // handle selector - //$plugin_object = new $selected_plugin; - - //$content['description'] = $plugin_object->get_description(); - - // fill options tab - // TODO: do we need all options templates online? - // NO, we can manipulate the session array of template id on xajax request - // however, there might be other solutions... we solve this in 1.3 - //$content['plugin_options_html'] = $plugin_object->get_options_etpl(); + if($selected_plugin) { + $plugin_object = new $selected_plugin; + + $content['description'] = $plugin_object->get_description(); + + // fill options tab + // TODO: do we need all options templates online? + // NO, we can manipulate the session array of template id on xajax request + // however, there might be other solutions... we solve this in 1.3 + $content['plugin_options_html'] = $plugin_object->get_options_etpl(); + } // fill selection tab if ($_selection) { @@ -169,7 +175,7 @@ class uiexport { //error_log(__LINE__.__FILE__.'$_content: '.print_r($_content,true)); $response = new xajaxResponse(); - if ($_content['defintion'] == 'expert') { + if ($_content['definition'] == 'expert') { $definition = new definition(); $definition->definition_id = $_content['definition_id'] ? $_content['definition_id'] : ''; $definition->name = $_content['name'] ? $_content['name'] : ''; @@ -247,11 +253,52 @@ class uiexport { return $et->exec(self::_appname. '.uiexport.export_dialog',$content,$sel_options,$readonlys,$preserv,2); } - public function ajax_get_plugins($_appname) { - $response = new xajaxResponse(); + public function ajax_get_definitions($_appname, xajaxResponse &$response = null) { + if(is_null($response)) { + $response = new xajaxResponse(); + } else { + $no_return = true; + } + if (!$_appname) { + $response->addScript("set_style_by_class('tr','select_definition','display','none');"); + return $no_return ? '' : $response->getXML(); + } + + $definitions = new bodefinitions(array( + 'type' => 'export', + 'application' => $_appname + )); + foreach ((array)$definitions->get_definitions() as $identifier) { + $definition = new definition($identifier); + if ($title = $definition->get_title()) { + if (!$selected_plugin) $selected_plugin = $plugin; + $sel_options['definition'] .= ''; + } + unset($definition); + } + unset($definitions); + $sel_options['definition'] .= '