summaryrefslogtreecommitdiffstats
path: root/apps/files_external
diff options
context:
space:
mode:
authorraghunayyar <me@iraghu.com>2014-01-16 14:42:37 +0530
committerraghunayyar <me@iraghu.com>2014-01-16 14:42:37 +0530
commit775e08e0ee4125cc7b2a594771437686f6a21b56 (patch)
tree362f84449171898335dd3e8511b65c97c150e9e1 /apps/files_external
parent4687d2dd0bde3f689eb57c90d0c4341cd00991bd (diff)
parentbd643c47f32ba6d7b3ba6a18ed1591aab0b81be8 (diff)
downloadnextcloud-server-775e08e0ee4125cc7b2a594771437686f6a21b56.tar.gz
nextcloud-server-775e08e0ee4125cc7b2a594771437686f6a21b56.zip
Merge branch 'master' into core-em-to-px
Conflicts: apps/files_sharing/css/public.css apps/user_ldap/css/settings.css core/css/multiselect.css core/css/share.css
Diffstat (limited to 'apps/files_external')
-rw-r--r--apps/files_external/3rdparty/php-opencloud/LICENSE16
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/Autoload.php296
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Base.php301
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Collection.php320
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncHttpError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncTimeoutError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AttributeError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AuthenticationError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/BaseException.php7
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnHttpError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnNotAvailableError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnTtlError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CollectionError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerCreateError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerDeleteError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNameError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNotEmptyError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNotFoundError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CreateError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CreateUpdateError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CredentialError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseCreateError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseDeleteError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseListError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseNameError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseUpdateError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DeleteError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DocumentError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DomainError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/EmptyResponseError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/EndpointError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/FlavorError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpForbiddenError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpOverLimitError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpRetryError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpTimeoutError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpUnauthorizedError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpUrlError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/IOError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/IdRequiredError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ImageError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceCreateError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceDeleteError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceFlavorError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceNotFound.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceUpdateError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidArgumentError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidIdTypeError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidIpTypeError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidParameterError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidRequestError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/JsonError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/LoggingException.php16
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataCreateError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataDeleteError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataJsonError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataKeyError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataPrefixError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataUpdateError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MisMatchedChecksumError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MissingValueError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NameError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkCreateError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkDeleteError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkUpdateError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkUrlError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NoContentTypeError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NoNameError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjFetchError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjectCopyError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjectError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/RebuildError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/RecordTypeError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerActionError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerCreateError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerDeleteError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerImageScheduleError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerIpsError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerJsonError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerUpdateError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerUrlError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServiceValueError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/SnapshotError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/TempUrlMethodError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnknownError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnknownParameterError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnrecognizedServiceError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedExtensionError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedFeatureExtension.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedVersionError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UpdateError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UrlError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserCreateError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserDeleteError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserListError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserNameError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserUpdateError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/VolumeError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/VolumeTypeError.php5
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/Role.php21
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/Tenant.php22
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/User.php73
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Lang.php21
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/AbstractLogger.php140
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/LogLevel.php38
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/Logger.php220
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/LoggerInterface.php134
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Metadata.php92
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Nova.php140
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/PersistentObject.php939
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Curl.php308
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/HttpRequestInterface.php23
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Response/Blank.php27
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Response/Http.php140
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Service.php489
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/ServiceCatalogItem.php18
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Globals.php252
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/AbstractService.php57
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/CDNService.php62
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/AbstractStorageObject.php170
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/CDNContainer.php298
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/Container.php401
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/DataObject.php941
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Service.php115
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/OpenStack.php1198
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Rackspace.php132
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/openstack.php8
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/php-opencloud.php15
-rw-r--r--apps/files_external/3rdparty/php-opencloud/lib/rackspace.php8
-rw-r--r--apps/files_external/3rdparty/smb4php/smb.php44
-rw-r--r--apps/files_external/ajax/dropbox.php2
-rw-r--r--apps/files_external/appinfo/app.php3
-rw-r--r--apps/files_external/css/settings.css8
-rw-r--r--apps/files_external/js/dropbox.js17
-rw-r--r--apps/files_external/js/google.js21
-rw-r--r--apps/files_external/js/settings.js61
-rw-r--r--apps/files_external/l10n/ar.php3
-rw-r--r--apps/files_external/l10n/es_MX.php28
-rw-r--r--apps/files_external/l10n/km.php5
-rw-r--r--apps/files_external/l10n/sk.php5
-rw-r--r--apps/files_external/l10n/sk_SK.php4
-rw-r--r--apps/files_external/l10n/sq.php1
-rw-r--r--apps/files_external/l10n/tr.php8
-rw-r--r--apps/files_external/lib/amazons3.php20
-rwxr-xr-xapps/files_external/lib/config.php70
-rwxr-xr-xapps/files_external/lib/dropbox.php70
-rw-r--r--apps/files_external/lib/ftp.php19
-rw-r--r--apps/files_external/lib/google.php4
-rw-r--r--apps/files_external/lib/owncloud.php51
-rw-r--r--apps/files_external/lib/sftp.php148
-rw-r--r--apps/files_external/lib/smb.php25
-rw-r--r--apps/files_external/lib/streamwrapper.php55
-rw-r--r--apps/files_external/lib/swift.php820
-rw-r--r--apps/files_external/lib/webdav.php65
-rw-r--r--apps/files_external/templates/settings.php4
-rw-r--r--apps/files_external/tests/config.php24
-rw-r--r--apps/files_external/tests/dropbox.php16
-rw-r--r--apps/files_external/tests/ftp.php20
-rw-r--r--apps/files_external/tests/mountconfig.php51
-rw-r--r--apps/files_external/tests/owncloud.php31
-rw-r--r--apps/files_external/tests/smb.php14
-rw-r--r--apps/files_external/tests/smbfunctions.php41
-rw-r--r--apps/files_external/tests/swift.php45
170 files changed, 9043 insertions, 718 deletions
diff --git a/apps/files_external/3rdparty/php-opencloud/LICENSE b/apps/files_external/3rdparty/php-opencloud/LICENSE
new file mode 100644
index 00000000000..f7c56967e6c
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/LICENSE
@@ -0,0 +1,16 @@
+ Copyright 2012-2013 Rackspace US, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ All contributions to this repository are covered under the same license,
+ terms, and conditions. \ No newline at end of file
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/Autoload.php b/apps/files_external/3rdparty/php-opencloud/lib/Autoload.php
new file mode 100644
index 00000000000..32e9dc24b7e
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/Autoload.php
@@ -0,0 +1,296 @@
+<?php
+
+// Copyright (c) 2004-2013 Fabien Potencier
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is furnished
+// to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+class ClassLoader
+{
+ private $namespaces = array();
+ private $prefixes = array();
+ private $namespaceFallbacks = array();
+ private $prefixFallbacks = array();
+ private $useIncludePath = false;
+
+ /**
+ * Turns on searching the include for class files. Allows easy loading
+ * of installed PEAR packages
+ *
+ * @param Boolean $useIncludePath
+ */
+ public function useIncludePath($useIncludePath)
+ {
+ $this->useIncludePath = $useIncludePath;
+ }
+
+ /**
+ * Can be used to check if the autoloader uses the include path to check
+ * for classes.
+ *
+ * @return Boolean
+ */
+ public function getUseIncludePath()
+ {
+ return $this->useIncludePath;
+ }
+
+ /**
+ * Gets the configured namespaces.
+ *
+ * @return array A hash with namespaces as keys and directories as values
+ */
+ public function getNamespaces()
+ {
+ return $this->namespaces;
+ }
+
+ /**
+ * Gets the configured class prefixes.
+ *
+ * @return array A hash with class prefixes as keys and directories as values
+ */
+ public function getPrefixes()
+ {
+ return $this->prefixes;
+ }
+
+ /**
+ * Gets the directory(ies) to use as a fallback for namespaces.
+ *
+ * @return array An array of directories
+ */
+ public function getNamespaceFallbacks()
+ {
+ return $this->namespaceFallbacks;
+ }
+
+ /**
+ * Gets the directory(ies) to use as a fallback for class prefixes.
+ *
+ * @return array An array of directories
+ */
+ public function getPrefixFallbacks()
+ {
+ return $this->prefixFallbacks;
+ }
+
+ /**
+ * Registers the directory to use as a fallback for namespaces.
+ *
+ * @param array $dirs An array of directories
+ *
+ * @api
+ */
+ public function registerNamespaceFallbacks(array $dirs)
+ {
+ $this->namespaceFallbacks = $dirs;
+ }
+
+ /**
+ * Registers a directory to use as a fallback for namespaces.
+ *
+ * @param string $dir A directory
+ */
+ public function registerNamespaceFallback($dir)
+ {
+ $this->namespaceFallbacks[] = $dir;
+ }
+
+ /**
+ * Registers directories to use as a fallback for class prefixes.
+ *
+ * @param array $dirs An array of directories
+ *
+ * @api
+ */
+ public function registerPrefixFallbacks(array $dirs)
+ {
+ $this->prefixFallbacks = $dirs;
+ }
+
+ /**
+ * Registers a directory to use as a fallback for class prefixes.
+ *
+ * @param string $dir A directory
+ */
+ public function registerPrefixFallback($dir)
+ {
+ $this->prefixFallbacks[] = $dir;
+ }
+
+ /**
+ * Registers an array of namespaces
+ *
+ * @param array $namespaces An array of namespaces (namespaces as keys and locations as values)
+ *
+ * @api
+ */
+ public function registerNamespaces(array $namespaces)
+ {
+ foreach ($namespaces as $namespace => $locations) {
+ $this->namespaces[$namespace] = (array) $locations;
+ }
+ }
+
+ /**
+ * Registers a namespace.
+ *
+ * @param string $namespace The namespace
+ * @param array|string $paths The location(s) of the namespace
+ *
+ * @api
+ */
+ public function registerNamespace($namespace, $paths)
+ {
+ $this->namespaces[$namespace] = (array) $paths;
+ }
+
+ /**
+ * Registers an array of classes using the PEAR naming convention.
+ *
+ * @param array $classes An array of classes (prefixes as keys and locations as values)
+ *
+ * @api
+ */
+ public function registerPrefixes(array $classes)
+ {
+ foreach ($classes as $prefix => $locations) {
+ $this->prefixes[$prefix] = (array) $locations;
+ }
+ }
+
+ /**
+ * Registers a set of classes using the PEAR naming convention.
+ *
+ * @param string $prefix The classes prefix
+ * @param array|string $paths The location(s) of the classes
+ *
+ * @api
+ */
+ public function registerPrefix($prefix, $paths)
+ {
+ $this->prefixes[$prefix] = (array) $paths;
+ }
+
+ /**
+ * Registers this instance as an autoloader.
+ *
+ * @param Boolean $prepend Whether to prepend the autoloader or not
+ *
+ * @api
+ */
+ public function register($prepend = false)
+ {
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+ }
+
+ /**
+ * Fix for certain versions of PHP that have trouble with
+ * namespaces with leading separators.
+ *
+ * @access private
+ * @param mixed $className
+ * @return void
+ */
+ private function makeBackwardsCompatible($className)
+ {
+ return (phpversion() < '5.3.3') ? ltrim($className, '\\') : $className;
+ }
+
+ /**
+ * Loads the given class or interface.
+ *
+ * @param string $class The name of the class
+ *
+ * @return Boolean|null True, if loaded
+ */
+ public function loadClass($class)
+ {
+ $class = $this->makeBackwardsCompatible($class);
+
+ if ($file = $this->findFile($class)) {
+ require $file;
+
+ return true;
+ }
+ }
+
+ /**
+ * Finds the path to the file where the class is defined.
+ *
+ * @param string $class The name of the class
+ *
+ * @return string|null The path, if found
+ */
+ public function findFile($class)
+ {
+ if (false !== $pos = strrpos($class, '\\')) {
+ // namespaced class name
+ $namespace = substr($class, 0, $pos);
+ $className = substr($class, $pos + 1);
+ $normalizedClass = str_replace('\\', DIRECTORY_SEPARATOR, $namespace).DIRECTORY_SEPARATOR.str_replace('_', DIRECTORY_SEPARATOR, $className).'.php';
+ foreach ($this->namespaces as $ns => $dirs) {
+ if (0 !== strpos($namespace, $ns)) {
+ continue;
+ }
+
+ foreach ($dirs as $dir) {
+ $file = $dir.DIRECTORY_SEPARATOR.$normalizedClass;
+ if (is_file($file)) {
+ return $file;
+ }
+ }
+ }
+
+ foreach ($this->namespaceFallbacks as $dir) {
+ $file = $dir.DIRECTORY_SEPARATOR.$normalizedClass;
+ if (is_file($file)) {
+ return $file;
+ }
+ }
+
+ } else {
+ // PEAR-like class name
+ $normalizedClass = str_replace('_', DIRECTORY_SEPARATOR, $class).'.php';
+ foreach ($this->prefixes as $prefix => $dirs) {
+ if (0 !== strpos($class, $prefix)) {
+ continue;
+ }
+
+ foreach ($dirs as $dir) {
+ $file = $dir.DIRECTORY_SEPARATOR.$normalizedClass;
+ if (is_file($file)) {
+ return $file;
+ }
+ }
+ }
+
+ foreach ($this->prefixFallbacks as $dir) {
+ $file = $dir.DIRECTORY_SEPARATOR.$normalizedClass;
+ if (is_file($file)) {
+ return $file;
+ }
+ }
+ }
+
+ if ($this->useIncludePath && $file = stream_resolve_include_path($normalizedClass)) {
+ return $file;
+ }
+ }
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Base.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Base.php
new file mode 100644
index 00000000000..f80c9320e2a
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Base.php
@@ -0,0 +1,301 @@
+<?php
+/**
+ * @copyright 2012-2013 Rackspace Hosting, Inc.
+ * See COPYING for licensing information
+ * @package phpOpenCloud
+ * @version 1.0
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ * @author Jamie Hannaford <jamie.hannaford@rackspace.com>
+ */
+
+namespace OpenCloud\Common;
+
+use OpenCloud\Common\Lang;
+use OpenCloud\Common\Exceptions\AttributeError;
+use OpenCloud\Common\Exceptions\JsonError;
+use OpenCloud\Common\Exceptions\UrlError;
+
+/**
+ * The root class for all other objects used or defined by this SDK.
+ *
+ * It contains common code for error handling as well as service functions that
+ * are useful. Because it is an abstract class, it cannot be called directly,
+ * and it has no publicly-visible properties.
+ */
+abstract class Base
+{
+
+ private $http_headers = array();
+ private $_errors = array();
+
+ /**
+ * Debug status.
+ *
+ * @var LoggerInterface
+ * @access private
+ */
+ private $logger;
+
+ /**
+ * Sets the Logger object.
+ *
+ * @param \OpenCloud\Common\Log\LoggerInterface $logger
+ */
+ public function setLogger(Log\LoggerInterface $logger)
+ {
+ $this->logger = $logger;
+ }
+
+ /**
+ * Returns the Logger object.
+ *
+ * @return \OpenCloud\Common\Log\AbstractLogger
+ */
+ public function getLogger()
+ {
+ if (null === $this->logger) {
+ $this->setLogger(new Log\Logger);
+ }
+ return $this->logger;
+ }
+
+ /**
+ * Returns the URL of the service/object
+ *
+ * The assumption is that nearly all objects will have a URL; at this
+ * base level, it simply throws an exception to enforce the idea that
+ * subclasses need to define this method.
+ *
+ * @throws UrlError
+ */
+ public function url($subresource = '')
+ {
+ throw new UrlError(Lang::translate(
+ 'URL method must be overridden in class definition'
+ ));
+ }
+
+/**
+ * Populates the current object based on an unknown data type.
+ *
+ * @param array|object|string|integer $info
+ * @throws Exceptions\InvalidArgumentError
+ */
+ public function populate($info, $setObjects = true)
+ {
+ if (is_string($info) || is_integer($info)) {
+
+ // If the data type represents an ID, the primary key is set
+ // and we retrieve the full resource from the API
+ $this->{$this->primaryKeyField()} = (string) $info;
+ $this->refresh($info);
+
+ } elseif (is_object($info) || is_array($info)) {
+
+ foreach($info as $key => $value) {
+
+ if ($key == 'metadata' || $key == 'meta') {
+
+ if (empty($this->metadata) || !$this->metadata instanceof Metadata) {
+ $this->metadata = new Metadata;
+ }
+
+ // Metadata
+ $this->$key->setArray($value);
+
+ } elseif (!empty($this->associatedResources[$key]) && $setObjects === true) {
+
+ // Associated resource
+ try {
+ $resource = $this->service()->resource($this->associatedResources[$key], $value);
+ $resource->setParent($this);
+ $this->$key = $resource;
+ } catch (Exception\ServiceException $e) {}
+
+ } elseif (!empty($this->associatedCollections[$key]) && $setObjects === true) {
+
+ // Associated collection
+ try {
+ $this->$key = $this->service()->resourceList($this->associatedCollections[$key], null, $this);
+ } catch (Exception\ServiceException $e) {}
+
+ } else {
+
+ // Normal key/value pair
+ $this->$key = $value;
+ }
+ }
+ } elseif (null !== $info) {
+ throw new Exceptions\InvalidArgumentError(sprintf(
+ Lang::translate('Argument for [%s] must be string or object'),
+ get_class()
+ ));
+ }
+ }
+
+ /**
+ * Sets extended attributes on an object and validates them
+ *
+ * This function is provided to ensure that attributes cannot
+ * arbitrarily added to an object. If this function is called, it
+ * means that the attribute is not defined on the object, and thus
+ * an exception is thrown.
+ *
+ * @codeCoverageIgnore
+ *
+ * @param string $property the name of the attribute
+ * @param mixed $value the value of the attribute
+ * @return void
+ */
+ public function __set($property, $value)
+ {
+ $this->setProperty($property, $value);
+ }
+
+ /**
+ * Sets an extended (unrecognized) property on the current object
+ *
+ * If RAXSDK_STRICT_PROPERTY_CHECKS is TRUE, then the prefix of the
+ * property name must appear in the $prefixes array, or else an
+ * exception is thrown.
+ *
+ * @param string $property the property name
+ * @param mixed $value the value of the property
+ * @param array $prefixes optional list of supported prefixes
+ * @throws \OpenCloud\AttributeError if strict checks are on and
+ * the property prefix is not in the list of prefixes.
+ */
+ public function setProperty($property, $value, array $prefixes = array())
+ {
+ // if strict checks are off, go ahead and set it
+ if (!RAXSDK_STRICT_PROPERTY_CHECKS
+ || $this->checkAttributePrefix($property, $prefixes)
+ ) {
+ $this->$property = $value;
+ } else {
+ // if that fails, then throw the exception
+ throw new AttributeError(sprintf(
+ Lang::translate('Unrecognized attribute [%s] for [%s]'),
+ $property,
+ get_class($this)
+ ));
+ }
+ }
+
+ /**
+ * Converts an array of key/value pairs into a single query string
+ *
+ * For example, array('A'=>1,'B'=>2) would become 'A=1&B=2'.
+ *
+ * @param array $arr array of key/value pairs
+ * @return string
+ */
+ public function makeQueryString($array)
+ {
+ $queryString = '';
+
+ foreach($array as $key => $value) {
+ if ($queryString) {
+ $queryString .= '&';
+ }
+ $queryString .= urlencode($key) . '=' . urlencode($this->to_string($value));
+ }
+
+ return $queryString;
+ }
+
+ /**
+ * Checks the most recent JSON operation for errors
+ *
+ * This function should be called after any `json_*()` function call.
+ * This ensures that nasty JSON errors are detected and the proper
+ * exception thrown.
+ *
+ * Example:
+ * `$obj = json_decode($string);`
+ * `if (check_json_error()) do something ...`
+ *
+ * @return boolean TRUE if an error occurred, FALSE if none
+ * @throws JsonError
+ *
+ * @codeCoverageIgnore
+ */
+ public function checkJsonError()
+ {
+ switch (json_last_error()) {
+ case JSON_ERROR_NONE:
+ return;
+ case JSON_ERROR_DEPTH:
+ $jsonError = 'JSON error: The maximum stack depth has been exceeded';
+ break;
+ case JSON_ERROR_STATE_MISMATCH:
+ $jsonError = 'JSON error: Invalid or malformed JSON';
+ break;
+ case JSON_ERROR_CTRL_CHAR:
+ $jsonError = 'JSON error: Control character error, possibly incorrectly encoded';
+ break;
+ case JSON_ERROR_SYNTAX:
+ $jsonError = 'JSON error: Syntax error';
+ break;
+ case JSON_ERROR_UTF8:
+ $jsonError = 'JSON error: Malformed UTF-8 characters, possibly incorrectly encoded';
+ break;
+ default:
+ $jsonError = 'Unexpected JSON error';
+ break;
+ }
+
+ if (isset($jsonError)) {
+ throw new JsonError(Lang::translate($jsonError));
+ }
+ }
+
+ /**
+ * Returns a class that implements the HttpRequest interface.
+ *
+ * This can be stubbed out for unit testing and avoid making live calls.
+ */
+ public function getHttpRequestObject($url, $method = 'GET', array $options = array())
+ {
+ return new Request\Curl($url, $method, $options);
+ }
+
+ /**
+ * Checks the attribute $property and only permits it if the prefix is
+ * in the specified $prefixes array
+ *
+ * This is to support extension namespaces in some services.
+ *
+ * @param string $property the name of the attribute
+ * @param array $prefixes a list of prefixes
+ * @return boolean TRUE if valid; FALSE if not
+ */
+ private function checkAttributePrefix($property, array $prefixes = array())
+ {
+ $prefix = strstr($property, ':', true);
+
+ if (in_array($prefix, $prefixes)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Converts a value to an HTTP-displayable string form
+ *
+ * @param mixed $x a value to convert
+ * @return string
+ */
+ private function to_string($x)
+ {
+ if (is_bool($x) && $x) {
+ return 'True';
+ } elseif (is_bool($x)) {
+ return 'False';
+ } else {
+ return (string) $x;
+ }
+ }
+
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Collection.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Collection.php
new file mode 100644
index 00000000000..e1bf80376e0
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Collection.php
@@ -0,0 +1,320 @@
+<?php
+
+namespace OpenCloud\Common;
+
+/**
+ * Provides an abstraction for working with ordered sets of objects
+ *
+ * Collection objects are used whenever there are multiples; for example,
+ * multiple objects in a container, or multiple servers in a service.
+ *
+ * @since 1.0
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ * @author Jamie Hannaford <jamie.hannaford@rackspace.com>
+ */
+class Collection extends Base
+{
+
+ private $service;
+ private $itemclass;
+ private $itemlist = array();
+ private $pointer = 0;
+ private $sortkey;
+ private $next_page_class;
+ private $next_page_callback;
+ private $next_page_url;
+
+ /**
+ * A Collection is an array of objects
+ *
+ * Some assumptions:
+ * * The `Collection` class assumes that there exists on its service
+ * a factory method with the same name of the class. For example, if
+ * you create a Collection of class `Foobar`, it will attempt to call
+ * the method `parent::Foobar()` to create instances of that class.
+ * * It assumes that the factory method can take an array of values, and
+ * it passes that to the method.
+ *
+ * @param Service $service - the service associated with the collection
+ * @param string $itemclass - the Class of each item in the collection
+ * (assumed to be the name of the factory method)
+ * @param array $arr - the input array
+ */
+ public function __construct($service, $itemclass, $array)
+ {
+ $this->service = $service;
+
+ $this->getLogger()->info(
+ 'Collection:service={class}, class={itemClass}, array={array}',
+ array(
+ 'class' => get_class($service),
+ 'itemClass' => $itemclass,
+ 'array' => print_r($array, true)
+ )
+ );
+
+ $this->next_page_class = $itemclass;
+
+ if (false !== ($classNamePos = strrpos($itemclass, '\\'))) {
+ $this->itemclass = substr($itemclass, $classNamePos + 1);
+ } else {
+ $this->itemclass = $itemclass;
+ }
+
+ if (!is_array($array)) {
+ throw new Exceptions\CollectionError(
+ Lang::translate('Cannot create a Collection without an array')
+ );
+ }
+
+ // save the array of items
+ $this->setItemList($array);
+ }
+
+ /**
+ * Set the entire data array.
+ *
+ * @param array $array
+ */
+ public function setItemList(array $array)
+ {
+ $this->itemlist = $array;
+ }
+
+ /**
+ * Retrieve the entire data array.
+ *
+ * @return array
+ */
+ public function getItemList()
+ {
+ return $this->itemlist;
+ }
+
+ /**
+ * Returns the number of items in the collection
+ *
+ * For most services, this is the total number of items. If the Collection
+ * is paginated, however, this only returns the count of items in the
+ * current page of data.
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->itemlist);
+ }
+
+ /**
+ * Pseudonym for count()
+ *
+ * @codeCoverageIgnore
+ */
+ public function size()
+ {
+ return $this->count();
+ }
+
+ /**
+ * Retrieves the service associated with the Collection
+ *
+ * @return Service
+ */
+ public function service()
+ {
+ return $this->service;
+ }
+
+ /**
+ * Resets the pointer to the beginning, but does NOT return the first item
+ *
+ * @api
+ * @return void
+ */
+ public function reset()
+ {
+ $this->pointer = 0;
+ }
+
+ /**
+ * Resets the collection pointer back to the first item in the page
+ * and returns it
+ *
+ * This is useful if you're only interested in the first item in the page.
+ *
+ * @api
+ * @return Base the first item in the set
+ */
+ public function first()
+ {
+ $this->reset();
+ return $this->next();
+ }
+
+ /**
+ * Returns the next item in the page
+ *
+ * @api
+ * @return Base the next item or FALSE if at the end of the page
+ */
+ public function next()
+ {
+ if ($this->pointer >= $this->count()) {
+ return false;
+ }
+
+ $service = $this->service();
+
+ if (method_exists($service, $this->itemclass)) {
+ return $service->{$this->itemclass}($this->itemlist[$this->pointer++]);
+ } elseif (method_exists($service, 'resource')) {
+ return $service->resource($this->itemclass, $this->itemlist[$this->pointer++]);
+ }
+ // @codeCoverageIgnoreStart
+ return false;
+ // @codeCoverageIgnoreEnd
+ }
+
+ /**
+ * sorts the collection on a specified key
+ *
+ * Note: only top-level keys can be used as the sort key. Note that this
+ * only sorts the data in the current page of the Collection (for
+ * multi-page data).
+ *
+ * @api
+ * @param string $keyname the name of the field to use as the sort key
+ * @return void
+ */
+ public function sort($keyname = 'id')
+ {
+ $this->sortkey = $keyname;
+ usort($this->itemlist, array($this, 'sortCompare'));
+ }
+
+ /**
+ * selects only specified items from the Collection
+ *
+ * This provides a simple form of filtering on Collections. For each item
+ * in the collection, it calls the callback function, passing it the item.
+ * If the callback returns `TRUE`, then the item is retained; if it returns
+ * `FALSE`, then the item is deleted from the collection.
+ *
+ * Note that this should not supersede server-side filtering; the
+ * `Collection::Select()` method requires that *all* of the data for the
+ * Collection be retrieved from the server before the filtering is
+ * performed; this can be very inefficient, especially for large data
+ * sets. This method is mostly useful on smaller-sized sets.
+ *
+ * Example:
+ * <code>
+ * $services = $connection->ServiceList();
+ * $services->Select(function($item){ return $item->region=='ORD';});
+ * // now the $services Collection only has items from the ORD region
+ * </code>
+ *
+ * `Select()` is *destructive*; that is, it actually removes entries from
+ * the collection. For example, if you use `Select()` to find items with
+ * the ID > 10, then use it again to find items that are <= 10, it will
+ * return an empty list.
+ *
+ * @api
+ * @param callable $testfunc a callback function that is passed each item
+ * in turn. Note that `Select()` performs an explicit test for
+ * `FALSE`, so functions like `strpos()` need to be cast into a
+ * boolean value (and not just return the integer).
+ * @returns void
+ * @throws DomainError if callback doesn't return a boolean value
+ */
+ public function select($testfunc)
+ {
+ foreach ($this->getItemList() as $index => $item) {
+ $test = call_user_func($testfunc, $item);
+ if (!is_bool($test)) {
+ throw new Exceptions\DomainError(
+ Lang::translate('Callback function for Collection::Select() did not return boolean')
+ );
+ }
+ if ($test === false) {
+ unset($this->itemlist[$index]);
+ }
+ }
+ }
+
+ /**
+ * returns the Collection object for the next page of results, or
+ * FALSE if there are no more pages
+ *
+ * Generally, the structure for a multi-page collection will look like
+ * this:
+ *
+ * $coll = $obj->Collection();
+ * do {
+ * while($item = $coll->Next()) {
+ * // do something with the item
+ * }
+ * } while ($coll = $coll->NextPage());
+ *
+ * @api
+ * @return Collection if there are more pages of results, otherwise FALSE
+ */
+ public function nextPage()
+ {
+ if (isset($this->next_page_url)) {
+ return call_user_func(
+ $this->next_page_callback,
+ $this->next_page_class,
+ $this->next_page_url
+ );
+ }
+ // @codeCoverageIgnoreStart
+ return false;
+ // @codeCoverageIgnoreEnd
+ }
+
+ /**
+ * for paginated collection, sets the callback function and URL for
+ * the next page
+ *
+ * The callback function should have the signature:
+ *
+ * function Whatever($class, $url, $parent)
+ *
+ * and the `$url` should be the URL of the next page of results
+ *
+ * @param callable $callback the name of the function (or array of
+ * object, function name)
+ * @param string $url the URL of the next page of results
+ * @return void
+ */
+ public function setNextPageCallback($callback, $url)
+ {
+ $this->next_page_callback = $callback;
+ $this->next_page_url = $url;
+ }
+
+ /**
+ * Compares two values of sort keys
+ */
+ private function sortCompare($a, $b)
+ {
+ $key = $this->sortkey;
+
+ // handle strings with strcmp()
+ if (is_string($a->$key)) {
+ return strcmp($a->$key, $b->$key);
+ }
+
+ // handle others with logical comparisons
+ if ($a->$key == $b->$key) {
+ return 0;
+ }
+
+ if ($a->$key < $b->$key) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncError.php
new file mode 100644
index 00000000000..cbbacff38bd
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class AsyncError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncHttpError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncHttpError.php
new file mode 100644
index 00000000000..dc7b2d7e3a7
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncHttpError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class AsyncHttpError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncTimeoutError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncTimeoutError.php
new file mode 100644
index 00000000000..bba5f09f64f
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncTimeoutError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class AsyncTimeoutError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AttributeError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AttributeError.php
new file mode 100644
index 00000000000..7d09ceb0147
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AttributeError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class AttributeError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AuthenticationError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AuthenticationError.php
new file mode 100644
index 00000000000..091e4602ec0
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AuthenticationError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class AuthenticationError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/BaseException.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/BaseException.php
new file mode 100644
index 00000000000..0bc967adf67
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/BaseException.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class BaseException extends \Exception
+{
+} \ No newline at end of file
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnError.php
new file mode 100644
index 00000000000..0f972e9c5c7
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class CdnError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnHttpError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnHttpError.php
new file mode 100644
index 00000000000..f1e2722f158
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnHttpError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class CdnHttpError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnNotAvailableError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnNotAvailableError.php
new file mode 100644
index 00000000000..853b17c7127
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnNotAvailableError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class CdnNotAvailableError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnTtlError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnTtlError.php
new file mode 100644
index 00000000000..b4364f93467
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnTtlError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class CdnTtlError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CollectionError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CollectionError.php
new file mode 100644
index 00000000000..9d5030403f6
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CollectionError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class CollectionError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerCreateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerCreateError.php
new file mode 100644
index 00000000000..afc8119bd5a
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerCreateError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class ContainerCreateError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerDeleteError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerDeleteError.php
new file mode 100644
index 00000000000..c212bfbaffd
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerDeleteError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class ContainerDeleteError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerError.php
new file mode 100644
index 00000000000..c9716fef075
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class ContainerError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNameError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNameError.php
new file mode 100644
index 00000000000..e0b9592835e
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNameError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class ContainerNameError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNotEmptyError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNotEmptyError.php
new file mode 100644
index 00000000000..e987449d444
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNotEmptyError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class ContainerNotEmptyError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNotFoundError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNotFoundError.php
new file mode 100644
index 00000000000..2e700dbe039
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNotFoundError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class ContainerNotFoundError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CreateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CreateError.php
new file mode 100644
index 00000000000..bb2030373fb
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CreateError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class CreateError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CreateUpdateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CreateUpdateError.php
new file mode 100644
index 00000000000..8aa651a76d9
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CreateUpdateError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class CreateUpdateError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CredentialError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CredentialError.php
new file mode 100644
index 00000000000..2769edaf378
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CredentialError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class CredentialError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseCreateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseCreateError.php
new file mode 100644
index 00000000000..eb19198c2fe
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseCreateError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class DatabaseCreateError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseDeleteError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseDeleteError.php
new file mode 100644
index 00000000000..41f397529fe
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseDeleteError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class DatabaseDeleteError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseListError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseListError.php
new file mode 100644
index 00000000000..04a7fb9e835
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseListError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class DatabaseListError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseNameError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseNameError.php
new file mode 100644
index 00000000000..17a987a03b0
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseNameError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class DatabaseNameError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseUpdateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseUpdateError.php
new file mode 100644
index 00000000000..c891c173787
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseUpdateError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class DatabaseUpdateError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DeleteError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DeleteError.php
new file mode 100644
index 00000000000..27c4b2a4894
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DeleteError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class DeleteError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DocumentError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DocumentError.php
new file mode 100644
index 00000000000..d501e3594b6
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DocumentError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class DocumentError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DomainError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DomainError.php
new file mode 100644
index 00000000000..b4eac2ae1d3
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DomainError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class DomainError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/EmptyResponseError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/EmptyResponseError.php
new file mode 100644
index 00000000000..c7863c09b01
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/EmptyResponseError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class EmptyResponseError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/EndpointError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/EndpointError.php
new file mode 100644
index 00000000000..a686a6456e9
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/EndpointError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class EndpointError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/FlavorError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/FlavorError.php
new file mode 100644
index 00000000000..469dc27e76c
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/FlavorError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class FlavorError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpError.php
new file mode 100644
index 00000000000..1b54b8a8253
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class HttpError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpForbiddenError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpForbiddenError.php
new file mode 100644
index 00000000000..a5c64780516
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpForbiddenError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class HttpForbiddenError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpOverLimitError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpOverLimitError.php
new file mode 100644
index 00000000000..243e8df64fd
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpOverLimitError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class HttpOverLimitError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpRetryError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpRetryError.php
new file mode 100644
index 00000000000..78345840bba
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpRetryError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class HttpRetryError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpTimeoutError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpTimeoutError.php
new file mode 100644
index 00000000000..81bc9dda608
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpTimeoutError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class HttpTimeoutError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpUnauthorizedError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpUnauthorizedError.php
new file mode 100644
index 00000000000..9b1edb20333
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpUnauthorizedError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class HttpUnauthorizedError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpUrlError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpUrlError.php
new file mode 100644
index 00000000000..fa2af82c564
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpUrlError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class HttpUrlError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/IOError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/IOError.php
new file mode 100644
index 00000000000..df816336c6c
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/IOError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class IOError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/IdRequiredError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/IdRequiredError.php
new file mode 100644
index 00000000000..398b9f3fd85
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/IdRequiredError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class IdRequiredError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ImageError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ImageError.php
new file mode 100644
index 00000000000..3b846a7551f
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ImageError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class ImageError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceCreateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceCreateError.php
new file mode 100644
index 00000000000..65caa154497
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceCreateError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class InstanceCreateError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceDeleteError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceDeleteError.php
new file mode 100644
index 00000000000..e4c6fdb7f57
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceDeleteError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class InstanceDeleteError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceError.php
new file mode 100644
index 00000000000..48152824862
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class InstanceError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceFlavorError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceFlavorError.php
new file mode 100644
index 00000000000..e8a074eb9bf
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceFlavorError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class InstanceFlavorError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceNotFound.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceNotFound.php
new file mode 100644
index 00000000000..4bc94797b3f
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceNotFound.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class InstanceNotFound extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceUpdateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceUpdateError.php
new file mode 100644
index 00000000000..b15f3426013
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceUpdateError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class InstanceUpdateError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidArgumentError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidArgumentError.php
new file mode 100644
index 00000000000..a655f11a731
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidArgumentError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class InvalidArgumentError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidIdTypeError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidIdTypeError.php
new file mode 100644
index 00000000000..f329c748957
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidIdTypeError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class InvalidIdTypeError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidIpTypeError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidIpTypeError.php
new file mode 100644
index 00000000000..370d8f650de
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidIpTypeError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class InvalidIpTypeError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidParameterError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidParameterError.php
new file mode 100644
index 00000000000..f13986ffc94
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidParameterError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class InvalidParameterError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidRequestError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidRequestError.php
new file mode 100644
index 00000000000..0266d8f22bd
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidRequestError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class InvalidRequestError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/JsonError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/JsonError.php
new file mode 100644
index 00000000000..96f9102ed37
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/JsonError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class JsonError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/LoggingException.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/LoggingException.php
new file mode 100644
index 00000000000..a5bdad705f4
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/LoggingException.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * @copyright Copyright 2012-2013 Rackspace US, Inc.
+ See COPYING for licensing information.
+ * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0
+ * @version 1.5.9
+ * @author Jamie Hannaford <jamie.hannaford@rackspace.com>
+ */
+
+namespace OpenCloud\Common\Exceptions;
+
+use Exception;
+
+class LoggingException extends Exception
+{
+} \ No newline at end of file
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataCreateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataCreateError.php
new file mode 100644
index 00000000000..a119397392f
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataCreateError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class MetadataCreateError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataDeleteError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataDeleteError.php
new file mode 100644
index 00000000000..4acd879afe9
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataDeleteError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class MetadataDeleteError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataError.php
new file mode 100644
index 00000000000..65f94975a44
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class MetadataError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataJsonError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataJsonError.php
new file mode 100644
index 00000000000..a7a74ca9e13
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataJsonError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class MetadataJsonError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataKeyError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataKeyError.php
new file mode 100644
index 00000000000..606f6d95874
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataKeyError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class MetadataKeyError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataPrefixError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataPrefixError.php
new file mode 100644
index 00000000000..271e69010a7
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataPrefixError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class MetadataPrefixError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataUpdateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataUpdateError.php
new file mode 100644
index 00000000000..49db43d6f70
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataUpdateError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class MetadataUpdateError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MisMatchedChecksumError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MisMatchedChecksumError.php
new file mode 100644
index 00000000000..75b4f926995
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MisMatchedChecksumError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class MisMatchedChecksumError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MissingValueError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MissingValueError.php
new file mode 100644
index 00000000000..0dd5b8ee737
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MissingValueError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class MissingValueError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NameError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NameError.php
new file mode 100644
index 00000000000..6918120a56c
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NameError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class NameError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkCreateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkCreateError.php
new file mode 100644
index 00000000000..a0c7640ffe8
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkCreateError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class NetworkCreateError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkDeleteError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkDeleteError.php
new file mode 100644
index 00000000000..0e2922babe2
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkDeleteError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class NetworkDeleteError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkError.php
new file mode 100644
index 00000000000..4b30806c1bc
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class NetworkError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkUpdateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkUpdateError.php
new file mode 100644
index 00000000000..f55f09d8ec2
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkUpdateError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class NetworkUpdateError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkUrlError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkUrlError.php
new file mode 100644
index 00000000000..666ec50482b
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkUrlError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class NetworkUrlError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NoContentTypeError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NoContentTypeError.php
new file mode 100644
index 00000000000..59a33088163
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NoContentTypeError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class NoContentTypeError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NoNameError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NoNameError.php
new file mode 100644
index 00000000000..2d56f5fcd0d
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NoNameError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class NoNameError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjFetchError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjFetchError.php
new file mode 100644
index 00000000000..9d7391823e8
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjFetchError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class ObjFetchError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjectCopyError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjectCopyError.php
new file mode 100644
index 00000000000..ef7b3b39220
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjectCopyError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class ObjectCopyError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjectError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjectError.php
new file mode 100644
index 00000000000..ea667ad25f6
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjectError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class ObjectError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/RebuildError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/RebuildError.php
new file mode 100644
index 00000000000..9ee6ab37fd9
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/RebuildError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class RebuildError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/RecordTypeError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/RecordTypeError.php
new file mode 100644
index 00000000000..718ce98574c
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/RecordTypeError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class RecordTypeError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerActionError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerActionError.php
new file mode 100644
index 00000000000..d4ad6453281
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerActionError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class ServerActionError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerCreateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerCreateError.php
new file mode 100644
index 00000000000..69904111c61
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerCreateError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class ServerCreateError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerDeleteError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerDeleteError.php
new file mode 100644
index 00000000000..94a1adc4f0b
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerDeleteError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class ServerDeleteError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerImageScheduleError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerImageScheduleError.php
new file mode 100644
index 00000000000..19fbcbd279c
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerImageScheduleError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class ServerImageScheduleError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerIpsError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerIpsError.php
new file mode 100644
index 00000000000..3e737c28614
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerIpsError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class ServerIpsError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerJsonError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerJsonError.php
new file mode 100644
index 00000000000..c10e67d645d
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerJsonError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class ServerJsonError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerUpdateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerUpdateError.php
new file mode 100644
index 00000000000..d9d7b370808
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerUpdateError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class ServerUpdateError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerUrlError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerUrlError.php
new file mode 100644
index 00000000000..ba0308d04e7
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerUrlError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class ServerUrlError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServiceValueError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServiceValueError.php
new file mode 100644
index 00000000000..7ce52c846a4
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServiceValueError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class ServiceValueError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/SnapshotError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/SnapshotError.php
new file mode 100644
index 00000000000..14d7614a9ee
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/SnapshotError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class SnapshotError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/TempUrlMethodError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/TempUrlMethodError.php
new file mode 100644
index 00000000000..61f4647d1b3
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/TempUrlMethodError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class TempUrlMethodError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnknownError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnknownError.php
new file mode 100644
index 00000000000..2b0772530fc
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnknownError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class UnknownError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnknownParameterError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnknownParameterError.php
new file mode 100644
index 00000000000..704ee28c052
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnknownParameterError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class UnknownParameterError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnrecognizedServiceError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnrecognizedServiceError.php
new file mode 100644
index 00000000000..396d451e131
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnrecognizedServiceError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class UnrecognizedServiceError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedExtensionError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedExtensionError.php
new file mode 100644
index 00000000000..5ff5ae89c73
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedExtensionError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class UnsupportedExtensionError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedFeatureExtension.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedFeatureExtension.php
new file mode 100644
index 00000000000..6d9143a1d91
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedFeatureExtension.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class UnsupportedFeatureExtension extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedVersionError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedVersionError.php
new file mode 100644
index 00000000000..060733ad5b5
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedVersionError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class UnsupportedVersionError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UpdateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UpdateError.php
new file mode 100644
index 00000000000..23f0dbb6aa7
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UpdateError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class UpdateError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UrlError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UrlError.php
new file mode 100644
index 00000000000..6c4d9ab69aa
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UrlError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class UrlError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserCreateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserCreateError.php
new file mode 100644
index 00000000000..f87ee0d2fc9
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserCreateError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class UserCreateError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserDeleteError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserDeleteError.php
new file mode 100644
index 00000000000..3196289aafc
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserDeleteError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class UserDeleteError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserListError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserListError.php
new file mode 100644
index 00000000000..7d287ae0ecf
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserListError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class UserListError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserNameError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserNameError.php
new file mode 100644
index 00000000000..51902f8e93c
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserNameError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class UserNameError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserUpdateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserUpdateError.php
new file mode 100644
index 00000000000..403b53420d0
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserUpdateError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class UserUpdateError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/VolumeError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/VolumeError.php
new file mode 100644
index 00000000000..c19c4c2009d
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/VolumeError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class VolumeError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/VolumeTypeError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/VolumeTypeError.php
new file mode 100644
index 00000000000..a9cc1e3f64b
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/VolumeTypeError.php
@@ -0,0 +1,5 @@
+<?php
+
+namespace OpenCloud\Common\Exceptions;
+
+class VolumeTypeError extends \Exception {}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/Role.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/Role.php
new file mode 100644
index 00000000000..b2c480d71b5
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/Role.php
@@ -0,0 +1,21 @@
+<?php
+
+/**
+ * PHP OpenCloud library.
+ *
+ * @author Jamie Hannaford <jamie@limetree.org>
+ * @version 2.0.0
+ * @copyright Copyright 2012-2013 Rackspace US, Inc.
+ * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0
+ */
+
+/**
+ * Description of Role
+ *
+ * @link
+ *
+ * @codeCoverageIgnore
+ */
+class Role
+{
+} \ No newline at end of file
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/Tenant.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/Tenant.php
new file mode 100644
index 00000000000..62783613c2f
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/Tenant.php
@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * PHP OpenCloud library.
+ *
+ * @author Jamie Hannaford <jamie@limetree.org>
+ * @version 2.0.0
+ * @copyright Copyright 2012-2013 Rackspace US, Inc.
+ * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0
+ */
+
+/**
+ * Description of Tenant
+ *
+ * @link
+ *
+ * @codeCoverageIgnore
+ */
+class Tenant
+{
+
+} \ No newline at end of file
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/User.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/User.php
new file mode 100644
index 00000000000..9e3862d1750
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/User.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * @copyright 2012-2013 Rackspace Hosting, Inc.
+ * See COPYING for licensing information
+ * @package phpOpenCloud
+ * @version 1.5.9
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ * @author Jamie Hannaford <jamie.hannaford@rackspace.co.uk>
+ */
+
+/**
+ * Represents a sub-user in Keystone.
+ *
+ * @link http://docs.rackspace.com/auth/api/v2.0/auth-client-devguide/content/User_Calls.html
+ *
+ * @codeCoverageIgnore
+ */
+class User extends PersistentObject
+{
+
+ public static function factory($info)
+ {
+ $user = new self;
+ }
+
+ /**
+ * Return detailed information about a specific user, by either user name or user ID.
+ * @param int|string $info
+ */
+ public function get($info)
+ {
+ if (is_integer($info)) {
+
+ } elseif (is_string($info)) {
+
+ } else {
+ throw new Exception\IdentityException(sprintf(
+ 'A string-based username or an integer-based user ID is valid'
+ ));
+ }
+ }
+
+ public function create()
+ {
+
+ }
+
+ public function update()
+ {
+
+ }
+
+ public function delete()
+ {
+
+ }
+
+ public function listAllCredentials()
+ {
+
+ }
+
+ public function getCredentials()
+ {
+
+ }
+
+ public function resetApiKey()
+ {
+
+ }
+
+} \ No newline at end of file
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Lang.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Lang.php
new file mode 100644
index 00000000000..7bb12859734
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Lang.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace OpenCloud\Common;
+
+class Lang
+{
+
+ public static function translate($word = null)
+ {
+ return $word;
+ }
+
+ public static function noslash($str)
+ {
+ while ($str && (substr($str, -1) == '/')) {
+ $str = substr($str, 0, strlen($str) - 1);
+ }
+ return $str;
+ }
+
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/AbstractLogger.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/AbstractLogger.php
new file mode 100644
index 00000000000..c7aea7f8767
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/AbstractLogger.php
@@ -0,0 +1,140 @@
+<?php
+
+// Copyright (c) 2012 PHP Framework Interoperability Group
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+namespace OpenCloud\Common\Log;
+
+/**
+ * This is a simple Logger implementation that other Loggers can inherit from.
+ *
+ * It simply delegates all log-level-specific methods to the `log` method to
+ * reduce boilerplate code that a simple Logger that does the same thing with
+ * messages regardless of the error level has to implement.
+ */
+abstract class AbstractLogger implements LoggerInterface
+{
+ /**
+ * System is unusable.
+ *
+ * @param string $message
+ * @param array $context
+ * @return null
+ */
+ public function emergency($message, array $context = array())
+ {
+ $this->log(LogLevel::EMERGENCY, $message, $context);
+ }
+
+ /**
+ * Action must be taken immediately.
+ *
+ * Example: Entire website down, database unavailable, etc. This should
+ * trigger the SMS alerts and wake you up.
+ *
+ * @param string $message
+ * @param array $context
+ * @return null
+ */
+ public function alert($message, array $context = array())
+ {
+ $this->log(LogLevel::ALERT, $message, $context);
+ }
+
+ /**
+ * Critical conditions.
+ *
+ * Example: Application component unavailable, unexpected exception.
+ *
+ * @param string $message
+ * @param array $context
+ * @return null
+ */
+ public function critical($message, array $context = array())
+ {
+ $this->log(LogLevel::CRITICAL, $message, $context);
+ }
+
+ /**
+ * Runtime errors that do not require immediate action but should typically
+ * be logged and monitored.
+ *
+ * @param string $message
+ * @param array $context
+ * @return null
+ */
+ public function error($message, array $context = array())
+ {
+ $this->log(LogLevel::ERROR, $message, $context);
+ }
+
+ /**
+ * Exceptional occurrences that are not errors.
+ *
+ * Example: Use of deprecated APIs, poor use of an API, undesirable things
+ * that are not necessarily wrong.
+ *
+ * @param string $message
+ * @param array $context
+ * @return null
+ */
+ public function warning($message, array $context = array())
+ {
+ $this->log(LogLevel::WARNING, $message, $context);
+ }
+
+ /**
+ * Normal but significant events.
+ *
+ * @param string $message
+ * @param array $context
+ * @return null
+ */
+ public function notice($message, array $context = array())
+ {
+ $this->log(LogLevel::NOTICE, $message, $context);
+ }
+
+ /**
+ * Interesting events.
+ *
+ * Example: User logs in, SQL logs.
+ *
+ * @param string $message
+ * @param array $context
+ * @return null
+ */
+ public function info($message, array $context = array())
+ {
+ $this->log(LogLevel::INFO, $message, $context);
+ }
+
+ /**
+ * Detailed debug information.
+ *
+ * @param string $message
+ * @param array $context
+ * @return null
+ */
+ public function debug($message, array $context = array())
+ {
+ $this->log(LogLevel::DEBUG, $message, $context);
+ }
+} \ No newline at end of file
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/LogLevel.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/LogLevel.php
new file mode 100644
index 00000000000..64b0169b507
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/LogLevel.php
@@ -0,0 +1,38 @@
+<?php
+
+// Copyright (c) 2012 PHP Framework Interoperability Group
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+namespace OpenCloud\Common\Log;
+
+/**
+ * Describes log levels
+ */
+class LogLevel
+{
+ const EMERGENCY = 'emergency';
+ const ALERT = 'alert';
+ const CRITICAL = 'critical';
+ const ERROR = 'error';
+ const WARNING = 'warning';
+ const NOTICE = 'notice';
+ const INFO = 'info';
+ const DEBUG = 'debug';
+} \ No newline at end of file
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/Logger.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/Logger.php
new file mode 100644
index 00000000000..e11d3fbb7ca
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/Logger.php
@@ -0,0 +1,220 @@
+<?php
+/**
+ * @copyright Copyright 2012-2013 Rackspace US, Inc.
+ See COPYING for licensing information.
+ * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0
+ * @version 1.5.9
+ * @author Jamie Hannaford <jamie.hannaford@rackspace.com>
+ */
+
+namespace OpenCloud\Common\Log;
+
+use OpenCloud\Common\Exceptions\LoggingException;
+
+/**
+ * Basic logger for OpenCloud which extends FIG's PSR-3 standard logger.
+ *
+ * @link https://github.com/php-fig/log
+ */
+class Logger extends AbstractLogger
+{
+ /**
+ * Is this debug class enabled or not?
+ *
+ * @var bool
+ */
+ private $enabled = false;
+
+ /**
+ * These are the levels which will always be outputted - regardless of
+ * user-imposed settings.
+ *
+ * @var array
+ */
+ private $urgentLevels = array(
+ LogLevel::EMERGENCY,
+ LogLevel::ALERT,
+ LogLevel::CRITICAL
+ );
+
+ /**
+ * Logging options.
+ *
+ * @var array
+ */
+ private $options = array(
+ 'outputToFile' => false,
+ 'logFile' => null,
+ 'dateFormat' => 'd/m/y H:I',
+ 'delimeter' => ' - '
+ );
+
+ /**
+ * Determines whether a log level needs to be outputted.
+ *
+ * @param string $logLevel
+ * @return bool
+ */
+ private function outputIsUrgent($logLevel)
+ {
+ return in_array($logLevel, $this->urgentLevels);
+ }
+
+ /**
+ * Interpolates context values into the message placeholders.
+ *
+ * @param string $message
+ * @param array $context
+ * @return type
+ */
+ private function interpolate($message, array $context = array())
+ {
+ // build a replacement array with braces around the context keys
+ $replace = array();
+ foreach ($context as $key => $val) {
+ $replace['{' . $key . '}'] = $val;
+ }
+
+ // interpolate replacement values into the message and return
+ return strtr($message, $replace);
+ }
+
+ /**
+ * Enable or disable the debug class.
+ *
+ * @param bool $enabled
+ * @return self
+ */
+ public function setEnabled($enabled)
+ {
+ $this->enabled = $enabled;
+ return $this;
+ }
+
+ /**
+ * Is the debug class enabled?
+ *
+ * @return bool
+ */
+ public function getEnabled()
+ {
+ return $this->enabled;
+ }
+
+ /**
+ * Set an array of options.
+ *
+ * @param array $options
+ */
+ public function setOptions(array $options = array())
+ {
+ foreach ($options as $key => $value) {
+ $this->setOption($key, $value);
+ }
+ }
+
+ /**
+ * Get all options.
+ *
+ * @return array
+ */
+ public function getOptions()
+ {
+ return $this->options;
+ }
+
+ /**
+ * Set an individual option.
+ *
+ * @param string $key
+ * @param string $value
+ */
+ public function setOption($key, $value)
+ {
+ if ($this->optionExists($key)) {
+ $this->options[$key] = $value;
+ }
+ }
+
+ /**
+ * Get an individual option.
+ *
+ * @param string $key
+ * @return string|null
+ */
+ public function getOption($key)
+ {
+ if ($this->optionExists($key)) {
+ return $this->options[$key];
+ }
+ }
+
+ /**
+ * Check whether an individual option exists.
+ *
+ * @param string $key
+ * @return bool
+ */
+ private function optionExists($key)
+ {
+ return array_key_exists($key, $this->getOptions());
+ }
+
+ /**
+ * Outputs a log message if necessary.
+ *
+ * @param string $logLevel
+ * @param string $message
+ * @param string $context
+ */
+ public function log($level, $message, array $context = array())
+ {
+ if ($this->outputIsUrgent($level)
+ || $this->getEnabled() === true
+ || RAXSDK_DEBUG === true
+ ) {
+ $this->dispatch($message, $context);
+ }
+ }
+
+ /**
+ * Used to format the line outputted in the log file.
+ *
+ * @param string $string
+ * @return string
+ */
+ private function formatFileLine($string)
+ {
+ $format = $this->getOption('dateFormat') . $this->getOption('delimeter');
+ return date($format) . $string;
+ }
+
+ /**
+ * Dispatch a log output message.
+ *
+ * @param string $message
+ * @param array $context
+ * @throws LoggingException
+ */
+ private function dispatch($message, $context)
+ {
+ $output = $this->interpolate($message, $context) . PHP_EOL;
+
+ if ($this->getOption('outputToFile') === true) {
+ $file = $this->getOption('logFile');
+
+ if (!is_writable($file)) {
+ throw new LoggingException(
+ 'The log file either does not exist or is not writeable'
+ );
+ }
+
+ // Output to file
+ file_put_contents($file, $this->formatFileLine($output));
+ } else {
+
+ echo $output;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/LoggerInterface.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/LoggerInterface.php
new file mode 100644
index 00000000000..daef1b04dad
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/LoggerInterface.php
@@ -0,0 +1,134 @@
+<?php
+
+// Copyright (c) 2012 PHP Framework Interoperability Group
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+namespace OpenCloud\Common\Log;
+
+/**
+ * Describes a logger instance
+ *
+ * The message MUST be a string or object implementing __toString().
+ *
+ * The message MAY contain placeholders in the form: {foo} where foo
+ * will be replaced by the context data in key "foo".
+ *
+ * The context array can contain arbitrary data, the only assumption that
+ * can be made by implementors is that if an Exception instance is given
+ * to produce a stack trace, it MUST be in a key named "exception".
+ *
+ * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
+ * for the full interface specification.
+ */
+interface LoggerInterface
+{
+ /**
+ * System is unusable.
+ *
+ * @param string $message
+ * @param array $context
+ * @return null
+ */
+ public function emergency($message, array $context = array());
+
+ /**
+ * Action must be taken immediately.
+ *
+ * Example: Entire website down, database unavailable, etc. This should
+ * trigger the SMS alerts and wake you up.
+ *
+ * @param string $message
+ * @param array $context
+ * @return null
+ */
+ public function alert($message, array $context = array());
+
+ /**
+ * Critical conditions.
+ *
+ * Example: Application component unavailable, unexpected exception.
+ *
+ * @param string $message
+ * @param array $context
+ * @return null
+ */
+ public function critical($message, array $context = array());
+
+ /**
+ * Runtime errors that do not require immediate action but should typically
+ * be logged and monitored.
+ *
+ * @param string $message
+ * @param array $context
+ * @return null
+ */
+ public function error($message, array $context = array());
+
+ /**
+ * Exceptional occurrences that are not errors.
+ *
+ * Example: Use of deprecated APIs, poor use of an API, undesirable things
+ * that are not necessarily wrong.
+ *
+ * @param string $message
+ * @param array $context
+ * @return null
+ */
+ public function warning($message, array $context = array());
+
+ /**
+ * Normal but significant events.
+ *
+ * @param string $message
+ * @param array $context
+ * @return null
+ */
+ public function notice($message, array $context = array());
+
+ /**
+ * Interesting events.
+ *
+ * Example: User logs in, SQL logs.
+ *
+ * @param string $message
+ * @param array $context
+ * @return null
+ */
+ public function info($message, array $context = array());
+
+ /**
+ * Detailed debug information.
+ *
+ * @param string $message
+ * @param array $context
+ * @return null
+ */
+ public function debug($message, array $context = array());
+
+ /**
+ * Logs with an arbitrary level.
+ *
+ * @param mixed $level
+ * @param string $message
+ * @param array $context
+ * @return null
+ */
+ public function log($level, $message, array $context = array());
+} \ No newline at end of file
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Metadata.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Metadata.php
new file mode 100644
index 00000000000..be6903e897e
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Metadata.php
@@ -0,0 +1,92 @@
+<?php
+/**
+ * A metadata object, used by other components in Compute and Object Storage
+ *
+ * @copyright 2012-2013 Rackspace Hosting, Inc.
+ * See COPYING for licensing information
+ *
+ * @package phpOpenCloud
+ * @version 1.0
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ */
+
+namespace OpenCloud\Common;
+
+/**
+ * The Metadata class represents either Server or Image metadata
+ *
+ * @api
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ */
+class Metadata extends Base
+{
+
+ // array holding the names of keys that were set
+ private $_keylist = array();
+
+ /**
+ * This setter overrides the base one, since the metadata key can be
+ * anything
+ *
+ * @param string $key
+ * @param string $value
+ * @return void
+ */
+ public function __set($key, $value)
+ {
+ // set the value and track the keys
+ if (!in_array($key, $this->_keylist)) {
+ $this->_keylist[] = $key;
+ }
+
+ $this->$key = $value;
+ }
+
+ /**
+ * Returns the list of keys defined
+ *
+ * @return array
+ */
+ public function Keylist()
+ {
+ return $this->_keylist;
+ }
+
+ /**
+ * Sets metadata values from an array, with optional prefix
+ *
+ * If $prefix is provided, then only array keys that match the prefix
+ * are set as metadata values, and $prefix is stripped from the key name.
+ *
+ * @param array $values an array of key/value pairs to set
+ * @param string $prefix if provided, a prefix that is used to identify
+ * metadata values. For example, you can set values from headers
+ * for a Container by using $prefix='X-Container-Meta-'.
+ * @return void
+ */
+ public function setArray($values, $prefix = null)
+ {
+ if (empty($values)) {
+ return false;
+ }
+
+ foreach ($values as $key => $value) {
+ if ($prefix) {
+ if (strpos($key, $prefix) === 0) {
+ $name = substr($key, strlen($prefix));
+ $this->getLogger()->info(
+ Lang::translate('Setting [{name}] to [{value}]'),
+ array(
+ 'name' => $name,
+ 'value' => $value
+ )
+ );
+ $this->$name = $value;
+ }
+ } else {
+ $this->$key = $value;
+ }
+ }
+ }
+
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Nova.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Nova.php
new file mode 100644
index 00000000000..fe4dcccc73f
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Nova.php
@@ -0,0 +1,140 @@
+<?php
+
+/**
+ * An abstract class that defines shared components for products that use
+ * OpenStack Nova
+ *
+ * @copyright 2012-2013 Rackspace Hosting, Inc.
+ * See COPYING for licensing information
+ *
+ * @package phpOpenCloud
+ * @version 1.0
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ */
+
+namespace OpenCloud\Common;
+
+use OpenCloud\OpenStack;
+use OpenCloud\Common\Lang;
+use OpenCloud\Compute\Flavor;
+
+/**
+ * Nova is an abstraction layer for the OpenStack compute service.
+ *
+ * Nova is used as a basis for several products, including Compute services
+ * as well as Rackspace's Cloud Databases. This class is, in essence, a vehicle
+ * for sharing common code between those other classes.
+ */
+abstract class Nova extends Service
+{
+
+ private $_url;
+
+ /**
+ * Called when creating a new Compute service object
+ *
+ * _NOTE_ that the order of parameters for this is *different* from the
+ * parent Service class. This is because the earlier parameters are the
+ * ones that most typically change, whereas the later ones are not
+ * modified as often.
+ *
+ * @param \OpenCloud\Identity $conn - a connection object
+ * @param string $serviceRegion - identifies the region of this Compute
+ * service
+ * @param string $urltype - identifies the URL type ("publicURL",
+ * "privateURL")
+ * @param string $serviceName - identifies the name of the service in the
+ * catalog
+ */
+ public function __construct(
+ OpenStack $conn,
+ $serviceType,
+ $serviceName,
+ $serviceRegion,
+ $urltype
+ ) {
+ parent::__construct(
+ $conn,
+ $serviceType,
+ $serviceName,
+ $serviceRegion,
+ $urltype
+ );
+
+ $this->_url = Lang::noslash(parent::Url());
+
+ $this->getLogger()->info(Lang::translate('Initializing Nova...'));
+ }
+
+ /**
+ * Returns a flavor from the service
+ *
+ * This is a factory method and should generally be called instead of
+ * creating a Flavor object directly.
+ *
+ * @api
+ * @param string $id - if supplied, the Flavor identified by this is
+ * retrieved
+ * @return Compute\Flavor object
+ */
+ public function Flavor($id = null)
+ {
+ return new Flavor($this, $id);
+ }
+
+ /**
+ * Returns a list of Flavor objects
+ *
+ * This is a factory method and should generally be called instead of
+ * creating a FlavorList object directly.
+ *
+ * @api
+ * @param boolean $details - if TRUE (the default), returns full details.
+ * Set to FALSE to retrieve minimal details and possibly improve
+ * performance.
+ * @param array $filter - optional key/value pairs for creating query
+ * strings
+ * @return Collection (or FALSE on an error)
+ */
+ public function FlavorList($details = true, array $filter = array())
+ {
+ if ($details) {
+ $url = $this->Url(Flavor::ResourceName().'/detail', $filter);
+ } else {
+ $url = $this->Url(Flavor::ResourceName(), $filter);
+ }
+ return $this->Collection('\OpenCloud\Compute\Flavor', $url);
+ }
+
+ /**
+ * Gets a request from an HTTP source and ensures that the
+ * content type is always "application/json"
+ *
+ * This is a simple subclass of the parent::Request() method that ensures
+ * that all Compute requests use application/json as the Content-Type:
+ *
+ * @param string $url - the URL of the request
+ * @param string $method - the HTTP method ("GET" by default)
+ * @param array $headers - an associative array of headers to pass to
+ * the request
+ * @param string $body - optional body for POST or PUT requests
+ * @return \Rackspace\HttpResult object
+ */
+ public function Request($url, $method = 'GET', array $headers = array(), $body = null)
+ {
+ $headers['Content-Type'] = RAXSDK_CONTENT_TYPE_JSON;
+ return parent::Request($url, $method, $headers, $body);
+ }
+
+ /**
+ * Loads the available namespaces from the /extensions resource
+ */
+ protected function load_namespaces()
+ {
+ $ext = $this->Extensions();
+ foreach($ext as $obj) {
+ $this->_namespaces[] = $obj->alias;
+ }
+ }
+
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/PersistentObject.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/PersistentObject.php
new file mode 100644
index 00000000000..0257526d709
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/PersistentObject.php
@@ -0,0 +1,939 @@
+<?php
+/**
+ * An abstraction that defines persistent objects associated with a service
+ *
+ * @copyright 2012-2013 Rackspace Hosting, Inc.
+ * See COPYING for licensing information
+ *
+ * @package phpOpenCloud
+ * @version 1.0
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ * @author Jamie Hannaford <jamie.hannaford@rackspace.com>
+ */
+
+namespace OpenCloud\Common;
+
+/**
+ * Represents an object that can be retrieved, created, updated and deleted.
+ *
+ * This class abstracts much of the common functionality between:
+ *
+ * * Nova servers;
+ * * Swift containers and objects;
+ * * DBAAS instances;
+ * * Cinder volumes;
+ * * and various other objects that:
+ * * have a URL;
+ * * can be created, updated, deleted, or retrieved;
+ * * use a standard JSON format with a top-level element followed by
+ * a child object with attributes.
+ *
+ * In general, you can create a persistent object class by subclassing this
+ * class and defining some protected, static variables:
+ *
+ * * $url_resource - the sub-resource value in the URL of the parent. For
+ * example, if the parent URL is `http://something/parent`, then setting this
+ * value to "another" would result in a URL for the persistent object of
+ * `http://something/parent/another`.
+ *
+ * * $json_name - the top-level JSON object name. For example, if the
+ * persistent object is represented by `{"foo": {"attr":value, ...}}`, then
+ * set $json_name to "foo".
+ *
+ * * $json_collection_name - optional; this value is the name of a collection
+ * of the persistent objects. If not provided, it defaults to `json_name`
+ * with an appended "s" (e.g., if `json_name` is "foo", then
+ * `json_collection_name` would be "foos"). Set this value if the collection
+ * name doesn't follow this pattern.
+ *
+ * * $json_collection_element - the common pattern for a collection is:
+ * `{"collection": [{"attr":"value",...}, {"attr":"value",...}, ...]}`
+ * That is, each element of the array is a \stdClass object containing the
+ * object's attributes. In rare instances, the objects in the array
+ * are named, and `json_collection_element` contains the name of the
+ * collection objects. For example, in this JSON response:
+ * `{"allowedDomain":[{"allowedDomain":{"name":"foo"}}]}`,
+ * `json_collection_element` would be set to "allowedDomain".
+ *
+ * The PersistentObject class supports the standard CRUD methods; if these are
+ * not needed (i.e. not supported by the service), the subclass should redefine
+ * these to call the `noCreate`, `noUpdate`, or `noDelete` methods, which will
+ * trigger an appropriate exception. For example, if an object cannot be created:
+ *
+ * function create($params = array())
+ * {
+ * $this->noCreate();
+ * }
+ */
+abstract class PersistentObject extends Base
+{
+
+ private $service;
+
+ private $parent;
+
+ protected $id;
+
+ /**
+ * Retrieves the instance from persistent storage
+ *
+ * @param mixed $service The service object for this resource
+ * @param mixed $info The ID or array/object of data
+ */
+ public function __construct($service = null, $info = null)
+ {
+ if ($service instanceof Service) {
+ $this->setService($service);
+ }
+
+ if (property_exists($this, 'metadata')) {
+ $this->metadata = new Metadata;
+ }
+
+ $this->populate($info);
+ }
+
+ /**
+ * Validates properties that have a namespace: prefix
+ *
+ * If the property prefix: appears in the list of supported extension
+ * namespaces, then the property is applied to the object. Otherwise,
+ * an exception is thrown.
+ *
+ * @param string $name the name of the property
+ * @param mixed $value the property's value
+ * @return void
+ * @throws AttributeError
+ */
+ public function __set($name, $value)
+ {
+ $this->setProperty($name, $value, $this->getService()->namespaces());
+ }
+
+ /**
+ * Sets the service associated with this resource object.
+ *
+ * @param \OpenCloud\Common\Service $service
+ */
+ public function setService(Service $service)
+ {
+ $this->service = $service;
+ return $this;
+ }
+
+ /**
+ * Returns the service object for this resource; required for making
+ * requests, etc. because it has direct access to the Connection.
+ *
+ * @return \OpenCloud\Common\Service
+ */
+ public function getService()
+ {
+ if (null === $this->service) {
+ throw new Exceptions\ServiceValueError(
+ 'No service defined'
+ );
+ }
+ return $this->service;
+ }
+
+ /**
+ * Legacy shortcut to getService
+ *
+ * @return \OpenCloud\Common\Service
+ */
+ public function service()
+ {
+ return $this->getService();
+ }
+
+ /**
+ * Set the parent object for this resource.
+ *
+ * @param \OpenCloud\Common\PersistentObject $parent
+ */
+ public function setParent(PersistentObject $parent)
+ {
+ $this->parent = $parent;
+ return $this;
+ }
+
+ /**
+ * Returns the parent.
+ *
+ * @return \OpenCloud\Common\PersistentObject
+ */
+ public function getParent()
+ {
+ if (null === $this->parent) {
+ $this->parent = $this->getService();
+ }
+ return $this->parent;
+ }
+
+ /**
+ * Legacy shortcut to getParent
+ *
+ * @return \OpenCloud\Common\PersistentObject
+ */
+ public function parent()
+ {
+ return $this->getParent();
+ }
+
+
+
+
+ /**
+ * API OPERATIONS (CRUD & CUSTOM)
+ */
+
+ /**
+ * Creates a new object
+ *
+ * @api
+ * @param array $params array of values to set when creating the object
+ * @return HttpResponse
+ * @throws VolumeCreateError if HTTP status is not Success
+ */
+ public function create($params = array())
+ {
+ // set parameters
+ if (!empty($params)) {
+ $this->populate($params, false);
+ }
+
+ // debug
+ $this->getLogger()->info('{class}::Create({name})', array(
+ 'class' => get_class($this),
+ 'name' => $this->Name()
+ ));
+
+ // construct the JSON
+ $object = $this->createJson();
+ $json = json_encode($object);
+ $this->checkJsonError();
+
+ $this->getLogger()->info('{class}::Create JSON [{json}]', array(
+ 'class' => get_class($this),
+ 'json' => $json
+ ));
+
+ // send the request
+ $response = $this->getService()->request(
+ $this->createUrl(),
+ 'POST',
+ array('Content-Type' => 'application/json'),
+ $json
+ );
+
+ // check the return code
+ // @codeCoverageIgnoreStart
+ if ($response->httpStatus() > 204) {
+ throw new Exceptions\CreateError(sprintf(
+ Lang::translate('Error creating [%s] [%s], status [%d] response [%s]'),
+ get_class($this),
+ $this->Name(),
+ $response->HttpStatus(),
+ $response->HttpBody()
+ ));
+ }
+
+ if ($response->HttpStatus() == "201" && ($location = $response->Header('Location'))) {
+ // follow Location header
+ $this->refresh(null, $location);
+ } else {
+ // set values from response
+ $object = json_decode($response->httpBody());
+
+ if (!$this->checkJsonError()) {
+ $top = $this->jsonName();
+ if (isset($object->$top)) {
+ $this->populate($object->$top);
+ }
+ }
+ }
+ // @codeCoverageIgnoreEnd
+
+ return $response;
+ }
+
+ /**
+ * Updates an existing object
+ *
+ * @api
+ * @param array $params array of values to set when updating the object
+ * @return HttpResponse
+ * @throws VolumeCreateError if HTTP status is not Success
+ */
+ public function update($params = array())
+ {
+ // set parameters
+ if (!empty($params)) {
+ $this->populate($params);
+ }
+
+ // debug
+ $this->getLogger()->info('{class}::Update({name})', array(
+ 'class' => get_class($this),
+ 'name' => $this->Name()
+ ));
+
+ // construct the JSON
+ $obj = $this->updateJson($params);
+ $json = json_encode($obj);
+
+ $this->checkJsonError();
+
+ $this->getLogger()->info('{class}::Update JSON [{json}]', array(
+ 'class' => get_class($this),
+ 'json' => $json
+ ));
+
+ // send the request
+ $response = $this->getService()->Request(
+ $this->url(),
+ 'PUT',
+ array(),
+ $json
+ );
+
+ // check the return code
+ // @codeCoverageIgnoreStart
+ if ($response->HttpStatus() > 204) {
+ throw new Exceptions\UpdateError(sprintf(
+ Lang::translate('Error updating [%s] with [%s], status [%d] response [%s]'),
+ get_class($this),
+ $json,
+ $response->HttpStatus(),
+ $response->HttpBody()
+ ));
+ }
+ // @codeCoverageIgnoreEnd
+
+ return $response;
+ }
+
+ /**
+ * Deletes an object
+ *
+ * @api
+ * @return HttpResponse
+ * @throws DeleteError if HTTP status is not Success
+ */
+ public function delete()
+ {
+ $this->getLogger()->info('{class}::Delete()', array('class' => get_class($this)));
+
+ // send the request
+ $response = $this->getService()->request($this->url(), 'DELETE');
+
+ // check the return code
+ // @codeCoverageIgnoreStart
+ if ($response->HttpStatus() > 204) {
+ throw new Exceptions\DeleteError(sprintf(
+ Lang::translate('Error deleting [%s] [%s], status [%d] response [%s]'),
+ get_class(),
+ $this->Name(),
+ $response->HttpStatus(),
+ $response->HttpBody()
+ ));
+ }
+ // @codeCoverageIgnoreEnd
+
+ return $response;
+ }
+
+ /**
+ * Returns an object for the Create() method JSON
+ * Must be overridden in a child class.
+ *
+ * @throws CreateError if not overridden
+ */
+ protected function createJson()
+ {
+ throw new Exceptions\CreateError(sprintf(
+ Lang::translate('[%s] CreateJson() must be overridden'),
+ get_class($this)
+ ));
+ }
+
+ /**
+ * Returns an object for the Update() method JSON
+ * Must be overridden in a child class.
+ *
+ * @throws UpdateError if not overridden
+ */
+ protected function updateJson($params = array())
+ {
+ throw new Exceptions\UpdateError(sprintf(
+ Lang::translate('[%s] UpdateJson() must be overridden'),
+ get_class($this)
+ ));
+ }
+
+ /**
+ * throws a CreateError for subclasses that don't support Create
+ *
+ * @throws CreateError
+ */
+ protected function noCreate()
+ {
+ throw new Exceptions\CreateError(sprintf(
+ Lang::translate('[%s] does not support Create()'),
+ get_class()
+ ));
+ }
+
+ /**
+ * throws a DeleteError for subclasses that don't support Delete
+ *
+ * @throws DeleteError
+ */
+ protected function noDelete()
+ {
+ throw new Exceptions\DeleteError(sprintf(
+ Lang::translate('[%s] does not support Delete()'),
+ get_class()
+ ));
+ }
+
+ /**
+ * throws a UpdateError for subclasses that don't support Update
+ *
+ * @throws UpdateError
+ */
+ protected function noUpdate()
+ {
+ throw new Exceptions\UpdateError(sprintf(
+ Lang::translate('[%s] does not support Update()'),
+ get_class()
+ ));
+ }
+
+ /**
+ * Returns the default URL of the object
+ *
+ * This may have to be overridden in subclasses.
+ *
+ * @param string $subresource optional sub-resource string
+ * @param array $qstr optional k/v pairs for query strings
+ * @return string
+ * @throws UrlError if URL is not defined
+ */
+ public function url($subresource = null, $queryString = array())
+ {
+ // find the primary key attribute name
+ $primaryKey = $this->primaryKeyField();
+
+ // first, see if we have a [self] link
+ $url = $this->findLink('self');
+
+ /**
+ * Next, check to see if we have an ID
+ * Note that we use Parent() instead of Service(), since the parent
+ * object might not be a service.
+ */
+ if (!$url && $this->$primaryKey) {
+ $url = Lang::noslash($this->getParent()->url($this->resourceName())) . '/' . $this->$primaryKey;
+ }
+
+ // add the subresource
+ if ($url) {
+ $url .= $subresource ? "/$subresource" : '';
+ if (count($queryString)) {
+ $url .= '?' . $this->makeQueryString($queryString);
+ }
+ return $url;
+ }
+
+ // otherwise, we don't have a URL yet
+ throw new Exceptions\UrlError(sprintf(
+ Lang::translate('%s does not have a URL yet'),
+ get_class($this)
+ ));
+ }
+
+ /**
+ * Waits for the server/instance status to change
+ *
+ * This function repeatedly polls the system for a change in server
+ * status. Once the status reaches the `$terminal` value (or 'ERROR'),
+ * then the function returns.
+ *
+ * The polling interval is set by the constant RAXSDK_POLL_INTERVAL.
+ *
+ * The function will automatically terminate after RAXSDK_SERVER_MAXTIMEOUT
+ * seconds elapse.
+ *
+ * @api
+ * @param string $terminal the terminal state to wait for
+ * @param integer $timeout the max time (in seconds) to wait
+ * @param callable $callback a callback function that is invoked with
+ * each repetition of the polling sequence. This can be used, for
+ * example, to update a status display or to permit other operations
+ * to continue
+ * @return void
+ */
+ public function waitFor(
+ $terminal = 'ACTIVE',
+ $timeout = RAXSDK_SERVER_MAXTIMEOUT,
+ $callback = NULL,
+ $sleep = RAXSDK_POLL_INTERVAL
+ ) {
+ // find the primary key field
+ $primaryKey = $this->PrimaryKeyField();
+
+ // save stats
+ $startTime = time();
+
+ $states = array('ERROR', $terminal);
+
+ while (true) {
+
+ $this->refresh($this->$primaryKey);
+
+ if ($callback) {
+ call_user_func($callback, $this);
+ }
+
+ if (in_array($this->status(), $states) || (time() - $startTime) > $timeout) {
+ return;
+ }
+ // @codeCoverageIgnoreStart
+ sleep($sleep);
+ }
+ }
+ // @codeCoverageIgnoreEnd
+
+ /**
+ * Refreshes the object from the origin (useful when the server is
+ * changing states)
+ *
+ * @return void
+ * @throws IdRequiredError
+ */
+ public function refresh($id = null, $url = null)
+ {
+ $primaryKey = $this->PrimaryKeyField();
+
+ if (!$url) {
+ if ($id === null) {
+ $id = $this->$primaryKey;
+ }
+
+ if (!$id) {
+ throw new Exceptions\IdRequiredError(sprintf(
+ Lang::translate('%s has no ID; cannot be refreshed'),
+ get_class())
+ );
+ }
+
+ // retrieve it
+ $this->getLogger()->info(Lang::translate('{class} id [{id}]'), array(
+ 'class' => get_class($this),
+ 'id' => $id
+ ));
+
+ $this->$primaryKey = $id;
+ $url = $this->url();
+ }
+
+ // reset status, if available
+ if (property_exists($this, 'status')) {
+ $this->status = null;
+ }
+
+ // perform a GET on the URL
+ $response = $this->getService()->Request($url);
+
+ // check status codes
+ // @codeCoverageIgnoreStart
+ if ($response->HttpStatus() == 404) {
+ throw new Exceptions\InstanceNotFound(
+ sprintf(Lang::translate('%s [%s] not found [%s]'),
+ get_class($this),
+ $this->$primaryKey,
+ $url
+ ));
+ }
+
+ if ($response->HttpStatus() >= 300) {
+ throw new Exceptions\UnknownError(
+ sprintf(Lang::translate('Unexpected %s error [%d] [%s]'),
+ get_class($this),
+ $response->HttpStatus(),
+ $response->HttpBody()
+ ));
+ }
+
+ // check for empty response
+ if (!$response->HttpBody()) {
+ throw new Exceptions\EmptyResponseError(
+ sprintf(Lang::translate('%s::Refresh() unexpected empty response, URL [%s]'),
+ get_class($this),
+ $url
+ ));
+ }
+
+ // we're ok, reload the response
+ if ($json = $response->HttpBody()) {
+
+ $this->getLogger()->info('refresh() JSON [{json}]', array('json' => $json));
+
+ $response = json_decode($json);
+
+ if ($this->CheckJsonError()) {
+ throw new Exceptions\ServerJsonError(sprintf(
+ Lang::translate('JSON parse error on %s refresh'),
+ get_class($this)
+ ));
+ }
+
+ $top = $this->JsonName();
+
+ if ($top && isset($response->$top)) {
+ $content = $response->$top;
+ } else {
+ $content = $response;
+ }
+
+ $this->populate($content);
+
+ }
+ // @codeCoverageIgnoreEnd
+ }
+
+
+ /**
+ * OBJECT INFORMATION
+ */
+
+ /**
+ * Returns the displayable name of the object
+ *
+ * Can be overridden by child objects; *must* be overridden by child
+ * objects if the object does not have a `name` attribute defined.
+ *
+ * @api
+ * @return string
+ * @throws NameError if attribute 'name' is not defined
+ */
+ public function name()
+ {
+ if (property_exists($this, 'name')) {
+ return $this->name;
+ } else {
+ throw new Exceptions\NameError(sprintf(
+ Lang::translate('Name attribute does not exist for [%s]'),
+ get_class($this)
+ ));
+ }
+ }
+
+ /**
+ * Sends the json string to the /action resource
+ *
+ * This is used for many purposes, such as rebooting the server,
+ * setting the root password, creating images, etc.
+ * Since it can only be used on a live server, it checks for a valid ID.
+ *
+ * @param $object - this will be encoded as json, and we handle all the JSON
+ * error-checking in one place
+ * @throws ServerIdError if server ID is not defined
+ * @throws ServerActionError on other errors
+ * @returns boolean; TRUE if successful, FALSE otherwise
+ */
+ protected function action($object)
+ {
+ $primaryKey = $this->primaryKeyField();
+
+ if (!$this->$primaryKey) {
+ throw new Exceptions\IdRequiredError(sprintf(
+ Lang::translate('%s is not defined'),
+ get_class($this)
+ ));
+ }
+
+ if (!is_object($object)) {
+ throw new Exceptions\ServerActionError(sprintf(
+ Lang::translate('%s::Action() requires an object as its parameter'),
+ get_class($this)
+ ));
+ }
+
+ // convert the object to json
+ $json = json_encode($object);
+ $this->getLogger()->info('JSON [{string}]', array('json' => $json));
+
+ $this->checkJsonError();
+
+ // debug - save the request
+ $this->getLogger()->info(Lang::translate('{class}::action [{json}]'), array(
+ 'class' => get_class($this),
+ 'json' => $json
+ ));
+
+ // get the URL for the POST message
+ $url = $this->url('action');
+
+ // POST the message
+ $response = $this->getService()->request($url, 'POST', array(), $json);
+
+ // @codeCoverageIgnoreStart
+ if (!is_object($response)) {
+ throw new Exceptions\HttpError(sprintf(
+ Lang::translate('Invalid response for %s::Action() request'),
+ get_class($this)
+ ));
+ }
+
+ // check for errors
+ if ($response->HttpStatus() >= 300) {
+ throw new Exceptions\ServerActionError(sprintf(
+ Lang::translate('%s::Action() [%s] failed; response [%s]'),
+ get_class($this),
+ $url,
+ $response->HttpBody()
+ ));
+ }
+ // @codeCoverageIgnoreStart
+
+ return $response;
+ }
+
+ /**
+ * Execute a custom resource request.
+ *
+ * @param string $path
+ * @param string $method
+ * @param string|array|object $body
+ * @return boolean
+ * @throws Exceptions\InvalidArgumentError
+ * @throws Exceptions\HttpError
+ * @throws Exceptions\ServerActionError
+ */
+ public function customAction($url, $method = 'GET', $body = null)
+ {
+ if (is_string($body) && (json_decode($body) === null)) {
+ throw new Exceptions\InvalidArgumentError(
+ 'Please provide either a well-formed JSON string, or an object '
+ . 'for JSON serialization'
+ );
+ } else {
+ $body = json_encode($body);
+ }
+
+ // POST the message
+ $response = $this->service()->request($url, $method, array(), $body);
+
+ if (!is_object($response)) {
+ throw new Exceptions\HttpError(sprintf(
+ Lang::translate('Invalid response for %s::customAction() request'),
+ get_class($this)
+ ));
+ }
+
+ // check for errors
+ // @codeCoverageIgnoreStart
+ if ($response->HttpStatus() >= 300) {
+ throw new Exceptions\ServerActionError(sprintf(
+ Lang::translate('%s::customAction() [%s] failed; response [%s]'),
+ get_class($this),
+ $url,
+ $response->HttpBody()
+ ));
+ }
+ // @codeCoverageIgnoreEnd
+
+ $object = json_decode($response->httpBody());
+
+ $this->checkJsonError();
+
+ return $object;
+ }
+
+ /**
+ * returns the object's status or `N/A` if not available
+ *
+ * @api
+ * @return string
+ */
+ public function status()
+ {
+ return (isset($this->status)) ? $this->status : 'N/A';
+ }
+
+ /**
+ * returns the object's identifier
+ *
+ * Can be overridden by a child class if the identifier is not in the
+ * `$id` property. Use of this function permits the `$id` attribute to
+ * be protected or private to prevent unauthorized overwriting for
+ * security.
+ *
+ * @api
+ * @return string
+ */
+ public function id()
+ {
+ return $this->id;
+ }
+
+ /**
+ * checks for `$alias` in extensions and throws an error if not present
+ *
+ * @throws UnsupportedExtensionError
+ */
+ public function checkExtension($alias)
+ {
+ if (!in_array($alias, $this->getService()->namespaces())) {
+ throw new Exceptions\UnsupportedExtensionError(sprintf(
+ Lang::translate('Extension [%s] is not installed'),
+ $alias
+ ));
+ }
+
+ return true;
+ }
+
+ /**
+ * returns the region associated with the object
+ *
+ * navigates to the parent service to determine the region.
+ *
+ * @api
+ */
+ public function region()
+ {
+ return $this->getService()->Region();
+ }
+
+ /**
+ * Since each server can have multiple links, this returns the desired one
+ *
+ * @param string $type - 'self' is most common; use 'bookmark' for
+ * the version-independent one
+ * @return string the URL from the links block
+ */
+ public function findLink($type = 'self')
+ {
+ if (empty($this->links)) {
+ return false;
+ }
+
+ foreach ($this->links as $link) {
+ if ($link->rel == $type) {
+ return $link->href;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * returns the URL used for Create
+ *
+ * @return string
+ */
+ protected function createUrl()
+ {
+ return $this->getParent()->Url($this->ResourceName());
+ }
+
+ /**
+ * Returns the primary key field for the object
+ *
+ * The primary key is usually 'id', but this function is provided so that
+ * (in rare cases where it is not 'id'), it can be overridden.
+ *
+ * @return string
+ */
+ protected function primaryKeyField()
+ {
+ return 'id';
+ }
+
+ /**
+ * Returns the top-level document identifier for the returned response
+ * JSON document; must be overridden in child classes
+ *
+ * For example, a server document is (JSON) `{"server": ...}` and an
+ * Instance document is `{"instance": ...}` - this function must return
+ * the top level document name (either "server" or "instance", in
+ * these examples).
+ *
+ * @throws DocumentError if not overridden
+ */
+ public static function jsonName()
+ {
+ if (isset(static::$json_name)) {
+ return static::$json_name;
+ }
+
+ throw new Exceptions\DocumentError(sprintf(
+ Lang::translate('No JSON object defined for class [%s] in JsonName()'),
+ get_class()
+ ));
+ }
+
+ /**
+ * returns the collection JSON element name
+ *
+ * When an object is returned in a collection, it usually has a top-level
+ * object that is an array holding child objects of the object types.
+ * This static function returns the name of the top-level element. Usually,
+ * that top-level element is simply the JSON name of the resource.'s';
+ * however, it can be overridden by specifying the $json_collection_name
+ * attribute.
+ *
+ * @return string
+ */
+ public static function jsonCollectionName()
+ {
+ if (isset(static::$json_collection_name)) {
+ return static::$json_collection_name;
+ } else {
+ return static::$json_name . 's';
+ }
+ }
+
+ /**
+ * returns the JSON name for each element in a collection
+ *
+ * Usually, elements in a collection are anonymous; this function, however,
+ * provides for an element level name:
+ *
+ * `{ "collection" : [ { "element" : ... } ] }`
+ *
+ * @return string
+ */
+ public static function jsonCollectionElement()
+ {
+ if (isset(static::$json_collection_element)) {
+ return static::$json_collection_element;
+ }
+ }
+
+ /**
+ * Returns the resource name for the URL of the object; must be overridden
+ * in child classes
+ *
+ * For example, a server is `/servers/`, a database instance is
+ * `/instances/`. Must be overridden in child classes.
+ *
+ * @throws UrlError
+ */
+ public static function resourceName()
+ {
+ if (isset(static::$url_resource)) {
+ return static::$url_resource;
+ }
+
+ throw new Exceptions\UrlError(sprintf(
+ Lang::translate('No URL resource defined for class [%s] in ResourceName()'),
+ get_class()
+ ));
+ }
+
+} \ No newline at end of file
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Curl.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Curl.php
new file mode 100644
index 00000000000..bb829afc5f6
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Curl.php
@@ -0,0 +1,308 @@
+<?php
+
+namespace OpenCloud\Common\Request;
+
+use OpenCloud\Common\Base;
+use OpenCloud\Common\Lang;
+use OpenCloud\Common\Exceptions\HttpRetryError;
+use OpenCloud\Common\Exceptions\HttpUrlError;
+use OpenCloud\Common\Exceptions\HttpTimeoutError;
+use OpenCloud\Common\Exceptions\HttpError;
+
+/**
+ * The CurlRequest class is a simple wrapper to CURL functions. Not only does
+ * this permit stubbing of the interface as described under the HttpRequest
+ * interface, it could potentially allow us to replace the interface methods
+ * with other function calls in the future.
+ *
+ * @api
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ */
+class Curl extends Base implements HttpRequestInterface
+{
+
+ private $url;
+ private $method;
+ private $handle;
+ private $retries = 0;
+ private $headers = array();
+ private $returnheaders = array();
+
+ /**
+ * Initializes the CURL handle and HTTP method
+ *
+ * The constructor also sets a number of default values for options.
+ *
+ * @param string $url the URL to connect to
+ * @param string $method the HTTP method (default "GET")
+ * @param array $options optional hashed array of options => value pairs
+ */
+ public function __construct($url, $method = 'GET', array $options = array())
+ {
+ $this->url = $url;
+ $this->method = $method;
+ $this->handle = curl_init($url);
+
+ // set our options
+ $this->setOption(CURLOPT_CUSTOMREQUEST, $method);
+
+ foreach($options as $opt => $value) {
+ $this->getLogger()->info(Lang::translate('Setting option {key}={val}'), array(
+ 'key' => $opt,
+ 'val' => $value
+ ));
+ $this->setOption($opt, $value);
+ }
+
+ // @codeCoverageIgnoreStart
+ if (RAXSDK_SSL_VERIFYHOST != 2) {
+ $this->getLogger()->warning("WARNING: RAXSDK_SSL_VERIFYHOST has reduced security, value [{value}]", array(
+ 'value' => RAXSDK_SSL_VERIFYHOST
+ ));
+ }
+
+ if (RAXSDK_SSL_VERIFYPEER !== true) {
+ $this->getLogger()->warning("WARNING: RAXSDK_SSL_VERIFYPEER has reduced security");
+ }
+ // @codeCoverageIgnoreEnd
+
+ $this->setOption(CURLOPT_SSL_VERIFYHOST, RAXSDK_SSL_VERIFYHOST);
+ $this->setOption(CURLOPT_SSL_VERIFYPEER, RAXSDK_SSL_VERIFYPEER);
+
+ if (defined('RAXSDK_CACERTPEM') && file_exists(RAXSDK_CACERTPEM)) {
+ $this->setOption(CURLOPT_CAINFO, RAXSDK_CACERTPEM);
+ }
+
+ // curl code [18]
+ // message [transfer closed with x bytes remaining to read]
+ if ($method === 'HEAD') {
+ $this->setOption(CURLOPT_NOBODY, true);
+ }
+
+ // follow redirects
+ $this->setOption(CURLOPT_FOLLOWLOCATION, true);
+
+ // don't return the headers in the request
+ $this->setOption(CURLOPT_HEADER, false);
+
+ // retrieve headers via callback
+ $this->setOption(CURLOPT_HEADERFUNCTION, array($this, '_get_header_cb'));
+
+ // return the entire request on curl_exec()
+ $this->setOption(CURLOPT_RETURNTRANSFER, true);
+
+ // set default timeouts
+ $this->setConnectTimeout(RAXSDK_CONNECTTIMEOUT);
+ $this->setHttpTimeout(RAXSDK_TIMEOUT);
+ }
+
+ /**
+ * Sets a CURL option
+ *
+ * @param const $name - a CURL named constant; e.g. CURLOPT_TIMEOUT
+ * @param mixed $value - the value for the option
+ */
+ public function setOption($name, $value)
+ {
+ return curl_setopt($this->handle, $name, $value);
+ }
+
+ /**
+ * Explicit method for setting the connect timeout
+ *
+ * The connect timeout is the time it takes for the initial connection
+ * request to be established. It is different than the HTTP timeout, which
+ * is the time for the entire request to be serviced.
+ *
+ * @param integer $value The connection timeout in seconds.
+ * Use 0 to wait indefinitely (NOT recommended)
+ */
+ public function setConnectTimeout($value)
+ {
+ $this->setOption(CURLOPT_CONNECTTIMEOUT, $value);
+ }
+
+ /**
+ * Explicit method for setting the HTTP timeout
+ *
+ * The HTTP timeout is the time it takes for the HTTP request to be
+ * serviced. This value is usually larger than the connect timeout
+ * value.
+ *
+ * @param integer $value - the number of seconds to wait before timing out
+ * the HTTP request.
+ */
+ public function setHttpTimeout($value)
+ {
+ $this->setOption(CURLOPT_TIMEOUT, $value);
+ }
+
+ /**
+ * Sets the number of retries
+ *
+ * If you set this to a non-zero value, then it will repeat the request
+ * up to that number.
+ */
+ public function setRetries($value)
+ {
+ $this->retries = $value;
+ }
+
+ /**
+ * Simplified method for setting lots of headers at once
+ *
+ * This method takes an associative array of header/value pairs and calls
+ * the setheader() method on each of them.
+ *
+ * @param array $arr an associative array of headers
+ */
+ public function setheaders($array)
+ {
+ if (!is_array($array)) {
+ throw new HttpError(Lang::translate(
+ 'Value passed to CurlRequest::setheaders() must be array'
+ ));
+ }
+
+ foreach ($array as $name => $value) {
+ $this->setHeader($name, $value);
+ }
+ }
+
+ /**
+ * Sets a single header
+ *
+ * For example, to set the content type to JSON:
+ * `$request->SetHeader('Content-Type','application/json');`
+ *
+ * @param string $name The name of the header
+ * @param mixed $value The value of the header
+ */
+ public function setHeader($name, $value)
+ {
+ $this->headers[$name] = $value;
+ }
+
+ /**
+ * Executes the current request
+ *
+ * This method actually performs the request using the values set
+ * previously. It throws a OpenCloud\HttpError exception on
+ * any CURL error.
+ *
+ * @return OpenCloud\HttpResponse
+ * @throws OpenCloud\HttpError
+ *
+ * @codeCoverageIgnore
+ */
+ public function execute()
+ {
+ // set all the headers
+ $headarr = array();
+
+ foreach ($this->headers as $name => $value) {
+ $headarr[] = $name.': '.$value;
+ }
+
+ $this->setOption(CURLOPT_HTTPHEADER, $headarr);
+
+ // set up to retry if necessary
+ $try_counter = 0;
+
+ do {
+ $data = curl_exec($this->handle);
+ if (curl_errno($this->handle) && ($try_counter<$this->retries)) {
+ $this->getLogger()->info(Lang::translate('Curl error [%d]; retrying [%s]'), array(
+ 'error' => curl_errno($this->handle),
+ 'url' => $this->url
+ ));
+ }
+
+ } while((++$try_counter <= $this->retries) && (curl_errno($this->handle) != 0));
+
+ // log retries error
+ if ($this->retries && curl_errno($this->handle)) {
+ throw new HttpRetryError(sprintf(
+ Lang::translate('No more retries available, last error [%d]'),
+ curl_errno($this->handle)
+ ));
+ }
+
+ // check for CURL errors
+ switch(curl_errno($this->handle)) {
+ case 0:
+ // everything's ok
+ break;
+ case 3:
+ throw new HttpUrlError(sprintf(Lang::translate('Malformed URL [%s]'), $this->url));
+ break;
+ case 28:
+ // timeout
+ throw new HttpTimeoutError(Lang::translate('Operation timed out; check RAXSDK_TIMEOUT value'));
+ break;
+ default:
+ throw new HttpError(sprintf(
+ Lang::translate('HTTP error on [%s], curl code [%d] message [%s]'),
+ $this->url,
+ curl_errno($this->handle),
+ curl_error($this->handle)
+ ));
+ }
+
+ // otherwise, return the HttpResponse
+ return new Response\Http($this, $data);
+ }
+
+ /**
+ * returns an array of information about the request
+ */
+ public function info()
+ {
+ return curl_getinfo($this->handle);
+ }
+
+ /**
+ * returns the most recent CURL error number
+ */
+ public function errno()
+ {
+ return curl_errno($this->handle);
+ }
+
+ /**
+ * returns the most recent CURL error string
+ */
+ public function error()
+ {
+ return curl_error($this->handle);
+ }
+
+ /**
+ * Closes the HTTP request
+ */
+ public function close()
+ {
+ return curl_close($this->handle);
+ }
+
+ /**
+ * Returns the headers as an array
+ */
+ public function returnHeaders()
+ {
+ return $this->returnheaders;
+ }
+
+ /**
+ * This is a callback method used to handle the returned HTTP headers
+ *
+ * @param mixed $ch a CURL handle
+ * @param string $header the header string in its entirety
+ */
+ public function _get_header_cb($ch, $header)
+ {
+ $this->returnheaders[] = $header;
+ return strlen($header);
+ }
+
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/HttpRequestInterface.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/HttpRequestInterface.php
new file mode 100644
index 00000000000..cbe3b5412a1
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/HttpRequestInterface.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace OpenCloud\Common\Request;
+
+/**
+ * The HttpRequest interface defines methods for wrapping CURL; this allows
+ * those methods to be stubbed out for unit testing, thus allowing us to
+ * test without actually making live calls.
+ */
+interface HttpRequestInterface
+{
+
+ public function SetOption($name, $value);
+
+ public function setheaders($arr);
+
+ public function SetHeader($header, $value);
+
+ public function Execute();
+
+ public function close();
+
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Response/Blank.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Response/Blank.php
new file mode 100644
index 00000000000..0c79adcef3a
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Response/Blank.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace OpenCloud\Common\Request\Response;
+
+class Blank extends Http
+{
+ public $errno;
+ public $error;
+ public $info;
+ public $body;
+ public $headers = array();
+ public $status = 200;
+ public $rawdata;
+
+ public function __construct(array $values = array())
+ {
+ foreach($values as $name => $value) {
+ $this->$name = $value;
+ }
+ }
+
+ public function httpStatus()
+ {
+ return $this->status;
+ }
+
+} \ No newline at end of file
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Response/Http.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Response/Http.php
new file mode 100644
index 00000000000..a7cb9e96346
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Response/Http.php
@@ -0,0 +1,140 @@
+<?php
+
+namespace OpenCloud\Common\Request\Response;
+
+use OpenCloud\Common\Base;
+
+/**
+ * The HttpResponse returns an object with status information, separated
+ * headers, and any response body necessary.
+ *
+ * @api
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ */
+
+class Http extends Base
+{
+
+ private $errno;
+ private $error;
+ private $info = array();
+ protected $body;
+ protected $headers = array();
+
+ /**
+ * The constructor parses everything necessary
+ */
+ public function __construct($request, $data)
+ {
+ // save the raw data (who knows? we might need it)
+ $this->setBody($data);
+
+ // and split each line into name: value pairs
+ foreach($request->returnHeaders() as $line) {
+ if (preg_match('/^([^:]+):\s+(.+?)\s*$/', $line, $matches)) {
+ $this->headers[$matches[1]] = $matches[2];
+ } else {
+ $this->headers[$line] = trim($line);
+ }
+ }
+
+ // @codeCoverageIgnoreStart
+ if (isset($this->headers['Cache-Control'])) {
+ $this->getLogger()->info('Cache-Control: {header}', array(
+ 'headers' => $this->headers['Cache-Control']
+ ));
+ }
+ if (isset($this->headers['Expires'])) {
+ $this->getLogger()->info('Expires: {header}', array(
+ 'headers' => $this->headers['Expires']
+ ));
+ }
+ // @codeCoverageIgnoreEnd
+
+ // set some other data
+ $this->info = $request->info();
+ $this->errno = $request->errno();
+ $this->error = $request->error();
+ }
+
+ /**
+ * Returns the full body of the request
+ *
+ * @return string
+ */
+ public function httpBody()
+ {
+ return $this->body;
+ }
+
+ /**
+ * Sets the body.
+ *
+ * @param string $body
+ */
+ public function setBody($body)
+ {
+ $this->body = $body;
+ }
+
+ /**
+ * Returns an array of headers
+ *
+ * @return associative array('header'=>value)
+ */
+ public function headers()
+ {
+ return $this->headers;
+ }
+
+ /**
+ * Returns a single header
+ *
+ * @return string with the value of the requested header, or NULL
+ */
+ public function header($name)
+ {
+ return isset($this->headers[$name]) ? $this->headers[$name] : null;
+ }
+
+ /**
+ * Returns an array of information
+ *
+ * @return array
+ */
+ public function info()
+ {
+ return $this->info;
+ }
+
+ /**
+ * Returns the most recent error number
+ *
+ * @return integer
+ */
+ public function errno()
+ {
+ return $this->errno;
+ }
+
+ /**
+ * Returns the most recent error message
+ *
+ * @return string
+ */
+ public function error()
+ {
+ return $this->error;
+ }
+
+ /**
+ * Returns the HTTP status code
+ *
+ * @return integer
+ */
+ public function httpStatus()
+ {
+ return $this->info['http_code'];
+ }
+
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Service.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Service.php
new file mode 100644
index 00000000000..5b3aa729a97
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Service.php
@@ -0,0 +1,489 @@
+<?php
+/**
+ * PHP OpenCloud library.
+ *
+ * @copyright Copyright 2013 Rackspace US, Inc. See COPYING for licensing information.
+ * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0
+ * @version 1.6.0
+ * @author Jamie Hannaford <jamie.hannaford@rackspace.com>
+ */
+
+namespace OpenCloud\Common;
+
+use OpenCloud\Common\Base;
+use OpenCloud\Common\Lang;
+use OpenCloud\OpenStack;
+use OpenCloud\Common\Exceptions;
+
+/**
+ * This class defines a cloud service; a relationship between a specific OpenStack
+ * and a provided service, represented by a URL in the service catalog.
+ *
+ * Because Service is an abstract class, it cannot be called directly. Provider
+ * services such as Rackspace Cloud Servers or OpenStack Swift are each
+ * subclassed from Service.
+ *
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ */
+
+abstract class Service extends Base
+{
+
+ protected $conn;
+ private $service_type;
+ private $service_name;
+ private $service_region;
+ private $service_url;
+
+ protected $_namespaces = array();
+
+ /**
+ * Creates a service on the specified connection
+ *
+ * Usage: `$x = new Service($conn, $type, $name, $region, $urltype);`
+ * The service's URL is defined in the OpenStack's serviceCatalog; it
+ * uses the $type, $name, $region, and $urltype to find the proper URL
+ * and set it. If it cannot find a URL in the service catalog that matches
+ * the criteria, then an exception is thrown.
+ *
+ * @param OpenStack $conn - a Connection object
+ * @param string $type - the service type (e.g., "compute")
+ * @param string $name - the service name (e.g., "cloudServersOpenStack")
+ * @param string $region - the region (e.g., "ORD")
+ * @param string $urltype - the specified URL from the catalog
+ * (e.g., "publicURL")
+ */
+ public function __construct(
+ OpenStack $conn,
+ $type,
+ $name,
+ $region,
+ $urltype = RAXSDK_URL_PUBLIC,
+ $customServiceUrl = null
+ ) {
+ $this->setConnection($conn);
+ $this->service_type = $type;
+ $this->service_name = $name;
+ $this->service_region = $region;
+ $this->service_url = $customServiceUrl ?: $this->getEndpoint($type, $name, $region, $urltype);
+ }
+
+ /**
+ * Set this service's connection.
+ *
+ * @param type $connection
+ */
+ public function setConnection($connection)
+ {
+ $this->conn = $connection;
+ }
+
+ /**
+ * Get this service's connection.
+ *
+ * @return type
+ */
+ public function getConnection()
+ {
+ return $this->conn;
+ }
+
+ /**
+ * Returns the URL for the Service
+ *
+ * @param string $resource optional sub-resource
+ * @param array $query optional k/v pairs for query strings
+ * @return string
+ */
+ public function url($resource = '', array $param = array())
+ {
+ $baseurl = $this->service_url;
+
+ // use strlen instead of boolean test because '0' is a valid name
+ if (strlen($resource) > 0) {
+ $baseurl = Lang::noslash($baseurl).'/'.$resource;
+ }
+
+ if (!empty($param)) {
+ $baseurl .= '?'.$this->MakeQueryString($param);
+ }
+
+ return $baseurl;
+ }
+
+ /**
+ * Returns the /extensions for the service
+ *
+ * @api
+ * @return array of objects
+ */
+ public function extensions()
+ {
+ $ext = $this->getMetaUrl('extensions');
+ return (is_object($ext) && isset($ext->extensions)) ? $ext->extensions : array();
+ }
+
+ /**
+ * Returns the /limits for the service
+ *
+ * @api
+ * @return array of limits
+ */
+ public function limits()
+ {
+ $limits = $this->getMetaUrl('limits');
+ return (is_object($limits)) ? $limits->limits : array();
+ }
+
+ /**
+ * Performs an authenticated request
+ *
+ * This method handles the addition of authentication headers to each
+ * request. It always adds the X-Auth-Token: header and will add the
+ * X-Auth-Project-Id: header if there is a tenant defined on the
+ * connection.
+ *
+ * @param string $url The URL of the request
+ * @param string $method The HTTP method (defaults to "GET")
+ * @param array $headers An associative array of headers
+ * @param string $body An optional body for POST/PUT requests
+ * @return \OpenCloud\HttpResult
+ */
+ public function request(
+ $url,
+ $method = 'GET',
+ array $headers = array(),
+ $body = null
+ ) {
+
+ $headers['X-Auth-Token'] = $this->conn->Token();
+
+ if ($tenant = $this->conn->Tenant()) {
+ $headers['X-Auth-Project-Id'] = $tenant;
+ }
+
+ return $this->conn->request($url, $method, $headers, $body);
+ }
+
+ /**
+ * returns a collection of objects
+ *
+ * @param string $class the class of objects to fetch
+ * @param string $url (optional) the URL to retrieve
+ * @param mixed $parent (optional) the parent service/object
+ * @return OpenCloud\Common\Collection
+ */
+ public function collection($class, $url = null, $parent = null)
+ {
+ // Set the element names
+ $collectionName = $class::JsonCollectionName();
+ $elementName = $class::JsonCollectionElement();
+
+ // Set the parent if empty
+ if (!$parent) {
+ $parent = $this;
+ }
+
+ // Set the URL if empty
+ if (!$url) {
+ $url = $parent->url($class::ResourceName());
+ }
+
+ // Save debug info
+ $this->getLogger()->info(
+ '{class}:Collection({url}, {collectionClass}, {collectionName})',
+ array(
+ 'class' => get_class($this),
+ 'url' => $url,
+ 'collectionClass' => $class,
+ 'collectionName' => $collectionName
+ )
+ );
+
+ // Fetch the list
+ $response = $this->request($url);
+
+ $this->getLogger()->info('Response {status} [{body}]', array(
+ 'status' => $response->httpStatus(),
+ 'body' => $response->httpBody()
+ ));
+
+ // Check return code
+ if ($response->httpStatus() > 204) {
+ throw new Exceptions\CollectionError(sprintf(
+ Lang::translate('Unable to retrieve [%s] list from [%s], status [%d] response [%s]'),
+ $class,
+ $url,
+ $response->httpStatus(),
+ $response->httpBody()
+ ));
+ }
+
+ // Handle empty response
+ if (strlen($response->httpBody()) == 0) {
+ return new Collection($parent, $class, array());
+ }
+
+ // Parse the return
+ $object = json_decode($response->httpBody());
+ $this->checkJsonError();
+
+ // See if there's a "next" link
+ // Note: not sure if the current API offers links as top-level structures;
+ // might have to refactor to allow $nextPageUrl as method argument
+ // @codeCoverageIgnoreStart
+ if (isset($object->links) && is_array($object->links)) {
+ foreach($object->links as $link) {
+ if (isset($link->rel) && $link->rel == 'next') {
+ if (isset($link->href)) {
+ $nextPageUrl = $link->href;
+ } else {
+ $this->getLogger()->warning(
+ 'Unexpected [links] found with no [href]'
+ );
+ }
+ }
+ }
+ }
+ // @codeCoverageIgnoreEnd
+
+ // How should we populate the collection?
+ $data = array();
+
+ if (!$collectionName) {
+ // No element name, just a plain object
+ // @codeCoverageIgnoreStart
+ $data = $object;
+ // @codeCoverageIgnoreEnd
+ } elseif (isset($object->$collectionName)) {
+ if (!$elementName) {
+ // The object has a top-level collection name only
+ $data = $object->$collectionName;
+ } else {
+ // The object has element levels which need to be iterated over
+ $data = array();
+ foreach($object->$collectionName as $item) {
+ $subValues = $item->$elementName;
+ unset($item->$elementName);
+ $data[] = array_merge((array)$item, (array)$subValues);
+ }
+ }
+ }
+
+ $collectionObject = new Collection($parent, $class, $data);
+
+ // if there's a $nextPageUrl, then we need to establish a callback
+ // @codeCoverageIgnoreStart
+ if (!empty($nextPageUrl)) {
+ $collectionObject->setNextPageCallback(array($this, 'Collection'), $nextPageUrl);
+ }
+ // @codeCoverageIgnoreEnd
+
+ return $collectionObject;
+ }
+
+ /**
+ * returns the Region associated with the service
+ *
+ * @api
+ * @return string
+ */
+ public function region()
+ {
+ return $this->service_region;
+ }
+
+ /**
+ * returns the serviceName associated with the service
+ *
+ * This is used by DNS for PTR record lookups
+ *
+ * @api
+ * @return string
+ */
+ public function name()
+ {
+ return $this->service_name;
+ }
+
+ /**
+ * Returns a list of supported namespaces
+ *
+ * @return array
+ */
+ public function namespaces()
+ {
+ return (isset($this->_namespaces) && is_array($this->_namespaces)) ? $this->_namespaces : array();
+ }
+
+ /**
+ * Given a service type, name, and region, return the url
+ *
+ * This function ensures that services are represented by an entry in the
+ * service catalog, and NOT by an arbitrarily-constructed URL.
+ *
+ * Note that it will always return the first match found in the
+ * service catalog (there *should* be only one, but you never know...)
+ *
+ * @param string $type The OpenStack service type ("compute" or
+ * "object-store", for example
+ * @param string $name The name of the service in the service catlog
+ * @param string $region The region of the service
+ * @param string $urltype The URL type; defaults to "publicURL"
+ * @return string The URL of the service
+ */
+ private function getEndpoint($type, $name, $region, $urltype = 'publicURL')
+ {
+ $catalog = $this->getConnection()->serviceCatalog();
+
+ // Search each service to find The One
+ foreach ($catalog as $service) {
+ // Find the service by comparing the type ("compute") and name ("openstack")
+ if (!strcasecmp($service->type, $type) && !strcasecmp($service->name, $name)) {
+ foreach($service->endpoints as $endpoint) {
+ // Only set the URL if:
+ // a. It is a regionless service (i.e. no region key set)
+ // b. The region matches the one we want
+ if (isset($endpoint->$urltype) &&
+ (!isset($endpoint->region) || !strcasecmp($endpoint->region, $region))
+ ) {
+ $url = $endpoint->$urltype;
+ }
+ }
+ }
+ }
+
+ // error if not found
+ if (empty($url)) {
+ throw new Exceptions\EndpointError(sprintf(
+ 'No endpoints for service type [%s], name [%s], region [%s] and urlType [%s]',
+ $type,
+ $name,
+ $region,
+ $urltype
+ ));
+ }
+
+ return $url;
+ }
+
+ /**
+ * Constructs a specified URL from the subresource
+ *
+ * Given a subresource (e.g., "extensions"), this constructs the proper
+ * URL and retrieves the resource.
+ *
+ * @param string $resource The resource requested; should NOT have slashes
+ * at the beginning or end
+ * @return \stdClass object
+ */
+ private function getMetaUrl($resource)
+ {
+ $urlBase = $this->getEndpoint(
+ $this->service_type,
+ $this->service_name,
+ $this->service_region,
+ RAXSDK_URL_PUBLIC
+ );
+
+ $url = Lang::noslash($urlBase) . '/' . $resource;
+
+ $response = $this->request($url);
+
+ // check for NOT FOUND response
+ if ($response->httpStatus() == 404) {
+ return array();
+ }
+
+ // @codeCoverageIgnoreStart
+ if ($response->httpStatus() >= 300) {
+ throw new Exceptions\HttpError(sprintf(
+ Lang::translate('Error accessing [%s] - status [%d], response [%s]'),
+ $urlBase,
+ $response->httpStatus(),
+ $response->httpBody()
+ ));
+ }
+ // @codeCoverageIgnoreEnd
+
+ // we're good; proceed
+ $object = json_decode($response->httpBody());
+
+ $this->checkJsonError();
+
+ return $object;
+ }
+
+ /**
+ * Get all associated resources for this service.
+ *
+ * @access public
+ * @return void
+ */
+ public function getResources()
+ {
+ return $this->resources;
+ }
+
+ /**
+ * Internal method for accessing child namespace from parent scope.
+ *
+ * @return type
+ */
+ protected function getCurrentNamespace()
+ {
+ $namespace = get_class($this);
+ return substr($namespace, 0, strrpos($namespace, '\\'));
+ }
+
+ /**
+ * Resolves fully-qualified classname for associated local resource.
+ *
+ * @param string $resourceName
+ * @return string
+ */
+ protected function resolveResourceClass($resourceName)
+ {
+ $className = substr_count($resourceName, '\\')
+ ? $resourceName
+ : $this->getCurrentNamespace() . '\\Resource\\' . ucfirst($resourceName);
+
+ if (!class_exists($className)) {
+ throw new Exceptions\UnrecognizedServiceError(sprintf(
+ '%s resource does not exist, please try one of the following: %s',
+ $resourceName,
+ implode(', ', $this->getResources())
+ ));
+ }
+
+ return $className;
+ }
+
+ /**
+ * Factory method for instantiating resource objects.
+ *
+ * @access public
+ * @param string $resourceName
+ * @param mixed $info (default: null)
+ * @return object
+ */
+ public function resource($resourceName, $info = null)
+ {
+ $className = $this->resolveResourceClass($resourceName);
+ return new $className($this, $info);
+ }
+
+ /**
+ * Factory method for instantiate a resource collection.
+ *
+ * @param string $resourceName
+ * @param string|null $url
+ * @return Collection
+ */
+ public function resourceList($resourceName, $url = null, $service = null)
+ {
+ $className = $this->resolveResourceClass($resourceName);
+ return $this->collection($className, $url, $service);
+ }
+
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/ServiceCatalogItem.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/ServiceCatalogItem.php
new file mode 100644
index 00000000000..3e20bcbc7b9
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/ServiceCatalogItem.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace OpenCloud\Common;
+
+/**
+ * Holds information on a single service from the Service Catalog
+ */
+class ServiceCatalogItem
+{
+
+ public function __construct($info = array())
+ {
+ foreach($info as $key => $value) {
+ $this->$key = $value;
+ }
+ }
+
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Globals.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Globals.php
new file mode 100644
index 00000000000..fbdc4355e02
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Globals.php
@@ -0,0 +1,252 @@
+<?php
+/**
+ * Defines global constants and functions
+ *
+ * @copyright 2012-2013 Rackspace Hosting, Inc.
+ * See COPYING for licensing information
+ *
+ * @package phpOpenCloud
+ * @version 1.0
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ */
+
+namespace OpenCloud;
+
+/**
+ * This file contains only configuration data such as constants.
+ * You can override these constants by defining them BEFORE you including
+ * any of the top-level files from the SDK.
+ *
+ * Definitions:
+ * * RAXSDK_TIMEZONE - the default timezone for interpreting date/time requests
+ * * RAXSDK_STRICT_PROPERTY_CHECKS - if TRUE, the library will strictly enforce
+ * property names on objects; only properties that are pre-defined or
+ * appear in the extensions aliases for the service will be permitted.
+ * When FALSE (the default), then any property can be set on an object.
+ * * RAXSDK_COMPUTE_NAME - the default name for the compute service
+ * * RAXSDK_COMPUTE_REGION - the default region for the compute service
+ * * RAXSDK_COMPUTE_URLTYPE - the default URL type for the compute service
+ * * RAXSDK_OBJSTORE_NAME - the default name for the object storage service
+ * * RAXSDK_OBJSTORE_REGION - the default region for the object storage service
+ * * RAXSDK_OBJSTORE_URLTYPE - the default URL type for the object storage
+ * service
+ * * RAXSDK_DATABASE_NAME - the default name for the DbService service
+ * * RAXSDK_DATABASE_REGION - the default region for the DbService service
+ * * RAXSDK_DATABASE_URLTYPE - the default URL type for the DbService service
+ * * RAXSDK_CONNECTTIMEOUT - the time (in seconds) to wait for a connection
+ * to a service
+ * * RAXSDK_TIMEOUT - the max time (in seconds) to wait for an HTTP request
+ * to complete
+ * * RAXSDK_SERVER_MAXTIMEOUT - the max time (in seconds) that a server
+ * will wait for a change in status (Server::WaitFor() method)
+ * * RAXSDK_POLL_INTERVAL - how often (in seconds) the Server::WaitFor() method
+ * will poll for a status change
+ * * RAXSDK_DEFAULT_IP_VERSION - the default IP version (4 or 6) to return for
+ * the server's primary IP address
+ * * RAXSDK_OVERLIMIT_TIMEOUT - the max time (in seconds) to wait before
+ * retrying a request that has failed because of rate limits. If the
+ * next available time for the request is more than (X) seconds away,
+ * then the request will fail; otherwise, the request will sleep until
+ * available.
+ */
+
+if (!defined('RAXSDK_TIMEZONE'))
+ define('RAXSDK_TIMEZONE', 'America/Chicago');
+if (!defined('RAXSDK_STRICT_PROPERTY_CHECKS'))
+ define('RAXSDK_STRICT_PROPERTY_CHECKS', FALSE);
+if (!defined('RAXSDK_COMPUTE_NAME'))
+ define('RAXSDK_COMPUTE_NAME', 'cloudServersOpenStack');
+if (!defined('RAXSDK_COMPUTE_REGION'))
+ define('RAXSDK_COMPUTE_REGION', NULL);
+if (!defined('RAXSDK_COMPUTE_URLTYPE'))
+ define('RAXSDK_COMPUTE_URLTYPE', 'publicURL');
+if (!defined('RAXSDK_MONITORING_NAME'))
+ define('RAXSDK_MONITORING_NAME', 'cloudMonitoring');
+if (!defined('RAXSDK_MONITORING_REGION'))
+ define('RAXSDK_MONITORING_REGION', '{ignore}');
+if (!defined('RAXSDK_MONITORING_URLTYPE'))
+ define('RAXSDK_MONITORING_URLTYPE', 'publicURL');
+if (!defined('RAXSDK_ORCHESTRATION_NAME'))
+ define('RAXSDK_ORCHESTRATION_NAME', 'cloudOrchestration');
+if (!defined('RAXSDK_ORCHESTRATION_REGION'))
+ define('RAXSDK_ORCHESTRATION_REGION', NULL);
+if (!defined('RAXSDK_ORCHESTRATION_URLTYPE'))
+ define('RAXSDK_ORCHESTRATION_URLTYPE', 'publicURL');
+if (!defined('RAXSDK_OBJSTORE_NAME'))
+ define('RAXSDK_OBJSTORE_NAME', 'cloudFiles');
+if (!defined('RAXSDK_OBJSTORE_REGION'))
+ define('RAXSDK_OBJSTORE_REGION', NULL);
+if (!defined('RAXSDK_OBJSTORE_URLTYPE'))
+ define('RAXSDK_OBJSTORE_URLTYPE', 'publicURL');
+if (!defined('RAXSDK_DATABASE_NAME'))
+ define('RAXSDK_DATABASE_NAME', 'cloudDatabases');
+if (!defined('RAXSDK_DATABASE_REGION'))
+ define('RAXSDK_DATABASE_REGION', NULL);
+if (!defined('RAXSDK_DATABASE_URLTYPE'))
+ define('RAXSDK_DATABASE_URLTYPE', 'publicURL');
+if (!defined('RAXSDK_VOLUME_NAME'))
+ define('RAXSDK_VOLUME_NAME', 'cloudBlockStorage');
+if (!defined('RAXSDK_VOLUME_REGION'))
+ define('RAXSDK_VOLUME_REGION', NULL);
+if (!defined('RAXSDK_VOLUME_URLTYPE'))
+ define('RAXSDK_VOLUME_URLTYPE', 'publicURL');
+if (!defined('RAXSDK_LBSERVICE_NAME'))
+ define('RAXSDK_LBSERVICE_NAME', 'cloudLoadBalancers');
+if (!defined('RAXSDK_LBSERVICE_REGION'))
+ define('RAXSDK_LBSERVICE_REGION', NULL);
+if (!defined('RAXSDK_LBSERVICE_URLTYPE'))
+ define('RAXSDK_LBSERVICE_URLTYPE', 'publicURL');
+if (!defined('RAXSDK_DNS_NAME'))
+ define('RAXSDK_DNS_NAME', 'cloudDNS');
+if (!defined('RAXSDK_DNS_REGION'))
+ define('RAXSDK_DNS_REGION', '{ignore}'); // DNS is regionless
+if (!defined('RAXSDK_DNS_URLTYPE'))
+ define('RAXSDK_DNS_URLTYPE', 'publicURL');
+if (!defined('RAXSDK_AUTOSCALE_NAME'))
+ define('RAXSDK_AUTOSCALE_NAME', 'autoscale');
+if (!defined('RAXSDK_AUTOSCALE_REGION'))
+ define('RAXSDK_AUTOSCALE_REGION', NULL);
+if (!defined('RAXSDK_AUTOSCALE_URLTYPE'))
+ define('RAXSDK_AUTOSCALE_URLTYPE', 'publicURL');
+if (!defined('RAXSDK_DNS_ASYNC_TIMEOUT'))
+ define('RAXSDK_DNS_ASYNC_TIMEOUT', 60);
+if (!defined('RAXSDK_DNS_ASYNC_INTERVAL'))
+ define('RAXSDK_DNS_ASYNC_INTERVAL', 1);
+if (!defined('RAXSDK_CONNECTTIMEOUT'))
+ define('RAXSDK_CONNECTTIMEOUT', 5);
+if (!defined('RAXSDK_TIMEOUT'))
+ define('RAXSDK_TIMEOUT', 60);
+if (!defined('RAXSDK_SERVER_MAXTIMEOUT'))
+ define('RAXSDK_SERVER_MAXTIMEOUT', 3600);
+if (!defined('RAXSDK_POLL_INTERVAL'))
+ define('RAXSDK_POLL_INTERVAL', 10);
+if (!defined('RAXSDK_DEFAULT_IP_VERSION'))
+ define('RAXSDK_DEFAULT_IP_VERSION', 4);
+if (!defined('RAXSDK_OVERLIMIT_TIMEOUT'))
+ define('RAXSDK_OVERLIMIT_TIMEOUT', 300);
+/**
+ * sets default (highly secure) value for CURLOPT_SSL_VERIFYHOST. If you
+ * are using a self-signed SSL certificate, you can reduce this setting, but
+ * you do so at your own risk.
+ */
+if (!defined('RAXSDK_SSL_VERIFYHOST'))
+ define('RAXSDK_SSL_VERIFYHOST', 2);
+/**
+ * sets default (highly secure) value for CURLOPT_SSL_VERIFYPEER. If you
+ * are using a self-signed SSL certificate, you can reduce this setting, but
+ * you do so at your own risk.
+ */
+if (!defined('RAXSDK_SSL_VERIFYPEER'))
+ define('RAXSDK_SSL_VERIFYPEER', TRUE);
+
+/**
+ * edit and uncomment this to set the default location of cacert.pem file
+ */
+//define('RAXSDK_CACERTPEM', __DIR__ . DIRECTORY_SEPARATOR . 'cacert.pem');
+
+/* these should not be overridden */
+define('RAXSDK_VERSION', '1.5.10');
+define('RAXSDK_USER_AGENT', 'php-opencloud/'.RAXSDK_VERSION.' (Rackspace)');
+define('RAXSDK_ERROR', 'Error:');
+define('RAXSDK_FATAL', 'FATAL ERROR:');
+define('RAXSDK_TERMINATED', '*** PROCESSING HALTED ***');
+define('RAXSDK_CONTENT_TYPE_JSON', 'application/json');
+define('RAXSDK_URL_PUBLIC', 'publicURL');
+define('RAXSDK_URL_INTERNAL', 'internalURL');
+define('RAXSDK_URL_VERSION_INFO', 'versionInfo');
+define('RAXSDK_URL_VERSION_LIST', 'versionList');
+
+/**
+ * definitions for Rackspace authentication endpoints
+ */
+define('RACKSPACE_US', 'https://identity.api.rackspacecloud.com/v2.0/');
+define('RACKSPACE_UK', 'https://lon.identity.api.rackspacecloud.com/v2.0/');
+
+/**
+ * We can re-authenticate this many seconds before the token expires
+ *
+ * Set this to a higher value if your service does not cache tokens; if
+ * it *does* cache them, then this value is not required.
+ */
+define('RAXSDK_FUDGE', 0);
+
+/**
+ * Readable constants
+ */
+define('RAXSDK_SOFT_REBOOT', 'soft');
+define('RAXSDK_HARD_REBOOT', 'hard');
+define('RAXSDK_DETAILS', TRUE);
+define('RAXSDK_MAX_CONTAINER_NAME_LEN', 256);
+
+/**
+ * UUID of the Rackspace 'public' network
+ */
+define('RAX_PUBLIC','00000000-0000-0000-0000-000000000000');
+/**
+ * UUID of the Rackspace 'private' network
+ */
+define('RAX_PRIVATE','11111111-1111-1111-1111-111111111111');
+
+// Turn off debug mode by default
+define('RAXSDK_DEBUG', false);
+
+/********** TIMEZONE MAGIC **********/
+
+/**
+ * This is called if there is an error getting the default timezone;
+ * that means that the default timezone isn't set.
+ *
+ * @codeCoverageIgnore
+ */
+function __raxsdk_timezone_set($errno, $errstr) {
+ if ($errno==2)
+ date_default_timezone_set(RAXSDK_TIMEZONE);
+ else
+ die(sprintf("Unknown error %d: %s\n", $errno, $errstr));
+}
+set_error_handler('\OpenCloud\__raxsdk_timezone_set');
+@date_default_timezone_get();
+restore_error_handler();
+
+/********** SOME GLOBAL FUNCTIONS **********/
+
+ /**
+ * \OpenCloud\Common\Lang::translate() - this function should be used to wrap all static strings. In the future,
+ * this may provide us with a hook for providing different language
+ * translations.
+ *
+ * @codeCoverageIgnore
+ */
+ function define_gettext() {
+ function translate($str) {
+ return $str;
+ }
+ }
+
+ if (!function_exists('_'))
+ define_gettext();
+
+ /**
+ * removes trailing slash(es) from a URL string
+ *
+ * Mainly, this is just for appearance's sake. I really hate to see
+ * URLs like .../servers//address, for some reason.
+ *
+ * @codeCoverageIgnore
+ */
+ function noslash($str) {
+ while ($str && (substr($str, -1) == '/'))
+ $str = substr($str, 0, strlen($str)-1);
+ return $str;
+ }
+
+ /**
+ * Turns debugging on or off
+ *
+ * @codeCoverageIgnore
+ */
+ function setDebug($state=TRUE) {
+ global $RAXSDK_DEBUG;
+ $RAXSDK_DEBUG=$state;
+ }
+
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/AbstractService.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/AbstractService.php
new file mode 100644
index 00000000000..4a2298d60ed
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/AbstractService.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * PHP OpenCloud library.
+ *
+ * @copyright Copyright 2013 Rackspace US, Inc. See COPYING for licensing information.
+ * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0
+ * @version 1.6.0
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ * @author Jamie Hannaford <jamie.hannaford@rackspace.com>
+ */
+
+namespace OpenCloud\ObjectStore;
+
+use OpenCloud\Common\Service as CommonService;
+
+define('SWIFT_MAX_OBJECT_SIZE', 5 * 1024 * 1024 * 1024 + 1);
+
+/**
+ * An abstract base class for common code shared between ObjectStore\Service
+ * (container) and ObjectStore\CDNService (CDN containers).
+ *
+ * @todo Maybe we use Traits instead of this small abstract class?
+ */
+abstract class AbstractService extends CommonService
+{
+
+ const MAX_CONTAINER_NAME_LEN = 256;
+ const MAX_OBJECT_NAME_LEN = 1024;
+ const MAX_OBJECT_SIZE = SWIFT_MAX_OBJECT_SIZE;
+
+ /**
+ * Creates a Container resource object.
+ *
+ * @param mixed $cdata The name of the container or an object from which to set values
+ * @return OpenCloud\ObjectStore\Resource\Container
+ */
+ public function container($cdata = null)
+ {
+ return new Resource\Container($this, $cdata);
+ }
+
+ /**
+ * Returns a Collection of Container objects.
+ *
+ * @param array $filter An array to filter the results
+ * @return OpenCloud\Common\Collection
+ */
+ public function containerList(array $filter = array())
+ {
+ $filter['format'] = 'json';
+
+ return $this->collection(
+ 'OpenCloud\ObjectStore\Resource\Container', $this->url(null, $filter)
+ );
+ }
+
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/CDNService.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/CDNService.php
new file mode 100644
index 00000000000..132d5f47ad6
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/CDNService.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * PHP OpenCloud library.
+ *
+ * @copyright Copyright 2013 Rackspace US, Inc. See COPYING for licensing information.
+ * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0
+ * @version 1.6.0
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ * @author Jamie Hannaford <jamie.hannaford@rackspace.com>
+ */
+
+namespace OpenCloud\ObjectStore;
+
+use OpenCloud\OpenStack;
+use OpenCloud\Common\Exceptions;
+
+/**
+ * This is the CDN version of the ObjectStore service.
+ */
+class CDNService extends AbstractService
+{
+
+ /**
+ * Creates a new CDNService object.
+ *
+ * This is a simple wrapper function around the parent Service construct,
+ * but supplies defaults for the service type.
+ *
+ * @param OpenCloud\OpenStack $connection The connection object
+ * @param string $serviceName The name of the service
+ * @param string $serviceRegion The service's region
+ * @param string $urlType The type of URL (normally 'publicURL')
+ */
+ public function __construct(
+ OpenStack $connection,
+ $serviceName = RAXSDK_OBJSTORE_NAME,
+ $serviceRegion = RAXSDK_OBJSTORE_REGION,
+ $urltype = RAXSDK_URL_PUBLIC
+ ) {
+ $this->getLogger()->info('Initializing CDN Service...');
+
+ parent::__construct(
+ $connection,
+ 'rax:object-cdn',
+ $serviceName,
+ $serviceRegion,
+ $urltype
+ );
+ }
+
+ /**
+ * Helps catch errors if someone calls the method on the
+ * wrong object
+ */
+ public function CDN()
+ {
+ throw new Exceptions\CdnError(
+ 'Invalid method call; no CDN() on the CDN object'
+ );
+ }
+
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/AbstractStorageObject.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/AbstractStorageObject.php
new file mode 100644
index 00000000000..c6799b22b7e
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/AbstractStorageObject.php
@@ -0,0 +1,170 @@
+<?php
+/**
+ * PHP OpenCloud library.
+ *
+ * @copyright Copyright 2013 Rackspace US, Inc. See COPYING for licensing information.
+ * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0
+ * @version 1.6.0
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ * @author Jamie Hannaford <jamie.hannaford@rackspace.com>
+ */
+
+namespace OpenCloud\ObjectStore\Resource;
+
+use OpenCloud\Common\Base;
+use OpenCloud\Common\Metadata;
+use OpenCloud\Common\Exceptions\NameError;
+use OpenCloud\Common\Exceptions\MetadataPrefixError;
+use OpenCloud\Common\Request\Response\Http;
+
+/**
+ * Abstract base class which implements shared functionality of ObjectStore
+ * resources. Provides support, for example, for metadata-handling and other
+ * features that are common to the ObjectStore components.
+ */
+abstract class AbstractStorageObject extends Base
+{
+
+ const ACCOUNT_META_PREFIX = 'X-Account-';
+ const CONTAINER_META_PREFIX = 'X-Container-Meta-';
+ const OBJECT_META_PREFIX = 'X-Object-Meta-';
+ const CDNCONTAINER_META_PREFIX = 'X-Cdn-';
+
+ /**
+ * Metadata belonging to a resource.
+ *
+ * @var OpenCloud\Common\Metadata
+ */
+ public $metadata;
+
+ /**
+ * Initializes the metadata component
+ */
+ public function __construct()
+ {
+ $this->metadata = new Metadata;
+ }
+
+ /**
+ * Given an Http response object, converts the appropriate headers
+ * to metadata
+ *
+ * @param OpenCloud\Common\Request\Response\Http
+ * @return void
+ */
+ public function getMetadata(Http $response)
+ {
+ $this->metadata = new Metadata;
+ $this->metadata->setArray($response->headers(), $this->prefix());
+ }
+
+ /**
+ * If object has metadata, return an associative array of headers.
+ *
+ * For example, if a DataObject has a metadata item named 'FOO',
+ * then this would return array('X-Object-Meta-FOO'=>$value);
+ *
+ * @return array
+ */
+ public function metadataHeaders()
+ {
+ $headers = array();
+
+ // only build if we have metadata
+ if (is_object($this->metadata)) {
+ foreach ($this->metadata as $key => $value) {
+ $headers[$this->prefix() . $key] = $value;
+ }
+ }
+
+ return $headers;
+ }
+
+ /**
+ * Returns the displayable name of the object
+ *
+ * Can be overridden by child objects; *must* be overridden by child
+ * objects if the object does not have a `name` attribute defined.
+ *
+ * @api
+ * @throws NameError if attribute 'name' is not defined
+ */
+ public function name()
+ {
+ if (property_exists($this, 'name')) {
+ return $this->name;
+ } else {
+ throw new NameError(sprintf(
+ 'Name attribute does not exist for [%s]',
+ get_class($this)
+ ));
+ }
+ }
+
+ /**
+ * Override parent method.
+ *
+ * @return null
+ */
+ public static function jsonName()
+ {
+ return null;
+ }
+
+ /**
+ * Override parent method.
+ *
+ * @return null
+ */
+ public static function jsonCollectionName()
+ {
+ return null;
+ }
+
+ /**
+ * Override parent method.
+ *
+ * @return null
+ */
+ public static function jsonCollectionElement()
+ {
+ return null;
+ }
+
+ /**
+ * Returns the proper prefix for the specified type of object
+ *
+ * @param string $type The type of object; derived from `get_class()` if not
+ * specified.
+ * @codeCoverageIgnore
+ */
+ private function prefix($type = null)
+ {
+ if ($type === null) {
+ $parts = preg_split('/\\\/', get_class($this));
+ $type = $parts[count($parts)-1];
+ }
+
+ switch($type) {
+ case 'Account':
+ $prefix = self::ACCOUNT_META_PREFIX;
+ break;
+ case 'CDNContainer':
+ $prefix = self::CDNCONTAINER_META_PREFIX;
+ break;
+ case 'Container':
+ $prefix = self::CONTAINER_META_PREFIX;
+ break;
+ case 'DataObject':
+ $prefix = self::OBJECT_META_PREFIX;
+ break;
+ default:
+ throw new MetadataPrefixError(sprintf(
+ 'Unrecognized metadata type [%s]',
+ $type
+ ));
+ }
+
+ return $prefix;
+ }
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/CDNContainer.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/CDNContainer.php
new file mode 100644
index 00000000000..9b6367c87e0
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/CDNContainer.php
@@ -0,0 +1,298 @@
+<?php
+/**
+ * PHP OpenCloud library.
+ *
+ * @copyright Copyright 2013 Rackspace US, Inc. See COPYING for licensing information.
+ * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0
+ * @version 1.6.0
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ * @author Jamie Hannaford <jamie.hannaford@rackspace.com>
+ */
+
+namespace OpenCloud\ObjectStore\Resource;
+
+use OpenCloud\Common\Service as AbstractService;
+use OpenCloud\Common\Lang;
+use OpenCloud\Common\Exceptions;
+use OpenCloud\ObjectStore\AbstractService as AbstractObjectService;
+
+/**
+ * A container that has been CDN-enabled. Each CDN-enabled container has a unique
+ * Uniform Resource Locator (URL) that can be combined with its object names and
+ * openly distributed in web pages, emails, or other applications.
+ */
+class CDNContainer extends AbstractStorageObject
+{
+ /**
+ * The name of the container.
+ *
+ * The only restrictions on container names is that they cannot contain a
+ * forward slash (/) and must be less than 256 bytes in length. Please note
+ * that the length restriction applies to the name after it has been URL
+ * encoded. For example, a container named Course Docs would be URL encoded
+ * as Course%20Docs - which is 13 bytes in length rather than the expected 11.
+ *
+ * @var string
+ */
+ public $name;
+
+ /**
+ * Count of how many objects exist in the container.
+ *
+ * @var int
+ */
+ public $count = 0;
+
+ /**
+ * The total bytes used in the container.
+ *
+ * @var int
+ */
+ public $bytes = 0;
+
+ /**
+ * The service object.
+ *
+ * @var AbstractService
+ */
+ private $service;
+
+ /**
+ * URL of the container.
+ *
+ * @var string
+ */
+ private $containerUrl;
+
+ /**
+ * Creates the container object
+ *
+ * Creates a new container object or, if the $cdata object is a string,
+ * retrieves the named container from the object store. If $cdata is an
+ * array or an object, then its values are used to set this object.
+ *
+ * @param OpenCloud\ObjectStore $service - the ObjectStore service
+ * @param mixed $cdata - if supplied, the name of the object
+ */
+ public function __construct(AbstractService $service, $cdata = null)
+ {
+ $this->getLogger()->info('Initializing CDN Container Service...');
+
+ parent::__construct();
+
+ $this->service = $service;
+
+ // Populate data if set
+ $this->populate($cdata);
+ }
+
+ /**
+ * Allow other objects to know what the primary key is.
+ *
+ * @return string
+ */
+ public function primaryKeyField()
+ {
+ return 'name';
+ }
+
+ /**
+ * Returns the Service associated with the Container
+ */
+ public function getService()
+ {
+ return $this->service;
+ }
+
+ /**
+ * Returns the URL of the container
+ *
+ * @return string
+ * @param string $subresource not used; required for compatibility
+ * @throws NoNameError
+ */
+ public function url($subresource = '')
+ {
+ if (strlen($this->name) == 0) {
+ throw new Exceptions\NoNameError(
+ Lang::translate('Container does not have an identifier')
+ );
+ }
+
+ return Lang::noslash($this->getService()->url(rawurlencode($this->name)));
+ }
+
+ /**
+ * Creates a new container with the specified attributes
+ *
+ * @param array $params array of parameters
+ * @return boolean TRUE on success; FALSE on failure
+ * @throws ContainerCreateError
+ */
+ public function create($params = array())
+ {
+ // Populate object and check container name
+ $this->populate($params);
+ $this->isValidName($this->name);
+
+ // Dispatch
+ $this->containerUrl = $this->url();
+ $response = $this->getService()->request($this->url(), 'PUT', $this->metadataHeaders());
+
+ // Check return code
+ // @codeCoverageIgnoreStart
+ if ($response->httpStatus() > 202) {
+ throw new Exceptions\ContainerCreateError(sprintf(
+ Lang::translate('Problem creating container [%s] status [%d] response [%s]'),
+ $this->url(),
+ $response->httpStatus(),
+ $response->httpBody()
+ ));
+ }
+ // @codeCoverageIgnoreEnd
+
+ return true;
+ }
+
+ /**
+ * Updates the metadata for a container
+ *
+ * @return boolean TRUE on success; FALSE on failure
+ * @throws ContainerCreateError
+ */
+ public function update()
+ {
+ $response = $this->getService()->request($this->url(), 'POST', $this->metadataHeaders());
+
+ // check return code
+ // @codeCoverageIgnoreStart
+ if ($response->httpStatus() > 204) {
+ throw new Exceptions\ContainerCreateError(sprintf(
+ Lang::translate('Problem updating container [%s] status [%d] response [%s]'),
+ $this->Url(),
+ $response->httpStatus(),
+ $response->httpBody()
+ ));
+ }
+ // @codeCoverageIgnoreEnd
+
+ return true;
+ }
+
+ /**
+ * Deletes the specified container
+ *
+ * @return boolean TRUE on success; FALSE on failure
+ * @throws ContainerDeleteError
+ */
+ public function delete()
+ {
+ $response = $this->getService()->request($this->url(), 'DELETE');
+
+ // validate the response code
+ // @codeCoverageIgnoreStart
+ if ($response->httpStatus() == 404) {
+ throw new Exceptions\ContainerNotFoundError(sprintf(
+ Lang::translate('Container [%s] not found'),
+ $this->name
+ ));
+ }
+
+ if ($response->httpStatus() == 409) {
+ throw new Exceptions\ContainerNotEmptyError(sprintf(
+ Lang::translate('Container [%s] must be empty before deleting'),
+ $this->name
+ ));
+ }
+
+ if ($response->httpStatus() >= 300) {
+ throw new Exceptions\ContainerDeleteError(sprintf(
+ Lang::translate('Problem deleting container [%s] status [%d] response [%s]'),
+ $this->url(),
+ $response->httpStatus(),
+ $response->httpBody()
+ ));
+ return false;
+ }
+ // @codeCoverageIgnoreEnd
+
+ return true;
+ }
+
+ /**
+ * Loads the object from the service
+ *
+ * @return void
+ */
+ public function refresh($name = null, $url = null)
+ {
+ $response = $this->getService()->request(
+ $this->url($name), 'HEAD', array('Accept' => '*/*')
+ );
+
+ // validate the response code
+ // @codeCoverageIgnoreStart
+ if ($response->HttpStatus() == 404) {
+ throw new Exceptions\ContainerNotFoundError(sprintf(
+ 'Container [%s] (%s) not found',
+ $this->name,
+ $this->url()
+ ));
+ }
+
+ if ($response->HttpStatus() >= 300) {
+ throw new Exceptions\HttpError(sprintf(
+ 'Error retrieving Container, status [%d] response [%s]',
+ $response->httpStatus(),
+ $response->httpBody()
+ ));
+ }
+
+ // check for headers (not metadata)
+ foreach($response->headers() as $header => $value) {
+ switch($header) {
+ case 'X-Container-Object-Count':
+ $this->count = $value;
+ break;
+ case 'X-Container-Bytes-Used':
+ $this->bytes = $value;
+ break;
+ }
+ }
+ // @codeCoverageIgnoreEnd
+
+ // parse the returned object
+ $this->getMetadata($response);
+ }
+
+ /**
+ * Validates that the container name is acceptable
+ *
+ * @param string $name the container name to validate
+ * @return boolean TRUE if ok; throws an exception if not
+ * @throws ContainerNameError
+ */
+ public function isValidName($name)
+ {
+ if (strlen($name) == 0) {
+ throw new Exceptions\ContainerNameError(
+ 'Container name cannot be blank'
+ );
+ }
+
+ if (strpos($name, '/') !== false) {
+ throw new Exceptions\ContainerNameError(
+ 'Container name cannot contain "/"'
+ );
+ }
+
+ if (strlen($name) > AbstractObjectService::MAX_CONTAINER_NAME_LEN) {
+ throw new Exceptions\ContainerNameError(
+ 'Container name is too long'
+ );
+ }
+
+ return true;
+ }
+
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/Container.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/Container.php
new file mode 100644
index 00000000000..3a56ebd9fca
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/Container.php
@@ -0,0 +1,401 @@
+<?php
+/**
+ * PHP OpenCloud library.
+ *
+ * @copyright Copyright 2013 Rackspace US, Inc. See COPYING for licensing information.
+ * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0
+ * @version 1.6.0
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ * @author Jamie Hannaford <jamie.hannaford@rackspace.com>
+ */
+
+namespace OpenCloud\ObjectStore\Resource;
+
+use OpenCloud\Common\Exceptions;
+use OpenCloud\Common\Lang;
+
+/**
+ * A container is a storage compartment for your data and provides a way for you
+ * to organize your data. You can think of a container as a folder in Windows®
+ * or a directory in UNIX®. The primary difference between a container and these
+ * other file system concepts is that containers cannot be nested.
+ *
+ * A container can also be CDN-enabled (for public access), in which case you
+ * will need to interact with a CDNContainer object instead of this one.
+ */
+class Container extends CDNContainer
+{
+
+ /**
+ * CDN container (if set).
+ *
+ * @var CDNContainer|null
+ */
+ private $cdn;
+
+ /**
+ * Sets the CDN container.
+ *
+ * @param OpenCloud\ObjectStore\Resource\CDNContainer $cdn
+ */
+ public function setCDN(CDNContainer $cdn)
+ {
+ $this->cdn = $cdn;
+ }
+
+ /**
+ * Returns the CDN container.
+ *
+ * @returns CDNContainer
+ */
+ public function getCDN()
+ {
+ if (!$this->cdn) {
+ throw new Exceptions\CdnNotAvailableError(
+ Lang::translate('CDN-enabled container is not available')
+ );
+ }
+
+ return $this->cdn;
+ }
+
+ /**
+ * Backwards compatability.
+ */
+ public function CDN()
+ {
+ return $this->getCDN();
+ }
+
+ /**
+ * Makes the container public via the CDN
+ *
+ * @api
+ * @param integer $TTL the Time-To-Live for the CDN container; if NULL,
+ * then the cloud's default value will be used for caching.
+ * @throws CDNNotAvailableError if CDN services are not available
+ * @return CDNContainer
+ */
+ public function enableCDN($ttl = null)
+ {
+ $url = $this->getService()->CDN()->url() . '/' . rawurlencode($this->name);
+
+ $headers = $this->metadataHeaders();
+
+ if ($ttl) {
+
+ // Make sure we're dealing with a real figure
+ if (!is_integer($ttl)) {
+ throw new Exceptions\CdnTtlError(sprintf(
+ Lang::translate('TTL value [%s] must be an integer'),
+ $ttl
+ ));
+ }
+
+ $headers['X-TTL'] = $ttl;
+ }
+
+ $headers['X-Log-Retention'] = 'True';
+ $headers['X-CDN-Enabled'] = 'True';
+
+ // PUT to the CDN container
+ $response = $this->getService()->request($url, 'PUT', $headers);
+
+ // check the response status
+ // @codeCoverageIgnoreStart
+ if ($response->httpStatus() > 202) {
+ throw new Exceptions\CdnHttpError(sprintf(
+ Lang::translate('HTTP error publishing to CDN, status [%d] response [%s]'),
+ $response->httpStatus(),
+ $response->httpBody()
+ ));
+ }
+ // @codeCoverageIgnoreEnd
+
+ // refresh the data
+ $this->refresh();
+
+ // return the CDN container object
+ $cdn = new CDNContainer($this->getService()->getCDNService(), $this->name);
+ $this->setCDN($cdn);
+
+ return $cdn;
+ }
+
+ /**
+ * Backwards compatability.
+ */
+ public function publishToCDN($ttl = null)
+ {
+ return $this->enableCDN($ttl);
+ }
+
+ /**
+ * Disables the containers CDN function.
+ *
+ * Note that the container will still be available on the CDN until
+ * its TTL expires.
+ *
+ * @api
+ * @return void
+ */
+ public function disableCDN()
+ {
+ // Set necessary headers
+ $headers['X-Log-Retention'] = 'False';
+ $headers['X-CDN-Enabled'] = 'False';
+
+ // PUT it to the CDN service
+ $response = $this->getService()->request($this->CDNURL(), 'PUT', $headers);
+
+ // check the response status
+ // @codeCoverageIgnoreStart
+ if ($response->httpStatus() != 201) {
+ throw new Exceptions\CdnHttpError(sprintf(
+ Lang::translate('HTTP error disabling CDN, status [%d] response [%s]'),
+ $response->httpStatus(),
+ $response->httpBody()
+ ));
+ }
+ // @codeCoverageIgnoreEnd
+
+ return true;
+ }
+
+ /**
+ * Creates a static website from the container
+ *
+ * @api
+ * @link http://docs.rackspace.com/files/api/v1/cf-devguide/content/Create_Static_Website-dle4000.html
+ * @param string $index the index page (starting page) of the website
+ * @return \OpenCloud\HttpResponse
+ */
+ public function createStaticSite($indexHtml)
+ {
+ $headers = array('X-Container-Meta-Web-Index' => $indexHtml);
+ $response = $this->getService()->request($this->url(), 'POST', $headers);
+
+ // check return code
+ // @codeCoverageIgnoreStart
+ if ($response->HttpStatus() > 204) {
+ throw new Exceptions\ContainerError(sprintf(
+ Lang::translate('Error creating static website for [%s], status [%d] response [%s]'),
+ $this->name,
+ $response->httpStatus(),
+ $response->httpBody()
+ ));
+ }
+ // @codeCoverageIgnoreEnd
+
+ return $response;
+ }
+
+ /**
+ * Sets the error page(s) for the static website
+ *
+ * @api
+ * @link http://docs.rackspace.com/files/api/v1/cf-devguide/content/Set_Error_Pages_for_Static_Website-dle4005.html
+ * @param string $name the name of the error page
+ * @return \OpenCloud\HttpResponse
+ */
+ public function staticSiteErrorPage($name)
+ {
+ $headers = array('X-Container-Meta-Web-Error' => $name);
+ $response = $this->getService()->request($this->url(), 'POST', $headers);
+
+ // check return code
+ // @codeCoverageIgnoreStart
+ if ($response->httpStatus() > 204) {
+ throw new Exceptions\ContainerError(sprintf(
+ Lang::translate('Error creating static site error page for [%s], status [%d] response [%s]'),
+ $this->name,
+ $response->httpStatus(),
+ $response->httpBody()
+ ));
+ }
+
+ return $response;
+ // @codeCoverageIgnoreEnd
+ }
+
+ /**
+ * Returns the CDN URL of the container (if enabled)
+ *
+ * The CDNURL() is used to manage the container. Note that it is different
+ * from the PublicURL() of the container, which is the publicly-accessible
+ * URL on the network.
+ *
+ * @api
+ * @return string
+ */
+ public function CDNURL()
+ {
+ return $this->getCDN()->url();
+ }
+
+ /**
+ * Returns the Public URL of the container (on the CDN network)
+ *
+ */
+ public function publicURL()
+ {
+ return $this->CDNURI();
+ }
+
+ /**
+ * Returns the CDN info about the container
+ *
+ * @api
+ * @return stdClass
+ */
+ public function CDNinfo($property = null)
+ {
+ // Not quite sure why this is here...
+ // @codeCoverageIgnoreStart
+ if ($this->getService() instanceof CDNService) {
+ return $this->metadata;
+ }
+ // @codeCoverageIgnoreEnd
+
+ // return NULL if the CDN container is not enabled
+ if (!isset($this->getCDN()->metadata->Enabled)
+ || $this->getCDN()->metadata->Enabled == 'False'
+ ) {
+ return null;
+ }
+
+ // check to see if it's set
+ if (isset($this->getCDN()->metadata->$property)) {
+ return trim($this->getCDN()->metadata->$property);
+ } elseif ($property !== null) {
+ return null;
+ }
+
+ // otherwise, return the whole metadata object
+ return $this->getCDN()->metadata;
+ }
+
+ /**
+ * Returns the CDN container URI prefix
+ *
+ * @api
+ * @return string
+ */
+ public function CDNURI()
+ {
+ return $this->CDNinfo('Uri');
+ }
+
+ /**
+ * Returns the SSL URI for the container
+ *
+ * @api
+ * @return string
+ */
+ public function SSLURI()
+ {
+ return $this->CDNinfo('Ssl-Uri');
+ }
+
+ /**
+ * Returns the streaming URI for the container
+ *
+ * @api
+ * @return string
+ */
+ public function streamingURI()
+ {
+ return $this->CDNinfo('Streaming-Uri');
+ }
+
+ /**
+ * Returns the IOS streaming URI for the container
+ *
+ * @api
+ * @link http://docs.rackspace.com/files/api/v1/cf-devguide/content/iOS-Streaming-d1f3725.html
+ * @return string
+ */
+ public function iosStreamingURI()
+ {
+ return $this->CDNinfo('Ios-Uri');
+ }
+
+ /**
+ * Creates a Collection of objects in the container
+ *
+ * @param array $params associative array of parameter values.
+ * * account/tenant - The unique identifier of the account/tenant.
+ * * container- The unique identifier of the container.
+ * * limit (Optional) - The number limit of results.
+ * * marker (Optional) - Value of the marker, that the object names
+ * greater in value than are returned.
+ * * end_marker (Optional) - Value of the marker, that the object names
+ * less in value than are returned.
+ * * prefix (Optional) - Value of the prefix, which the returned object
+ * names begin with.
+ * * format (Optional) - Value of the serialized response format, either
+ * json or xml.
+ * * delimiter (Optional) - Value of the delimiter, that all the object
+ * names nested in the container are returned.
+ * @link http://api.openstack.org for a list of possible parameter
+ * names and values
+ * @return OpenCloud\Collection
+ * @throws ObjFetchError
+ */
+ public function objectList($params = array())
+ {
+ // construct a query string out of the parameters
+ $params['format'] = 'json';
+
+ $queryString = $this->makeQueryString($params);
+
+ // append the query string to the URL
+ $url = $this->url();
+ if (strlen($queryString) > 0) {
+ $url .= '?' . $queryString;
+ }
+
+ return $this->getService()->collection(
+ 'OpenCloud\ObjectStore\Resource\DataObject', $url, $this
+ );
+ }
+
+ /**
+ * Returns a new DataObject associated with this container
+ *
+ * @param string $name if supplied, the name of the object to return
+ * @return DataObject
+ */
+ public function dataObject($name = null)
+ {
+ return new DataObject($this, $name);
+ }
+
+ /**
+ * Refreshes, then associates the CDN container
+ */
+ public function refresh($id = null, $url = null)
+ {
+ parent::refresh($id, $url);
+
+ // @codeCoverageIgnoreStart
+ if ($this->getService() instanceof CDNService) {
+ return;
+ }
+
+
+ if (null !== ($cdn = $this->getService()->CDN())) {
+ try {
+ $this->cdn = new CDNContainer(
+ $cdn,
+ $this->name
+ );
+ } catch (Exceptions\ContainerNotFoundError $e) {
+ $this->cdn = new CDNContainer($cdn);
+ $this->cdn->name = $this->name;
+ }
+ }
+ // @codeCoverageIgnoreEnd
+ }
+
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/DataObject.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/DataObject.php
new file mode 100644
index 00000000000..443df1f651f
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/DataObject.php
@@ -0,0 +1,941 @@
+<?php
+/**
+ * PHP OpenCloud library.
+ *
+ * @copyright Copyright 2013 Rackspace US, Inc. See COPYING for licensing information.
+ * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0
+ * @version 1.6.0
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ * @author Jamie Hannaford <jamie.hannaford@rackspace.com>
+ */
+
+namespace OpenCloud\ObjectStore\Resource;
+
+use finfo as FileInfo;
+use OpenCloud\Common\Lang;
+use OpenCloud\Common\Exceptions;
+use OpenCloud\ObjectStore\AbstractService;
+use OpenCloud\Common\Request\Response\Http;
+
+/**
+ * Objects are the basic storage entities in Cloud Files. They represent the
+ * files and their optional metadata you upload to the system. When you upload
+ * objects to Cloud Files, the data is stored as-is (without compression or
+ * encryption) and consists of a location (container), the object's name, and
+ * any metadata you assign consisting of key/value pairs.
+ */
+class DataObject extends AbstractStorageObject
+{
+ /**
+ * Object name. The only restriction on object names is that they must be
+ * less than 1024 bytes in length after URL encoding.
+ *
+ * @var string
+ */
+ public $name;
+
+ /**
+ * Hash value of the object.
+ *
+ * @var string
+ */
+ public $hash;
+
+ /**
+ * Size of object in bytes.
+ *
+ * @var string
+ */
+ public $bytes;
+
+ /**
+ * Date of last modification.
+ *
+ * @var string
+ */
+ public $last_modified;
+
+ /**
+ * Object's content type.
+ *
+ * @var string
+ */
+ public $content_type;
+
+ /**
+ * Object's content length.
+ *
+ * @var string
+ */
+ public $content_length;
+
+ /**
+ * Other headers set for this object (e.g. Access-Control-Allow-Origin)
+ *
+ * @var array
+ */
+ public $extra_headers = array();
+
+ /**
+ * Whether or not to calculate and send an ETag on create.
+ *
+ * @var bool
+ */
+ public $send_etag = true;
+
+ /**
+ * The data contained by the object.
+ *
+ * @var string
+ */
+ private $data;
+
+ /**
+ * The ETag value.
+ *
+ * @var string
+ */
+ private $etag;
+
+ /**
+ * The parent container of this object.
+ *
+ * @var CDNContainer
+ */
+ private $container;
+
+ /**
+ * Is this data object a pseudo directory?
+ *
+ * @var bool
+ */
+ private $directory = false;
+
+ /**
+ * Used to translate header values (returned by requests) into properties.
+ *
+ * @var array
+ */
+ private $headerTranslate = array(
+ 'Etag' => 'hash',
+ 'ETag' => 'hash',
+ 'Last-Modified' => 'last_modified',
+ 'Content-Length' => array('bytes', 'content_length'),
+ );
+
+ /**
+ * These properties can be freely set by the user for CRUD operations.
+ *
+ * @var array
+ */
+ private $allowedProperties = array(
+ 'name',
+ 'content_type',
+ 'extra_headers',
+ 'send_etag'
+ );
+
+ /**
+ * Option for clearing the status cache when objects are uploaded to API.
+ * By default, it is set to FALSE for performance; but if you have files
+ * that are rapidly and very often updated, you might want to clear the status
+ * cache so PHP reads the files directly, instead of relying on the cache.
+ *
+ * @link http://php.net/manual/en/function.clearstatcache.php
+ * @var bool
+ */
+ public $clearStatusCache = false;
+
+ /**
+ * A DataObject is related to a container and has a name
+ *
+ * If `$name` is specified, then it attempts to retrieve the object from the
+ * object store.
+ *
+ * @param Container $container the container holding this object
+ * @param mixed $cdata if an object or array, it is treated as values
+ * with which to populate the object. If it is a string, it is
+ * treated as a name and the object's info is retrieved from
+ * the service.
+ * @return void
+ */
+ public function __construct($container, $cdata = null)
+ {
+ parent::__construct();
+
+ $this->container = $container;
+
+ // For pseudo-directories, we need to ensure the name is set
+ if (!empty($cdata->subdir)) {
+ $this->name = $cdata->subdir;
+ $this->directory = true;
+ } else {
+ $this->populate($cdata);
+ }
+ }
+
+ /**
+ * Is this data object a pseudo-directory?
+ *
+ * @return bool
+ */
+ public function isDirectory()
+ {
+ return $this->directory;
+ }
+
+ /**
+ * Allow other objects to know what the primary key is.
+ *
+ * @return string
+ */
+ public function primaryKeyField()
+ {
+ return 'name';
+ }
+
+ /**
+ * Is this a real file?
+ *
+ * @param string $filename
+ * @return bool
+ */
+ private function isRealFile($filename)
+ {
+ return $filename != '/dev/null' && $filename != 'NUL';
+ }
+
+ /**
+ * Set this file's content type.
+ *
+ * @param string $contentType
+ */
+ public function setContentType($contentType)
+ {
+ $this->content_type = $contentType;
+ }
+
+ /**
+ * Return the content type.
+ *
+ * @return string
+ */
+ public function getContentType()
+ {
+ return $this->content_type;
+ }
+
+ /**
+ * Returns the URL of the data object
+ *
+ * If the object is new and doesn't have a name, then an exception is
+ * thrown.
+ *
+ * @param string $subresource Not used
+ * @return string
+ * @throws NoNameError
+ */
+ public function url($subresource = '')
+ {
+ if (!$this->name) {
+ throw new Exceptions\NoNameError(Lang::translate('Object has no name'));
+ }
+
+ return Lang::noslash(
+ $this->container->url()) . '/' . str_replace('%2F', '/', rawurlencode($this->name)
+ );
+ }
+
+ /**
+ * Creates (or updates; both the same) an instance of the object
+ *
+ * @api
+ * @param array $params an optional associative array that can contain the
+ * 'name' and 'content_type' of the object
+ * @param string $filename if provided, then the object is loaded from the
+ * specified file
+ * @return boolean
+ * @throws CreateUpdateError
+ */
+ public function create($params = array(), $filename = null, $extractArchive = null)
+ {
+ // Set and validate params
+ $this->setParams($params);
+
+ // assume no file upload
+ $fp = false;
+
+ // if the filename is provided, process it
+ if ($filename) {
+
+ if (!$fp = @fopen($filename, 'r')) {
+ throw new Exceptions\IOError(sprintf(
+ Lang::translate('Could not open file [%s] for reading'),
+ $filename
+ ));
+ }
+
+ // @todo Maybe, for performance, we could set the "clear status cache"
+ // feature to false by default - but allow users to set to true if required
+ clearstatcache($this->clearStatusCache === true, $filename);
+
+ // Cast filesize as a floating point
+ $filesize = (float) filesize($filename);
+
+ // Check it's below a reasonable size, and set
+ // @codeCoverageIgnoreStart
+ if ($filesize > AbstractService::MAX_OBJECT_SIZE) {
+ throw new Exceptions\ObjectError("File size exceeds maximum object size.");
+ }
+ // @codeCoverageIgnoreEnd
+ $this->content_length = $filesize;
+
+ // Guess the content type if necessary
+ if (!$this->getContentType() && $this->isRealFile($filename)) {
+ $this->setContentType($this->inferContentType($filename));
+ }
+
+ // Send ETag checksum if necessary
+ if ($this->send_etag) {
+ $this->etag = md5_file($filename);
+ }
+
+ // Announce to the world
+ $this->getLogger()->info('Uploading {size} bytes from {name}', array(
+ 'size' => $filesize,
+ 'name' => $filename
+ ));
+
+ } else {
+ // compute the length
+ $this->content_length = strlen($this->data);
+
+ if ($this->send_etag) {
+ $this->etag = md5($this->data);
+ }
+ }
+
+ // Only allow supported archive types
+ // http://docs.rackspace.com/files/api/v1/cf-devguide/content/Extract_Archive-d1e2338.html
+ $extractArchiveUrlArg = '';
+
+ if ($extractArchive) {
+ if ($extractArchive !== "tar.gz" && $extractArchive !== "tar.bz2") {
+ throw new Exceptions\ObjectError(
+ "Extract Archive only supports tar.gz and tar.bz2"
+ );
+ } else {
+ $extractArchiveUrlArg = "?extract-archive=" . $extractArchive;
+ $this->etag = null;
+ $this->setContentType('');
+ }
+ }
+
+ // Set headers
+ $headers = $this->metadataHeaders();
+
+ if (!empty($this->etag)) {
+ $headers['ETag'] = $this->etag;
+ }
+
+ // Content-Type is no longer required; if not specified, it will
+ // attempt to guess based on the file extension.
+ if (!$this->getContentType()) {
+ $headers['Content-Type'] = $this->getContentType();
+ }
+
+ $headers['Content-Length'] = $this->content_length;
+
+ // Merge in extra headers
+ if (!empty($this->extra_headers)) {
+ $headers = $this->extra_headers + $headers;
+ }
+
+ // perform the request
+ $response = $this->getService()->request(
+ $this->url() . $extractArchiveUrlArg,
+ 'PUT',
+ $headers,
+ $fp ? $fp : $this->data
+ );
+
+ // check the status
+ // @codeCoverageIgnoreStart
+ if (($status = $response->httpStatus()) >= 300) {
+ throw new Exceptions\CreateUpdateError(sprintf(
+ Lang::translate('Problem saving/updating object [%s] HTTP status [%s] response [%s]'),
+ $this->url() . $extractArchiveUrlArg,
+ $status,
+ $response->httpBody()
+ ));
+ }
+ // @codeCoverageIgnoreEnd
+
+ // set values from response
+ $this->saveResponseHeaders($response);
+
+ // close the file handle
+ if ($fp) {
+ fclose($fp);
+ }
+
+ return $response;
+ }
+
+ /**
+ * Update() is provided as an alias for the Create() method
+ *
+ * Since update and create both use a PUT request, the different functions
+ * may allow the developer to distinguish between the semantics in his or
+ * her application.
+ *
+ * @api
+ * @param array $params an optional associative array that can contain the
+ * 'name' and 'type' of the object
+ * @param string $filename if provided, the object is loaded from the file
+ * @return boolean
+ */
+ public function update($params = array(), $filename = '')
+ {
+ return $this->create($params, $filename);
+ }
+
+ /**
+ * UpdateMetadata() - updates headers
+ *
+ * Updates metadata headers
+ *
+ * @api
+ * @param array $params an optional associative array that can contain the
+ * 'name' and 'type' of the object
+ * @return boolean
+ */
+ public function updateMetadata($params = array())
+ {
+ $this->setParams($params);
+
+ // set the headers
+ $headers = $this->metadataHeaders();
+ $headers['Content-Type'] = $this->getContentType();
+
+ $response = $this->getService()->request(
+ $this->url(),
+ 'POST',
+ $headers
+ );
+
+ // check the status
+ // @codeCoverageIgnoreStart
+ if (($stat = $response->httpStatus()) >= 204) {
+ throw new Exceptions\UpdateError(sprintf(
+ Lang::translate('Problem updating object [%s] HTTP status [%s] response [%s]'),
+ $this->url(),
+ $stat,
+ $response->httpBody()
+ ));
+ }
+ // @codeCoverageIgnoreEnd
+
+ return $response;
+ }
+
+ /**
+ * Deletes an object from the Object Store
+ *
+ * Note that we can delete without retrieving by specifying the name in the
+ * parameter array.
+ *
+ * @api
+ * @param array $params an array of parameters
+ * @return HttpResponse if successful; FALSE if not
+ * @throws DeleteError
+ */
+ public function delete($params = array())
+ {
+ $this->setParams($params);
+
+ $response = $this->getService()->request($this->url(), 'DELETE');
+
+ // check the status
+ // @codeCoverageIgnoreStart
+ if (($stat = $response->httpStatus()) >= 300) {
+ throw new Exceptions\DeleteError(sprintf(
+ Lang::translate('Problem deleting object [%s] HTTP status [%s] response [%s]'),
+ $this->url(),
+ $stat,
+ $response->httpBody()
+ ));
+ }
+ // @codeCoverageIgnoreEnd
+
+ return $response;
+ }
+
+ /**
+ * Copies the object to another container/object
+ *
+ * Note that this function, because it operates within the Object Store
+ * itself, is much faster than downloading the object and re-uploading it
+ * to a new object.
+ *
+ * @param DataObject $target the target of the COPY command
+ */
+ public function copy(DataObject $target)
+ {
+ $uri = sprintf('/%s/%s', $target->container()->name(), $target->name());
+
+ $this->getLogger()->info('Copying object to [{uri}]', array('uri' => $uri));
+
+ $response = $this->getService()->request(
+ $this->url(),
+ 'COPY',
+ array('Destination' => $uri)
+ );
+
+ // check response code
+ // @codeCoverageIgnoreStart
+ if ($response->httpStatus() > 202) {
+ throw new Exceptions\ObjectCopyError(sprintf(
+ Lang::translate('Error copying object [%s], status [%d] response [%s]'),
+ $this->url(),
+ $response->httpStatus(),
+ $response->httpBody()
+ ));
+ }
+ // @codeCoverageIgnoreEnd
+
+ return $response;
+ }
+
+ /**
+ * Returns the container of the object
+ *
+ * @return Container
+ */
+ public function container()
+ {
+ return $this->container;
+ }
+
+ /**
+ * returns the TEMP_URL for the object
+ *
+ * Some notes:
+ * * The `$secret` value is arbitrary; it must match the value set for
+ * the `X-Account-Meta-Temp-URL-Key` on the account level. This can be
+ * set by calling `$service->SetTempUrlSecret($secret)`.
+ * * The `$expires` value is the number of seconds you want the temporary
+ * URL to be valid for. For example, use `60` to make it valid for a
+ * minute
+ * * The `$method` must be either GET or PUT. No other methods are
+ * supported.
+ *
+ * @param string $secret the shared secret
+ * @param integer $expires the expiration time (in seconds)
+ * @param string $method either GET or PUT
+ * @return string the temporary URL
+ */
+ public function tempUrl($secret, $expires, $method)
+ {
+ $method = strtoupper($method);
+ $expiry_time = time() + $expires;
+
+ // check for proper method
+ if ($method != 'GET' && $method != 'PUT') {
+ throw new Exceptions\TempUrlMethodError(sprintf(
+ Lang::translate(
+ 'Bad method [%s] for TempUrl; only GET or PUT supported'),
+ $method
+ ));
+ }
+
+ // construct the URL
+ $url = $this->url();
+ $path = urldecode(parse_url($url, PHP_URL_PATH));
+
+ $hmac_body = "$method\n$expiry_time\n$path";
+ $hash = hash_hmac('sha1', $hmac_body, $secret);
+
+ $this->getLogger()->info('URL [{url}]; SIG [{sig}]; HASH [{hash}]', array(
+ 'url' => $url,
+ 'sig' => $hmac_body,
+ 'hash' => $hash
+ ));
+
+ $temp_url = sprintf('%s?temp_url_sig=%s&temp_url_expires=%d', $url, $hash, $expiry_time);
+
+ // debug that stuff
+ $this->getLogger()->info('TempUrl generated [{url}]', array(
+ 'url' => $temp_url
+ ));
+
+ return $temp_url;
+ }
+
+ /**
+ * Sets object data from string
+ *
+ * This is a convenience function to permit the use of other technologies
+ * for setting an object's content.
+ *
+ * @param string $data
+ * @return void
+ */
+ public function setData($data)
+ {
+ $this->data = (string) $data;
+ }
+
+ /**
+ * Return object's data as a string
+ *
+ * @return string the entire object
+ */
+ public function saveToString()
+ {
+ return $this->getService()->request($this->url())->httpBody();
+ }
+
+ /**
+ * Saves the object's data to local filename
+ *
+ * Given a local filename, the Object's data will be written to the newly
+ * created file.
+ *
+ * Example:
+ * <code>
+ * # ... authentication/connection/container code excluded
+ * # ... see previous examples
+ *
+ * # Whoops! I deleted my local README, let me download/save it
+ * #
+ * $my_docs = $conn->get_container("documents");
+ * $doc = $my_docs->get_object("README");
+ *
+ * $doc->SaveToFilename("/home/ej/cloudfiles/readme.restored");
+ * </code>
+ *
+ * @param string $filename name of local file to write data to
+ * @return boolean <kbd>TRUE</kbd> if successful
+ * @throws IOException error opening file
+ * @throws InvalidResponseException unexpected response
+ */
+ public function saveToFilename($filename)
+ {
+ if (!$fp = @fopen($filename, "wb")) {
+ throw new Exceptions\IOError(sprintf(
+ Lang::translate('Could not open file [%s] for writing'),
+ $filename
+ ));
+ }
+
+ $result = $this->getService()->request($this->url(), 'GET', array(), $fp);
+
+ fclose($fp);
+
+ return $result;
+ }
+
+ /**
+ * Saves the object's to a stream filename
+ *
+ * Given a local filename, the Object's data will be written to the stream
+ *
+ * Example:
+ * <code>
+ * # ... authentication/connection/container code excluded
+ * # ... see previous examples
+ *
+ * # If I want to write the README to a temporary memory string I
+ * # do :
+ * #
+ * $my_docs = $conn->get_container("documents");
+ * $doc = $my_docs->DataObject(array("name"=>"README"));
+ *
+ * $fp = fopen('php://temp', 'r+');
+ * $doc->SaveToStream($fp);
+ * fclose($fp);
+ * </code>
+ *
+ * @param string $filename name of local file to write data to
+ * @return boolean <kbd>TRUE</kbd> if successful
+ * @throws IOException error opening file
+ * @throws InvalidResponseException unexpected response
+ */
+ public function saveToStream($resource)
+ {
+ if (!is_resource($resource)) {
+ throw new Exceptions\ObjectError(
+ Lang::translate("Resource argument not a valid PHP resource."
+ ));
+ }
+
+ return $this->getService()->request($this->url(), 'GET', array(), $resource);
+ }
+
+
+ /**
+ * Returns the object's MD5 checksum
+ *
+ * Accessor method for reading Object's private ETag attribute.
+ *
+ * @api
+ * @return string MD5 checksum hexidecimal string
+ */
+ public function getETag()
+ {
+ return $this->etag;
+ }
+
+ /**
+ * Purges the object from the CDN
+ *
+ * Note that the object will still be served up to the time of its
+ * TTL value.
+ *
+ * @api
+ * @param string $email An email address that will be notified when
+ * the object is purged.
+ * @return void
+ * @throws CdnError if the container is not CDN-enabled
+ * @throws CdnHttpError if there is an HTTP error in the transaction
+ */
+ public function purgeCDN($email)
+ {
+ // @codeCoverageIgnoreStart
+ if (!$cdn = $this->Container()->CDNURL()) {
+ throw new Exceptions\CdnError(Lang::translate('Container is not CDN-enabled'));
+ }
+ // @codeCoverageIgnoreEnd
+
+ $url = $cdn . '/' . $this->name;
+ $headers['X-Purge-Email'] = $email;
+ $response = $this->getService()->request($url, 'DELETE', $headers);
+
+ // check the status
+ // @codeCoverageIgnoreStart
+ if ($response->httpStatus() > 204) {
+ throw new Exceptions\CdnHttpError(sprintf(
+ Lang::translate('Error purging object, status [%d] response [%s]'),
+ $response->httpStatus(),
+ $response->httpBody()
+ ));
+ }
+ // @codeCoverageIgnoreEnd
+
+ return true;
+ }
+
+ /**
+ * Returns the CDN URL (for managing the object)
+ *
+ * Note that the DataObject::PublicURL() method is used to return the
+ * publicly-available URL of the object, while the CDNURL() is used
+ * to manage the object.
+ *
+ * @return string
+ */
+ public function CDNURL()
+ {
+ return $this->container()->CDNURL() . '/' . $this->name;
+ }
+
+ /**
+ * Returns the object's Public CDN URL, if available
+ *
+ * @api
+ * @param string $type can be 'streaming', 'ssl', 'ios-streaming',
+ * or anything else for the
+ * default URL. For example, `$object->PublicURL('ios-streaming')`
+ * @return string
+ */
+ public function publicURL($type = null)
+ {
+ if (!$prefix = $this->container()->CDNURI()) {
+ return null;
+ }
+
+ switch(strtoupper($type)) {
+ case 'SSL':
+ $url = $this->container()->SSLURI().'/'.$this->name;
+ break;
+ case 'STREAMING':
+ $url = $this->container()->streamingURI().'/'.$this->name;
+ break;
+ case 'IOS':
+ case 'IOS-STREAMING':
+ $url = $this->container()->iosStreamingURI().'/'.$this->name;
+ break;
+ default:
+ $url = $prefix.'/'.$this->name;
+ break;
+ }
+
+ return $url;
+ }
+
+ /**
+ * Sets parameters from an array and validates them.
+ *
+ * @param array $params Associative array of parameters
+ * @return void
+ */
+ private function setParams(array $params = array())
+ {
+ // Inspect the user's array for any unapproved keys, and unset if necessary
+ foreach (array_diff(array_keys($params), $this->allowedProperties) as $key) {
+ $this->getLogger()->warning('You cannot use the {keyName} key when creating an object', array(
+ 'keyName' => $key
+ ));
+ unset($params[$key]);
+ }
+
+ $this->populate($params);
+ }
+
+ /**
+ * Retrieves a single object, parses headers
+ *
+ * @return void
+ * @throws NoNameError, ObjFetchError
+ */
+ private function fetch()
+ {
+ if (!$this->name) {
+ throw new Exceptions\NoNameError(Lang::translate('Cannot retrieve an unnamed object'));
+ }
+
+ $response = $this->getService()->request($this->url(), 'HEAD', array('Accept' => '*/*'));
+
+ // check for errors
+ // @codeCoverageIgnoreStart
+ if ($response->httpStatus() >= 300) {
+ throw new Exceptions\ObjFetchError(sprintf(
+ Lang::translate('Problem retrieving object [%s]'),
+ $this->url()
+ ));
+ }
+ // @codeCoverageIgnoreEnd
+
+ // set headers as metadata?
+ $this->saveResponseHeaders($response);
+
+ // parse the metadata
+ $this->getMetadata($response);
+ }
+
+ /**
+ * Extracts the headers from the response, and saves them as object
+ * attributes. Additional name conversions are done where necessary.
+ *
+ * @param Http $response
+ */
+ private function saveResponseHeaders(Http $response, $fillExtraIfNotFound = true)
+ {
+ foreach ($response->headers() as $header => $value) {
+ if (isset($this->headerTranslate[$header])) {
+ // This header needs to be translated
+ $property = $this->headerTranslate[$header];
+ // Are there multiple properties that need to be set?
+ if (is_array($property)) {
+ foreach ($property as $subProperty) {
+ $this->$subProperty = $value;
+ }
+ } else {
+ $this->$property = $value;
+ }
+ } elseif ($fillExtraIfNotFound === true) {
+ // Otherwise, stock extra headers
+ $this->extra_headers[$header] = $value;
+ }
+ }
+ }
+
+ /**
+ * Compatability.
+ */
+ public function refresh()
+ {
+ return $this->fetch();
+ }
+
+ /**
+ * Returns the service associated with this object
+ *
+ * It's actually the object's container's service, so this method will
+ * simplify things a bit.
+ */
+ private function getService()
+ {
+ return $this->container->getService();
+ }
+
+ /**
+ * Performs an internal check to get the proper MIME type for an object
+ *
+ * This function would go over the available PHP methods to get
+ * the MIME type.
+ *
+ * By default it will try to use the PHP fileinfo library which is
+ * available from PHP 5.3 or as an PECL extension
+ * (http://pecl.php.net/package/Fileinfo).
+ *
+ * It will get the magic file by default from the system wide file
+ * which is usually available in /usr/share/magic on Unix or try
+ * to use the file specified in the source directory of the API
+ * (share directory).
+ *
+ * if fileinfo is not available it will try to use the internal
+ * mime_content_type function.
+ *
+ * @param string $handle name of file or buffer to guess the type from
+ * @return boolean <kbd>TRUE</kbd> if successful
+ * @throws BadContentTypeException
+ * @codeCoverageIgnore
+ */
+ private function inferContentType($handle)
+ {
+ if ($contentType = $this->getContentType()) {
+ return $contentType;
+ }
+
+ $contentType = false;
+
+ $filePath = (is_string($handle)) ? $handle : (string) $handle;
+
+ if (function_exists("finfo_open")) {
+
+ $magicPath = dirname(__FILE__) . "/share/magic";
+ $finfo = new FileInfo(FILEINFO_MIME, file_exists($magicPath) ? $magicPath : null);
+
+ if ($finfo) {
+
+ $contentType = is_file($filePath)
+ ? $finfo->file($handle)
+ : $finfo->buffer($handle);
+
+ /**
+ * PHP 5.3 fileinfo display extra information like charset so we
+ * remove everything after the ; since we are not into that stuff
+ */
+ if (null !== ($extraInfo = strpos($contentType, "; "))) {
+ $contentType = substr($contentType, 0, $extraInfo);
+ }
+ }
+
+ //unset($finfo);
+ }
+
+ if (!$contentType) {
+ // Try different native function instead
+ if (is_file((string) $handle) && function_exists("mime_content_type")) {
+ $contentType = mime_content_type($handle);
+ } else {
+ $this->getLogger()->error('Content-Type cannot be found');
+ }
+ }
+
+ return $contentType;
+ }
+
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Service.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Service.php
new file mode 100644
index 00000000000..571b33378ac
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Service.php
@@ -0,0 +1,115 @@
+<?php
+/**
+ * PHP OpenCloud library.
+ *
+ * @copyright Copyright 2013 Rackspace US, Inc. See COPYING for licensing information.
+ * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0
+ * @version 1.6.0
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ * @author Jamie Hannaford <jamie.hannaford@rackspace.com>
+ */
+
+namespace OpenCloud\ObjectStore;
+
+use OpenCloud\OpenStack;
+use OpenCloud\Common\Exceptions;
+use OpenCloud\Common\Lang;
+
+/**
+ * The ObjectStore (Cloud Files) service.
+ */
+class Service extends AbstractService
+{
+
+ /**
+ * This holds the associated CDN service (for Rackspace public cloud)
+ * or is NULL otherwise. The existence of an object here is
+ * indicative that the CDN service is available.
+ */
+ private $cdn;
+
+ /**
+ * Creates a new ObjectStore service object.
+ *
+ * @param OpenCloud\OpenStack $connection The connection object
+ * @param string $serviceName The name of the service
+ * @param string $serviceRegion The service's region
+ * @param string $urlType The type of URL (normally 'publicURL')
+ */
+ public function __construct(
+ OpenStack $connection,
+ $serviceName = RAXSDK_OBJSTORE_NAME,
+ $serviceRegion = RAXSDK_OBJSTORE_REGION,
+ $urltype = RAXSDK_OBJSTORE_URLTYPE
+ ) {
+ $this->getLogger()->info('Initializing Container Service...');
+
+ parent::__construct(
+ $connection,
+ 'object-store',
+ $serviceName,
+ $serviceRegion,
+ $urltype
+ );
+
+ // establish the CDN container, if available
+ try {
+ $this->cdn = new CDNService(
+ $connection,
+ $serviceName . 'CDN',
+ $serviceRegion,
+ $urltype
+ );
+ } catch (Exceptions\EndpointError $e) {
+ // If we have an endpoint error, then the CDN functionality is not
+ // available. In this case, we silently ignore it.
+ }
+ }
+
+ /**
+ * Sets the shared secret value for the TEMP_URL
+ *
+ * @param string $secret the shared secret
+ * @return HttpResponse
+ */
+ public function setTempUrlSecret($secret)
+ {
+ $response = $this->request(
+ $this->url(),
+ 'POST',
+ array('X-Account-Meta-Temp-Url-Key' => $secret)
+ );
+
+ // @codeCoverageIgnoreStart
+ if ($response->httpStatus() > 204) {
+ throw new Exceptions\HttpError(sprintf(
+ Lang::translate('Error in request, status [%d] for URL [%s] [%s]'),
+ $response->httpStatus(),
+ $this->url(),
+ $response->httpBody()
+ ));
+ }
+ // @codeCoverageIgnoreEnd
+
+ return $response;
+ }
+
+ /**
+ * Get the CDN service.
+ *
+ * @return null|CDNService
+ */
+ public function getCDNService()
+ {
+ return $this->cdn;
+ }
+
+ /**
+ * Backwards compability.
+ */
+ public function CDN()
+ {
+ return $this->getCDNService();
+ }
+
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/OpenStack.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/OpenStack.php
new file mode 100644
index 00000000000..c3e645a5406
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/OpenStack.php
@@ -0,0 +1,1198 @@
+<?php
+/**
+ * PHP OpenCloud library.
+ *
+ * @copyright Copyright 2013 Rackspace US, Inc. See COPYING for licensing information.
+ * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0
+ * @version 1.6.0
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ * @author Jamie Hannaford <jamie.hannaford@rackspace.com>
+ */
+
+namespace OpenCloud;
+
+require_once __DIR__ . '/Globals.php';
+
+use OpenCloud\Common\Base;
+use OpenCloud\Common\Lang;
+use OpenCloud\Common\Exceptions;
+use OpenCloud\Common\ServiceCatalogItem;
+
+/**
+ * The OpenStack class represents a relationship (or "connection")
+ * between a user and a service.
+ *
+ * This is the primary entry point into an OpenStack system, and the only one
+ * where the developer is required to know and provide the endpoint URL (in
+ * all other cases, the endpoint is derived from the Service Catalog provided
+ * by the authentication system).
+ *
+ * Since various providers have different mechanisms for authentication, users
+ * will often use a subclass of OpenStack. For example, the Rackspace
+ * class is provided for users of Rackspace's cloud services, and other cloud
+ * providers are welcome to add their own subclasses as well.
+ *
+ * General usage example:
+ * <code>
+ * $username = 'My Username';
+ * $secret = 'My Secret';
+ * $connection = new OpenCloud\OpenStack($username, $secret);
+ * // having established the connection, we can set some defaults
+ * // this sets the default name and region of the Compute service
+ * $connection->SetDefaults('Compute', 'cloudServersOpenStack', 'ORD');
+ * // access a Compute service
+ * $chicago = $connection->Compute();
+ * // if we want to access a different service, we can:
+ * $dallas = $connection->Compute('cloudServersOpenStack', 'DFW');
+ * </code>
+ */
+class OpenStack extends Base
+{
+
+ /**
+ * This holds the HTTP User-Agent: used for all requests to the services. It
+ * is public so that, if necessary, it can be entirely overridden by the
+ * developer. However, it's strongly recomended that you use the
+ * appendUserAgent() method to APPEND your own User Agent identifier to the
+ * end of this string; the user agent information can be very valuable to
+ * service providers to track who is using their service.
+ *
+ * @var string
+ */
+ public $useragent = RAXSDK_USER_AGENT;
+
+ protected $url;
+ protected $secret = array();
+ protected $token;
+ protected $expiration = 0;
+ protected $tenant;
+ protected $catalog;
+ protected $connectTimeout = RAXSDK_CONNECTTIMEOUT;
+ protected $httpTimeout = RAXSDK_TIMEOUT;
+ protected $overlimitTimeout = RAXSDK_OVERLIMIT_TIMEOUT;
+
+ /**
+ * This associative array holds default values used to identify each
+ * service (and to select it from the Service Catalog). Use the
+ * Compute::SetDefaults() method to change the default values, or
+ * define the global constants (for example, RAXSDK_COMPUTE_NAME)
+ * BEFORE loading the OpenCloud library:
+ *
+ * <code>
+ * define('RAXSDK_COMPUTE_NAME', 'cloudServersOpenStack');
+ * include('openstack.php');
+ * </code>
+ */
+ protected $defaults = array(
+ 'Compute' => array(
+ 'name' => RAXSDK_COMPUTE_NAME,
+ 'region' => RAXSDK_COMPUTE_REGION,
+ 'urltype' => RAXSDK_COMPUTE_URLTYPE
+ ),
+ 'ObjectStore' => array(
+ 'name' => RAXSDK_OBJSTORE_NAME,
+ 'region' => RAXSDK_OBJSTORE_REGION,
+ 'urltype' => RAXSDK_OBJSTORE_URLTYPE
+ ),
+ 'Database' => array(
+ 'name' => RAXSDK_DATABASE_NAME,
+ 'region' => RAXSDK_DATABASE_REGION,
+ 'urltype' => RAXSDK_DATABASE_URLTYPE
+ ),
+ 'Volume' => array(
+ 'name' => RAXSDK_VOLUME_NAME,
+ 'region' => RAXSDK_VOLUME_REGION,
+ 'urltype' => RAXSDK_VOLUME_URLTYPE
+ ),
+ 'LoadBalancer' => array(
+ 'name' => RAXSDK_LBSERVICE_NAME,
+ 'region' => RAXSDK_LBSERVICE_REGION,
+ 'urltype' => RAXSDK_LBSERVICE_URLTYPE
+ ),
+ 'DNS' => array(
+ 'name' => RAXSDK_DNS_NAME,
+ 'region' => RAXSDK_DNS_REGION,
+ 'urltype' => RAXSDK_DNS_URLTYPE
+ ),
+ 'Orchestration' => array(
+ 'name' => RAXSDK_ORCHESTRATION_NAME,
+ 'region' => RAXSDK_ORCHESTRATION_REGION,
+ 'urltype' => RAXSDK_ORCHESTRATION_URLTYPE
+ ),
+ 'CloudMonitoring' => array(
+ 'name' => RAXSDK_MONITORING_NAME,
+ 'region' => RAXSDK_MONITORING_REGION,
+ 'urltype' => RAXSDK_MONITORING_URLTYPE
+ ),
+ 'Autoscale' => array(
+ 'name' => RAXSDK_AUTOSCALE_NAME,
+ 'region' => RAXSDK_AUTOSCALE_REGION,
+ 'urltype' => RAXSDK_AUTOSCALE_URLTYPE
+ )
+ );
+
+ private $_user_write_progress_callback_func;
+ private $_user_read_progress_callback_func;
+
+ /**
+ * Tracks file descriptors used by streaming downloads
+ *
+ * This will permit multiple simultaneous streaming downloads; the
+ * key is the URL of the object, and the value is its file descriptor.
+ *
+ * To prevent memory overflows, each array element is deleted when
+ * the end of the file is reached.
+ */
+ private $fileDescriptors = array();
+
+ /**
+ * array of options to pass to the CURL request object
+ */
+ private $curlOptions = array();
+
+ /**
+ * list of attributes to export/import
+ */
+ private $exportItems = array(
+ 'token',
+ 'expiration',
+ 'tenant',
+ 'catalog'
+ );
+
+ /**
+ * Creates a new OpenStack object
+ *
+ * The OpenStack object needs two bits of information: the URL to
+ * authenticate against, and a "secret", which is an associative array
+ * of name/value pairs. Usually, the secret will be a username and a
+ * password, but other values may be required by different authentication
+ * systems. For example, OpenStack Keystone requires a username and
+ * password, but Rackspace uses a username, tenant ID, and API key.
+ * (See OpenCloud\Rackspace for that.)
+ *
+ * @param string $url - the authentication endpoint URL
+ * @param array $secret - an associative array of auth information:
+ * * username
+ * * password
+ * @param array $options - CURL options to pass to the HttpRequest object
+ */
+ public function __construct($url, array $secret, array $options = array())
+ {
+ // check for supported version
+ // @codeCoverageIgnoreStart
+ $version = phpversion();
+ if ($version < '5.3.1') {
+ throw new Exceptions\UnsupportedVersionError(sprintf(
+ Lang::translate('PHP version [%s] is not supported'),
+ $version
+ ));
+ }
+ // @codeCoverageIgnoreEnd
+
+ // Start processing
+ $this->getLogger()->info(Lang::translate('Initializing OpenStack client'));
+
+ // Set properties
+ $this->setUrl($url);
+ $this->setSecret($secret);
+ $this->setCurlOptions($options);
+ }
+
+ /**
+ * Set user agent.
+ *
+ * @param string $useragent
+ * @return OpenCloud\OpenStack
+ */
+ public function setUserAgent($useragent)
+ {
+ $this->useragent = $useragent;
+
+ return $this;
+ }
+
+ /**
+ * Allows the user to append a user agent string
+ *
+ * Programs that are using these bindings are encouraged to add their
+ * user agent to the one supplied by this SDK. This will permit cloud
+ * providers to track users so that they can provide better service.
+ *
+ * @param string $agent an arbitrary user-agent string; e.g. "My Cloud App"
+ * @return OpenCloud\OpenStack
+ */
+ public function appendUserAgent($useragent)
+ {
+ $this->useragent .= ';' . $useragent;
+
+ return $this;
+ }
+
+ /**
+ * Get user agent.
+ *
+ * @return string
+ */
+ public function getUserAgent()
+ {
+ return $this->useragent;
+ }
+
+ /**
+ * Sets the URL which the client will access.
+ *
+ * @param string $url
+ * @return OpenCloud\OpenStack
+ */
+ public function setUrl($url)
+ {
+ $this->url = $url;
+
+ return $this;
+ }
+
+ /**
+ * Get the URL.
+ *
+ * @return string
+ */
+ public function getUrl()
+ {
+ return $this->url;
+ }
+
+ /**
+ * Set the secret for the client.
+ *
+ * @param array $secret
+ * @return OpenCloud\OpenStack
+ */
+ public function setSecret(array $secret = array())
+ {
+ $this->secret = $secret;
+
+ return $this;
+ }
+
+ /**
+ * Get the secret.
+ *
+ * @return array
+ */
+ public function getSecret()
+ {
+ return $this->secret;
+ }
+
+ /**
+ * Set the token for this client.
+ *
+ * @param string $token
+ * @return OpenCloud\OpenStack
+ */
+ public function setToken($token)
+ {
+ $this->token = $token;
+
+ return $this;
+ }
+
+ /**
+ * Get the token for this client.
+ *
+ * @return string
+ */
+ public function getToken()
+ {
+ return $this->token;
+ }
+
+ /**
+ * Set the expiration for this token.
+ *
+ * @param int $expiration
+ * @return OpenCloud\OpenStack
+ */
+ public function setExpiration($expiration)
+ {
+ $this->expiration = $expiration;
+
+ return $this;
+ }
+
+ /**
+ * Get the expiration time.
+ *
+ * @return int
+ */
+ public function getExpiration()
+ {
+ return $this->expiration;
+ }
+
+ /**
+ * Set the tenant for this client.
+ *
+ * @param string $tenant
+ * @return OpenCloud\OpenStack
+ */
+ public function setTenant($tenant)
+ {
+ $this->tenant = $tenant;
+
+ return $this;
+ }
+
+ /**
+ * Get the tenant for this client.
+ *
+ * @return string
+ */
+ public function getTenant()
+ {
+ return $this->tenant;
+ }
+
+ /**
+ * Set the service catalog.
+ *
+ * @param mixed $catalog
+ * @return OpenCloud\OpenStack
+ */
+ public function setCatalog($catalog)
+ {
+ $this->catalog = $catalog;
+
+ return $this;
+ }
+
+ /**
+ * Get the service catalog.
+ *
+ * @return array
+ */
+ public function getCatalog()
+ {
+ return $this->catalog;
+ }
+
+ /**
+ * Set (all) the cURL options.
+ *
+ * @param array $options
+ * @return OpenCloud\OpenStack
+ */
+ public function setCurlOptions(array $options)
+ {
+ $this->curlOptions = $options;
+
+ return $this;
+ }
+
+ /**
+ * Get the cURL options.
+ *
+ * @return array
+ */
+ public function getCurlOptions()
+ {
+ return $this->curlOptions;
+ }
+
+ /**
+ * Set a specific file descriptor (associated with a URL)
+ *
+ * @param string $key
+ * @param resource $value
+ * @return OpenCloud\OpenStack
+ */
+ public function setFileDescriptor($key, $value)
+ {
+ $this->descriptors[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get a specific file descriptor (associated with a URL)
+ *
+ * @param string $key
+ * @return resource|false
+ */
+ public function getFileDescriptor($key)
+ {
+ return (!isset($this->descriptors[$key])) ? false : $this->descriptors[$key];
+ }
+
+ /**
+ * Get the items to be exported.
+ *
+ * @return array
+ */
+ public function getExportItems()
+ {
+ return $this->exportItems;
+ }
+
+ /**
+ * Sets the connect timeout.
+ *
+ * @param int $timeout
+ * @return OpenCloud\OpenStack
+ */
+ public function setConnectTimeout($timeout)
+ {
+ $this->connectTimeout = $timeout;
+
+ return $this;
+ }
+
+ /**
+ * Get the connect timeout.
+ *
+ * @return int
+ */
+ public function getConnectTimeout()
+ {
+ return $this->connectTimeout;
+ }
+
+ /**
+ * Set the HTTP timeout.
+ *
+ * @param int $timeout
+ * @return OpenCloud\OpenStack
+ */
+ public function setHttpTimeout($timeout)
+ {
+ $this->httpTimeout = $timeout;
+
+ return $this;
+ }
+
+ /**
+ * Get the HTTP timeout.
+ *
+ * @return int
+ */
+ public function getHttpTimeout()
+ {
+ return $this->httpTimeout;
+ }
+
+ /**
+ * Set the overlimit timeout.
+ *
+ * @param int $timeout
+ * @return OpenCloud\OpenStack
+ */
+ public function setOverlimitTimeout($timeout)
+ {
+ $this->overlimitTimeout = $timeout;
+
+ return $this;
+ }
+
+ /**
+ * Get the overlimit timeout.
+ *
+ * @return int
+ */
+ public function getOverlimitTimeout()
+ {
+ return $this->overlimitTimeout;
+ }
+
+ /**
+ * Sets default values (an array) for a service. Each array must contain a
+ * "name", "region" and "urltype" key.
+ *
+ * @param string $service
+ * @param array $value
+ * @return OpenCloud\OpenStack
+ */
+ public function setDefault($service, array $value = array())
+ {
+ if (isset($value['name']) && isset($value['region']) && isset($value['urltype'])) {
+ $this->defaults[$service] = $value;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get a specific default value for a service. If none exist, return FALSE.
+ *
+ * @param string $service
+ * @return array|false
+ */
+ public function getDefault($service)
+ {
+ return (!isset($this->defaults[$service])) ? false : $this->defaults[$service];
+ }
+
+/**
+ * Sets the timeouts for the current connection
+ *
+ * @api
+ * @param integer $t_http the HTTP timeout value (the max period that
+ * the OpenStack object will wait for any HTTP request to complete).
+ * Value is in seconds.
+ * @param integer $t_conn the Connect timeout value (the max period
+ * that the OpenStack object will wait to establish an HTTP
+ * connection). Value is in seconds.
+ * @param integer $t_overlimit the overlimit timeout value (the max period
+ * that the OpenStack object will wait to retry on an overlimit
+ * condition). Value is in seconds.
+ * @return void
+ */
+ public function setTimeouts($httpTimeout, $connectTimeout = null, $overlimitTimeout = null)
+ {
+ $this->setHttpTimeout($httpTimeout);
+
+ if (isset($connectTimeout)) {
+ $this->setConnectTimeout($connectTimeout);
+ }
+
+ if (isset($overlimitTimeout)) {
+ $this->setOverlimitTimeout($overlimitTimeout);
+ }
+ }
+
+ /**
+ * Returns the URL of this object
+ *
+ * @api
+ * @param string $subresource specified subresource
+ * @return string
+ */
+ public function url($subresource='tokens')
+ {
+ return Lang::noslash($this->url) . '/' . $subresource;
+ }
+
+ /**
+ * Returns the stored secret
+ *
+ * @return array
+ */
+ public function secret()
+ {
+ return $this->getSecret();
+ }
+
+ /**
+ * Re-authenticates session if expired.
+ */
+ public function checkExpiration()
+ {
+ if ($this->hasExpired()) {
+ $this->authenticate();
+ }
+ }
+
+ /**
+ * Checks whether token has expired.
+ *
+ * @return bool
+ */
+ public function hasExpired()
+ {
+ return time() > ($this->getExpiration() - RAXSDK_FUDGE);
+ }
+
+ /**
+ * Returns the cached token; if it has expired, then it re-authenticates
+ *
+ * @api
+ * @return string
+ */
+ public function token()
+ {
+ $this->checkExpiration();
+
+ return $this->getToken();
+ }
+
+ /**
+ * Returns the cached expiration time;
+ * if it has expired, then it re-authenticates
+ *
+ * @api
+ * @return string
+ */
+ public function expiration()
+ {
+ $this->checkExpiration();
+
+ return $this->getExpiration();
+ }
+
+ /**
+ * Returns the tenant ID, re-authenticating if necessary
+ *
+ * @api
+ * @return string
+ */
+ public function tenant()
+ {
+ $this->checkExpiration();
+
+ return $this->getTenant();
+ }
+
+ /**
+ * Returns the service catalog object from the auth service
+ *
+ * @return \stdClass
+ */
+ public function serviceCatalog()
+ {
+ $this->checkExpiration();
+
+ return $this->getCatalog();
+ }
+
+ /**
+ * Returns a Collection of objects with information on services
+ *
+ * Note that these are informational (read-only) and are not actually
+ * 'Service'-class objects.
+ */
+ public function serviceList()
+ {
+ return new Common\Collection($this, 'ServiceCatalogItem', $this->serviceCatalog());
+ }
+
+ /**
+ * Creates and returns the formatted credentials to POST to the auth
+ * service.
+ *
+ * @return string
+ */
+ public function credentials()
+ {
+ if (isset($this->secret['username']) && isset($this->secret['password'])) {
+
+ $credentials = array(
+ 'auth' => array(
+ 'passwordCredentials' => array(
+ 'username' => $this->secret['username'],
+ 'password' => $this->secret['password']
+ )
+ )
+ );
+
+ if (isset($this->secret['tenantName'])) {
+ $credentials['auth']['tenantName'] = $this->secret['tenantName'];
+ }
+
+ return json_encode($credentials);
+
+ } else {
+ throw new Exceptions\CredentialError(
+ Lang::translate('Unrecognized credential secret')
+ );
+ }
+ }
+
+ /**
+ * Authenticates using the supplied credentials
+ *
+ * @api
+ * @return void
+ * @throws AuthenticationError
+ */
+ public function authenticate()
+ {
+ // try to auth
+ $response = $this->request(
+ $this->url(),
+ 'POST',
+ array('Content-Type'=>'application/json'),
+ $this->credentials()
+ );
+
+ $json = $response->httpBody();
+
+ // check for errors
+ if ($response->HttpStatus() >= 400) {
+ throw new Exceptions\AuthenticationError(sprintf(
+ Lang::translate('Authentication failure, status [%d], response [%s]'),
+ $response->httpStatus(),
+ $json
+ ));
+ }
+
+ // Decode and check
+ $object = json_decode($json);
+ $this->checkJsonError();
+
+ // Save the token information as well as the ServiceCatalog
+ $this->setToken($object->access->token->id);
+ $this->setExpiration(strtotime($object->access->token->expires));
+ $this->setCatalog($object->access->serviceCatalog);
+
+ /**
+ * In some cases, the tenant name/id is not returned
+ * as part of the auth token, so we check for it before
+ * we set it. This occurs with pure Keystone, but not
+ * with the Rackspace auth.
+ */
+ if (isset($object->access->token->tenant)) {
+ $this->setTenant($object->access->token->tenant->id);
+ }
+ }
+
+ /**
+ * Performs a single HTTP request
+ *
+ * The request() method is one of the most frequently-used in the entire
+ * library. It performs an HTTP request using the specified URL, method,
+ * and with the supplied headers and body. It handles error and
+ * exceptions for the request.
+ *
+ * @api
+ * @param string url - the URL of the request
+ * @param string method - the HTTP method (defaults to GET)
+ * @param array headers - an associative array of headers
+ * @param string data - either a string or a resource (file pointer) to
+ * use as the request body (for PUT or POST)
+ * @return HttpResponse object
+ * @throws HttpOverLimitError, HttpUnauthorizedError, HttpForbiddenError
+ */
+ public function request($url, $method = 'GET', $headers = array(), $data = null)
+ {
+ $this->getLogger()->info('Resource [{url}] method [{method}] body [{body}]', array(
+ 'url' => $url,
+ 'method' => $method,
+ 'data' => $data
+ ));
+
+ // get the request object
+ $http = $this->getHttpRequestObject($url, $method, $this->getCurlOptions());
+
+ // set various options
+ $this->getLogger()->info('Headers: [{headers}]', array(
+ 'headers' => print_r($headers, true)
+ ));
+
+ $http->setheaders($headers);
+ $http->setHttpTimeout($this->getHttpTimeout());
+ $http->setConnectTimeout($this->getConnectTimeout());
+ $http->setOption(CURLOPT_USERAGENT, $this->getUserAgent());
+
+ // data can be either a resource or a string
+ if (is_resource($data)) {
+ // loading from or writing to a file
+ // set the appropriate callback functions
+ switch($method) {
+ // @codeCoverageIgnoreStart
+ case 'GET':
+ // need to save the file descriptor
+ $this->setFileDescriptor($url, $data);
+ // set the CURL options
+ $http->setOption(CURLOPT_FILE, $data);
+ $http->setOption(CURLOPT_WRITEFUNCTION, array($this, '_write_cb'));
+ break;
+ // @codeCoverageIgnoreEnd
+ case 'PUT':
+ case 'POST':
+ // need to save the file descriptor
+ $this->setFileDescriptor($url, $data);
+ if (!isset($headers['Content-Length'])) {
+ throw new Exceptions\HttpError(
+ Lang::translate('The Content-Length: header must be specified for file uploads')
+ );
+ }
+ $http->setOption(CURLOPT_UPLOAD, TRUE);
+ $http->setOption(CURLOPT_INFILE, $data);
+ $http->setOption(CURLOPT_INFILESIZE, $headers['Content-Length']);
+ $http->setOption(CURLOPT_READFUNCTION, array($this, '_read_cb'));
+ break;
+ default:
+ // do nothing
+ break;
+ }
+ } elseif (is_string($data)) {
+ $http->setOption(CURLOPT_POSTFIELDS, $data);
+ } elseif (isset($data)) {
+ throw new Exceptions\HttpError(
+ Lang::translate('Unrecognized data type for PUT/POST body, must be string or resource')
+ );
+ }
+
+ // perform the HTTP request; returns an HttpResult object
+ $response = $http->execute();
+
+ // handle and retry on overlimit errors
+ if ($response->httpStatus() == 413) {
+
+ $object = json_decode($response->httpBody());
+ $this->checkJsonError();
+
+ // @codeCoverageIgnoreStart
+ if (isset($object->overLimit)) {
+ /**
+ * @TODO(glen) - The documentation says "retryAt", but
+ * the field returned is "retryAfter". If the doc changes,
+ * then there's no problem, but we'll need to fix this if
+ * they change the code to match the docs.
+ */
+ $retryAfter = $object->overLimit->retryAfter;
+ $sleepInterval = strtotime($retryAfter) - time();
+
+ if ($sleepInterval && $sleepInterval <= $this->getOverlimitTimeout()) {
+ sleep($sleepInterval);
+ $response = $http->Execute();
+ } else {
+ throw new Exceptions\HttpOverLimitError(sprintf(
+ Lang::translate('Over limit; next available request [%s][%s] is not for [%d] seconds at [%s]'),
+ $method,
+ $url,
+ $sleepInterval,
+ $retryAfter
+ ));
+ }
+ }
+ // @codeCoverageIgnoreEnd
+ }
+
+ // do some common error checking
+ switch ($response->httpStatus()) {
+ case 401:
+ throw new Exceptions\HttpUnauthorizedError(sprintf(
+ Lang::translate('401 Unauthorized for [%s] [%s]'),
+ $url,
+ $response->HttpBody()
+ ));
+ break;
+ case 403:
+ throw new Exceptions\HttpForbiddenError(sprintf(
+ Lang::translate('403 Forbidden for [%s] [%s]'),
+ $url,
+ $response->HttpBody()
+ ));
+ break;
+ case 413: // limit
+ throw new Exceptions\HttpOverLimitError(sprintf(
+ Lang::translate('413 Over limit for [%s] [%s]'),
+ $url,
+ $response->HttpBody()
+ ));
+ break;
+ default:
+ // everything is fine here, we're fine, how are you?
+ break;
+ }
+
+ // free the handle
+ $http->close();
+
+ // return the HttpResponse object
+ $this->getLogger()->info('HTTP STATUS [{code}]', array(
+ 'code' => $response->httpStatus()
+ ));
+
+ return $response;
+ }
+
+ /**
+ * Sets default values for name, region, URL type for a service
+ *
+ * Once these are set (and they can also be set by defining global
+ * constants), then you do not need to specify these values when
+ * creating new service objects.
+ *
+ * @api
+ * @param string $service the name of a supported service; e.g. 'Compute'
+ * @param string $name the service name; e.g., 'cloudServersOpenStack'
+ * @param string $region the region name; e.g., 'LON'
+ * @param string $urltype the type of URL to use; e.g., 'internalURL'
+ * @return void
+ * @throws UnrecognizedServiceError
+ */
+ public function setDefaults(
+ $service,
+ $name = null,
+ $region = null,
+ $urltype = null
+ ) {
+
+ if (!isset($this->defaults[$service])) {
+ throw new Exceptions\UnrecognizedServiceError(sprintf(
+ Lang::translate('Service [%s] is not recognized'), $service
+ ));
+ }
+
+ if (isset($name)) {
+ $this->defaults[$service]['name'] = $name;
+ }
+
+ if (isset($region)) {
+ $this->defaults[$service]['region'] = $region;
+ }
+
+ if (isset($urltype)) {
+ $this->defaults[$service]['urltype'] = $urltype;
+ }
+ }
+
+ /**
+ * Allows the user to define a function for tracking uploads
+ *
+ * This can be used to implement a progress bar or similar function. The
+ * callback function is called with a single parameter, the length of the
+ * data that is being uploaded on this call.
+ *
+ * @param callable $callback the name of a global callback function, or an
+ * array($object, $functionname)
+ * @return void
+ */
+ public function setUploadProgressCallback($callback)
+ {
+ $this->_user_write_progress_callback_func = $callback;
+ }
+
+ /**
+ * Allows the user to define a function for tracking downloads
+ *
+ * This can be used to implement a progress bar or similar function. The
+ * callback function is called with a single parameter, the length of the
+ * data that is being downloaded on this call.
+ *
+ * @param callable $callback the name of a global callback function, or an
+ * array($object, $functionname)
+ * @return void
+ */
+ public function setDownloadProgressCallback($callback)
+ {
+ $this->_user_read_progress_callback_func = $callback;
+ }
+
+ /**
+ * Callback function to handle reads for file uploads
+ *
+ * Internal function for handling file uploads. Note that, although this
+ * function's visibility is public, this is only because it must be called
+ * from the HttpRequest interface. This should NOT be called by users
+ * directly.
+ *
+ * @param resource $ch a CURL handle
+ * @param resource $fd a file descriptor
+ * @param integer $length the amount of data to read
+ * @return string the data read
+ * @codeCoverageIgnore
+ */
+ public function _read_cb($ch, $fd, $length)
+ {
+ $data = fread($fd, $length);
+ $len = strlen($data);
+ if (isset($this->_user_write_progress_callback_func)) {
+ call_user_func($this->_user_write_progress_callback_func, $len);
+ }
+ return $data;
+ }
+
+ /**
+ * Callback function to handle writes for file downloads
+ *
+ * Internal function for handling file downloads. Note that, although this
+ * function's visibility is public, this is only because it must be called
+ * via the HttpRequest interface. This should NOT be called by users
+ * directly.
+ *
+ * @param resource $ch a CURL handle
+ * @param string $data the data to be written to a file
+ * @return integer the number of bytes written
+ * @codeCoverageIgnore
+ */
+ public function _write_cb($ch, $data)
+ {
+ $url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
+
+ if (false === ($fp = $this->getFileDescriptor($url))) {
+ throw new Exceptions\HttpUrlError(sprintf(
+ Lang::translate('Cannot find file descriptor for URL [%s]'), $url)
+ );
+ }
+
+ $dlen = strlen($data);
+ fwrite($fp, $data, $dlen);
+
+ // call used callback function
+ if (isset($this->_user_read_progress_callback_func)) {
+ call_user_func($this->_user_read_progress_callback_func, $dlen);
+ }
+
+ // MUST return the length to CURL
+ return $dlen;
+ }
+
+ /**
+ * exports saved token, expiration, tenant, and service catalog as an array
+ *
+ * This could be stored in a cache (APC or disk file) and reloaded using
+ * ImportCredentials()
+ *
+ * @return array
+ */
+ public function exportCredentials()
+ {
+ $this->authenticate();
+
+ $array = array();
+
+ foreach ($this->getExportItems() as $key) {
+ $array[$key] = $this->$key;
+ }
+
+ return $array;
+ }
+
+ /**
+ * imports credentials from an array
+ *
+ * Takes the same values as ExportCredentials() and reuses them.
+ *
+ * @return void
+ */
+ public function importCredentials(array $values)
+ {
+ foreach ($this->getExportItems() as $item) {
+ $this->$item = $values[$item];
+ }
+ }
+
+ /********** FACTORY METHODS **********
+ *
+ * These methods are provided to permit easy creation of services
+ * (for example, Nova or Swift) from a connection object. As new
+ * services are supported, factory methods should be provided here.
+ */
+
+ /**
+ * Creates a new ObjectStore object (Swift/Cloud Files)
+ *
+ * @api
+ * @param string $name the name of the Object Storage service to attach to
+ * @param string $region the name of the region to use
+ * @param string $urltype the URL type (normally "publicURL")
+ * @return ObjectStore
+ */
+ public function objectStore($name = null, $region = null, $urltype = null)
+ {
+ return $this->service('ObjectStore', $name, $region, $urltype);
+ }
+
+ /**
+ * Creates a new Compute object (Nova/Cloud Servers)
+ *
+ * @api
+ * @param string $name the name of the Compute service to attach to
+ * @param string $region the name of the region to use
+ * @param string $urltype the URL type (normally "publicURL")
+ * @return Compute
+ */
+ public function compute($name = null, $region = null, $urltype = null)
+ {
+ return $this->service('Compute', $name, $region, $urltype);
+ }
+
+ /**
+ * Creates a new Orchestration (heat) service object
+ *
+ * @api
+ * @param string $name the name of the Compute service to attach to
+ * @param string $region the name of the region to use
+ * @param string $urltype the URL type (normally "publicURL")
+ * @return Orchestration\Service
+ * @codeCoverageIgnore
+ */
+ public function orchestration($name = null, $region = null, $urltype = null)
+ {
+ return $this->service('Orchestration', $name, $region, $urltype);
+ }
+
+ /**
+ * Creates a new VolumeService (cinder) service object
+ *
+ * This is a factory method that is Rackspace-only (NOT part of OpenStack).
+ *
+ * @param string $name the name of the service (e.g., 'cloudBlockStorage')
+ * @param string $region the region (e.g., 'DFW')
+ * @param string $urltype the type of URL (e.g., 'publicURL');
+ */
+ public function volumeService($name = null, $region = null, $urltype = null)
+ {
+ return $this->service('Volume', $name, $region, $urltype);
+ }
+
+ /**
+ * Generic Service factory method
+ *
+ * Contains code reused by the other service factory methods.
+ *
+ * @param string $class the name of the Service class to produce
+ * @param string $name the name of the Compute service to attach to
+ * @param string $region the name of the region to use
+ * @param string $urltype the URL type (normally "publicURL")
+ * @return Service (or subclass such as Compute, ObjectStore)
+ * @throws ServiceValueError
+ */
+ public function service($class, $name = null, $region = null, $urltype = null)
+ {
+ // debug message
+ $this->getLogger()->info('Factory for class [{class}] [{name}/{region}/{urlType}]', array(
+ 'class' => $class,
+ 'name' => $name,
+ 'region' => $region,
+ 'urlType' => $urltype
+ ));
+
+ // Strips off base namespace
+ $class = preg_replace('#\\\?OpenCloud\\\#', '', $class);
+
+ // check for defaults
+ $default = $this->getDefault($class);
+
+ // report errors
+ if (!$name = $name ?: $default['name']) {
+ throw new Exceptions\ServiceValueError(sprintf(
+ Lang::translate('No value for %s name'),
+ $class
+ ));
+ }
+
+ if (!$region = $region ?: $default['region']) {
+ throw new Exceptions\ServiceValueError(sprintf(
+ Lang::translate('No value for %s region'),
+ $class
+ ));
+ }
+
+ if (!$urltype = $urltype ?: $default['urltype']) {
+ throw new Exceptions\ServiceValueError(sprintf(
+ Lang::translate('No value for %s URL type'),
+ $class
+ ));
+ }
+
+ // return the object
+ $fullclass = 'OpenCloud\\' . $class . '\\Service';
+
+ return new $fullclass($this, $name, $region, $urltype);
+ }
+
+ /**
+ * returns a service catalog item
+ *
+ * This is a helper function used to list service catalog items easily
+ */
+ public function serviceCatalogItem($info = array())
+ {
+ return new ServiceCatalogItem($info);
+ }
+
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Rackspace.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Rackspace.php
new file mode 100644
index 00000000000..41be608b347
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Rackspace.php
@@ -0,0 +1,132 @@
+<?php
+/**
+ * The Rackspace cloud/connection class (which uses different authentication
+ * than the pure OpenStack class)
+ *
+ * @copyright 2012-2013 Rackspace Hosting, Inc.
+ * See COPYING for licensing information
+ *
+ * @package phpOpenCloud
+ * @version 1.0
+ * @author Glen Campbell <glen.campbell@rackspace.com>
+ */
+
+namespace OpenCloud;
+
+/**
+ * Rackspace extends the OpenStack class with support for Rackspace's
+ * API key and tenant requirements.
+ *
+ * The only difference between Rackspace and OpenStack is that the
+ * Rackspace class generates credentials using the username
+ * and API key, as required by the Rackspace authentication
+ * service.
+ *
+ * Example:
+ * <code>
+ * $username = 'FRED';
+ * $apiKey = '0900af093093788912388fc09dde090ffee09';
+ * $conn = new Rackspace(
+ * 'https://identity.api.rackspacecloud.com/v2.0/',
+ * array(
+ * 'username' => $username,
+ * 'apiKey' => $apiKey
+ * ));
+ * </code>
+ */
+class Rackspace extends OpenStack
+{
+
+ //this is the JSON string for our new credentials
+const APIKEYTEMPLATE = <<<ENDCRED
+{ "auth": { "RAX-KSKEY:apiKeyCredentials": { "username": "%s",
+ "apiKey": "%s"
+ }
+ }
+}
+ENDCRED;
+
+ /**
+ * Generates Rackspace API key credentials
+ *
+ * @return string
+ */
+ public function Credentials()
+ {
+ $sec = $this->Secret();
+ if (isset($sec['username'])
+ && isset($sec['apiKey'])
+ ) {
+ return sprintf(
+ self::APIKEYTEMPLATE,
+ $sec['username'],
+ $sec['apiKey']
+ );
+ } else {
+ return parent::Credentials();
+ }
+ }
+
+ /**
+ * Creates a new DbService (Database as a Service) object
+ *
+ * This is a factory method that is Rackspace-only (NOT part of OpenStack).
+ *
+ * @param string $name the name of the service (e.g., 'Cloud Databases')
+ * @param string $region the region (e.g., 'DFW')
+ * @param string $urltype the type of URL (e.g., 'publicURL');
+ */
+ public function DbService($name = null, $region = null, $urltype = null)
+ {
+ return $this->Service('Database', $name, $region, $urltype);
+ }
+
+ /**
+ * Creates a new LoadBalancerService object
+ *
+ * This is a factory method that is Rackspace-only (NOT part of OpenStack).
+ *
+ * @param string $name the name of the service
+ * (e.g., 'Cloud Load Balancers')
+ * @param string $region the region (e.g., 'DFW')
+ * @param string $urltype the type of URL (e.g., 'publicURL');
+ */
+ public function LoadBalancerService($name = null, $region = null, $urltype = null)
+ {
+ return $this->Service('LoadBalancer', $name, $region, $urltype);
+ }
+
+ /**
+ * creates a new DNS service object
+ *
+ * This is a factory method that is currently Rackspace-only
+ * (not available via the OpenStack class)
+ */
+ public function DNS($name = null, $region = null, $urltype = null)
+ {
+ return $this->Service('DNS', $name, $region, $urltype);
+ }
+
+ /**
+ * creates a new CloudMonitoring service object
+ *
+ * This is a factory method that is currently Rackspace-only
+ * (not available via the OpenStack class)
+ */
+ public function CloudMonitoring($name=null, $region=null, $urltype=null)
+ {
+ return $this->Service('CloudMonitoring', $name, $region, $urltype);
+ }
+
+ /**
+ * creates a new Autoscale service object
+ *
+ * This is a factory method that is currently Rackspace-only
+ * (not available via the OpenStack class)
+ */
+ public function Autoscale($name=null, $region=null, $urltype=null)
+ {
+ return $this->Service('Autoscale', $name, $region, $urltype);
+ }
+
+}
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/openstack.php b/apps/files_external/3rdparty/php-opencloud/lib/openstack.php
new file mode 100644
index 00000000000..738902d244e
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/openstack.php
@@ -0,0 +1,8 @@
+<?php
+/**
+ * provided for backwards compatibility
+ *
+ * @copyright 2013 Rackspace Hosting, Inc.
+ * @license http://www.apache.org/licenses/LICENSE-2.0
+ */
+require_once __DIR__.'/php-opencloud.php';
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/php-opencloud.php b/apps/files_external/3rdparty/php-opencloud/lib/php-opencloud.php
new file mode 100644
index 00000000000..15ff034b92d
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/php-opencloud.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * entry point for PHP-OpenCloud library
+ *
+ * @copyright 2013 Rackspace Hosting, Inc.
+ * @license http://www.apache.org/licenses/LICENSE-2.0
+ */
+require_once(__DIR__ . '/Autoload.php');
+require_once(__DIR__ . '/OpenCloud/Globals.php');
+
+$classLoader = new ClassLoader;
+$classLoader->registerNamespaces(array(
+ 'OpenCloud' => array(__DIR__, __DIR__ . '/../tests')
+));
+$classLoader->register(); \ No newline at end of file
diff --git a/apps/files_external/3rdparty/php-opencloud/lib/rackspace.php b/apps/files_external/3rdparty/php-opencloud/lib/rackspace.php
new file mode 100644
index 00000000000..738902d244e
--- /dev/null
+++ b/apps/files_external/3rdparty/php-opencloud/lib/rackspace.php
@@ -0,0 +1,8 @@
+<?php
+/**
+ * provided for backwards compatibility
+ *
+ * @copyright 2013 Rackspace Hosting, Inc.
+ * @license http://www.apache.org/licenses/LICENSE-2.0
+ */
+require_once __DIR__.'/php-opencloud.php';
diff --git a/apps/files_external/3rdparty/smb4php/smb.php b/apps/files_external/3rdparty/smb4php/smb.php
index e7d1dfa09fe..622942b052a 100644
--- a/apps/files_external/3rdparty/smb4php/smb.php
+++ b/apps/files_external/3rdparty/smb4php/smb.php
@@ -19,6 +19,10 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
+# Addition 17/12/2012 Frank Karlitschek (frank@owncloud.org)
+# On the official website http://www.phpclasses.org/smb4php the
+# license is listed as LGPL so we assume that this is
+# dual-licensed GPL/LGPL
###################################################################
define ('SMB4PHP_VERSION', '0.8');
@@ -126,7 +130,8 @@ class smb {
// this put env is necessary to read the output of smbclient correctly
$old_locale = getenv('LC_ALL');
putenv('LC_ALL=en_US.UTF-8');
- $output = popen (SMB4PHP_SMBCLIENT." -N {$auth} {$options} {$port} {$options} {$params} 2>/dev/null", 'r');
+ $output = popen ('TZ=UTC '.SMB4PHP_SMBCLIENT." -N {$auth} {$options} {$port} {$options} {$params} 2>/dev/null", 'r');
+ $gotInfo = false;
$info = array ();
$info['info']= array ();
$mode = '';
@@ -159,7 +164,7 @@ class smb {
$i = ($mode == 'servers') ? array ($name, "server") : array ($name, "workgroup", $master);
break;
case 'files':
- list ($attr, $name) = preg_match ("/^(.*)[ ]+([D|A|H|S|R]+)$/", trim ($regs[1]), $regs2)
+ list ($attr, $name) = preg_match ("/^(.*)[ ]+([D|A|H|N|S|R]+)$/", trim ($regs[1]), $regs2)
? array (trim ($regs2[2]), trim ($regs2[1]))
: array ('', trim ($regs[1]));
list ($his, $im) = array (
@@ -181,12 +186,19 @@ class smb {
return false;
}elseif(substr($regs[0],0,31)=='NT_STATUS_OBJECT_PATH_NOT_FOUND'){
return false;
+ }elseif(substr($regs[0],0,31)=='NT_STATUS_OBJECT_NAME_NOT_FOUND'){
+ return false;
}elseif(substr($regs[0],0,29)=='NT_STATUS_FILE_IS_A_DIRECTORY'){
return false;
}
trigger_error($regs[0].' params('.$params.')', E_USER_ERROR);
case 'error-connect':
- return false;
+ // connection error can happen after obtaining share list if
+ // NetBIOS is disabled/blocked on the target server,
+ // in which case we keep the info and continue
+ if (!$gotInfo) {
+ return false;
+ }
}
if ($i) switch ($i[1]) {
case 'file':
@@ -194,6 +206,7 @@ class smb {
case 'disk':
case 'server':
case 'workgroup': $info[$i[1]][] = $i[0];
+ $gotInfo = true;
}
}
pclose($output);
@@ -293,6 +306,7 @@ class smb {
}
function rename ($url_from, $url_to) {
+ $replace = false;
list ($from, $to) = array (smb::parse_url($url_from), smb::parse_url($url_to));
if ($from['host'] <> $to['host'] ||
$from['share'] <> $to['share'] ||
@@ -305,7 +319,21 @@ class smb {
trigger_error('rename(): error in URL', E_USER_ERROR);
}
smb::clearstatcache ($url_from);
- return smb::execute ('rename "'.$from['path'].'" "'.$to['path'].'"', $to);
+ $cmd = '';
+ // check if target file exists
+ if (smb::url_stat($url_to)) {
+ // delete target file first
+ $cmd = 'del "' . $to['path'] . '"; ';
+ $replace = true;
+ }
+ $cmd .= 'rename "' . $from['path'] . '" "' . $to['path'] . '"';
+ $result = smb::execute($cmd, $to);
+ if ($replace) {
+ // clear again, else the cache will return the info
+ // from the old file
+ smb::clearstatcache ($url_to);
+ }
+ return $result !== false;
}
function mkdir ($url, $mode, $options) {
@@ -430,7 +458,10 @@ class smb_stream_wrapper extends smb {
case 'rb':
case 'a':
case 'a+': $this->tmpfile = tempnam('/tmp', 'smb.down.');
- smb::execute ('get "'.$pu['path'].'" "'.$this->tmpfile.'"', $pu);
+ $result = smb::execute ('get "'.$pu['path'].'" "'.$this->tmpfile.'"', $pu);
+ if($result === false){
+ return $result;
+ }
break;
case 'w':
case 'w+':
@@ -454,7 +485,8 @@ class smb_stream_wrapper extends smb {
function stream_tell () { return ftell($this->stream); }
- function stream_seek ($offset, $whence=null) { return fseek($this->stream, $offset, $whence); }
+ // PATCH: the wrapper must return true when fseek succeeded by returning 0.
+ function stream_seek ($offset, $whence=null) { return fseek($this->stream, $offset, $whence) === 0; }
function stream_flush () {
if ($this->mode <> 'r' && $this->need_flush) {
diff --git a/apps/files_external/ajax/dropbox.php b/apps/files_external/ajax/dropbox.php
index bc9821c62ec..91c465500d0 100644
--- a/apps/files_external/ajax/dropbox.php
+++ b/apps/files_external/ajax/dropbox.php
@@ -1,6 +1,6 @@
<?php
-require_once 'Dropbox/autoload.php';
+require_once __DIR__ . '/../3rdparty/Dropbox/autoload.php';
OCP\JSON::checkAppEnabled('files_external');
OCP\JSON::checkLoggedIn();
diff --git a/apps/files_external/appinfo/app.php b/apps/files_external/appinfo/app.php
index dd0b76ed9d7..5b1cd86a170 100644
--- a/apps/files_external/appinfo/app.php
+++ b/apps/files_external/appinfo/app.php
@@ -9,8 +9,9 @@
OC::$CLASSPATH['OC\Files\Storage\StreamWrapper'] = 'files_external/lib/streamwrapper.php';
OC::$CLASSPATH['OC\Files\Storage\FTP'] = 'files_external/lib/ftp.php';
OC::$CLASSPATH['OC\Files\Storage\DAV'] = 'files_external/lib/webdav.php';
+OC::$CLASSPATH['OC\Files\Storage\OwnCloud'] = 'files_external/lib/owncloud.php';
OC::$CLASSPATH['OC\Files\Storage\Google'] = 'files_external/lib/google.php';
-OC::$CLASSPATH['OC\Files\Storage\SWIFT'] = 'files_external/lib/swift.php';
+OC::$CLASSPATH['OC\Files\Storage\Swift'] = 'files_external/lib/swift.php';
OC::$CLASSPATH['OC\Files\Storage\SMB'] = 'files_external/lib/smb.php';
OC::$CLASSPATH['OC\Files\Storage\AmazonS3'] = 'files_external/lib/amazons3.php';
OC::$CLASSPATH['OC\Files\Storage\Dropbox'] = 'files_external/lib/dropbox.php';
diff --git a/apps/files_external/css/settings.css b/apps/files_external/css/settings.css
index 4a32ac4153f..11aeb10184b 100644
--- a/apps/files_external/css/settings.css
+++ b/apps/files_external/css/settings.css
@@ -4,7 +4,6 @@ td.status > span {
width: 16px;
vertical-align: text-bottom;
}
-
span.success {
background: #37ce02;
border-radius: 8px;
@@ -12,9 +11,6 @@ span.success {
span.error {
background: #ce3702;
}
-span.waiting {
- background: none;
-}
td.mountPoint, td.backend { width:160px; }
td.remove>img { visibility:hidden; padding-top:13px; }
@@ -22,3 +18,7 @@ tr:hover>td.remove>img { visibility:visible; cursor:pointer; }
#addMountPoint>td { border:none; }
#addMountPoint>td.applicable { visibility:hidden; }
#selectBackend { margin-left:-10px; }
+
+#externalStorage label > input[type="checkbox"] {
+ margin-right: 3px;
+}
diff --git a/apps/files_external/js/dropbox.js b/apps/files_external/js/dropbox.js
index 957daeb4d1f..6baaabe11b6 100644
--- a/apps/files_external/js/dropbox.js
+++ b/apps/files_external/js/dropbox.js
@@ -23,9 +23,12 @@ $(document).ready(function() {
$(token).val(result.access_token);
$(token_secret).val(result.access_token_secret);
$(configured).val('true');
- OC.MountConfig.saveStorage(tr);
- $(tr).find('.configuration input').attr('disabled', 'disabled');
- $(tr).find('.configuration').append('<span id="access" style="padding-left:0.5em;">'+t('files_external', 'Access granted')+'</span>');
+ OC.MountConfig.saveStorage(tr, function(status) {
+ if (status) {
+ $(tr).find('.configuration input').attr('disabled', 'disabled');
+ $(tr).find('.configuration').append('<span id="access" style="padding-left:0.5em;">'+t('files_external', 'Access granted')+'</span>');
+ }
+ });
} else {
OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Dropbox storage'));
}
@@ -77,7 +80,6 @@ $(document).ready(function() {
var tr = $(this).parent().parent();
var app_key = $(this).parent().find('[data-parameter="app_key"]').val();
var app_secret = $(this).parent().find('[data-parameter="app_secret"]').val();
- var statusSpan = $(tr).find('.status span');
if (app_key != '' && app_secret != '') {
var tr = $(this).parent().parent();
var configured = $(this).parent().find('[data-parameter="configured"]');
@@ -88,10 +90,9 @@ $(document).ready(function() {
$(configured).val('false');
$(token).val(result.data.request_token);
$(token_secret).val(result.data.request_token_secret);
- OC.MountConfig.saveStorage(tr);
- statusSpan.removeClass();
- statusSpan.addClass('waiting');
- window.location = result.data.url;
+ OC.MountConfig.saveStorage(tr, function() {
+ window.location = result.data.url;
+ });
} else {
OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Dropbox storage'));
}
diff --git a/apps/files_external/js/google.js b/apps/files_external/js/google.js
index b4be1c1dc41..068c2c13c66 100644
--- a/apps/files_external/js/google.js
+++ b/apps/files_external/js/google.js
@@ -32,11 +32,14 @@ $(document).ready(function() {
if (result && result.status == 'success') {
$(token).val(result.data.token);
$(configured).val('true');
- OC.MountConfig.saveStorage(tr);
- $(tr).find('.configuration input').attr('disabled', 'disabled');
- $(tr).find('.configuration').append($('<span/>')
- .attr('id', 'access')
- .text(t('files_external', 'Access granted')));
+ OC.MountConfig.saveStorage(tr, function(status) {
+ if (status) {
+ $(tr).find('.configuration input').attr('disabled', 'disabled');
+ $(tr).find('.configuration').append($('<span/>')
+ .attr('id', 'access')
+ .text(t('files_external', 'Access granted')));
+ }
+ });
} else {
OC.dialogs.alert(result.data.message,
t('files_external', 'Error configuring Google Drive storage')
@@ -99,7 +102,6 @@ $(document).ready(function() {
var configured = $(this).parent().find('[data-parameter="configured"]');
var client_id = $(this).parent().find('[data-parameter="client_id"]').val();
var client_secret = $(this).parent().find('[data-parameter="client_secret"]').val();
- var statusSpan = $(tr).find('.status span');
if (client_id != '' && client_secret != '') {
var token = $(this).parent().find('[data-parameter="token"]');
$.post(OC.filePath('files_external', 'ajax', 'google.php'),
@@ -112,10 +114,9 @@ $(document).ready(function() {
if (result && result.status == 'success') {
$(configured).val('false');
$(token).val('false');
- OC.MountConfig.saveStorage(tr);
- statusSpan.removeClass();
- statusSpan.addClass('waiting');
- window.location = result.data.url;
+ OC.MountConfig.saveStorage(tr, function(status) {
+ window.location = result.data.url;
+ });
} else {
OC.dialogs.alert(result.data.message,
t('files_external', 'Error configuring Google Drive storage')
diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js
index 3e605c59a93..895f97bd2c3 100644
--- a/apps/files_external/js/settings.js
+++ b/apps/files_external/js/settings.js
@@ -1,10 +1,23 @@
+(function(){
+
+function updateStatus(statusEl, result){
+ statusEl.removeClass('success error loading-small');
+ if (result && result.status == 'success' && result.data.message) {
+ statusEl.addClass('success');
+ return true;
+ } else {
+ statusEl.addClass('error');
+ return false;
+ }
+}
+
OC.MountConfig={
- saveStorage:function(tr) {
+ saveStorage:function(tr, callback) {
var mountPoint = $(tr).find('.mountPoint input').val();
if (mountPoint == '') {
return false;
}
- var statusSpan = $(tr).find('.status span');
+ var statusSpan = $(tr).closest('tr').find('.status span');
var backendClass = $(tr).find('.backend').data('class');
var configuration = $(tr).find('.configuration input');
var addMountPoint = true;
@@ -58,6 +71,7 @@ OC.MountConfig={
}
users.push(applicable);
}
+ statusSpan.addClass('loading-small').removeClass('error success');
$.ajax({type: 'POST',
url: OC.filePath('files_external', 'ajax', 'addMountPoint.php'),
data: {
@@ -68,14 +82,16 @@ OC.MountConfig={
applicable: applicable,
isPersonal: isPersonal
},
- async: false,
success: function(result) {
- statusSpan.removeClass();
- if (result && result.status == 'success' && result.data.message) {
- status = true;
- statusSpan.addClass('success');
- } else {
- statusSpan.addClass('error');
+ status = updateStatus(statusSpan, result);
+ if (callback) {
+ callback(status);
+ }
+ },
+ error: function(result){
+ status = updateStatus(statusSpan, result);
+ if (callback) {
+ callback(status);
}
}
});
@@ -93,8 +109,7 @@ OC.MountConfig={
mountType: mountType,
applicable: applicable,
isPersonal: isPersonal
- },
- async: false
+ }
});
});
var mountType = 'user';
@@ -108,14 +123,14 @@ OC.MountConfig={
mountType: mountType,
applicable: applicable,
isPersonal: isPersonal
- },
- async: false
+ }
});
});
} else {
var isPersonal = true;
var mountType = 'user';
var applicable = OC.currentUser;
+ statusSpan.addClass('loading-small').removeClass('error success');
$.ajax({type: 'POST',
url: OC.filePath('files_external', 'ajax', 'addMountPoint.php'),
data: {
@@ -126,14 +141,16 @@ OC.MountConfig={
applicable: applicable,
isPersonal: isPersonal
},
- async: false,
success: function(result) {
- statusSpan.removeClass();
- if (result && result.status == 'success' && result.data.message) {
- status = true;
- statusSpan.addClass('success');
- } else {
- statusSpan.addClass('error');
+ status = updateStatus(statusSpan, result);
+ if (callback) {
+ callback(status);
+ }
+ },
+ error: function(result){
+ status = updateStatus(statusSpan, result);
+ if (callback) {
+ callback(status);
}
}
});
@@ -157,7 +174,7 @@ $(document).ready(function() {
$(tr).find('.mountPoint input').val(suggestMountPoint(selected));
}
$(tr).addClass(backendClass);
- $(tr).find('.status').append('<span class="waiting"></span>');
+ $(tr).find('.status').append('<span></span>');
$(tr).find('.backend').data('class', backendClass);
var configurations = $(this).data('configurations');
var td = $(tr).find('td.configuration');
@@ -293,3 +310,5 @@ $(document).ready(function() {
});
});
+
+})();
diff --git a/apps/files_external/l10n/ar.php b/apps/files_external/l10n/ar.php
index 905d221e886..338526d2afd 100644
--- a/apps/files_external/l10n/ar.php
+++ b/apps/files_external/l10n/ar.php
@@ -1,5 +1,8 @@
<?php
$TRANSLATIONS = array(
+"Folder name" => "اسم المجلد",
+"Options" => "خيارات",
+"All Users" => "كل المستخدمين",
"Groups" => "مجموعات",
"Users" => "المستخدمين",
"Delete" => "إلغاء"
diff --git a/apps/files_external/l10n/es_MX.php b/apps/files_external/l10n/es_MX.php
new file mode 100644
index 00000000000..b508df8476a
--- /dev/null
+++ b/apps/files_external/l10n/es_MX.php
@@ -0,0 +1,28 @@
+<?php
+$TRANSLATIONS = array(
+"Access granted" => "Acceso concedido",
+"Error configuring Dropbox storage" => "Error configurando el almacenamiento de Dropbox",
+"Grant access" => "Conceder acceso",
+"Please provide a valid Dropbox app key and secret." => "Por favor, proporcione un una clave válida de la app Dropbox y una clave secreta.",
+"Error configuring Google Drive storage" => "Error configurando el almacenamiento de Google Drive",
+"<b>Warning:</b> \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "<b>Advertencia:</b> El cliente \"smbclient\" no se encuentra instalado. El montado de carpetas CIFS/SMB no es posible. Por favor pida al administrador de su sistema que lo instale.",
+"<b>Warning:</b> The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "<b>Advertencia:</b> El soporte de FTP en PHP no se encuentra instalado. El montado de carpetas FTP no es posible. Por favor pida al administrador de su sistema que lo instale.",
+"<b>Warning:</b> The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "<b>Advertencia:</b> El soporte de Curl en PHP no está activado ni instalado. El montado de ownCloud, WebDAV o GoogleDrive no es posible. Pida al administrador de su sistema que lo instale.",
+"External Storage" => "Almacenamiento externo",
+"Folder name" => "Nombre de la carpeta",
+"External storage" => "Almacenamiento externo",
+"Configuration" => "Configuración",
+"Options" => "Opciones",
+"Applicable" => "Aplicable",
+"Add storage" => "Añadir almacenamiento",
+"None set" => "No se ha configurado",
+"All Users" => "Todos los usuarios",
+"Groups" => "Grupos",
+"Users" => "Usuarios",
+"Delete" => "Eliminar",
+"Enable User External Storage" => "Habilitar almacenamiento externo de usuario",
+"Allow users to mount their own external storage" => "Permitir a los usuarios montar su propio almacenamiento externo",
+"SSL root certificates" => "Certificados raíz SSL",
+"Import Root Certificate" => "Importar certificado raíz"
+);
+$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
diff --git a/apps/files_external/l10n/km.php b/apps/files_external/l10n/km.php
new file mode 100644
index 00000000000..f7d9faa38c5
--- /dev/null
+++ b/apps/files_external/l10n/km.php
@@ -0,0 +1,5 @@
+<?php
+$TRANSLATIONS = array(
+"Delete" => "លុប"
+);
+$PLURAL_FORMS = "nplurals=1; plural=0;";
diff --git a/apps/files_external/l10n/sk.php b/apps/files_external/l10n/sk.php
new file mode 100644
index 00000000000..3129cf5c411
--- /dev/null
+++ b/apps/files_external/l10n/sk.php
@@ -0,0 +1,5 @@
+<?php
+$TRANSLATIONS = array(
+"Delete" => "Odstrániť"
+);
+$PLURAL_FORMS = "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;";
diff --git a/apps/files_external/l10n/sk_SK.php b/apps/files_external/l10n/sk_SK.php
index ca445387bca..664d97c43b2 100644
--- a/apps/files_external/l10n/sk_SK.php
+++ b/apps/files_external/l10n/sk_SK.php
@@ -9,7 +9,7 @@ $TRANSLATIONS = array(
"<b>Warning:</b> The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "<b>Upozornenie:</b> Podpora FTP v PHP nie je povolená alebo nainštalovaná. Nie je možné pripojenie oddielov FTP. Požiadajte administrátora systému, nech ho nainštaluje.",
"<b>Warning:</b> The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "<b>Varovanie:</b> nie je nainštalovaná, alebo povolená, podpora Curl v PHP. Nie je možné pripojenie oddielov ownCloud, WebDAV, či GoogleDrive. Prosím požiadajte svojho administrátora systému, nech ju nainštaluje.",
"External Storage" => "Externé úložisko",
-"Folder name" => "Meno priečinka",
+"Folder name" => "Názov priečinka",
"External storage" => "Externé úložisko",
"Configuration" => "Nastavenia",
"Options" => "Možnosti",
@@ -21,7 +21,7 @@ $TRANSLATIONS = array(
"Users" => "Používatelia",
"Delete" => "Zmazať",
"Enable User External Storage" => "Povoliť externé úložisko",
-"Allow users to mount their own external storage" => "Povoliť používateľom pripojiť ich vlastné externé úložisko",
+"Allow users to mount their own external storage" => "Povoliť používateľom pripojiť si vlastné externé úložisko",
"SSL root certificates" => "Koreňové SSL certifikáty",
"Import Root Certificate" => "Importovať koreňový certifikát"
);
diff --git a/apps/files_external/l10n/sq.php b/apps/files_external/l10n/sq.php
index 42de15edadc..328822dcde8 100644
--- a/apps/files_external/l10n/sq.php
+++ b/apps/files_external/l10n/sq.php
@@ -1,5 +1,6 @@
<?php
$TRANSLATIONS = array(
+"Groups" => "Grupet",
"Users" => "Përdoruesit",
"Delete" => "Elimino"
);
diff --git a/apps/files_external/l10n/tr.php b/apps/files_external/l10n/tr.php
index cc52c425b8d..5d5e2b726a9 100644
--- a/apps/files_external/l10n/tr.php
+++ b/apps/files_external/l10n/tr.php
@@ -5,12 +5,12 @@ $TRANSLATIONS = array(
"Grant access" => "Erişim sağlandı",
"Please provide a valid Dropbox app key and secret." => "Lütfen Dropbox app key ve secret temin ediniz",
"Error configuring Google Drive storage" => "Google Drive depo yapılandırma hatası",
-"<b>Warning:</b> \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "<b>Uyari.</b>''smbclient''yüklü değil. Mont etme CIFS/SMB hissenin mümkün değildir. Lutfen kullanici sistemin sormak onu yuklemek ici, ",
-"<b>Warning:</b> The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "<Uyari.</b>. Sistem FTP PHPden aktif degil veya yuklemedi. Monte etme hissenin FTP mumkun degildir. Lutfen kullaniici sistemin sormak onu yuklemek icin.",
-"<b>Warning:</b> The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "<b> Ihbar </b>. Dayanma Curl PHPden aktif veya yuklemedi degil. Monte ownClouden/WebDay veya GoogleDrive mumkun degil. Lutfen sistm yonetici sormak yuklemek icin. ",
+"<b>Warning:</b> \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "<b>Uyarı:</b> \"smbclient\" kurulu değil. CIFS/SMB paylaşımlarını bağlama işlemi mümkün olmadı. Lütfen kurulumu için sistem yöneticinize danışın.",
+"<b>Warning:</b> The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "<b>Uyarı:</b> PHP içerisinde FTP desteği etkin veya yüklü değil. FTP paylaşımlarını bağlama işlemi mümkün olmadı. Lütfen kurulumu için sistem yöneticinize danışın.",
+"<b>Warning:</b> The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "<b>Uyarı:</b> PHP içerisinde Curl desteği etkin veya yüklü değil. OwnCloud / WebDAV veya GoogleDrive bağlama işlemi mümkün olmadı. Lütfen kurulumu için sistem yöneticinizde danışın.",
"External Storage" => "Harici Depolama",
"Folder name" => "Dizin ismi",
-"External storage" => "Harici Depolama",
+"External storage" => "Harici depolama",
"Configuration" => "Yapılandırma",
"Options" => "Seçenekler",
"Applicable" => "Uygulanabilir",
diff --git a/apps/files_external/lib/amazons3.php b/apps/files_external/lib/amazons3.php
index c08a266b48c..00baacd488c 100644
--- a/apps/files_external/lib/amazons3.php
+++ b/apps/files_external/lib/amazons3.php
@@ -81,9 +81,9 @@ class AmazonS3 extends \OC\Files\Storage\Common {
$scheme = ($params['use_ssl'] === 'false') ? 'http' : 'https';
$this->test = isset($params['test']);
$this->timeout = ( ! isset($params['timeout'])) ? 15 : $params['timeout'];
- $params['region'] = ( ! isset($params['region'])) ? 'eu-west-1' : $params['region'];
- $params['hostname'] = ( !isset($params['hostname'])) ? 's3.amazonaws.com' : $params['hostname'];
- if (!isset($params['port'])) {
+ $params['region'] = ( ! isset($params['region']) || $params['region'] === '' ) ? 'eu-west-1' : $params['region'];
+ $params['hostname'] = ( !isset($params['hostname']) || $params['hostname'] === '' ) ? 's3.amazonaws.com' : $params['hostname'];
+ if (!isset($params['port']) || $params['port'] === '') {
$params['port'] = ($params['use_ssl'] === 'false') ? 80 : 443;
}
$base_url = $scheme.'://'.$params['hostname'].':'.$params['port'].'/';
@@ -300,14 +300,6 @@ class AmazonS3 extends \OC\Files\Storage\Common {
return false;
}
- public function isReadable($path) {
- return true;
- }
-
- public function isUpdatable($path) {
- return true;
- }
-
public function unlink($path) {
$path = $this->normalizePath($path);
@@ -515,8 +507,10 @@ class AmazonS3 extends \OC\Files\Storage\Common {
}
public function test() {
- $test = $this->s3->get_canonical_user_id();
- if (isset($test['id']) && $test['id'] != '') {
+ $test = $this->connection->getBucketAcl(array(
+ 'Bucket' => $this->bucket,
+ ));
+ if (isset($test) && !is_null($test->getPath('Owner/ID'))) {
return true;
}
return false;
diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php
index 659959e662e..01d588b3721 100755
--- a/apps/files_external/lib/config.php
+++ b/apps/files_external/lib/config.php
@@ -50,9 +50,9 @@ class OC_Mount_Config {
'key' => 'Access Key',
'secret' => '*Secret Key',
'bucket' => 'Bucket',
- 'hostname' => 'Hostname (optional)',
- 'port' => 'Port (optional)',
- 'region' => 'Region (optional)',
+ 'hostname' => '&Hostname (optional)',
+ 'port' => '&Port (optional)',
+ 'region' => '&Region (optional)',
'use_ssl' => '!Enable SSL',
'use_path_style' => '!Enable Path Style'));
@@ -84,14 +84,22 @@ class OC_Mount_Config {
'token' => '#token'),
'custom' => 'google');
- $backends['\OC\Files\Storage\SWIFT']=array(
- 'backend' => 'OpenStack Swift',
- 'configuration' => array(
- 'host' => 'URL',
- 'user' => 'Username',
- 'token' => '*Token',
- 'root' => '&Root',
- 'secure' => '!Secure ftps://'));
+ if(OC_Mount_Config::checkcurl()) {
+ $backends['\OC\Files\Storage\Swift'] = array(
+ 'backend' => 'OpenStack Object Storage',
+ 'configuration' => array(
+ 'user' => 'Username (required)',
+ 'bucket' => 'Bucket (required)',
+ 'region' => '&Region (optional for OpenStack Object Storage)',
+ 'key' => '*API Key (required for Rackspace Cloud Files)',
+ 'tenant' => '&Tenantname (required for OpenStack Object Storage)',
+ 'password' => '*Password (required for OpenStack Object Storage)',
+ 'service_name' => '&Service Name (required for OpenStack Object Storage)',
+ 'url' => '&URL of identity endpoint (required for OpenStack Object Storage)',
+ 'timeout' => '&Timeout of HTTP requests in seconds (optional)',
+ )
+ );
+ }
if (!OC_Util::runningOnWindows()) {
if (OC_Mount_Config::checksmbclient()) {
@@ -106,14 +114,24 @@ class OC_Mount_Config {
}
}
- if(OC_Mount_Config::checkcurl()) $backends['\OC\Files\Storage\DAV']=array(
- 'backend' => 'ownCloud / WebDAV',
- 'configuration' => array(
- 'host' => 'URL',
- 'user' => 'Username',
- 'password' => '*Password',
- 'root' => '&Root',
- 'secure' => '!Secure https://'));
+ if(OC_Mount_Config::checkcurl()){
+ $backends['\OC\Files\Storage\DAV']=array(
+ 'backend' => 'WebDAV',
+ 'configuration' => array(
+ 'host' => 'URL',
+ 'user' => 'Username',
+ 'password' => '*Password',
+ 'root' => '&Root',
+ 'secure' => '!Secure https://'));
+ $backends['\OC\Files\Storage\OwnCloud']=array(
+ 'backend' => 'ownCloud',
+ 'configuration' => array(
+ 'host' => 'URL',
+ 'user' => 'Username',
+ 'password' => '*Password',
+ 'root' => '&Remote subfolder',
+ 'secure' => '!Secure https://'));
+ }
$backends['\OC\Files\Storage\SFTP']=array(
'backend' => 'SFTP',
@@ -236,6 +254,7 @@ class OC_Mount_Config {
$storage = new $class($options);
return $storage->test();
} catch (Exception $exception) {
+ \OCP\Util::logException('files_external', $exception);
return false;
}
}
@@ -258,6 +277,11 @@ class OC_Mount_Config {
$mountType,
$applicable,
$isPersonal = false) {
+ $mountPoint = OC\Files\Filesystem::normalizePath($mountPoint);
+ if ($mountPoint === '' || $mountPoint === '/' || $mountPoint == '/Shared') {
+ // can't mount at root or "Shared" folder
+ return false;
+ }
if ($isPersonal) {
// Verify that the mount point applies for the current user
// Prevent non-admin users from mounting local storage
@@ -368,8 +392,7 @@ class OC_Mount_Config {
* @return array
*/
public static function getCertificates() {
- $view = \OCP\Files::getStorage('files_external');
- $path=\OCP\Config::getSystemValue('datadirectory').$view->getAbsolutePath("").'uploads/';
+ $path=OC_User::getHome(OC_User::getUser()) . '/files_external/uploads/';
\OCP\Util::writeLog('files_external', 'checking path '.$path, \OCP\Util::INFO);
if ( ! is_dir($path)) {
//path might not exist (e.g. non-standard OC_User::getHome() value)
@@ -391,8 +414,7 @@ class OC_Mount_Config {
* creates certificate bundle
*/
public static function createCertificateBundle() {
- $view = \OCP\Files::getStorage("files_external");
- $path = \OCP\Config::getSystemValue('datadirectory').$view->getAbsolutePath("");
+ $path=OC_User::getHome(OC_User::getUser()) . '/files_external';
$certs = OC_Mount_Config::getCertificates();
$fh_certs = fopen($path."/rootcerts.crt", 'w');
@@ -417,7 +439,7 @@ class OC_Mount_Config {
*/
public static function checksmbclient() {
if(function_exists('shell_exec')) {
- $output=shell_exec('which smbclient');
+ $output=shell_exec('which smbclient 2> /dev/null');
return !empty($output);
}else{
return false;
diff --git a/apps/files_external/lib/dropbox.php b/apps/files_external/lib/dropbox.php
index b6deab6e5a7..f7d8d98cf03 100755
--- a/apps/files_external/lib/dropbox.php
+++ b/apps/files_external/lib/dropbox.php
@@ -50,6 +50,22 @@ class Dropbox extends \OC\Files\Storage\Common {
}
}
+ private function deleteMetaData($path) {
+ $path = $this->root.$path;
+ if (isset($this->metaData[$path])) {
+ unset($this->metaData[$path]);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @brief Returns the path's metadata
+ * @param $path path for which to return the metadata
+ * @param $list if true, also return the directory's contents
+ * @return directory contents if $list is true, file metadata if $list is
+ * false, null if the file doesn't exist or "false" if the operation failed
+ */
private function getMetaData($path, $list = false) {
$path = $this->root.$path;
if ( ! $list && isset($this->metaData[$path])) {
@@ -62,24 +78,35 @@ class Dropbox extends \OC\Files\Storage\Common {
\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
return false;
}
+ $contents = array();
if ($response && isset($response['contents'])) {
- $contents = $response['contents'];
// Cache folder's contents
- foreach ($contents as $file) {
- $this->metaData[$path.'/'.basename($file['path'])] = $file;
+ foreach ($response['contents'] as $file) {
+ if (!isset($file['is_deleted']) || !$file['is_deleted']) {
+ $this->metaData[$path.'/'.basename($file['path'])] = $file;
+ $contents[] = $file;
+ }
}
unset($response['contents']);
+ }
+ if (!isset($response['is_deleted']) || !$response['is_deleted']) {
$this->metaData[$path] = $response;
}
- $this->metaData[$path] = $response;
// Return contents of folder only
return $contents;
} else {
try {
$response = $this->dropbox->getMetaData($path, 'false');
- $this->metaData[$path] = $response;
- return $response;
+ if (!isset($response['is_deleted']) || !$response['is_deleted']) {
+ $this->metaData[$path] = $response;
+ return $response;
+ }
+ return null;
} catch (\Exception $exception) {
+ if ($exception instanceof \Dropbox_Exception_NotFound) {
+ // don't log, might be a file_exist check
+ return false;
+ }
\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
return false;
}
@@ -108,7 +135,7 @@ class Dropbox extends \OC\Files\Storage\Common {
public function opendir($path) {
$contents = $this->getMetaData($path, true);
- if ($contents) {
+ if ($contents !== false) {
$files = array();
foreach ($contents as $file) {
$files[] = basename($file['path']);
@@ -146,14 +173,6 @@ class Dropbox extends \OC\Files\Storage\Common {
return false;
}
- public function isReadable($path) {
- return $this->file_exists($path);
- }
-
- public function isUpdatable($path) {
- return $this->file_exists($path);
- }
-
public function file_exists($path) {
if ($path == '' || $path == '/') {
return true;
@@ -165,9 +184,9 @@ class Dropbox extends \OC\Files\Storage\Common {
}
public function unlink($path) {
- $path = $this->root.$path;
try {
- $this->dropbox->delete($path);
+ $this->dropbox->delete($this->root.$path);
+ $this->deleteMetaData($path);
return true;
} catch (\Exception $exception) {
\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
@@ -176,10 +195,14 @@ class Dropbox extends \OC\Files\Storage\Common {
}
public function rename($path1, $path2) {
- $path1 = $this->root.$path1;
- $path2 = $this->root.$path2;
try {
- $this->dropbox->move($path1, $path2);
+ // overwrite if target file exists and is not a directory
+ $destMetaData = $this->getMetaData($path2);
+ if (isset($destMetaData) && $destMetaData !== false && !$destMetaData['is_dir']) {
+ $this->unlink($path2);
+ }
+ $this->dropbox->move($this->root.$path1, $this->root.$path2);
+ $this->deleteMetaData($path1);
return true;
} catch (\Exception $exception) {
\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
@@ -277,7 +300,12 @@ class Dropbox extends \OC\Files\Storage\Common {
}
public function touch($path, $mtime = null) {
- return false;
+ if ($this->file_exists($path)) {
+ return false;
+ } else {
+ $this->file_put_contents($path, '');
+ }
+ return true;
}
}
diff --git a/apps/files_external/lib/ftp.php b/apps/files_external/lib/ftp.php
index ca6c635eb2b..00bf7a189ce 100644
--- a/apps/files_external/lib/ftp.php
+++ b/apps/files_external/lib/ftp.php
@@ -35,6 +35,9 @@ class FTP extends \OC\Files\Storage\StreamWrapper{
if ( ! $this->root || $this->root[0]!='/') {
$this->root='/'.$this->root;
}
+ if (substr($this->root, -1) !== '/') {
+ $this->root .= '/';
+ }
} else {
throw new \Exception();
}
@@ -58,6 +61,22 @@ class FTP extends \OC\Files\Storage\StreamWrapper{
$url.='://'.$this->user.':'.$this->password.'@'.$this->host.$this->root.$path;
return $url;
}
+
+ /**
+ * Unlinks file or directory
+ * @param string @path
+ */
+ public function unlink($path) {
+ if ($this->is_dir($path)) {
+ return $this->rmdir($path);
+ }
+ else {
+ $url = $this->constructUrl($path);
+ $result = unlink($url);
+ clearstatcache(true, $url);
+ return $result;
+ }
+ }
public function fopen($path,$mode) {
switch($mode) {
case 'r':
diff --git a/apps/files_external/lib/google.php b/apps/files_external/lib/google.php
index b63b5885de1..426caf008ec 100644
--- a/apps/files_external/lib/google.php
+++ b/apps/files_external/lib/google.php
@@ -317,10 +317,6 @@ class Google extends \OC\Files\Storage\Common {
}
}
- public function isReadable($path) {
- return $this->file_exists($path);
- }
-
public function isUpdatable($path) {
$file = $this->getDriveFile($path);
if ($file) {
diff --git a/apps/files_external/lib/owncloud.php b/apps/files_external/lib/owncloud.php
new file mode 100644
index 00000000000..98314102a64
--- /dev/null
+++ b/apps/files_external/lib/owncloud.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) 2013 Vincent Petry <pvince81@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\Files\Storage;
+
+/**
+ * ownCloud backend for external storage based on DAV backend.
+ *
+ * The ownCloud URL consists of three parts:
+ * http://%host/%context/remote.php/webdav/%root
+ *
+ */
+class OwnCloud extends \OC\Files\Storage\DAV{
+ const OC_URL_SUFFIX = 'remote.php/webdav';
+
+ public function __construct($params) {
+ // extract context path from host if specified
+ // (owncloud install path on host)
+ $host = $params['host'];
+ $contextPath = '';
+ $hostSlashPos = strpos($host, '/');
+ if ($hostSlashPos !== false){
+ $contextPath = substr($host, $hostSlashPos);
+ $host = substr($host, 0, $hostSlashPos);
+ }
+
+ if (substr($contextPath , 1) !== '/'){
+ $contextPath .= '/';
+ }
+
+ if (isset($params['root'])){
+ $root = $params['root'];
+ if (substr($root, 1) !== '/'){
+ $root = '/' . $root;
+ }
+ }
+ else{
+ $root = '/';
+ }
+
+ $params['host'] = $host;
+ $params['root'] = $contextPath . self::OC_URL_SUFFIX . $root;
+
+ parent::__construct($params);
+ }
+}
diff --git a/apps/files_external/lib/sftp.php b/apps/files_external/lib/sftp.php
index f7f329b8993..95e0cefa398 100644
--- a/apps/files_external/lib/sftp.php
+++ b/apps/files_external/lib/sftp.php
@@ -29,83 +29,97 @@ class SFTP extends \OC\Files\Storage\Common {
}
$this->user = $params['user'];
$this->password = $params['password'];
- $this->root = isset($params['root']) ? $this->cleanPath($params['root']) : '/';
- if ($this->root[0] != '/') $this->root = '/' . $this->root;
- if (substr($this->root, -1, 1) != '/') $this->root .= '/';
+ $this->root
+ = isset($params['root']) ? $this->cleanPath($params['root']) : '/';
- $host_keys = $this->read_host_keys();
+ if ($this->root[0] != '/') {
+ $this->root = '/' . $this->root;
+ }
+
+ if (substr($this->root, -1, 1) != '/') {
+ $this->root .= '/';
+ }
+ $hostKeys = $this->readHostKeys();
$this->client = new \Net_SFTP($this->host);
+
if (!$this->client->login($this->user, $this->password)) {
throw new \Exception('Login failed');
}
- $current_host_key = $this->client->getServerPublicHostKey();
+ $currentHostKey = $this->client->getServerPublicHostKey();
- if (array_key_exists($this->host, $host_keys)) {
- if ($host_keys[$this->host] != $current_host_key) {
+ if (array_key_exists($this->host, $hostKeys)) {
+ if ($hostKeys[$this->host] != $currentHostKey) {
throw new \Exception('Host public key does not match known key');
}
} else {
- $host_keys[$this->host] = $current_host_key;
- $this->write_host_keys($host_keys);
+ $hostKeys[$this->host] = $currentHostKey;
+ $this->writeHostKeys($hostKeys);
}
}
public function test() {
- if (!isset($params['host']) || !isset($params['user']) || !isset($params['password'])) {
- throw new \Exception("Required parameters not set");
+ if (
+ !isset($this->host)
+ || !isset($this->user)
+ || !isset($this->password)
+ ) {
+ return false;
}
+ return $this->client->nlist() !== false;
}
public function getId(){
return 'sftp::' . $this->user . '@' . $this->host . '/' . $this->root;
}
- private function abs_path($path) {
+ private function absPath($path) {
return $this->root . $this->cleanPath($path);
}
- private function host_keys_path() {
+ private function hostKeysPath() {
try {
$storage_view = \OCP\Files::getStorage('files_external');
if ($storage_view) {
return \OCP\Config::getSystemValue('datadirectory') .
$storage_view->getAbsolutePath('') .
- 'ssh_host_keys';
+ 'ssh_hostKeys';
}
} catch (\Exception $e) {
}
return false;
}
- private function write_host_keys($keys) {
+ private function writeHostKeys($keys) {
try {
- $key_path = $this->host_keys_path();
- $fp = fopen($key_path, 'w');
- foreach ($keys as $host => $key) {
- fwrite($fp, $host . '::' . $key . "\n");
+ $keyPath = $this->hostKeysPath();
+ if ($keyPath && file_exists($keyPath)) {
+ $fp = fopen($keyPath, 'w');
+ foreach ($keys as $host => $key) {
+ fwrite($fp, $host . '::' . $key . "\n");
+ }
+ fclose($fp);
+ return true;
}
- fclose($fp);
- return true;
} catch (\Exception $e) {
- return false;
}
+ return false;
}
- private function read_host_keys() {
+ private function readHostKeys() {
try {
- $key_path = $this->host_keys_path();
- if (file_exists($key_path)) {
+ $keyPath = $this->hostKeysPath();
+ if (file_exists($keyPath)) {
$hosts = array();
$keys = array();
- $lines = file($key_path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+ $lines = file($keyPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if ($lines) {
foreach ($lines as $line) {
- $host_key_arr = explode("::", $line, 2);
- if (count($host_key_arr) == 2) {
- $hosts[] = $host_key_arr[0];
- $keys[] = $host_key_arr[1];
+ $hostKeyArray = explode("::", $line, 2);
+ if (count($hostKeyArray) == 2) {
+ $hosts[] = $hostKeyArray[0];
+ $keys[] = $hostKeyArray[1];
}
}
return array_combine($hosts, $keys);
@@ -118,7 +132,7 @@ class SFTP extends \OC\Files\Storage\Common {
public function mkdir($path) {
try {
- return $this->client->mkdir($this->abs_path($path));
+ return $this->client->mkdir($this->absPath($path));
} catch (\Exception $e) {
return false;
}
@@ -126,7 +140,7 @@ class SFTP extends \OC\Files\Storage\Common {
public function rmdir($path) {
try {
- return $this->client->delete($this->abs_path($path), true);
+ return $this->client->delete($this->absPath($path), true);
} catch (\Exception $e) {
return false;
}
@@ -134,16 +148,16 @@ class SFTP extends \OC\Files\Storage\Common {
public function opendir($path) {
try {
- $list = $this->client->nlist($this->abs_path($path));
+ $list = $this->client->nlist($this->absPath($path));
$id = md5('sftp:' . $path);
- $dir_stream = array();
+ $dirStream = array();
foreach($list as $file) {
if ($file != '.' && $file != '..') {
- $dir_stream[] = $file;
+ $dirStream[] = $file;
}
}
- \OC\Files\Stream\Dir::register($id, $dir_stream);
+ \OC\Files\Stream\Dir::register($id, $dirStream);
return opendir('fakedir://' . $id);
} catch(\Exception $e) {
return false;
@@ -152,25 +166,23 @@ class SFTP extends \OC\Files\Storage\Common {
public function filetype($path) {
try {
- $stat = $this->client->stat($this->abs_path($path));
- if ($stat['type'] == NET_SFTP_TYPE_REGULAR) return 'file';
- if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) return 'dir';
+ $stat = $this->client->stat($this->absPath($path));
+ if ($stat['type'] == NET_SFTP_TYPE_REGULAR) {
+ return 'file';
+ }
+
+ if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
+ return 'dir';
+ }
} catch (\Exeption $e) {
+
}
return false;
}
- public function isReadable($path) {
- return true;
- }
-
- public function isUpdatable($path) {
- return true;
- }
-
public function file_exists($path) {
try {
- return $this->client->stat($this->abs_path($path)) !== false;
+ return $this->client->stat($this->absPath($path)) !== false;
} catch (\Exception $e) {
return false;
}
@@ -178,7 +190,7 @@ class SFTP extends \OC\Files\Storage\Common {
public function unlink($path) {
try {
- return $this->client->delete($this->abs_path($path), true);
+ return $this->client->delete($this->absPath($path), true);
} catch (\Exception $e) {
return false;
}
@@ -186,18 +198,21 @@ class SFTP extends \OC\Files\Storage\Common {
public function fopen($path, $mode) {
try {
- $abs_path = $this->abs_path($path);
+ $absPath = $this->absPath($path);
switch($mode) {
case 'r':
case 'rb':
- if ( !$this->file_exists($path)) return false;
+ if ( !$this->file_exists($path)) {
+ return false;
+ }
+
if (strrpos($path, '.')!==false) {
$ext=substr($path, strrpos($path, '.'));
} else {
$ext='';
}
$tmp = \OC_Helper::tmpFile($ext);
- $this->getFile($abs_path, $tmp);
+ $this->getFile($absPath, $tmp);
return fopen($tmp, $mode);
case 'w':
@@ -217,12 +232,18 @@ class SFTP extends \OC\Files\Storage\Common {
} else {
$ext='';
}
+
$tmpFile=\OC_Helper::tmpFile($ext);
- \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
+ \OC\Files\Stream\Close::registerCallback(
+ $tmpFile,
+ array($this, 'writeBack')
+ );
+
if ($this->file_exists($path)) {
- $this->getFile($abs_path, $tmpFile);
+ $this->getFile($absPath, $tmpFile);
}
- self::$tempFiles[$tmpFile]=$abs_path;
+
+ self::$tempFiles[$tmpFile]=$absPath;
return fopen('close://'.$tmpFile, $mode);
}
} catch (\Exception $e) {
@@ -240,9 +261,11 @@ class SFTP extends \OC\Files\Storage\Common {
public function touch($path, $mtime=null) {
try {
- if (!is_null($mtime)) return false;
+ if (!is_null($mtime)) {
+ return false;
+ }
if (!$this->file_exists($path)) {
- $this->client->put($this->abs_path($path), '');
+ $this->client->put($this->absPath($path), '');
} else {
return false;
}
@@ -262,7 +285,13 @@ class SFTP extends \OC\Files\Storage\Common {
public function rename($source, $target) {
try {
- return $this->client->rename($this->abs_path($source), $this->abs_path($target));
+ if (!$this->is_dir($target) && $this->file_exists($target)) {
+ $this->unlink($target);
+ }
+ return $this->client->rename(
+ $this->absPath($source),
+ $this->absPath($target)
+ );
} catch (\Exception $e) {
return false;
}
@@ -270,7 +299,7 @@ class SFTP extends \OC\Files\Storage\Common {
public function stat($path) {
try {
- $stat = $this->client->stat($this->abs_path($path));
+ $stat = $this->client->stat($this->absPath($path));
$mtime = $stat ? $stat['mtime'] : -1;
$size = $stat ? $stat['size'] : 0;
@@ -279,6 +308,5 @@ class SFTP extends \OC\Files\Storage\Common {
} catch (\Exception $e) {
return false;
}
-
}
}
diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php
index ecd4dae0484..c5fba92ee68 100644
--- a/apps/files_external/lib/smb.php
+++ b/apps/files_external/lib/smb.php
@@ -47,8 +47,13 @@ class SMB extends \OC\Files\Storage\StreamWrapper{
public function constructUrl($path) {
if (substr($path, -1)=='/') {
- $path=substr($path, 0, -1);
+ $path = substr($path, 0, -1);
}
+ if (substr($path, 0, 1)=='/') {
+ $path = substr($path, 1);
+ }
+ // remove trailing dots which some versions of samba don't seem to like
+ $path = rtrim($path, '.');
$path = urlencode($path);
$user = urlencode($this->user);
$pass = urlencode($this->password);
@@ -77,6 +82,24 @@ class SMB extends \OC\Files\Storage\StreamWrapper{
}
/**
+ * Unlinks file or directory
+ * @param string @path
+ */
+ public function unlink($path) {
+ if ($this->is_dir($path)) {
+ $this->rmdir($path);
+ }
+ else {
+ $url = $this->constructUrl($path);
+ unlink($url);
+ clearstatcache(false, $url);
+ }
+ // smb4php still returns false even on success so
+ // check here whether file was really deleted
+ return !file_exists($path);
+ }
+
+ /**
* check if a file or folder has been updated since $time
* @param string $path
* @param int $time
diff --git a/apps/files_external/lib/streamwrapper.php b/apps/files_external/lib/streamwrapper.php
index beb4ec5605f..e484325e2fb 100644
--- a/apps/files_external/lib/streamwrapper.php
+++ b/apps/files_external/lib/streamwrapper.php
@@ -8,7 +8,7 @@
namespace OC\Files\Storage;
-abstract class StreamWrapper extends Common{
+abstract class StreamWrapper extends Common {
abstract public function constructUrl($path);
public function mkdir($path) {
@@ -16,9 +16,18 @@ abstract class StreamWrapper extends Common{
}
public function rmdir($path) {
- if($this->file_exists($path)) {
- $success = rmdir($this->constructUrl($path));
- clearstatcache();
+ if ($this->file_exists($path)) {
+ $dh = $this->opendir($path);
+ while (($file = readdir($dh)) !== false) {
+ if ($this->is_dir($path . '/' . $file)) {
+ $this->rmdir($path . '/' . $file);
+ } else {
+ $this->unlink($path . '/' . $file);
+ }
+ }
+ $url = $this->constructUrl($path);
+ $success = rmdir($url);
+ clearstatcache(false, $url);
return $success;
} else {
return false;
@@ -30,15 +39,7 @@ abstract class StreamWrapper extends Common{
}
public function filetype($path) {
- return filetype($this->constructUrl($path));
- }
-
- public function isReadable($path) {
- return true;//not properly supported
- }
-
- public function isUpdatable($path) {
- return true;//not properly supported
+ return @filetype($this->constructUrl($path));
}
public function file_exists($path) {
@@ -46,8 +47,11 @@ abstract class StreamWrapper extends Common{
}
public function unlink($path) {
- $success = unlink($this->constructUrl($path));
- clearstatcache();
+ $url = $this->constructUrl($path);
+ $success = unlink($url);
+ // normally unlink() is supposed to do this implicitly,
+ // but doing it anyway just to be sure
+ clearstatcache(false, $url);
return $success;
}
@@ -55,15 +59,20 @@ abstract class StreamWrapper extends Common{
return fopen($this->constructUrl($path), $mode);
}
- public function touch($path, $mtime=null) {
- if(is_null($mtime)) {
- $fh = $this->fopen($path, 'a');
- fwrite($fh, '');
- fclose($fh);
-
- return true;
+ public function touch($path, $mtime = null) {
+ if ($this->file_exists($path)) {
+ if (is_null($mtime)) {
+ $fh = $this->fopen($path, 'a');
+ fwrite($fh, '');
+ fclose($fh);
+
+ return true;
+ } else {
+ return false; //not supported
+ }
} else {
- return false;//not supported
+ $this->file_put_contents($path, '');
+ return true;
}
}
diff --git a/apps/files_external/lib/swift.php b/apps/files_external/lib/swift.php
index a9cfe5bd20f..b615d24ce76 100644
--- a/apps/files_external/lib/swift.php
+++ b/apps/files_external/lib/swift.php
@@ -1,462 +1,311 @@
<?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.
+ * ownCloud
+ *
+ * @author Christian Berendt
+ * @copyright 2013 Christian Berendt berendt@b1-systems.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/>.
*/
namespace OC\Files\Storage;
-require_once 'php-cloudfiles/cloudfiles.php';
-
-class SWIFT extends \OC\Files\Storage\Common{
- private $id;
- private $host;
- private $root;
- private $user;
- private $token;
- private $secure;
- private $ready = false;
- /**
- * @var \CF_Authentication auth
- */
- private $auth;
- /**
- * @var \CF_Connection conn
- */
- private $conn;
- /**
- * @var \CF_Container rootContainer
- */
- private $rootContainer;
-
- private static $tempFiles=array();
- private $objects=array();
- private $containers=array();
-
- const SUBCONTAINER_FILE='.subcontainers';
-
- /**
- * translate directory path to container name
- * @param string $path
- * @return string
- */
- private function getContainerName($path) {
- $path=trim(trim($this->root, '/') . "/".$path, '/.');
- return str_replace('/', '\\', $path);
- }
+set_include_path(get_include_path() . PATH_SEPARATOR .
+ \OC_App::getAppPath('files_external') . '/3rdparty/php-opencloud/lib');
+require_once 'openstack.php';
- /**
- * get container by path
- * @param string $path
- * @return \CF_Container
- */
- private function getContainer($path) {
- if ($path=='' or $path=='/') {
- return $this->rootContainer;
- }
- if (isset($this->containers[$path])) {
- return $this->containers[$path];
- }
- try {
- $container=$this->conn->get_container($this->getContainerName($path));
- $this->containers[$path]=$container;
- return $container;
- } catch(\NoSuchContainerException $e) {
- return null;
- }
- }
+use \OpenCloud;
+use \OpenCloud\Common\Exceptions;
- /**
- * create container
- * @param string $path
- * @return \CF_Container
- */
- private function createContainer($path) {
- if ($path=='' or $path=='/' or $path=='.') {
- return $this->conn->create_container($this->getContainerName($path));
- }
- $parent=dirname($path);
- if ($parent=='' or $parent=='/' or $parent=='.') {
- $parentContainer=$this->rootContainer;
- } else {
- if ( ! $this->containerExists($parent)) {
- $parentContainer=$this->createContainer($parent);
- } else {
- $parentContainer=$this->getContainer($parent);
- }
+class Swift extends \OC\Files\Storage\Common {
+
+ /**
+ * @var \OpenCloud\ObjectStore
+ */
+ private $connection;
+ /**
+ * @var \OpenCloud\ObjectStore\Container
+ */
+ private $container;
+ /**
+ * @var \OpenCloud\OpenStack
+ */
+ private $anchor;
+ /**
+ * @var string
+ */
+ private $bucket;
+ /**
+ * @var array
+ */
+ private static $tmpFiles = array();
+
+ private function normalizePath($path) {
+ $path = trim($path, '/');
+
+ if (!$path) {
+ $path = '.';
}
- $this->addSubContainer($parentContainer, basename($path));
- return $this->conn->create_container($this->getContainerName($path));
+
+ return $path;
}
- /**
- * get object by path
- * @param string $path
- * @return \CF_Object
- */
- private function getObject($path) {
- if (isset($this->objects[$path])) {
- return $this->objects[$path];
- }
- $container=$this->getContainer(dirname($path));
- if (is_null($container)) {
- return null;
- } else {
- if ($path=="/" or $path=='') {
- return null;
- }
- try {
- $obj=$container->get_object(basename($path));
- $this->objects[$path]=$obj;
- return $obj;
- } catch(\NoSuchObjectException $e) {
- return null;
- }
+ private function doesObjectExist($path) {
+ try {
+ $object = $this->container->DataObject($path);
+ return true;
+ } catch (Exceptions\ObjFetchError $e) {
+ \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
+ return false;
+ } catch (Exceptions\HttpError $e) {
+ \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
+ return false;
}
}
- /**
- * get the names of all objects in a container
- * @param CF_Container
- * @return array
- */
- private function getObjects($container) {
- if (is_null($container)) {
- return array();
- } else {
- $files=$container->get_objects();
- foreach ($files as &$file) {
- $file=$file->name;
- }
- return $files;
+ public function __construct($params) {
+ if ((!isset($params['key']) and !isset($params['password']))
+ or !isset($params['user']) or !isset($params['bucket'])
+ or !isset($params['region'])) {
+ throw new \Exception("API Key or password, Username, Bucket and Region have to be configured.");
}
- }
- /**
- * create object
- * @param string $path
- * @return \CF_Object
- */
- private function createObject($path) {
- $container=$this->getContainer(dirname($path));
- if ( ! is_null($container)) {
- $container=$this->createContainer(dirname($path));
- }
- return $container->create_object(basename($path));
- }
+ $this->id = 'swift::' . $params['user'] . md5($params['bucket']);
+ $this->bucket = $params['bucket'];
- /**
- * check if an object exists
- * @param string
- * @return bool
- */
- private function objectExists($path) {
- return !is_null($this->getObject($path));
- }
+ if (!isset($params['url'])) {
+ $params['url'] = 'https://identity.api.rackspacecloud.com/v2.0/';
+ }
- /**
- * check if container for path exists
- * @param string $path
- * @return bool
- */
- private function containerExists($path) {
- return !is_null($this->getContainer($path));
- }
+ if (!isset($params['service_name'])) {
+ $params['service_name'] = 'cloudFiles';
+ }
- /**
- * get the list of emulated sub containers
- * @param \CF_Container $container
- * @return array
- */
- private function getSubContainers($container) {
- $tmpFile=\OCP\Files::tmpFile();
- $obj=$this->getSubContainerFile($container);
- try {
- $obj->save_to_filename($tmpFile);
- } catch(\Exception $e) {
- return array();
+ $settings = array(
+ 'username' => $params['user'],
+
+ );
+
+ if (isset($params['password'])) {
+ $settings['password'] = $params['password'];
+ } else if (isset($params['key'])) {
+ $settings['apiKey'] = $params['key'];
}
- $obj->save_to_filename($tmpFile);
- $containers=file($tmpFile);
- unlink($tmpFile);
- foreach ($containers as &$sub) {
- $sub=trim($sub);
+
+ if (isset($params['tenant'])) {
+ $settings['tenantName'] = $params['tenant'];
}
- return $containers;
- }
- /**
- * add an emulated sub container
- * @param \CF_Container $container
- * @param string $name
- * @return bool
- */
- private function addSubContainer($container, $name) {
- if ( ! $name) {
- return false;
+ $this->anchor = new \OpenCloud\OpenStack($params['url'], $settings);
+
+ if (isset($params['timeout'])) {
+ $this->anchor->setHttpTimeout($params['timeout']);
}
- $tmpFile=\OCP\Files::tmpFile();
- $obj=$this->getSubContainerFile($container);
+
+ $this->connection = $this->anchor->ObjectStore($params['service_name'], $params['region'], 'publicURL');
+
try {
- $obj->save_to_filename($tmpFile);
- $containers=file($tmpFile);
- foreach ($containers as &$sub) {
- $sub=trim($sub);
- }
- if(array_search($name, $containers) !== false) {
- unlink($tmpFile);
- return false;
- } else {
- $fh=fopen($tmpFile, 'a');
- fwrite($fh, $name . "\n");
- }
- } catch(\Exception $e) {
- file_put_contents($tmpFile, $name . "\n");
+ $this->container = $this->connection->Container($this->bucket);
+ } catch (Exceptions\ContainerNotFoundError $e) {
+ $this->container = $this->connection->Container();
+ $this->container->Create(array('name' => $this->bucket));
}
- $obj->load_from_filename($tmpFile);
- unlink($tmpFile);
- return true;
+ if (!$this->file_exists('.')) {
+ $this->mkdir('.');
+ }
}
- /**
- * remove an emulated sub container
- * @param \CF_Container $container
- * @param string $name
- * @return bool
- */
- private function removeSubContainer($container, $name) {
- if ( ! $name) {
- return false;
- }
- $tmpFile=\OCP\Files::tmpFile();
- $obj=$this->getSubContainerFile($container);
- try {
- $obj->save_to_filename($tmpFile);
- $containers=file($tmpFile);
- } catch (\Exception $e) {
+ public function mkdir($path) {
+ $path = $this->normalizePath($path);
+
+ if ($this->is_dir($path)) {
return false;
}
- foreach ($containers as &$sub) {
- $sub=trim($sub);
+
+ if($path !== '.') {
+ $path .= '/';
}
- $i=array_search($name, $containers);
- if ($i===false) {
- unlink($tmpFile);
+
+ try {
+ $object = $this->container->DataObject();
+ $object->Create(array(
+ 'name' => $path,
+ 'content_type' => 'httpd/unix-directory'
+ ));
+ } catch (Exceptions\CreateUpdateError $e) {
+ \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
return false;
- } else {
- unset($containers[$i]);
- file_put_contents($tmpFile, implode("\n", $containers)."\n");
}
- $obj->load_from_filename($tmpFile);
- unlink($tmpFile);
return true;
}
- /**
- * ensure a subcontainer file exists and return it's object
- * @param \CF_Container $container
- * @return \CF_Object
- */
- private function getSubContainerFile($container) {
- try {
- return $container->get_object(self::SUBCONTAINER_FILE);
- } catch(\NoSuchObjectException $e) {
- return $container->create_object(self::SUBCONTAINER_FILE);
- }
- }
+ public function file_exists($path) {
+ $path = $this->normalizePath($path);
- public function __construct($params) {
- if (isset($params['token']) && isset($params['host']) && isset($params['user'])) {
- $this->token=$params['token'];
- $this->host=$params['host'];
- $this->user=$params['user'];
- $this->root=isset($params['root'])?$params['root']:'/';
- if (isset($params['secure'])) {
- if (is_string($params['secure'])) {
- $this->secure = ($params['secure'] === 'true');
- } else {
- $this->secure = (bool)$params['secure'];
- }
- } else {
- $this->secure = false;
- }
- if ( ! $this->root || $this->root[0]!='/') {
- $this->root='/'.$this->root;
- }
- $this->id = 'swift:' . $this->host . ':'.$this->root . ':' . $this->user;
- } else {
- throw new \Exception();
+ if ($path !== '.' && $this->is_dir($path)) {
+ $path .= '/';
}
+ return $this->doesObjectExist($path);
}
- private function init(){
- if($this->ready) {
- return;
+ public function rmdir($path) {
+ $path = $this->normalizePath($path);
+
+ if (!$this->is_dir($path)) {
+ return false;
}
- $this->ready = true;
- $this->auth = new \CF_Authentication($this->user, $this->token, null, $this->host);
- $this->auth->authenticate();
+ $dh = $this->opendir($path);
+ while ($file = readdir($dh)) {
+ if ($file === '.' || $file === '..') {
+ continue;
+ }
- $this->conn = new \CF_Connection($this->auth);
+ if ($this->is_dir($path . '/' . $file)) {
+ $this->rmdir($path . '/' . $file);
+ } else {
+ $this->unlink($path . '/' . $file);
+ }
+ }
- if ( ! $this->containerExists('/')) {
- $this->rootContainer=$this->createContainer('/');
- } else {
- $this->rootContainer=$this->getContainer('/');
+ try {
+ $object = $this->container->DataObject($path . '/');
+ $object->Delete();
+ } catch (Exceptions\DeleteError $e) {
+ \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
+ return false;
}
- }
- public function getId(){
- return $this->id;
+ return true;
}
+ public function opendir($path) {
+ $path = $this->normalizePath($path);
- public function mkdir($path) {
- $this->init();
- if ($this->containerExists($path)) {
- return false;
+ if ($path === '.') {
+ $path = '';
} else {
- $this->createContainer($path);
- return true;
+ $path .= '/';
}
- }
- public function rmdir($path) {
- $this->init();
- if (!$this->containerExists($path)) {
- return false;
- } else {
- $this->emptyContainer($path);
- if ($path!='' and $path!='/') {
- $parentContainer=$this->getContainer(dirname($path));
- $this->removeSubContainer($parentContainer, basename($path));
+ try {
+ $files = array();
+ $objects = $this->container->ObjectList(array(
+ 'prefix' => $path,
+ 'delimiter' => '/'
+ ));
+
+ while ($object = $objects->Next()) {
+ $file = basename($object->Name());
+ if ($file !== basename($path)) {
+ $files[] = $file;
+ }
}
- $this->conn->delete_container($this->getContainerName($path));
- unset($this->containers[$path]);
- return true;
+ \OC\Files\Stream\Dir::register('swift' . $path, $files);
+ return opendir('fakedir://swift' . $path);
+ } catch (Exception $e) {
+ \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
+ return false;
}
+
}
- private function emptyContainer($path) {
- $container=$this->getContainer($path);
- if (is_null($container)) {
- return;
- }
- $subContainers=$this->getSubContainers($container);
- foreach ($subContainers as $sub) {
- if ($sub) {
- $this->emptyContainer($path.'/'.$sub);
- $this->conn->delete_container($this->getContainerName($path.'/'.$sub));
- unset($this->containers[$path.'/'.$sub]);
- }
- }
+ public function stat($path) {
+ $path = $this->normalizePath($path);
- $objects=$this->getObjects($container);
- foreach ($objects as $object) {
- $container->delete_object($object);
- unset($this->objects[$path.'/'.$object]);
+ if ($this->is_dir($path) && $path != '.') {
+ $path .= '/';
}
- }
- public function opendir($path) {
- $this->init();
- $container=$this->getContainer($path);
- $files=$this->getObjects($container);
- $i=array_search(self::SUBCONTAINER_FILE, $files);
- if ($i!==false) {
- unset($files[$i]);
- }
- $subContainers=$this->getSubContainers($container);
- $files=array_merge($files, $subContainers);
- $id=$this->getContainerName($path);
- \OC\Files\Stream\Dir::register($id, $files);
- return opendir('fakedir://'.$id);
- }
+ try {
+ $object = $this->container->DataObject($path);
+ } catch (Exceptions\ObjFetchError $e) {
+ \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
+ return false;
+ }
- public function filetype($path) {
- $this->init();
- if ($this->containerExists($path)) {
- return 'dir';
- } else {
- return 'file';
+ $mtime = $object->extra_headers['X-Timestamp'];
+ if (isset($object->extra_headers['X-Object-Meta-Timestamp'])) {
+ $mtime = $object->extra_headers['X-Object-Meta-Timestamp'];
}
- }
- public function isReadable($path) {
- return true;
+ $stat = array();
+ $stat['size'] = $object->content_length;
+ $stat['mtime'] = $mtime;
+ $stat['atime'] = time();
+ return $stat;
}
- public function isUpdatable($path) {
- return true;
- }
+ public function filetype($path) {
+ $path = $this->normalizePath($path);
- public function file_exists($path) {
- $this->init();
- if ($this->is_dir($path)) {
- return true;
- } else {
- return $this->objectExists($path);
+ if ($path !== '.' && $this->doesObjectExist($path)) {
+ return 'file';
}
- }
- public function file_get_contents($path) {
- $this->init();
- $obj=$this->getObject($path);
- if (is_null($obj)) {
- return false;
+ if ($path !== '.') {
+ $path .= '/';
}
- return $obj->read();
- }
- public function file_put_contents($path, $content) {
- $this->init();
- $obj=$this->getObject($path);
- if (is_null($obj)) {
- $container=$this->getContainer(dirname($path));
- if (is_null($container)) {
- return false;
- }
- $obj=$container->create_object(basename($path));
+ if ($this->doesObjectExist($path)) {
+ return 'dir';
}
- $this->resetMTime($obj);
- return $obj->write($content);
}
public function unlink($path) {
- $this->init();
- if ($this->containerExists($path)) {
- return $this->rmdir($path);
- }
- if ($this->objectExists($path)) {
- $container=$this->getContainer(dirname($path));
- $container->delete_object(basename($path));
- unset($this->objects[$path]);
- } else {
+ $path = $this->normalizePath($path);
+
+ try {
+ $object = $this->container->DataObject($path);
+ $object->Delete();
+ } catch (Exceptions\DeleteError $e) {
+ \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
+ return false;
+ } catch (Exceptions\ObjFetchError $e) {
+ \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
return false;
}
+
+ return true;
}
public function fopen($path, $mode) {
- $this->init();
- switch($mode) {
+ $path = $this->normalizePath($path);
+
+ switch ($mode) {
case 'r':
case 'rb':
- $obj=$this->getObject($path);
- if (is_null($obj)) {
+ $tmpFile = \OC_Helper::tmpFile();
+ self::$tmpFiles[$tmpFile] = $path;
+ try {
+ $object = $this->container->DataObject($path);
+ } catch (Exceptions\ObjFetchError $e) {
+ \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
return false;
}
- $fp = fopen('php://temp', 'r+');
- $obj->stream($fp);
-
- rewind($fp);
- return $fp;
+ try {
+ $object->SaveToFilename($tmpFile);
+ } catch (Exceptions\IOError $e) {
+ \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
+ return false;
+ }
+ return fopen($tmpFile, 'r');
case 'w':
case 'wb':
case 'a':
@@ -469,119 +318,166 @@ class SWIFT extends \OC\Files\Storage\Common{
case 'x+':
case 'c':
case 'c+':
- $tmpFile=$this->getTmpFile($path);
+ if (strrpos($path, '.') !== false) {
+ $ext = substr($path, strrpos($path, '.'));
+ } else {
+ $ext = '';
+ }
+ $tmpFile = \OC_Helper::tmpFile($ext);
\OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
- self::$tempFiles[$tmpFile]=$path;
- return fopen('close://'.$tmpFile, $mode);
+ if ($this->file_exists($path)) {
+ $source = $this->fopen($path, 'r');
+ file_put_contents($tmpFile, $source);
+ }
+ self::$tmpFiles[$tmpFile] = $path;
+
+ return fopen('close://' . $tmpFile, $mode);
}
}
- public function writeBack($tmpFile) {
- if (isset(self::$tempFiles[$tmpFile])) {
- $this->fromTmpFile($tmpFile, self::$tempFiles[$tmpFile]);
- unlink($tmpFile);
+ public function getMimeType($path) {
+ $path = $this->normalizePath($path);
+
+ if ($this->is_dir($path)) {
+ return 'httpd/unix-directory';
+ } else if ($this->file_exists($path)) {
+ $object = $this->container->DataObject($path);
+ return $object->extra_headers["Content-Type"];
}
+ return false;
}
- public function touch($path, $mtime=null) {
- $this->init();
- $obj=$this->getObject($path);
- if (is_null($obj)) {
- return false;
+ public function touch($path, $mtime = null) {
+ $path = $this->normalizePath($path);
+ if ($this->file_exists($path)) {
+ if ($this->is_dir($path) && $path != '.') {
+ $path .= '/';
+ }
+
+ $object = $this->container->DataObject($path);
+ if( is_null($mtime)) {
+ $mtime = time();
+ }
+ $settings = array(
+ 'name' => $path,
+ 'extra_headers' => array(
+ 'X-Object-Meta-Timestamp' => $mtime
+ )
+ );
+ return $object->Update($settings);
+ } else {
+ $object = $this->container->DataObject();
+ if (is_null($mtime)) {
+ $mtime = time();
+ }
+ $settings = array(
+ 'name' => $path,
+ 'content_type' => 'text/plain',
+ 'extra_headers' => array(
+ 'X-Object-Meta-Timestamp' => $mtime
+ )
+ );
+ return $object->Create($settings);
}
- if (is_null($mtime)) {
- $mtime=time();
+ }
+
+ public function copy($path1, $path2) {
+ $path1 = $this->normalizePath($path1);
+ $path2 = $this->normalizePath($path2);
+
+ if ($this->is_file($path1)) {
+ try {
+ $source = $this->container->DataObject($path1);
+ $target = $this->container->DataObject();
+ $target->Create(array(
+ 'name' => $path2,
+ ));
+ $source->Copy($target);
+ } catch (Exceptions\ObjectCopyError $e) {
+ \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
+ return false;
+ }
+ } else {
+ if ($this->file_exists($path2)) {
+ return false;
+ }
+
+ try {
+ $source = $this->container->DataObject($path1 . '/');
+ $target = $this->container->DataObject();
+ $target->Create(array(
+ 'name' => $path2 . '/',
+ ));
+ $source->Copy($target);
+ } catch (Exceptions\ObjectCopyError $e) {
+ \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
+ return false;
+ }
+
+ $dh = $this->opendir($path1);
+ while ($file = readdir($dh)) {
+ if ($file === '.' || $file === '..') {
+ continue;
+ }
+
+ $source = $path1 . '/' . $file;
+ $target = $path2 . '/' . $file;
+ $this->copy($source, $target);
+ }
}
- //emulate setting mtime with metadata
- $obj->metadata['Mtime']=$mtime;
- $obj->sync_metadata();
+ return true;
}
public function rename($path1, $path2) {
- $this->init();
- $sourceContainer=$this->getContainer(dirname($path1));
- $targetContainer=$this->getContainer(dirname($path2));
- $result=$sourceContainer->move_object_to(basename($path1), $targetContainer, basename($path2));
- unset($this->objects[$path1]);
- if ($result) {
- $targetObj=$this->getObject($path2);
- $this->resetMTime($targetObj);
- }
- return $result;
- }
+ $path1 = $this->normalizePath($path1);
+ $path2 = $this->normalizePath($path2);
- public function copy($path1, $path2) {
- $this->init();
- $sourceContainer=$this->getContainer(dirname($path1));
- $targetContainer=$this->getContainer(dirname($path2));
- $result=$sourceContainer->copy_object_to(basename($path1), $targetContainer, basename($path2));
- if ($result) {
- $targetObj=$this->getObject($path2);
- $this->resetMTime($targetObj);
- }
- return $result;
- }
+ if ($this->is_file($path1)) {
+ if ($this->copy($path1, $path2) === false) {
+ return false;
+ }
- public function stat($path) {
- $this->init();
- $container=$this->getContainer($path);
- if ( ! is_null($container)) {
- return array(
- 'mtime'=>-1,
- 'size'=>$container->bytes_used,
- 'ctime'=>-1
- );
- }
+ if ($this->unlink($path1) === false) {
+ $this->unlink($path2);
+ return false;
+ }
+ } else {
+ if ($this->file_exists($path2)) {
+ return false;
+ }
- $obj=$this->getObject($path);
+ if ($this->copy($path1, $path2) === false) {
+ return false;
+ }
- if (is_null($obj)) {
- return false;
+ if ($this->rmdir($path1) === false) {
+ $this->rmdir($path2);
+ return false;
+ }
}
- if (isset($obj->metadata['Mtime']) and $obj->metadata['Mtime']>-1) {
- $mtime=$obj->metadata['Mtime'];
- } else {
- $mtime=strtotime($obj->last_modified);
- }
- return array(
- 'mtime'=>$mtime,
- 'size'=>$obj->content_length,
- 'ctime'=>-1,
- );
+ return true;
}
- private function getTmpFile($path) {
- $this->init();
- $obj=$this->getObject($path);
- if ( ! is_null($obj)) {
- $tmpFile=\OCP\Files::tmpFile();
- $obj->save_to_filename($tmpFile);
- return $tmpFile;
- } else {
- return \OCP\Files::tmpFile();
- }
+ public function getId() {
+ return $this->id;
}
- private function fromTmpFile($tmpFile, $path) {
- $this->init();
- $obj=$this->getObject($path);
- if (is_null($obj)) {
- $obj=$this->createObject($path);
- }
- $obj->load_from_filename($tmpFile);
- $this->resetMTime($obj);
+ public function getConnection() {
+ return $this->connection;
}
- /**
- * remove custom mtime metadata
- * @param \CF_Object $obj
- */
- private function resetMTime($obj) {
- if (isset($obj->metadata['Mtime'])) {
- $obj->metadata['Mtime']=-1;
- $obj->sync_metadata();
+ public function writeBack($tmpFile) {
+ if (!isset(self::$tmpFiles[$tmpFile])) {
+ return false;
}
+
+ $object = $this->container->DataObject();
+ $object->Create(array(
+ 'name' => self::$tmpFiles[$tmpFile],
+ 'content_type' => \OC_Helper::getMimeType($tmpFile)
+ ), $tmpFile);
+ unlink($tmpFile);
}
}
diff --git a/apps/files_external/lib/webdav.php b/apps/files_external/lib/webdav.php
index 66920fc9f64..0f8034e57d9 100644
--- a/apps/files_external/lib/webdav.php
+++ b/apps/files_external/lib/webdav.php
@@ -14,6 +14,7 @@ class DAV extends \OC\Files\Storage\Common{
private $host;
private $secure;
private $root;
+ private $certPath;
private $ready;
/**
* @var \Sabre_DAV_Client
@@ -40,6 +41,12 @@ class DAV extends \OC\Files\Storage\Common{
} else {
$this->secure = false;
}
+ if ($this->secure === true) {
+ $certPath=\OC_User::getHome(\OC_User::getUser()) . '/files_external/rootcerts.crt';
+ if (file_exists($certPath)) {
+ $this->certPath=$certPath;
+ }
+ }
$this->root=isset($params['root'])?$params['root']:'/';
if ( ! $this->root || $this->root[0]!='/') {
$this->root='/'.$this->root;
@@ -58,20 +65,16 @@ class DAV extends \OC\Files\Storage\Common{
}
$this->ready = true;
- $settings = array(
- 'baseUri' => $this->createBaseUri(),
- 'userName' => $this->user,
- 'password' => $this->password,
- );
+ $settings = array(
+ 'baseUri' => $this->createBaseUri(),
+ 'userName' => $this->user,
+ 'password' => $this->password,
+ );
$this->client = new \Sabre_DAV_Client($settings);
- $caview = \OCP\Files::getStorage('files_external');
- if ($caview) {
- $certPath=\OCP\Config::getSystemValue('datadirectory').$caview->getAbsolutePath("").'rootcerts.crt';
- if (file_exists($certPath)) {
- $this->client->addTrustedCertificates($certPath);
- }
+ if ($this->secure === true && $this->certPath) {
+ $this->client->addTrustedCertificates($this->certPath);
}
}
@@ -79,7 +82,7 @@ class DAV extends \OC\Files\Storage\Common{
return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root;
}
- private function createBaseUri() {
+ protected function createBaseUri() {
$baseUri='http';
if ($this->secure) {
$baseUri.='s';
@@ -134,14 +137,6 @@ class DAV extends \OC\Files\Storage\Common{
}
}
- public function isReadable($path) {
- return true;//not properly supported
- }
-
- public function isUpdatable($path) {
- return true;//not properly supported
- }
-
public function file_exists($path) {
$this->init();
$path=$this->cleanPath($path);
@@ -174,7 +169,14 @@ class DAV extends \OC\Files\Storage\Common{
curl_setopt($curl, CURLOPT_URL, $this->createBaseUri().str_replace(' ', '%20', $path));
curl_setopt($curl, CURLOPT_FILE, $fp);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
-
+ if ($this->secure === true) {
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
+ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
+ if($this->certPath){
+ curl_setopt($curl, CURLOPT_CAINFO, $this->certPath);
+ }
+ }
+
curl_exec ($curl);
curl_close ($curl);
rewind($fp);
@@ -242,6 +244,7 @@ class DAV extends \OC\Files\Storage\Common{
} else {
$this->file_put_contents($path, '');
}
+ return true;
}
public function getFile($path, $target) {
@@ -261,6 +264,13 @@ class DAV extends \OC\Files\Storage\Common{
curl_setopt($curl, CURLOPT_INFILE, $source); // file pointer
curl_setopt($curl, CURLOPT_INFILESIZE, filesize($path));
curl_setopt($curl, CURLOPT_PUT, true);
+ if ($this->secure === true) {
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
+ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
+ if($this->certPath){
+ curl_setopt($curl, CURLOPT_CAINFO, $this->certPath);
+ }
+ }
curl_exec ($curl);
curl_close ($curl);
}
@@ -268,7 +278,7 @@ class DAV extends \OC\Files\Storage\Common{
public function rename($path1, $path2) {
$this->init();
$path1=$this->cleanPath($path1);
- $path2=$this->root.$this->cleanPath($path2);
+ $path2=$this->createBaseUri().$this->cleanPath($path2);
try {
$this->client->request('MOVE', $path1, null, array('Destination'=>$path2));
return true;
@@ -280,7 +290,7 @@ class DAV extends \OC\Files\Storage\Common{
public function copy($path1, $path2) {
$this->init();
$path1=$this->cleanPath($path1);
- $path2=$this->root.$this->cleanPath($path2);
+ $path2=$this->createBaseUri().$this->cleanPath($path2);
try {
$this->client->request('COPY', $path1, null, array('Destination'=>$path2));
return true;
@@ -323,11 +333,9 @@ class DAV extends \OC\Files\Storage\Common{
}
public function cleanPath($path) {
- if ( ! $path || $path[0]=='/') {
- return substr($path, 1);
- } else {
- return $path;
- }
+ $path = \OC\Files\Filesystem::normalizePath($path);
+ // remove leading slash
+ return substr($path, 1);
}
private function simpleResponse($method, $path, $body, $expected) {
@@ -340,3 +348,4 @@ class DAV extends \OC\Files\Storage\Common{
}
}
}
+
diff --git a/apps/files_external/templates/settings.php b/apps/files_external/templates/settings.php
index 028a384cf34..3ca16c3c7a8 100644
--- a/apps/files_external/templates/settings.php
+++ b/apps/files_external/templates/settings.php
@@ -2,7 +2,7 @@
<fieldset class="personalblock">
<h2><?php p($l->t('External Storage')); ?></h2>
<?php if (isset($_['dependencies']) and ($_['dependencies']<>'')) print_unescaped(''.$_['dependencies'].''); ?>
- <table id="externalStorage" data-admin='<?php print_unescaped(json_encode($_['isAdminPage'])); ?>'>
+ <table id="externalStorage" class="grid" data-admin='<?php print_unescaped(json_encode($_['isAdminPage'])); ?>'>
<thead>
<tr>
<th></th>
@@ -60,7 +60,7 @@
class="optional"
data-parameter="<?php p($parameter); ?>"
value="<?php p($value); ?>"
- placeholder="<?php p(substr($placeholder, 5)); ?>" />
+ placeholder="<?php p(substr($placeholder, 1)); ?>" />
<?php elseif (strpos($placeholder, '#') !== false): ?>
<input type="hidden"
data-parameter="<?php p($parameter); ?>"
diff --git a/apps/files_external/tests/config.php b/apps/files_external/tests/config.php
index d4a69d29c0f..e296bfcb5b2 100644
--- a/apps/files_external/tests/config.php
+++ b/apps/files_external/tests/config.php
@@ -23,6 +23,13 @@ return array(
'password'=>'test',
'root'=>'/owncloud/files/webdav.php',
),
+ 'owncloud'=>array(
+ 'run'=>true,
+ 'host'=>'localhost/owncloud',
+ 'user'=>'test',
+ 'password'=>'test',
+ 'root'=>'',
+ ),
'google'=>array(
'run'=> false,
'configured' => 'true',
@@ -30,12 +37,17 @@ return array(
'client_secret' => '',
'token' => '',
),
- 'swift'=>array(
- 'run'=>false,
- 'user'=>'test:tester',
- 'token'=>'testing',
- 'host'=>'localhost.local:8080/auth',
- 'root'=>'/',
+ 'swift' => array(
+ 'run' => false,
+ 'user' => 'test',
+ 'bucket' => 'test',
+ 'region' => 'DFW',
+ 'key' => 'test', //to be used only with Rackspace Cloud Files
+ //'tenant' => 'test', //to be used only with OpenStack Object Storage
+ //'password' => 'test', //to be use only with OpenStack Object Storage
+ //'service_name' => 'swift', //should be 'swift' for OpenStack Object Storage and 'cloudFiles' for Rackspace Cloud Files (default value)
+ //'url' => 'https://identity.api.rackspacecloud.com/v2.0/', //to be used with Rackspace Cloud Files and OpenStack Object Storage
+ //'timeout' => 5 // timeout of HTTP requests in seconds
),
'smb'=>array(
'run'=>false,
diff --git a/apps/files_external/tests/dropbox.php b/apps/files_external/tests/dropbox.php
index e4e598b06b0..4b052282019 100644
--- a/apps/files_external/tests/dropbox.php
+++ b/apps/files_external/tests/dropbox.php
@@ -21,6 +21,22 @@ class Dropbox extends Storage {
$this->instance = new \OC\Files\Storage\Dropbox($this->config['dropbox']);
}
+ public function directoryProvider() {
+ // doesn't support leading/trailing spaces
+ return array(array('folder'));
+ }
+
+ public function testDropboxTouchReturnValue() {
+ $this->assertFalse($this->instance->file_exists('foo'));
+
+ // true because succeeded
+ $this->assertTrue($this->instance->touch('foo'));
+ $this->assertTrue($this->instance->file_exists('foo'));
+
+ // false because not supported
+ $this->assertFalse($this->instance->touch('foo'));
+ }
+
public function tearDown() {
if ($this->instance) {
$this->instance->unlink('/');
diff --git a/apps/files_external/tests/ftp.php b/apps/files_external/tests/ftp.php
index e146725473a..3037793120a 100644
--- a/apps/files_external/tests/ftp.php
+++ b/apps/files_external/tests/ftp.php
@@ -34,19 +34,31 @@ class FTP extends Storage {
'password' => 'ftp',
'root' => '/',
'secure' => false );
- $instance = new OC_Filestorage_FTP($config);
+ $instance = new \OC\Files\Storage\FTP($config);
$this->assertEquals('ftp://ftp:ftp@localhost/', $instance->constructUrl(''));
$config['secure'] = true;
- $instance = new OC_Filestorage_FTP($config);
+ $instance = new \OC\Files\Storage\FTP($config);
$this->assertEquals('ftps://ftp:ftp@localhost/', $instance->constructUrl(''));
$config['secure'] = 'false';
- $instance = new OC_Filestorage_FTP($config);
+ $instance = new \OC\Files\Storage\FTP($config);
$this->assertEquals('ftp://ftp:ftp@localhost/', $instance->constructUrl(''));
$config['secure'] = 'true';
- $instance = new OC_Filestorage_FTP($config);
+ $instance = new \OC\Files\Storage\FTP($config);
$this->assertEquals('ftps://ftp:ftp@localhost/', $instance->constructUrl(''));
+
+ $config['root'] = '';
+ $instance = new \OC\Files\Storage\FTP($config);
+ $this->assertEquals('ftps://ftp:ftp@localhost/somefile.txt', $instance->constructUrl('somefile.txt'));
+
+ $config['root'] = '/abc';
+ $instance = new \OC\Files\Storage\FTP($config);
+ $this->assertEquals('ftps://ftp:ftp@localhost/abc/somefile.txt', $instance->constructUrl('somefile.txt'));
+
+ $config['root'] = '/abc/';
+ $instance = new \OC\Files\Storage\FTP($config);
+ $this->assertEquals('ftps://ftp:ftp@localhost/abc/somefile.txt', $instance->constructUrl('somefile.txt'));
}
}
diff --git a/apps/files_external/tests/mountconfig.php b/apps/files_external/tests/mountconfig.php
new file mode 100644
index 00000000000..941aec680bb
--- /dev/null
+++ b/apps/files_external/tests/mountconfig.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Vincent Petry
+ * Copyright (c) 2013 Vincent Petry <pvince81@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/>.
+ *
+ */
+
+require_once __DIR__ . '/../../../lib/base.php';
+
+require __DIR__ . '/../lib/config.php';
+
+class Test_Mount_Config_Dummy_Storage {
+ public function test() {
+ return true;
+ }
+}
+
+/**
+ * Class Test_Mount_Config
+ */
+class Test_Mount_Config extends \PHPUnit_Framework_TestCase {
+ /**
+ * Test mount point validation
+ */
+ public function testAddMountPointValidation() {
+ $storageClass = 'Test_Mount_Config_Dummy_Storage';
+ $mountType = 'user';
+ $applicable = 'all';
+ $isPersonal = false;
+ $this->assertEquals(false, OC_Mount_Config::addMountPoint('', $storageClass, array(), $mountType, $applicable, $isPersonal));
+ $this->assertEquals(false, OC_Mount_Config::addMountPoint('/', $storageClass, array(), $mountType, $applicable, $isPersonal));
+ $this->assertEquals(false, OC_Mount_Config::addMountPoint('Shared', $storageClass, array(), $mountType, $applicable, $isPersonal));
+ $this->assertEquals(false, OC_Mount_Config::addMountPoint('/Shared', $storageClass, array(), $mountType, $applicable, $isPersonal));
+
+ }
+}
diff --git a/apps/files_external/tests/owncloud.php b/apps/files_external/tests/owncloud.php
new file mode 100644
index 00000000000..408a55864f2
--- /dev/null
+++ b/apps/files_external/tests/owncloud.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Copyright (c) 2013 Vincent Petry <pvince81@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Test\Files\Storage;
+
+class OwnCloud extends Storage {
+
+ private $config;
+
+ public function setUp() {
+ $id = uniqid();
+ $this->config = include('files_external/tests/config.php');
+ if ( ! is_array($this->config) or ! isset($this->config['owncloud']) or ! $this->config['owncloud']['run']) {
+ $this->markTestSkipped('ownCloud backend not configured');
+ }
+ $this->config['owncloud']['root'] .= '/' . $id; //make sure we have an new empty folder to work in
+ $this->instance = new \OC\Files\Storage\OwnCloud($this->config['owncloud']);
+ $this->instance->mkdir('/');
+ }
+
+ public function tearDown() {
+ if ($this->instance) {
+ $this->instance->rmdir('/');
+ }
+ }
+}
diff --git a/apps/files_external/tests/smb.php b/apps/files_external/tests/smb.php
index ca2a93c8944..199e35af676 100644
--- a/apps/files_external/tests/smb.php
+++ b/apps/files_external/tests/smb.php
@@ -15,7 +15,7 @@ class SMB extends Storage {
public function setUp() {
$id = uniqid();
$this->config = include('files_external/tests/config.php');
- if ( ! is_array($this->config) or ! isset($this->config['smb']) or ! $this->config['smb']['run']) {
+ if (!is_array($this->config) or !isset($this->config['smb']) or !$this->config['smb']['run']) {
$this->markTestSkipped('Samba backend not configured');
}
$this->config['smb']['root'] .= $id; //make sure we have an new empty folder to work in
@@ -28,4 +28,16 @@ class SMB extends Storage {
\OCP\Files::rmdirr($this->instance->constructUrl(''));
}
}
+
+ public function directoryProvider() {
+ // doesn't support leading/trailing spaces
+ return array(array('folder'));
+ }
+
+ public function testRenameWithSpaces() {
+ $this->instance->mkdir('with spaces');
+ $result = $this->instance->rename('with spaces', 'foo bar');
+ $this->assertTrue($result);
+ $this->assertTrue($this->instance->is_dir('foo bar'));
+ }
}
diff --git a/apps/files_external/tests/smbfunctions.php b/apps/files_external/tests/smbfunctions.php
new file mode 100644
index 00000000000..749906d0136
--- /dev/null
+++ b/apps/files_external/tests/smbfunctions.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Copyright (c) 2013 Vincent Petry <pvince81@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Test\Files\Storage;
+
+class SMBFunctions extends \PHPUnit_Framework_TestCase {
+
+ public function setUp() {
+ $id = uniqid();
+ // dummy config
+ $this->config = array(
+ 'run'=>false,
+ 'user'=>'test',
+ 'password'=>'testpassword',
+ 'host'=>'smbhost',
+ 'share'=>'/sharename',
+ 'root'=>'/rootdir/',
+ );
+
+ $this->instance = new \OC\Files\Storage\SMB($this->config);
+ }
+
+ public function tearDown() {
+ }
+
+ public function testGetId() {
+ $this->assertEquals('smb::test@smbhost//sharename//rootdir/', $this->instance->getId());
+ }
+
+ public function testConstructUrl() {
+ $this->assertEquals("smb://test:testpassword@smbhost/sharename/rootdir/abc", $this->instance->constructUrl('/abc'));
+ $this->assertEquals("smb://test:testpassword@smbhost/sharename/rootdir/abc", $this->instance->constructUrl('/abc/'));
+ $this->assertEquals("smb://test:testpassword@smbhost/sharename/rootdir/abc%2F", $this->instance->constructUrl('/abc/.'));
+ $this->assertEquals("smb://test:testpassword@smbhost/sharename/rootdir/abc%2Fdef", $this->instance->constructUrl('/abc/def'));
+ }
+}
diff --git a/apps/files_external/tests/swift.php b/apps/files_external/tests/swift.php
index 5c782840246..bdfdbdeebe9 100644
--- a/apps/files_external/tests/swift.php
+++ b/apps/files_external/tests/swift.php
@@ -1,30 +1,51 @@
<?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.
+ * ownCloud
+ *
+ * @author Christian Berendt
+ * @copyright 2013 Christian Berendt berendt@b1-systems.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/>.
*/
namespace Test\Files\Storage;
-class SWIFT extends Storage {
+class Swift extends Storage {
+
private $config;
public function setUp() {
- $id = uniqid();
$this->config = include('files_external/tests/config.php');
- if ( ! is_array($this->config) or ! isset($this->config['swift']) or ! $this->config['swift']['run']) {
- $this->markTestSkipped('OpenStack SWIFT backend not configured');
+ if (!is_array($this->config) or !isset($this->config['swift'])
+ or !$this->config['swift']['run']) {
+ $this->markTestSkipped('OpenStack Object Storage backend not configured');
}
- $this->config['swift']['root'] .= '/' . $id; //make sure we have an new empty folder to work in
- $this->instance = new \OC\Files\Storage\SWIFT($this->config['swift']);
+ $this->instance = new \OC\Files\Storage\Swift($this->config['swift']);
}
-
public function tearDown() {
if ($this->instance) {
- $this->instance->rmdir('');
+ $connection = $this->instance->getConnection();
+ $container = $connection->Container($this->config['swift']['bucket']);
+
+ $objects = $container->ObjectList();
+ while($object = $objects->Next()) {
+ $object->Delete();
+ }
+
+ $container->Delete();
}
}
}