aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--3rdparty/MDB2/Driver/mysql.php2
-rw-r--r--3rdparty/phpass/PasswordHash.php253
-rw-r--r--3rdparty/phpass/c/Makefile21
-rw-r--r--3rdparty/phpass/c/crypt_private.c106
-rw-r--r--3rdparty/phpass/test.php72
-rw-r--r--apps/bookmarks/appinfo/app.php3
-rw-r--r--apps/bookmarks/css/bookmarks.css4
-rw-r--r--apps/bookmarks/js/bookmarks.js19
-rw-r--r--apps/bookmarks/lib/search.php7
-rw-r--r--apps/bookmarks/templates/bookmarklet.php2
-rwxr-xr-xapps/calendar/ajax/events.php33
-rw-r--r--apps/calendar/ajax/import/import.php4
-rw-r--r--apps/calendar/ajax/settings/getfirstday.php12
-rwxr-xr-xapps/calendar/ajax/settings/guesstimezone.php45
-rw-r--r--apps/calendar/ajax/settings/setfirstday.php17
-rw-r--r--apps/calendar/appinfo/app.php44
-rw-r--r--apps/calendar/caldav.php2
-rw-r--r--apps/calendar/index.php4
-rw-r--r--apps/calendar/js/calendar.js7
-rwxr-xr-xapps/calendar/js/geo.js1
-rw-r--r--apps/calendar/js/settings.js12
-rw-r--r--apps/calendar/lib/calendar.php3
-rw-r--r--apps/calendar/lib/hooks.php15
-rw-r--r--apps/calendar/lib/object.php15
-rw-r--r--apps/calendar/lib/search.php5
-rwxr-xr-xapps/calendar/templates/calendar.php1
-rw-r--r--apps/calendar/templates/settings.php9
-rw-r--r--apps/contacts/ajax/addcard.php103
-rw-r--r--apps/contacts/ajax/addcontact.php2
-rw-r--r--apps/contacts/ajax/addproperty.php17
-rw-r--r--apps/contacts/ajax/categories/categoriesfor.php28
-rw-r--r--apps/contacts/ajax/categories/delete.php60
-rw-r--r--apps/contacts/ajax/categories/list.php17
-rw-r--r--apps/contacts/ajax/categories/rescan.php49
-rw-r--r--apps/contacts/ajax/contactdetails.php2
-rw-r--r--apps/contacts/ajax/deleteproperty.php2
-rw-r--r--apps/contacts/ajax/loadcard.php (renamed from apps/contacts/ajax/showsetproperty.php)39
-rw-r--r--apps/contacts/ajax/loadphoto.php17
-rw-r--r--apps/contacts/ajax/messagebox.php15
-rw-r--r--apps/contacts/ajax/savecrop.php3
-rw-r--r--apps/contacts/ajax/saveproperty.php34
-rw-r--r--apps/contacts/ajax/setproperty.php106
-rw-r--r--apps/contacts/ajax/showaddcard.php40
-rw-r--r--apps/contacts/ajax/showaddproperty.php37
-rw-r--r--apps/contacts/appinfo/app.php6
-rw-r--r--apps/contacts/carddav.php2
-rw-r--r--apps/contacts/css/contacts.css8
-rw-r--r--apps/contacts/css/styles.css37
-rw-r--r--apps/contacts/import.php14
-rw-r--r--apps/contacts/index.php7
-rw-r--r--apps/contacts/js/contacts.js326
-rw-r--r--apps/contacts/js/interface.js409
-rw-r--r--apps/contacts/js/jquery.multi-autocomplete.js81
-rw-r--r--apps/contacts/l10n/xgettextfiles5
-rw-r--r--apps/contacts/lib/app.php10
-rw-r--r--apps/contacts/lib/hooks.php60
-rw-r--r--apps/contacts/lib/search.php5
-rw-r--r--apps/contacts/lib/vcard.php183
-rw-r--r--apps/contacts/templates/index.php1
-rw-r--r--apps/contacts/templates/part.addcardform.php138
-rw-r--r--apps/contacts/templates/part.contact.php20
-rw-r--r--apps/contacts/templates/part.contactphoto.php3
-rw-r--r--apps/contacts/templates/part.details.php96
-rw-r--r--apps/contacts/templates/part.edit_categories_dialog.php16
-rw-r--r--apps/contacts/templates/part.messagebox.php3
-rw-r--r--apps/contacts/templates/part.no_contacts.php8
-rw-r--r--apps/contacts/templates/part.property.FN.php9
-rw-r--r--apps/contacts/templates/part.property.N.php4
-rw-r--r--apps/contacts/templates/part.property.php86
-rw-r--r--apps/contacts/templates/part.setpropertyform.php91
-rw-r--r--apps/contacts/templates/settings.php11
-rw-r--r--apps/external/ajax/setsites.php25
-rw-r--r--apps/external/ajax/seturls.php24
-rw-r--r--apps/external/appinfo/app.php66
-rw-r--r--apps/external/css/style.css14
-rw-r--r--apps/external/index.php59
-rw-r--r--apps/external/js/admin.js87
-rw-r--r--apps/external/lib/external.php36
-rw-r--r--apps/external/settings.php12
-rw-r--r--apps/external/templates/settings.php30
-rw-r--r--apps/files_archive/appinfo/app.php18
-rw-r--r--apps/files_archive/appinfo/info.xml10
-rw-r--r--apps/files_archive/js/archive.js15
-rw-r--r--apps/files_archive/lib/archive.php99
-rw-r--r--apps/files_archive/lib/storage.php142
-rw-r--r--apps/files_archive/lib/zip.php182
-rw-r--r--apps/files_archive/tests/archive.php97
-rw-r--r--apps/files_archive/tests/storage.php25
-rw-r--r--apps/files_archive/tests/zip.php20
-rw-r--r--apps/files_encryption/appinfo/app.php19
-rw-r--r--apps/files_encryption/appinfo/info.xml10
-rw-r--r--apps/files_encryption/js/settings.js19
-rw-r--r--apps/files_encryption/lib/crypt.php (renamed from lib/crypt.php)149
-rw-r--r--apps/files_encryption/lib/cryptstream.php153
-rw-r--r--apps/files_encryption/lib/proxy.php115
-rw-r--r--apps/files_encryption/settings.php16
-rw-r--r--apps/files_encryption/templates/settings.php11
-rw-r--r--apps/files_sharing/sharedstorage.php21
-rw-r--r--apps/files_texteditor/ajax/savefile.php2
-rw-r--r--apps/files_texteditor/js/editor.js55
-rw-r--r--apps/gallery/ajax/galleryOp.php68
-rw-r--r--apps/gallery/ajax/getAlbums.php41
-rw-r--r--apps/gallery/appinfo/app.php6
-rw-r--r--apps/gallery/appinfo/database.xml34
-rw-r--r--apps/gallery/appinfo/info.xml2
-rw-r--r--apps/gallery/css/styles.css13
-rw-r--r--apps/gallery/img/loading.gifbin0 -> 1849 bytes
-rw-r--r--apps/gallery/js/album_cover.js273
-rw-r--r--apps/gallery/js/albums.js181
-rw-r--r--apps/gallery/js/scanner.js34
-rw-r--r--apps/gallery/lib/album.php126
-rw-r--r--apps/gallery/lib/hooks_handlers.php39
-rw-r--r--apps/gallery/lib/photo.php51
-rw-r--r--apps/gallery/lib/scanner.php203
-rw-r--r--apps/gallery/templates/index.php61
-rw-r--r--apps/media/ajax/api.php5
-rw-r--r--apps/media/appinfo/app.php3
-rw-r--r--apps/media/js/scanner.js2
-rw-r--r--apps/media/lib_media.php7
-rw-r--r--apps/media/lib_scanner.php2
-rw-r--r--apps/remoteStorage/BearerAuth.php61
-rw-r--r--apps/remoteStorage/WebDAV.php9
-rw-r--r--apps/remoteStorage/ajax/revokeToken.php41
-rw-r--r--apps/remoteStorage/appinfo/app.php1
-rw-r--r--apps/remoteStorage/appinfo/info.xml4
-rw-r--r--apps/remoteStorage/auth.css8
-rw-r--r--apps/remoteStorage/auth.php96
-rw-r--r--apps/remoteStorage/lib_remoteStorage.php35
-rw-r--r--apps/remoteStorage/oauth_ro_auth.php25
-rw-r--r--apps/remoteStorage/remoteStorage-big.pngbin0 -> 9742 bytes
-rw-r--r--apps/remoteStorage/remoteStorage.pngbin0 -> 1273 bytes
-rw-r--r--apps/remoteStorage/settings.php7
-rw-r--r--apps/remoteStorage/templates/settings.php28
-rw-r--r--apps/user_ldap/settings.php6
-rw-r--r--apps/user_ldap/templates/settings.php9
-rw-r--r--apps/user_ldap/user_ldap.php27
-rw-r--r--apps/user_webfinger/appinfo/info.xml4
-rw-r--r--apps/user_webfinger/host-meta.php4
-rw-r--r--apps/user_webfinger/webfinger.php4
-rw-r--r--core/ajax/appconfig.php35
-rw-r--r--core/ajax/vcategories/add.php43
-rw-r--r--core/ajax/vcategories/delete.php38
-rw-r--r--core/ajax/vcategories/edit.php35
-rw-r--r--core/css/oc-vcategories.css7
-rw-r--r--core/css/styles.css6
-rw-r--r--core/js/config.js55
-rw-r--r--core/js/js.js50
-rw-r--r--core/js/multiselect.js19
-rw-r--r--core/js/oc-dialogs.js149
-rw-r--r--core/js/oc-vcategories.js115
-rw-r--r--core/js/oc-vcategories.txt28
-rw-r--r--core/templates/edit_categories_dialog.php16
-rw-r--r--dav.php77
-rw-r--r--db_structure.xml106
-rw-r--r--files/admin.php24
-rw-r--r--files/ajax/newfile.php26
-rw-r--r--files/ajax/newfolder.php4
-rw-r--r--files/ajax/upload.php16
-rw-r--r--files/appinfo/app.php2
-rw-r--r--files/index.php2
-rw-r--r--files/js/files.js133
-rw-r--r--files/templates/admin.php14
-rw-r--r--files/templates/index.php1
-rw-r--r--lib/app.php23
-rw-r--r--lib/base.php73
-rw-r--r--lib/connector/sabre/auth.php1
-rw-r--r--lib/connector/sabre/directory.php4
-rw-r--r--lib/connector/sabre/principal.php44
-rw-r--r--lib/db.php37
-rw-r--r--lib/fakedirstream.php45
-rw-r--r--lib/filecache.php115
-rw-r--r--lib/fileproxy.php17
-rw-r--r--lib/files.php44
-rw-r--r--lib/filestorage.php54
-rw-r--r--lib/filestorage/common.php159
-rw-r--r--lib/filestorage/commontest.php75
-rw-r--r--lib/filestorage/google.php340
-rw-r--r--lib/filestorage/local.php95
-rw-r--r--lib/filestoragecommon.php83
-rw-r--r--lib/filesystem.php12
-rw-r--r--lib/filesystemview.php114
-rw-r--r--lib/geo.php31
-rw-r--r--lib/helper.php145
-rw-r--r--lib/image.php2
-rw-r--r--lib/installer.php23
-rw-r--r--lib/l10n.php4
-rw-r--r--lib/log.php26
-rw-r--r--lib/search.php4
-rw-r--r--lib/search/provider.php8
-rw-r--r--lib/search/provider/file.php8
-rw-r--r--lib/streamwrappers.php306
-rw-r--r--lib/template.php47
-rw-r--r--lib/user.php6
-rw-r--r--lib/user/database.php49
-rw-r--r--lib/util.php10
-rw-r--r--lib/vcategories.php211
-rw-r--r--owncloud.db.filesystembin2348032 -> 0 bytes
-rw-r--r--settings/ajax/getlog.php17
-rw-r--r--settings/ajax/setquota.php5
-rw-r--r--settings/css/settings.css4
-rw-r--r--settings/js/log.js46
-rw-r--r--settings/log.php5
-rw-r--r--settings/templates/log.php5
-rw-r--r--tests/index.php26
-rw-r--r--tests/lib/filestorage.php91
-rw-r--r--tests/lib/filestorage/commontest.php41
-rw-r--r--tests/lib/streamwrappers.php78
207 files changed, 6299 insertions, 3214 deletions
diff --git a/3rdparty/MDB2/Driver/mysql.php b/3rdparty/MDB2/Driver/mysql.php
index b9b46c0d762..2cec1e9c033 100644
--- a/3rdparty/MDB2/Driver/mysql.php
+++ b/3rdparty/MDB2/Driver/mysql.php
@@ -794,7 +794,7 @@ class MDB2_Driver_mysql extends MDB2_Driver_Common
? 'mysql_query' : 'mysql_unbuffered_query';
$result = @$function($query, $connection);
if (!$result) {
- $err =& $this->raiseError(null, null, null,
+ $err =$this->raiseError(null, null, null,
'Could not execute statement', __FUNCTION__);
return $err;
}
diff --git a/3rdparty/phpass/PasswordHash.php b/3rdparty/phpass/PasswordHash.php
new file mode 100644
index 00000000000..12958c7f19e
--- /dev/null
+++ b/3rdparty/phpass/PasswordHash.php
@@ -0,0 +1,253 @@
+<?php
+#
+# Portable PHP password hashing framework.
+#
+# Version 0.3 / genuine.
+#
+# Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
+# the public domain. Revised in subsequent years, still public domain.
+#
+# There's absolutely no warranty.
+#
+# The homepage URL for this framework is:
+#
+# http://www.openwall.com/phpass/
+#
+# Please be sure to update the Version line if you edit this file in any way.
+# It is suggested that you leave the main version number intact, but indicate
+# your project name (after the slash) and add your own revision information.
+#
+# Please do not change the "private" password hashing method implemented in
+# here, thereby making your hashes incompatible. However, if you must, please
+# change the hash type identifier (the "$P$") to something different.
+#
+# Obviously, since this code is in the public domain, the above are not
+# requirements (there can be none), but merely suggestions.
+#
+class PasswordHash {
+ var $itoa64;
+ var $iteration_count_log2;
+ var $portable_hashes;
+ var $random_state;
+
+ function PasswordHash($iteration_count_log2, $portable_hashes)
+ {
+ $this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
+
+ if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
+ $iteration_count_log2 = 8;
+ $this->iteration_count_log2 = $iteration_count_log2;
+
+ $this->portable_hashes = $portable_hashes;
+
+ $this->random_state = microtime();
+ if (function_exists('getmypid'))
+ $this->random_state .= getmypid();
+ }
+
+ function get_random_bytes($count)
+ {
+ $output = '';
+ if (is_readable('/dev/urandom') &&
+ ($fh = @fopen('/dev/urandom', 'rb'))) {
+ $output = fread($fh, $count);
+ fclose($fh);
+ }
+
+ if (strlen($output) < $count) {
+ $output = '';
+ for ($i = 0; $i < $count; $i += 16) {
+ $this->random_state =
+ md5(microtime() . $this->random_state);
+ $output .=
+ pack('H*', md5($this->random_state));
+ }
+ $output = substr($output, 0, $count);
+ }
+
+ return $output;
+ }
+
+ function encode64($input, $count)
+ {
+ $output = '';
+ $i = 0;
+ do {
+ $value = ord($input[$i++]);
+ $output .= $this->itoa64[$value & 0x3f];
+ if ($i < $count)
+ $value |= ord($input[$i]) << 8;
+ $output .= $this->itoa64[($value >> 6) & 0x3f];
+ if ($i++ >= $count)
+ break;
+ if ($i < $count)
+ $value |= ord($input[$i]) << 16;
+ $output .= $this->itoa64[($value >> 12) & 0x3f];
+ if ($i++ >= $count)
+ break;
+ $output .= $this->itoa64[($value >> 18) & 0x3f];
+ } while ($i < $count);
+
+ return $output;
+ }
+
+ function gensalt_private($input)
+ {
+ $output = '$P$';
+ $output .= $this->itoa64[min($this->iteration_count_log2 +
+ ((PHP_VERSION >= '5') ? 5 : 3), 30)];
+ $output .= $this->encode64($input, 6);
+
+ return $output;
+ }
+
+ function crypt_private($password, $setting)
+ {
+ $output = '*0';
+ if (substr($setting, 0, 2) == $output)
+ $output = '*1';
+
+ $id = substr($setting, 0, 3);
+ # We use "$P$", phpBB3 uses "$H$" for the same thing
+ if ($id != '$P$' && $id != '$H$')
+ return $output;
+
+ $count_log2 = strpos($this->itoa64, $setting[3]);
+ if ($count_log2 < 7 || $count_log2 > 30)
+ return $output;
+
+ $count = 1 << $count_log2;
+
+ $salt = substr($setting, 4, 8);
+ if (strlen($salt) != 8)
+ return $output;
+
+ # We're kind of forced to use MD5 here since it's the only
+ # cryptographic primitive available in all versions of PHP
+ # currently in use. To implement our own low-level crypto
+ # in PHP would result in much worse performance and
+ # consequently in lower iteration counts and hashes that are
+ # quicker to crack (by non-PHP code).
+ if (PHP_VERSION >= '5') {
+ $hash = md5($salt . $password, TRUE);
+ do {
+ $hash = md5($hash . $password, TRUE);
+ } while (--$count);
+ } else {
+ $hash = pack('H*', md5($salt . $password));
+ do {
+ $hash = pack('H*', md5($hash . $password));
+ } while (--$count);
+ }
+
+ $output = substr($setting, 0, 12);
+ $output .= $this->encode64($hash, 16);
+
+ return $output;
+ }
+
+ function gensalt_extended($input)
+ {
+ $count_log2 = min($this->iteration_count_log2 + 8, 24);
+ # This should be odd to not reveal weak DES keys, and the
+ # maximum valid value is (2**24 - 1) which is odd anyway.
+ $count = (1 << $count_log2) - 1;
+
+ $output = '_';
+ $output .= $this->itoa64[$count & 0x3f];
+ $output .= $this->itoa64[($count >> 6) & 0x3f];
+ $output .= $this->itoa64[($count >> 12) & 0x3f];
+ $output .= $this->itoa64[($count >> 18) & 0x3f];
+
+ $output .= $this->encode64($input, 3);
+
+ return $output;
+ }
+
+ function gensalt_blowfish($input)
+ {
+ # This one needs to use a different order of characters and a
+ # different encoding scheme from the one in encode64() above.
+ # We care because the last character in our encoded string will
+ # only represent 2 bits. While two known implementations of
+ # bcrypt will happily accept and correct a salt string which
+ # has the 4 unused bits set to non-zero, we do not want to take
+ # chances and we also do not want to waste an additional byte
+ # of entropy.
+ $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+
+ $output = '$2a$';
+ $output .= chr(ord('0') + $this->iteration_count_log2 / 10);
+ $output .= chr(ord('0') + $this->iteration_count_log2 % 10);
+ $output .= '$';
+
+ $i = 0;
+ do {
+ $c1 = ord($input[$i++]);
+ $output .= $itoa64[$c1 >> 2];
+ $c1 = ($c1 & 0x03) << 4;
+ if ($i >= 16) {
+ $output .= $itoa64[$c1];
+ break;
+ }
+
+ $c2 = ord($input[$i++]);
+ $c1 |= $c2 >> 4;
+ $output .= $itoa64[$c1];
+ $c1 = ($c2 & 0x0f) << 2;
+
+ $c2 = ord($input[$i++]);
+ $c1 |= $c2 >> 6;
+ $output .= $itoa64[$c1];
+ $output .= $itoa64[$c2 & 0x3f];
+ } while (1);
+
+ return $output;
+ }
+
+ function HashPassword($password)
+ {
+ $random = '';
+
+ if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
+ $random = $this->get_random_bytes(16);
+ $hash =
+ crypt($password, $this->gensalt_blowfish($random));
+ if (strlen($hash) == 60)
+ return $hash;
+ }
+
+ if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
+ if (strlen($random) < 3)
+ $random = $this->get_random_bytes(3);
+ $hash =
+ crypt($password, $this->gensalt_extended($random));
+ if (strlen($hash) == 20)
+ return $hash;
+ }
+
+ if (strlen($random) < 6)
+ $random = $this->get_random_bytes(6);
+ $hash =
+ $this->crypt_private($password,
+ $this->gensalt_private($random));
+ if (strlen($hash) == 34)
+ return $hash;
+
+ # Returning '*' on error is safe here, but would _not_ be safe
+ # in a crypt(3)-like function used _both_ for generating new
+ # hashes and for validating passwords against existing hashes.
+ return '*';
+ }
+
+ function CheckPassword($password, $stored_hash)
+ {
+ $hash = $this->crypt_private($password, $stored_hash);
+ if ($hash[0] == '*')
+ $hash = crypt($password, $stored_hash);
+
+ return $hash == $stored_hash;
+ }
+}
+
+?>
diff --git a/3rdparty/phpass/c/Makefile b/3rdparty/phpass/c/Makefile
new file mode 100644
index 00000000000..fe48917f7f5
--- /dev/null
+++ b/3rdparty/phpass/c/Makefile
@@ -0,0 +1,21 @@
+#
+# Written by Solar Designer and placed in the public domain.
+# See crypt_private.c for more information.
+#
+CC = gcc
+LD = $(CC)
+RM = rm -f
+CFLAGS = -Wall -O2 -fomit-frame-pointer -funroll-loops
+LDFLAGS = -s
+LIBS = -lcrypto
+
+all: crypt_private-test
+
+crypt_private-test: crypt_private-test.o
+ $(LD) $(LDFLAGS) $(LIBS) crypt_private-test.o -o $@
+
+crypt_private-test.o: crypt_private.c
+ $(CC) -c $(CFLAGS) crypt_private.c -DTEST -o $@
+
+clean:
+ $(RM) crypt_private-test*
diff --git a/3rdparty/phpass/c/crypt_private.c b/3rdparty/phpass/c/crypt_private.c
new file mode 100644
index 00000000000..6abc05bc1de
--- /dev/null
+++ b/3rdparty/phpass/c/crypt_private.c
@@ -0,0 +1,106 @@
+/*
+ * This code exists for the sole purpose to serve as another implementation
+ * of the "private" password hashing method implemened in PasswordHash.php
+ * and thus to confirm that these password hashes are indeed calculated as
+ * intended.
+ *
+ * Other uses of this code are discouraged. There are much better password
+ * hashing algorithms available to C programmers; one of those is bcrypt:
+ *
+ * http://www.openwall.com/crypt/
+ *
+ * Written by Solar Designer <solar at openwall.com> in 2005 and placed in
+ * the public domain.
+ *
+ * There's absolutely no warranty.
+ */
+
+#include <string.h>
+#include <openssl/md5.h>
+
+#ifdef TEST
+#include <stdio.h>
+#endif
+
+static char *itoa64 =
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static void encode64(char *dst, char *src, int count)
+{
+ int i, value;
+
+ i = 0;
+ do {
+ value = (unsigned char)src[i++];
+ *dst++ = itoa64[value & 0x3f];
+ if (i < count)
+ value |= (unsigned char)src[i] << 8;
+ *dst++ = itoa64[(value >> 6) & 0x3f];
+ if (i++ >= count)
+ break;
+ if (i < count)
+ value |= (unsigned char)src[i] << 16;
+ *dst++ = itoa64[(value >> 12) & 0x3f];
+ if (i++ >= count)
+ break;
+ *dst++ = itoa64[(value >> 18) & 0x3f];
+ } while (i < count);
+}
+
+char *crypt_private(char *password, char *setting)
+{
+ static char output[35];
+ MD5_CTX ctx;
+ char hash[MD5_DIGEST_LENGTH];
+ char *p, *salt;
+ int count_log2, length, count;
+
+ strcpy(output, "*0");
+ if (!strncmp(setting, output, 2))
+ output[1] = '1';
+
+ if (strncmp(setting, "$P$", 3))
+ return output;
+
+ p = strchr(itoa64, setting[3]);
+ if (!p)
+ return output;
+ count_log2 = p - itoa64;
+ if (count_log2 < 7 || count_log2 > 30)
+ return output;
+
+ salt = setting + 4;
+ if (strlen(salt) < 8)
+ return output;
+
+ length = strlen(password);
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, salt, 8);
+ MD5_Update(&ctx, password, length);
+ MD5_Final(hash, &ctx);
+
+ count = 1 << count_log2;
+ do {
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, hash, MD5_DIGEST_LENGTH);
+ MD5_Update(&ctx, password, length);
+ MD5_Final(hash, &ctx);
+ } while (--count);
+
+ memcpy(output, setting, 12);
+ encode64(&output[12], hash, MD5_DIGEST_LENGTH);
+
+ return output;
+}
+
+#ifdef TEST
+int main(int argc, char **argv)
+{
+ if (argc != 3) return 1;
+
+ puts(crypt_private(argv[1], argv[2]));
+
+ return 0;
+}
+#endif
diff --git a/3rdparty/phpass/test.php b/3rdparty/phpass/test.php
new file mode 100644
index 00000000000..2f4a41c8c31
--- /dev/null
+++ b/3rdparty/phpass/test.php
@@ -0,0 +1,72 @@
+<?php
+#
+# This is a test program for the portable PHP password hashing framework.
+#
+# Written by Solar Designer and placed in the public domain.
+# See PasswordHash.php for more information.
+#
+
+require 'PasswordHash.php';
+
+header('Content-type: text/plain');
+
+$ok = 0;
+
+# Try to use stronger but system-specific hashes, with a possible fallback to
+# the weaker portable hashes.
+$t_hasher = new PasswordHash(8, FALSE);
+
+$correct = 'test12345';
+$hash = $t_hasher->HashPassword($correct);
+
+print 'Hash: ' . $hash . "\n";
+
+$check = $t_hasher->CheckPassword($correct, $hash);
+if ($check) $ok++;
+print "Check correct: '" . $check . "' (should be '1')\n";
+
+$wrong = 'test12346';
+$check = $t_hasher->CheckPassword($wrong, $hash);
+if (!$check) $ok++;
+print "Check wrong: '" . $check . "' (should be '0' or '')\n";
+
+unset($t_hasher);
+
+# Force the use of weaker portable hashes.
+$t_hasher = new PasswordHash(8, TRUE);
+
+$hash = $t_hasher->HashPassword($correct);
+
+print 'Hash: ' . $hash . "\n";
+
+$check = $t_hasher->CheckPassword($correct, $hash);
+if ($check) $ok++;
+print "Check correct: '" . $check . "' (should be '1')\n";
+
+$check = $t_hasher->CheckPassword($wrong, $hash);
+if (!$check) $ok++;
+print "Check wrong: '" . $check . "' (should be '0' or '')\n";
+
+# A correct portable hash for 'test12345'.
+# Please note the use of single quotes to ensure that the dollar signs will
+# be interpreted literally. Of course, a real application making use of the
+# framework won't store password hashes within a PHP source file anyway.
+# We only do this for testing.
+$hash = '$P$9IQRaTwmfeRo7ud9Fh4E2PdI0S3r.L0';
+
+print 'Hash: ' . $hash . "\n";
+
+$check = $t_hasher->CheckPassword($correct, $hash);
+if ($check) $ok++;
+print "Check correct: '" . $check . "' (should be '1')\n";
+
+$check = $t_hasher->CheckPassword($wrong, $hash);
+if (!$check) $ok++;
+print "Check wrong: '" . $check . "' (should be '0' or '')\n";
+
+if ($ok == 6)
+ print "All tests have PASSED\n";
+else
+ print "Some tests have FAILED\n";
+
+?>
diff --git a/apps/bookmarks/appinfo/app.php b/apps/bookmarks/appinfo/app.php
index a1f6139d89b..09d7b5df525 100644
--- a/apps/bookmarks/appinfo/app.php
+++ b/apps/bookmarks/appinfo/app.php
@@ -8,6 +8,7 @@
*/
OC::$CLASSPATH['OC_Bookmarks_Bookmarks'] = 'apps/bookmarks/lib/bookmarks.php';
+OC::$CLASSPATH['OC_Search_Provider_Bookmarks'] = 'apps/bookmarks/lib/search.php';
OC_App::register( array( 'order' => 70, 'id' => 'bookmark', 'name' => 'Bookmarks' ));
@@ -15,5 +16,5 @@ $l = new OC_l10n('bookmarks');
OC_App::addNavigationEntry( array( 'id' => 'bookmarks_index', 'order' => 70, 'href' => OC_Helper::linkTo( 'bookmarks', 'index.php' ), 'icon' => OC_Helper::imagePath( 'bookmarks', 'bookmarks.png' ), 'name' => $l->t('Bookmarks')));
OC_App::registerPersonal('bookmarks', 'settings');
-require_once('apps/bookmarks/lib/search.php');
OC_Util::addScript('bookmarks','bookmarksearch');
+OC_Search::registerProvider('OC_Search_Provider_Bookmarks');
diff --git a/apps/bookmarks/css/bookmarks.css b/apps/bookmarks/css/bookmarks.css
index b1139f2c346..3a3e0fbf6b3 100644
--- a/apps/bookmarks/css/bookmarks.css
+++ b/apps/bookmarks/css/bookmarks.css
@@ -17,7 +17,9 @@
}
.bookmarks_list {
- margin-top: 36px;
+ overflow: auto;
+ position: fixed;
+ top: 6.5em;
}
.bookmarks_addBml {
diff --git a/apps/bookmarks/js/bookmarks.js b/apps/bookmarks/js/bookmarks.js
index 7317a154a76..fa5adde2545 100644
--- a/apps/bookmarks/js/bookmarks.js
+++ b/apps/bookmarks/js/bookmarks.js
@@ -5,7 +5,11 @@ var bookmarks_sorting = 'bookmarks_sorting_recent';
$(document).ready(function() {
$('#bookmark_add_submit').click(addOrEditBookmark);
- $(window).scroll(updateOnBottom);
+ $(window).resize(function () {
+ fillWindow($('.bookmarks_list'));
+ });
+ $(window).resize();
+ $($('.bookmarks_list')).scroll(updateOnBottom);
$('.bookmarks_list').empty();
getBookmarks();
@@ -21,7 +25,9 @@ function getBookmarks() {
url: 'ajax/updateList.php',
data: 'tag=' + encodeURI($('#bookmarkFilterTag').val()) + '&page=' + bookmarks_page + '&sort=' + bookmarks_sorting,
success: function(bookmarks){
- bookmarks_page += 1;
+ if (bookmarks.data.length) {
+ bookmarks_page += 1;
+ }
$('.bookmark_link').unbind('click', recordClick);
$('.bookmark_delete').unbind('click', delBookmark);
$('.bookmark_edit').unbind('click', showBookmark);
@@ -39,6 +45,9 @@ function getBookmarks() {
$('.bookmark_edit').click(showBookmark);
bookmarks_loading = false;
+ if (bookmarks.data.length) {
+ updateOnBottom()
+ }
}
});
}
@@ -146,7 +155,11 @@ function updateBookmarksList(bookmark) {
function updateOnBottom() {
//check wether user is on bottom of the page
- if ($('body').height() <= ($(window).height() + $(window).scrollTop())) {
+ var top = $('.bookmarks_list>:last-child').position().top;
+ var height = $('.bookmarks_list').height();
+ // use a bit of margin to begin loading before we are really at the
+ // bottom
+ if (top < height * 1.2) {
getBookmarks();
}
}
diff --git a/apps/bookmarks/lib/search.php b/apps/bookmarks/lib/search.php
index 59495db82ea..235587855d9 100644
--- a/apps/bookmarks/lib/search.php
+++ b/apps/bookmarks/lib/search.php
@@ -20,8 +20,8 @@
*
*/
-class OC_Search_Provider_Bookmarks extends OC_Search_Provider{
- function search($query){
+class OC_Search_Provider_Bookmarks implements OC_Search_Provider{
+ static function search($query){
$results=array();
$offset = 0;
@@ -45,6 +45,3 @@ class OC_Search_Provider_Bookmarks extends OC_Search_Provider{
return $results;
}
}
-new OC_Search_Provider_Bookmarks();
-
-?>
diff --git a/apps/bookmarks/templates/bookmarklet.php b/apps/bookmarks/templates/bookmarklet.php
index 3d8bbcc7b31..5ea67f04df2 100644
--- a/apps/bookmarks/templates/bookmarklet.php
+++ b/apps/bookmarks/templates/bookmarklet.php
@@ -3,6 +3,6 @@
function createBookmarklet() {
$l = new OC_L10N('bookmarks');
echo '<small>' . $l->t('Drag this to your browser bookmarks and click it, when you want to bookmark a webpage quickly:') . '</small>'
- . '<a class="button" href="javascript:(function(){var a=window,b=document,c=encodeURIComponent,d=a.open(\'' . OC_Helper::linkToAbsolute('bookmarks', 'addBm.php') . '?output=popup&url=\'+c(b.location),\'bkmk_popup\',\'left=\'+((a.screenX||a.screenLeft)+10)+\',top=\'+((a.screenY||a.screenTop)+10)+\',height=230px,width=230px,resizable=1,alwaysRaised=1\');a.setTimeout(function(){d.focus()},300);})();">'
+ . '<a class="bookmarklet" href="javascript:(function(){var a=window,b=document,c=encodeURIComponent,d=a.open(\'' . OC_Helper::linkToAbsolute('bookmarks', 'addBm.php') . '?output=popup&url=\'+c(b.location),\'bkmk_popup\',\'left=\'+((a.screenX||a.screenLeft)+10)+\',top=\'+((a.screenY||a.screenTop)+10)+\',height=230px,width=230px,resizable=1,alwaysRaised=1\');a.setTimeout(function(){d.focus()},300);})();">'
. $l->t('Read later') . '</a>';
}
diff --git a/apps/calendar/ajax/events.php b/apps/calendar/ajax/events.php
index 6ea556a7abf..dff02e15875 100755
--- a/apps/calendar/ajax/events.php
+++ b/apps/calendar/ajax/events.php
@@ -27,25 +27,40 @@ function create_return_event($event, $vevent){
OC_JSON::checkLoggedIn();
OC_JSON::checkAppEnabled('calendar');
-$start = DateTime::createFromFormat('U', $_GET['start']);
-$end = DateTime::createFromFormat('U', $_GET['end']);
+if(version_compare(PHP_VERSION, '5.3.0', '>=')){
+ $start = DateTime::createFromFormat('U', $_GET['start']);
+ $end = DateTime::createFromFormat('U', $_GET['end']);
+}else{
+ $start = new DateTime('@' . $_GET['start']);
+ $end = new DateTime('@' . $_GET['end']);
+}
-$calendar = OC_Calendar_App::getCalendar($_GET['calendar_id']);
-OC_Response::enableCaching(0);
-OC_Response::setETagHeader($calendar['ctag']);
+$calendar_id = $_GET['calendar_id'];
+if (is_numeric($calendar_id)) {
+ $calendar = OC_Calendar_App::getCalendar($calendar_id);
+ OC_Response::enableCaching(0);
+ OC_Response::setETagHeader($calendar['ctag']);
+ $events = OC_Calendar_Object::allInPeriod($calendar_id, $start, $end);
+} else {
+ $events = array();
+ OC_Hook::emit('OC_Calendar', 'getEvents', array('calendar_id' => $calendar_id, 'events' => &$events));
+}
-$events = OC_Calendar_Object::allInPeriod($_GET['calendar_id'], $start, $end);
$user_timezone = OC_Preferences::getValue(OC_USER::getUser(), 'calendar', 'timezone', date_default_timezone_get());
$return = array();
foreach($events as $event){
- $object = OC_VObject::parse($event['calendardata']);
- $vevent = $object->VEVENT;
+ if (isset($event['calendardata'])) {
+ $object = OC_VObject::parse($event['calendardata']);
+ $vevent = $object->VEVENT;
+ } else {
+ $vevent = $event['vevent'];
+ }
$return_event = create_return_event($event, $vevent);
$dtstart = $vevent->DTSTART;
- $dtend = OC_Calendar_Object::getDTEndFromVEvent($vevent);
$start_dt = $dtstart->getDateTime();
+ $dtend = OC_Calendar_Object::getDTEndFromVEvent($vevent);
$end_dt = $dtend->getDateTime();
if ($dtstart->getDateType() == Sabre_VObject_Property_DateTime::DATE){
$return_event['allDay'] = true;
diff --git a/apps/calendar/ajax/import/import.php b/apps/calendar/ajax/import/import.php
index 96d7af48341..c0797f6e425 100644
--- a/apps/calendar/ajax/import/import.php
+++ b/apps/calendar/ajax/import/import.php
@@ -11,7 +11,7 @@ require_once('../../../../lib/base.php');
OC_JSON::checkLoggedIn();
OC_Util::checkAppEnabled('calendar');
$nl = "\n";
-$progressfile = OC::$SERVERROOT . '/apps/calendar/import_tmp/' . md5(session_id()) . '.txt';
+$progressfile = OC::$APPSROOT . '/apps/calendar/import_tmp/' . md5(session_id()) . '.txt';
if(is_writable('import_tmp/')){
$progressfopen = fopen($progressfile, 'w');
fwrite($progressfopen, '10');
@@ -117,4 +117,4 @@ sleep(3);
if(is_writable('import_tmp/')){
unlink($progressfile);
}
-OC_JSON::success(); \ No newline at end of file
+OC_JSON::success();
diff --git a/apps/calendar/ajax/settings/getfirstday.php b/apps/calendar/ajax/settings/getfirstday.php
new file mode 100644
index 00000000000..cab5870509a
--- /dev/null
+++ b/apps/calendar/ajax/settings/getfirstday.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Copyright (c) 2012 Georg Ehrke <ownclouddev at georgswebsite dot de>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+require_once('../../../../lib/base.php');
+OC_JSON::checkLoggedIn();
+$firstday = OC_Preferences::getValue( OC_User::getUser(), 'calendar', 'firstday', 'mo');
+OC_JSON::encodedPrint(array('firstday' => $firstday));
+?>
diff --git a/apps/calendar/ajax/settings/guesstimezone.php b/apps/calendar/ajax/settings/guesstimezone.php
index cfa92e1aee8..d45a70e1ce3 100755
--- a/apps/calendar/ajax/settings/guesstimezone.php
+++ b/apps/calendar/ajax/settings/guesstimezone.php
@@ -5,44 +5,23 @@
* later.
* See the COPYING-README file.
*/
-function make_array_out_of_xml ($xml){
- $returnarray = array();
- $xml = (array)$xml ;
- foreach ($xml as $property => $value){
- $value = (array)$value;
- if(!isset($value[0])){
- $returnarray[$property] = make_array_out_of_xml($value);
- }else{
- $returnarray[$property] = trim($value[0]);
- }
- }
- return $returnarray;
-}
require_once('../../../../lib/base.php');
+
OC_JSON::checkLoggedIn();
OC_JSON::checkAppEnabled('calendar');
+
$l = new OC_L10N('calendar');
+
$lat = $_GET['lat'];
-$long = $_GET['long'];
-if(OC_Preferences::getValue(OC_USER::getUser(), 'calendar', 'position') == $lat . '-' . $long && OC_Preferences::getValue(OC_USER::getUser(), 'calendar', 'timezone') != null){
- OC_JSON::success();
- exit;
-}
-OC_Preferences::setValue(OC_USER::getUser(), 'calendar', 'position', $lat . '-' . $long);
-$geolocation = file_get_contents('http://ws.geonames.org/timezone?lat=' . $lat . '&lng=' . $long);
-//Information are by Geonames (http://www.geonames.org) and licensed under the Creative Commons Attribution 3.0 License
-$geoxml = simplexml_load_string($geolocation);
-$geoarray = make_array_out_of_xml($geoxml);
-if($geoarray['timezone']['timezoneId'] == OC_Preferences::getValue(OC_USER::getUser(), 'calendar', 'timezone')){
+$lng = $_GET['long'];
+
+$timezone = OC_Geo::timezone($lat, $lng);
+
+if($timezone == OC_Preferences::getValue(OC_USER::getUser(), 'calendar', 'timezone')){
OC_JSON::success();
exit;
}
-if(in_array($geoarray['timezone']['timezoneId'], DateTimeZone::listIdentifiers())){
- OC_Preferences::setValue(OC_USER::getUser(), 'calendar', 'timezone', $geoarray['timezone']['timezoneId']);
- $message = array('message'=> $l->t('New Timezone:') . $geoarray['timezone']['timezoneId']);
- OC_JSON::success($message);
-}else{
- OC_JSON::error();
-}
-
-?>
+OC_Preferences::setValue(OC_USER::getUser(), 'calendar', 'timezone', $timezone);
+$message = array('message'=> $l->t('New Timezone:') . $timezone);
+OC_JSON::success($message);
+?> \ No newline at end of file
diff --git a/apps/calendar/ajax/settings/setfirstday.php b/apps/calendar/ajax/settings/setfirstday.php
new file mode 100644
index 00000000000..3b652212205
--- /dev/null
+++ b/apps/calendar/ajax/settings/setfirstday.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Copyright (c) 2012 Georg Ehrke <ownclouddev at georgswebsite dot de>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+require_once('../../../../lib/base.php');
+OC_JSON::checkLoggedIn();
+if(isset($_POST["firstday"])){
+ OC_Preferences::setValue(OC_User::getUser(), 'calendar', 'firstday', $_POST["firstday"]);
+ OC_JSON::success();
+}else{
+ OC_JSON::error();
+}
+?>
+
diff --git a/apps/calendar/appinfo/app.php b/apps/calendar/appinfo/app.php
index 9c95768895f..f297c4d16d4 100644
--- a/apps/calendar/appinfo/app.php
+++ b/apps/calendar/appinfo/app.php
@@ -1,23 +1,23 @@
<?php
-if(version_compare(PHP_VERSION, '5.3.0', '>=')){
- $l=new OC_L10N('calendar');
- OC::$CLASSPATH['OC_Calendar_App'] = 'apps/calendar/lib/app.php';
- OC::$CLASSPATH['OC_Calendar_Calendar'] = 'apps/calendar/lib/calendar.php';
- OC::$CLASSPATH['OC_Calendar_Object'] = 'apps/calendar/lib/object.php';
- OC::$CLASSPATH['OC_Calendar_Hooks'] = 'apps/calendar/lib/hooks.php';
- OC::$CLASSPATH['OC_Connector_Sabre_CalDAV'] = 'apps/calendar/lib/connector_sabre.php';
- OC_HOOK::connect('OC_User', 'post_deleteUser', 'OC_Calendar_Hooks', 'deleteUser');
- OC_Util::addScript('calendar','loader');
- OC_App::register( array(
- 'order' => 10,
- 'id' => 'calendar',
- 'name' => 'Calendar' ));
- OC_App::addNavigationEntry( array(
- 'id' => 'calendar_index',
- 'order' => 10,
- 'href' => OC_Helper::linkTo( 'calendar', 'index.php' ),
- 'icon' => OC_Helper::imagePath( 'calendar', 'icon.svg' ),
- 'name' => $l->t('Calendar')));
- OC_App::registerPersonal('calendar', 'settings');
- require_once('apps/calendar/lib/search.php');
-}
+$l=new OC_L10N('calendar');
+OC::$CLASSPATH['OC_Calendar_App'] = 'apps/calendar/lib/app.php';
+OC::$CLASSPATH['OC_Calendar_Calendar'] = 'apps/calendar/lib/calendar.php';
+OC::$CLASSPATH['OC_Calendar_Object'] = 'apps/calendar/lib/object.php';
+OC::$CLASSPATH['OC_Calendar_Hooks'] = 'apps/calendar/lib/hooks.php';
+OC::$CLASSPATH['OC_Connector_Sabre_CalDAV'] = 'apps/calendar/lib/connector_sabre.php';
+OC::$CLASSPATH['OC_Search_Provider_Calendar'] = 'apps/calendar/lib/search.php';
+OC_HOOK::connect('OC_User', 'post_deleteUser', 'OC_Calendar_Hooks', 'deleteUser');
+OC_Hook::connect('OC_DAV', 'initialize', 'OC_Calendar_Hooks', 'initializeCalDAV');
+OC_Util::addScript('calendar','loader');
+OC_App::register( array(
+ 'order' => 10,
+ 'id' => 'calendar',
+ 'name' => 'Calendar' ));
+OC_App::addNavigationEntry( array(
+ 'id' => 'calendar_index',
+ 'order' => 10,
+ 'href' => OC_Helper::linkTo( 'calendar', 'index.php' ),
+ 'icon' => OC_Helper::imagePath( 'calendar', 'icon.svg' ),
+ 'name' => $l->t('Calendar')));
+OC_App::registerPersonal('calendar', 'settings');
+OC_Search::registerProvider('OC_Search_Provider_Calendar'); \ No newline at end of file
diff --git a/apps/calendar/caldav.php b/apps/calendar/caldav.php
index db0b35da118..b710b99ea43 100644
--- a/apps/calendar/caldav.php
+++ b/apps/calendar/caldav.php
@@ -25,7 +25,7 @@ $nodes = array(
// Fire up server
$server = new Sabre_DAV_Server($nodes);
-$server->setBaseUri(OC::$WEBROOT.'/apps/calendar/caldav.php');
+$server->setBaseUri(OC::$APPSWEBROOT.'/apps/calendar/caldav.php');
// Add plugins
$server->addPlugin(new Sabre_DAV_Auth_Plugin($authBackend,'ownCloud'));
$server->addPlugin(new Sabre_CalDAV_Plugin());
diff --git a/apps/calendar/index.php b/apps/calendar/index.php
index 12b51f564b4..c00a4098f7a 100644
--- a/apps/calendar/index.php
+++ b/apps/calendar/index.php
@@ -9,16 +9,20 @@
require_once ('../../lib/base.php');
OC_Util::checkLoggedIn();
OC_Util::checkAppEnabled('calendar');
+
// Create default calendar ...
$calendars = OC_Calendar_Calendar::allCalendars(OC_User::getUser(), 1);
if( count($calendars) == 0){
OC_Calendar_Calendar::addCalendar(OC_User::getUser(),'Default calendar');
$calendars = OC_Calendar_Calendar::allCalendars(OC_User::getUser(), 1);
}
+
$eventSources = array();
foreach($calendars as $calendar){
$eventSources[] = OC_Calendar_Calendar::getEventSourceInfo($calendar);
}
+OC_Hook::emit('OC_Calendar', 'getSources', array('sources' => &$eventSources));
+
//Fix currentview for fullcalendar
if(OC_Preferences::getValue(OC_USER::getUser(), 'calendar', 'currentview', 'month') == "oneweekview"){
OC_Preferences::setValue(OC_USER::getUser(), "calendar", "currentview", "agendaWeek");
diff --git a/apps/calendar/js/calendar.js b/apps/calendar/js/calendar.js
index 84b76a3c88f..907d94edb02 100644
--- a/apps/calendar/js/calendar.js
+++ b/apps/calendar/js/calendar.js
@@ -73,6 +73,9 @@ Calendar={
}
},
editEvent:function(calEvent, jsEvent, view){
+ if (calEvent.editable == false || calEvent.source.editable == false) {
+ return;
+ }
var id = calEvent.id;
if($('#event').dialog('isOpen') == true){
// TODO: save event
@@ -214,7 +217,7 @@ Calendar={
},
initScroll:function(){
if(window.addEventListener)
- document.addEventListener('DOMMouseScroll', Calendar.UI.scrollCalendar);
+ document.addEventListener('DOMMouseScroll', Calendar.UI.scrollCalendar, false);
//}else{
document.onmousewheel = Calendar.UI.scrollCalendar;
//}
@@ -661,7 +664,7 @@ $(document).ready(function(){
Calendar.UI.initScroll();
$('#calendar_holder').fullCalendar({
header: false,
- firstDay: 1,
+ firstDay: firstDay,
editable: true,
defaultView: defaultView,
timeFormat: {
diff --git a/apps/calendar/js/geo.js b/apps/calendar/js/geo.js
index c9cc5dd0955..7018c6298a2 100755
--- a/apps/calendar/js/geo.js
+++ b/apps/calendar/js/geo.js
@@ -10,7 +10,6 @@ if (navigator.geolocation) {
function(data){
if (data.status == 'success' && typeof(data.message) != 'undefined'){
$('#notification').html(data.message);
- $('#notification').attr('title', 'CC BY 3.0 by Geonames.org');
$('#notification').slideDown();
window.setTimeout(function(){$('#notification').slideUp();}, 5000);
}else{
diff --git a/apps/calendar/js/settings.js b/apps/calendar/js/settings.js
index fcbfc423db3..c768a47a797 100644
--- a/apps/calendar/js/settings.js
+++ b/apps/calendar/js/settings.js
@@ -17,6 +17,14 @@ $(document).ready(function(){
}
});
});
+ $('#firstday').change( function(){
+ var data = $('#firstday').serialize();
+ $.post( OC.filePath('calendar', 'ajax/settings', 'setfirstday.php'), data, function(data){
+ if(data == 'error'){
+ console.log('saving firstday failed');
+ }
+ });
+ });
$('#timezonedetection').change( function(){
var post = $('#timezonedetection').serialize();
$.post( OC.filePath('calendar', 'ajax/settings', 'timezonedetection.php'), post, function(data){
@@ -32,4 +40,8 @@ $(document).ready(function(){
$('#timezonedetection').attr('checked', 'checked');
}
});
+ $.getJSON(OC.filePath('calendar', 'ajax/settings', 'getfirstday.php'), function(jsondata, status) {
+ $('#' + jsondata.firstday).attr('selected',true);
+ $('#firstday').chosen();
+ });
});
diff --git a/apps/calendar/lib/calendar.php b/apps/calendar/lib/calendar.php
index 277539af97d..7eeb004d181 100644
--- a/apps/calendar/lib/calendar.php
+++ b/apps/calendar/lib/calendar.php
@@ -240,9 +240,10 @@ class OC_Calendar_Calendar{
'#9fc6e7', // "light blue"
);
}
+
public static function getEventSourceInfo($calendar){
return array(
- 'url' => 'ajax/events.php?calendar_id='.$calendar['id'],
+ 'url' => OC_Helper::linkTo('calendar', 'ajax/events.php').'?calendar_id='.$calendar['id'],
'backgroundColor' => $calendar['calendarcolor'],
'borderColor' => '#888',
'textColor' => 'black',
diff --git a/apps/calendar/lib/hooks.php b/apps/calendar/lib/hooks.php
index 14f96bb5fe1..54f1680a36e 100644
--- a/apps/calendar/lib/hooks.php
+++ b/apps/calendar/lib/hooks.php
@@ -17,11 +17,24 @@ class OC_Calendar_Hooks{
*/
public static function deleteUser($parameters) {
$calendars = OC_Calendar_Calendar::allCalendars($parameters['uid']);
-
+
foreach($calendars as $calendar) {
OC_Calendar_Calendar::deleteCalendar($calendar['id']);
}
return true;
}
+
+ /**
+ * @brief Adds the CardDAV resource to the DAV server
+ * @param paramters parameters from initialize-Hook
+ * @return array
+ */
+ public static function initializeCalDAV($parameters){
+ // We need a backend, the root node and the caldav plugin
+ $parameters['backends']['caldav'] = new OC_Connector_Sabre_CalDAV();
+ $parameters['nodes'][] = new Sabre_CalDAV_CalendarRootNode($parameters['backends']['principal'], $parameters['backends']['caldav']);
+ $parameters['plugins'][] = new Sabre_CalDAV_Plugin();
+ return true;
+ }
}
diff --git a/apps/calendar/lib/object.php b/apps/calendar/lib/object.php
index 0b2cbb38157..a471aa84034 100644
--- a/apps/calendar/lib/object.php
+++ b/apps/calendar/lib/object.php
@@ -96,8 +96,7 @@ class OC_Calendar_Object{
list($type,$startdate,$enddate,$summary,$repeating,$uid) = self::extractData($object);
if(is_null($uid)){
- $uid = self::createUID();
- $object->add('UID',$uid);
+ $object->setUID();
$data = $object->serialize();
}
@@ -209,14 +208,6 @@ class OC_Calendar_Object{
}
/**
- * @brief Creates a UID
- * @return string
- */
- protected static function createUID(){
- return substr(md5(rand().time()),0,10);
- }
-
- /**
* @brief Extracts data from a vObject-Object
* @param Sabre_VObject $object
* @return array
@@ -309,6 +300,8 @@ class OC_Calendar_Object{
$dtend = $vevent->DTEND;
}else{
$dtend = clone $vevent->DTSTART;
+ // clone creates a shallow copy, also clone DateTime
+ $dtend->setDateTime(clone $dtend->getDateTime(), $dtend->getDateType());
if ($vevent->DURATION){
$duration = strval($vevent->DURATION);
$invert = 0;
@@ -817,4 +810,4 @@ class OC_Calendar_Object{
return $vcalendar;
}
-} \ No newline at end of file
+}
diff --git a/apps/calendar/lib/search.php b/apps/calendar/lib/search.php
index 79c8dba0f4d..10fc3f84346 100644
--- a/apps/calendar/lib/search.php
+++ b/apps/calendar/lib/search.php
@@ -1,6 +1,6 @@
<?php
-class OC_Search_Provider_Calendar extends OC_Search_Provider{
- function search($query){
+class OC_Search_Provider_Calendar implements OC_Search_Provider{
+ static function search($query){
$calendars = OC_Calendar_Calendar::allCalendars(OC_User::getUser(), 1);
if(count($calendars)==0 || !OC_App::isEnabled('calendar')){
//return false;
@@ -44,4 +44,3 @@ class OC_Search_Provider_Calendar extends OC_Search_Provider{
return $results;
}
}
-new OC_Search_Provider_Calendar();
diff --git a/apps/calendar/templates/calendar.php b/apps/calendar/templates/calendar.php
index eb82d0d02ad..63c3b500296 100755
--- a/apps/calendar/templates/calendar.php
+++ b/apps/calendar/templates/calendar.php
@@ -19,6 +19,7 @@
var missing_field_startsbeforeends = '<?php echo addslashes($l->t('The event ends before it starts')) ?>';
var missing_field_dberror = '<?php echo addslashes($l->t('There was a database fail')) ?>';
var totalurl = '<?php echo OC_Helper::linkToAbsolute('calendar', 'caldav.php'); ?>/calendars';
+ var firstDay = '<?php echo (OC_Preferences::getValue(OC_USER::getUser(), 'calendar', 'firstday', 'mo') == 'mo' ? '1' : '0'); ?>';
$(document).ready(function() {
<?php
if(array_key_exists('showevent', $_)){
diff --git a/apps/calendar/templates/settings.php b/apps/calendar/templates/settings.php
index 979634874e4..fb2a04a6498 100644
--- a/apps/calendar/templates/settings.php
+++ b/apps/calendar/templates/settings.php
@@ -31,12 +31,19 @@
</select><input type="checkbox" name="timezonedetection" id="timezonedetection"><label for="timezonedetection"><?php echo $l->t('Check always for changes of the timezone'); ?></label></td></tr>
<tr><td><label for="timeformat" class="bold"><?php echo $l->t('Timeformat');?></label></td><td>
- <select style="display: none;" id="timeformat" title="<?php echo "timeformat"; ?>" name="timeformat">
+ <select style="display: none; width: 60px;" id="timeformat" title="<?php echo "timeformat"; ?>" name="timeformat">
<option value="24" id="24h"><?php echo $l->t("24h"); ?></option>
<option value="ampm" id="ampm"><?php echo $l->t("12h"); ?></option>
</select>
</td></tr>
+ <tr><td><label for="firstday" class="bold"><?php echo $l->t('First day of the week');?></label></td><td>
+ <select style="display: none;" id="firstday" title="<?php echo "First day"; ?>" name="firstday">
+ <option value="mo" id="mo"><?php echo $l->t("Monday"); ?></option>
+ <option value="su" id="su"><?php echo $l->t("Sunday"); ?></option>
+ </select>
+ </td></tr>
+
</table>
<?php echo $l->t('Calendar CalDAV syncing address:');?>
diff --git a/apps/contacts/ajax/addcard.php b/apps/contacts/ajax/addcard.php
deleted file mode 100644
index b1dc69a4691..00000000000
--- a/apps/contacts/ajax/addcard.php
+++ /dev/null
@@ -1,103 +0,0 @@
-<?php
-/**
- * ownCloud - Addressbook
- *
- * @author Jakob Sack
- * @copyright 2011 Jakob Sack mail@jakobsack.de
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * 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/>.
- *
- */
-
-// Init owncloud
-require_once('../../../lib/base.php');
-function bailOut($msg) {
- OC_JSON::error(array('data' => array('message' => $msg)));
- OC_Log::write('contacts','ajax/addcard.php: '.$msg, OC_Log::DEBUG);
- exit();
-}
-
-// Check if we are a user
-OC_JSON::checkLoggedIn();
-OC_JSON::checkAppEnabled('contacts');
-
-$aid = $_POST['id'];
-OC_Contacts_App::getAddressbook( $aid ); // is owner access check
-
-$fn = trim($_POST['fn']);
-$values = $_POST['value'];
-$parameters = $_POST['parameters'];
-
-$vcard = new OC_VObject('VCARD');
-$vcard->setUID();
-
-$n = isset($values['N'][0])?trim($values['N'][0]).';':';';
-$n .= isset($values['N'][1])?trim($values['N'][1]).';':';';
-$n .= isset($values['N'][2])?trim($values['N'][2]).';;':';;';
-
-if(!$fn || ($n == ';;;;')) {
- bailOut('You have to enter both the extended name and the display name.');
-}
-
-$vcard->setString('N',$n);
-$vcard->setString('FN',$fn);
-
-// Data to add ...
-$add = array('TEL', 'EMAIL', 'ORG');
-$address = false;
-for($i = 0; $i < 7; $i++){
- if( isset($values['ADR'][$i] ) && $values['ADR'][$i]) $address = true;
-}
-if( $address ) $add[] = 'ADR';
-
-// Add data
-foreach( $add as $propname){
- if( !( isset( $values[$propname] ) && $values[$propname] )){
- continue;
- }
- $value = $values[$propname];
- if( isset( $parameters[$propname] ) && count( $parameters[$propname] )){
- $prop_parameters = $parameters[$propname];
- } else {
- $prop_parameters = array();
- }
- if(is_array($value)){
- ksort($value); // NOTE: Important, otherwise the compound value will be set in the order the fields appear in the form!
- $value = OC_VObject::escapeSemicolons($value);
- }
- $vcard->addProperty($propname, strip_tags($value)); //, $prop_parameters);
- $line = count($vcard->children) - 1;
- foreach ($prop_parameters as $key=>$element) {
- if(is_array($element) && strtoupper($key) == 'TYPE') {
- // FIXME: Maybe this doesn't only apply for TYPE?
- // And it probably shouldn't be done here anyways :-/
- foreach($element as $e){
- if($e != '' && !is_null($e)){
- $vcard->children[$line]->parameters[] = new Sabre_VObject_Parameter($key,$e);
- }
- }
- } else {
- $vcard->children[$line]->parameters[] = new Sabre_VObject_Parameter($key,$element);
- }
- }
-}
-$id = OC_Contacts_VCard::add($aid,$vcard->serialize());
-if(!$id) {
- OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('There was an error adding the contact.'))));
- OC_Log::write('contacts','ajax/addcard.php: Recieved non-positive ID on adding card: '.$id, OC_Log::ERROR);
- exit();
-}
-
-// NOTE: Why is this in OC_Contacts_App?
-OC_Contacts_App::renderDetails($id, $vcard);
diff --git a/apps/contacts/ajax/addcontact.php b/apps/contacts/ajax/addcontact.php
index 5d17631caa4..839a3919981 100644
--- a/apps/contacts/ajax/addcontact.php
+++ b/apps/contacts/ajax/addcontact.php
@@ -52,7 +52,7 @@ $vcard->setUID();
$vcard->setString('FN',$fn);
$vcard->setString('N',$n);
-$id = OC_Contacts_VCard::add($aid,$vcard->serialize());
+$id = OC_Contacts_VCard::add($aid,$vcard);
if(!$id) {
OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('There was an error adding the contact.'))));
OC_Log::write('contacts','ajax/addcontact.php: Recieved non-positive ID on adding card: '.$id, OC_Log::ERROR);
diff --git a/apps/contacts/ajax/addproperty.php b/apps/contacts/ajax/addproperty.php
index 028974e1c66..e1a31292837 100644
--- a/apps/contacts/ajax/addproperty.php
+++ b/apps/contacts/ajax/addproperty.php
@@ -27,14 +27,16 @@ require_once('../../../lib/base.php');
OC_JSON::checkLoggedIn();
OC_JSON::checkAppEnabled('contacts');
-$id = $_POST['id'];
-$vcard = OC_Contacts_App::getContactVCard( $id );
+$id = isset($_POST['id'])?$_POST['id']:null;
+$name = isset($_POST['name'])?$_POST['name']:null;
+$value = isset($_POST['value'])?$_POST['value']:null;
+$parameters = isset($_POST['parameters'])?$_POST['parameters']:array();
+
+$vcard = OC_Contacts_App::getContactVCard($id);
-$name = $_POST['name'];
-$value = $_POST['value'];
if(!is_array($value)){
$value = trim($value);
- if(!$value && in_array($name, array('TEL', 'EMAIL', 'ORG', 'BDAY', 'NICKNAME'))) {
+ if(!$value && in_array($name, array('TEL', 'EMAIL', 'ORG', 'BDAY', 'NICKNAME', 'NOTE'))) {
OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('Cannot add empty property.'))));
exit();
}
@@ -51,7 +53,6 @@ if(!is_array($value)){
exit();
}
}
-$parameters = isset($_POST['parameters']) ? $_POST['parameters'] : array();
// Prevent setting a duplicate entry
$current = $vcard->select($name);
@@ -82,7 +83,9 @@ switch($name) {
}
case 'N':
case 'ORG':
+ case 'NOTE':
case 'NICKNAME':
+ // TODO: Escape commas and semicolons.
break;
case 'EMAIL':
$value = strtolower($value);
@@ -113,7 +116,7 @@ foreach ($parameters as $key=>$element) {
}
$checksum = md5($vcard->children[$line]->serialize());
-if(!OC_Contacts_VCard::edit($id,$vcard->serialize())) {
+if(!OC_Contacts_VCard::edit($id,$vcard)) {
OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('Error adding contact property.'))));
OC_Log::write('contacts','ajax/addproperty.php: Error updating contact property: '.$name, OC_Log::ERROR);
exit();
diff --git a/apps/contacts/ajax/categories/categoriesfor.php b/apps/contacts/ajax/categories/categoriesfor.php
new file mode 100644
index 00000000000..c02c37914a2
--- /dev/null
+++ b/apps/contacts/ajax/categories/categoriesfor.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+require_once('../../../../lib/base.php');
+OC_JSON::checkLoggedIn();
+OC_JSON::checkAppEnabled('contacts');
+
+$id = isset($_GET['id'])?$_GET['id']:null;
+if(is_null($id)) {
+ OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('No ID provided'))));
+ exit();
+}
+$vcard = OC_Contacts_App::getContactVCard( $id );
+foreach($vcard->children as $property){
+ //OC_Log::write('contacts','ajax/categories/checksumfor.php: '.$property->name, OC_Log::DEBUG);
+ if($property->name == 'CATEGORIES') {
+ $checksum = md5($property->serialize());
+ OC_JSON::success(array('data' => array('value'=>$property->value, 'checksum'=>$checksum)));
+ exit();
+ }
+}
+OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('Error setting checksum.'))));
+?>
diff --git a/apps/contacts/ajax/categories/delete.php b/apps/contacts/ajax/categories/delete.php
new file mode 100644
index 00000000000..3ba5aa16068
--- /dev/null
+++ b/apps/contacts/ajax/categories/delete.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+require_once('../../../../lib/base.php');
+OC_JSON::checkLoggedIn();
+OC_JSON::checkAppEnabled('contacts');
+
+foreach ($_POST as $key=>$element) {
+ debug('_POST: '.$key.'=>'.print_r($element, true));
+}
+
+function bailOut($msg) {
+ OC_JSON::error(array('data' => array('message' => $msg)));
+ OC_Log::write('contacts','ajax/categories/delete.php: '.$msg, OC_Log::DEBUG);
+ exit();
+}
+function debug($msg) {
+ OC_Log::write('contacts','ajax/categories/delete.php: '.$msg, OC_Log::DEBUG);
+}
+
+$categories = isset($_POST['categories'])?$_POST['categories']:null;
+
+if(is_null($categories)) {
+ bailOut(OC_Contacts_App::$l10n->t('No categories selected for deletion.'));
+}
+
+debug(print_r($categories, true));
+
+$addressbooks = OC_Contacts_Addressbook::all(OC_User::getUser());
+if(count($addressbooks) == 0) {
+ bailOut(OC_Contacts_App::$l10n->t('No address books found.'));
+}
+$addressbookids = array();
+foreach($addressbooks as $addressbook) {
+ $addressbookids[] = $addressbook['id'];
+}
+$contacts = OC_Contacts_VCard::all($addressbookids);
+if(count($contacts) == 0) {
+ bailOut(OC_Contacts_App::$l10n->t('No contacts found.'));
+}
+
+$cards = array();
+foreach($contacts as $contact) {
+ $cards[] = array($contact['id'], $contact['carddata']);
+}
+
+debug('Before delete: '.print_r($categories, true));
+
+$catman = new OC_VCategories('contacts');
+$catman->delete($categories, $cards);
+debug('After delete: '.print_r($catman->categories(), true));
+OC_Contacts_VCard::updateDataByID($cards);
+OC_JSON::success(array('data' => array('categories'=>$catman->categories())));
+
+?>
diff --git a/apps/contacts/ajax/categories/list.php b/apps/contacts/ajax/categories/list.php
new file mode 100644
index 00000000000..3b41b7bfa95
--- /dev/null
+++ b/apps/contacts/ajax/categories/list.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+require_once('../../../../lib/base.php');
+OC_JSON::checkLoggedIn();
+OC_JSON::checkAppEnabled('contacts');
+
+$categories = OC_Contacts_App::$categories->categories();
+
+OC_JSON::success(array('data' => array('categories'=>$categories)));
+
+?>
diff --git a/apps/contacts/ajax/categories/rescan.php b/apps/contacts/ajax/categories/rescan.php
new file mode 100644
index 00000000000..dd27192baa0
--- /dev/null
+++ b/apps/contacts/ajax/categories/rescan.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+require_once('../../../../lib/base.php');
+OC_JSON::checkLoggedIn();
+OC_JSON::checkAppEnabled('contacts');
+
+foreach ($_POST as $key=>$element) {
+ debug('_POST: '.$key.'=>'.print_r($element, true));
+}
+
+function bailOut($msg) {
+ OC_JSON::error(array('data' => array('message' => $msg)));
+ OC_Log::write('contacts','ajax/categories/rescan.php: '.$msg, OC_Log::DEBUG);
+ exit();
+}
+function debug($msg) {
+ OC_Log::write('contacts','ajax/categories/rescan.php: '.$msg, OC_Log::DEBUG);
+}
+
+$addressbooks = OC_Contacts_Addressbook::all(OC_User::getUser());
+if(count($addressbooks) == 0) {
+ bailOut(OC_Contacts_App::$l10n->t('No address books found.'));
+}
+$addressbookids = array();
+foreach($addressbooks as $addressbook) {
+ $addressbookids[] = $addressbook['id'];
+}
+$contacts = OC_Contacts_VCard::all($addressbookids);
+if(count($contacts) == 0) {
+ bailOut(OC_Contacts_App::$l10n->t('No contacts found.'));
+}
+
+$cards = array();
+foreach($contacts as $contact) {
+ $cards[] = $contact['carddata'];
+}
+
+OC_Contacts_App::$categories->rescan($cards);
+$categories = OC_Contacts_App::$categories->categories();
+
+OC_JSON::success(array('data' => array('categories'=>$categories)));
+
+?>
diff --git a/apps/contacts/ajax/contactdetails.php b/apps/contacts/ajax/contactdetails.php
index f35fd595c56..03895c862aa 100644
--- a/apps/contacts/ajax/contactdetails.php
+++ b/apps/contacts/ajax/contactdetails.php
@@ -71,5 +71,5 @@ if(isset($details['PHOTO'])) {
$details['PHOTO'] = false;
}
$details['id'] = $id;
-
+OC_Contacts_App::setLastModifiedHeader($vcard);
OC_JSON::success(array('data' => $details));
diff --git a/apps/contacts/ajax/deleteproperty.php b/apps/contacts/ajax/deleteproperty.php
index a9afffaad4c..ab0958cac58 100644
--- a/apps/contacts/ajax/deleteproperty.php
+++ b/apps/contacts/ajax/deleteproperty.php
@@ -39,7 +39,7 @@ if(is_null($line)){
unset($vcard->children[$line]);
-if(!OC_Contacts_VCard::edit($id,$vcard->serialize())) {
+if(!OC_Contacts_VCard::edit($id,$vcard)) {
OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('Error deleting contact property.'))));
OC_Log::write('contacts','ajax/deleteproperty.php: Error deleting contact property', OC_Log::ERROR);
exit();
diff --git a/apps/contacts/ajax/showsetproperty.php b/apps/contacts/ajax/loadcard.php
index 73bef655351..037fe2a6df2 100644
--- a/apps/contacts/ajax/showsetproperty.php
+++ b/apps/contacts/ajax/loadcard.php
@@ -2,8 +2,8 @@
/**
* ownCloud - Addressbook
*
- * @author Jakob Sack
- * @copyright 2011 Jakob Sack mail@jakobsack.de
+ * @author Thomas Tanghus
+ * @copyright 2012 Thomas Tanghus <thomas@tanghus.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@@ -22,31 +22,38 @@
// Init owncloud
require_once('../../../lib/base.php');
+function bailOut($msg) {
+ OC_JSON::error(array('data' => array('message' => $msg)));
+ OC_Log::write('contacts','ajax/loadcard.php: '.$msg, OC_Log::DEBUG);
+ exit();
+}
+function debug($msg) {
+ OC_Log::write('contacts','ajax/loadcard.php: '.$msg, OC_Log::DEBUG);
+}
+// foreach ($_POST as $key=>$element) {
+// debug('_POST: '.$key.'=>'.$element);
+// }
// Check if we are a user
OC_JSON::checkLoggedIn();
OC_JSON::checkAppEnabled('contacts');
-$id = $_GET['id'];
-$checksum = $_GET['checksum'];
-
-$vcard = OC_Contacts_App::getContactVCard( $id );
-
-$line = OC_Contacts_App::getPropertyLineByChecksum($vcard, $checksum);
-if(is_null($line)){
- OC_JSON::error(array('data' => array( 'message' => OC_Contacts_App::$l10n->t('Information about vCard is incorrect. Please reload the page.'))));
- exit();
-}
+$upload_max_filesize = OC_Helper::computerFileSize(ini_get('upload_max_filesize'));
+$post_max_size = OC_Helper::computerFileSize(ini_get('post_max_size'));
+$maxUploadFilesize = min($upload_max_filesize, $post_max_size);
+$freeSpace=OC_Filesystem::free_space('/');
+$freeSpace=max($freeSpace,0);
+$maxUploadFilesize = min($maxUploadFilesize ,$freeSpace);
$adr_types = OC_Contacts_App::getTypesOfProperty('ADR');
$phone_types = OC_Contacts_App::getTypesOfProperty('TEL');
-$tmpl = new OC_Template('contacts','part.setpropertyform');
-$tmpl->assign('id',$id);
-$tmpl->assign('checksum',$checksum);
-$tmpl->assign('property',OC_Contacts_VCard::structureProperty($vcard->children[$line]));
+$tmpl = new OC_Template('contacts','part.contact');
+$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize);
+$tmpl->assign('uploadMaxHumanFilesize', OC_Helper::humanFileSize($maxUploadFilesize));
$tmpl->assign('adr_types',$adr_types);
$tmpl->assign('phone_types',$phone_types);
+$tmpl->assign('id','');
$page = $tmpl->fetchPage();
OC_JSON::success(array('data' => array( 'page' => $page )));
diff --git a/apps/contacts/ajax/loadphoto.php b/apps/contacts/ajax/loadphoto.php
index 358e046942b..2c8bb7bf1ed 100644
--- a/apps/contacts/ajax/loadphoto.php
+++ b/apps/contacts/ajax/loadphoto.php
@@ -18,8 +18,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: Translatable strings.
- * Remember to delete tmp file at some point.
*/
// Init owncloud
require_once('../../../lib/base.php');
@@ -33,7 +31,7 @@ OC_JSON::checkAppEnabled('contacts');
function bailOut($msg) {
OC_JSON::error(array('data' => array('message' => $msg)));
- OC_Log::write('contacts','ajax/savecrop.php: '.$msg, OC_Log::DEBUG);
+ OC_Log::write('contacts','ajax/loadphoto.php: '.$msg, OC_Log::DEBUG);
exit();
}
@@ -42,11 +40,20 @@ $image = null;
$id = isset($_GET['id']) ? $_GET['id'] : '';
if($id == '') {
- bailOut('Missing contact id.');
+ bailOut(OC_Contacts_App::$l10n->t('Missing contact id.'));
+}
+
+$checksum = '';
+$vcard = OC_Contacts_App::getContactVCard( $id );
+foreach($vcard->children as $property){
+ if($property->name == 'PHOTO') {
+ $checksum = md5($property->serialize());
+ break;
+ }
}
$tmpl = new OC_TEMPLATE("contacts", "part.contactphoto");
$tmpl->assign('id', $id);
$page = $tmpl->fetchPage();
-OC_JSON::success(array('data' => array('page'=>$page)));
+OC_JSON::success(array('data' => array('page'=>$page, 'checksum'=>$checksum)));
?>
diff --git a/apps/contacts/ajax/messagebox.php b/apps/contacts/ajax/messagebox.php
deleted file mode 100644
index 408e7a537aa..00000000000
--- a/apps/contacts/ajax/messagebox.php
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-/**
- * Copyright (c) 2011 Thomas Tanghus <thomas@tanghus.net>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
- */
-
-require_once('../../../lib/base.php');
-OC_JSON::checkLoggedIn();
-OC_JSON::checkAppEnabled('contacts');
-
-$output = new OC_TEMPLATE("contacts", "part.messagebox");
-$output -> printpage();
-?>
diff --git a/apps/contacts/ajax/savecrop.php b/apps/contacts/ajax/savecrop.php
index 1a84f6fdfae..0df4e1998cb 100644
--- a/apps/contacts/ajax/savecrop.php
+++ b/apps/contacts/ajax/savecrop.php
@@ -95,7 +95,7 @@ if(file_exists($tmp_path)) {
OC_Log::write('contacts','savecrop.php: files: Adding PHOTO property.', OC_Log::DEBUG);
$card->addProperty('PHOTO', $image->__toString(), array('ENCODING' => 'b', 'TYPE' => $image->mimeType()));
}
- if(!OC_Contacts_VCard::edit($id,$card->serialize())) {
+ if(!OC_Contacts_VCard::edit($id,$card)) {
bailOut('Error saving contact.');
}
unlink($tmpfname);
@@ -104,6 +104,7 @@ if(file_exists($tmp_path)) {
$tmpl->assign('tmp_path', $tmpfname);
$tmpl->assign('mime', $image->mimeType());
$tmpl->assign('id', $id);
+ $tmpl->assign('refresh', true);
$tmpl->assign('width', $image->width());
$tmpl->assign('height', $image->height());
$page = $tmpl->fetchPage();
diff --git a/apps/contacts/ajax/saveproperty.php b/apps/contacts/ajax/saveproperty.php
index 6f8366243fe..95a7ac20193 100644
--- a/apps/contacts/ajax/saveproperty.php
+++ b/apps/contacts/ajax/saveproperty.php
@@ -36,7 +36,7 @@ function debug($msg) {
OC_Log::write('contacts','ajax/saveproperty.php: '.$msg, OC_Log::DEBUG);
}
foreach ($_POST as $key=>$element) {
- debug('_POST: '.$key.'=>'.$element);
+ debug('_POST: '.$key.'=>'.print_r($element, true));
}
$id = isset($_POST['id'])?$_POST['id']:null;
@@ -51,12 +51,8 @@ $checksum = isset($_POST['checksum'])?$_POST['checksum']:null;
// }
// }
-if(is_array($value)){
- $value = array_map('strip_tags', $value);
- ksort($value); // NOTE: Important, otherwise the compound value will be set in the order the fields appear in the form!
- $value = OC_VObject::escapeSemicolons($value);
-} else {
- $value = trim(strip_tags($value));
+if(!$name) {
+ bailOut(OC_Contacts_App::$l10n->t('element name is not set.'));
}
if(!$id) {
bailOut(OC_Contacts_App::$l10n->t('id is not set.'));
@@ -64,14 +60,22 @@ if(!$id) {
if(!$checksum) {
bailOut(OC_Contacts_App::$l10n->t('checksum is not set.'));
}
-if(!$name) {
- bailOut(OC_Contacts_App::$l10n->t('element name is not set.'));
+if(is_array($value)){
+ $value = array_map('strip_tags', $value);
+ ksort($value); // NOTE: Important, otherwise the compound value will be set in the order the fields appear in the form!
+ //if($name == 'CATEGORIES') {
+ // $value = OC_Contacts_VCard::escapeDelimiters($value, ',');
+ //} else {
+ $value = OC_Contacts_VCard::escapeDelimiters($value, ';');
+ //}
+} else {
+ $value = trim(strip_tags($value));
}
$vcard = OC_Contacts_App::getContactVCard( $id );
$line = OC_Contacts_App::getPropertyLineByChecksum($vcard, $checksum);
if(is_null($line)) {
- bailOut(OC_Contacts_App::$l10n->t('Information about vCard is incorrect. Please reload the page.'.$checksum.' "'.$line.'"'));
+ bailOut(OC_Contacts_App::$l10n->t('Information about vCard is incorrect. Please reload the page: ').$checksum);
}
$element = $vcard->children[$line]->name;
@@ -91,7 +95,9 @@ switch($element) {
}
case 'N':
case 'ORG':
+ case 'NOTE':
case 'NICKNAME':
+ case 'CATEGORIES':
debug('Setting string:'.$name.' '.$value);
$vcard->setString($name, $value);
break;
@@ -122,13 +128,9 @@ switch($element) {
$checksum = md5($vcard->children[$line]->serialize());
debug('New checksum: '.$checksum);
-if(!OC_Contacts_VCard::edit($id,$vcard->serialize())) {
- OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('Error updating contact property.'))));
- OC_Log::write('contacts','ajax/setproperty.php: Error updating contact property: '.$value, OC_Log::ERROR);
+if(!OC_Contacts_VCard::edit($id,$vcard)) {
+ bailOut(OC_Contacts_App::$l10n->t('Error updating contact property.'));
exit();
}
-//$adr_types = OC_Contacts_App::getTypesOfProperty('ADR');
-//$phone_types = OC_Contacts_App::getTypesOfProperty('TEL');
-
OC_JSON::success(array('data' => array( 'line' => $line, 'checksum' => $checksum, 'oldchecksum' => $_POST['checksum'] )));
diff --git a/apps/contacts/ajax/setproperty.php b/apps/contacts/ajax/setproperty.php
deleted file mode 100644
index f9e2a8e8647..00000000000
--- a/apps/contacts/ajax/setproperty.php
+++ /dev/null
@@ -1,106 +0,0 @@
-<?php
-/**
- * ownCloud - Addressbook
- *
- * @author Jakob Sack
- * @copyright 2011 Jakob Sack mail@jakobsack.de
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * 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/>.
- *
- */
-
-// Init owncloud
-require_once('../../../lib/base.php');
-
-// Check if we are a user
-OC_JSON::checkLoggedIn();
-OC_JSON::checkAppEnabled('contacts');
-
-$id = $_POST['id'];
-$checksum = $_POST['checksum'];
-
-$vcard = OC_Contacts_App::getContactVCard( $id );
-$line = OC_Contacts_App::getPropertyLineByChecksum($vcard, $checksum);
-
-// Set the value
-$value = $_POST['value'];
-if(is_array($value)){
- ksort($value); // NOTE: Important, otherwise the compound value will be set in the order the fields appear in the form!
- foreach(array_keys($value) as $key) {
- OC_Log::write('contacts','ajax/setproperty.php: setting: '.$key.': '.$value[$key], OC_Log::DEBUG);
- }
- $value = OC_VObject::escapeSemicolons($value);
-}
-OC_Log::write('contacts','ajax/setproperty.php: setting: '.$vcard->children[$line]->name.': '.$value, OC_Log::DEBUG);
-$vcard->children[$line]->setValue(strip_tags($value));
-
-// Add parameters
-$postparameters = isset($_POST['parameters'])?$_POST['parameters']:array();
-if ($vcard->children[$line]->name == 'TEL' && !array_key_exists('TYPE', $postparameters)){
- $postparameters['TYPE']='';
-}
-for($i=0;$i<count($vcard->children[$line]->parameters);$i++){
- $name = $vcard->children[$line]->parameters[$i]->name;
- if(array_key_exists($name,$postparameters)){
- if($postparameters[$name] == '' || is_null($postparameters[$name])){
- unset($vcard->children[$line]->parameters[$i]);
- }
- else{
- unset($vcard->children[$line][$name]);
- $values = $postparameters[$name];
- if (!is_array($values)){
- $values = array($values);
- }
- foreach($values as $value){
- $vcard->children[$line]->add($name, $value);
- }
- }
- unset($postparameters[$name]);
- }
-}
-$missingparameters = array_keys($postparameters);
-foreach($missingparameters as $i){
- if(!$postparameters[$i] == '' && !is_null($postparameters[$i])){
- $vcard->children[$line]->parameters[] = new Sabre_VObject_Parameter($i,$postparameters[$i]);
- }
-}
-
-// Do checksum and be happy
-// NOTE: This checksum is not used..?
-$checksum = md5($vcard->children[$line]->serialize());
-
-if(!OC_Contacts_VCard::edit($id,$vcard->serialize())) {
- OC_JSON::error(array('data' => array('message' => $l->t('Error updating contact property.'))));
- OC_Log::write('contacts','ajax/setproperty.php: Error updating contact property: '.$value, OC_Log::ERROR);
- exit();
-}
-
-$adr_types = OC_Contacts_App::getTypesOfProperty('ADR');
-$phone_types = OC_Contacts_App::getTypesOfProperty('TEL');
-
-if ($vcard->children[$line]->name == 'FN'){
- $tmpl = new OC_Template('contacts','part.property.FN');
-}
-elseif ($vcard->children[$line]->name == 'N'){
- $tmpl = new OC_Template('contacts','part.property.N');
-}
-else{
- $tmpl = new OC_Template('contacts','part.property');
-}
-$tmpl->assign('adr_types',$adr_types);
-$tmpl->assign('phone_types',$phone_types);
-$tmpl->assign('property',OC_Contacts_VCard::structureProperty($vcard->children[$line],$line));
-$page = $tmpl->fetchPage();
-
-OC_JSON::success(array('data' => array( 'page' => $page, 'line' => $line, 'checksum' => $checksum, 'oldchecksum' => $_POST['checksum'] )));
diff --git a/apps/contacts/ajax/showaddcard.php b/apps/contacts/ajax/showaddcard.php
deleted file mode 100644
index 54592c89c0d..00000000000
--- a/apps/contacts/ajax/showaddcard.php
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-/**
- * ownCloud - Addressbook
- *
- * @author Jakob Sack
- * @copyright 2011 Jakob Sack mail@jakobsack.de
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * 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/>.
- *
- */
-
-// Init owncloud
-require_once('../../../lib/base.php');
-
-// Check if we are a user
-OC_JSON::checkLoggedIn();
-OC_JSON::checkAppEnabled('contacts');
-
-$adr_types = OC_Contacts_App::getTypesOfProperty('ADR');
-$phone_types = OC_Contacts_App::getTypesOfProperty('TEL');
-
-$addressbooks = OC_Contacts_Addressbook::all(OC_USER::getUser());
-$tmpl = new OC_Template('contacts','part.addcardform');
-$tmpl->assign('addressbooks',$addressbooks);
-$tmpl->assign('adr_types',$adr_types);
-$tmpl->assign('phone_types',$phone_types);
-$page = $tmpl->fetchPage();
-
-OC_JSON::success(array('data' => array( 'page' => $page )));
diff --git a/apps/contacts/ajax/showaddproperty.php b/apps/contacts/ajax/showaddproperty.php
deleted file mode 100644
index 30eb7634f80..00000000000
--- a/apps/contacts/ajax/showaddproperty.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-/**
- * ownCloud - Addressbook
- *
- * @author Jakob Sack
- * @copyright 2011 Jakob Sack mail@jakobsack.de
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * 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/>.
- *
- */
-
-// Init owncloud
-require_once('../../../lib/base.php');
-
-// Check if we are a user
-OC_JSON::checkLoggedIn();
-OC_JSON::checkAppEnabled('contacts');
-
-$id = $_GET['id'];
-$card = OC_Contacts_App::getContactObject( $id );
-
-$tmpl = new OC_Template('contacts','part.addpropertyform');
-$tmpl->assign('id',$id);
-$page = $tmpl->fetchPage();
-
-OC_JSON::success(array('data' => array( 'page' => $page )));
diff --git a/apps/contacts/appinfo/app.php b/apps/contacts/appinfo/app.php
index 9e424aa89f8..85c383c4c32 100644
--- a/apps/contacts/appinfo/app.php
+++ b/apps/contacts/appinfo/app.php
@@ -4,7 +4,11 @@ OC::$CLASSPATH['OC_Contacts_Addressbook'] = 'apps/contacts/lib/addressbook.php';
OC::$CLASSPATH['OC_Contacts_VCard'] = 'apps/contacts/lib/vcard.php';
OC::$CLASSPATH['OC_Contacts_Hooks'] = 'apps/contacts/lib/hooks.php';
OC::$CLASSPATH['OC_Connector_Sabre_CardDAV'] = 'apps/contacts/lib/connector_sabre.php';
+OC::$CLASSPATH['OC_Search_Provider_Contacts'] = 'apps/contacts/lib/search.php';
OC_HOOK::connect('OC_User', 'post_deleteUser', 'OC_Contacts_Hooks', 'deleteUser');
+OC_HOOK::connect('OC_Calendar', 'getEvents', 'OC_Contacts_Hooks', 'getBirthdayEvents');
+OC_HOOK::connect('OC_Calendar', 'getSources', 'OC_Contacts_Hooks', 'getCalenderSources');
+OC_Hook::connect('OC_DAV', 'initialize', 'OC_Contacts_Hooks', 'initializeCardDAV');
OC_App::register( array(
'order' => 10,
@@ -21,4 +25,4 @@ OC_App::addNavigationEntry( array(
OC_APP::registerPersonal('contacts','settings');
OC_UTIL::addScript('contacts', 'loader');
-require_once('apps/contacts/lib/search.php');
+OC_Search::registerProvider('OC_Search_Provider_Contacts');
diff --git a/apps/contacts/carddav.php b/apps/contacts/carddav.php
index a2bf492e206..654aeb66a72 100644
--- a/apps/contacts/carddav.php
+++ b/apps/contacts/carddav.php
@@ -39,7 +39,7 @@ $nodes = array(
// Fire up server
$server = new Sabre_DAV_Server($nodes);
-$server->setBaseUri(OC::$WEBROOT.'/apps/contacts/carddav.php');
+$server->setBaseUri(OC::$APPSWEBROOT.'/apps/contacts/carddav.php');
// Add plugins
$server->addPlugin(new Sabre_DAV_Auth_Plugin($authBackend,'ownCloud'));
$server->addPlugin(new Sabre_CardDAV_Plugin());
diff --git a/apps/contacts/css/contacts.css b/apps/contacts/css/contacts.css
index b24ec438f24..7c36a511d6e 100644
--- a/apps/contacts/css/contacts.css
+++ b/apps/contacts/css/contacts.css
@@ -20,7 +20,8 @@
#firstrun { width: 100%; position: absolute; top: 5em; left: 0; text-align: center; font-weight:bold; font-size:1.5em; color:#777; }
#firstrun #selections { font-size:0.8em; margin: 2em auto auto auto; clear: both; }
-#card input[type="text"].contacts_property,input[type="email"].contacts_property { width: 16em; }
+#card input[type="text"].contacts_property,input[type="email"].contacts_property { width: 14em; }
+.categories { float: left; width: 16em; }
#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; }
@@ -68,7 +69,7 @@ dl.form
/*background-color: yellow;*/
}
-.loading { background: url('../../../core/img/loading.gif') no-repeat center !important;}
+.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; }*/
@@ -185,4 +186,5 @@ input[type="checkbox"] { width: 20px; height: 20px; vertical-align: bottom; }
.propertylist li > input[type="checkbox"],input[type="radio"] { float: left; clear: left; width: 20px; height: 20px; vertical-align: middle; }
.propertylist li > select { float: left; max-width: 8em; }
.typelist { float: left; max-width: 10em; } /* for multiselect */
-.addresslist { clear: both; } \ No newline at end of file
+.addresslist { clear: both; }
+
diff --git a/apps/contacts/css/styles.css b/apps/contacts/css/styles.css
deleted file mode 100644
index 58e1bf6c93e..00000000000
--- a/apps/contacts/css/styles.css
+++ /dev/null
@@ -1,37 +0,0 @@
-#contacts { padding-left:2px; padding-top: 5px; background: #fff; }
-#leftcontent a { height: 23px; display: block; margin: 0 0 0 0; padding: 0 0 0 25px; }
-#chooseaddressbook {margin-right: 170px; float: right;}
-#contacts_details_name { font-weight:bold;font-size:1.1em;margin-left:25%;}
-#contacts_details_name_n { font-size:0.8em;margin-left:25%;color:#666;}
-#contacts_details_photo { margin:.5em 0em .5em 25%; }
-
-#contacts_deletecard {position:absolute;top:15px;right:25px;}
-#contacts_downloadcard {position:absolute;top:15px;right:50px;}
-#contacts_details_list { list-style:none; }
-#contacts_details_list li { overflow:visible; }
-#contacts_details_list li p.contacts_property_name { width:25%; float:left;text-align:right;padding-right:0.3em;color:#666; }
-#contacts_details_list li p.contacts_property_data, #contacts_details_list li ul.contacts_property_data { width:72%;float:left; clear: right; }
-#contacts_setproperty_button { margin-left:25%; }
-
-#contacts_addcardform legend,label { font-weight: bold; width: 10em; overflow: ellipsis; }
-#contacts_addcardform legend { padding-left: 3em; font-size:1.1em; }
-#contacts_addcardform input[type="text"] { width: 25em; }
-#contacts_addcardform input[type="email"] { width: 15em; }
-#contacts_addcardform input[type="tel"] { width: 15em; }
-
-dl.form { width: 100%; float: left; clear: right; margin: 1em; padding: 0; }
-.form dt { display: table-cell; clear: left; float: left; min-width: 10em; margin: 0; padding-top: 0.5em; padding-right: 1em;font-weight: bold; text-align:right; vertical-align: text-bottom; bottom: 0px; }
-.form dd { display: table-cell; clear: right; float: left; min-width: 20em; margin: 0; padding: 0; white-space: nowrap; top: 0px; }
-.form input { position: relative; width: 20em; }
-
-.contacts_property_data ul, ol.contacts_property_data { list-style:none; }
-.contacts_property_data li { overflow: hidden; }
-.contacts_property_data li label { width:20%; float:left; text-align:right;padding-right:0.3em; }
-.contacts_property_data input { float:left; }
-.contacts_property_data li input { width:70%;overflow:hidden; }
-
-.chzn-container { margin:3px 0 0; }
-.chzn-container .chzn-choices { border-radius: 0.5em; }
-.chzn-container.chzn-container-active .chzn-choices { border-bottom-left-radius: 0;border-bottom-right-radius: 0; }
-.chzn-container .chzn-drop { border-bottom-left-radius: 0.5em;border-bottom-right-radius: 0.5em; }
-
diff --git a/apps/contacts/import.php b/apps/contacts/import.php
index 4638bf0d73c..04cfc397d56 100644
--- a/apps/contacts/import.php
+++ b/apps/contacts/import.php
@@ -97,11 +97,15 @@ if(is_writable('import_tmp/')){
fclose($progressfopen);
}
if(count($parts) == 1){
- OC_Contacts_VCard::add($id, $file);
-}else{
- foreach($importready as $import){
- OC_Contacts_VCard::add($id, $import);
+ $importready = array($file);
+}
+foreach($importready as $import){
+ $card = OC_VObject::parse($import);
+ if (!$card) {
+ OC_Log::write('contacts','Import: skipping card. Error parsing VCard: '.$import, OC_Log::ERROR);
+ continue; // Ditch cards that can't be parsed by Sabre.
}
+ OC_Contacts_VCard::add($id, $card);
}
//done the import
if(is_writable('import_tmp/')){
@@ -113,4 +117,4 @@ sleep(3);
if(is_writable('import_tmp/')){
unlink($progressfile);
}
-OC_JSON::success(); \ No newline at end of file
+OC_JSON::success();
diff --git a/apps/contacts/index.php b/apps/contacts/index.php
index 0a21ddd04b6..04f6c65a145 100644
--- a/apps/contacts/index.php
+++ b/apps/contacts/index.php
@@ -34,6 +34,7 @@ if(!is_null($id)) {
}
$property_types = OC_Contacts_App::getAddPropertyOptions();
$phone_types = OC_Contacts_App::getTypesOfProperty('TEL');
+$categories = OC_Contacts_App::$categories->categories();
$upload_max_filesize = OC_Helper::computerFileSize(ini_get('upload_max_filesize'));
$post_max_size = OC_Helper::computerFileSize(ini_get('post_max_size'));
@@ -44,12 +45,14 @@ $freeSpace=max($freeSpace,0);
$maxUploadFilesize = min($maxUploadFilesize ,$freeSpace);
OC_Util::addScript('','jquery.multiselect');
+OC_Util::addScript('','oc-vcategories');
OC_Util::addScript('contacts','contacts');
OC_Util::addScript('contacts','jquery.combobox');
OC_Util::addScript('contacts','jquery.inview');
OC_Util::addScript('contacts','jquery.Jcrop');
+OC_Util::addScript('contacts','jquery.multi-autocomplete');
OC_Util::addStyle('','jquery.multiselect');
-//OC_Util::addStyle('contacts','styles');
+OC_Util::addStyle('','oc-vcategories');
OC_Util::addStyle('contacts','jquery.combobox');
OC_Util::addStyle('contacts','jquery.Jcrop');
OC_Util::addStyle('contacts','contacts');
@@ -58,7 +61,9 @@ $tmpl = new OC_Template( "contacts", "index", "user" );
$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize);
$tmpl->assign('uploadMaxHumanFilesize', OC_Helper::humanFileSize($maxUploadFilesize));
$tmpl->assign('property_types',$property_types);
+$tmpl->assign('categories',OC_Contacts_App::getCategories());
$tmpl->assign('phone_types',$phone_types);
+$tmpl->assign('categories',$categories);
$tmpl->assign('addressbooks', $addressbooks);
$tmpl->assign('contacts', $contacts);
$tmpl->assign('details', $details );
diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js
index d033e3f21cd..18214cb1cc5 100644
--- a/apps/contacts/js/contacts.js
+++ b/apps/contacts/js/contacts.js
@@ -10,17 +10,16 @@ String.prototype.strip_tags = function(){
return stripped;
};
-
Contacts={
UI:{
notImplemented:function() {
- Contacts.UI.messageBox(t('contacts', 'Not implemented'), t('contacts', 'Sorry, this functionality has not been implemented yet'));
+ OC.dialogs.alert(t('contacts', 'Sorry, this functionality has not been implemented yet'), t('contacts', 'Not implemented'));
},
searchOSM:function(obj) {
var adr = Contacts.UI.propertyContainerFor(obj).find('.adr').val();
console.log('adr 1: ' + adr);
if(adr == undefined) {
- Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', 'Couldn\'t get a valid address.'));
+ OC.dialogs.alert(t('contacts', 'Couldn\'t get a valid address.'), t('contacts', 'Error'));
return;
}
// FIXME: I suck at regexp. /Tanghus
@@ -48,12 +47,11 @@ Contacts={
console.log('uri: ' + uri);
var newWindow = window.open(uri,'_blank');
newWindow.focus();
- //Contacts.UI.notImplemented();
},
mailTo:function(obj) {
var adr = Contacts.UI.propertyContainerFor($(obj)).find('input[type="email"]').val().trim();
if(adr == '') {
- Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', 'Please enter an email address.'));
+ OC.dialogs.alert(t('contacts', 'Please enter an email address.'), t('contacts', 'Error'));
return;
}
window.location.href='mailto:' + adr;
@@ -68,7 +66,7 @@ Contacts={
return $(obj).parents('.propertycontainer').first().data('element');
},
showHideContactInfo:function() {
- var show = ($('#emaillist li[class*="propertycontainer"]').length > 0 || $('#phonelist li[class*="propertycontainer"]').length > 0 || $('#addressdisplay dl[class*="propertycontainer"]').length > 0);
+ var show = ($('#emaillist li.propertycontainer').length > 0 || $('#phonelist li.propertycontainer').length > 0 || $('#addressdisplay dl.propertycontainer').length > 0);
console.log('showHideContactInfo: ' + show);
if(show) {
$('#contact_communication').show();
@@ -82,19 +80,19 @@ Contacts={
switch (type) {
case 'EMAIL':
console.log('emails: '+$('#emaillist>li').length);
- if($('#emaillist li[class*="propertycontainer"]').length == 0) {
+ if($('#emaillist li.propertycontainer').length == 0) {
$('#emails').hide();
}
break;
case 'TEL':
console.log('phones: '+$('#phonelist>li').length);
- if($('#phonelist li[class*="propertycontainer"]').length == 0) {
+ if($('#phonelist li.propertycontainer').length == 0) {
$('#phones').hide();
}
break;
case 'ADR':
console.log('addresses: '+$('#addressdisplay>dl').length);
- if($('#addressdisplay dl[class*="propertycontainer"]').length == 0) {
+ if($('#addressdisplay dl.propertycontainer').length == 0) {
$('#addresses').hide();
}
break;
@@ -116,34 +114,6 @@ Contacts={
$('#carddav_url').show();
$('#carddav_url_close').show();
},
- messageBox:function(title, msg) {
- if(msg.toLowerCase().indexOf('auth') != -1) {
- // fugly hack, I know
- alert(msg);
- }
- if($('#messagebox').dialog('isOpen') == true){
- // NOTE: Do we ever get here?
- $('#messagebox').dialog('moveToTop');
- }else{
- $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'messagebox.php'), function(){
- $('#messagebox').dialog(
- {
- autoOpen: true,
- title: title,
- buttons: [{
- text: "Ok",
- click: function() { $(this).dialog("close"); }
- }],
- close: function(event, ui) {
- $(this).dialog('destroy').remove();
- },
- open: function(event, ui) {
- $('#messagebox_msg').html(msg);
- }
- });
- });
- };
- },
loadListHandlers:function() {
//$('.add,.delete').hide();
$('.globe,.mail,.delete,.edit').tipsy();
@@ -182,8 +152,14 @@ Contacts={
$('#bday').datepicker({
dateFormat : 'dd-mm-yy'
});
+ /*$('#categories_value').find('select').multiselect({
+ noneSelectedText: t('contacts', 'Select categories'),
+ header: false,
+ selectedList: 6,
+ classes: 'categories'
+ });*/
// Style phone types
- $('#phonelist').find('select[class*="contacts_property"]').multiselect({
+ $('#phonelist').find('select.contacts_property').multiselect({
noneSelectedText: t('contacts', 'Select type'),
header: false,
selectedList: 4,
@@ -223,6 +199,7 @@ Contacts={
click: function() { $(this).dialog('close'); }
}
] );
+ $('#categories').multiple_autocomplete({source: categories});
Contacts.UI.loadListHandlers();
},
Card:{
@@ -252,12 +229,12 @@ Contacts={
if(jsondata.status == 'success'){
Contacts.UI.Card.loadContact(jsondata.data);
} else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
}
});
}
} else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
}
});
}
@@ -269,7 +246,7 @@ Contacts={
$('#rightcontent').data('id','');
$('#rightcontent').html(jsondata.data.page);
} else {
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
}
});
}
@@ -309,7 +286,7 @@ Contacts={
}
else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
//alert(jsondata.data.message);
}
});
@@ -318,7 +295,7 @@ Contacts={
// TODO: Add to contacts list.
}
else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
//alert(jsondata.data.message);
}
});
@@ -344,13 +321,13 @@ Contacts={
$('#rightcontent').html(jsondata.data.page);
}
else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
}
});
}
}
else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
//alert(jsondata.data.message);
}
});
@@ -361,19 +338,29 @@ Contacts={
this.data = jsondata;
this.id = this.data.id;
$('#rightcontent').data('id',this.id);
- //console.log('loaded: ' + this.data.FN[0]['value']);
+ console.log('loaded: ' + this.data.FN[0]['value']);
this.populateNameFields();
- this.loadCategories();
+ //this.loadCategories();
this.loadPhoto();
this.loadMails();
this.loadPhones();
this.loadAddresses();
this.loadSingleProperties();
+ // TODO: load NOTE ;-)
+ if(this.data.NOTE) {
+ $('#note').data('checksum', this.data.NOTE[0]['checksum']);
+ $('#note').find('textarea').val(this.data.NOTE[0]['value']);
+ $('#note').show();
+ } else {
+ $('#note').data('checksum', '');
+ $('#note').find('textarea').val('');
+ $('#note').hide();
+ }
},
loadSingleProperties:function() {
- var props = ['BDAY', 'NICKNAME', 'ORG'];
+ var props = ['BDAY', 'NICKNAME', 'ORG', 'CATEGORIES'];
// Clear all elements
- $('#ident .propertycontainer[class*="propertycontainer"]').each(function(){
+ $('#ident .propertycontainer').each(function(){
if(props.indexOf($(this).data('element')) > -1) {
$(this).data('checksum', '');
$(this).find('input').val('');
@@ -407,6 +394,12 @@ Contacts={
$('#contact_identity').find('#org_label').show();
$('#contact_identity').find('#org_value').show();
break;
+ case 'CATEGORIES':
+ $('#contact_identity').find('#categories').val(value);
+ $('#contact_identity').find('#categories_value').data('checksum', checksum);
+ $('#contact_identity').find('#categories_label').show();
+ $('#contact_identity').find('#categories_value').show();
+ break;
}
} else {
$('#contacts_propertymenu a[data-type="'+props[prop]+'"]').parent().show();
@@ -424,11 +417,11 @@ Contacts={
} else {
narray = this.data.N[0]['value'];
}
- this.famname = narray[0];
- this.givname = narray[1];
- this.addname = narray[2];
- this.honpre = narray[3];
- this.honsuf = narray[4];
+ this.famname = narray[0] || '';
+ this.givname = narray[1] || '';
+ this.addname = narray[2] || '';
+ this.honpre = narray[3] || '';
+ this.honsuf = narray[4] || '';
if(this.honpre.length > 0) {
this.fullname += this.honpre + ' ';
}
@@ -448,6 +441,9 @@ Contacts={
$('#fn_select option').remove();
$('#fn_select').combobox('value', this.fn);
var names = [this.fullname, this.givname + ' ' + this.famname, this.famname + ' ' + this.givname, this.famname + ', ' + this.givname];
+ if(this.data.ORG) {
+ names[names.length]=this.data.ORG[0].value;
+ }
$.each(names, function(key, value) {
$('#fn_select')
.append($('<option></option>')
@@ -457,36 +453,79 @@ Contacts={
$('#contact_identity').find('*[data-element="FN"]').data('checksum', this.data.FN[0]['checksum']);
$('#contact_identity').show();
},
- loadCategories:function(){
+ hasCategory:function(category) {
if(this.data.CATEGORIES) {
- //
+ var categories = this.data.CATEGORIES[0]['value'].split(/,\s*/);
+ for(var c in categories) {
+ var cat = this.data.CATEGORIES[0]['value'][c];
+ console.log('hasCategory: ' + cat + ' === ' + category + '?');
+ if(typeof cat === 'string' && (cat.toUpperCase() === category.toUpperCase())) {
+ console.log('Yes');
+ return true;
+ }
+ }
}
+ return false;
},
+ categoriesChanged:function(newcategories) { // Categories added/deleted.
+ console.log('categoriesChanged for ' + Contacts.UI.Card.id + ' : ' + newcategories);
+ categories = newcategories;
+ var categorylist = $('#categories_value').find('input');
+ $.getJSON(OC.filePath('contacts', 'ajax', 'categories/categoriesfor.php'),{'id':Contacts.UI.Card.id},function(jsondata){
+ if(jsondata.status == 'success'){
+ console.log('Setting checksum: ' + jsondata.data.checksum + ', value: ' + jsondata.data.value);
+ $('#categories_value').data('checksum', jsondata.data.checksum);
+ categorylist.val(jsondata.data.value);
+ } else {
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
+ }
+ });
+ },
+ /*loadCategories:function(){ // On loading contact.
+ var categories = $('#categories_value').find('select');
+ if(this.data.CATEGORIES) {
+ $('#categories_value').data('checksum', this.data.CATEGORIES[0]['checksum']);
+ } else {
+ $('#categories_value').data('checksum', '');
+ }
+ categories.find('option').each(function(){
+ if(Contacts.UI.Card.hasCategory($(this).val())) {
+ $(this).attr('selected', 'selected');
+ } else {
+ $(this).removeAttr('selected');
+ }
+ });
+ categories.multiselect('refresh');
+ },*/
editNew:function(){ // add a new contact
this.id = ''; this.fn = ''; this.fullname = ''; this.givname = ''; this.famname = ''; this.addname = ''; this.honpre = ''; this.honsuf = '';
- $.getJSON('ajax/newcontact.php',{},function(jsondata){
+ $.getJSON(OC.filePath('contacts', 'ajax', 'newcontact.php'),{},function(jsondata){
if(jsondata.status == 'success'){
id = '';
$('#rightcontent').data('id','');
$('#rightcontent').html(jsondata.data.page);
Contacts.UI.Card.editName();
- }
- else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
+ } else {
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
//alert(jsondata.data.message);
}
});
},
savePropertyInternal:function(name, fields, oldchecksum, checksum){
// TODO: Add functionality for new fields.
- //console.log('savePropertyInternal: ' + name + ', checksum: ' + checksum);
- //console.log('savePropertyInternal: ' + this.data[name]);
+ console.log('savePropertyInternal: ' + name + ', fields: ' + fields + 'checksum: ' + checksum);
+ console.log('savePropertyInternal: ' + this.data[name]);
+ var multivalue = ['CATEGORIES'];
var params = {};
- var value = undefined;
+ var value = multivalue.indexOf(name) != -1 ? new Array() : undefined;
jQuery.each(fields, function(i, field){
//.substring(11,'parameters[TYPE][]'.indexOf(']'))
if(field.name.substring(0, 5) === 'value') {
- value = field.value;
+ if(multivalue.indexOf(name) != -1) {
+ value.push(field.value);
+ } else {
+ value = field.value;
+ }
} else if(field.name.substring(0, 10) === 'parameters') {
var p = field.name.substring(11,'parameters[TYPE][]'.indexOf(']'));
if(!(p in params)) {
@@ -506,11 +545,11 @@ Contacts={
saveProperty:function(obj){
// I couldn't get the selector to filter on 'contacts_property' so I filter by hand here :-/
if(!$(obj).hasClass('contacts_property')) {
- //console.log('Filtering out object.' + obj);
+ console.log('Filtering out object.' + obj);
return false;
}
if($(obj).hasClass('nonempty') && $(obj).val().trim() == '') {
- Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', 'This property has to be non-empty.'));
+ OC.dialogs.alert(t('contacts', 'This property has to be non-empty.'), t('contacts', 'Error'));
return false;
}
container = $(obj).parents('.propertycontainer').first(); // get the parent holding the metadata.
@@ -518,8 +557,8 @@ Contacts={
var checksum = container.data('checksum');
var name = container.data('element');
console.log('saveProperty: ' + name);
- var fields = container.find('input[class*="contacts_property"],select[class*="contacts_property"]').serializeArray();
- var q = container.find('input[class*="contacts_property"],select[class*="contacts_property"]').serialize();
+ var fields = container.find('input.contacts_property,select.contacts_property').serializeArray();
+ var q = container.find('input.contacts_property,select.contacts_property,textarea.contacts_property').serialize();
if(q == '' || q == undefined) {
console.log('Couldn\'t serialize elements.');
Contacts.UI.loading(container, false);
@@ -529,32 +568,38 @@ Contacts={
if(checksum != undefined && checksum != '') { // save
q = q + '&checksum=' + checksum;
console.log('Saving: ' + q);
+ $(obj).attr('disabled', 'disabled');
$.post('ajax/saveproperty.php',q,function(jsondata){
if(jsondata.status == 'success'){
container.data('checksum', jsondata.data.checksum);
Contacts.UI.Card.savePropertyInternal(name, fields, checksum, jsondata.data.checksum);
Contacts.UI.loading(container, false);
+ $(obj).removeAttr('disabled');
return true;
}
else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
Contacts.UI.loading(container, false);
+ $(obj).removeAttr('disabled');
return false;
}
},'json');
} else { // add
console.log('Adding: ' + q);
+ $(obj).attr('disabled', 'disabled');
$.post('ajax/addproperty.php',q,function(jsondata){
if(jsondata.status == 'success'){
container.data('checksum', jsondata.data.checksum);
// TODO: savePropertyInternal doesn't know about new fields
//Contacts.UI.Card.savePropertyInternal(name, fields, checksum, jsondata.data.checksum);
Contacts.UI.loading(container, false);
+ $(obj).removeAttr('disabled');
return true;
}
else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
Contacts.UI.loading(container, false);
+ $(obj).removeAttr('disabled');
return false;
}
},'json');
@@ -565,10 +610,14 @@ Contacts={
console.log('addProperty:' + type);
switch (type) {
case 'PHOTO':
- this.loadPhoto();
+ this.loadPhoto(true);
$('#file_upload_form').show();
$('#contacts_propertymenu a[data-type="'+type+'"]').parent().hide();
break;
+ case 'NOTE':
+ $('#note').show();
+ $('#contacts_propertymenu a[data-type="'+type+'"]').parent().hide();
+ break;
case 'EMAIL':
if($('#emaillist>li').length == 1) {
$('#emails').show();
@@ -593,6 +642,7 @@ Contacts={
case 'NICKNAME':
case 'ORG':
case 'BDAY':
+ case 'CATEGORIES':
$('dl dt[data-element="'+type+'"],dd[data-element="'+type+'"]').show();
$('#contacts_propertymenu a[data-type="'+type+'"]').parent().hide();
break;
@@ -612,17 +662,25 @@ Contacts={
} else if(type == 'single') {
var proptype = Contacts.UI.propertyTypeFor(obj);
console.log('deleteProperty, hiding: ' + proptype);
- $('dl dt[data-element="'+proptype+'"],dd[data-element="'+proptype+'"]').hide();
+ var othertypes = ['NOTE', 'PHOTO'];
+ if(othertypes.indexOf(proptype) != -1) {
+ console.log('NOTE or PHOTO');
+ Contacts.UI.propertyContainerFor(obj).hide();
+ Contacts.UI.propertyContainerFor(obj).data('checksum', '');
+ } else {
+ $('dl dt[data-element="'+proptype+'"],dd[data-element="'+proptype+'"]').hide();
+ $('dl dd[data-element="'+proptype+'"]').data('checksum', '');
+ }
$('#contacts_propertymenu a[data-type="'+proptype+'"]').parent().show();
Contacts.UI.loading(obj, false);
} else {
- Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', '\'deleteProperty\' called without type argument. Please report at bugs.owncloud.org'));
+ OC.dialogs.alert(t('contacts', '\'deleteProperty\' called without type argument. Please report at bugs.owncloud.org'), t('contacts', 'Error'));
Contacts.UI.loading(obj, false);
}
}
else{
Contacts.UI.loading(obj, false);
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
}
});
} else { // Property hasn't been saved so there's nothing to delete.
@@ -637,7 +695,7 @@ Contacts={
$('#contacts_propertymenu a[data-type="'+proptype+'"]').parent().show();
Contacts.UI.loading(obj, false);
} else {
- Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', '\'deleteProperty\' called without type argument. Please report at bugs.owncloud.org'));
+ OC.dialogs.alert(t('contacts', '\'deleteProperty\' called without type argument. Please report at bugs.owncloud.org'), t('contacts', 'Error'));
}
}
},
@@ -647,8 +705,9 @@ Contacts={
if($('#edit_name_dialog').dialog('isOpen') == true){
$('#edit_name_dialog').dialog('moveToTop');
}else{ // TODO: If id=='' call addcontact.php (or whatever name) instead and reload view with id.
- $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'editname.php')+'?id='+this.id, function(){
- $('#edit_name_dialog' ).dialog({
+ $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'editname.php')+'?id='+this.id, function(jsondata){
+ if(jsondata.status != 'error'){
+ $('#edit_name_dialog' ).dialog({
modal: (isnew && true || false),
closeOnEscape: (isnew == '' && false || true),
title: (isnew && t('contacts', 'Add contact') || t('contacts', 'Edit name')),
@@ -667,7 +726,10 @@ Contacts={
open : function(event, ui) {
// load 'N' property - maybe :-P
}*/
- });
+ });
+ } else {
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
+ }
});
}
},
@@ -692,7 +754,14 @@ Contacts={
$('#fn_select option').remove();
//$('#fn_select').combobox('value', this.fn);
- var names = [this.fullname, this.givname + ' ' + this.famname, this.famname + ' ' + this.givname, this.famname + ', ' + this.givname];
+ var tmp = [this.fullname, this.givname + ' ' + this.famname, this.famname + ' ' + this.givname, this.famname + ', ' + this.givname];
+ var names = new Array();
+ for(var name in tmp) {
+ console.log('idx: ' + names.indexOf(tmp[name]));
+ if(names.indexOf(tmp[name]) == -1) {
+ names.push(tmp[name]);
+ }
+ }
$.each(names, function(key, value) {
$('#fn_select')
.append($('<option></option>')
@@ -708,7 +777,7 @@ Contacts={
},
loadAddresses:function(){
$('#addresses').hide();
- $('#addressdisplay dl[class*="propertycontainer"]').remove();
+ $('#addressdisplay dl.propertycontainer').remove();
for(var adr in this.data.ADR) {
$('#addressdisplay dl').first().clone().insertAfter($('#addressdisplay dl').last()).show();
$('#addressdisplay dl').last().removeClass('template').addClass('propertycontainer');
@@ -771,8 +840,9 @@ Contacts={
if($('#edit_address_dialog').dialog('isOpen') == true){
$('#edit_address_dialog').dialog('moveToTop');
}else{
- $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'editaddress.php')+q, function(){
- $('#edit_address_dialog' ).dialog({
+ $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'editaddress.php')+q, function(jsondata){
+ if(jsondata.status != 'error'){
+ $('#edit_address_dialog' ).dialog({
/*modal: true,*/
height: 'auto', width: 'auto',
buttons: {
@@ -803,7 +873,10 @@ Contacts={
open : function(event, ui) {
// load 'ADR' property - maybe :-P
}*/
- });
+ });
+ } else {
+ alert(jsondata.data.message);
+ }
});
}
},
@@ -843,7 +916,7 @@ Contacts={
},
uploadPhoto:function(filelist) {
if(!filelist) {
- Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts','No files selected for upload.'));
+ OC.dialogs.alert(t('contacts','No files selected for upload.'), t('contacts', 'Error'));
return;
}
//var file = filelist.item(0);
@@ -852,7 +925,7 @@ Contacts={
var form = $('#file_upload_form');
var totalSize=0;
if(file.size > $('#max_upload').val()){
- Contacts.UI.messageBox(t('Upload too large'), t('contacts','The file you are trying to upload exceed the maximum size for file uploads on this server.'));
+ OC.dialogs.alert(t('contacts','The file you are trying to upload exceed the maximum size for file uploads on this server.'), t('contacts', 'Error'));
return;
} else {
target.load(function(){
@@ -861,21 +934,22 @@ Contacts={
Contacts.UI.Card.editPhoto(response.data.id, response.data.tmp);
//alert('File: ' + file.tmp + ' ' + file.name + ' ' + file.mime);
}else{
- Contacts.UI.messageBox(t('contacts', 'Error'), response.data.message);
+ OC.dialogs.alert(response.data.message, t('contacts', 'Error'));
}
});
form.submit();
}
},
- loadPhoto:function(){
- if(this.data.PHOTO) {
+ loadPhoto:function(force){
+ if(this.data.PHOTO||force==true) {
$.getJSON('ajax/loadphoto.php',{'id':this.id},function(jsondata){
if(jsondata.status == 'success'){
//alert(jsondata.data.page);
+ $('#file_upload_form').data('checksum', jsondata.data.checksum);
$('#contacts_details_photo_wrapper').html(jsondata.data.page);
}
else{
- Contacts.UI.messageBox(jsondata.data.message);
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
}
});
$('#file_upload_form').show();
@@ -894,7 +968,7 @@ Contacts={
$('#edit_photo_dialog_img').html(jsondata.data.page);
}
else{
- Contacts.UI.messageBox(jsondata.data.message);
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
}
});
if($('#edit_photo_dialog').dialog('isOpen') == true){
@@ -913,22 +987,22 @@ Contacts={
// load cropped photo.
$('#contacts_details_photo_wrapper').html(response.data.page);
}else{
- Contacts.UI.messageBox(t('contacts','Error'), response.data.message);
+ OC.dialogs.alert(response.data.message, t('contacts', 'Error'));
}
});
$('#contacts [data-id="'+this.id+'"]').find('a').css('background','url(thumbnail.php?id='+this.id+'&refresh=1'+Math.random()+') no-repeat');
},
addMail:function() {
//alert('addMail');
- $('#emaillist li[class*="template"]:first-child').clone().appendTo($('#emaillist')).show();
- $('#emaillist li[class*="template"]:last-child').removeClass('template').addClass('propertycontainer');
+ $('#emaillist li.template:first-child').clone().appendTo($('#emaillist')).show();
+ $('#emaillist li.template:last-child').removeClass('template').addClass('propertycontainer');
$('#emaillist li:last-child').find('input[type="email"]').focus();
Contacts.UI.loadListHandlers();
return false;
},
loadMails:function() {
$('#emails').hide();
- $('#emaillist li[class*="propertycontainer"]').remove();
+ $('#emaillist li.propertycontainer').remove();
for(var mail in this.data.EMAIL) {
this.addMail();
//$('#emaillist li:first-child').clone().appendTo($('#emaillist')).show();
@@ -950,9 +1024,9 @@ Contacts={
return false;
},
addPhone:function() {
- $('#phonelist li[class*="template"]:first-child').clone().appendTo($('#phonelist')); //.show();
- $('#phonelist li[class*="template"]:last-child').find('select').addClass('contacts_property');
- $('#phonelist li[class*="template"]:last-child').removeClass('template').addClass('propertycontainer');
+ $('#phonelist li.template:first-child').clone().appendTo($('#phonelist')); //.show();
+ $('#phonelist li.template:last-child').find('select').addClass('contacts_property');
+ $('#phonelist li.template:last-child').removeClass('template').addClass('propertycontainer');
$('#phonelist li:last-child').find('input[type="text"]').focus();
Contacts.UI.loadListHandlers();
$('#phonelist li:last-child').find('select').multiselect({
@@ -966,7 +1040,7 @@ Contacts={
},
loadPhones:function() {
$('#phones').hide();
- $('#phonelist li[class*="propertycontainer"]').remove();
+ $('#phonelist li.propertycontainer').remove();
for(var phone in this.data.TEL) {
this.addPhone();
$('#phonelist li:last-child').find('select').multiselect('destroy');
@@ -1006,13 +1080,17 @@ Contacts={
if($('#chooseaddressbook_dialog').dialog('isOpen') == true){
$('#chooseaddressbook_dialog').dialog('moveToTop');
}else{
- $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'chooseaddressbook.php'), function(){
- $('#chooseaddressbook_dialog').dialog({
- width : 600,
- close : function(event, ui) {
- $(this).dialog('destroy').remove();
- }
- });
+ $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'chooseaddressbook.php'), function(jsondata){
+ if(jsondata.status != 'error'){
+ $('#chooseaddressbook_dialog').dialog({
+ width : 600,
+ close : function(event, ui) {
+ $(this).dialog('destroy').remove();
+ }
+ });
+ } else {
+ alert(jsondata.data.message);
+ }
});
}
},
@@ -1049,7 +1127,7 @@ Contacts={
Contacts.UI.Contacts.update();
Contacts.UI.Addressbooks.overview();
} else {
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
//alert('Error: ' + data.message);
}
});
@@ -1064,7 +1142,7 @@ Contacts={
var description = $("#description_"+bookid).val();
if(displayname.length == 0) {
- Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', 'Displayname cannot be empty.'));
+ OC.dialogs.alert(t('contacts', 'Displayname cannot be empty.'), t('contacts', 'Error'));
return false;
}
var url;
@@ -1079,7 +1157,7 @@ Contacts={
$(button).closest('tr').prev().html(jsondata.page).show().next().remove();
Contacts.UI.Contacts.update();
} else {
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
}
});
},
@@ -1099,7 +1177,7 @@ Contacts={
Contacts.UI.Card.update();
}
else{
- Contacts.UI.messageBox(t('contacts', 'Error'),jsondata.data.message);
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
//alert(jsondata.data.message);
}
});
@@ -1121,6 +1199,8 @@ Contacts={
$(document).ready(function(){
Contacts.UI.loadHandlers();
+ OCCategories.changed = Contacts.UI.Card.categoriesChanged;
+ OCCategories.app = 'contacts';
/**
* Show the Addressbook chooser
@@ -1148,7 +1228,7 @@ $(document).ready(function(){
Contacts.UI.Card.loadContact(jsondata.data);
}
else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
//alert(jsondata.data.message);
}
});
@@ -1189,7 +1269,8 @@ $(document).ready(function(){
// NOTE: For some reason the selector doesn't work when I select by '.contacts_property' too...
// I do the filtering in the event handler instead.
- $('input[type="text"],input[type="checkbox"],input[type="email"],input[type="tel"],input[type="date"], select').live('change', function(){
+ //$('input[type="text"],input[type="checkbox"],input[type="email"],input[type="tel"],input[type="date"], select').live('change', function(){
+ $('.contacts_property').live('change', function(){
Contacts.UI.Card.saveProperty(this);
});
@@ -1246,17 +1327,17 @@ $(document).ready(function(){
var file = files[0];
console.log('size: '+file.size);
if(file.size > $('#max_upload').val()){
- Contacts.UI.messageBox(t('contacts','Upload too large'), t('contacts','The file you are trying to upload exceed the maximum size for file uploads on this server.'));
+ OC.dialogs.alert(t('contacts','The file you are trying to upload exceed the maximum size for file uploads on this server.'), t('contacts','Upload too large'));
return;
}
if (file.type.indexOf("image") != 0) {
- Contacts.UI.messageBox(t('contacts','Wrong file type'), t('contacts','Only image files can be used as profile picture.'));
+ OC.dialogs.alert(t('contacts','Only image files can be used as profile picture.'), t('contacts','Wrong file type'));
return;
}
var xhr = new XMLHttpRequest();
if (!xhr.upload) {
- Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', 'Your browser doesn\'t support AJAX upload. Please click on the profile picture to select a photo to upload.'))
+ OC.dialogs.alert(t('contacts', 'Your browser doesn\'t support AJAX upload. Please click on the profile picture to select a photo to upload.'), t('contacts', 'Error'))
}
fileUpload = xhr.upload,
xhr.onreadystatechange = function() {
@@ -1266,11 +1347,11 @@ $(document).ready(function(){
if(xhr.status == 200) {
Contacts.UI.Card.editPhoto(response.data.id, response.data.tmp);
} else {
- Contacts.UI.messageBox(t('contacts', 'Error'), xhr.status + ': ' + xhr.responseText);
+ OC.dialogs.alert(xhr.status + ': ' + xhr.responseText, t('contacts', 'Error'));
}
} else {
//alert(xhr.responseText);
- Contacts.UI.messageBox(t('contacts', 'Error'), response.data.message);
+ OC.dialogs.alert(response.data.message, t('contacts', 'Error'));
}
// stop loading indicator
//$('#contacts_details_photo_progress').hide();
@@ -1298,8 +1379,19 @@ $(document).ready(function(){
xhr.send(file);
}
+ $('body').live('click',function(e){
+ if(!$(e.target).is('#contacts_propertymenu_button')) {
+ $('#contacts_propertymenu').hide();
+ }
+ });
$('#contacts_propertymenu_button').live('click',function(){
- $('#contacts_propertymenu').is(':hidden') && $('#contacts_propertymenu').slideDown() || $('#contacts_propertymenu').slideUp();
+ var menu = $('#contacts_propertymenu');
+ if(menu.is(':hidden')) {
+ menu.show();
+ menu.find('ul').focus();
+ } else {
+ menu.hide();
+ }
});
$('#contacts_propertymenu a').live('click',function(){
Contacts.UI.Card.addProperty(this);
diff --git a/apps/contacts/js/interface.js b/apps/contacts/js/interface.js
deleted file mode 100644
index 5908dd767a2..00000000000
--- a/apps/contacts/js/interface.js
+++ /dev/null
@@ -1,409 +0,0 @@
-/**
- * ownCloud - Addressbook
- *
- * @author Jakob Sack
- * @copyright 2011 Jakob Sack mail@jakobsack.de
- * @copyright 2011-2012 Thomas Tanghus <thomas@tanghus.net>
- *
- * 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/>.
- *
- */
-
-
-Contacts={
- UI:{
- showCardDAVUrl:function(username, bookname){
- $('#carddav_url').val(totalurl + '/' + username + '/' + bookname);
- $('#carddav_url').show();
- $('#carddav_url_close').show();
- },
- messageBox:function(title, msg) {
- if($('#messagebox').dialog('isOpen') == true){
- // NOTE: Do we ever get here?
- $('#messagebox').dialog('moveToTop');
- }else{
- $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'messagebox.php'), function(){
- $('#messagebox').dialog(
- {
- autoOpen: true,
- title: title,
- buttons: [{
- text: "Ok",
- click: function() { $(this).dialog("close"); }
- }],
- close: function(event, ui) {
- $(this).dialog('destroy').remove();
- },
- open: function(event, ui) {
- $('#messagebox_msg').html(msg);
- }
- });
- });
- }
- },
- Addressbooks:{
- overview:function(){
- if($('#chooseaddressbook_dialog').dialog('isOpen') == true){
- $('#chooseaddressbook_dialog').dialog('moveToTop');
- }else{
- $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'chooseaddressbook.php'), function(){
- $('#chooseaddressbook_dialog').dialog({
- width : 600,
- close : function(event, ui) {
- $(this).dialog('destroy').remove();
- }
- });
- });
- }
- },
- activation:function(checkbox, bookid)
- {
- $.post(OC.filePath('contacts', 'ajax', 'activation.php'), { bookid: bookid, active: checkbox.checked?1:0 },
- function(data) {
- /*
- * Arguments:
- * data.status
- * data.bookid
- * data.active
- */
- if (data.status == 'success'){
- checkbox.checked = data.active == 1;
- Contacts.UI.Contacts.update();
- }
- });
- },
- newAddressbook:function(object){
- var tr = $(document.createElement('tr'))
- .load(OC.filePath('contacts', 'ajax', 'addbook.php'));
- $(object).closest('tr').after(tr).hide();
- /* TODO: Shouldn't there be some kinda error checking here? */
- },
- editAddressbook:function(object, bookid){
- var tr = $(document.createElement('tr'))
- .load(OC.filePath('contacts', 'ajax', 'editaddressbook.php') + "?bookid="+bookid);
- $(object).closest('tr').after(tr).hide();
- },
- deleteAddressbook:function(bookid){
- var check = confirm("Do you really want to delete this address book?");
- if(check == false){
- return false;
- }else{
- $.post(OC.filePath('contacts', 'ajax', 'deletebook.php'), { id: bookid},
- function(data) {
- if (data.status == 'success'){
- $('#chooseaddressbook_dialog').dialog('destroy').remove();
- Contacts.UI.Contacts.update();
- Contacts.UI.Addressbooks.overview();
- } else {
- Contacts.UI.messageBox(t('contacts', 'Error'), data.message);
- //alert('Error: ' + data.message);
- }
- });
- }
- },
- submit:function(button, bookid){
- var displayname = $("#displayname_"+bookid).val();
- var active = $("#edit_active_"+bookid+":checked").length;
- var description = $("#description_"+bookid).val();
-
- var url;
- if (bookid == 'new'){
- url = OC.filePath('contacts', 'ajax', 'createaddressbook.php');
- }else{
- url = OC.filePath('contacts', 'ajax', 'updateaddressbook.php');
- }
- $.post(url, { id: bookid, name: displayname, active: active, description: description },
- function(jsondata){
- if(jsondata.status == 'success'){
- $(button).closest('tr').prev().html(data.page).show().next().remove();
- Contacts.UI.Contacts.update();
- } else {
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
- }
- });
- },
- cancel:function(button, bookid){
- $(button).closest('tr').prev().show().next().remove();
- }
- },
- Contacts:{
- /**
- * Reload the contacts list.
- */
- update:function(){
- $.getJSON('ajax/contacts.php',{},function(jsondata){
- if(jsondata.status == 'success'){
- $('#contacts').html(jsondata.data.page);
- }
- else{
- Contacts.UI.messageBox(t('contacts', 'Error'),jsondata.data.message);
- //alert(jsondata.data.message);
- }
- });
- setTimeout(Contacts.UI.Contacts.lazyupdate, 500);
- },
- /**
- * Add thumbnails to the contact list as they become visible in the viewport.
- */
- lazyupdate:function(){
- $('#contacts li').live('inview', function(){
- if (!$(this).find('a').attr('style')) {
- $(this).find('a').css('background','url(thumbnail.php?id='+$(this).data('id')+') no-repeat');
- }
- });
- }
- }
- }
-}
-
-$(document).ready(function(){
- /*-------------------------------------------------------------------------
- * Event handlers
- *-----------------------------------------------------------------------*/
-
- /**
- * Load the details view for a contact.
- */
- $('#leftcontent li').live('click',function(){
- var id = $(this).data('id');
- var oldid = $('#rightcontent').data('id');
- if(oldid != 0){
- $('#leftcontent li[data-id="'+oldid+'"]').removeClass('active');
- }
- $.getJSON('ajax/getdetails.php',{'id':id},function(jsondata){
- if(jsondata.status == 'success'){
- $('#rightcontent').data('id',jsondata.data.id);
- $('#rightcontent').html(jsondata.data.page);
- $('#leftcontent li[data-id="'+jsondata.data.id+'"]').addClass('active');
- }
- else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
- //alert(jsondata.data.message);
- }
- });
- return false;
- });
-
- /**
- * Delete currently selected contact (and clear form?)
- */
- $('#contacts_deletecard').live('click',function(){
- $('#contacts_deletecard').tipsy('hide');
- var id = $('#rightcontent').data('id');
- $.getJSON('ajax/deletecard.php',{'id':id},function(jsondata){
- if(jsondata.status == 'success'){
- $('#leftcontent [data-id="'+jsondata.data.id+'"]').remove();
- $('#rightcontent').data('id','');
- $('#rightcontent').empty();
- }
- else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
- //alert(jsondata.data.message);
- }
- });
- return false;
- });
-
- /**
- * Add a property to the contact.
- * NOTE: Where does 'contacts_addproperty' exist?
- */
- $('#contacts_addproperty').live('click',function(){
- var id = $('#rightcontent').data('id');
- $.getJSON('ajax/showaddproperty.php',{'id':id},function(jsondata){
- if(jsondata.status == 'success'){
- $('#contacts_details_list').append(jsondata.data.page);
- $('#contacts_addproperty').hide();
- }
- else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
- alert('From handler: '+jsondata.data.message);
- }
- });
- return false;
- });
-
- /**
- * Change the inputs based on which type of property is selected for addition.
- */
- $('#contacts_addpropertyform [name="name"]').live('change',function(){
- $('#contacts_addpropertyform #contacts_addresspart').remove();
- $('#contacts_addpropertyform #contacts_phonepart').remove();
- $('#contacts_addpropertyform #contacts_fieldpart').remove();
- $('#contacts_addpropertyform #contacts_generic').remove();
- if($(this).val() == 'ADR'){
- $('#contacts_addresspart').clone().insertAfter($('#contacts_addpropertyform .contacts_property_name'));
- }
- else if($(this).val() == 'TEL'){
- $('#contacts_phonepart').clone().insertAfter($('#contacts_addpropertyform .contacts_property_name'));
- }
- else{
- $('#contacts_generic').clone().insertAfter($('#contacts_addpropertyform .contacts_property_name'));
- }
- $('#contacts_addpropertyform .contacts_property_data select').chosen();
- });
-
- $('#contacts_addpropertyform input[type="submit"]').live('click',function(){
- $.post('ajax/addproperty.php',$('#contacts_addpropertyform').serialize(),function(jsondata){
- if(jsondata.status == 'success'){
- $('#contacts_addpropertyform').before(jsondata.data.page);
- }
- else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
- }
- }, 'json');
- return false;
- });
-
- /**
- * Show the Addressbook chooser
- */
- $('#chooseaddressbook').click(function(){
- Contacts.UI.Addressbooks.overview();
- return false;
- });
-
- /**
- * Open blank form to add new contact.
- */
- $('#contacts_newcontact').click(function(){
- $.getJSON('ajax/showaddcard.php',{},function(jsondata){
- if(jsondata.status == 'success'){
- $('#rightcontent').data('id','');
- $('#rightcontent').html(jsondata.data.page)
- .find('select').chosen();
- }
- else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
- //alert(jsondata.data.message);
- }
- });
- return false;
- });
-
- /**
- * Add and insert a new contact into the list.
- */
- $('#contacts_addcardform input[type="submit"]').live('click',function(){
- $.post('ajax/addcard.php',$('#contacts_addcardform').serialize(),function(jsondata){
- if(jsondata.status == 'success'){
- $('#rightcontent').data('id',jsondata.data.id);
- $('#rightcontent').html(jsondata.data.page);
- $('#leftcontent .active').removeClass('active');
- var item = '<li data-id="'+jsondata.data.id+'" class="active"><a href="index.php?id='+jsondata.data.id+'" style="background: url(thumbnail.php?id='+jsondata.data.id+') no-repeat scroll 0% 0% transparent;">'+jsondata.data.name+'</a></li>';
- var added = false;
- $('#leftcontent ul li').each(function(){
- if ($(this).text().toLowerCase() > jsondata.data.name.toLowerCase()) {
- $(this).before(item).fadeIn('fast');
- added = true;
- return false;
- }
- });
- if(!added) {
- $('#leftcontent ul').append(item);
- }
- }
- else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
- //alert(jsondata.data.message);
- }
- }, 'json');
- return false;
- });
-
- /**
- * Show inputs for editing a property.
- */
- $('.contacts_property [data-use="edit"]').live('click',function(){
- var id = $('#rightcontent').data('id');
- var checksum = $(this).parents('.contacts_property').first().data('checksum');
- $.getJSON('ajax/showsetproperty.php',{'id': id, 'checksum': checksum },function(jsondata){
- if(jsondata.status == 'success'){
- $('.contacts_property[data-checksum="'+checksum+'"]').html(jsondata.data.page)
- .find('select').chosen();
- }
- else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
- //alert(jsondata.data.message);
- }
- });
- return false;
- });
-
- /**
- * Save the edited property
- */
- $('#contacts_setpropertyform input[type="submit"]').live('click',function(){
- $.post('ajax/setproperty.php',$(this).parents('form').first().serialize(),function(jsondata){
- if(jsondata.status == 'success'){
- $('.contacts_property[data-checksum="'+jsondata.data.oldchecksum+'"]').replaceWith(jsondata.data.page);
- }
- else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
- //alert(jsondata.data.message);
- }
- },'json');
- return false;
- });
-
- $('.contacts_property [data-use="delete"]').live('click',function(){
- var id = $('#rightcontent').data('id');
- var checksum = $(this).parents('li').first().data('checksum');
- $.getJSON('ajax/deleteproperty.php',{'id': id, 'checksum': checksum },function(jsondata){
- if(jsondata.status == 'success'){
- $('.contacts_property[data-checksum="'+checksum+'"]').remove();
- }
- else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
- //alert(jsondata.data.message);
- }
- });
- return false;
- });
-
-
- $('.contacts_property').live('mouseenter',function(){
- $(this).find('span[data-use]').show();
- });
-
- $('.contacts_property').live('mouseleave',function(){
- $(this).find('span[data-use]').hide();
- });
-
- $('#contacts_addcardform select').chosen();
-
- $('#contacts li').bind('inview', function(event, isInView, visiblePartX, visiblePartY) {
- if (isInView) { //NOTE: I've kept all conditions for future reference ;-)
- // element is now visible in the viewport
- if (visiblePartY == 'top') {
- // top part of element is visible
- } else if (visiblePartY == 'bottom') {
- // bottom part of element is visible
- } else {
- // whole part of element is visible
- if (!$(this).find('a').attr('style')) {
- //alert($(this).data('id') + ' has background: ' + $(this).attr('style'));
- $(this).find('a').css('background','url(thumbnail.php?id='+$(this).data('id')+') no-repeat');
- }/* else {
- alert($(this).data('id') + ' has style ' + $(this).attr('style').match('url'));
- }*/
- }
- } else {
- // element has gone out of viewport
- }
- });
-
- $('.button').tipsy();
- //Contacts.UI.messageBox('Hello','Sailor');
-});
diff --git a/apps/contacts/js/jquery.multi-autocomplete.js b/apps/contacts/js/jquery.multi-autocomplete.js
new file mode 100644
index 00000000000..1c923a2543d
--- /dev/null
+++ b/apps/contacts/js/jquery.multi-autocomplete.js
@@ -0,0 +1,81 @@
+/**
+ * Inspired by http://jqueryui.com/demos/autocomplete/#multiple
+ */
+
+(function( $ ) {
+ $.widget('ui.multiple_autocomplete', {
+ _create: function() {
+ function split( val ) {
+ return val.split( /,\s*/ );
+ }
+ function extractLast( term ) {
+ return split( term ).pop();
+ }
+ //console.log('_create: ' + this.options['id']);
+ var self = this;
+ this.element.bind('blur', function( event ) {
+ var tmp = self.element.val().trim();
+ if(tmp[tmp.length-1] == ',') {
+ self.element.val(tmp.substring(0, tmp.length-1));
+ } else {
+ self.element.val(tmp);
+ }
+ self.element.trigger('change'); // Changes wasn't saved when only using the dropdown.
+ });
+ this.element.bind( "keydown", function( event ) {
+ if ( event.keyCode === $.ui.keyCode.TAB &&
+ $( this ).data( "autocomplete" ).menu.active ) {
+ event.preventDefault();
+ }
+ })
+ .autocomplete({
+ minLength: 0,
+ source: function( request, response ) {
+ // delegate back to autocomplete, but extract the last term
+ response( $.ui.autocomplete.filter(
+ self.options.source, extractLast( request.term ) ) );
+ },
+ focus: function() {
+ // prevent value inserted on focus
+ return false;
+ },
+ select: function( event, ui ) {
+ var terms = split( this.value );
+ // remove the current input
+ terms.pop();
+ // add the selected item
+ terms.push( ui.item.value );
+ // add placeholder to get the comma-and-space at the end
+ terms.push( "" );
+ this.value = terms.join( ", " );
+ return false;
+ }
+ });
+ this.button = $( "<button type='button'>&nbsp;</button>" )
+ .attr( "tabIndex", -1 )
+ .attr( "title", "Show All Items" )
+ .insertAfter( this.element )
+ .addClass('svg')
+ .addClass('action')
+ .addClass('combo-button')
+ .click(function() {
+ // close if already visible
+ if ( self.element.autocomplete( "widget" ).is( ":visible" ) ) {
+ self.element.autocomplete( "close" );
+ return;
+ }
+
+ // work around a bug (likely same cause as #5265)
+ $( this ).blur();
+
+ var tmp = self.element.val().trim();
+ if(tmp[tmp.length-1] != ',') {
+ self.element.val(tmp+', ');
+ }
+ // pass empty string as value to search for, displaying all results
+ self.element.autocomplete( "search", "" );
+ self.element.focus();
+ });
+ },
+ });
+})( jQuery );
diff --git a/apps/contacts/l10n/xgettextfiles b/apps/contacts/l10n/xgettextfiles
index 91d5da46db0..e2492431ff8 100644
--- a/apps/contacts/l10n/xgettextfiles
+++ b/apps/contacts/l10n/xgettextfiles
@@ -1,20 +1,17 @@
../appinfo/app.php
../ajax/activation.php
../ajax/addbook.php
-../ajax/addcard.php
../ajax/addproperty.php
../ajax/createaddressbook.php
../ajax/deletebook.php
../ajax/deleteproperty.php
../ajax/getdetails.php
-../ajax/setproperty.php
+../ajax/saveproperty.php
../ajax/updateaddressbook.php
../lib/app.php
../templates/index.php
-../templates/part.addcardform.php
../templates/part.chooseaddressbook.php
../templates/part.chooseaddressbook.rowfields.php
-../templates/part.details.php
../templates/part.editaddressbook.php
../templates/part.property.php
../templates/part.setpropertyform.php
diff --git a/apps/contacts/lib/app.php b/apps/contacts/lib/app.php
index ff348403a9b..cc33c733007 100644
--- a/apps/contacts/lib/app.php
+++ b/apps/contacts/lib/app.php
@@ -10,8 +10,10 @@
* This class manages our app actions
*/
OC_Contacts_App::$l10n = new OC_L10N('contacts');
+OC_Contacts_App::$categories = new OC_VCategories('contacts');
class OC_Contacts_App {
public static $l10n;
+ public static $categories;
/**
* Render templates/part.details to json output
@@ -83,7 +85,7 @@ class OC_Contacts_App {
$vcard = OC_VObject::parse($card['carddata']);
// Try to fix cards with missing 'N' field from pre ownCloud 4. Hot damn, this is ugly...
if(!is_null($vcard) && !$vcard->__isset('N')) {
- $appinfo = $info=OC_App::getAppInfo('contacts');
+ $appinfo = OC_App::getAppInfo('contacts');
if($appinfo['version'] >= 5) {
OC_Log::write('contacts','OC_Contacts_App::getContactVCard. Deprecated check for missing N field', OC_Log::DEBUG);
}
@@ -92,7 +94,7 @@ class OC_Contacts_App {
OC_Log::write('contacts','getContactVCard, found FN field: '.$vcard->__get('FN'), OC_Log::DEBUG);
$n = implode(';', array_reverse(array_slice(explode(' ', $vcard->__get('FN')), 0, 2))).';;;';
$vcard->setString('N', $n);
- OC_Contacts_VCard::edit( $id, $vcard->serialize());
+ OC_Contacts_VCard::edit( $id, $vcard);
} else { // Else just add an empty 'N' field :-P
$vcard->setString('N', 'Unknown;Name;;;');
}
@@ -153,6 +155,10 @@ class OC_Contacts_App {
}
}
+ public static function getCategories() {
+ return self::$categories->categories();
+ }
+
public static function setLastModifiedHeader($contact) {
$rev = $contact->getAsString('REV');
if ($rev) {
diff --git a/apps/contacts/lib/hooks.php b/apps/contacts/lib/hooks.php
index 155cf40f914..e09da20be86 100644
--- a/apps/contacts/lib/hooks.php
+++ b/apps/contacts/lib/hooks.php
@@ -29,7 +29,7 @@ class OC_Contacts_Hooks{
* @param paramters parameters from postDeleteUser-Hook
* @return array
*/
- public function deleteUser($parameters) {
+ static public function deleteUser($parameters) {
$addressbooks = OC_Contacts_Addressbook::all($parameters['uid']);
foreach($addressbooks as $addressbook) {
@@ -38,4 +38,62 @@ class OC_Contacts_Hooks{
return true;
}
+
+ /**
+ * @brief Adds the CardDAV resource to the DAV server
+ * @param paramters parameters from initialize-Hook
+ * @return array
+ */
+ static public function initializeCardDAV($parameters){
+ // We need a backend, the root node and the carddav plugin
+ $parameters['backends']['carddav'] = new OC_Connector_Sabre_CardDAV();
+ $parameters['nodes'][] = new Sabre_CardDAV_AddressBookRoot($parameters['backends']['principal'], $parameters['backends']['carddav']);
+ $parameters['plugins'][] = new Sabre_CardDAV_Plugin();
+ return true;
+ }
+
+ static public function getCalenderSources($parameters) {
+ $base_url = OC_Helper::linkTo('calendar', 'ajax/events.php').'?calendar_id=';
+ foreach(OC_Contacts_Addressbook::all(OC_User::getUser()) as $addressbook) {
+ $parameters['sources'][] =
+ array(
+ 'url' => $base_url.'birthday_'. $addressbook['id'],
+ 'backgroundColor' => '#cccccc',
+ 'borderColor' => '#888',
+ 'textColor' => 'black',
+ 'cache' => true,
+ 'editable' => false,
+ );
+ }
+ }
+
+ static public function getBirthdayEvents($parameters) {
+ $name = $parameters['calendar_id'];
+ if (strpos('birthday_', $name) != 0) {
+ return;
+ }
+ $info = explode('_', $name);
+ $aid = $info[1];
+ OC_Contacts_App::getAddressbook($aid);
+ foreach(OC_Contacts_VCard::all($aid) as $card){
+ $vcard = OC_VObject::parse($card['carddata']);
+ $birthday = $vcard->BDAY;
+ if ($birthday) {
+ $date = new DateTime($birthday);
+ $vevent = new OC_VObject('VEVENT');
+ $vevent->setDateTime('LAST-MODIFIED', new DateTime($vcard->REV));
+ $vevent->setDateTime('DTSTART', $date, Sabre_VObject_Element_DateTime::DATE);
+ $vevent->setString('DURATION', 'P1D');
+ // DESCRIPTION?
+ $vevent->setString('RRULE', 'FREQ=YEARLY');
+ $title = str_replace('{name}', $vcard->getAsString('FN'), OC_Contacts_App::$l10n->t('{name}\'s Birthday'));
+ $parameters['events'][] = array(
+ 'id' => 0,//$card['id'],
+ 'vevent' => $vevent,
+ 'repeating' => true,
+ 'summary' => $title,
+ );
+ }
+ }
+ }
}
diff --git a/apps/contacts/lib/search.php b/apps/contacts/lib/search.php
index 5aad6a25f09..cf0a5fe6997 100644
--- a/apps/contacts/lib/search.php
+++ b/apps/contacts/lib/search.php
@@ -1,6 +1,6 @@
<?php
-class OC_Search_Provider_Contacts extends OC_Search_Provider{
- function search($query){
+class OC_Search_Provider_Contacts implements OC_Search_Provider{
+ static function search($query){
$addressbooks = OC_Contacts_Addressbook::all(OC_User::getUser(), 1);
// if(count($calendars)==0 || !OC_App::isEnabled('contacts')){
// //return false;
@@ -26,4 +26,3 @@ class OC_Search_Provider_Contacts extends OC_Search_Provider{
return $results;
}
}
-new OC_Search_Provider_Contacts();
diff --git a/apps/contacts/lib/vcard.php b/apps/contacts/lib/vcard.php
index 0b8d95a2d97..3736f18c647 100644
--- a/apps/contacts/lib/vcard.php
+++ b/apps/contacts/lib/vcard.php
@@ -4,6 +4,7 @@
*
* @author Jakob Sack
* @copyright 2011 Jakob Sack mail@jakobsack.de
+ * @copyright 2012 Thomas Tanghus <thomas@tanghus.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@@ -174,6 +175,9 @@ class OC_Contacts_VCard{
if($property->name == 'UID'){
$uid = $property->value;
}
+ if($property->name == 'ORG'){
+ $org = $property->value;
+ }
if($property->name == 'EMAIL' && is_null($email)){ // only use the first email as substitute for missing N or FN.
$email = $property->value;
}
@@ -184,6 +188,8 @@ class OC_Contacts_VCard{
$fn = join(' ', array_reverse(array_slice(explode(';', $n), 0, 2)));
} elseif($email) {
$fn = $email;
+ } elseif($org) {
+ $fn = $org;
} else {
$fn = 'Unknown Name';
}
@@ -217,31 +223,37 @@ class OC_Contacts_VCard{
/**
* @brief Adds a card
- * @param integer $id Addressbook id
- * @param string $data vCard file
- * @return insertid on success or null if card is not parseable.
+ * @param integer $aid Addressbook id
+ * @param OC_VObject $card vCard file
+ * @param string $uri the uri of the card, default based on the UID
+ * @return insertid on success or null if no card.
*/
- public static function add($id,$data){
- $fn = null;
-
- $card = OC_VObject::parse($data);
- if(!is_null($card)){
- self::updateValuesFromAdd($card);
- $data = $card->serialize();
- }
- else{
- OC_Log::write('contacts','OC_Contacts_VCard::add. Error parsing VCard: '.$data,OC_Log::ERROR);
- return null; // Ditch cards that can't be parsed by Sabre.
+ public static function add($aid, $card, $uri=null){
+ if(is_null($card)){
+ OC_Log::write('contacts','OC_Contacts_VCard::add. No vCard supplied', OC_Log::ERROR);
+ return null;
};
+ OC_Contacts_App::$categories->loadFromVObject($card);
+
+ self::updateValuesFromAdd($card);
+
$fn = $card->getAsString('FN');
- $uid = $card->getAsString('UID');
- $uri = $uid.'.vcf';
+ if (empty($fn)) {
+ $fn = null;
+ }
+
+ if (!$uri) {
+ $uid = $card->getAsString('UID');
+ $uri = $uid.'.vcf';
+ }
+
+ $data = $card->serialize();
$stmt = OC_DB::prepare( 'INSERT INTO *PREFIX*contacts_cards (addressbookid,fullname,carddata,uri,lastmodified) VALUES(?,?,?,?,?)' );
- $result = $stmt->execute(array($id,$fn,$data,$uri,time()));
+ $result = $stmt->execute(array($aid,$fn,$data,$uri,time()));
$newid = OC_DB::insertid('*PREFIX*contacts_cards');
- OC_Contacts_Addressbook::touch($id);
+ OC_Contacts_Addressbook::touch($aid);
return $newid;
}
@@ -255,49 +267,56 @@ class OC_Contacts_VCard{
*/
public static function addFromDAVData($id,$uri,$data){
$card = OC_VObject::parse($data);
- if(!is_null($card)){
- self::updateValuesFromAdd($card);
- $data = $card->serialize();
- } else {
- OC_Log::write('contacts','OC_Contacts_VCard::addFromDAVData. Error parsing VCard: '.$data, OC_Log::ERROR);
- return null; // Ditch cards that can't be parsed by Sabre.
- };
- $fn = $card->getAsString('FN');
-
- $stmt = OC_DB::prepare( 'INSERT INTO *PREFIX*contacts_cards (addressbookid,fullname,carddata,uri,lastmodified) VALUES(?,?,?,?,?)' );
- $result = $stmt->execute(array($id,$fn,$data,$uri,time()));
- $newid = OC_DB::insertid('*PREFIX*contacts_cards');
-
- OC_Contacts_Addressbook::touch($id);
+ return self::add($id, $data, $uri);
+ }
- return $newid;
+ /**
+ * @brief Mass updates an array of cards
+ * @param array $objects An array of [id, carddata].
+ */
+ public static function updateDataByID($objects){
+ $stmt = OC_DB::prepare( 'UPDATE *PREFIX*contacts_cards SET carddata = ?, lastmodified = ? WHERE id = ?' );
+ $now = new DateTime;
+ foreach($objects as $object) {
+ $vcard = OC_VObject::parse($object[1]);
+ if(!is_null($vcard)){
+ $vcard->setString('REV', $now->format(DateTime::W3C));
+ $data = $vcard->serialize();
+ try {
+ $result = $stmt->execute(array($data,time(),$object[0]));
+ //OC_Log::write('contacts','OC_Contacts_VCard::updateDataByID, id: '.$object[0].': '.$object[1],OC_Log::DEBUG);
+ } catch(Exception $e) {
+ OC_Log::write('contacts','OC_Contacts_VCard::updateDataByID:, exception: '.$e->getMessage(),OC_Log::DEBUG);
+ OC_Log::write('contacts','OC_Contacts_VCard::updateDataByID, id: '.$object[0],OC_Log::DEBUG);
+ }
+ }
+ }
}
/**
* @brief edits a card
* @param integer $id id of card
- * @param string $data vCard file
+ * @param OC_VObject $card vCard file
* @return boolean
*/
- public static function edit($id, $data){
+ public static function edit($id, OC_VObject $card){
$oldcard = self::find($id);
- $fn = null;
- $card = OC_VObject::parse($data);
- if(!is_null($card)){
- foreach($card->children as $property){
- if($property->name == 'FN'){
- $fn = $property->value;
- break;
- }
- }
- } else {
+ if(is_null($card)) {
return false;
}
+
+ OC_Contacts_App::$categories->loadFromVObject($card);
+
+ $fn = $card->getAsString('FN');
+ if (empty($fn)) {
+ $fn = null;
+ }
+
$now = new DateTime;
$card->setString('REV', $now->format(DateTime::W3C));
- $data = $card->serialize();
+ $data = $card->serialize();
$stmt = OC_DB::prepare( 'UPDATE *PREFIX*contacts_cards SET fullname = ?,carddata = ?, lastmodified = ? WHERE id = ?' );
$result = $stmt->execute(array($fn,$data,time(),$id));
@@ -315,27 +334,8 @@ class OC_Contacts_VCard{
*/
public static function editFromDAVData($aid,$uri,$data){
$oldcard = self::findWhereDAVDataIs($aid,$uri);
-
- $fn = null;
$card = OC_VObject::parse($data);
- if(!is_null($card)){
- foreach($card->children as $property){
- if($property->name == 'FN'){
- $fn = $property->value;
- break;
- }
- }
- }
- $now = new DateTime;
- $card->setString('REV', $now->format(DateTime::W3C));
- $data = $card->serialize();
-
- $stmt = OC_DB::prepare( 'UPDATE *PREFIX*contacts_cards SET fullname = ?,carddata = ?, lastmodified = ? WHERE id = ?' );
- $result = $stmt->execute(array($fn,$data,time(),$oldcard['id']));
-
- OC_Contacts_Addressbook::touch($oldcard['addressbookid']);
-
- return true;
+ return self::edit($oldcard['id'], $card);
}
/**
@@ -352,14 +352,6 @@ class OC_Contacts_VCard{
}
/**
- * @brief Creates a UID
- * @return string
- */
- public static function createUID(){
- return substr(md5(rand().time()),0,10);
- }
-
- /**
* @brief deletes a card with the data provided by sabredav
* @param integer $aid Addressbook id
* @param string $uri the uri of the card
@@ -375,6 +367,43 @@ class OC_Contacts_VCard{
}
/**
+ * @brief Escapes delimiters from an array and returns a string.
+ * @param array $value
+ * @param char $delimiter
+ * @return string
+ */
+ public static function escapeDelimiters($value, $delimiter=';') {
+ foreach($value as &$i ) {
+ $i = implode("\\$delimiter", explode($delimiter, $i));
+ }
+ return implode($delimiter, $value);
+ }
+
+
+ /**
+ * @brief Creates an array out of a multivalue property
+ * @param string $value
+ * @param char $delimiter
+ * @return array
+ */
+ public static function unescapeDelimiters($value, $delimiter=';') {
+ $array = explode($delimiter,$value);
+ for($i=0;$i<count($array);$i++) {
+ if(substr($array[$i],-1,1)=="\\") {
+ if(isset($array[$i+1])) {
+ $array[$i] = substr($array[$i],0,count($array[$i])-2).$delimiter.$array[$i+1];
+ unset($array[$i+1]);
+ } else {
+ $array[$i] = substr($array[$i],0,count($array[$i])-2).$delimiter;
+ }
+ $i = $i - 1;
+ }
+ }
+ $array = array_map('trim', $array);
+ return $array;
+ }
+
+ /**
* @brief Data structure of vCard
* @param object $property
* @return associative array
@@ -412,8 +441,10 @@ class OC_Contacts_VCard{
$value = $property->value;
//$value = htmlspecialchars($value);
if($property->name == 'ADR' || $property->name == 'N'){
- $value = OC_VObject::unescapeSemicolons($value);
- }
+ $value = self::unescapeDelimiters($value);
+ }/* elseif($property->name == 'CATEGORIES') {
+ $value = self::unescapeDelimiters($value, ',');
+ }*/
$temp = array(
'name' => $property->name,
'value' => $value,
diff --git a/apps/contacts/templates/index.php b/apps/contacts/templates/index.php
index e81597f23d6..af159ce9c60 100644
--- a/apps/contacts/templates/index.php
+++ b/apps/contacts/templates/index.php
@@ -1,5 +1,6 @@
<script type='text/javascript'>
var totalurl = '<?php echo OC_Helper::linkToAbsolute('contacts', 'carddav.php'); ?>/addressbooks';
+ var categories = <?php sort($_['categories']); echo json_encode($_['categories']); ?>;
</script>
<div id="controls">
<form>
diff --git a/apps/contacts/templates/part.addcardform.php b/apps/contacts/templates/part.addcardform.php
deleted file mode 100644
index 1ad4c18b35b..00000000000
--- a/apps/contacts/templates/part.addcardform.php
+++ /dev/null
@@ -1,138 +0,0 @@
-<form id="contacts_addcardform">
- <?php if(count($_['addressbooks'])==1): ?>
- <input type="hidden" name="id" value="<?php echo $_['addressbooks'][0]['id']; ?>">
- <?php else: ?>
- <fieldset class="inputs">
- <dl class="form">
- <dt>
- <label for="id"><?php echo $l->t('Addressbook'); ?></label>
- </dt>
- <dd>
- <select name="id" size="1">
- <?php echo html_select_options($_['addressbooks'], null, array('value'=>'id', 'label'=>'displayname')); ?>
- </select>
- </dd>
- </dl>
- </fieldset>
- <?php endif; ?>
- <fieldset class="inputs">
- <dl class="form">
- <dt>
- <label for="n1"><?php echo $l->t('Given name'); ?></label>
- </dd>
- <dd>
- <input id="n1" type="text" name="value[N][1]" value="">
- </dd>
- <dt>
- <label for="n0"><?php echo $l->t('Family name'); ?></label>
- </dd>
- <dd>
- <input id="n0" type="text" name="value[N][0]" value="">
- </dd>
- <dt>
- <label for="n2"><?php echo $l->t('Additional names'); ?></label>
- </dd>
- <dd>
- <input id="n2" type="text" name="value[N][2]" value="">
- <input type="hidden" name="value[N][4]" value="">
- <input type="hidden" name="value[N][5]" value="">
- </dd>
- </dl>
- </fieldset>
- <fieldset class="inputs">
- <dl class="form">
- <dt>
- <label for="fn"><?php echo $l->t('Display name'); ?></label>
- </dd>
- <dd>
- <input id="fn" type="text" name="fn" placeholder="<?php echo $l->t('How you want the name displayed in the list'); ?>" value="">
- </dd>
- <dt>
- <label for="org"><?php echo $l->t('Organization'); ?></label>
- </dt>
- <dd>
- <input id="org" type="text" name="value[ORG]" value="">
- </dd>
- </dl>
- </fieldset>
- <fieldset class="inputs">
- <dl class="form">
- <dt>
- <label for="email"><?php echo $l->t('Email'); ?></label>
- </dt>
- <dd>
- <input id="email" type="email" name="value[EMAIL]" value="">
- </dd>
- <dt>
- <label for="tel"><?php echo $l->t('Telephone'); ?></label>
- </dt>
- <dd>
- <input type="tel" id="tel" name="value[TEL]" value="">
- <select id="TEL" name="parameters[TEL][TYPE][]" multiple="multiple">
- <?php echo html_select_options($_['phone_types'], 'CELL') ?>
- </select>
- </dd>
- </dl>
- </fieldset>
- <fieldset class="inputs">
- <legend><?php echo $l->t('Address'); ?></legend>
- <dl class="form">
- <dt>
- <label for="adr_type"><?php echo $l->t('Type'); ?></label>
- </dt>
- <dd>
- <select id="adr_type" name="parameters[ADR][TYPE]" size="1">
- <?php echo html_select_options($_['adr_types'], 'HOME') ?>
- </select>
- </dd>
- <dt>
- <label for="adr_pobox"><?php echo $l->t('PO Box'); ?></label>
- </dt>
- <dd>
- <input type="text" id="adr_pobox" name="value[ADR][0]" placeholder="<?php echo $l->t('Post Office box'); ?>" value="">
- </dd>
- <dd>
- <!-- dt>
- <label class="label" for="adr_extended"><?php echo $l->t('Extended'); ?></label>
- </dt>
- <dd>
- <input type="text" id="adr_extended" name="value[ADR][1]" value="">
- </dd -->
- <dt>
- <label for="adr_street"><?php echo $l->t('Street'); ?></label>
- </dt>
- <dd>
- <input style="width: 12em;" type="text" id="adr_street" name="value[ADR][2]" placeholder="<?php echo $l->t('Street name and no.'); ?>" value="">
- <label for="adr_extended"><?php echo $l->t('Extended'); ?></label>
- <input style="width: 7em;" type="text" id="adr_extended" name="value[ADR][1]" placeholder="<?php echo $l->t('Apart. no., floor'); ?>" value="">
- </dd>
- <dt>
- <label for="adr_city"><?php echo $l->t('City'); ?></label>
- </dt>
- <dd>
- <input style="width: 12em;" type="text" id="adr_city" name="value[ADR][3]" value="">
- <label for="adr_zipcode"><?php echo $l->t('Zipcode'); ?></label>
- <input style="width: 5em;" type="text" id="adr_zipcode" name="value[ADR][5]" value="">
- </dd>
- <dt>
- <label for="adr_region"><?php echo $l->t('Region'); ?></label>
- </dt>
- <dd>
- <input type="text" id="adr_region" name="value[ADR][4]" placeholder="<?php echo $l->t('E.g. state or province'); ?>" value="">
- </dd>
- <!-- dt>
- <label class="label" for="adr_zipcode"><?php echo $l->t('Zipcode'); ?></label>
- </dt>
- <dd>
- <input type="text" id="adr_zipcode" name="value[ADR][5]" value="">
- </dd -->
- <dt>
- <label for="adr_country"><?php echo $l->t('Country'); ?></label>
- </dt>
- <dd>
- <input type="text" id="adr_country" name="value[ADR][6]" value="">
- </dd>
- </dl>
- </fieldset>
- <input class="create" type="submit" name="submit" value="<?php echo $l->t('Create Contact'); ?>">
-</form>
diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php
index 5be20964f4b..cb1e080a40a 100644
--- a/apps/contacts/templates/part.contact.php
+++ b/apps/contacts/templates/part.contact.php
@@ -13,6 +13,8 @@ $id = isset($_['id']) ? $_['id'] : '';
<li><a data-type="TEL"><?php echo $l->t('Phone'); ?></a></li>
<li><a data-type="EMAIL"><?php echo $l->t('Email'); ?></a></li>
<li><a data-type="ADR"><?php echo $l->t('Address'); ?></a></li>
+ <li><a data-type="NOTE"><?php echo $l->t('Note'); ?></a></li>
+ <li><a data-type="CATEGORIES"><?php echo $l->t('Categories'); ?></a></li>
</ul>
</div>
<img onclick="Contacts.UI.Card.export();" class="svg action" id="contacts_downloadcard" src="<?php echo image_path('', 'actions/download.svg'); ?>" title="<?php echo $l->t('Download contact');?>" />
@@ -21,8 +23,9 @@ $id = isset($_['id']) ? $_['id'] : '';
<div class="contactsection">
- <form style="display:none;" id="file_upload_form" action="ajax/uploadphoto.php" method="post" enctype="multipart/form-data" target="file_upload_target">
+ <form style="display:none;" id="file_upload_form" action="ajax/uploadphoto.php" method="post" enctype="multipart/form-data" target="file_upload_target" class="propertycontainer" data-element="PHOTO">
<fieldset id="photo" class="formfloat">
+ <a class="action delete" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'single');" title="<?php echo $l->t('Delete'); ?>"></a>
<div id="contacts_details_photo_wrapper" title="<?php echo $l->t('Click or drop to upload picture'); ?> (max <?php echo $_['uploadMaxHumanFilesize']; ?>)">
<!-- img style="padding: 1em;" id="contacts_details_photo" alt="Profile picture" src="photo.php?id=<?php echo $_['id']; ?>" / -->
<progress id="contacts_details_photo_progress" style="display:none;" value="0" max="100">0 %</progress>
@@ -45,7 +48,7 @@ $id = isset($_['id']) ? $_['id'] : '';
<dt><label for="fn"><?php echo $l->t('Display name'); ?></label></dt>
<dd class="propertycontainer" data-element="FN">
<select id="fn_select" title="<?php echo $l->t('Format custom, Short name, Full name, Reverse or Reverse with comma'); ?>" style="width:16em;">
- </select><a id="edit_name" class="edit" title="<?php echo $l->t('Edit name details'); ?>"></a>
+ </select><a id="edit_name" class="action edit" title="<?php echo $l->t('Edit name details'); ?>"></a>
</dd>
<dt style="display:none;" id="org_label" data-element="ORG"><label for="org"><?php echo $l->t('Organization'); ?></label></dt>
<dd style="display:none;" class="propertycontainer" id="org_value" data-element="ORG"><input id="org" required="required" name="value[ORG]" type="text" class="contacts_property" style="width:16em;" name="value" value="" placeholder="<?php echo $l->t('Organization'); ?>" /><a class="delete" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'single');" title="<?php echo $l->t('Delete'); ?>"></a></dd>
@@ -53,8 +56,21 @@ $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="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="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>
</fieldset>
+ <fieldset id="note" class="formfloat propertycontainer contactpart" style="display:none;" data-element="NOTE">
+ <legend><?php echo $l->t('Note'); ?><a class="delete" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'single');" title="<?php echo $l->t('Delete'); ?>"></a></legend>
+ <textarea class="contacts_property note" name="value" cols="60" rows="10"></textarea>
+ </fieldset>
</form>
</div>
diff --git a/apps/contacts/templates/part.contactphoto.php b/apps/contacts/templates/part.contactphoto.php
index 9e3f5876cd1..bcb2f75815c 100644
--- a/apps/contacts/templates/part.contactphoto.php
+++ b/apps/contacts/templates/part.contactphoto.php
@@ -2,8 +2,9 @@
$id = $_['id'];
$wattr = isset($_['width'])?'width="'.$_['width'].'"':'';
$hattr = isset($_['height'])?'height="'.$_['height'].'"':'';
+$rand = isset($_['refresh'])?'&'.rand().'='.rand():'';
?>
-<img class="loading" id="contacts_details_photo" <?php echo $wattr; ?> <?php echo $hattr; ?> src="<?php echo OC_Helper::linkToAbsolute('contacts', 'photo.php'); ?>?id=<?php echo $id; ?>&amp;refresh=<?php echo rand(); ?>" />
+<img class="loading" id="contacts_details_photo" <?php echo $wattr; ?> <?php echo $hattr; ?> src="<?php echo OC_Helper::linkToAbsolute('contacts', 'photo.php'); ?>?id=<?php echo $id.$rand; ?>" />
<progress id="contacts_details_photo_progress" style="display:none;" value="0" max="100">0 %</progress>
diff --git a/apps/contacts/templates/part.details.php b/apps/contacts/templates/part.details.php
deleted file mode 100644
index 5badd816155..00000000000
--- a/apps/contacts/templates/part.details.php
+++ /dev/null
@@ -1,96 +0,0 @@
-<?php if(array_key_exists('FN',$_['details'])): ?>
- <?php echo $this->inc('part.property.FN', array('property' => $_['details']['FN'][0])); ?>
- <?php echo $this->inc('part.property.N', array('property' => $_['details']['N'][0])); ?>
- <a href="export.php?contactid=<?php echo $_['id']; ?>"><img class="svg action" id="contacts_downloadcard" src="<?php echo image_path('', 'actions/download.svg'); ?>" title="<?php echo $l->t('Download contact');?>" /></a>
- <img class="svg action" id="contacts_deletecard" src="<?php echo image_path('', 'actions/delete.svg'); ?>" title="<?php echo $l->t('Delete contact');?>" />
-
- <?php if(isset($_['details']['PHOTO'])): // Emails first ?>
- <img id="contacts_details_photo" src="photo.php?id=<?php echo $_['id']; ?>">
- <?php endif; ?>
-
- <ul id="contacts_details_list">
- <?php if(isset($_['details']['BDAY'])): // Emails first ?>
- <?php echo $this->inc('part.property', array('property' => $_['details']['BDAY'][0])); ?>
- <?php endif; ?>
-
- <?php if(isset($_['details']['ORG'])): // Emails first ?>
- <?php echo $this->inc('part.property', array('property' => $_['details']['ORG'][0])); ?>
- <?php endif; ?>
-
- <?php foreach(array('EMAIL','TEL','ADR') as $type): ?>
- <?php if(isset($_['details'][$type])): // Emails first ?>
- <?php foreach($_['details'][$type] as $property): ?>
- <?php echo $this->inc('part.property',array('property' => $property )); ?>
- <?php endforeach; ?>
- <?php endif; ?>
- <?php endforeach; ?>
- <li class="contacts_property_add">
- <form id="contacts_addpropertyform">
- <input type="hidden" name="id" value="<?php echo $_['id']; ?>">
- <p class="contacts_property_name">
- <select name="name" size="1">
- <?php echo html_select_options($_['property_types'], 'EMAIL') ?>
- </select>
- <br>
- <input id="contacts_addproperty_button" type="submit" value="<?php echo $l->t('Add'); ?>">
- </p>
- <p class="contacts_property_data" id="contacts_generic">
- <input type="text" name="value" value="">
- </p>
- </form>
- <div id="contacts_addcontactsparts" style="display:none;">
- <ul class="contacts_property_data" id="contacts_addresspart">
- <li>
- <label for="adr_type"><?php echo $l->t('Type'); ?></label>
- <select id="adr_type" name="parameters[TYPE]" size="1">
- <?php echo html_select_options($_['adr_types'], 'HOME') ?>
- </select>
- </li>
- <li>
- <label for="adr_pobox"><?php echo $l->t('PO Box'); ?></label>
- <input id="adr_pobox" type="text" name="value[0]" value="">
- </li>
- <li>
- <label for="adr_extended"><?php echo $l->t('Extended'); ?></label>
- <input id="adr_extended" type="text" name="value[1]" value="">
- </li>
- <li>
- <label for="adr_street"><?php echo $l->t('Street'); ?></label>
- <input id="adr_street" type="text" name="value[2]" value="">
- </li>
- <li>
- <label for="adr_city"><?php echo $l->t('City'); ?></label>
- <input id="adr_city" type="text" name="value[3]" value="">
- </li>
- <li>
- <label for="adr_region"><?php echo $l->t('Region'); ?></label>
- <input id="adr_region" type="text" name="value[4]" value="">
- </li>
- <li>
- <label for="adr_zipcode"><?php echo $l->t('Zipcode'); ?></label>
- <input id="adr_zipcode" type="text" name="value[5]" value="">
- </li>
- <li>
- <label for="adr_country"><?php echo $l->t('Country'); ?></label>
- <input id="adr_country" type="text" name="value[6]" value="">
- </li>
- </ul>
- <p class="contacts_property_data" id="contacts_phonepart">
- <input type="text" name="value" value="">
- <select name="parameters[TYPE][]" multiple="multiple" data-placeholder="<?php echo $l->t('Type') ?>">
- <?php echo html_select_options($_['phone_types'], 'CELL') ?>
- </select>
- </p>
- <p class="contacts_property_data" id="contacts_generic">
- <input type="text" name="value" value="">
- </p>
- </div>
- </li>
- </ul>
-<?php endif; ?>
-<script language="Javascript">
-/* Re-tipsify ;-)*/
- $('#contacts_deletecard').tipsy({gravity: 'ne'});
- $('#contacts_downloadcard').tipsy({gravity: 'ne'});
- $('.button').tipsy();
-</script>
diff --git a/apps/contacts/templates/part.edit_categories_dialog.php b/apps/contacts/templates/part.edit_categories_dialog.php
new file mode 100644
index 00000000000..8997fa586bd
--- /dev/null
+++ b/apps/contacts/templates/part.edit_categories_dialog.php
@@ -0,0 +1,16 @@
+<?php
+$categories = isset($_['categories'])?$_['categories']:array();
+?>
+<div id="edit_categories_dialog" title="<?php echo $l->t('Edit categories'); ?>">
+<!-- ?php print_r($types); ? -->
+ <form method="post" id="categoryform">
+ <div class="scrollarea">
+ <ul id="categorylist">
+ <?php foreach($categories as $category) { ?>
+ <li><input type="checkbox" name="categories[]" value="<?php echo $category; ?>" /><?php echo $category; ?></li>
+ <?php } ?>
+ </ul>
+ </div>
+ <div class="bottombuttons"><input type="text" id="category_addinput" name="category" /><button id="category_addbutton" disabled="disabled"><?php echo $l->t('Add'); ?></button></div>
+ </form>
+</div>
diff --git a/apps/contacts/templates/part.messagebox.php b/apps/contacts/templates/part.messagebox.php
deleted file mode 100644
index 5db10e7e6c5..00000000000
--- a/apps/contacts/templates/part.messagebox.php
+++ /dev/null
@@ -1,3 +0,0 @@
-<div id="messagebox">
-<div id="messagebox_msg"></div>
-</di>
diff --git a/apps/contacts/templates/part.no_contacts.php b/apps/contacts/templates/part.no_contacts.php
deleted file mode 100644
index f58fdef09f0..00000000000
--- a/apps/contacts/templates/part.no_contacts.php
+++ /dev/null
@@ -1,8 +0,0 @@
-<div id="firstrun">
-You have no contacts in your list.
- <div id="selections">
- <input type="button" value="Import contacts" onclick="Contacts.UI.Addressbooks.import()" />
- <input type="button" value="Add contact" onclick="Contacts.UI.Card.editNew()" />
- <input type="button" value="Edit addressbooks" onclick="Contacts.UI.Addressbooks.overview()" />
- </div>
-</div> \ No newline at end of file
diff --git a/apps/contacts/templates/part.property.FN.php b/apps/contacts/templates/part.property.FN.php
deleted file mode 100644
index c9e21c20e60..00000000000
--- a/apps/contacts/templates/part.property.FN.php
+++ /dev/null
@@ -1,9 +0,0 @@
- <p id="contacts_details_name" class="contacts_property" data-checksum="<?php echo $_['property']['checksum']; ?>">
- <?php echo htmlspecialchars($_['property']['value']); ?>
- <span style="display:none;" data-use="edit"><img class="svg action" src="<?php echo image_path('', 'actions/rename.svg'); ?>" /></span>
- </p>
-<?php if (!isset($_['details'])): ?>
-<script>
-$('#leftcontent li.active a').text('<?php echo htmlspecialchars($_['property']['value']); ?>');
-</script>
-<?php endif ?>
diff --git a/apps/contacts/templates/part.property.N.php b/apps/contacts/templates/part.property.N.php
deleted file mode 100644
index 73d599ad7b4..00000000000
--- a/apps/contacts/templates/part.property.N.php
+++ /dev/null
@@ -1,4 +0,0 @@
-<p id="contacts_details_name_n" class="contacts_property" data-checksum="<?php echo $_['property']['checksum']; ?>">
- (<?php echo $_['property']['value'][0].', '.$_['property']['value'][1].' '.$_['property']['value'][2]; ?>)
- <span style="display:none;" data-use="edit"><img class="svg action" src="<?php echo image_path('', 'actions/rename.svg'); ?>" /></span>
-</p>
diff --git a/apps/contacts/templates/part.property.php b/apps/contacts/templates/part.property.php
deleted file mode 100644
index 7b23fae45b5..00000000000
--- a/apps/contacts/templates/part.property.php
+++ /dev/null
@@ -1,86 +0,0 @@
-<li class="contacts_property" data-checksum="<?php echo $_['property']['checksum']; ?>">
- <?php if($_['property']['name'] == 'BDAY'): ?>
- <p class="contacts_property_name"><?php echo $l->t('Birthday'); ?></p>
- <p class="contacts_property_data">
- <?php echo $l->l('date',new DateTime($_['property']['value'])); ?>
- <span style="display:none;" data-use="delete"><img class="svg action" src="<?php echo image_path('', 'actions/delete.svg'); ?>" /></span>
- </p>
- <?php elseif($_['property']['name'] == 'ORG'): ?>
- <p class="contacts_property_name"><?php echo $l->t('Organization'); ?></p>
- <p class="contacts_property_data">
- <?php echo htmlspecialchars($_['property']['value']); ?>
- <span style="display:none;" data-use="edit"><img class="svg action" src="<?php echo image_path('', 'actions/rename.svg'); ?>" /></span>
- <span style="display:none;" data-use="delete"><img class="svg action" src="<?php echo image_path('', 'actions/delete.svg'); ?>" /></span>
- </p>
- <?php elseif($_['property']['name'] == 'EMAIL'): ?>
- <p class="contacts_property_name"><?php echo $l->t('Email'); ?></p>
- <p class="contacts_property_data">
- <?php echo htmlspecialchars($_['property']['value']); ?>
- <span style="display:none;" data-use="edit"><img class="svg action" src="<?php echo image_path('', 'actions/rename.svg'); ?>" /></span>
- <span style="display:none;" data-use="delete"><img class="svg action" src="<?php echo image_path('', 'actions/delete.svg'); ?>" /></span>
- </p>
- <?php elseif($_['property']['name'] == 'TEL'): ?>
- <p class="contacts_property_name"><?php echo (isset($_['property']['parameters']['PREF']) && $_['property']['parameters']['PREF']) ? $l->t('Preferred').' ' : '' ?><?php echo $l->t('Phone'); ?></p>
- <p class="contacts_property_data">
- <?php echo htmlspecialchars($_['property']['value']); ?>
- <?php if(isset($_['property']['parameters']['TYPE']) && !empty($_['property']['parameters']['TYPE'])): ?>
-<?php
- foreach($_['property']['parameters']['TYPE'] as $type) {
- if (isset($_['phone_types'][strtoupper($type)])){
- $types[]=$_['phone_types'][strtoupper($type)];
- }
- else{
- $types[]=$l->t(ucwords(strtolower($type)));
- }
- }
- $label = join(' ', $types);
-?>
- (<?php echo $label; ?>)
- <?php endif; ?>
- <span style="display:none;" data-use="edit"><img class="svg action" src="<?php echo image_path('', 'actions/rename.svg'); ?>" /></span>
- <span style="display:none;" data-use="delete"><img class="svg action" src="<?php echo image_path('', 'actions/delete.svg'); ?>" /></span>
- </p>
- <?php elseif($_['property']['name'] == 'ADR'): ?>
- <p class="contacts_property_name">
- <?php echo $l->t('Address'); ?>
- <?php if(isset($_['property']['parameters']['TYPE'])): ?>
- <br>
-<?php
- $type = $_['property']['parameters']['TYPE'];
- if (isset($_['adr_types'][strtoupper($type)])){
- $label=$_['adr_types'][strtoupper($type)];
- }
- else{
- $label=$l->t(ucwords(strtolower($type)));
- }
-?>
- (<?php echo $label; ?>)
- <?php endif; ?>
- </p>
- <p class="contacts_property_data">
- <?php if(!empty($_['property']['value'][0])): ?>
- <?php echo htmlspecialchars($_['property']['value'][0]); ?><br>
- <?php endif; ?>
- <?php if(!empty($_['property']['value'][1])): ?>
- <?php echo htmlspecialchars($_['property']['value'][1]); ?><br>
- <?php endif; ?>
- <?php if(!empty($_['property']['value'][2])): ?>
- <?php echo htmlspecialchars($_['property']['value'][2]); ?><br>
- <?php endif; ?>
- <?php if(!empty($_['property']['value'][3])): ?>
- <?php echo htmlspecialchars($_['property']['value'][3]); ?><br>
- <?php endif; ?>
- <?php if(!empty($_['property']['value'][4])): ?>
- <?php echo htmlspecialchars($_['property']['value'][4]); ?><br>
- <?php endif; ?>
- <?php if(!empty($_['property']['value'][5])): ?>
- <?php echo htmlspecialchars($_['property']['value'][5]); ?><br>
- <?php endif; ?>
- <?php if(!empty($_['property']['value'][6])): ?>
- <?php echo htmlspecialchars($_['property']['value'][6]); ?>
- <?php endif; ?>
- <span style="display:none;" data-use="edit"><img class="svg action" src="<?php echo image_path('', 'actions/rename.svg'); ?>" /></span>
- <span style="display:none;" data-use="delete"><img class="svg action" src="<?php echo image_path('', 'actions/delete.svg'); ?>" /></span>
- </p>
- <?php endif; ?>
-</li>
diff --git a/apps/contacts/templates/part.setpropertyform.php b/apps/contacts/templates/part.setpropertyform.php
deleted file mode 100644
index 93ade8faaa7..00000000000
--- a/apps/contacts/templates/part.setpropertyform.php
+++ /dev/null
@@ -1,91 +0,0 @@
- <form id="contacts_setpropertyform">
- <input type="hidden" name="checksum" value="<?php echo $_['property']['checksum']; ?>">
- <input type="hidden" name="id" value="<?php echo $_['id']; ?>">
- <?php if($_['property']['name']=='N'): ?>
- <p class="contacts_property_name">
- <dl class="contacts_property_data form">
- <dt><label for="n1"><?php echo $l->t('Given name'); ?></label></dt>
- <dd><input id="n1" type="text" name="value[1]" value="<?php echo htmlspecialchars($_['property']['value'][1]); ?>"></dd>
- <dt><label for="n0"><?php echo $l->t('Family name'); ?></dt>
- <dd><input id="n0" type="text" name="value[0]" value="<?php echo htmlspecialchars($_['property']['value'][0]); ?>"></dd>
- <dt><label for="n2"><?php echo $l->t('Additional names'); ?></dt>
- <dd><input id="n2" type="text" name="value[2]" value="<?php echo htmlspecialchars($_['property']['value'][2]); ?>">
- <input id="n3" type="hidden" name="value[3]" value="<?php echo htmlspecialchars($_['property']['value'][3]); ?>">
- <input id="n4" type="hidden" name="value[4]" value="<?php echo htmlspecialchars($_['property']['value'][4]); ?>">
- </dd>
- </dl>
- </p>
- <?php elseif($_['property']['name']=='FN'): ?>
- <p class="contacts_property_data"><input id="fn" type="text" name="value" value="<?php echo htmlspecialchars($_['property']['value']); ?>"></p>
- <?php elseif($_['property']['name']=='ADR'): ?>
- <p class="contacts_property_name"><label for="adr_pobox"><?php echo $l->t('Address'); ?></label></p>
- <dl class="contacts_property_data form" id="contacts_addresspart">
- <dt>
- <label class="label" for="adr_type"><?php echo $l->t('Type'); ?></label>
- </dt>
- <dd>
- <select id="adr_type" name="parameters[TYPE]" size="1">
- <?php echo html_select_options($_['adr_types'], strtoupper($_['property']['parameters']['TYPE'])) ?>
- </select>
- </dd>
- <dt>
- <label for="adr_pobox"><?php echo $l->t('PO Box'); ?></label>
- </dt>
- <dd>
- <input id="adr_pobox" type="text" name="value[0]" value="<?php echo htmlspecialchars($_['property']['value'][0]) ?>">
- </dd>
- <!-- dt>
- <label for="adr_extended"><?php echo $l->t('Extended'); ?></label>
- </dt>
- <dd>
- <input style="width: 7em;" id="adr_extended" type="text" name="value[1]" value="<?php echo htmlspecialchars($_['property']['value'][1]) ?>">
- </dd -->
- <dt>
- <label for="adr_street"><?php echo $l->t('Street'); ?></label>
- </dt>
- <dd>
- <input style="width: 12em;" id="adr_street" type="text" name="value[2]" value="<?php echo htmlspecialchars($_['property']['value'][2]) ?>">
- <label for="adr_extended"><?php echo $l->t('Extended'); ?></label><input style="width: 7em;" id="adr_extended" type="text" name="value[1]" value="<?php echo htmlspecialchars($_['property']['value'][1]) ?>">
- </dd>
- <dt>
- <label for="adr_city"><?php echo $l->t('City'); ?></label>
- </dt>
- <dd>
- <input style="width: 12em;" id="adr_city" type="text" name="value[3]" value="<?php echo htmlspecialchars($_['property']['value'][3]) ?>">
- <label for="adr_zipcode"><?php echo $l->t('Zipcode'); ?></label>
- <input style="width: 5em;" id="adr_zipcode" type="text" name="value[5]" value="<?php echo htmlspecialchars($_['property']['value'][5]) ?>">
- </dd>
- <dt>
- <label for="adr_region"><?php echo $l->t('Region'); ?></label>
- </dt>
- <dd>
- <input id="adr_region" type="text" name="value[4]" value="<?php echo htmlspecialchars($_['property']['value'][4]) ?>">
- </dd>
- <!-- dt>
- <label for="adr_zipcode"><?php echo $l->t('Zipcode'); ?></label>
- </dt>
- <dd>
- <input style="width: 7em;" id="adr_zipcode" type="text" name="value[5]" value="<?php echo htmlspecialchars($_['property']['value'][5]) ?>">
- </dd -->
- <dt>
- <label for="adr_country"><?php echo $l->t('Country'); ?></label>
- </dt>
- <dd>
- <input style="width: 25em;" id="adr_country" type="text" name="value[6]" value="<?php echo htmlspecialchars($_['property']['value'][6]) ?>">
- </dd>
- </dl>
- <?php elseif($_['property']['name']=='TEL'): ?>
- <p class="contacts_property_name"><label for="tel"><?php echo $l->t('Phone'); ?></label></p>
- <p class="contacts_property_data"><input id="tel" type="phone" name="value" value="<?php echo htmlspecialchars($_['property']['value']) ?>">
- <select id="tel_type<?php echo $_['property']['checksum'] ?>" name="parameters[TYPE][]" multiple="multiple" data-placeholder="<?php echo $l->t('Type') ?>">
- <?php echo html_select_options($_['phone_types'], isset($_['property']['parameters']['TYPE'])?$_['property']['parameters']['TYPE']:array()) ?>
- </select></p>
- <?php elseif($_['property']['name']=='EMAIL'): ?>
- <p class="contacts_property_name"><label for="email"><?php echo $l->t('Email'); ?></label></p>
- <p class="contacts_property_data"><input id="email" type="text" name="value" value="<?php echo htmlspecialchars($_['property']['value']); ?>"></p>
- <?php elseif($_['property']['name']=='ORG'): ?>
- <p class="contacts_property_name"><label for="org"><?php echo $l->t('Organization'); ?></label></p>
- <p class="contacts_property_data"><input id="org" type="text" name="value" value="<?php echo htmlspecialchars($_['property']['value']); ?>"></p>
- <?php endif; ?>
- <input id="contacts_setproperty_button" type="submit" value="<?php echo $l->t('Update'); ?>">
- </form>
diff --git a/apps/contacts/templates/settings.php b/apps/contacts/templates/settings.php
index 8673e4521d9..f56de0ec8b0 100644
--- a/apps/contacts/templates/settings.php
+++ b/apps/contacts/templates/settings.php
@@ -1,7 +1,12 @@
-<form id="mediaform">
+<form id="contacts">
<fieldset class="personalblock">
<strong><?php echo $l->t('Contacts'); ?></strong><br />
- <?php echo $l->t('CardDAV syncing address:'); ?>
- <?php echo OC_Helper::linkToAbsolute('contacts', 'carddav.php'); ?><br />
+ <?php echo $l->t('CardDAV syncing addresses:'); ?>
+ <dl>
+ <dt><?php echo $l->t('Primary address (Kontact et al)'); ?></dt>
+ <dd><code><?php echo OC_Helper::linkToAbsolute('contacts', 'carddav.php'); ?>/</code></dd>
+ <dt><?php echo $l->t('iOS/OS X'); ?></dt>
+ <dd><code><?php echo OC_Helper::linkToAbsolute('contacts', 'carddav.php'); ?>/principals/<?php echo OC_User::getUser(); ?></code>/</dd>
+ </dl>
</fieldset>
</form>
diff --git a/apps/external/ajax/setsites.php b/apps/external/ajax/setsites.php
new file mode 100644
index 00000000000..0537b7ea581
--- /dev/null
+++ b/apps/external/ajax/setsites.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * Copyright (c) 2011, Frank Karlitschek <karlitschek@kde.org>
+ * This file is licensed under the Affero General Public License version 3 or later.
+ * See the COPYING-README file.
+ */
+
+require_once('../../../lib/base.php');
+OC_Util::checkAdminUser();
+
+$sites = array();
+for ($i = 0; $i < sizeof($_POST['site_name']); $i++) {
+ if (!empty($_POST['site_name'][$i]) && !empty($_POST['site_url'][$i])) {
+ array_push($sites, array($_POST['site_name'][$i], $_POST['site_url'][$i]));
+ }
+}
+
+if (sizeof($sites) == 0)
+ OC_Appconfig::deleteKey('external', 'sites');
+else
+ OC_Appconfig::setValue('external', 'sites', json_encode($sites));
+
+echo 'true';
+?>
diff --git a/apps/external/ajax/seturls.php b/apps/external/ajax/seturls.php
deleted file mode 100644
index e994385a199..00000000000
--- a/apps/external/ajax/seturls.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-/**
- * Copyright (c) 2011, Frank Karlitschek <karlitschek@kde.org>
- * This file is licensed under the Affero General Public License version 3 or later.
- * See the COPYING-README file.
- */
-
-require_once('../../../lib/base.php');
-OC_Util::checkAdminUser();
-
-if(isset($_POST['s1name'])) OC_Appconfig::setValue( 'external','site1name', $_POST['s1name'] );
-if(isset($_POST['s1url'])) OC_Appconfig::setValue( 'external','site1url', $_POST['s1url'] );
-if(isset($_POST['s2name'])) OC_Appconfig::setValue( 'external','site2name', $_POST['s2name'] );
-if(isset($_POST['s2url'])) OC_Appconfig::setValue( 'external','site2url', $_POST['s2url'] );
-if(isset($_POST['s3name'])) OC_Appconfig::setValue( 'external','site3name', $_POST['s3name'] );
-if(isset($_POST['s3url'])) OC_Appconfig::setValue( 'external','site3url', $_POST['s3url'] );
-if(isset($_POST['s4name'])) OC_Appconfig::setValue( 'external','site4name', $_POST['s4name'] );
-if(isset($_POST['s4url'])) OC_Appconfig::setValue( 'external','site4url', $_POST['s4url'] );
-if(isset($_POST['s5name'])) OC_Appconfig::setValue( 'external','site5name', $_POST['s5name'] );
-if(isset($_POST['s5url'])) OC_Appconfig::setValue( 'external','site5url', $_POST['s5url'] );
-
-echo 'true';
-
-?>
diff --git a/apps/external/appinfo/app.php b/apps/external/appinfo/app.php
index 0f536cbf418..74e6d5c94c6 100644
--- a/apps/external/appinfo/app.php
+++ b/apps/external/appinfo/app.php
@@ -1,37 +1,35 @@
<?php
/**
-* ownCloud - External plugin
-*
-* @author Frank Karlitschek
-* @copyright 2011 Frank Karlitschek karlitschek@kde.org
-*
-* 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 Lesser General Public
-* License along with this library. If not, see <http://www.gnu.org/licenses/>.
-*
-*/
-
-OC_APP::registerAdmin('external','settings');
-
-OC_App::register( array( 'order' => 70, 'id' => 'external', 'name' => 'External' ));
-
-if(OC_Appconfig::getValue( "external","site1name", '' )<>'') OC_App::addNavigationEntry( array( 'id' => 'external_index1', 'order' => 80, 'href' => OC_Helper::linkTo( 'external', 'index.php' ).'?id=1', 'icon' => OC_Helper::imagePath( 'external', 'external.png' ), 'name' => OC_Appconfig::getValue( "external","site1name", '' )));
-
-if(OC_Appconfig::getValue( "external","site2name", '' )<>'') OC_App::addNavigationEntry( array( 'id' => 'external_index2', 'order' => 80, 'href' => OC_Helper::linkTo( 'external', 'index.php' ).'?id=2', 'icon' => OC_Helper::imagePath( 'external', 'external.png' ), 'name' => OC_Appconfig::getValue( "external","site2name", '' )));
-
-if(OC_Appconfig::getValue( "external","site3name", '' )<>'') OC_App::addNavigationEntry( array( 'id' => 'external_index3', 'order' => 80, 'href' => OC_Helper::linkTo( 'external', 'index.php' ).'?id=3', 'icon' => OC_Helper::imagePath( 'external', 'external.png' ), 'name' => OC_Appconfig::getValue( "external","site3name", '' )));
-
-if(OC_Appconfig::getValue( "external","site4name", '' )<>'') OC_App::addNavigationEntry( array( 'id' => 'external_index4', 'order' => 80, 'href' => OC_Helper::linkTo( 'external', 'index.php' ).'?id=4', 'icon' => OC_Helper::imagePath( 'external', 'external.png' ), 'name' => OC_Appconfig::getValue( "external","site4name", '' )));
-
-if(OC_Appconfig::getValue( "external","site5name", '' )<>'') OC_App::addNavigationEntry( array( 'id' => 'external_index5', 'order' => 80, 'href' => OC_Helper::linkTo( 'external', 'index.php' ).'?id=5', 'icon' => OC_Helper::imagePath( 'external', 'external.png' ), 'name' => OC_Appconfig::getValue( "external","site5name", '' )));
-
+ * ownCloud - External plugin
+ *
+ * @author Frank Karlitschek
+ * @copyright 2011 Frank Karlitschek karlitschek@kde.org
+ *
+ * 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 Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+OC::$CLASSPATH['OC_External'] = 'apps/external/lib/external.php';
+OC_Util::addStyle( 'external', 'style');
+
+OC_APP::registerAdmin('external', 'settings');
+
+OC_App::register(array('order' => 70, 'id' => 'external', 'name' => 'External'));
+
+$sites = OC_External::getSites();
+for ($i = 0; $i < sizeof($sites); $i++) {
+ OC_App::addNavigationEntry(
+ array('id' => 'external_index' . ($i + 1), 'order' => 80 + $i, 'href' => OC_Helper::linkTo('external', 'index.php') . '?id=' . ($i + 1), 'icon' => OC_Helper::imagePath('external', 'external.png'), 'name' => $sites[$i][0]));
+} \ No newline at end of file
diff --git a/apps/external/css/style.css b/apps/external/css/style.css
new file mode 100644
index 00000000000..f891cb4bc55
--- /dev/null
+++ b/apps/external/css/style.css
@@ -0,0 +1,14 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- /
+/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
+
+.site_url {
+ width: 250px;
+}
+
+.delete_button {
+ display: none;
+}
+
+.external_sites {
+ width: 450px;
+}
diff --git a/apps/external/index.php b/apps/external/index.php
index 51cdc344bbf..1c20f59eaff 100644
--- a/apps/external/index.php
+++ b/apps/external/index.php
@@ -1,42 +1,43 @@
<?php
/**
-* ownCloud - External plugin
-*
-* @author Frank Karlitschek
-* @copyright 2011 Frank Karlitschek karlitschek@kde.org
-*
-* 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 Lesser General Public
-* License along with this library. If not, see <http://www.gnu.org/licenses/>.
-*
-*/
-
+ * ownCloud - External plugin
+ *
+ * @author Frank Karlitschek
+ * @copyright 2011 Frank Karlitschek karlitschek@kde.org
+ *
+ * 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 Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
require_once('../../lib/base.php');
+require_once('lib/external.php');
OC_Util::checkLoggedIn();
-if(isset($_GET['id'])){
+if (isset($_GET['id'])) {
- $id=$_GET['id'];
+ $id = $_GET['id'];
$id = (int) $id;
- $url=OC_Appconfig::getValue( "external","site".$id."url", '' );
- OC_App::setActiveNavigationEntry( 'external_index'.$id );
-
- $tmpl = new OC_Template( 'external', 'frame', 'user' );
- $tmpl->assign('url',$url);
- $tmpl->printPage();
+ $sites = OC_External::getSites();
+ if (sizeof($sites) >= $id) {
+ $url = $sites[$id - 1][1];
+ OC_App::setActiveNavigationEntry('external_index' . $id);
+ $tmpl = new OC_Template('external', 'frame', 'user');
+ $tmpl->assign('url', $url);
+ $tmpl->printPage();
+ }
}
-
?>
diff --git a/apps/external/js/admin.js b/apps/external/js/admin.js
index 6b9b6c67737..0caaabd0b96 100644
--- a/apps/external/js/admin.js
+++ b/apps/external/js/admin.js
@@ -1,67 +1,56 @@
$(document).ready(function(){
+ newSiteHtml = '<li><input type="text" class="site_name" name="site_name[]" value="" placeholder="Name" />\n\
+ <input type="text" name="site_url[]" class="site_url" value="" placeholder="URL" />\n\
+<img class="svg action delete_button" src="'+OC.imagePath("core", "actions/delete") +'" title="Remove site" /></li>';
-
-
- $('#s1name').blur(function(event){
+ // Handler functions
+ function addSiteEventHandler(event) {
event.preventDefault();
- var post = $( "#s1name" ).serialize();
- $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s1name .msg', data); });
- });
+
+ saveSites();
+ }
- $('#s2name').blur(function(event){
+ function deleteButtonEventHandler(event) {
event.preventDefault();
- var post = $( "#s2name" ).serialize();
- $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s2name .msg', data); });
- });
- $('#s3name').blur(function(event){
- event.preventDefault();
- var post = $( "#s3name" ).serialize();
- $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s3name .msg', data); });
- });
+ $(this).tipsy('hide');
+ $(this).parent().remove();
- $('#s4name').blur(function(event){
- event.preventDefault();
- var post = $( "#s4name" ).serialize();
- $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s4name .msg', data); });
- });
+ saveSites();
+ }
- $('#s5name').blur(function(event){
- event.preventDefault();
- var post = $( "#s5name" ).serialize();
- $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s5name .msg', data); });
- });
+ function saveSites() {
+ var post = $('#external').serialize();
+ $.post( OC.filePath('external','ajax','setsites.php') , post, function(data) {
+ // OC.msg.finishedSaving('#site_name .msg', data);
+ });
+ }
- $('#s1url').blur(function(event){
- event.preventDefault();
- var post = $( "#s1url" ).serialize();
- $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s1url .msg', data); });
- });
+ function showDeleteButton(event) {
+ $(this).find('img.delete_button').fadeIn(100);
+ }
- $('#s2url').blur(function(event){
- event.preventDefault();
- var post = $( "#s2url" ).serialize();
- $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s2url .msg', data); });
- });
+ function hideDeleteButton(event) {
+ $(this).find('img.delete_button').fadeOut(100);
+ }
- $('#s3url').blur(function(event){
- event.preventDefault();
- var post = $( "#s3url" ).serialize();
- $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s3url .msg', data); });
- });
+ // Initialize events
+ $('input[name^=site_]').change(addSiteEventHandler);
+ $('img.delete_button').click(deleteButtonEventHandler);
+ $('img.delete_button').tipsy();
- $('#s4url').blur(function(event){
- event.preventDefault();
- var post = $( "#s4url" ).serialize();
- $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s4url .msg', data); });
- });
+ $('#external li').hover(showDeleteButton, hideDeleteButton);
- $('#s5url').blur(function(event){
+ $('#add_external_site').click(function(event) {
event.preventDefault();
- var post = $( "#s5url" ).serialize();
- $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s5url .msg', data); });
- });
+ $('#external ul').append(newSiteHtml);
+ $('input.site_url:last').prev('input.site_name').andSelf().change(addSiteEventHandler);
+ $('img.delete_button').click(deleteButtonEventHandler);
+ $('img.delete_button:last').tipsy();
+ $('#external li:last').hover(showDeleteButton, hideDeleteButton);
+
+ });
});
diff --git a/apps/external/lib/external.php b/apps/external/lib/external.php
new file mode 100644
index 00000000000..9dd32321135
--- /dev/null
+++ b/apps/external/lib/external.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * ownCloud - gallery application
+ *
+ * @author Bartek Przybylski
+ * @copyright 2012 Bartek Przybylski bart.p.pl@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 Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+class OC_External {
+
+ public static function getSites() {
+ if (($sites = json_decode(OC_Appconfig::getValue("external", "sites", ''))) != NULL) {
+ return $sites;
+ }
+
+ return array();
+ }
+
+}
+
+?>
diff --git a/apps/external/settings.php b/apps/external/settings.php
index 3e0c3425128..416c9a5c11f 100644
--- a/apps/external/settings.php
+++ b/apps/external/settings.php
@@ -6,17 +6,5 @@ OC_Util::addScript( "external", "admin" );
$tmpl = new OC_Template( 'external', 'settings');
- $tmpl->assign('s1name',OC_Appconfig::getValue( "external","site1name", '' ));
- $tmpl->assign('s2name',OC_Appconfig::getValue( "external","site2name", '' ));
- $tmpl->assign('s3name',OC_Appconfig::getValue( "external","site3name", '' ));
- $tmpl->assign('s4name',OC_Appconfig::getValue( "external","site4name", '' ));
- $tmpl->assign('s5name',OC_Appconfig::getValue( "external","site5name", '' ));
-
- $tmpl->assign('s1url',OC_Appconfig::getValue( "external","site1url", '' ));
- $tmpl->assign('s2url',OC_Appconfig::getValue( "external","site2url", '' ));
- $tmpl->assign('s3url',OC_Appconfig::getValue( "external","site3url", '' ));
- $tmpl->assign('s4url',OC_Appconfig::getValue( "external","site4url", '' ));
- $tmpl->assign('s5url',OC_Appconfig::getValue( "external","site5url", '' ));
-
return $tmpl->fetchPage();
?>
diff --git a/apps/external/templates/settings.php b/apps/external/templates/settings.php
index a72327d35c8..a130477d465 100644
--- a/apps/external/templates/settings.php
+++ b/apps/external/templates/settings.php
@@ -1,23 +1,21 @@
<form id="external">
<fieldset class="personalblock">
<strong>External Sites</strong><br />
- <input type="text" name="s1name" id="s1name" value="<?php echo $_['s1name']; ?>" placeholder="<?php echo $l->t('Name');?>" />
- <input type="text" name="s1url" id="s1url" value="<?php echo $_['s1url']; ?>" placeholder="<?php echo $l->t('Url');?>" />
- <br />
- <input type="text" name="s2name" id="s2name" value="<?php echo $_['s2name']; ?>" placeholder="<?php echo $l->t('Name');?>" />
- <input type="text" name="s2url" id="s2url" value="<?php echo $_['s2url']; ?>" placeholder="<?php echo $l->t('Url');?>" />
- <br />
- <input type="text" name="s3name" id="s3name" value="<?php echo $_['s3name']; ?>" placeholder="<?php echo $l->t('Name');?>" />
- <input type="text" name="s3url" id="s3url" value="<?php echo $_['s3url']; ?>" placeholder="<?php echo $l->t('Url');?>" />
- <br />
- <input type="text" name="s4name" id="s4name" value="<?php echo $_['s4name']; ?>" placeholder="<?php echo $l->t('Name');?>" />
- <input type="text" name="s4url" id="s4url" value="<?php echo $_['s4url']; ?>" placeholder="<?php echo $l->t('Url');?>" />
- <br />
- <input type="text" name="s5name" id="s5name" value="<?php echo $_['s5name']; ?>" placeholder="<?php echo $l->t('Name');?>" />
- <input type="text" name="s5url" id="s5url" value="<?php echo $_['s5url']; ?>" placeholder="<?php echo $l->t('Url');?>" />
- <br />
+ <ul class="external_sites">
+ <?php
+ $sites = OC_External::getSites();
+ for($i = 0; $i < sizeof($sites); $i++) {
+ echo '<li><input type="text" name="site_name[]" class="site_name" value="'.$sites[$i][0].'" placeholder="'.$l->t('Name').'" />
+ <input type="text" class="site_url" name="site_url[]" value="'.$sites[$i][1].'" placeholder="'.$l->t('URL').'" />
+ <img class="svg action delete_button" src="'.image_path("", "actions/delete.svg") .'" title="'.$l->t("Remove site").'" />
+ </li>';
+ }
+ ?>
-<span class="msg"></span>
+ </ul>
+
+ <input type="button" id="add_external_site" value="Add" />
+ <span class="msg"></span>
</fieldset>
</form>
diff --git a/apps/files_archive/appinfo/app.php b/apps/files_archive/appinfo/app.php
new file mode 100644
index 00000000000..693c28d98a0
--- /dev/null
+++ b/apps/files_archive/appinfo/app.php
@@ -0,0 +1,18 @@
+<?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_Archive'] = 'apps/files_archive/lib/archive.php';
+foreach(array('ZIP') as $type){
+ OC::$CLASSPATH['OC_Archive_'.$type] = 'apps/files_archive/lib/'.strtolower($type).'.php';
+}
+
+OC::$CLASSPATH['OC_Filestorage_Archive']='apps/files_archive/lib/storage.php';
+
+OC_Hook::connect('OC_Filesystem','get_mountpoint','OC_Filestorage_Archive','autoMount');
+
+OC_Util::addScript( 'files_archive', 'archive' );
diff --git a/apps/files_archive/appinfo/info.xml b/apps/files_archive/appinfo/info.xml
new file mode 100644
index 00000000000..df767d39f6b
--- /dev/null
+++ b/apps/files_archive/appinfo/info.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<info>
+ <id>files_archive</id>
+ <name>Archive support</name>
+ <description>Transparent opening of archives</description>
+ <version>0.1</version>
+ <licence>AGPL</licence>
+ <author>Robin Appelman</author>
+ <require>3</require>
+</info>
diff --git a/apps/files_archive/js/archive.js b/apps/files_archive/js/archive.js
new file mode 100644
index 00000000000..ec316c7bf2c
--- /dev/null
+++ b/apps/files_archive/js/archive.js
@@ -0,0 +1,15 @@
+/**
+ * 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.
+ */
+
+$(document).ready(function() {
+ if(typeof FileActions!=='undefined'){
+ FileActions.register('application/zip','Open','',function(filename){
+ window.location='index.php?dir='+encodeURIComponent($('#dir').val()).replace(/%2F/g, '/')+'/'+encodeURIComponent(filename);
+ });
+ FileActions.setDefault('application/zip','Open');
+ }
+});
diff --git a/apps/files_archive/lib/archive.php b/apps/files_archive/lib/archive.php
new file mode 100644
index 00000000000..be89f894fb7
--- /dev/null
+++ b/apps/files_archive/lib/archive.php
@@ -0,0 +1,99 @@
+<?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.
+ */
+
+abstract class OC_Archive{
+ /**
+ * open any of the supporeted archive types
+ * @param string path
+ * @return OC_Archive
+ */
+ public static function open($path){
+ $ext=substr($path,strrpos($path,'.'));
+ switch($ext){
+ case '.zip':
+ return new OC_Archive_ZIP($path);
+ }
+ }
+
+ abstract function __construct($source);
+ /**
+ * add an empty folder to the archive
+ * @param string path
+ * @return bool
+ */
+ abstract function addFolder($path);
+ /**
+ * add a file to the archive
+ * @param string path
+ * @param string source either a local file or string data
+ * @return bool
+ */
+ abstract function addFile($path,$source='');
+ /**
+ * rename a file or folder in the archive
+ * @param string source
+ * @param string dest
+ * @return bool
+ */
+ abstract function rename($source,$dest);
+ /**
+ * get the uncompressed size of a file in the archive
+ * @param string path
+ * @return int
+ */
+ abstract function filesize($path);
+ /**
+ * get the last modified time of a file in the archive
+ * @param string path
+ * @return int
+ */
+ abstract function mtime($path);
+ /**
+ * get the files in a folder
+ * @param path
+ * @return array
+ */
+ abstract function getFolder($path);
+ /**
+ *get all files in the archive
+ * @return array
+ */
+ abstract function getFiles();
+ /**
+ * get the content of a file
+ * @param string path
+ * @return string
+ */
+ abstract function getFile($path);
+ /**
+ * extract a single file from the archive
+ * @param string path
+ * @param string dest
+ * @return bool
+ */
+ abstract function extractFile($path,$dest);
+ /**
+ * check if a file or folder exists in the archive
+ * @param string path
+ * @return bool
+ */
+ abstract function fileExists($path);
+ /**
+ * remove a file or folder from the archive
+ * @param string path
+ * @return bool
+ */
+ abstract function remove($path);
+ /**
+ * get a file handler
+ * @param string path
+ * @param string mode
+ * @return resource
+ */
+ abstract function getStream($path,$mode);
+}
diff --git a/apps/files_archive/lib/storage.php b/apps/files_archive/lib/storage.php
new file mode 100644
index 00000000000..72a96ca5a5d
--- /dev/null
+++ b/apps/files_archive/lib/storage.php
@@ -0,0 +1,142 @@
+<?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_Filestorage_Archive extends OC_Filestorage_Common{
+ /**
+ * underlying local storage used for missing functions
+ * @var OC_Archive
+ */
+ private $archive;
+ private $path;
+ private static $mounted=array();
+ private static $enableAutomount=true;
+ private static $rootView;
+
+ private function stripPath($path){//files should never start with /
+ if(substr($path,0,1)=='/'){
+ $path=substr($path,1);
+ }
+ return $path;
+ }
+
+ public function __construct($params){
+ $this->archive=OC_Archive::open($params['archive']);
+ $this->path=$params['archive'];
+ }
+
+ public function mkdir($path){
+ $path=$this->stripPath($path);
+ return $this->archive->addFolder($path);
+ }
+ public function rmdir($path){
+ $path=$this->stripPath($path);
+ return $this->archive->remove($path.'/');
+ }
+ public function opendir($path){
+ $path=$this->stripPath($path);
+ $content=$this->archive->getFolder($path);
+ foreach($content as &$file){
+ if(substr($file,-1)=='/'){
+ $file=substr($file,0,-1);
+ }
+ }
+ $id=md5($this->path.$path);
+ OC_FakeDirStream::$dirs[$id]=$content;
+ return opendir('fakedir://'.$id);
+ }
+ public function stat($path){
+ $ctime=filectime($this->path);
+ $path=$this->stripPath($path);
+ if($path==''){
+ $stat=stat($this->path);
+ }else{
+ if($this->is_dir($path)){
+ $stat=array('size'=>0);
+ $stat['mtime']=filemtime($this->path);
+ }else{
+ $stat=array();
+ $stat['mtime']=$this->archive->mtime($path);
+ $stat['size']=$this->archive->filesize($path);
+ }
+ }
+ $stat['ctime']=$ctime;
+ return $stat;
+ }
+ public function filetype($path){
+ $path=$this->stripPath($path);
+ if($path==''){
+ return 'dir';
+ }
+ if(substr($path,-1)=='/'){
+ return $this->archive->fileExists($path)?'dir':'file';
+ }else{
+ return $this->archive->fileExists($path.'/')?'dir':'file';
+ }
+ }
+ public function is_readable($path){
+ return is_readable($this->path);
+ }
+ public function is_writable($path){
+ return is_writable($this->path);
+ }
+ public function file_exists($path){
+ $path=$this->stripPath($path);
+ if($path==''){
+ return file_exists($this->path);
+ }
+ return $this->archive->fileExists($path) or $this->archive->fileExists($path.'/');
+ }
+ public function unlink($path){
+ $path=$this->stripPath($path);
+ return $this->archive->remove($path);
+ }
+ public function fopen($path,$mode){
+ $path=$this->stripPath($path);
+ return $this->archive->getStream($path,$mode);
+ }
+ public function free_space($path){
+ return 0;
+ }
+ public function touch($path, $mtime=null){
+ if(is_null($mtime)){
+ $tmpFile=OC_Helper::tmpFile();
+ $this->archive->extractFile($path,$tmpFile);
+ $this->archive->addfile($path,$tmpFile);
+ }else{
+ return false;//not supported
+ }
+ }
+
+ /**
+ * automount paths from file hooks
+ * @param aray params
+ */
+ public static function autoMount($params){
+ if(!self::$enableAutomount){
+ return;
+ }
+ $path=$params['path'];
+ if(!self::$rootView){
+ self::$rootView=new OC_FilesystemView('');
+ }
+ self::$enableAutomount=false;//prevent recursion
+ $supported=array('zip');
+ foreach($supported as $type){
+ $ext='.'.$type.'/';
+ if(($pos=strpos(strtolower($path),$ext))!==false){
+ $archive=substr($path,0,$pos+strlen($ext)-1);
+ if(self::$rootView->file_exists($archive) and array_search($archive,self::$mounted)===false){
+ $localArchive=self::$rootView->getLocalFile($archive);
+ OC_Filesystem::mount('OC_Filestorage_Archive',array('archive'=>$localArchive),$archive.'/');
+ self::$mounted[]=$archive;
+ }
+ }
+ }
+ self::$enableAutomount=true;
+ }
+}
diff --git a/apps/files_archive/lib/zip.php b/apps/files_archive/lib/zip.php
new file mode 100644
index 00000000000..eab101b3a5c
--- /dev/null
+++ b/apps/files_archive/lib/zip.php
@@ -0,0 +1,182 @@
+<?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_ZIP extends OC_Archive{
+ /**
+ * @var ZipArchive zip
+ */
+ private $zip=null;
+ private $contents=array();
+ private $success=false;
+ private $path;
+
+ function __construct($source){
+ $this->path=$source;
+ $this->zip=new ZipArchive();
+ if($this->zip->open($source,ZipArchive::CREATE)){
+ }else{
+ OC_LOG::write('files_archive','Error while opening archive '.$source,OC_Log::WARN);
+ }
+ }
+ /**
+ * add an empty folder to the archive
+ * @param string path
+ * @return bool
+ */
+ function addFolder($path){
+ return $this->zip->addEmptyDir($path);
+ }
+ /**
+ * 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(file_exists($source)){
+ $result=$this->zip->addFile($source,$path);
+ }else{
+ $result=$this->zip->addFromString($path,$source);
+ }
+ if($result){
+ $this->zip->close();//close and reopen to save the zip
+ $this->zip->open($this->path);
+ }
+ return $result;
+ }
+ /**
+ * rename a file or folder in the archive
+ * @param string source
+ * @param string dest
+ * @return bool
+ */
+ function rename($source,$dest){
+ return $this->zip->renameName($source,$dest);
+ }
+ /**
+ * get the uncompressed size of a file in the archive
+ * @param string path
+ * @return int
+ */
+ function filesize($path){
+ $stat=$this->zip->statName($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->zip->statName($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(){
+ 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;
+ }
+ /**
+ * get the content of a file
+ * @param string path
+ * @return string
+ */
+ function getFile($path){
+ return $this->zip->getFromName($path);
+ }
+ /**
+ * extract a single file from the archive
+ * @param string path
+ * @param string dest
+ * @return bool
+ */
+ function extractFile($path,$dest){
+ $fp = $this->zip->getStream($path);
+ file_put_contents($dest,$fp);
+ }
+ /**
+ * check if a file or folder exists in the archive
+ * @param string path
+ * @return bool
+ */
+ function fileExists($path){
+ return $this->zip->locateName($path)!==false;
+ }
+ /**
+ * remove a file or folder from the archive
+ * @param string path
+ * @return bool
+ */
+ function remove($path){
+ return $this->zip->deleteName($path);
+ }
+ /**
+ * get a file handler
+ * @param string path
+ * @param string mode
+ * @return resource
+ */
+ function getStream($path,$mode){
+ if($mode=='r' or $mode=='rb'){
+ return $this->zip->getStream($path);
+ }else{//since we cant directly get a writable stream, make a temp copy of the file and put it back in the archive when the stream is closed
+ if(strrpos($path,'.')!==false){
+ $ext=substr($path,strrpos($path,'.'));
+ }else{
+ $ext='';
+ }
+ $tmpFile=OC_Helper::tmpFile($ext);
+ OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this,'writeBack');
+ if($this->fileExists($path)){
+ $this->extractFile($path,$tmpFile);
+ }
+ 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);
+ }
+ }
+}
diff --git a/apps/files_archive/tests/archive.php b/apps/files_archive/tests/archive.php
new file mode 100644
index 00000000000..2e26b5e03b5
--- /dev/null
+++ b/apps/files_archive/tests/archive.php
@@ -0,0 +1,97 @@
+<?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.
+ */
+
+abstract class Test_Archive extends UnitTestCase {
+ /**
+ * @var OC_Archive
+ */
+ protected $instance;
+
+ /**
+ * get the existing test archive
+ * @return OC_Archive
+ */
+ abstract protected function getExisting();
+ /**
+ * get a new archive for write testing
+ * @return OC_Archive
+ */
+ abstract protected function getNew();
+
+ public function testGetFiles(){
+ $this->instance=$this->getExisting();
+ $allFiles=$this->instance->getFiles();
+ $expected=array('lorem.txt','logo-wide.png','dir/','dir/lorem.txt');
+ $this->assertEqual(4,count($allFiles));
+ foreach($expected as $file){
+ $this->assertNotIdentical(false,array_search($file,$allFiles),'cant find '.$file.' in archive');
+ $this->assertTrue($this->instance->fileExists($file));
+ }
+ $this->assertFalse($this->instance->fileExists('non/existing/file'));
+
+ $rootContent=$this->instance->getFolder('');
+ $expected=array('lorem.txt','logo-wide.png','dir/');
+ $this->assertEqual(3,count($rootContent));
+ foreach($expected as $file){
+ $this->assertNotIdentical(false,array_search($file,$rootContent),'cant find '.$file.' in archive');
+ }
+
+ $dirContent=$this->instance->getFolder('dir/');
+ $expected=array('lorem.txt');
+ $this->assertEqual(1,count($dirContent));
+ foreach($expected as $file){
+ $this->assertNotIdentical(false,array_search($file,$dirContent),'cant find '.$file.' in archive');
+ }
+ }
+
+ public function testContent(){
+ $this->instance=$this->getExisting();
+ $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
+ $textFile=$dir.'/lorem.txt';
+ $this->assertEqual(file_get_contents($textFile),$this->instance->getFile('lorem.txt'));
+
+ $tmpFile=OC_Helper::tmpFile('.txt');
+ $this->instance->extractFile('lorem.txt',$tmpFile);
+ $this->assertEqual(file_get_contents($textFile),file_get_contents($tmpFile));
+ }
+
+ public function testWrite(){
+ $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
+ $textFile=$dir.'/lorem.txt';
+ $this->instance=$this->getNew();
+ $this->assertEqual(0,count($this->instance->getFiles()));
+ $this->instance->addFile('lorem.txt',$textFile);
+ $this->assertEqual(1,count($this->instance->getFiles()));
+ $this->assertTrue($this->instance->fileExists('lorem.txt'));
+
+ $this->assertEqual(file_get_contents($textFile),$this->instance->getFile('lorem.txt'));
+ $this->instance->addFile('lorem.txt','foobar');
+ $this->assertEqual('foobar',$this->instance->getFile('lorem.txt'));
+ }
+
+ public function testReadStream(){
+ $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
+ $this->instance=$this->getExisting();
+ $fh=$this->instance->getStream('lorem.txt','r');
+ $this->assertTrue($fh);
+ $content=fread($fh,$this->instance->filesize('lorem.txt'));
+ fclose($fh);
+ $this->assertEqual(file_get_contents($dir.'/lorem.txt'),$content);
+ }
+ public function testWriteStream(){
+ $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
+ $this->instance=$this->getNew();
+ $fh=$this->instance->getStream('lorem.txt','w');
+ $source=fopen($dir.'/lorem.txt','r');
+ OC_Helper::streamCopy($source,$fh);
+ fclose($source);
+ fclose($fh);
+ $this->assertTrue($this->instance->fileExists('lorem.txt'));
+ $this->assertEqual(file_get_contents($dir.'/lorem.txt'),$this->instance->getFile('lorem.txt'));
+ }
+}
diff --git a/apps/files_archive/tests/storage.php b/apps/files_archive/tests/storage.php
new file mode 100644
index 00000000000..4d0a83356bd
--- /dev/null
+++ b/apps/files_archive/tests/storage.php
@@ -0,0 +1,25 @@
+<?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 Test_Filestorage_Archive_Zip extends Test_FileStorage {
+ /**
+ * @var string tmpDir
+ */
+ private $tmpFile;
+
+ public function setUp(){
+ $this->tmpFile=OC_Helper::tmpFile('.zip');
+ $this->instance=new OC_Filestorage_Archive(array('archive'=>$this->tmpFile));
+ }
+
+ public function tearDown(){
+ unlink($this->tmpFile);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/apps/files_archive/tests/zip.php b/apps/files_archive/tests/zip.php
new file mode 100644
index 00000000000..3ff713eda70
--- /dev/null
+++ b/apps/files_archive/tests/zip.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_ZIP extends Test_Archive{
+ protected function getExisting(){
+ $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data';
+ return new OC_Archive_ZIP($dir.'/data.zip');
+ }
+
+ protected function getNew(){
+ return new OC_Archive_ZIP(OC_Helper::tmpFile('.zip'));
+ }
+}
diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php
new file mode 100644
index 00000000000..68c445d5d77
--- /dev/null
+++ b/apps/files_encryption/appinfo/app.php
@@ -0,0 +1,19 @@
+<?php
+
+OC::$CLASSPATH['OC_Crypt'] = 'apps/files_encryption/lib/crypt.php';
+OC::$CLASSPATH['OC_CryptStream'] = 'apps/files_encryption/lib/cryptstream.php';
+OC::$CLASSPATH['OC_FileProxy_Encryption'] = 'apps/files_encryption/lib/proxy.php';
+
+OC_FileProxy::register(new OC_FileProxy_Encryption());
+
+OC_Hook::connect('OC_User','post_login','OC_Crypt','loginListener');
+
+stream_wrapper_register('crypt','OC_CryptStream');
+
+if(!isset($_SESSION['enckey']) and OC_User::isLoggedIn()){//force the user to re-loggin if the encryption key isn't unlocked (happens when a user is logged in before the encryption app is enabled)
+ OC_User::logout();
+ header("Location: ".OC::$WEBROOT.'/');
+ exit();
+}
+
+OC_App::registerAdmin('files_encryption', 'settings');
diff --git a/apps/files_encryption/appinfo/info.xml b/apps/files_encryption/appinfo/info.xml
new file mode 100644
index 00000000000..053044aaed2
--- /dev/null
+++ b/apps/files_encryption/appinfo/info.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<info>
+ <id>files_encryption</id>
+ <name>Encryption</name>
+ <description>Server side encryption of files</description>
+ <version>0.1</version>
+ <licence>AGPL</licence>
+ <author>Robin Appelman</author>
+ <require>3</require>
+</info>
diff --git a/apps/files_encryption/js/settings.js b/apps/files_encryption/js/settings.js
new file mode 100644
index 00000000000..adbf0c87245
--- /dev/null
+++ b/apps/files_encryption/js/settings.js
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2011, Robin Appelman <icewind1991@gmail.com>
+ * This file is licensed under the Affero General Public License version 3 or later.
+ * See the COPYING-README file.
+ */
+
+
+$(document).ready(function(){
+ $('#encryption_blacklist').multiSelect({
+ oncheck:blackListChange,
+ onuncheck:blackListChange,
+ createText:'...',
+ });
+
+ function blackListChange(){
+ var blackList=$('#encryption_blacklist').val().join(',');
+ OC.AppConfig.setValue('files_encryption','type_blacklist',blackList);
+ }
+}) \ No newline at end of file
diff --git a/lib/crypt.php b/apps/files_encryption/lib/crypt.php
index 60020679480..0a593b98c4b 100644
--- a/lib/crypt.php
+++ b/apps/files_encryption/lib/crypt.php
@@ -37,90 +37,111 @@ require_once('Crypt_Blowfish/Blowfish.php');
* This class is for crypting and decrypting
*/
class OC_Crypt {
+ static private $bf = null;
- static $encription_extension='.encrypted';
+ public static function loginListener($params){
+ self::init($params['uid'],$params['password']);
+ }
public static function init($login,$password) {
- $_SESSION['user_password'] = $password; // save the password as passcode for the encryption
- if(OC_User::isLoggedIn()){
- // does key exist?
- if(!file_exists(OC_Config::getValue( "datadirectory").'/'.$login.'/encryption.key')){
- OC_Crypt::createkey($_SESSION['user_password']);
- }
+ $view=new OC_FilesystemView('/'.$login);
+ OC_FileProxy::$enabled=false;
+ if(!$view->file_exists('/encryption.key')){// does key exist?
+ OC_Crypt::createkey($login,$password);
}
+ $key=$view->file_get_contents('/encryption.key');
+ OC_FileProxy::$enabled=true;
+ $_SESSION['enckey']=OC_Crypt::decrypt($key, $password);
}
+ /**
+ * get the blowfish encryption handeler for a key
+ * @param string $key (optional)
+ * @return Crypt_Blowfish
+ *
+ * if the key is left out, the default handeler will be used
+ */
+ public static function getBlowfish($key=''){
+ if($key){
+ return new Crypt_Blowfish($key);
+ }else{
+ if(!isset($_SESSION['enckey'])){
+ return false;
+ }
+ if(!self::$bf){
+ self::$bf=new Crypt_Blowfish($_SESSION['enckey']);
+ }
+ return self::$bf;
+ }
+ }
+ public static function createkey($username,$passcode) {
+ // generate a random key
+ $key=mt_rand(10000,99999).mt_rand(10000,99999).mt_rand(10000,99999).mt_rand(10000,99999);
- public static function createkey($passcode) {
- if(OC_User::isLoggedIn()){
- // generate a random key
- $key=mt_rand(10000,99999).mt_rand(10000,99999).mt_rand(10000,99999).mt_rand(10000,99999);
-
- // encrypt the key with the passcode of the user
- $enckey=OC_Crypt::encrypt($key,$passcode);
+ // encrypt the key with the passcode of the user
+ $enckey=OC_Crypt::encrypt($key,$passcode);
- // Write the file
- $username=OC_USER::getUser();
- @file_put_contents(OC_Config::getValue( "datadirectory").'/'.$username.'/encryption.key', $enckey );
- }
+ // Write the file
+ $proxyEnabled=OC_FileProxy::$enabled;
+ OC_FileProxy::$enabled=false;
+ $view=new OC_FilesystemView('/'.$username);
+ $view->file_put_contents('/encryption.key',$enckey);
+ OC_FileProxy::$enabled=$proxyEnabled;
}
- public static function changekeypasscode( $newpasscode) {
+ public static function changekeypasscode($oldPassword, $newPassword) {
if(OC_User::isLoggedIn()){
- $username=OC_USER::getUser();
+ $username=OC_USER::getUser();
+ $view=new OC_FilesystemView('/'.$username);
// read old key
- $key=file_get_contents(OC_Config::getValue( "datadirectory").'/'.$username.'/encryption.key');
+ $key=$view->file_get_contents('/encryption.key');
// decrypt key with old passcode
- $key=OC_Crypt::decrypt($key, $_SESSION['user_password']);
+ $key=OC_Crypt::decrypt($key, $oldPassword);
// encrypt again with new passcode
- $key=OC_Crypt::encrypt($key,$newpassword);
+ $key=OC_Crypt::encrypt($key, $newPassword);
// store the new key
- file_put_contents(OC_Config::getValue( "datadirectory").'/'.$username.'/encryption.key', $key );
-
- $_SESSION['user_password']=$newpasscode;
+ $view->file_put_contents('/encryption.key', $key );
}
}
/**
* @brief encrypts an content
* @param $content the cleartext message you want to encrypt
- * @param $key the encryption key
+ * @param $key the encryption key (optional)
* @returns encrypted content
*
* This function encrypts an content
*/
- public static function encrypt( $content, $key) {
- $bf = new Crypt_Blowfish($key);
+ public static function encrypt( $content, $key='') {
+ $bf = self::getBlowfish($key);
return($bf->encrypt($content));
}
+ /**
+ * @brief decryption of an content
+ * @param $content the cleartext message you want to decrypt
+ * @param $key the encryption key (optional)
+ * @returns cleartext content
+ *
+ * This function decrypts an content
+ */
+ public static function decrypt( $content, $key='') {
+ $bf = self::getBlowfish($key);
+ return($bf->decrypt($content));
+ }
- /**
- * @brief decryption of an content
- * @param $content the cleartext message you want to decrypt
- * @param $key the encryption key
- * @returns cleartext content
- *
- * This function decrypts an content
- */
- public static function decrypt( $content, $key) {
- $bf = new Crypt_Blowfish($key);
- return($bf->encrypt($contents));
- }
-
-
- /**
- * @brief encryption of a file
- * @param $filename
- * @param $key the encryption key
- *
- * This function encrypts a file
- */
+ /**
+ * @brief encryption of a file
+ * @param $filename
+ * @param $key the encryption key
+ *
+ * This function encrypts a file
+ */
public static function encryptfile( $filename, $key) {
$handleread = fopen($filename, "rb");
if($handleread<>FALSE) {
@@ -158,8 +179,28 @@ class OC_Crypt {
}
fclose($handleread);
}
-
-
-
-
+
+ /**
+ * encrypt data in 8192b sized blocks
+ */
+ public static function blockEncrypt($data){
+ $result='';
+ while(strlen($data)){
+ $result=self::encrypt(substr($data,0,8192));
+ $data=substr($data,8192);
+ }
+ return $result;
+ }
+
+ /**
+ * decrypt data in 8192b sized blocks
+ */
+ public static function blockDecrypt($data){
+ $result='';
+ while(strlen($data)){
+ $result=self::decrypt(substr($data,0,8192));
+ $data=substr($data,8192);
+ }
+ return $result;
+ }
}
diff --git a/apps/files_encryption/lib/cryptstream.php b/apps/files_encryption/lib/cryptstream.php
new file mode 100644
index 00000000000..86583096f1d
--- /dev/null
+++ b/apps/files_encryption/lib/cryptstream.php
@@ -0,0 +1,153 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Robin Appelman
+ * @copyright 2011 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/>.
+ *
+ */
+
+/**
+ * transparently encrypted filestream
+ *
+ * you can use it as wrapper around an existing stream by setting OC_CryptStream::$sourceStreams['foo']=array('path'=>$path,'stream'=>$stream)
+ * and then fopen('crypt://streams/foo');
+ */
+
+class OC_CryptStream{
+ public static $sourceStreams=array();
+ private $source;
+ private $path;
+ private $readBuffer;//for streams that dont support seeking
+ private $meta=array();//header/meta for source stream
+
+ public function stream_open($path, $mode, $options, &$opened_path){
+ $path=str_replace('crypt://','',$path);
+ if(dirname($path)=='streams' and isset(self::$sourceStreams[basename($path)])){
+ $this->source=self::$sourceStreams[basename($path)]['stream'];
+ $this->path=self::$sourceStreams[basename($path)]['path'];
+ }else{
+ $this->path=$path;
+ OC_Log::write('files_encryption','open encrypted '.$path. ' in '.$mode,OC_Log::DEBUG);
+ OC_FileProxy::$enabled=false;//disable fileproxies so we can open the source file
+ $this->source=OC_FileSystem::fopen($path,$mode);
+ OC_FileProxy::$enabled=true;
+ if(!is_resource($this->source)){
+ OC_Log::write('files_encryption','failed to open '.$path,OC_Log::ERROR);
+ }
+ }
+ if(is_resource($this->source)){
+ $this->meta=stream_get_meta_data($this->source);
+ }
+ return is_resource($this->source);
+ }
+
+ public function stream_seek($offset, $whence=SEEK_SET){
+ fseek($this->source,$offset,$whence);
+ }
+
+ public function stream_tell(){
+ return ftell($this->source);
+ }
+
+ public function stream_read($count){
+ $pos=0;
+ $currentPos=ftell($this->source);
+ $offset=$currentPos%8192;
+ $result='';
+ if($offset>0){
+ if($this->meta['seekable']){
+ fseek($this->source,-$offset,SEEK_CUR);//if seeking isnt supported the internal read buffer will be used
+ }else{
+ $pos=strlen($this->readBuffer);
+ $result=$this->readBuffer;
+ }
+ }
+ while($count>$pos){
+ $data=fread($this->source,8192);
+ $pos+=8192;
+ if(strlen($data)){
+ $result.=OC_Crypt::decrypt($data);
+ }
+ }
+ if(!$this->meta['seekable']){
+ $this->readBuffer=substr($result,$count);
+ }
+ return substr($result,0,$count);
+ }
+
+ public function stream_write($data){
+ $length=strlen($data);
+ $written=0;
+ $currentPos=ftell($this->source);
+ if($currentPos%8192!=0){
+ //make sure we always start on a block start
+ fseek($this->source,-($currentPos%8192),SEEK_CUR);
+ $encryptedBlock=fread($this->source,8192);
+ fseek($this->source,-($currentPos%8192),SEEK_CUR);
+ $block=OC_Crypt::decrypt($encryptedBlock);
+ $data=substr($block,0,$currentPos%8192).$data;
+ }
+ while(strlen($data)>0){
+ if(strlen($data)<8192){
+ //fetch the current data in that block and append it to the input so we always write entire blocks
+ $oldPos=ftell($this->source);
+ $encryptedBlock=fread($this->source,8192);
+ fseek($this->source,$oldPos);
+ $block=OC_Crypt::decrypt($encryptedBlock);
+ $data.=substr($block,strlen($data));
+ }
+ $encrypted=OC_Crypt::encrypt(substr($data,0,8192));
+ fwrite($this->source,$encrypted);
+ $data=substr($data,8192);
+ }
+ return $length;
+ }
+
+ public function stream_set_option($option,$arg1,$arg2){
+ switch($option){
+ case STREAM_OPTION_BLOCKING:
+ stream_set_blocking($this->source,$arg1);
+ break;
+ case STREAM_OPTION_READ_TIMEOUT:
+ stream_set_timeout($this->source,$arg1,$arg2);
+ break;
+ case STREAM_OPTION_WRITE_BUFFER:
+ stream_set_write_buffer($this->source,$arg1,$arg2);
+ }
+ }
+
+ public function stream_stat(){
+ return fstat($this->source);
+ }
+
+ public function stream_lock($mode){
+ flock($this->source,$mode);
+ }
+
+ public function stream_flush(){
+ return fflush($this->source);
+ }
+
+ public function stream_eof(){
+ return feof($this->source);
+ }
+
+ public function stream_close(){
+ OC_FileCache::put($this->path,array('encrypted'=>true));
+ return fclose($this->source);
+ }
+} \ No newline at end of file
diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php
new file mode 100644
index 00000000000..c1c26d7754f
--- /dev/null
+++ b/apps/files_encryption/lib/proxy.php
@@ -0,0 +1,115 @@
+<?php
+
+/**
+* ownCloud
+*
+* @author Robin Appelman
+* @copyright 2011 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/>.
+*
+*/
+
+/**
+ * transparent encryption
+ */
+
+class OC_FileProxy_Encryption extends OC_FileProxy{
+ private static $blackList=null; //mimetypes blacklisted from encryption
+ private static $metaData=array(); //metadata cache
+
+ /**
+ * check if a file should be encrypted during write
+ * @param string $path
+ * @return bool
+ */
+ private static function shouldEncrypt($path){
+ if(is_null(self::$blackList)){
+ self::$blackList=explode(',',OC_Appconfig::getValue('files_encryption','type_blacklist','jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg'));
+ }
+ if(self::isEncrypted($path)){
+ return true;
+ }
+ $extention=substr($path,strrpos($path,'.')+1);
+ if(array_search($extention,self::$blackList)===false){
+ return true;
+ }
+ }
+
+ /**
+ * check if a file is encrypted
+ * @param string $path
+ * @return bool
+ */
+ private static function isEncrypted($path){
+ if(isset(self::$metaData[$path])){
+ $metadata=self::$metaData[$path];
+ }else{
+ $metadata=OC_FileCache::getCached($path);
+ self::$metaData[$path]=$metadata;
+ }
+ return (bool)$metadata['encrypted'];
+ }
+
+ public function preFile_put_contents($path,&$data){
+ if(self::shouldEncrypt($path)){
+ if (!is_resource($data)) {//stream put contents should have been converter to fopen
+ $data=OC_Crypt::blockEncrypt($data);
+ OC_FileCache::put($path,array('encrypted'=>true));
+ }
+ }
+ }
+
+ public function postFile_get_contents($path,$data){
+ if(self::isEncrypted($path)){
+ $data=OC_Crypt::blockDecrypt($data);
+ }
+ return $data;
+ }
+
+ public function postFopen($path,&$result){
+ if(!$result){
+ return $result;
+ }
+ $meta=stream_get_meta_data($result);
+ if(self::isEncrypted($path)){
+ fclose($result);
+ $result=fopen('crypt://'.$path,$meta['mode']);
+ }elseif(self::shouldEncrypt($path) and $meta['mode']!='r' and $meta['mode']!='rb'){
+ if(OC_Filesystem::file_exists($path) and OC_Filesystem::filesize($path)>0){
+ //first encrypt the target file so we don't end up with a half encrypted file
+ OC_Log::write('files_encryption','Decrypting '.$path.' before writing',OC_Log::DEBUG);
+ $tmp=fopen('php://temp');
+ while(!feof($result)){
+ $chunk=fread($result,8192);
+ if($chunk){
+ fwrite($tmp,$chunk);
+ }
+ }
+ fclose($result);
+ OC_Filesystem::file_put_contents($path,$tmp);
+ fclose($tmp);
+ }
+ $result=fopen('crypt://'.$path,$meta['mode']);
+ }
+ return $result;
+ }
+
+ public function postGetMimeType($path,$mime){
+ if(self::isEncrypted($path)){
+ $mime=OC_Helper::getMimeType('crypt://'.$path,'w');
+ }
+ return $mime;
+ }
+}
diff --git a/apps/files_encryption/settings.php b/apps/files_encryption/settings.php
new file mode 100644
index 00000000000..396ad1ba78d
--- /dev/null
+++ b/apps/files_encryption/settings.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Copyright (c) 2011 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+$tmpl = new OC_Template( 'files_encryption', 'settings');
+$blackList=explode(',',OC_Appconfig::getValue('files_encryption','type_blacklist','jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg'));
+$tmpl->assign('blacklist',$blackList);
+
+OC_Util::addScript('files_encryption','settings');
+OC_Util::addScript('core','multiselect');
+
+return $tmpl->fetchPage();
diff --git a/apps/files_encryption/templates/settings.php b/apps/files_encryption/templates/settings.php
new file mode 100644
index 00000000000..724a03836a8
--- /dev/null
+++ b/apps/files_encryption/templates/settings.php
@@ -0,0 +1,11 @@
+<form id="calendar">
+ <fieldset class="personalblock">
+ <strong><?php echo $l->t('Encryption'); ?></strong>
+ <?php echo $l->t("Exclude the following file types from encryption"); ?>
+ <select id='encryption_blacklist' title="<?php echo $l->t('None')?>" multiple="multiple">
+ <?php foreach($_["blacklist"] as $type): ?>
+ <option selected="selected" value="<?php echo $type;?>"><?php echo $type;?></option>
+ <?php endforeach;?>
+ </select>
+ </fieldset>
+</form>
diff --git a/apps/files_sharing/sharedstorage.php b/apps/files_sharing/sharedstorage.php
index cb641e68a84..845659588ef 100644
--- a/apps/files_sharing/sharedstorage.php
+++ b/apps/files_sharing/sharedstorage.php
@@ -58,7 +58,7 @@ class OC_Filestorage_Shared extends OC_Filestorage {
}
public function mkdir($path) {
- if ($path == "" || $path == "/" || !$this->is_writeable($path)) {
+ if ($path == "" || $path == "/" || !$this->is_writable($path)) {
return false;
} else {
$source = $this->getSource($path);
@@ -79,7 +79,6 @@ class OC_Filestorage_Shared extends OC_Filestorage {
if ($path == "" || $path == "/") {
$path = $this->datadir.$path;
$sharedItems = OC_Share::getItemsInFolder($path);
- global $FAKEDIRS;
$files = array();
foreach ($sharedItems as $item) {
// If item is in the root of the shared storage provider and the item exists add it to the fakedirs
@@ -87,7 +86,7 @@ class OC_Filestorage_Shared extends OC_Filestorage {
$files[] = basename($item['target']);
}
}
- $FAKEDIRS['shared'] = $files;
+ OC_FakeDirStream::$dirs['shared']=$files;
return opendir('fakedir://shared');
} else {
$source = $this->getSource($path);
@@ -281,14 +280,6 @@ class OC_Filestorage_Shared extends OC_Filestorage {
}
}
- public function readfile($path) {
- $source = $this->getSource($path);
- if ($source) {
- $storage = OC_Filesystem::getStorage($source);
- return $storage->readfile($this->getInternalPath($source));
- }
- }
-
public function filectime($path) {
if ($path == "" || $path == "/") {
$ctime = 0;
@@ -514,7 +505,13 @@ class OC_Filestorage_Shared extends OC_Filestorage {
return $storage->getLocalFile($this->getInternalPath($source));
}
}
-
+ public function touch($path, $mtime=null){
+ $source = $this->getSource($path);
+ if ($source) {
+ $storage = OC_Filesystem::getStorage($source);
+ return $storage->touch($this->getInternalPath($source),$time);
+ }
+ }
}
?>
diff --git a/apps/files_texteditor/ajax/savefile.php b/apps/files_texteditor/ajax/savefile.php
index 589428d1862..57a948478f5 100644
--- a/apps/files_texteditor/ajax/savefile.php
+++ b/apps/files_texteditor/ajax/savefile.php
@@ -28,7 +28,7 @@ require_once('../../../lib/base.php');
OC_JSON::checkLoggedIn();
// Get paramteres
-$filecontents = htmlspecialchars_decode($_POST['filecontents']);
+$filecontents = $_POST['filecontents'];
$path = isset($_POST['path']) ? $_POST['path'] : '';
$mtime = isset($_POST['mtime']) ? $_POST['mtime'] : '';
diff --git a/apps/files_texteditor/js/editor.js b/apps/files_texteditor/js/editor.js
index e45652b6ef3..02d39b98430 100644
--- a/apps/files_texteditor/js/editor.js
+++ b/apps/files_texteditor/js/editor.js
@@ -11,37 +11,43 @@ function getFileExtension(file){
function setSyntaxMode(ext){
// Loads the syntax mode files and tells the editor
var filetype = new Array();
- // Todo finish these
- filetype["h"] = "c_cpp";
- filetype["c"] = "c_cpp";
- filetype["clj"] = "clojure";
- filetype["coffee"] = "coffee"; // coffescript can be compiled to javascript
- filetype["coldfusion"] = "cfc";
- filetype["cpp"] = "c_cpp";
- filetype["cs"] = "csharp";
+ // add file extensions like this: filetype["extension"] = "filetype":
+ filetype["h"] = "c_cpp";
+ filetype["c"] = "c_cpp";
+ filetype["clj"] = "clojure";
+ filetype["coffee"] = "coffee"; // coffescript can be compiled to javascript
+ filetype["coldfusion"] = "cfc";
+ filetype["cpp"] = "c_cpp";
+ filetype["cs"] = "csharp";
filetype["css"] = "css";
- filetype["groovy"] = "groovy";
- filetype["haxe"] = "hx";
+ filetype["groovy"] = "groovy";
+ filetype["haxe"] = "hx";
filetype["html"] = "html";
- filetype["java"] = "java";
+ filetype["java"] = "java";
filetype["js"] = "javascript";
- filetype["json"] = "json";
- filetype["latex"] = "latex";
- filetype["lua"] = "lua";
- filetype["markdown"] = "markdown"; // also: .md .markdown .mdown .mdwn
- filetype["ml"] = "ocaml";
- filetype["mli"] = "ocaml";
+ filetype["json"] = "json";
+ filetype["latex"] = "latex";
+ filetype["ly"] = "latex";
+ filetype["ily"] = "latex";
+ filetype["lua"] = "lua";
+ filetype["markdown"] = "markdown";
+ filetype["md"] = "markdown";
+ filetype["mdown"] = "markdown";
+ filetype["mdwn"] = "markdown";
+ filetype["mkd"] = "markdown";
+ filetype["ml"] = "ocaml";
+ filetype["mli"] = "ocaml";
filetype["pl"] = "perl";
filetype["php"] = "php";
filetype["powershell"] = "ps1";
filetype["py"] = "python";
filetype["rb"] = "ruby";
- filetype["scad"] = "scad"; // seems to be something like 3d model files printed with e.g. reprap
- filetype["scala"] = "scala";
- filetype["scss"] = "scss"; // "sassy css"
- filetype["sql"] = "sql";
- filetype["svg"] = "svg";
- filetype["textile"] = "textile"; // related to markdown
+ filetype["scad"] = "scad"; // seems to be something like 3d model files printed with e.g. reprap
+ filetype["scala"] = "scala";
+ filetype["scss"] = "scss"; // "sassy css"
+ filetype["sql"] = "sql";
+ filetype["svg"] = "svg";
+ filetype["textile"] = "textile"; // related to markdown
filetype["xml"] = "xml";
if(filetype[ext]!=null){
@@ -142,7 +148,7 @@ function doFileSave(){
// Show saving spinner
$("#editor_save").die('click',doFileSave);
$('#save_result').remove();
- $('#editor_save').text(t('files_texteditor','Saving...'));//after('<img id="saving_icon" src="'+OC.filePath('core','img','loading.gif')+'"></img>');
+ $('#editor_save').text(t('files_texteditor','Saving...'));
// Get the data
var filecontents = window.aceEditor.getSession().getValue();
// Send the data
@@ -192,6 +198,7 @@ function showFileEditor(dir,filename){
$('#editor').attr('data-filename', filename);
window.aceEditor = ace.edit("editor");
aceEditor.setShowPrintMargin(false);
+ aceEditor.getSession().setUseWrapMode(true);
if(result.data.write=='false'){
aceEditor.setReadOnly(true);
}
diff --git a/apps/gallery/ajax/galleryOp.php b/apps/gallery/ajax/galleryOp.php
index 5ac6d295108..459c30f6ac6 100644
--- a/apps/gallery/ajax/galleryOp.php
+++ b/apps/gallery/ajax/galleryOp.php
@@ -21,6 +21,7 @@
*
*/
+header('Content-type: text/html; charset=UTF-8') ;
require_once('../../../lib/base.php');
OC_JSON::checkLoggedIn();
@@ -41,34 +42,28 @@ function handleRemove($name) {
function handleGetThumbnails($albumname) {
OC_Response::enableCaching(3600 * 24); // 24 hour
- $thumbnail = OC::$CONFIG_DATADIRECTORY.'/../gallery/'.$albumname.'.png';
+ $thumbnail = OC::$CONFIG_DATADIRECTORY.'/../gallery/'.urldecode($albumname).'.png';
header('Content-Type: '.OC_Image::getMimeTypeForFile($thumbnail));
OC_Response::sendFile($thumbnail);
}
function handleGalleryScanning() {
- OC_Gallery_Scanner::cleanup();
- OC_JSON::success(array('albums' => OC_Gallery_Scanner::scan('/')));
+ OC_DB::beginTransaction();
+ set_time_limit(0);
+ OC_Gallery_Album::cleanup();
+ $eventSource = new OC_EventSource();
+ OC_Gallery_Scanner::scan($eventSource);
+ $eventSource->close();
+ OC_DB::commit();
}
function handleFilescan($cleanup) {
if ($cleanup) OC_Gallery_Album::cleanup();
- $root = OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'root', '').'/';
- $pathlist = OC_Gallery_Scanner::find_paths($root);
+ $pathlist = OC_Gallery_Scanner::find_paths();
sort($pathlist);
OC_JSON::success(array('paths' => $pathlist));
}
-function handlePartialCreate($path) {
- if (empty($path)) OC_JSON::error(array('cause' => 'No path specified'));
- if (!OC_Filesystem::is_dir($path)) OC_JSON::error(array('cause' => 'Invalid path given'));
-
- $album = OC_Gallery_Album::find(OC_User::getUser(), null, $path);
- $albums = array();
- OC_Gallery_Scanner::scanDir($path, $albums);
- OC_JSON::success(array('album_details' => $albums));
-}
-
function handleStoreSettings($root, $order) {
if (!OC_Filesystem::file_exists($root)) {
OC_JSON::error(array('cause' => 'No such file or directory'));
@@ -80,13 +75,45 @@ function handleStoreSettings($root, $order) {
}
$current_root = OC_Preferences::getValue(OC_User::getUser(),'gallery', 'root', '/');
- $root = trim(rtrim($root, '/'));
+ $root = trim($root);
+ $root = rtrim($root, '/').'/';
$rescan = $current_root==$root?'no':'yes';
OC_Preferences::setValue(OC_User::getUser(), 'gallery', 'root', $root);
OC_Preferences::setValue(OC_User::getUser(), 'gallery', 'order', $order);
OC_JSON::success(array('rescan' => $rescan));
}
+function handleGetGallery($path) {
+ $a = array();
+ $root = OC_Preferences::getValue(OC_User::getUser(),'gallery', 'root', '/');
+ $path = utf8_decode(rtrim($root.$path,'/'));
+ if($path == '') $path = '/';
+ $pathLen = strlen($path);
+ $result = OC_Gallery_Album::find(OC_User::getUser(), null, $path);
+ $album_details = $result->fetchRow();
+
+ $result = OC_Gallery_Album::find(OC_User::getUser(), null, null, $path);
+
+ while ($r = $result->fetchRow()) {
+ $album_name = $r['album_name'];
+ $size=OC_Gallery_Album::getAlbumSize($r['album_id']);
+ // this is a fallback mechanism and seems expensive
+ if ($size == 0) $size = OC_Gallery_Album::getIntermediateGallerySize($r['album_path']);
+
+ $a[] = array('name' => utf8_encode($album_name), 'numOfItems' => min($size, 10),'path'=>substr($r['album_path'], $pathLen));
+ }
+
+ $result = OC_Gallery_Photo::find($album_details['album_id']);
+
+ $p = array();
+
+ while ($r = $result->fetchRow()) {
+ $p[] = utf8_encode($r['file_path']);
+ }
+
+ OC_JSON::success(array('albums'=>$a, 'photos'=>$p));
+}
+
if ($_GET['operation']) {
switch($_GET['operation']) {
case 'rename':
@@ -103,15 +130,12 @@ if ($_GET['operation']) {
case 'scan':
handleGalleryScanning();
break;
- case 'filescan':
- handleFilescan($_GET['cleanup']);
- break;
- case 'partial_create':
- handlePartialCreate(urldecode($_GET['path']));
- break;
case 'store_settings':
handleStoreSettings($_GET['root'], $_GET['order']);
break;
+ case 'get_gallery':
+ handleGetGallery($_GET['path']);
+ break;
default:
OC_JSON::error(array('cause' => 'Unknown operation'));
}
diff --git a/apps/gallery/ajax/getAlbums.php b/apps/gallery/ajax/getAlbums.php
deleted file mode 100644
index 9e9c6ef496c..00000000000
--- a/apps/gallery/ajax/getAlbums.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-/**
-* ownCloud - gallery application
-*
-* @author Bartek Przybylski
-* @copyright 2012 Bartek Przybylski bart.p.pl@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 Lesser General Public
-* License along with this library. If not, see <http://www.gnu.org/licenses/>.
-*
-*/
-
-require_once('../../../lib/base.php');
-OC_JSON::checkLoggedIn();
-OC_JSON::checkAppEnabled('gallery');
-
-$a = array();
-
-$result = OC_Gallery_Album::find(OC_User::getUser());
-
-while ($r = $result->fetchRow()) {
- $album_name = $r['album_name'];
- $tmp_res = OC_Gallery_Photo::find($r['album_id']);
-
- $a[] = array('name' => $album_name, 'numOfItems' => min($tmp_res->numRows(), 10), 'bgPath' => OC::$WEBROOT.'/data/'.OC_User::getUser().'/gallery/'.$album_name.'.png');
-}
-
-OC_JSON::success(array('albums'=>$a));
-
-?>
diff --git a/apps/gallery/appinfo/app.php b/apps/gallery/appinfo/app.php
index b8de32ea587..1e5e27d408f 100644
--- a/apps/gallery/appinfo/app.php
+++ b/apps/gallery/appinfo/app.php
@@ -40,8 +40,8 @@ OC_App::addNavigationEntry( array(
'icon' => OC_Helper::imagePath('core', 'places/picture.svg'),
'name' => $l->t('Gallery')));
- class OC_GallerySearchProvider extends OC_Search_Provider{
- function search($query){
+ class OC_GallerySearchProvider implements OC_Search_Provider{
+ static function search($query){
$stmt = OC_DB::prepare('SELECT * FROM *PREFIX*gallery_albums WHERE uid_owner = ? AND album_name LIKE ?');
$result = $stmt->execute(array(OC_User::getUser(),'%'.$query.'%'));
$results=array();
@@ -52,7 +52,7 @@ OC_App::addNavigationEntry( array(
}
}
-new OC_GallerySearchProvider();
+OC_Search::registerProvider('OC_GallerySearchProvider');
require_once('apps/gallery/lib/hooks_handlers.php');
?>
diff --git a/apps/gallery/appinfo/database.xml b/apps/gallery/appinfo/database.xml
index db88e4c1b5a..62fdbee9cd8 100644
--- a/apps/gallery/appinfo/database.xml
+++ b/apps/gallery/appinfo/database.xml
@@ -11,9 +11,9 @@
<name>album_id</name>
<type>integer</type>
<default>0</default>
- <notnull>true</notnull>
- <autoincrement>1</autoincrement>
- <length>4</length>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <length>4</length>
</field>
<field>
<name>uid_owner</name>
@@ -27,12 +27,18 @@
<notnull>true</notnull>
<length>100</length>
</field>
- <field>
- <name>album_path</name>
- <type>text</type>
- <notnull>true</notnull>
- <length>100</length>
- </field>
+ <field>
+ <name>album_path</name>
+ <type>text</type>
+ <notnull>true</notnull>
+ <length>100</length>
+ </field>
+ <field>
+ <name>parent_path</name>
+ <type>text</type>
+ <notnull>true</notnull>
+ <length>100</length>
+ </field>
</declaration>
</table>
<table>
@@ -42,16 +48,16 @@
<name>photo_id</name>
<type>integer</type>
<default>0</default>
- <notnull>true</notnull>
- <autoincrement>1</autoincrement>
- <length>4</length>
+ <notnull>true</notnull>
+ <autoincrement>1</autoincrement>
+ <length>4</length>
</field>
<field>
<name>album_id</name>
<type>integer</type>
<default>0</default>
- <notnull>true</notnull>
- <length>4</length>
+ <notnull>true</notnull>
+ <length>4</length>
</field>
<field>
<name>file_path</name>
diff --git a/apps/gallery/appinfo/info.xml b/apps/gallery/appinfo/info.xml
index 9aecb0c781d..19c5dc8b25e 100644
--- a/apps/gallery/appinfo/info.xml
+++ b/apps/gallery/appinfo/info.xml
@@ -2,7 +2,7 @@
<info>
<id>gallery</id>
<name>Gallery</name>
- <version>0.3</version>
+ <version>0.4</version>
<licence>AGPL</licence>
<author>Bartek Przybylski</author>
<require>2</require>
diff --git a/apps/gallery/css/styles.css b/apps/gallery/css/styles.css
index da94f9ac9e5..013cd1b262d 100644
--- a/apps/gallery/css/styles.css
+++ b/apps/gallery/css/styles.css
@@ -1,13 +1,14 @@
div#gallery_list { margin: 4.5em 2em 0 2em; }
div#gallery_list.leftcontent { padding-top: 15pt; margin: 0; position: absolute; bottom:0px; text-align: center; overflow: auto; }
-div.gallery_album_box { width: 200px; position:relative; text-align: center; border: 0; display: inline-block; margin: 5pt; vertical-align: top; padding: 5px 5px 5px 5px; position: relative; -webkit-transition: color 0.5s ease-in-out; -o-transition: color 0.5s ease-in-out; -moz-transition: color 0.5s ease-in-out;color: #BBB;}
-div.gallery_album_box h1 { font-size: 9pt; font-family: Verdana; }
-div.gallery_album_decoration { width: 200px; position: absolute; border: 0; height: 20px; top: 5px; text-align:right; vertical-align:middle; background-color: #eee; opacity: 0; -webkit-transition: opacity 0.5s ease-in-out; -moz-transition: opacity 0.5s ease-in-out; -o-transition: opacity 0.5s ease-in-out; border-bottom-right-radius: 7px; border-bottom-left-radius: 7px; -moz-border-radius-bottomright: 7px; -moz-border-radius-bottomleft:7px;}
-div.gallery_album_box:hover { color: black; }
-div.gallery_album_box:hover div.gallery_album_decoration { opacity: 0.7;}
+div.gallery_box { width: 200px; position:relative; text-align: center; border: 0; display: inline-block; margin: 5pt; vertical-align: top; padding: 5px 5px 5px 5px; position: relative; -webkit-transition: color 0.5s ease-in-out; -o-transition: color 0.5s ease-in-out; -moz-transition: color 0.5s ease-in-out;color: #BBB;}
+div.album {border: 1px solid #e0e0e0; border-radius: 7px;}
+div.gallery_box h1 { font-size: 9pt; font-family: Verdana; }
+div.gallery_album_decoration { width: 200px; position: absolute; border: 0; height: 20px; top: 5px; text-align:right; vertical-align:middle; background-color: #eee; opacity: 0; -webkit-transition: opacity 0.5s ease-in-out; -moz-transition: opacity 0.5s ease-in-out; -o-transition: opacity 0.5s ease-in-out; }
+div.gallery_box:hover { color: black; }
+div.gallery_box:hover div.gallery_album_decoration { opacity: 0.7;}
div.gallery_album_decoration a {padding: 0 4pt; cursor: pointer;}
div.gallery_album_cover { width: 200px; height: 200px; border: 0; padding: 0; position:relative;}
-div.gallery_album_box:hover div.gallery_control_overlay { opacity:0.5 }
+div.gallery_box:hover div.gallery_control_overlay { opacity:0.5 }
div.gallery_control_overlay a { color:white; }
#gallery_images.rightcontent { padding:10px 5px; bottom: 0px; overflow: auto; right:0px}
#scan { position:absolute; right:13.5em; top:0em; }
diff --git a/apps/gallery/img/loading.gif b/apps/gallery/img/loading.gif
new file mode 100644
index 00000000000..5b33f7e54f4
--- /dev/null
+++ b/apps/gallery/img/loading.gif
Binary files differ
diff --git a/apps/gallery/js/album_cover.js b/apps/gallery/js/album_cover.js
index 4ddac2f2111..8cafce35f98 100644
--- a/apps/gallery/js/album_cover.js
+++ b/apps/gallery/js/album_cover.js
@@ -1,190 +1,109 @@
var actual_cover;
-$(document).ready(function() {
- $.getJSON('ajax/getAlbums.php', function(r) {
- if (r.status == 'success') {
- for (var i in r.albums) {
- var a = r.albums[i];
- Albums.add(a.name, a.numOfItems);
- }
- var targetDiv = document.getElementById('gallery_list');
- if (targetDiv) {
- $(targetDiv).html('');
- Albums.display(targetDiv);
- $('#gallery_list').sortable({revert:true});
- $('.gallery_album_box').each(function(i, e) {
- $(e).draggable({connectToSortable: '#gallery_list', handle: '.dummy'})
- });
- } else {
- alert('Error occured: no such layer `gallery_list`');
- }
- } else {
- alert('Error occured: ' + r.message);
- }
- });
-});
+var paths = [];
+var crumbCount = 0;
+$(document).ready(returnToElement(0));
-function createNewAlbum() {
- var name = prompt("album name", "");
- if (name != null && name != "") {
- $.getJSON("ajax/createAlbum.php", {album_name: name}, function(r) {
- if (r.status == "success") {
- var v = '<div class="gallery_album_box"><a href="?view='+r.name+'"><img class="gallery_album_cover"/></a><h1>'+r.name+'</h1></div>';
- $('div#gallery_list').append(v);
- }
- });
- }
+function returnToElement(num) {
+ while (crumbCount != num) {
+ $('#g-album-navigation .last').remove();
+ $('#g-album-navigation .crumb :last').parent().addClass('last');
+ crumbCount--;
+ paths.pop();
+ }
+ var p='';
+ for (var i in paths) p += paths[i]+'/';
+ $('#g-album-loading').show();
+ $.getJSON(OC.filePath('gallery','ajax','galleryOp.php'), {operation: 'get_gallery', path: p }, albumClickHandler);
}
-var albumCounter = 0;
-var totalAlbums = 0;
-
-function scanForAlbums(cleanup) {
- cleanup = cleanup?true:false;
- var albumCounter = 0;
- var totalAlbums = 0;
- $('#g-scan-button').attr('disabled', 'true');
- $.getJSON('ajax/galleryOp.php?operation=filescan', {cleanup: cleanup}, function(r) {
-
- if (r.status == 'success') {
- totalAlbums = r.paths.length;
- if (totalAlbums == 0) {
- $('#notification').text(t('gallery', "No photos found")).fadeIn().slideDown().delay(3000).fadeOut().slideUp();
- return;
- }
- $('#scanprogressbar').progressbar({ value: (albumCounter/totalAlbums)*100 }).fadeIn();
- for(var a in r.paths) {
- $.getJSON('ajax/galleryOp.php?operation=partial_create&path='+r.paths[a], function(r) {
-
- if (r.status == 'success') {
- Albums.add(r.album_details.albumName, r.album_details.imagesCount);
- }
-
- albumCounter++;
- $('#scanprogressbar').progressbar({ value: (albumCounter/totalAlbums)*100 });
- if (albumCounter == totalAlbums) {
- $('#scanprogressbar').fadeOut();
- var targetDiv = document.getElementById('gallery_list');
- if (targetDiv) {
- targetDiv.innerHTML = '';
- Albums.display(targetDiv);
- } else {
- alert('Error occured: no such layer `gallery_list`');
- }
- $('#g-scan-button').attr('disabled', null);
- }
- });
- }
- } else {
- alert('Error occured: ' + r.message);
- }
- });
+function albumClick(title) {
+ paths.push(title);
+ crumbCount++;
+ var p = '';
+ for (var i in paths) p += paths[i]+'/';
+ $('#g-album-loading').show();
+ $.getJSON(OC.filePath('gallery','ajax','galleryOp.php'), {operation: 'get_gallery', path: p }, function(r) {
+ albumClickHandler(r);
+ if ($('#g-album-navigation :last-child'))
+ $('#g-album-navigation :last-child').removeClass('last');
+ $('#g-album-navigation').append('<div class="crumb last real" style="background-image:url(\''+OC.imagePath('core','breadcrumb')+'\')"><a href=\"javascript:returnToElement('+crumbCount+');\">'+decodeURIComponent(escape(title))+'</a></div>');
+ });
}
-function galleryRemove(albumName) {
- // a workaround for a flaw in the demo system (http://dev.jqueryui.com/ticket/4375), ignore!
- $( "#dialog:ui-dialog" ).dialog( "destroy" );
- $('#albumName', $("#dialog-confirm")).text(albumName);
-
- $( '#dialog-confirm' ).dialog({
- resizable: false,
- height:150,
- buttons: [{
- text: t('gallery', 'OK'),
- click: function() {
- $.getJSON("ajax/galleryOp.php", {operation: "remove", name: albumName}, function(r) {
- if (r.status == "success") {
- $(".gallery_album_box").filterAttr('data-album',albumName).remove();
- Albums.remove(albumName);
- } else {
- alert("Error: " + r.cause);
- }
- $('#dialog-confirm').dialog('close');
- });
- }},
- {
- text: t('gallery', 'Cancel'),
- click: function() {
- $( this ).dialog( 'close' );
- }}]
- });
+function albumClickHandler(r) {
+ Albums.photos = [];
+ Albums.albums = [];
+ if (r.status == 'success') {
+ for (var i in r.albums) {
+ var a = r.albums[i];
+ Albums.add(a.name, a.numOfItems,a.path);
+ }
+ for (var i in r.photos) {
+ Albums.photos.push(r.photos[i]);
+ }
+ var targetDiv = document.getElementById('gallery_list');
+ if (targetDiv) {
+ $(targetDiv).html('');
+ Albums.display(targetDiv);
+ //$('#gallery_list').sortable({revert:true});
+ $('.album').each(function(i, el) {
+ $(el).click(albumClick.bind(null,$(el).attr('title')));
+ //$(el).draggable({connectToSortable: '#gallery_list', handle: '.dummy'});
+ });
+ } else {
+ OC.dialogs.alert(t('gallery', 'Error: no such layer `gallery_list`'), t('gallery', 'Internal error'));
+ }
+ } else {
+ OC.dialogs.alert(t('gallery', 'Error: ') + r.message, t('gallery', 'Internal error'));
+ }
+ $('#g-album-loading').hide();
}
-function galleryRename(name) {
- $('#name', $('#dialog-form')).val(name);
- $( "#dialog-form" ).dialog({
- height: 140,
- width: 350,
- modal: false,
- buttons: [{
- text: t('gallery', 'Change name'),
- click: function() {
- var newname = $('#name', $('#dialog-form')).val();
- if (newname == name || newname == '') {
- $(this).dialog("close");
- return;
- }
- if (Albums.find(newname)) {
- alert("Album ", newname, " exists");
- $(this).dialog("close");
- return;
- }
- $.getJSON('ajax/galleryOp.php', {operation: 'rename', oldname: name, newname: newname}, function(r) {
- if (r.status == "success") {
- Albums.rename($(".gallery_album_box").filterAttr('data-album',name), newname);
- } else {
- alert("Error: " + r.cause);
- }
- $('#dialog-form').dialog('close');
- });
+var albumCounter = 0;
+var totalAlbums = 0;
- }
- },
- {
- text: t('gallery', 'Cancel'),
- click: function() {
- $( this ).dialog('close');
- }
- }
- ],
- });
+function scanForAlbums(cleanup) {
+ Scanner.scanAlbums();
+ return;
}
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();
- if (scanning_root == '') {
- alert('Scanning root cannot be empty');
- return;
- }
- $.getJSON('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;
- }
- } else {
- alert('Error: ' + r.cause);
- return;
- }
- $('#g-dialog-settings').dialog('close');
- });
- }
- },
- {
- text: t('gallery', 'Cancel'),
- click: function() {
- $(this).dialog('close');
- }
- }
- ],
- });
+ $( '#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();
+ if (scanning_root == '') {
+ alert('Scanning root cannot be empty');
+ 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;
+ }
+ } else {
+ alert('Error: ' + r.cause);
+ return;
+ }
+ $('#g-dialog-settings').dialog('close');
+ });
+ }
+ },
+ {
+ text: t('gallery', 'Cancel'),
+ click: function() {
+ $(this).dialog('close');
+ }
+ }
+ ],
+ });
}
diff --git a/apps/gallery/js/albums.js b/apps/gallery/js/albums.js
index 987412f28e0..d3326841cc7 100644
--- a/apps/gallery/js/albums.js
+++ b/apps/gallery/js/albums.js
@@ -1,89 +1,98 @@
Albums={
- // album item in this array should look as follow
- // {name: string,
- // numOfCovers: int}
- //
- // previews array should be an array of base64 decoded images
- // to display to user as preview picture when scrolling throught
- // the album cover
- albums:new Array(),
- // add simply adds new album to internal structure
- // however albums names must be unique so other
- // album with the same name wont be insered,
- // and false will be returned
- // true on success
- add: function(album_name, num) {
- if (Albums.albums[album_name] != undefined) return false;
- Albums.albums[album_name] = {name: album_name, numOfCovers: num};
- return true;
- },
- // remove element with given name
- // returns remove element or undefined if no such element was present
- remove: function(name) {
- var i = -1, tmp = 0;
- for (var a in Albums.albums) {
- if (a.name == name) {
- i = tmp;
- break;
- }
- tmp++;
- }
- if (i != -1) {
- return Albums.albums.splice(i,1);
- }
- return undefined;
- },
- // return element which match given name
- // of undefined if such element do not exist
- find: function(name) {
- return Albums.albums[name];
- },
- // displays gallery in linear representation
- // on given element, and apply default styles for gallery
- display: function(element) {
- var displayTemplate = '<div class="gallery_album_box"><div class="dummy"></div><a class="view"><div class="gallery_album_cover"></div></a><h1></h1><div class="gallery_album_decoration"><a><img src="img/share.png" title="Share"></a><a class="rename"><img src="img/rename.png" title="Rename"></a><a class="remove"><img src="img/delete.png" title="Delete"></a></div></div>';
- for (var i in Albums.albums) {
- var a = Albums.albums[i];
- var local=$(displayTemplate);
- local.attr('data-album',a.name);
- $(".gallery_album_decoration a.rename", local).bind('click', {name: a.name},function(event){
- event.preventDefault();
- galleryRename(event.data.name);
- });
- $(".gallery_album_decoration a.remove", local).bind('click', {name: a.name},function(event){
- event.preventDefault();
- galleryRemove(event.data.name);
- });
- $("a.view", local).attr('href','?view='+escape(a.name));
- $('h1',local).text(a.name);
- $(".gallery_album_cover", local).attr('title',a.name);
- $(".gallery_album_cover", local).css('background-repeat', 'no-repeat');
- $(".gallery_album_cover", local).css('background-position', '0');
- $(".gallery_album_cover", local).css('background-image','url("ajax/galleryOp.php?operation=get_covers&albumname='+escape(a.name)+'")');
- $(".gallery_album_cover", local).mousemove(function(e) {
-
- var albumMetadata = Albums.find(this.title);
- if (albumMetadata == undefined) {
- return;
- }
- var x = Math.floor((e.layerX - this.offsetLeft)/(this.offsetWidth/albumMetadata.numOfCovers));
- x *= this.offsetWidth;
- if (x < 0) x=0;
- $(this).css('background-position', -x+'px 0');
- });
- $(element).append(local);
- }
- },
- rename: function(element, new_name) {
- if (new_name) {
- $(element).attr("data-album", new_name);
- $("a.view", element).attr("href", "?view="+new_name);
- $("h1", element).text(new_name);
+ // album item in this array should look as follow
+ // {name: string,
+ // numOfCovers: int}
+ //
+ // previews array should be an array of base64 decoded images
+ // to display to user as preview picture when scrolling throught
+ // the album cover
+ albums:new Array(),
+ photos:new Array(),
+ // add simply adds new album to internal structure
+ // however albums names must be unique so other
+ // album with the same name wont be insered,
+ // and false will be returned
+ // true on success
+ add: function(album_name, num,path) {
+ if (Albums.albums[album_name] != undefined) return false;
+ Albums.albums[album_name] = {name: album_name, numOfCovers: num, path:path};
+ return true;
+ },
+ // remove element with given name
+ // returns remove element or undefined if no such element was present
+ remove: function(name) {
+ var i = -1, tmp = 0;
+ for (var a in Albums.albums) {
+ if (a.name == name) {
+ i = tmp;
+ break;
+ }
+ tmp++;
+ }
+ if (i != -1) {
+ return Albums.albums.splice(i,1);
+ }
+ return undefined;
+ },
+ // return element which match given name
+ // of undefined if such element do not exist
+ find: function(name) {
+ return Albums.albums[name];
+ },
+ // displays gallery in linear representation
+ // on given element, and apply default styles for gallery
+ display: function(element) {
+ var displayTemplate = '<div class="gallery_box album"><div class="dummy"></div><a class="view"><div class="gallery_album_cover"></div></a><h1></h1></div>';
+ for (var i in Albums.albums) {
+ var a = Albums.albums[i];
+ var local=$(displayTemplate);
+ local.attr('title', a.name);
+ local.attr('data-path', a.path);
+ local.attr('data-album',a.name);
+ $(".gallery_album_decoration a.rename", local).bind('click', {name: a.name},function(name,event){
+ event.preventDefault();
+ event.stopPropagation();
+ galleryRename(name);
+ }.bind(null,a.name));
+ $(".gallery_album_decoration a.remove", local).bind('click', {name: a.name},function(name,event){
+ event.preventDefault();
+ event.stopPropagation();
+ galleryRemove(name);
+ }.bind(null,a.name));
+ $('h1',local).text(decodeURIComponent(escape(a.name)));
+ $(".gallery_album_cover", local).attr('title',decodeURIComponent(escape(a.name)));
+ $(".gallery_album_cover", local).css('background-repeat', 'no-repeat');
+ $(".gallery_album_cover", local).css('background-position', '0');
+ $(".gallery_album_cover", local).css('background-image','url("'+OC.filePath('gallery','ajax','galleryOp.php')+'?operation=get_covers&albumname='+escape(a.name)+'")');
+ $(".gallery_album_cover", local).mousemove(function(e) {
+ var albumMetadata = Albums.find(this.title);
+ if (albumMetadata == undefined) {
+ return;
+ }
+ var x = Math.floor((e.layerX - this.offsetLeft)/(this.offsetWidth/albumMetadata.numOfCovers));
+ x *= this.offsetWidth;
+ if (x < 0) x=0;
+ $(this).css('background-position', -x+'px 0');
+ });
+ $(element).append(local);
+ }
+ var photoDisplayTemplate = '<div class="gallery_box"><div class="dummy"></div><div><a rel="images" href="'+OC.linkTo('files','download.php')+'?file=URLPATH"><img src="'+OC.filePath('gallery','ajax','thumbnail.php')+'?img=IMGPATH"></a></div></div>';
+ for (var i in Albums.photos) {
+ $(element).append(photoDisplayTemplate.replace("IMGPATH", escape(Albums.photos[i])).replace("URLPATH", escape(Albums.photos[i])));
+ }
+ $("a[rel=images]").fancybox({
+ 'titlePosition': 'inside'
+ });
+ },
+ rename: function(element, new_name) {
+ if (new_name) {
+ $(element).attr("data-album", new_name);
+ $("a.view", element).attr("href", "?view="+new_name);
+ $("h1", element).text(new_name);
+ }
+ },
+ clear: function(element) {
+ Albums.albums = new Array();
+ element.innerHTML = '';
}
- },
- clear: function(element) {
- Albums.albums = new Array();
- element.innerHTML = '';
- }
-
}
diff --git a/apps/gallery/js/scanner.js b/apps/gallery/js/scanner.js
new file mode 100644
index 00000000000..804ee9d229b
--- /dev/null
+++ b/apps/gallery/js/scanner.js
@@ -0,0 +1,34 @@
+Scanner={
+ albumsFound:0,
+ eventSource:null,
+ albumsScanned:0,
+ scanAlbums:function(callback){
+ $('#scanprogressbar').progressbar({value:0});
+ $('#scanprogressbar').fadeIn();
+ $('#scan input.start').hide();
+ $('#scan input.stop').show();
+ Scanner.albumsScanned=0;
+ Scanner.eventSource=new OC.EventSource(OC.linkTo('gallery', 'ajax/galleryOp.php'),{operation:'scan'});
+ Scanner.eventSource.listen('count', function(total){Scanner.albumsFound=total;});
+ Scanner.eventSource.listen('scanned', function(data) {
+ Scanner.albumsScanned++;
+ var progress=(Scanner.albumsScanned/Scanner.albumsFound)*100;
+ $('#scanprogressbar').progressbar('value',progress);
+ });
+ Scanner.eventSource.listen('done', function(count){
+ $('#scan input.start').show();
+ $('#scan input.stop').hide();
+ $('#scanprogressbar').fadeOut();
+ returnToElement(0);
+ });
+ if (callback)
+ callback();
+ },
+ stop:function() {
+ Scanner.eventSource.close();
+ $('#scan input.start').show();
+ $('#scan input.stop').hide();
+ $('#scanprogressbar').fadeOut();
+ }
+}
+
diff --git a/apps/gallery/lib/album.php b/apps/gallery/lib/album.php
index d1405333ac7..070afdd6cd6 100644
--- a/apps/gallery/lib/album.php
+++ b/apps/gallery/lib/album.php
@@ -4,97 +4,113 @@
* ownCloud - gallery application
*
* @author Bartek Przybylski
-* @copyright 2012 Bartek Przybylski bart.p.pl@gmail.com
-*
+* @copyright 2012 Bartek Przybylski <bartek@alefzero.eu>
+*
* 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
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
-*
+*
* You should have received a copy of the GNU Lesser General Public
-* License along with this library. If not, see <http://www.gnu.org/licenses/>.
-*
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
*/
+require_once('base.php');
+
class OC_Gallery_Album {
public static function create($owner, $name, $path){
- $stmt = OC_DB::prepare('INSERT INTO *PREFIX*gallery_albums (uid_owner, album_name, album_path) VALUES (?, ?, ?)');
- $stmt->execute(array($owner, $name, $path));
+ $stmt = OC_DB::prepare('INSERT INTO *PREFIX*gallery_albums (uid_owner, album_name, album_path, parent_path) VALUES (?, ?, ?, ?)');
+ $stmt->execute(array($owner, $name, $path, self::getParentPath($path)));
}
-
- public static function rename($oldname, $newname, $owner) {
- $stmt = OC_DB::prepare('UPDATE *PREFIX*gallery_albums SET album_name=? WHERE uid_owner=? AND album_name=?');
- $stmt->execute(array($newname, $owner, $oldname));
+
+ public static function cleanup() {
+ $albums = self::find(OC_User::getUser());
+ while ($r = $albums->fetchRow()) {
+ OC_Gallery_Photo::removeByAlbumId($r['album_id']);
+ self::remove(OC_User::getUser(), $r['album_name']);
+ }
}
- public static function cleanup() {
- $albums = self::find(OC_User::getUser());
- while ($r = $albums->fetchRow()) {
- OC_Gallery_Photo::removeByAlbumId($r['album_id']);
- self::remove(OC_User::getUser(), $r['album_name']);
- }
- }
-
- public static function remove($owner, $name=null) {
- $sql = 'DELETE FROM *PREFIX*gallery_albums WHERE uid_owner = ?';
+ public static function getParentPath($path) {
+ return $path === '/' ? '' : dirname($path);
+ }
+
+ public static function remove($owner, $name=null, $path=null, $parent=null) {
+ $sql = 'DELETE FROM *PREFIX*gallery_albums WHERE uid_owner LIKE ?';
$args = array($owner);
if (!is_null($name)){
- $sql .= ' AND album_name = ?';
+ $sql .= ' AND album_name LIKE ?';
$args[] = $name;
}
+ if (!is_null($path)){
+ $sql .= ' AND album_path LIKE ?';
+ $args[] = $path;
+ }
+ if (!is_null($parent)){
+ $sql .= ' AND parent_path LIKE ?';
+ $args[] = $parent;
+ }
$stmt = OC_DB::prepare($sql);
return $stmt->execute($args);
}
- public static function removeByPath($path, $owner) {
- $album = self::find($owner, null, $path);
- $album = $album->fetchRow();
- self::remove($owner, $album['album_name']);
- OC_Gallery_Photo::removeByAlbumId($album['album_id']);
- // find and remove any gallery which might be stored lower in dir hierarchy
- $path = $path.'/%';
- $stmt = OC_DB::prepare('SELECT * FROM *PREFIX*gallery_albums WHERE album_path LIKE ? AND uid_owner = ?');
- $result = $stmt->execute(array($path, $owner));
- while (($album = $result->fetchRow())) {
- OC_Gallery_Photo::removeByAlbumId($album['album_id']);
- self::remove($owner, $album['album_name']);
- }
- }
+ public static function removeByName($owner, $name) { self::remove($ownmer, $name); }
+ public static function removeByPath($owner, $path) { self::remove($owner, null, $path); }
+ public static function removeByParentPath($owner, $parent) { self::remove($owner, null, null, $parent); }
- public static function find($owner, $name=null, $path=null){
+ public static function find($owner, $name=null, $path=null, $parent=null){
$sql = 'SELECT * FROM *PREFIX*gallery_albums WHERE uid_owner = ?';
$args = array($owner);
if (!is_null($name)){
$sql .= ' AND album_name = ?';
$args[] = $name;
- }
- if (!is_null($path)){
- $sql .= ' AND album_path = ?';
- $args[] = $path;
- }
- $order = OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'order', 'ASC');
- $sql .= ' ORDER BY album_name ' . $order;
+ }
+ if (!is_null($path)){
+ $sql .= ' AND album_path = ?';
+ $args[] = $path;
+ }
+ if (!is_null($parent)){
+ $sql .= ' AND parent_path = ?';
+ $args[] = $parent;
+ }
+ $order = OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'order', 'ASC');
+ $sql .= ' ORDER BY album_name ' . $order;
$stmt = OC_DB::prepare($sql);
return $stmt->execute($args);
}
- public static function changePath($oldname, $newname, $owner) {
- $stmt = OC_DB::prepare('UPDATE *PREFIX*gallery_albums SET album_path=? WHERE uid_owner=? AND album_path=?');
- $stmt->execute(array($newname, $owner, $oldname));
- }
+ public static function changePath($oldname, $newname, $owner) {
+ $stmt = OC_DB::prepare('UPDATE *PREFIX*gallery_albums SET album_path=? WHERE uid_owner=? AND album_path=?');
+ $stmt->execute(array($newname, $owner, $oldname));
+ }
- public static function changeThumbnailPath($oldname, $newname) {
- require_once('../../../lib/base.php');
- $thumbpath = OC::$CONFIG_DATADIRECTORY.'/../gallery/';
- rename($thumbpath.$oldname.'.png', $thumbpath.$newname.'.png');
- }
+ public static function changeThumbnailPath($oldname, $newname) {
+ require_once('../../../lib/base.php');
+ $thumbpath = OC::$CONFIG_DATADIRECTORY.'/../gallery/';
+ rename($thumbpath.$oldname.'.png', $thumbpath.$newname.'.png');
+ }
+ public static function getAlbumSize($id){
+ $sql = 'SELECT COUNT(*) as size FROM *PREFIX*gallery_photos WHERE album_id = ?';
+ $stmt = OC_DB::prepare($sql);
+ $result=$stmt->execute(array($id))->fetchRow();
+ return $result['size'];
+ }
+
+ public static function getIntermediateGallerySize($path) {
+ $path .= '%';
+ $sql = 'SELECT COUNT(*) as size FROM *PREFIX*gallery_photos photos, *PREFIX*gallery_albums albums WHERE photos.album_id = albums.album_id AND uid_owner = ? AND file_path LIKE ?';
+ $stmt = OC_DB::prepare($sql);
+ $result = $stmt->execute(array(OC_User::getUser(), $path))->fetchRow();
+ return $result['size'];
+ }
}
?>
diff --git a/apps/gallery/lib/hooks_handlers.php b/apps/gallery/lib/hooks_handlers.php
index 046866e5c5d..2788337bbe8 100644
--- a/apps/gallery/lib/hooks_handlers.php
+++ b/apps/gallery/lib/hooks_handlers.php
@@ -21,9 +21,9 @@
*
*/
-OC_Hook::connect(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_write, "OC_Gallery_Hooks_Handlers", "addPhotoFromPath");
-OC_Hook::connect(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_delete, "OC_Gallery_Hooks_Handlers", "removePhoto");
-OC_Hook::connect(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_rename, "OC_Gallery_Hooks_Handlers", "renamePhoto");
+//OC_Hook::connect(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_write, "OC_Gallery_Hooks_Handlers", "addPhotoFromPath");
+//OC_Hook::connect(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_delete, "OC_Gallery_Hooks_Handlers", "removePhoto");
+//OC_Hook::connect(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_rename, "OC_Gallery_Hooks_Handlers", "renamePhoto");
require_once(OC::$CLASSPATH['OC_Gallery_Album']);
require_once(OC::$CLASSPATH['OC_Gallery_Photo']);
@@ -37,7 +37,7 @@ class OC_Gallery_Hooks_Handlers {
}
private static function directoryContainsPhotos($dirpath) {
- $dirhandle = opendir(OC::$CONFIG_DATADIRECTORY.$dirpath);
+ $dirhandle = OC_Filesystem::opendir($dirpath.'/');
if ($dirhandle != FALSE) {
while (($filename = readdir($dirhandle)) != FALSE) {
if ($filename[0] == '.') continue;
@@ -68,7 +68,7 @@ class OC_Gallery_Hooks_Handlers {
if (!self::isPhoto($fullpath)) return;
- $path = substr($fullpath, 0, strrpos($fullpath, '/'));
+ $path = dirname($fullpath);
if (!self::pathInRoot($path)) return;
OC_Gallery_Scanner::scanDir($path, $albums);
@@ -76,9 +76,9 @@ class OC_Gallery_Hooks_Handlers {
public static function removePhoto($params) {
$path = $params[OC_Filesystem::signal_param_path];
- if (OC_Filesystem::is_dir($path) && self::directoryContainsPhotos($path)) {
+ if (OC_Filesystem::is_dir($path.'/') && self::directoryContainsPhotos($path)) {
if(!self::pathInRoot($path)) return;
- OC_Gallery_Album::removeByPath($path.'/', OC_User::getUser());
+ OC_Gallery_Album::removeByPath($path, OC_User::getUser());
} elseif (self::isPhoto($path)) {
OC_Gallery_Photo::removeByPath($path);
}
@@ -87,11 +87,11 @@ class OC_Gallery_Hooks_Handlers {
public static function renamePhoto($params) {
$oldpath = $params[OC_Filesystem::signal_param_oldpath];
$newpath = $params[OC_Filesystem::signal_param_newpath];
- if (OC_Filesystem::is_dir($newpath) && self::directoryContainsPhotos($newpath)) {
+ if (OC_Filesystem::is_dir($newpath.'/') && self::directoryContainsPhotos($newpath)) {
OC_Gallery_Album::changePath($oldpath, $newpath, OC_User::getUser());
- } elseif (!self::isPhoto($newpath)) {
- $olddir = substr($oldpath, 0, strrpos($oldpath, '/'));
- $newdir = substr($newpath, 0, strrpos($newpath, '/'));
+ } elseif (self::isPhoto($newpath)) {
+ $olddir = dirname($oldpath);
+ $newdir = dirname($newpath);
if ($olddir == '') $olddir = '/';
if ($newdir == '') $newdir = '/';
if (!self::isPhoto($newpath)) return;
@@ -101,25 +101,26 @@ class OC_Gallery_Hooks_Handlers {
$oldAlbumId;
if ($olddir == $newdir) {
// album changing is not needed
- $album = OC_Gallery_Album::find(OC_User::getUser(), null, $olddir);
- if ($album->numRows() == 0) {
- $album = self::createAlbum($newdir);
+ $albums = OC_Gallery_Album::find(OC_User::getUser(), null, $olddir);
+ $album = $albums->fetchRow();
+ if (!$album) {
+ $albums = self::createAlbum($newdir);
+ $album = $albums->fetchRow();
}
- $album = $album->fetchRow();
$newAlbumId = $oldAlbumId = $album['album_id'];
} else {
$newalbum = OC_Gallery_Album::find(OC_User::getUser(), null, $newdir);
$oldalbum = OC_Gallery_Album::find(OC_User::getUser(), null, $olddir);
- if ($newalbum->numRows() == 0) {
+ if (!($newalbum = $newalbum->fetchRow())) {
$newalbum = self::createAlbum($newdir);
+ $newalbum = $newalbum->fetchRow();
}
- $newalbum = $newalbum->fetchRow();
- if ($oldalbum->numRows() == 0) {
+ $oldalbum = $oldalbum->fetchRow();
+ if (!$oldalbum) {
OC_Gallery_Photo::create($newalbum['album_id'], $newpath);
return;
}
- $oldalbum = $oldalbum->fetchRow();
$newAlbumId = $newalbum['album_id'];
$oldAlbumId = $oldalbum['album_id'];
diff --git a/apps/gallery/lib/photo.php b/apps/gallery/lib/photo.php
index 872ecc9488a..5e6df8069b5 100644
--- a/apps/gallery/lib/photo.php
+++ b/apps/gallery/lib/photo.php
@@ -13,11 +13,11 @@
*
* 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
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
-*
+*
* You should have received a copy of the GNU Lesser General Public
-* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
@@ -46,38 +46,39 @@ class OC_Gallery_Photo {
return $stmt->execute(array($owner, $album_name));
}
- public static function removeByPath($path) {
- $stmt = OC_DB::prepare('DELETE FROM *PREFIX*gallery_photos WHERE file_path LIKE ?');
- $stmt->execute(array($path));
- }
+ public static function removeByPath($path) {
+ $stmt = OC_DB::prepare('DELETE FROM *PREFIX*gallery_photos WHERE file_path LIKE ?');
+ $stmt->execute(array($path));
+ }
- public static function removeById($id) {
- $stmt = OC_DB::prepare('DELETE FROM *PREFIX*gallery_photos WHERE photo_id = ?');
- $stmt->execute(array($id));
- }
+ public static function removeById($id) {
+ $stmt = OC_DB::prepare('DELETE FROM *PREFIX*gallery_photos WHERE photo_id = ?');
+ $stmt->execute(array($id));
+ }
- public static function removeByAlbumId($albumid) {
- $stmt = OC_DB::prepare('DELETE FROM *PREFIX*gallery_photos WHERE album_id = ?');
- $stmt->execute(array($albumid));
- }
+ public static function removeByAlbumId($albumid) {
+ $stmt = OC_DB::prepare('DELETE FROM *PREFIX*gallery_photos WHERE album_id = ?');
+ $stmt->execute(array($albumid));
+ }
- public static function changePath($oldAlbumId, $newAlbumId, $oldpath, $newpath) {
- $stmt = OC_DB::prepare("UPDATE *PREFIX*gallery_photos SET file_path = ?, album_id = ? WHERE album_id = ? and file_path = ?");
- $stmt->execute(array($newpath, $newAlbumId, $oldAlbumId, $oldpath));
- }
+ public static function changePath($oldAlbumId, $newAlbumId, $oldpath, $newpath) {
+ $stmt = OC_DB::prepare("UPDATE *PREFIX*gallery_photos SET file_path = ?, album_id = ? WHERE album_id = ? and file_path = ?");
+ $stmt->execute(array($newpath, $newAlbumId, $oldAlbumId, $oldpath));
+ }
public static function getThumbnail($image_name) {
$save_dir = OC_Config::getValue("datadirectory").'/'. OC_User::getUser() .'/gallery/';
$save_dir .= dirname($image_name). '/';
- $thumb_file = $save_dir . $image_name;
+ $image_path = $image_name;
+ $thumb_file = $save_dir . basename($image_name);
if (file_exists($thumb_file)) {
$image = new OC_Image($thumb_file);
} else {
- $imagePath = OC_Filesystem::getLocalFile($image_name);
- if(!file_exists($imagePath)) {
+ $image_path = OC_Filesystem::getLocalFile($image_path);
+ if(!file_exists($image_path)) {
return null;
}
- $image = new OC_Image($imagePath);
+ $image = new OC_Image($image_path);
if ($image->valid()) {
$image->centerCrop();
$image->resize(200);
@@ -93,4 +94,8 @@ class OC_Gallery_Photo {
}
return null;
}
+
+ public static function getGalleryRoot() {
+ return OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'root', '');
+ }
}
diff --git a/apps/gallery/lib/scanner.php b/apps/gallery/lib/scanner.php
index 64efb006ad1..c8825c267eb 100644
--- a/apps/gallery/lib/scanner.php
+++ b/apps/gallery/lib/scanner.php
@@ -4,7 +4,7 @@
* ownCloud - gallery application
*
* @author Bartek Przybylski
-* @copyright 2012 Bartek Przybylski bart.p.pl@gmail.com
+* @copyright 2012 Bartek Przybylski <bartek@alefzero.eu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@@ -13,111 +13,130 @@
*
* 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
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
-*
+*
* You should have received a copy of the GNU Lesser General Public
-* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
-require_once('base.php'); // base lib
-require_once('images_utils.php');
-
class OC_Gallery_Scanner {
- public static function scan($root) {
- $albums = array();
- self::scanDir($root, $albums);
- return $albums;
- }
-
- public static function cleanUp() {
- $stmt = OC_DB::prepare('DELETE FROM *PREFIX*gallery_albums');
- $stmt->execute(array());
- $stmt = OC_DB::prepare('DELETE FROM *PREFIX*gallery_photos');
- $stmt->execute(array());
- }
+ public static function getGalleryRoot() {
+ return OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'root', '/');
+ }
+ public static function getScanningRoot() {
+ return OC_Filesystem::getRoot().self::getGalleryRoot();
+ }
- public static function createName($name) {
- $root = OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'root', '/');
- $name = str_replace('/', '.', str_replace(OC::$CONFIG_DATADIRECTORY, '', $name));
- if (substr($name, 0, strlen($root)) == str_replace('/','.',$root)) {
- $name = substr($name, strlen($root));
- }
- $name = ($name==='.') ? 'main' : trim($name,'.');
- return $name;
- }
+ public static function cleanUp() {
+ OC_Gallery_Album::cleanup();
+ }
- public static function scanDir($path, &$albums) {
- $current_album = array('name'=> $path, 'imagesCount' => 0, 'images' => array());
- $current_album['name'] = self::createName($current_album['name']);
+ public static function createName($name) {
+ $name = basename($name);
+ return $name == '.' ? '' : $name;
+ }
- if ($dh = OC_Filesystem::opendir($path)) {
- while (($filename = readdir($dh)) !== false) {
- $filepath = ($path[strlen($path)-1]=='/'?$path:$path.'/').$filename;
- if (substr($filename, 0, 1) == '.') continue;
- if (self::isPhoto($path.'/'.$filename)) {
- $current_album['images'][] = $filepath;
- }
- }
- }
- $current_album['imagesCount'] = count($current_album['images']);
- $albums['imagesCount'] = $current_album['imagesCount'];
- $albums['albumName'] = $current_album['name'];
+ // Scan single dir relative to gallery root
+ public static function scan($eventSource) {
+ $paths = self::findPaths();
+ $eventSource->send('count', count($paths)+1);
+ $owner = OC_User::getUser();
+ foreach ($paths as $path) {
+ $name = self::createName($path);
+ $images = self::findFiles($path);
- $result = OC_Gallery_Album::find(OC_User::getUser(), /*$current_album['name']*/ null, $path);
- // don't duplicate galleries with same path (bug oc-33)
- if ($result->numRows() == 0 && count($current_album['images'])) {
- OC_Gallery_Album::create(OC_User::getUser(), $current_album['name'], $path);
- $result = OC_Gallery_Album::find(OC_User::getUser(), $current_album['name']);
- }
- $albumId = $result->fetchRow();
- $albumId = $albumId['album_id'];
- foreach ($current_album['images'] as $img) {
- $result = OC_Gallery_Photo::find($albumId, $img);
- if ($result->numRows() == 0) {
- OC_Gallery_Photo::create($albumId, $img);
- }
- }
- if (count($current_album['images'])) {
- self::createThumbnail($current_album['name'],$current_album['images']);
- }
- }
+ $result = OC_Gallery_Album::find($owner, null, $path);
+ // don't duplicate galleries with same path
+ if (!($albumId = $result->fetchRow())) {
+ OC_Gallery_Album::create($owner, $name, $path);
+ $result = OC_Gallery_Album::find($owner, $name, $path);
+ $albumId = $result->fetchRow();
+ }
+ $albumId = $albumId['album_id'];
+ foreach ($images as $img) {
+ $result = OC_Gallery_Photo::find($albumId, $img);
+ if (!$result->fetchRow())
+ OC_Gallery_Photo::create($albumId, $img);
+ }
+ if (count($images))
+ self::createThumbnails($name, $images);
+ $eventSource->send('scanned', '');
+ }
+ self::createIntermediateAlbums();
+ $eventSource->send('scanned', '');
+ $eventSource->send('done', 1);
+ }
- public static function createThumbnail($albumName, $files) {
- $file_count = min(count($files), 10);
- $thumbnail = imagecreatetruecolor($file_count*200, 200);
- for ($i = 0; $i < $file_count; $i++) {
- $image = OC_Gallery_Photo::getThumbnail($files[$i]);
- if ($image && $image->valid()) {
- imagecopyresampled($thumbnail, $image->resource(), $i*200, 0, 0, 0, 200, 200, 200, 200);
- }
- }
- imagepng($thumbnail, OC_Config::getValue("datadirectory").'/'. OC_User::getUser() .'/gallery/' . $albumName.'.png');
- }
+ public static function createThumbnails($albumName, $files) {
+ // create gallery thumbnail
+ $file_count = min(count($files), 10);
+ $thumbnail = imagecreatetruecolor($file_count*200, 200);
+ for ($i = 0; $i < $file_count; $i++) {
+ $image = OC_Gallery_Photo::getThumbnail($files[$i]);
+ if ($image && $image->valid()) {
+ imagecopyresampled($thumbnail, $image->resource(), $i*200, 0, 0, 0, 200, 200, 200, 200);
+ }
+ }
+ imagepng($thumbnail, OC_Config::getValue("datadirectory").'/'. OC_User::getUser() .'/gallery/' . $albumName.'.png');
+ }
- public static function isPhoto($filename) {
- $ext = strtolower(substr($filename, strrpos($filename, '.')+1));
- return $ext=='png' || $ext=='jpeg' || $ext=='jpg' || $ext=='gif';
- }
+ public static function createIntermediateAlbums() {
+ $paths = self::findPaths();
+ for ($i = 1; $i < count($paths); $i++) {
+ $prevLen = strlen($paths[$i-1]);
+ if (strncmp($paths[$i-1], $paths[$i], $prevLen)==0) {
+ $s = substr($paths[$i], $prevLen);
+ if (strrpos($s, '/') != 0) {
+ $a = explode('/', trim($s, '/'));
+ $p = $paths[$i-1];
+ foreach ($a as $e) {
+ $p .= ($p == '/'?'':'/').$e;
+ OC_Gallery_Album::create(OC_User::getUser(), $e, $p);
+ $arr = OC_FileCache::searchByMime('image','', OC_Filesystem::getRoot().$p);
+ $step = floor(count($arr)/10);
+ if ($step == 0) $step = 1;
+ $na = array();
+ for ($j = 0; $j < count($arr); $j+=$step) {
+ $na[] = $p.$arr[$j];
+ }
+ if (count($na))
+ self::createThumbnails($e, $na);
+ }
+ }
+ }
+ }
+ }
- public static function find_paths($path) {
- $ret = array();
- $dirres;
- $addpath = FALSE;
- if (($dirres = OC_Filesystem::opendir($path)) == FALSE) return $ret;
+ public static function isPhoto($filename) {
+ $ext = strtolower(substr($filename, strrpos($filename, '.')+1));
+ return $ext=='png' || $ext=='jpeg' || $ext=='jpg' || $ext=='gif';
+ }
- while (($file = readdir($dirres)) != FALSE) {
- if ($file[0] == '.') continue;
- if (OC_Filesystem::is_dir($path.$file))
- $ret = array_merge($ret, self::find_paths($path.$file.'/'));
- if (self::isPhoto($path.$file)) $addpath = TRUE;
- }
+ public static function findFiles($path) {
+ $images = OC_FileCache::searchByMime('image','', OC_Filesystem::getRoot().$path);
+ $new = array();
+ foreach ($images as $i)
+ if (strpos($i, '/',1) === FALSE)
+ $new[] = $path.$i;
+ return $new;
+ }
- if ($addpath) $ret[] = urlencode($path);
-
- return $ret;
- }
+ public static function findPaths() {
+ $images=OC_FileCache::searchByMime('image','', self::getScanningRoot());
+ $paths=array();
+ foreach($images as $image){
+ $path=dirname($image);
+ $path = self::getGalleryRoot().($path=='.'?'':$path);
+ if ($path !== '/') $path=rtrim($path,'/');
+ if(array_search($path,$paths)===false){
+ $paths[]=$path;
+ }
+ }
+ sort($paths);
+ return $paths;
+ }
}
-?>
+
diff --git a/apps/gallery/templates/index.php b/apps/gallery/templates/index.php
index 7cc7dad3ac6..dc5852733bd 100644
--- a/apps/gallery/templates/index.php
+++ b/apps/gallery/templates/index.php
@@ -1,31 +1,42 @@
<?php
OC_Util::addStyle('gallery', 'styles');
OC_Util::addScript('gallery', 'albums');
+OC_Util::addScript('gallery', 'scanner');
OC_Util::addScript('gallery', 'album_cover');
+OC_Util::addStyle('files', 'files');
+OC_Util::addScript('files_imageviewer', 'jquery.mousewheel-3.0.4.pack');
+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');
?>
-<div id="notification"><div id="gallery_notification_text">Creating thumbnails</div></div>
<div id="controls">
- <div id="scan">
- <div id="scanprogressbar"></div>
- <input type="button" id="g-scan-button" value="<?php echo $l->t('Rescan');?>" onclick="javascript:scanForAlbums();" />
- </div>
- <div id="g-settings">
- <input type="button" id="g-settings-button" value="<?php echo $l->t('Settings');?>" onclick="javascript:settings();"/>
- </div>
+ <div id="scan">
+ <div id="scanprogressbar"></div>
+ <input type="button" class="start" value="<?php echo $l->t('Rescan');?>" onclick="javascript:scanForAlbums();" />
+ <input type="button" class="stop" style="display:none" value="<?php echo $l->t('Stop');?>" onclick="javascript:Scanner.stop();" />
+ <input type="button" id="g-settings-button" value="<?php echo $l->t('Settings');?>" onclick="javascript:settings();"/>
+ </div>
+ <div id="g-album-navigation">
+ <div class="crumb last" style="background-image:url('<?php echo OC::$WEBROOT;?>/core/img/breadcrumb.png')">
+ <a href="javascript:returnToElement(0);">main</a>
+ </div>
+ </div>
+ <div id="g-album-loading" class="crumb" style="display:none">
+ <img src="img/loading.gif">
+ </div>
</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>
+ <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>
+ <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>
@@ -33,23 +44,23 @@ $l = new OC_L10N('gallery');
<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/>
+ <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('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>
- -->
+ <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/ajax/api.php b/apps/media/ajax/api.php
index bb4502690b5..9d9c14deb17 100644
--- a/apps/media/ajax/api.php
+++ b/apps/media/ajax/api.php
@@ -120,7 +120,10 @@ if($arguments['action']){
OC_Filesystem::readfile($arguments['path']);
exit;
case 'find_music':
- OC_JSON::encodedPrint(OC_FileCache::searchByMime('audio'));
+ $music=OC_FileCache::searchByMime('audio');
+ $ogg=OC_FileCache::searchByMime('application','ogg');
+ $music=array_merge($music,$ogg);
+ OC_JSON::encodedPrint($music);
exit;
}
}
diff --git a/apps/media/appinfo/app.php b/apps/media/appinfo/app.php
index 475a33500f4..651067fbbe1 100644
--- a/apps/media/appinfo/app.php
+++ b/apps/media/appinfo/app.php
@@ -30,4 +30,5 @@ OC_APP::registerPersonal('media','settings');
OC_App::register( array( 'order' => 3, 'id' => 'media', 'name' => 'Media' ));
OC_App::addNavigationEntry(array('id' => 'media_index', 'order' => 2, 'href' => OC_Helper::linkTo('media', 'index.php'), 'icon' => OC_Helper::imagePath('core', 'places/music.svg'), 'name' => $l->t('Music')));
-?>
+
+OC_Search::registerProvider('OC_MediaSearchProvider');
diff --git a/apps/media/js/scanner.js b/apps/media/js/scanner.js
index 6c991b60d52..a9321f99964 100644
--- a/apps/media/js/scanner.js
+++ b/apps/media/js/scanner.js
@@ -38,7 +38,7 @@ Scanner={
$('#scancount').show();
},
stop:function(){
- Scanner.close();
+ Scanner.eventSource.close();
},
};
diff --git a/apps/media/lib_media.php b/apps/media/lib_media.php
index 1bcd0f08c80..9de291e8da2 100644
--- a/apps/media/lib_media.php
+++ b/apps/media/lib_media.php
@@ -56,6 +56,7 @@ class OC_MEDIA{
*/
public static function updateFile($params){
$path=$params['path'];
+ if(!$path) return;
require_once 'lib_scanner.php';
require_once 'lib_collection.php';
//fix a bug where there were multiply '/' in front of the path, it should only be one
@@ -81,8 +82,8 @@ class OC_MEDIA{
}
}
-class OC_MediaSearchProvider extends OC_Search_Provider{
- function search($query){
+class OC_MediaSearchProvider implements OC_Search_Provider{
+ static function search($query){
require_once('lib_collection.php');
$artists=OC_MEDIA_COLLECTION::getArtists($query);
$albums=OC_MEDIA_COLLECTION::getAlbums(0,$query);
@@ -106,5 +107,3 @@ class OC_MediaSearchProvider extends OC_Search_Provider{
}
}
-new OC_MediaSearchProvider();
-?>
diff --git a/apps/media/lib_scanner.php b/apps/media/lib_scanner.php
index ea594ee8e3c..39658b27ba9 100644
--- a/apps/media/lib_scanner.php
+++ b/apps/media/lib_scanner.php
@@ -38,6 +38,8 @@ class OC_MEDIA_SCANNER{
*/
public static function scanCollection($eventSource=null){
$music=OC_FileCache::searchByMime('audio');
+ $ogg=OC_FileCache::searchByMime('application','ogg');
+ $music=array_merge($music,$ogg);
$eventSource->send('count',count($music));
$songs=0;
foreach($music as $file){
diff --git a/apps/remoteStorage/BearerAuth.php b/apps/remoteStorage/BearerAuth.php
new file mode 100644
index 00000000000..ebcf189dfb9
--- /dev/null
+++ b/apps/remoteStorage/BearerAuth.php
@@ -0,0 +1,61 @@
+<?php
+
+/**
+ * HTTP Bearer Authentication handler
+ *
+ * Use this class for easy http authentication setup
+ *
+ * @package Sabre
+ * @subpackage HTTP
+ * @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
+ * @author Evert Pot (http://www.rooftopsolutions.nl/)
+ * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
+ */
+class Sabre_HTTP_BearerAuth extends Sabre_HTTP_AbstractAuth {
+
+ /**
+ * Returns the supplied username and password.
+ *
+ * The returned array has two values:
+ * * 0 - username
+ * * 1 - password
+ *
+ * If nothing was supplied, 'false' will be returned
+ *
+ * @return mixed
+ */
+ public function getUserPass() {
+
+ // Apache and mod_php
+ if (($user = $this->httpRequest->getRawServerValue('PHP_AUTH_USER')) && ($pass = $this->httpRequest->getRawServerValue('PHP_AUTH_PW'))) {
+
+ return array($user,$pass);
+
+ }
+
+ // Most other webservers
+ $auth = $this->httpRequest->getHeader('Authorization');
+
+ if (!$auth) return false;
+
+ if (strpos(strtolower($auth),'bearer')!==0) return false;
+
+ return explode(':', base64_decode(substr($auth, 7)));
+
+ }
+
+ /**
+ * Returns an HTTP 401 header, forcing login
+ *
+ * This should be called when username and password are incorrect, or not supplied at all
+ *
+ * @return void
+ */
+ public function requireLogin() {
+
+ $this->httpResponse->setHeader('WWW-Authenticate','Basic realm="' . $this->realm . '"');
+ $this->httpResponse->sendStatus(401);
+
+ }
+
+}
diff --git a/apps/remoteStorage/WebDAV.php b/apps/remoteStorage/WebDAV.php
index e048d19e8f2..cad465181a9 100644
--- a/apps/remoteStorage/WebDAV.php
+++ b/apps/remoteStorage/WebDAV.php
@@ -33,6 +33,7 @@ require_once('../../lib/base.php');
OC_Util::checkAppEnabled('remoteStorage');
require_once('Sabre/autoload.php');
require_once('lib_remoteStorage.php');
+require_once('BearerAuth.php');
require_once('oauth_ro_auth.php');
ini_set('default_charset', 'UTF-8');
@@ -68,7 +69,10 @@ if(count($pathParts) >= 3 && $pathParts[0] == '') {
$server->setBaseUri(OC::$WEBROOT."/apps/remoteStorage/WebDAV.php/$ownCloudUser");
// Auth backend
- $authBackend = new OC_Connector_Sabre_Auth_ro_oauth(OC_remoteStorage::getValidTokens($ownCloudUser, $category));
+ $authBackend = new OC_Connector_Sabre_Auth_ro_oauth(
+ OC_remoteStorage::getValidTokens($ownCloudUser, $category),
+ $category
+ );
$authPlugin = new Sabre_DAV_Auth_Plugin($authBackend,'ownCloud');//should use $validTokens here
$server->addPlugin($authPlugin);
@@ -81,5 +85,6 @@ if(count($pathParts) >= 3 && $pathParts[0] == '') {
// And off we go!
$server->exec();
} else {
- die('not the right address format '.var_export($pathParts, true));
+ //die('not the right address format '.var_export($pathParts, true));
+ die('not the right address format');
}
diff --git a/apps/remoteStorage/ajax/revokeToken.php b/apps/remoteStorage/ajax/revokeToken.php
new file mode 100644
index 00000000000..ca56cf560ec
--- /dev/null
+++ b/apps/remoteStorage/ajax/revokeToken.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+* ownCloud
+*
+* Original:
+* @author Frank Karlitschek
+* @copyright 2010 Frank Karlitschek karlitschek@kde.org
+*
+* Adapted:
+* @author Michiel de Jong, 2012
+*
+* 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/>.
+*
+*/
+
+
+// Do not load FS ...
+$RUNTIME_NOSETUPFS = true;
+
+require_once('../../../lib/base.php');
+OC_Util::checkAppEnabled('remoteStorage');
+require_once('Sabre/autoload.php');
+require_once('../lib_remoteStorage.php');
+
+ini_set('default_charset', 'UTF-8');
+#ini_set('error_reporting', '');
+@ob_clean();
+
+echo OC_remoteStorage::deleteToken(file_get_contents("php://input"));
diff --git a/apps/remoteStorage/appinfo/app.php b/apps/remoteStorage/appinfo/app.php
index ac1ecde5082..a1fbebc42f5 100644
--- a/apps/remoteStorage/appinfo/app.php
+++ b/apps/remoteStorage/appinfo/app.php
@@ -3,3 +3,4 @@ OC_App::register( array(
'order' => 10,
'id' => 'remoteStorage',
'name' => 'remoteStorage compatibility' ));
+OC_APP::registerPersonal('remoteStorage','settings');
diff --git a/apps/remoteStorage/appinfo/info.xml b/apps/remoteStorage/appinfo/info.xml
index 8179ca99112..121587795db 100644
--- a/apps/remoteStorage/appinfo/info.xml
+++ b/apps/remoteStorage/appinfo/info.xml
@@ -3,8 +3,8 @@
<id>remoteStorage</id>
<name>remoteStorage compatibility</name>
<description>Enables your users to use ownCloud as their remote storage for unhosted applications.</description>
- <version>0.2</version>
- <licence>AGPL</licence>
+ <version>0.5</version>
+ <licence>AGPL or MIT</licence>
<author>Michiel de Jong</author>
<require>2</require>
</info>
diff --git a/apps/remoteStorage/auth.css b/apps/remoteStorage/auth.css
new file mode 100644
index 00000000000..2dedad5dd0f
--- /dev/null
+++ b/apps/remoteStorage/auth.css
@@ -0,0 +1,8 @@
+h2 { font-size:2em; font-weight:bold; margin-bottom:1em; white-space:nowrap; }
+ul.scopes { list-style:disc; }
+ul.scopes li { white-space:nowrap; }
+h2 img { width: 50% }
+#oauth { margin:4em auto 2em; width:20em; }
+#allow-auth { background-color:#5c3; text-shadow:#5e3 0 1px 0; color:#fff;
+-webkit-box-shadow:0 1px 1px #fff, 0 1px 1px #5f3 inset; -moz-box-shadow:0 1px 1px #fff, 0 1px 1px #5f3 inset; box-shadow:0 1px 1px #fff, 0 1px 1px #5f3 inset; }
+#deny-auth { padding:0; margin:.7em; border:0; background:none; font-size:1.2em; -moz-box-shadow: 0 0 0 #fff, 0 0 0 #fff inset; -webkit-box-shadow: 0 0 0 #fff, 0 0 0 #fff inset; box-shadow: 0 0 0 #fff, 0 0 0 #fff inset; }
diff --git a/apps/remoteStorage/auth.php b/apps/remoteStorage/auth.php
index 85421ba3d88..c00f9d5555c 100644
--- a/apps/remoteStorage/auth.php
+++ b/apps/remoteStorage/auth.php
@@ -8,7 +8,7 @@
* @copyright 2010 Frank Karlitschek karlitschek@kde.org
*
* Adapted:
-* @author Michiel de Jong, 2011
+* @author Michiel de Jong, 2012
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@@ -17,11 +17,11 @@
*
* 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
+* 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/>.
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
@@ -39,24 +39,8 @@ ini_set('default_charset', 'UTF-8');
#ini_set('error_reporting', '');
@ob_clean();
-//allow use as remote storage for other websites
-if(isset($_SERVER['HTTP_ORIGIN'])) {
- header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
- header('Access-Control-Max-Age: 3600');
- header('Access-Control-Allow-Methods: OPTIONS, GET, PUT, DELETE, PROPFIND');
- header('Access-Control-Allow-Headers: Authorization, Content-Type');
-} else {
- header('Access-Control-Allow-Origin: *');
-}
-
$path = substr($_SERVER["REQUEST_URI"], strlen($_SERVER["SCRIPT_NAME"]));
-$pathParts = explode('/', $path);
-// for webdav:
-// 0/ 1 / 2 / 3 / 4 / 5 / 6 / 7
-// /$ownCloudUser/remoteStorage/webdav/$userHost/$userName/$dataScope/$key
-// for oauth:
-// 0/ 1 / 2 / 3 / 4
-// /$ownCloudUser/remoteStorage/oauth/auth
+$pathParts = explode('/', $path);
if(count($pathParts) == 2 && $pathParts[0] == '') {
//TODO: input checking. these explodes may fail to produces the desired arrays:
@@ -66,19 +50,69 @@ if(count($pathParts) == 2 && $pathParts[0] == '') {
if($k=='user_address'){
$userAddress=$v;
} else if($k=='redirect_uri'){
- $appUrl=$v;
+ $appUrlParts=explode('/', $v);
+ $appUrl = $appUrlParts[2];//bit dodgy i guess
} else if($k=='scope'){
- $category=$v;
+ $categories=$v;
}
}
$currUser = OC_User::getUser();
if($currUser == $ownCloudUser) {
if(isset($_POST['allow'])) {
//TODO: check if this can be faked by editing the cookie in firebug!
- $token=OC_remoteStorage::createCategory($appUrl, $category);
+ $token=OC_remoteStorage::createCategories($appUrl, $categories);
header('Location: '.$_GET['redirect_uri'].'#access_token='.$token.'&token_type=bearer');
} else {
- echo '<form method="POST"><input name="allow" type="submit" value="Allow this web app to store stuff on your owncloud."></form>';
+?>
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>ownCloud</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <link rel="shortcut icon" href="../../../core/img/favicon.png" /><link rel="apple-touch-icon-precomposed" href="../../../core/img/favicon-touch.png" />
+ <link rel="stylesheet" href="../../../core/css/styles.css" type="text/css" media="screen" />
+ <link rel="stylesheet" href="../auth.css" type="text/css" media="screen" />
+ </head>
+ <body id="body-login">
+ <div id="login">
+ <header>
+ <div id="header">
+ <img src="../../../core/img/owncloud-logo-medium-white.png" alt="ownCloud" />
+ </div>
+ </header>
+ <section id="main">
+ <div id="oauth">
+ <h2><img src="../remoteStorage-big.png" alt="remoteStorage" /></h2>
+ <p><strong><?php $appUrlParts = explode('/', $_GET['redirect_uri']); echo htmlentities($appUrlParts[2]); ?></strong>
+ requests read &amp; write access to your
+ <?php
+ $categories = explode(',', htmlentities($_GET['scope']));
+ if(!count($categories)) {
+ echo htmlentities($_GET['scope']);
+ } else {
+ echo '<em>'.$categories[0].'</em>';
+ if(count($categories)==2) {
+ echo ' and <em>'.$categories[1].'</em>';
+ } else if(count($categories)>2) {
+ for($i=1; $i<count($categories)-1; $i++) {
+ echo ', <em>'.$categories[$i].'</em>';
+ }
+ echo ', and <em>'.$categories[$i].'</em>';
+ }
+ }
+ ?>.
+ </p>
+ <form accept-charset="UTF-8" method="post">
+ <input id="allow-auth" name="allow" type="submit" value="Allow" />
+ <input id="deny-auth" name="deny" type="submit" value="Deny" />
+ </form>
+ </div>
+ </section>
+ </div>
+ <footer><p class="info"><a href="http://owncloud.org/">ownCloud</a> &ndash; web services under your control</p></footer>
+ </body>
+</html>
+<?php
}
} else {
if((isset($_SERVER['HTTPS'])) && ($_SERVER['HTTPS'])) {
@@ -88,13 +122,13 @@ if(count($pathParts) == 2 && $pathParts[0] == '') {
}
$url .= $_SERVER['SERVER_NAME'];
$url .= substr($_SERVER['SCRIPT_NAME'], 0, -strlen('apps/remoteStorage/compat.php'));
- die('You are '.($currUser?'logged in as '.$currUser.' instead of '.$ownCloudUser:'not logged in').'. Please '
- .'<input type="submit" onclick="'
- ."window.open('$url','Close me!','height=600,width=300');"
- .'" value="log in">'
- .', close the pop-up, and '
- .'<form method="POST"><input name="allow" type="submit" value="Click here"></form>');
+ if($currUser) {
+ die('You are logged in as '.$currUser.' instead of '.$ownCloudUser);
+ } else {
+ header('Location: /?redirect_url='.urlencode('/apps/remoteStorage/auth.php'.$_SERVER['PATH_INFO'].'?'.$_SERVER['QUERY_STRING']));
+ }
}
} else {
- die('please use auth.php/username?params. '.var_export($pathParts, true));
+ //die('please use auth.php/username?params. '.var_export($pathParts, true));
+ die('please use auth.php/username?params.');
}
diff --git a/apps/remoteStorage/lib_remoteStorage.php b/apps/remoteStorage/lib_remoteStorage.php
index 4f19310904e..6e6a19c739f 100644
--- a/apps/remoteStorage/lib_remoteStorage.php
+++ b/apps/remoteStorage/lib_remoteStorage.php
@@ -2,11 +2,13 @@
class OC_remoteStorage {
public static function getValidTokens($ownCloudUser, $category) {
- $query=OC_DB::prepare("SELECT token,appUrl FROM *PREFIX*authtoken WHERE user=? AND category=? LIMIT 100");
- $result=$query->execute(array($ownCloudUser,$category));
+ $query=OC_DB::prepare("SELECT token,appUrl,category FROM *PREFIX*authtoken WHERE user=? LIMIT 100");
+ $result=$query->execute(array($ownCloudUser));
$ret = array();
while($row=$result->fetchRow()){
- $ret[$row['token']]=true;
+ if(in_array($category, explode(',', $row['category']))) {
+ $ret[$row['token']]=true;
+ }
}
return $ret;
}
@@ -18,8 +20,8 @@ class OC_remoteStorage {
$ret = array();
while($row=$result->fetchRow()){
$ret[$row['token']] = array(
- 'appUrl' => $row['appurl'],
- 'category' => $row['category'],
+ 'appUrl' => $row['appUrl'],
+ 'categories' => $row['category'],
);
}
return $ret;
@@ -29,22 +31,25 @@ class OC_remoteStorage {
$user=OC_User::getUser();
$query=OC_DB::prepare("DELETE FROM *PREFIX*authtoken WHERE token=? AND user=?");
$result=$query->execute(array($token,$user));
+ return 'unknown';//how can we see if any rows were affected?
}
- private static function addToken($token, $appUrl, $category){
+ private static function addToken($token, $appUrl, $categories){
$user=OC_User::getUser();
$query=OC_DB::prepare("INSERT INTO *PREFIX*authtoken (`token`,`appUrl`,`user`,`category`) VALUES(?,?,?,?)");
- $result=$query->execute(array($token,$appUrl,$user,$category));
+ $result=$query->execute(array($token,$appUrl,$user,$categories));
}
- public static function createCategory($appUrl, $category) {
+ public static function createCategories($appUrl, $categories) {
$token=uniqid();
- self::addToken($token, $appUrl, $category);
- //TODO: input checking on $category
OC_Util::setupFS(OC_User::getUser());
- $scopePathParts = array('remoteStorage', $category);
- for($i=0;$i<=count($scopePathParts);$i++){
- $thisPath = '/'.implode('/', array_slice($scopePathParts, 0, $i));
- if(!OC_Filesystem::file_exists($thisPath)) {
- OC_Filesystem::mkdir($thisPath);
+ self::addToken($token, $appUrl, $categories);
+ foreach(explode(',', $categories) as $category) {
+ //TODO: input checking on $category
+ $scopePathParts = array('remoteStorage', $category);
+ for($i=0;$i<=count($scopePathParts);$i++){
+ $thisPath = '/'.implode('/', array_slice($scopePathParts, 0, $i));
+ if(!OC_Filesystem::file_exists($thisPath)) {
+ OC_Filesystem::mkdir($thisPath);
+ }
}
}
return base64_encode('remoteStorage:'.$token);
diff --git a/apps/remoteStorage/oauth_ro_auth.php b/apps/remoteStorage/oauth_ro_auth.php
index 5403fbe20c9..085a5469920 100644
--- a/apps/remoteStorage/oauth_ro_auth.php
+++ b/apps/remoteStorage/oauth_ro_auth.php
@@ -16,9 +16,10 @@
class OC_Connector_Sabre_Auth_ro_oauth extends Sabre_DAV_Auth_Backend_AbstractBasic {
private $validTokens;
-
- public function __construct($validTokensArg) {
+ private $category;
+ public function __construct($validTokensArg, $categoryArg) {
$this->validTokens = $validTokensArg;
+ $this->category = $categoryArg;
}
/**
@@ -31,29 +32,31 @@ class OC_Connector_Sabre_Auth_ro_oauth extends Sabre_DAV_Auth_Backend_AbstractBa
*/
protected function validateUserPass($username, $password){
//always give read-only:
- if(in_array($_SERVER['REQUEST_METHOD'], array('GET', 'HEAD', 'OPTIONS'))) {
- OC_Util::setUpFS();
- return true;
- } else if(isset($this->validTokens[$password]) && $this->validTokens[$password] == $username) {
+ if(($_SERVER['REQUEST_METHOD'] == 'OPTIONS')
+ || (isset($this->validTokens[$password]))
+ || (($_SERVER['REQUEST_METHOD'] == 'GET') && ($this->category == 'public'))
+ ) {
OC_Util::setUpFS();
return true;
} else {
-var_export($_SERVER);
-var_export($this->validTokens);
-die('not getting in with "'.$username.'"/"'.$password.'"!');
+ //var_export($_SERVER);
+ //var_export($this->validTokens);
+ //die('not getting in with "'.$username.'"/"'.$password.'"!');
return false;
}
}
//overwriting this to make it not automatically fail if no auth header is found:
public function authenticate(Sabre_DAV_Server $server,$realm) {
- $auth = new Sabre_HTTP_BasicAuth();
+ $auth = new Sabre_HTTP_BearerAuth();
$auth->setHTTPRequest($server->httpRequest);
$auth->setHTTPResponse($server->httpResponse);
$auth->setRealm($realm);
$userpass = $auth->getUserPass();
if (!$userpass) {
- if(in_array($_SERVER['REQUEST_METHOD'], array('OPTIONS'))) {
+ if(($_SERVER['REQUEST_METHOD'] == 'OPTIONS')
+ ||(($_SERVER['REQUEST_METHOD'] == 'GET') && ($this->category == 'public'))
+ ) {
$userpass = array('', '');
} else {
$auth->requireLogin();
diff --git a/apps/remoteStorage/remoteStorage-big.png b/apps/remoteStorage/remoteStorage-big.png
new file mode 100644
index 00000000000..7c429a6a738
--- /dev/null
+++ b/apps/remoteStorage/remoteStorage-big.png
Binary files differ
diff --git a/apps/remoteStorage/remoteStorage.png b/apps/remoteStorage/remoteStorage.png
new file mode 100644
index 00000000000..6b751c09997
--- /dev/null
+++ b/apps/remoteStorage/remoteStorage.png
Binary files differ
diff --git a/apps/remoteStorage/settings.php b/apps/remoteStorage/settings.php
new file mode 100644
index 00000000000..fa85f77a535
--- /dev/null
+++ b/apps/remoteStorage/settings.php
@@ -0,0 +1,7 @@
+<?php
+
+require_once('lib_remoteStorage.php');
+$tmpl = new OC_Template( 'remoteStorage', 'settings');
+
+return $tmpl->fetchPage();
+?>
diff --git a/apps/remoteStorage/templates/settings.php b/apps/remoteStorage/templates/settings.php
new file mode 100644
index 00000000000..9b5c3b6229c
--- /dev/null
+++ b/apps/remoteStorage/templates/settings.php
@@ -0,0 +1,28 @@
+ <fieldset class="personalblock">
+ <?php
+ echo '<img src="/apps/remoteStorage/remoteStorage.png" style="width:16px"> '
+ .'<strong>'.$l->t('remoteStorage').'</strong> user address: '
+ .OC_User::getUser().'@'.$_SERVER['SERVER_NAME']
+ .' (<a href="http://unhosted.org/">more info</a>)';
+ ?>
+ <p><em>Apps that currently have access to your ownCloud:</em></p>
+ <script>
+ function revokeToken(token) {
+ var xhr = new XMLHttpRequest();
+ xhr.open('POST', '/apps/remoteStorage/ajax/revokeToken.php', true);
+ xhr.send(token);
+ }
+ </script>
+ <ul>
+ <?php
+ foreach(OC_remoteStorage::getAllTokens() as $token => $details) {
+ echo '<li onmouseover="'
+ .'document.getElementById(\'revoke_'.$token.'\').style.display=\'inline\';"'
+ .'onmouseout="document.getElementById(\'revoke_'.$token.'\').style.display=\'none\';"'
+ .'> <strong>'.$details['appUrl'].'</strong>: '.$details['categories']
+ .' <a href="#" title="Revoke" class="action" style="display:none" id="revoke_'.$token.'" onclick="'
+ .'revokeToken(\''.$token.'\');this.parentNode.style.display=\'none\';"'
+ .'><img src="/core/img/actions/delete.svg"></a></li>'."\n";
+ }
+ ?></ul>
+ </fieldset>
diff --git a/apps/user_ldap/settings.php b/apps/user_ldap/settings.php
index 1f2d8ed9af3..ad44fe95f9e 100644
--- a/apps/user_ldap/settings.php
+++ b/apps/user_ldap/settings.php
@@ -20,7 +20,7 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
-$params = array('ldap_host', 'ldap_port', 'ldap_dn', 'ldap_password', 'ldap_base', 'ldap_filter', 'ldap_display_name', 'ldap_tls', 'ldap_nocase');
+$params = array('ldap_host', 'ldap_port', 'ldap_dn', 'ldap_password', 'ldap_base', 'ldap_userlist_filter', 'ldap_login_filter', 'ldap_display_name', 'ldap_tls', 'ldap_nocase'. 'ldap_quota_def', 'ldap_quota_attr', 'ldap_email_attr');
if ($_POST) {
foreach($params as $param){
@@ -29,12 +29,12 @@ if ($_POST) {
}
elseif('ldap_tls' == $param) {
// unchecked checkboxes are not included in the post paramters
- OC_Appconfig::setValue('user_ldap', $param, 0);
+ OC_Appconfig::setValue('user_ldap', $param, 0);
}
elseif('ldap_nocase' == $param) {
OC_Appconfig::setValue('user_ldap', $param, 0);
}
-
+
}
}
diff --git a/apps/user_ldap/templates/settings.php b/apps/user_ldap/templates/settings.php
index 5bbd5d4008d..828c72cba97 100644
--- a/apps/user_ldap/templates/settings.php
+++ b/apps/user_ldap/templates/settings.php
@@ -6,15 +6,16 @@
<p><label for="ldap_dn"><?php echo $l->t('Name');?></label><input type="text" id="ldap_dn" name="ldap_dn" value="<?php echo $_['ldap_dn']; ?>" />
<label for="ldap_password"><?php echo $l->t('Password');?></label><input type="password" id="ldap_password" name="ldap_password" value="<?php echo $_['ldap_password']; ?>" />
<small><?php echo $l->t('Leave both empty for anonymous bind for search, then bind with users credentials.');?></small></p>
- <p><label for="ldap_base"><?php echo $l->t('Base');?></label><input type="text" id="ldap_base" name="ldap_base" value="<?php echo $_['ldap_base']; ?>" />
- <label for="ldap_filter"><?php echo $l->t('Filter (use %%uid placeholder)');?></label><input type="text" id="ldap_filter" name="ldap_filter" value="<?php echo $_['ldap_filter']; ?>" /></p>
+ <p><label for="ldap_base"><?php echo $l->t('Base');?></label><input type="text" id="ldap_base" name="ldap_base" value="<?php echo $_['ldap_base']; ?>" /></p>
+ <p><label for="ldap_login_filter"><?php echo $l->t('User Login Filter');?></label><input type="text" id="ldap_login_filter" name="ldap_login_filter" value="<?php echo $_['ldap_login_filter']; ?>" /><small><?php echo $l->t('use %%uid placeholder, e.g. uid=%%uid');?></small></p>
+ <p><label for="ldap_userlist_filter"><?php echo $l->t('User List Filter');?></label><input type="text" id="ldap_userlist_filter" name="ldap_userlist_filter" value="<?php echo $_['ldap_userlist_filter']; ?>" /><small><?php echo $l->t('without any placeholder, e.g. "objectClass=person".');?> </p>
<p><label for="ldap_display_name"><?php echo $l->t('Display Name Field');?></label><input type="text" id="ldap_display_name" name="ldap_display_name" value="<?php echo $_['ldap_display_name']; ?>" />
<small><?php echo $l->t('Currently the display name field needs to be the same you matched %%uid against in the filter above, because ownCloud doesn\'t distinguish between user id and user name.');?></small></p>
<p><input type="checkbox" id="ldap_tls" name="ldap_tls" value="1"<?php if ($_['ldap_tls']) echo ' checked'; ?>><label for="ldap_tls"><?php echo $l->t('Use TLS');?></label></p>
<p><input type="checkbox" id="ldap_nocase" name="ldap_nocase" value="1"<?php if ($_['ldap_nocase']) echo ' checked'; ?>><label for="ldap_nocase"><?php echo $l->t('Case insensitve LDAP server (Windows)');?></label></p>
- <p><label for="ldap_quota">Quota Attribute</label><input type="text" id="ldap_quota" name="ldap_quota" value="<?php echo $_['ldap_quota']; ?>" />
+ <p><label for="ldap_quota_attr">Quota Attribute</label><input type="text" id="ldap_quota_attr" name="ldap_quota_attr" value="<?php echo $_['ldap_quota_attr']; ?>" />
<label for="ldap_quota_def">Quota Default</label><input type="text" id="ldap_quota_def" name="ldap_quota_def" value="<?php echo $_['ldap_quota_def']; ?>" />bytes</p>
- <p><label for="ldap_email">Email Attribute</label><input type="text" id="ldap_email" name="ldap_email" value="<?php echo $_['ldap_email']; ?>" /></p>
+ <p><label for="ldap_email_attr">Email Attribute</label><input type="text" id="ldap_email_attr" name="ldap_email_attr" value="<?php echo $_['ldap_email_attr']; ?>" /></p>
<input type="submit" value="Save" />
</fieldset>
</form>
diff --git a/apps/user_ldap/user_ldap.php b/apps/user_ldap/user_ldap.php
index 670d938ea95..3521a9d90cf 100644
--- a/apps/user_ldap/user_ldap.php
+++ b/apps/user_ldap/user_ldap.php
@@ -32,7 +32,8 @@ class OC_USER_LDAP extends OC_User_Backend {
protected $ldap_dn;
protected $ldap_password;
protected $ldap_base;
- protected $ldap_filter;
+ protected $ldap_login_filter;
+ protected $ldap_userlist_filter;
protected $ldap_tls;
protected $ldap_nocase;
protected $ldap_display_name;
@@ -49,7 +50,8 @@ class OC_USER_LDAP extends OC_User_Backend {
$this->ldap_dn = OC_Appconfig::getValue('user_ldap', 'ldap_dn','');
$this->ldap_password = OC_Appconfig::getValue('user_ldap', 'ldap_password','');
$this->ldap_base = OC_Appconfig::getValue('user_ldap', 'ldap_base','');
- $this->ldap_filter = OC_Appconfig::getValue('user_ldap', 'ldap_filter','');
+ $this->ldap_login_filter = OC_Appconfig::getValue('user_ldap', 'ldap_login_filter','');
+ $this->ldap_userlist_filter = OC_Appconfig::getValue('user_ldap', 'ldap_userlist_filter','objectClass=person');
$this->ldap_tls = OC_Appconfig::getValue('user_ldap', 'ldap_tls', 0);
$this->ldap_nocase = OC_Appconfig::getValue('user_ldap', 'ldap_nocase', 0);
$this->ldap_display_name = OC_Appconfig::getValue('user_ldap', 'ldap_display_name', OC_USER_BACKEND_LDAP_DEFAULT_DISPLAY_NAME);
@@ -61,7 +63,7 @@ class OC_USER_LDAP extends OC_User_Backend {
&& !empty($this->ldap_port)
&& ((!empty($this->ldap_dn) && !empty($this->ldap_password)) || (empty($this->ldap_dn) && empty($this->ldap_password)))
&& !empty($this->ldap_base)
- && !empty($this->ldap_filter)
+ && !empty($this->ldap_login_filter)
&& !empty($this->ldap_display_name)
)
{
@@ -79,9 +81,13 @@ class OC_USER_LDAP extends OC_User_Backend {
if( !$this->ldap_dc )
return false;
- $quota = $this->ldap_dc[$this->ldap_quota_attr][0];
+ if(!empty($this->ldap_quota_attr)) {
+ $quota = $this->ldap_dc[strtolower($this->ldap_quota_attr)][0];
+ } else {
+ $quota = false;
+ }
$quota = $quota != -1 ? $quota : $this->ldap_quota_def;
- OC_Preferences::setValue($uid, 'files', 'quota', $quota);
+ OC_Preferences::setValue($uid, 'files', 'quota', OC_Helper::computerFileSize($quota));
}
private function setEmail( $uid ) {
@@ -127,7 +133,7 @@ class OC_USER_LDAP extends OC_User_Backend {
return false;
// get dn
- $filter = str_replace('%uid', $uid, $this->ldap_filter);
+ $filter = str_replace('%uid', $uid, $this->ldap_login_filter);
$sr = ldap_search( $this->getDs(), $this->ldap_base, $filter );
$entries = ldap_get_entries( $this->getDs(), $sr );
@@ -152,7 +158,7 @@ class OC_USER_LDAP extends OC_User_Backend {
return false;
}
- if(!empty($this->ldap_quota) && !empty($this->ldap_quota_def)) {
+ if(!empty($this->ldap_quota_attr) || !empty($this->ldap_quota_def)) {
$this->setQuota($uid);
}
@@ -161,7 +167,7 @@ class OC_USER_LDAP extends OC_User_Backend {
}
if($this->ldap_nocase) {
- $filter = str_replace('%uid', $uid, $this->ldap_filter);
+ $filter = str_replace('%uid', $uid, $this->ldap_login_filter);
$sr = ldap_search( $this->getDs(), $this->ldap_base, $filter );
$entries = ldap_get_entries( $this->getDs(), $sr );
if( $entries['count'] == 1 ) {
@@ -187,7 +193,7 @@ class OC_USER_LDAP extends OC_User_Backend {
if(!$this->configured){
return false;
}
- $dn = $this->getDn($uid);
+ $dn = $this->getDc($uid);
return !empty($dn);
}
@@ -202,8 +208,7 @@ class OC_USER_LDAP extends OC_User_Backend {
return false;
// get users
- $filter = 'objectClass=person';
- $sr = ldap_search( $this->getDs(), $this->ldap_base, $filter );
+ $sr = ldap_search( $this->getDs(), $this->ldap_base, $this->ldap_userlist_filter );
$entries = ldap_get_entries( $this->getDs(), $sr );
if( $entries['count'] == 0 )
return false;
diff --git a/apps/user_webfinger/appinfo/info.xml b/apps/user_webfinger/appinfo/info.xml
index a4071dae172..55cf2cf2201 100644
--- a/apps/user_webfinger/appinfo/info.xml
+++ b/apps/user_webfinger/appinfo/info.xml
@@ -3,8 +3,8 @@
<id>user_webfinger</id>
<name>Webfinger</name>
<description>Provide WebFinger for all users so they get a user address like user@owncloudinstance which can be used for unhosted applications. If you don't run ownCloud in the root of your domain, for instance if you run it on example.com/owncloud/, then make sure you link example.com/.well-known/ to example.com/owncloud/apps/user_webfinger/ - by running something like "ln -s /var/www/owncloud/apps/user_webfinger /var/www/.well-known". Only enable this app if you run this ownCloud installation on a public web address, not if you run it on an intranet or on localhost.</description>
- <version>0.1</version>
- <licence>AGPL</licence>
+ <version>0.2</version>
+ <licence>AGPL or MIT</licence>
<author>Michiel de Jong</author>
<require>2</require>
</info>
diff --git a/apps/user_webfinger/host-meta.php b/apps/user_webfinger/host-meta.php
index ceb15f22da4..ac577cf9a0c 100644
--- a/apps/user_webfinger/host-meta.php
+++ b/apps/user_webfinger/host-meta.php
@@ -4,13 +4,13 @@ if($_SERVER['SCRIPT_NAME'] == '/.well-known/host-meta.php') {
} else {
header('Please-first: activate');
}
-header("Content-Type: application/xml+xrd");
+header("Content-Type: application/xrd+xml");
echo "<";
?>
?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0" xmlns:hm="http://host-meta.net/xrd/1.0">
<hm:Host xmlns="http://host-meta.net/xrd/1.0"><?php echo $_SERVER['SERVER_NAME'] ?></hm:Host>
- <Link rel="lrdd" template="http<?php echo ($_SERVER['HTTPS']?'s':''); ?>://<?php echo $_SERVER['SERVER_NAME'] ?>/.well-known/webfinger.php?q={uri}">
+ <Link rel="lrdd" template="http<?php echo (isset($_SERVER['HTTPS'])?'s':''); ?>://<?php echo $_SERVER['SERVER_NAME'] ?>/.well-known/webfinger.php?q={uri}">
</Link>
</XRD>
diff --git a/apps/user_webfinger/webfinger.php b/apps/user_webfinger/webfinger.php
index d695a833f31..5c2a24aa070 100644
--- a/apps/user_webfinger/webfinger.php
+++ b/apps/user_webfinger/webfinger.php
@@ -4,7 +4,7 @@ if($_SERVER['SCRIPT_NAME'] == '/.well-known/webfinger.php') {
} else {
header('Please-first: activate');
}
-// header("Content-Type: application/xml+xrd");
+header("Content-Type: application/xrd+xml");
// calculate the documentroot
// modified version of the one in lib/base.php that takes the .well-known symlink into account
@@ -22,7 +22,7 @@ if($_GET['q']) {
if(substr($userName, 0, 5) == 'acct:') {
$userName = substr($userName, 5);
}
-if($_SERVER['HTTPS']) {
+if(isset($_SERVER['HTTPS'])) {
$baseAddress = 'https://'.$_SERVER['SERVER_NAME'].'/apps/remoteStorage/';
} else {
$baseAddress = 'http://'.$_SERVER['SERVER_NAME'].'/apps/remoteStorage/';
diff --git a/core/ajax/appconfig.php b/core/ajax/appconfig.php
new file mode 100644
index 00000000000..50984ac32b9
--- /dev/null
+++ b/core/ajax/appconfig.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Copyright (c) 2011, Robin Appelman <icewind1991@gmail.com>
+ * This file is licensed under the Affero General Public License version 3 or later.
+ * See the COPYING-README file.
+ */
+
+require_once ("../../lib/base.php");
+OC_JSON::checkLoggedIn();
+$action=isset($_POST['action'])?$_POST['action']:$_GET['action'];
+$result=false;
+switch($action){
+ case 'getValue':
+ $result=OC_Appconfig::getValue($_GET['app'],$_GET['key'],$_GET['default']);
+ break;
+ case 'setValue':
+ $result=OC_Appconfig::setValue($_POST['app'],$_POST['key'],$_POST['value']);
+ break;
+ case 'getApps':
+ $result=OC_Appconfig::getApps();
+ break;
+ case 'getKeys':
+ $result=OC_Appconfig::getKeys($_GET['app']);
+ break;
+ case 'hasKey':
+ $result=OC_Appconfig::hasKey($_GET['app'],$_GET['key']);
+ break;
+ case 'deleteKey':
+ $result=OC_Appconfig::deleteKey($_POST['app'],$_POST['key']);
+ break;
+ case 'deleteApp':
+ $result=OC_Appconfig::deleteApp($_POST['app']);
+ break;
+}
+OC_JSON::success(array('data'=>$result));
diff --git a/core/ajax/vcategories/add.php b/core/ajax/vcategories/add.php
new file mode 100644
index 00000000000..a58489228d8
--- /dev/null
+++ b/core/ajax/vcategories/add.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+function bailOut($msg) {
+ OC_JSON::error(array('data' => array('message' => $msg)));
+ OC_Log::write('core','ajax/vcategories/add.php: '.$msg, OC_Log::DEBUG);
+ exit();
+}
+function debug($msg) {
+ OC_Log::write('core','ajax/vcategories/add.php: '.$msg, OC_Log::DEBUG);
+}
+
+require_once('../../../lib/base.php');
+OC_JSON::checkLoggedIn();
+$category = isset($_GET['category'])?strip_tags($_GET['category']):null;
+$app = isset($_GET['app'])?$_GET['app']:null;
+
+if(is_null($app)) {
+ bailOut(OC_Contacts_App::$l10n->t('Application name not provided.'));
+}
+
+OC_JSON::checkAppEnabled($app);
+
+if(is_null($category)) {
+ bailOut(OC_Contacts_App::$l10n->t('No category to add?'));
+}
+
+debug(print_r($category, true));
+
+$categories = new OC_VCategories($app);
+if($categories->hasCategory($category)) {
+ bailOut(OC_Contacts_App::$l10n->t('This category already exists: '.$category));
+} else {
+ $categories->add($category, true);
+}
+
+OC_JSON::success(array('data' => array('categories'=>$categories->categories())));
+
+?>
diff --git a/core/ajax/vcategories/delete.php b/core/ajax/vcategories/delete.php
new file mode 100644
index 00000000000..602ee1d74a4
--- /dev/null
+++ b/core/ajax/vcategories/delete.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+function bailOut($msg) {
+ OC_JSON::error(array('data' => array('message' => $msg)));
+ OC_Log::write('core','ajax/vcategories/delete.php: '.$msg, OC_Log::DEBUG);
+ exit();
+}
+function debug($msg) {
+ OC_Log::write('core','ajax/vcategories/delete.php: '.$msg, OC_Log::DEBUG);
+}
+
+require_once('../../../lib/base.php');
+OC_JSON::checkLoggedIn();
+$app = isset($_GET['app'])?$_GET['app']:null;
+$categories = isset($_POST['categories'])?$_POST['categories']:null;
+if(is_null($app)) {
+ bailOut(OC_Contacts_App::$l10n->t('Application name not provided.'));
+}
+
+OC_JSON::checkAppEnabled($app);
+
+debug('The application "'.$app.'" uses the default file. OC_VObjects will not be updated.');
+
+if(is_null($categories)) {
+ bailOut('No categories selected for deletion.');
+}
+
+$vcategories = new OC_VCategories($app);
+$vcategories->delete($categories);
+OC_JSON::success(array('data' => array('categories'=>$vcategories->categories())));
+
+?>
diff --git a/core/ajax/vcategories/edit.php b/core/ajax/vcategories/edit.php
new file mode 100644
index 00000000000..252b3d3454c
--- /dev/null
+++ b/core/ajax/vcategories/edit.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+function bailOut($msg) {
+ OC_JSON::error(array('data' => array('message' => $msg)));
+ OC_Log::write('core','ajax/vcategories/edit.php: '.$msg, OC_Log::DEBUG);
+ exit();
+}
+function debug($msg) {
+ OC_Log::write('core','ajax/vcategories/edit.php: '.$msg, OC_Log::DEBUG);
+}
+
+require_once('../../../lib/base.php');
+OC_JSON::checkLoggedIn();
+$app = isset($_GET['app'])?$_GET['app']:null;
+
+if(is_null($app)) {
+ bailOut('Application name not provided.');
+}
+
+OC_JSON::checkAppEnabled($app);
+$tmpl = new OC_TEMPLATE("core", "edit_categories_dialog");
+
+$vcategories = new OC_VCategories($app);
+$categories = $vcategories->categories();
+debug(print_r($categories, true));
+$tmpl->assign('categories',$categories);
+$tmpl->printpage();
+
+?>
diff --git a/core/css/oc-vcategories.css b/core/css/oc-vcategories.css
new file mode 100644
index 00000000000..68ff832bb06
--- /dev/null
+++ b/core/css/oc-vcategories.css
@@ -0,0 +1,7 @@
+#categoryform .scrollarea { position: absolute; left: 10px; top: 10px; right: 10px; bottom: 50px; overflow: auto; border:1px solid #ddd; background: #f8f8f8; }
+#categoryform .bottombuttons { position: absolute; bottom: 10px;}
+#categoryform .bottombuttons * { float: left;}
+/*#categorylist { border:1px solid #ddd;}*/
+#categorylist li { background:#f8f8f8; padding:.3em .8em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; -webkit-transition:background-color 500ms; -moz-transition:background-color 500ms; -o-transition:background-color 500ms; transition:background-color 500ms; }
+#categorylist li:hover, li:active { background:#eee; }
+#category_addinput { width: 10em; }
diff --git a/core/css/styles.css b/core/css/styles.css
index b14c8fb9caf..f5a181c4529 100644
--- a/core/css/styles.css
+++ b/core/css/styles.css
@@ -60,7 +60,7 @@ input[type="submit"].highlight{ background:#ffc100; border:1px solid #db0; text-
#leftcontent, .leftcontent { position:fixed; overflow: auto; top:6.4em; width:20em; background:#f8f8f8; border-right:1px solid #ddd; }
#leftcontent li, .leftcontent li { background:#f8f8f8; padding:.3em .8em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; -webkit-transition:background-color 500ms; -moz-transition:background-color 500ms; -o-transition:background-color 500ms; transition:background-color 500ms; }
#leftcontent li:hover, #leftcontent li:active, #leftcontent li.active, .leftcontent li:hover, .leftcontent li:active, .leftcontent li.active { background:#eee; }
-#rightcontent, .rightcontent { position:fixed; top: 6.4em; left: 32.5em; }
+#rightcontent, .rightcontent { position:fixed; top: 6.4em; left: 32.5em; overflow: auto }
/* LOG IN & INSTALLATION ------------------------------------------------------------ */
@@ -128,4 +128,6 @@ div.jp-play-bar, div.jp-seek-bar { padding:0; }
li.error { width:640px; margin:4em auto; padding:1em 1em 1em 4em; background:#ffe .8em .8em no-repeat; color: #FF3B3B; border:1px solid #ccc; -moz-border-radius:10px; -webkit-border-radius:10px; border-radius:10px; }
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { overflow: hidden; text-overflow: ellipsis; }
.hint { background-image: url('/core/img/actions/info.png'); background-repeat:no-repeat; color: #777777; padding-left: 25px; background-position: 0 0.3em;}
-.separator { display: inline; border-left: 1px solid #d3d3d3; border-right: 1px solid #fff; height: 10px; width:0px; margin: 4px; } \ No newline at end of file
+.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 }
diff --git a/core/js/config.js b/core/js/config.js
new file mode 100644
index 00000000000..500fe072a64
--- /dev/null
+++ b/core/js/config.js
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2011, Robin Appelman <icewind1991@gmail.com>
+ * This file is licensed under the Affero General Public License version 3 or later.
+ * See the COPYING-README file.
+ */
+
+OC.AppConfig={
+ url:OC.filePath('core','ajax','appconfig.php'),
+ getCall:function(action,data,callback){
+ data.action=action;
+ $.getJSON(OC.AppConfig.url,data,function(result){
+ if(result.status='success'){
+ if(callback){
+ callback(result.data);
+ }
+ }
+ });
+ },
+ postCall:function(action,data,callback){
+ data.action=action;
+ $.post(OC.AppConfig.url,data,function(result){
+ if(result.status='success'){
+ if(callback){
+ callback(result.data);
+ }
+ }
+ },'json');
+ },
+ getValue:function(app,key,defaultValue,callback){
+ if(typeof defaultValue=='function'){
+ callback=defaultValue;
+ defaultValue=null;
+ }
+ OC.AppConfig.getCall('getValue',{app:app,key:key,default:defaultValue},callback);
+ },
+ setValue:function(app,key,value){
+ OC.AppConfig.postCall('setValue',{app:app,key:key,value:value});
+ },
+ getApps:function(callback){
+ OC.AppConfig.getCall('getApps',{},callback);
+ },
+ getKeys:function(app,callback){
+ OC.AppConfig.getCall('getKeys',{app:app},callback);
+ },
+ hasKey:function(app,key,callback){
+ OC.AppConfig.getCall('hasKey',{app:app,key:key},callback);
+ },
+ deleteKey:function(app,key){
+ OC.AppConfig.postCall('deleteKey',{app:app,key:key});
+ },
+ deleteApp:function(app){
+ OC.AppConfig.postCall('deleteApp',{app:app});
+ },
+}
+//TODO OC.Preferences
diff --git a/core/js/js.js b/core/js/js.js
index 6da9c29e693..df1b5c6ce76 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -125,7 +125,8 @@ OC={
OC.search.showResults(results);
});
}
- }
+ },
+ dialogs:OCdialogs
};
OC.search.customResults={};
OC.search.currentResult=-1;
@@ -252,16 +253,22 @@ function replaceSVG(){
$('.svg').each(function(index,element){
element=$(element);
var background=element.css('background-image');
- if(background && background!='none'){
- background=background.substr(0,background.length-4)+'png)';
- element.css('background-image',background);
+ if(background){
+ var i=background.lastIndexOf('.svg');
+ if(i>=0){
+ background=background.substr(0,i)+'.png'+background.substr(i+4);
+ element.css('background-image',background);
+ }
}
element.find('*').each(function(index,element) {
element=$(element);
var background=element.css('background-image');
- if(background && background!='none'){
- background=background.substr(0,background.length-4)+'png)';
- element.css('background-image',background);
+ if(background){
+ var i=background.lastIndexOf('.svg');
+ if(i>=0){
+ background=background.substr(0,i)+'.png'+background.substr(i+4);
+ element.css('background-image',background);
+ }
}
});
});
@@ -444,4 +451,33 @@ $.fn.filterAttr = function(attr_name, attr_value) {
return this.filter(function() { return $(this).attr(attr_name) === attr_value; });
};
+function humanFileSize(size) {
+ humanList = ['B', 'kB', 'MB', 'GB', 'TB'];
+ // Calculate Log with base 1024: size = 1024 ** order
+ order = Math.floor(Math.log(size) / Math.log(1024));
+ // Stay in range of the byte sizes that are defined
+ order = Math.min(humanList.length - 1, order);
+ readableFormat = humanList[order];
+ relativeSize = (size / Math.pow(1024, order)).toFixed(1);
+ if(relativeSize.substr(relativeSize.length-2,2)=='.0'){
+ relativeSize=relativeSize.substr(0,relativeSize.length-2);
+ }
+ return relativeSize + ' ' + readableFormat;
+}
+
+function simpleFileSize(bytes) {
+ mbytes = Math.round(bytes/(1024*1024/10))/10;
+ if(bytes == 0) { return '0'; }
+ else if(mbytes < 0.1) { return '< 0.1'; }
+ else if(mbytes > 1000) { return '> 1000'; }
+ else { return mbytes.toFixed(1); }
+}
+function formatDate(date){
+ if(typeof date=='number'){
+ date=new Date(date);
+ }
+ var monthNames = [ t('files','January'), t('files','February'), t('files','March'), t('files','April'), t('files','May'), t('files','June'),
+ t('files','July'), t('files','August'), t('files','September'), t('files','October'), t('files','November'), t('files','December') ];
+ return monthNames[date.getMonth()]+' '+date.getDate()+', '+date.getFullYear()+', '+((date.getHours()<10)?'0':'')+date.getHours()+':'+date.getMinutes();
+}
diff --git a/core/js/multiselect.js b/core/js/multiselect.js
index 96fc09a0759..541dddf0f70 100644
--- a/core/js/multiselect.js
+++ b/core/js/multiselect.js
@@ -12,6 +12,11 @@
'minWidth': 'default;',
};
$.extend(settings,options);
+ $.each(this.children(),function(i,option){
+ if($(option).attr('selected') && settings.checked.indexOf($(option).val())==-1){
+ settings.checked.push($(option).val());
+ }
+ });
var button=$('<div class="multiselect button"><span>'+settings.title+'</span><span>â–¾</span></div>');
var span=$('<span/>');
span.append(button);
@@ -46,9 +51,11 @@
});
button.addClass('active');
event.stopPropagation();
- var options=$(this).parent().next().children().map(function(){return $(this).val();});
+ var options=$(this).parent().next().children();
var list=$('<ul class="multiselectoptions"/>').hide().appendTo($(this).parent());
- function createItem(item,checked){
+ function createItem(element,checked){
+ element=$(element);
+ var item=element.val();
var id='ms'+multiSelectId+'-option-'+item;
var input=$('<input id="'+id+'" type="checkbox"/>');
var label=$('<label for="'+id+'">'+item+'</label>');
@@ -61,6 +68,7 @@
input.change(function(){
var groupname=$(this).next().text();
if($(this).is(':checked')){
+ element.attr('selected','selected');
if(settings.oncheck){
if(settings.oncheck(groupname)===false){
$(this).attr('checked', false);
@@ -70,6 +78,7 @@
settings.checked.push(groupname);
}else{
var index=settings.checked.indexOf(groupname);
+ element.attr('selected',null);
if(settings.onuncheck){
if(settings.onuncheck(groupname)===false){
$(this).attr('checked',true);
@@ -119,11 +128,11 @@
var li=$(this).parent();
$(this).remove();
li.text('+ '+settings.createText);
- li.before(createItem($(this).val()));
+ li.before(createItem(this));
+ var select=button.parent().next();
+ select.append($('<option selected="selected" value="'+$(this).val()+'">'+$(this).val()+'</option>'));
li.prev().children('input').trigger('click');
button.parent().data('preventHide',false);
- var select=button.parent().next();
- select.append($('<option value="'+$(this).val()+'">'+$(this).val()+'</option>'));
if(settings.createCallback){
settings.createCallback();
}
diff --git a/core/js/oc-dialogs.js b/core/js/oc-dialogs.js
new file mode 100644
index 00000000000..9ce2bae1642
--- /dev/null
+++ b/core/js/oc-dialogs.js
@@ -0,0 +1,149 @@
+/**
+ * ownCloud
+ *
+ * @author Bartek Przybylski
+ * @copyright 2012 Bartek Przybylski bart.p.pl@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/>.
+ *
+ * todo(bartek): add select option in form
+ */
+
+/**
+ * this class ease usage of jquery dialogs
+ */
+OCdialogs = {
+ /**
+ * displays alert dialog
+ * @param text content of dialog
+ * @param title dialog title
+ * @param callback which will be triggered when user press OK
+ */
+ alert:function(text, title, callback) {
+ var content = '<p><span class="ui-icon ui-icon-alert"></span>'+text+'</p>';
+ OCdialogs.message(content, title, OCdialogs.ALERT_DIALOG, OCdialogs.OK_BUTTON, callback);
+ },
+ /**
+ * displays info dialog
+ * @param text content of dialog
+ * @param title dialog title
+ * @param callback which will be triggered when user press OK
+ */
+ info:function(text, title, callback) {
+ var content = '<p><span class="ui-icon ui-icon-info"></span>'+text+'</p>';
+ OCdialogs.message(content, title, OCdialogs.ALERT_DIALOG, OCdialogs.OK_BUTTON, callback);
+ },
+ /**
+ * displays confirmation dialog
+ * @param text content of dialog
+ * @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) {
+ 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);
+ },
+ /**
+ * prompt for user input
+ * @param text content of dialog
+ * @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) {
+ 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);
+ },
+ /**
+ * prompt user for input with custom form
+ * fields should be passed in following format: [{text:'prompt text', name:'return name', type:'input type'},...]
+ * @param fields to display
+ * @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) {
+ var content = '<table>';
+ for (var a in fields) {
+ content += '<tr><td>'+fields[a].text+'</td><td>';
+ var type=fields[a].type;
+ if (type == 'text' || type == 'checkbox' || type == 'password')
+ content += '<input type="'+type+'" name="'+fields[a].name+'">';
+ content += "</td></tr>"
+ }
+ content += "</table>";
+ OCdialogs.message(content, title, OCdialogs.FORM_DIALOG, OCdialogs.OK_CANCEL_BUTTONS, callback);
+ },
+ message:function(content, title, dialog_type, buttons, callback) {
+ var c_name = 'oc-dialog-'+OCdialogs.dialogs_counter+'-content';
+ var c_id = '#'+c_name;
+ var d = '<div id="'+c_name+'" title="'+title+'">'+content+'</div>';
+ $('body').append(d);
+ var b = [];
+ switch (buttons) {
+ case OCdialogs.YES_NO_BUTTONS:
+ b[1] = {text: t('dialogs', 'No'), click: function(){ if (callback != undefined) callback(false); $(c_id).dialog('close'); }};
+ b[0] = {text: t('dialogs', 'Yes'), click: function(){ if (callback != undefined) callback(true); $(c_id).dialog('close');}};
+ break;
+ case OCdialogs.OK_CANCEL_BUTTONS:
+ b[1] = {text: t('dialogs', 'Cancel'), click: function(){$(c_id).dialog('close'); }};
+ case OCdialogs.OK_BUTTON: // fallthrough
+ var f;
+ switch(dialog_type) {
+ case OCdialogs.ALERT_DIALOG:
+ f = function(){$(c_id).dialog('close'); };
+ break;
+ case OCdialogs.PROMPT_DIALOG:
+ f = function(){OCdialogs.prompt_ok_handler(callback, c_id)};
+ break;
+ case OCdialogs.FORM_DIALOG:
+ f = function(){OCdialogs.form_ok_handler(callback, c_id)};
+ break;
+ }
+ b[0] = {text: t('dialogs', 'Ok'), click: f};
+ break;
+ }
+ $(c_id).dialog({width: 4*$(document).width()/9, height: $(d).height() + 150, modal: false, buttons: b});
+ OCdialogs.dialogs_counter++;
+ },
+ // dialogs buttons types
+ YES_NO_BUTTONS: 70,
+ OK_BUTTONS: 71,
+ OK_CANCEL_BUTTONS: 72,
+ // dialogs types
+ ALERT_DIALOG: 80,
+ INFO_DIALOG: 81,
+ PROMPT_DIALOG: 82,
+ FORM_DIALOG: 83,
+ dialogs_counter: 0,
+ determineValue: function(element) {
+ switch ($(element).attr('type')) {
+ case 'checkbox': return $(element).attr('checked') != undefined;
+ }
+ return $(element).val();
+ },
+ prompt_ok_handler: function(callback, c_id) { $(c_id).dialog('close'); if (callback != undefined) callback($(c_id + " input#oc-dialog-prompt-input").val()); },
+ form_ok_handler: function(callback, c_id) {
+ if (callback != undefined) {
+ var r = [];
+ var c = 0;
+ $(c_id + ' input').each(function(i, elem) {
+ r[c] = {name: $(elem).attr('name'), value: OCdialogs.determineValue(elem)};
+ c++;
+ });
+ $(c_id).dialog('close');
+ callback(r);
+ } else {
+ $(c_id).dialog('close');
+ }
+ }
+};
diff --git a/core/js/oc-vcategories.js b/core/js/oc-vcategories.js
new file mode 100644
index 00000000000..a6dcccf88e0
--- /dev/null
+++ b/core/js/oc-vcategories.js
@@ -0,0 +1,115 @@
+OCCategories={
+ edit:function(){
+ console.log('OCCategories.edit');
+ if(OCCategories.app == undefined) {
+ OC.dialogs.alert('OCCategories.app is not set!');
+ return;
+ }
+ $('body').append('<div id="category_dialog"></div>');
+ $('#category_dialog').load(OC.filePath('core', 'ajax', 'vcategories/edit.php')+'?app='+OCCategories.app, function(response){
+ try {
+ var jsondata = jQuery.parseJSON(response);
+ if(response.status == 'error'){
+ OC.dialogs.alert(response.data.message, 'Error');
+ return;
+ }
+ } catch(e) {
+ $('#edit_categories_dialog').dialog({
+ modal: true,
+ height: 350, minHeight:200, width: 250, minWidth: 200,
+ buttons: {
+ 'Delete':function() {
+ OCCategories.delete();
+ },
+ 'Rescan':function() {
+ OCCategories.rescan();
+ }
+ },
+ close : function(event, ui) {
+ $(this).dialog('destroy').remove();
+ $('#category_dialog').remove();
+ },
+ open : function(event, ui) {
+ $('#category_addinput').live('input',function(){
+ if($(this).val().length > 0) {
+ $('#category_addbutton').removeAttr('disabled');
+ }
+ });
+ $('#categoryform').submit(function() {
+ OCCategories.add($('#category_addinput').val());
+ $('#category_addinput').val('');
+ $('#category_addbutton').attr('disabled', 'disabled');
+ return false;
+ });
+ $('#category_addbutton').live('click',function(e){
+ e.preventDefault();
+ if($('#category_addinput').val().length > 0) {
+ OCCategories.add($('#category_addinput').val());
+ $('#category_addinput').val('');
+ }
+ });
+ }
+ });
+ }
+ });
+ },
+ delete:function(){
+ var categories = $('#categorylist').find('input[type="checkbox"]').serialize();
+ categories += '&app=' + OCCategories.app;
+ console.log('OCCategories.delete: ' + categories);
+ $.post(OC.filePath(OCCategories.app, 'ajax', 'categories/delete.php'),categories,function(jsondata, status, xhr){
+ if (status == 'error' && xhr.status == 404) {
+ $.post(OC.filePath('core', 'ajax', 'vcategories/delete.php'),categories,function(jsondata, status, xhr){
+ if(jsondata.status == 'success'){
+ OCCategories._update(jsondata.data.categories);
+ } else {
+ OC.dialogs.alert(jsondata.data.message, 'Error');
+ }
+ });
+ return;
+ }
+ if(jsondata.status == 'success'){
+ OCCategories._update(jsondata.data.categories);
+ } else {
+ OC.dialogs.alert(jsondata.data.message, 'Error');
+ }
+ });
+ },
+ add:function(category){
+ console.log('OCCategories.add ' + category);
+ $.getJSON(OC.filePath('core', 'ajax', 'vcategories/add.php'),{'category':category, 'app':OCCategories.app},function(jsondata){
+ if(jsondata.status == 'success'){
+ OCCategories._update(jsondata.data.categories);
+ } else {
+ OC.dialogs.alert(jsondata.data.message, 'Error');
+ }
+ });
+ return false;
+ },
+ rescan:function(){
+ console.log('Categories.rescan');
+ $.getJSON(OC.filePath(OCCategories.app, 'ajax', 'categories/rescan.php'),{},function(jsondata, status, xhr){
+ if (status == 'error' && xhr.status == 404) {
+ OC.dialogs.alert('The required file ' + OC.filePath(Categories.app, 'ajax', 'categories/rescan.php') + ' is not installed!', 'Error');
+ return;
+ }
+ if(jsondata.status == 'success'){
+ OCCategories._update(jsondata.data.categories);
+ } else {
+ OC.dialogs.alert(jsondata.data.message, 'Error');
+ }
+ });
+ },
+ _update:function(categories){
+ var categorylist = $('#categorylist');
+ categorylist.find('li').remove();
+ for(var category in categories) {
+ var item = '<li><input type="checkbox" name="categories" value="' + categories[category] + '" />' + categories[category] + '</li>';
+ $(item).appendTo(categorylist);
+ }
+ if(OCCategories.changed != undefined) {
+ OCCategories.changed(categories);
+ }
+ }
+}
+
diff --git a/core/js/oc-vcategories.txt b/core/js/oc-vcategories.txt
new file mode 100644
index 00000000000..76d4245f5eb
--- /dev/null
+++ b/core/js/oc-vcategories.txt
@@ -0,0 +1,28 @@
+Using OCCategories
+
+This 'class' is meant for any apps that uses OC_VObjects with the CATEGORIES field e.g.
+Contacts and Calendar. It provides an editor UI for adding/deleting and rescanning categories
+and basic ajax functions for adding and deleting.
+To use the mass updating of OC_VObjects that /lib/vcategories.php provides, the app must implement
+its own ajax functions in /apps/$(APP)/ajax/categories/rescan.php and /apps/$(APP)/ajax/categories/delete.php
+See examples in /apps/contacts/ajax/categories and the inline docs in /lib/vcategories.php.
+
+In your app make sure you load the script and stylesheet:
+
+OC_Util::addScript('','oc-vcategories');
+OC_Util::addStyle('','oc-vcategories');
+
+Set the app specific values in your javascript file. This is what I've used for the Contacts app:
+
+ OCCategories.app = 'contacts';
+ OCCategories.changed = Contacts.UI.Card.categoriesChanged;
+
+If OCCategories.changed point is set that function will be called each time the categories have been changed
+in the editor (add/delete/rescan) to allow the app to update the UI accordingly. The only argument to the function
+is an array of the updated categories e.g.:
+
+OCCategories.changed = function(categories) {
+ for(var category in categories) {
+ console.log(categories[category]);
+ }
+} \ No newline at end of file
diff --git a/core/templates/edit_categories_dialog.php b/core/templates/edit_categories_dialog.php
new file mode 100644
index 00000000000..8997fa586bd
--- /dev/null
+++ b/core/templates/edit_categories_dialog.php
@@ -0,0 +1,16 @@
+<?php
+$categories = isset($_['categories'])?$_['categories']:array();
+?>
+<div id="edit_categories_dialog" title="<?php echo $l->t('Edit categories'); ?>">
+<!-- ?php print_r($types); ? -->
+ <form method="post" id="categoryform">
+ <div class="scrollarea">
+ <ul id="categorylist">
+ <?php foreach($categories as $category) { ?>
+ <li><input type="checkbox" name="categories[]" value="<?php echo $category; ?>" /><?php echo $category; ?></li>
+ <?php } ?>
+ </ul>
+ </div>
+ <div class="bottombuttons"><input type="text" id="category_addinput" name="category" /><button id="category_addbutton" disabled="disabled"><?php echo $l->t('Add'); ?></button></div>
+ </form>
+</div>
diff --git a/dav.php b/dav.php
new file mode 100644
index 00000000000..78e2711aec8
--- /dev/null
+++ b/dav.php
@@ -0,0 +1,77 @@
+<?php
+
+/**
+* ownCloud
+*
+* @author Jakob Sack
+* @copyright 2012 Jakob Sack owncloud@jakobsack.de
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* 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/>.
+*
+*/
+
+require_once('lib/base.php');
+
+// Backends we always need (auth, principal and files)
+$backends = array(
+ 'auth' => new OC_Connector_Sabre_Auth(),
+ 'principal' => new OC_Connector_Sabre_Principal()
+);
+
+// Root nodes
+$nodes = array(
+ new Sabre_CalDAV_Principal_Collection($backends['principal'])
+);
+
+// Plugins
+$plugins = array(
+ new Sabre_DAV_Auth_Plugin($backends['auth'],'ownCloud'),
+ new Sabre_DAVACL_Plugin(),
+ new Sabre_DAV_Browser_Plugin(false) // Show something in the Browser, but no upload
+);
+
+// Load the plugins etc we need for usual file sharing
+$backends['lock'] = new OC_Connector_Sabre_Locks();
+$plugins[] = new Sabre_DAV_Locks_Plugin($backends['lock']);
+// Add a RESTful user directory
+// /files/$username/
+if( OC_User::isLoggedIn()){
+ $currentuser = OC_User::getUser();
+ $files = new Sabre_DAV_SimpleCollection('files');
+ foreach( OC_User::getUsers() as $username ){
+ if( $username == $currentuser ){
+ $public = new OC_Connector_Sabre_Directory('.');
+ $files->addChild( new Sabre_DAV_SimpleCollection( $username, $public->getChildren()));
+ }
+ else{
+ $files->addChild(new Sabre_DAV_SimpleCollection( $username ));
+ }
+ }
+ $nodes[] = $files;
+}
+
+// Get the other plugins and nodes
+OC_Hook::emit( 'OC_DAV', 'initialize', array( 'backends' => &$backends, 'nodes' => &$nodes, 'plugins' => &$plugins ));
+
+// Fire up server
+$server = new Sabre_DAV_Server($nodes);
+$server->setBaseUri(OC::$WEBROOT.'/dav.php');
+
+// Load additional plugins
+foreach( $plugins as &$plugin ){
+ $server->addPlugin( $plugin );
+} unset( $plugin ); // Always do this after foreach with references!
+
+// And off we go!
+$server->exec();
diff --git a/db_structure.xml b/db_structure.xml
index 1d459b75fda..5eef44d8e84 100644
--- a/db_structure.xml
+++ b/db_structure.xml
@@ -70,7 +70,7 @@
<default>
</default>
<notnull>true</notnull>
- <length>4</length>
+ <length>8</length>
</field>
<field>
@@ -96,7 +96,7 @@
<type>integer</type>
<default></default>
<notnull>true</notnull>
- <length>4</length>
+ <length>8</length>
</field>
<field>
@@ -105,7 +105,7 @@
<default>
</default>
<notnull>true</notnull>
- <length>4</length>
+ <length>8</length>
</field>
<field>
@@ -114,7 +114,7 @@
<default>
</default>
<notnull>true</notnull>
- <length>4</length>
+ <length>8</length>
</field>
<field>
@@ -291,7 +291,7 @@
<type>integer</type>
<default></default>
<notnull>false</notnull>
- <length>4</length>
+ <length>8</length>
</field>
<field>
@@ -429,102 +429,6 @@
<table>
- <name>*dbprefix*principalgroups</name>
-
- <declaration>
-
- <field>
- <name>id</name>
- <type>integer</type>
- <default>0</default>
- <notnull>true</notnull>
- <autoincrement>1</autoincrement>
- <unsigned>true</unsigned>
- <length>4</length>
- </field>
-
- <field>
- <name>principal_id</name>
- <type>integer</type>
- <default></default>
- <notnull>true</notnull>
- <unsigned>true</unsigned>
- <length>4</length>
- </field>
-
- <field>
- <name>member_id</name>
- <type>integer</type>
- <default></default>
- <notnull>true</notnull>
- <unsigned>true</unsigned>
- <length>4</length>
- </field>
-
- <index>
- <name>principals_members_index</name>
- <unique>true</unique>
- <field>
- <name>principal_id</name>
- <sorting>ascending</sorting>
- </field>
- <field>
- <name>member_id</name>
- <sorting>ascending</sorting>
- </field>
- </index>
-
- </declaration>
-
- </table>
-
- <table>
-
- <name>*dbprefix*principals</name>
-
- <declaration>
-
- <field>
- <name>id</name>
- <type>integer</type>
- <default>0</default>
- <notnull>true</notnull>
- <autoincrement>1</autoincrement>
- <unsigned>true</unsigned>
- <length>4</length>
- </field>
-
- <field>
- <name>uri</name>
- <type>text</type>
- <default></default>
- <notnull>false</notnull>
- <length>255</length>
- </field>
-
- <field>
- <name>displayname</name>
- <type>text</type>
- <default></default>
- <notnull>false</notnull>
- <length>255</length>
- </field>
-
- <index>
- <name>uri</name>
- <unique>true</unique>
- <field>
- <name>uri</name>
- <sorting>ascending</sorting>
- </field>
- </index>
-
- </declaration>
-
- </table>
-
- <table>
-
<name>*dbprefix*properties</name>
<declaration>
diff --git a/files/admin.php b/files/admin.php
index 861b6037f3c..7e410652cfb 100644
--- a/files/admin.php
+++ b/files/admin.php
@@ -25,23 +25,29 @@
// Init owncloud
require_once('../lib/base.php');
-OC_User::checkAdminUser();
+OC_Util::checkAdminUser();
$htaccessWorking=(getenv('htaccessWorking')=='true');
-if(isset($_POST['maxUploadSize'])){
- $maxUploadFilesize=$_POST['maxUploadSize'];
- OC_Files::setUploadLimit(OC_Helper::computerFileSize($maxUploadFilesize));
+if($_POST) {
+ if(isset($_POST['maxUploadSize'])){
+ $maxUploadFilesize=$_POST['maxUploadSize'];
+ OC_Files::setUploadLimit(OC_Helper::computerFileSize($maxUploadFilesize));
+ }
+ if(isset($_POST['maxZipInputSize'])) {
+ $maxZipInputSize=$_POST['maxZipInputSize'];
+ OC_Preferences::setValue('', 'files', 'maxZipInputSize', OC_Helper::computerFileSize($maxZipInputSize));
+ }
}else{
$upload_max_filesize = OC_Helper::computerFileSize(ini_get('upload_max_filesize'));
$post_max_size = OC_Helper::computerFileSize(ini_get('post_max_size'));
$maxUploadFilesize = min($upload_max_filesize, $post_max_size);
+ $maxZipInputSize = OC_Helper::humanfilesize(OC_Preferences::getValue('', 'files', 'maxZipInputSize', OC_Helper::computerFileSize('800 MB')));
}
OC_App::setActiveNavigationEntry( "files_administration" );
-// return template
-$tmpl = new OC_Template( "files", "admin", "user" );
+
+$tmpl = new OC_Template( 'files', 'admin' );
$tmpl->assign( 'htaccessWorking', $htaccessWorking );
$tmpl->assign( 'uploadMaxFilesize', $maxUploadFilesize);
-$tmpl->printPage();
-
-?>
+$tmpl->assign( 'maxZipInputSize', $maxZipInputSize);
+return $tmpl->fetchPage(); \ No newline at end of file
diff --git a/files/ajax/newfile.php b/files/ajax/newfile.php
index afc444bc0ac..2d1372f06ee 100644
--- a/files/ajax/newfile.php
+++ b/files/ajax/newfile.php
@@ -6,15 +6,35 @@ require_once('../../lib/base.php');
OC_JSON::checkLoggedIn();
// Get the params
-$dir = isset( $_GET['dir'] ) ? stripslashes($_GET['dir']) : '';
-$filename = isset( $_GET['filename'] ) ? stripslashes($_GET['filename']) : '';
-$content = isset( $_GET['content'] ) ? $_GET['content'] : '';
+$dir = isset( $_POST['dir'] ) ? stripslashes($_POST['dir']) : '';
+$filename = isset( $_POST['filename'] ) ? stripslashes($_POST['filename']) : '';
+$content = isset( $_POST['content'] ) ? $_POST['content'] : '';
+$source = isset( $_POST['source'] ) ? stripslashes($_POST['source']) : '';
if($filename == '') {
OC_JSON::error(array("data" => array( "message" => "Empty Filename" )));
exit();
}
+if($source){
+ if(substr($source,0,8)!='https://' and substr($source,0,7)!='http://'){
+ OC_JSON::error(array("data" => array( "message" => "Not a valid source" )));
+ exit();
+ }
+ $sourceStream=fopen($source,'rb');
+ $target=$dir.'/'.$filename;
+ $result=OC_Filesystem::file_put_contents($target,$sourceStream);
+ if($result){
+ $mime=OC_Filesystem::getMimetype($target);
+ OC_JSON::success(array("data" => array('mime'=>$mime)));
+ exit();
+ }else{
+ OC_JSON::error(array("data" => array( "message" => "Error while downloading ".$source. ' to '.$target )));
+ exit();
+ }
+}
+
+
if(OC_Files::newFile($dir, $filename, 'file')) {
if($content){
OC_Filesystem::file_put_contents($dir.'/'.$filename,$content);
diff --git a/files/ajax/newfolder.php b/files/ajax/newfolder.php
index 6db045c4e17..228e369fbef 100644
--- a/files/ajax/newfolder.php
+++ b/files/ajax/newfolder.php
@@ -6,8 +6,8 @@ require_once('../../lib/base.php');
OC_JSON::checkLoggedIn();
// Get the params
-$dir = isset( $_GET['dir'] ) ? stripslashes($_GET['dir']) : '';
-$foldername = isset( $_GET['foldername'] ) ? stripslashes($_GET['foldername']) : '';
+$dir = isset( $_POST['dir'] ) ? stripslashes($_POST['dir']) : '';
+$foldername = isset( $_POST['foldername'] ) ? stripslashes($_POST['foldername']) : '';
if(trim($foldername) == '') {
OC_JSON::error(array("data" => array( "message" => "Empty Foldername" )));
diff --git a/files/ajax/upload.php b/files/ajax/upload.php
index 241edc216ff..f8b8f0e2e5f 100644
--- a/files/ajax/upload.php
+++ b/files/ajax/upload.php
@@ -16,12 +16,13 @@ foreach ($_FILES['files']['error'] as $error) {
if ($error != 0) {
$l=new OC_L10N('files');
$errors = array(
- 0=>$l->t("There is no error, the file uploaded with success"),
- 1=>$l->t("The uploaded file exceeds the upload_max_filesize directive in php.ini").ini_get('upload_max_filesize'),
- 2=>$l->t("The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form"),
- 3=>$l->t("The uploaded file was only partially uploaded"),
- 4=>$l->t("No file was uploaded"),
- 6=>$l->t("Missing a temporary folder")
+ UPLOAD_ERR_OK=>$l->t("There is no error, the file uploaded with success"),
+ UPLOAD_ERR_INI_SIZE=>$l->t("The uploaded file exceeds the upload_max_filesize directive in php.ini").ini_get('upload_max_filesize'),
+ UPLOAD_ERR_FORM_SIZE=>$l->t("The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form"),
+ UPLOAD_ERR_PARTIAL=>$l->t("The uploaded file was only partially uploaded"),
+ UPLOAD_ERR_NO_FILE=>$l->t("No file was uploaded"),
+ UPLOAD_ERR_NO_TMP_DIR=>$l->t("Missing a temporary folder"),
+ UPLOAD_ERR_CANT_WRITE=>$l->t('Failed to write to disk'),
);
OC_JSON::error(array("data" => array( "message" => $errors[$error] )));
exit();
@@ -48,7 +49,8 @@ if(strpos($dir,'..') === false){
for($i=0;$i<$fileCount;$i++){
$target=stripslashes($dir) . $files['name'][$i];
if(is_uploaded_file($files['tmp_name'][$i]) and OC_Filesystem::fromTmpFile($files['tmp_name'][$i],$target)){
- $result[]=array( "status" => "success", 'mime'=>OC_Filesystem::getMimeType($target),'size'=>OC_Filesystem::filesize($target),'name'=>$files['name'][$i]);
+ $meta=OC_FileCache::getCached($target);
+ $result[]=array( "status" => "success", 'mime'=>$meta['mimetype'],'size'=>$meta['size'],'name'=>$files['name'][$i]);
}
}
OC_JSON::encodedPrint($result);
diff --git a/files/appinfo/app.php b/files/appinfo/app.php
index e434296b250..0bf73d9a07e 100644
--- a/files/appinfo/app.php
+++ b/files/appinfo/app.php
@@ -7,4 +7,4 @@ OC_App::register( array( "order" => 2, "id" => "files", "name" => "Files" ));
OC_App::addNavigationEntry( array( "id" => "files_index", "order" => 1, "href" => OC_Helper::linkTo( "files", "index.php" ), "icon" => OC_Helper::imagePath( "core", "places/home.svg" ), "name" => $l->t("Files") ));
-?>
+OC_Search::registerProvider('OC_Search_Provider_File');
diff --git a/files/index.php b/files/index.php
index a29d3fb7e1e..79261e495be 100644
--- a/files/index.php
+++ b/files/index.php
@@ -40,7 +40,7 @@ OC_App::setActiveNavigationEntry( "files_index" );
// Load the files
$dir = isset( $_GET['dir'] ) ? stripslashes($_GET['dir']) : '';
// Redirect if directory does not exist
-if(!OC_Filesystem::is_dir($dir)) {
+if(!OC_Filesystem::is_dir($dir.'/')) {
header("Location: ".$_SERVER['PHP_SELF']."");
}
diff --git a/files/js/files.js b/files/js/files.js
index 9f1f5368df0..539d5598899 100644
--- a/files/js/files.js
+++ b/files/js/files.js
@@ -3,11 +3,11 @@ $(document).ready(function() {
//little hack to set unescape filenames in attribute
$(this).attr('data-file',decodeURIComponent($(this).attr('data-file')));
});
-
+
if($('tr[data-file]').length==0){
$('.file_upload_filename').addClass('highlight');
}
-
+
$('#file_action_panel').attr('activeAction', false);
//drag/drop of files
@@ -16,7 +16,7 @@ $(document).ready(function() {
$('div.crumb').droppable(crumbDropOptions);
$('ul#apps>li:first-child').data('dir','');
$('ul#apps>li:first-child').droppable(crumbDropOptions);
-
+
// Triggers invisible file input
$('.file_upload_button_wrapper').live('click', function() {
$(this).parent().children('.file_upload_start').trigger('click');
@@ -81,9 +81,9 @@ $(document).ready(function() {
}
}
}
-
+
});
-
+
// Sets the select_all checkbox behaviour :
$('#select_all').click(function() {
if($(this).attr('checked')){
@@ -97,7 +97,7 @@ $(document).ready(function() {
}
procesSelection();
});
-
+
$('td.filename input:checkbox').live('click',function(event) {
if (event.shiftKey) {
var last = $(lastChecked).parent().parent().prevAll().length;
@@ -126,37 +126,22 @@ $(document).ready(function() {
}
procesSelection();
});
-
- $('#file_newfolder_form').submit(function(event) {
- event.preventDefault();
- $.ajax({
- url: 'ajax/newfolder.php',
- data: "dir="+$('#dir').val()+"&foldername="+$('#file_newfolder_name').val(),
- complete: function(data){boolOperationFinished(data, function(){
- var date=new Date();
- FileList.addDir($('#file_newfolder_name').val(),0,date);
- $('#file_newfolder_name').val('New Folder');
- $('#file_newfolder_name').blur();
- });}
- });
- });
-
+
$('#file_newfolder_name').click(function(){
if($('#file_newfolder_name').val() == 'New Folder'){
$('#file_newfolder_name').val('');
}
});
-
+
$('.download').click('click',function(event) {
var files=getSelectedFiles('name').join(';');
-
- //send the browser to the download location
var dir=$('#dir').val()||'/';
-// alert(files);
+ $('#notification').text(t('files','generating ZIP-file, it may take some time.'));
+ $('#notification').fadeIn();
window.location='ajax/download.php?files='+encodeURIComponent(files)+'&dir='+encodeURIComponent(dir);
return false;
});
-
+
$('.delete').click(function(event) {
var files=getSelectedFiles('name');
event.preventDefault();
@@ -242,7 +227,7 @@ $(document).ready(function() {
form.hide();
}
});
-
+
//add multiply file upload attribute to all browsers except konqueror (which crashes when it's used)
if(navigator.userAgent.search(/konqueror/i)==-1){
$('.file_upload_start').attr('multiple','multiple')
@@ -269,7 +254,7 @@ $(document).ready(function() {
text=text.substr(0,text.length-6)+'...';
crumb.text(text);
}
-
+
$(window).click(function(){
$('#new>ul').hide();
$('#new').removeClass('active');
@@ -293,14 +278,14 @@ $(document).ready(function() {
if($(this).children('p').length==0){
return;
}
-
+
$('#new li').each(function(i,element){
if($(element).children('p').length==0){
$(element).children('input').remove();
$(element).append('<p>'+$(element).data('text')+'</p>');
}
});
-
+
var type=$(this).data('type');
var text=$(this).children('p').text();
$(this).data('text',text);
@@ -312,10 +297,10 @@ $(document).ready(function() {
var name=$(this).val();
switch(type){
case 'file':
- $.ajax({
- url: OC.filePath('files','ajax','newfile.php'),
- data: "dir="+encodeURIComponent($('#dir').val())+"&filename="+encodeURIComponent(name)+'&content=%20%0A',
- complete: function(data){boolOperationFinished(data, function(){
+ $.post(
+ OC.filePath('files','ajax','newfile.php'),
+ {dir:$('#dir').val(),filename:name,content:" \n"},
+ function(data){
var date=new Date();
FileList.addFile(name,0,date);
var tr=$('tr').filterAttr('data-file',name);
@@ -323,18 +308,49 @@ $(document).ready(function() {
getMimeIcon('text/plain',function(path){
tr.find('td.filename').attr('style','background-image:url('+path+')');
});
- });}
- });
+ }
+ );
break;
case 'folder':
- $.ajax({
- url: OC.filePath('files','ajax','newfolder.php'),
- data: "dir="+encodeURIComponent($('#dir').val())+"&foldername="+encodeURIComponent(name),
- complete: function(data){boolOperationFinished(data, function(){
+ $.post(
+ OC.filePath('files','ajax','newfolder.php'),
+ {dir:$('#dir').val(),foldername:name},
+ function(data){
var date=new Date();
FileList.addDir(name,0,date);
- });}
- });
+ }
+ );
+ break;
+ case 'web':
+ if(name.substr(0,8)!='https://' && name.substr(0,7)!='http://'){
+ name='http://'.name;
+ }
+ var localName=name;
+ if(localName.substr(localName.length-1,1)=='/'){//strip /
+ localName=localName.substr(0,localName.length-1)
+ }
+ if(localName.indexOf('/')){//use last part of url
+ localName=localName.split('/').pop();
+ }else{//or the domain
+ localName=(localName.match(/:\/\/(.[^/]+)/)[1]).replace('www.','');
+ }
+ $.post(
+ OC.filePath('files','ajax','newfile.php'),
+ {dir:$('#dir').val(),source:name,filename:localName},
+ function(result){
+ if(result.status == 'success'){
+ var date=new Date();
+ FileList.addFile(localName,0,date);
+ var tr=$('tr').filterAttr('data-file',localName);
+ tr.data('mime',result.data.mime);
+ getMimeIcon(result.data.mime,function(path){
+ tr.find('td.filename').attr('style','background-image:url('+path+')');
+ });
+ }else{
+
+ }
+ }
+ );
break;
}
var li=$(this).parent();
@@ -387,39 +403,6 @@ function updateBreadcrumb(breadcrumbHtml) {
$('p.nav').empty().html(breadcrumbHtml);
}
-function humanFileSize(bytes){
- if( bytes < 1024 ){
- return bytes+' B';
- }
- bytes = Math.round(bytes / 1024, 1 );
- if( bytes < 1024 ){
- return bytes+' kB';
- }
- bytes = Math.round( bytes / 1024, 1 );
- if( bytes < 1024 ){
- return bytes+' MB';
- }
-
- // Wow, heavy duty for owncloud
- bytes = Math.round( bytes / 1024, 1 );
- return bytes+' GB';
-}
-
-function simpleFileSize(bytes) {
- mbytes = Math.round(bytes/(1024*1024/10))/10;
- if(bytes == 0) { return '0'; }
- else if(mbytes < 0.1) { return '< 0.1'; }
- else if(mbytes > 1000) { return '> 1000'; }
- else { return mbytes.toFixed(1); }
-}
-
-function formatDate(date){
- var monthNames = [ t('files','January'), t('files','February'), t('files','March'), t('files','April'), t('files','May'), t('files','June'),
- t('files','July'), t('files','August'), t('files','September'), t('files','October'), t('files','November'), t('files','December') ];
- return monthNames[date.getMonth()]+' '+date.getDate()+', '+date.getFullYear()+', '+((date.getHours()<10)?'0':'')+date.getHours()+':'+date.getMinutes();
-}
-
-
//options for file drag/dropp
var dragOptions={
distance: 20, revert: 'invalid', opacity: 0.7,
diff --git a/files/templates/admin.php b/files/templates/admin.php
index 0122865ee72..8c3ba56ad52 100644
--- a/files/templates/admin.php
+++ b/files/templates/admin.php
@@ -1,10 +1,12 @@
<?php OC_Util::addScript('files','admin'); ?>
<form name="filesForm" action='#' method='post'>
- <?php if($_['htaccessWorking']):?>
- <label for="maxUploadSize"><?php echo $l->t( 'Maximum upload size' ); ?> </label><input name='maxUploadSize' id="maxUploadSize" value='<?php echo $_['uploadMaxFilesize'] ?>'/><br/>
- <input type='submit' value='Save'/>
- <?php else:?>
- No settings currently available.
- <?php endif;?>
+ <fieldset class="personalblock">
+ <legend><strong><?php echo $l->t('File handling');?></strong></legend>
+ <?php if($_['htaccessWorking']):?>
+ <label for="maxUploadSize"><?php echo $l->t( 'Maximum upload size' ); ?> </label><input name='maxUploadSize' id="maxUploadSize" value='<?php echo $_['uploadMaxFilesize'] ?>'/><br/>
+ <?php endif;?>
+ <label for="maxZipInputSize"><?php echo $l->t( 'Maximum input size for zip files (affects folder- and multi-file download)' ); ?> </label><input name="maxZipInputSize" id="maxZipInputSize" value='<?php echo $_['maxZipInputSize'] ?>'/><br/>
+ <input type="submit" value="Save"/>
+ </fieldset>
</form>
diff --git a/files/templates/index.php b/files/templates/index.php
index 7e9505dec2f..7fc51c288e1 100644
--- a/files/templates/index.php
+++ b/files/templates/index.php
@@ -7,6 +7,7 @@
<ul class="popup popupTop">
<li style="background-image:url('<?php echo mimetype_icon('text/plain') ?>')" data-type='file'><p><?php echo $l->t('Text file');?></p></li>
<li style="background-image:url('<?php echo mimetype_icon('dir') ?>')" data-type='folder'><p><?php echo $l->t('Folder');?></p></li>
+ <li style="background-image:url('<?php echo image_path('core','actions/public.png') ?>')" data-type='web'><p><?php echo $l->t('From url');?></p></li>
</ul>
</div>
<div class="file_upload_wrapper svg">
diff --git a/lib/app.php b/lib/app.php
index 1879a89cee3..64cbe8894ea 100644
--- a/lib/app.php
+++ b/lib/app.php
@@ -58,8 +58,8 @@ class OC_App{
$apps = OC_Appconfig::getApps();
foreach( $apps as $app ){
if( self::isEnabled( $app )){
- if(is_file(OC::$SERVERROOT.'/apps/'.$app.'/appinfo/app.php')){
- require( 'apps/'.$app.'/appinfo/app.php' );
+ if(is_file(OC::$APPSROOT.'/apps/'.$app.'/appinfo/app.php')){
+ require( $app.'/appinfo/app.php' );
}
}
}
@@ -268,7 +268,7 @@ class OC_App{
if(is_file($appid)){
$file=$appid;
}else{
- $file=OC::$SERVERROOT.'/apps/'.$appid.'/appinfo/info.xml';
+ $file=OC::$APPSROOT.'/apps/'.$appid.'/appinfo/info.xml';
if(!is_file($file)){
return array();
}
@@ -325,6 +325,7 @@ class OC_App{
$source=self::$settingsForms;
break;
case 'admin':
+ $forms[] = include 'files/admin.php'; //hardcode own apps
$source=self::$adminForms;
break;
case 'personal':
@@ -363,15 +364,15 @@ class OC_App{
*/
public static function getAllApps(){
$apps=array();
- $dh=opendir(OC::$SERVERROOT.'/apps');
+ $dh=opendir(OC::$APPSROOT.'/apps');
while($file=readdir($dh)){
- if(is_file(OC::$SERVERROOT.'/apps/'.$file.'/appinfo/app.php')){
+ if(substr($file,0,1)!='.' and is_file(OC::$APPSROOT.'/apps/'.$file.'/appinfo/app.php')){
$apps[]=$file;
}
}
return $apps;
}
-
+
/**
* check if any apps need updating and update those
*/
@@ -390,17 +391,17 @@ class OC_App{
}
}
}
-
+
/**
* update the database for the app and call the update script
* @param string appid
*/
public static function updateApp($appid){
- if(file_exists(OC::$SERVERROOT.'/apps/'.$appid.'/appinfo/database.xml')){
- OC_DB::updateDbFromStructure(OC::$SERVERROOT.'/apps/'.$appid.'/appinfo/database.xml');
+ if(file_exists(OC::$APPSROOT.'/apps/'.$appid.'/appinfo/database.xml')){
+ OC_DB::updateDbFromStructure(OC::$APPSROOT.'/apps/'.$appid.'/appinfo/database.xml');
}
- if(file_exists(OC::$SERVERROOT.'/apps/'.$appid.'/appinfo/update.php')){
- include OC::$SERVERROOT.'/apps/'.$appid.'/appinfo/update.php';
+ if(file_exists(OC::$APPSROOT.'/apps/'.$appid.'/appinfo/update.php')){
+ include OC::$APPSROOT.'/apps/'.$appid.'/appinfo/update.php';
}
}
diff --git a/lib/base.php b/lib/base.php
index a95c9d2b21a..9995544f14e 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -62,6 +62,14 @@ class OC{
* the root path of the 3rdparty folder for http requests (e.g. owncloud/3rdparty)
*/
public static $THIRDPARTYWEBROOT = '';
+ /**
+ * The installation path of the apps folder on the server (e.g. /srv/http/owncloud)
+ */
+ public static $APPSROOT = '';
+ /**
+ * the root path of the apps folder for http requests (e.g. owncloud)
+ */
+ public static $APPSWEBROOT = '';
/**
* SPL autoload
@@ -136,6 +144,12 @@ class OC{
$_SERVER['PHP_AUTH_PW'] = strip_tags($password);
}
+ // register the stream wrappers
+ require_once('streamwrappers.php');
+ stream_wrapper_register("fakedir", "OC_FakeDirStream");
+ stream_wrapper_register('static', 'OC_StaticStreamWrapper');
+ stream_wrapper_register('close', 'OC_CloseStreamWrapper');
+
// calculate the documentroot
OC::$DOCUMENTROOT=realpath($_SERVER['DOCUMENT_ROOT']);
OC::$SERVERROOT=str_replace("\\",'/',substr(__FILE__,0,-13));
@@ -143,8 +157,17 @@ class OC{
$scriptName=$_SERVER["SCRIPT_NAME"];
if(substr($scriptName,-1)=='/'){
$scriptName.='index.php';
+ //make sure suburi follows the same rules as scriptName
+ if(substr(OC::$SUBURI,-9)!='index.php'){
+ if(substr(OC::$SUBURI,-1)!='/'){
+ OC::$SUBURI=OC::$SUBURI.'/';
+ }
+ OC::$SUBURI=OC::$SUBURI.'index.php';
+ }
}
- OC::$WEBROOT=substr($scriptName,0,strlen($scriptName)-strlen(OC::$SUBURI));
+ OC::$WEBROOT=substr($scriptName,0,strlen($scriptName)-strlen(OC::$SUBURI));
+ // try a new way to detect the WEBROOT which is simpler and also works with the app directory outside the owncloud folder. let´s see if this works for everybody
+// OC::$WEBROOT=substr(OC::$SERVERROOT,strlen(OC::$DOCUMENTROOT));
if(OC::$WEBROOT!='' and OC::$WEBROOT[0]!=='/'){
@@ -159,22 +182,35 @@ class OC{
OC::$THIRDPARTYROOT=OC::$SERVERROOT;
OC::$THIRDPARTYWEBROOT=OC::$WEBROOT;
}elseif(file_exists(OC::$SERVERROOT.'/../3rdparty')){
- $url_tmp=explode('/',OC::$WEBROOT);
- $length=count($url_tmp);
- unset($url_tmp[$length-1]);
- OC::$THIRDPARTYWEBROOT=implode('/',$url_tmp);
- $root_tmp=explode('/',OC::$SERVERROOT);
- $length=count($root_tmp);
- unset($root_tmp[$length-1]);
- OC::$THIRDPARTYROOT=implode('/',$root_tmp);
+ OC::$THIRDPARTYWEBROOT=rtrim(dirname(OC::$WEBROOT), '/');
+ OC::$THIRDPARTYROOT=rtrim(dirname(OC::$SERVERROOT), '/');
}else{
echo("3rdparty directory not found! Please put the ownCloud 3rdparty folder in the ownCloud folder or the folder above. You can also configure the location in the config.php file.");
exit;
}
+ // search the apps folder
+ if(file_exists(OC::$SERVERROOT.'/apps')){
+ OC::$APPSROOT=OC::$SERVERROOT;
+ OC::$APPSWEBROOT=OC::$WEBROOT;
+ }elseif(file_exists(OC::$SERVERROOT.'/../apps')){
+ OC::$APPSWEBROOT=rtrim(dirname(OC::$WEBROOT), '/');
+ OC::$APPSROOT=rtrim(dirname(OC::$SERVERROOT), '/');
+ }else{
+ echo("apps directory not found! Please put the ownCloud apps folder in the ownCloud folder or the folder above. You can also configure the location in the config.php file.");
+ exit;
+ }
// set the right include path
- set_include_path(OC::$SERVERROOT.'/lib'.PATH_SEPARATOR.OC::$SERVERROOT.'/config'.PATH_SEPARATOR.OC::$THIRDPARTYROOT.'/3rdparty'.PATH_SEPARATOR.get_include_path().PATH_SEPARATOR.OC::$SERVERROOT);
+ set_include_path(
+ OC::$SERVERROOT.'/lib'.PATH_SEPARATOR.
+ OC::$SERVERROOT.'/config'.PATH_SEPARATOR.
+ OC::$THIRDPARTYROOT.'/3rdparty'.PATH_SEPARATOR.
+ OC::$APPSROOT.PATH_SEPARATOR.
+ OC::$APPSROOT.'/apps'.PATH_SEPARATOR.
+ get_include_path().PATH_SEPARATOR.
+ OC::$SERVERROOT
+ );
// Redirect to installer if not installed
if (!OC_Config::getValue('installed', false) && OC::$SUBURI != '/index.php') {
@@ -234,8 +270,10 @@ class OC{
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" );
@@ -261,6 +299,7 @@ class OC{
$_SESSION['user_id'] = '';
}
+
OC_User::useBackend( OC_Config::getValue( "userbackend", "database" ));
OC_Group::setBackend( OC_Config::getValue( "groupbackend", "database" ));
@@ -277,9 +316,8 @@ class OC{
OC_App::loadApps();
}
- // Last part: connect some hooks
- OC_HOOK::connect('OC_User', 'post_createUser', 'OC_Connector_Sabre_Principal', 'addPrincipal');
- OC_HOOK::connect('OC_User', 'post_deleteUser', 'OC_Connector_Sabre_Principal', 'deletePrincipal');
+ //make sure temporary files are cleaned up
+ register_shutdown_function(array('OC_Helper','cleanTmp'));
}
}
@@ -302,15 +340,10 @@ if(!function_exists('get_temp_dir')) {
unlink($temp);
return dirname($temp);
}
+ if( $temp=sys_get_temp_dir()) return $temp;
+
return null;
}
}
OC::init();
-
-require_once('fakedirstream.php');
-
-
-
-// FROM search.php
-new OC_Search_Provider_File();
diff --git a/lib/connector/sabre/auth.php b/lib/connector/sabre/auth.php
index 1e87c7cee08..8964ef7d0de 100644
--- a/lib/connector/sabre/auth.php
+++ b/lib/connector/sabre/auth.php
@@ -23,6 +23,7 @@ class OC_Connector_Sabre_Auth extends Sabre_DAV_Auth_Backend_AbstractBasic {
* @return bool
*/
protected function validateUserPass($username, $password){
+ OC_Util::setUpFS();//login hooks may need early access to the filesystem
if(OC_User::login($username,$password)){
OC_Util::setUpFS();
return true;
diff --git a/lib/connector/sabre/directory.php b/lib/connector/sabre/directory.php
index d1cb55ce130..912c8cd439a 100644
--- a/lib/connector/sabre/directory.php
+++ b/lib/connector/sabre/directory.php
@@ -73,8 +73,8 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa
$nodes = array();
// foreach(scandir($this->path) as $node) if($node!='.' && $node!='..') $nodes[] = $this->getChild($node);
- if( OC_Filesystem::is_dir($this->path)){
- $dh = OC_Filesystem::opendir($this->path);
+ if( OC_Filesystem::is_dir($this->path . '/')){
+ $dh = OC_Filesystem::opendir($this->path . '/');
while(( $node = readdir($dh)) !== false ){
if($node!='.' && $node!='..'){
$nodes[] = $this->getChild($node);
diff --git a/lib/connector/sabre/principal.php b/lib/connector/sabre/principal.php
index 6cfb3449e1a..d1456f7c642 100644
--- a/lib/connector/sabre/principal.php
+++ b/lib/connector/sabre/principal.php
@@ -9,50 +9,6 @@
class OC_Connector_Sabre_Principal implements Sabre_DAVACL_IPrincipalBackend {
/**
- * TODO: write doc
- */
- public static function addPrincipal($params){
- // Add the user
- $uri = 'principals/'.$params['uid'];
- $displayname = $params['uid'];
- $query = OC_DB::prepare('INSERT INTO *PREFIX*principals (uri,displayname) VALUES(?,?)');
- $query->execute(array($uri,$displayname));
-
- // Add calendar and addressbook read and write support (sharing calendars)
- $uri = 'principals/'.$params['uid'].'/calendar-proxy-read';
- $displayname = null;
- $query->execute(array($uri,$displayname));
- $uri = 'principals/'.$params['uid'].'/calendar-proxy-write';
- $query->execute(array($uri,$displayname));
- $uri = 'principals/'.$params['uid'].'/addressbook-proxy-read';
- $query->execute(array($uri,$displayname));
- $uri = 'principals/'.$params['uid'].'/addressbook-proxy-write';
- $query->execute(array($uri,$displayname));
-
- return true;
- }
-
- /**
- * TODO: write doc
- */
- public static function deletePrincipal($params){
- $query = OC_DB::prepare('SELECT * FROM *PREFIX*principals');
- $result = $query->execute();
-
- $deleteprincipal = OC_DB::prepare('DELETE FROM *PREFIX*principals WHERE id = ?');
- $deletegroup = OC_DB::prepare('DELETE FROM *PREFIX*principalgroups WHERE principal_id = ? OR member_id = ?');
- // We have to delete the principals and relations! Principals include
- while($row = $result->fetchRow()){
- // Checking if the principal is in the prefix
- $array = explode('/',$row['uri']);
- if ($array[1] != $params['uid']) continue;
- $deleteprincipal->execute(array($row['id']));
- $deletegroup->execute(array($row['id'],$row['id']));
- }
- return true;
- }
-
- /**
* Returns a list of principals based on a prefix.
*
* This prefix will often contain something like 'principals'. You are only
diff --git a/lib/db.php b/lib/db.php
index 4c17cd0dbd1..9fab51edfcd 100644
--- a/lib/db.php
+++ b/lib/db.php
@@ -316,8 +316,8 @@ class OC_DB {
// read file
$content = file_get_contents( $file );
- // Make changes and save them to a temporary file
- $file2 = tempnam( get_temp_dir(), 'oc_db_scheme_' );
+ // 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');
}
@@ -331,7 +331,7 @@ class OC_DB {
// Try to create tables
$definition = self::$schema->parseDatabaseDefinitionFile( $file2 );
- // Delete our temporary file
+ //clean up memory
unlink( $file2 );
// Die in case something went wrong
@@ -371,8 +371,8 @@ class OC_DB {
return false;
}
- // Make changes and save them to a temporary file
- $file2 = tempnam( get_temp_dir(), 'oc_db_scheme_' );
+ // Make changes and save them to an in-memory file
+ $file2 = 'static://db_scheme';
$content = str_replace( '*dbname*', $previousSchema['name'], $content );
$content = str_replace( '*dbprefix*', $CONFIG_DBTABLEPREFIX, $content );
if( $CONFIG_DBTYPE == 'pgsql' ){ //mysql support it too but sqlite doesn't
@@ -381,7 +381,7 @@ class OC_DB {
file_put_contents( $file2, $content );
$op = self::$schema->updateDatabase($file2, $previousSchema, array(), false);
- // Delete our temporary file
+ //clean up memory
unlink( $file2 );
if (PEAR::isError($op)) {
@@ -508,6 +508,21 @@ class OC_DB {
self::$connection->commit();
self::$inTransaction=false;
}
+
+ /**
+ * check if a result is an error, works with MDB2 and PDOException
+ * @param mixed $result
+ * @return bool
+ */
+ public static function isError($result){
+ if(!$result){
+ return true;
+ }elseif(self::$backend==self::BACKEND_MDB2 and PEAR::isError($result)){
+ return true;
+ }else{
+ return false;
+ }
+ }
}
/**
@@ -527,11 +542,15 @@ class PDOStatementWrapper{
public function execute($input=array()){
$this->lastArguments=$input;
if(count($input)>0){
- $this->statement->execute($input);
+ $result=$this->statement->execute($input);
+ }else{
+ $result=$this->statement->execute();
+ }
+ if($result){
+ return $this;
}else{
- $this->statement->execute();
+ return false;
}
- return $this;
}
/**
diff --git a/lib/fakedirstream.php b/lib/fakedirstream.php
deleted file mode 100644
index fa3e64da62c..00000000000
--- a/lib/fakedirstream.php
+++ /dev/null
@@ -1,45 +0,0 @@
-<?php
-global $FAKEDIRS;
-$FAKEDIRS=array();
-
-class fakeDirStream{
- private $name;
- private $data;
- private $index;
-
- public function dir_opendir($path,$options){
- global $FAKEDIRS;
- $url=parse_url($path);
- $this->name=substr($path,strlen('fakedir://'));
- $this->index=0;
- if(isset($FAKEDIRS[$this->name])){
- $this->data=$FAKEDIRS[$this->name];
- }else{
- $this->data=array();
- }
- return true;
- }
-
- public function dir_readdir(){
- if($this->index>=count($this->data)){
- return false;
- }
- $filename=$this->data[$this->index];
- $this->index++;
- return $filename;
- }
-
- public function dir_closedir() {
- $this->data=false;
- $this->name='';
- return true;
- }
-
- public function dir_rewinddir() {
- $this->index=0;
- return true;
- }
-}
-
-stream_wrapper_register("fakedir", "fakeDirStream");
-
diff --git a/lib/filecache.php b/lib/filecache.php
index faadddfb37e..280a9929db0 100644
--- a/lib/filecache.php
+++ b/lib/filecache.php
@@ -28,6 +28,8 @@
* It will try to keep the data up to date but changes from outside ownCloud can invalidate the cache
*/
class OC_FileCache{
+ private static $savedData=array();
+
/**
* get the filesystem info from the cache
* @param string path
@@ -93,6 +95,14 @@ class OC_FileCache{
self::update($id,$data);
return;
}
+ if(isset(self::$savedData[$path])){
+ $data=array_merge($data,self::$savedData[$path]);
+ unset(self::$savedData[$path]);
+ }
+ if(!isset($data['size']) or !isset($data['mtime'])){//save incomplete data for the next time we write it
+ self::$savedData[$path]=$data;
+ return;
+ }
if(!isset($data['encrypted'])){
$data['encrypted']=false;
}
@@ -101,9 +111,11 @@ 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) VALUES(?,?,?,?,?,?,?,?,?,?)');
- $query->execute(array($parent,basename($path),$path,$data['size'],$data['mtime'],$data['ctime'],$data['mimetype'],$mimePart,$user,$data['writable']));
-
+ $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']));
+ if(OC_DB::isError($result)){
+ OC_Log::write('files','error while writing file('.$path.') to cache',OC_Log::ERROR);
+ }
}
/**
@@ -128,7 +140,10 @@ class OC_FileCache{
$sql = 'UPDATE *PREFIX*fscache SET '.implode(' , ',$queryParts).' WHERE id=?';
$query=OC_DB::prepare($sql);
- $query->execute($arguments);
+ $result=$query->execute($arguments);
+ if(OC_DB::isError($result)){
+ OC_Log::write('files','error while updating file('.$path.') in cache',OC_Log::ERROR);
+ }
}
/**
@@ -153,19 +168,28 @@ class OC_FileCache{
/**
* delete info from the cache
- * @param string $path
+ * @param string/int $file
* @param string root (optional)
*/
- public static function delete($path,$root=''){
- if(!$root){
- $root=OC_Filesystem::getRoot();
- }
- if($root=='/'){
- $root='';
+ public static function delete($file,$root=''){
+ if(!is_numeric($file)){
+ if(!$root){
+ $root=OC_Filesystem::getRoot();
+ }
+ if($root=='/'){
+ $root='';
+ }
+ $path=$root.$file;
+ self::delete(self::getFileId($path));
+ }elseif($file!=-1){
+ $query=OC_DB::prepare('SELECT id FROM *PREFIX*fscache WHERE parent=?');
+ $result=$query->execute(array($file));
+ while($child=$result->fetchRow()){
+ self::delete(intval($child['id']));
+ }
+ $query=OC_DB::prepare('DELETE FROM *PREFIX*fscache WHERE id=?');
+ $query->execute(array($file));
}
- $path=$root.$path;
- $query=OC_DB::prepare('DELETE FROM *PREFIX*fscache WHERE path=?');
- $query->execute(array($path));
}
/**
@@ -262,11 +286,20 @@ class OC_FileCache{
*/
private static function getFileId($path){
$query=OC_DB::prepare('SELECT id FROM *PREFIX*fscache WHERE path=?');
- $result=$query->execute(array($path))->fetchRow();
+ 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));
+ if(OC_DB::isError($result)){
+ OC_Log::write('files','error while getting file id of '.$path,OC_Log::ERROR);
+ return -1;
+ }
+ $result=$result->fetchRow();
if(is_array($result)){
return $result['id'];
}else{
- OC_Log::write('getFileId(): file not found in cache ('.$path.')','core',OC_Log::DEBUG);
+ OC_Log::write('getFileId(): file not found in cache ('.$path.')','core',OC_Log::DEBUG);
return -1;
}
}
@@ -299,10 +332,11 @@ class OC_FileCache{
$path=$params['path'];
$fullPath=$view->getRoot().$path;
$mimetype=$view->getMimeType($path);
+ $dir=$view->is_dir($path.'/');
//dont use self::get here, we don't want inifinte loops when a file has changed
$cachedSize=self::getCachedSize($path,$root);
$size=0;
- if($mimetype=='httpd/unix-directory'){
+ if($dir){
if(self::inCache($path,$root)){
$parent=self::getFileId($fullPath);
$query=OC_DB::prepare('SELECT size FROM *PREFIX*fscache WHERE parent=?');
@@ -323,7 +357,29 @@ class OC_FileCache{
}
self::increaseSize(dirname($fullPath),$size-$cachedSize);
}
-
+
+ public static function getCached($path,$root=''){
+ if(!$root){
+ $root=OC_Filesystem::getRoot();
+ }else{
+ if($root=='/'){
+ $root='';
+ }
+ }
+ $path=$root.$path;
+ $query=OC_DB::prepare('SELECT ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE path=?');
+ $result=$query->execute(array($path))->fetchRow();
+ if(is_array($result)){
+ if(isset(self::$savedData[$path])){
+ $result=array_merge($result,self::$savedData[$path]);
+ }
+ return $result;
+ }else{
+ OC_Log::write('get(): file not found in cache ('.$path.')','core',OC_Log::DEBUG);
+ return false;
+ }
+ }
+
private static function getCachedSize($path,$root){
if(!$root){
$root=OC_Filesystem::getRoot();
@@ -332,6 +388,7 @@ class OC_FileCache{
$root='';
}
}
+ $path=$root.$path;
$query=OC_DB::prepare('SELECT size FROM *PREFIX*fscache WHERE path=?');
$result=$query->execute(array($path));
if($row=$result->fetchRow()){
@@ -418,13 +475,13 @@ class OC_FileCache{
$view=new OC_FilesystemView(($root=='/')?'':$root);
}
self::scanFile($path,$root);
- $dh=$view->opendir($path);
+ $dh=$view->opendir($path.'/');
$totalSize=0;
if($dh){
while (($filename = readdir($dh)) !== false) {
if($filename != '.' and $filename != '..'){
$file=$path.'/'.$filename;
- if($view->is_dir($file)){
+ if($view->is_dir($file.'/')){
if($eventSource){
$eventSource->send('scanning',array('file'=>$file,'count'=>$count));
}
@@ -465,7 +522,7 @@ class OC_FileCache{
}
/**
- * fine files by mimetype
+ * find files by mimetype
* @param string $part1
* @param string $part2 (optional)
* @param string root (optional)
@@ -477,20 +534,21 @@ class OC_FileCache{
* seccond mimetype part can be ommited
* e.g. searchByMime('audio')
*/
- public static function searchByMime($part1,$part2='',$root=''){
+ public static function searchByMime($part1,$part2=null,$root=null){
if(!$root){
$root=OC_Filesystem::getRoot();
- }elseif($root='/'){
+ }elseif($root=='/'){
$root='';
}
$rootLen=strlen($root);
+ $root .= '%';
$user=OC_User::getUser();
if(!$part2){
- $query=OC_DB::prepare('SELECT path FROM *PREFIX*fscache WHERE mimepart=? AND user=?');
- $result=$query->execute(array($part1,$user));
+ $query=OC_DB::prepare('SELECT path FROM *PREFIX*fscache WHERE mimepart=? AND user=? AND path LIKE ?');
+ $result=$query->execute(array($part1,$user, $root));
}else{
- $query=OC_DB::prepare('SELECT path FROM *PREFIX*fscache WHERE mimetype=? AND user=?');
- $result=$query->execute(array($part1.'/'.$part2,$user));
+ $query=OC_DB::prepare('SELECT path FROM *PREFIX*fscache WHERE mimetype=? AND user=? AND path LIKE ? ');
+ $result=$query->execute(array($part1.'/'.$part2,$user, $root));
}
$names=array();
while($row=$result->fetchRow()){
@@ -515,6 +573,9 @@ class OC_FileCache{
}
$view=new OC_FilesystemView($root);
}
+ if(!$view->file_exists($path)){
+ return false;
+ }
$mtime=$view->filemtime($path);
$isDir=$view->is_dir($path);
$path=$root.$path;
diff --git a/lib/fileproxy.php b/lib/fileproxy.php
index 235fc8bf284..46fc2f49c50 100644
--- a/lib/fileproxy.php
+++ b/lib/fileproxy.php
@@ -34,11 +34,12 @@
* A post-proxy recieves 2 arguments, the filepath and the result of the operation.
* The return calue of the post-proxy will be used as the new result of the operation
* The operations that have a post-proxy are
- * file_get_contents, is_file, is_dir, file_exists, stat, is_readable, is_writable, filemtime, filectime, file_get_contents, getMimeType, hash, free_space and search
+ * file_get_contents, is_file, is_dir, file_exists, stat, is_readable, is_writable, fileatime, filemtime, filectime, file_get_contents, getMimeType, hash, fopen, free_space and search
*/
class OC_FileProxy{
private static $proxies=array();
+ public static $enabled=true;
/**
* check if this proxy implments a specific proxy operation
@@ -83,16 +84,19 @@ class OC_FileProxy{
return $proxies;
}
- public static function runPreProxies($operation,$filepath,$filepath2=null){
+ public static function runPreProxies($operation,&$filepath,&$filepath2=null){
+ if(!self::$enabled){
+ return true;
+ }
$proxies=self::getProxies($operation,false);
$operation='pre'.$operation;
foreach($proxies as $proxy){
- if($filepath2){
- if(!$proxy->$operation($filepath,$filepath2)){
+ if(!is_null($filepath2)){
+ if($proxy->$operation($filepath,$filepath2)===false){
return false;
}
}else{
- if(!$proxy->$operation($filepath)){
+ if($proxy->$operation($filepath)===false){
return false;
}
}
@@ -101,6 +105,9 @@ class OC_FileProxy{
}
public static function runPostProxies($operation,$path,$result){
+ if(!self::$enabled){
+ return $result;
+ }
$proxies=self::getProxies($operation,true);
$operation='post'.$operation;
foreach($proxies as $proxy){
diff --git a/lib/files.php b/lib/files.php
index 1f8331afb21..50223df1d36 100644
--- a/lib/files.php
+++ b/lib/files.php
@@ -59,6 +59,9 @@ class OC_Files {
}
if(is_array($files)){
+ self::checkZipInputSize($dir,$files);
+ $executionTime = intval(ini_get('max_execution_time'));
+ set_time_limit(0);
$zip = new ZipArchive();
$filename = get_temp_dir()."/ownCloud.zip";
if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) {
@@ -75,7 +78,11 @@ class OC_Files {
}
}
$zip->close();
+ set_time_limit($executionTime);
}elseif(OC_Filesystem::is_dir($dir.'/'.$files)){
+ self::checkZipInputSize($dir,$files);
+ $executionTime = intval(ini_get('max_execution_time'));
+ set_time_limit(0);
$zip = new ZipArchive();
$filename = get_temp_dir()."/ownCloud.zip";
if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) {
@@ -84,6 +91,7 @@ class OC_Files {
$file=$dir.'/'.$files;
self::zipAddDir($file,$zip);
$zip->close();
+ set_time_limit($executionTime);
}else{
$zip=false;
$filename=$dir.'/'.$files;
@@ -210,6 +218,40 @@ class OC_Files {
}
/**
+ * checks if the selected files are within the size constraint. If not, outputs an error page.
+ *
+ * @param dir $dir
+ * @param files $files
+ */
+ static function checkZipInputSize($dir, $files) {
+ $zipLimit = OC_Preferences::getValue('', 'files', 'maxZipInputSize', OC_Helper::computerFileSize('800 MB'));
+ if($zipLimit > 0) {
+ $totalsize = 0;
+ if(is_array($files)){
+ foreach($files as $file){
+ $totalsize += OC_Filesystem::filesize($dir.'/'.$file);
+ }
+ }else{
+ $totalsize += OC_Filesystem::filesize($dir.'/'.$files);
+ }
+ if($totalsize > $zipLimit) {
+ $l = new OC_L10N('files');
+ header("HTTP/1.0 409 Conflict");
+ $tmpl = new OC_Template( '', 'error', 'user' );
+ $errors = array(
+ array(
+ 'error' => $l->t('Selected files too large to generate zip file.'),
+ 'hint' => 'Download the files in smaller chunks, seperately or kindly ask your administrator.<br/><a href="javascript:history.back()">' . $l->t('Back to Files') . '</a>',
+ )
+ );
+ $tmpl->assign('errors', $errors);
+ $tmpl->printPage();
+ exit;
+ }
+ }
+ }
+
+ /**
* try to detect the mime type of a file
*
* @param string path
@@ -256,7 +298,7 @@ class OC_Files {
return false;
}
}
-
+
/**
* set the maximum upload size limit for apache hosts using .htaccess
* @param int size filesisze in bytes
diff --git a/lib/filestorage.php b/lib/filestorage.php
index 4523144f6f4..fd6497b9478 100644
--- a/lib/filestorage.php
+++ b/lib/filestorage.php
@@ -23,33 +23,31 @@
/**
* Privde a common interface to all different storage options
*/
-class OC_Filestorage{
+abstract class OC_Filestorage{
public function __construct($parameters){}
- public function mkdir($path){}
- public function rmdir($path){}
- public function opendir($path){}
- public function is_dir($path){}
- public function is_file($path){}
- public function stat($path){}
- public function filetype($path){}
- public function filesize($path){}
- public function is_readable($path){}
- public function is_writable($path){}
- public function file_exists($path){}
- public function readfile($path){}
- public function filectime($path){}
- public function filemtime($path){}
- public function file_get_contents($path){}
- public function file_put_contents($path,$data){}
- public function unlink($path){}
- public function rename($path1,$path2){}
- public function copy($path1,$path2){}
- public function fopen($path,$mode){}
- public function toTmpFile($path){}//copy the file to a temporary file, used for cross-storage file actions
- public function fromTmpFile($tmpPath,$path){}//copy a file from a temporary file, used for cross-storage file actions
- public function getMimeType($path){}
- public function hash($type,$path,$raw){}
- public function free_space($path){}
- public function search($query){}
- public function getLocalFile($path){}// get a path to a local version of the file, whether the original file is local or remote
+ abstract public function mkdir($path);
+ abstract public function rmdir($path);
+ abstract public function opendir($path);
+ abstract public function is_dir($path);
+ abstract public function is_file($path);
+ abstract public function stat($path);
+ abstract public function filetype($path);
+ abstract public function filesize($path);
+ abstract public function is_readable($path);
+ abstract public function is_writable($path);
+ abstract public function file_exists($path);
+ abstract public function filectime($path);
+ abstract public function filemtime($path);
+ abstract public function file_get_contents($path);
+ abstract public function file_put_contents($path,$data);
+ abstract public function unlink($path);
+ abstract public function rename($path1,$path2);
+ abstract public function copy($path1,$path2);
+ abstract public function fopen($path,$mode);
+ abstract public function getMimeType($path);
+ abstract public function hash($type,$path,$raw);
+ abstract public function free_space($path);
+ abstract public function search($query);
+ abstract public function touch($path, $mtime=null);
+ abstract public function getLocalFile($path);// get a path to a local version of the file, whether the original file is local or remote
}
diff --git a/lib/filestorage/common.php b/lib/filestorage/common.php
new file mode 100644
index 00000000000..f632474df01
--- /dev/null
+++ b/lib/filestorage/common.php
@@ -0,0 +1,159 @@
+<?php
+
+/**
+* ownCloud
+*
+* @author Michael Gapczynski
+* @copyright 2012 Michael Gapczynski GapczynskiM@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/>.
+*/
+
+abstract class OC_Filestorage_Common extends OC_Filestorage {
+
+ public function __construct($parameters){}
+// abstract public function mkdir($path);
+// abstract public function rmdir($path);
+// abstract public function opendir($path);
+ public function is_dir($path){
+ return $this->filetype($path)=='dir';
+ }
+ public function is_file($path){
+ return $this->filetype($path)=='file';
+ }
+// abstract public function stat($path);
+// abstract public function filetype($path);
+ public function filesize($path) {
+ if($this->is_dir($path)){
+ return 0;//by definition
+ }else{
+ $stat = $this->stat($path);
+ return $stat['size'];
+ }
+ }
+// abstract public function is_readable($path);
+// abstract public function is_writable($path);
+// abstract public function file_exists($path);
+ public function filectime($path) {
+ $stat = $this->stat($path);
+ return $stat['ctime'];
+ }
+ public function filemtime($path) {
+ $stat = $this->stat($path);
+ return $stat['mtime'];
+ }
+ public function fileatime($path) {
+ $stat = $this->stat($path);
+ return $stat['atime'];
+ }
+ public function file_get_contents($path) {
+ $handle = $this->fopen($path, "r");
+ if(!$handle){
+ return false;
+ }
+ $size=$this->filesize($path);
+ if($size==0){
+ return '';
+ }
+ return fread($handle, $size);
+ }
+ public function file_put_contents($path,$data) {
+ $handle = $this->fopen($path, "w");
+ return fwrite($handle, $data);
+ }
+// abstract public function unlink($path);
+ public function rename($path1,$path2){
+ if($this->copy($path1,$path2)){
+ return $this->unlink($path1);
+ }else{
+ return false;
+ }
+ }
+ public function copy($path1,$path2) {
+ $source=$this->fopen($path1,'r');
+ $target=$this->fopen($path2,'w');
+ $count=OC_Helper::streamCopy($source,$target);
+ return $count>0;
+ }
+// abstract public function fopen($path,$mode);
+ public function getMimeType($path){
+ if(!$this->file_exists($path)){
+ return false;
+ }
+ if($this->is_dir($path)){
+ return 'httpd/unix-directory';
+ }
+ $source=$this->fopen($path,'r');
+ if(!$source){
+ return false;
+ }
+ $head=fread($source,8192);//8kb should suffice to determine a mimetype
+ if($pos=strrpos($path,'.')){
+ $extention=substr($path,$pos);
+ }else{
+ $extention='';
+ }
+ $tmpFile=OC_Helper::tmpFile($extention);
+ file_put_contents($tmpFile,$head);
+ $mime=OC_Helper::getMimeType($tmpFile);
+ unlink($tmpFile);
+ return $mime;
+ }
+ public function hash($type,$path,$raw){
+ $tmpFile=$this->getLocalFile();
+ $hash=hash($type,$tmpFile,$raw);
+ unlink($tmpFile);
+ return $hash;
+ }
+// abstract public function free_space($path);
+ public function search($query){
+ return $this->searchInDir($query);
+ }
+ public function getLocalFile($path){
+ return $this->toTmpFile($path);
+ }
+ private function toTmpFile($path){//no longer in the storage api, still usefull here
+ $source=$this->fopen($path,'r');
+ if(!$source){
+ return false;
+ }
+ if($pos=strrpos($path,'.')){
+ $extention=substr($path,$pos);
+ }else{
+ $extention='';
+ }
+ $tmpFile=OC_Helper::tmpFile($extention);
+ $target=fopen($tmpFile,'w');
+ $count=OC_Helper::streamCopy($source,$target);
+ return $tmpFile;
+ }
+// abstract public function touch($path, $mtime=null);
+
+ protected function searchInDir($query,$dir=''){
+ $files=array();
+ $dh=$this->opendir($dir);
+ if($dh){
+ while($item=readdir($dh)){
+ if ($item == '.' || $item == '..') continue;
+ if(strstr(strtolower($item),strtolower($query))!==false){
+ $files[]=$dir.'/'.$item;
+ }
+ if($this->is_dir($dir.'/'.$item)){
+ $files=array_merge($files,$this->searchInDir($query,$dir.'/'.$item));
+ }
+ }
+ }
+ return $files;
+ }
+}
diff --git a/lib/filestorage/commontest.php b/lib/filestorage/commontest.php
new file mode 100644
index 00000000000..1b01ff856a3
--- /dev/null
+++ b/lib/filestorage/commontest.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+* ownCloud
+*
+* @author Robin Appelman
+* @copyright 2012 Robin Appelman icewind@owncloud.com
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+/**
+ * test implementation for OC_FileStorage_Common with OC_FileStorage_Local
+ */
+
+class OC_Filestorage_CommonTest extends OC_Filestorage_Common{
+ /**
+ * underlying local storage used for missing functions
+ * @var OC_FileStorage_Local
+ */
+ private $storage;
+
+ public function __construct($params){
+ $this->storage=new OC_Filestorage_Local($params);
+ }
+
+ public function mkdir($path){
+ return $this->storage->mkdir($path);
+ }
+ public function rmdir($path){
+ return $this->storage->rmdir($path);
+ }
+ public function opendir($path){
+ return $this->storage->opendir($path);
+ }
+ public function stat($path){
+ return $this->storage->stat($path);
+ }
+ public function filetype($path){
+ return $this->storage->filetype($path);
+ }
+ public function is_readable($path){
+ return $this->storage->is_readable($path);
+ }
+ public function is_writable($path){
+ return $this->storage->is_writable($path);
+ }
+ public function file_exists($path){
+ return $this->storage->file_exists($path);
+ }
+ public function unlink($path){
+ return $this->storage->unlink($path);
+ }
+ public function fopen($path,$mode){
+ return $this->storage->fopen($path,$mode);
+ }
+ public function free_space($path){
+ return $this->storage->free_space($path);
+ }
+ public function touch($path, $mtime=null){
+ return $this->storage->touch($path,$mtime);
+ }
+} \ No newline at end of file
diff --git a/lib/filestorage/google.php b/lib/filestorage/google.php
index fc271f4e4ba..49985548382 100644
--- a/lib/filestorage/google.php
+++ b/lib/filestorage/google.php
@@ -20,36 +20,322 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
+require_once 'common.inc.php';
+
class OC_Filestorage_Google extends OC_Filestorage_Common {
+
+ private $datadir;
+ private $consumer;
+ private $oauth_token;
+ private $sig_method;
+ private $entries;
+
+ public function __construct($arguments) {
+ $this->datadir = $arguments['datadir'];
+ $consumer_key = isset($arguments['consumer_key']) ? $arguments['consumer_key'] : 'anonymous';
+ $consumer_secret = isset($arguments['consumer_secret']) ? $arguments['consumer_secret'] : 'anonymous';
+ $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret);
+ $this->oauth_token = new OAuthToken($arguments['token'], $arguments['token_secret']);
+ $this->sig_method = new OAuthSignatureMethod_HMAC_SHA1();
+ $this->entries = array();
+ }
+
+ private function sendRequest($feedUri, $http_method, $postData = null) {
+ $feedUri = trim($feedUri);
+ // create an associative array from each key/value url query param pair.
+ $params = array();
+ $pieces = explode('?', $feedUri);
+ if (isset($pieces[1])) {
+ $params = explode_assoc('=', '&', $pieces[1]);
+ }
+ // urlencode each url parameter key/value pair
+ $tempStr = $pieces[0];
+ foreach ($params as $key => $value) {
+ $tempStr .= '&' . urlencode($key) . '=' . urlencode($value);
+ }
+ $feedUri = preg_replace('/&/', '?', $tempStr, 1);
+ $req = OAuthRequest::from_consumer_and_token($this->consumer, $this->oauth_token, $http_method, $feedUri, $params);
+ $req->sign_request($this->sig_method, $this->consumer, $this->oauth_token);
+ $auth_header = $req->to_header();
+ $result = send_signed_request($http_method, $feedUri, array($auth_header, 'Content-Type: application/atom+xml', 'GData-Version: 3.0'), $postData);
+ // TODO Return false if error is received
+ if (!$result) {
+ return false;
+ }
+ $result = explode('<', $result, 2);
+ $result = isset($result[1]) ? '<'.$result[1] : $result[0];
+ $dom = new DOMDocument();
+ $dom->loadXML($result);
+ return $dom;
+ }
+
+ private function getResource($path) {
+ if (array_key_exists($path, $this->entries)) {
+ return $this->entries[$path];
+ } else {
+ $title = basename($path);
+ $dom = $this->sendRequest('https://docs.google.com/feeds/default/private/full?showfolders=true&title='.$title, 'GET');
+ // Check if request was successful and entry exists
+ if ($dom && $entry = $dom->getElementsByTagName('entry')->item(0)) {
+ $this->entries[$path] = $entry;
+ return $entry;
+ }
+ return false;
+ }
+ }
+
+ private function getExtension($entry) {
+ $mimetype = $this->getMimeType('', $entry);
+ switch($mimetype) {
+ case 'httpd/unix-directory':
+ return '';
+ case 'application/vnd.oasis.opendocument.text':
+ return 'odt';
+ case 'application/vnd.oasis.opendocument.spreadsheet':
+ return 'ods';
+ case 'application/vnd.oasis.opendocument.presentation':
+ return 'pptx';
+ case 'text/html':
+ return 'html';
+ default:
+ return 'html';
+ }
+ }
- private $auth;
- public function __construct($parameters) {
-
+ public function mkdir($path) {
+ $dir = dirname($path);
+ // Check if path parent is root directory
+ if ($dir == '/' || $dir == '\.' || $dir == '.') {
+ $feedUri = 'https://docs.google.com/feeds/default/private/full';
+ // Get parent content link
+ } else if ($dom = $this->getResource(basename($dir))) {
+ $feedUri = $dom->getElementsByTagName('content')->item(0)->getAttribute('src');
+ }
+ if (isset($feedUri)) {
+ $title = basename($path);
+ // Construct post data
+ $postData = '<?xml version="1.0" encoding="UTF-8"?>';
+ $postData .= '<entry xmlns="http://www.w3.org/2005/Atom">';
+ $postData .= '<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#folder"/>';
+ $postData .= '<title>'.$title.'</title>';
+ $postData .= '</entry>';
+ if ($dom = $this->sendRequest($feedUri, 'POST', $postData)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public function rmdir($path) {
+ return $this->unlink($path);
+ }
+
+ public function opendir($path) {
+ if ($path == '' || $path == '/') {
+ $next = 'https://docs.google.com/feeds/default/private/full/folder%3Aroot/contents';
+ } else {
+ if ($entry = $this->getResource($path)) {
+ $next = $entry->getElementsByTagName('content')->item(0)->getAttribute('src');
+ } else {
+ return false;
+ }
+ }
+ $files = array();
+ while ($next) {
+ $dom = $this->sendRequest($next, 'GET');
+ $links = $dom->getElementsByTagName('link');
+ foreach ($links as $link) {
+ if ($link->getAttribute('rel') == 'next') {
+ $next = $link->getAttribute('src');
+ break;
+ } else {
+ $next = false;
+ }
+ }
+ $entries = $dom->getElementsByTagName('entry');
+ foreach ($entries as $entry) {
+ $name = $entry->getElementsByTagName('title')->item(0)->nodeValue;
+ // Google Docs resources don't always include extensions in title
+ if (!strpos($name, '.')) {
+ $name .= '.'.$this->getExtension($entry);
+ }
+ $files[] = $name;
+ // Cache entry for future use
+ $this->entries[$name] = $entry;
+ }
+ }
+ OC_FakeDirStream::$dirs['google'] = $files;
+ return opendir('fakedir://google');
+ }
+
+ public function stat($path) {
+ if ($path == '' || $path == '/') {
+ $stat['size'] = $this->free_space($path);
+ $stat['atime'] = time();
+ $stat['mtime'] = time();
+ $stat['ctime'] = time();
+ } else if ($entry = $this->getResource($path)) {
+ // NOTE: Native resources don't have a file size
+ $stat['size'] = $entry->getElementsByTagNameNS('http://schemas.google.com/g/2005', 'quotaBytesUsed')->item(0)->nodeValue;
+ $stat['atime'] = strtotime($entry->getElementsByTagNameNS('http://schemas.google.com/g/2005', 'lastViewed')->item(0)->nodeValue);
+ $stat['mtime'] = strtotime($entry->getElementsByTagName('updated')->item(0)->nodeValue);
+ $stat['ctime'] = strtotime($entry->getElementsByTagName('published')->item(0)->nodeValue);
+ }
+ return $stat;
+ }
+
+ public function filetype($path) {
+ if ($path == '' || $path == '/') {
+ return 'dir';
+ } else if ($entry = $this->getResource($path)) {
+ $categories = $entry->getElementsByTagName('category');
+ foreach ($categories as $category) {
+ if ($category->getAttribute('scheme') == 'http://schemas.google.com/g/2005#kind') {
+ $type = $category->getAttribute('label');
+ if (strlen(strstr($type, 'folder')) > 0) {
+ return 'dir';
+ } else {
+ return 'file';
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public function is_readable($path) {
+ return true;
+ }
+
+ public function is_writable($path) {
+ if ($path == '' || $path == '/') {
+ return true;
+ } else if ($entry = $this->getResource($path)) {
+ // Check if edit or edit-media links exist
+ $links = $entry->getElementsByTagName('link');
+ foreach ($links as $link) {
+ if ($link->getAttribute('rel') == 'edit') {
+ return true;
+ } else if ($link->getAttribute('rel') == 'edit-media') {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public function file_exists($path) {
+ if ($path == '' || $path == '/') {
+ return true;
+ } else if ($this->getResource($path)) {
+ return true;
+ }
+ return false;
+ }
+
+ public function unlink($path) {
+ // Get resource self link to trash resource
+ if ($entry = $this->getResource($path)) {
+ $links = $entry->getElementsByTagName('link');
+ foreach ($links as $link) {
+ if ($link->getAttribute('rel') == 'self') {
+ $feedUri = $link->getAttribute('href');
+ }
+ }
+ }
+ if (isset($feedUri)) {
+ $this->sendRequest($feedUri, 'DELETE');
+ return true;
+ }
+ return false;
+ }
+
+ public function rename($path1, $path2) {
+ // TODO Add support for moving to different collections
+ // Get resource edit link to rename resource
+ if ($entry = $this->getResource($path1)) {
+ $etag = $entry->getElementsByTagName('entry')->item(0)->getAttribute('gd:etag');
+ $links = $entry->getElementsByTagName('link');
+ foreach ($links as $link) {
+ if ($link->getAttribute('rel') == 'edit') {
+ $feedUri = $link->getAttribute('href');
+ }
+ }
+ }
+ if (isset($etag) && isset($feedUri)) {
+ $title = basename($path2);
+ // Construct post data
+ $postData = '<?xml version="1.0" encoding="UTF-8"?>';
+ $postData .= '<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007" xmlns:gd="http://schemas.google.com/g/2005" gd:etag='.$etag.'>';
+ $postData .= '<title>'.$title.'</title>';
+ $postData .= '</entry>';
+ $this->sendRequest($feedUri, 'PUT', $postData);
+ return true;
+ }
+ return false;
+ }
+
+ public function fopen($path, $mode) {
+ if ($entry = $this->getResource($path)) {
+ $extension = $this->getExtension($path);
+ $downloadUri = $entry->getElementsByTagName('content')->item(0)->getAttribute('src');
+ // TODO Non-native documents don't need these additional parameters
+ $downloadUri .= '&exportFormat='.$extension.'&format='.$extension;
+ }
+ }
+
+ public function getMimeType($path, $entry = null) {
+ if ($entry == null) {
+ if ($path == '' || $path == '/') {
+ return 'httpd/unix-directory';
+ } else {
+ $entry = $this->getResource($path);
+ }
+ }
+ if ($entry) {
+ $mimetype = $entry->getElementsByTagName('content')->item(0)->getAttribute('type');
+ // Native Google Docs resources often default to text/html, but it may be more useful to default to a corresponding ODF mimetype
+ // Collections get reported as application/atom+xml, make sure it actually is a folder and fix the mimetype
+ if ($mimetype == 'text/html' || $mimetype == 'application/atom+xml') {
+ $categories = $entry->getElementsByTagName('category');
+ foreach ($categories as $category) {
+ if ($category->getAttribute('scheme') == 'http://schemas.google.com/g/2005#kind') {
+ $type = $category->getAttribute('label');
+ if (strlen(strstr($type, 'folder')) > 0) {
+ return 'httpd/unix-directory';
+ } else if (strlen(strstr($type, 'document')) > 0) {
+ return 'application/vnd.oasis.opendocument.text';
+ } else if (strlen(strstr($type, 'spreadsheet')) > 0) {
+ return 'application/vnd.oasis.opendocument.spreadsheet';
+ } else if (strlen(strstr($type, 'presentation')) > 0) {
+ return 'application/vnd.oasis.opendocument.presentation';
+ } else if (strlen(strstr($type, 'drawing')) > 0) {
+ return 'application/vnd.oasis.opendocument.graphics';
+ } else {
+ // If nothing matches return text/html, all native Google Docs resources can be exported as text/html
+ return 'text/html';
+ }
+ }
+ }
+ }
+ return $mimetype;
+ }
+ return false;
}
- private function connect() {
-
- }
- public function mkdir($path){}
- public function rmdir($path){}
- public function opendir($path){}
- public function is_dir($path){}
- public function is_file($path){}
- public function stat($path){}
- public function filetype($path){}
- public function is_readable($path){}
- public function is_writable($path){}
- public function file_exists($path){}
- public function unlink($path){}
- public function rename($path1,$path2){}
- public function fopen($path,$mode){}
- public function toTmpFile($path){}
- public function fromTmpFile($tmpPath,$path){}
- public function fromUploadedFile($tmpPath,$path){}
- public function getMimeType($path){}
- public function hash($type,$path,$raw){}
- public function free_space($path){}
- public function search($query){}
- public function getLocalFile($path){}
+ public function free_space($path) {
+ if ($dom = $this->sendRequest('https://docs.google.com/feeds/metadata/default', 'GET')) {
+ // NOTE: Native Google Docs resources don't count towards quota
+ $total = $dom->getElementsByTagNameNS('http://schemas.google.com/g/2005', 'quotaBytesTotal')->item(0)->nodeValue;
+ $used = $dom->getElementsByTagNameNS('http://schemas.google.com/g/2005', 'quotaBytesUsed')->item(0)->nodeValue;
+ return $total - $used;
+ }
+ return false;
+ }
+
+ public function search($query) {
+
+ }
+
} \ No newline at end of file
diff --git a/lib/filestorage/local.php b/lib/filestorage/local.php
index dcb516a3afb..688501aee90 100644
--- a/lib/filestorage/local.php
+++ b/lib/filestorage/local.php
@@ -21,7 +21,10 @@ class OC_Filestorage_Local extends OC_Filestorage{
return opendir($this->datadir.$path);
}
public function is_dir($path){
- return (is_dir($this->datadir.$path) or substr($path,-1)=='/');
+ if(substr($path,-1)=='/'){
+ $path=substr($path,0,-1);
+ }
+ return is_dir($this->datadir.$path);
}
public function is_file($path){
return is_file($this->datadir.$path);
@@ -52,31 +55,32 @@ class OC_Filestorage_Local extends OC_Filestorage{
public function file_exists($path){
return file_exists($this->datadir.$path);
}
- public function readfile($path){
- return readfile($this->datadir.$path);
- }
public function filectime($path){
return filectime($this->datadir.$path);
}
public function filemtime($path){
return filemtime($this->datadir.$path);
}
- public function touch($path, $mtime){
+ public function touch($path, $mtime=null){
// sets the modification time of the file to the given value.
// If mtime is nil the current time is set.
// note that the access time of the file always changes to the current time.
- if( touch( $this->datadir.$path, $mtime ) ) {
+ if(!is_null($mtime)){
+ $result=touch( $this->datadir.$path, $mtime );
+ }else{
+ $result=touch( $this->datadir.$path);
+ }
+ if( $result ) {
clearstatcache( true, $this->datadir.$path );
}
- return touch($this->datadir.$path, $mtime);
+ return $result;
}
public function file_get_contents($path){
return file_get_contents($this->datadir.$path);
}
public function file_put_contents($path,$data){
- if($return=file_put_contents($this->datadir.$path,$data)){
- }
+ return file_put_contents($this->datadir.$path,$data);
}
public function unlink($path){
return $this->delTree($path);
@@ -99,9 +103,7 @@ class OC_Filestorage_Local extends OC_Filestorage{
$source=substr($path1,strrpos($path1,'/')+1);
$path2.=$source;
}
- if($return=copy($this->datadir.$path1,$this->datadir.$path2)){
- }
- return $return;
+ return copy($this->datadir.$path1,$this->datadir.$path2);
}
public function fopen($path,$mode){
if($return=fopen($this->datadir.$path,$mode)){
@@ -122,72 +124,9 @@ class OC_Filestorage_Local extends OC_Filestorage{
return $return;
}
- public function getMimeType($fspath){
- if($this->is_readable($fspath)){
- $mimeType='application/octet-stream';
- if ($mimeType=='application/octet-stream') {
- self::$mimetypes = include('mimetypes.fixlist.php');
- $extention=strtolower(strrchr(basename($fspath), "."));
- $extention=substr($extention,1);//remove leading .
- $mimeType=(isset(self::$mimetypes[$extention]))?self::$mimetypes[$extention]:'application/octet-stream';
-
- }
- if (@is_dir($this->datadir.$fspath)) {
- // directories are easy
- return "httpd/unix-directory";
- }
- if($mimeType=='application/octet-stream' and function_exists('finfo_open') and function_exists('finfo_file') and $finfo=finfo_open(FILEINFO_MIME)){
- $mimeType =strtolower(finfo_file($finfo,$this->datadir.$fspath));
- $mimeType=substr($mimeType,0,strpos($mimeType,';'));
- finfo_close($finfo);
- }
- if ($mimeType=='application/octet-stream' && function_exists("mime_content_type")) {
- // use mime magic extension if available
- $mimeType = mime_content_type($this->datadir.$fspath);
- }
- if ($mimeType=='application/octet-stream' && OC_Helper::canExecute("file")) {
- // it looks like we have a 'file' command,
- // lets see it it does have mime support
- $fspath=str_replace("'","\'",$fspath);
- $fp = popen("file -i -b '{$this->datadir}$fspath' 2>/dev/null", "r");
- $reply = fgets($fp);
- pclose($fp);
-
- //trim the character set from the end of the response
- $mimeType=substr($reply,0,strrpos($reply,' '));
- }
- if ($mimeType=='application/octet-stream') {
- // Fallback solution: (try to guess the type by the file extension
- if(!self::$mimetypes || self::$mimetypes != include('mimetypes.list.php')){
- self::$mimetypes=include('mimetypes.list.php');
- }
- $extention=strtolower(strrchr(basename($fspath), "."));
- $extention=substr($extention,1);//remove leading .
- $mimeType=(isset(self::$mimetypes[$extention]))?self::$mimetypes[$extention]:'application/octet-stream';
- }
- return $mimeType;
- }else{
- return false;
- }
- }
-
- public function toTmpFile($path){
- $tmpFolder=get_temp_dir();
- $filename=tempnam($tmpFolder,'OC_TEMP_FILE_'.substr($path,strrpos($path,'.')));
- $fileStats = stat($this->datadir.$path);
- if(copy($this->datadir.$path,$filename)){
- touch($filename, $fileStats['mtime'], $fileStats['atime']);
- return $filename;
- }else{
- return false;
- }
- }
-
- public function fromTmpFile($tmpFile,$path){
- $fileStats = stat($tmpFile);
- if(rename($tmpFile,$this->datadir.$path)){
- touch($this->datadir.$path, $fileStats['mtime'], $fileStats['atime']);
- return true;
+ public function getMimeType($path){
+ if($this->is_readable($path)){
+ return OC_Helper::getMimeType($this->datadir.$path);
}else{
return false;
}
diff --git a/lib/filestoragecommon.php b/lib/filestoragecommon.php
deleted file mode 100644
index f522d15c4e9..00000000000
--- a/lib/filestoragecommon.php
+++ /dev/null
@@ -1,83 +0,0 @@
-<?php
-
-/**
-* ownCloud
-*
-* @author Michael Gapczynski
-* @copyright 2012 Michael Gapczynski GapczynskiM@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/>.
-*/
-
-class OC_Filestorage_Common extends OC_Filestorage {
-
- public function __construct($parameters){}
- public function mkdir($path){}
- public function rmdir($path){}
- public function opendir($path){}
- public function is_dir($path){}
- public function is_file($path){}
- public function stat($path){}
- public function filetype($path){}
- public function filesize($path) {
- $stat = $this->stat($path);
- return $stat['size'];
- }
- public function is_readable($path){}
- public function is_writable($path){}
- public function file_exists($path){}
- public function readfile($path) {
- $handle = $this->fopen($path, "r");
- $chunk = 1024;
- while (!feof($handle)) {
- echo fread($handle, $chunk);
- }
- return $this->filesize($path);
- }
- public function filectime($path) {
- $stat = $this->stat($path);
- return $stat['ctime'];
- }
- public function filemtime($path) {
- $stat = $this->stat($path);
- return $stat['mtime'];
- }
- public function fileatime($path) {
- $stat = $this->stat($path);
- return $stat['atime'];
- }
- public function file_get_contents($path) {
- $handle = $this->fopen($path, "r");
- return fread($handle, $this->filesize($path));
- }
- public function file_put_contents($path,$data) {
- $handle = $this->fopen($path, "w");
- return fwrite($handle, $data);
- }
- public function unlink($path){}
- public function rename($path1,$path2){}
- public function copy($path1,$path2) {
- $data = $this->file_get_contents($path1);
- return $this->file_put_contents($path2, $data);
- }
- public function fopen($path,$mode){}
- public function toTmpFile($path){}
- public function fromTmpFile($tmpPath,$path){}
- public function fromUploadedFile($tmpPath,$path){}
- public function getMimeType($path){}
- public function hash($type,$path,$raw){}
- public function free_space($path){}
- public function search($query){}
- public function getLocalFile($path){}
-}
diff --git a/lib/filesystem.php b/lib/filesystem.php
index 90195bc2130..12905d189f9 100644
--- a/lib/filesystem.php
+++ b/lib/filesystem.php
@@ -146,20 +146,15 @@ class OC_Filesystem{
* @return string
*/
static public function getMountPoint($path){
+ OC_Hook::emit(self::CLASSNAME,'get_mountpoint',array('path'=>$path));
if(!$path){
$path='/';
}
if(substr($path,0,1)!=='/'){
$path='/'.$path;
}
- if(substr($path,-1)!=='/'){
- $path=$path.'/';
- }
$foundMountPoint='';
foreach(OC_Filesystem::$mounts as $mountpoint=>$storage){
- if(substr($mountpoint,-1)!=='/'){
- $mountpoint=$mountpoint.'/';
- }
if($mountpoint==$path){
return $mountpoint;
}
@@ -259,6 +254,9 @@ class OC_Filesystem{
* @param string mountpoint
*/
static public function mount($class,$arguments,$mountpoint){
+ if(substr($mountpoint,-1)!=='/'){
+ $mountpoint=$mountpoint.'/';
+ }
if(substr($mountpoint,0,1)!=='/'){
$mountpoint='/'.$mountpoint;
}
@@ -345,7 +343,7 @@ class OC_Filesystem{
static public function filemtime($path){
return self::$defaultInstance->filemtime($path);
}
- static public function touch($path, $mtime){
+ static public function touch($path, $mtime=null){
return self::$defaultInstance->touch($path, $mtime);
}
static public function file_get_contents($path){
diff --git a/lib/filesystemview.php b/lib/filesystemview.php
index 91c6cd17720..89e0385fe9c 100644
--- a/lib/filesystemview.php
+++ b/lib/filesystemview.php
@@ -136,7 +136,14 @@ class OC_FilesystemView {
return $this->basicOperation('filesize',$path);
}
public function readfile($path){
- return $this->basicOperation('readfile',$path,array('read'));
+ $handle=$this->fopen($path,'r');
+ $chunkSize = 1024*1024;// 1 MB chunks
+ while (!feof($handle)) {
+ echo fread($handle, $chunkSize);
+ @ob_flush();
+ flush();
+ }
+ return $this->filesize($path);
}
public function is_readable($path){
return $this->basicOperation('is_readable',$path);
@@ -156,14 +163,27 @@ class OC_FilesystemView {
public function filemtime($path){
return $this->basicOperation('filemtime',$path);
}
- public function touch($path, $mtime){
+ public function touch($path, $mtime=null){
return $this->basicOperation('touch', $path, array('write'), $mtime);
}
public function file_get_contents($path){
return $this->basicOperation('file_get_contents',$path,array('read'));
}
public function file_put_contents($path,$data){
- return $this->basicOperation('file_put_contents',$path,array('create','write'),$data);
+ if(is_resource($data)){//not having to deal with streams in file_put_contents makes life easier
+ $target=$this->fopen($path,'w');
+ if($target){
+ $count=OC_Helper::streamCopy($data,$target);
+ fclose($target);
+ fclose($data);
+ OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_write, array( OC_Filesystem::signal_param_path => $path));
+ return $count>0;
+ }else{
+ return false;
+ }
+ }else{
+ return $this->basicOperation('file_put_contents',$path,array('create','write'),$data);
+ }
}
public function unlink($path){
return $this->basicOperation('unlink',$path,array('delete'));
@@ -179,10 +199,13 @@ class OC_FilesystemView {
if($storage=$this->getStorage($path1)){
$result=$storage->rename($this->getInternalPath($path1),$this->getInternalPath($path2));
}
- }elseif($storage1=$this->getStorage($path1) and $storage2=$this->getStorage($path2)){
- $tmpFile=$storage1->toTmpFile($this->getInternalPath($path1));
- $result=$storage2->fromTmpFile($tmpFile,$this->getInternalPath($path2));
+ }else{
+ $source=$this->fopen($path1,'r');
+ $target=$this->fopen($path2,'w');
+ $count=OC_Helper::streamCopy($data,$target);
+ $storage1=$this->getStorage($path1);
$storage1->unlink($this->getInternalPath($path1));
+ $result=$count>0;
}
OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_rename, array( OC_Filesystem::signal_param_oldpath => $path1, OC_Filesystem::signal_param_newpath=>$path2));
return $result;
@@ -207,9 +230,10 @@ class OC_FilesystemView {
if($storage=$this->getStorage($path1)){
$result=$storage->copy($this->getInternalPath($path1),$this->getInternalPath($path2));
}
- }elseif($storage1=$this->getStorage($path1) and $storage2=$this->getStorage($path2)){
- $tmpFile=$storage1->toTmpFile($this->getInternalPath($path1));
- $result=$storage2->fromTmpFile($tmpFile,$this->getInternalPath($path2));
+ }else{
+ $source=$this->fopen($path1,'r');
+ $target=$this->fopen($path2,'w');
+ $count=OC_Helper::streamCopy($data,$target);
}
OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_copy, array( OC_Filesystem::signal_param_oldpath => $path1 , OC_Filesystem::signal_param_newpath=>$path2));
if(!$exists){
@@ -224,18 +248,26 @@ class OC_FilesystemView {
$hooks=array();
switch($mode){
case 'r':
+ case 'rb':
$hooks[]='read';
break;
case 'r+':
+ case 'rb+':
case 'w+':
+ case 'wb+':
case 'x+':
+ case 'xb+':
case 'a+':
+ case 'ab+':
$hooks[]='read';
$hooks[]='write';
break;
case 'w':
+ case 'wb':
case 'x':
+ case 'xb':
case 'a':
+ case 'ab':
$hooks[]='write';
break;
default:
@@ -245,29 +277,29 @@ class OC_FilesystemView {
return $this->basicOperation('fopen',$path,$hooks,$mode);
}
public function toTmpFile($path){
- if(OC_FileProxy::runPreProxies('toTmpFile',$path) and OC_Filesystem::isValidPath($path) and $storage=$this->getStorage($path)){
- OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_read, array( OC_Filesystem::signal_param_path => $path));
- return $storage->toTmpFile($this->getInternalPath($path));
+ if(OC_Filesystem::isValidPath($path)){
+ $source=$this->fopen($path,'r');
+ if($source){
+ $extention=substr($path,strrpos($path,'.'));
+ $tmpFile=OC_Helper::tmpFile($extention);
+ return file_put_contents($tmpFile,$source);
+ }
}
}
public function fromTmpFile($tmpFile,$path){
- if(OC_FileProxy::runPreProxies('copy',$tmpFile,$path) and OC_Filesystem::isValidPath($path) and $storage=$this->getStorage($path)){
- $run=true;
- $exists=$this->file_exists($path);
- if(!$exists){
- OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_create, array( OC_Filesystem::signal_param_path => $path, OC_Filesystem::signal_param_run => &$run));
+ if(OC_Filesystem::isValidPath($path)){
+ if(!$tmpFile){
+ debug_print_backtrace();
}
- if($run){
- OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_write, array( OC_Filesystem::signal_param_path => $path, OC_Filesystem::signal_param_run => &$run));
- }
- if($run){
- $result=$storage->fromTmpFile($tmpFile,$this->getInternalPath($path));
- if(!$exists){
- OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_create, array( OC_Filesystem::signal_param_path => $path));
- }
- OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_write, array( OC_Filesystem::signal_param_path => $path));
- return $result;
+ $source=fopen($tmpFile,'r');
+ if($source){
+ $this->file_put_contents($path,$source);
+ unlink($tmpFile);
+ return true;
+ }else{
}
+ }else{
+ return false;
}
}
@@ -291,26 +323,32 @@ class OC_FilesystemView {
* @return mixed
*/
private function basicOperation($operation,$path,$hooks=array(),$extraParam=null){
- if(OC_FileProxy::runPreProxies($operation,$path, $extraParam) and OC_Filesystem::isValidPath($path) and $storage=$this->getStorage($path)){
+ if(OC_FileProxy::runPreProxies($operation,$path, $extraParam) and OC_Filesystem::isValidPath($path)){
$interalPath=$this->getInternalPath($path);
$run=true;
- foreach($hooks as $hook){
- if($hook!='read'){
- OC_Hook::emit( OC_Filesystem::CLASSNAME, $hook, array( OC_Filesystem::signal_param_path => $path, OC_Filesystem::signal_param_run => &$run));
- }else{
- OC_Hook::emit( OC_Filesystem::CLASSNAME, $hook, array( OC_Filesystem::signal_param_path => $path));
+ if(OC_Filesystem::$loaded and $this->fakeRoot==OC_Filesystem::getRoot()){
+ foreach($hooks as $hook){
+ if($hook!='read'){
+ OC_Hook::emit( OC_Filesystem::CLASSNAME, $hook, array( OC_Filesystem::signal_param_path => $path, OC_Filesystem::signal_param_run => &$run));
+ }else{
+ OC_Hook::emit( OC_Filesystem::CLASSNAME, $hook, array( OC_Filesystem::signal_param_path => $path));
+ }
}
}
- if($run){
- if($extraParam){
+ if($run and $storage=$this->getStorage($path)){
+ if(!is_null($extraParam)){
$result=$storage->$operation($interalPath,$extraParam);
}else{
$result=$storage->$operation($interalPath);
}
$result=OC_FileProxy::runPostProxies($operation,$path,$result);
- foreach($hooks as $hook){
- if($hook!='read'){
- OC_Hook::emit( OC_Filesystem::CLASSNAME, 'post_'.$hook, array( OC_Filesystem::signal_param_path => $path));
+ if(OC_Filesystem::$loaded and $this->fakeRoot==OC_Filesystem::getRoot()){
+ if($operation!='fopen'){//no post hooks for fopen, the file stream is still open
+ foreach($hooks as $hook){
+ if($hook!='read'){
+ OC_Hook::emit( OC_Filesystem::CLASSNAME, 'post_'.$hook, array( OC_Filesystem::signal_param_path => $path));
+ }
+ }
}
}
return $result;
diff --git a/lib/geo.php b/lib/geo.php
new file mode 100644
index 00000000000..a967ab28a96
--- /dev/null
+++ b/lib/geo.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Copyright (c) 2012 Georg Ehrke <ownclouddev at georgswebsite dot de>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+class OC_Geo{
+ /*
+ * @brief returns the closest timezone to coordinates
+ * @param (string) $latitude - Latitude
+ * @param (string) $longitude - Longitude
+ * @return (string) $timezone - closest timezone
+ */
+ public static function timezone($latitude, $longitude){
+ $alltimezones = DateTimeZone::listIdentifiers();
+ $variances = array();
+ //calculate for all timezones the system know
+ foreach($alltimezones as $timezone){
+ $datetimezoneobj = new DateTimeZone($timezone);
+ $locationinformations = $datetimezoneobj->getLocation();
+ $latitudeoftimezone = $locationinformations['latitude'];
+ $longitudeoftimezone = $locationinformations['longitude'];
+ $variances[abs($latitudeoftimezone - $latitude) + abs($longitudeoftimezone - $longitude)] = $timezone;
+ }
+ //sort array and return the timezone with the smallest difference
+ ksort($variances);
+ reset($variances);
+ return current($variances);
+ }
+} \ No newline at end of file
diff --git a/lib/helper.php b/lib/helper.php
index 2f71bdad2dc..0c6c73aa76b 100644
--- a/lib/helper.php
+++ b/lib/helper.php
@@ -25,6 +25,9 @@
* Collection of useful functions
*/
class OC_Helper {
+ private static $mimetypes=array();
+ private static $tmpFiles=array();
+
/**
* @brief Creates an url
* @param $app app
@@ -37,8 +40,8 @@ class OC_Helper {
if( $app != '' ){
$app .= '/';
// Check if the app is in the app folder
- if( file_exists( OC::$SERVERROOT . '/apps/'. $app.$file )){
- $urlLinkTo = OC::$WEBROOT . '/apps/' . $app . $file;
+ if( file_exists( OC::$APPSROOT . '/apps/'. $app.$file )){
+ $urlLinkTo = OC::$APPSWEBROOT . '/apps/' . $app . $file;
}
else{
$urlLinkTo = OC::$WEBROOT . '/' . $app . $file;
@@ -81,24 +84,27 @@ class OC_Helper {
* Returns the path to the image.
*/
public static function imagePath( $app, $image ){
- // Read the selected theme from the config file
- $theme=OC_Config::getValue( "theme" );
+ // Read the selected theme from the config file
+ $theme=OC_Config::getValue( "theme" );
- // Check if the app is in the app folder
- if( file_exists( OC::$SERVERROOT."/themes/$theme/apps/$app/img/$image" )){
- return OC::$WEBROOT."/themes/$theme/apps/$app/img/$image";
- }elseif( file_exists( OC::$SERVERROOT."/apps/$app/img/$image" )){
- return OC::$WEBROOT."/apps/$app/img/$image";
- }elseif( !empty( $app ) and file_exists( OC::$SERVERROOT."/themes/$theme/$app/img/$image" )){
- return OC::$WEBROOT."/themes/$theme/$app/img/$image";
- }elseif( !empty( $app ) and file_exists( OC::$SERVERROOT."/$app/img/$image" )){
- return OC::$WEBROOT."/$app/img/$image";
- }elseif( file_exists( OC::$SERVERROOT."/themes/$theme/core/img/$image" )){
- return OC::$WEBROOT."/themes/$theme/core/img/$image";
- }else{
- return OC::$WEBROOT."/core/img/$image";
- }
- }
+ // Check if the app is in the app folder
+ if( file_exists( OC::$SERVERROOT."/themes/$theme/apps/$app/img/$image" )){
+ return OC::$WEBROOT."/themes/$theme/apps/$app/img/$image";
+ }elseif( file_exists( OC::$APPSROOT."/apps/$app/img/$image" )){
+ return OC::$APPSWEBROOT."/apps/$app/img/$image";
+ }elseif( !empty( $app ) and file_exists( OC::$SERVERROOT."/themes/$theme/$app/img/$image" )){
+ return OC::$WEBROOT."/themes/$theme/$app/img/$image";
+ }elseif( !empty( $app ) and file_exists( OC::$SERVERROOT."/$app/img/$image" )){
+ return OC::$WEBROOT."/$app/img/$image";
+ }elseif( file_exists( OC::$SERVERROOT."/themes/$theme/core/img/$image" )){
+ return OC::$WEBROOT."/themes/$theme/core/img/$image";
+ }elseif( file_exists( OC::$SERVERROOT."/core/img/$image" )){
+ return OC::$WEBROOT."/core/img/$image";
+ }else{
+ echo('image not found: image:'.$image.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT);
+ die();
+ }
+ }
/**
* @brief get path to icon of file type
@@ -194,7 +200,7 @@ class OC_Helper {
$bytes *= $bytes_array[$matches[1]];
}
- $bytes = intval(round($bytes, 2));
+ $bytes = round($bytes, 2);
return $bytes;
}
@@ -267,6 +273,62 @@ class OC_Helper {
unlink($dir);
}
}
+
+ /**
+ * get the mimetype form a local file
+ * @param string path
+ * @return string
+ * does NOT work for ownClouds filesystem, use OC_FileSystem::getMimeType instead
+ */
+ static function getMimeType($path){
+ $isWrapped=(strpos($path,'://')!==false) and (substr($path,0,7)=='file://');
+ $mimeType='application/octet-stream';
+ if ($mimeType=='application/octet-stream') {
+ if(count(self::$mimetypes)>0){
+ self::$mimetypes = include('mimetypes.fixlist.php');
+ }
+ $extention=strtolower(strrchr(basename($path), "."));
+ $extention=substr($extention,1);//remove leading .
+ $mimeType=(isset(self::$mimetypes[$extention]))?self::$mimetypes[$extention]:'application/octet-stream';
+
+ }
+ if (@is_dir($path)) {
+ // directories are easy
+ return "httpd/unix-directory";
+ }
+ if($mimeType=='application/octet-stream' and function_exists('finfo_open') and function_exists('finfo_file') and $finfo=finfo_open(FILEINFO_MIME)){
+ $info = @strtolower(finfo_file($finfo,$path));
+ if($info){
+ $mimeType=substr($info,0,strpos($info,';'));
+ }
+ finfo_close($finfo);
+ }
+ if (!$isWrapped and $mimeType=='application/octet-stream' && function_exists("mime_content_type")) {
+ // use mime magic extension if available
+ $mimeType = mime_content_type($path);
+ }
+ if (!$isWrapped and $mimeType=='application/octet-stream' && OC_Helper::canExecute("file")) {
+ // it looks like we have a 'file' command,
+ // lets see it it does have mime support
+ $path=str_replace("'","\'",$path);
+ $fp = popen("file -i -b '$path' 2>/dev/null", "r");
+ $reply = fgets($fp);
+ pclose($fp);
+
+ //trim the character set from the end of the response
+ $mimeType=substr($reply,0,strrpos($reply,' '));
+ }
+ if ($mimeType=='application/octet-stream') {
+ // Fallback solution: (try to guess the type by the file extension
+ if(!self::$mimetypes || self::$mimetypes != include('mimetypes.list.php')){
+ self::$mimetypes=include('mimetypes.list.php');
+ }
+ $extention=strtolower(strrchr(basename($path), "."));
+ $extention=substr($extention,1);//remove leading .
+ $mimeType=(isset(self::$mimetypes[$extention]))?self::$mimetypes[$extention]:'application/octet-stream';
+ }
+ return $mimeType;
+ }
/**
* @brief Checks $_REQUEST contains a var for the $s key. If so, returns the html-escaped value of this var; otherwise returns the default value provided by $d.
@@ -340,4 +402,47 @@ class OC_Helper {
}
return false;
}
+
+ /**
+ * copy the contents of one stream to another
+ * @param resource source
+ * @param resource target
+ * @return int the number of bytes copied
+ */
+ public static function streamCopy($source,$target){
+ if(!$source or !$target){
+ return false;
+ }
+ $count=0;
+ while(!feof($source)){
+ $count+=fwrite($target,fread($source,8192));
+ }
+ return $count;
+ }
+
+ /**
+ * create a temporary file with an unique filename
+ * @param string postfix
+ * @return string
+ *
+ * temporary files are automatically cleaned up after the script is finished
+ */
+ public static function tmpFile($postfix=''){
+ $file=get_temp_dir().'/'.md5(time().rand()).$postfix;
+ $fh=fopen($file,'w');
+ fclose($fh);
+ self::$tmpFiles[]=$file;
+ return $file;
+ }
+
+ /**
+ * remove all files created by self::tmpFile
+ */
+ public static function cleanTmp(){
+ foreach(self::$tmpFiles as $file){
+ if(file_exists($file)){
+ unlink($file);
+ }
+ }
+ }
}
diff --git a/lib/image.php b/lib/image.php
index fe8349be543..60a714880d0 100644
--- a/lib/image.php
+++ b/lib/image.php
@@ -216,7 +216,7 @@ class OC_Image {
OC_Log::write('core','OC_Image->fixOrientation() No readable file path set.', OC_Log::DEBUG);
return false;
}
- $exif = exif_read_data($this->filepath, 'IFD0');
+ $exif = @exif_read_data($this->filepath, 'IFD0');
if(!$exif) {
return false;
}
diff --git a/lib/installer.php b/lib/installer.php
index b2f817e702f..2a9676998f6 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=tempnam(get_temp_dir(),'oc_installer_');
+ $path=OC_Helper::tmpFile('.zip');
if(!isset($data['href'])){
OC_Log::write('core','No href specified when installing app from http',OC_Log::ERROR);
return false;
@@ -103,7 +103,7 @@ class OC_Installer{
return false;
}
$info=OC_App::getAppInfo($extractDir.'/appinfo/info.xml');
- $basedir=OC::$SERVERROOT.'/apps/'.$info['id'];
+ $basedir=OC::$APPSROOT.'/apps/'.$info['id'];
//check if an app with the same id is already installed
if(self::isInstalled( $info['id'] )){
@@ -142,9 +142,6 @@ class OC_Installer{
//remove temporary files
OC_Helper::rmdirr($extractDir);
- if($data['source']=='http'){
- unlink($path);
- }
//install the database
if(is_file($basedir.'/appinfo/database.xml')){
@@ -244,10 +241,10 @@ class OC_Installer{
* If $enabled is false, apps are installed as disabled.
*/
public static function installShippedApps(){
- $dir = opendir( OC::$SERVERROOT."/apps" );
+ $dir = opendir( OC::$APPSROOT."/apps" );
while( false !== ( $filename = readdir( $dir ))){
- if( substr( $filename, 0, 1 ) != '.' and is_dir(OC::$SERVERROOT."/apps/$filename") ){
- if( file_exists( OC::$SERVERROOT."/apps/$filename/appinfo/app.php" )){
+ if( substr( $filename, 0, 1 ) != '.' and is_dir(OC::$APPSROOT."/apps/$filename") ){
+ if( file_exists( OC::$APPSROOT."/apps/$filename/appinfo/app.php" )){
if(!OC_Installer::isInstalled($filename)){
$info = OC_Installer::installShippedApp($filename);
$enabled = isset($info['default_enable']);
@@ -270,15 +267,15 @@ class OC_Installer{
*/
public static function installShippedApp($app){
//install the database
- if(is_file(OC::$SERVERROOT."/apps/$app/appinfo/database.xml")){
- OC_DB::createDbFromStructure(OC::$SERVERROOT."/apps/$app/appinfo/database.xml");
+ if(is_file(OC::$APPSROOT."/apps/$app/appinfo/database.xml")){
+ OC_DB::createDbFromStructure(OC::$APPSROOT."/apps/$app/appinfo/database.xml");
}
//run appinfo/install.php
- if(is_file(OC::$SERVERROOT."/apps/$app/appinfo/install.php")){
- include(OC::$SERVERROOT."/apps/$app/appinfo/install.php");
+ if(is_file(OC::$APPSROOT."/apps/$app/appinfo/install.php")){
+ include(OC::$APPSROOT."/apps/$app/appinfo/install.php");
}
- $info=OC_App::getAppInfo(OC::$SERVERROOT."/apps/$app/appinfo/info.xml");
+ $info=OC_App::getAppInfo(OC::$APPSROOT."/apps/$app/appinfo/info.xml");
OC_Appconfig::setValue($app,'installed_version',$info['version']);
return $info;
}
diff --git a/lib/l10n.php b/lib/l10n.php
index a5544eb3a27..636326f9864 100644
--- a/lib/l10n.php
+++ b/lib/l10n.php
@@ -243,8 +243,8 @@ class OC_L10N{
$i18ndir = OC::$SERVERROOT.'/core/l10n/';
if($app != ''){
// Check if the app is in the app folder
- if(file_exists(OC::$SERVERROOT.'/apps/'.$app.'/l10n/')){
- $i18ndir = OC::$SERVERROOT.'/apps/'.$app.'/l10n/';
+ if(file_exists(OC::$APPSROOT.'/apps/'.$app.'/l10n/')){
+ $i18ndir = OC::$APPSROOT.'/apps/'.$app.'/l10n/';
}
else{
$i18ndir = OC::$SERVERROOT.'/'.$app.'/l10n/';
diff --git a/lib/log.php b/lib/log.php
index 446ddd48848..4e450a027f5 100644
--- a/lib/log.php
+++ b/lib/log.php
@@ -3,7 +3,7 @@
* ownCloud
*
* @author Robin Appelman
- * @copyright 2011 Robin Appelman icewind1991@gmail.com
+ * @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
@@ -50,25 +50,29 @@ class OC_Log{
fclose($fh);
}
}
-
- public static function getEntries(){
+
+ /**
+ * 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();
}
- $fh=fopen($logFile,'r');
- if($fh === false){ // Unable to read log file!
+ $contents=file($logFile);
+ if(!$contents){//error while reading log
return array();
}
- while(!feof($fh)){
- $line=fgets($fh);
- if($line){
- $entries[]=json_decode($line);
- }
+ $end=max(count($contents)-$offset-1,0);
+ $start=max($end-$limit,0);
+ for($i=$end;$i>$start;$i--){
+ $entries[]=json_decode($contents[$i]);
}
- fclose($fh);
return $entries;
}
}
diff --git a/lib/search.php b/lib/search.php
index f6f805bfe65..6b33fa38140 100644
--- a/lib/search.php
+++ b/lib/search.php
@@ -29,7 +29,7 @@ class OC_Search{
/**
* register a new search provider to be used
- * @param OC_Search_Provider $provider
+ * @param string $provider class name of a OC_Search_Provider
*/
public static function registerProvider($provider){
self::$providers[]=$provider;
@@ -43,7 +43,7 @@ class OC_Search{
public static function search($query){
$results=array();
foreach(self::$providers as $provider){
- $results=array_merge($results,$provider->search($query));
+ $results=array_merge($results, $provider::search($query));
}
return $results;
}
diff --git a/lib/search/provider.php b/lib/search/provider.php
index cceed8b04a3..9487ca51f2b 100644
--- a/lib/search/provider.php
+++ b/lib/search/provider.php
@@ -2,15 +2,11 @@
/**
* provides search functionalty
*/
-abstract class OC_Search_Provider{
- public function __construct(){
- OC_Search::registerProvider($this);
- }
-
+interface OC_Search_Provider {
/**
* search for $query
* @param string $query
* @return array An array of OC_Search_Result's
*/
- abstract function search($query);
+ static function search($query);
}
diff --git a/lib/search/provider/file.php b/lib/search/provider/file.php
index 34803c75aeb..3bdb3bcd2af 100644
--- a/lib/search/provider/file.php
+++ b/lib/search/provider/file.php
@@ -1,15 +1,15 @@
<?php
-class OC_Search_Provider_File extends OC_Search_Provider{
- function search($query){
+class OC_Search_Provider_File implements OC_Search_Provider{
+ static function search($query){
$files=OC_FileCache::search($query,true);
$results=array();
foreach($files as $fileData){
$file=$fileData['path'];
- if($fileData['mime']=='httpd/unix-directory'){
+ $mime=$fileData['mimetype'];
+ if($mime=='httpd/unix-directory'){
$results[]=new OC_Search_Result(basename($file),'',OC_Helper::linkTo( 'files', 'index.php' ).'?dir='.$file,'Files');
}else{
- $mime=$fileData['mime'];
$mimeBase=$fileData['mimepart'];
switch($mimeBase){
case 'audio':
diff --git a/lib/streamwrappers.php b/lib/streamwrappers.php
new file mode 100644
index 00000000000..f1e0fa0e1d9
--- /dev/null
+++ b/lib/streamwrappers.php
@@ -0,0 +1,306 @@
+<?php
+global $FAKEDIRS;
+$FAKEDIRS=array();
+
+class OC_FakeDirStream{
+ public static $dirs=array();
+ private $name;
+ private $index;
+
+ public function dir_opendir($path,$options){
+ global $FAKEDIRS;
+ $url=parse_url($path);
+ $this->name=substr($path,strlen('fakedir://'));
+ $this->index=0;
+ if(!isset(self::$dirs[$this->name])){
+ self::$dirs[$this->name]=array();
+ }
+ return true;
+ }
+
+ public function dir_readdir(){
+ if($this->index>=count(self::$dirs[$this->name])){
+ return false;
+ }
+ $filename=self::$dirs[$this->name][$this->index];
+ $this->index++;
+ return $filename;
+ }
+
+ public function dir_closedir() {
+ $this->name='';
+ return true;
+ }
+
+ public function dir_rewinddir() {
+ $this->index=0;
+ return true;
+ }
+}
+
+class OC_StaticStreamWrapper {
+ public $context;
+ protected static $data = array();
+
+ protected $path = '';
+ protected $pointer = 0;
+ protected $writable = false;
+
+ public function stream_close() {}
+
+ public function stream_eof() {
+ return $this->pointer >= strlen(self::$data[$this->path]);
+ }
+
+ public function stream_flush() {}
+
+ public function stream_open($path, $mode, $options, &$opened_path) {
+ switch ($mode[0]) {
+ case 'r':
+ if (!isset(self::$data[$path])) return false;
+ $this->path = $path;
+ $this->writable = isset($mode[1]) && $mode[1] == '+';
+ break;
+ case 'w':
+ self::$data[$path] = '';
+ $this->path = $path;
+ $this->writable = true;
+ break;
+ case 'a':
+ if (!isset(self::$data[$path])) self::$data[$path] = '';
+ $this->path = $path;
+ $this->writable = true;
+ $this->pointer = strlen(self::$data[$path]);
+ break;
+ case 'x':
+ if (isset(self::$data[$path])) return false;
+ $this->path = $path;
+ $this->writable = true;
+ break;
+ case 'c':
+ if (!isset(self::$data[$path])) self::$data[$path] = '';
+ $this->path = $path;
+ $this->writable = true;
+ break;
+ default:
+ return false;
+ }
+ $opened_path = $this->path;
+ return true;
+ }
+
+ public function stream_read($count) {
+ $bytes = min(strlen(self::$data[$this->path]) - $this->pointer, $count);
+ $data = substr(self::$data[$this->path], $this->pointer, $bytes);
+ $this->pointer += $bytes;
+ return $data;
+ }
+
+ public function stream_seek($offset, $whence = SEEK_SET) {
+ $len = strlen(self::$data[$this->path]);
+ switch ($whence) {
+ case SEEK_SET:
+ if ($offset <= $len) {
+ $this->pointer = $offset;
+ return true;
+ }
+ break;
+ case SEEK_CUR:
+ if ($this->pointer + $offset <= $len) {
+ $this->pointer += $offset;
+ return true;
+ }
+ break;
+ case SEEK_END:
+ if ($len + $offset <= $len) {
+ $this->pointer = $len + $offset;
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
+ public function stream_stat() {
+ $size = strlen(self::$data[$this->path]);
+ $time = time();
+ return array(
+ 0 => 0,
+ 'dev' => 0,
+ 1 => 0,
+ 'ino' => 0,
+ 2 => 0777,
+ 'mode' => 0777,
+ 3 => 1,
+ 'nlink' => 1,
+ 4 => 0,
+ 'uid' => 0,
+ 5 => 0,
+ 'gid' => 0,
+ 6 => '',
+ 'rdev' => '',
+ 7 => $size,
+ 'size' => $size,
+ 8 => $time,
+ 'atime' => $time,
+ 9 => $time,
+ 'mtime' => $time,
+ 10 => $time,
+ 'ctime' => $time,
+ 11 => -1,
+ 'blksize' => -1,
+ 12 => -1,
+ 'blocks' => -1,
+ );
+ }
+
+ public function stream_tell() {
+ return $this->pointer;
+ }
+
+ public function stream_write($data) {
+ if (!$this->writable) return 0;
+ $size = strlen($data);
+ $len = strlen(self::$data[$this->path]);
+ if ($this->stream_eof()) {
+ self::$data[$this->path] .= $data;
+ } else {
+ self::$data[$this->path] = substr_replace(
+ self::$data[$this->path],
+ $data,
+ $this->pointer
+ );
+ }
+ $this->pointer += $size;
+ return $size;
+ }
+
+ public function unlink($path) {
+ if (isset(self::$data[$path])) {
+ unset(self::$data[$path]);
+ }
+ return true;
+ }
+
+ public function url_stat($path) {
+ if (isset(self::$data[$path])) {
+ $size = strlen(self::$data[$path]);
+ $time = time();
+ return array(
+ 0 => 0,
+ 'dev' => 0,
+ 1 => 0,
+ 'ino' => 0,
+ 2 => 0777,
+ 'mode' => 0777,
+ 3 => 1,
+ 'nlink' => 1,
+ 4 => 0,
+ 'uid' => 0,
+ 5 => 0,
+ 'gid' => 0,
+ 6 => '',
+ 'rdev' => '',
+ 7 => $size,
+ 'size' => $size,
+ 8 => $time,
+ 'atime' => $time,
+ 9 => $time,
+ 'mtime' => $time,
+ 10 => $time,
+ 'ctime' => $time,
+ 11 => -1,
+ 'blksize' => -1,
+ 12 => -1,
+ 'blocks' => -1,
+ );
+ }
+ return false;
+ }
+}
+
+/**
+ * stream wrapper that provides a callback on stream close
+ */
+class OC_CloseStreamWrapper{
+ public static $callBacks=array();
+ private $path='';
+ private $source;
+ private static $open=array();
+ public function stream_open($path, $mode, $options, &$opened_path){
+ $path=substr($path,strlen('close://'));
+ $this->path=$path;
+ $this->source=fopen($path,$mode);
+ if(is_resource($this->source)){
+ $this->meta=stream_get_meta_data($this->source);
+ }
+ self::$open[]=$path;
+ return is_resource($this->source);
+ }
+
+ public function stream_seek($offset, $whence=SEEK_SET){
+ fseek($this->source,$offset,$whence);
+ }
+
+ public function stream_tell(){
+ return ftell($this->source);
+ }
+
+ public function stream_read($count){
+ return fread($this->source,$count);
+ }
+
+ public function stream_write($data){
+ return fwrite($this->source,$data);
+ }
+
+ public function stream_set_option($option,$arg1,$arg2){
+ switch($option){
+ case STREAM_OPTION_BLOCKING:
+ stream_set_blocking($this->source,$arg1);
+ break;
+ case STREAM_OPTION_READ_TIMEOUT:
+ stream_set_timeout($this->source,$arg1,$arg2);
+ break;
+ case STREAM_OPTION_WRITE_BUFFER:
+ stream_set_write_buffer($this->source,$arg1,$arg2);
+ }
+ }
+
+ public function stream_stat(){
+ return fstat($this->source);
+ }
+
+ public function stream_lock($mode){
+ flock($this->source,$mode);
+ }
+
+ public function stream_flush(){
+ return fflush($this->source);
+ }
+
+ public function stream_eof(){
+ return feof($this->source);
+ }
+
+ public function url_stat($path) {
+ $path=substr($path,strlen('close://'));
+ if(file_exists($path)){
+ return stat($path);
+ }else{
+ return false;
+ }
+ }
+
+ public function stream_close(){
+ fclose($this->source);
+ if(isset(self::$callBacks[$this->path])){
+ call_user_func(self::$callBacks[$this->path],$this->path);
+ }
+ }
+
+ public function unlink($path){
+ $path=substr($path,strlen('close://'));
+ return unlink($path);
+ }
+}
diff --git a/lib/template.php b/lib/template.php
index 5fe2eb7d6c7..eea2925975c 100644
--- a/lib/template.php
+++ b/lib/template.php
@@ -171,7 +171,7 @@ class OC_Template{
// Check if it is a app template or not.
if( $app != "" ){
// Check if the app is in the app folder or in the root
- if( file_exists( OC::$SERVERROOT."/apps/$app/templates/" )){
+ if( file_exists( OC::$APPSROOT."/apps/$app/templates/" )){
// Check if the template is overwritten by the selected theme
if( file_exists( OC::$SERVERROOT."/themes/$theme/apps/$app/templates/"."$name$fext.php" )){
$template = OC::$SERVERROOT."/themes/$theme/apps/$app/templates/"."$name$fext.php";
@@ -179,12 +179,12 @@ class OC_Template{
}elseif( file_exists( OC::$SERVERROOT."/themes/$theme/apps/$app/templates/"."$name.php" )){
$template = OC::$SERVERROOT."/themes/$theme/apps/$app/templates/"."$name.php";
$path = OC::$SERVERROOT."/themes/$theme/apps/$app/templates/";
- }elseif( OC::$SERVERROOT."/apps/$app/templates/"."$name$fext.php" ){
- $template = OC::$SERVERROOT."/apps/$app/templates/"."$name$fext.php";
- $path = OC::$SERVERROOT."/apps/$app/templates/";
+ }elseif( OC::$APPSROOT."/apps/$app/templates/"."$name$fext.php" ){
+ $template = OC::$APPSROOT."/apps/$app/templates/"."$name$fext.php";
+ $path = OC::$APPSROOT."/apps/$app/templates/";
}else{
- $template = OC::$SERVERROOT."/apps/$app/templates/"."$name.php";
- $path = OC::$SERVERROOT."/apps/$app/templates/";
+ $template = OC::$APPSROOT."/apps/$app/templates/"."$name.php";
+ $path = OC::$APPSROOT."/apps/$app/templates/";
}
}else{
// Check if the template is overwritten by the selected theme
@@ -197,12 +197,15 @@ class OC_Template{
}elseif( file_exists( OC::$SERVERROOT."/$app/templates/"."$name$fext.php" )){
$template = OC::$SERVERROOT."/$app/templates/"."$name$fext.php";
$path = OC::$SERVERROOT."/$app/templates/";
- }else{
+ }elseif( file_exists( OC::$SERVERROOT."/$app/templates/"."$name.php" )){
$template = OC::$SERVERROOT."/$app/templates/"."$name.php";
$path = OC::$SERVERROOT."/$app/templates/";
+ }else{
+ echo('template not found: template:'.$name.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT);
+ die();
}
- }
+ }
}else{
// Check if the template is overwritten by the selected theme
if( file_exists( OC::$SERVERROOT."/themes/$theme/core/templates/"."$name$fext.php" )){
@@ -357,10 +360,10 @@ class OC_Template{
$page->append( "jsfiles", OC::$WEBROOT."/themes/$theme/apps/$script.js" );
// Is it part of an app?
- }elseif(is_file(OC::$SERVERROOT."/apps/$script$fext.js" )){
- $page->append( "jsfiles", OC::$WEBROOT."/apps/$script$fext.js" );
- }elseif(is_file(OC::$SERVERROOT."/apps/$script.js" )){
- $page->append( "jsfiles", OC::$WEBROOT."/apps/$script.js" );
+ }elseif(is_file(OC::$APPSROOT."/apps/$script$fext.js" )){
+ $page->append( "jsfiles", OC::$APPSWEBROOT."/apps/$script$fext.js" );
+ }elseif(is_file(OC::$APPSROOT."/apps/$script.js" )){
+ $page->append( "jsfiles", OC::$APPSWEBROOT."/apps/$script.js" );
// Is it in the owncloud root but overwritten by the theme?
}elseif(is_file(OC::$SERVERROOT."/themes/$theme/$script$fext.js" )){
@@ -383,9 +386,13 @@ class OC_Template{
// Is it in core?
}elseif(is_file(OC::$SERVERROOT."/core/$script$fext.js" )){
$page->append( "jsfiles", OC::$WEBROOT."/core/$script$fext.js" );
- }else{
+ }elseif(is_file(OC::$SERVERROOT."/core/$script.js" )){
$page->append( "jsfiles", OC::$WEBROOT."/core/$script.js" );
+ }else{
+ echo('js file not found: script:'.$script.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT);
+ die();
+
}
}
// Add the css files
@@ -394,10 +401,10 @@ class OC_Template{
if(is_file(OC::$THIRDPARTYROOT."/$style.css" )){
$page->append( "cssfiles", OC::$THIRDPARTYWEBROOT."/$style.css" );
// or in apps?
- }elseif(is_file(OC::$SERVERROOT."/apps/$style$fext.css" )){
- $page->append( "cssfiles", OC::$WEBROOT."/apps/$style$fext.css" );
- }elseif(is_file(OC::$SERVERROOT."/apps/$style.css" )){
- $page->append( "cssfiles", OC::$WEBROOT."/apps/$style.css" );
+ }elseif(is_file(OC::$APPSROOT."/apps/$style$fext.css" )){
+ $page->append( "cssfiles", OC::$APPSWEBROOT."/apps/$style$fext.css" );
+ }elseif(is_file(OC::$APPSROOT."/apps/$style.css" )){
+ $page->append( "cssfiles", OC::$APPSWEBROOT."/apps/$style.css" );
// or in the owncloud root?
}elseif(is_file(OC::$SERVERROOT."/$style$fext.css" )){
$page->append( "cssfiles", OC::$WEBROOT."/$style$fext.css" );
@@ -406,8 +413,12 @@ class OC_Template{
// or in core ?
}elseif(is_file(OC::$SERVERROOT."/core/$style$fext.css" )){
$page->append( "cssfiles", OC::$WEBROOT."/core/$style$fext.css" );
- }else{
+ }elseif(is_file(OC::$SERVERROOT."/core/$style.css" )){
$page->append( "cssfiles", OC::$WEBROOT."/core/$style.css" );
+
+ }else{
+ echo('css file not found: style:'.$script.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT);
+ die();
}
}
// Add the theme css files. you can override the default values here
diff --git a/lib/user.php b/lib/user.php
index 0746fcc6eb4..fda19a33154 100644
--- a/lib/user.php
+++ b/lib/user.php
@@ -195,8 +195,9 @@ class OC_User {
if( $run ){
$uid=self::checkPassword( $uid, $password );
if($uid){
- OC_Crypt::init($uid,$password);
- return self::setUserId($uid);
+ self::setUserId($uid);
+ OC_Hook::emit( "OC_User", "post_login", array( "uid" => $uid, 'password'=>$password ));
+ return true;
}
}
return false;
@@ -209,7 +210,6 @@ class OC_User {
*/
public static function setUserId($uid) {
$_SESSION['user_id'] = $uid;
- OC_Hook::emit( "OC_User", "post_login", array( "uid" => $uid ));
return true;
}
diff --git a/lib/user/database.php b/lib/user/database.php
index 452709c1fb9..3eade276dd9 100644
--- a/lib/user/database.php
+++ b/lib/user/database.php
@@ -33,12 +33,28 @@
*
*/
+require_once 'phpass/PasswordHash.php';
+
/**
* Class for user management in a SQL Database (e.g. MySQL, SQLite)
*/
class OC_User_Database extends OC_User_Backend {
static private $userGroupCache=array();
+ /**
+ * @var PasswordHash
+ */
+ static private $hasher=null;
+
+ private function getHasher(){
+ if(!self::$hasher){
+ //we don't want to use DES based crypt(), since it doesn't return a has with a recognisable prefix
+ $forcePortable=(CRYPT_BLOWFISH!=1);
+ self::$hasher=new PasswordHash(8,$forcePortable);
+ }
+ return self::$hasher;
+ }
+
/**
* @brief Create a new user
* @param $uid The username of the user to create
@@ -51,10 +67,11 @@ class OC_User_Database extends OC_User_Backend {
public function createUser( $uid, $password ){
if( $this->userExists($uid) ){
return false;
- }
- else{
+ }else{
+ $hasher=$this->getHasher();
+ $hash = $hasher->HashPassword($password);
$query = OC_DB::prepare( "INSERT INTO `*PREFIX*users` ( `uid`, `password` ) VALUES( ?, ? )" );
- $result = $query->execute( array( $uid, sha1( $password )));
+ $result = $query->execute( array( $uid, $hash));
return $result ? true : false;
}
@@ -84,8 +101,10 @@ class OC_User_Database extends OC_User_Backend {
*/
public function setPassword( $uid, $password ){
if( $this->userExists($uid) ){
+ $hasher=$this->getHasher();
+ $hash = $hasher->HashPassword($password);
$query = OC_DB::prepare( "UPDATE *PREFIX*users SET password = ? WHERE uid = ?" );
- $result = $query->execute( array( sha1( $password ), $uid ));
+ $result = $query->execute( array( $hash, $uid ));
return true;
}
@@ -103,12 +122,28 @@ class OC_User_Database extends OC_User_Backend {
* Check if the password is correct without logging in the user
*/
public function checkPassword( $uid, $password ){
- $query = OC_DB::prepare( "SELECT uid FROM *PREFIX*users WHERE uid LIKE ? AND password = ?" );
- $result = $query->execute( array( $uid, sha1( $password )));
+ $query = OC_DB::prepare( "SELECT uid, password FROM *PREFIX*users WHERE uid LIKE ?" );
+ $result = $query->execute( array( $uid));
$row=$result->fetchRow();
if($row){
- return $row['uid'];
+ $storedHash=$row['password'];
+ if (substr($storedHash,0,1)=='$'){//the new phpass based hashing
+ $hasher=$this->getHasher();
+ if($hasher->CheckPassword($password, $storedHash)){
+ return $row['uid'];
+ }else{
+ return false;
+ }
+ }else{//old sha1 based hashing
+ if(sha1($password)==$storedHash){
+ //upgrade to new hashing
+ $this->setPassword($row['uid'],$password);
+ return $row['uid'];
+ }else{
+ return false;
+ }
+ }
}else{
return false;
}
diff --git a/lib/util.php b/lib/util.php
index 05caeca0e3e..fa5b3daaab6 100644
--- a/lib/util.php
+++ b/lib/util.php
@@ -8,6 +8,7 @@ class OC_Util {
public static $scripts=array();
public static $styles=array();
public static $headers=array();
+ private static $rootMounted=false;
private static $fsSetup=false;
// Can be set up
@@ -35,9 +36,12 @@ class OC_Util {
$user = OC_User::getUser();
}
- if( $user != "" ){ //if we aren't logged in, there is no use to set up the filesystem
- //first set up the local "root" storage
+ //first set up the local "root" storage
+ if(!self::$rootMounted){
OC_Filesystem::mount('OC_Filestorage_Local',array('datadir'=>$CONFIG_DATADIRECTORY_ROOT),'/');
+ self::$rootMounted=true;
+ }
+ if( $user != "" ){ //if we aren't logged in, there is no use to set up the filesystem
OC::$CONFIG_DATADIRECTORY = $CONFIG_DATADIRECTORY_ROOT."/$user/$root";
if( !is_dir( OC::$CONFIG_DATADIRECTORY )){
@@ -62,7 +66,7 @@ class OC_Util {
* @return array
*/
public static function getVersion(){
- return array(3,00,2);
+ return array(3,00,3);
}
/**
diff --git a/lib/vcategories.php b/lib/vcategories.php
new file mode 100644
index 00000000000..5a7bacd2025
--- /dev/null
+++ b/lib/vcategories.php
@@ -0,0 +1,211 @@
+<?php
+/**
+* ownCloud
+*
+* @author Thomas Tanghus
+* @copyright 2012 Thomas Tanghus <thomas@tanghus.net>
+* @copyright 2012 Bart Visscher bartv@thisnet.nl
+*
+* 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/>.
+*
+*/
+
+
+/**
+ * Class for easy access to categories in VCARD, VEVENT, VTODO and VJOURNAL.
+ * A Category can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or
+ * anything else that is either parsed from a vobject or that the user chooses
+ * to add.
+ * Category names are not case-sensitive, but will be saved with the case they
+ * are entered in. If a user already has a category 'family' for an app, and
+ * tries to add a category named 'Family' it will be silently ignored.
+ * NOTE: There is a limitation in that the the configvalue field in the
+ * preferences table is a varchar(255).
+ */
+class OC_VCategories {
+ const PREF_CATEGORIES_LABEL = 'extra_categories';
+ /**
+ * Categories
+ */
+ private $categories = array();
+
+ private $app = null;
+ private $user = null;
+
+ /**
+ * @brief Constructor.
+ * @param $app The application identifier e.g. 'contacts' or 'calendar'.
+ * @param $user The user whos data the object will operate on. This
+ * parameter should normally be omitted but to make an app able to
+ * update categories for all users it is made possible to provide it.
+ * @param $defcategories An array of default categories to be used if none is stored.
+ * NOTE: Not implemented.
+ */
+ public function __construct($app, $user=null, $defcategories=null) {
+ $this->app = $app;
+ $this->user = is_null($user) ? OC_User::getUser() : $user;
+ $categories = trim(OC_Preferences::getValue($this->user, $app, self::PREF_CATEGORIES_LABEL, ''));
+ $this->categories = $categories != '' ? unserialize($categories) : array();
+ }
+
+ /**
+ * @brief Get the categories for a specific user.
+ * @returns array containing the categories as strings.
+ */
+ public function categories() {
+ OC_Log::write('core','OC_VCategories::categories: '.print_r($this->categories, true), OC_Log::DEBUG);
+ return $this->categories;
+ }
+
+ /**
+ * @brief Checks whether a category is already saved.
+ * @param $name The name to check for.
+ * @returns bool
+ */
+ public function hasCategory($name) {
+ return $this->in_arrayi($name, $this->categories);
+ }
+
+ /**
+ * @brief Add a new category name.
+ * @param $names A string with a name or an array of strings containing
+ * the name(s) of the categor(y|ies) to add.
+ * @param $sync bool When true, save the categories
+ * @returns bool Returns false on error.
+ */
+ public function add($names, $sync=false) {
+ if(!is_array($names)) {
+ $names = array($names);
+ }
+ $names = array_map('trim', $names);
+ $newones = array();
+ foreach($names as $name) {
+ if(($this->in_arrayi($name, $this->categories) == false) && $name != '') {
+ $newones[] = $name;
+ }
+ }
+ if(count($newones) > 0) {
+ $this->categories = array_merge($this->categories, $newones);
+ natcasesort($this->categories); // Dunno if this is necessary
+ if($sync === true) {
+ $this->save();
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @brief Extracts categories from a vobject and add the ones not already present.
+ * @param $vobject The instance of OC_VObject to load the categories from.
+ */
+ public function loadFromVObject($vobject, $sync=false) {
+ $this->add($vobject->getAsArray('CATEGORIES'), $sync);
+ }
+
+ /**
+ * @brief Reset saved categories and rescan supplied vobjects for categories.
+ * @param $objects An array of vobjects (as text).
+ * To get the object array, do something like:
+ * // For Addressbook:
+ * $categories = new OC_VCategories('contacts');
+ * $stmt = OC_DB::prepare( 'SELECT carddata FROM *PREFIX*contacts_cards' );
+ * $result = $stmt->execute();
+ * $objects = array();
+ * if(!is_null($result)) {
+ * while( $row = $result->fetchRow()){
+ * $objects[] = $row['carddata'];
+ * }
+ * }
+ * $categories->rescan($objects);
+ */
+ public function rescan($objects, $sync=true) {
+ $this->categories = array();
+ foreach($objects as $object) {
+ //OC_Log::write('core','OC_VCategories::rescan: '.substr($object, 0, 100).'(...)', OC_Log::DEBUG);
+ $vobject = OC_VObject::parse($object);
+ if(!is_null($vobject)) {
+ $this->loadFromVObject($vobject, $sync);
+ } else {
+ OC_Log::write('core','OC_VCategories::rescan, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 50).'(...)', OC_Log::DEBUG);
+ }
+ }
+ $this->save();
+ }
+
+ /**
+ * @brief Save the list with categories
+ */
+ private function save() {
+ $escaped_categories = serialize($this->categories);
+ OC_Log::write('core','OC_VCategories::save: '.print_r($this->categories, true), OC_Log::DEBUG);
+ OC_Preferences::setValue($this->user, $this->app, self::PREF_CATEGORIES_LABEL, $escaped_categories);
+ }
+
+ /**
+ * @brief Delete categories from the db and from all the vobject supplied
+ * @param $names An array of categories to delete
+ * @param $objects An array of arrays with [id,vobject] (as text) pairs suitable for updating the apps object table.
+ */
+ public function delete($names, array &$objects=null) {
+ if(!is_array($names)) {
+ $names = array($names);
+ }
+ OC_Log::write('core','OC_VCategories::delete, before: '.print_r($this->categories, true), OC_Log::DEBUG);
+ foreach($names as $name) {
+ OC_Log::write('core','OC_VCategories::delete: '.$name, OC_Log::DEBUG);
+ if($this->hasCategory($name)) {
+ OC_Log::write('core','OC_VCategories::delete: '.$name.' got it', OC_Log::DEBUG);
+ unset($this->categories[$this->array_searchi($name, $this->categories)]);
+ }
+ }
+ $this->save();
+ OC_Log::write('core','OC_VCategories::delete, after: '.print_r($this->categories, true), OC_Log::DEBUG);
+ if(!is_null($objects)) {
+ foreach($objects as $key=>&$value) {
+ $vobject = OC_VObject::parse($value[1]);
+ if(!is_null($vobject)){
+ $categories = $vobject->getAsArray('CATEGORIES');
+ //OC_Log::write('core','OC_VCategories::delete, before: '.$key.': '.print_r($categories, true), OC_Log::DEBUG);
+ foreach($names as $name) {
+ $idx = $this->array_searchi($name, $categories);
+ OC_Log::write('core','OC_VCategories::delete, loop: '.$name.', '.print_r($idx, true), OC_Log::DEBUG);
+ if($idx !== false) {
+ OC_Log::write('core','OC_VCategories::delete, unsetting: '.$categories[$this->array_searchi($name, $categories)], OC_Log::DEBUG);
+ unset($categories[$this->array_searchi($name, $categories)]);
+ //unset($categories[$idx]);
+ }
+ }
+ OC_Log::write('core','OC_VCategories::delete, after: '.$key.': '.print_r($categories, true), OC_Log::DEBUG);
+ $vobject->setString('CATEGORIES', implode(',', $categories));
+ $value[1] = $vobject->serialize();
+ $objects[$key] = $value;
+ } else {
+ OC_Log::write('core','OC_VCategories::delete, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 50).'(...)', OC_Log::DEBUG);
+ }
+ }
+ }
+ }
+
+ // case-insensitive in_array
+ private function in_arrayi($needle, $haystack) {
+ return in_array(strtolower($needle), array_map('strtolower', $haystack));
+ }
+
+ // case-insensitive array_search
+ private function array_searchi($needle, $haystack) {
+ return array_search(strtolower($needle),array_map('strtolower',$haystack));
+ }
+
+}
+?>
diff --git a/owncloud.db.filesystem b/owncloud.db.filesystem
deleted file mode 100644
index 082977a37ef..00000000000
--- a/owncloud.db.filesystem
+++ /dev/null
Binary files differ
diff --git a/settings/ajax/getlog.php b/settings/ajax/getlog.php
new file mode 100644
index 00000000000..600ebefcece
--- /dev/null
+++ b/settings/ajax/getlog.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Copyright (c) 2012, Robin Appelman <icewind1991@gmail.com>
+ * This file is licensed under the Affero General Public License version 3 or later.
+ * See the COPYING-README file.
+ */
+
+// Init owncloud
+require_once('../../lib/base.php');
+
+OC_JSON::checkAdminUser();
+
+$count=(isset($_GET['count']))?$_GET['count']:50;
+$offset=(isset($_GET['offset']))?$_GET['offset']:0;
+
+$entries=OC_Log::getEntries($count,$offset);
+OC_JSON::success(array("data" => $entries));
diff --git a/settings/ajax/setquota.php b/settings/ajax/setquota.php
index dc87625a05d..f59017600ac 100644
--- a/settings/ajax/setquota.php
+++ b/settings/ajax/setquota.php
@@ -1,4 +1,9 @@
<?php
+/**
+ * Copyright (c) 2012, Robin Appelman <icewind1991@gmail.com>
+ * This file is licensed under the Affero General Public License version 3 or later.
+ * See the COPYING-README file.
+ */
// Init owncloud
require_once('../../lib/base.php');
diff --git a/settings/css/settings.css b/settings/css/settings.css
index 7a5873bb4d2..42576953d04 100644
--- a/settings/css/settings.css
+++ b/settings/css/settings.css
@@ -5,6 +5,7 @@ input#openid, input#webdav { width:20em; }
#passworderror { display:none; }
#passwordchanged { display:none; }
input#identity { width:20em; }
+#email { width: 17em; }
.msg.success{ color:#fff; background-color:#0f0; padding:3px; text-shadow:1px 1px #000; }
.msg.error{ color:#fff; background-color:#f00; padding:3px; text-shadow:1px 1px #000; }
@@ -40,3 +41,6 @@ select.quota.active { background: #fff; }
li { color:#888; }
li.active { color:#000; }
span.version { margin-left:3em; color:#ddd; }
+
+/* LOF */
+#log { white-space:normal; } \ No newline at end of file
diff --git a/settings/js/log.js b/settings/js/log.js
new file mode 100644
index 00000000000..3814d9c10bf
--- /dev/null
+++ b/settings/js/log.js
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2012, Robin Appelman <icewind1991@gmail.com>
+ * This file is licensed under the Affero General Public License version 3 or later.
+ * See the COPYING-README file.
+ */
+
+OC.Log={
+ levels:['Debug','Info','Warning','Error','Fatal'],
+ loaded:50,//are initially loaded
+ getMore:function(){
+ $.get(OC.filePath('settings','ajax','getlog.php'),{offset:OC.Log.loaded},function(result){
+ if(result.status=='success'){
+ OC.Log.addEntries(result.data);
+ }
+ });
+ OC.Log.loaded+=50;
+ },
+ addEntries:function(entries){
+ for(var i=0;i<entries.length;i++){
+ var entry=entries[i];
+ var row=$('<tr/>');
+ var levelTd=$('<td/>');
+ levelTd.text(OC.Log.levels[entry.level]);
+ row.append(levelTd);
+
+ var appTd=$('<td/>');
+ appTd.text(entry.app);
+ row.append(appTd);
+
+ var messageTd=$('<td/>');
+ messageTd.text(entry.message);
+ row.append(messageTd);
+
+ var timeTd=$('<td/>');
+ timeTd.text(formatDate(entry.time));
+ row.append(timeTd);
+ $('#log').append(row);
+ }
+ }
+}
+
+$(document).ready(function(){
+ $('#moreLog').click(function(){
+ OC.Log.getMore();
+ })
+});
diff --git a/settings/log.php b/settings/log.php
index 21303c2170f..946f2b6f8e5 100644
--- a/settings/log.php
+++ b/settings/log.php
@@ -3,7 +3,7 @@
* ownCloud
*
* @author Robin Appelman
- * @copyright 2011 Robin Appelman icewind1991@gmail.com
+ * @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
@@ -30,6 +30,9 @@ OC_App::setActiveNavigationEntry( "core_log" );
$entries=OC_Log::getEntries();
+OC_Util::addScript('settings','log');
+OC_Util::addStyle('settings','settings');
+
function compareEntries($a,$b){
return $b->time - $a->time;
}
diff --git a/settings/templates/log.php b/settings/templates/log.php
index bcf5258f5f5..da5defc320e 100644
--- a/settings/templates/log.php
+++ b/settings/templates/log.php
@@ -9,7 +9,7 @@ $levels=array('Debug','Info','Warning','Error','Fatal');
<div id="controls">
</div>
-<table>
+<table id='log'>
<?php foreach($_['entries'] as $entry):?>
<tr>
<td>
@@ -26,4 +26,5 @@ $levels=array('Debug','Info','Warning','Error','Fatal');
</td>
</tr>
<?php endforeach;?>
-</table> \ No newline at end of file
+</table>
+<input id='moreLog' type='button' value='<?php echo $l->t('More');?>...'></input>
diff --git a/tests/index.php b/tests/index.php
index d29579a4bba..2e86366740b 100644
--- a/tests/index.php
+++ b/tests/index.php
@@ -26,22 +26,29 @@ require_once 'simpletest/mock_objects.php';
require_once 'simpletest/collector.php';
require_once 'simpletest/default_reporter.php';
-//load all test cases
-loadTests();
+//load core test cases
+loadTests(dirname(__FILE__));
+
+//load app test cases
+$apps=OC_Appconfig::getApps();
+foreach($apps as $app){
+ if(is_dir(OC::$SERVERROOT.'/apps/'.$app.'/tests')){
+ loadTests(OC::$SERVERROOT.'/apps/'.$app.'/tests');
+ }
+}
function loadTests($dir=''){
- $basedir=dirname(__FILE__).'/';
- if($dh=opendir($basedir.$dir)){
+ if($dh=opendir($dir)){
while($name=readdir($dh)){
if(substr($name,0,1)!='.'){//no hidden files, '.' or '..'
$file=$dir.'/'.$name;
- if(is_dir($basedir.$file)){
+ if(is_dir($file)){
loadTests($file);
}elseif(substr($file,-4)=='.php' and $file!=__FILE__){
$testCase=new TestSuite(getTestName($file));
- $testCase->addFile($basedir.$file);
+ $testCase->addFile($file);
if($testCase->getSize()>0){
- $testCase->run(new DefaultReporter());
+ $testCase->run(new HtmlReporter());
}
}
}
@@ -50,6 +57,7 @@ function loadTests($dir=''){
}
function getTestName($file){
- //TODO: get better test names
- return substr($file,5,-4);//strip /lib/ and .php
+// //TODO: get better test names
+ $file=substr($file,strlen(OC::$SERVERROOT));
+ return substr($file,0,-4);//strip .php
}
diff --git a/tests/lib/filestorage.php b/tests/lib/filestorage.php
index 7f024dafaa3..9ffa0eca9cb 100644
--- a/tests/lib/filestorage.php
+++ b/tests/lib/filestorage.php
@@ -81,10 +81,6 @@ abstract class Test_FileStorage extends UnitTestCase {
$this->instance->file_put_contents('/lorem.txt',$sourceText);
$this->assertEqual($sourceText,$this->instance->file_get_contents('/lorem.txt'),'data returned from file_get_contents is not equal to the source data');
- //fill a file with a stream
- $this->instance->file_put_contents('/lorem.txt',fopen($sourceFile,'r'));
- $this->assertEqual($sourceText,$this->instance->file_get_contents('/lorem.txt'),'data returned from file_get_contents is not equal to the source data');
-
//empty the file
$this->instance->file_put_contents('/lorem.txt','');
$this->assertEqual('',$this->instance->file_get_contents('/lorem.txt'),'file not emptied');
@@ -98,17 +94,96 @@ abstract class Test_FileStorage extends UnitTestCase {
$this->assertEqual(false,$this->instance->getMimeType('/non/existing/file'));
$textFile=OC::$SERVERROOT.'/tests/data/lorem.txt';
- $this->instance->file_put_contents('/lorem.txt',fopen($textFile,'r'));
+ $this->instance->file_put_contents('/lorem.txt',file_get_contents($textFile,'r'));
$this->assertEqual('text/plain',$this->instance->getMimeType('/lorem.txt'));
$pngFile=OC::$SERVERROOT.'/tests/data/logo-wide.png';
- $this->instance->file_put_contents('/logo-wide.png',fopen($pngFile,'r'));
+ $this->instance->file_put_contents('/logo-wide.png',file_get_contents($pngFile,'r'));
$this->assertEqual('image/png',$this->instance->getMimeType('/logo-wide.png'));
$svgFile=OC::$SERVERROOT.'/tests/data/logo-wide.svg';
- $this->instance->file_put_contents('/logo-wide.svg',fopen($svgFile,'r'));
+ $this->instance->file_put_contents('/logo-wide.svg',file_get_contents($svgFile,'r'));
$this->assertEqual('image/svg+xml',$this->instance->getMimeType('/logo-wide.svg'));
}
-}
+
+ public function testCopyAndMove(){
+ $textFile=OC::$SERVERROOT.'/tests/data/lorem.txt';
+ $this->instance->file_put_contents('/source.txt',file_get_contents($textFile));
+ $this->instance->copy('/source.txt','/target.txt');
+ $this->assertTrue($this->instance->file_exists('/target.txt'));
+ $this->assertEqual($this->instance->file_get_contents('/source.txt'),$this->instance->file_get_contents('/target.txt'));
+
+ $this->instance->rename('/source.txt','/target2.txt');
+ $this->assertTrue($this->instance->file_exists('/target2.txt'));
+ $this->assertFalse($this->instance->file_exists('/source.txt'));
+ $this->assertEqual(file_get_contents($textFile),$this->instance->file_get_contents('/target.txt'));
+ }
+
+ public function testLocalFile(){
+ $textFile=OC::$SERVERROOT.'/tests/data/lorem.txt';
+ $this->instance->file_put_contents('/lorem.txt',file_get_contents($textFile));
+ $localFile=$this->instance->getLocalFile('/lorem.txt');
+ $this->assertTrue(file_exists($localFile));
+ $this->assertEqual(file_get_contents($localFile),file_get_contents($textFile));
+ }
+ public function testStat(){
+ $textFile=OC::$SERVERROOT.'/tests/data/lorem.txt';
+ $ctimeStart=time();
+ $this->instance->file_put_contents('/lorem.txt',file_get_contents($textFile));
+ $this->assertTrue($this->instance->is_readable('/lorem.txt'));
+ $ctimeEnd=time();
+ $cTime=$this->instance->filectime('/lorem.txt');
+ $mTime=$this->instance->filemtime('/lorem.txt');
+ $this->assertTrue($ctimeStart<=$cTime);
+ $this->assertTrue($cTime<=$ctimeEnd);
+ $this->assertTrue($ctimeStart<=$mTime);
+ $this->assertTrue($mTime<=$ctimeEnd);
+ $this->assertEqual(filesize($textFile),$this->instance->filesize('/lorem.txt'));
+
+ $stat=$this->instance->stat('/lorem.txt');
+ //only size, mtime and ctime are requered in the result
+ $this->assertEqual($stat['size'],$this->instance->filesize('/lorem.txt'));
+ $this->assertEqual($stat['mtime'],$mTime);
+ $this->assertEqual($stat['ctime'],$cTime);
+
+ $mtimeStart=time();
+ $this->instance->touch('/lorem.txt');
+ $mtimeEnd=time();
+ $originalCTime=$cTime;
+ $cTime=$this->instance->filectime('/lorem.txt');
+ $mTime=$this->instance->filemtime('/lorem.txt');
+ $this->assertTrue($mtimeStart<=$mTime);
+ $this->assertTrue($mTime<=$mtimeEnd);
+ $this->assertEqual($cTime,$originalCTime);
+
+ if($this->instance->touch('/lorem.txt',100)!==false){
+ $mTime=$this->instance->filemtime('/lorem.txt');
+ $this->assertEqual($mTime,100);
+ }
+
+ $mtimeStart=time();
+ $fh=$this->instance->fopen('/lorem.txt','a');
+ fwrite($fh,' ');
+ fclose($fh);
+ clearstatcache();
+ $mtimeEnd=time();
+ $originalCTime=$cTime;
+ $mTime=$this->instance->filemtime('/lorem.txt');
+ $this->assertTrue($mtimeStart<=$mTime);
+ $this->assertTrue($mTime<=$mtimeEnd);
+ }
+ public function testSearch(){
+ $textFile=OC::$SERVERROOT.'/tests/data/lorem.txt';
+ $this->instance->file_put_contents('/lorem.txt',file_get_contents($textFile,'r'));
+ $pngFile=OC::$SERVERROOT.'/tests/data/logo-wide.png';
+ $this->instance->file_put_contents('/logo-wide.png',file_get_contents($pngFile,'r'));
+ $svgFile=OC::$SERVERROOT.'/tests/data/logo-wide.svg';
+ $this->instance->file_put_contents('/logo-wide.svg',file_get_contents($svgFile,'r'));
+ $result=$this->instance->search('logo');
+ $this->assertEqual(2,count($result));
+ $this->assertNotIdentical(false,array_search('/logo-wide.svg',$result));
+ $this->assertNotIdentical(false,array_search('/logo-wide.png',$result));
+ }
+}
diff --git a/tests/lib/filestorage/commontest.php b/tests/lib/filestorage/commontest.php
new file mode 100644
index 00000000000..ab5375ec2b0
--- /dev/null
+++ b/tests/lib/filestorage/commontest.php
@@ -0,0 +1,41 @@
+<?php
+/**
+* ownCloud
+*
+* @author Robin Appelman
+* @copyright 2012 Robin Appelman icewind@owncloud.com
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+class Test_Filestorage_CommonTest extends Test_FileStorage {
+ /**
+ * @var string tmpDir
+ */
+ private $tmpDir;
+ public function setUp(){
+ $this->tmpDir=get_temp_dir().'/filestoragecommon';
+ if(!file_exists($this->tmpDir)){
+ mkdir($this->tmpDir);
+ }
+ $this->instance=new OC_Filestorage_CommonTest(array('datadir'=>$this->tmpDir));
+ }
+
+ public function tearDown(){
+ OC_Helper::rmdirr($this->tmpDir);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/tests/lib/streamwrappers.php b/tests/lib/streamwrappers.php
new file mode 100644
index 00000000000..17a92c6658c
--- /dev/null
+++ b/tests/lib/streamwrappers.php
@@ -0,0 +1,78 @@
+<?php
+/**
+* ownCloud
+*
+* @author Robin Appelman
+* @copyright 2012 Robin Appelman icewind@owncloud.com
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+class Test_StreamWrappers extends UnitTestCase {
+ public function testFakeDir(){
+ $items=array('foo','bar');
+ OC_FakeDirStream::$dirs['test']=$items;
+ $dh=opendir('fakedir://test');
+ $result=array();
+ while($file=readdir($dh)){
+ $result[]=$file;
+ $this->assertNotIdentical(false,array_search($file,$items));
+ }
+ $this->assertEqual(count($items),count($result));
+ }
+
+ public function testStaticStream(){
+ $sourceFile=OC::$SERVERROOT.'/tests/data/lorem.txt';
+ $staticFile='static://test';
+ $this->assertFalse(file_exists($staticFile));
+ file_put_contents($staticFile,file_get_contents($sourceFile));
+ $this->assertTrue(file_exists($staticFile));
+ $this->assertEqual(file_get_contents($sourceFile),file_get_contents($staticFile));
+ unlink($staticFile);
+ clearstatcache();
+ $this->assertFalse(file_exists($staticFile));
+ }
+
+ public function testCloseStream(){
+ //ensure all basic stream stuff works
+ $sourceFile=OC::$SERVERROOT.'/tests/data/lorem.txt';
+ $tmpFile=OC_Helper::TmpFile('.txt');
+ $file='close://'.$tmpFile;
+ $this->assertTrue(file_exists($file));
+ file_put_contents($file,file_get_contents($sourceFile));
+ $this->assertEqual(file_get_contents($sourceFile),file_get_contents($file));
+ unlink($file);
+ clearstatcache();
+ $this->assertFalse(file_exists($file));
+
+ //test callback
+ $tmpFile=OC_Helper::TmpFile('.txt');
+ $file='close://'.$tmpFile;
+ OC_CloseStreamWrapper::$callBacks[$tmpFile]=array('Test_StreamWrappers','closeCallBack');
+ $fh=fopen($file,'w');
+ fwrite($fh,'asd');
+ try{
+ fclose($fh);
+ $this->fail('Expected exception');
+ }catch(Exception $e){
+ $path=$e->getMessage();
+ $this->assertEqual($path,$tmpFile);
+ }
+ }
+
+ public static function closeCallBack($path){
+ throw new Exception($path);
+ }
+} \ No newline at end of file