summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Hülsmann <fh@cbix.de>2012-04-02 23:54:18 +0200
committerFlorian Hülsmann <fh@cbix.de>2012-04-02 23:54:18 +0200
commitbd9fa658deb40f798f4134caebf0d91fda1f5c1b (patch)
treea410707843ca62760bcfae7143d2a146e5fae964
parent2cb741adff905f0a53c950fc654d92d60958e4f5 (diff)
parentff5dbc52b8137bc1d4e082c422049271d5f89978 (diff)
downloadnextcloud-server-bd9fa658deb40f798f4134caebf0d91fda1f5c1b.tar.gz
nextcloud-server-bd9fa658deb40f798f4134caebf0d91fda1f5c1b.zip
merged from upstream
-rw-r--r--3rdparty/Archive/Tar.php1954
-rw-r--r--README5
-rw-r--r--apps/calendar/ajax/import/import.php2
-rw-r--r--apps/calendar/export.php2
-rw-r--r--apps/contacts/ajax/deletecard.php10
-rw-r--r--apps/contacts/appinfo/migrate.php68
-rw-r--r--apps/contacts/css/contacts.css127
-rw-r--r--apps/contacts/js/contacts.js87
-rw-r--r--apps/contacts/templates/part.contact.php8
-rw-r--r--apps/files_archive/appinfo/app.php3
-rw-r--r--apps/files_archive/appinfo/info.xml3
-rw-r--r--apps/files_archive/js/archive.js4
-rw-r--r--apps/files_archive/lib/archive.php16
-rw-r--r--apps/files_archive/lib/storage.php6
-rw-r--r--apps/files_archive/lib/tar.php277
-rw-r--r--apps/files_archive/lib/zip.php34
-rw-r--r--apps/files_archive/tests/archive.php40
-rw-r--r--apps/files_archive/tests/tar.php20
-rw-r--r--apps/files_encryption/appinfo/info.xml3
-rw-r--r--apps/files_external/appinfo/app.php11
-rw-r--r--apps/files_external/appinfo/info.xml13
-rw-r--r--apps/files_external/lib/ftp.php (renamed from apps/files_remote/lib/ftp.php)0
-rw-r--r--apps/files_external/lib/google.php (renamed from apps/files_remote/lib/google.php)0
-rw-r--r--apps/files_external/lib/webdav.php (renamed from apps/files_remote/lib/webdav.php)0
-rw-r--r--apps/files_external/tests/config.php (renamed from apps/files_remote/tests/config.php)0
-rw-r--r--apps/files_external/tests/ftp.php (renamed from apps/files_remote/tests/ftp.php)2
-rw-r--r--apps/files_external/tests/google.php (renamed from apps/files_remote/tests/google.php)4
-rw-r--r--apps/files_external/tests/webdav.php (renamed from apps/files_remote/tests/webdav.php)2
-rw-r--r--apps/files_remote/appinfo/app.php11
-rw-r--r--apps/files_remote/appinfo/info.xml10
-rw-r--r--apps/files_sharing/ajax/userautocomplete.php22
-rw-r--r--apps/files_sharing/appinfo/info.xml3
-rw-r--r--apps/files_sharing/lib_share.php14
-rw-r--r--apps/files_texteditor/js/editor.js85
-rw-r--r--apps/gallery/ajax/galleryOp.php3
-rw-r--r--apps/gallery/appinfo/app.php4
-rw-r--r--apps/gallery/appinfo/info.xml4
-rw-r--r--apps/gallery/js/album_cover.js49
-rw-r--r--apps/gallery/templates/index.php39
-rw-r--r--apps/media/css/music.css1
-rw-r--r--apps/remoteStorage/appinfo/info.xml2
-rw-r--r--core/css/styles.css6
-rw-r--r--core/js/eventsource.js12
-rw-r--r--core/js/js.js8
-rw-r--r--core/js/oc-dialogs.js119
-rw-r--r--core/templates/login.php3
-rw-r--r--db_structure.xml27
-rw-r--r--files/ajax/download.php3
-rw-r--r--files/ajax/list.php3
-rw-r--r--files/ajax/mimeicon.php3
-rw-r--r--files/ajax/rawlist.php23
-rw-r--r--files/ajax/scan.php1
-rw-r--r--files/css/files.css4
-rw-r--r--files/js/files.js2
-rw-r--r--files/templates/index.php7
-rw-r--r--files/webdav.php3
-rwxr-xr-xlib/app.php91
-rw-r--r--lib/base.php91
-rw-r--r--lib/db.php3
-rw-r--r--lib/eventsource.php3
-rw-r--r--lib/filecache.php47
-rw-r--r--lib/filestorage/local.php4
-rw-r--r--lib/filesystemview.php17
-rwxr-xr-xlib/helper.php15
-rw-r--r--lib/installer.php39
-rw-r--r--lib/log.php71
-rw-r--r--lib/log/owncloud.php79
-rw-r--r--lib/log/syslog.php37
-rw-r--r--lib/updater.php1
-rw-r--r--lib/util.php10
-rw-r--r--settings/ajax/getlog.php2
-rw-r--r--settings/log.php2
-rw-r--r--settings/templates/personal.php2
-rw-r--r--status.php2
-rw-r--r--tests/index.php12
75 files changed, 3208 insertions, 492 deletions
diff --git a/3rdparty/Archive/Tar.php b/3rdparty/Archive/Tar.php
new file mode 100644
index 00000000000..d8eae851bdc
--- /dev/null
+++ b/3rdparty/Archive/Tar.php
@@ -0,0 +1,1954 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * File::CSV
+ *
+ * PHP versions 4 and 5
+ *
+ * Copyright (c) 1997-2008,
+ * Vincent Blavet <vincent@phpconcept.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category File_Formats
+ * @package Archive_Tar
+ * @author Vincent Blavet <vincent@phpconcept.net>
+ * @copyright 1997-2010 The Authors
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @version CVS: $Id: Tar.php 323476 2012-02-24 15:27:26Z mrook $
+ * @link http://pear.php.net/package/Archive_Tar
+ */
+
+require_once 'PEAR.php';
+
+define('ARCHIVE_TAR_ATT_SEPARATOR', 90001);
+define('ARCHIVE_TAR_END_BLOCK', pack("a512", ''));
+
+/**
+* Creates a (compressed) Tar archive
+*
+* @package Archive_Tar
+* @author Vincent Blavet <vincent@phpconcept.net>
+* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+* @version $Revision: 323476 $
+*/
+class Archive_Tar extends PEAR
+{
+ /**
+ * @var string Name of the Tar
+ */
+ var $_tarname='';
+
+ /**
+ * @var boolean if true, the Tar file will be gzipped
+ */
+ var $_compress=false;
+
+ /**
+ * @var string Type of compression : 'none', 'gz' or 'bz2'
+ */
+ var $_compress_type='none';
+
+ /**
+ * @var string Explode separator
+ */
+ var $_separator=' ';
+
+ /**
+ * @var file descriptor
+ */
+ var $_file=0;
+
+ /**
+ * @var string Local Tar name of a remote Tar (http:// or ftp://)
+ */
+ var $_temp_tarname='';
+
+ /**
+ * @var string regular expression for ignoring files or directories
+ */
+ var $_ignore_regexp='';
+
+ /**
+ * @var object PEAR_Error object
+ */
+ var $error_object=null;
+
+ // {{{ constructor
+ /**
+ * Archive_Tar Class constructor. This flavour of the constructor only
+ * declare a new Archive_Tar object, identifying it by the name of the
+ * tar file.
+ * If the compress argument is set the tar will be read or created as a
+ * gzip or bz2 compressed TAR file.
+ *
+ * @param string $p_tarname The name of the tar archive to create
+ * @param string $p_compress can be null, 'gz' or 'bz2'. This
+ * parameter indicates if gzip or bz2 compression
+ * is required. For compatibility reason the
+ * boolean value 'true' means 'gz'.
+ *
+ * @access public
+ */
+ function Archive_Tar($p_tarname, $p_compress = null)
+ {
+ $this->PEAR();
+ $this->_compress = false;
+ $this->_compress_type = 'none';
+ if (($p_compress === null) || ($p_compress == '')) {
+ if (@file_exists($p_tarname)) {
+ if ($fp = @fopen($p_tarname, "rb")) {
+ // look for gzip magic cookie
+ $data = fread($fp, 2);
+ fclose($fp);
+ if ($data == "\37\213") {
+ $this->_compress = true;
+ $this->_compress_type = 'gz';
+ // No sure it's enought for a magic code ....
+ } elseif ($data == "BZ") {
+ $this->_compress = true;
+ $this->_compress_type = 'bz2';
+ }
+ }
+ } else {
+ // probably a remote file or some file accessible
+ // through a stream interface
+ if (substr($p_tarname, -2) == 'gz') {
+ $this->_compress = true;
+ $this->_compress_type = 'gz';
+ } elseif ((substr($p_tarname, -3) == 'bz2') ||
+ (substr($p_tarname, -2) == 'bz')) {
+ $this->_compress = true;
+ $this->_compress_type = 'bz2';
+ }
+ }
+ } else {
+ if (($p_compress === true) || ($p_compress == 'gz')) {
+ $this->_compress = true;
+ $this->_compress_type = 'gz';
+ } else if ($p_compress == 'bz2') {
+ $this->_compress = true;
+ $this->_compress_type = 'bz2';
+ } else {
+ $this->_error("Unsupported compression type '$p_compress'\n".
+ "Supported types are 'gz' and 'bz2'.\n");
+ return false;
+ }
+ }
+ $this->_tarname = $p_tarname;
+ if ($this->_compress) { // assert zlib or bz2 extension support
+ if ($this->_compress_type == 'gz')
+ $extname = 'zlib';
+ else if ($this->_compress_type == 'bz2')
+ $extname = 'bz2';
+
+ if (!extension_loaded($extname)) {
+ PEAR::loadExtension($extname);
+ }
+ if (!extension_loaded($extname)) {
+ $this->_error("The extension '$extname' couldn't be found.\n".
+ "Please make sure your version of PHP was built ".
+ "with '$extname' support.\n");
+ return false;
+ }
+ }
+ }
+ // }}}
+
+ // {{{ destructor
+ function _Archive_Tar()
+ {
+ $this->_close();
+ // ----- Look for a local copy to delete
+ if ($this->_temp_tarname != '')
+ @unlink($this->_temp_tarname);
+ $this->_PEAR();
+ }
+ // }}}
+
+ // {{{ create()
+ /**
+ * This method creates the archive file and add the files / directories
+ * that are listed in $p_filelist.
+ * If a file with the same name exist and is writable, it is replaced
+ * by the new tar.
+ * The method return false and a PEAR error text.
+ * The $p_filelist parameter can be an array of string, each string
+ * representing a filename or a directory name with their path if
+ * needed. It can also be a single string with names separated by a
+ * single blank.
+ * For each directory added in the archive, the files and
+ * sub-directories are also added.
+ * See also createModify() method for more details.
+ *
+ * @param array $p_filelist An array of filenames and directory names, or a
+ * single string with names separated by a single
+ * blank space.
+ *
+ * @return true on success, false on error.
+ * @see createModify()
+ * @access public
+ */
+ function create($p_filelist)
+ {
+ return $this->createModify($p_filelist, '', '');
+ }
+ // }}}
+
+ // {{{ add()
+ /**
+ * This method add the files / directories that are listed in $p_filelist in
+ * the archive. If the archive does not exist it is created.
+ * The method return false and a PEAR error text.
+ * The files and directories listed are only added at the end of the archive,
+ * even if a file with the same name is already archived.
+ * See also createModify() method for more details.
+ *
+ * @param array $p_filelist An array of filenames and directory names, or a
+ * single string with names separated by a single
+ * blank space.
+ *
+ * @return true on success, false on error.
+ * @see createModify()
+ * @access public
+ */
+ function add($p_filelist)
+ {
+ return $this->addModify($p_filelist, '', '');
+ }
+ // }}}
+
+ // {{{ extract()
+ function extract($p_path='', $p_preserve=false)
+ {
+ return $this->extractModify($p_path, '', $p_preserve);
+ }
+ // }}}
+
+ // {{{ listContent()
+ function listContent()
+ {
+ $v_list_detail = array();
+
+ if ($this->_openRead()) {
+ if (!$this->_extractList('', $v_list_detail, "list", '', '')) {
+ unset($v_list_detail);
+ $v_list_detail = 0;
+ }
+ $this->_close();
+ }
+
+ return $v_list_detail;
+ }
+ // }}}
+
+ // {{{ createModify()
+ /**
+ * This method creates the archive file and add the files / directories
+ * that are listed in $p_filelist.
+ * If the file already exists and is writable, it is replaced by the
+ * new tar. It is a create and not an add. If the file exists and is
+ * read-only or is a directory it is not replaced. The method return
+ * false and a PEAR error text.
+ * The $p_filelist parameter can be an array of string, each string
+ * representing a filename or a directory name with their path if
+ * needed. It can also be a single string with names separated by a
+ * single blank.
+ * The path indicated in $p_remove_dir will be removed from the
+ * memorized path of each file / directory listed when this path
+ * exists. By default nothing is removed (empty path '')
+ * The path indicated in $p_add_dir will be added at the beginning of
+ * the memorized path of each file / directory listed. However it can
+ * be set to empty ''. The adding of a path is done after the removing
+ * of path.
+ * The path add/remove ability enables the user to prepare an archive
+ * for extraction in a different path than the origin files are.
+ * See also addModify() method for file adding properties.
+ *
+ * @param array $p_filelist An array of filenames and directory names,
+ * or a single string with names separated by
+ * a single blank space.
+ * @param string $p_add_dir A string which contains a path to be added
+ * to the memorized path of each element in
+ * the list.
+ * @param string $p_remove_dir A string which contains a path to be
+ * removed from the memorized path of each
+ * element in the list, when relevant.
+ *
+ * @return boolean true on success, false on error.
+ * @access public
+ * @see addModify()
+ */
+ function createModify($p_filelist, $p_add_dir, $p_remove_dir='')
+ {
+ $v_result = true;
+
+ if (!$this->_openWrite())
+ return false;
+
+ if ($p_filelist != '') {
+ if (is_array($p_filelist))
+ $v_list = $p_filelist;
+ elseif (is_string($p_filelist))
+ $v_list = explode($this->_separator, $p_filelist);
+ else {
+ $this->_cleanFile();
+ $this->_error('Invalid file list');
+ return false;
+ }
+
+ $v_result = $this->_addList($v_list, $p_add_dir, $p_remove_dir);
+ }
+
+ if ($v_result) {
+ $this->_writeFooter();
+ $this->_close();
+ } else
+ $this->_cleanFile();
+
+ return $v_result;
+ }
+ // }}}
+
+ // {{{ addModify()
+ /**
+ * This method add the files / directories listed in $p_filelist at the
+ * end of the existing archive. If the archive does not yet exists it
+ * is created.
+ * The $p_filelist parameter can be an array of string, each string
+ * representing a filename or a directory name with their path if
+ * needed. It can also be a single string with names separated by a
+ * single blank.
+ * The path indicated in $p_remove_dir will be removed from the
+ * memorized path of each file / directory listed when this path
+ * exists. By default nothing is removed (empty path '')
+ * The path indicated in $p_add_dir will be added at the beginning of
+ * the memorized path of each file / directory listed. However it can
+ * be set to empty ''. The adding of a path is done after the removing
+ * of path.
+ * The path add/remove ability enables the user to prepare an archive
+ * for extraction in a different path than the origin files are.
+ * If a file/dir is already in the archive it will only be added at the
+ * end of the archive. There is no update of the existing archived
+ * file/dir. However while extracting the archive, the last file will
+ * replace the first one. This results in a none optimization of the
+ * archive size.
+ * If a file/dir does not exist the file/dir is ignored. However an
+ * error text is send to PEAR error.
+ * If a file/dir is not readable the file/dir is ignored. However an
+ * error text is send to PEAR error.
+ *
+ * @param array $p_filelist An array of filenames and directory
+ * names, or a single string with names
+ * separated by a single blank space.
+ * @param string $p_add_dir A string which contains a path to be
+ * added to the memorized path of each
+ * element in the list.
+ * @param string $p_remove_dir A string which contains a path to be
+ * removed from the memorized path of
+ * each element in the list, when
+ * relevant.
+ *
+ * @return true on success, false on error.
+ * @access public
+ */
+ function addModify($p_filelist, $p_add_dir, $p_remove_dir='')
+ {
+ $v_result = true;
+
+ if (!$this->_isArchive())
+ $v_result = $this->createModify($p_filelist, $p_add_dir,
+ $p_remove_dir);
+ else {
+ if (is_array($p_filelist))
+ $v_list = $p_filelist;
+ elseif (is_string($p_filelist))
+ $v_list = explode($this->_separator, $p_filelist);
+ else {
+ $this->_error('Invalid file list');
+ return false;
+ }
+
+ $v_result = $this->_append($v_list, $p_add_dir, $p_remove_dir);
+ }
+
+ return $v_result;
+ }
+ // }}}
+
+ // {{{ addString()
+ /**
+ * This method add a single string as a file at the
+ * end of the existing archive. If the archive does not yet exists it
+ * is created.
+ *
+ * @param string $p_filename A string which contains the full
+ * filename path that will be associated
+ * with the string.
+ * @param string $p_string The content of the file added in
+ * the archive.
+ *
+ * @return true on success, false on error.
+ * @access public
+ */
+ function addString($p_filename, $p_string)
+ {
+ $v_result = true;
+
+ if (!$this->_isArchive()) {
+ if (!$this->_openWrite()) {
+ return false;
+ }
+ $this->_close();
+ }
+
+ if (!$this->_openAppend())
+ return false;
+
+ // Need to check the get back to the temporary file ? ....
+ $v_result = $this->_addString($p_filename, $p_string);
+
+ $this->_writeFooter();
+
+ $this->_close();
+
+ return $v_result;
+ }
+ // }}}
+
+ // {{{ extractModify()
+ /**
+ * This method extract all the content of the archive in the directory
+ * indicated by $p_path. When relevant the memorized path of the
+ * files/dir can be modified by removing the $p_remove_path path at the
+ * beginning of the file/dir path.
+ * While extracting a file, if the directory path does not exists it is
+ * created.
+ * While extracting a file, if the file already exists it is replaced
+ * without looking for last modification date.
+ * While extracting a file, if the file already exists and is write
+ * protected, the extraction is aborted.
+ * While extracting a file, if a directory with the same name already
+ * exists, the extraction is aborted.
+ * While extracting a directory, if a file with the same name already
+ * exists, the extraction is aborted.
+ * While extracting a file/directory if the destination directory exist
+ * and is write protected, or does not exist but can not be created,
+ * the extraction is aborted.
+ * If after extraction an extracted file does not show the correct
+ * stored file size, the extraction is aborted.
+ * When the extraction is aborted, a PEAR error text is set and false
+ * is returned. However the result can be a partial extraction that may
+ * need to be manually cleaned.
+ *
+ * @param string $p_path The path of the directory where the
+ * files/dir need to by extracted.
+ * @param string $p_remove_path Part of the memorized path that can be
+ * removed if present at the beginning of
+ * the file/dir path.
+ * @param boolean $p_preserve Preserve user/group ownership of files
+ *
+ * @return boolean true on success, false on error.
+ * @access public
+ * @see extractList()
+ */
+ function extractModify($p_path, $p_remove_path, $p_preserve=false)
+ {
+ $v_result = true;
+ $v_list_detail = array();
+
+ if ($v_result = $this->_openRead()) {
+ $v_result = $this->_extractList($p_path, $v_list_detail,
+ "complete", 0, $p_remove_path, $p_preserve);
+ $this->_close();
+ }
+
+ return $v_result;
+ }
+ // }}}
+
+ // {{{ extractInString()
+ /**
+ * This method extract from the archive one file identified by $p_filename.
+ * The return value is a string with the file content, or NULL on error.
+ *
+ * @param string $p_filename The path of the file to extract in a string.
+ *
+ * @return a string with the file content or NULL.
+ * @access public
+ */
+ function extractInString($p_filename)
+ {
+ if ($this->_openRead()) {
+ $v_result = $this->_extractInString($p_filename);
+ $this->_close();
+ } else {
+ $v_result = null;
+ }
+
+ return $v_result;
+ }
+ // }}}
+
+ // {{{ extractList()
+ /**
+ * This method extract from the archive only the files indicated in the
+ * $p_filelist. These files are extracted in the current directory or
+ * in the directory indicated by the optional $p_path parameter.
+ * If indicated the $p_remove_path can be used in the same way as it is
+ * used in extractModify() method.
+ *
+ * @param array $p_filelist An array of filenames and directory names,
+ * or a single string with names separated
+ * by a single blank space.
+ * @param string $p_path The path of the directory where the
+ * files/dir need to by extracted.
+ * @param string $p_remove_path Part of the memorized path that can be
+ * removed if present at the beginning of
+ * the file/dir path.
+ * @param boolean $p_preserve Preserve user/group ownership of files
+ *
+ * @return true on success, false on error.
+ * @access public
+ * @see extractModify()
+ */
+ function extractList($p_filelist, $p_path='', $p_remove_path='', $p_preserve=false)
+ {
+ $v_result = true;
+ $v_list_detail = array();
+
+ if (is_array($p_filelist))
+ $v_list = $p_filelist;
+ elseif (is_string($p_filelist))
+ $v_list = explode($this->_separator, $p_filelist);
+ else {
+ $this->_error('Invalid string list');
+ return false;
+ }
+
+ if ($v_result = $this->_openRead()) {
+ $v_result = $this->_extractList($p_path, $v_list_detail, "partial",
+ $v_list, $p_remove_path, $p_preserve);
+ $this->_close();
+ }
+
+ return $v_result;
+ }
+ // }}}
+
+ // {{{ setAttribute()
+ /**
+ * This method set specific attributes of the archive. It uses a variable
+ * list of parameters, in the format attribute code + attribute values :
+ * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ',');
+ *
+ * @param mixed $argv variable list of attributes and values
+ *
+ * @return true on success, false on error.
+ * @access public
+ */
+ function setAttribute()
+ {
+ $v_result = true;
+
+ // ----- Get the number of variable list of arguments
+ if (($v_size = func_num_args()) == 0) {
+ return true;
+ }
+
+ // ----- Get the arguments
+ $v_att_list = &func_get_args();
+
+ // ----- Read the attributes
+ $i=0;
+ while ($i<$v_size) {
+
+ // ----- Look for next option
+ switch ($v_att_list[$i]) {
+ // ----- Look for options that request a string value
+ case ARCHIVE_TAR_ATT_SEPARATOR :
+ // ----- Check the number of parameters
+ if (($i+1) >= $v_size) {
+ $this->_error('Invalid number of parameters for '
+ .'attribute ARCHIVE_TAR_ATT_SEPARATOR');
+ return false;
+ }
+
+ // ----- Get the value
+ $this->_separator = $v_att_list[$i+1];
+ $i++;
+ break;
+
+ default :
+ $this->_error('Unknow attribute code '.$v_att_list[$i].'');
+ return false;
+ }
+
+ // ----- Next attribute
+ $i++;
+ }
+
+ return $v_result;
+ }
+ // }}}
+
+ // {{{ setIgnoreRegexp()
+ /**
+ * This method sets the regular expression for ignoring files and directories
+ * at import, for example:
+ * $arch->setIgnoreRegexp("#CVS|\.svn#");
+ *
+ * @param string $regexp regular expression defining which files or directories to ignore
+ *
+ * @access public
+ */
+ function setIgnoreRegexp($regexp)
+ {
+ $this->_ignore_regexp = $regexp;
+ }
+ // }}}
+
+ // {{{ setIgnoreList()
+ /**
+ * This method sets the regular expression for ignoring all files and directories
+ * matching the filenames in the array list at import, for example:
+ * $arch->setIgnoreList(array('CVS', '.svn', 'bin/tool'));
+ *
+ * @param array $list a list of file or directory names to ignore
+ *
+ * @access public
+ */
+ function setIgnoreList($list)
+ {
+ $regexp = str_replace(array('#', '.', '^', '$'), array('\#', '\.', '\^', '\$'), $list);
+ $regexp = '#/'.join('$|/', $list).'#';
+ $this->setIgnoreRegexp($regexp);
+ }
+ // }}}
+
+ // {{{ _error()
+ function _error($p_message)
+ {
+ $this->error_object = $this->raiseError($p_message);
+ }
+ // }}}
+
+ // {{{ _warning()
+ function _warning($p_message)
+ {
+ $this->error_object = $this->raiseError($p_message);
+ }
+ // }}}
+
+ // {{{ _isArchive()
+ function _isArchive($p_filename=null)
+ {
+ if ($p_filename == null) {
+ $p_filename = $this->_tarname;
+ }
+ clearstatcache();
+ return @is_file($p_filename) && !@is_link($p_filename);
+ }
+ // }}}
+
+ // {{{ _openWrite()
+ function _openWrite()
+ {
+ if ($this->_compress_type == 'gz' && function_exists('gzopen'))
+ $this->_file = @gzopen($this->_tarname, "wb9");
+ else if ($this->_compress_type == 'bz2' && function_exists('bzopen'))
+ $this->_file = @bzopen($this->_tarname, "w");
+ else if ($this->_compress_type == 'none')
+ $this->_file = @fopen($this->_tarname, "wb");
+ else
+ $this->_error('Unknown or missing compression type ('
+ .$this->_compress_type.')');
+
+ if ($this->_file == 0) {
+ $this->_error('Unable to open in write mode \''
+ .$this->_tarname.'\'');
+ return false;
+ }
+
+ return true;
+ }
+ // }}}
+
+ // {{{ _openRead()
+ function _openRead()
+ {
+ if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') {
+
+ // ----- Look if a local copy need to be done
+ if ($this->_temp_tarname == '') {
+ $this->_temp_tarname = uniqid('tar').'.tmp';
+ if (!$v_file_from = @fopen($this->_tarname, 'rb')) {
+ $this->_error('Unable to open in read mode \''
+ .$this->_tarname.'\'');
+ $this->_temp_tarname = '';
+ return false;
+ }
+ if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) {
+ $this->_error('Unable to open in write mode \''
+ .$this->_temp_tarname.'\'');
+ $this->_temp_tarname = '';
+ return false;
+ }
+ while ($v_data = @fread($v_file_from, 1024))
+ @fwrite($v_file_to, $v_data);
+ @fclose($v_file_from);
+ @fclose($v_file_to);
+ }
+
+ // ----- File to open if the local copy
+ $v_filename = $this->_temp_tarname;
+
+ } else
+ // ----- File to open if the normal Tar file
+ $v_filename = $this->_tarname;
+
+ if ($this->_compress_type == 'gz')
+ $this->_file = @gzopen($v_filename, "rb");
+ else if ($this->_compress_type == 'bz2')
+ $this->_file = @bzopen($v_filename, "r");
+ else if ($this->_compress_type == 'none')
+ $this->_file = @fopen($v_filename, "rb");
+ else
+ $this->_error('Unknown or missing compression type ('
+ .$this->_compress_type.')');
+
+ if ($this->_file == 0) {
+ $this->_error('Unable to open in read mode \''.$v_filename.'\'');
+ return false;
+ }
+
+ return true;
+ }
+ // }}}
+
+ // {{{ _openReadWrite()
+ function _openReadWrite()
+ {
+ if ($this->_compress_type == 'gz')
+ $this->_file = @gzopen($this->_tarname, "r+b");
+ else if ($this->_compress_type == 'bz2') {
+ $this->_error('Unable to open bz2 in read/write mode \''
+ .$this->_tarname.'\' (limitation of bz2 extension)');
+ return false;
+ } else if ($this->_compress_type == 'none')
+ $this->_file = @fopen($this->_tarname, "r+b");
+ else
+ $this->_error('Unknown or missing compression type ('
+ .$this->_compress_type.')');
+
+ if ($this->_file == 0) {
+ $this->_error('Unable to open in read/write mode \''
+ .$this->_tarname.'\'');
+ return false;
+ }
+
+ return true;
+ }
+ // }}}
+
+ // {{{ _close()
+ function _close()
+ {
+ //if (isset($this->_file)) {
+ if (is_resource($this->_file)) {
+ if ($this->_compress_type == 'gz')
+ @gzclose($this->_file);
+ else if ($this->_compress_type == 'bz2')
+ @bzclose($this->_file);
+ else if ($this->_compress_type == 'none')
+ @fclose($this->_file);
+ else
+ $this->_error('Unknown or missing compression type ('
+ .$this->_compress_type.')');
+
+ $this->_file = 0;
+ }
+
+ // ----- Look if a local copy need to be erase
+ // Note that it might be interesting to keep the url for a time : ToDo
+ if ($this->_temp_tarname != '') {
+ @unlink($this->_temp_tarname);
+ $this->_temp_tarname = '';
+ }
+
+ return true;
+ }
+ // }}}
+
+ // {{{ _cleanFile()
+ function _cleanFile()
+ {
+ $this->_close();
+
+ // ----- Look for a local copy
+ if ($this->_temp_tarname != '') {
+ // ----- Remove the local copy but not the remote tarname
+ @unlink($this->_temp_tarname);
+ $this->_temp_tarname = '';
+ } else {
+ // ----- Remove the local tarname file
+ @unlink($this->_tarname);
+ }
+ $this->_tarname = '';
+
+ return true;
+ }
+ // }}}
+
+ // {{{ _writeBlock()
+ function _writeBlock($p_binary_data, $p_len=null)
+ {
+ if (is_resource($this->_file)) {
+ if ($p_len === null) {
+ if ($this->_compress_type == 'gz')
+ @gzputs($this->_file, $p_binary_data);
+ else if ($this->_compress_type == 'bz2')
+ @bzwrite($this->_file, $p_binary_data);
+ else if ($this->_compress_type == 'none')
+ @fputs($this->_file, $p_binary_data);
+ else
+ $this->_error('Unknown or missing compression type ('
+ .$this->_compress_type.')');
+ } else {
+ if ($this->_compress_type == 'gz')
+ @gzputs($this->_file, $p_binary_data, $p_len);
+ else if ($this->_compress_type == 'bz2')
+ @bzwrite($this->_file, $p_binary_data, $p_len);
+ else if ($this->_compress_type == 'none')
+ @fputs($this->_file, $p_binary_data, $p_len);
+ else
+ $this->_error('Unknown or missing compression type ('
+ .$this->_compress_type.')');
+
+ }
+ }
+ return true;
+ }
+ // }}}
+
+ // {{{ _readBlock()
+ function _readBlock()
+ {
+ $v_block = null;
+ if (is_resource($this->_file)) {
+ if ($this->_compress_type == 'gz')
+ $v_block = @gzread($this->_file, 512);
+ else if ($this->_compress_type == 'bz2')
+ $v_block = @bzread($this->_file, 512);
+ else if ($this->_compress_type == 'none')
+ $v_block = @fread($this->_file, 512);
+ else
+ $this->_error('Unknown or missing compression type ('
+ .$this->_compress_type.')');
+ }
+ return $v_block;
+ }
+ // }}}
+
+ // {{{ _jumpBlock()
+ function _jumpBlock($p_len=null)
+ {
+ if (is_resource($this->_file)) {
+ if ($p_len === null)
+ $p_len = 1;
+
+ if ($this->_compress_type == 'gz') {
+ @gzseek($this->_file, gztell($this->_file)+($p_len*512));
+ }
+ else if ($this->_compress_type == 'bz2') {
+ // ----- Replace missing bztell() and bzseek()
+ for ($i=0; $i<$p_len; $i++)
+ $this->_readBlock();
+ } else if ($this->_compress_type == 'none')
+ @fseek($this->_file, $p_len*512, SEEK_CUR);
+ else
+ $this->_error('Unknown or missing compression type ('
+ .$this->_compress_type.')');
+
+ }
+ return true;
+ }
+ // }}}
+
+ // {{{ _writeFooter()
+ function _writeFooter()
+ {
+ if (is_resource($this->_file)) {
+ // ----- Write the last 0 filled block for end of archive
+ $v_binary_data = pack('a1024', '');
+ $this->_writeBlock($v_binary_data);
+ }
+ return true;
+ }
+ // }}}
+
+ // {{{ _addList()
+ function _addList($p_list, $p_add_dir, $p_remove_dir)
+ {
+ $v_result=true;
+ $v_header = array();
+
+ // ----- Remove potential windows directory separator
+ $p_add_dir = $this->_translateWinPath($p_add_dir);
+ $p_remove_dir = $this->_translateWinPath($p_remove_dir, false);
+
+ if (!$this->_file) {
+ $this->_error('Invalid file descriptor');
+ return false;
+ }
+
+ if (sizeof($p_list) == 0)
+ return true;
+
+ foreach ($p_list as $v_filename) {
+ if (!$v_result) {
+ break;
+ }
+
+ // ----- Skip the current tar name
+ if ($v_filename == $this->_tarname)
+ continue;
+
+ if ($v_filename == '')
+ continue;
+
+ // ----- ignore files and directories matching the ignore regular expression
+ if ($this->_ignore_regexp && preg_match($this->_ignore_regexp, '/'.$v_filename)) {
+ $this->_warning("File '$v_filename' ignored");
+ continue;
+ }
+
+ if (!file_exists($v_filename) && !is_link($v_filename)) {
+ $this->_warning("File '$v_filename' does not exist");
+ continue;
+ }
+
+ // ----- Add the file or directory header
+ if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir))
+ return false;
+
+ if (@is_dir($v_filename) && !@is_link($v_filename)) {
+ if (!($p_hdir = opendir($v_filename))) {
+ $this->_warning("Directory '$v_filename' can not be read");
+ continue;
+ }
+ while (false !== ($p_hitem = readdir($p_hdir))) {
+ if (($p_hitem != '.') && ($p_hitem != '..')) {
+ if ($v_filename != ".")
+ $p_temp_list[0] = $v_filename.'/'.$p_hitem;
+ else
+ $p_temp_list[0] = $p_hitem;
+
+ $v_result = $this->_addList($p_temp_list,
+ $p_add_dir,
+ $p_remove_dir);
+ }
+ }
+
+ unset($p_temp_list);
+ unset($p_hdir);
+ unset($p_hitem);
+ }
+ }
+
+ return $v_result;
+ }
+ // }}}
+
+ // {{{ _addFile()
+ function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir,$v_stored_filename=null)
+ {
+ if (!$this->_file) {
+ $this->_error('Invalid file descriptor');
+ return false;
+ }
+
+ if ($p_filename == '') {
+ $this->_error('Invalid file name');
+ return false;
+ }
+ if(is_null($v_stored_filename)){
+
+ // ----- Calculate the stored filename
+ $p_filename = $this->_translateWinPath($p_filename, false);
+ $v_stored_filename = $p_filename;
+ if (strcmp($p_filename, $p_remove_dir) == 0) {
+ return true;
+ }
+ if ($p_remove_dir != '') {
+ if (substr($p_remove_dir, -1) != '/')
+ $p_remove_dir .= '/';
+
+ if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir)
+ $v_stored_filename = substr($p_filename, strlen($p_remove_dir));
+ }
+ $v_stored_filename = $this->_translateWinPath($v_stored_filename);
+ if ($p_add_dir != '') {
+ if (substr($p_add_dir, -1) == '/')
+ $v_stored_filename = $p_add_dir.$v_stored_filename;
+ else
+ $v_stored_filename = $p_add_dir.'/'.$v_stored_filename;
+ }
+
+ $v_stored_filename = $this->_pathReduction($v_stored_filename);
+ }
+
+ if ($this->_isArchive($p_filename)) {
+ if (($v_file = @fopen($p_filename, "rb")) == 0) {
+ $this->_warning("Unable to open file '".$p_filename
+ ."' in binary read mode");
+ return true;
+ }
+
+ if (!$this->_writeHeader($p_filename, $v_stored_filename))
+ return false;
+
+ while (($v_buffer = fread($v_file, 512)) != '') {
+ $v_binary_data = pack("a512", "$v_buffer");
+ $this->_writeBlock($v_binary_data);
+ }
+
+ fclose($v_file);
+
+ } else {
+ // ----- Only header for dir
+ if (!$this->_writeHeader($p_filename, $v_stored_filename))
+ return false;
+ }
+
+ return true;
+ }
+ // }}}
+
+ // {{{ _addString()
+ function _addString($p_filename, $p_string)
+ {
+ if (!$this->_file) {
+ $this->_error('Invalid file descriptor');
+ return false;
+ }
+
+ if ($p_filename == '') {
+ $this->_error('Invalid file name');
+ return false;
+ }
+
+ // ----- Calculate the stored filename
+ $p_filename = $this->_translateWinPath($p_filename, false);;
+
+ if (!$this->_writeHeaderBlock($p_filename, strlen($p_string),
+ time(), 384, "", 0, 0))
+ return false;
+
+ $i=0;
+ while (($v_buffer = substr($p_string, (($i++)*512), 512)) != '') {
+ $v_binary_data = pack("a512", $v_buffer);
+ $this->_writeBlock($v_binary_data);
+ }
+
+ return true;
+ }
+ // }}}
+
+ // {{{ _writeHeader()
+ function _writeHeader($p_filename, $p_stored_filename)
+ {
+ if ($p_stored_filename == '')
+ $p_stored_filename = $p_filename;
+ $v_reduce_filename = $this->_pathReduction($p_stored_filename);
+
+ if (strlen($v_reduce_filename) > 99) {
+ if (!$this->_writeLongHeader($v_reduce_filename))
+ return false;
+ }
+
+ $v_info = lstat($p_filename);
+ $v_uid = sprintf("%07s", DecOct($v_info[4]));
+ $v_gid = sprintf("%07s", DecOct($v_info[5]));
+ $v_perms = sprintf("%07s", DecOct($v_info['mode'] & 000777));
+
+ $v_mtime = sprintf("%011s", DecOct($v_info['mtime']));
+
+ $v_linkname = '';
+
+ if (@is_link($p_filename)) {
+ $v_typeflag = '2';
+ $v_linkname = readlink($p_filename);
+ $v_size = sprintf("%011s", DecOct(0));
+ } elseif (@is_dir($p_filename)) {
+ $v_typeflag = "5";
+ $v_size = sprintf("%011s", DecOct(0));
+ } else {
+ $v_typeflag = '0';
+ clearstatcache();
+ $v_size = sprintf("%011s", DecOct($v_info['size']));
+ }
+
+ $v_magic = 'ustar ';
+
+ $v_version = ' ';
+
+ if (function_exists('posix_getpwuid'))
+ {
+ $userinfo = posix_getpwuid($v_info[4]);
+ $groupinfo = posix_getgrgid($v_info[5]);
+
+ $v_uname = $userinfo['name'];
+ $v_gname = $groupinfo['name'];
+ }
+ else
+ {
+ $v_uname = '';
+ $v_gname = '';
+ }
+
+ $v_devmajor = '';
+
+ $v_devminor = '';
+
+ $v_prefix = '';
+
+ $v_binary_data_first = pack("a100a8a8a8a12a12",
+ $v_reduce_filename, $v_perms, $v_uid,
+ $v_gid, $v_size, $v_mtime);
+ $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
+ $v_typeflag, $v_linkname, $v_magic,
+ $v_version, $v_uname, $v_gname,
+ $v_devmajor, $v_devminor, $v_prefix, '');
+
+ // ----- Calculate the checksum
+ $v_checksum = 0;
+ // ..... First part of the header
+ for ($i=0; $i<148; $i++)
+ $v_checksum += ord(substr($v_binary_data_first,$i,1));
+ // ..... Ignore the checksum value and replace it by ' ' (space)
+ for ($i=148; $i<156; $i++)
+ $v_checksum += ord(' ');
+ // ..... Last part of the header
+ for ($i=156, $j=0; $i<512; $i++, $j++)
+ $v_checksum += ord(substr($v_binary_data_last,$j,1));
+
+ // ----- Write the first 148 bytes of the header in the archive
+ $this->_writeBlock($v_binary_data_first, 148);
+
+ // ----- Write the calculated checksum
+ $v_checksum = sprintf("%06s ", DecOct($v_checksum));
+ $v_binary_data = pack("a8", $v_checksum);
+ $this->_writeBlock($v_binary_data, 8);
+
+ // ----- Write the last 356 bytes of the header in the archive
+ $this->_writeBlock($v_binary_data_last, 356);
+
+ return true;
+ }
+ // }}}
+
+ // {{{ _writeHeaderBlock()
+ function _writeHeaderBlock($p_filename, $p_size, $p_mtime=0, $p_perms=0,
+ $p_type='', $p_uid=0, $p_gid=0)
+ {
+ $p_filename = $this->_pathReduction($p_filename);
+
+ if (strlen($p_filename) > 99) {
+ if (!$this->_writeLongHeader($p_filename))
+ return false;
+ }
+
+ if ($p_type == "5") {
+ $v_size = sprintf("%011s", DecOct(0));
+ } else {
+ $v_size = sprintf("%011s", DecOct($p_size));
+ }
+
+ $v_uid = sprintf("%07s", DecOct($p_uid));
+ $v_gid = sprintf("%07s", DecOct($p_gid));
+ $v_perms = sprintf("%07s", DecOct($p_perms & 000777));
+
+ $v_mtime = sprintf("%11s", DecOct($p_mtime));
+
+ $v_linkname = '';
+
+ $v_magic = 'ustar ';
+
+ $v_version = ' ';
+
+ if (function_exists('posix_getpwuid'))
+ {
+ $userinfo = posix_getpwuid($p_uid);
+ $groupinfo = posix_getgrgid($p_gid);
+
+ $v_uname = $userinfo['name'];
+ $v_gname = $groupinfo['name'];
+ }
+ else
+ {
+ $v_uname = '';
+ $v_gname = '';
+ }
+
+ $v_devmajor = '';
+
+ $v_devminor = '';
+
+ $v_prefix = '';
+
+ $v_binary_data_first = pack("a100a8a8a8a12A12",
+ $p_filename, $v_perms, $v_uid, $v_gid,
+ $v_size, $v_mtime);
+ $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
+ $p_type, $v_linkname, $v_magic,
+ $v_version, $v_uname, $v_gname,
+ $v_devmajor, $v_devminor, $v_prefix, '');
+
+ // ----- Calculate the checksum
+ $v_checksum = 0;
+ // ..... First part of the header
+ for ($i=0; $i<148; $i++)
+ $v_checksum += ord(substr($v_binary_data_first,$i,1));
+ // ..... Ignore the checksum value and replace it by ' ' (space)
+ for ($i=148; $i<156; $i++)
+ $v_checksum += ord(' ');
+ // ..... Last part of the header
+ for ($i=156, $j=0; $i<512; $i++, $j++)
+ $v_checksum += ord(substr($v_binary_data_last,$j,1));
+
+ // ----- Write the first 148 bytes of the header in the archive
+ $this->_writeBlock($v_binary_data_first, 148);
+
+ // ----- Write the calculated checksum
+ $v_checksum = sprintf("%06s ", DecOct($v_checksum));
+ $v_binary_data = pack("a8", $v_checksum);
+ $this->_writeBlock($v_binary_data, 8);
+
+ // ----- Write the last 356 bytes of the header in the archive
+ $this->_writeBlock($v_binary_data_last, 356);
+
+ return true;
+ }
+ // }}}
+
+ // {{{ _writeLongHeader()
+ function _writeLongHeader($p_filename)
+ {
+ $v_size = sprintf("%11s ", DecOct(strlen($p_filename)));
+
+ $v_typeflag = 'L';
+
+ $v_linkname = '';
+
+ $v_magic = '';
+
+ $v_version = '';
+
+ $v_uname = '';
+
+ $v_gname = '';
+
+ $v_devmajor = '';
+
+ $v_devminor = '';
+
+ $v_prefix = '';
+
+ $v_binary_data_first = pack("a100a8a8a8a12a12",
+ '././@LongLink', 0, 0, 0, $v_size, 0);
+ $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
+ $v_typeflag, $v_linkname, $v_magic,
+ $v_version, $v_uname, $v_gname,
+ $v_devmajor, $v_devminor, $v_prefix, '');
+
+ // ----- Calculate the checksum
+ $v_checksum = 0;
+ // ..... First part of the header
+ for ($i=0; $i<148; $i++)
+ $v_checksum += ord(substr($v_binary_data_first,$i,1));
+ // ..... Ignore the checksum value and replace it by ' ' (space)
+ for ($i=148; $i<156; $i++)
+ $v_checksum += ord(' ');
+ // ..... Last part of the header
+ for ($i=156, $j=0; $i<512; $i++, $j++)
+ $v_checksum += ord(substr($v_binary_data_last,$j,1));
+
+ // ----- Write the first 148 bytes of the header in the archive
+ $this->_writeBlock($v_binary_data_first, 148);
+
+ // ----- Write the calculated checksum
+ $v_checksum = sprintf("%06s ", DecOct($v_checksum));
+ $v_binary_data = pack("a8", $v_checksum);
+ $this->_writeBlock($v_binary_data, 8);
+
+ // ----- Write the last 356 bytes of the header in the archive
+ $this->_writeBlock($v_binary_data_last, 356);
+
+ // ----- Write the filename as content of the block
+ $i=0;
+ while (($v_buffer = substr($p_filename, (($i++)*512), 512)) != '') {
+ $v_binary_data = pack("a512", "$v_buffer");
+ $this->_writeBlock($v_binary_data);
+ }
+
+ return true;
+ }
+ // }}}
+
+ // {{{ _readHeader()
+ function _readHeader($v_binary_data, &$v_header)
+ {
+ if (strlen($v_binary_data)==0) {
+ $v_header['filename'] = '';
+ return true;
+ }
+
+ if (strlen($v_binary_data) != 512) {
+ $v_header['filename'] = '';
+ $this->_error('Invalid block size : '.strlen($v_binary_data));
+ return false;
+ }
+
+ if (!is_array($v_header)) {
+ $v_header = array();
+ }
+ // ----- Calculate the checksum
+ $v_checksum = 0;
+ // ..... First part of the header
+ for ($i=0; $i<148; $i++)
+ $v_checksum+=ord(substr($v_binary_data,$i,1));
+ // ..... Ignore the checksum value and replace it by ' ' (space)
+ for ($i=148; $i<156; $i++)
+ $v_checksum += ord(' ');
+ // ..... Last part of the header
+ for ($i=156; $i<512; $i++)
+ $v_checksum+=ord(substr($v_binary_data,$i,1));
+
+ $v_data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/" .
+ "a8checksum/a1typeflag/a100link/a6magic/a2version/" .
+ "a32uname/a32gname/a8devmajor/a8devminor/a131prefix",
+ $v_binary_data);
+
+ if (strlen($v_data["prefix"]) > 0) {
+ $v_data["filename"] = "$v_data[prefix]/$v_data[filename]";
+ }
+
+ // ----- Extract the checksum
+ $v_header['checksum'] = OctDec(trim($v_data['checksum']));
+ if ($v_header['checksum'] != $v_checksum) {
+ $v_header['filename'] = '';
+
+ // ----- Look for last block (empty block)
+ if (($v_checksum == 256) && ($v_header['checksum'] == 0))
+ return true;
+
+ $this->_error('Invalid checksum for file "'.$v_data['filename']
+ .'" : '.$v_checksum.' calculated, '
+ .$v_header['checksum'].' expected');
+ return false;
+ }
+
+ // ----- Extract the properties
+ $v_header['filename'] = $v_data['filename'];
+ if ($this->_maliciousFilename($v_header['filename'])) {
+ $this->_error('Malicious .tar detected, file "' . $v_header['filename'] .
+ '" will not install in desired directory tree');
+ return false;
+ }
+ $v_header['mode'] = OctDec(trim($v_data['mode']));
+ $v_header['uid'] = OctDec(trim($v_data['uid']));
+ $v_header['gid'] = OctDec(trim($v_data['gid']));
+ $v_header['size'] = OctDec(trim($v_data['size']));
+ $v_header['mtime'] = OctDec(trim($v_data['mtime']));
+ if (($v_header['typeflag'] = $v_data['typeflag']) == "5") {
+ $v_header['size'] = 0;
+ }
+ $v_header['link'] = trim($v_data['link']);
+ /* ----- All these fields are removed form the header because
+ they do not carry interesting info
+ $v_header[magic] = trim($v_data[magic]);
+ $v_header[version] = trim($v_data[version]);
+ $v_header[uname] = trim($v_data[uname]);
+ $v_header[gname] = trim($v_data[gname]);
+ $v_header[devmajor] = trim($v_data[devmajor]);
+ $v_header[devminor] = trim($v_data[devminor]);
+ */
+
+ return true;
+ }
+ // }}}
+
+ // {{{ _maliciousFilename()
+ /**
+ * Detect and report a malicious file name
+ *
+ * @param string $file
+ *
+ * @return bool
+ * @access private
+ */
+ function _maliciousFilename($file)
+ {
+ if (strpos($file, '/../') !== false) {
+ return true;
+ }
+ if (strpos($file, '../') === 0) {
+ return true;
+ }
+ return false;
+ }
+ // }}}
+
+ // {{{ _readLongHeader()
+ function _readLongHeader(&$v_header)
+ {
+ $v_filename = '';
+ $n = floor($v_header['size']/512);
+ for ($i=0; $i<$n; $i++) {
+ $v_content = $this->_readBlock();
+ $v_filename .= $v_content;
+ }
+ if (($v_header['size'] % 512) != 0) {
+ $v_content = $this->_readBlock();
+ $v_filename .= trim($v_content);
+ }
+
+ // ----- Read the next header
+ $v_binary_data = $this->_readBlock();
+
+ if (!$this->_readHeader($v_binary_data, $v_header))
+ return false;
+
+ $v_filename = trim($v_filename);
+ $v_header['filename'] = $v_filename;
+ if ($this->_maliciousFilename($v_filename)) {
+ $this->_error('Malicious .tar detected, file "' . $v_filename .
+ '" will not install in desired directory tree');
+ return false;
+ }
+
+ return true;
+ }
+ // }}}
+
+ // {{{ _extractInString()
+ /**
+ * This method extract from the archive one file identified by $p_filename.
+ * The return value is a string with the file content, or null on error.
+ *
+ * @param string $p_filename The path of the file to extract in a string.
+ *
+ * @return a string with the file content or null.
+ * @access private
+ */
+ function _extractInString($p_filename)
+ {
+ $v_result_str = "";
+
+ While (strlen($v_binary_data = $this->_readBlock()) != 0)
+ {
+ if (!$this->_readHeader($v_binary_data, $v_header))
+ return null;
+
+ if ($v_header['filename'] == '')
+ continue;
+
+ // ----- Look for long filename
+ if ($v_header['typeflag'] == 'L') {
+ if (!$this->_readLongHeader($v_header))
+ return null;
+ }
+
+ if ($v_header['filename'] == $p_filename) {
+ if ($v_header['typeflag'] == "5") {
+ $this->_error('Unable to extract in string a directory '
+ .'entry {'.$v_header['filename'].'}');
+ return null;
+ } else {
+ $n = floor($v_header['size']/512);
+ for ($i=0; $i<$n; $i++) {
+ $v_result_str .= $this->_readBlock();
+ }
+ if (($v_header['size'] % 512) != 0) {
+ $v_content = $this->_readBlock();
+ $v_result_str .= substr($v_content, 0,
+ ($v_header['size'] % 512));
+ }
+ return $v_result_str;
+ }
+ } else {
+ $this->_jumpBlock(ceil(($v_header['size']/512)));
+ }
+ }
+
+ return null;
+ }
+ // }}}
+
+ // {{{ _extractList()
+ function _extractList($p_path, &$p_list_detail, $p_mode,
+ $p_file_list, $p_remove_path, $p_preserve=false)
+ {
+ $v_result=true;
+ $v_nb = 0;
+ $v_extract_all = true;
+ $v_listing = false;
+
+ $p_path = $this->_translateWinPath($p_path, false);
+ if ($p_path == '' || (substr($p_path, 0, 1) != '/'
+ && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))) {
+ $p_path = "./".$p_path;
+ }
+ $p_remove_path = $this->_translateWinPath($p_remove_path);
+
+ // ----- Look for path to remove format (should end by /)
+ if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/'))
+ $p_remove_path .= '/';
+ $p_remove_path_size = strlen($p_remove_path);
+
+ switch ($p_mode) {
+ case "complete" :
+ $v_extract_all = true;
+ $v_listing = false;
+ break;
+ case "partial" :
+ $v_extract_all = false;
+ $v_listing = false;
+ break;
+ case "list" :
+ $v_extract_all = false;
+ $v_listing = true;
+ break;
+ default :
+ $this->_error('Invalid extract mode ('.$p_mode.')');
+ return false;
+ }
+
+ clearstatcache();
+
+ while (strlen($v_binary_data = $this->_readBlock()) != 0)
+ {
+ $v_extract_file = FALSE;
+ $v_extraction_stopped = 0;
+
+ if (!$this->_readHeader($v_binary_data, $v_header))
+ return false;
+
+ if ($v_header['filename'] == '') {
+ continue;
+ }
+
+ // ----- Look for long filename
+ if ($v_header['typeflag'] == 'L') {
+ if (!$this->_readLongHeader($v_header))
+ return false;
+ }
+
+ if ((!$v_extract_all) && (is_array($p_file_list))) {
+ // ----- By default no unzip if the file is not found
+ $v_extract_file = false;
+
+ for ($i=0; $i<sizeof($p_file_list); $i++) {
+ // ----- Look if it is a directory
+ if (substr($p_file_list[$i], -1) == '/') {
+ // ----- Look if the directory is in the filename path
+ if ((strlen($v_header['filename']) > strlen($p_file_list[$i]))
+ && (substr($v_header['filename'], 0, strlen($p_file_list[$i]))
+ == $p_file_list[$i])) {
+ $v_extract_file = true;
+ break;
+ }
+ }
+
+ // ----- It is a file, so compare the file names
+ elseif ($p_file_list[$i] == $v_header['filename']) {
+ $v_extract_file = true;
+ break;
+ }
+ }
+ } else {
+ $v_extract_file = true;
+ }
+
+ // ----- Look if this file need to be extracted
+ if (($v_extract_file) && (!$v_listing))
+ {
+ if (($p_remove_path != '')
+ && (substr($v_header['filename'], 0, $p_remove_path_size)
+ == $p_remove_path))
+ $v_header['filename'] = substr($v_header['filename'],
+ $p_remove_path_size);
+ if (($p_path != './') && ($p_path != '/')) {
+ while (substr($p_path, -1) == '/')
+ $p_path = substr($p_path, 0, strlen($p_path)-1);
+
+ if (substr($v_header['filename'], 0, 1) == '/')
+ $v_header['filename'] = $p_path.$v_header['filename'];
+ else
+ $v_header['filename'] = $p_path.'/'.$v_header['filename'];
+ }
+ if (file_exists($v_header['filename'])) {
+ if ( (@is_dir($v_header['filename']))
+ && ($v_header['typeflag'] == '')) {
+ $this->_error('File '.$v_header['filename']
+ .' already exists as a directory');
+ return false;
+ }
+ if ( ($this->_isArchive($v_header['filename']))
+ && ($v_header['typeflag'] == "5")) {
+ $this->_error('Directory '.$v_header['filename']
+ .' already exists as a file');
+ return false;
+ }
+ if (!is_writeable($v_header['filename'])) {
+ $this->_error('File '.$v_header['filename']
+ .' already exists and is write protected');
+ return false;
+ }
+ if (filemtime($v_header['filename']) > $v_header['mtime']) {
+ // To be completed : An error or silent no replace ?
+ }
+ }
+
+ // ----- Check the directory availability and create it if necessary
+ elseif (($v_result
+ = $this->_dirCheck(($v_header['typeflag'] == "5"
+ ?$v_header['filename']
+ :dirname($v_header['filename'])))) != 1) {
+ $this->_error('Unable to create path for '.$v_header['filename']);
+ return false;
+ }
+
+ if ($v_extract_file) {
+ if ($v_header['typeflag'] == "5") {
+ if (!@file_exists($v_header['filename'])) {
+ if (!@mkdir($v_header['filename'], 0777)) {
+ $this->_error('Unable to create directory {'
+ .$v_header['filename'].'}');
+ return false;
+ }
+ }
+ } elseif ($v_header['typeflag'] == "2") {
+ if (@file_exists($v_header['filename'])) {
+ @unlink($v_header['filename']);
+ }
+ if (!@symlink($v_header['link'], $v_header['filename'])) {
+ $this->_error('Unable to extract symbolic link {'
+ .$v_header['filename'].'}');
+ return false;
+ }
+ } else {
+ if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
+ $this->_error('Error while opening {'.$v_header['filename']
+ .'} in write binary mode');
+ return false;
+ } else {
+ $n = floor($v_header['size']/512);
+ for ($i=0; $i<$n; $i++) {
+ $v_content = $this->_readBlock();
+ fwrite($v_dest_file, $v_content, 512);
+ }
+ if (($v_header['size'] % 512) != 0) {
+ $v_content = $this->_readBlock();
+ fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
+ }
+
+ @fclose($v_dest_file);
+
+ if ($p_preserve) {
+ @chown($v_header['filename'], $v_header['uid']);
+ @chgrp($v_header['filename'], $v_header['gid']);
+ }
+
+ // ----- Change the file mode, mtime
+ @touch($v_header['filename'], $v_header['mtime']);
+ if ($v_header['mode'] & 0111) {
+ // make file executable, obey umask
+ $mode = fileperms($v_header['filename']) | (~umask() & 0111);
+ @chmod($v_header['filename'], $mode);
+ }
+ }
+
+ // ----- Check the file size
+ clearstatcache();
+ if (!is_file($v_header['filename'])) {
+ $this->_error('Extracted file '.$v_header['filename']
+ .'does not exist. Archive may be corrupted.');
+ return false;
+ }
+
+ $filesize = filesize($v_header['filename']);
+ if ($filesize != $v_header['size']) {
+ $this->_error('Extracted file '.$v_header['filename']
+ .' does not have the correct file size \''
+ .$filesize
+ .'\' ('.$v_header['size']
+ .' expected). Archive may be corrupted.');
+ return false;
+ }
+ }
+ } else {
+ $this->_jumpBlock(ceil(($v_header['size']/512)));
+ }
+ } else {
+ $this->_jumpBlock(ceil(($v_header['size']/512)));
+ }
+
+ /* TBC : Seems to be unused ...
+ if ($this->_compress)
+ $v_end_of_file = @gzeof($this->_file);
+ else
+ $v_end_of_file = @feof($this->_file);
+ */
+
+ if ($v_listing || $v_extract_file || $v_extraction_stopped) {
+ // ----- Log extracted files
+ if (($v_file_dir = dirname($v_header['filename']))
+ == $v_header['filename'])
+ $v_file_dir = '';
+ if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == ''))
+ $v_file_dir = '/';
+
+ $p_list_detail[$v_nb++] = $v_header;
+ if (is_array($p_file_list) && (count($p_list_detail) == count($p_file_list))) {
+ return true;
+ }
+ }
+ }
+
+ return true;
+ }
+ // }}}
+
+ // {{{ _openAppend()
+ function _openAppend()
+ {
+ if (filesize($this->_tarname) == 0)
+ return $this->_openWrite();
+
+ if ($this->_compress) {
+ $this->_close();
+
+ if (!@rename($this->_tarname, $this->_tarname.".tmp")) {
+ $this->_error('Error while renaming \''.$this->_tarname
+ .'\' to temporary file \''.$this->_tarname
+ .'.tmp\'');
+ return false;
+ }
+
+ if ($this->_compress_type == 'gz')
+ $v_temp_tar = @gzopen($this->_tarname.".tmp", "rb");
+ elseif ($this->_compress_type == 'bz2')
+ $v_temp_tar = @bzopen($this->_tarname.".tmp", "r");
+
+ if ($v_temp_tar == 0) {
+ $this->_error('Unable to open file \''.$this->_tarname
+ .'.tmp\' in binary read mode');
+ @rename($this->_tarname.".tmp", $this->_tarname);
+ return false;
+ }
+
+ if (!$this->_openWrite()) {
+ @rename($this->_tarname.".tmp", $this->_tarname);
+ return false;
+ }
+
+ if ($this->_compress_type == 'gz') {
+ while (!@gzeof($v_temp_tar)) {
+ $v_buffer = @gzread($v_temp_tar, 512);
+ if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
+ // do not copy end blocks, we will re-make them
+ // after appending
+ continue;
+ }
+ $v_binary_data = pack("a512", $v_buffer);
+ $this->_writeBlock($v_binary_data);
+ }
+
+ @gzclose($v_temp_tar);
+ }
+ elseif ($this->_compress_type == 'bz2') {
+ while (strlen($v_buffer = @bzread($v_temp_tar, 512)) > 0) {
+ if ($v_buffer == ARCHIVE_TAR_END_BLOCK) {
+ continue;
+ }
+ $v_binary_data = pack("a512", $v_buffer);
+ $this->_writeBlock($v_binary_data);
+ }
+
+ @bzclose($v_temp_tar);
+ }
+
+ if (!@unlink($this->_tarname.".tmp")) {
+ $this->_error('Error while deleting temporary file \''
+ .$this->_tarname.'.tmp\'');
+ }
+
+ } else {
+ // ----- For not compressed tar, just add files before the last
+ // one or two 512 bytes block
+ if (!$this->_openReadWrite())
+ return false;
+
+ clearstatcache();
+ $v_size = filesize($this->_tarname);
+
+ // We might have zero, one or two end blocks.
+ // The standard is two, but we should try to handle
+ // other cases.
+ fseek($this->_file, $v_size - 1024);
+ if (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
+ fseek($this->_file, $v_size - 1024);
+ }
+ elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
+ fseek($this->_file, $v_size - 512);
+ }
+ }
+
+ return true;
+ }
+ // }}}
+
+ // {{{ _append()
+ function _append($p_filelist, $p_add_dir='', $p_remove_dir='')
+ {
+ if (!$this->_openAppend())
+ return false;
+
+ if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir))
+ $this->_writeFooter();
+
+ $this->_close();
+
+ return true;
+ }
+ // }}}
+
+ // {{{ _dirCheck()
+
+ /**
+ * Check if a directory exists and create it (including parent
+ * dirs) if not.
+ *
+ * @param string $p_dir directory to check
+ *
+ * @return bool true if the directory exists or was created
+ */
+ function _dirCheck($p_dir)
+ {
+ clearstatcache();
+ if ((@is_dir($p_dir)) || ($p_dir == ''))
+ return true;
+
+ $p_parent_dir = dirname($p_dir);
+
+ if (($p_parent_dir != $p_dir) &&
+ ($p_parent_dir != '') &&
+ (!$this->_dirCheck($p_parent_dir)))
+ return false;
+
+ if (!@mkdir($p_dir, 0777)) {
+ $this->_error("Unable to create directory '$p_dir'");
+ return false;
+ }
+
+ return true;
+ }
+
+ // }}}
+
+ // {{{ _pathReduction()
+
+ /**
+ * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar",
+ * rand emove double slashes.
+ *
+ * @param string $p_dir path to reduce
+ *
+ * @return string reduced path
+ *
+ * @access private
+ *
+ */
+ function _pathReduction($p_dir)
+ {
+ $v_result = '';
+
+ // ----- Look for not empty path
+ if ($p_dir != '') {
+ // ----- Explode path by directory names
+ $v_list = explode('/', $p_dir);
+
+ // ----- Study directories from last to first
+ for ($i=sizeof($v_list)-1; $i>=0; $i--) {
+ // ----- Look for current path
+ if ($v_list[$i] == ".") {
+ // ----- Ignore this directory
+ // Should be the first $i=0, but no check is done
+ }
+ else if ($v_list[$i] == "..") {
+ // ----- Ignore it and ignore the $i-1
+ $i--;
+ }
+ else if ( ($v_list[$i] == '')
+ && ($i!=(sizeof($v_list)-1))
+ && ($i!=0)) {
+ // ----- Ignore only the double '//' in path,
+ // but not the first and last /
+ } else {
+ $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?'/'
+ .$v_result:'');
+ }
+ }
+ }
+
+ if (defined('OS_WINDOWS') && OS_WINDOWS) {
+ $v_result = strtr($v_result, '\\', '/');
+ }
+
+ return $v_result;
+ }
+
+ // }}}
+
+ // {{{ _translateWinPath()
+ function _translateWinPath($p_path, $p_remove_disk_letter=true)
+ {
+ if (defined('OS_WINDOWS') && OS_WINDOWS) {
+ // ----- Look for potential disk letter
+ if ( ($p_remove_disk_letter)
+ && (($v_position = strpos($p_path, ':')) != false)) {
+ $p_path = substr($p_path, $v_position+1);
+ }
+ // ----- Change potential windows directory separator
+ if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) {
+ $p_path = strtr($p_path, '\\', '/');
+ }
+ }
+ return $p_path;
+ }
+ // }}}
+
+}
+?>
diff --git a/README b/README
index 4d4be2728e1..77379a46456 100644
--- a/README
+++ b/README
@@ -3,10 +3,11 @@ A personal cloud which runs on your own server.
http://ownCloud.org
-Installation instructions: http://owncloud.org/support/setup-and-installation/
-Source code: http://gitorious.org/owncloud
+Installation instructions: http://owncloud.org/support
+Source code: http://gitorious.org/owncloud
Mailing list: http://mail.kde.org/mailman/listinfo/owncloud
IRC channel: http://webchat.freenode.net/?channels=owncloud
Diaspora: https://joindiaspora.com/u/owncloud
Identi.ca: http://identi.ca/owncloud
+
diff --git a/apps/calendar/ajax/import/import.php b/apps/calendar/ajax/import/import.php
index c0797f6e425..d0bdab4f0d5 100644
--- a/apps/calendar/ajax/import/import.php
+++ b/apps/calendar/ajax/import/import.php
@@ -10,7 +10,7 @@ ob_start();
require_once('../../../../lib/base.php');
OC_JSON::checkLoggedIn();
OC_Util::checkAppEnabled('calendar');
-$nl = "\n";
+$nl = "\n\r";
$progressfile = OC::$APPSROOT . '/apps/calendar/import_tmp/' . md5(session_id()) . '.txt';
if(is_writable('import_tmp/')){
$progressfopen = fopen($progressfile, 'w');
diff --git a/apps/calendar/export.php b/apps/calendar/export.php
index 9886ad8e8cc..2736eec96c2 100644
--- a/apps/calendar/export.php
+++ b/apps/calendar/export.php
@@ -11,7 +11,7 @@ OC_Util::checkLoggedIn();
OC_Util::checkAppEnabled('calendar');
$cal = isset($_GET['calid']) ? $_GET['calid'] : NULL;
$event = isset($_GET['eventid']) ? $_GET['eventid'] : NULL;
-$nl = "\n";
+$nl = "\n\r";
if(isset($cal)){
$calendar = OC_Calendar_App::getCalendar($cal);
$calobjects = OC_Calendar_Object::all($cal);
diff --git a/apps/contacts/ajax/deletecard.php b/apps/contacts/ajax/deletecard.php
index e26dfd6ebfe..5675aef5f15 100644
--- a/apps/contacts/ajax/deletecard.php
+++ b/apps/contacts/ajax/deletecard.php
@@ -19,6 +19,11 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
+function bailOut($msg) {
+ OC_JSON::error(array('data' => array('message' => $msg)));
+ OC_Log::write('contacts','ajax/saveproperty.php: '.$msg, OC_Log::DEBUG);
+ exit();
+}
// Init owncloud
require_once('../../../lib/base.php');
@@ -27,7 +32,10 @@ require_once('../../../lib/base.php');
OC_JSON::checkLoggedIn();
OC_JSON::checkAppEnabled('contacts');
-$id = $_GET['id'];
+$id = isset($_GET['id'])?$_GET['id']:null;
+if(!$id) {
+ bailOut(OC_Contacts_App::$l10n->t('id is not set.'));
+}
$card = OC_Contacts_App::getContactObject( $id );
OC_Contacts_VCard::delete($id);
diff --git a/apps/contacts/appinfo/migrate.php b/apps/contacts/appinfo/migrate.php
new file mode 100644
index 00000000000..a6c6bc20fa4
--- /dev/null
+++ b/apps/contacts/appinfo/migrate.php
@@ -0,0 +1,68 @@
+<?php
+class OC_Migration_Provider_Contacts extends OC_Migration_Provider{
+
+ // Create the xml for the user supplied
+ function export( ){
+ $options = array(
+ 'table'=>'contacts_addressbooks',
+ 'matchcol'=>'userid',
+ 'matchval'=>$this->uid,
+ 'idcol'=>'id'
+ );
+ $ids = $this->content->copyRows( $options );
+
+ $options = array(
+ 'table'=>'contacts_cards',
+ 'matchcol'=>'addressbookid',
+ 'matchval'=>$ids
+ );
+
+ // Export tags
+ $ids2 = $this->content->copyRows( $options );
+
+ // If both returned some ids then they worked
+ if( is_array( $ids ) && is_array( $ids2 ) )
+ {
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+
+ // Import function for bookmarks
+ function import( ){
+ switch( $this->appinfo->version ){
+ default:
+ // All versions of the app have had the same db structure, so all can use the same import function
+ $query = $this->content->prepare( "SELECT * FROM contacts_addressbooks WHERE userid LIKE ?" );
+ $results = $query->execute( array( $this->olduid ) );
+ $idmap = array();
+ while( $row = $results->fetchRow() ){
+ // Import each bookmark, saving its id into the map
+ $query = OC_DB::prepare( "INSERT INTO *PREFIX*contacts_addressbooks (`userid`, `displayname`, `uri`, `description`, `ctag`) VALUES (?, ?, ?, ?, ?)" );
+ $query->execute( array( $this->uid, $row['displayname'], $row['uri'], $row['description'], $row['ctag'] ) );
+ // Map the id
+ $idmap[$row['id']] = OC_DB::insertid();
+ }
+ // Now tags
+ foreach($idmap as $oldid => $newid){
+ $query = $this->content->prepare( "SELECT * FROM contacts_cards WHERE addressbookid LIKE ?" );
+ $results = $query->execute( array( $oldid ) );
+ while( $row = $results->fetchRow() ){
+ // Import the tags for this bookmark, using the new bookmark id
+ $query = OC_DB::prepare( "INSERT INTO *PREFIX*contacts_cards (`addressbookid`, `fullname`, `carddata`, `uri`, `lastmodified`) VALUES (?, ?, ?, ?, ?)" );
+ $query->execute( array( $newid, $row['fullname'], $row['carddata'], $row['uri'], $row['lastmodified'] ) );
+ }
+ }
+ // All done!
+ break;
+ }
+
+ return true;
+ }
+
+}
+
+// Load the provider
+new OC_Migration_Provider_Contacts( 'contacts' ); \ No newline at end of file
diff --git a/apps/contacts/css/contacts.css b/apps/contacts/css/contacts.css
index 7c36a511d6e..76b5972ba3c 100644
--- a/apps/contacts/css/contacts.css
+++ b/apps/contacts/css/contacts.css
@@ -10,8 +10,6 @@
#contacts_propertymenu_button { position:absolute;top:15px;right:150px; background:url('../../../core/img/actions/add.svg') no-repeat center; }
#contacts_propertymenu { background-color: #fff; position:absolute;top:40px;right:150px; overflow:hidden; text-overflow:ellipsis; /*border: thin solid #1d2d44;*/ -moz-box-shadow:0 0 10px #000; -webkit-box-shadow:0 0 10px #000; box-shadow:0 0 10px #000; -moz-border-radius:0.5em; -webkit-border-radius:0.5em; border-radius:0.5em; -moz-border-radius:0.5em; -webkit-border-radius:0.5em; border-radius:0.5em; }
#contacts_propertymenu li { display: block; font-weight: bold; height: 20px; width: 100px; }
-/*#contacts_propertymenu li:first-child { border-top: thin solid #1d2d44; -moz-border-radius-topleft:0.5em; -webkit-border-top-left-radius:0.5em; border-top-left-radius:0.5em; -moz-border-radius-topright:0.5em; -webkit-border-top-right-radius:0.5em; border-top-right-radius:0.5em; }
-#contacts_propertymenu li:last-child { border-bottom: thin solid #1d2d44; -moz-border-radius-bottomleft:0.5em; -webkit-border-bottom-left-radius:0.5em; border-bottom-left-radius:0.5em; -moz-border-radius-bottomright:0.5em; -webkit-border-bottom-right-radius:0.5em; border-bottom-right-radius:0.5em; }*/
#contacts_propertymenu li a { padding: 3px; display: block }
#contacts_propertymenu li:hover { background-color: #1d2d44; }
#contacts_propertymenu li a:hover { color: #fff }
@@ -25,54 +23,12 @@
#card input[type="text"],input[type="email"],input[type="tel"],input[type="date"], select { background-color: #f8f8f8; 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 { 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 #fff, 0 2px 0 #bbb inset; -webkit-box-shadow:0 1px 1px #fff, 0 1px 0 #bbb inset; box-shadow:0 1px 1px #fff, 0 1px 0 #bbb inset; -moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em; outline:none; float: left; }
input[type="text"]:invalid,input[type="email"]:invalid,input[type="tel"]:invalid,input[type="date"]:invalid { background-color: #ffc0c0 !important; }
-/*input[type="text"]:valid,input[type="email"]:valid,input[type="tel"]:valid,input[type="date"]:valid { background-color: #b1d28f !important; }*/
-dl.form
-{
- width: 100%;
- float: left;
- clear: right;
- margin: 0;
- padding: 0;
-}
-
-.form dt
-{
- display: table-cell;
- clear: left;
- float: left;
- width: 7em;
- /*overflow: hidden;*/
- margin: 0;
- padding: 0.8em 0.5em 0 0;
- font-weight: bold;
- text-align:right;
- text-overflow:ellipsis;
- o-text-overflow: ellipsis;
- vertical-align: text-bottom;
- /*
- white-space: pre-wrap;
- white-space: -moz-pre-wrap !important;
- white-space: -pre-wrap;
- white-space: -o-pre-wrap;*/
-}
-
-.form dd
-{
- display: table-cell;
- clear: right;
- float: left;
- margin: 0;
- padding: 0px;
- white-space: nowrap;
- vertical-align: text-bottom;
- /*min-width: 20em;*/
- /*background-color: yellow;*/
-}
+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; font-weight: bold; text-align:right; text-overflow:ellipsis; o-text-overflow: ellipsis; vertical-align: text-bottom;/* white-space: pre-wrap; white-space: -moz-pre-wrap !important; white-space: -pre-wrap; white-space: -o-pre-wrap;*/ }
+.form dd { display: table-cell; clear: right; float: left; margin: 0; padding: 0px; white-space: nowrap; vertical-align: text-bottom; }
.loading { background: url('../../../core/img/loading.gif') no-repeat center !important; /*cursor: progress; */ cursor: wait; }
-/*.add { cursor: pointer; width: 25px; height: 25px; margin: 0px; float: right; position:relative; content: "\+"; font-weight: bold; color: #666; font-size: large; bottom: 0px; right: 0px; clear: both; text-align: center; vertical-align: bottom; display: none; }*/
-
.listactions { height: 1em; width:60px; float: left; clear: right; }
.add,.edit,.delete,.mail, .globe { cursor: pointer; width: 20px; height: 20px; margin: 0; float: left; position:relative; display: none; }
.add { background:url('../../../core/img/actions/add.svg') no-repeat center; clear: both; }
@@ -82,75 +38,21 @@ dl.form
/*.globe { background:url('../img/globe.svg') no-repeat center; }*/
.globe { background:url('../../../core/img/actions/public.svg') no-repeat center; }
-#messagebox_msg { font-weight: bold; font-size: 1.2em; }
-
-/* Name editor */
-#edit_name_dialog {
- /*width: 25em;*/
- padding:0;
-}
-#edit_name_dialog > input {
- width: 15em;
-}
-/* Address editor */
-#edit_address_dialog {
- /*width: 30em;*/
-}
-#edit_address_dialog > input {
- width: 15em;
-}
+#edit_name_dialog { padding:0; }
+#edit_name_dialog > input { width: 15em; }
+#edit_address_dialog { /*width: 30em;*/ }
+#edit_address_dialog > input { width: 15em; }
#edit_photo_dialog_img { display: block; width: 150; height: 200; border: thin solid black; }
#fn { float: left; }
/**
* Create classes form, floateven and floatodd which flows left and right respectively.
*/
-.contactsection {
- float: left;
- min-width: 30em;
- max-width: 40em;
- margin: 0.5em;
- border: thin solid lightgray;
- -webkit-border-radius: 0.5em;
- -moz-border-radius: 0.5em;
- border-radius: 0.5em;
- background-color: #f8f8f8;
-}
+.contactsection { float: left; min-width: 30em; max-width: 40em; margin: 0.5em; border: thin solid lightgray; -webkit-border-radius: 0.5em; -moz-border-radius: 0.5em; border-radius: 0.5em; background-color: #f8f8f8; }
-.contactpart legend {
- /*background: #fff;
- font-weight: bold;
- left: 1em;
- border: thin solid gray;
- -webkit-border-radius: 0.5em;
- -moz-border-radius: 0.5em;
- border-radius: 0.5em;
- padding: 3px;*/
-width:auto; padding:.3em; border:1px solid #ddd; font-weight:bold; cursor:pointer; background:#f8f8f8; color:#555; text-shadow:#fff 0 1px 0; -moz-box-shadow:0 1px 1px #fff, 0 1px 1px #fff inset; -webkit-box-shadow:0 1px 1px #fff, 0 1px 1px #fff inset; -moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em;
-}
-/*#contacts_details_photo {
- cursor: pointer;
- z-index:1;
- margin: auto;
-}
-*/
-#cropbox {
- margin: auto;
-}
+.contactpart legend { width:auto; padding:.3em; border:1px solid #ddd; font-weight:bold; cursor:pointer; background:#f8f8f8; color:#555; text-shadow:#fff 0 1px 0; -moz-box-shadow:0 1px 1px #fff, 0 1px 1px #fff inset; -webkit-box-shadow:0 1px 1px #fff, 0 1px 1px #fff inset; -moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em; }
+#cropbox { margin: auto; }
-/* Photo editor */
-/*#contacts_details_photo_wrapper {
- z-index: 1000;
-}*/
-#contacts_details_photo {
- border-radius: 0.5em;
- border: thin solid #bbb;
- padding: 0.5em;
- margin: 1em 1em 1em 7em;
- cursor: pointer;
- /*background: #f8f8f8;*/
- background: url(../../../core/img/loading.gif) no-repeat center center;
- clear: right;
-}
+#contacts_details_photo { border-radius: 0.5em; border: thin solid #bbb; padding: 0.5em; margin: 1em 1em 1em 7em; cursor: pointer; background: url(../../../core/img/loading.gif) no-repeat center center; clear: right; }
#contacts_details_photo:hover { background: #fff; }
#contacts_details_photo_progress { margin: 0.3em 0.3em 0.3em 7em; clear: left; }
/* Address editor */
@@ -168,13 +70,6 @@ dl.addresscard dd > ul { margin: 0.3em; padding: 0.3em; }
#adr_zipcode {}
#adr_country {}
-.delimiter {
- height: 10px;
- clear: both;
-}
-
-/*input[type="text"] { float: left; max-width: 15em; }
-input[type="radio"] { float: left; -khtml-appearance: none; width: 20px; height: 20px; vertical-align: middle; }*/
#file_upload_target, #crop_target { display:none; }
#file_upload_start { opacity:0; filter:alpha(opacity=0); z-index:1; position:absolute; left:0; top:0; cursor:pointer; width:0; height:0;}
diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js
index e1827027453..d314878cc0a 100644
--- a/apps/contacts/js/contacts.js
+++ b/apps/contacts/js/contacts.js
@@ -213,19 +213,27 @@ Contacts={
honpre:'',
honsuf:'',
data:undefined,
- update:function() {
+ update:function(id) {
// Make sure proper DOM is loaded.
- console.log('Card.update(), #n: ' + $('#n').length);
+ var newid;
+ console.log('Card.update(), id: ' + id);
console.log('Card.update(), #contacts: ' + $('#contacts li').length);
- if($('#n').length == 0 && $('#contacts li').length > 0) {
+ if(id == undefined) {
+ newid = $('#contacts li:first-child').data('id');
+ } else {
+ newid = id;
+ }
+ if($('#contacts li').length > 0) {
$.getJSON(OC.filePath('contacts', 'ajax', 'loadcard.php'),{},function(jsondata){
if(jsondata.status == 'success'){
$('#rightcontent').html(jsondata.data.page);
Contacts.UI.loadHandlers();
if($('#contacts li').length > 0) {
- var firstid = $('#contacts li:first-child').data('id');
- console.log('trying to load: ' + firstid);
- $.getJSON(OC.filePath('contacts', 'ajax', 'contactdetails.php'),{'id':firstid},function(jsondata){
+ //var newid = $('#contacts li:first-child').data('id');
+ //$('#contacts li:first-child').addClass('active');
+ $('#leftcontent li[data-id="'+newid+'"]').addClass('active');
+ console.log('trying to load: ' + newid);
+ $.getJSON(OC.filePath('contacts', 'ajax', 'contactdetails.php'),{'id':newid},function(jsondata){
if(jsondata.status == 'success'){
Contacts.UI.Card.loadContact(jsondata.data);
} else{
@@ -300,35 +308,49 @@ Contacts={
}
});
},
- delete: function() {
+ delete:function() {
$('#contacts_deletecard').tipsy('hide');
- $.getJSON('ajax/deletecard.php',{'id':this.id},function(jsondata){
- if(jsondata.status == 'success'){
- $('#leftcontent [data-id="'+jsondata.data.id+'"]').remove();
- $('#rightcontent').data('id','');
- //$('#rightcontent').empty();
- this.id = this.fn = this.fullname = this.shortname = this.famname = this.givname = this.addname = this.honpre = this.honsuf = '';
- this.data = undefined;
- // Load first in list.
- if($('#contacts li').length > 0) {
- Contacts.UI.Card.update();
- } else {
- // load intro page
- $.getJSON('ajax/loadintro.php',{},function(jsondata){
- if(jsondata.status == 'success'){
- id = '';
- $('#rightcontent').data('id','');
- $('#rightcontent').html(jsondata.data.page);
+ OC.dialogs.confirm(t('contacts', 'Are you sure you want to delete this contact?'), t('contacts', 'Warning'), function(answer) {
+ if(answer == true) {
+ $.getJSON('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 newlistitem = curlistitem.prev();
+ console.log('Previous: ' + newlistitem);
+ if(newlistitem == undefined) {
+ newlistitem = curlistitem.next();
}
- else{
- OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
+ curlistitem.remove();
+ if(newlistitem != undefined) {
+ newid = newlistitem.data('id');
}
- });
- }
- }
- else{
- OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
- //alert(jsondata.data.message);
+ $('#rightcontent').data('id',newid);
+ //$('#rightcontent').empty();
+ this.id = this.fn = this.fullname = this.shortname = this.famname = this.givname = this.addname = this.honpre = this.honsuf = '';
+ this.data = undefined;
+ // Load first in list.
+ if($('#contacts li').length > 0) {
+ Contacts.UI.Card.update(newid);
+ } else {
+ // load intro page
+ $.getJSON('ajax/loadintro.php',{},function(jsondata){
+ if(jsondata.status == 'success'){
+ id = '';
+ $('#rightcontent').data('id','');
+ $('#rightcontent').html(jsondata.data.page);
+ }
+ else{
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
+ }
+ });
+ }
+ }
+ else{
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
+ //alert(jsondata.data.message);
+ }
+ });
}
});
return false;
@@ -1232,6 +1254,7 @@ $(document).ready(function(){
*/
$('#leftcontent li').live('click',function(){
var id = $(this).data('id');
+ $(this).addClass('active');
var oldid = $('#rightcontent').data('id');
if(oldid != 0){
$('#leftcontent li[data-id="'+oldid+'"]').removeClass('active');
diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php
index a93069fa722..d243c2b5e14 100644
--- a/apps/contacts/templates/part.contact.php
+++ b/apps/contacts/templates/part.contact.php
@@ -56,13 +56,6 @@ $id = isset($_['id']) ? $_['id'] : '';
<dd style="display:none;" class="propertycontainer" id="nickname_value" data-element="NICKNAME"><input id="nickname" required="required" name="value[NICKNAME]" type="text" class="contacts_property" style="width:16em;" name="value" value="" placeholder="<?php echo $l->t('Enter nickname'); ?>" /><a class="action delete" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'single');" title="<?php echo $l->t('Delete'); ?>"></a></dd>
<dt style="display:none;" id="bday_label" data-element="BDAY"><label for="bday"><?php echo $l->t('Birthday'); ?></label></dt>
<dd style="display:none;" class="propertycontainer" id="bday_value" data-element="BDAY"><input id="bday" required="required" name="value" type="text" class="contacts_property" value="" placeholder="<?php echo $l->t('dd-mm-yyyy'); ?>" /><a class="action delete" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'single');" title="<?php echo $l->t('Delete'); ?>"></a></dd>
- <!-- dt id="categories_label" data-element="CATEGORIES"><label for="categories"><?php echo $l->t('Categories'); ?></label></dt>
- <dd class="propertycontainer" id="categories_value" data-element="CATEGORIES">
- <select class="contacts_property" multiple="multiple" id="categories" name="value[]">
- <?php echo html_select_options($_['categories'], array(), array('combine'=>true)) ?>
- </select>
- <a class="action edit" onclick="$(this).tipsy('hide');OCCategories.edit();" title="<?php echo $l->t('Edit categories'); ?>"></a>
- </dd -->
<dt style="display:none;" id="categories_label" data-element="CATEGORIES"><label for="categories"><?php echo $l->t('Categories'); ?></label></dt>
<dd style="display:none;" class="propertycontainer" id="categories_value" data-element="CATEGORIES"><input id="categories" required="required" name="value[CATEGORIES]" type="text" class="contacts_property" style="width:16em;" name="value" value="" placeholder="<?php echo $l->t('Categories'); ?>" /><a class="action delete" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'single');" title="<?php echo $l->t('Delete'); ?>"></a><a class="action edit" onclick="$(this).tipsy('hide');OCCategories.edit();" title="<?php echo $l->t('Edit categories'); ?>"></a></dd>
</dl>
@@ -131,6 +124,7 @@ $(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);
}
else{
diff --git a/apps/files_archive/appinfo/app.php b/apps/files_archive/appinfo/app.php
index 693c28d98a0..67809ec980a 100644
--- a/apps/files_archive/appinfo/app.php
+++ b/apps/files_archive/appinfo/app.php
@@ -7,7 +7,8 @@
*/
OC::$CLASSPATH['OC_Archive'] = 'apps/files_archive/lib/archive.php';
-foreach(array('ZIP') as $type){
+OC::$CLASSPATH['Archive_Tar'] = '3rdparty/Archive/Tar.php';
+foreach(array('ZIP','TAR') as $type){
OC::$CLASSPATH['OC_Archive_'.$type] = 'apps/files_archive/lib/'.strtolower($type).'.php';
}
diff --git a/apps/files_archive/appinfo/info.xml b/apps/files_archive/appinfo/info.xml
index df767d39f6b..236b5a64b05 100644
--- a/apps/files_archive/appinfo/info.xml
+++ b/apps/files_archive/appinfo/info.xml
@@ -7,4 +7,7 @@
<licence>AGPL</licence>
<author>Robin Appelman</author>
<require>3</require>
+ <types>
+ <filesystem/>
+ </types>
</info>
diff --git a/apps/files_archive/js/archive.js b/apps/files_archive/js/archive.js
index ec316c7bf2c..531eb61c01a 100644
--- a/apps/files_archive/js/archive.js
+++ b/apps/files_archive/js/archive.js
@@ -11,5 +11,9 @@ $(document).ready(function() {
window.location='index.php?dir='+encodeURIComponent($('#dir').val()).replace(/%2F/g, '/')+'/'+encodeURIComponent(filename);
});
FileActions.setDefault('application/zip','Open');
+ FileActions.register('application/x-gzip','Open','',function(filename){
+ window.location='index.php?dir='+encodeURIComponent($('#dir').val()).replace(/%2F/g, '/')+'/'+encodeURIComponent(filename);
+ });
+ FileActions.setDefault('application/x-gzip','Open');
}
});
diff --git a/apps/files_archive/lib/archive.php b/apps/files_archive/lib/archive.php
index be89f894fb7..113f92e9604 100644
--- a/apps/files_archive/lib/archive.php
+++ b/apps/files_archive/lib/archive.php
@@ -17,6 +17,15 @@ abstract class OC_Archive{
switch($ext){
case '.zip':
return new OC_Archive_ZIP($path);
+ case '.gz':
+ case '.bz':
+ case '.bz2':
+ if(strpos($path,'.tar.')){
+ return new OC_Archive_TAR($path);
+ }
+ break;
+ case '.tgz':
+ return new OC_Archive_TAR($path);
}
}
@@ -78,6 +87,13 @@ abstract class OC_Archive{
*/
abstract function extractFile($path,$dest);
/**
+ * extract the archive
+ * @param string path
+ * @param string dest
+ * @return bool
+ */
+ abstract function extract($dest);
+ /**
* check if a file or folder exists in the archive
* @param string path
* @return bool
diff --git a/apps/files_archive/lib/storage.php b/apps/files_archive/lib/storage.php
index 72a96ca5a5d..700d9633042 100644
--- a/apps/files_archive/lib/storage.php
+++ b/apps/files_archive/lib/storage.php
@@ -125,7 +125,7 @@ class OC_Filestorage_Archive extends OC_Filestorage_Common{
self::$rootView=new OC_FilesystemView('');
}
self::$enableAutomount=false;//prevent recursion
- $supported=array('zip');
+ $supported=array('zip','tar.gz','tar.bz2','tgz');
foreach($supported as $type){
$ext='.'.$type.'/';
if(($pos=strpos(strtolower($path),$ext))!==false){
@@ -139,4 +139,8 @@ class OC_Filestorage_Archive extends OC_Filestorage_Common{
}
self::$enableAutomount=true;
}
+
+ public function rename($path1,$path2){
+ return $this->archive->rename($path1,$path2);
+ }
}
diff --git a/apps/files_archive/lib/tar.php b/apps/files_archive/lib/tar.php
new file mode 100644
index 00000000000..a5d54004788
--- /dev/null
+++ b/apps/files_archive/lib/tar.php
@@ -0,0 +1,277 @@
+<?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.
+ */
+
+class OC_Archive_TAR extends OC_Archive{
+ const PLAIN=0;
+ const GZIP=1;
+ const BZIP=2;
+
+ /**
+ * @var Archive_Tar tar
+ */
+ private $tar=null;
+ private $path;
+
+ function __construct($source){
+ $types=array(null,'gz','bz');
+ $this->path=$source;
+ $this->tar=new Archive_Tar($source,$types[self::getTarType($source)]);
+ }
+
+ /**
+ * try to detect the type of tar compression
+ * @param string file
+ * @return str
+ */
+ static public function getTarType($file){
+ if(strpos($file,'.')){
+ $extention=substr($file,strrpos($file,'.'));
+ switch($extention){
+ case 'gz':
+ case 'tgz':
+ return self::GZIP;
+ case 'bz':
+ case 'bz2':
+ return self::BZIP;
+ default:
+ return self::PLAIN;
+ }
+ }else{
+ return self::PLAIN;
+ }
+ }
+
+ /**
+ * add an empty folder to the archive
+ * @param string path
+ * @return bool
+ */
+ function addFolder($path){
+ $tmpBase=get_temp_dir().'/';
+ if(substr($path,-1,1)!='/'){
+ $path.='/';
+ }
+ if($this->fileExists($path)){
+ return false;
+ }
+ mkdir($tmpBase.$path);
+ $result=$this->tar->addModify(array($tmpBase.$path),'',$tmpBase);
+ rmdir($tmpBase.$path);
+ return $result;
+ }
+ /**
+ * add a file to the archive
+ * @param string path
+ * @param string source either a local file or string data
+ * @return bool
+ */
+ function addFile($path,$source=''){
+ if($this->fileExists($path)){
+ $this->remove($path);
+ }
+ if(file_exists($source)){
+ $header=array();
+ $dummy='';
+ $this->tar->_openAppend();
+ $result=$this->tar->_addfile($source,$header,$dummy,$dummy,$path);
+ }else{
+ $result=$this->tar->addString($path,$source);
+ }
+ return $result;
+ }
+
+ /**
+ * rename a file or folder in the archive
+ * @param string source
+ * @param string dest
+ * @return bool
+ */
+ function rename($source,$dest){
+ //no proper way to delete, rename entire archive, rename file and remake archive
+ $tmp=OC_Helper::tmpFolder();
+ $this->tar->extract($tmp);
+ rename($tmp.$source,$tmp.$dest);
+ $this->tar=null;
+ unlink($this->path);
+ $types=array(null,'gz','bz');
+ $this->tar=new Archive_Tar($this->path,$types[self::getTarType($this->path)]);
+ $this->tar->createModify(array($tmp),'',$tmp.'/');
+ }
+
+ private function getHeader($file){
+ $headers=$this->tar->listContent();
+ foreach($headers as $header){
+ if($file==$header['filename'] or $file.'/'==$header['filename']){
+ return $header;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * get the uncompressed size of a file in the archive
+ * @param string path
+ * @return int
+ */
+ function filesize($path){
+ $stat=$this->getHeader($path);
+ return $stat['size'];
+ }
+ /**
+ * get the last modified time of a file in the archive
+ * @param string path
+ * @return int
+ */
+ function mtime($path){
+ $stat=$this->getHeader($path);
+ return $stat['mtime'];
+ }
+
+ /**
+ * get the files in a folder
+ * @param path
+ * @return array
+ */
+ function getFolder($path){
+ $files=$this->getFiles();
+ $folderContent=array();
+ $pathLength=strlen($path);
+ foreach($files as $file){
+ if(substr($file,0,$pathLength)==$path and $file!=$path){
+ if(strrpos(substr($file,0,-1),'/')<=$pathLength){
+ $folderContent[]=substr($file,$pathLength);
+ }
+ }
+ }
+ return $folderContent;
+ }
+ /**
+ *get all files in the archive
+ * @return array
+ */
+ function getFiles(){
+ $headers=$this->tar->listContent();
+ $files=array();
+ foreach($headers as $header){
+ $files[]=$header['filename'];
+ }
+ return $files;
+ }
+ /**
+ * get the content of a file
+ * @param string path
+ * @return string
+ */
+ function getFile($path){
+ return $this->tar->extractInString($path);
+ }
+ /**
+ * extract a single file from the archive
+ * @param string path
+ * @param string dest
+ * @return bool
+ */
+ function extractFile($path,$dest){
+ $tmp=OC_Helper::tmpFolder();
+ if(!$this->fileExists($path)){
+ return false;
+ }
+ $success=$this->tar->extractList(array($path),$tmp);
+ if($success){
+ rename($tmp.$path,$dest);
+ }
+ OC_Helper::rmdirr($tmp);
+ return $success;
+ }
+ /**
+ * extract the archive
+ * @param string path
+ * @param string dest
+ * @return bool
+ */
+ function extract($dest){
+ return $this->tar->extract($dest);
+ }
+ /**
+ * check if a file or folder exists in the archive
+ * @param string path
+ * @return bool
+ */
+ function fileExists($path){
+ return $this->getHeader($path)!==null;
+ }
+
+ /**
+ * remove a file or folder from the archive
+ * @param string path
+ * @return bool
+ */
+ function remove($path){
+ if(!$this->fileExists($path)){
+ return false;
+ }
+ //no proper way to delete, extract entire archive, delete file and remake archive
+ $tmp=OC_Helper::tmpFolder();
+ $this->tar->extract($tmp);
+ OC_Helper::rmdirr($tmp.$path);
+ $this->tar=null;
+ unlink($this->path);
+ $this->reopen();
+ $this->tar->createModify(array($tmp),'',$tmp);
+ return true;
+ }
+ /**
+ * get a file handler
+ * @param string path
+ * @param string mode
+ * @return resource
+ */
+ function getStream($path,$mode){
+ if(strrpos($path,'.')!==false){
+ $ext=substr($path,strrpos($path,'.'));
+ }else{
+ $ext='';
+ }
+ $tmpFile=OC_Helper::tmpFile($ext);
+ if($this->fileExists($path)){
+ $this->extractFile($path,$tmpFile);
+ }elseif($mode=='r' or $mode=='rb'){
+ return false;
+ }
+ if($mode=='r' or $mode=='rb'){
+ return fopen($tmpFile,$mode);
+ }else{
+ OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this,'writeBack');
+ self::$tempFiles[$tmpFile]=$path;
+ return fopen('close://'.$tmpFile,$mode);
+ }
+ }
+
+ private static $tempFiles=array();
+ /**
+ * write back temporary files
+ */
+ function writeBack($tmpFile){
+ if(isset(self::$tempFiles[$tmpFile])){
+ $this->addFile(self::$tempFiles[$tmpFile],$tmpFile);
+ unlink($tmpFile);
+ }
+ }
+
+ /**
+ * reopen the archive to ensure everything is written
+ */
+ private function reopen(){
+ if($this->tar){
+ $this->tar->_close();
+ $this->tar=null;
+ }
+ $types=array(null,'gz','bz');
+ $this->tar=new Archive_Tar($this->path,$types[self::getTarType($this->path)]);
+ }
+}
diff --git a/apps/files_archive/lib/zip.php b/apps/files_archive/lib/zip.php
index eab101b3a5c..5a5bc766875 100644
--- a/apps/files_archive/lib/zip.php
+++ b/apps/files_archive/lib/zip.php
@@ -11,7 +11,6 @@ class OC_Archive_ZIP extends OC_Archive{
* @var ZipArchive zip
*/
private $zip=null;
- private $contents=array();
private $success=false;
private $path;
@@ -56,7 +55,9 @@ class OC_Archive_ZIP extends OC_Archive{
* @return bool
*/
function rename($source,$dest){
- return $this->zip->renameName($source,$dest);
+ $source=$this->stripPath($source);
+ $dest=$this->stripPath($dest);
+ $this->zip->renameName($source,$dest);
}
/**
* get the uncompressed size of a file in the archive
@@ -99,15 +100,11 @@ class OC_Archive_ZIP extends OC_Archive{
* @return array
*/
function getFiles(){
- if(count($this->contents)){
- return $this->contents;
- }
$fileCount=$this->zip->numFiles;
$files=array();
for($i=0;$i<$fileCount;$i++){
$files[]=$this->zip->getNameIndex($i);
}
- $this->contents=$files;
return $files;
}
/**
@@ -129,12 +126,21 @@ class OC_Archive_ZIP extends OC_Archive{
file_put_contents($dest,$fp);
}
/**
+ * extract the archive
+ * @param string path
+ * @param string dest
+ * @return bool
+ */
+ function extract($dest){
+ return $this->zip->extractTo($dest);
+ }
+ /**
* check if a file or folder exists in the archive
* @param string path
* @return bool
*/
function fileExists($path){
- return $this->zip->locateName($path)!==false;
+ return ($this->zip->locateName($path)!==false) or ($this->zip->locateName($path.'/')!==false);
}
/**
* remove a file or folder from the archive
@@ -142,7 +148,11 @@ class OC_Archive_ZIP extends OC_Archive{
* @return bool
*/
function remove($path){
- return $this->zip->deleteName($path);
+ if($this->fileExists($path.'/')){
+ return $this->zip->deleteName($path.'/');
+ }else{
+ return $this->zip->deleteName($path);
+ }
}
/**
* get a file handler
@@ -179,4 +189,12 @@ class OC_Archive_ZIP extends OC_Archive{
unlink($tmpFile);
}
}
+
+ private function stripPath($path){
+ if(substr($path,0,1)=='/'){
+ return substr($path,1);
+ }else{
+ return $path;
+ }
+ }
}
diff --git a/apps/files_archive/tests/archive.php b/apps/files_archive/tests/archive.php
index 2e26b5e03b5..9e99466a521 100644
--- a/apps/files_archive/tests/archive.php
+++ b/apps/files_archive/tests/archive.php
@@ -27,10 +27,10 @@ abstract class Test_Archive extends UnitTestCase {
$this->instance=$this->getExisting();
$allFiles=$this->instance->getFiles();
$expected=array('lorem.txt','logo-wide.png','dir/','dir/lorem.txt');
- $this->assertEqual(4,count($allFiles));
+ $this->assertEqual(4,count($allFiles),'only found '.count($allFiles).' out of 4 expected files');
foreach($expected as $file){
$this->assertNotIdentical(false,array_search($file,$allFiles),'cant find '.$file.' in archive');
- $this->assertTrue($this->instance->fileExists($file));
+ $this->assertTrue($this->instance->fileExists($file),'file '.$file.' does not exist in archive');
}
$this->assertFalse($this->instance->fileExists('non/existing/file'));
@@ -68,6 +68,7 @@ abstract class Test_Archive extends UnitTestCase {
$this->instance->addFile('lorem.txt',$textFile);
$this->assertEqual(1,count($this->instance->getFiles()));
$this->assertTrue($this->instance->fileExists('lorem.txt'));
+ $this->assertFalse($this->instance->fileExists('lorem.txt/'));
$this->assertEqual(file_get_contents($textFile),$this->instance->getFile('lorem.txt'));
$this->instance->addFile('lorem.txt','foobar');
@@ -94,4 +95,39 @@ abstract class Test_Archive extends UnitTestCase {
$this->assertTrue($this->instance->fileExists('lorem.txt'));
$this->assertEqual(file_get_contents($dir.'/lorem.txt'),$this->instance->getFile('lorem.txt'));
}
+ public function testFolder(){
+ $this->instance=$this->getNew();
+ $this->assertFalse($this->instance->fileExists('/test'));
+ $this->assertFalse($this->instance->fileExists('/test/'));
+ $this->instance->addFolder('/test');
+ $this->assertTrue($this->instance->fileExists('/test'));
+ $this->assertTrue($this->instance->fileExists('/test/'));
+ $this->instance->remove('/test');
+ $this->assertFalse($this->instance->fileExists('/test'));
+ $this->assertFalse($this->instance->fileExists('/test/'));
+ }
+ public function testExtract(){
+ $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
+ $this->instance=$this->getExisting();
+ $tmpDir=OC_Helper::tmpFolder();
+ $this->instance->extract($tmpDir);
+ $this->assertEqual(true,file_exists($tmpDir.'lorem.txt'));
+ $this->assertEqual(true,file_exists($tmpDir.'dir/lorem.txt'));
+ $this->assertEqual(true,file_exists($tmpDir.'logo-wide.png'));
+ $this->assertEqual(file_get_contents($dir.'/lorem.txt'),file_get_contents($tmpDir.'lorem.txt'));
+ OC_Helper::rmdirr($tmpDir);
+ }
+ public function testMoveRemove(){
+ $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
+ $textFile=$dir.'/lorem.txt';
+ $this->instance=$this->getNew();
+ $this->instance->addFile('lorem.txt',$textFile);
+ $this->assertFalse($this->instance->fileExists('target.txt'));
+ $this->instance->rename('lorem.txt','target.txt');
+ $this->assertTrue($this->instance->fileExists('target.txt'));
+ $this->assertFalse($this->instance->fileExists('lorem.txt'));
+ $this->assertEqual(file_get_contents($textFile),$this->instance->getFile('target.txt'));
+ $this->instance->remove('target.txt');
+ $this->assertFalse($this->instance->fileExists('target.txt'));
+ }
}
diff --git a/apps/files_archive/tests/tar.php b/apps/files_archive/tests/tar.php
new file mode 100644
index 00000000000..193a65b550a
--- /dev/null
+++ b/apps/files_archive/tests/tar.php
@@ -0,0 +1,20 @@
+<?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.
+ */
+
+require_once('archive.php');
+
+class Test_Archive_TAR extends Test_Archive{
+ protected function getExisting(){
+ $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
+ return new OC_Archive_TAR($dir.'/data.tar.gz');
+ }
+
+ protected function getNew(){
+ return new OC_Archive_TAR(OC_Helper::tmpFile('.tar.gz'));
+ }
+}
diff --git a/apps/files_encryption/appinfo/info.xml b/apps/files_encryption/appinfo/info.xml
index 053044aaed2..691b265bf60 100644
--- a/apps/files_encryption/appinfo/info.xml
+++ b/apps/files_encryption/appinfo/info.xml
@@ -7,4 +7,7 @@
<licence>AGPL</licence>
<author>Robin Appelman</author>
<require>3</require>
+ <types>
+ <filesystem/>
+ </types>
</info>
diff --git a/apps/files_external/appinfo/app.php b/apps/files_external/appinfo/app.php
new file mode 100644
index 00000000000..95770b44b75
--- /dev/null
+++ b/apps/files_external/appinfo/app.php
@@ -0,0 +1,11 @@
+<?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.
+ */
+
+OC::$CLASSPATH['OC_Filestorage_FTP']='apps/files_external/lib/ftp.php';
+OC::$CLASSPATH['OC_Filestorage_DAV']='apps/files_external/lib/webdav.php';
+OC::$CLASSPATH['OC_Filestorage_Google']='apps/files_external/lib/google.php';
diff --git a/apps/files_external/appinfo/info.xml b/apps/files_external/appinfo/info.xml
new file mode 100644
index 00000000000..fb58297ff17
--- /dev/null
+++ b/apps/files_external/appinfo/info.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<info>
+ <id>files_external</id>
+ <name>External storage support</name>
+ <description>Mount external storage sources</description>
+ <version>0.1</version>
+ <licence>AGPL</licence>
+ <author>Robin Appelman</author>
+ <require>3</require>
+ <types>
+ <filesystem/>
+ </types>
+</info>
diff --git a/apps/files_remote/lib/ftp.php b/apps/files_external/lib/ftp.php
index 802446b4fd8..802446b4fd8 100644
--- a/apps/files_remote/lib/ftp.php
+++ b/apps/files_external/lib/ftp.php
diff --git a/apps/files_remote/lib/google.php b/apps/files_external/lib/google.php
index 0d6db1987f8..0d6db1987f8 100644
--- a/apps/files_remote/lib/google.php
+++ b/apps/files_external/lib/google.php
diff --git a/apps/files_remote/lib/webdav.php b/apps/files_external/lib/webdav.php
index 7a2da5c8ec0..7a2da5c8ec0 100644
--- a/apps/files_remote/lib/webdav.php
+++ b/apps/files_external/lib/webdav.php
diff --git a/apps/files_remote/tests/config.php b/apps/files_external/tests/config.php
index 9b40d2b98cf..9b40d2b98cf 100644
--- a/apps/files_remote/tests/config.php
+++ b/apps/files_external/tests/config.php
diff --git a/apps/files_remote/tests/ftp.php b/apps/files_external/tests/ftp.php
index 03633b7c0d1..aa565751ba3 100644
--- a/apps/files_remote/tests/ftp.php
+++ b/apps/files_external/tests/ftp.php
@@ -12,7 +12,7 @@ class Test_Filestorage_FTP extends Test_FileStorage {
public function setUp(){
$id=uniqid();
- $this->config=include('apps/files_remote/tests/config.php');
+ $this->config=include('apps/files_external/tests/config.php');
$this->config['ftp']['root'].='/'.$id;//make sure we have an new empty folder to work in
$this->instance=new OC_Filestorage_FTP($this->config['ftp']);
}
diff --git a/apps/files_remote/tests/google.php b/apps/files_external/tests/google.php
index b49f9e4647c..1c028945228 100644
--- a/apps/files_remote/tests/google.php
+++ b/apps/files_external/tests/google.php
@@ -27,7 +27,7 @@ class Test_Filestorage_Google extends Test_FileStorage {
public function setUp(){
$id=uniqid();
- $this->config=include('apps/files_remote/tests/config.php');
+ $this->config=include('apps/files_external/tests/config.php');
$this->config['google']['root'].='/'.$id;//make sure we have an new empty folder to work in
$this->instance=new OC_Filestorage_Google($this->config['google']);
}
@@ -35,4 +35,4 @@ class Test_Filestorage_Google extends Test_FileStorage {
public function tearDown(){
$this->instance->rmdir('/');
}
-} \ No newline at end of file
+}
diff --git a/apps/files_remote/tests/webdav.php b/apps/files_external/tests/webdav.php
index 219fff8852d..51799290540 100644
--- a/apps/files_remote/tests/webdav.php
+++ b/apps/files_external/tests/webdav.php
@@ -12,7 +12,7 @@ class Test_Filestorage_DAV extends Test_FileStorage {
public function setUp(){
$id=uniqid();
- $this->config=include('apps/files_remote/tests/config.php');
+ $this->config=include('apps/files_external/tests/config.php');
$this->config['webdav']['root'].='/'.$id;//make sure we have an new empty folder to work in
$this->instance=new OC_Filestorage_DAV($this->config['webdav']);
}
diff --git a/apps/files_remote/appinfo/app.php b/apps/files_remote/appinfo/app.php
deleted file mode 100644
index 02c1c3ae313..00000000000
--- a/apps/files_remote/appinfo/app.php
+++ /dev/null
@@ -1,11 +0,0 @@
-<?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.
- */
-
-OC::$CLASSPATH['OC_Filestorage_FTP']='apps/files_remote/lib/ftp.php';
-OC::$CLASSPATH['OC_Filestorage_DAV']='apps/files_remote/lib/webdav.php';
-OC::$CLASSPATH['OC_Filestorage_Google']='apps/files_remote/lib/google.php';
diff --git a/apps/files_remote/appinfo/info.xml b/apps/files_remote/appinfo/info.xml
deleted file mode 100644
index 0720b6095b9..00000000000
--- a/apps/files_remote/appinfo/info.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0"?>
-<info>
- <id>files_remote</id>
- <name>Remote storage support</name>
- <description>Mount remote storage sources</description>
- <version>0.1</version>
- <licence>AGPL</licence>
- <author>Robin Appelman</author>
- <require>3</require>
-</info>
diff --git a/apps/files_sharing/ajax/userautocomplete.php b/apps/files_sharing/ajax/userautocomplete.php
index 9d971fb62af..38b673ee51b 100644
--- a/apps/files_sharing/ajax/userautocomplete.php
+++ b/apps/files_sharing/ajax/userautocomplete.php
@@ -7,21 +7,23 @@ OC_JSON::checkLoggedIn();
OC_JSON::checkAppEnabled('files_sharing');
$users = array();
-$ocusers = OC_User::getUsers();
+$groups = array();
$self = OC_User::getUser();
-$groups = OC_Group::getUserGroups($self);
+$userGroups = OC_Group::getUserGroups($self);
$users[] = "<optgroup label='Users'>";
-foreach ($ocusers as $user) {
- if ($user != $self) {
- $users[] = "<option value='".$user."'>".$user."</option>";
+$groups[] = "<optgroup label='Groups'>";
+foreach ($userGroups as $group) {
+ $groupUsers = OC_Group::usersInGroup($group);
+ foreach ($groupUsers as $user) {
+ if ($user != $self) {
+ $users[] = "<option value='".$user."'>".$user."</option>";
+ }
}
+ $groups[] = "<option value='".$group."'>".$group."</option>";
}
$users[] = "</optgroup>";
-$users[] = "<optgroup label='Groups'>";
-foreach ($groups as $group) {
- $users[] = "<option value='".$group."'>".$group."</option>";
-}
-$users[] = "</optgroup>";
+$groups[] = "</optgroup>";
+$users = array_merge($users, $groups);
OC_JSON::encodedPrint($users);
?>
diff --git a/apps/files_sharing/appinfo/info.xml b/apps/files_sharing/appinfo/info.xml
index abf847b4483..8fda775520b 100644
--- a/apps/files_sharing/appinfo/info.xml
+++ b/apps/files_sharing/appinfo/info.xml
@@ -8,4 +8,7 @@
<author>Michael Gapczynski</author>
<require>2</require>
<default_enable/>
+ <types>
+ <filesystem/>
+ </types>
</info>
diff --git a/apps/files_sharing/lib_share.php b/apps/files_sharing/lib_share.php
index 42739bdfba9..673984f393b 100644
--- a/apps/files_sharing/lib_share.php
+++ b/apps/files_sharing/lib_share.php
@@ -52,8 +52,18 @@ class OC_Share {
// Remove the owner from the list of users in the group
$uid_shared_with = array_diff($uid_shared_with, array($uid_owner));
} else if (OC_User::userExists($uid_shared_with)) {
- $gid = null;
- $uid_shared_with = array($uid_shared_with);
+ $userGroups = OC_Group::getUserGroups($uid_owner);
+ // Check if the user is in one of the owner's groups
+ foreach ($userGroups as $group) {
+ if ($inGroup = OC_Group::inGroup($uid_shared_with, $group)) {
+ $gid = null;
+ $uid_shared_with = array($uid_shared_with);
+ break;
+ }
+ }
+ if (!$inGroup) {
+ throw new Exception("You can't share with ".$uid_shared_with);
+ }
} else {
throw new Exception($uid_shared_with." is not a user");
}
diff --git a/apps/files_texteditor/js/editor.js b/apps/files_texteditor/js/editor.js
index 02d39b98430..1e136fe68e5 100644
--- a/apps/files_texteditor/js/editor.js
+++ b/apps/files_texteditor/js/editor.js
@@ -76,7 +76,7 @@ function showControls(filename,writeperms){
function bindControlEvents(){
$("#editor_save").die('click',doFileSave).live('click',doFileSave);
- $('#editor_close').die('click',hideFileEditor).live('click',hideFileEditor);
+ $('#editor_close').die('click',closeBtnClick).live('click',closeBtnClick);
$('#gotolineval').die('keyup', goToLine).live('keyup', goToLine);
$('#editorsearchval').die('keyup', doSearch).live('keyup', doSearch);
$('#clearsearchbtn').die('click', resetSearch).live('click', resetSearch);
@@ -141,31 +141,38 @@ function doSearch(){
// Tries to save the file.
function doFileSave(){
if(editorIsShown()){
- // Get file path
- var path = $('#editor').attr('data-dir')+'/'+$('#editor').attr('data-filename');
- // Get original mtime
- var mtime = $('#editor').attr('data-mtime');
- // Show saving spinner
- $("#editor_save").die('click',doFileSave);
- $('#save_result').remove();
- $('#editor_save').text(t('files_texteditor','Saving...'));
- // Get the data
- var filecontents = window.aceEditor.getSession().getValue();
- // Send the data
- $.post(OC.filePath('files_texteditor','ajax','savefile.php'), { filecontents: filecontents, path: path, mtime: mtime },function(jsondata){
- if(jsondata.status!='success'){
- // Save failed
- $('#editor_save').text(t('files_texteditor','Save'));
- $('#editor_save').after('<p id="save_result" style="float: left">Failed to save file</p>');
- $("#editor_save").live('click',doFileSave);
- } else {
- // Save OK
- // Update mtime
- $('#editor').attr('data-mtime',jsondata.data.mtime);
- $('#editor_save').text(t('files_texteditor','Save'));
- $("#editor_save").live('click',doFileSave);
- }
- },'json');
+ // Changed contents?
+ if($('#editor').attr('data-edited')=='true'){
+ // Get file path
+ var path = $('#editor').attr('data-dir')+'/'+$('#editor').attr('data-filename');
+ // Get original mtime
+ var mtime = $('#editor').attr('data-mtime');
+ // Show saving spinner
+ $("#editor_save").die('click',doFileSave);
+ $('#save_result').remove();
+ $('#editor_save').text(t('files_texteditor','Saving...'));
+ // Get the data
+ var filecontents = window.aceEditor.getSession().getValue();
+ // Send the data
+ $.post(OC.filePath('files_texteditor','ajax','savefile.php'), { filecontents: filecontents, path: path, mtime: mtime },function(jsondata){
+ if(jsondata.status!='success'){
+ // Save failed
+ $('#editor_save').text(t('files_texteditor','Save'));
+ $('#editor_save').after('<p id="save_result" style="float: left">Failed to save file</p>');
+ $("#editor_save").live('click',doFileSave);
+ } else {
+ // Save OK
+ // Update mtime
+ $('#editor').attr('data-mtime',jsondata.data.mtime);
+ $('#editor_save').text(t('files_texteditor','Save'));
+ $("#editor_save").live('click',doFileSave);
+ // Update titles
+ $('#editor').attr('data-edited', 'false');
+ $('#breadcrumb_file').text($('#editor').attr('data-filename'));
+ document.title = $('#editor').attr('data-filename')+' - ownCloud';
+ }
+ },'json');
+ }
}
};
@@ -192,10 +199,11 @@ function showFileEditor(dir,filename){
// Show the control bar
showControls(filename,result.data.write);
// Update document title
- document.title = filename;
+ document.title = filename+' - ownCloud';
$('#editor').text(result.data.filecontents);
$('#editor').attr('data-dir', dir);
$('#editor').attr('data-filename', filename);
+ $('#editor').attr('data-edited', 'false');
window.aceEditor = ace.edit("editor");
aceEditor.setShowPrintMargin(false);
aceEditor.getSession().setUseWrapMode(true);
@@ -207,10 +215,17 @@ function showFileEditor(dir,filename){
OC.addScript('files_texteditor','aceeditor/theme-clouds', function(){
window.aceEditor.setTheme("ace/theme/clouds");
});
+ window.aceEditor.getSession().on('change', function(){
+ if($('#editor').attr('data-edited')!='true'){
+ $('#editor').attr('data-edited', 'true');
+ $('#breadcrumb_file').text($('#breadcrumb_file').text()+' *');
+ document.title = $('#editor').attr('data-filename')+' * - ownCloud';
+ }
+ });
});
} else {
// Failed to get the file.
- alert(result.data.message);
+ OC.dialogs.alert(result.data.message, t('files_texteditor','An error occurred!'));
}
// End success
}
@@ -220,6 +235,19 @@ function showFileEditor(dir,filename){
}
}
+function closeBtnClick(){
+ if($('#editor').attr('data-edited')=='true'){
+ // Show confirm
+ OC.dialogs.confirm(t('files_texteditor','You have unsaved changes that will be lost! Do you still want to close?'),t('files_texteditor','Really close?'),function(close){
+ if(close){
+ hideFileEditor();
+ }
+ });
+ } else {
+ hideFileEditor();
+ }
+}
+
// Fades out the editor.
function hideFileEditor(){
// Fades out editor controls
@@ -287,4 +315,5 @@ $(document).ready(function(){
$('#editor').remove();
// Binds the save keyboard shortcut events
//$(document).unbind('keydown').bind('keydown',checkForSaveKeyPress);
+
});
diff --git a/apps/gallery/ajax/galleryOp.php b/apps/gallery/ajax/galleryOp.php
index b0433898cda..1b3ad48f561 100644
--- a/apps/gallery/ajax/galleryOp.php
+++ b/apps/gallery/ajax/galleryOp.php
@@ -127,6 +127,9 @@ function handleGetGallery($path) {
function handleShare($path, $share, $recursive) {
$recursive = $recursive == 'true' ? 1 : 0;
$owner = OC_User::getUser();
+ $root = OC_Preferences::getValue(OC_User::getUser(),'gallery', 'root', '/');
+ $path = utf8_decode(rtrim($root.$path,'/'));
+ if($path == '') $path = '/';
$r = OC_Gallery_Album::find($owner, null, $path);
if ($row = $r->fetchRow()) {
$albumId = $row['album_id'];
diff --git a/apps/gallery/appinfo/app.php b/apps/gallery/appinfo/app.php
index 3e7e38301cf..f7e0651275e 100644
--- a/apps/gallery/appinfo/app.php
+++ b/apps/gallery/appinfo/app.php
@@ -32,14 +32,14 @@ $l = new OC_L10N('gallery');
OC_App::register(array(
'order' => 20,
'id' => 'gallery',
- 'name' => 'Gallery'));
+ 'name' => 'Pictures'));
OC_App::addNavigationEntry( array(
'id' => 'gallery_index',
'order' => 20,
'href' => OC_Helper::linkTo('gallery', 'index.php'),
'icon' => OC_Helper::imagePath('core', 'places/picture.svg'),
- 'name' => $l->t('Gallery')));
+ 'name' => $l->t('Pictures')));
class OC_GallerySearchProvider implements OC_Search_Provider{
static function search($query){
diff --git a/apps/gallery/appinfo/info.xml b/apps/gallery/appinfo/info.xml
index 19c5dc8b25e..4c8c1cee242 100644
--- a/apps/gallery/appinfo/info.xml
+++ b/apps/gallery/appinfo/info.xml
@@ -1,11 +1,11 @@
<?xml version="1.0"?>
<info>
<id>gallery</id>
- <name>Gallery</name>
+ <name>Pictures</name>
<version>0.4</version>
<licence>AGPL</licence>
<author>Bartek Przybylski</author>
<require>2</require>
- <description>Gallery application for ownCloud</description>
+ <description>Dedicated pictures application</description>
<default_enable/>
</info>
diff --git a/apps/gallery/js/album_cover.js b/apps/gallery/js/album_cover.js
index 061bbcd0b47..d44e7f83d1f 100644
--- a/apps/gallery/js/album_cover.js
+++ b/apps/gallery/js/album_cover.js
@@ -43,8 +43,9 @@ function shareGallery() {
{text: 'Shared gallery address', name: 'address', type: 'text', value: existing_token}];
OC.dialogs.form(form_fields, t('gallery', 'Share gallery'), function(values){
var p = '';
- for (var i in paths) p += '/'+paths[i];
+ for (var i in paths) p += paths[i]+'/';
if (p == '') p = '/';
+ alert(p);
$.getJSON(OC.filePath('gallery', 'ajax', 'galleryOp.php'), {operation: 'share', path: p, share: values[0].value, recursive: values[1].value}, function(r) {
if (r.status == 'success') {
Albums.shared = r.sharing;
@@ -112,42 +113,28 @@ function scanForAlbums(cleanup) {
}
function settings() {
- $( '#g-dialog-settings' ).dialog({
- height: 180,
- width: 350,
- modal: false,
- buttons: [
- {
- text: t('gallery', 'Apply'),
- click: function() {
- var scanning_root = $('#g-scanning-root').val();
- var disp_order = $('#g-display-order option:selected').val();
+ OC.dialogs.form([{text: t('gallery', 'Scanning root'), name: 'root', type:'text', value:gallery_scanning_root},
+ {text: t('gallery', 'Default order'), name: 'order', type:'select', value:gallery_default_order, options:[
+ {text:t('gallery', 'Ascending'), value:'ASC'}, {text: t('gallery', 'Descending'), value:'DESC'} ]}],
+ t('gallery', 'Settings'),
+ function(values) {
+ var scanning_root = values[0].value;
+ var disp_order = values[1].value;
if (scanning_root == '') {
- alert('Scanning root cannot be empty');
+ OC.dialogs.alert(t('gallery', 'Scanning root cannot be empty'), t('gallery', 'Error'));
return;
}
$.getJSON(OC.filePath('gallery','ajax','galleryOp.php'), {operation: 'store_settings', root: scanning_root, order: disp_order}, function(r) {
if (r.status == 'success') {
- if (r.rescan == 'yes') {
- $('#g-dialog-settings').dialog('close');
- Albums.clear(document.getElementById('gallery_list'));
- scanForAlbums(true);
- return;
- }
+ if (r.rescan == 'yes') {
+ Albums.clear(document.getElementById('gallery_list'));
+ scanForAlbums(true);
+ }
+ gallery_scanning_root = scanning_root;
} else {
- alert('Error: ' + r.cause);
- return;
+ OC.dialogs.alert(t('gallery', 'Error: ') + r.cause, t('gallery', 'Error'));
+ return;
}
- $('#g-dialog-settings').dialog('close');
});
- }
- },
- {
- text: t('gallery', 'Cancel'),
- click: function() {
- $(this).dialog('close');
- }
- }
- ],
- });
+ });
}
diff --git a/apps/gallery/templates/index.php b/apps/gallery/templates/index.php
index c6373d3b0a2..9bec5db1b91 100644
--- a/apps/gallery/templates/index.php
+++ b/apps/gallery/templates/index.php
@@ -9,7 +9,7 @@ OC_Util::addScript('files_imageviewer', 'jquery.fancybox-1.3.4.pack');
OC_Util::addStyle( 'files_imageviewer', 'jquery.fancybox-1.3.4' );
$l = new OC_L10N('gallery');
?>
-
+<script type="text/javascript">var gallery_scanning_root='<? echo OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'root', '/'); ?>'; var gallery_default_order = '<? echo OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'order', 'ASC'); ?>';</script>
<div id="controls">
<div id="scan">
<div id="scanprogressbar"></div>
@@ -29,40 +29,3 @@ $l = new OC_L10N('gallery');
</div>
<div id="gallery_list">
</div>
-
-<div id="dialog-confirm" title="<?php echo $l->t('Remove confirmation');?>" style="display: none">
- <p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span><?php echo $l->t('Do you want to remove album');?> <span id="albumName"></span>?</p>
-</div>
-
-<div id="dialog-form" title="<?php echo $l->t('Change album name');?>" style="display:none">
- <form>
- <fieldset>
- <label for="name"><?php echo $l->t('New album name');?></label>
- <input type="text" name="name" id="name" class="text ui-widget-content ui-corner-all" />
- </fieldset>
- </form>
-</div>
-
-<div id="g-dialog-settings" title="<?php echo $l->t('Settings');?>" style="display:none">
- <form>
- <fieldset><?php $root = OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'root', '/'); $order = OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'order', 'ASC');?>
- <label for="name"><?php echo $l->t('Scanning root');?></label>
- <input type="text" name="g-scanning-root" id="g-scanning-root" class="text ui-widget-content ui-corner-all" value="<?php echo $root;?>" /><br/>
-
- <label for="sort"><?php echo $l->t('Default sorting'); ?></label>
- <select id="g-display-order">
- <option value="ASC"<?php echo $order=='ASC'?'selected':'';?>><?php echo $l->t('Ascending'); ?></option>
- <option value="DESC"<?php echo $order=='DESC'?'selected':'';?>><?php echo $l->t('Descending'); ?></option>
- </select><br/>
-<!--
- <label for="sort"><?php echo $l->t('Thumbnails size'); ?></label>
- <select>
- <option value="100">100px</option>
- <option value="150">150px</option>
- <option value="200">200px</option>
- </select>
- -->
- </fieldset>
- </form>
-</div>
-
diff --git a/apps/media/css/music.css b/apps/media/css/music.css
index 07173624018..164a6c62ae6 100644
--- a/apps/media/css/music.css
+++ b/apps/media/css/music.css
@@ -22,6 +22,7 @@ div.jp-volume-bar-value { background:#ccc; width:0; height:0.4em; }
#leftcontent img.remove { display:none; float:right; cursor:pointer; opacity: 0; }
#leftcontent li:hover img.remove { display:inline; opacity: .3; }
#leftcontent li div.label { float: left; width: 200px; overflow: hidden; text-overflow: ellipsis; }
+#rightcontent { overflow: auto; }
#playlist li { list-style-type:none; }
.template { display:none; }
.collection_playing { background:#eee; font-weight: bold; }
diff --git a/apps/remoteStorage/appinfo/info.xml b/apps/remoteStorage/appinfo/info.xml
index 1ab55e8c094..1f9618a3334 100644
--- a/apps/remoteStorage/appinfo/info.xml
+++ b/apps/remoteStorage/appinfo/info.xml
@@ -2,7 +2,7 @@
<info>
<id>remoteStorage</id>
<name>remoteStorage compatibility</name>
- <description>Enables your users to use ownCloud as their remote storage for unhosted applications.</description>
+ <description>Enables you to use ownCloud as their remote storage for unhosted applications. This app requires the Webfinger app to be installed and enabled correctly. More info on <a href="http://unhosted.org">the website of the unhosted movement</a>.</description>
<version>0.6</version>
<licence>AGPL or MIT</licence>
<author>Michiel de Jong</author>
diff --git a/core/css/styles.css b/core/css/styles.css
index f5a181c4529..1c50df9e58b 100644
--- a/core/css/styles.css
+++ b/core/css/styles.css
@@ -131,3 +131,9 @@ li.error { width:640px; margin:4em auto; padding:1em 1em 1em 4em; background:#ff
.separator { display: inline; border-left: 1px solid #d3d3d3; border-right: 1px solid #fff; height: 10px; width:0px; margin: 4px; }
a.bookmarklet { background-color: #ddd; border:1px solid #ccc; padding: 5px;padding-top: 0px;padding-bottom: 2px; text-decoration: none; margin-top: 5px }
+
+/* ---- DIALOGS ---- */
+
+#dirtree {width: 100%;}
+#filelist {height: 270px; overflow:scroll; background-color: white;}
+.filepicker_element_selected { background-color: lightblue;}
diff --git a/core/js/eventsource.js b/core/js/eventsource.js
index dece1a69d04..08259e02cae 100644
--- a/core/js/eventsource.js
+++ b/core/js/eventsource.js
@@ -33,8 +33,12 @@
*/
OC.EventSource=function(src,data){
var dataStr='';
- for(name in data){
- dataStr+=name+'='+encodeURIComponent(data[name])+'&';
+ this.typelessListeners=[];
+ this.listeners={};
+ if(data){
+ for(name in data){
+ dataStr+=name+'='+encodeURIComponent(data[name])+'&';
+ }
}
if(!this.useFallBack && typeof EventSource !='undefined'){
this.source=new EventSource(src+'?'+dataStr);
@@ -42,7 +46,7 @@ OC.EventSource=function(src,data){
for(var i=0;i<this.typelessListeners.length;i++){
this.typelessListeners[i](JSON.parse(e.data));
}
- }
+ }.bind(this);
}else{
iframeId='oc_eventsource_iframe_'+OC.EventSource.iframeCount;
OC.EventSource.fallBackSources[OC.EventSource.iframeCount]=this;
@@ -64,7 +68,7 @@ OC.EventSource=function(src,data){
OC.EventSource.fallBackSources=[];
OC.EventSource.iframeCount=0;//number of fallback iframes
OC.EventSource.fallBackCallBack=function(id,type,data){
- OC.EventSource.fallBackSources[id].fallBackCallBack(type,JSON.parse(data));
+ OC.EventSource.fallBackSources[id].fallBackCallBack(type,data);
}
OC.EventSource.prototype={
typelessListeners:[],
diff --git a/core/js/js.js b/core/js/js.js
index df1b5c6ce76..44b4f503b8c 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -126,7 +126,13 @@ OC={
});
}
},
- dialogs:OCdialogs
+ dialogs:OCdialogs,
+ mtime2date:function(mtime) {
+ mtime = parseInt(mtime);
+ var date = new Date(1000*mtime);
+ var ret = date.getDate()+'.'+(date.getMonth()+1)+'.'+date.getFullYear()+', '+date.getHours()+':'+date.getMinutes();
+ return ret;
+ }
};
OC.search.customResults={};
OC.search.currentResult=-1;
diff --git a/core/js/oc-dialogs.js b/core/js/oc-dialogs.js
index c11ac13332b..d40c433bda2 100644
--- a/core/js/oc-dialogs.js
+++ b/core/js/oc-dialogs.js
@@ -17,7 +17,6 @@
* 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(bartek): add select option in form
*/
/**
@@ -30,9 +29,9 @@ OCdialogs = {
* @param title dialog title
* @param callback which will be triggered when user press OK
*/
- alert:function(text, title, callback) {
+ alert:function(text, title, callback, modal) {
var content = '<p><span class="ui-icon ui-icon-alert"></span>'+text+'</p>';
- OCdialogs.message(content, title, OCdialogs.ALERT_DIALOG, OCdialogs.OK_BUTTON, callback);
+ OCdialogs.message(content, title, OCdialogs.ALERT_DIALOG, OCdialogs.OK_BUTTON, callback, modal);
},
/**
* displays info dialog
@@ -40,9 +39,9 @@ OCdialogs = {
* @param title dialog title
* @param callback which will be triggered when user press OK
*/
- info:function(text, title, callback) {
+ info:function(text, title, callback, modal) {
var content = '<p><span class="ui-icon ui-icon-info"></span>'+text+'</p>';
- OCdialogs.message(content, title, OCdialogs.ALERT_DIALOG, OCdialogs.OK_BUTTON, callback);
+ OCdialogs.message(content, title, OCdialogs.ALERT_DIALOG, OCdialogs.OK_BUTTON, callback, modal);
},
/**
* displays confirmation dialog
@@ -50,9 +49,9 @@ OCdialogs = {
* @param title dialog title
* @param callback which will be triggered when user press YES or NO (true or false would be passed to callback respectively)
*/
- confirm:function(text, title, callback) {
+ confirm:function(text, title, callback, modal) {
var content = '<p><span class="ui-icon ui-icon-notice"></span>'+text+'</p>';
- OCdialogs.message(content, title, OCdialogs.ALERT_DIALOG, OCdialogs.YES_NO_BUTTONS, callback);
+ OCdialogs.message(content, title, OCdialogs.ALERT_DIALOG, OCdialogs.YES_NO_BUTTONS, callback, modal);
},
/**
* prompt for user input
@@ -60,9 +59,9 @@ OCdialogs = {
* @param title dialog title
* @param callback which will be triggered when user press OK (input text will be passed to callback)
*/
- prompt:function(text, title, default_value, callback) {
+ prompt:function(text, title, default_value, callback, modal) {
var content = '<p><span class="ui-icon ui-icon-pencil"></span>'+text+':<br/><input type="text" id="oc-dialog-prompt-input" value="'+default_value+'" style="width:90%"></p>';
- OCdialogs.message(content, title, OCdialogs.PROMPT_DIALOG, OCdialogs.OK_CANCEL_BUTTONS, callback);
+ OCdialogs.message(content, title, OCdialogs.PROMPT_DIALOG, OCdialogs.OK_CANCEL_BUTTONS, callback, modal);
},
/**
* prompt user for input with custom form
@@ -71,7 +70,7 @@ OCdialogs = {
* @param title dialog title
* @param callback which will be triggered when user press OK (user answers will be passed to callback in following format: [{name:'return name', value: 'user value'},...])
*/
- form:function(fields, title, callback) {
+ form:function(fields, title, callback, modal) {
var content = '<table>';
for (var a in fields) {
content += '<tr><td>'+fields[a].text+'</td><td>';
@@ -84,16 +83,63 @@ OCdialogs = {
} else content += '>';
} else if (type == 'text' || type == 'password' && fields[a].value)
content += ' value="'+fields[a].value+'">';
+ } else if (type == 'select') {
+ content += '<select name="'+fields[a].name+'"';
+ if (fields[a].value != undefined)
+ content += ' value="'+fields[a].value+'"';
+ content += '>';
+ for (var o in fields[a].options)
+ content += '<option value="'+fields[a].options[o].value+'">'+fields[a].options[o].text+'</option>';
+ content += '</select>';
}
- content += "</td></tr>"
+ content += '</td></tr>';
}
- content += "</table>";
- OCdialogs.message(content, title, OCdialogs.FORM_DIALOG, OCdialogs.OK_CANCEL_BUTTONS, callback);
+ content += '</table>';
+ OCdialogs.message(content, title, OCdialogs.FORM_DIALOG, OCdialogs.OK_CANCEL_BUTTONS, callback, modal);
},
- message:function(content, title, dialog_type, buttons, callback) {
+ filepicker:function(title, callback, multiselect, mimetype_filter, modal) {
+ var c_name = 'oc-dialog-'+OCdialogs.dialogs_counter+'-content';
+ var c_id = '#'+c_name;
+ var d = '<div id="'+c_name+'" title="'+title+'"><select id="dirtree"><option value="0">'+OC.currentUser+'</option></select><div id="filelist"></div></div>';
+ if (!modal) modal = false;
+ if (!multiselect) multiselect = false;
+ $('body').append(d);
+ $(c_id + ' #dirtree').focus(function() { var t = $(this); t.data('oldval', t.val())})
+ .change({dcid: c_id}, OC.dialogs.handleTreeListSelect);
+ $(c_id).ready(function(){
+ $.getJSON(OC.webroot+'/files/ajax/rawlist.php', function(r){OC.dialogs.fillFilePicker(r, c_id, callback)});
+ }).data('multiselect', multiselect);
+ // build buttons
+ var b = [
+ {text: t('dialogs', 'Choose'), click: function(){
+ if (callback != undefined) {
+ var p;
+ if ($(c_id).data('multiselect') == true) {
+ p = [];
+ $(c_id+' .filepicker_element_selected #filename').each(function(i, elem) {
+ p.push(($(c_id).data('path')?$(c_id).data('path'):'')+'/'+$(elem).text());
+ });
+ } else {
+ var p = $(c_id).data('path');
+ if (p == undefined) p = '';
+ p = p+'/'+$(c_id+' .filepicker_element_selected #filename').text()
+ }
+ callback(p);
+ $(c_id).dialog('close');
+ }
+ }
+ },
+ {text: t('dialogs', 'Cancel'), click: function(){$(c_id).dialog('close'); }}
+ ];
+ $(c_id).dialog({width: 4*$(document).width()/9, height: 400, modal: modal, buttons: b});
+ OCdialogs.dialogs_counter++;
+ },
+ // guts, dont use, dont touch
+ message:function(content, title, dialog_type, buttons, callback, modal) {
var c_name = 'oc-dialog-'+OCdialogs.dialogs_counter+'-content';
var c_id = '#'+c_name;
var d = '<div id="'+c_name+'" title="'+title+'">'+content+'</div>';
+ if (modal == undefined) modal = false;
$('body').append(d);
var b = [];
switch (buttons) {
@@ -107,7 +153,7 @@ OCdialogs = {
var f;
switch(dialog_type) {
case OCdialogs.ALERT_DIALOG:
- f = function(){$(c_id).dialog('close'); };
+ f = function(){$(c_id).dialog('close'); callback();};
break;
case OCdialogs.PROMPT_DIALOG:
f = function(){OCdialogs.prompt_ok_handler(callback, c_id)};
@@ -120,7 +166,7 @@ OCdialogs = {
break;
}
var possible_height = ($('tr', d).size()+1)*30;
- $(c_id).dialog({width: 4*$(document).width()/9, height: possible_height + 120, modal: false, buttons: b});
+ $(c_id).dialog({width: 4*$(document).width()/9, height: possible_height + 120, modal: modal, buttons: b});
OCdialogs.dialogs_counter++;
},
// dialogs buttons types
@@ -144,7 +190,7 @@ OCdialogs = {
if (callback != undefined) {
var r = [];
var c = 0;
- $(c_id + ' input').each(function(i, elem) {
+ $(c_id + ' input, '+c_id+' select').each(function(i, elem) {
r[c] = {name: $(elem).attr('name'), value: OCdialogs.determineValue(elem)};
c++;
});
@@ -153,5 +199,44 @@ OCdialogs = {
} else {
$(c_id).dialog('close');
}
+ },
+ fillFilePicker:function(r, dialog_content_id) {
+ var entry_template = '<div onclick="javascript:OC.dialogs.handlePickerClick(this, \'*ENTRYNAME*\',\''+dialog_content_id+'\')" data="*ENTRYTYPE*"><img src="*MIMETYPEICON*" style="margin-right:1em;"><span id="filename">*NAME*</span><div style="float:right;margin-right:1em;">*LASTMODDATE*</div></div>';
+ var names = '';
+ for (var a in r.data) {
+ names += entry_template.replace('*LASTMODDATE*', OC.mtime2date(r.data[a].mtime)).replace('*NAME*', r.data[a].name).replace('*MIMETYPEICON*', OC.webroot+'/core/img/filetypes/'+(r.data[a].type=='dir'?'folder':r.data[a].mimetype.replace('/','-'))+'.png').replace('*ENTRYNAME*', r.data[a].name).replace('*ENTRYTYPE*', r.data[a].type);
+ }
+ $(dialog_content_id + ' #filelist').html(names);
+ },
+ handleTreeListSelect:function(event) {
+ var newval = parseInt($(this).val());
+ var oldval = parseInt($(this).data('oldval'));
+ while (newval != oldval && oldval > 0) {
+ $('option:last', this).remove();
+ $('option:last', this).attr('selected','selected');
+ oldval--;
+ }
+ var skip_first = true;
+ var path = '';
+ $(this).children().each(function(i, element) { if (skip_first) {skip_first = false; return; }path += '/'+$(element).text(); });
+ $(event.data.dcid).data('path', path);
+ $.getJSON(OC.webroot+'/files/ajax/rawlist.php', {dir: path}, function(r){OC.dialogs.fillFilePicker(r, event.data.dcid)});
+ },
+ // this function is in early development state, please dont use it unlsess you know what you are doing
+ handlePickerClick:function(element, name, dcid) {
+ var p = $(dcid).data('path');
+ if (p == undefined) p = '';
+ p = p+'/'+name;
+ if ($(element).attr('data') == 'file'){
+ if ($(dcid).data('multiselect') != true)
+ $(dcid+' .filepicker_element_selected').removeClass('filepicker_element_selected');
+ $(element).toggleClass('filepicker_element_selected');
+ return;
+ }
+ $(dcid).data('path', p);
+ $(dcid + ' #dirtree option:last').removeAttr('selected');
+ var newval = parseInt($(dcid + ' #dirtree option:last').val())+1;
+ $(dcid + ' #dirtree').append('<option selected="selected" value="'+newval+'">'+name+'</option>');
+ $.getJSON(OC.webroot+'/files/ajax/rawlist.php', {dir: p}, function(r){OC.dialogs.fillFilePicker(r, dcid)});
}
};
diff --git a/core/templates/login.php b/core/templates/login.php
index 6c0a7a12227..4ba92221a7d 100644
--- a/core/templates/login.php
+++ b/core/templates/login.php
@@ -1,3 +1,4 @@
+<!--[if IE 8]><style>input[type="checkbox"]{padding:0;}</style><![endif]-->
<form action="index.php" method="post">
<fieldset>
<?php if(!empty($_['redirect'])) { echo '<input type="hidden" name="redirect_url" value="'.$_['redirect'].'" />'; } ?>
@@ -6,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'])?$_POST['user'].'"':'" autofocus'; ?> autocomplete="off" required />
+ <input type="text" name="user" id="user" value="<?php echo !empty($_POST['user'])?htmlentities($_POST['user']).'"':'" autofocus'; ?> autocomplete="off" required />
</p>
<p class="infield">
<label for="password" class="infield"><?php echo $l->t( 'Password' ); ?></label>
diff --git a/db_structure.xml b/db_structure.xml
index 5eef44d8e84..2df218d359c 100644
--- a/db_structure.xml
+++ b/db_structure.xml
@@ -65,6 +65,14 @@
</field>
<field>
+ <name>path_hash</name>
+ <type>text</type>
+ <default></default>
+ <notnull>true</notnull>
+ <length>32</length>
+ </field>
+
+ <field>
<name>parent</name>
<type>integer</type>
<default>
@@ -79,7 +87,7 @@
<default>
</default>
<notnull>true</notnull>
- <length>512</length>
+ <length>300</length>
</field>
<field>
@@ -159,14 +167,13 @@
<length>1</length>
</field>
- <!--<index>
- <name>fscache_path_index</name>
- <unique>true</unique>
+ <index>
+ <name>fscache_path_hash_index</name>
<field>
- <name>path</name>
+ <name>path_hash</name>
<sorting>ascending</sorting>
</field>
- </index>-->
+ </index>
<index>
<name>parent_index</name>
@@ -177,6 +184,14 @@
</index>
<index>
+ <name>name_index</name>
+ <field>
+ <name>name</name>
+ <sorting>ascending</sorting>
+ </field>
+ </index>
+
+ <index>
<name>parent_name_index</name>
<field>
<name>parent</name>
diff --git a/files/ajax/download.php b/files/ajax/download.php
index 198069f3fa1..39852613ab9 100644
--- a/files/ajax/download.php
+++ b/files/ajax/download.php
@@ -21,6 +21,9 @@
*
*/
+// only need filesystem apps
+$RUNTIME_APPTYPES=array('filesystem');
+
// Init owncloud
require_once('../../lib/base.php');
diff --git a/files/ajax/list.php b/files/ajax/list.php
index 8a414827e1c..ec9ab7342dd 100644
--- a/files/ajax/list.php
+++ b/files/ajax/list.php
@@ -1,5 +1,8 @@
<?php
+// only need filesystem apps
+$RUNTIME_APPTYPES=array('filesystem');
+
// Init owncloud
require_once('../../lib/base.php');
diff --git a/files/ajax/mimeicon.php b/files/ajax/mimeicon.php
index 8724016b3a1..ff72ba0f5b7 100644
--- a/files/ajax/mimeicon.php
+++ b/files/ajax/mimeicon.php
@@ -1,5 +1,8 @@
<?php
+// no need for apps
+$RUNTIME_NOAPPS=false;
+
// Init owncloud
require_once('../../lib/base.php');
diff --git a/files/ajax/rawlist.php b/files/ajax/rawlist.php
new file mode 100644
index 00000000000..0abe81e6725
--- /dev/null
+++ b/files/ajax/rawlist.php
@@ -0,0 +1,23 @@
+<?php
+
+// only need filesystem apps
+$RUNTIME_APPTYPES=array('filesystem');
+
+// Init owncloud
+require_once('../../lib/base.php');
+
+OC_JSON::checkLoggedIn();
+
+// Load the files
+$dir = isset( $_GET['dir'] ) ? $_GET['dir'] : '';
+
+// make filelist
+$files = array();
+foreach( OC_Files::getdirectorycontent( $dir ) as $i ){
+ $i["date"] = OC_Util::formatDate($i["mtime"] );
+ $files[] = $i;
+}
+
+OC_JSON::success(array('data' => $files));
+
+?>
diff --git a/files/ajax/scan.php b/files/ajax/scan.php
index 565275911b4..db09b7d5c64 100644
--- a/files/ajax/scan.php
+++ b/files/ajax/scan.php
@@ -17,6 +17,7 @@ if($force or !OC_FileCache::inCache('')){
if(!$checkOnly){
OC_DB::beginTransaction();
OC_FileCache::scan('',$eventSource);
+ OC_FileCache::clean();
OC_DB::commit();
$eventSource->send('success',true);
}else{
diff --git a/files/css/files.css b/files/css/files.css
index 512e462cb6f..9e950517b82 100644
--- a/files/css/files.css
+++ b/files/css/files.css
@@ -64,8 +64,8 @@ table td.filename .nametext { width:60%; }
table td.filename form { float:left; font-size:.85em; }
table thead.fixed tr{ position:fixed; top:6.5em; z-index:49; -moz-box-shadow:0 -3px 7px #ddd; -webkit-box-shadow:0 -3px 7px #ddd; box-shadow:0 -3px 7px #ddd; }
table thead.fixed { height:2em; }
-#fileList tr td.filename>input[type=checkbox]:first-child { opacity:0; float:left; margin:.7em 0 0 1em; /* bigger clickable area doesn’t work in FF width:2.8em; height:2.4em;*/ -webkit-transition:opacity 500ms; -moz-transition:opacity 500ms; -o-transition:opacity 500ms; transition:opacity 500ms; }
-#fileList tr td.filename>input[type="checkbox"]:hover:first-child { opacity:.8; }
+#fileList tr td.filename>input[type=checkbox]:first-child { opacity:0; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; float:left; margin:.7em 0 0 1em; /* bigger clickable area doesn’t work in FF width:2.8em; height:2.4em;*/ -webkit-transition:opacity 500ms; -moz-transition:opacity 500ms; -o-transition:opacity 500ms; transition:opacity 500ms; }
+#fileList tr td.filename>input[type="checkbox"]:hover:first-child { opacity:.8; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=80)"; }
#fileList tr td.filename>input[type="checkbox"]:checked:first-child { opacity:1; }
#fileList tr td.filename { -webkit-transition:background-image 500ms; -moz-transition:background-image 500ms; -o-transition:background-image 500ms; transition:background-image 500ms; }
#select_all { float:left; margin:.3em 0.6em 0 .5em; }
diff --git a/files/js/files.js b/files/js/files.js
index 539d5598899..df9f45a7af4 100644
--- a/files/js/files.js
+++ b/files/js/files.js
@@ -98,7 +98,7 @@ $(document).ready(function() {
procesSelection();
});
- $('td.filename input:checkbox').live('click',function(event) {
+ $('td.filename input:checkbox').live('change',function(event) {
if (event.shiftKey) {
var last = $(lastChecked).parent().parent().prevAll().length;
var first = $(this).parent().parent().prevAll().length;
diff --git a/files/templates/index.php b/files/templates/index.php
index da1e58ce137..f591d066d8c 100644
--- a/files/templates/index.php
+++ b/files/templates/index.php
@@ -1,3 +1,4 @@
+<!--[if IE 8]><style>input[type="checkbox"]{padding:0;}table td{position:static !important;}</style><![endif]-->
<div id="controls">
<?php echo($_['breadcrumb']); ?>
<?php if (!isset($_['readonly']) || !$_['readonly']):?>
@@ -62,12 +63,12 @@
</div>
<div id="scanning-message">
<h3>
- <?php echo $l->t('Files are being scanned, please wait.');?> <span id='scan-count'></spann>
+ <?php echo $l->t('Files are being scanned, please wait.');?> <span id='scan-count'></span>
</h3>
<p>
- <?php echo $l->t('Current scanning');?> <span id='scan-current'></spann>
+ <?php echo $l->t('Current scanning');?> <span id='scan-current'></span>
</p>
</div>
<!-- config hints for javascript -->
-<input type="hidden" name="allowZipDownload" id="allowZipDownload" value="<?php echo $_['allowZipDownload']; ?>" /> \ No newline at end of file
+<input type="hidden" name="allowZipDownload" id="allowZipDownload" value="<?php echo $_['allowZipDownload']; ?>" />
diff --git a/files/webdav.php b/files/webdav.php
index 6fae33a8f71..1120973787c 100644
--- a/files/webdav.php
+++ b/files/webdav.php
@@ -26,6 +26,9 @@
// Do not load FS ...
$RUNTIME_NOSETUPFS = true;
+// only need filesystem apps
+$RUNTIME_APPTYPES=array('filesystem');
+
require_once('../lib/base.php');
// Backends
diff --git a/lib/app.php b/lib/app.php
index 3daf539aa21..7d5e8fa91c6 100755
--- a/lib/app.php
+++ b/lib/app.php
@@ -34,16 +34,20 @@ class OC_App{
static private $settingsForms = array();
static private $adminForms = array();
static private $personalForms = array();
+ static private $appInfo = array();
/**
* @brief loads all apps
+ * @param array $types
* @returns true/false
*
* This function walks through the owncloud directory and loads all apps
* it can find. A directory contains an app if the file /appinfo/app.php
* exists.
+ *
+ * if $types is set, only apps of those types will be loaded
*/
- public static function loadApps(){
+ public static function loadApps($types=null){
// Did we allready load everything?
if( self::$init ){
return true;
@@ -51,13 +55,15 @@ class OC_App{
// Our very own core apps are hardcoded
foreach( array('files', 'settings') as $app ){
- require( $app.'/appinfo/app.php' );
+ if(is_null($types)){
+ require( $app.'/appinfo/app.php' );
+ }
}
// The rest comes here
- $apps = OC_Appconfig::getApps();
+ $apps = self::getEnabledApps();
foreach( $apps as $app ){
- if( self::isEnabled( $app )){
+ if(is_null($types) or self::isType($app,$types)){
if(is_file(OC::$APPSROOT.'/apps/'.$app.'/appinfo/app.php')){
require( $app.'/appinfo/app.php' );
}
@@ -71,6 +77,41 @@ class OC_App{
}
/**
+ * check if an app is of a sepcific type
+ * @param string $app
+ * @param string/array $types
+ */
+ public static function isType($app,$types){
+ if(is_string($types)){
+ $types=array($types);
+ }
+ $appData=self::getAppInfo($app);
+ if(!isset($appData['types'])){
+ return false;
+ }
+ $appTypes=$appData['types'];
+ foreach($types as $type){
+ if(array_search($type,$appTypes)!==false){
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * get all enabled apps
+ */
+ public static function getEnabledApps(){
+ $apps=array();
+ $query = OC_DB::prepare( 'SELECT appid FROM *PREFIX*appconfig WHERE configkey = \'enabled\' AND configvalue=\'yes\'' );
+ $result=$query->execute();
+ while($row=$result->fetchRow()){
+ $apps[]=$row['appid'];
+ }
+ return $apps;
+ }
+
+ /**
* @brief checks whether or not an app is enabled
* @param $app app
* @returns true/false
@@ -265,24 +306,36 @@ class OC_App{
/**
* @brief Read app metadata from the info.xml file
* @param string $appid id of the app or the path of the info.xml file
+ * @param boolean path (optional)
* @returns array
*/
- public static function getAppInfo($appid){
- if(is_file($appid)){
+ public static function getAppInfo($appid,$path=false){
+ if($path){
$file=$appid;
}else{
- $file=OC::$APPSROOT.'/apps/'.$appid.'/appinfo/info.xml';
- if(!is_file($file)){
- return array();
+ if(isset(self::$appInfo[$appid])){
+ return self::$appInfo[$appid];
}
+ $file=OC::$APPSROOT.'/apps/'.$appid.'/appinfo/info.xml';
}
$data=array();
$content=file_get_contents($file);
+ if(!$content){
+ return;
+ }
$xml = new SimpleXMLElement($content);
$data['info']=array();
foreach($xml->children() as $child){
- $data[$child->getName()]=(string)$child;
+ if($child->getName()=='types'){
+ $data['types']=array();
+ foreach($child->children() as $type){
+ $data['types'][]=$type->getName();
+ }
+ }else{
+ $data[$child->getName()]=(string)$child;
+ }
}
+ self::$appInfo[$appid]=$data;
return $data;
}
@@ -381,9 +434,8 @@ class OC_App{
*/
public static function updateApps(){
// The rest comes here
- $apps = OC_Appconfig::getApps();
- foreach( $apps as $app ){
- $installedVersion=OC_Appconfig::getValue($app,'installed_version');
+ $versions = self::getAppVersions();
+ foreach( $versions as $app=>$installedVersion ){
$appInfo=OC_App::getAppInfo($app);
if (isset($appInfo['version'])) {
$currentVersion=$appInfo['version'];
@@ -396,6 +448,19 @@ class OC_App{
}
/**
+ * get the installed version of all papps
+ */
+ public static function getAppVersions(){
+ $versions=array();
+ $query = OC_DB::prepare( 'SELECT appid, configvalue FROM *PREFIX*appconfig WHERE configkey = \'installed_version\'' );
+ $result = $query->execute();
+ while($row = $result->fetchRow()){
+ $versions[$row['appid']]=$row['configvalue'];
+ }
+ return $versions;
+ }
+
+ /**
* update the database for the app and call the update script
* @param string appid
*/
diff --git a/lib/base.php b/lib/base.php
index b07ac5af416..a4a94e86968 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -229,6 +229,39 @@ 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.6.4.min" );
+ OC_Util::addScript( "jquery-ui-1.8.16.custom.min" );
+ OC_Util::addScript( "jquery-showpassword" );
+ OC_Util::addScript( "jquery.infieldlabel.min" );
+ OC_Util::addScript( "jquery-tipsy" );
+ OC_Util::addScript( "oc-dialogs" );
+ OC_Util::addScript( "js" );
+ OC_Util::addScript( "eventsource" );
+ OC_Util::addScript( "config" );
+ //OC_Util::addScript( "multiselect" );
+ OC_Util::addScript('search','result');
+ OC_Util::addStyle( "styles" );
+ OC_Util::addStyle( "multiselect" );
+ OC_Util::addStyle( "jquery-ui-1.8.16.custom" );
+ OC_Util::addStyle( "jquery-tipsy" );
+ }
+
+ public static function initSession() {
+ ini_set('session.cookie_httponly','1;');
+ session_start();
+ }
+
public static function init(){
// register autoloader
spl_autoload_register(array('OC','autoload'));
@@ -244,6 +277,24 @@ class OC{
date_default_timezone_set('Europe/Berlin');
ini_set('arg_separator.output','&amp;');
+ //try to configure php to enable big file uploads.
+ //this doesn´t work always depending on the webserver and php configuration.
+ //Let´s try to overwrite some defaults anyways
+
+ //try to set the maximum execution time to 60min
+ @set_time_limit(3600);
+ @ini_set('max_execution_time',3600);
+ @ini_set('max_input_time',3600);
+
+ //try to set the maximum filesize to 10G
+ @ini_set('upload_max_filesize','10G');
+ @ini_set('post_max_size','10G');
+ @ini_set('file_uploads','50');
+
+ //try to set the session lifetime to 60min
+ @ini_set('gc_maxlifetime','3600');
+
+
//set http auth headers for apache+php-cgi work around
if (isset($_SERVER['HTTP_AUTHORIZATION']) && preg_match('/Basic\s+(.*)$/i', $_SERVER['HTTP_AUTHORIZATION'], $matches))
{
@@ -270,37 +321,10 @@ class OC{
self::checkInstalled();
self::checkSSL();
- self::checkUpgrade();
-
- ini_set('session.cookie_httponly','1;');
- session_start();
- // 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.6.4.min" );
- OC_Util::addScript( "jquery-ui-1.8.16.custom.min" );
- OC_Util::addScript( "jquery-showpassword" );
- OC_Util::addScript( "jquery.infieldlabel.min" );
- OC_Util::addScript( "jquery-tipsy" );
- OC_Util::addScript( "oc-dialogs" );
- OC_Util::addScript( "js" );
- OC_Util::addScript( "eventsource" );
- OC_Util::addScript( "config" );
- //OC_Util::addScript( "multiselect" );
- OC_Util::addScript('search','result');
- OC_Util::addStyle( "styles" );
- OC_Util::addStyle( "multiselect" );
- OC_Util::addStyle( "jquery-ui-1.8.16.custom" );
- OC_Util::addStyle( "jquery-tipsy" );
+ self::initSession();
+ self::initTemplateEngine();
+ self::checkUpgrade();
$errors=OC_Util::checkServer();
if(count($errors)>0) {
@@ -333,8 +357,13 @@ class OC{
// Load Apps
// This includes plugins for users and filesystems as well
global $RUNTIME_NOAPPS;
+ global $RUNTIME_APPTYPES;
if(!$RUNTIME_NOAPPS ){
- OC_App::loadApps();
+ if($RUNTIME_APPTYPES){
+ OC_App::loadApps($RUNTIME_APPTYPES);
+ }else{
+ OC_App::loadApps();
+ }
}
//make sure temporary files are cleaned up
diff --git a/lib/db.php b/lib/db.php
index 9fab51edfcd..a0fb6c385d8 100644
--- a/lib/db.php
+++ b/lib/db.php
@@ -318,9 +318,6 @@ class OC_DB {
// Make changes and save them to an in-memory file
$file2 = 'static://db_scheme';
- if($file2 == ''){
- die('could not create tempfile in get_temp_dir() - aborting');
- }
$content = str_replace( '*dbname*', $CONFIG_DBNAME, $content );
$content = str_replace( '*dbprefix*', $CONFIG_DBTABLEPREFIX, $content );
if( $CONFIG_DBTYPE == 'pgsql' ){ //mysql support it too but sqlite doesn't
diff --git a/lib/eventsource.php b/lib/eventsource.php
index 523f72403c3..cf10660b94c 100644
--- a/lib/eventsource.php
+++ b/lib/eventsource.php
@@ -32,6 +32,7 @@ class OC_EventSource{
private $fallBackId=0;
public function __construct(){
+ @ob_end_clean();
header('Cache-Control: no-cache');
$this->fallback=isset($_GET['fallback']) and $_GET['fallback']=='true';
if($this->fallback){
@@ -58,7 +59,7 @@ class OC_EventSource{
$type=null;
}
if($this->fallback){
- $response='<script type="text/javascript">window.parent.OC.EventSource.fallBackCallBack('.$this->fallBackId.',"'.$type.'","'.json_encode($data).'")</script>'.PHP_EOL;
+ $response='<script type="text/javascript">window.parent.OC.EventSource.fallBackCallBack('.$this->fallBackId.',"'.$type.'",'.json_encode($data).')</script>'.PHP_EOL;
echo $response;
}else{
if($type){
diff --git a/lib/filecache.php b/lib/filecache.php
index 280a9929db0..4a4183cbdb5 100644
--- a/lib/filecache.php
+++ b/lib/filecache.php
@@ -59,8 +59,8 @@ class OC_FileCache{
$root='';
}
$path=$root.$path;
- $query=OC_DB::prepare('SELECT ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE path=?');
- $result=$query->execute(array($path))->fetchRow();
+ $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{
@@ -111,8 +111,8 @@ class OC_FileCache{
}
$mimePart=dirname($data['mimetype']);
$user=OC_User::getUser();
- $query=OC_DB::prepare('INSERT INTO *PREFIX*fscache(parent, name, path, size, mtime, ctime, mimetype, mimepart,user,writable,encrypted,versioned) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)');
- $result=$query->execute(array($parent,basename($path),$path,$data['size'],$data['mtime'],$data['ctime'],$data['mimetype'],$mimePart,$user,$data['writable'],$data['encrypted'],$data['versioned']));
+ $query=OC_DB::prepare('INSERT INTO *PREFIX*fscache(parent, name, path, path_hash, size, mtime, ctime, mimetype, mimepart,user,writable,encrypted,versioned) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)');
+ $result=$query->execute(array($parent,basename($path),$path,md5($path),$data['size'],$data['mtime'],$data['ctime'],$data['mimetype'],$mimePart,$user,$data['writable'],$data['encrypted'],$data['versioned']));
if(OC_DB::isError($result)){
OC_Log::write('files','error while writing file('.$path.') to cache',OC_Log::ERROR);
}
@@ -162,8 +162,8 @@ class OC_FileCache{
$oldPath=$root.$oldPath;
$newPath=$root.$newPath;
$newParent=self::getParentId($newPath);
- $query=OC_DB::prepare('UPDATE *PREFIX*fscache SET parent=? ,name=?, path=? WHERE path=?');
- $query->execute(array($newParent,basename($newPath),$newPath,$oldPath));
+ $query=OC_DB::prepare('UPDATE *PREFIX*fscache SET parent=? ,name=?, path=?, path_hash=? WHERE path_hash=?');
+ $query->execute(array($newParent,basename($newPath),$newPath,md5($newPath),md5($oldPath)));
}
/**
@@ -285,12 +285,12 @@ class OC_FileCache{
* @return int
*/
private static function getFileId($path){
- $query=OC_DB::prepare('SELECT id FROM *PREFIX*fscache WHERE 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;
}
- $result=$query->execute(array($path));
+ $result=$query->execute(array(md5($path)));
if(OC_DB::isError($result)){
OC_Log::write('files','error while getting file id of '.$path,OC_Log::ERROR);
return -1;
@@ -367,8 +367,8 @@ class OC_FileCache{
}
}
$path=$root.$path;
- $query=OC_DB::prepare('SELECT ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE path=?');
- $result=$query->execute(array($path))->fetchRow();
+ $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]);
@@ -389,8 +389,8 @@ class OC_FileCache{
}
}
$path=$root.$path;
- $query=OC_DB::prepare('SELECT size FROM *PREFIX*fscache WHERE path=?');
- $result=$query->execute(array($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
@@ -469,6 +469,10 @@ class OC_FileCache{
* @param string root (optionak)
*/
public static function scan($path,$eventSource=false,&$count=0,$root=''){
+ if($eventSource){
+ $eventSource->send('scanning',array('file'=>$path,'count'=>$count));
+ }
+ $lastSend=$count;
if(!$root){
$view=OC_Filesystem::getView();
}else{
@@ -482,13 +486,14 @@ class OC_FileCache{
if($filename != '.' and $filename != '..'){
$file=$path.'/'.$filename;
if($view->is_dir($file.'/')){
- if($eventSource){
- $eventSource->send('scanning',array('file'=>$file,'count'=>$count));
- }
self::scan($file,$eventSource,$count,$root);
}else{
$totalSize+=self::scanFile($file,$root);
$count++;
+ if($count>$lastSend+25 and $eventSource){
+ $lastSend=$count;
+ $eventSource->send('scanning',array('file'=>$path,'count'=>$count));
+ }
}
}
}
@@ -579,8 +584,8 @@ class OC_FileCache{
$mtime=$view->filemtime($path);
$isDir=$view->is_dir($path);
$path=$root.$path;
- $query=OC_DB::prepare('SELECT mtime FROM *PREFIX*fscache WHERE path=?');
- $result=$query->execute(array($path));
+ $query=OC_DB::prepare('SELECT mtime FROM *PREFIX*fscache WHERE path_hash=?');
+ $result=$query->execute(array(md5($path)));
if($row=$result->fetchRow()){
$cachedMTime=$row['mtime'];
return ($mtime>$cachedMTime);
@@ -637,6 +642,14 @@ class OC_FileCache{
self::fileSystemWatcherWrite(array('path'=>$path),$root);
}
}
+
+ /**
+ * clean old pre-path_hash entries
+ */
+ public static function clean(){
+ $query=OC_DB::prepare('DELETE FROM *PREFIX*fscache WHERE LENGTH(path_hash)<30');
+ $query->execute();
+ }
}
//watch for changes and try to keep the cache up to date
diff --git a/lib/filestorage/local.php b/lib/filestorage/local.php
index 688501aee90..bd757f52ce7 100644
--- a/lib/filestorage/local.php
+++ b/lib/filestorage/local.php
@@ -86,6 +86,10 @@ class OC_Filestorage_Local extends OC_Filestorage{
return $this->delTree($path);
}
public function rename($path1,$path2){
+ if (!$this->is_writable($path1)) {
+ OC_Log::write('core','unable to rename, file is not writable : '.$path1,OC_Log::ERROR);
+ return false;
+ }
if(! $this->file_exists($path1)){
OC_Log::write('core','unable to rename, file does not exists : '.$path1,OC_Log::ERROR);
return false;
diff --git a/lib/filesystemview.php b/lib/filesystemview.php
index 39e47975b28..9d530c7ad63 100644
--- a/lib/filesystemview.php
+++ b/lib/filesystemview.php
@@ -137,13 +137,16 @@ class OC_FilesystemView {
}
public function readfile($path){
$handle=$this->fopen($path,'r');
- $chunkSize = 1024*1024;// 1 MB chunks
- while (!feof($handle)) {
- echo fread($handle, $chunkSize);
- @ob_flush();
- flush();
+ if ($handle) {
+ $chunkSize = 1024*1024;// 1 MB chunks
+ while (!feof($handle)) {
+ echo fread($handle, $chunkSize);
+ @ob_flush();
+ flush();
+ }
+ return $this->filesize($path);
}
- return $this->filesize($path);
+ return false;
}
public function is_readable($path){
return $this->basicOperation('is_readable',$path);
@@ -189,7 +192,7 @@ class OC_FilesystemView {
return $this->basicOperation('unlink',$path,array('delete'));
}
public function rename($path1,$path2){
- if(OC_FileProxy::runPreProxies('rename',$path1,$path2) and $this->is_writable($path1) and OC_Filesystem::isValidPath($path2)){
+ if(OC_FileProxy::runPreProxies('rename',$path1,$path2) and OC_Filesystem::isValidPath($path2)){
$run=true;
OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_rename, array( OC_Filesystem::signal_param_oldpath => $path1 , OC_Filesystem::signal_param_newpath=>$path2, OC_Filesystem::signal_param_run => &$run));
if($run){
diff --git a/lib/helper.php b/lib/helper.php
index 66f31d929be..efff00c2fe6 100755
--- a/lib/helper.php
+++ b/lib/helper.php
@@ -432,6 +432,19 @@ class OC_Helper {
self::$tmpFiles[]=$file;
return $file;
}
+
+ /**
+ * create a temporary folder with an unique filename
+ * @return string
+ *
+ * temporary files are automatically cleaned up after the script is finished
+ */
+ public static function tmpFolder(){
+ $path=get_temp_dir().'/'.md5(time().rand());
+ mkdir($path);
+ self::$tmpFiles[]=$path;
+ return $path.'/';
+ }
/**
* remove all files created by self::tmpFile
@@ -439,7 +452,7 @@ class OC_Helper {
public static function cleanTmp(){
foreach(self::$tmpFiles as $file){
if(file_exists($file)){
- unlink($file);
+ self::rmdirr($file);
}
}
}
diff --git a/lib/installer.php b/lib/installer.php
index 2a9676998f6..38e17130e3c 100644
--- a/lib/installer.php
+++ b/lib/installer.php
@@ -62,7 +62,7 @@ class OC_Installer{
//download the file if necesary
if($data['source']=='http'){
- $path=OC_Helper::tmpFile('.zip');
+ $path=OC_Helper::tmpFile();
if(!isset($data['href'])){
OC_Log::write('core','No href specified when installing app from http',OC_Log::ERROR);
return false;
@@ -76,14 +76,24 @@ class OC_Installer{
$path=$data['path'];
}
+ //detect the archive type
+ $mime=OC_Helper::getMimeType($path);
+ if($mime=='application/zip'){
+ rename($path,$path.'.zip');
+ $path.='.zip';
+ }elseif($mime=='application/x-gzip'){
+ rename($path,$path.'.tgz');
+ $path.='.tgz';
+ }else{
+ OC_Log::write('core','Archives of type '.$mime.' are not supported',OC_Log::ERROR);
+ return false;
+ }
+
//extract the archive in a temporary folder
- $extractDir=tempnam(get_temp_dir(),'oc_installer_uncompressed_');
- unlink($extractDir);
+ $extractDir=OC_Helper::tmpFolder();
mkdir($extractDir);
- $zip = new ZipArchive;
- if($zip->open($path)===true){
- $zip->extractTo($extractDir);
- $zip->close();
+ if($archive=OC_Archive::open($path)){
+ $archive->extract($extractDir);
} else {
OC_Log::write('core','Failed to open archive when installing app',OC_Log::ERROR);
OC_Helper::rmdirr($extractDir);
@@ -95,6 +105,17 @@ class OC_Installer{
//load the info.xml file of the app
if(!is_file($extractDir.'/appinfo/info.xml')){
+ //try to find it in a subdir
+ $dh=opendir($extractDir);
+ while($folder=readdir($dh)){
+ if(substr($folder,0,1)!='.' and is_dir($extractDir.'/'.$folder)){
+ if(is_file($extractDir.'/'.$folder.'/appinfo/info.xml')){
+ $extractDir.='/'.$folder;
+ }
+ }
+ }
+ }
+ if(!is_file($extractDir.'/appinfo/info.xml')){
OC_Log::write('core','App does not provide an info.xml file',OC_Log::ERROR);
OC_Helper::rmdirr($extractDir);
if($data['source']=='http'){
@@ -102,7 +123,7 @@ class OC_Installer{
}
return false;
}
- $info=OC_App::getAppInfo($extractDir.'/appinfo/info.xml');
+ $info=OC_App::getAppInfo($extractDir.'/appinfo/info.xml',true);
$basedir=OC::$APPSROOT.'/apps/'.$info['id'];
//check if an app with the same id is already installed
@@ -275,7 +296,7 @@ class OC_Installer{
if(is_file(OC::$APPSROOT."/apps/$app/appinfo/install.php")){
include(OC::$APPSROOT."/apps/$app/appinfo/install.php");
}
- $info=OC_App::getAppInfo(OC::$APPSROOT."/apps/$app/appinfo/info.xml");
+ $info=OC_App::getAppInfo($app);
OC_Appconfig::setValue($app,'installed_version',$info['version']);
return $info;
}
diff --git a/lib/log.php b/lib/log.php
index 4e450a027f5..8bb2839be66 100644
--- a/lib/log.php
+++ b/lib/log.php
@@ -1,78 +1,39 @@
<?php
/**
- * ownCloud
- *
- * @author Robin Appelman
- * @copyright 2012 Robin Appelman icewind1991@gmail.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/>.
- *
+ * 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.
*/
/**
- *logging utilities
+ * logging utilities
*
- * Log is saved at data/owncloud.log (on default)
+ * Log is saved by default at data/owncloud.log using OC_Log_Owncloud.
+ * Selecting other backend is done with a config option 'log_type'.
*/
-class OC_Log{
+class OC_Log {
const DEBUG=0;
const INFO=1;
const WARN=2;
const ERROR=3;
const FATAL=4;
+ static protected $class = null;
+
/**
* write a message in the log
* @param string $app
* @param string $message
* @param int level
*/
- public static function write($app,$message,$level){
- $minLevel=OC_Config::getValue( "loglevel", 2 );
- if($level>=$minLevel){
- $datadir=OC_Config::getValue( "datadirectory", OC::$SERVERROOT.'/data' );
- $logFile=OC_Config::getValue( "logfile", $datadir.'/owncloud.log' );
- $entry=array('app'=>$app,'message'=>$message,'level'=>$level,'time'=>time());
- $fh=fopen($logFile,'a');
- fwrite($fh,json_encode($entry)."\n");
- fclose($fh);
- }
- }
-
- /**
- * get entries from the log in reverse chronological order
- * @param int limit
- * @param int offset
- * @return array
- */
- public static function getEntries($limit=50,$offset=0){
- $datadir=OC_Config::getValue( "datadirectory", OC::$SERVERROOT.'/data' );
- $logFile=OC_Config::getValue( "logfile", $datadir.'/owncloud.log' );
- $entries=array();
- if(!file_exists($logFile)){
- return array();
- }
- $contents=file($logFile);
- if(!$contents){//error while reading log
- return array();
- }
- $end=max(count($contents)-$offset-1,0);
- $start=max($end-$limit,0);
- for($i=$end;$i>$start;$i--){
- $entries[]=json_decode($contents[$i]);
+ public static function write($app, $message, $level) {
+ if (!self::$class) {
+ self::$class = 'OC_Log_'.ucfirst(OC_Config::getValue('log_type', 'owncloud'));
+ call_user_func(array(self::$class, 'init'));
}
- return $entries;
+ $log_class=self::$class;
+ $log_class::write($app, $message, $level);
}
}
diff --git a/lib/log/owncloud.php b/lib/log/owncloud.php
new file mode 100644
index 00000000000..0ed30510134
--- /dev/null
+++ b/lib/log/owncloud.php
@@ -0,0 +1,79 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Robin Appelman
+ * @copyright 2012 Robin Appelman icewind1991@gmail.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/>.
+ *
+ */
+
+/**
+ * logging utilities
+ *
+ * Log is saved at data/owncloud.log (on default)
+ */
+
+class OC_Log_Owncloud {
+ static protected $logFile;
+
+ /**
+ * Init class data
+ */
+ public static function init() {
+ $datadir=OC_Config::getValue( "datadirectory", OC::$SERVERROOT.'/data' );
+ self::$logFile=OC_Config::getValue( "logfile", $datadir.'/owncloud.log' );
+ }
+
+ /**
+ * write a message in the log
+ * @param string $app
+ * @param string $message
+ * @param int level
+ */
+ public static function write($app, $message, $level) {
+ $minLevel=OC_Config::getValue( "loglevel", 2 );
+ if($level>=$minLevel){
+ $entry=array('app'=>$app, 'message'=>$message, 'level'=>$level,'time'=>time());
+ $fh=fopen(self::$logFile, 'a');
+ fwrite($fh, json_encode($entry)."\n");
+ fclose($fh);
+ }
+ }
+
+ /**
+ * get entries from the log in reverse chronological order
+ * @param int limit
+ * @param int offset
+ * @return array
+ */
+ public static function getEntries($limit=50, $offset=0){
+ self::init();
+ $entries=array();
+ if(!file_exists(self::$logFile)) {
+ return array();
+ }
+ $contents=file(self::$logFile);
+ if(!$contents) {//error while reading log
+ return array();
+ }
+ $end=max(count($contents)-$offset-1, 0);
+ $start=max($end-$limit,0);
+ for($i=$end;$i>$start;$i--) {
+ $entries[]=json_decode($contents[$i]);
+ }
+ return $entries;
+ }
+}
diff --git a/lib/log/syslog.php b/lib/log/syslog.php
new file mode 100644
index 00000000000..d1fb28d8b0a
--- /dev/null
+++ b/lib/log/syslog.php
@@ -0,0 +1,37 @@
+<?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_Log_Syslog {
+ static protected $levels = array(
+ OC_Log::DEBUG => LOG_DEBUG,
+ OC_Log::INFO => LOG_INFO,
+ OC_Log::WARN => LOG_WARNING,
+ OC_Log::ERROR => LOG_ERR,
+ OC_Log::FATAL => LOG_CRIT,
+ );
+
+ /**
+ * Init class data
+ */
+ public static function init() {
+ openlog('ownCloud', LOG_PID | LOG_CONS, LOG_USER);
+ // Close at shutdown
+ register_shutdown_function('closelog');
+ }
+
+ /**
+ * write a message in the log
+ * @param string $app
+ * @param string $message
+ * @param int level
+ */
+ public static function write($app, $message, $level) {
+ $syslog_level = self::$levels[$level];
+ syslog($syslog_level, '{'.$app.'} '.$message);
+ }
+}
diff --git a/lib/updater.php b/lib/updater.php
index 57623797ae5..196822ac35d 100644
--- a/lib/updater.php
+++ b/lib/updater.php
@@ -36,6 +36,7 @@ class OC_Updater{
$version['installed']=OC_Config::getValue('installedat');
$version['updated']=OC_Appconfig::getValue('core', 'lastupdatedat', OC_Config::getValue( 'lastupdatedat'));
$version['updatechannel']='stable';
+ $version['edition']=OC_Util::getEditionString();
$versionstring=implode('x',$version);
//fetch xml data from updater
diff --git a/lib/util.php b/lib/util.php
index fa5b3daaab6..722b7404d0c 100644
--- a/lib/util.php
+++ b/lib/util.php
@@ -66,7 +66,7 @@ class OC_Util {
* @return array
*/
public static function getVersion(){
- return array(3,00,3);
+ return array(3,00,4);
}
/**
@@ -77,6 +77,14 @@ class OC_Util {
return '3';
}
+ /**
+ * get the current installed edition of ownCloud. There is the community edition that just returns an empty string and the enterprise edition that returns "Enterprise".
+ * @return string
+ */
+ public static function getEditionString(){
+ return '';
+ }
+
/**
* add a javascript file
*
diff --git a/settings/ajax/getlog.php b/settings/ajax/getlog.php
index 600ebefcece..ed48b2cae1a 100644
--- a/settings/ajax/getlog.php
+++ b/settings/ajax/getlog.php
@@ -13,5 +13,5 @@ OC_JSON::checkAdminUser();
$count=(isset($_GET['count']))?$_GET['count']:50;
$offset=(isset($_GET['offset']))?$_GET['offset']:0;
-$entries=OC_Log::getEntries($count,$offset);
+$entries=OC_Log_Owncloud::getEntries($count,$offset);
OC_JSON::success(array("data" => $entries));
diff --git a/settings/log.php b/settings/log.php
index 946f2b6f8e5..ddbf72c4433 100644
--- a/settings/log.php
+++ b/settings/log.php
@@ -28,7 +28,7 @@ OC_Util::addStyle( "settings", "settings" );
OC_Util::addScript( "settings", "apps" );
OC_App::setActiveNavigationEntry( "core_log" );
-$entries=OC_Log::getEntries();
+$entries=OC_Log_Owncloud::getEntries();
OC_Util::addScript('settings','log');
OC_Util::addStyle('settings','settings');
diff --git a/settings/templates/personal.php b/settings/templates/personal.php
index 57731d979d9..d40da7eb773 100644
--- a/settings/templates/personal.php
+++ b/settings/templates/personal.php
@@ -50,7 +50,7 @@
};?>
<p class="personalblock">
- <strong>ownCloud</strong> <?php echo(OC_Util::getVersionString()); ?><br />
+ <strong>ownCloud</strong> <?php echo(OC_Util::getVersionString()); ?> <?php echo(OC_Util::getEditionString()); ?><br />
developed by the <a href="http://ownCloud.org/credits" target="_blank">ownCloud community</a><br />
<?php echo(OC_Updater::ShowUpdatingHint()); ?><br />
<a href="http://gitorious.org/owncloud" target="_blank">source code</a> licensed freely under <a href="http://www.gnu.org/licenses/agpl-3.0.html" target="_blank">AGPL</a>
diff --git a/status.php b/status.php
index 94c8cfce842..81f339fa53f 100644
--- a/status.php
+++ b/status.php
@@ -26,7 +26,7 @@ $RUNTIME_NOAPPS = TRUE; //no apps, yet
require_once('lib/base.php');
if(OC_Config::getValue('installed')==1) $installed='true'; else $installed='false';
-$values=array('installed'=>$installed,'version'=>implode('.',OC_Util::getVersion()),'versionstring'=>OC_Util::getVersionString());
+$values=array('installed'=>$installed,'version'=>implode('.',OC_Util::getVersion()),'versionstring'=>OC_Util::getVersionString(),'edition'=>OC_Util::getEditionString());
echo(json_encode($values));
diff --git a/tests/index.php b/tests/index.php
index 2e86366740b..a6f678b3bc2 100644
--- a/tests/index.php
+++ b/tests/index.php
@@ -38,6 +38,7 @@ foreach($apps as $app){
}
function loadTests($dir=''){
+ $test=isset($_GET['test'])?$_GET['test']:false;
if($dh=opendir($dir)){
while($name=readdir($dh)){
if(substr($name,0,1)!='.'){//no hidden files, '.' or '..'
@@ -45,10 +46,13 @@ function loadTests($dir=''){
if(is_dir($file)){
loadTests($file);
}elseif(substr($file,-4)=='.php' and $file!=__FILE__){
- $testCase=new TestSuite(getTestName($file));
- $testCase->addFile($file);
- if($testCase->getSize()>0){
- $testCase->run(new HtmlReporter());
+ $name=getTestName($file);
+ if($test===false or $test==$name or substr($name,0,strlen($test))==$test){
+ $testCase=new TestSuite($name);
+ $testCase->addFile($file);
+ if($testCase->getSize()>0){
+ $testCase->run(new HtmlReporter());
+ }
}
}
}