diff options
author | Brice Maron <brice@bmaron.net> | 2012-06-21 21:15:35 +0400 |
---|---|---|
committer | Brice Maron <brice@bmaron.net> | 2012-06-21 21:15:35 +0400 |
commit | e5c56b2433b1987e4b6b8020e01f4da03623c4b8 (patch) | |
tree | a650870f7bbc497833b8ea00051f9046e1779f5e | |
parent | df83df5263db57056d0bd70edfa3b28e7b5e6b6b (diff) | |
parent | 6707e4187e4c1186eff8dfe06999c4539ab80de7 (diff) |
Merge branch 'master' into multi_app_dir
Conflicts:
lib/app.php
lib/base.php
lib/minimizer/css.php
lib/minimizer/js.php
lib/template.php
lib/util.php
171 files changed, 2722 insertions, 2337 deletions
diff --git a/3rdparty/MDB2/Schema/Parser.php b/3rdparty/MDB2/Schema/Parser.php index cfd0c37d8a3..3c4345661b1 100644 --- a/3rdparty/MDB2/Schema/Parser.php +++ b/3rdparty/MDB2/Schema/Parser.php @@ -147,33 +147,6 @@ class MDB2_Schema_Parser extends XML_Parser } /** - * PHP 4 compatible constructor - * - * @param array $variables mixed array with user defined schema - * variables - * @param bool $fail_on_invalid_names array with reserved words per RDBMS - * @param array $structure multi dimensional array with - * database schema and data - * @param array $valid_types information of all valid fields - * types - * @param bool $force_defaults if true sets a default value to - * field when not explicit - * @param int $max_identifiers_length maximum allowed size for entities - * name - * - * @return void - * - * @access public - * @static - */ - function MDB2_Schema_Parser($variables, $fail_on_invalid_names = true, - $structure = false, $valid_types = array(), $force_defaults = true, - $max_identifiers_length = null - ) { - $this->__construct($variables, $fail_on_invalid_names, $structure, $valid_types, $force_defaults); - } - - /** * Triggered when reading a XML open tag <element> * * @param resource $xp xml parser resource diff --git a/3rdparty/MDB2/Schema/Parser2.php b/3rdparty/MDB2/Schema/Parser2.php index b415b4a336e..f27dffbabf9 100644 --- a/3rdparty/MDB2/Schema/Parser2.php +++ b/3rdparty/MDB2/Schema/Parser2.php @@ -144,33 +144,6 @@ class MDB2_Schema_Parser2 extends XML_Unserializer } /** - * PHP 4 compatible constructor - * - * @param array $variables mixed array with user defined schema - * variables - * @param bool $fail_on_invalid_names array with reserved words per RDBMS - * @param array $structure multi dimensional array with - * database schema and data - * @param array $valid_types information of all valid fields - * types - * @param bool $force_defaults if true sets a default value to - * field when not explicit - * @param int $max_identifiers_length maximum allowed size for entities - * name - * - * @return void - * - * @access public - * @static - */ - function MDB2_Schema_Parser2($variables, $fail_on_invalid_names = true, - $structure = false, $valid_types = array(), $force_defaults = true, - $max_identifiers_length = null - ) { - $this->__construct($variables, $fail_on_invalid_names, $structure, $valid_types, $force_defaults); - } - - /** * Main method. Parses XML Schema File. * * @return bool|error object diff --git a/3rdparty/MDB2/Schema/Validate.php b/3rdparty/MDB2/Schema/Validate.php index 4cff175576f..4a8e0d27bac 100644 --- a/3rdparty/MDB2/Schema/Validate.php +++ b/3rdparty/MDB2/Schema/Validate.php @@ -108,28 +108,6 @@ class MDB2_Schema_Validate $this->max_identifiers_length = $max_identifiers_length; } - /** - * PHP 4 compatible constructor - * - * @param bool $fail_on_invalid_names array with reserved words per RDBMS - * @param array $valid_types information of all valid fields - * types - * @param bool $force_defaults if true sets a default value to - * field when not explicit - * @param int $max_identifiers_length maximum allowed size for entities - * name - * - * @return void - * - * @access public - * @static - */ - function MDB2_Schema_Validate($fail_on_invalid_names = true, $valid_types = array(), - $force_defaults = true, $max_identifiers_length = null - ) { - $this->__construct($fail_on_invalid_names, $valid_types, $force_defaults); - } - // }}} // {{{ raiseError() diff --git a/3rdparty/MDB2/Schema/Writer.php b/3rdparty/MDB2/Schema/Writer.php index 70a03168de6..3eaa39a2071 100644 --- a/3rdparty/MDB2/Schema/Writer.php +++ b/3rdparty/MDB2/Schema/Writer.php @@ -82,22 +82,6 @@ class MDB2_Schema_Writer $this->valid_types = $valid_types; } - /** - * PHP 4 compatible constructor - * - * @param array $valid_types information of all valid fields - * types - * - * @return void - * - * @access public - * @static - */ - function MDB2_Schema_Writer($valid_types = array()) - { - $this->__construct($valid_types); - } - // }}} // {{{ raiseError() diff --git a/3rdparty/fullcalendar/js/fullcalendar.js b/3rdparty/fullcalendar/js/fullcalendar.js index 779a313c761..314f8c8a1a5 100644 --- a/3rdparty/fullcalendar/js/fullcalendar.js +++ b/3rdparty/fullcalendar/js/fullcalendar.js @@ -4662,7 +4662,7 @@ function DayEventRenderer() { "</span>"; } html += - "<span class='fc-event-title'>" + htmlEscape(event.title) + "</span>" + + "<span class='fc-event-title'>" + event.title + "</span>" + "</div>"; if (seg.isEnd && isEventResizable(event)) { html += diff --git a/3rdparty/smb4php/smb.php b/3rdparty/smb4php/smb.php index 69fb2487bc0..12c5890723b 100644 --- a/3rdparty/smb4php/smb.php +++ b/3rdparty/smb4php/smb.php @@ -326,8 +326,11 @@ class smb_stream_wrapper extends smb { $this->dir = array_keys($o['info']); $this->dir_index = 0; $this->adddircache ($url, $this->dir); + if(substr($url,-1,1)=='/'){ + $url=substr($url,0,-1); + } foreach ($o['info'] as $name => $info) { - smb::addstatcache($url . '/' . urlencode($name), $info); + smb::addstatcache($url . '/' . $name, $info); } } else { trigger_error ("dir_opendir(): dir failed for path '".$pu['path']."'", E_USER_WARNING); diff --git a/3rdparty/when/MIT-LICENSE.txt b/3rdparty/when/MIT-LICENSE.txt deleted file mode 100644 index b4429c89ac1..00000000000 --- a/3rdparty/when/MIT-LICENSE.txt +++ /dev/null @@ -1,9 +0,0 @@ -License - -Copyright (c) 2010 Thomas Planer - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file diff --git a/3rdparty/when/When.php b/3rdparty/when/When.php deleted file mode 100644 index 185836bf0c5..00000000000 --- a/3rdparty/when/When.php +++ /dev/null @@ -1,731 +0,0 @@ -<?php -/** - * Name: When - * Author: Thomas Planer <tplaner@gmail.com> - * Location: http://github.com/tplaner/When - * Created: September 2010 - * Description: Determines the next date of recursion given an iCalendar "rrule" like pattern. - * Requirements: PHP 5.3+ - makes extensive use of the Date and Time library (http://us2.php.net/manual/en/book.datetime.php) - */ -class When -{ - protected $frequency; - - protected $start_date; - protected $try_date; - - protected $end_date; - - protected $gobymonth; - protected $bymonth; - - protected $gobyweekno; - protected $byweekno; - - protected $gobyyearday; - protected $byyearday; - - protected $gobymonthday; - protected $bymonthday; - - protected $gobyday; - protected $byday; - - protected $gobysetpos; - protected $bysetpos; - - protected $suggestions; - - protected $count; - protected $counter; - - protected $goenddate; - - protected $interval; - - protected $wkst; - - protected $valid_week_days; - protected $valid_frequency; - - /** - * __construct - */ - public function __construct() - { - $this->frequency = null; - - $this->gobymonth = false; - $this->bymonth = range(1,12); - - $this->gobymonthday = false; - $this->bymonthday = range(1,31); - - $this->gobyday = false; - // setup the valid week days (0 = sunday) - $this->byday = range(0,6); - - $this->gobyyearday = false; - $this->byyearday = range(0,366); - - $this->gobysetpos = false; - $this->bysetpos = range(1,366); - - $this->gobyweekno = false; - // setup the range for valid weeks - $this->byweekno = range(0,54); - - $this->suggestions = array(); - - // this will be set if a count() is specified - $this->count = 0; - // how many *valid* results we returned - $this->counter = 0; - - // max date we'll return - $this->end_date = new DateTime('9999-12-31'); - - // the interval to increase the pattern by - $this->interval = 1; - - // what day does the week start on? (0 = sunday) - $this->wkst = 0; - - $this->valid_week_days = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'); - - $this->valid_frequency = array('SECONDLY', 'MINUTELY', 'HOURLY', 'DAILY', 'WEEKLY', 'MONTHLY', 'YEARLY'); - } - - /** - * @param DateTime|string $start_date of the recursion - also is the first return value. - * @param string $frequency of the recrusion, valid frequencies: secondly, minutely, hourly, daily, weekly, monthly, yearly - */ - public function recur($start_date, $frequency = "daily") - { - try - { - if(is_object($start_date)) - { - $this->start_date = clone $start_date; - } - else - { - // timestamps within the RFC have a 'Z' at the end of them, remove this. - $start_date = trim($start_date, 'Z'); - $this->start_date = new DateTime($start_date); - } - - $this->try_date = clone $this->start_date; - } - catch(Exception $e) - { - throw new InvalidArgumentException('Invalid start date DateTime: ' . $e); - } - - $this->freq($frequency); - - return $this; - } - - public function freq($frequency) - { - if(in_array(strtoupper($frequency), $this->valid_frequency)) - { - $this->frequency = strtoupper($frequency); - } - else - { - throw new InvalidArgumentException('Invalid frequency type.'); - } - - return $this; - } - - // accepts an rrule directly - public function rrule($rrule) - { - // strip off a trailing semi-colon - $rrule = trim($rrule, ";"); - - $parts = explode(";", $rrule); - - foreach($parts as $part) - { - list($rule, $param) = explode("=", $part); - - $rule = strtoupper($rule); - $param = strtoupper($param); - - switch($rule) - { - case "FREQ": - $this->frequency = $param; - break; - case "UNTIL": - $this->until($param); - break; - case "COUNT": - $this->count($param); - break; - case "INTERVAL": - $this->interval($param); - break; - case "BYDAY": - $params = explode(",", $param); - $this->byday($params); - break; - case "BYMONTHDAY": - $params = explode(",", $param); - $this->bymonthday($params); - break; - case "BYYEARDAY": - $params = explode(",", $param); - $this->byyearday($params); - break; - case "BYWEEKNO": - $params = explode(",", $param); - $this->byweekno($params); - break; - case "BYMONTH": - $params = explode(",", $param); - $this->bymonth($params); - break; - case "BYSETPOS": - $params = explode(",", $param); - $this->bysetpos($params); - break; - case "WKST": - $this->wkst($param); - break; - } - } - - return $this; - } - - //max number of items to return based on the pattern - public function count($count) - { - $this->count = (int)$count; - - return $this; - } - - // how often the recurrence rule repeats - public function interval($interval) - { - $this->interval = (int)$interval; - - return $this; - } - - // starting day of the week - public function wkst($day) - { - switch($day) - { - case 'SU': - $this->wkst = 0; - break; - case 'MO': - $this->wkst = 1; - break; - case 'TU': - $this->wkst = 2; - break; - case 'WE': - $this->wkst = 3; - break; - case 'TH': - $this->wkst = 4; - break; - case 'FR': - $this->wkst = 5; - break; - case 'SA': - $this->wkst = 6; - break; - } - - return $this; - } - - // max date - public function until($end_date) - { - try - { - if(is_object($end_date)) - { - $this->end_date = clone $end_date; - } - else - { - // timestamps within the RFC have a 'Z' at the end of them, remove this. - $end_date = trim($end_date, 'Z'); - $this->end_date = new DateTime($end_date); - } - } - catch(Exception $e) - { - throw new InvalidArgumentException('Invalid end date DateTime: ' . $e); - } - - return $this; - } - - public function bymonth($months) - { - if(is_array($months)) - { - $this->gobymonth = true; - $this->bymonth = $months; - } - - return $this; - } - - public function bymonthday($days) - { - if(is_array($days)) - { - $this->gobymonthday = true; - $this->bymonthday = $days; - } - - return $this; - } - - public function byweekno($weeks) - { - $this->gobyweekno = true; - - if(is_array($weeks)) - { - $this->byweekno = $weeks; - } - - return $this; - } - - public function bysetpos($days) - { - $this->gobysetpos = true; - - if(is_array($days)) - { - $this->bysetpos = $days; - } - - return $this; - } - - public function byday($days) - { - $this->gobyday = true; - - if(is_array($days)) - { - $this->byday = array(); - foreach($days as $day) - { - $len = strlen($day); - - $as = '+'; - - // 0 mean no occurence is set - $occ = 0; - - if($len == 3) - { - $occ = substr($day, 0, 1); - } - if($len == 4) - { - $as = substr($day, 0, 1); - $occ = substr($day, 1, 1); - } - - if($as == '-') - { - $occ = '-' . $occ; - } - else - { - $occ = '+' . $occ; - } - - $day = substr($day, -2, 2); - switch($day) - { - case 'SU': - $this->byday[] = $occ . 'SU'; - break; - case 'MO': - $this->byday[] = $occ . 'MO'; - break; - case 'TU': - $this->byday[] = $occ . 'TU'; - break; - case 'WE': - $this->byday[] = $occ . 'WE'; - break; - case 'TH': - $this->byday[] = $occ . 'TH'; - break; - case 'FR': - $this->byday[] = $occ . 'FR'; - break; - case 'SA': - $this->byday[] = $occ . 'SA'; - break; - } - } - } - - return $this; - } - - public function byyearday($days) - { - $this->gobyyearday = true; - - if(is_array($days)) - { - $this->byyearday = $days; - } - - return $this; - } - - // this creates a basic list of dates to "try" - protected function create_suggestions() - { - switch($this->frequency) - { - case "YEARLY": - $interval = 'year'; - break; - case "MONTHLY": - $interval = 'month'; - break; - case "WEEKLY": - $interval = 'week'; - break; - case "DAILY": - $interval = 'day'; - break; - case "HOURLY": - $interval = 'hour'; - break; - case "MINUTELY": - $interval = 'minute'; - break; - case "SECONDLY": - $interval = 'second'; - break; - } - - $month_day = $this->try_date->format('j'); - $month = $this->try_date->format('n'); - $year = $this->try_date->format('Y'); - - $timestamp = $this->try_date->format('H:i:s'); - - if($this->gobysetpos) - { - if($this->try_date == $this->start_date) - { - $this->suggestions[] = clone $this->try_date; - } - else - { - if($this->gobyday) - { - foreach($this->bysetpos as $_pos) - { - $tmp_array = array(); - $_mdays = range(1, date('t',mktime(0,0,0,$month,1,$year))); - foreach($_mdays as $_mday) - { - $date_time = new DateTime($year . '-' . $month . '-' . $_mday . ' ' . $timestamp); - - $occur = ceil($_mday / 7); - - $day_of_week = $date_time->format('l'); - $dow_abr = strtoupper(substr($day_of_week, 0, 2)); - - // set the day of the month + (positive) - $occur = '+' . $occur . $dow_abr; - $occur_zero = '+0' . $dow_abr; - - // set the day of the month - (negative) - $total_days = $date_time->format('t') - $date_time->format('j'); - $occur_neg = '-' . ceil(($total_days + 1)/7) . $dow_abr; - - $day_from_end_of_month = $date_time->format('t') + 1 - $_mday; - - if(in_array($occur, $this->byday) || in_array($occur_zero, $this->byday) || in_array($occur_neg, $this->byday)) - { - $tmp_array[] = clone $date_time; - } - } - - if($_pos > 0) - { - $this->suggestions[] = clone $tmp_array[$_pos - 1]; - } - else - { - $this->suggestions[] = clone $tmp_array[count($tmp_array) + $_pos]; - } - - } - } - } - } - elseif($this->gobyyearday) - { - foreach($this->byyearday as $_day) - { - if($_day >= 0) - { - $_day--; - - $_time = strtotime('+' . $_day . ' days', mktime(0, 0, 0, 1, 1, $year)); - $this->suggestions[] = new Datetime(date('Y-m-d', $_time) . ' ' . $timestamp); - } - else - { - $year_day_neg = 365 + $_day; - $leap_year = $this->try_date->format('L'); - if($leap_year == 1) - { - $year_day_neg = 366 + $_day; - } - - $_time = strtotime('+' . $year_day_neg . ' days', mktime(0, 0, 0, 1, 1, $year)); - $this->suggestions[] = new Datetime(date('Y-m-d', $_time) . ' ' . $timestamp); - } - } - } - // special case because for years you need to loop through the months too - elseif($this->gobyday && $interval == "year") - { - foreach($this->bymonth as $_month) - { - // this creates an array of days of the month - $_mdays = range(1, date('t',mktime(0,0,0,$_month,1,$year))); - foreach($_mdays as $_mday) - { - $date_time = new DateTime($year . '-' . $_month . '-' . $_mday . ' ' . $timestamp); - - // get the week of the month (1, 2, 3, 4, 5, etc) - $week = $date_time->format('W'); - - if($date_time >= $this->start_date && in_array($week, $this->byweekno)) - { - $this->suggestions[] = clone $date_time; - } - } - } - } - elseif($interval == "day") - { - $this->suggestions[] = clone $this->try_date; - } - elseif($interval == "week") - { - $this->suggestions[] = clone $this->try_date; - - if($this->gobyday) - { - $week_day = $this->try_date->format('w'); - - $days_in_month = $this->try_date->format('t'); - - $overflow_count = 1; - $_day = $month_day; - - $run = true; - while($run) - { - $_day++; - if($_day <= $days_in_month) - { - $tmp_date = new DateTime($year . '-' . $month . '-' . $_day . ' ' . $timestamp); - } - else - { - //$tmp_month = $month+1; - $tmp_date = new DateTime($year . '-' . $month . '-' . $overflow_count . ' ' . $timestamp); - $tmp_date->modify('+1 month'); - $overflow_count++; - } - - $week_day = $tmp_date->format('w'); - - if($this->try_date == $this->start_date) - { - if($week_day == $this->wkst) - { - $this->try_date = clone $tmp_date; - $this->try_date->modify('-7 days'); - $run = false; - } - } - - if($week_day != $this->wkst) - { - $this->suggestions[] = clone $tmp_date; - } - else - { - $run = false; - } - } - } - } - elseif($this->gobyday && $interval == "month") - { - $_mdays = range(1, date('t',mktime(0,0,0,$month,1,$year))); - foreach($_mdays as $_mday) - { - $date_time = new DateTime($year . '-' . $month . '-' . $_mday . ' ' . $timestamp); - - // get the week of the month (1, 2, 3, 4, 5, etc) - $week = $date_time->format('W'); - - if($date_time >= $this->start_date && in_array($week, $this->byweekno)) - { - $this->suggestions[] = clone $date_time; - } - } - } - elseif($this->gobymonth) - { - foreach($this->bymonth as $_month) - { - $date_time = new DateTime($year . '-' . $_month . '-' . $month_day . ' ' . $timestamp); - - if($date_time >= $this->start_date) - { - $this->suggestions[] = clone $date_time; - } - } - } - else - { - $this->suggestions[] = clone $this->try_date; - } - - if($interval == "month") - { - - $this->try_date->modify('first day of next month'); - if((int) date('t', $this->try_date->format('U')) > (int) $this->start_date->format('j')){ - $this->try_date->modify('+' . (int) $this->start_date->format('j') - 1 . ' day'); - }else{ - $this->try_date->modify('+' . (int) date('t', $this->try_date->format('U')) - 1 . ' day'); - } - } - else - { - $this->try_date->modify($this->interval . ' ' . $interval); - } - } - - protected function valid_date($date) - { - $year = $date->format('Y'); - $month = $date->format('n'); - $day = $date->format('j'); - - $year_day = $date->format('z') + 1; - - $year_day_neg = -366 + $year_day; - $leap_year = $date->format('L'); - if($leap_year == 1) - { - $year_day_neg = -367 + $year_day; - } - - // this is the nth occurence of the date - $occur = ceil($day / 7); - - $week = $date->format('W'); - - $day_of_week = $date->format('l'); - $dow_abr = strtoupper(substr($day_of_week, 0, 2)); - - // set the day of the month + (positive) - $occur = '+' . $occur . $dow_abr; - $occur_zero = '+0' . $dow_abr; - - // set the day of the month - (negative) - $total_days = $date->format('t') - $date->format('j'); - $occur_neg = '-' . ceil(($total_days + 1)/7) . $dow_abr; - - $day_from_end_of_month = $date->format('t') + 1 - $day; - - if(in_array($month, $this->bymonth) && - (in_array($occur, $this->byday) || in_array($occur_zero, $this->byday) || in_array($occur_neg, $this->byday)) && - in_array($week, $this->byweekno) && - (in_array($day, $this->bymonthday) || in_array(-$day_from_end_of_month, $this->bymonthday)) && - (in_array($year_day, $this->byyearday) || in_array($year_day_neg, $this->byyearday))) - { - return true; - } - else - { - return false; - } - } - - // return the next valid DateTime object which matches the pattern and follows the rules - public function next() - { - // check the counter is set - if($this->count !== 0) - { - if($this->counter >= $this->count) - { - return false; - } - } - - // create initial set of suggested dates - if(count($this->suggestions) === 0) - { - $this->create_suggestions(); - } - - // loop through the suggested dates - while(count($this->suggestions) > 0) - { - // get the first one on the array - $try_date = array_shift($this->suggestions); - - // make sure the date doesn't exceed the max date - if($try_date > $this->end_date) - { - return false; - } - - // make sure it falls within the allowed days - if($this->valid_date($try_date) === true) - { - $this->counter++; - return $try_date; - } - else - { - // we might be out of suggested days, so load some more - if(count($this->suggestions) === 0) - { - $this->create_suggestions(); - } - } - } - } -}
\ No newline at end of file diff --git a/apps/admin_audit/appinfo/app.php b/apps/admin_audit/appinfo/app.php new file mode 100644 index 00000000000..e52f633cf14 --- /dev/null +++ b/apps/admin_audit/appinfo/app.php @@ -0,0 +1,18 @@ +<?php + +OC::$CLASSPATH['OC_Admin_Audit_Hooks_Handlers'] = 'apps/admin_audit/lib/hooks_handlers.php'; + +OCP\Util::connectHook('OCP\User', 'pre_login', 'OC_Admin_Audit_Hooks_Handlers', 'pre_login'); +OCP\Util::connectHook('OCP\User', 'post_login', 'OC_Admin_Audit_Hooks_Handlers', 'post_login'); +OCP\Util::connectHook('OCP\User', 'logout', 'OC_Admin_Audit_Hooks_Handlers', 'logout'); + +OCP\Util::connectHook(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_rename, 'OC_Admin_Audit_Hooks_Handlers', 'rename'); +OCP\Util::connectHook(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_create, 'OC_Admin_Audit_Hooks_Handlers', 'create'); +OCP\Util::connectHook(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_copy, 'OC_Admin_Audit_Hooks_Handlers', 'copy'); +OCP\Util::connectHook(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_write, 'OC_Admin_Audit_Hooks_Handlers', 'write'); +OCP\Util::connectHook(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_read, 'OC_Admin_Audit_Hooks_Handlers', 'read'); +OCP\Util::connectHook(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_delete, 'OC_Admin_Audit_Hooks_Handlers', 'delete'); + +OCP\Util::connectHook('OC_Share', 'public', 'OC_Admin_Audit_Hooks_Handlers', 'share_public'); +OCP\Util::connectHook('OC_Share', 'public-download', 'OC_Admin_Audit_Hooks_Handlers', 'share_public_download'); +OCP\Util::connectHook('OC_Share', 'user', 'OC_Admin_Audit_Hooks_Handlers', 'share_user'); diff --git a/apps/admin_audit/appinfo/info.xml b/apps/admin_audit/appinfo/info.xml new file mode 100644 index 00000000000..6eb62fbbd16 --- /dev/null +++ b/apps/admin_audit/appinfo/info.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<info> + <id>admin_audit</id> + <name>Log audit info</name> + <version>0.1</version> + <licence>AGPL</licence> + <author>Bart Visscher</author> + <require>2</require> + <description>Audit user actions in Owncloud</description> +</info> diff --git a/apps/admin_audit/lib/hooks_handlers.php b/apps/admin_audit/lib/hooks_handlers.php new file mode 100644 index 00000000000..c5aec97d939 --- /dev/null +++ b/apps/admin_audit/lib/hooks_handlers.php @@ -0,0 +1,72 @@ +<?php + +class OC_Admin_Audit_Hooks_Handlers { + static public function pre_login($params) { + $path = $params['uid']; + self::log('Trying login '.$user); + } + static public function post_login($params) { + $path = $params['uid']; + self::log('Login '.$user); + } + static public function logout($params) { + $user = OCP\User::getUser(); + self::log('Logout '.$user); + } + + static public function rename($params) { + $oldpath = $params[OC_Filesystem::signal_param_oldpath]; + $newpath = $params[OC_Filesystem::signal_param_newpath]; + $user = OCP\User::getUser(); + self::log('Rename "'.$oldpath.'" to "'.$newpath.'" by '.$user); + } + static public function create($params) { + $path = $params[OC_Filesystem::signal_param_path]; + $user = OCP\User::getUser(); + self::log('Create "'.$path.'" by '.$user); + } + static public function copy($params) { + $oldpath = $params[OC_Filesystem::signal_param_oldpath]; + $newpath = $params[OC_Filesystem::signal_param_newpath]; + $user = OCP\User::getUser(); + self::log('Copy "'.$oldpath.'" to "'.$newpath.'" by '.$user); + } + static public function write($params) { + $path = $params[OC_Filesystem::signal_param_path]; + $user = OCP\User::getUser(); + self::log('Write "'.$path.'" by '.$user); + } + static public function read($params) { + $path = $params[OC_Filesystem::signal_param_path]; + $user = OCP\User::getUser(); + self::log('Read "'.$path.'" by '.$user); + } + static public function delete($params) { + $path = $params[OC_Filesystem::signal_param_path]; + $user = OCP\User::getUser(); + self::log('Delete "'.$path.'" by '.$user); + } + static public function share_public($params) { + $path = $params['source']; + $token = $params['token']; + $user = OCP\User::getUser(); + self::log('Shared "'.$path.'" with public, token="'.$token.'" by '.$user); + } + static public function share_public_download($params) { + $path = $params['source']; + $token = $params['token']; + $user = $_SERVER['REMOTE_ADDR']; + self::log('Download of shared "'.$path.'" token="'.$token.'" by '.$user); + } + static public function share_user($params) { + $path = $params['source']; + $permissions = $params['permissions']; + $with = $params['with']; + $user = OCP\User::getUser(); + $rw = $permissions & OC_Share::WRITE ? 'w' : 'o'; + self::log('Shared "'.$path.'" (r'.$rw.') with user "'.$with.'" by '.$user); + } + static protected function log($msg) { + OCP\Util::writeLog('admin_audit', $msg, OCP\Util::INFO); + } +} diff --git a/apps/bookmarks/addBm.php b/apps/bookmarks/addBm.php index 866fa1e7b1e..4df93c8b05f 100644 --- a/apps/bookmarks/addBm.php +++ b/apps/bookmarks/addBm.php @@ -5,20 +5,20 @@ * * @author Arthur Schiwon * @copyright 2011 Arthur Schiwon blizzz@arthur-schiwon.de -* +* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE -* License as published by the Free Software Foundation; either +* License as published by the Free Software Foundation; either * version 3 of the License, or any later version. -* +* * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU AFFERO GENERAL PUBLIC LICENSE for more details. -* -* You should have received a copy of the GNU Lesser General Public +* +* You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <http://www.gnu.org/licenses/>. -* +* */ @@ -28,6 +28,6 @@ OCP\User::checkLoggedIn(); OCP\App::checkAppEnabled('bookmarks'); require_once('bookmarksHelper.php'); -addBookmark($_POST['url'], '', 'Read-Later'); +addBookmark($_GET['url'], '', 'Read-Later'); include 'templates/addBm.php'; diff --git a/apps/bookmarks/ajax/editBookmark.php b/apps/bookmarks/ajax/editBookmark.php index fcec2e1cedb..439b680dc20 100644 --- a/apps/bookmarks/ajax/editBookmark.php +++ b/apps/bookmarks/ajax/editBookmark.php @@ -40,18 +40,26 @@ if( $CONFIG_DBTYPE == 'sqlite' or $CONFIG_DBTYPE == 'sqlite3' ){ } $bookmark_id = (int)$_POST["id"]; +$user_id = OCP\USER::getUser(); $query = OCP\DB::prepare(" UPDATE *PREFIX*bookmarks SET url = ?, title =?, lastmodified = $_ut - WHERE id = $bookmark_id + WHERE id = ? + AND user_id = ? "); $params=array( htmlspecialchars_decode($_POST["url"]), htmlspecialchars_decode($_POST["title"]), + $bookmark_id, + $user_id, ); -$query->execute($params); + +$result = $query->execute($params); + +# Abort the operation if bookmark couldn't be set (probably because the user is not allowed to edit this bookmark) +if ($result->numRows() == 0) exit(); # Remove old tags and insert new ones. $query = OCP\DB::prepare(" @@ -66,7 +74,7 @@ $query = OCP\DB::prepare(" (bookmark_id, tag) VALUES (?, ?) "); - + $tags = explode(' ', urldecode($_POST["tags"])); foreach ($tags as $tag) { if(empty($tag)) { diff --git a/apps/bookmarks/css/bookmarks.css b/apps/bookmarks/css/bookmarks.css index 3a3e0fbf6b3..a67afcd44fa 100644 --- a/apps/bookmarks/css/bookmarks.css +++ b/apps/bookmarks/css/bookmarks.css @@ -1,5 +1,5 @@ #content { overflow: auto; height: 100%; } -#firstrun { width: 80%; margin: 5em auto auto auto; text-align: center; font-weight:bold; font-size:1.5em; color:#777;} +#firstrun { width: 80%; margin: 5em auto auto auto; text-align: center; font-weight:bold; font-size:1.5em; color:#777; position: relative;} #firstrun small { display: block; font-weight: normal; font-size: 0.5em; margin-bottom: 1.5em; } #firstrun .button { font-size: 0.7em; } #firstrun #selections { font-size:0.8em; font-weight: normal; width: 100%; margin: 2em auto auto auto; clear: both; } diff --git a/apps/bookmarks/templates/list.php b/apps/bookmarks/templates/list.php index 84436ae7409..4b84b438900 100644 --- a/apps/bookmarks/templates/list.php +++ b/apps/bookmarks/templates/list.php @@ -7,7 +7,7 @@ * See the COPYING-README file. */ ?> -<input type="hidden" id="bookmarkFilterTag" value="<?php if(isset($_GET['tag'])) echo htmlentities($_GET['tag'],ENT_COMPAT,'utf-8'); ?>" /> +<input type="hidden" id="bookmarkFilterTag" value="<?php if(isset($_GET['tag'])) echo OCP\Util::sanitizeHTML($_GET['tag']); ?>" /> <div id="controls"> <input type="hidden" id="bookmark_add_id" value="0" /> <input type="text" id="bookmark_add_url" placeholder="<?php echo $l->t('Address'); ?>" class="bookmarks_input" /> diff --git a/apps/calendar/ajax/cache/rescan.php b/apps/calendar/ajax/cache/rescan.php new file mode 100644 index 00000000000..3417f1ae4b4 --- /dev/null +++ b/apps/calendar/ajax/cache/rescan.php @@ -0,0 +1,15 @@ +<?php +/** + * Copyright (c) 2012 Georg Ehrke <georg@ownCloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +OCP\JSON::checkLoggedIn(); +OCP\JSON::checkAppEnabled('calendar'); +$calendars = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser()); +foreach($calendars as $calendar){ + OC_Calendar_Repeat::cleancalendar($calendar['id']); + OC_Calendar_Repeat::generatecalendar($calendar['id']); +} +OCP\JSON::success();
\ No newline at end of file diff --git a/apps/calendar/ajax/cache/status.php b/apps/calendar/ajax/cache/status.php new file mode 100644 index 00000000000..d2806d47895 --- /dev/null +++ b/apps/calendar/ajax/cache/status.php @@ -0,0 +1,22 @@ +<?php +/** + * Copyright (c) 2012 Georg Ehrke <georg@ownCloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +OCP\JSON::checkLoggedIn(); +OCP\JSON::checkAppEnabled('calendar'); +$calendars = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser()); +$allcached = true; +foreach($calendars as $calendar){ + if(!OC_Calendar_Repeat::is_calendar_cached($calendar['id'])){ + $allcached = false; + } +} +$l = new OC_L10N('calendar'); +if(!$allcached){ + OCP\JSON::error(array('message'=>'Not all calendars are completely cached', 'l10n'=>$l->t('Not all calendars are completely cached'))); +}else{ + OCP\JSON::success(array('message'=>'Everything seems to be completely cached', 'l10n'=>$l->t('Everything seems to be completely cached'))); +}
\ No newline at end of file diff --git a/apps/calendar/ajax/calendar/activation.php b/apps/calendar/ajax/calendar/activation.php index 380db6a9437..e31908beb14 100644 --- a/apps/calendar/ajax/calendar/activation.php +++ b/apps/calendar/ajax/calendar/activation.php @@ -20,4 +20,4 @@ $calendar = OC_Calendar_App::getCalendar($calendarid); OCP\JSON::success(array( 'active' => $calendar['active'], 'eventSource' => OC_Calendar_Calendar::getEventSourceInfo($calendar), -)); +));
\ No newline at end of file diff --git a/apps/calendar/ajax/calendar/delete.php b/apps/calendar/ajax/calendar/delete.php index 9e092f2df1d..4d6706f6002 100644 --- a/apps/calendar/ajax/calendar/delete.php +++ b/apps/calendar/ajax/calendar/delete.php @@ -21,5 +21,4 @@ if($del == true){ OCP\JSON::success(); }else{ OCP\JSON::error(array('error'=>'dberror')); -} -?> +}
\ No newline at end of file diff --git a/apps/calendar/ajax/calendar/edit.form.php b/apps/calendar/ajax/calendar/edit.form.php index 036ed12bb74..3916c527637 100644 --- a/apps/calendar/ajax/calendar/edit.form.php +++ b/apps/calendar/ajax/calendar/edit.form.php @@ -16,5 +16,4 @@ $tmpl = new OCP\Template("calendar", "part.editcalendar"); $tmpl->assign('new', false); $tmpl->assign('calendarcolor_options', $calendarcolor_options); $tmpl->assign('calendar', $calendar); -$tmpl->printPage(); -?> +$tmpl->printPage();
\ No newline at end of file diff --git a/apps/calendar/ajax/calendar/edit.php b/apps/calendar/ajax/calendar/edit.php index 516c9f6c765..82f18fe7f44 100644 --- a/apps/calendar/ajax/calendar/edit.php +++ b/apps/calendar/ajax/calendar/edit.php @@ -20,5 +20,4 @@ $tmpl = new OCP\Template("calendar", "part.editcalendar"); $tmpl->assign('new', false); $tmpl->assign('calendarcolor_options', $calendarcolor_options); $tmpl->assign('calendar', $calendar); -$tmpl->printPage(); -?> +$tmpl->printPage();
\ No newline at end of file diff --git a/apps/calendar/ajax/calendar/new.form.php b/apps/calendar/ajax/calendar/new.form.php index ee46757f56b..0783b6168f8 100644 --- a/apps/calendar/ajax/calendar/new.form.php +++ b/apps/calendar/ajax/calendar/new.form.php @@ -19,5 +19,4 @@ $tmpl = new OCP\Template('calendar', 'part.editcalendar'); $tmpl->assign('new', true); $tmpl->assign('calendarcolor_options', $calendarcolor_options); $tmpl->assign('calendar', $calendar); -$tmpl->printPage(); -?> +$tmpl->printPage();
\ No newline at end of file diff --git a/apps/calendar/ajax/calendar/new.php b/apps/calendar/ajax/calendar/new.php index 76dbef6b9df..278c8e5520b 100644 --- a/apps/calendar/ajax/calendar/new.php +++ b/apps/calendar/ajax/calendar/new.php @@ -34,4 +34,4 @@ $tmpl->assign('calendar', $calendar); OCP\JSON::success(array( 'page' => $tmpl->fetchPage(), 'eventSource' => OC_Calendar_Calendar::getEventSourceInfo($calendar), -)); +));
\ No newline at end of file diff --git a/apps/calendar/ajax/calendar/overview.php b/apps/calendar/ajax/calendar/overview.php index 96312537507..9d43364ffbf 100644 --- a/apps/calendar/ajax/calendar/overview.php +++ b/apps/calendar/ajax/calendar/overview.php @@ -11,5 +11,4 @@ $l10n = OC_L10N::get('calendar'); OCP\JSON::checkLoggedIn(); OCP\JSON::checkAppEnabled('calendar'); $output = new OCP\Template("calendar", "part.choosecalendar"); -$output -> printpage(); -?> +$output -> printpage();
\ No newline at end of file diff --git a/apps/calendar/ajax/calendar/update.php b/apps/calendar/ajax/calendar/update.php index dce0027304a..5cf63d396f7 100644 --- a/apps/calendar/ajax/calendar/update.php +++ b/apps/calendar/ajax/calendar/update.php @@ -39,4 +39,4 @@ $tmpl->assign('calendar', $calendar); OCP\JSON::success(array( 'page' => $tmpl->fetchPage(), 'eventSource' => OC_Calendar_Calendar::getEventSourceInfo($calendar), -)); +));
\ No newline at end of file diff --git a/apps/calendar/ajax/categories/rescan.php b/apps/calendar/ajax/categories/rescan.php index 93e8c50954a..f0060cb23b2 100644 --- a/apps/calendar/ajax/categories/rescan.php +++ b/apps/calendar/ajax/categories/rescan.php @@ -39,4 +39,4 @@ if(count($events) == 0) { OC_Calendar_App::scanCategories($events); $categories = OC_Calendar_App::getCategoryOptions(); -OCP\JSON::success(array('data' => array('categories'=>$categories))); +OCP\JSON::success(array('data' => array('categories'=>$categories)));
\ No newline at end of file diff --git a/apps/calendar/ajax/changeview.php b/apps/calendar/ajax/changeview.php index 0099fd5ec21..47e690f3293 100644 --- a/apps/calendar/ajax/changeview.php +++ b/apps/calendar/ajax/changeview.php @@ -18,5 +18,4 @@ switch($view){ exit; } OCP\Config::setUserValue(OCP\USER::getUser(), 'calendar', 'currentview', $view); -OCP\JSON::success(); -?> +OCP\JSON::success();
\ No newline at end of file diff --git a/apps/calendar/ajax/event/delete.php b/apps/calendar/ajax/event/delete.php index cb30621af4d..f183d431afa 100644 --- a/apps/calendar/ajax/event/delete.php +++ b/apps/calendar/ajax/event/delete.php @@ -17,4 +17,4 @@ if($access != 'owner' && $access != 'rw'){ exit; } $result = OC_Calendar_Object::delete($id); -OCP\JSON::success(); +OCP\JSON::success();
\ No newline at end of file diff --git a/apps/calendar/ajax/event/edit.form.php b/apps/calendar/ajax/event/edit.form.php index dbb78edb798..26a0cc2a60a 100644 --- a/apps/calendar/ajax/event/edit.form.php +++ b/apps/calendar/ajax/event/edit.form.php @@ -27,6 +27,14 @@ $vevent = $object->VEVENT; $dtstart = $vevent->DTSTART; $dtend = OC_Calendar_Object::getDTEndFromVEvent($vevent); switch($dtstart->getDateType()) { + case Sabre_VObject_Property_DateTime::UTC: + $timeOffset = OC_Calendar_App::$tz*60; + $newDT = $dtstart->getDateTime(); + $newDT->add(new DateInterval("PT" . $timeOffset . "M")); + $dtstart->setDateTime($newDT); + $newDT = $dtend->getDateTime(); + $newDT->add(new DateInterval("PT" . $timeOffset . "M")); + $dtend->setDateTime($newDT); case Sabre_VObject_Property_DateTime::LOCALTZ: case Sabre_VObject_Property_DateTime::LOCAL: $startdate = $dtstart->getDateTime()->format('d-m-Y'); @@ -261,4 +269,4 @@ if($repeat['repeat'] != 'doesnotrepeat'){ $tmpl->assign('repeat_date', ''); $tmpl->assign('repeat_year', 'bydate'); } -$tmpl->printpage(); +$tmpl->printpage();
\ No newline at end of file diff --git a/apps/calendar/ajax/event/edit.php b/apps/calendar/ajax/event/edit.php index e615fb093de..1c3babc3d90 100644 --- a/apps/calendar/ajax/event/edit.php +++ b/apps/calendar/ajax/event/edit.php @@ -42,5 +42,4 @@ if($errarr){ OC_Calendar_Object::moveToCalendar($id, $cal); } OCP\JSON::success(); -} -?> +}
\ No newline at end of file diff --git a/apps/calendar/ajax/event/move.php b/apps/calendar/ajax/event/move.php index 8added69143..04cf2fb0513 100644 --- a/apps/calendar/ajax/event/move.php +++ b/apps/calendar/ajax/event/move.php @@ -43,4 +43,4 @@ $vevent->setDateTime('DTSTAMP', 'now', Sabre_VObject_Property_DateTime::UTC); $result = OC_Calendar_Object::edit($id, $vcalendar->serialize()); $lastmodified = $vevent->__get('LAST-MODIFIED')->getDateTime(); -OCP\JSON::success(array('lastmodified'=>(int)$lastmodified->format('U'))); +OCP\JSON::success(array('lastmodified'=>(int)$lastmodified->format('U')));
\ No newline at end of file diff --git a/apps/calendar/ajax/event/new.form.php b/apps/calendar/ajax/event/new.form.php index 91b85fff07f..0b19e7e92f9 100644 --- a/apps/calendar/ajax/event/new.form.php +++ b/apps/calendar/ajax/event/new.form.php @@ -72,4 +72,4 @@ $tmpl->assign('repeat_count', '10'); $tmpl->assign('repeat_weekofmonth', 'auto'); $tmpl->assign('repeat_date', ''); $tmpl->assign('repeat_year', 'bydate'); -$tmpl->printpage(); +$tmpl->printpage();
\ No newline at end of file diff --git a/apps/calendar/ajax/event/new.php b/apps/calendar/ajax/event/new.php index 72d57be03bf..30e2b0cae36 100644 --- a/apps/calendar/ajax/event/new.php +++ b/apps/calendar/ajax/event/new.php @@ -21,5 +21,4 @@ if($errarr){ $vcalendar = OC_Calendar_Object::createVCalendarFromRequest($_POST); $result = OC_Calendar_Object::add($cal, $vcalendar->serialize()); OCP\JSON::success(); -} -?> +}
\ No newline at end of file diff --git a/apps/calendar/ajax/event/resize.php b/apps/calendar/ajax/event/resize.php index 0dc0a5fca7f..56b83205e85 100644 --- a/apps/calendar/ajax/event/resize.php +++ b/apps/calendar/ajax/event/resize.php @@ -35,4 +35,4 @@ $vevent->setDateTime('DTSTAMP', 'now', Sabre_VObject_Property_DateTime::UTC); OC_Calendar_Object::edit($id, $vcalendar->serialize()); $lastmodified = $vevent->__get('LAST-MODIFIED')->getDateTime(); -OCP\JSON::success(array('lastmodified'=>(int)$lastmodified->format('U'))); +OCP\JSON::success(array('lastmodified'=>(int)$lastmodified->format('U')));
\ No newline at end of file diff --git a/apps/calendar/ajax/events.php b/apps/calendar/ajax/events.php index b0c5587633f..ae55cbc02db 100644 --- a/apps/calendar/ajax/events.php +++ b/apps/calendar/ajax/events.php @@ -5,30 +5,26 @@ * later. * See the COPYING-README file. */ - - -require_once('when/When.php'); - OCP\JSON::checkLoggedIn(); OCP\JSON::checkAppEnabled('calendar'); +session_write_close(); // Look for the calendar id -$calendar_id = OC_Calendar_App::getCalendar($_GET['calendar_id'], false, false); -if($calendar_id !== false){ - if(! is_numeric($calendar_id['userid']) && $calendar_id['userid'] != OCP\User::getUser()){ - OCP\JSON::error(); - exit; +$calendar_id = null; +if (strval(intval($_GET['calendar_id'])) == strval($_GET['calendar_id'])) { // integer for sure. + $id = intval($_GET['calendar_id']); + $calendarrow = OC_Calendar_App::getCalendar($id, true, false); // Let's at least security check otherwise we might as well use OC_Calendar_Calendar::find() + if($calendarrow !== false && is_int($calendar_id['userid']) && $id == $calendar_id['userid']) { + $calendar_id = $id; } } -else { - $calendar_id = $_GET['calendar_id']; -} +$calendar_id = (is_null($calendar_id)?strip_tags($_GET['calendar_id']):$calendar_id); $start = (version_compare(PHP_VERSION, '5.3.0', '>='))?DateTime::createFromFormat('U', $_GET['start']):new DateTime('@' . $_GET['start']); $end = (version_compare(PHP_VERSION, '5.3.0', '>='))?DateTime::createFromFormat('U', $_GET['end']):new DateTime('@' . $_GET['end']); -$events = OC_Calendar_App::getrequestedEvents($calendar_id, $start, $end); +$events = OC_Calendar_App::getrequestedEvents($_GET['calendar_id'], $start, $end); $output = array(); foreach($events as $event){ $output = array_merge($output, OC_Calendar_App::generateEventOutput($event, $start, $end)); } -OCP\JSON::encodedPrint($output); +OCP\JSON::encodedPrint(OCP\Util::sanitizeHTML($output)); diff --git a/apps/calendar/ajax/import/dialog.php b/apps/calendar/ajax/import/dialog.php index 3be02d2a6db..b99c32278c4 100644 --- a/apps/calendar/ajax/import/dialog.php +++ b/apps/calendar/ajax/import/dialog.php @@ -12,5 +12,4 @@ OCP\App::checkAppEnabled('calendar'); $tmpl = new OCP\Template('calendar', 'part.import'); $tmpl->assign('path', $_POST['path']); $tmpl->assign('filename', $_POST['filename']); -$tmpl->printpage(); -?> +$tmpl->printpage();
\ No newline at end of file diff --git a/apps/calendar/ajax/import/dropimport.php b/apps/calendar/ajax/import/dropimport.php index e98c282ef41..87667d4de68 100644 --- a/apps/calendar/ajax/import/dropimport.php +++ b/apps/calendar/ajax/import/dropimport.php @@ -45,7 +45,7 @@ foreach($lines as $line) { } $i++; } -$calendars = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser(), 1); +$calendars = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser(), true); $id = $calendars[0]['id']; foreach($uids as $uid) { $prefix=$suffix=$content=array(); @@ -70,5 +70,4 @@ foreach($uids as $uid) { OC_Calendar_Object::add($id, $import); } } -OCP\JSON::success(); -?>
\ No newline at end of file +OCP\JSON::success();
\ No newline at end of file diff --git a/apps/calendar/ajax/import/import.php b/apps/calendar/ajax/import/import.php index 6fdad12c085..1facedfe0da 100644 --- a/apps/calendar/ajax/import/import.php +++ b/apps/calendar/ajax/import/import.php @@ -119,4 +119,4 @@ foreach($uids as $uid) { writeProgress('100'); sleep(3); OC_Cache::remove($progresskey); -OCP\JSON::success(); +OCP\JSON::success();
\ No newline at end of file diff --git a/apps/calendar/ajax/settings/getfirstday.php b/apps/calendar/ajax/settings/getfirstday.php index 23b71bba043..bc995f7d6e8 100644 --- a/apps/calendar/ajax/settings/getfirstday.php +++ b/apps/calendar/ajax/settings/getfirstday.php @@ -8,5 +8,4 @@ OCP\JSON::checkLoggedIn(); $firstday = OCP\Config::getUserValue( OCP\USER::getUser(), 'calendar', 'firstday', 'mo'); -OCP\JSON::encodedPrint(array('firstday' => $firstday)); -?> +OCP\JSON::encodedPrint(array('firstday' => $firstday));
\ No newline at end of file diff --git a/apps/calendar/ajax/settings/guesstimezone.php b/apps/calendar/ajax/settings/guesstimezone.php index f36f3bf061f..6b6b8bef9c1 100644 --- a/apps/calendar/ajax/settings/guesstimezone.php +++ b/apps/calendar/ajax/settings/guesstimezone.php @@ -23,5 +23,4 @@ if($timezone == OCP\Config::getUserValue(OCP\USER::getUser(), 'calendar', 'timez } OCP\Config::setUserValue(OCP\USER::getUser(), 'calendar', 'timezone', $timezone); $message = array('message'=> $l->t('New Timezone:') . $timezone); -OCP\JSON::success($message); -?>
\ No newline at end of file +OCP\JSON::success($message);
\ No newline at end of file diff --git a/apps/calendar/ajax/settings/setfirstday.php b/apps/calendar/ajax/settings/setfirstday.php index 373eeee7968..056a6037524 100644 --- a/apps/calendar/ajax/settings/setfirstday.php +++ b/apps/calendar/ajax/settings/setfirstday.php @@ -12,6 +12,4 @@ if(isset($_POST["firstday"])){ OCP\JSON::success(); }else{ OCP\JSON::error(); -} -?> - +}
\ No newline at end of file diff --git a/apps/calendar/ajax/settings/settimeformat.php b/apps/calendar/ajax/settings/settimeformat.php index eae7be54e80..8e95f6f3bf5 100644 --- a/apps/calendar/ajax/settings/settimeformat.php +++ b/apps/calendar/ajax/settings/settimeformat.php @@ -12,6 +12,4 @@ if(isset($_POST["timeformat"])){ OCP\JSON::success(); }else{ OCP\JSON::error(); -} -?> - +}
\ No newline at end of file diff --git a/apps/calendar/ajax/settings/settimezone.php b/apps/calendar/ajax/settings/settimezone.php index d2797a08aae..6d029a6643a 100644 --- a/apps/calendar/ajax/settings/settimezone.php +++ b/apps/calendar/ajax/settings/settimezone.php @@ -22,6 +22,4 @@ if( isset( $_POST['timezone'] ) ){ OCP\JSON::success(array('data' => array( 'message' => $l->t('Timezone changed') ))); }else{ OCP\JSON::error(array('data' => array( 'message' => $l->t('Invalid request') ))); -} - -?> +}
\ No newline at end of file diff --git a/apps/calendar/ajax/settings/timeformat.php b/apps/calendar/ajax/settings/timeformat.php index 809164e870a..eebb687dfac 100644 --- a/apps/calendar/ajax/settings/timeformat.php +++ b/apps/calendar/ajax/settings/timeformat.php @@ -8,5 +8,4 @@ OCP\JSON::checkLoggedIn(); $timeformat = OCP\Config::getUserValue( OCP\USER::getUser(), 'calendar', 'timeformat', "24"); -OCP\JSON::encodedPrint(array("timeformat" => $timeformat)); -?> +OCP\JSON::encodedPrint(array("timeformat" => $timeformat));
\ No newline at end of file diff --git a/apps/calendar/appinfo/app.php b/apps/calendar/appinfo/app.php index 886c218f7c1..f1f2a26d87d 100644 --- a/apps/calendar/appinfo/app.php +++ b/apps/calendar/appinfo/app.php @@ -5,9 +5,15 @@ OC::$CLASSPATH['OC_Calendar_Calendar'] = 'apps/calendar/lib/calendar.php'; OC::$CLASSPATH['OC_Calendar_Object'] = 'apps/calendar/lib/object.php'; OC::$CLASSPATH['OC_Calendar_Hooks'] = 'apps/calendar/lib/hooks.php'; OC::$CLASSPATH['OC_Connector_Sabre_CalDAV'] = 'apps/calendar/lib/connector_sabre.php'; +OC::$CLASSPATH['OC_Calendar_Repeat'] = 'apps/calendar/lib/repeat.php'; OC::$CLASSPATH['OC_Calendar_Share'] = 'apps/calendar/lib/share.php'; OC::$CLASSPATH['OC_Search_Provider_Calendar'] = 'apps/calendar/lib/search.php'; OCP\Util::connectHook('OC_User', 'post_deleteUser', 'OC_Calendar_Hooks', 'deleteUser'); +OCP\Util::connectHook('OC_Calendar', 'addEvent', 'OC_Calendar_Repeat', 'generate'); +OCP\Util::connectHook('OC_Calendar', 'editEvent', 'OC_Calendar_Repeat', 'update'); +OCP\Util::connectHook('OC_Calendar', 'deleteEvent', 'OC_Calendar_Repeat', 'clean'); +OCP\Util::connectHook('OC_Calendar', 'moveEvent', 'OC_Calendar_Repeat', 'update'); +OCP\Util::connectHook('OC_Calendar', 'deleteCalendar', 'OC_Calendar_Repeat', 'cleanCalendar'); OCP\Util::addscript('calendar','loader'); OCP\Util::addscript("3rdparty", "chosen/chosen.jquery.min"); OCP\Util::addStyle("3rdparty", "chosen/chosen"); diff --git a/apps/calendar/appinfo/database.xml b/apps/calendar/appinfo/database.xml index 5a3ad32dc24..73457e6c6cc 100644 --- a/apps/calendar/appinfo/database.xml +++ b/apps/calendar/appinfo/database.xml @@ -290,4 +290,56 @@ </table> + <table> + + <name>*dbprefix*calendar_repeat</name> + + <declaration> + + <field> + <name>id</name> + <type>integer</type> + <default>0</default> + <notnull>true</notnull> + <autoincrement>1</autoincrement> + <unsigned>true</unsigned> + <length>4</length> + </field> + + <field> + <name>eventid</name> + <type>integer</type> + <default>0</default> + <notnull>true</notnull> + <unsigned>true</unsigned> + <length>4</length> + </field> + + <field> + <name>calid</name> + <type>integer</type> + <default>0</default> + <notnull>true</notnull> + <unsigned>true</unsigned> + <length>4</length> + </field> + + <field> + <name>startdate</name> + <type>timestamp</type> + <default>0000-00-00 00:00:00</default> + <notnull>false</notnull> + </field> + + <field> + <name>enddate</name> + <type>timestamp</type> + <default>0000-00-00 00:00:00</default> + <notnull>false</notnull> + </field> + + </declaration> + + </table> + </database> diff --git a/apps/calendar/appinfo/update.php b/apps/calendar/appinfo/update.php index ce7f304a499..98159c33831 100644 --- a/apps/calendar/appinfo/update.php +++ b/apps/calendar/appinfo/update.php @@ -14,4 +14,11 @@ if (version_compare($installedVersion, '0.2.1', '<')) { $stmt = OCP\DB::prepare( 'UPDATE *PREFIX*calendar_calendars SET calendarcolor=? WHERE id=?' ); $r = $stmt->execute(array($color,$id)); } +} +if (version_compare($installedVersion, '0.5', '<')) { + $calendars = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser()); + foreach($calendars as $calendar){ + OC_Calendar_Repeat::cleanCalendar($calendar['id']); + OC_Calendar_Repeat::generateCalendar($calendar['id']); + } }
\ No newline at end of file diff --git a/apps/calendar/appinfo/version b/apps/calendar/appinfo/version index 267577d47e4..2eb3c4fe4ee 100644 --- a/apps/calendar/appinfo/version +++ b/apps/calendar/appinfo/version @@ -1 +1 @@ -0.4.1 +0.5 diff --git a/apps/calendar/index.php b/apps/calendar/index.php index 05a808a5ae0..4b871195927 100644 --- a/apps/calendar/index.php +++ b/apps/calendar/index.php @@ -11,15 +11,17 @@ OCP\User::checkLoggedIn(); OCP\App::checkAppEnabled('calendar'); // Create default calendar ... -$calendars = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser(), 1); +$calendars = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser(), false); if( count($calendars) == 0){ OC_Calendar_Calendar::addCalendar(OCP\USER::getUser(),'Default calendar'); - $calendars = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser(), 1); + $calendars = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser(), true); } $eventSources = array(); foreach($calendars as $calendar){ - $eventSources[] = OC_Calendar_Calendar::getEventSourceInfo($calendar); + if($calendar['active'] == 1) { + $eventSources[] = OC_Calendar_Calendar::getEventSourceInfo($calendar); + } } $eventSources[] = array('url' => '?app=calendar&getfile=ajax/events.php?calendar_id=shared_rw', 'backgroundColor' => '#1D2D44', 'borderColor' => '#888', 'textColor' => 'white', 'editable'=>'true'); diff --git a/apps/calendar/js/calendar.js b/apps/calendar/js/calendar.js index 1cbe5c67646..3b1be59381b 100644 --- a/apps/calendar/js/calendar.js +++ b/apps/calendar/js/calendar.js @@ -430,6 +430,7 @@ Calendar={ $('#calendar_holder').fullCalendar('removeEventSource', url); $('#choosecalendar_dialog').dialog('destroy').remove(); Calendar.UI.Calendar.overview(); + $('#calendar_holder').fullCalendar('refetchEvents'); } }); } @@ -868,7 +869,7 @@ $(document).ready(function(){ eventDrop: Calendar.UI.moveEvent, eventResize: Calendar.UI.resizeEvent, eventRender: function(event, element) { - element.find('.fc-event-title').html(element.find('.fc-event-title').text()); + element.find('.fc-event-title').html(element.find('.fc-event-title').html()); element.tipsy({ className: 'tipsy-event', opacity: 0.9, diff --git a/apps/calendar/js/settings.js b/apps/calendar/js/settings.js index c768a47a797..03e4217573d 100644 --- a/apps/calendar/js/settings.js +++ b/apps/calendar/js/settings.js @@ -44,4 +44,24 @@ $(document).ready(function(){ $('#' + jsondata.firstday).attr('selected',true); $('#firstday').chosen(); }); + $('#cleancalendarcache').click(function(){ + $.getJSON(OC.filePath('calendar', 'ajax/cache', 'rescan.php'), function(){ + calendarcachecheck(); + }); + }); + calendarcachecheck(); }); +function calendarcachecheck(){ + $.getJSON(OC.filePath('calendar', 'ajax/cache', 'status.php'), function(jsondata, status) { + $('#cleancalendarcache').attr('title', jsondata.l10n.text); + if(jsondata.status == 'success'){ + $('#cleancalendarcache').css('background', '#90EE90'); + $('#cleancalendarcache').css('color', '#333'); + $('#cleancalendarcache').css('text-shadow', '#fff 0 1px 0'); + }else{ + $('#cleancalendarcache').css('background', '#DC143C'); + $('#cleancalendarcache').css('color', '#FFFFFF'); + $('#cleancalendarcache').css('text-shadow', '0px 0px 0px #fff, 0px 0px #fff'); + } + }); +}
\ No newline at end of file diff --git a/apps/calendar/lib/app.php b/apps/calendar/lib/app.php index e04f2ed0cdf..8e13b13b8a3 100644 --- a/apps/calendar/lib/app.php +++ b/apps/calendar/lib/app.php @@ -50,10 +50,7 @@ class OC_Calendar_App{ return false; } } - if($calendar === false){ - return false; - } - return OC_Calendar_Calendar::find($id); + return $calendar; } /* @@ -119,8 +116,7 @@ class OC_Calendar_App{ * @brief returns the default categories of ownCloud * @return (array) $categories */ - protected static function getDefaultCategories() - { + protected static function getDefaultCategories(){ return array( self::$l10n->t('Birthday'), self::$l10n->t('Business'), @@ -155,8 +151,7 @@ class OC_Calendar_App{ * @brief returns the categories of the vcategories object * @return (array) $categories */ - public static function getCategoryOptions() - { + public static function getCategoryOptions(){ $categories = self::getVCategories()->categories(); return $categories; } @@ -343,6 +338,9 @@ class OC_Calendar_App{ $singleevents = OC_Calendar_Share::allSharedwithuser(OCP\USER::getUser(), OC_Calendar_Share::EVENT, 1, ($_GET['calendar_id'] == 'shared_rw')?'rw':'r'); foreach($singleevents as $singleevent){ $event = OC_Calendar_Object::find($singleevent['eventid']); + if(!array_key_exists('summary', $event)){ + $event['summary'] = self::$l10n->t('unnamed'); + } $event['summary'] .= ' (' . self::$l10n->t('by') . ' ' . OC_Calendar_Object::getowner($event['id']) . ')'; $events[] = $event; } @@ -362,94 +360,57 @@ class OC_Calendar_App{ /* * @brief generates the output for an event which will be readable for our js * @param (mixed) $event - event object / array - * @param (int) $start - unixtimestamp of start - * @param (int) $end - unixtimestamp of end + * @param (int) $start - DateTime object of start + * @param (int) $end - DateTime object of end * @return (array) $output - readable output */ public static function generateEventOutput($event, $start, $end){ - $output = array(); - if(isset($event['calendardata'])){ $object = OC_VObject::parse($event['calendardata']); $vevent = $object->VEVENT; }else{ $vevent = $event['vevent']; } - + $return = array(); + $id = $event['id']; + $allday = ($vevent->DTSTART->getDateType() == Sabre_VObject_Element_DateTime::DATE)?true:false; $last_modified = @$vevent->__get('LAST-MODIFIED'); $lastmodified = ($last_modified)?$last_modified->getDateTime()->format('U'):0; - - $output = array('id'=>(int)$event['id'], - 'title' => ($event['summary']!=NULL || $event['summary'] != '')?$event['summary']: self::$l10n->t('unnamed'), - 'description' => isset($vevent->DESCRIPTION)?$vevent->DESCRIPTION->value:'', - 'lastmodified'=>$lastmodified); - - $dtstart = $vevent->DTSTART; - $start_dt = $dtstart->getDateTime(); - $dtend = OC_Calendar_Object::getDTEndFromVEvent($vevent); - $end_dt = $dtend->getDateTime(); - - if ($dtstart->getDateType() == Sabre_VObject_Element_DateTime::DATE){ - $output['allDay'] = true; - }else{ - $output['allDay'] = false; - $start_dt->setTimezone(new DateTimeZone(self::$tz)); - $end_dt->setTimezone(new DateTimeZone(self::$tz)); - } - - // Handle exceptions to recurring events - $exceptionDateObjects = $vevent->select('EXDATE'); - $exceptionDateMap = Array(); - foreach ($exceptionDateObjects as $exceptionObject) { - foreach($exceptionObject->getDateTimes() as $datetime) { - $ts = $datetime->getTimestamp(); - $exceptionDateMap[idate('Y',$ts)][idate('m', $ts)][idate('d', $ts)] = true; - } - } - - $return = array(); - if($event['repeating'] == 1){ - $duration = (double) $end_dt->format('U') - (double) $start_dt->format('U'); - $r = new When(); - $r->recur($start_dt)->rrule((string) $vevent->RRULE); - /*$r = new iCal_Repeat_Generator(array('RECUR' => $start_dt, - * 'RRULE' => (string)$vevent->RRULE - * 'RDATE' => (string)$vevent->RDATE - * 'EXRULE' => (string)$vevent->EXRULE - * 'EXDATE' => (string)$vevent->EXDATE));*/ - while($result = $r->next()){ - if($result < $start){ - continue; - } - if($result > $end){ - break; - } - // Check for exceptions to recurring events - $ts = $result->getTimestamp(); - if (isset($exceptionDateMap[idate('Y',$ts)][idate('m', $ts)][idate('d', $ts)])) { - continue; - } - unset($ts); - - if($output['allDay'] == true){ - $output['start'] = $result->format('Y-m-d'); - $output['end'] = date('Y-m-d', $result->format('U') + --$duration); + $staticoutput = array('id'=>(int)$event['id'], + 'title' => htmlspecialchars(($event['summary']!=NULL || $event['summary'] != '')?$event['summary']: self::$l10n->t('unnamed')), + 'description' => isset($vevent->DESCRIPTION)?htmlspecialchars($vevent->DESCRIPTION->value):'', + 'lastmodified'=>$lastmodified, + 'allDay'=>$allday); + if(OC_Calendar_Object::isrepeating($id) && OC_Calendar_Repeat::is_cached_inperiod($event['id'], $start, $end)){ + $cachedinperiod = OC_Calendar_Repeat::get_inperiod($id, $start, $end); + foreach($cachedinperiod as $cachedevent){ + $dynamicoutput = array(); + if($allday){ + $start_dt = new DateTime($cachedevent['startdate'], new DateTimeZone('UTC')); + $end_dt = new DateTime($cachedevent['enddate'], new DateTimeZone('UTC')); + $dynamicoutput['start'] = $start_dt->format('Y-m-d'); + $dynamicoutput['end'] = $end_dt->format('Y-m-d'); }else{ - $output['start'] = $result->format('Y-m-d H:i:s'); - $output['end'] = date('Y-m-d H:i:s', $result->format('U') + $duration); + $start_dt = new DateTime($cachedevent['startdate'], new DateTimeZone('UTC')); + $end_dt = new DateTime($cachedevent['enddate'], new DateTimeZone('UTC')); + $start_dt->setTimezone(new DateTimeZone(self::$tz)); + $end_dt->setTimezone(new DateTimeZone(self::$tz)); + $dynamicoutput['start'] = $start_dt->format('Y-m-d H:i:s'); + $dynamicoutput['end'] = $end_dt->format('Y-m-d H:i:s'); } - $return[] = $output; + $return[] = array_merge($staticoutput, $dynamicoutput); } }else{ - if($output['allDay'] == true){ - $output['start'] = $start_dt->format('Y-m-d'); - $end_dt->modify('-1 sec'); - $output['end'] = $end_dt->format('Y-m-d'); - }else{ - $output['start'] = $start_dt->format('Y-m-d H:i:s'); - $output['end'] = $end_dt->format('Y-m-d H:i:s'); + if(OC_Calendar_Object::isrepeating($id)){ + $object->expand($start, $end); + } + foreach($object->getComponents() as $singleevent){ + if(!($singleevent instanceof Sabre_VObject_Component_VEvent)){ + continue; + } + $dynamicoutput = OC_Calendar_Object::generateStartEndDate($singleevent->DTSTART, OC_Calendar_Object::getDTEndFromVEvent($singleevent), $allday, self::$tz); + $return[] = array_merge($staticoutput, $dynamicoutput); } - $return[] = $output; } return $return; } diff --git a/apps/calendar/lib/calendar.php b/apps/calendar/lib/calendar.php index 869b35e2e1b..b725898858d 100644 --- a/apps/calendar/lib/calendar.php +++ b/apps/calendar/lib/calendar.php @@ -44,13 +44,13 @@ class OC_Calendar_Calendar{ /** * @brief Returns the list of calendars for a specific user. * @param string $uid User ID - * @param boolean $active Only return calendars with this $active state, default(=null) is don't care + * @param boolean $active Only return calendars with this $active state, default(=false) is don't care * @return array */ - public static function allCalendars($uid, $active=null){ + public static function allCalendars($uid, $active=false){ $values = array($uid); $active_where = ''; - if (!is_null($active) && $active){ + if ($active){ $active_where = ' AND active = ?'; $values[] = $active; } @@ -109,7 +109,10 @@ class OC_Calendar_Calendar{ $stmt = OCP\DB::prepare( 'INSERT INTO *PREFIX*calendar_calendars (userid,displayname,uri,ctag,calendarorder,calendarcolor,timezone,components) VALUES(?,?,?,?,?,?,?,?)' ); $result = $stmt->execute(array($userid,$name,$uri,1,$order,$color,$timezone,$components)); - return OCP\DB::insertid('*PREFIX*calendar_calendars'); + $insertid = OCP\DB::insertid('*PREFIX*calendar_calendars'); + OCP\Util::emitHook('OC_Calendar', 'addCalendar', $insertid); + + return $insertid; } /** @@ -129,7 +132,10 @@ class OC_Calendar_Calendar{ $stmt = OCP\DB::prepare( 'INSERT INTO *PREFIX*calendar_calendars (userid,displayname,uri,ctag,calendarorder,calendarcolor,timezone,components) VALUES(?,?,?,?,?,?,?,?)' ); $result = $stmt->execute(array($userid,$name,$uri,1,$order,$color,$timezone,$components)); - return OCP\DB::insertid('*PREFIX*calendar_calendars'); + $insertid = OCP\DB::insertid('*PREFIX*calendar_calendars'); + OCP\Util::emitHook('OC_Calendar', 'addCalendar', $insertid); + + return $insertid; } /** @@ -158,6 +164,7 @@ class OC_Calendar_Calendar{ $stmt = OCP\DB::prepare( 'UPDATE *PREFIX*calendar_calendars SET displayname=?,calendarorder=?,calendarcolor=?,timezone=?,components=?,ctag=ctag+1 WHERE id=?' ); $result = $stmt->execute(array($name,$order,$color,$timezone,$components,$id)); + OCP\Util::emitHook('OC_Calendar', 'editCalendar', $id); return true; } @@ -198,6 +205,11 @@ class OC_Calendar_Calendar{ $stmt = OCP\DB::prepare( 'DELETE FROM *PREFIX*calendar_objects WHERE calendarid = ?' ); $stmt->execute(array($id)); + OCP\Util::emitHook('OC_Calendar', 'deleteCalendar', $id); + if(count(self::allCalendars()) == 0) { + self::addCalendar(OCP\USER::getUser(),'Default calendar'); + } + return true; } diff --git a/apps/calendar/lib/object.php b/apps/calendar/lib/object.php index 9e4806227b0..7f3322b1ab5 100644 --- a/apps/calendar/lib/object.php +++ b/apps/calendar/lib/object.php @@ -108,7 +108,7 @@ class OC_Calendar_Object{ $object_id = OCP\DB::insertid('*PREFIX*calendar_objects'); OC_Calendar_Calendar::touchCalendar($id); - + OCP\Util::emitHook('OC_Calendar', 'addEvent', $object_id); return $object_id; } @@ -128,7 +128,7 @@ class OC_Calendar_Object{ $object_id = OCP\DB::insertid('*PREFIX*calendar_objects'); OC_Calendar_Calendar::touchCalendar($id); - + OCP\Util::emitHook('OC_Calendar', 'addEvent', $object_id); return $object_id; } @@ -149,6 +149,7 @@ class OC_Calendar_Object{ $stmt->execute(array($type,$startdate,$enddate,$repeating,$summary,$data,time(),$id)); OC_Calendar_Calendar::touchCalendar($oldobject['calendarid']); + OCP\Util::emitHook('OC_Calendar', 'editEvent', $id); return true; } @@ -170,6 +171,7 @@ class OC_Calendar_Object{ $stmt->execute(array($type,$startdate,$enddate,$repeating,$summary,$data,time(),$oldobject['id'])); OC_Calendar_Calendar::touchCalendar($oldobject['calendarid']); + OCP\Util::emitHook('OC_Calendar', 'editEvent', $oldobject['id']); return true; } @@ -184,6 +186,7 @@ class OC_Calendar_Object{ $stmt = OCP\DB::prepare( 'DELETE FROM *PREFIX*calendar_objects WHERE id = ?' ); $stmt->execute(array($id)); OC_Calendar_Calendar::touchCalendar($oldobject['calendarid']); + OCP\Util::emitHook('OC_Calendar', 'deleteEvent', $id); return true; } @@ -195,9 +198,11 @@ class OC_Calendar_Object{ * @return boolean */ public static function deleteFromDAVData($cid,$uri){ + $oldobject = self::findWhereDAVDataIs($cid, $uri); $stmt = OCP\DB::prepare( 'DELETE FROM *PREFIX*calendar_objects WHERE calendarid = ? AND uri=?' ); $stmt->execute(array($cid,$uri)); OC_Calendar_Calendar::touchCalendar($cid); + OCP\Util::emitHook('OC_Calendar', 'deleteEvent', $oldobject['id']); return true; } @@ -207,6 +212,7 @@ class OC_Calendar_Object{ $stmt->execute(array($calendarid,$id)); OC_Calendar_Calendar::touchCalendar($id); + OCP\Util::emitHook('OC_Calendar', 'moveEvent', $id); return true; } @@ -294,12 +300,11 @@ class OC_Calendar_Object{ * This function creates a date string that can be used by MDB2. * Furthermore it converts the time to UTC. */ - protected static function getUTCforMDB($datetime){ + public static function getUTCforMDB($datetime){ return date('Y-m-d H:i', $datetime->format('U') - $datetime->getOffset()); } - public static function getDTEndFromVEvent($vevent) - { + public static function getDTEndFromVEvent($vevent){ if ($vevent->DTEND) { $dtend = $vevent->DTEND; }else{ @@ -600,8 +605,8 @@ class OC_Calendar_Object{ public static function updateVCalendarFromRequest($request, $vcalendar) { - $title = strip_tags($request["title"]); - $location = strip_tags($request["location"]); + $title = $request["title"]; + $location = $request["location"]; $categories = $request["categories"]; $allday = isset($request["allday"]); $from = $request["from"]; @@ -611,7 +616,7 @@ class OC_Calendar_Object{ $totime = $request['totime']; } $vevent = $vcalendar->VEVENT; - $description = strip_tags($request["description"]); + $description = $request["description"]; $repeat = $request["repeat"]; if($repeat != 'doesnotrepeat'){ $rrule = ''; @@ -796,4 +801,29 @@ class OC_Calendar_Object{ $event = self::find($id); return $event['calendarid']; } + + public static function isrepeating($id){ + $event = self::find($id); + return ($event['repeating'] == 1)?true:false; + } + + public static function generateStartEndDate($dtstart, $dtend, $allday, $tz){ + $start_dt = $dtstart->getDateTime(); + $end_dt = $dtend->getDateTime(); + $return = array(); + if($allday){ + $return['start'] = $start_dt->format('Y-m-d'); + $end_dt->modify('-1 minute'); + while($start_dt >= $end_dt){ + $end_dt->modify('+1 day'); + } + $return['end'] = $end_dt->format('Y-m-d'); + }else{ + $start_dt->setTimezone(new DateTimeZone($tz)); + $end_dt->setTimezone(new DateTimeZone($tz)); + $return['start'] = $start_dt->format('Y-m-d H:i:s'); + $return['end'] = $end_dt->format('Y-m-d H:i:s'); + } + return $return; + } } diff --git a/apps/calendar/lib/repeat.php b/apps/calendar/lib/repeat.php new file mode 100644 index 00000000000..204f96a5a2a --- /dev/null +++ b/apps/calendar/lib/repeat.php @@ -0,0 +1,204 @@ +<?php +/** + * Copyright (c) 2012 Georg Ehrke <ownclouddev@georgswebsite.de> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +/* + * This class manages the caching of repeating events + * Events will be cached for the current year Âą 5 years + */ +class OC_Calendar_Repeat{ + /* + * @brief returns the cache of an event + * @param (int) $id - id of the event + * @return (array) + */ + public static function get($id){ + $stmt = OCP\DB::prepare('SELECT * FROM *PREFIX*calendar_repeat WHERE eventid = ?'); + $result = $stmt->execute(array($id)); + $return = array(); + while($row = $result->fetchRow()){ + $return[] = $row; + } + return $return; + } + /* + * @brief returns the cache of an event in a specific peroid + * @param (int) $id - id of the event + * @param (DateTime) $from - start for period in UTC + * @param (DateTime) $until - end for period in UTC + * @return (array) + */ + public static function get_inperiod($id, $from, $until){ + $stmt = OCP\DB::prepare( 'SELECT * FROM *PREFIX*calendar_repeat WHERE eventid = ?' + .' AND ((startdate >= ? AND startdate <= ?)' + .' OR (enddate >= ? AND enddate <= ?))'); + $result = $stmt->execute(array($id, + OC_Calendar_Object::getUTCforMDB($from), OC_Calendar_Object::getUTCforMDB($until), + OC_Calendar_Object::getUTCforMDB($from), OC_Calendar_Object::getUTCforMDB($until))); + $return = array(); + while($row = $result->fetchRow()){ + $return[] = $row; + } + return $return; + } + /* + * @brief returns the cache of all repeating events of a calendar + * @param (int) $id - id of the calendar + * @return (array) + */ + public static function getCalendar($id){ + $stmt = OCP\DB::prepare('SELECT * FROM *PREFIX*calendar_repeat WHERE calid = ?'); + $result = $stmt->execute(array($id)); + $return = array(); + while($row = $result->fetchRow()){ + $return[] = $row; + } + return $return; + } + /* + * @brief returns the cache of all repeating events of a calendar in a specific period + * @param (int) $id - id of the event + * @param (string) $from - start for period in UTC + * @param (string) $until - end for period in UTC + * @return (array) + */ + public static function getCalendar_inperiod($id, $from, $until){ + $stmt = OCP\DB::prepare( 'SELECT * FROM *PREFIX*calendar_repeat WHERE calid = ?' + .' AND ((startdate >= ? AND startdate <= ?)' + .' OR (enddate >= ? AND enddate <= ?))'); + $result = $stmt->execute(array($id, + $from, $until, + $from, $until)); + $return = array(); + while($row = $result->fetchRow()){ + $return[] = $row; + } + return $return; + } + /* + * @brief generates the cache the first time + * @param (int) id - id of the event + * @return (bool) + */ + public static function generate($id){ + $event = OC_Calendar_Object::find($id); + if($event['repeating'] == 0){ + return false; + } + $object = OC_VObject::parse($event['calendardata']); + $start = new DateTime('01-01-' . date('Y') . ' 00:00:00', new DateTimeZone('UTC')); + $start->modify('-5 years'); + $end = new DateTime('31-12-' . date('Y') . ' 23:59:59', new DateTimeZone('UTC')); + $end->modify('+5 years'); + $object->expand($start, $end); + foreach($object->getComponents() as $vevent){ + if(!($vevent instanceof Sabre_VObject_Component_VEvent)){ + continue; + } + $startenddate = OC_Calendar_Object::generateStartEndDate($vevent->DTSTART, OC_Calendar_Object::getDTEndFromVEvent($vevent), ($vevent->DTSTART->getDateType() == Sabre_VObject_Element_DateTime::DATE)?true:false, 'UTC'); + $stmt = OCP\DB::prepare('INSERT INTO *PREFIX*calendar_repeat (eventid,calid,startdate,enddate) VALUES(?,?,?,?)'); + $stmt->execute(array($id,OC_Calendar_Object::getCalendarid($id),$startenddate['start'],$startenddate['end'])); + } + return true; + } + /* + * @brief generates the cache the first time for all repeating event of an calendar + * @param (int) id - id of the calendar + * @return (bool) + */ + public static function generateCalendar($id){ + $allobjects = OC_Calendar_Object::all($id); + foreach($allobjects as $event){ + self::generate($event['id']); + } + return true; + } + /* + * @brief updates an event that is already cached + * @param (int) id - id of the event + * @return (bool) + */ + public static function update($id){ + self::clean($id); + self::generate($id); + return true; + } + /* + * @brief updates all repating events of a calendar that are already cached + * @param (int) id - id of the calendar + * @return (bool) + */ + public static function updateCalendar($id){ + self::cleanCalendar($id); + self::generateCalendar($id); + return true; + } + /* + * @brief checks if an event is already cached + * @param (int) id - id of the event + * @return (bool) + */ + public static function is_cached($id){ + if(count(self::get($id)) != 0){ + return true; + }else{ + return false; + } + } + /* + * @brief checks if an event is already cached in a specific period + * @param (int) id - id of the event + * @param (DateTime) $from - start for period in UTC + * @param (DateTime) $until - end for period in UTC + * @return (bool) + */ + public static function is_cached_inperiod($id, $start, $end){ + if(count(self::get_inperiod($id, $start, $end)) != 0){ + return true; + }else{ + return false; + } + + } + /* + * @brief checks if a whole calendar is already cached + * @param (int) id - id of the calendar + * @return (bool) + */ + public static function is_calendar_cached($id){ + $cachedevents = count(self::getCalendar($id)); + $repeatingevents = 0; + $allevents = OC_Calendar_Object::all($id); + foreach($allevents as $event){ + if($event['repeating'] === 1){ + $repeatingevents++; + } + } + if($cachedevents < $repeatingevents){ + return false; + }else{ + return true; + } + } + /* + * @brief removes the cache of an event + * @param (int) id - id of the event + * @return (bool) + */ + public static function clean($id){ + $stmt = OCP\DB::prepare('DELETE FROM *PREFIX*calendar_repeat WHERE eventid = ?'); + $stmt->execute(array($id)); + } + /* + * @brief removes the cache of all events of a calendar + * @param (int) id - id of the calendar + * @return (bool) + */ + public static function cleanCalendar($id){ + $stmt = OCP\DB::prepare('DELETE FROM *PREFIX*calendar_repeat WHERE calid = ?'); + $stmt->execute(array($id)); + } +}
\ No newline at end of file diff --git a/apps/calendar/lib/search.php b/apps/calendar/lib/search.php index 03516b3b70c..6526b4223ac 100644 --- a/apps/calendar/lib/search.php +++ b/apps/calendar/lib/search.php @@ -1,7 +1,7 @@ <?php class OC_Search_Provider_Calendar extends OC_Search_Provider{ function search($query){ - $calendars = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser(), 1); + $calendars = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser(), true); if(count($calendars)==0 || !OCP\App::isEnabled('calendar')){ //return false; } diff --git a/apps/calendar/templates/settings.php b/apps/calendar/templates/settings.php index feb06655120..6d018f15110 100644 --- a/apps/calendar/templates/settings.php +++ b/apps/calendar/templates/settings.php @@ -1,7 +1,7 @@ <?php /** * Copyright (c) 2011 Bart Visscher <bartv@thisnet.nl> - * Copyright (c) 2011 Georg Ehrke <ownclouddev at georgswebsite dot de> + * Copyright (c) 2012 Georg Ehrke <ownclouddev at georgswebsite dot de> * This file is licensed under the Affero General Public License version 3 or * later. * See the COPYING-README file. @@ -44,7 +44,11 @@ </select> </td></tr> - </table> + <tr><td><label for="" class="bold"><?php echo $l->t('Cache');?></label></td><td> + <input id="cleancalendarcache" type="button" class="button" value="<?php echo $l->t('Clear cache for repeating events');?>"> + </td></tr> + + </table> <?php echo $l->t('Calendar CalDAV syncing addresses'); ?> (<a href="http://owncloud.org/synchronisation/" target="_blank"><?php echo $l->t('more info'); ?></a>) <dl> diff --git a/apps/contacts/ajax/addcontact.php b/apps/contacts/ajax/addcontact.php index e45072c9542..12f7bb9db96 100644 --- a/apps/contacts/ajax/addcontact.php +++ b/apps/contacts/ajax/addcontact.php @@ -47,4 +47,4 @@ if(!$id) { exit(); } -OCP\JSON::success(array('data' => array( 'id' => $id ))); +OCP\JSON::success(array('data' => array( 'id' => $id, 'aid' => $aid ))); diff --git a/apps/contacts/ajax/contacts.php b/apps/contacts/ajax/contacts.php index 37d396cd83a..16730ec9474 100644 --- a/apps/contacts/ajax/contacts.php +++ b/apps/contacts/ajax/contacts.php @@ -6,15 +6,54 @@ * See the COPYING-README file. */ +function cmp($a, $b) +{ + if ($a['displayname'] == $b['displayname']) { + return 0; + } + return ($a['displayname'] < $b['displayname']) ? -1 : 1; +} OCP\JSON::checkLoggedIn(); OCP\JSON::checkAppEnabled('contacts'); -$ids = OC_Contacts_Addressbook::activeIds(OCP\USER::getUser()); -$contacts = OC_Contacts_VCard::all($ids); +$active_addressbooks = OC_Contacts_Addressbook::active(OCP\USER::getUser()); +error_log('active_addressbooks: '.print_r($active_addressbooks, true)); + +$contacts_addressbook = array(); +$ids = array(); +foreach($active_addressbooks as $addressbook) { + $ids[] = $addressbook['id']; + if(!isset($contacts_addressbook[$addressbook['id']])) { + $contacts_addressbook[$addressbook['id']] = array('contacts' => array()); + $contacts_addressbook[$addressbook['id']]['displayname'] = $addressbook['displayname']; + } +} +error_log('ids: '.print_r($ids, true)); +$contacts_alphabet = OC_Contacts_VCard::all($ids); +error_log('contacts_alphabet: '.print_r($contacts_alphabet, true)); + +// Our new array for the contacts sorted by addressbook +foreach($contacts_alphabet as $contact) { + if(!isset($contacts_addressbook[$contact['addressbookid']])) { // It should never execute. + $contacts_addressbook[$contact['addressbookid']] = array('contacts' => array()); + } + $display = trim($contact['fullname']); + if(!$display) { + $vcard = OC_Contacts_App::getContactVCard($contact['id']); + if(!is_null($vcard)) { + $struct = OC_Contacts_VCard::structureContact($vcard); + $display = isset($struct['EMAIL'][0])?$struct['EMAIL'][0]['value']:'[UNKNOWN]'; + } + } + $contacts_addressbook[$contact['addressbookid']]['contacts'][] = array('id' => $contact['id'], 'addressbookid' => $contact['addressbookid'], 'displayname' => htmlspecialchars($display)); +} + +uasort($contacts_addressbook, 'cmp'); + $tmpl = new OCP\Template("contacts", "part.contacts"); -$tmpl->assign('contacts', $contacts); +$tmpl->assign('books', $contacts_addressbook, false); $page = $tmpl->fetchPage(); OCP\JSON::success(array('data' => array( 'page' => $page ))); -?> + diff --git a/apps/contacts/ajax/editaddress.php b/apps/contacts/ajax/editaddress.php index 969aeeba8f4..2d7aba11b0e 100644 --- a/apps/contacts/ajax/editaddress.php +++ b/apps/contacts/ajax/editaddress.php @@ -20,7 +20,18 @@ if($checksum) { $line = OC_Contacts_App::getPropertyLineByChecksum($vcard, $checksum); $element = $vcard->children[$line]; $adr = OC_Contacts_VCard::structureProperty($element); - $tmpl->assign('adr',$adr); + $types = array(); + if(isset($adr['parameters']['TYPE'])) { + if(is_array($adr['parameters']['TYPE'])) { + $types = array_map('htmlspecialchars', $adr['parameters']['TYPE']); + $types = array_map('strtoupper', $types); + } else { + $types = array(strtoupper(htmlspecialchars($adr['parameters']['TYPE']))); + } + } + $tmpl->assign('types', $types, false); + $adr = array_map('htmlspecialchars', $adr['value']); + $tmpl->assign('adr', $adr, false); } $tmpl->assign('id',$id); diff --git a/apps/contacts/ajax/editname.php b/apps/contacts/ajax/editname.php index d06d416b7ed..62cae894b6f 100644 --- a/apps/contacts/ajax/editname.php +++ b/apps/contacts/ajax/editname.php @@ -28,8 +28,9 @@ if($id) { $name = OC_Contacts_VCard::structureProperty($property); } } - $tmpl->assign('name',$name); - $tmpl->assign('id',$id); + $name = array_map('htmlspecialchars', $name['value']); + $tmpl->assign('name',$name, false); + $tmpl->assign('id',$id, false); } else { bailOut(OC_Contacts_App::$l10n->t('Contact ID is missing.')); } diff --git a/apps/contacts/css/contacts.css b/apps/contacts/css/contacts.css index 8de68fbf052..6c65db2b772 100644 --- a/apps/contacts/css/contacts.css +++ b/apps/contacts/css/contacts.css @@ -2,9 +2,12 @@ font-weight: bold; }*/ #leftcontent { top: 3.5em !important; padding: 0; margin: 0; } +#leftcontent a { padding: 0 0 0 25px; } #rightcontent { top: 3.5em !important; padding-top: 5px; } -#contacts { background: #fff; width: 20em; left: 12.5em; top: 3.7em; bottom:3em; position: fixed; overflow: auto; padding: 0; margin: 0; } -#contacts a { height: 23px; display: block; margin: 0 0 0 0; padding: 0 0 0 25px; } +#leftcontent h3 { cursor: pointer; -moz-transition: background 300ms ease 0s; background: none no-repeat scroll 1em center #eee; border-bottom: 1px solid #ddd; border-top: 1px solid #fff; display: block; max-width: 100%; padding: 0.5em 0.8em; color: #666; text-shadow: 0 1px 0 #f8f8f8; font-size: 1.2em; } +#leftcontent h3:hover { background-color: #DBDBDB; border-bottom: 1px solid #CCCCCC; border-top: 1px solid #D4D4D4; color: #333333; } +#contacts { position: fixed; background: #fff; max-width: 100%; width: 20em; left: 12.5em; top: 3.7em; bottom: 3em; overflow: auto; padding: 0; margin: 0; } +.contacts a { height: 23px; display: block; left: 12.5em; margin: 0 0 0 0; padding: 0 0 0 25px; } #bottomcontrols { padding: 0; bottom:0px; height:2.8em; width: 20em; margin:0; background:#eee; border-top:1px solid #ccc; position:fixed; -moz-box-shadow: 0 -3px 3px -3px #000; -webkit-box-shadow: 0 -3px 3px -3px #000; box-shadow: 0 -3px 3px -3px #000;} #contacts_newcontact { float: left; margin: 0.2em 0 0 1em; } #chooseaddressbook { float: right; margin: 0.2em 1em 0 0; } @@ -22,10 +25,10 @@ #firstrun { width: 100%; position: absolute; top: 5em; left: 0; text-align: center; font-weight:bold; font-size:1.5em; color:#777; } #firstrun #selections { font-size:0.8em; margin: 2em auto auto auto; clear: both; } -#card input[type="text"].contacts_property,input[type="email"].contacts_property { width: 14em; float: left; font-weight: bold; } +#card input[type="text"].contacts_property,input[type="email"].contacts_property,input[type="url"].contacts_property { width: 14em; float: left; font-weight: bold; } .categories { float: left; width: 16em; } -#card input[type="text"],input[type="email"],input[type="tel"],input[type="date"], select, textarea { background-color: #fefefe; border: 0 !important; -webkit-appearance:none !important; -moz-appearance:none !important; -webkit-box-sizing:none !important; -moz-box-sizing:none !important; box-sizing:none !important; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; float: left; } -#card input[type="text"]:hover, input[type="text"]:focus, input[type="text"]:active,input[type="email"]:hover,input[type="tel"]:hover,input[type="date"]:hover,input[type="date"],input[type="date"]:hover,input[type="date"]:active,input[type="date"]:active,input[type="date"]:active,input[type="email"]:active,input[type="tel"]:active, select:hover, select:focus, select:active, textarea:focus, textarea:hover { border: 0 !important; -webkit-appearance:textfield; -moz-appearance:textfield; -webkit-box-sizing:content-box; -moz-box-sizing:content-box; box-sizing:content-box; background:#fff; color:#333; border:1px solid #ddd; -moz-box-shadow:0 1px 1px #ddd, 0 2px 0 #bbb inset; -webkit-box-shadow:0 1px 1px #ddd, 0 1px 0 #bbb inset; box-shadow:0 1px 1px #ddd, 0 1px 0 #bbb inset; -moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em; outline:none; float: left; } +#card input[type="text"],input[type="email"],input[type="url"],input[type="tel"],input[type="date"], select, textarea { background-color: #fefefe; border: 0 !important; -webkit-appearance:none !important; -moz-appearance:none !important; -webkit-box-sizing:none !important; -moz-box-sizing:none !important; box-sizing:none !important; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; float: left; } +#card input[type="text"]:hover, input[type="text"]:focus, input[type="text"]:active,input[type="email"]:hover,input[type="url"]:hover,input[type="tel"]:hover,input[type="date"]:hover,input[type="date"],input[type="date"]:hover,input[type="date"]:active,input[type="date"]:active,input[type="date"]:active,input[type="email"]:active,input[type="url"]:active,input[type="tel"]:active, select:hover, select:focus, select:active, textarea:focus, textarea:hover { border: 0 !important; -webkit-appearance:textfield; -moz-appearance:textfield; -webkit-box-sizing:content-box; -moz-box-sizing:content-box; box-sizing:content-box; background:#fff; color:#333; border:1px solid #ddd; -moz-box-shadow:0 1px 1px #ddd, 0 2px 0 #bbb inset; -webkit-box-shadow:0 1px 1px #ddd, 0 1px 0 #bbb inset; box-shadow:0 1px 1px #ddd, 0 1px 0 #bbb inset; -moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em; outline:none; float: left; } textarea { width: 80%; min-height: 5em; min-width: 30em; margin: 0 !important; padding: 0 !important; outline: 0 !important;} dl.form { width: 100%; float: left; clear: right; margin: 0; padding: 0; } .form dt { display: table-cell; clear: left; float: left; width: 7em; margin: 0; padding: 0.8em 0.5em 0 0; text-align:right; text-overflow:ellipsis; o-text-overflow: ellipsis; vertical-align: text-bottom; color: #bbb;/* white-space: pre-wrap; white-space: -moz-pre-wrap !important; white-space: -pre-wrap; white-space: -o-pre-wrap;*/ } diff --git a/apps/contacts/index.php b/apps/contacts/index.php index 74b7c43c556..bdb52c123ce 100644 --- a/apps/contacts/index.php +++ b/apps/contacts/index.php @@ -66,7 +66,7 @@ $tmpl->assign('phone_types', $phone_types); $tmpl->assign('email_types', $email_types); $tmpl->assign('categories', $categories); $tmpl->assign('addressbooks', $addressbooks); -$tmpl->assign('contacts', $contacts); +$tmpl->assign('contacts', $contacts, false); $tmpl->assign('details', $details ); $tmpl->assign('id',$id); $tmpl->printPage(); diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index a1b9976006d..8ab2a3fbb88 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -171,13 +171,14 @@ Contacts={ });*/ // Name has changed. Update it and reorder. + // TODO: Take addressbook into account $('#fn').change(function(){ var name = $('#fn').val().strip_tags(); - var item = $('#contacts [data-id="'+Contacts.UI.Card.id+'"]'); + var item = $('.contacts li[data-id="'+Contacts.UI.Card.id+'"]'); $(item).find('a').html(name); Contacts.UI.Card.fn = name; var added = false; - $('#contacts li').each(function(){ + $('.contacts li[data-bookid="'+Contacts.UI.Card.bookid+'"]').each(function(){ if ($(this).text().toLowerCase() > name.toLowerCase()) { $(this).before(item).fadeIn('fast'); added = true; @@ -185,7 +186,7 @@ Contacts={ } }); if(!added) { - $('#leftcontent ul').append(item); + $('#contacts ul[data-id="'+Contacts.UI.Card.bookid+'"]').append(item); } Contacts.UI.Contacts.scrollTo(Contacts.UI.Card.id); }); @@ -245,19 +246,23 @@ Contacts={ honpre:'', honsuf:'', data:undefined, - update:function(id) { - var newid; + update:function(id, bookid) { + var newid, firstitem; if(!id) { - newid = $('#contacts li:first-child').data('id'); + firstitem = $('#contacts:first-child li:first-child'); + if(firstitem.length > 0) { + newid = firstitem.data('id'); + bookid = firstitem.data('bookid'); + } } else { newid = id; } - var localLoadContact = function(id) { - if($('#contacts li').length > 0) { - $('#leftcontent li[data-id="'+newid+'"]').addClass('active'); + var localLoadContact = function(newid, bookid) { + if($('.contacts li').length > 0) { + firstitem.addClass('active'); $.getJSON(OC.filePath('contacts', 'ajax', 'contactdetails.php'),{'id':newid},function(jsondata){ if(jsondata.status == 'success'){ - Contacts.UI.Card.loadContact(jsondata.data); + Contacts.UI.Card.loadContact(jsondata.data, bookid); } else { OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } @@ -266,19 +271,19 @@ Contacts={ } // Make sure proper DOM is loaded. - if(!$('#card')[0]) { + if(!$('#card')[0] && newid) { $.getJSON(OC.filePath('contacts', 'ajax', 'loadcard.php'),{},function(jsondata){ if(jsondata.status == 'success'){ $('#rightcontent').html(jsondata.data.page).ready(function() { Contacts.UI.loadHandlers(); - localLoadContact(newid); + localLoadContact(newid, bookid); }); } else { OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); } - else if($('#contacts li').length == 0) { + else if(!newid) { // load intro page $.getJSON(OC.filePath('contacts', 'ajax', 'loadintro.php'),{},function(jsondata){ if(jsondata.status == 'success'){ @@ -291,7 +296,7 @@ Contacts={ }); } else { - localLoadContact(); + localLoadContact(newid, bookid); } }, doExport:function() { @@ -313,13 +318,14 @@ Contacts={ if (jsondata.status == 'success'){ $('#rightcontent').data('id',jsondata.data.id); var id = jsondata.data.id; + var aid = jsondata.data.aid; $.getJSON(OC.filePath('contacts', 'ajax', 'contactdetails.php'),{'id':id},function(jsondata){ if(jsondata.status == 'success'){ - Contacts.UI.Card.loadContact(jsondata.data); - $('#leftcontent .active').removeClass('active'); + Contacts.UI.Card.loadContact(jsondata.data, aid); + $('#contacts .active').removeClass('active'); var item = $('<li data-id="'+jsondata.data.id+'" class="active"><a href="index.php?id='+jsondata.data.id+'" style="background: url('+OC.filePath('contacts', '', 'thumbnail.php')+'?id='+jsondata.data.id+') no-repeat scroll 0% 0% transparent;">'+Contacts.UI.Card.fn+'</a></li>'); var added = false; - $('#leftcontent ul li').each(function(){ + $('#contacts ul[data-id="'+aid+'"] li').each(function(){ if ($(this).text().toLowerCase() > Contacts.UI.Card.fn.toLowerCase()) { $(this).before(item).fadeIn('fast'); added = true; @@ -327,7 +333,7 @@ Contacts={ } }); if(!added) { - $('#leftcontent ul').append(item); + $('#contacts ul[data-id="'+aid+'"]').append(item); } if(isnew) { // add some default properties Contacts.UI.Card.addProperty('EMAIL'); @@ -370,8 +376,8 @@ Contacts={ if(answer == true) { $.post(OC.filePath('contacts', 'ajax', 'deletecard.php'),{'id':Contacts.UI.Card.id},function(jsondata){ if(jsondata.status == 'success'){ - var newid = ''; - var curlistitem = $('#leftcontent [data-id="'+jsondata.data.id+'"]'); + var newid = '', bookid; + var curlistitem = $('#contacts li[data-id="'+jsondata.data.id+'"]'); var newlistitem = curlistitem.prev(); if(newlistitem == undefined) { newlistitem = curlistitem.next(); @@ -379,13 +385,14 @@ Contacts={ curlistitem.remove(); if(newlistitem != undefined) { newid = newlistitem.data('id'); + bookid = newlistitem.data('id'); } $('#rightcontent').data('id',newid); this.id = this.fn = this.fullname = this.shortname = this.famname = this.givname = this.addname = this.honpre = this.honsuf = ''; this.data = undefined; - if($('#contacts li').length > 0) { // Load first in list. - Contacts.UI.Card.update(newid); + if($('.contacts li').length > 0) { // Load first in list. + Contacts.UI.Card.update(newid, bookid); } else { // load intro page $.getJSON(OC.filePath('contacts', 'ajax', 'loadintro.php'),{},function(jsondata){ @@ -408,9 +415,10 @@ Contacts={ }); return false; }, - loadContact:function(jsondata){ + loadContact:function(jsondata, bookid){ this.data = jsondata; this.id = this.data.id; + this.bookid = bookid; $('#rightcontent').data('id',this.id); this.populateNameFields(); this.loadPhoto(); @@ -1498,40 +1506,54 @@ Contacts={ update:function(){ $.getJSON(OC.filePath('contacts', 'ajax', 'contacts.php'),{},function(jsondata){ if(jsondata.status == 'success'){ - $('#contacts').html(jsondata.data.page); + $('#contacts').html(jsondata.data.page).ready(function() { + /*setTimeout(function() { + $('.contacts li').unbind('inview'); + $('.contacts li:visible').bind('inview', function(event, isInView, visiblePartX, visiblePartY) { + if (isInView) { + if (!$(this).find('a').attr('style')) { + $(this).find('a').css('background','url('+OC.filePath('contacts', '', 'thumbnail.php')+'?id='+$(this).data('id')+') no-repeat'); + } + } + })}, 100); + setTimeout(Contacts.UI.Contacts.lazyupdate, 500);*/ + }); Contacts.UI.Card.update(); } else{ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); - setTimeout(function() { - $('#contacts li').unbind('inview'); - $('#contacts li').bind('inview', function(event, isInView, visiblePartX, visiblePartY) { + /*setTimeout(function() { + $('.contacts li').unbind('inview'); + $('.contacts li:visible').bind('inview', function(event, isInView, visiblePartX, visiblePartY) { if (isInView) { if (!$(this).find('a').attr('style')) { $(this).find('a').css('background','url('+OC.filePath('contacts', '', 'thumbnail.php')+'?id='+$(this).data('id')+') no-repeat'); } } })}, 500); - setTimeout(Contacts.UI.Contacts.lazyupdate, 500); + setTimeout(Contacts.UI.Contacts.lazyupdate, 500);*/ }, // Add thumbnails to the contact list as they become visible in the viewport. lazyupdate:function(){ - $('#contacts li').live('inview', function(){ + $('.contacts li').live('inview', function(){ if (!$(this).find('a').attr('style')) { $(this).find('a').css('background','url('+OC.filePath('contacts', '', 'thumbnail.php')+'?id='+$(this).data('id')+') no-repeat'); } }); }, refreshThumbnail:function(id){ - var item = $('#contacts [data-id="'+id+'"]').find('a'); + var item = $('.contacts li[data-id="'+id+'"]').find('a'); item.html(Contacts.UI.Card.fn); item.css('background','url('+OC.filePath('contacts', '', 'thumbnail.php')+'?id='+id+'&refresh=1'+Math.random()+') no-repeat'); }, scrollTo:function(id){ - $('#contacts').animate({ - scrollTop: $('#leftcontent li[data-id="'+id+'"]').offset().top-20}, 'slow','swing'); + var item = $('#contacts li[data-id="'+id+'"]'); + if(item) { + $('.contacts').animate({ + scrollTop: $('#contacts li[data-id="'+id+'"]').offset().top-20}, 'slow','swing'); + } } } } @@ -1552,24 +1574,25 @@ $(document).ready(function(){ $('#contacts_newcontact').keydown(Contacts.UI.Card.editNew); // Load a contact. - $('#contacts').keydown(function(event) { + $('.contacts').keydown(function(event) { if(event.which == 13) { - $('#contacts').click(); + $('.contacts').click(); } }); - $('#contacts').click(function(event){ + $(document).on('click', '.contacts', function(event){ var $tgt = $(event.target); if ($tgt.is('li') || $tgt.is('a')) { var item = $tgt.is('li')?$($tgt):($tgt).parent(); var id = item.data('id'); + var bookid = item.data('bookid'); item.addClass('active'); var oldid = $('#rightcontent').data('id'); if(oldid != 0){ - $('#contacts li[data-id="'+oldid+'"]').removeClass('active'); + $('.contacts li[data-id="'+oldid+'"]').removeClass('active'); } $.getJSON(OC.filePath('contacts', 'ajax', 'contactdetails.php'),{'id':id},function(jsondata){ if(jsondata.status == 'success'){ - Contacts.UI.Card.loadContact(jsondata.data); + Contacts.UI.Card.loadContact(jsondata.data, bookid); } else{ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); @@ -1579,7 +1602,12 @@ $(document).ready(function(){ return false; }); - $('#contacts li').bind('inview', function(event, isInView, visiblePartX, visiblePartY) { + $(document).on('click', '.addressbook', function(event){ + $(this).next().slideToggle(300); + return false; + }); + + /*$('.contacts li').bind('inview', function(event, isInView, visiblePartX, visiblePartY) { if (isInView) { //NOTE: I've kept all conditions for future reference ;-) // element is now visible in the viewport if (visiblePartY == 'top') { @@ -1591,14 +1619,14 @@ $(document).ready(function(){ if (!$(this).find('a').attr('style')) { //alert($(this).data('id') + ' has background: ' + $(this).attr('style')); $(this).find('a').css('background','url('+OC.filePath('contacts', '', 'thumbnail.php')+'?id='+$(this).data('id')+') no-repeat'); - }/* else { - alert($(this).data('id') + ' has style ' + $(this).attr('style').match('url')); - }*/ + }// else { + // alert($(this).data('id') + ' has style ' + $(this).attr('style').match('url')); + //} } } else { // element has gone out of viewport } - }); + });*/ $('.contacts_property').live('change', function(){ Contacts.UI.Card.saveProperty(this); @@ -1677,4 +1705,7 @@ $(document).ready(function(){ } $('#contacts_propertymenu_dropdown a').click(propertyMenuItem); $('#contacts_propertymenu_dropdown a').keydown(propertyMenuItem); + + Contacts.UI.loadHandlers(); + Contacts.UI.Contacts.update(); }); diff --git a/apps/contacts/lib/addressbook.php b/apps/contacts/lib/addressbook.php index 79445ceeee1..878d8835f94 100644 --- a/apps/contacts/lib/addressbook.php +++ b/apps/contacts/lib/addressbook.php @@ -172,12 +172,11 @@ class OC_Contacts_Addressbook{ if(!$prefbooks){ $addressbooks = OC_Contacts_Addressbook::all($uid); if(count($addressbooks) == 0){ - OC_Contacts_Addressbook::add($uid,'default','Default Address Book'); - $addressbooks = OC_Contacts_Addressbook::all($uid); + $id = OC_Contacts_Addressbook::add($uid,'default','Default Address Book'); + self::setActive($id, true); } - $prefbooks = $addressbooks[0]['id']; - OCP\Config::setUserValue($uid,'contacts','openaddressbooks',$prefbooks); } + $prefbooks = OCP\Config::getUserValue($uid,'contacts','openaddressbooks',null); return explode(';',$prefbooks); } @@ -195,7 +194,7 @@ class OC_Contacts_Addressbook{ $stmt = OCP\DB::prepare( $prep ); $result = $stmt->execute($active); } catch(Exception $e) { - OCP\Util::writeLog('contacts','OC_Contacts_Addressbook:active:, exception: '.$e->getMessage(),OCP\Util::DEBUG); + OCP\Util::writeLog('contacts','OC_Contacts_Addressbook:active:, exception: '.$e->getMessage(),OCP\Util::ERROR); OCP\Util::writeLog('contacts','OC_Contacts_Addressbook:active, ids: '.join(',', $active),OCP\Util::DEBUG); OCP\Util::writeLog('contacts','OC_Contacts_Addressbook::active, SQL:'.$prep,OCP\Util::DEBUG); } @@ -210,7 +209,7 @@ class OC_Contacts_Addressbook{ /** * @brief Activates an addressbook * @param integer $id - * @param integer $name + * @param boolean $active * @return boolean */ public static function setActive($id,$active){ @@ -256,11 +255,15 @@ class OC_Contacts_Addressbook{ * @return boolean */ public static function delete($id){ - // FIXME: There's no error checking at all. self::setActive($id, false); - $stmt = OCP\DB::prepare( 'DELETE FROM *PREFIX*contacts_addressbooks WHERE id = ?' ); - $stmt->execute(array($id)); - + try { + $stmt = OCP\DB::prepare( 'DELETE FROM *PREFIX*contacts_addressbooks WHERE id = ?' ); + $stmt->execute(array($id)); + } catch(Exception $e) { + OCP\Util::writeLog('contacts','OC_Contacts_Addressbook:delete:, exception for '.$id.': '.$e->getMessage(),OCP\Util::ERROR); + return false; + } + $cards = OC_Contacts_VCard::all($id); foreach($cards as $card){ OC_Contacts_VCard::delete($card['id']); diff --git a/apps/contacts/lib/hooks.php b/apps/contacts/lib/hooks.php index e3d5df3d51f..e74b465a47b 100644 --- a/apps/contacts/lib/hooks.php +++ b/apps/contacts/lib/hooks.php @@ -56,7 +56,7 @@ class OC_Contacts_Hooks{ static public function getBirthdayEvents($parameters) { $name = $parameters['calendar_id']; - if (strpos('birthday_', $name) != 0) { + if (strpos($name, 'birthday_') != 0) { return; } $info = explode('_', $name); diff --git a/apps/contacts/lib/search.php b/apps/contacts/lib/search.php index 144138a7c2c..19330fa9be1 100644 --- a/apps/contacts/lib/search.php +++ b/apps/contacts/lib/search.php @@ -2,17 +2,10 @@ class OC_Search_Provider_Contacts extends OC_Search_Provider{ function search($query){ $addressbooks = OC_Contacts_Addressbook::all(OCP\USER::getUser(), 1); -// if(count($calendars)==0 || !OCP\App::isEnabled('contacts')){ -// //return false; -// } - // NOTE: Does the following do anything - $results=array(); - $searchquery=array(); - if(substr_count($query, ' ') > 0){ - $searchquery = explode(' ', $query); - }else{ - $searchquery[] = $query; + if(count($addressbooks)==0 || !OCP\App::isEnabled('contacts')){ + return array(); } + $results=array(); $l = new OC_l10n('contacts'); foreach($addressbooks as $addressbook){ $vcards = OC_Contacts_VCard::all($addressbook['id']); diff --git a/apps/contacts/lib/vcard.php b/apps/contacts/lib/vcard.php index 71a874d783b..110d721ace0 100644 --- a/apps/contacts/lib/vcard.php +++ b/apps/contacts/lib/vcard.php @@ -56,7 +56,7 @@ class OC_Contacts_VCard{ $stmt = OCP\DB::prepare( $prep ); $result = $stmt->execute($id); } catch(Exception $e) { - OCP\Util::writeLog('contacts','OC_Contacts_VCard:all:, exception: '.$e->getMessage(),OCP\Util::DEBUG); + OCP\Util::writeLog('contacts','OC_Contacts_VCard:all:, exception: '.$e->getMessage(),OCP\Util::ERROR); OCP\Util::writeLog('contacts','OC_Contacts_VCard:all, ids: '.join(',', $id),OCP\Util::DEBUG); OCP\Util::writeLog('contacts','SQL:'.$prep,OCP\Util::DEBUG); } diff --git a/apps/contacts/templates/index.php b/apps/contacts/templates/index.php index 7d212e71ba8..d16356d4a56 100644 --- a/apps/contacts/templates/index.php +++ b/apps/contacts/templates/index.php @@ -3,16 +3,15 @@ var categories = <?php echo json_encode($_['categories']); ?>; var lang = '<?php echo OCP\Config::getUserValue(OCP\USER::getUser(), 'core', 'lang', 'en'); ?>'; </script> -<div id="leftcontent" class="leftcontent"> - <ul id="contacts"> - <?php echo $this->inc("part.contacts"); ?> - </ul> -</div> -<div id="bottomcontrols"> - <form> - <button class="svg" id="contacts_newcontact" title="<?php echo $l->t('Add Contact'); ?>"><img class="svg" src="<?php echo OCP\Util::linkTo('contacts', 'img/contact-new.svg'); ?>" alt="<?php echo $l->t('Add Contact'); ?>" /></button> - <button class="svg" id="chooseaddressbook" title="<?php echo $l->t('Addressbooks'); ?>"><img class="svg" src="core/img/actions/settings.svg" alt="<?php echo $l->t('Addressbooks'); ?>" /></button> - </form> +<div id="leftcontent"> + <div id="contacts"> + </div> + <div id="bottomcontrols"> + <form> + <button class="svg" id="contacts_newcontact" title="<?php echo $l->t('Add Contact'); ?>"><img class="svg" src="<?php echo OCP\Util::linkTo('contacts', 'img/contact-new.svg'); ?>" alt="<?php echo $l->t('Add Contact'); ?>" /></button> + <button class="svg" id="chooseaddressbook" title="<?php echo $l->t('Addressbooks'); ?>"><img class="svg" src="core/img/actions/settings.svg" alt="<?php echo $l->t('Addressbooks'); ?>" /></button> + </form> + </div> </div> <div id="rightcontent" class="rightcontent" data-id="<?php echo $_['id']; ?>"> <?php diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php index ca682baaf80..5757563fe5b 100644 --- a/apps/contacts/templates/part.contact.php +++ b/apps/contacts/templates/part.contact.php @@ -33,15 +33,15 @@ $id = isset($_['id']) ? $_['id'] : ''; </span> <dl id="identityprops" class="form"> <dt class="hidden" id="org_label" data-element="ORG"><label for="org"><?php echo $l->t('Organization'); ?></label></dt> - <dd class="propertycontainer hidden" id="org_value" data-element="ORG"><input id="org" required="required" name="value[ORG]" type="text" class="contacts_property big" name="value" value="" placeholder="<?php echo $l->t('Organization'); ?>" /><a role="button" class="action delete" title="<?php echo $l->t('Delete'); ?>"></a></dd> + <dd class="propertycontainer hidden" id="org_value" data-element="ORG"><input id="org" required="required" type="text" class="contacts_property big" name="value" value="" placeholder="<?php echo $l->t('Organization'); ?>" /><a role="button" class="action delete" title="<?php echo $l->t('Delete'); ?>"></a></dd> <dt class="hidden" id="nickname_label" data-element="NICKNAME"><label for="nickname"><?php echo $l->t('Nickname'); ?></label></dt> - <dd class="propertycontainer hidden" id="nickname_value" data-element="NICKNAME"><input id="nickname" required="required" name="value[NICKNAME]" type="text" class="contacts_property big" name="value" value="" placeholder="<?php echo $l->t('Enter nickname'); ?>" /><a role="button" class="action delete" title="<?php echo $l->t('Delete'); ?>"></a></dd> + <dd class="propertycontainer hidden" id="nickname_value" data-element="NICKNAME"><input id="nickname" required="required" type="text" class="contacts_property big" name="value" value="" placeholder="<?php echo $l->t('Enter nickname'); ?>" /><a role="button" class="action delete" title="<?php echo $l->t('Delete'); ?>"></a></dd> <dt class="hidden" id="url_label" data-element="URL"><label for="url"><?php echo $l->t('Web site'); ?></label></dt> - <dd class="propertycontainer hidden" id="url_value" data-element="URL"><input id="url" required="required" name="value[URL]" type="text" class="contacts_property big" name="value" value="" placeholder="<?php echo $l->t('http://www.somesite.com'); ?>" /><a role="button" class="action globe" title="<?php echo $l->t('Go to web site'); ?>"><a role="button" class="action delete" title="<?php echo $l->t('Delete'); ?>"></a></dd> + <dd class="propertycontainer hidden" id="url_value" data-element="URL"><input id="url" required="required" type="url" class="contacts_property big" name="value" value="" placeholder="<?php echo $l->t('http://www.somesite.com'); ?>" /><a role="button" class="action globe" title="<?php echo $l->t('Go to web site'); ?>"><a role="button" class="action delete" title="<?php echo $l->t('Delete'); ?>"></a></dd> <dt class="hidden" id="bday_label" data-element="BDAY"><label for="bday"><?php echo $l->t('Birthday'); ?></label></dt> <dd class="propertycontainer hidden" id="bday_value" data-element="BDAY"><input id="bday" required="required" name="value" type="text" class="contacts_property big" value="" placeholder="<?php echo $l->t('dd-mm-yyyy'); ?>" /><a role="button" class="action delete" title="<?php echo $l->t('Delete'); ?>"></a></dd> <dt class="hidden" id="categories_label" data-element="CATEGORIES"><label for="categories"><?php echo $l->t('Groups'); ?></label></dt> - <dd class="propertycontainer hidden" id="categories_value" data-element="CATEGORIES"><input id="categories" required="required" name="value[CATEGORIES]" type="text" class="contacts_property bold" name="value" value="" placeholder=" + <dd class="propertycontainer hidden" id="categories_value" data-element="CATEGORIES"><input id="categories" required="required" type="text" class="contacts_property bold" name="value" value="" placeholder=" <?php echo $l->t('Separate groups with commas'); ?>" /> <a role="button" class="action delete" title="<?php echo $l->t('Delete'); ?>"></a><a role="button" class="action edit" title="<?php echo $l->t('Edit groups'); ?>"></a></dd> </dl> @@ -121,19 +121,3 @@ $id = isset($_['id']) ? $_['id'] : ''; <div id="edit_photo_dialog" title="Edit photo"> <div id="edit_photo_dialog_img"></div> </div> -<script language="Javascript"> -$(document).ready(function(){ - if('<?php echo $id; ?>'!='') { - $.getJSON(OC.filePath('contacts', 'ajax', 'contactdetails.php'),{'id':'<?php echo $id; ?>'},function(jsondata){ - if(jsondata.status == 'success'){ - $('#leftcontent li[data-id="<?php echo $id; ?>"]').addClass('active'); - Contacts.UI.Card.loadContact(jsondata.data); - Contacts.UI.loadHandlers(); - } - else{ - OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); - } - }); - } -}); -</script> diff --git a/apps/contacts/templates/part.contacts.php b/apps/contacts/templates/part.contacts.php index 00a61f72fdd..f0b14c8e5f2 100644 --- a/apps/contacts/templates/part.contacts.php +++ b/apps/contacts/templates/part.contacts.php @@ -1,12 +1,10 @@ -<?php foreach( $_['contacts'] as $contact ): - $display = trim($contact['fullname']); - if(!$display) { - $vcard = OC_Contacts_App::getContactVCard($contact['id']); - if(!is_null($vcard)) { - $struct = OC_Contacts_VCard::structureContact($vcard); - $display = isset($struct['EMAIL'][0])?$struct['EMAIL'][0]['value']:'[UNKNOWN]'; - } +<?php +foreach($_['books'] as $id => $addressbook) { + echo '<h3 class="addressbook" data-id="'.$id.'">'.$addressbook['displayname'].'</h3>'; + echo '<ul class="contacts hidden" data-id="'.$id.'">'; + foreach($addressbook['contacts'] as $contact) { + echo '<li role="button" data-bookid="'.$contact['addressbookid'].'" data-id="'.$contact['id'].'"><a href="index.php?id='.$contact['id'].'" style="background: url('.link_to('contacts','thumbnail.php').'?id='.$contact['id'].') no-repeat scroll 0 0 transparent;">'.$contact['displayname'].'</a></li>'; } + echo '</ul>'; +} ?> - <li role="button" book-id="<?php echo $contact['addressbookid']; ?>" data-id="<?php echo $contact['id']; ?>"><a href="index.php?id=<?php echo $contact['id']; ?>"><?php echo $display; ?></a></li> -<?php endforeach; ?> diff --git a/apps/contacts/templates/part.cropphoto.php b/apps/contacts/templates/part.cropphoto.php index 1079afc808a..6d7b1e44777 100644 --- a/apps/contacts/templates/part.cropphoto.php +++ b/apps/contacts/templates/part.cropphoto.php @@ -4,7 +4,7 @@ $tmpkey = $_['tmpkey']; $requesttoken = $_['requesttoken']; OCP\Util::writeLog('contacts','templates/part.cropphoto.php: tmpkey: '.$tmpkey, OCP\Util::DEBUG); ?> -<script language="Javascript"> +<script type="text/javascript"> jQuery(function($) { $('#cropbox').Jcrop({ onChange: showCoords, diff --git a/apps/contacts/templates/part.edit_address_dialog.php b/apps/contacts/templates/part.edit_address_dialog.php index 7684795f348..d5ea95ba465 100644 --- a/apps/contacts/templates/part.edit_address_dialog.php +++ b/apps/contacts/templates/part.edit_address_dialog.php @@ -1,13 +1,9 @@ <?php $adr = isset($_['adr'])?$_['adr']:array(); -$id = $_['id']; -$types = array(); -foreach(isset($adr['parameters']['TYPE'])?array($adr['parameters']['TYPE']):array() as $type) { - $types[] = strtoupper($type); -} +$id = isset($_['id'])?$_['id']:array(); +$types = isset($_['types'])?$_['types']:array(); ?> <div id="edit_address_dialog" title="<?php echo $l->t('Edit address'); ?>"> -<!-- ?php print_r($types); ? --> <fieldset id="address"> <dl class="form"> <dt> @@ -22,43 +18,43 @@ foreach(isset($adr['parameters']['TYPE'])?array($adr['parameters']['TYPE']):arra <label class="label" for="adr_pobox"><?php echo $l->t('PO Box'); ?></label> </dt> <dd> - <input type="text" id="adr_pobox" name="value[ADR][0]" placeholder="<?php echo $l->t('PO Box'); ?>" value="<?php echo isset($adr['value'][0])?$adr['value'][0]:''; ?>"> + <input type="text" id="adr_pobox" name="value[ADR][0]" placeholder="<?php echo $l->t('PO Box'); ?>" value="<?php echo isset($adr[0])?$adr[0]:''; ?>"> </dd> <dt> <label class="label" for="adr_street"><?php echo $l->t('Street address'); ?></label> </dt> <dd> - <input type="text" id="adr_street" name="value[ADR][2]" placeholder="<?php echo $l->t('Street and number'); ?>" value="<?php echo isset($adr['value'][2])?$adr['value'][2]:''; ?>"> + <input type="text" id="adr_street" name="value[ADR][2]" placeholder="<?php echo $l->t('Street and number'); ?>" value="<?php echo isset($adr[2])?$adr[2]:''; ?>"> </dd> <dt> <label class="label" for="adr_extended"><?php echo $l->t('Extended'); ?></label> </dt> <dd> - <input type="text" id="adr_extended" name="value[ADR][1]" placeholder="<?php echo $l->t('Apartment number etc.'); ?>" value="<?php echo isset($adr['value'][1])?$adr['value'][1]:''; ?>"> + <input type="text" id="adr_extended" name="value[ADR][1]" placeholder="<?php echo $l->t('Apartment number etc.'); ?>" value="<?php echo isset($adr[1])?$adr[1]:''; ?>"> </dd> <dt> <label class="label" for="adr_city"><?php echo $l->t('City'); ?></label> </dt> <dd> - <input type="text" id="adr_city" name="value[ADR][3]" placeholder="<?php echo $l->t('City'); ?>" value="<?php echo isset($adr['value'][3])?$adr['value'][3]:''; ?>"> + <input type="text" id="adr_city" name="value[ADR][3]" placeholder="<?php echo $l->t('City'); ?>" value="<?php echo isset($adr[3])?$adr[3]:''; ?>"> </dd> <dt> <label class="label" for="adr_region"><?php echo $l->t('Region'); ?></label> </dt> <dd> - <input type="text" id="adr_region" name="value[ADR][4]" placeholder="<?php echo $l->t('E.g. state or province'); ?>" value="<?php echo isset($adr['value'][4])?$adr['value'][4]:''; ?>"> + <input type="text" id="adr_region" name="value[ADR][4]" placeholder="<?php echo $l->t('E.g. state or province'); ?>" value="<?php echo isset($adr[4])?$adr[4]:''; ?>"> </dd> <dt> <label class="label" for="adr_zipcode"><?php echo $l->t('Zipcode'); ?></label> </dt> <dd> - <input type="text" id="adr_zipcode" name="value[ADR][5]" placeholder="<?php echo $l->t('Postal code'); ?>" value="<?php echo isset($adr['value'][5])?$adr['value'][5]:''; ?>"> + <input type="text" id="adr_zipcode" name="value[ADR][5]" placeholder="<?php echo $l->t('Postal code'); ?>" value="<?php echo isset($adr[5])?$adr[5]:''; ?>"> </dd> <dt> <label class="label" for="adr_country"><?php echo $l->t('Country'); ?></label> </dt> <dd> - <input type="text" id="adr_country" name="value[ADR][6]" placeholder="<?php echo $l->t('Country'); ?>" value="<?php echo isset($adr['value'][6])?$adr['value'][6]:''; ?>"> + <input type="text" id="adr_country" name="value[ADR][6]" placeholder="<?php echo $l->t('Country'); ?>" value="<?php echo isset($adr[6])?$adr[6]:''; ?>"> </dd> </dl> </fieldset> diff --git a/apps/contacts/templates/part.edit_name_dialog.php b/apps/contacts/templates/part.edit_name_dialog.php index be45f9a5b06..f984c232a30 100644 --- a/apps/contacts/templates/part.edit_name_dialog.php +++ b/apps/contacts/templates/part.edit_name_dialog.php @@ -22,7 +22,7 @@ $addressbooks = isset($_['addressbooks'])?$_['addressbooks']:null; <?php }} ?> <dt><label for="pre"><?php echo $l->t('Hon. prefixes'); ?></label></dt> <dd> - <input name="pre" id="pre" value="<?php echo isset($name['value'][3]) ? $name['value'][3] : ''; ?>" type="text" list="prefixes" /> + <input name="pre" id="pre" value="<?php echo isset($name[3]) ? $name[3] : ''; ?>" type="text" list="prefixes" /> <datalist id="prefixes"> <option value="<?php echo $l->t('Miss'); ?>"> <option value="<?php echo $l->t('Ms'); ?>"> @@ -33,14 +33,14 @@ $addressbooks = isset($_['addressbooks'])?$_['addressbooks']:null; </datalist> </dd> <dt><label for="giv"><?php echo $l->t('Given name'); ?></label></dt> - <dd><input name="giv" id="giv" value="<?php echo isset($name['value'][1]) ? $name['value'][1] : ''; ?>" type="text" /></dd> + <dd><input name="giv" id="giv" value="<?php echo isset($name[1]) ? $name[1] : ''; ?>" type="text" /></dd> <dt><label for="add"><?php echo $l->t('Additional names'); ?></label></dt> - <dd><input name="add" id="add" value="<?php echo isset($name['value'][2]) ? $name['value'][2] : ''; ?>" type="text" /></dd> + <dd><input name="add" id="add" value="<?php echo isset($name[2]) ? $name[2] : ''; ?>" type="text" /></dd> <dt><label for="fam"><?php echo $l->t('Family name'); ?></label></dt> - <dd><input name="fam" id="fam" value="<?php echo isset($name['value'][0]) ? $name['value'][0] : ''; ?>" type="text" /></dd> + <dd><input name="fam" id="fam" value="<?php echo isset($name[0]) ? $name[0] : ''; ?>" type="text" /></dd> <dt><label for="suf"><?php echo $l->t('Hon. suffixes'); ?></label></dt> <dd> - <input name="suf" id="suf" value="<?php echo isset($name['value'][4]) ? $name['value'][4] : ''; ?>" type="text" list="suffixes" /> + <input name="suf" id="suf" value="<?php echo isset($name[4]) ? $name[4] : ''; ?>" type="text" list="suffixes" /> <datalist id="suffixes"> <option value="<?php echo $l->t('J.D.'); ?>"> <option value="<?php echo $l->t('M.D.'); ?>"> diff --git a/apps/files/ajax/scan.php b/apps/files/ajax/scan.php index d695ce81617..6fcf97688c2 100644 --- a/apps/files/ajax/scan.php +++ b/apps/files/ajax/scan.php @@ -10,6 +10,7 @@ if(!$checkOnly){ $eventSource=new OC_EventSource(); } +session_write_close(); //create the file cache if necesary if($force or !OC_FileCache::inCache('')){ diff --git a/apps/files/ajax/upload.php b/apps/files/ajax/upload.php index d6c799af32c..b779924cfb4 100644 --- a/apps/files/ajax/upload.php +++ b/apps/files/ajax/upload.php @@ -48,7 +48,7 @@ if(strpos($dir,'..') === false){ for($i=0;$i<$fileCount;$i++){ $target = OCP\Files::buildNotExistingFileName(stripslashes($dir), $files['name'][$i]); if(is_uploaded_file($files['tmp_name'][$i]) and OC_Filesystem::fromTmpFile($files['tmp_name'][$i],$target)){ - $meta=OC_FileCache::getCached($target); + $meta=OC_FileCache_Cached::get($target); $result[]=array( "status" => "success", 'mime'=>$meta['mimetype'],'size'=>$meta['size'],'name'=>basename($target)); } } diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js index deec640bc12..4dc05088eed 100644 --- a/apps/files/js/fileactions.js +++ b/apps/files/js/fileactions.js @@ -141,7 +141,7 @@ $(document).ready(function(){ var downloadScope = 'file'; } FileActions.register(downloadScope,'Download',function(){return OC.imagePath('core','actions/download')},function(filename){ - window.location=OC.filePath('files', 'ajax', 'download.php') + '?files='+encodeURIComponent(filename)+'&dir='+encodeURIComponent($('#dir').val()); + window.location=OC.filePath('files', 'ajax', 'download.php') + encodeURIComponent('?files='+encodeURIComponent(filename)+'&dir='+encodeURIComponent($('#dir').val())); }); }); diff --git a/apps/files/templates/part.breadcrumb.php b/apps/files/templates/part.breadcrumb.php index 43fe2d1fa95..22d9bb4490d 100644 --- a/apps/files/templates/part.breadcrumb.php +++ b/apps/files/templates/part.breadcrumb.php @@ -1,6 +1,6 @@ <?php for($i=0; $i<count($_["breadcrumb"]); $i++): $crumb = $_["breadcrumb"][$i]; ?> <div class="crumb <?php if($i == count($_["breadcrumb"])-1) echo 'last';?> svg" data-dir='<?php echo $crumb["dir"];?>' style='background-image:url("<?php echo OCP\image_path('core','breadcrumb.png');?>")'> - <a href="<?php echo $_['baseURL'].$crumb["dir"]; ?>"><?php echo htmlentities($crumb["name"],ENT_COMPAT,'utf-8'); ?></a> + <a href="<?php echo $_['baseURL'].$crumb["dir"]; ?>"><?php echo OCP\Util::sanitizeHTML($crumb["name"]); ?></a> </div> <?php endfor;?> diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index d2b8ad145ae..849e88ee0b2 100644 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -43,22 +43,20 @@ class OC_Crypt { self::init($params['uid'],$params['password']); } - public static function init($login,$password) { - $view1=new OC_FilesystemView('/'); - if(!$view1->file_exists('/'.$login)){ - $view1->mkdir('/'.$login); - } - - $view=new OC_FilesystemView('/'.$login); - - OC_FileProxy::$enabled=false; - if(!$view->file_exists('/encryption.key')){// does key exist? - OC_Crypt::createkey($login,$password); - } - $key=$view->file_get_contents('/encryption.key'); - OC_FileProxy::$enabled=true; - $_SESSION['enckey']=OC_Crypt::decrypt($key, $password); - } + public static function init($login,$password) { + $view=new OC_FilesystemView('/'); + if(!$view->file_exists('/'.$login)){ + $view->mkdir('/'.$login); + } + + OC_FileProxy::$enabled=false; + if(!$view->file_exists('/'.$login.'/encryption.key')){// does key exist? + OC_Crypt::createkey($login,$password); + } + $key=$view->file_get_contents('/'.$login.'/encryption.key'); + OC_FileProxy::$enabled=true; + $_SESSION['enckey']=OC_Crypt::decrypt($key, $password); + } /** @@ -140,7 +138,7 @@ class OC_Crypt { public static function decrypt( $content, $key='') { $bf = self::getBlowfish($key); $data=$bf->decrypt($content); - return rtrim($data, "\0"); + return $data; } /** @@ -181,6 +179,9 @@ class OC_Crypt { while (!feof($handleread)) { $content = fread($handleread, 8192); $enccontent=OC_CRYPT::decrypt( $content, $key); + if(feof($handleread)){ + $enccontent=rtrim($enccontent, "\0"); + } fwrite($handlewrite, $enccontent); } fclose($handlewrite); @@ -203,12 +204,16 @@ class OC_Crypt { /** * decrypt data in 8192b sized blocks */ - public static function blockDecrypt($data, $key=''){ + public static function blockDecrypt($data, $key='',$maxLength=0){ $result=''; while(strlen($data)){ $result.=self::decrypt(substr($data,0,8192),$key); $data=substr($data,8192); } - return $result; + if($maxLength>0){ + return substr($result,0,$maxLength); + }else{ + return rtrim($result, "\0"); + } } } diff --git a/apps/files_encryption/lib/cryptstream.php b/apps/files_encryption/lib/cryptstream.php index a698ee00335..e0020537563 100644 --- a/apps/files_encryption/lib/cryptstream.php +++ b/apps/files_encryption/lib/cryptstream.php @@ -35,6 +35,7 @@ class OC_CryptStream{ private $meta=array();//header/meta for source stream private $count; private $writeCache; + private $size; private static $rootView; public function stream_open($path, $mode, $options, &$opened_path){ @@ -45,9 +46,14 @@ class OC_CryptStream{ if(dirname($path)=='streams' and isset(self::$sourceStreams[basename($path)])){ $this->source=self::$sourceStreams[basename($path)]['stream']; $this->path=self::$sourceStreams[basename($path)]['path']; + $this->size=self::$sourceStreams[basename($path)]['size']; }else{ $this->path=$path; - OCP\Util::writeLog('files_encryption','open encrypted '.$path. ' in '.$mode,OCP\Util::DEBUG); + if($mode=='w' or $mode=='w+' or $mode=='wb' or $mode=='wb+'){ + $this->size=0; + }else{ + $this->size=self::$rootView->filesize($path,$mode); + } OC_FileProxy::$enabled=false;//disable fileproxies so we can open the source file $this->source=self::$rootView->fopen($path,$mode); OC_FileProxy::$enabled=true; @@ -78,12 +84,17 @@ class OC_CryptStream{ OCP\Util::writeLog('files_encryption','php bug 21641 no longer holds, decryption will not work',OCP\Util::FATAL); die(); } + $pos=ftell($this->source); $data=fread($this->source,8192); if(strlen($data)){ $result=OC_Crypt::decrypt($data); }else{ $result=''; } + $length=$this->size-$pos; + if($length<8192){ + $result=substr($result,0,$length); + } return $result; } @@ -104,8 +115,9 @@ class OC_CryptStream{ $data=substr($block,0,$currentPos%8192).$data; fseek($this->source,-($currentPos%8192),SEEK_CUR); } - while(strlen($data)>0){ - if(strlen($data)<8192){ + $currentPos=ftell($this->source); + while($remainingLength=strlen($data)>0){ + if($remainingLength<8192){ $this->writeCache=$data; $data=''; }else{ @@ -114,6 +126,7 @@ class OC_CryptStream{ $data=substr($data,8192); } } + $this->size=max($this->size,$currentPos+$length); return $length; } @@ -157,7 +170,7 @@ class OC_CryptStream{ public function stream_close(){ $this->flush(); if($this->meta['mode']!='r' and $this->meta['mode']!='rb'){ - OC_FileCache::put($this->path,array('encrypted'=>true)); + OC_FileCache::put($this->path,array('encrypted'=>true,'size'=>$this->size),''); } return fclose($this->source); } diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index 9fd57c0f02b..f25e4a662f6 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -59,22 +59,24 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ * @return bool */ private static function isEncrypted($path){ - $metadata=OC_FileCache::getCached($path,''); + $metadata=OC_FileCache_Cached::get($path,''); return isset($metadata['encrypted']) and (bool)$metadata['encrypted']; } public function preFile_put_contents($path,&$data){ if(self::shouldEncrypt($path)){ if (!is_resource($data)) {//stream put contents should have been converter to fopen + $size=strlen($data); $data=OC_Crypt::blockEncrypt($data); - OC_FileCache::put($path,array('encrypted'=>true)); + OC_FileCache::put($path,array('encrypted'=>true,'size'=>$size),''); } } } public function postFile_get_contents($path,$data){ if(self::isEncrypted($path)){ - $data=OC_Crypt::blockDecrypt($data); + $cached=OC_FileCache_Cached::get($path,''); + $data=OC_Crypt::blockDecrypt($data,'',$cached['size']); } return $data; } @@ -108,4 +110,21 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ } return $mime; } + + public function postStat($path,$data){ + if(self::isEncrypted($path)){ + $cached=OC_FileCache_Cached::get($path,''); + $data['size']=$cached['size']; + } + return $data; + } + + public function postFileSize($path,$size){ + if(self::isEncrypted($path)){ + $cached=OC_FileCache_Cached::get($path,''); + return $cached['size']; + }else{ + return $size; + } + } } diff --git a/apps/files_encryption/tests/binary b/apps/files_encryption/tests/binary Binary files differnew file mode 100644 index 00000000000..79bc99479da --- /dev/null +++ b/apps/files_encryption/tests/binary diff --git a/apps/files_encryption/tests/encryption.php b/apps/files_encryption/tests/encryption.php index cf24a225d28..286770a69f5 100644 --- a/apps/files_encryption/tests/encryption.php +++ b/apps/files_encryption/tests/encryption.php @@ -13,6 +13,7 @@ class Test_Encryption extends UnitTestCase { $source=file_get_contents($file); //nice large text file $encrypted=OC_Crypt::encrypt($source,$key); $decrypted=OC_Crypt::decrypt($encrypted,$key); + $decrypted=rtrim($decrypted, "\0"); $this->assertNotEqual($encrypted,$source); $this->assertEqual($decrypted,$source); @@ -20,6 +21,7 @@ class Test_Encryption extends UnitTestCase { $encrypted=OC_Crypt::encrypt($chunk,$key); $this->assertEqual(strlen($chunk),strlen($encrypted)); $decrypted=OC_Crypt::decrypt($encrypted,$key); + $decrypted=rtrim($decrypted, "\0"); $this->assertEqual($decrypted,$chunk); $encrypted=OC_Crypt::blockEncrypt($source,$key); @@ -43,6 +45,7 @@ class Test_Encryption extends UnitTestCase { $source=file_get_contents($file); //binary file $encrypted=OC_Crypt::encrypt($source,$key); $decrypted=OC_Crypt::decrypt($encrypted,$key); + $decrypted=rtrim($decrypted, "\0"); $this->assertEqual($decrypted,$source); $encrypted=OC_Crypt::blockEncrypt($source,$key); @@ -50,4 +53,20 @@ class Test_Encryption extends UnitTestCase { $this->assertEqual($decrypted,$source); } + + function testBinary(){ + $key=uniqid(); + + $file=__DIR__.'/binary'; + $source=file_get_contents($file); //binary file + $encrypted=OC_Crypt::encrypt($source,$key); + $decrypted=OC_Crypt::decrypt($encrypted,$key); + + $decrypted=rtrim($decrypted, "\0"); + $this->assertEqual($decrypted,$source); + + $encrypted=OC_Crypt::blockEncrypt($source,$key); + $decrypted=OC_Crypt::blockDecrypt($encrypted,$key,strlen($source)); + $this->assertEqual($decrypted,$source); + } } diff --git a/apps/files_encryption/tests/proxy.php b/apps/files_encryption/tests/proxy.php index f36b2193430..4533289265a 100644 --- a/apps/files_encryption/tests/proxy.php +++ b/apps/files_encryption/tests/proxy.php @@ -7,8 +7,13 @@ */ class Test_CryptProxy extends UnitTestCase { + private $oldConfig; public function setUp(){ + $this->oldConfig=OCP\Config::getAppValue('files_encryption','enable_encryption','true'); + OCP\Config::setAppValue('files_encryption','enable_encryption','true'); + + //set testing key $_SESSION['enckey']=md5(time()); @@ -29,10 +34,11 @@ class Test_CryptProxy extends UnitTestCase { $rootView->mkdir('/'.OC_User::getUser().'/files'); } + public function tearDown(){ + OCP\Config::setAppValue('files_encryption','enable_encryption',$this->oldConfig); + } + public function testSimple(){ - $oldConfig=OCP\Config::getAppValue('files_encryption','enable_encryption','true'); - OCP\Config::setAppValue('files_encryption','enable_encryption','true'); - $file=OC::$SERVERROOT.'/3rdparty/MDB2.php'; $original=file_get_contents($file); @@ -44,18 +50,59 @@ class Test_CryptProxy extends UnitTestCase { $fromFile=OC_Filesystem::file_get_contents('/file'); $this->assertNotEqual($original,$stored); + $this->assertEqual(strlen($original),strlen($fromFile)); $this->assertEqual($original,$fromFile); + } + + public function testView(){ + $file=OC::$SERVERROOT.'/3rdparty/MDB2.php'; + $original=file_get_contents($file); + $rootView=new OC_FilesystemView(''); $view=new OC_FilesystemView('/'.OC_User::getUser()); $userDir='/'.OC_User::getUser().'/files'; + $rootView->file_put_contents($userDir.'/file',$original); + + OC_FileProxy::$enabled=false; + $stored=$rootView->file_get_contents($userDir.'/file'); + OC_FileProxy::$enabled=true; + + $this->assertNotEqual($original,$stored); $fromFile=$rootView->file_get_contents($userDir.'/file'); $this->assertEqual($original,$fromFile); $fromFile=$view->file_get_contents('files/file'); $this->assertEqual($original,$fromFile); + } + + public function testBinary(){ + $file=__DIR__.'/binary'; + $original=file_get_contents($file); + + OC_Filesystem::file_put_contents('/file',$original); + + OC_FileProxy::$enabled=false; + $stored=OC_Filesystem::file_get_contents('/file'); + OC_FileProxy::$enabled=true; + + $fromFile=OC_Filesystem::file_get_contents('/file'); + $this->assertNotEqual($original,$stored); + $this->assertEqual(strlen($original),strlen($fromFile)); + $this->assertEqual($original,$fromFile); - OCP\Config::setAppValue('files_encryption','enable_encryption',$oldConfig); + $file=__DIR__.'/zeros'; + $original=file_get_contents($file); + + OC_Filesystem::file_put_contents('/file',$original); + + OC_FileProxy::$enabled=false; + $stored=OC_Filesystem::file_get_contents('/file'); + OC_FileProxy::$enabled=true; + + $fromFile=OC_Filesystem::file_get_contents('/file'); + $this->assertNotEqual($original,$stored); + $this->assertEqual(strlen($original),strlen($fromFile)); } } diff --git a/apps/files_encryption/tests/stream.php b/apps/files_encryption/tests/stream.php index b23805d60b0..d95ea792f72 100644 --- a/apps/files_encryption/tests/stream.php +++ b/apps/files_encryption/tests/stream.php @@ -10,23 +10,23 @@ class Test_CryptStream extends UnitTestCase { private $tmpFiles=array(); function testStream(){ - $stream=$this->getStream('test1','w'); + $stream=$this->getStream('test1','w',strlen('foobar')); fwrite($stream,'foobar'); fclose($stream); - $stream=$this->getStream('test1','r'); + $stream=$this->getStream('test1','r',strlen('foobar')); $data=fread($stream,6); fclose($stream); $this->assertEqual('foobar',$data); $file=OC::$SERVERROOT.'/3rdparty/MDB2.php'; $source=fopen($file,'r'); - $target=$this->getStream('test2','w'); + $target=$this->getStream('test2','w',0); OCP\Files::streamCopy($source,$target); fclose($target); fclose($source); - $stream=$this->getStream('test2','r'); + $stream=$this->getStream('test2','r',filesize($file)); $data=stream_get_contents($stream); $original=file_get_contents($file); $this->assertEqual(strlen($original),strlen($data)); @@ -37,9 +37,10 @@ class Test_CryptStream extends UnitTestCase { * get a cryptstream to a temporary file * @param string $id * @param string $mode + * @param int size * @return resource */ - function getStream($id,$mode){ + function getStream($id,$mode,$size){ if($id===''){ $id=uniqid(); } @@ -50,7 +51,35 @@ class Test_CryptStream extends UnitTestCase { $file=$this->tmpFiles[$id]; } $stream=fopen($file,$mode); - OC_CryptStream::$sourceStreams[$id]=array('path'=>'dummy','stream'=>$stream); + OC_CryptStream::$sourceStreams[$id]=array('path'=>'dummy'.$id,'stream'=>$stream,'size'=>$size); return fopen('crypt://streams/'.$id,$mode); } + + function testBinary(){ + $file=__DIR__.'/binary'; + $source=file_get_contents($file); + + $stream=$this->getStream('test','w',strlen($source)); + fwrite($stream,$source); + fclose($stream); + + $stream=$this->getStream('test','r',strlen($source)); + $data=stream_get_contents($stream); + fclose($stream); + $this->assertEqual(strlen($data),strlen($source)); + $this->assertEqual($source,$data); + + $file=__DIR__.'/zeros'; + $source=file_get_contents($file); + + $stream=$this->getStream('test2','w',strlen($source)); + fwrite($stream,$source); + fclose($stream); + + $stream=$this->getStream('test2','r',strlen($source)); + $data=stream_get_contents($stream); + fclose($stream); + $this->assertEqual(strlen($data),strlen($source)); + $this->assertEqual($source,$data); + } } diff --git a/apps/files_encryption/tests/zeros b/apps/files_encryption/tests/zeros Binary files differnew file mode 100644 index 00000000000..ff982acf423 --- /dev/null +++ b/apps/files_encryption/tests/zeros diff --git a/apps/files_external/lib/google.php b/apps/files_external/lib/google.php index c2a4af0ff8a..fe60a06629a 100644 --- a/apps/files_external/lib/google.php +++ b/apps/files_external/lib/google.php @@ -40,7 +40,7 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { $this->entries = array(); } - private function sendRequest($uri, $httpMethod, $postData = null, $extraHeaders = null, $isDownload = false, $returnHeaders = false, $isContentXML = true) { + private function sendRequest($uri, $httpMethod, $postData = null, $extraHeaders = null, $isDownload = false, $returnHeaders = false, $isContentXML = true, $returnHTTPCode = false) { $uri = trim($uri); // create an associative array from each key/value url query param pair. $params = array(); @@ -108,6 +108,8 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { if ($httpCode <= 308) { if ($isDownload) { return $tmpFile; + } else if ($returnHTTPCode) { + return array('result' => $result, 'code' => $httpCode); } else { return $result; } @@ -425,7 +427,7 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { $etag = $entry->getAttribute('gd:etag'); $links = $entry->getElementsByTagName('link'); foreach ($links as $link) { - if ($link->getAttribute('rel') == 'http://schemas.google.com/g/2005#resumable-edit-media') { + if ($link->getAttribute('rel') == 'http://schemas.google.com/g/2005#resumable-create-media') { $uploadUri = $link->getAttribute('href'); break; } @@ -461,12 +463,12 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { } } $end = $i + $chunkSize - 1; - $headers = array('Content-Length: '.$chunkSize, 'Content-Type: '.$mimetype, 'Content Range: bytes '.$i.'-'.$end.'/'.$size); + $headers = array('Content-Length: '.$chunkSize, 'Content-Type: '.$mimetype, 'Content-Range: bytes '.$i.'-'.$end.'/'.$size); $postData = fread($handle, $chunkSize); - $result = $this->sendRequest($uploadUri, 'PUT', $postData, $headers, false, true, false); - if ($result) { - // Get next location to upload file chunk - if (preg_match('@^Location: (.*)$@m', $result, $matches)) { + $result = $this->sendRequest($uploadUri, 'PUT', $postData, $headers, false, true, false, true); + if ($result['code'] == '308') { + if (preg_match('@^Location: (.*)$@m', $result['result'], $matches)) { + // Get next location to upload file chunk $uploadUri = trim($matches[1]); } $i += $chunkSize; diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index 9112655194a..5e34deb2337 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -47,6 +47,52 @@ class OC_FileStorage_SMB extends OC_FileStorage_StreamWrapper{ $path=substr($path,0,-1); } return 'smb://'.$this->user.':'.$this->password.'@'.$this->host.$this->share.$this->root.$path; - + } + + public function stat($path){ + if(!$path and $this->root=='/'){//mtime doesn't work for shares + $mtime=$this->shareMTime(); + $stat=stat($this->constructUrl($path)); + $stat['mtime']=$mtime; + return $stat; + }else{ + return stat($this->constructUrl($path)); + } + } + + public function filetype($path){ + return (bool)@$this->opendir($path);//using opendir causes the same amount of requests and caches the content of the folder in one go + } + + /** + * check if a file or folder has been updated since $time + * @param int $time + * @return bool + */ + public function hasUpdated($path,$time){ + if(!$path and $this->root=='/'){ + //mtime doesn't work for shares, but giving the nature of the backend, doing a full update is still just fast enough + return true; + }else{ + $actualTime=$this->filemtime($path); + return $actualTime>$time; + } + } + + /** + * get the best guess for the modification time of the share + */ + private function shareMTime(){ + $dh=$this->opendir(''); + $lastCtime=0; + while($file=readdir($dh)){ + if($file!='.' and $file!='..'){ + $ctime=$this->filemtime($file); + if($ctime>$lastCtime){ + $lastCtime=$ctime; + } + } + } + return $lastCtime; } } diff --git a/apps/files_imageviewer/js/lightbox.js b/apps/files_imageviewer/js/lightbox.js index 69cda7a0ecc..31f08456d22 100644 --- a/apps/files_imageviewer/js/lightbox.js +++ b/apps/files_imageviewer/js/lightbox.js @@ -22,7 +22,7 @@ function viewImage(dir, file) { if(file.indexOf('.psd')>0){//can't view those return; } - var location=OC.filePath('files','ajax','download.php')+'?files='+encodeURIComponent(file)+'&dir='+encodeURIComponent(dir); + var location=OC.filePath('files','ajax','download.php')+encodeURIComponent('?files='+encodeURIComponent(file)+'&dir='+encodeURIComponent(dir)); $.fancybox({ "href": location, "title": file.replace(/</, "<").replace(/>/, ">"), diff --git a/apps/files_pdfviewer/js/viewer.js b/apps/files_pdfviewer/js/viewer.js index d98bedc5c09..2c9cbb9b431 100644 --- a/apps/files_pdfviewer/js/viewer.js +++ b/apps/files_pdfviewer/js/viewer.js @@ -13,7 +13,7 @@ function hidePDFviewer() { function showPDFviewer(dir,filename){ if(!showPDFviewer.shown){ $("#editor").hide(); - var url = OC.filePath('files','ajax','download.php')+'?files='+encodeURIComponent(filename)+"&dir="+encodeURIComponent(dir); + var url = OC.filePath('files','ajax','download.php')+encodeURIComponent('?files='+encodeURIComponent(filename)+"&dir="+encodeURIComponent(dir)); $('table').hide(); function im(path) { return OC.filePath('files_pdfviewer','js','pdfjs/web/images/'+path); } showPDFviewer.oldcode = $("#controls").html(); diff --git a/apps/files_sharing/appinfo/app.php b/apps/files_sharing/appinfo/app.php index ea3a9da6f7a..bbb753d5e69 100644 --- a/apps/files_sharing/appinfo/app.php +++ b/apps/files_sharing/appinfo/app.php @@ -1,15 +1,20 @@ <?php -require_once('apps/files_sharing/sharedstorage.php'); - OC::$CLASSPATH['OC_Share'] = "apps/files_sharing/lib_share.php"; +OC::$CLASSPATH['OC_Filestorage_Shared'] = "apps/files_sharing/sharedstorage.php"; + OCP\App::registerAdmin('files_sharing', 'settings'); + +OCP\Util::connectHook('OC_Filesystem', 'setup', 'OC_Filestorage_Shared', 'setup'); + OCP\Util::connectHook("OC_Filesystem", "post_delete", "OC_Share", "deleteItem"); OCP\Util::connectHook("OC_Filesystem", "post_rename", "OC_Share", "renameItem"); OCP\Util::connectHook("OC_Filesystem", "post_write", "OC_Share", "updateItem"); + OCP\Util::connectHook('OC_User', 'post_deleteUser', 'OC_Share', 'removeUser'); OCP\Util::connectHook('OC_User', 'post_addToGroup', 'OC_Share', 'addToGroupShare'); OCP\Util::connectHook('OC_User', 'post_removeFromGroup', 'OC_Share', 'removeFromGroupShare'); + $dir = isset($_GET['dir']) ? $_GET['dir'] : '/'; if ($dir != '/Shared' || OCP\Config::getAppValue('files_sharing', 'resharing', 'yes') == 'yes') { OCP\Util::addscript("files_sharing", "share"); diff --git a/apps/files_sharing/get.php b/apps/files_sharing/get.php index e2fcb82750d..1ab8c6a257f 100644 --- a/apps/files_sharing/get.php +++ b/apps/files_sharing/get.php @@ -61,7 +61,7 @@ if (isset($_GET['token']) && $source = OC_Share::getSource($_GET['token'])) { $list->assign("downloadURL", OCP\Util::linkTo("", "public.php")."?service=files&token=".$token."&path="); $list->assign("readonly", true); $tmpl = new OCP\Template("files", "index", "user"); - $tmpl->assign("fileList", $list->fetchPage()); + $tmpl->assign("fileList", $list->fetchPage(), false); $tmpl->assign("breadcrumb", $breadcrumbNav->fetchPage()); $tmpl->assign("readonly", true); $tmpl->assign("allowZipDownload", false); @@ -77,6 +77,7 @@ if (isset($_GET['token']) && $source = OC_Share::getSource($_GET['token'])) { header("Content-Length: " . OC_Filesystem::filesize($source)); //download the file @ob_clean(); + OCP\Util::emitHook('OC_Share', 'public-download', array('source'=>$source, 'token'=>$token); OC_Filesystem::readfile($source); } } else { diff --git a/apps/files_sharing/lib_share.php b/apps/files_sharing/lib_share.php index 4abf80ae19c..6e092269250 100644 --- a/apps/files_sharing/lib_share.php +++ b/apps/files_sharing/lib_share.php @@ -47,6 +47,7 @@ class OC_Share { } if ($uid_shared_with == self::PUBLICLINK) { $token = sha1("$uid_shared_with-$source"); + OCP\Util::emitHook('OC_Share', 'public', array('source'=>$source, 'token'=>$token, 'permissions'=>$permissions)); $query->execute(array($uid_owner, self::PUBLICLINK, $source, $token, $permissions)); $this->token = $token; } else { @@ -118,6 +119,7 @@ class OC_Share { if (isset($gid)) { $uid = $uid."@".$gid; } + OCP\Util::emitHook('OC_Share', 'user', array('source'=>$source, 'target'=>$target, 'with'=>$uid, 'permissions'=>$permissions)); $query->execute(array($uid_owner, $uid, $source, $target, $permissions)); } } diff --git a/apps/files_sharing/sharedstorage.php b/apps/files_sharing/sharedstorage.php index 3bb6e73035e..62c86ee18e4 100644 --- a/apps/files_sharing/sharedstorage.php +++ b/apps/files_sharing/sharedstorage.php @@ -320,6 +320,11 @@ class OC_Filestorage_Shared extends OC_Filestorage { public function file_get_contents($path) { $source = $this->getSource($path); if ($source) { + $info = array( + 'target' => $this->datadir.$path, + 'source' => $source, + ); + OCP\Util::emitHook('OC_Filestorage_Shared', 'file_get_contents', $info); $storage = OC_Filesystem::getStorage($source); return $storage->file_get_contents($this->getInternalPath($source)); } @@ -329,6 +334,11 @@ class OC_Filestorage_Shared extends OC_Filestorage { if ($this->is_writable($path)) { $source = $this->getSource($path); if ($source) { + $info = array( + 'target' => $this->datadir.$path, + 'source' => $source, + ); + OCP\Util::emitHook('OC_Filestorage_Shared', 'file_put_contents', $info); $storage = OC_Filesystem::getStorage($source); $result = $storage->file_put_contents($this->getInternalPath($source), $data); if ($result) { @@ -416,6 +426,12 @@ class OC_Filestorage_Shared extends OC_Filestorage { public function fopen($path, $mode) { $source = $this->getSource($path); if ($source) { + $info = array( + 'target' => $this->datadir.$path, + 'source' => $source, + 'mode' => $mode, + ); + OCP\Util::emitHook('OC_Filestorage_Shared', 'fopen', $info); $storage = OC_Filesystem::getStorage($source); return $storage->fopen($this->getInternalPath($source), $mode); } @@ -508,16 +524,18 @@ class OC_Filestorage_Shared extends OC_Filestorage { } } - public static function setup() { - OC_Filesystem::mount('OC_Filestorage_Shared', array('datadir' => '/'.OCP\USER::getUser().'/files/Shared'), '/'.OCP\USER::getUser().'/files/Shared/'); + public static function setup($options) { + $user_dir = $options['user_dir']; + OC_Filesystem::mount('OC_Filestorage_Shared', array('datadir' => $user_dir.'/Shared'), $user_dir.'/Shared/'); } + /** + * check if a file or folder has been updated since $time + * @param int $time + * @return bool + */ + public function hasUpdated($path,$time){ + //TODO + return $this->filemtime($path)>$time; + } } - -if (OCP\USER::isLoggedIn()) { - OC_Filestorage_Shared::setup(); -} else { - OCP\Util::connectHook('OC_User', 'post_login', 'OC_Filestorage_Shared', 'setup'); -} - -?> diff --git a/apps/files_sharing_log/appinfo/app.php b/apps/files_sharing_log/appinfo/app.php new file mode 100644 index 00000000000..23cae61fbf4 --- /dev/null +++ b/apps/files_sharing_log/appinfo/app.php @@ -0,0 +1,22 @@ +<?php +/** + * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +OC::$CLASSPATH['OC_Files_Sharing_Log'] = 'apps/files_sharing_log/log.php'; + +$l=new OC_L10N('files_sharing_log'); +OCP\App::addNavigationEntry( array( + 'id' => 'files_sharing_log_index', + 'order' => 5, + 'href' => OCP\Util::linkTo( 'files_sharing_log', 'index.php' ), + 'icon' => OCP\Util::imagePath( 'files_sharing_log', 'icon.png' ), + 'name' => $l->t('Shared files log')) +); + +OCP\Util::connectHook('OC_Filestorage_Shared', 'fopen', 'OC_Files_Sharing_Log', 'fopen'); +OCP\Util::connectHook('OC_Filestorage_Shared', 'file_get_contents', 'OC_Files_Sharing_Log', 'file_get_contents'); +OCP\Util::connectHook('OC_Filestorage_Shared', 'file_put_contents', 'OC_Files_Sharing_Log', 'file_put_contents'); diff --git a/apps/files_sharing_log/appinfo/database.xml b/apps/files_sharing_log/appinfo/database.xml new file mode 100644 index 00000000000..92e5f0125bd --- /dev/null +++ b/apps/files_sharing_log/appinfo/database.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> +<database> + <name>*dbname*</name> + <create>true</create> + <overwrite>false</overwrite> + <charset>latin1</charset> + <table> + <name>*dbprefix*sharing_log</name> + <declaration> + <field> + <name>user_id</name> + <type>text</type> + <notnull>true</notnull> + <length>64</length> + </field> + <field> + <name>source</name> + <type>text</type> + <notnull>true</notnull> + <length>128</length> + </field> + <field> + <name>uid_who</name> + <type>text</type> + <notnull>true</notnull> + <length>64</length> + </field> + <field> + <name>when</name> + <type>integer</type> + <default></default> + <notnull>false</notnull> + <unsigned>true</unsigned> + <length>4</length> + </field> + <field> + <name>mode</name> + <type>text</type> + <notnull>true</notnull> + <length>4</length> + </field> + </declaration> + </table> +</database> diff --git a/apps/files_sharing_log/appinfo/info.xml b/apps/files_sharing_log/appinfo/info.xml new file mode 100644 index 00000000000..d5e3283df3f --- /dev/null +++ b/apps/files_sharing_log/appinfo/info.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<info> + <id>files_sharing_log</id> + <name>File Shared access logging app</name> + <description>Log access to shared files</description> + <licence>AGPL</licence> + <author>Bart Visscher</author> + <require>4</require> + <shipped>true</shipped> +</info> diff --git a/apps/files_sharing_log/appinfo/version b/apps/files_sharing_log/appinfo/version new file mode 100644 index 00000000000..49d59571fbf --- /dev/null +++ b/apps/files_sharing_log/appinfo/version @@ -0,0 +1 @@ +0.1 diff --git a/apps/files_sharing_log/css/style.css b/apps/files_sharing_log/css/style.css new file mode 100644 index 00000000000..069d3a45e0d --- /dev/null +++ b/apps/files_sharing_log/css/style.css @@ -0,0 +1,7 @@ +#files_sharing_log { +padding: 2em; +} +#files_sharing_log th, +#files_sharing_log td { +padding: 0 1em; +} diff --git a/apps/files_sharing_log/index.php b/apps/files_sharing_log/index.php new file mode 100644 index 00000000000..ffacbdd8604 --- /dev/null +++ b/apps/files_sharing_log/index.php @@ -0,0 +1,21 @@ +<?php +/** + * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +OCP\User::checkLoggedIn(); +OCP\App::checkAppEnabled('files_sharing_log'); + +OCP\App::setActiveNavigationEntry('files_sharing_log_index'); + +OCP\Util::addStyle('files_sharing_log', 'style'); + +$query = OCP\DB::prepare('SELECT * FROM *PREFIX*sharing_log WHERE user_id = ?'); +$log = $query->execute(array(OCP\User::getUser()))->fetchAll(); + +$output = new OCP\Template('files_sharing_log', 'index', 'user'); +$output->assign('log', $log); +$output->printPage(); diff --git a/apps/files_sharing_log/log.php b/apps/files_sharing_log/log.php new file mode 100644 index 00000000000..e6a12b9fb1d --- /dev/null +++ b/apps/files_sharing_log/log.php @@ -0,0 +1,34 @@ +<?php + +class OC_Files_Sharing_Log { + static public function fopen($arguments) { + $target = $arguments['target']; + $source = $arguments['source']; + $mode = $arguments['mode']; + self::log($target, $source, $mode); + } + + static public function file_get_contents($arguments) { + $target = $arguments['target']; + $source = $arguments['source']; + $mode = 'get'; + self::log($target, $source, $mode); + } + + static public function file_put_contents($arguments) { + $target = $arguments['target']; + $source = $arguments['source']; + $mode = 'put'; + self::log($target, $source, $mode); + } + + static public function log($target, $source, $mode) { + $query = OCP\DB::prepare("SELECT * FROM *PREFIX*sharing WHERE source = ? AND target = ?"); + $info = $query->execute(array($source, $target))->fetchAll(); + $info = $info[0]; + //var_dump($info); + $query = OCP\DB::prepare("INSERT INTO *PREFIX*sharing_log VALUES (?,?,?,?,?)"); + $query->execute(array($info['uid_owner'], $source, OCP\User::getUser(), time(), $mode)); + //die; + } +} diff --git a/apps/files_sharing_log/templates/index.php b/apps/files_sharing_log/templates/index.php new file mode 100644 index 00000000000..55bfc1d6a3c --- /dev/null +++ b/apps/files_sharing_log/templates/index.php @@ -0,0 +1,42 @@ +<table id="files_sharing_log"> + <thead> + <tr> + <th><?php echo $l->t('File') ?></th> + <th><?php echo $l->t('Who') ?></th> + <th><?php echo $l->t('When') ?></th> + <th><?php echo $l->t('What') ?></th> + </tr> + </thead> + <tbody> + <?php foreach($_['log'] as $log): ?> + <tr> + <td> + <?php echo $log['source'] ?> + </td> + <td> + <?php echo $log['uid_who'] ?> + </td> + <td> + <?php echo date('Y-m-d H:i:s', $log['when']) ?> + </td> + <td> + <?php switch ($log['mode']): + case 'get': + echo $l->t('Read'); + break; + case 'put': + echo $l->t('Write'); + break; + default: + if (strpos('r', $log['mode']) !== false): + echo $l->t('Read'); + else: + echo $l->t('Write'); + endif; + endswitch; + ?> + </td> + </tr> + <?php endforeach; ?> + </tbody> +</table> diff --git a/apps/files_texteditor/js/editor.js b/apps/files_texteditor/js/editor.js index 70bb74a9101..9d168c1c4f6 100644 --- a/apps/files_texteditor/js/editor.js +++ b/apps/files_texteditor/js/editor.js @@ -67,7 +67,7 @@ function setSyntaxMode(ext){ function showControls(filename,writeperms){ // Loads the control bar at the top. // Load the new toolbar. - var editorbarhtml = '<div id="editorcontrols" style="display: none;"><div class="crumb svg last" id="breadcrumb_file" style="background-image:url("'+OC.imagePath('core','breadcrumb.png')+'")"><p>'+filename.replace(/</, "<").replace(/>/, ">")+'</p></div>'; + var editorbarhtml = '<div id="editorcontrols" style="display: none;"><div class="crumb svg last" id="breadcrumb_file" style="background-image:url("'+OC.imagePath('core','breadcrumb.png')+'")"><p>'+filename+'</p></div>'; if(writeperms=="true"){ editorbarhtml += '<button id="editor_save">'+t('files_texteditor','Save')+'</button><div class="separator"></div>'; } diff --git a/apps/files_versions/ajax/expireAll.php b/apps/files_versions/ajax/expireAll.php new file mode 100644 index 00000000000..f9cd74aed02 --- /dev/null +++ b/apps/files_versions/ajax/expireAll.php @@ -0,0 +1,41 @@ +<?php + +/** + * ownCloud - user_migrate + * + * @author Sam Tuke + * @copyright 2012 Sam Tuke samtuke@owncloud.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +// TODO: Allow admins to expire versions of any user +// TODO: Provide feedback as to how many versions were deleted + +// Check user and app status +OCP\JSON::checkLoggedIn(); +OCP\App::checkAppEnabled('files_versions'); + +if( OCA_Versions\Storage::expireAll() ){ + + OCP\JSON::success(); + die(); + +} else { + + OCP\JSON::error(); + die(); + +}
\ No newline at end of file diff --git a/apps/files_versions/appinfo/app.php b/apps/files_versions/appinfo/app.php index 49f1573f7c2..ef2f54dd3f9 100644 --- a/apps/files_versions/appinfo/app.php +++ b/apps/files_versions/appinfo/app.php @@ -3,7 +3,9 @@ require_once('apps/files_versions/versions.php'); OCP\App::registerAdmin('files_versions', 'settings'); +OCP\App::registerPersonal('files_versions','settings-personal'); + OCP\Util::addscript('files_versions', 'versions'); // Listen to write signals -OCP\Util::connectHook(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_write, "OCA_Versions\Storage", "write_hook"); +OCP\Util::connectHook('OC_Filesystem', 'post_write', "OCA_Versions\Storage", "write_hook");
\ No newline at end of file diff --git a/apps/files_versions/js/settings-personal.js b/apps/files_versions/js/settings-personal.js new file mode 100644 index 00000000000..6ea8c1a950f --- /dev/null +++ b/apps/files_versions/js/settings-personal.js @@ -0,0 +1,39 @@ +// TODO: allow the button to be clicked only once + +$( document ).ready(function(){ + // + $( '#expireAllBtn' ).click( + + function( event ) { + + // Prevent page from reloading + event.preventDefault(); + + // Show loading gif + $('.expireAllLoading').show(); + + $.getJSON( + OC.filePath('files_versions','ajax','expireAll.php'), + function(result){ + if (result.status == 'success') { + $('.expireAllLoading').hide(); + $('#expireAllBtn').html('Expiration successful'); + } else { + + // Cancel loading + $('#expireAllBtn').html('Expiration failed'); + + // Show Dialog + OC.dialogs.alert( + 'Something went wrong, your files may not have been expired', + 'An error has occurred', + function(){ + $('#expireAllBtn').html(t('files_versions', 'Expire all versions')+'<img style="display: none;" class="loading" src="'+OC.filePath('core','img','loading.gif')+'" />'); + } + ); + } + } + ); + } + ); +});
\ No newline at end of file diff --git a/apps/files_versions/settings-personal.php b/apps/files_versions/settings-personal.php new file mode 100644 index 00000000000..db80172979d --- /dev/null +++ b/apps/files_versions/settings-personal.php @@ -0,0 +1,8 @@ +<?php + +$tmpl = new OCP\Template( 'files_versions', 'settings-personal'); + +OCP\Util::addscript('files_versions','settings-personal'); + +return $tmpl->fetchPage(); +?>
\ No newline at end of file diff --git a/apps/files_versions/templates/settings-personal.php b/apps/files_versions/templates/settings-personal.php new file mode 100644 index 00000000000..7ff016b585e --- /dev/null +++ b/apps/files_versions/templates/settings-personal.php @@ -0,0 +1,9 @@ +<form id="versions"> + <fieldset class="personalblock"> + <legend> + <strong>Versions</strong><!-- translate using echo $l->t('foo'); --> + </legend> + <p>This will delete all existing backup versions of your files</p><!-- translate using echo $l->t('foo'); --> + <button id="expireAllBtn">Expire all versions<img style="display: none;" class="expireAllLoading" src="<?php echo OCP\Util::linkTo('core', 'img/loading.gif'); ?>" /></button> + </fieldset> +</form>
\ No newline at end of file diff --git a/apps/files_versions/versions.php b/apps/files_versions/versions.php index 44ce7c635aa..7522538caf2 100644 --- a/apps/files_versions/versions.php +++ b/apps/files_versions/versions.php @@ -303,66 +303,86 @@ class Storage { */ public static function expireAll() { - function deleteAll($directory, $empty = false) { + function deleteAll( $directory, $empty = false ) { - if(substr($directory,-1) == "/") { - $directory = substr($directory,0,-1); + // strip leading slash + if( substr( $directory, 0, 1 ) == "/" ) { + + $directory = substr( $directory, 1 ); + + } + + // strip trailing slash + if( substr( $directory, -1) == "/" ) { + + $directory = substr( $directory, 0, -1 ); + } - if(!file_exists($directory) || !is_dir($directory)) { + $view = new \OC_FilesystemView(''); + + if ( !$view->file_exists( $directory ) || !$view->is_dir( $directory ) ) { return false; - } elseif(!is_readable($directory)) { + } elseif( !$view->is_readable( $directory ) ) { return false; } else { - $directoryHandle = opendir($directory); - - while ($contents = readdir($directoryHandle)) { + $foldername = \OCP\Config::getSystemValue('datadirectory') .'/' . \OCP\USER::getUser() .'/' . $directory; // have to set an absolute path for use with PHP's opendir as OC version doesn't work + + $directoryHandle = $view->opendir( \OCP\USER::getUser() . '/' . $directory ); - if( $contents != '.' && $contents != '..') { + while ( $contents = readdir( $directoryHandle ) ) { + + if ( $contents != '.' && $contents != '..') { $path = $directory . "/" . $contents; - if( is_dir($path) ) { + if ( $view->is_dir( $path ) ) { - deleteAll($path); + deleteAll( $path ); } else { - - unlink($path); + + $view->unlink( \OCP\USER::getUser() .'/' . $path ); // TODO: make unlink use same system path as is_dir } } } - closedir( $directoryHandle ); + //$view->closedir( $directoryHandle ); // TODO: implement closedir in OC_FSV - if( $empty == false ) { + if ( $empty == false ) { - if(!rmdir($directory)) { + if ( !$view->rmdir( $directory ) ) { return false; } - } + } return true; } } + + $dir = \OCP\Config::getSystemValue('files_versionsfolder', Storage::DEFAULTFOLDER); + + if ( deleteAll( $dir, true ) ) { + + return true; + + } else { + + return false; + + } - /* - // FIXME: make this path dynamic - $dir = '/home/samtuke/owncloud/git/oc5/data/admin/versions'; - - ( deleteAll( $dir, 1 ) ? return true : return false ); - */ } diff --git a/apps/gallery/css/styles.css b/apps/gallery/css/styles.css index 98d36515493..dcef1f08c6d 100644 --- a/apps/gallery/css/styles.css +++ b/apps/gallery/css/styles.css @@ -4,3 +4,11 @@ div#controls input[type=button] { -webkit-transition: opacity 0.5s ease-in-out; input[type=button]:disabled { opacity: 0.5 } .ui-dialog tr {background-color: #eee;} .ui-dialog input {width: 90%;} + +div.gallery_div {position:relative; display: inline-block; height: 152px; width: 150px; margin: 5px;} +div.miniature_border {position:absolute; height: 150px; -moz-transition-duration: 0.2s; -o-transition-duration:0.2s; -webkit-transition-duration: .2s; background-position: 50%;} +div.line {display:inline-block; border: 0; width: auto; height: 160px} +div.gallery_div img{position:absolute; top: 1; left: 0; -moz-transition-duration: 0.3s; -o-transition-duration:0.3s; -webkit-transition-duration: 0.3s; height:150px; width: auto;} +div.gallery_div img.shrinker {width:80px !important;} +div.title { opacity: 0; text-align: center; vertical-align: middle; font-family: Arial; font-size: 12px; border: 0; position: absolute; text-overflow: ellipsis; bottom: 20px; right:-5px; height:auto; padding: 5px; width: 140px; background-color: black; color: white; -webkit-transition: opacity 0.5s; z-index:1000; border-radius: 7px} +div.visible { opacity: 0.8;} diff --git a/apps/gallery/index.php b/apps/gallery/index.php index b87d99bb6cc..c08305bff9e 100644 --- a/apps/gallery/index.php +++ b/apps/gallery/index.php @@ -31,6 +31,70 @@ OCP\Util::addStyle('files', 'files'); OCP\Util::addStyle('gallery', 'styles'); OCP\Util::addScript('gallery', 'pictures'); +include('apps/gallery/lib/tiles.php'); + +$root = !empty($_GET['root']) ? $_GET['root'] : '/'; +$images = \OC_FileCache::searchByMime('image', null, '/'.\OCP\USER::getUser().'/files'.$root); +sort($images); + +$tl = new \OC\Pictures\TilesLine(); +$ts = new \OC\Pictures\TileStack(array(), ''); +$previous_element = @$images[0]; + +$root_images = array(); +$second_level_images = array(); + +$fallback_images = array(); // if the folder only cotains subfolders with images -> these are taken for the stack preview + +for($i = 0; $i < count($images); $i++) { + $prev_dir_arr = explode('/', $previous_element); + $dir_arr = explode('/', $images[$i]); + + if(count($dir_arr) == 1) { // getting the images in this directory + $root_images[] = $root.$images[$i]; + } else { + if(strcmp($prev_dir_arr[0], $dir_arr[0]) != 0) { // if we entered a new directory + if(count($second_level_images) == 0) { // if we don't have images in this directory + if(count($fallback_images) != 0) { // but have fallback_images + $tl->addTile(new \OC\Pictures\TileStack($fallback_images, $prev_dir_arr[0])); + $fallback_images = array(); + } + } else { // if we collected images for this directory + $tl->addTile(new \OC\Pictures\TileStack($second_level_images, $prev_dir_arr[0])); + $fallback_images = array(); + $second_level_images = array(); + } + } + if (count($dir_arr) == 2) { // These are the pics in our current subdir + $second_level_images[] = $root.$images[$i]; + $fallback_images = array(); + } else { // These are images from the deeper directories + if(count($second_level_images) == 0) { + $fallback_images[] = $root.$images[$i]; + } + } + // have us a little something to compare against + $previous_element = $images[$i]; + } +} + +// if last element in the directory was a directory we don't want to miss it :) +if(count($second_level_images)>0) { + $tl->addTile(new \OC\Pictures\TileStack($second_level_images, $prev_dir_arr[0])); +} + +// if last element in the directory was a directory with no second_level_images we also don't want to miss it ... +if(count($fallback_images)>0) { + $tl->addTile(new \OC\Pictures\TileStack($fallback_images, $prev_dir_arr[0])); +} + +// and finally our images actually stored in the root folder +for($i = 0; $i<count($root_images); $i++) { + $tl->addTile(new \OC\Pictures\TileSingle($root_images[$i])); +} + $tmpl = new OCP\Template( 'gallery', 'index', 'user' ); +$tmpl->assign('root', $root); +$tmpl->assign('tl', $tl, false); $tmpl->printPage(); ?> diff --git a/apps/gallery/js/pictures.js b/apps/gallery/js/pictures.js index 678c9bcbf55..3a797889688 100644 --- a/apps/gallery/js/pictures.js +++ b/apps/gallery/js/pictures.js @@ -1,4 +1,3 @@ - function constructSharingPath() { return document.location.protocol + '//' + document.location.host + OC.linkTo('', 'public.php') + '?service=gallery&token=' + Albums.token; } @@ -35,3 +34,35 @@ function shareGallery() { }); }); } + +function explode(element) { + $('div', element).each(function(index, elem) { + if ($(elem).hasClass('title')) { + $(elem).addClass('visible'); + } else { + $(elem).css('margin-top', Math.floor(30-(Math.random()*60)) + 'px') + .css('margin-left', Math.floor(30-(Math.random()*60))+ 'px') + .css('z-index', '999'); + } + }); +} + +function deplode(element) { + $('div', element).each(function(index, elem) { + if ($(elem).hasClass('title')) { + $(elem).removeClass('visible'); + } else { + $(elem).css('margin-top', Math.floor(5-(Math.random()*10)) + 'px') + .css('margin-left', Math.floor(5-(Math.random()*10))+ 'px') + .css('z-index', '3'); + } + }); +} + +function openNewGal(album_name) { + root = root + album_name + "/"; + var url = window.location.toString().replace(window.location.search, ''); + url = url + "?app=gallery&root="+encodeURIComponent(root); + + window.location = url; +} diff --git a/apps/gallery/lib/hooks_handlers.php b/apps/gallery/lib/hooks_handlers.php index a9f4dc6affc..093979834da 100644 --- a/apps/gallery/lib/hooks_handlers.php +++ b/apps/gallery/lib/hooks_handlers.php @@ -21,7 +21,7 @@ * */ -OCP\Util::connectHook(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_delete, "OC_Gallery_Hooks_Handlers", "removePhoto"); +OCP\Util::connectHook('OC_Filesystem', 'delete', "OC_Gallery_Hooks_Handlers", "removePhoto"); //OCP\Util::connectHook(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_rename, "OC_Gallery_Hooks_Handlers", "renamePhoto"); require_once(OC::$CLASSPATH['Pictures_Managers']); diff --git a/apps/gallery/lib/tiles.php b/apps/gallery/lib/tiles.php index e43c99bb76a..2ff4fa5647b 100644 --- a/apps/gallery/lib/tiles.php +++ b/apps/gallery/lib/tiles.php @@ -63,7 +63,7 @@ class TilesLine { $img_w = $this->tiles_array[$i]->getWidth(); $extra = ''; if ($img_w != IMAGE_WIDTH) $extra = ' style="width:'.$img_w.'px"'; - $r .= '<div class="gallery_div" '.$extra.' onmouseover="'.$this->tiles_array[$i]->getOnHoverAction().'" onmouseout="'.$this->tiles_array[$i]->getOnOutAction().'" onclick="'.$this->tiles_array[$i]->getOnClickAction().'">'.$this->tiles_array[$i]->get().'</div>'; + $r .= '<div class="gallery_div" '.$extra.' onmouseover="'.$this->tiles_array[$i]->getOnHoverAction().'" onmouseout="'.$this->tiles_array[$i]->getOnOutAction().'" onclick="'.$this->tiles_array[$i]->getOnClickAction().'" style="background-color:#ddd">'.$this->tiles_array[$i]->get().'</div>'; } $r .= '</div>'; @@ -122,7 +122,7 @@ class TileStack extends TileBase { $this->tiles_array = array(); $this->stack_name = $stack_name; for ($i = 0; $i < count($path_array) && $i < self::STACK_REPRESENTATIVES; $i++) { - $tile = new TileSingle($path_array[$i]); + $tile = new TileSingle($path_array[$i]); array_push($this->tiles_array, $tile); } } diff --git a/apps/gallery/templates/index.php b/apps/gallery/templates/index.php index 749f8891f81..1890552fc0c 100644 --- a/apps/gallery/templates/index.php +++ b/apps/gallery/templates/index.php @@ -1,52 +1,6 @@ -<?php - -$l = OC_L10N::get('gallery'); -$root = !empty($_GET['root']) ? $_GET['root'] : '/'; -?> -<style> -div.gallery_div {position:relative; display: inline-block; height: 152px; width: 150px; margin: 5px;} -div.miniature_border {position:absolute; height: 150px; -moz-transition-duration: 0.2s; -o-transition-duration:0.2s; -webkit-transition-duration: .2s; background-position: 50%;} -div.line {display:inline-block; border: 0; width: auto; height: 160px} -div.gallery_div img{position:absolute; top: 1; left: 0; -moz-transition-duration: 0.3s; -o-transition-duration:0.3s; -webkit-transition-duration: 0.3s; height:150px; width: auto;} -div.gallery_div img.shrinker {width:80px !important;} -div.title { opacity: 0; text-align: center; vertical-align: middle; font-family: Arial; font-size: 12px; border: 0; position: absolute; text-overflow: ellipsis; bottom: 20px; left:5px; height:auto; padding: 5px; width: 140px; background-color: black; color: white; -webkit-transition: opacity 0.5s; z-index:1000; border-radius: 7px} -div.visible { opacity: 0.8;} -</style> <script type="text/javascript"> -var root = "<?php echo htmlentities($root); ?>"; - -function explode(element) { - $('div', element).each(function(index, elem) { - if ($(elem).hasClass('title')) { - $(elem).addClass('visible'); - } else { - $(elem).css('margin-top', Math.floor(30-(Math.random()*60)) + 'px') - .css('margin-left', Math.floor(30-(Math.random()*60))+ 'px') - .css('z-index', '999'); - } - }); -} - -function deplode(element) { - $('div', element).each(function(index, elem) { - if ($(elem).hasClass('title')) { - $(elem).removeClass('visible'); - } else { - $(elem).css('margin-top', Math.floor(5-(Math.random()*10)) + 'px') - .css('margin-left', Math.floor(5-(Math.random()*10))+ 'px') - .css('z-index', '3'); - } - }); -} - -function openNewGal(album_name) { - root = root + album_name + "/"; - var url = window.location.toString().replace(window.location.search, ''); - url = url + "?app=gallery&root="+encodeURIComponent(root); - - window.location = url; -} +var root = "<?php echo $_['root']; ?>"; $(document).ready(function() { $("a[rel=images]").fancybox({ @@ -57,7 +11,7 @@ $(document).ready(function() { </script> <div id="controls"><?php - $sr = trim($root, '/'); + $sr = trim($_['root'], '/'); if (!empty($sr)) { $paths = explode('/', $sr); $path = '/'; @@ -68,53 +22,12 @@ $(document).ready(function() { } } -?> <!--<a href="javascript:shareGallery();"><input type="button" value="<?php echo $l->t('Share');?>" /></a>--><br/> +?><br/> </div> <div id="gallerycontent"> <?php -include('apps/gallery/lib/tiles.php'); -$root = empty($_GET['root'])?'/':$_GET['root']; - -$images = \OC_FileCache::searchByMime('image', null, '/'.\OCP\USER::getUser().'/files'.$root); -sort($images); - -$arr = array(); -$tl = new \OC\Pictures\TilesLine(); -$ts = new \OC\Pictures\TileStack(array(), ''); -$previous_element = @$images[0]; -for($i = 0; $i < count($images); $i++) { - $prev_dir_arr = explode('/', $previous_element); - $dir_arr = explode('/', $images[$i]); - - if (count($dir_arr)==1) { - $tl->addTile(new \OC\Pictures\TileSingle($root.$images[$i])); - continue; - } - if (strcmp($prev_dir_arr[0], $dir_arr[0])!=0) { - $tl->addTile(new \OC\Pictures\TileStack($arr, $prev_dir_arr[0])); - $arr = array(); - } - $arr[] = $root.$images[$i]; - $previous_element = $images[$i]; -} - -$dir_arr = explode('/', $previous_element); - -if (count($images)>1 && count($dir_arr) > 1) { - if (count($dir_arr) && $ts->getCount() == 0){ - $ts = new \OC\Pictures\TileStack(array($root.$previous_element), $dir_arr[0]); - } else { - $arr[] = $previous_element; - $ts->addTile($arr); - } -} - -if ($ts->getCount() != 0) { - $tl->addTile($ts); -} - -echo $tl->get(); +echo $_['tl']->get(); ?> </div> diff --git a/apps/media/ajax/api.php b/apps/media/ajax/api.php index a229c17e804..23abc579272 100644 --- a/apps/media/ajax/api.php +++ b/apps/media/ajax/api.php @@ -46,6 +46,9 @@ if(!isset($arguments['album'])){ if(!isset($arguments['search'])){ $arguments['search']=''; } + +session_write_close(); + OC_MEDIA_COLLECTION::$uid=OCP\USER::getUser(); if($arguments['action']){ switch($arguments['action']){ diff --git a/apps/media/js/collection.js b/apps/media/js/collection.js index 03d577c7c98..161fc0c6810 100644 --- a/apps/media/js/collection.js +++ b/apps/media/js/collection.js @@ -97,13 +97,13 @@ Collection={ if(artist.name && artist.songs.length>0){ var tr=template.clone().removeClass('template'); if(artist.songs.length>1){ - tr.find('td.title a').text(artist.songs.length+' '+t('media','songs')); - tr.find('td.album a').text(artist.albums.length+' '+t('media','albums')); + tr.find('td.title a').html(artist.songs.length+' '+t('media','songs')); + tr.find('td.album a').html(artist.albums.length+' '+t('media','albums')); }else{ - tr.find('td.title a').text(artist.songs[0].name); - tr.find('td.album a').text(artist.albums[0].name); + tr.find('td.title a').html(artist.songs[0].name); + tr.find('td.album a').html(artist.albums[0].name); } - tr.find('td.artist a').text(artist.name); + tr.find('td.artist a').html(artist.name); tr.data('artistData',artist); tr.find('td.artist a').click(function(event){ event.preventDefault(); diff --git a/apps/media/js/player.js b/apps/media/js/player.js index ad406830833..867ea802363 100644 --- a/apps/media/js/player.js +++ b/apps/media/js/player.js @@ -40,7 +40,7 @@ var PlayList={ PlayList.init(items[index].type,null); // init calls load that calls play }else{ PlayList.player.jPlayer("setMedia", items[PlayList.current]); - $(".jp-current-song").text(items[PlayList.current].name); + $(".jp-current-song").html(items[PlayList.current].name); items[index].playcount++; PlayList.player.jPlayer("play",time); if(index>0){ diff --git a/apps/media/lib_scanner.php b/apps/media/lib_scanner.php index 82170e5ca82..a8218c3a4d0 100644 --- a/apps/media/lib_scanner.php +++ b/apps/media/lib_scanner.php @@ -79,19 +79,19 @@ class OC_MEDIA_SCANNER{ OCP\Util::writeLog('media',"error reading artist tag in '$file'",OCP\Util::WARN); $artist='unknown'; }else{ - $artist=strip_tags(stripslashes($data['comments']['artist'][0])); + $artist=OCP\Util::sanitizeHTML(stripslashes($data['comments']['artist'][0])); } if(!isset($data['comments']['album'])){ OCP\Util::writeLog('media',"error reading album tag in '$file'",OCP\Util::WARN); $album='unknown'; }else{ - $album=strip_tags(stripslashes($data['comments']['album'][0])); + $album=OCP\Util::sanitizeHTML(stripslashes($data['comments']['album'][0])); } if(!isset($data['comments']['title'])){ OCP\Util::writeLog('media',"error reading title tag in '$file'",OCP\Util::WARN); $title='unknown'; }else{ - $title=strip_tags(stripslashes($data['comments']['title'][0])); + $title=OCP\Util::sanitizeHTML(stripslashes($data['comments']['title'][0])); } $size=$data['filesize']; if (isset($data['comments']['track'])) diff --git a/apps/user_ldap/group_ldap.php b/apps/user_ldap/group_ldap.php index 78bc5b46566..a3117b5a41e 100644 --- a/apps/user_ldap/group_ldap.php +++ b/apps/user_ldap/group_ldap.php @@ -166,7 +166,9 @@ class OC_GROUP_LDAP extends OC_Group_Backend { $result[] = OC_LDAP::dn2username($ldap_users[0]); continue; } else { - $result[] = OC_LDAP::dn2username($member); + if($ocname = OC_LDAP::dn2username($member)){ + $result[] = $ocname; + } } } if(!$isMemberUid) { diff --git a/apps/user_ldap/lib_ldap.php b/apps/user_ldap/lib_ldap.php index befdf267bcd..aa104eb5126 100644 --- a/apps/user_ldap/lib_ldap.php +++ b/apps/user_ldap/lib_ldap.php @@ -166,11 +166,14 @@ class OC_LDAP { * @brief returns the internal ownCloud name for the given LDAP DN of the group * @param $dn the dn of the group object * @param $ldapname optional, the display name of the object - * @returns string with with the name to use in ownCloud + * @returns string with with the name to use in ownCloud, false on DN outside of search DN * * returns the internal ownCloud name for the given LDAP DN of the group */ static public function dn2groupname($dn, $ldapname = null) { + if(strrpos($dn, self::$ldapBaseGroups) !== (strlen($dn)-strlen(self::$ldapBaseGroups))) { + return false; + } return self::dn2ocname($dn, $ldapname, false); } @@ -180,9 +183,12 @@ class OC_LDAP { * @param $ldapname optional, the display name of the object * @returns string with with the name to use in ownCloud * - * returns the internal ownCloud name for the given LDAP DN of the user + * returns the internal ownCloud name for the given LDAP DN of the user, false on DN outside of search DN */ static public function dn2username($dn, $ldapname = null) { + if(strrpos($dn, self::$ldapBaseUsers) !== (strlen($dn)-strlen(self::$ldapBaseUsers))) { + return false; + } return self::dn2ocname($dn, $ldapname, true); } diff --git a/apps/user_migrate/admin.php b/apps/user_migrate/admin.php deleted file mode 100644 index df8bff01c8d..00000000000 --- a/apps/user_migrate/admin.php +++ /dev/null @@ -1,87 +0,0 @@ -<?php - -/** - * ownCloud - user_migrate - * - * @author Tom Needham - * @copyright 2012 Tom Needham tom@owncloud.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU AFFERO GENERAL PUBLIC LICENSE for more details. - * - * You should have received a copy of the GNU Affero General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. - * - */ -OCP\User::checkAdminUser(); -OCP\App::checkAppEnabled('user_migrate'); - -// Import? -if (isset($_POST['user_import'])) { - - $root = OC::$SERVERROOT . "/"; - $importname = "owncloud_import_" . date("y-m-d_H-i-s"); - - // Save data dir for later - $datadir = OCP\Config::getSystemValue( 'datadirectory' ); - - // Copy the uploaded file - $from = $_FILES['owncloud_import']['tmp_name']; - $to = get_temp_dir().'/'.$importname.'.zip'; - if( !move_uploaded_file( $from, $to ) ){ - $error = array('error'=>'Failed to move the uploaded file','hint'=>'Try checking the permissions of the '.get_temp_dir().' dir.'); - OCP\Util::writeLog( 'user_migrate', "Failed to copy the uploaded file", OCP\Util::ERROR ); - $tmpl = new OCP\Template('user_migrate', 'admin'); - $tmpl->assign('error',$error); - return $tmpl->fetchPage(); - } - $response = json_decode( OC_Migrate::import( $to, 'user' ) ); - if( !$response->success ){ - $error = array('error'=>'There was an error while importing the user!','hint'=>'Please check the logs for a more detailed explaination'); - $tmpl = new OCP\Template('user_migrate', 'admin'); - $tmpl->assign('error',$error); - return $tmpl->fetchPage(); - } else { - // Check import status - foreach( $response->data as $app => $status ){ - if( $status != 'true' ){ - // It failed for some reason - if( $status == 'notsupported' ){ - $notsupported[] = $app; - } else if( !$status ){ - $failed[] = $app; - } - } - } - // Any problems? - if( isset( $notsupported ) || isset( $failed ) ){ - if( count( $failed ) > 0 ){ - $error = array('error'=>'Some app data failed to import','hint'=>'App data for: '.implode(', ', $failed).' failed to import.'); - $tmpl = new OCP\Template('user_migrate', 'admin'); - $tmpl->assign('error',$error); - return $tmpl->fetchPage(); - } else if( count( $notsupported ) > 0 ){ - $error = array('error'=>'Some app data could not be imported, as the apps are not installed on this instance','hint'=>'App data for: '.implode(', ', $notsupported).' failed to import as they were not found. Please install the apps and try again'); - $tmpl = new OCP\Template('user_migrate', 'admin'); - $tmpl->assign('error',$error); - return $tmpl->fetchPage(); - } - } else { - // Went swimmingly! - $tmpl = new OCP\Template('user_migrate', 'admin'); - return $tmpl->fetchPage(); - } - } - -} else { -// fill template - $tmpl = new OCP\Template('user_migrate', 'admin'); - return $tmpl->fetchPage(); -} diff --git a/apps/user_migrate/appinfo/app.php b/apps/user_migrate/appinfo/app.php index e57bfc2a9d3..9d314b59ce7 100644 --- a/apps/user_migrate/appinfo/app.php +++ b/apps/user_migrate/appinfo/app.php @@ -22,7 +22,6 @@ */ OCP\App::registerPersonal( 'user_migrate', 'settings' ); -OCP\App::registerAdmin( 'user_migrate', 'admin' ); OCP\Util::addscript( 'user_migrate', 'export'); // add settings page to navigation @@ -32,4 +31,4 @@ $entry = array( 'href' => OCP\Util::linkTo( "user_migrate", "admin.php" ), 'name' => 'Import' ); -?>
\ No newline at end of file +?> diff --git a/apps/user_migrate/settings.php b/apps/user_migrate/settings.php index 8edd0353388..098927fa17d 100644 --- a/apps/user_migrate/settings.php +++ b/apps/user_migrate/settings.php @@ -23,7 +23,67 @@ * */ OCP\App::checkAppEnabled('user_migrate'); +if (isset($_POST['user_import'])) { + $root = OC::$SERVERROOT . "/"; + $importname = "owncloud_import_" . date("y-m-d_H-i-s"); + + // Save data dir for later + $datadir = OCP\Config::getSystemValue( 'datadirectory' ); + + // Copy the uploaded file + $from = $_FILES['owncloud_import']['tmp_name']; + $to = get_temp_dir().'/'.$importname.'.zip'; + if( !move_uploaded_file( $from, $to ) ){ -// fill template -$tmpl = new OCP\Template('user_migrate', 'settings'); -return $tmpl->fetchPage();
\ No newline at end of file + $error = array('error'=>'Failed to move the uploaded file','hint'=>'Try checking the permissions of the '.get_temp_dir().' dir.'); + OCP\Util::writeLog( 'user_migrate', "Failed to copy the uploaded file", OCP\Util::ERROR ); + $tmpl = new OCP\Template('user_migrate', 'settings'); + $tmpl->assign('error',$error); + //return $tmpl->fetchPage(); + } + + + $response = json_decode( OC_Migrate::import( $to, 'user' ) ); + if( !$response->success ){ + $error = array('error'=>'There was an error while importing the user!','hint'=>'Please check the logs for a more detailed explaination'); + $tmpl = new OCP\Template('user_migrate', 'settings'); + $tmpl->assign('error',$error); + //return $tmpl->fetchPage(); + } else { + // Check import status + foreach( $response->data as $app => $status ){ + if( $status != 'true' ){ + // It failed for some reason + if( $status == 'notsupported' ){ + $notsupported[] = $app; + } else if( !$status ){ + $failed[] = $app; + } + } + } + // Any problems? + if( isset( $notsupported ) || isset( $failed ) ){ + if( count( $failed ) > 0 ){ + $error = array('error'=>'Some app data failed to import','hint'=>'App data for: '.implode(', ', $failed).' failed to import.'); + $tmpl = new OCP\Template('user_migrate', 'settings'); + $tmpl->assign('error',$error); + //return $tmpl->fetchPage(); + } else if( count( $notsupported ) > 0 ){ + $error = array('error'=>'Some app data could not be imported, as the apps are not installed on this instance','hint'=>'App data for: '.implode(', ', $notsupported).' failed to import as they were not found. Please install the apps and try again'); + $tmpl = new OCP\Template('user_migrate', 'settings'); + $tmpl->assign('error',$error); + //return $tmpl->fetchPage(); + } + } else { + // Went swimmingly! + $tmpl = new OCP\Template('user_migrate', 'settings'); + //return $tmpl->fetchPage(); + } + + } + +} else { + // fill template + $tmpl = new OCP\Template('user_migrate', 'settings'); + return $tmpl->fetchPage(); +}
\ No newline at end of file diff --git a/apps/user_migrate/templates/admin.php b/apps/user_migrate/templates/admin.php deleted file mode 100644 index ff51f43ffde..00000000000 --- a/apps/user_migrate/templates/admin.php +++ /dev/null @@ -1,13 +0,0 @@ -<form id="import" action="#" method="post" enctype="multipart/form-data"> - <fieldset class="personalblock"> - <?php if(isset($_['error'])){ ?> - <h3><?php echo $_['error']['error']; ?></h3> - <p><?php echo $_['error']['hint']; ?></p> - <?php } ?> - <legend><strong><?php echo $l->t('Import user account');?></strong></legend> - </p> - <p><input type="file" id="owncloud_import" name="owncloud_import" style="width:180px;"><label for="owncloud_import"> <?php echo $l->t('ownCloud User Zip');?></label> - </p> - <input type="submit" name="user_import" value="<?php echo $l->t('Import'); ?>" /> - </fieldset> -</form> diff --git a/apps/user_migrate/templates/settings.php b/apps/user_migrate/templates/settings.php index 8f1fe41df01..1718abe9e0f 100644 --- a/apps/user_migrate/templates/settings.php +++ b/apps/user_migrate/templates/settings.php @@ -4,3 +4,16 @@ </p> <button id="exportbtn">Export<img style="display: none;" class="loading" src="<?php echo OCP\Util::linkTo('core', 'img/loading.gif'); ?>" /></button> </fieldset> +<form id="import" action="#" method="post" enctype="multipart/form-data"> + <fieldset class="personalblock"> + <?php if(isset($_['error'])){ ?> + <h3><?php echo $_['error']['error']; ?></h3> + <p><?php echo $_['error']['hint']; ?></p> + <?php } ?> + <legend><strong><?php echo $l->t('Import user account');?></strong></legend> + </p> + <p><input type="file" id="owncloud_import" name="owncloud_import" style="width:180px;"><label for="owncloud_import"> <?php echo $l->t('ownCloud User Zip');?></label> + </p> + <input type="submit" name="user_import" value="<?php echo $l->t('Import'); ?>" /> + </fieldset> +</form> diff --git a/apps/user_openid/appinfo/info.xml b/apps/user_openid/appinfo/info.xml index 268af239738..7aae4271fa8 100644 --- a/apps/user_openid/appinfo/info.xml +++ b/apps/user_openid/appinfo/info.xml @@ -8,6 +8,7 @@ <require>4</require> <shipped>true</shipped> <types> + <prelogin/> <authentication/> </types> </info> diff --git a/apps/user_webfinger/webfinger.php b/apps/user_webfinger/webfinger.php index 67cbba54a4c..6b64a7e2860 100644 --- a/apps/user_webfinger/webfinger.php +++ b/apps/user_webfinger/webfinger.php @@ -17,13 +17,6 @@ header("Content-Type: application/xrd+json"); * '* but can also use complex database queries to generate the webfinger result **/ -// calculate the documentroot -// modified version of the one in lib/base.php that takes the .well-known symlink into account -/*$DOCUMENTROOT=realpath($_SERVER['DOCUMENT_ROOT']); -$SERVERROOT=str_replace("\\",'/',dirname(dirname(dirname(dirname(__FILE__))))); -$SUBURI=substr(realpath($_SERVER["SCRIPT_FILENAME"]),strlen($SERVERROOT)); -$WEBROOT=substr($SUBURI,0,-34); -*/ $userName = ''; $hostName = ''; diff --git a/core/css/styles.css b/core/css/styles.css index b6b5918d653..44fd1e084fe 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -16,7 +16,7 @@ body { background:#fefefe; font:normal .8em/1.6em "Lucida Grande", Arial, Verdan /* HEADERS */ -#body-user #header, #body-settings #header { position:fixed; top:0; z-index:100; width:100%; height:2.5em; padding:.5em; background:#1d2d44; -moz-box-shadow:0 0 10px rgba(0, 0, 0, .5), inset 0 -2px 10px #222; -webkit-box-shadow:0 0 10px rgba(0, 0, 0, .5), inset 0 -2px 10px #222; box-shadow:0 0 10px rgba(0, 0, 0, .5), inset 0 -2px 10px #222; } +#body-user #header, #body-settings #header { position:fixed; top:0; left:0; right:0; z-index:100; height:2.5em; line-height:2.5em; padding:.5em; background:#1d2d44; -moz-box-shadow:0 0 10px rgba(0, 0, 0, .5), inset 0 -2px 10px #222; -webkit-box-shadow:0 0 10px rgba(0, 0, 0, .5), inset 0 -2px 10px #222; box-shadow:0 0 10px rgba(0, 0, 0, .5), inset 0 -2px 10px #222; } #body-login #header { margin: -2em auto 0; text-align:center; height:10em; padding:1em 0 .5em; -moz-box-shadow:0 0 1em rgba(0, 0, 0, .5); -webkit-box-shadow:0 0 1em rgba(0, 0, 0, .5); box-shadow:0 0 1em rgba(0, 0, 0, .5); background: #1d2d44; /* Old browsers */ @@ -28,8 +28,9 @@ background: -ms-linear-gradient(top, #35537a 0%,#1d2d42 100%); /* IE10+ */ background: linear-gradient(top, #35537a 0%,#1d2d42 100%); /* W3C */ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#35537a', endColorstr='#1d2d42',GradientType=0 ); /* IE6-9 */ } -#owncloud { float:left; } - +#owncloud { float:left; vertical-align:middle; } +.header-right { float:right; vertical-align:middle; padding:0 0.5em; } +.header-right > * { vertical-align:middle; } /* INPUTS */ input[type="text"], input[type="password"] { cursor:text; } @@ -49,7 +50,7 @@ input[type="checkbox"] { width:auto; } #body-login input[type="text"], #body-login input[type="password"] { width: 13em; } #body-login input.login { width: auto; float: right; } #remember_login { margin:.8em .2em 0 1em; } -.searchbox input[type="search"] { position:fixed; font-size:1.2em; top:.4em; right:3em; padding:.2em .5em .2em 1.5em; background:#fff url('../img/actions/search.svg') no-repeat .5em center; border:0; -moz-border-radius:1em; -webkit-border-radius:1em; border-radius:1em; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=70)"; filter:alpha(opacity=70);opacity:.7; -webkit-transition:opacity 300ms; -moz-transition:opacity 300ms; -o-transition:opacity 300ms; transition:opacity 300ms; } +.searchbox input[type="search"] { font-size:1.2em; padding:.2em .5em .2em 1.5em; background:#fff url('../img/actions/search.svg') no-repeat .5em center; border:0; -moz-border-radius:1em; -webkit-border-radius:1em; border-radius:1em; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=70)"; filter:alpha(opacity=70);opacity:.7; -webkit-transition:opacity 300ms; -moz-transition:opacity 300ms; -o-transition:opacity 300ms; transition:opacity 300ms; } input[type="submit"].enabled { background:#66f866; border:1px solid #5e5; -moz-box-shadow:0 1px 1px #f8f8f8, 0 1px 1px #cfc inset; -webkit-box-shadow:0 1px 1px #f8f8f8, 0 1px 1px #cfc inset; box-shadow:0 1px 1px #f8f8f8, 0 1px 1px #cfc inset; } input[type="submit"].highlight{ background:#ffc100; border:1px solid #db0; text-shadow:#ffeedd 0 1px 0; -moz-box-shadow:0 1px 1px #f8f8f8, 0 1px 1px #ffeedd inset; -webkit-box-shadow:0 1px 1px #f8f8f8, 0 1px 1px #ffeedd inset; box-shadow:0 1px 1px #f8f8f8, 0 1px 1px #ffeedd inset; } #select_all{ margin-top: .4em !important;} @@ -101,8 +102,6 @@ label.infield { cursor: text !important; } #expand { position:relative; z-index:100; margin-bottom:-.5em; padding:.5em 10.1em .7em 1.2em; cursor:pointer; } #expand+span { position:absolute; z-index:99; margin:-1.7em 0 0 2.5em; font-size:1.2em; color:#666; text-shadow:#f8f8f8 0 1px 0; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter:alpha(opacity=0); opacity:0; -webkit-transition:opacity 300ms; -moz-transition:opacity 300ms; -o-transition:opacity 300ms; transition:opacity 300ms; } #expand:hover+span, #expand+span:hover { -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; filter:alpha(opacity=100); opacity:1; cursor:pointer; } -#logout { position:absolute; right:0; top:0; padding:1.2em 2em .55em 1.2em; } - /* VARIOUS REUSABLE SELECTORS */ .hidden { display:none; } @@ -112,8 +111,8 @@ label.infield { cursor: text !important; } .action, .selectedActions a { -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; filter:alpha(opacity=50); opacity:.5; -webkit-transition:opacity 200ms; -moz-transition:opacity 200ms; -o-transition:opacity 200ms; transition:opacity 200ms; } .action { width: 16px; height: 16px; } -#logout { -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=80)"; filter:alpha(opacity=80); opacity:.8; } -.action:hover, .selectedActions a:hover, #logout:hover { -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; filter:alpha(opacity=100); opacity:1; } +.header-action { -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=80)"; filter:alpha(opacity=80); opacity:.8; } +.action:hover, .selectedActions a:hover, .header-action:hover { -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; filter:alpha(opacity=100); opacity:1; } table:not(.nostyle) tr { -webkit-transition:background-color 200ms; -moz-transition:background-color 200ms; -o-transition:background-color 200ms; transition:background-color 200ms; } tbody tr:hover, tr:active { background-color:#f8f8f8; } diff --git a/core/minimizer.php b/core/minimizer.php index 6828acc87d8..0abbca75027 100644 --- a/core/minimizer.php +++ b/core/minimizer.php @@ -1,14 +1,15 @@ <?php +session_write_close(); OC_App::loadApps(); if ($service == 'core.css'){ $minimizer = new OC_Minimizer_CSS(); - $files = $minimizer->findFiles(OC_Util::$core_styles); - $minimizer->output($files); + $files = OC_TemplateLayout::findStylesheetFiles(OC_Util::$core_styles); + $minimizer->output($files, $service); } else if ($service == 'core.js'){ $minimizer = new OC_Minimizer_JS(); - $files = $minimizer->findFiles(OC_Util::$core_scripts); - $minimizer->output($files); + $files = OC_TemplateLayout::findJavascriptFiles(OC_Util::$core_scripts); + $minimizer->output($files, $service); } diff --git a/core/templates/layout.user.php b/core/templates/layout.user.php index fabc28f6637..d6911fd1e18 100644 --- a/core/templates/layout.user.php +++ b/core/templates/layout.user.php @@ -45,10 +45,10 @@ <body id="<?php echo $_['bodyid'];?>"> <header><div id="header"> <a href="<?php echo link_to('', 'index.php'); ?>" title="" id="owncloud"><img class="svg" src="<?php echo image_path('', 'logo-wide.svg'); ?>" alt="ownCloud" /></a> - <form class="searchbox" action="#" method="post"> - <input id="searchbox" class="svg" type="search" name="query" value="<?php if(isset($_POST['query'])){echo htmlentities($_POST['query']);};?>" autocomplete="off" /> + <a class="header-right header-action" id="logout" href="<?php echo link_to('', 'index.php'); ?>?logout=true"><img class="svg" alt="<?php echo $l->t('Log out');?>" title="<?php echo $l->t('Log out');?>" src="<?php echo image_path('', 'actions/logout.svg'); ?>" /></a> + <form class="searchbox header-right" action="#" method="post"> + <input id="searchbox" class="svg" type="search" name="query" value="<?php if(isset($_POST['query'])){echo OC_Util::sanitizeHTML($_POST['query']);};?>" autocomplete="off" /> </form> - <a id="logout" href="<?php echo link_to('', 'index.php'); ?>?logout=true"><img class="svg" alt="<?php echo $l->t('Log out');?>" title="<?php echo $l->t('Log out');?>" src="<?php echo image_path('', 'actions/logout.svg'); ?>" /></a> </div></header> <nav><div id="navigation"> diff --git a/core/templates/login.php b/core/templates/login.php index a40bf5c330a..985cf90c2a2 100644 --- a/core/templates/login.php +++ b/core/templates/login.php @@ -7,7 +7,7 @@ <?php endif; ?> <p class="infield"> <label for="user" class="infield"><?php echo $l->t( 'Username' ); ?></label> - <input type="text" name="user" id="user" value="<?php echo !empty($_POST['user'])?htmlentities($_POST['user'],ENT_COMPAT,'utf-8').'"':'" autofocus'; ?> autocomplete="off" required /> + <input type="text" name="user" id="user" value="<?php echo !empty($_POST['user'])?OC_Util::sanitizeHTML($_POST['user'],ENT_COMPAT,'utf-8').'"':'" autofocus'; ?> autocomplete="off" required /> </p> <p class="infield"> <label for="password" class="infield"><?php echo $l->t( 'Password' ); ?></label> diff --git a/index.php b/index.php index b90b1b310a9..e3c94adf66f 100755 --- a/index.php +++ b/index.php @@ -69,6 +69,7 @@ elseif(OC_User::isLoggedIn()) { // For all others cases, we display the guest page : } else { + OC_App::loadApps(array('prelogin')); $error = false; // remember was checked after last login if(isset($_COOKIE["oc_remember_login"]) && isset($_COOKIE["oc_token"]) && isset($_COOKIE["oc_username"]) && $_COOKIE["oc_remember_login"]) { @@ -121,7 +122,7 @@ elseif(OC_User::isLoggedIn()) { if(!array_key_exists('sectoken', $_SESSION) || (array_key_exists('sectoken', $_SESSION) && is_null(OC::$REQUESTEDFILE)) || substr(OC::$REQUESTEDFILE, -3) == 'php'){ $sectoken=rand(1000000,9999999); $_SESSION['sectoken']=$sectoken; - $redirect_url = (isset($_REQUEST['redirect_url'])) ? $_REQUEST['redirect_url'] : $_SERVER['REQUEST_URI']; + $redirect_url = (isset($_REQUEST['redirect_url'])) ? OC_Util::sanitizeHTML($_REQUEST['redirect_url']) : $_SERVER['REQUEST_URI']; OC_Template::printGuestPage('', 'login', array('error' => $error, 'sectoken' => $sectoken, 'redirect' => $redirect_url)); } } diff --git a/lib/app.php b/lib/app.php index 1dcccee1da0..1a2dc370d69 100755 --- a/lib/app.php +++ b/lib/app.php @@ -536,32 +536,33 @@ class OC_App{ $currentVersion=OC_App::getAppVersion($app); if ($currentVersion) { if (version_compare($currentVersion, $installedVersion, '>')) { - OC_Log::write($app,'starting app upgrade from '.$installedVersion.' to '.$currentVersion,OC_Log::DEBUG); + OC_Log::write($app, 'starting app upgrade from '.$installedVersion.' to '.$currentVersion,OC_Log::DEBUG); OC_App::updateApp($app); - OC_Appconfig::setValue($app,'installed_version',OC_App::getAppVersion($app)); + OC_Appconfig::setValue($app, 'installed_version', OC_App::getAppVersion($app)); } } } + } - // check if the current enabled apps are compatible with the current ownCloud version. disable them if not. - // this is important if you upgrade ownCloud and have non ported 3rd party apps installed - $apps =OC_App::getEnabledApps(); - $version=OC_Util::getVersion(); + /** + * check if the current enabled apps are compatible with the current + * ownCloud version. disable them if not. + * This is important if you upgrade ownCloud and have non ported 3rd + * party apps installed. + */ + public static function checkAppsRequirements($apps = array()){ + if (empty($apps)) { + $apps = OC_App::getEnabledApps(); + } + $version = OC_Util::getVersion(); foreach($apps as $app) { - // check if the app is compatible with this version of ownCloud - $info=OC_App::getAppInfo($app); + $info = OC_App::getAppInfo($app); if(!isset($info['require']) or ($version[0]>$info['require'])){ OC_Log::write('core','App "'.$info['name'].'" can\'t be used because it is not compatible with this version of ownCloud',OC_Log::ERROR); OC_App::disable( $app ); } - - - } - - - } /** @@ -589,6 +590,7 @@ class OC_App{ return; } if(file_exists(self::getAppPath($appid).'/appinfo/update.php')){ + self::loadApp($appid); include self::getAppPath($appid).'/appinfo/update.php'; } diff --git a/lib/base.php b/lib/base.php index a0f5e83dd47..2f16f7dab4c 100644 --- a/lib/base.php +++ b/lib/base.php @@ -43,10 +43,6 @@ class OC{ */ public static $WEBROOT = ''; /** - * the folder that stores that data files for the filesystem of the user (e.g. /srv/http/owncloud/data/myusername/files) - */ - public static $CONFIG_DATADIRECTORY = ''; - /** * The installation path of the 3rdparty folder on the server (e.g. /srv/http/owncloud/3rdparty) */ public static $THIRDPARTYROOT = ''; @@ -91,34 +87,8 @@ class OC{ } } - /** - * autodetects the formfactor of the used device - * default -> the normal desktop browser interface - * mobile -> interface for smartphones - * tablet -> interface for tablets - * standalone -> the default interface but without header, footer and sidebar. just the application. useful to ue just a specific app on the desktop in a standalone window. - */ - public static function detectFormfactor(){ - // please add more useragent strings for other devices - if(isset($_SERVER['HTTP_USER_AGENT'])){ - if(stripos($_SERVER['HTTP_USER_AGENT'],'ipad')>0) { - $mode='tablet'; - }elseif(stripos($_SERVER['HTTP_USER_AGENT'],'iphone')>0){ - $mode='mobile'; - }elseif((stripos($_SERVER['HTTP_USER_AGENT'],'N9')>0) and (stripos($_SERVER['HTTP_USER_AGENT'],'nokia')>0)){ - $mode='mobile'; - }else{ - $mode='default'; - } - }else{ - $mode='default'; - } - return($mode); - } - public static function initPaths(){ - // calculate the documentroot - $DOCUMENTROOT=realpath($_SERVER['DOCUMENT_ROOT']); + // calculate the root directories OC::$SERVERROOT=str_replace("\\",'/',substr(__FILE__,0,-13)); OC::$SUBURI= str_replace("\\","/",substr(realpath($_SERVER["SCRIPT_FILENAME"]),strlen(OC::$SERVERROOT))); $scriptName=$_SERVER["SCRIPT_NAME"]; @@ -133,9 +103,6 @@ class OC{ } } OC::$WEBROOT=substr($scriptName,0,strlen($scriptName)-strlen(OC::$SUBURI)); - // try a new way to detect the WEBROOT which is simpler and also works with the app directory outside the owncloud folder. letÂīs see if this works for everybody -// OC::$WEBROOT=substr(OC::$SERVERROOT,strlen($DOCUMENTROOT)); - if(OC::$WEBROOT!='' and OC::$WEBROOT[0]!=='/'){ OC::$WEBROOT='/'.OC::$WEBROOT; @@ -234,6 +201,7 @@ class OC{ } OC_Config::setValue('version',implode('.',OC_Util::getVersion())); + OC_App::checkAppsRequirements(); } OC_App::updateApps(); @@ -241,15 +209,6 @@ class OC{ } public static function initTemplateEngine() { - // if the formfactor is not yet autodetected do the autodetection now. For possible forfactors check the detectFormfactor documentation - if(!isset($_SESSION['formfactor'])){ - $_SESSION['formfactor']=OC::detectFormfactor(); - } - // allow manual override via GET parameter - if(isset($_GET['formfactor'])){ - $_SESSION['formfactor']=$_GET['formfactor']; - } - // Add the stuff we need always OC_Util::addScript( "jquery-1.7.2.min" ); OC_Util::addScript( "jquery-ui-1.8.16.custom.min" ); @@ -286,7 +245,7 @@ class OC{ if(substr(OC::$REQUESTEDFILE, -3) == 'css'){ $file = OC_App::getAppWebPath(OC::$REQUESTEDAPP). '/' . OC::$REQUESTEDFILE; $minimizer = new OC_Minimizer_CSS(); - $minimizer->output(array(array(OC_App::getAppPath(OC::$REQUESTEDAPP), OC_App::getAppWebPath(OC::$REQUESTEDAPP), OC::$REQUESTEDFILE))); + $minimizer->output(array(array(OC_App::getAppPath(OC::$REQUESTEDAPP), OC_App::getAppWebPath(OC::$REQUESTEDAPP), OC::$REQUESTEDFILE)),$file); exit; }elseif(substr(OC::$REQUESTEDFILE, -3) == 'php'){ require_once(OC_App::getAppPath(OC::$REQUESTEDAPP). '/' . OC::$REQUESTEDFILE); @@ -388,28 +347,14 @@ class OC{ exit; } - // TODO: we should get rid of this one, too - // WARNING: to make everything even more confusing, - // DATADIRECTORY is a var that changes and DATADIRECTORY_ROOT - // stays the same, but is set by "datadirectory". - // Any questions? - OC::$CONFIG_DATADIRECTORY = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); - // User and Groups if( !OC_Config::getValue( "installed", false )){ $_SESSION['user_id'] = ''; } - OC_User::useBackend( OC_Config::getValue( "userbackend", "database" )); OC_Group::useBackend(new OC_Group_Database()); - // Set up file system unless forbidden - global $RUNTIME_NOSETUPFS; - if(!$RUNTIME_NOSETUPFS ){ - OC_Util::setupFS(); - } - // Load Apps // This includes plugins for users and filesystems as well global $RUNTIME_NOAPPS; diff --git a/lib/cache/fileglobal.php b/lib/cache/fileglobal.php new file mode 100644 index 00000000000..1c2c9bdc82d --- /dev/null +++ b/lib/cache/fileglobal.php @@ -0,0 +1,78 @@ +<?php +/** + * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + + +class OC_Cache_FileGlobal{ + protected function getCacheDir() { + $cache_dir = get_temp_dir().'/owncloud-'.OC_Util::getInstanceId().'/'; + if (!is_dir($cache_dir)) { + mkdir($cache_dir); + } + return $cache_dir; + } + + protected function fixKey($key) { + return str_replace('/', '_', $key); + } + + public function get($key) { + $key = $this->fixKey($key); + if ($this->hasKey($key)) { + $cache_dir = $this->getCacheDir(); + return file_get_contents($cache_dir.$key); + } + return null; + } + + public function set($key, $value, $ttl=0) { + $key = $this->fixKey($key); + $cache_dir = $this->getCacheDir(); + if ($cache_dir and file_put_contents($cache_dir.$key, $value)) { + if ($ttl === 0) { + $ttl = 86400; // 60*60*24 + } + return touch($cache_dir.$key, time() + $ttl); + } + return false; + } + + public function hasKey($key) { + $key = $this->fixKey($key); + $cache_dir = $this->getCacheDir(); + if ($cache_dir && is_file($cache_dir.$key)) { + $mtime = filemtime($cache_dir.$key); + if ($mtime < time()) { + unlink($cache_dir.$key); + return false; + } + return true; + } + return false; + } + + public function remove($key) { + $cache_dir = $this->getCacheDir(); + if(!$cache_dir){ + return false; + } + $key = $this->fixKey($key); + return unlink($cache_dir.$key); + } + + public function clear(){ + $cache_dir = $this->getCacheDir(); + if($cache_dir and is_dir($cache_dir)){ + $dh=opendir($cache_dir); + while($file=readdir($dh)){ + if($file!='.' and $file!='..'){ + unlink($cache_dir.$file); + } + } + } + } +} diff --git a/lib/connector/sabre/directory.php b/lib/connector/sabre/directory.php index e74d832cb00..9832449af3a 100644 --- a/lib/connector/sabre/directory.php +++ b/lib/connector/sabre/directory.php @@ -59,22 +59,23 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa * @throws Sabre_DAV_Exception_FileNotFound * @return Sabre_DAV_INode */ - public function getChild($name) { + public function getChild($name, $info = null) { $path = $this->path . '/' . $name; + if (is_null($info)) { + $info = OC_FileCache::get($path); + } - if (!OC_Filesystem::file_exists($path)) throw new Sabre_DAV_Exception_NotFound('File with name ' . $path . ' could not be located'); - - if (OC_Filesystem::is_dir($path)) { - - return new OC_Connector_Sabre_Directory($path); + if (!$info) throw new Sabre_DAV_Exception_NotFound('File with name ' . $path . ' could not be located'); + if ($info['mimetype'] == 'httpd/unix-directory') { + $node = new OC_Connector_Sabre_Directory($path); } else { - - return new OC_Connector_Sabre_File($path); - + $node = new OC_Connector_Sabre_File($path); } + $node->setFileinfoCache($info); + return $node; } /** @@ -84,18 +85,30 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa */ public function getChildren() { + $folder_content = OC_FileCache::getFolderContent($this->path); + $paths = array(); + foreach($folder_content as $info) { + $paths[] = $this->path.'/'.$info['name']; + } + $placeholders = join(',', array_fill(0, count($paths), '?')); + $query = OC_DB::prepare( 'SELECT * FROM *PREFIX*properties WHERE userid = ?' . ' AND propertypath IN ('.$placeholders.')' ); + array_unshift($paths, OC_User::getUser()); // prepend userid + $result = $query->execute( $paths ); + $properties = array_fill_keys($paths, array()); + while($row = $result->fetchRow()) { + $propertypath = $row['propertypath']; + $propertyname = $row['propertyname']; + $propertyvalue = $row['propertyvalue']; + $properties[$propertypath][$propertyname] = $propertyvalue; + } + $nodes = array(); - // foreach(scandir($this->path) as $node) if($node!='.' && $node!='..') $nodes[] = $this->getChild($node); - if( OC_Filesystem::is_dir($this->path . '/')){ - $dh = OC_Filesystem::opendir($this->path . '/'); - while(( $node = readdir($dh)) !== false ){ - if($node!='.' && $node!='..'){ - $nodes[] = $this->getChild($node); - } - } + foreach($folder_content as $info) { + $node = $this->getChild($info['name'], $info); + $node->setPropertyCache($properties[$this->path.'/'.$info['name']]); + $nodes[] = $node; } return $nodes; - } /** diff --git a/lib/connector/sabre/file.php b/lib/connector/sabre/file.php index 3ba1b3355f2..dd25df78c29 100644 --- a/lib/connector/sabre/file.php +++ b/lib/connector/sabre/file.php @@ -63,8 +63,8 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D * @return int */ public function getSize() { - $this->stat(); - return $this->stat_cache['size']; + $this->getFileinfoCache(); + return $this->fileinfo_cache['size']; } @@ -92,6 +92,9 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D * @return mixed */ public function getContentType() { + if (isset($this->fileinfo_cache['mimetype'])) { + return $this->fileinfo_cache['mimetype']; + } return OC_Filesystem::getMimeType($this->path); diff --git a/lib/connector/sabre/node.php b/lib/connector/sabre/node.php index e7bcea3171d..be315a0ffd9 100644 --- a/lib/connector/sabre/node.php +++ b/lib/connector/sabre/node.php @@ -30,10 +30,15 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr */ protected $path; /** - * file stat cache + * node fileinfo cache * @var array */ - protected $stat_cache; + protected $fileinfo_cache; + /** + * node properties cache + * @var array + */ + protected $property_cache = null; /** * Sets up the node, expects a full path name @@ -82,23 +87,38 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr } + public function setFileinfoCache($fileinfo_cache) + { + $this->fileinfo_cache = $fileinfo_cache; + } + /** - * Set the stat cache + * Make sure the fileinfo cache is filled. Uses OC_FileCache or a direct stat */ - protected function stat() { - if (!isset($this->stat_cache)) { - $this->stat_cache = OC_Filesystem::stat($this->path); + protected function getFileinfoCache() { + if (!isset($this->fileinfo_cache)) { + if ($fileinfo_cache = OC_FileCache::get($this->path)) { + } else { + $fileinfo_cache = OC_Filesystem::stat($this->path); + } + + $this->fileinfo_cache = $fileinfo_cache; } } + public function setPropertyCache($property_cache) + { + $this->property_cache = $property_cache; + } + /** * Returns the last modification time, as a unix timestamp * * @return int */ public function getLastModified() { - $this->stat(); - return $this->stat_cache['mtime']; + $this->getFileinfoCache(); + return $this->fileinfo_cache['mtime']; } @@ -129,7 +149,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr } } else { - if( strcmp( $propertyName, "lastmodified")) { + if( strcmp( $propertyName, "lastmodified") === 0) { $this->touch($propertyValue); } else { if(!array_key_exists( $propertyName, $existing )){ @@ -143,6 +163,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr } } + $this->setPropertyCache(null); return true; } @@ -158,23 +179,24 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr * @return void */ function getProperties($properties) { - // At least some magic in here :-) - $query = OC_DB::prepare( 'SELECT * FROM *PREFIX*properties WHERE userid = ? AND propertypath = ?' ); - $result = $query->execute( array( OC_User::getUser(), $this->path )); + if (is_null($this->property_cache)) { + $query = OC_DB::prepare( 'SELECT * FROM *PREFIX*properties WHERE userid = ? AND propertypath = ?' ); + $result = $query->execute( array( OC_User::getUser(), $this->path )); - $existing = array(); - while( $row = $result->fetchRow()){ - $existing[$row['propertyname']] = $row['propertyvalue']; + $this->property_cache = array(); + while( $row = $result->fetchRow()){ + $this->property_cache[$row['propertyname']] = $row['propertyvalue']; + } } // if the array was empty, we need to return everything if(count($properties) == 0){ - return $existing; + return $this->property_cache; } $props = array(); foreach($properties as $property) { - if (isset($existing[$property])) $props[$property] = $existing[$property]; + if (isset($this->property_cache[$property])) $props[$property] = $this->property_cache[$property]; } return $props; } diff --git a/lib/filecache.php b/lib/filecache.php index 3fb8e4113cb..e3bcc7d0000 100644 --- a/lib/filecache.php +++ b/lib/filecache.php @@ -28,15 +28,13 @@ * It will try to keep the data up to date but changes from outside ownCloud can invalidate the cache */ class OC_FileCache{ - private static $savedData=array(); - /** * get the filesystem info from the cache * @param string path * @param string root (optional) * @return array * - * returns an assiciative array with the following keys: + * returns an associative array with the following keys: * - size * - mtime * - ctime @@ -44,29 +42,15 @@ class OC_FileCache{ * - encrypted * - versioned */ - public static function get($path,$root=''){ - if(self::isUpdated($path,$root)){ - if(!$root){//filesystem hooks are only valid for the default root + public static function get($path,$root=false){ + if(OC_FileCache_Update::hasUpdated($path,$root)){ + if($root===false){//filesystem hooks are only valid for the default root OC_Hook::emit('OC_Filesystem','post_write',array('path'=>$path)); }else{ - self::fileSystemWatcherWrite(array('path'=>$path),$root); + OC_FileCache_Update::update($path,$root); } } - if(!$root){ - $root=OC_Filesystem::getRoot(); - } - if($root=='/'){ - $root=''; - } - $path=$root.$path; - $query=OC_DB::prepare('SELECT ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE path_hash=?'); - $result=$query->execute(array(md5($path)))->fetchRow(); - if(is_array($result)){ - return $result; - }else{ - OC_Log::write('files','get(): file not found in cache ('.$path.')',OC_Log::DEBUG); - return false; - } + return OC_FileCache_Cached::get($path,$root); } /** @@ -77,30 +61,23 @@ class OC_FileCache{ * * $data is an assiciative array in the same format as returned by get */ - public static function put($path,$data,$root=''){ - if(!$root){ + public static function put($path,$data,$root=false){ + if($root===false){ $root=OC_Filesystem::getRoot(); } - if($root=='/'){ - $root=''; - } $path=$root.$path; - if($path=='/'){ - $parent=-1; - }else{ - $parent=self::getFileId(dirname($path)); + $parent=self::getParentId($path); + $id=self::getId($path,''); + if(isset(OC_FileCache_Cached::$savedData[$path])){ + $data=array_merge(OC_FileCache_Cached::$savedData[$path],$data); + unset(OC_FileCache_Cached::$savedData[$path]); } - $id=self::getFileId($path); if($id!=-1){ self::update($id,$data); return; } - if(isset(self::$savedData[$path])){ - $data=array_merge($data,self::$savedData[$path]); - unset(self::$savedData[$path]); - } if(!isset($data['size']) or !isset($data['mtime'])){//save incomplete data for the next time we write it - self::$savedData[$path]=$data; + OC_FileCache_Cached::$savedData[$path]=$data; return; } if(!isset($data['encrypted'])){ @@ -157,13 +134,10 @@ class OC_FileCache{ * @param string newPath * @param string root (optional) */ - public static function move($oldPath,$newPath,$root=''){ - if(!$root){ + public static function move($oldPath,$newPath,$root=false){ + if($root===false){ $root=OC_Filesystem::getRoot(); } - if($root=='/'){ - $root=''; - } $oldPath=$root.$oldPath; $newPath=$root.$newPath; $newParent=self::getParentId($newPath); @@ -182,28 +156,19 @@ class OC_FileCache{ /** * delete info from the cache - * @param string/int $file + * @param string path * @param string root (optional) */ - public static function delete($file,$root=''){ - if(!is_numeric($file)){ - if(!$root){ - $root=OC_Filesystem::getRoot(); - } - if($root=='/'){ - $root=''; - } - $path=$root.$file; - self::delete(self::getFileId($path)); - }elseif($file!=-1){ - $query=OC_DB::prepare('SELECT id FROM *PREFIX*fscache WHERE parent=?'); - $result=$query->execute(array($file)); - while($child=$result->fetchRow()){ - self::delete(intval($child['id'])); - } - $query=OC_DB::prepare('DELETE FROM *PREFIX*fscache WHERE id=?'); - $query->execute(array($file)); + public static function delete($path,$root=false){ + if($root===false){ + $root=OC_Filesystem::getRoot(); } + $query=OC_DB::prepare('DELETE FROM *PREFIX*fscache WHERE path_hash=?'); + $query->execute(array(md5($root.$path))); + + //delete everything inside the folder + $query=OC_DB::prepare('DELETE FROM *PREFIX*fscache WHERE path LIKE ?'); + $query->execute(array($root.$path.'/%')); } /** @@ -213,13 +178,10 @@ class OC_FileCache{ * @param string root (optional) * @return array of filepaths */ - public static function search($search,$returnData=false,$root=''){ - if(!$root){ + public static function search($search,$returnData=false,$root=false){ + if($root===false){ $root=OC_Filesystem::getRoot(); } - if($root=='/'){ - $root=''; - } $rootLen=strlen($root); if(!$returnData){ $query=OC_DB::prepare('SELECT path FROM *PREFIX*fscache WHERE name LIKE ? AND `user`=?'); @@ -254,26 +216,11 @@ class OC_FileCache{ * - encrypted * - versioned */ - public static function getFolderContent($path,$root='',$mimetype_filter=''){ - if(self::isUpdated($path,$root)){ - self::updateFolder($path,$root); - } - if(!$root){ - $root=OC_Filesystem::getRoot(); - } - if($root=='/'){ - $root=''; - } - $path=$root.$path; - $parent=self::getFileId($path); - $query=OC_DB::prepare('SELECT name,ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE parent=? AND (mimetype LIKE ? OR mimetype = ?)'); - $result=$query->execute(array($parent, $mimetype_filter.'%', 'httpd/unix-directory'))->fetchAll(); - if(is_array($result)){ - return $result; - }else{ - OC_Log::write('files','getFolderContent(): file not found in cache ('.$path.')',OC_Log::DEBUG); - return false; + public static function getFolderContent($path,$root=false,$mimetype_filter=''){ + if(OC_FileCache_Update::hasUpdated($path,$root,true)){ + OC_FileCache_Update::updateFolder($path,$root); } + return OC_FileCache_Cached::getFolderContent($path,$root,$mimetype_filter); } /** @@ -282,61 +229,37 @@ class OC_FileCache{ * @param string root (optional) * @return bool */ - public static function inCache($path,$root=''){ - if(!$root){ - $root=OC_Filesystem::getRoot(); - } - if($root=='/'){ - $root=''; - } - $path=$root.$path; - return self::getFileId($path)!=-1; + public static function inCache($path,$root=false){ + return self::getId($path,$root)!=-1; } /** * get the file id as used in the cache - * unlike the public getId, full paths are used here (/usename/files/foo instead of /foo) - * @param string $path + * @param string path + * @param string root (optional) * @return int */ - private static function getFileId($path){ - $query=OC_DB::prepare('SELECT id FROM *PREFIX*fscache WHERE path_hash=?'); - if(OC_DB::isError($query)){ - OC_Log::write('files','error while getting file id of '.$path,OC_Log::ERROR); - return -1; + public static function getId($path,$root=false){ + if($root===false){ + $root=OC_Filesystem::getRoot(); } - $result=$query->execute(array(md5($path))); + + $query=OC_DB::prepare('SELECT id FROM *PREFIX*fscache WHERE path_hash=?'); + $result=$query->execute(array(md5($root.$path))); if(OC_DB::isError($result)){ OC_Log::write('files','error while getting file id of '.$path,OC_Log::ERROR); return -1; } + $result=$result->fetchRow(); if(is_array($result)){ return $result['id']; }else{ - OC_Log::write('files','getFileId(): file not found in cache ('.$path.')',OC_Log::DEBUG); return -1; } } /** - * get the file id as used in the cache - * @param string path - * @param string root (optional) - * @return int - */ - public static function getId($path,$root=''){ - if(!$root){ - $root=OC_Filesystem::getRoot(); - } - if($root=='/'){ - $root=''; - } - $path=$root.$path; - return self::getFileId($path); - } - - /** * get the file path from the id, relative to the home folder of the user * @param int id * @param string user (optional) @@ -366,154 +289,23 @@ class OC_FileCache{ if($path=='/'){ return -1; }else{ - return self::getFileId(dirname($path)); - } - } - - /** - * called when changes are made to files - * @param array $params - * @param string root (optional) - */ - public static function fileSystemWatcherWrite($params,$root=''){ - if(!$root){ - $view=OC_Filesystem::getView(); - }else{ - $view=new OC_FilesystemView(($root=='/')?'':$root); - } - - $path=$params['path']; - $fullPath=$view->getRoot().$path; - $mimetype=$view->getMimeType($path); - $dir=$view->is_dir($path.'/'); - //dont use self::get here, we don't want inifinte loops when a file has changed - $cachedSize=self::getCachedSize($path,$root); - $size=0; - if($dir){ - if(self::inCache($path,$root)){ - $parent=self::getFileId($fullPath); - $query=OC_DB::prepare('SELECT size FROM *PREFIX*fscache WHERE parent=?'); - $result=$query->execute(array($parent)); - while($row=$result->fetchRow()){ - $size+=$row['size']; - } - $mtime=$view->filemtime($path); - $ctime=$view->filectime($path); - $writable=$view->is_writable($path); - self::put($path,array('size'=>$size,'mtime'=>$mtime,'ctime'=>$ctime,'mimetype'=>$mimetype,'writable'=>$writable)); - }else{ - $count=0; - self::scan($path,null,$count,$root); - } - }else{ - $size=self::scanFile($path,$root); - } - self::increaseSize(dirname($fullPath),$size-$cachedSize); - } - - public static function getCached($path,$root=''){ - if(!$root){ - $root=OC_Filesystem::getRoot(); - }else{ - if($root=='/'){ - $root=''; - } - } - $path=$root.$path; - $query=OC_DB::prepare('SELECT ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE path_hash=?'); - $result=$query->execute(array(md5($path)))->fetchRow(); - if(is_array($result)){ - if(isset(self::$savedData[$path])){ - $result=array_merge($result,self::$savedData[$path]); - } - return $result; - }else{ - OC_Log::write('files','getCached(): file not found in cache ('.$path.')',OC_Log::DEBUG); - if(isset(self::$savedData[$path])){ - return self::$savedData[$path]; - }else{ - return array(); - } + return self::getId(dirname($path),''); } } - private static function getCachedSize($path,$root){ - if(!$root){ - $root=OC_Filesystem::getRoot(); - }else{ - if($root=='/'){ - $root=''; - } - } - $path=$root.$path; - $query=OC_DB::prepare('SELECT size FROM *PREFIX*fscache WHERE path_hash=?'); - $result=$query->execute(array(md5($path))); - if($row=$result->fetchRow()){ - return $row['size']; - }else{//file not in cache - return 0; - } - } - - /** - * called when files are deleted - * @param array $params - * @param string root (optional) - */ - public static function fileSystemWatcherDelete($params,$root=''){ - if(!$root){ - $root=OC_Filesystem::getRoot(); - } - if($root=='/'){ - $root=''; - } - $path=$params['path']; - $fullPath=$root.$path; - if(self::getFileId($fullPath)==-1){ - return; - } - $size=self::getCachedSize($path,$root); - self::increaseSize(dirname($fullPath),-$size); - self::delete($path); - } - - /** - * called when files are deleted - * @param array $params - * @param string root (optional) - */ - public static function fileSystemWatcherRename($params,$root=''){ - if(!$root){ - $root=OC_Filesystem::getRoot(); - } - if($root=='/'){ - $root=''; - } - $oldPath=$params['oldpath']; - $newPath=$params['newpath']; - $fullOldPath=$root.$oldPath; - $fullNewPath=$root.$newPath; - if(($id=self::getFileId($fullOldPath))!=-1){ - $oldSize=self::getCachedSize($oldPath,$root); - }else{ - return; - } - $size=OC_Filesystem::filesize($newPath); - self::increaseSize(dirname($fullOldPath),-$oldSize); - self::increaseSize(dirname($fullNewPath),$oldSize); - self::move($oldPath,$newPath); - } - /** * adjust the size of the parent folders * @param string $path * @param int $sizeDiff + * @param string root (optinal) */ - private static function increaseSize($path,$sizeDiff){ + public static function increaseSize($path,$sizeDiff, $root=false){ if($sizeDiff==0) return; - while(($id=self::getFileId($path))!=-1){//walk up the filetree increasing the size of all parent folders + $id=self::getId($path,''); + while($id!=-1){//walk up the filetree increasing the size of all parent folders $query=OC_DB::prepare('UPDATE *PREFIX*fscache SET size=size+? WHERE id=?'); $query->execute(array($sizeDiff,$id)); + $id=self::getParentId($path); $path=dirname($path); } } @@ -525,15 +317,15 @@ class OC_FileCache{ * @param int count (optional) * @param string root (optionak) */ - public static function scan($path,$eventSource=false,&$count=0,$root=''){ + public static function scan($path,$eventSource=false,&$count=0,$root=false){ if($eventSource){ $eventSource->send('scanning',array('file'=>$path,'count'=>$count)); } $lastSend=$count; - if(!$root){ + if($root===false){ $view=OC_Filesystem::getView(); }else{ - $view=new OC_FilesystemView(($root=='/')?'':$root); + $view=new OC_FilesystemView($root); } self::scanFile($path,$root); $dh=$view->opendir($path.'/'); @@ -555,8 +347,9 @@ class OC_FileCache{ } } } - self::cleanFolder($path,$root); - self::increaseSize($view->getRoot().$path,$totalSize); + + OC_FileCache_Update::cleanFolder($path,$root); + self::increaseSize($path,$totalSize,$root); } /** @@ -565,11 +358,11 @@ class OC_FileCache{ * @param string root (optional) * @return int size of the scanned file */ - public static function scanFile($path,$root=''){ - if(!$root){ + public static function scanFile($path,$root=false){ + if($root===false){ $view=OC_Filesystem::getView(); }else{ - $view=new OC_FilesystemView(($root=='/')?'':$root); + $view=new OC_FilesystemView($root); } if(!$view->is_readable($path)) return; //cant read, nothing we can do clearstatcache(); @@ -602,11 +395,9 @@ class OC_FileCache{ * seccond mimetype part can be ommited * e.g. searchByMime('audio') */ - public static function searchByMime($part1,$part2=null,$root=null){ - if(!$root){ + public static function searchByMime($part1,$part2=null,$root=false){ + if($root===false){ $root=OC_Filesystem::getRoot(); - }elseif($root=='/'){ - $root=''; } $rootLen=strlen($root); $root .= '%'; @@ -626,103 +417,6 @@ class OC_FileCache{ } /** - * check if a file or folder is updated outside owncloud - * @param string path - * @param string root (optional) - * @return bool - */ - public static function isUpdated($path,$root=''){ - if(!$root){ - $root=OC_Filesystem::getRoot(); - $view=OC_Filesystem::getView(); - }else{ - if($root=='/'){ - $root=''; - } - $view=new OC_FilesystemView($root); - } - if(!$view->file_exists($path)){ - return false; - } - $mtime=$view->filemtime($path); - $isDir=$view->is_dir($path); - $fullPath=$root.$path; - $query=OC_DB::prepare('SELECT mtime FROM *PREFIX*fscache WHERE path_hash=?'); - $result=$query->execute(array(md5($fullPath))); - if($row=$result->fetchRow()){ - $cachedMTime=$row['mtime']; - return ($mtime>$cachedMTime); - }else{//file not in cache, so it has to be updated - if($path=='/' or $path==''){//dont auto update the root folder, it will be scanned - return false; - } - return true; - } - } - - /** - * update the cache according to changes in the folder - * @param string path - * @param string root (optional) - */ - private static function updateFolder($path,$root=''){ - if(!$root){ - $view=OC_Filesystem::getView(); - }else{ - $view=new OC_FilesystemView(($root=='/')?'':$root); - } - $dh=$view->opendir($path.'/'); - if($dh){//check for changed/new files - while (($filename = readdir($dh)) !== false) { - if($filename != '.' and $filename != '..'){ - $file=$path.'/'.$filename; - if(self::isUpdated($file,$root)){ - if(!$root){//filesystem hooks are only valid for the default root - OC_Hook::emit('OC_Filesystem','post_write',array('path'=>$file)); - }else{ - self::fileSystemWatcherWrite(array('path'=>$file),$root); - } - } - } - } - } - - self::cleanFolder($path,$root); - - //update the folder last, so we can calculate the size correctly - if(!$root){//filesystem hooks are only valid for the default root - OC_Hook::emit('OC_Filesystem','post_write',array('path'=>$path)); - }else{ - self::fileSystemWatcherWrite(array('path'=>$path),$root); - } - } - - /** - * delete non existing files from the cache - */ - private static function cleanFolder($path,$root=''){ - if(!$root){ - $view=OC_Filesystem::getView(); - }else{ - $view=new OC_FilesystemView(($root=='/')?'':$root); - } - //check for removed files, not using getFolderContent to prevent loops - $parent=self::getFileId($view->getRoot().$path); - $query=OC_DB::prepare('SELECT name FROM *PREFIX*fscache WHERE parent=?'); - $result=$query->execute(array($parent)); - while($row=$result->fetchRow()){ - $file=$path.'/'.$row['name']; - if(!$view->file_exists($file)){ - if(!$root){//filesystem hooks are only valid for the default root - OC_Hook::emit('OC_Filesystem','post_delete',array('path'=>$file)); - }else{ - self::fileSystemWatcherDelete(array('path'=>$file),$root); - } - } - } - } - - /** * clean old pre-path_hash entries */ public static function clean(){ @@ -732,6 +426,6 @@ class OC_FileCache{ } //watch for changes and try to keep the cache up to date -OC_Hook::connect('OC_Filesystem','post_write','OC_FileCache','fileSystemWatcherWrite'); -OC_Hook::connect('OC_Filesystem','post_delete','OC_FileCache','fileSystemWatcherDelete'); -OC_Hook::connect('OC_Filesystem','post_rename','OC_FileCache','fileSystemWatcherRename'); +OC_Hook::connect('OC_Filesystem','post_write','OC_FileCache_Update','fileSystemWatcherWrite'); +OC_Hook::connect('OC_Filesystem','post_delete','OC_FileCache_Update','fileSystemWatcherDelete'); +OC_Hook::connect('OC_Filesystem','post_rename','OC_FileCache_Update','fileSystemWatcherRename'); diff --git a/lib/filecache/cached.php b/lib/filecache/cached.php new file mode 100644 index 00000000000..17a792a23d4 --- /dev/null +++ b/lib/filecache/cached.php @@ -0,0 +1,70 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + + +/** + * get data from the filecache without checking for updates + */ +class OC_FileCache_Cached{ + public static $savedData=array(); + + public static function get($path,$root=false){ + if($root===false){ + $root=OC_Filesystem::getRoot(); + } + $path=$root.$path; + $query=OC_DB::prepare('SELECT path,ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE path_hash=?'); + $result=$query->execute(array(md5($path)))->fetchRow(); + if(is_array($result)){ + if(isset(self::$savedData[$path])){ + $result=array_merge($result,self::$savedData[$path]); + } + return $result; + }else{ + if(isset(self::$savedData[$path])){ + return self::$savedData[$path]; + }else{ + return array(); + } + } + } + + /** + * get all files and folders in a folder + * @param string path + * @param string root (optional) + * @return array + * + * returns an array of assiciative arrays with the following keys: + * - path + * - name + * - size + * - mtime + * - ctime + * - mimetype + * - encrypted + * - versioned + */ + public static function getFolderContent($path,$root=false,$mimetype_filter=''){ + if($root===false){ + $root=OC_Filesystem::getRoot(); + } + $parent=OC_FileCache::getId($path,$root); + if($parent==-1){ + return array(); + } + $query=OC_DB::prepare('SELECT path,name,ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE parent=? AND (mimetype LIKE ? OR mimetype = ?)'); + $result=$query->execute(array($parent, $mimetype_filter.'%', 'httpd/unix-directory'))->fetchAll(); + if(is_array($result)){ + return $result; + }else{ + OC_Log::write('files','getFolderContent(): file not found in cache ('.$path.')',OC_Log::DEBUG); + return false; + } + } +}
\ No newline at end of file diff --git a/lib/filecache/update.php b/lib/filecache/update.php new file mode 100644 index 00000000000..dd77f491ca0 --- /dev/null +++ b/lib/filecache/update.php @@ -0,0 +1,215 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + + +/** + * handles updating the filecache according to outside changes + */ +class OC_FileCache_Update{ + /** + * check if a file or folder is updated outside owncloud + * @param string path + * @param string root (optional) + * @param boolean folder + * @return bool + */ + public static function hasUpdated($path,$root=false,$folder=false){ + if($root===false){ + $view=OC_Filesystem::getView(); + }else{ + $view=new OC_FilesystemView($root); + } + if(!$view->file_exists($path)){ + return false; + } + $cachedData=OC_FileCache_Cached::get($path,$root); + if(isset($cachedData['mtime'])){ + $cachedMTime=$cachedData['mtime']; + if($folder){ + return $view->hasUpdated($path.'/',$cachedMTime); + }else{ + return $view->hasUpdated($path,$cachedMTime); + } + }else{//file not in cache, so it has to be updated + if(($path=='/' or $path=='') and $root===false){//dont auto update the home folder, it will be scanned + return false; + } + return true; + } + } + + /** + * delete non existing files from the cache + */ + public static function cleanFolder($path,$root=false){ + if($root===false){ + $view=OC_Filesystem::getView(); + }else{ + $view=new OC_FilesystemView($root); + } + + $cachedContent=OC_FileCache_Cached::getFolderContent($path,$root); + foreach($cachedContent as $fileData){ + $path=$fileData['path']; + $file=$view->getRelativePath($path); + if(!$view->file_exists($file)){ + if($root===false){//filesystem hooks are only valid for the default root + OC_Hook::emit('OC_Filesystem','post_delete',array('path'=>$file)); + }else{ + self::delete($file,$root); + } + } + } + } + + /** + * update the cache according to changes in the folder + * @param string path + * @param string root (optional) + */ + public static function updateFolder($path,$root=false){ + if($root===false){ + $view=OC_Filesystem::getView(); + }else{ + $view=new OC_FilesystemView($root); + } + $dh=$view->opendir($path.'/'); + if($dh){//check for changed/new files + while (($filename = readdir($dh)) !== false) { + if($filename != '.' and $filename != '..'){ + $file=$path.'/'.$filename; + if(self::hasUpdated($file,$root)){ + if($root===false){//filesystem hooks are only valid for the default root + OC_Hook::emit('OC_Filesystem','post_write',array('path'=>$file)); + }else{ + self::update($file,$root); + } + } + } + } + } + + self::cleanFolder($path,$root); + + //update the folder last, so we can calculate the size correctly + if($root===false){//filesystem hooks are only valid for the default root + OC_Hook::emit('OC_Filesystem','post_write',array('path'=>$path)); + }else{ + self::update($path,$root); + } + } + + /** + * called when changes are made to files + * @param array $params + * @param string root (optional) + */ + public static function fileSystemWatcherWrite($params){ + $path=$params['path']; + self::update($path); + } + + /** + * called when files are deleted + * @param array $params + * @param string root (optional) + */ + public static function fileSystemWatcherDelete($params){ + $path=$params['path']; + self::delete($path); + } + + /** + * called when files are deleted + * @param array $params + * @param string root (optional) + */ + public static function fileSystemWatcherRename($params){ + $oldPath=$params['oldpath']; + $newPath=$params['newpath']; + self::rename($oldPath,$newPath); + } + + /** + * update the filecache according to changes to the fileysystem + * @param string path + * @param string root (optional) + */ + public static function update($path,$root=false){ + if($root===false){ + $view=OC_Filesystem::getView(); + }else{ + $view=new OC_FilesystemView($root); + } + + $mimetype=$view->getMimeType($path); + + $size=0; + $cached=OC_FileCache_Cached::get($path,$root); + $cachedSize=isset($cached['size'])?$cached['size']:0; + + if($mimetype=='httpd/unix-directory'){ + if(OC_FileCache::inCache($path,$root)){ + $cachedContent=OC_FileCache_Cached::getFolderContent($path,$root); + foreach($cachedContent as $file){ + $size+=$file['size']; + } + $mtime=$view->filemtime($path.'/'); + $ctime=$view->filectime($path.'/'); + $writable=$view->is_writable($path.'/'); + OC_FileCache::put($path,array('size'=>$size,'mtime'=>$mtime,'ctime'=>$ctime,'mimetype'=>$mimetype,'writable'=>$writable)); + }else{ + $count=0; + OC_FileCache::scan($path,null,$count,$root); + return; //increaseSize is already called inside scan + } + }else{ + $size=OC_FileCache::scanFile($path,$root); + } + OC_FileCache::increaseSize(dirname($path),$size-$cachedSize,$root); + } + + /** + * update the filesystem after a delete has been detected + * @param string path + * @param string root (optional) + */ + public static function delete($path,$root=false){ + $cached=OC_FileCache_Cached::get($path,$root); + if(!isset($cached['size'])){ + return; + } + $size=$cached['size']; + OC_FileCache::increaseSize(dirname($path),-$size,$root); + OC_FileCache::delete($path,$root); + } + + /** + * update the filesystem after a rename has been detected + * @param string oldPath + * @param string newPath + * @param string root (optional) + */ + public static function rename($oldPath,$newPath,$root=false){ + if(!OC_FileCache::inCache($oldPath,$root)){ + return; + } + if($root===false){ + $view=OC_Filesystem::getView(); + }else{ + $view=new OC_FilesystemView($root); + } + + $cached=OC_FileCache_Cached::get($oldPath,$root); + $oldSize=$cached['size']; + $size=$view->filesize($newPath); + OC_FileCache::increaseSize(dirname($oldPath),-$oldSize,$root); + OC_FileCache::increaseSize(dirname($newPath),$oldSize,$root); + OC_FileCache::move($oldPath,$newPath); + } +}
\ No newline at end of file diff --git a/lib/fileproxy/quota.php b/lib/fileproxy/quota.php index 9e4c2d0643e..7316224cc61 100644 --- a/lib/fileproxy/quota.php +++ b/lib/fileproxy/quota.php @@ -54,8 +54,15 @@ class OC_FileProxy_Quota extends OC_FileProxy{ * @return int */ private function getFreeSpace(){ - $rootInfo=OC_FileCache::get(''); - $usedSpace=$rootInfo['size']; + $rootInfo=OC_FileCache_Cached::get(''); + // TODO Remove after merge of share_api + if (OC_FileCache::inCache('/Shared')) { + $sharedInfo=OC_FileCache_Cached::get('/Shared'); + } else { + $sharedInfo = null; + } + $usedSpace=isset($rootInfo['size'])?$rootInfo['size']:0; + $usedSpace=isset($sharedInfo['size'])?$usedSpace-$sharedInfo['size']:$usedSpace; $totalSpace=$this->getQuota(); if($totalSpace==0){ return 0; diff --git a/lib/files.php b/lib/files.php index 705b7a6ca66..469c3a15b8e 100644 --- a/lib/files.php +++ b/lib/files.php @@ -30,13 +30,10 @@ class OC_Files { /** * get the content of a directory - * @param dir $directory + * @param dir $directory path under datadirectory */ public static function getDirectoryContent($directory, $mimetype_filter = ''){ - if(strpos($directory,OC::$CONFIG_DATADIRECTORY)===0){ - $directory=substr($directory,strlen(OC::$CONFIG_DATADIRECTORY)); - } - $files=OC_FileCache::getFolderContent($directory, '', $mimetype_filter); + $files=OC_FileCache::getFolderContent($directory, false, $mimetype_filter); foreach($files as &$file){ $file['directory']=$directory; $file['type']=($file['mimetype']=='httpd/unix-directory')?'dir':'file'; diff --git a/lib/filestorage.php b/lib/filestorage.php index 1d7e004af3b..71ef4aed00b 100644 --- a/lib/filestorage.php +++ b/lib/filestorage.php @@ -50,4 +50,13 @@ abstract class OC_Filestorage{ abstract public function search($query); abstract public function touch($path, $mtime=null); abstract public function getLocalFile($path);// get a path to a local version of the file, whether the original file is local or remote + /** + * check if a file or folder has been updated since $time + * @param int $time + * @return bool + * + * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed. + * returning true for other changes in the folder is optional + */ + abstract public function hasUpdated($path,$time); } diff --git a/lib/filestorage/common.php b/lib/filestorage/common.php index f0bfc064cb5..f2a5775fd19 100644 --- a/lib/filestorage/common.php +++ b/lib/filestorage/common.php @@ -156,4 +156,13 @@ abstract class OC_Filestorage_Common extends OC_Filestorage { } return $files; } + + /** + * check if a file or folder has been updated since $time + * @param int $time + * @return bool + */ + public function hasUpdated($path,$time){ + return $this->filemtime($path)>$time; + } } diff --git a/lib/filestorage/local.php b/lib/filestorage/local.php index ea9a9070263..44a2ab0f634 100644 --- a/lib/filestorage/local.php +++ b/lib/filestorage/local.php @@ -194,4 +194,13 @@ class OC_Filestorage_Local extends OC_Filestorage{ public function getFolderSize($path){ return 0;//depricated, use OC_FileCach instead } + + /** + * check if a file or folder has been updated since $time + * @param int $time + * @return bool + */ + public function hasUpdated($path,$time){ + return $this->filemtime($path)>$time; + } } diff --git a/lib/filesystem.php b/lib/filesystem.php index 28bd7d52900..0ab3bd69acd 100644 --- a/lib/filesystem.php +++ b/lib/filesystem.php @@ -25,7 +25,7 @@ /** * Class for abstraction of filesystem functions * This class won't call any filesystem functions for itself but but will pass them to the correct OC_Filestorage object - * this class should also handle all the file premission related stuff + * this class should also handle all the file permission related stuff * * Hooks provided: * read(path) @@ -399,6 +399,9 @@ class OC_Filesystem{ static public function opendir($path){ return self::$defaultInstance->opendir($path); } + static public function readdir($path){ + return self::$defaultInstance->readdir($path); + } static public function is_dir($path){ return self::$defaultInstance->is_dir($path); } @@ -474,6 +477,16 @@ class OC_Filesystem{ static public function search($query){ return OC_FileCache::search($query); } + + /** + * check if a file or folder has been updated since $time + * @param int $time + * @return bool + */ + static public function hasUpdated($path,$time){ + return self::$defaultInstance->hasUpdated($path); + } } +OC_Util::setupFS(); require_once('filecache.php'); diff --git a/lib/filesystemview.php b/lib/filesystemview.php index 58657671b98..da622bcf920 100644 --- a/lib/filesystemview.php +++ b/lib/filesystemview.php @@ -158,6 +158,10 @@ class OC_FilesystemView { public function opendir($path){ return $this->basicOperation('opendir',$path,array('read')); } + public function readdir($handle){ + $fsLocal= new OC_Filestorage_Local( array( 'datadir' => '/' ) ); + return $fsLocal->readdir( $handle ); + } public function is_dir($path){ if($path=='/'){ return true; @@ -444,4 +448,13 @@ class OC_FilesystemView { } return null; } + + /** + * check if a file or folder has been updated since $time + * @param int $time + * @return bool + */ + public function hasUpdated($path,$time){ + return $this->basicOperation('hasUpdated',$path,array(),$time); + } } diff --git a/lib/helper.php b/lib/helper.php index 73d4b659a34..37914b73e17 100644 --- a/lib/helper.php +++ b/lib/helper.php @@ -378,6 +378,12 @@ class OC_Helper { //trim the character set from the end of the response $mimeType=substr($reply,0,strrpos($reply,' ')); + + //trim ; + if (strpos($mimeType, ';') !== false) { + $mimeType = strstr($mimeType, ';', true); + } + } if ($mimeType=='application/octet-stream') { // Fallback solution: (try to guess the type by the file extension diff --git a/lib/l10n.php b/lib/l10n.php index 887652e2b85..4acbc5dcebc 100644 --- a/lib/l10n.php +++ b/lib/l10n.php @@ -40,6 +40,16 @@ class OC_L10N{ protected static $language = ''; /** + * App of this object + */ + protected $app; + + /** + * Language of this object + */ + protected $lang; + + /** * Translations */ private $translations = array(); @@ -77,10 +87,17 @@ class OC_L10N{ * language. */ public function __construct($app, $lang = null){ - $this->init($app, $lang); + $this->app = $app; + $this->lang = $lang; } - protected function init($app, $lang = null){ + protected function init(){ + if ($this->app === true) { + return; + } + $app = $this->app; + $lang = $this->lang; + $this->app = true; // Find the right language if(is_null($lang)){ $lang = self::findLanguage($app); @@ -127,10 +144,7 @@ class OC_L10N{ * returned. */ public function t($text, $parameters = array()){ - if(array_key_exists($text, $this->translations)){ - return vsprintf($this->translations[$text], $parameters); - } - return vsprintf($text, $parameters); + return new OC_L10N_String($this, $text, $parameters); } /** @@ -144,7 +158,7 @@ class OC_L10N{ public function tA($textArray){ $result = array(); foreach($textArray as $key => $text){ - $result[$key] = $this->t($text); + $result[$key] = (string)$this->t($text); } return $result; } @@ -156,6 +170,7 @@ class OC_L10N{ * Returns an associative array with all translations */ public function getTranslations(){ + $this->init(); return $this->translations; } @@ -182,6 +197,7 @@ class OC_L10N{ * - params: timestamp (int/string) */ public function l($type, $data){ + $this->init(); switch($type){ // If you add something don't forget to add it to $localizations // at the top of the page @@ -228,23 +244,29 @@ class OC_L10N{ return self::$language; } - $available = array(); - if(is_array($app)){ - $available = $app; - } - else{ - $available=self::findAvailableLanguages($app); - } if(OC_User::getUser() && OC_Preferences::getValue(OC_User::getUser(), 'core', 'lang')){ $lang = OC_Preferences::getValue(OC_User::getUser(), 'core', 'lang'); self::$language = $lang; - if(array_search($lang, $available) !== false){ + if(is_array($app)){ + $available = $app; + $lang_exists = array_search($lang, $available) !== false; + } + else { + $lang_exists = self::languageExists($app, $lang); + } + if($lang_exists){ return $lang; } } if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])){ $accepted_languages = preg_split('/,\s*/', $_SERVER['HTTP_ACCEPT_LANGUAGE']); + if(is_array($app)){ + $available = $app; + } + else{ + $available = self::findAvailableLanguages($app); + } foreach($accepted_languages as $i){ $temp = explode(';', $i); if(array_search($temp[0], $available) !== false){ @@ -296,4 +318,15 @@ class OC_L10N{ } return $available; } + + public static function languageExists($app, $lang){ + if ($lang == 'en'){//english is always available + return true; + } + $dir = self::findI18nDir($app); + if(is_dir($dir)){ + return file_exists($dir.'/'.$lang.'.php'); + } + return false; + } } diff --git a/lib/l10n/string.php b/lib/l10n/string.php new file mode 100644 index 00000000000..4769790a16d --- /dev/null +++ b/lib/l10n/string.php @@ -0,0 +1,25 @@ +<?php +/** + * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_L10N_String{ + protected $l10n; + public function __construct($l10n, $text, $parameters){ + $this->l10n = $l10n; + $this->text = $text; + $this->parameters = $parameters; + + } + + public function __toString(){ + $translations = $this->l10n->getTranslations(); + if(array_key_exists($this->text, $translations)){ + return vsprintf($translations[$this->text], $this->parameters); + } + return vsprintf($this->text, $this->parameters); + } +} diff --git a/lib/migrate.php b/lib/migrate.php index f9cab915d04..5939ba32e50 100644 --- a/lib/migrate.php +++ b/lib/migrate.php @@ -196,7 +196,7 @@ class OC_Migrate{ * @param optional $uid userid of new user */ public static function import( $path, $type='user', $uid=null ){ - OC_Util::checkAdminUser(); + $datadir = OC_Config::getValue( 'datadirectory' ); // Extract the zip if( !$extractpath = self::extractZip( $path ) ){ @@ -216,12 +216,19 @@ class OC_Migrate{ } self::$exporttype = $type; + $currentuser = OC_User::getUser(); + // Have we got a user if type is user if( self::$exporttype == 'user' ){ - if( !$uid ){ - self::$uid = $json->exporteduser; - } else { - self::$uid = $uid; + self::$uid = !is_null($uid) ? $uid : $currentuser; + } + + // We need to be an admin if we are not importing our own data + if(($type == 'user' && self::$uid != $currentuser) || $type != 'user' ){ + if( !OC_Group::inGroup( OC_User::getUser(), 'admin' )){ + // Naughty. + OC_Log::write( 'migration', 'Import not permitted.', OC_Log::ERROR ); + return json_encode( array( 'success' => false ) ); } } @@ -229,27 +236,8 @@ class OC_Migrate{ switch( self::$exporttype ){ case 'user': // Check user availability - if( OC_User::userExists( self::$uid ) ){ - OC_Log::write( 'migration', 'User already exists', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - $run = true; - OC_Hook::emit( "OC_User", "pre_createUser", array( "run" => &$run, "uid" => self::$uid, "password" => $json->hash )); - if( !$run ){ - // Something stopped the user creation - OC_Log::write( 'migration', 'User creation failed', OC_Log::ERROR ); - return json_encode( array( 'success' => false ) ); - } - // Create the user - if( !self::createUser( self::$uid, $json->hash ) ){ - return json_encode( array( 'success' => false ) ); - } - // Emit the post_createUser hook (password is already hashed, will cause problems - OC_Hook::emit( "OC_User", "post_createUser", array( "uid" => self::$uid, "password" => $json->hash )); - // Make the new users data dir - $path = $datadir . '/' . self::$uid; - if( !mkdir( $path, 0755, true ) ){ - OC_Log::write( 'migration', 'Failed to create users data dir: '.$path, OC_Log::ERROR ); + if( !OC_User::userExists( self::$uid ) ){ + OC_Log::write( 'migration', 'User doesn\'t exist', OC_Log::ERROR ); return json_encode( array( 'success' => false ) ); } // Copy data diff --git a/lib/mimetypes.fixlist.php b/lib/mimetypes.fixlist.php index a40fbd9e228..13e3f16b369 100644 --- a/lib/mimetypes.fixlist.php +++ b/lib/mimetypes.fixlist.php @@ -17,5 +17,6 @@ return array( 'xlsx'=>'application/msexcel', 'ppt'=>'application/mspowerpoint', 'pptx'=>'application/mspowerpoint', - 'sgf' => 'application/sgf' + 'sgf' => 'application/sgf', + 'cdr' => 'application/coreldraw' ); diff --git a/lib/minimizer.php b/lib/minimizer.php index 9f9ef086c4a..e17c114f065 100644 --- a/lib/minimizer.php +++ b/lib/minimizer.php @@ -1,17 +1,6 @@ <?php -abstract class OC_Minimizer -{ - protected $files = array(); - - protected function appendIfExist($root, $webroot, $file) { - if (is_file($root.'/'.$file)) { - $this->files[] = array($root, $webroot, $file); - return true; - } - return false; - } - +abstract class OC_Minimizer { public function getLastModified($files) { $last_modified = 0; foreach($files as $file_info) { @@ -26,14 +15,30 @@ abstract class OC_Minimizer abstract public function minimizeFiles($files); - public function output($files) { + public function output($files, $cache_key) { header('Content-Type: '.$this->contentType); OC_Response::enableCaching(); $last_modified = $this->getLastModified($files); OC_Response::setLastModifiedHeader($last_modified); - $out = $this->minimizeFiles($files); - OC_Response::setETagHeader(md5($out)); + $gzout = false; + $cache = new OC_Cache_FileGlobal(); + if (!OC_Request::isNoCache() && (!defined('DEBUG') || !DEBUG)){ + $gzout = $cache->get($cache_key.'.gz'); + OC_Response::setETagHeader(md5($gzout)); + } + + if (!$gzout) { + $out = $this->minimizeFiles($files); + $gzout = gzencode($out); + $cache->set($cache_key.'.gz', $gzout); + } + if ($encoding = OC_Request::acceptGZip()) { + header('Content-Encoding: '.$encoding); + $out = $gzout; + } else { + $out = gzdecode($gzout); + } header('Content-Length: '.strlen($out)); echo $out; } diff --git a/lib/minimizer/css.php b/lib/minimizer/css.php index c7e5d96e06b..97099adbdf6 100644 --- a/lib/minimizer/css.php +++ b/lib/minimizer/css.php @@ -6,54 +6,6 @@ class OC_Minimizer_CSS extends OC_Minimizer { protected $contentType = 'text/css'; - public function findFiles($styles) { - // Read the selected theme from the config file - $theme=OC_Config::getValue( "theme" ); - - // Read the detected formfactor and use the right file name. - $fext = OC_Template::getFormFactorExtension(); - foreach($styles as $style){ - // is it in 3rdparty? - if($this->appendIfExist(OC::$THIRDPARTYROOT, OC::$THIRDPARTYWEBROOT, $style.'.css')) { - - // or in the owncloud root? - }elseif($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "$style$fext.css" )) { - }elseif($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "$style.css" )) { - - // or in core ? - }elseif($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "core/$style$fext.css" )) { - }elseif($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "core/$style.css" )) { - - }else{ - $append = false; - foreach( OC::$APPSROOTS as $apps_dir) - { - if($this->appendIfExist($apps_dir['path'], $apps_dir['url'], "$style$fext.css", true)) { $append =true; break; } - elseif($this->appendIfExist($apps_dir['path'], $apps_dir['url'], "$style.css", true )) { $append =true; break; } - } - if(! $append) { - echo('css file not found: style:'.$script.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); - die(); - } - } - } - // Add the theme css files. you can override the default values here - if(!empty($theme)) { - foreach($styles as $style){ - if($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$style$fext.css" )) { - }elseif($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$style.css" )) { - - }elseif($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$style$fext.css" )) { - }elseif($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$style.css" )) { - - }elseif($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$style$fext.css" )) { - }elseif($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$style.css" )) { - } - } - } - return $this->files; - } - public function minimizeFiles($files) { $css_out = ''; $webroot = (string) OC::$WEBROOT; @@ -78,7 +30,9 @@ class OC_Minimizer_CSS extends OC_Minimizer $remote .= dirname($file_info[2]); $css_out .= CSSMin::remap($css, dirname($file), $remote, true); } - $css_out = CSSMin::minify($css_out); + if (!defined('DEBUG') || !DEBUG){ + $css_out = CSSMin::minify($css_out); + } return $css_out; } } diff --git a/lib/minimizer/js.php b/lib/minimizer/js.php index dd7d15de061..0f5cb7e5577 100644 --- a/lib/minimizer/js.php +++ b/lib/minimizer/js.php @@ -6,54 +6,6 @@ class OC_Minimizer_JS extends OC_Minimizer { protected $contentType = 'application/javascript'; - public function findFiles($scripts) { - // Read the selected theme from the config file - $theme=OC_Config::getValue( "theme" ); - - // Read the detected formfactor and use the right file name. - $fext = OC_Template::getFormFactorExtension(); - // Add the core js files or the js files provided by the selected theme - foreach($scripts as $script){ - // Is it in 3rd party? - if($this->appendIfExist(OC::$THIRDPARTYROOT, OC::$THIRDPARTYWEBROOT, $script.'.js')) { - - // Is it in apps and overwritten by the theme? - }elseif($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$script$fext.js" )) { - }elseif($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$script.js" )) { - - // Is it in the owncloud root but overwritten by the theme? - }elseif($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$script$fext.js" )) { - }elseif($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$script.js" )) { - - // Is it in the owncloud root ? - }elseif($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "$script$fext.js" )) { - }elseif($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "$script.js" )) { - - // Is in core but overwritten by a theme? - }elseif($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$script$fext.js" )) { - }elseif($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$script.js" )) { - - // Is it in core? - }elseif($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "core/$script$fext.js" )) { - }elseif($this->appendIfExist(OC::$SERVERROOT, OC::$WEBROOT, "core/$script.js" )) { - - }else{ - // Is it part of an app? - $append = false; - foreach( OC::$APPSROOTS as $apps_dir) - { - if($this->appendIfExist($apps_dir['path'], $apps_dir['url'], "$script$fext.js" , true)) { $append =true; break; } - elseif($this->appendIfExist($apps_dir['path'], $apps_dir['url'], "$script.js", true )) { $append =true; break; } - } - if(! $append) { - echo('js file not found: script:'.$script.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); - die(); - } - } - } - return $this->files; - } - public function minimizeFiles($files) { $js_out = ''; foreach($files as $file_info) { @@ -61,7 +13,9 @@ class OC_Minimizer_JS extends OC_Minimizer $js_out .= '/* ' . $file . ' */' . "\n"; $js_out .= file_get_contents($file); } - $js_out = JavaScriptMinifier::minify($js_out); + if (!defined('DEBUG') || !DEBUG){ + $js_out = JavaScriptMinifier::minify($js_out); + } return $js_out; } } diff --git a/lib/public/util.php b/lib/public/util.php index d79d3f26b1e..c611d59a533 100644 --- a/lib/public/util.php +++ b/lib/public/util.php @@ -264,6 +264,18 @@ class Util { public static function callCheck(){ return(\OC_Util::callCheck()); } + + /**
+ * @brief Used to sanitize HTML
+ *
+ * This function is used to sanitize HTML and should be applied on any string or array of strings before displaying it on a web page.
+ *
+ * @param string or array of strings
+ * @return array with sanitized strings or a single sinitized string, depends on the input parameter.
+ */
+ public static function sanitizeHTML( $value ){
+ return(\OC_Util::sanitizeHTML($value));
+ } } ?> diff --git a/lib/request.php b/lib/request.php new file mode 100644 index 00000000000..0b5aaf8ef30 --- /dev/null +++ b/lib/request.php @@ -0,0 +1,28 @@ +<?php +/** + * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_Request { + static public function isNoCache() { + if (!isset($_SERVER['HTTP_CACHE_CONTROL'])) { + return false; + } + return $_SERVER['HTTP_CACHE_CONTROL'] == 'no-cache'; + } + + static public function acceptGZip() { + if (!isset($_SERVER['HTTP_ACCEPT_ENCODING'])) { + return false; + } + $HTTP_ACCEPT_ENCODING = $_SERVER["HTTP_ACCEPT_ENCODING"]; + if( strpos($HTTP_ACCEPT_ENCODING, 'x-gzip') !== false ) + return 'x-gzip'; + else if( strpos($HTTP_ACCEPT_ENCODING,'gzip') !== false ) + return 'gzip'; + return false; + } +} diff --git a/lib/template.php b/lib/template.php index 149859aa8a5..3b48c27b9b4 100644 --- a/lib/template.php +++ b/lib/template.php @@ -167,10 +167,47 @@ class OC_Template{ } /** + * autodetects the formfactor of the used device + * default -> the normal desktop browser interface + * mobile -> interface for smartphones + * tablet -> interface for tablets + * standalone -> the default interface but without header, footer and + * sidebar, just the application. Useful to use just a specific + * app on the desktop in a standalone window. + */ + public static function detectFormfactor(){ + // please add more useragent strings for other devices + if(isset($_SERVER['HTTP_USER_AGENT'])){ + if(stripos($_SERVER['HTTP_USER_AGENT'],'ipad')>0) { + $mode='tablet'; + }elseif(stripos($_SERVER['HTTP_USER_AGENT'],'iphone')>0){ + $mode='mobile'; + }elseif((stripos($_SERVER['HTTP_USER_AGENT'],'N9')>0) and (stripos($_SERVER['HTTP_USER_AGENT'],'nokia')>0)){ + $mode='mobile'; + }else{ + $mode='default'; + } + }else{ + $mode='default'; + } + return($mode); + } + + /** * @brief Returns the formfactor extension for current formfactor */ static public function getFormFactorExtension() { + // if the formfactor is not yet autodetected do the + // autodetection now. For possible formfactors check the + // detectFormfactor documentation + if(!isset($_SESSION['formfactor'])){ + $_SESSION['formfactor'] = self::detectFormfactor(); + } + // allow manual override via GET parameter + if(isset($_GET['formfactor'])){ + $_SESSION['formfactor']=$_GET['formfactor']; + } $formfactor=$_SESSION['formfactor']; if($formfactor=='default') { $fext=''; @@ -270,29 +307,12 @@ class OC_Template{ * * If the key existed before, it will be overwritten */ - public function assign( $key, $value, $sanitizeHTML=true ){ - if($sanitizeHTML == true) { - if(is_array($value)) { - array_walk_recursive($value,'OC_Template::sanitizeHTML'); - } else { - $value = OC_Template::sanitizeHTML($value); - } - } + public function assign( $key, $value, $sanitizeHTML=true ){ + if($sanitizeHTML == true) $value=OC_Util::sanitizeHTML($value); $this->vars[$key] = $value; return true; } - - /** - * @brief Internaly used to sanitze HTML - * - * This function is internally used to sanitize HTML. - */ - private static function sanitizeHTML( &$value ){ - $value = htmlentities( $value ); - return $value; - } - /** * @brief Appends a variable * @param $key key @@ -340,38 +360,6 @@ class OC_Template{ } /** - * @brief append the $file-url if exist at $root - * @param $type of collection to use when appending - * @param $root path to check - * @param $web base for path - * @param $file the filename - * @param $in_app boolean is part of an app? (default false) - */ - public function appendIfExist($type, $root, $web, $file, $in_app = false) { - - if (is_file($root.'/'.$file)) { - $pathes = explode('/', $file); - $in_root = false; - foreach(OC::$APPSROOTS as $app_root) { - if($root == $app_root['path']) { - $in_root = true; - break; - } - } - if($type == 'cssfiles' && $in_root && $in_app){ - $app = $pathes[0]; - unset($pathes[0]); - $path = implode('/', $pathes); - $this->append( $type, OC_Helper::linkTo($app, $path)); - }else{ - $this->append( $type, $web.'/'.$file); - } - return true; - } - return false; - } - - /** * @brief Proceeds the template * @returns content * @@ -382,123 +370,9 @@ class OC_Template{ $data = $this->_fetch(); if( $this->renderas ){ - // Decide which page we show - if( $this->renderas == "user" ){ - $page = new OC_Template( "core", "layout.user" ); - $page->assign('searchurl',OC_Helper::linkTo( 'search', 'index.php' ), false); + $page = new OC_TemplateLayout($this->renderas); + if($this->renderas == 'user') { $page->assign('requesttoken', $this->vars['requesttoken']); - if(array_search(OC_APP::getCurrentApp(),array('settings','admin','help'))!==false){ - $page->assign('bodyid','body-settings', false); - }else{ - $page->assign('bodyid','body-user', false); - } - - // Add navigation entry - $navigation = OC_App::getNavigation(); - $page->assign( "navigation", $navigation, false); - $page->assign( "settingsnavigation", OC_App::getSettingsNavigation(), false); - foreach($navigation as $entry) { - if ($entry['active']) { - $page->assign( 'application', $entry['name'], false ); - break; - } - } - }else{ - $page = new OC_Template( "core", "layout.guest" ); - } - $apps_paths = array(); - foreach(OC_App::getEnabledApps() as $app){ - $apps_paths[$app] = OC_App::getAppWebPath($app); - } - $page->assign( 'apps_paths', str_replace('\\/', '/',json_encode($apps_paths)) , false); // Ugly unescape slashes waiting for better solution - - // Read the selected theme from the config file - $theme=OC_Config::getValue( "theme" ); - - // Read the detected formfactor and use the right file name. - $fext = self::getFormFactorExtension(); - - $page->assign('jsfiles', array(), false); - // Add the core js files or the js files provided by the selected theme - foreach(OC_Util::$scripts as $script){ - // Is it in 3rd party? - if($page->appendIfExist('jsfiles', OC::$THIRDPARTYROOT, OC::$THIRDPARTYWEBROOT, $script.'.js')) { - - // Is it in apps and overwritten by the theme? - }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$script$fext.js" )) { - }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$script.js" )) { - - // Is it in the owncloud root but overwritten by the theme? - }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$script$fext.js" )) { - }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$script.js" )) { - - // Is it in the owncloud root ? - }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "$script$fext.js" )) { - }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "$script.js" )) { - - // Is in core but overwritten by a theme? - }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$script$fext.js" )) { - }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$script.js" )) { - - // Is it in core? - }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "core/$script$fext.js" )) { - }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "core/$script.js" )) { - - }else{ - // Is it part of an app? - $append = false; - foreach( OC::$APPSROOTS as $apps_dir) - { - if($page->appendIfExist('jsfiles', $apps_dir['path'], $apps_dir['url'], "$script$fext.js" , true)) { $append =true; break; } - elseif($page->appendIfExist('jsfiles', $apps_dir['path'], $apps_dir['url'], "$script.js", true )) { $append =true; break; } - } - if(! $append) { - echo('js file not found: script:'.$script.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); - die(); - } - } - } - // Add the css files - $page->assign('cssfiles', array()); - foreach(OC_Util::$styles as $style){ - // is it in 3rdparty? - if($page->appendIfExist('cssfiles', OC::$THIRDPARTYROOT, OC::$THIRDPARTYWEBROOT, $style.'.css')) { - - // or in the owncloud root? - }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "$style$fext.css" )) { - }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "$style.css" )) { - - // or in core ? - }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "core/$style$fext.css" )) { - }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "core/$style.css" )) { - - }else{ - // or in apps? - $append = false; - foreach( OC::$APPSROOTS as $apps_dir) - { - if($page->appendIfExist('cssfiles', $apps_dir['path'], $apps_dir['url'], "$style$fext.css", true)) { $append =true; break; } - elseif($page->appendIfExist('cssfiles', $apps_dir['path'], $apps_dir['url'], "$style.css", true )) { $append =true; break; } - } - if(! $append) { - echo('css file not found: style:'.$script.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); - die(); - } - } - } - // Add the theme css files. you can override the default values here - if(!empty($theme)) { - foreach(OC_Util::$styles as $style){ - if($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$style$fext.css" )) { - }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$style.css" )) { - - }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$style$fext.css" )) { - }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$style.css" )) { - - }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$style$fext.css" )) { - }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$style.css" )) { - } - } } // Add custom headers @@ -507,7 +381,6 @@ class OC_Template{ $page->append('headers',$header); } - // Add css files and js files $page->assign( "content", $data, false ); return $page->fetchPage(); } diff --git a/lib/templatelayout.php b/lib/templatelayout.php new file mode 100644 index 00000000000..1f82e82be74 --- /dev/null +++ b/lib/templatelayout.php @@ -0,0 +1,170 @@ +<?php +/** + * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_TemplateLayout extends OC_Template { + public function __construct( $renderas ){ + // Decide which page we show + if( $renderas == 'user' ){ + parent::__construct( 'core', 'layout.user' ); + $this->assign('searchurl',OC_Helper::linkTo( 'search', 'index.php' ), false); + if(array_search(OC_APP::getCurrentApp(),array('settings','admin','help'))!==false){ + $this->assign('bodyid','body-settings', false); + }else{ + $this->assign('bodyid','body-user', false); + } + + // Add navigation entry + $navigation = OC_App::getNavigation(); + $this->assign( 'navigation', $navigation, false); + $this->assign( 'settingsnavigation', OC_App::getSettingsNavigation(), false); + foreach($navigation as $entry) { + if ($entry['active']) { + $this->assign( 'application', $entry['name'], false ); + break; + } + } + }else{ + parent::__construct( 'core', 'layout.guest' ); + } + + // Add the js files + $jsfiles = self::findJavascriptFiles(OC_Util::$scripts); + $this->assign('jsfiles', array(), false); + foreach($jsfiles as $info) { + $root = $info[0]; + $web = $info[1]; + $file = $info[2]; + $this->append( 'jsfiles', $web.'/'.$file); + } + + // Add the css files + $cssfiles = self::findStylesheetFiles(OC_Util::$styles); + $this->assign('cssfiles', array()); + foreach($cssfiles as $info) { + $root = $info[0]; + $web = $info[1]; + $file = $info[2]; + $paths = explode('/', $file); + if($root == OC::$APPSROOT && $paths[0] == 'apps'){ + $app = $paths[1]; + unset($paths[0]); + unset($paths[1]); + $path = implode('/', $paths); + $this->append( 'cssfiles', OC_Helper::linkTo($app, $path)); + }else{ + $this->append( 'cssfiles', $web.'/'.$file); + } + } + } + + /* + * @brief append the $file-url if exist at $root + * @param $files array to append file info to + * @param $root path to check + * @param $web base for path + * @param $file the filename + */ + static public function appendIfExist(&$files, $root, $webroot, $file) { + if (is_file($root.'/'.$file)) { + $files[] = array($root, $webroot, $file); + return true; + } + return false; + } + + static public function findStylesheetFiles($styles){ + // Read the selected theme from the config file + $theme=OC_Config::getValue( 'theme' ); + + // Read the detected formfactor and use the right file name. + $fext = self::getFormFactorExtension(); + + $files = array(); + foreach($styles as $style){ + // is it in 3rdparty? + if(self::appendIfExist($files, OC::$THIRDPARTYROOT, OC::$THIRDPARTYWEBROOT, $style.'.css')) { + + // or in apps? + }elseif(self::appendIfExist($files, OC::$APPSROOT, OC::$APPSWEBROOT, "apps/$style$fext.css" )) { + }elseif(self::appendIfExist($files, OC::$APPSROOT, OC::$APPSWEBROOT, "apps/$style.css" )) { + + // or in the owncloud root? + }elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "$style$fext.css" )) { + }elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "$style.css" )) { + + // or in core ? + }elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "core/$style$fext.css" )) { + }elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "core/$style.css" )) { + + }else{ + echo('css file not found: style:'.$style.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); + die(); + } + } + // Add the theme css files. you can override the default values here + if(!empty($theme)) { + foreach($styles as $style){ + if(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$style$fext.css" )) { + }elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$style.css" )) { + + }elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$style$fext.css" )) { + }elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$style.css" )) { + + }elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$style$fext.css" )) { + }elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$style.css" )) { + } + } + } + return $files; + } + + static public function findJavascriptFiles($scripts){ + // Read the selected theme from the config file + $theme=OC_Config::getValue( 'theme' ); + + // Read the detected formfactor and use the right file name. + $fext = self::getFormFactorExtension(); + + $files = array(); + foreach($scripts as $script){ + // Is it in 3rd party? + if(self::appendIfExist($files, OC::$THIRDPARTYROOT, OC::$THIRDPARTYWEBROOT, $script.'.js')) { + + // Is it in apps and overwritten by the theme? + }elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$script$fext.js" )) { + }elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$script.js" )) { + + // Is it part of an app? + }elseif(self::appendIfExist($files, OC::$APPSROOT, OC::$APPSWEBROOT, "apps/$script$fext.js" )) { + }elseif(self::appendIfExist($files, OC::$APPSROOT, OC::$APPSWEBROOT, "apps/$script.js" )) { + + // Is it in the owncloud root but overwritten by the theme? + }elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$script$fext.js" )) { + }elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$script.js" )) { + + // Is it in the owncloud root ? + }elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "$script$fext.js" )) { + }elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "$script.js" )) { + + // Is in core but overwritten by a theme? + }elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$script$fext.js" )) { + }elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$script.js" )) { + + // Is it in core? + }elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "core/$script$fext.js" )) { + }elseif(self::appendIfExist($files, OC::$SERVERROOT, OC::$WEBROOT, "core/$script.js" )) { + + }else{ + echo('js file not found: script:'.$script.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); + die(); + + } + } + return $files; + } +} diff --git a/lib/user.php b/lib/user.php index f1903093d6d..23b88aa1d06 100644 --- a/lib/user.php +++ b/lib/user.php @@ -240,13 +240,17 @@ class OC_User { * Checks if the user is logged in */ public static function isLoggedIn(){ + static $is_login_checked = null; + if (!is_null($is_login_checked)) { + return $is_login_checked; + } if( isset($_SESSION['user_id']) AND $_SESSION['user_id']) { OC_App::loadApps(array('authentication')); if (self::userExists($_SESSION['user_id']) ){ - return true; + return $is_login_checked = true; } } - return false; + return $is_login_checked = false; } /** diff --git a/lib/util.php b/lib/util.php index cedbe3fa460..8a2d913109d 100755 --- a/lib/util.php +++ b/lib/util.php @@ -14,41 +14,16 @@ class OC_Util { public static $core_scripts=array(); // Can be set up - public static function setupFS( $user = "", $root = "files" ){// configure the initial filesystem based on the configuration + public static function setupFS( $user = '' ){// configure the initial filesystem based on the configuration if(self::$fsSetup){//setting up the filesystem twice can only lead to trouble return false; } - $CONFIG_DATADIRECTORY_ROOT = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); - $CONFIG_BACKUPDIRECTORY = OC_Config::getValue( "backupdirectory", OC::$SERVERROOT."/backup" ); - - // Check if config folder is writable. - if(!is_writable(OC::$SERVERROOT."/config/")) { - $tmpl = new OC_Template( '', 'error', 'guest' ); - $tmpl->assign('errors',array(1=>array('error'=>"Can't write into config directory 'config'",'hint'=>"You can usually fix this by giving the webserver user write access to the config directory in owncloud"))); - $tmpl->printPage(); - exit; - } - - // Check if there is a writable install folder. - if(OC_Config::getValue('appstoreenabled', true)) { - if( OC_App::getInstallPath() === null || !is_writable(OC_App::getInstallPath())) { - $tmpl = new OC_Template( '', 'error', 'guest' ); - $tmpl->assign('errors',array(1=>array('error'=>"Can't write into apps directory 'apps'",'hint'=>"You can usually fix this by giving the webserver user write access to the config directory in owncloud"))); - $tmpl->printPage(); - exit; - } - } - - // Create root dir. - if(!is_dir($CONFIG_DATADIRECTORY_ROOT)){ - $success=@mkdir($CONFIG_DATADIRECTORY_ROOT); - if(!$success) { - $tmpl = new OC_Template( '', 'error', 'guest' ); - $tmpl->assign('errors',array(1=>array('error'=>"Can't create data directory (".$CONFIG_DATADIRECTORY_ROOT.")",'hint'=>"You can usually fix this by giving the webserver write access to the ownCloud directory '".OC::$SERVERROOT."' (in a terminal, use the command 'chown -R www-data:www-data /path/to/your/owncloud/install/data' "))); - $tmpl->printPage(); - exit; - } + $CONFIG_DATADIRECTORY = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); + //first set up the local "root" storage + if(!self::$rootMounted){ + OC_Filesystem::mount('OC_Filestorage_Local',array('datadir'=>$CONFIG_DATADIRECTORY),'/'); + self::$rootMounted=true; } // If we are not forced to load a specific user we load the one that is logged in @@ -56,31 +31,28 @@ class OC_Util { $user = OC_User::getUser(); } - //first set up the local "root" storage - if(!self::$rootMounted){ - OC_Filesystem::mount('OC_Filestorage_Local',array('datadir'=>$CONFIG_DATADIRECTORY_ROOT),'/'); - self::$rootMounted=true; - } if( $user != "" ){ //if we aren't logged in, there is no use to set up the filesystem - OC::$CONFIG_DATADIRECTORY = $CONFIG_DATADIRECTORY_ROOT."/$user/$root"; - if( !is_dir( OC::$CONFIG_DATADIRECTORY )){ - mkdir( OC::$CONFIG_DATADIRECTORY, 0755, true ); + $user_dir = '/'.$user.'/files'; + $userdirectory = $CONFIG_DATADIRECTORY.$user_dir; + if( !is_dir( $userdirectory )){ + mkdir( $userdirectory, 0755, true ); } //jail the user into his "home" directory - OC_Filesystem::init('/'.$user.'/'.$root); + OC_Filesystem::init($user_dir); $quotaProxy=new OC_FileProxy_Quota(); OC_FileProxy::register($quotaProxy); self::$fsSetup=true; // Load personal mount config - if (is_file($CONFIG_DATADIRECTORY_ROOT.'/'.$user.'/mount.php')) { - $mountConfig = include($CONFIG_DATADIRECTORY_ROOT.'/'.$user.'/mount.php'); + if (is_file($CONFIG_DATADIRECTORY.'/'.$user.'/mount.php')) { + $mountConfig = include($CONFIG_DATADIRECTORY.'/'.$user.'/mount.php'); if (isset($mountConfig['user'][$user])) { foreach ($mountConfig['user'][$user] as $mountPoint => $options) { OC_Filesystem::mount($options['class'], $options['options'], $mountPoint); } } } + OC_Hook::emit('OC_Filesystem', 'setup', array('user' => $user, 'user_dir' => $user_dir)); } } @@ -211,9 +183,6 @@ class OC_Util { * @return array arrays with error messages and hints */ public static function checkServer(){ - $CONFIG_DATADIRECTORY_ROOT = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); - $CONFIG_BACKUPDIRECTORY = OC_Config::getValue( "backupdirectory", OC::$SERVERROOT."/backup" ); - $CONFIG_INSTALLED = OC_Config::getValue( "installed", false ); $errors=array(); //check for database drivers @@ -226,19 +195,31 @@ class OC_Util { //common hint for all file permissons error messages $permissionsHint="Permissions can usually be fixed by giving the webserver write access to the ownCloud directory"; + // Check if config folder is writable. + if(!is_writable(OC::$SERVERROOT."/config/")) { + $errors[]=array('error'=>"Can't write into config directory 'config'",'hint'=>"You can usually fix this by giving the webserver user write access to the config directory in owncloud"); + } + + // Check if apps folder is writable. + if(OC_Config::getValue('writable_appsdir', true) && !is_writable(OC::$SERVERROOT."/apps/")) { + $errors[]=array('error'=>"Can't write into apps directory 'apps'",'hint'=>"You can usually fix this by giving the webserver user write access to the config directory in owncloud"); + } + + $CONFIG_DATADIRECTORY = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); //check for correct file permissions if(!stristr(PHP_OS, 'WIN')){ $permissionsModHint="Please change the permissions to 0770 so that the directory cannot be listed by other users."; - $prems=substr(decoct(@fileperms($CONFIG_DATADIRECTORY_ROOT)),-3); + $prems=substr(decoct(@fileperms($CONFIG_DATADIRECTORY)),-3); if(substr($prems,-1)!='0'){ - OC_Helper::chmodr($CONFIG_DATADIRECTORY_ROOT,0770); + OC_Helper::chmodr($CONFIG_DATADIRECTORY,0770); clearstatcache(); - $prems=substr(decoct(@fileperms($CONFIG_DATADIRECTORY_ROOT)),-3); + $prems=substr(decoct(@fileperms($CONFIG_DATADIRECTORY)),-3); if(substr($prems,2,1)!='0'){ - $errors[]=array('error'=>'Data directory ('.$CONFIG_DATADIRECTORY_ROOT.') is readable for other users<br/>','hint'=>$permissionsModHint); + $errors[]=array('error'=>'Data directory ('.$CONFIG_DATADIRECTORY.') is readable for other users<br/>','hint'=>$permissionsModHint); } } if( OC_Config::getValue( "enablebackup", false )){ + $CONFIG_BACKUPDIRECTORY = OC_Config::getValue( "backupdirectory", OC::$SERVERROOT."/backup" ); $prems=substr(decoct(@fileperms($CONFIG_BACKUPDIRECTORY)),-3); if(substr($prems,-1)!='0'){ OC_Helper::chmodr($CONFIG_BACKUPDIRECTORY,0770); @@ -252,8 +233,14 @@ class OC_Util { }else{ //TODO: permissions checks for windows hosts } - if(is_dir($CONFIG_DATADIRECTORY_ROOT) and !is_writable($CONFIG_DATADIRECTORY_ROOT)){ - $errors[]=array('error'=>'Data directory ('.$CONFIG_DATADIRECTORY_ROOT.') not writable by ownCloud<br/>','hint'=>$permissionsHint); + // Create root dir. + if(!is_dir($CONFIG_DATADIRECTORY)){ + $success=@mkdir($CONFIG_DATADIRECTORY); + if(!$success) { + $errors[]=array('error'=>"Can't create data directory (".$CONFIG_DATADIRECTORY.")",'hint'=>"You can usually fix this by giving the webserver write access to the ownCloud directory '".OC::$SERVERROOT."' (in a terminal, use the command 'chown -R www-data:www-data /path/to/your/owncloud/install/data' "); + } + } else if(!is_writable($CONFIG_DATADIRECTORY)){ + $errors[]=array('error'=>'Data directory ('.$CONFIG_DATADIRECTORY.') not writable by ownCloud<br/>','hint'=>$permissionsHint); } // check if all required php modules are present @@ -337,7 +324,11 @@ class OC_Util { OC_Log::write('core','redirectToDefaultPage',OC_Log::DEBUG); if(isset($_REQUEST['redirect_url']) && (substr($_REQUEST['redirect_url'], 0, strlen(OC::$WEBROOT)) == OC::$WEBROOT || $_REQUEST['redirect_url'][0] == '/')) { header( 'Location: '.$_REQUEST['redirect_url']); - } else { + } + else if (isset(OC::$REQUESTEDAPP) && !empty(OC::$REQUESTEDAPP)) { + header( 'Location: '.OC::$WEBROOT.'/?app='.OC::$REQUESTEDAPP ); + } + else { header( 'Location: '.OC::$WEBROOT.'/'.OC_Appconfig::getValue('core', 'defaultpage', '?app=files')); } exit(); @@ -372,7 +363,7 @@ class OC_Util { $_SESSION['requesttoken-'.$token]=time(); // cleanup old tokens garbage collector - // only run every 20th time so we donīt waste cpu cycles + // only run every 20th time so we don't waste cpu cycles if(rand(0,20)==0) { foreach($_SESSION as $key=>$value) { // search all tokens in the session @@ -428,4 +419,58 @@ class OC_Util { exit; } } + + /** + * @brief Public function to sanitize HTML + * + * This function is used to sanitize HTML and should be applied on any string or array of strings before displaying it on a web page. + * + * @param string or array of strings + * @return array with sanitized strings or a single sinitized string, depends on the input parameter. + */ + public static function sanitizeHTML( &$value ){ + if (is_array($value) || is_object($value)) array_walk_recursive($value,'OC_Util::sanitizeHTML'); + else $value = htmlentities($value, ENT_QUOTES, 'UTF-8'); //Specify encoding for PHP<5.4 + return $value; + } + + + /** + * Check if the htaccess file is working buy creating a test file in the data directory and trying to access via http + */ + public static function ishtaccessworking() { + + // testdata + $filename='/htaccesstest.txt'; + $testcontent='testcontent'; + + // creating a test file + $testfile = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ).'/'.$filename; + $fp = @fopen($testfile, 'w'); + @fwrite($fp, $testcontent); + @fclose($fp); + + // accessing the file via http + $url = OC_Helper::serverProtocol(). '://' . OC_Helper::serverHost() . OC::$WEBROOT.'/data'.$filename; + $fp = @fopen($url, 'r'); + $content=@fread($fp, 2048); + @fclose($fp); + + // cleanup + @unlink($testfile); + + // does it work ? + if($content==$testcontent) { + return(false); + }else{ + return(true); + + } + + } + + + + + } diff --git a/remote.php b/remote.php index 9fb73c4ce1d..a58b1c0a0fc 100644 --- a/remote.php +++ b/remote.php @@ -5,7 +5,7 @@ require_once('lib/base.php'); if (array_key_exists('PATH_INFO', $_SERVER)){ $path_info = $_SERVER['PATH_INFO']; }else{ - $path_info = substr($_SERVER['PHP_SELF'], strpos($_SERVER['PHP_SELF'], basename(__FILE__)) + strlen(basename(__FILE__))); + $path_info = substr($_SERVER['REQUEST_URI'], strlen($_SERVER['SCRIPT_NAME'])); } if ($path_info === false) { OC_Response::setStatus(OC_Response::STATUS_NOT_FOUND); diff --git a/settings/admin.php b/settings/admin.php index 4cbd67c3678..8369ee64e06 100644..100755 --- a/settings/admin.php +++ b/settings/admin.php @@ -15,6 +15,7 @@ OC_App::setActiveNavigationEntry( "admin" ); $tmpl = new OC_Template( 'settings', 'admin', 'user'); $forms=OC_App::getForms('admin'); +$htaccessworking=OC_Util::ishtaccessworking(); $entries=OC_Log_Owncloud::getEntries(3); function compareEntries($a,$b){ @@ -23,7 +24,8 @@ function compareEntries($a,$b){ usort($entries, 'compareEntries'); $tmpl->assign('loglevel',OC_Config::getValue( "loglevel", 2 )); -$tmpl->assign('entries',$entries,false); +$tmpl->assign('entries',$entries); +$tmpl->assign('htaccessworking',$htaccessworking); $tmpl->assign('forms',array()); foreach($forms as $form){ $tmpl->append('forms',$form); diff --git a/settings/ajax/getlog.php b/settings/ajax/getlog.php index ed48b2cae1a..d9e80de37ba 100644 --- a/settings/ajax/getlog.php +++ b/settings/ajax/getlog.php @@ -14,4 +14,4 @@ $count=(isset($_GET['count']))?$_GET['count']:50; $offset=(isset($_GET['offset']))?$_GET['offset']:0; $entries=OC_Log_Owncloud::getEntries($count,$offset); -OC_JSON::success(array("data" => $entries)); +OC_JSON::success(array("data" => OC_Util::sanitizeHTML($entries))); diff --git a/settings/ajax/togglegroups.php b/settings/ajax/togglegroups.php index f76e22f51d2..7773c1049c3 100644 --- a/settings/ajax/togglegroups.php +++ b/settings/ajax/togglegroups.php @@ -10,7 +10,7 @@ $error = "add user to"; $action = "add"; $username = $_POST["username"]; -$group = htmlentities($_POST["group"]); +$group = OC_Util::sanitizeHTML($_POST["group"]); if(!OC_Group::groupExists($group)){ OC_Group::createGroup($group); diff --git a/settings/css/settings.css b/settings/css/settings.css index df1e3cfd3c2..80e96df5e66 100644 --- a/settings/css/settings.css +++ b/settings/css/settings.css @@ -48,5 +48,8 @@ li.active { color:#000; } small.externalapp { color:#FFF; background-color:#BBB; font-weight:bold; font-size:6pt; padding:4px; border-radius: 4px;} span.version { margin-left:3em; color:#ddd; } -/* LOF */ +/* LOG */ #log { white-space:normal; } + +/* ADMIN */ +span.securitywarning {color:#C33; font-weight:bold; } diff --git a/settings/personal.php b/settings/personal.php index 64e08be89eb..26a9f601d9a 100644 --- a/settings/personal.php +++ b/settings/personal.php @@ -17,7 +17,8 @@ OC_App::setActiveNavigationEntry( 'personal' ); // calculate the disc space $rootInfo=OC_FileCache::get(''); -$used=$rootInfo['size']; +$sharedInfo=OC_FileCache::get('/Shared');
+$used=$rootInfo['size']-$sharedInfo['size']; $free=OC_Filesystem::free_space(); $total=$free+$used; if($total==0) $total=1; // prevent division by zero diff --git a/settings/templates/admin.php b/settings/templates/admin.php index 38c6042c82a..a9f727d6764 100644..100755 --- a/settings/templates/admin.php +++ b/settings/templates/admin.php @@ -6,6 +6,21 @@ $levels=array('Debug','Info','Warning','Error','Fatal'); ?> +<?php + +if(!$_['htaccessworking']) { +?> +<fieldset class="personalblock"> + <legend><strong><?php echo $l->t('Security Warning');?></strong></legend> + + <span class="securitywarning">Your data directory and your files are probably accessible from the internet. The .htaccess file that ownCloud provides is not working. We strongly suggest that you configure your webserver in a way that the data directory is no longer accessible or you move the data directory outside the webserver document root.</span> + +</fieldset> +<?php +} +?> + + <?php foreach($_['forms'] as $form){ echo $form; };?> diff --git a/tests/lib/filestorage.php b/tests/lib/filestorage.php index f71b658253a..00f37b9f1a2 100644 --- a/tests/lib/filestorage.php +++ b/tests/lib/filestorage.php @@ -149,6 +149,9 @@ abstract class Test_FileStorage extends UnitTestCase { $this->assertTrue(($ctimeStart-1)<=$cTime); $this->assertTrue($cTime<=($ctimeEnd+1)); } + $this->assertTrue($this->instance->hasUpdated('/lorem.txt',$ctimeStart-1)); + $this->assertTrue($this->instance->hasUpdated('/',$ctimeStart-1)); + $this->assertTrue(($ctimeStart-1)<=$mTime); $this->assertTrue($mTime<=($ctimeEnd+1)); $this->assertEqual(filesize($textFile),$this->instance->filesize('/lorem.txt')); @@ -168,6 +171,8 @@ abstract class Test_FileStorage extends UnitTestCase { $this->assertTrue(($mtimeStart-1)<=$mTime); $this->assertTrue($mTime<=($mtimeEnd+1)); $this->assertEqual($cTime,$originalCTime); + + $this->assertTrue($this->instance->hasUpdated('/lorem.txt',$mtimeStart-1)); if($this->instance->touch('/lorem.txt',100)!==false){ $mTime=$this->instance->filemtime('/lorem.txt'); @@ -184,6 +189,9 @@ abstract class Test_FileStorage extends UnitTestCase { $mTime=$this->instance->filemtime('/lorem.txt'); $this->assertTrue(($mtimeStart-1)<=$mTime); $this->assertTrue($mTime<=($mtimeEnd+1)); + + $this->instance->unlink('/lorem.txt'); + $this->assertTrue($this->instance->hasUpdated('/',$mtimeStart-1)); } public function testSearch(){ |