Projects
Kolab:Winterfell
roundcubemail-selfcontained
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 4
View file
roundcubemail.spec
Changed
@@ -48,7 +48,7 @@ %global logdir /var/log/roundcubemail %global tmpdir /var/lib/roundcubemail -%global rc_version 1.4.11.20 +%global rc_version 1.4.13 %global plugin_version 3.5.9 #%%global rc_rel_suffix rc2.12 %global dot_rel_suffix %{?rc_rel_suffix:.%{rc_rel_suffix}}
View file
buildroundcubemailtarball.sh
Changed
@@ -2,11 +2,16 @@ set -e -VERSION=1.4.11.20 -GIT_REF=1.4.11-20-g4e1358b4d +VERSION=1.4.13 +GIT_REF=1.4.13 NAME=roundcubemail-$VERSION PLESK_SKIN="roundcubemail-skin-plesk-0.4.0" -LESSC=~/node_modules/less/bin/lessc + +if [ -x "/usr/local/bin/lessc" ]; then + LESSC=/usr/local/bin/lessc +else + LESSC=~/node_modules/less/bin/lessc +fi ROOT_DIR=$(pwd) @@ -42,6 +47,13 @@ }, { "type": "path", + "url": "$PWD/roundcubemail-plugins-kolab-latest/plugins/kolab_auth", + "options": { + "symlink": false + } + }, + { + "type": "path", "url": "$PWD/roundcubemail-plugins-kolab-latest/plugins/kolab_config", "options": { "symlink": false @@ -145,16 +157,19 @@ "kolab/calendar": "~3.5.9", "kolab/kolab_activesync": "~3.5.6", "kolab/kolab_addressbook": "~3.5.6", - "kolab/kolab_config": "~3.4.0", + "kolab/kolab_auth": "~3.5.6", "kolab/kolab_chat": "~3.5.2", + "kolab/kolab_config": "~3.4.0", "kolab/kolab_files": "~3.5.2", "kolab/kolab_folders": "~3.5.2", "kolab/kolab_notes": "~3.5.5", "kolab/kolab_tags": "~3.5.2", + "kolab/net_ldap3": "~1.1.1", "kolab/odfviewer": "~3.4.0", "kolab/pdfviewer": "~3.4.0", "kolab/tasklist": "~3.5.9", "johndoh/contextmenu": "~3.2.1", + "zf1/zend-json": "~1.12.11", "zf1/zend-log": "~1.12.11", "zf1/zend-controller": "~1.12.11", "sabre/dav" : "~2.1.6", @@ -165,7 +180,6 @@ "phpunit/phpunit": "^4.8.36 || ^5.7.21" }, "suggest": { - "kolab/net_ldap3": "~1.1.1 required for connecting to LDAP", "mkopinsky/zxcvbn-php": "^4.4.2 required for Zxcvbn password strength driver" } } @@ -255,7 +269,6 @@ popd - tar --exclude="$NAME/.git" -czf "$ROOT_DIR/$NAME.tar.gz" $NAME cd "$PWD"
View file
debian.changelog
Changed
@@ -1,3 +1,9 @@ +roundcubemail (1.4.13-0~kolab1) unstable; urgency=low + + * Check in 1.4.13 + + -- Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> Fri, 14 Jan 2022 11:11:11 +0200 + roundcubemail (1.4.11.20-0~kolab1) unstable; urgency=low * Check in 1.4.11.20
View file
roundcubemail-1.4.11.20.tar.gz/CHANGELOG -> roundcubemail-1.4.13.tar.gz/CHANGELOG
Changed
@@ -1,7 +1,12 @@ CHANGELOG Roundcube Webmail =========================== -- Disable the default spellchecker option using spell.roundcube.net (#8182) +RELEASE 1.4.13 +-------------- +- Security: Fix cross-site scripting (XSS) via HTML messages with malicious CSS content + +RELEASE 1.4.12 +-------------- - Enigma: Fix bug where signature verification could fail for non-ascii bodies (#7919) - Fix bug where contacts search didn't work with addressbook_search_mods set to an empty array (#7974) - Fix bug causing some HTML message content to be not centered in Elastic skin (#7911)
View file
roundcubemail-1.4.11.20.tar.gz/composer.json -> roundcubemail-1.4.13.tar.gz/composer.json
Changed
@@ -10,98 +10,105 @@ "repositories": [ { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_activesync", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_activesync", "options": { "symlink": false } }, { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_addressbook", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_addressbook", "options": { "symlink": false } }, { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_config", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_auth", "options": { "symlink": false } }, { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_files", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_config", "options": { "symlink": false } }, { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_folders", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_files", "options": { "symlink": false } }, { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_notes", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_folders", "options": { "symlink": false } }, { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_tags", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_notes", "options": { "symlink": false } }, { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_chat", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_tags", "options": { "symlink": false } }, { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/odfviewer", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_chat", "options": { "symlink": false } }, { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/pdfviewer", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/odfviewer", "options": { "symlink": false } }, { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/tasklist", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/pdfviewer", "options": { "symlink": false } }, { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/calendar", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/tasklist", "options": { "symlink": false } }, { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/libcalendaring", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/calendar", "options": { "symlink": false } }, { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/libkolab", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/libcalendaring", + "options": { + "symlink": false + } + }, + { + "type": "path", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/libkolab", "options": { "symlink": false } @@ -127,16 +134,19 @@ "kolab/calendar": "~3.5.9", "kolab/kolab_activesync": "~3.5.6", "kolab/kolab_addressbook": "~3.5.6", - "kolab/kolab_config": "~3.4.0", + "kolab/kolab_auth": "~3.5.6", "kolab/kolab_chat": "~3.5.2", + "kolab/kolab_config": "~3.4.0", "kolab/kolab_files": "~3.5.2", "kolab/kolab_folders": "~3.5.2", "kolab/kolab_notes": "~3.5.5", "kolab/kolab_tags": "~3.5.2", + "kolab/net_ldap3": "~1.1.1", "kolab/odfviewer": "~3.4.0", "kolab/pdfviewer": "~3.4.0", "kolab/tasklist": "~3.5.9", "johndoh/contextmenu": "~3.2.1", + "zf1/zend-json": "~1.12.11", "zf1/zend-log": "~1.12.11", "zf1/zend-controller": "~1.12.11", "sabre/dav" : "~2.1.6", @@ -147,7 +157,6 @@ "phpunit/phpunit": "^4.8.36 || ^5.7.21" }, "suggest": { - "kolab/net_ldap3": "~1.1.1 required for connecting to LDAP", "mkopinsky/zxcvbn-php": "^4.4.2 required for Zxcvbn password strength driver" } }
View file
roundcubemail-1.4.11.20.tar.gz/composer.lock -> roundcubemail-1.4.13.tar.gz/composer.lock
Changed
@@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7d3579392baf5b35c391ae0ae452a2ba", + "content-hash": "e65d5f8b63e0f2575bc85a12dfffc054", "packages": [ { "name": "caxy/php-htmldiff", @@ -224,7 +224,7 @@ "version": "3.5.10", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/calendar", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/calendar", "reference": "45103d5bdee63f976c918f8cfcf20b400310bcb0" }, "require": { @@ -267,7 +267,7 @@ "version": "3.5.6", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_activesync", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_activesync", "reference": "7e8c46290074fe6c1ab72bc9f6b90aa271ee16ef" }, "require": { @@ -303,7 +303,7 @@ "version": "3.5.10", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_addressbook", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_addressbook", "reference": "29195279f672640ffe38f70ddabe87b56172e889" }, "require": { @@ -335,11 +335,47 @@ } }, { + "name": "kolab/kolab_auth", + "version": "3.5.8", + "dist": { + "type": "path", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_auth", + "reference": "ab0ed459f74a03f8eab6822652e084f0430a4f07" + }, + "require": { + "kolab/libkolab": ">=3.5.1", + "php": ">=5.3.0", + "roundcube/plugin-installer": ">=0.1.3" + }, + "type": "roundcube-plugin", + "license": [ + "AGPLv3" + ], + "authors": [ + { + "name": "Thomas Bruederli", + "email": "bruederli@kolabsys.com", + "role": "Lead" + }, + { + "name": "Aleksander Machniak", + "email": "machniak@kolabsys.com", + "role": "Lead" + } + ], + "description": "Kolab authentication", + "homepage": "https://git.kolab.org/diffusion/RPK/", + "transport-options": { + "symlink": false, + "relative": false + } + }, + { "name": "kolab/kolab_chat", "version": "3.5.4", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_chat", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_chat", "reference": "b2f85fcb8324b9961dd02fb3e3acd92be33b558e" }, "require": { @@ -370,7 +406,7 @@ "version": "3.4.0", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_config", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_config", "reference": "b31a76c1700679249fc222c46582ecbd1215f117" }, "require": { @@ -401,7 +437,7 @@ "version": "3.5.2", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_files", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_files", "reference": "0439d3783b59d6e52f23e86046881fd0ca8c0bd5" }, "require": { @@ -432,7 +468,7 @@ "version": "3.5.2", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_folders", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_folders", "reference": "c70560fcfe40bf1582ea79debf3ae2aebbe94688" }, "require": { @@ -463,7 +499,7 @@ "version": "3.5.5", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_notes", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_notes", "reference": "07297b8ea8b3827d0ba46801760854b0db560576" }, "require": { @@ -499,7 +535,7 @@ "version": "3.5.2", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_tags", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_tags", "reference": "62ffa5279d9f351941be6b23b0d0478aeff91bfd" }, "require": { @@ -530,7 +566,7 @@ "version": "3.5.10", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/libcalendaring", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/libcalendaring", "reference": "b9ab21ae1a5b134a06c66d55372712630171a590" }, "require": { @@ -566,7 +602,7 @@ "version": "3.5.10", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/libkolab", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/libkolab", "reference": "a8abbba8039ee3bdde7be1b6758893aeff0287d8" }, "require": { @@ -599,11 +635,65 @@ } }, { + "name": "kolab/net_ldap3", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://gitlab.com/roundcube/net_ldap3.git", + "reference": "e1835e36fa5d3434f9804670fc3cdd16992ec66a" + }, + "dist": { + "type": "zip", + "url": "https://gitlab.com/api/v4/projects/roundcube%2Fnet_ldap3/repository/archive.zip?sha=e1835e36fa5d3434f9804670fc3cdd16992ec66a", + "reference": "e1835e36fa5d3434f9804670fc3cdd16992ec66a", + "shasum": "" + }, + "require": { + "pear/net_ldap2": ">=2.0.12", + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-3.0+" + ], + "authors": [ + { + "name": "Jeroen van Meeuwen", + "email": "vanmeeuwen@kolabsys.com", + "role": "Lead" + }, + { + "name": "Aleksander Machniak", + "email": "machniak@kolabsys.com", + "role": "Developer" + }, + { + "name": "Thomas Bruederli", + "email": "roundcube@gmail.com", + "role": "Developer" + } + ], + "description": "A successor of the PEAR:Net_LDAP2 module providing advanced functionality for accessing LDAP directories", + "homepage": "http://git.kolab.org/pear/Net_LDAP3/", + "keywords": [ + "PEAR", + "ldap", + "vlv" + ], + "time": "2019-10-21T11:18:59+00:00" + }, + { "name": "kolab/odfviewer", "version": "3.4.0", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/odfviewer", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/odfviewer", "reference": "43f3c0cf314cb818f9bc96d6bd378793e22a4ed4" }, "require": { @@ -633,7 +723,7 @@ "version": "3.4.0", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/pdfviewer", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/pdfviewer", "reference": "3437085223a60d929fbf076c232008e4377407c1" }, "require": { @@ -663,7 +753,7 @@ "version": "3.5.10", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/tasklist", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/tasklist", "reference": "7ae02f72964925d19fb244754f9d3e9b20af677c" }, "require": { @@ -1227,6 +1317,49 @@ "time": "2017-03-06T20:46:41+00:00" }, { + "name": "pear/net_ldap2", + "version": "v2.2.0", + "source": { + "type": "git", + "url": "https://github.com/pear/Net_LDAP2.git", + "reference": "38f1b22a96dfbd7ec53852f0e1e7ec1a9a5eb0e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pear/Net_LDAP2/zipball/38f1b22a96dfbd7ec53852f0e1e7ec1a9a5eb0e8", + "reference": "38f1b22a96dfbd7ec53852f0e1e7ec1a9a5eb0e8", + "shasum": "" + }, + "require": { + "ext-ldap": "*", + "pear/pear-core-minimal": "^1.10.1" + }, + "type": "library", + "autoload": { + "classmap": [ + "Net/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "." + ], + "license": [ + "LGPL-3.0" + ], + "description": "Object oriented interface for searching and manipulating LDAP-entries", + "homepage": "http://pear.php.net/package/Net_LDAP2", + "keywords": [ + "PEAR", + "ldap" + ], + "support": { + "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=Net_LDAP2", + "source": "https://github.com/pear/Net_LDAP2" + }, + "time": "2015-10-30T20:34:22+00:00" + }, + { "name": "pear/net_sieve", "version": "1.4.5", "source": { @@ -1907,16 +2040,16 @@ }, { "name": "smarty/smarty", - "version": "v3.1.40", + "version": "v3.1.43", "source": { "type": "git", "url": "https://github.com/smarty-php/smarty.git", - "reference": "9d4f8309ed49702e0d7152f9983c3a9c4b98eb9d" + "reference": "273f7e00fec034f6d61112552e9caf08d19565b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/smarty-php/smarty/zipball/9d4f8309ed49702e0d7152f9983c3a9c4b98eb9d", - "reference": "9d4f8309ed49702e0d7152f9983c3a9c4b98eb9d", + "url": "https://api.github.com/repos/smarty-php/smarty/zipball/273f7e00fec034f6d61112552e9caf08d19565b7", + "reference": "273f7e00fec034f6d61112552e9caf08d19565b7", "shasum": "" }, "require": { @@ -1964,9 +2097,9 @@ "forum": "http://www.smarty.net/forums/", "irc": "irc://irc.freenode.org/smarty", "issues": "https://github.com/smarty-php/smarty/issues", - "source": "https://github.com/smarty-php/smarty/tree/v3.1.40" + "source": "https://github.com/smarty-php/smarty/tree/v3.1.43" }, - "time": "2021-10-13T10:04:31+00:00" + "time": "2022-01-10T09:52:40+00:00" }, { "name": "zf1/zend-cache", @@ -2148,6 +2281,50 @@ "time": "2015-04-30T11:10:20+00:00" }, { + "name": "zf1/zend-json", + "version": "1.12.20", + "source": { + "type": "git", + "url": "https://github.com/zf1/zend-json.git", + "reference": "dbf5d4b46bdf6299bf1f7c6b1ef7311e4299602f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zf1/zend-json/zipball/dbf5d4b46bdf6299bf1f7c6b1ef7311e4299602f", + "reference": "dbf5d4b46bdf6299bf1f7c6b1ef7311e4299602f", + "shasum": "" + }, + "require": { + "php": ">=5.2.11", + "zf1/zend-exception": "self.version", + "zf1/zend-loader": "self.version", + "zf1/zend-server": "self.version", + "zf1/zend-xml": "self.version" + }, + "type": "library", + "autoload": { + "psr-0": { + "Zend_Json": "library/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Zend Framework 1 Json package", + "homepage": "http://framework.zend.com/", + "keywords": [ + "ZF1", + "framework", + "json", + "zend" + ], + "support": { + "source": "https://github.com/zf1/zend-json/tree/release-1.12.11" + }, + "time": "2015-04-30T11:11:12+00:00" + }, + { "name": "zf1/zend-loader", "version": "1.12.20", "source": { @@ -2323,6 +2500,47 @@ "time": "2017-07-11T23:55:24+00:00" }, { + "name": "zf1/zend-server", + "version": "1.12.20", + "source": { + "type": "git", + "url": "https://github.com/zf1/zend-server.git", + "reference": "ce8242896b3d63a51f3984ef1d6ed9cc9c67e547" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zf1/zend-server/zipball/ce8242896b3d63a51f3984ef1d6ed9cc9c67e547", + "reference": "ce8242896b3d63a51f3984ef1d6ed9cc9c67e547", + "shasum": "" + }, + "require": { + "php": ">=5.2.11", + "zf1/zend-exception": "self.version" + }, + "type": "library", + "autoload": { + "psr-0": { + "Zend_Server": "library/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Zend Framework 1 Server package", + "homepage": "http://framework.zend.com/", + "keywords": [ + "ZF1", + "framework", + "server", + "zend" + ], + "support": { + "source": "https://github.com/zf1/zend-server/tree/release-1.12.11" + }, + "time": "2015-04-30T11:11:32+00:00" + }, + { "name": "zf1/zend-uri", "version": "1.12.20", "source": { @@ -2751,16 +2969,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.5.1", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae" + "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/a12f7e301eb7258bb68acd89d4aefa05c2906cae", - "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706", + "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706", "shasum": "" }, "require": { @@ -2795,9 +3013,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.1" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.0" }, - "time": "2021-10-02T14:08:47+00:00" + "time": "2022-01-04T19:58:01+00:00" }, { "name": "phpspec/prophecy", @@ -3850,21 +4068,24 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.23.0", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" + "reference": "30885182c981ab175d4d034db0f6f469898070ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", + "reference": "30885182c981ab175d4d034db0f6f469898070ab", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-ctype": "*" + }, "suggest": { "ext-ctype": "For best performance" }, @@ -3909,7 +4130,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.24.0" }, "funding": [ { @@ -3925,20 +4146,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2021-10-20T20:35:02+00:00" }, { "name": "symfony/yaml", - "version": "v4.4.34", + "version": "v4.4.36", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "2c309e258adeb9970229042be39b360d34986fad" + "reference": "a19f7c44ba665fa9d9d415cc4493361381b93f9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/2c309e258adeb9970229042be39b360d34986fad", - "reference": "2c309e258adeb9970229042be39b360d34986fad", + "url": "https://api.github.com/repos/symfony/yaml/zipball/a19f7c44ba665fa9d9d415cc4493361381b93f9b", + "reference": "a19f7c44ba665fa9d9d415cc4493361381b93f9b", "shasum": "" }, "require": { @@ -3980,7 +4201,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v4.4.34" + "source": "https://github.com/symfony/yaml/tree/v4.4.36" }, "funding": [ { @@ -3996,7 +4217,7 @@ "type": "tidelift" } ], - "time": "2021-11-18T18:49:23+00:00" + "time": "2021-11-25T16:40:00+00:00" }, { "name": "webmozart/assert", @@ -4069,5 +4290,5 @@ "platform-overrides": { "php": "7.2.24" }, - "plugin-api-version": "2.1.0" + "plugin-api-version": "2.0.0" }
View file
roundcubemail-1.4.11.20.tar.gz/config/defaults.inc.php -> roundcubemail-1.4.13.tar.gz/config/defaults.inc.php
Changed
@@ -784,25 +784,28 @@ // if in your system 0 quota means no limit set this option to true $config['quota_zero_as_unlimited'] = false; -// Make use of the built-in spell checker. It is based on GoogieSpell. -$config['enable_spellcheck'] = false; +// Make use of the built-in spell checker. +$config['enable_spellcheck'] = true; // Enables spellchecker exceptions dictionary. // Setting it to 'shared' will make the dictionary shared by all users. $config['spellcheck_dictionary'] = false; // Set the spell checking engine. Possible values: -// - 'googie' - requires 'spellcheck_uri' option to be set (also used for connecting to Nox Spell Server) +// - 'googie' - the default (also used for connecting to Nox Spell Server, see 'spellcheck_uri' setting) // - 'pspell' - requires the PHP Pspell module and aspell installed // - 'enchant' - requires the PHP Enchant module // - 'atd' - install your own After the Deadline server or check with the people at http://www.afterthedeadline.com before using their API +// Since Google shut down their public spell checking service, the default settings +// connect to http://spell.roundcube.net which is a hosted service provided by Roundcube. // You can connect to any other googie-compliant service by setting 'spellcheck_uri' accordingly. $config['spellcheck_engine'] = 'googie'; // For locally installed Nox Spell Server or After the Deadline services, // please specify the URI to call it. -// Get Nox Spell Server from https://github.com/handwritingio/nox_spell_server or -// the After the Deadline package from http://www.afterthedeadline.com +// Get Nox Spell Server from http://orangoo.com/labs/?page_id=72 or +// the After the Deadline package from http://www.afterthedeadline.com. +// Leave empty to use the public API of service.afterthedeadline.com $config['spellcheck_uri'] = ''; // These languages can be selected for spell checking.
View file
roundcubemail-1.4.11.20.tar.gz/index.php -> roundcubemail-1.4.13.tar.gz/index.php
Changed
@@ -2,7 +2,7 @@ /** +-------------------------------------------------------------------------+ | Roundcube Webmail IMAP Client | - | Version 1.4.11 | + | Version 1.4.13 | | | | Copyright (C) The Roundcube Dev Team | | |
View file
roundcubemail-1.4.11.20.tar.gz/installer/index.php -> roundcubemail-1.4.13.tar.gz/installer/index.php
Changed
@@ -3,7 +3,7 @@ /** +-------------------------------------------------------------------------+ | Roundcube Webmail setup tool | - | Version 1.4.11 | + | Version 1.4.13 | | | | Copyright (C) The Roundcube Dev Team | | |
View file
roundcubemail-1.4.11.20.tar.gz/plugins/calendar/calendar.php -> roundcubemail-1.4.13.tar.gz/plugins/calendar/calendar.php
Changed
@@ -2349,7 +2349,7 @@ } $attachments = []; - $eventid = 'cal-' . (!empty($event['id']) ? $event['id'] : 'new-event'); + $eventid = 'cal-' . (!empty($event['id']) ? $event['id'] : 'new'); if (!empty($_SESSION[self::SESSION_KEY]) && $_SESSION[self::SESSION_KEY]['id'] == $eventid) { if (!empty($_SESSION[self::SESSION_KEY]['attachments'])) {
View file
roundcubemail-1.4.11.20.tar.gz/plugins/calendar/calendar_ui.js -> roundcubemail-1.4.13.tar.gz/plugins/calendar/calendar_ui.js
Changed
@@ -399,7 +399,7 @@ $('#event-alarm').show().find('.event-text').html(Q(event.alarms_text).replace(',', ',<br>')); if (calendar.name) $('#event-calendar').show().find('.event-text').html(Q(calendar.name)).addClass('cal-'+calendar.id); - if (event.categories) + if (event.categories && String(event.categories).length) $('#event-category').show().find('.event-text').text(event.categories).addClass('cat-'+String(event.categories).toLowerCase().replace(rcmail.identifier_expr, '')); if (event.free_busy) $('#event-free-busy').show().find('.event-text').text(rcmail.gettext(event.free_busy, 'calendar'));
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/LICENSE
Added
@@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +<http://www.gnu.org/licenses/>.
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/composer.json
Added
@@ -0,0 +1,31 @@ +{ + "name": "kolab/kolab_auth", + "type": "roundcube-plugin", + "description": "Kolab authentication", + "homepage": "https://git.kolab.org/diffusion/RPK/", + "license": "AGPLv3", + "version": "3.5.8", + "authors": [ + { + "name": "Thomas Bruederli", + "email": "bruederli@kolabsys.com", + "role": "Lead" + }, + { + "name": "Aleksander Machniak", + "email": "machniak@kolabsys.com", + "role": "Lead" + } + ], + "repositories": [ + { + "type": "composer", + "url": "https://plugins.roundcube.net" + } + ], + "require": { + "php": ">=5.3.0", + "roundcube/plugin-installer": ">=0.1.3", + "kolab/libkolab": ">=3.5.1" + } +}
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/config.inc.php
Added
@@ -0,0 +1,97 @@ +<?php + +// The id of the LDAP address book (which refers to the $rcmail_config['ldap_public']) +// or complete addressbook definition array. +// -------------------------------------------------------------------- +// Note: Multi-domain (hosted) installations can resolve domain aliases +// by adding following settings in kolab_auth_addressbook spec.: +// +// 'domain_base_dn' => 'cn=kolab,cn=config', +// 'domain_filter' => '(&(objectclass=domainrelatedobject)(associateddomain=%s))', +// 'domain_name_attr' => 'associateddomain', +// +// With this %dc variable in base_dn and groups/base_dn will be +// replaced with DN string of resolved domain +//--------------------------------------------------------------------- +$config['kolab_auth_addressbook'] = ''; + +// This will overwrite defined filter +$config['kolab_auth_filter'] = '(&(objectClass=kolabInetOrgPerson)(|(uid=%u)(mail=%fu)(alias=%fu)))'; + +// Use this field (from fieldmap configuration) to get authentication ID. Don't use an array here! +$config['kolab_auth_login'] = 'email'; + +// Use these fields (from fieldmap configuration) for default identity. +// If the value array contains more than one field, first non-empty will be used +// Note: These aren't LDAP attributes, but field names in config +// Note: If there's more than one email address, as many identities will be created +$config['kolab_auth_name'] = array('name', 'cn'); +$config['kolab_auth_email'] = array('email'); +$config['kolab_auth_organization'] = array('organization'); + +// Role field (from fieldmap configuration) +$config['kolab_auth_role'] = 'role'; + +// Template for user names displayed in the UI. +// You can use all attributes from the 'fieldmap' property of the 'kolab_auth_addressbook' configuration +$config['kolab_auth_user_displayname'] = '{name} ({ou})'; + +// Login and password of the admin user. Enables "Login As" feature. +$config['kolab_auth_admin_login'] = ''; +$config['kolab_auth_admin_password'] = ''; + +// Enable audit logging for abuse of administrative privileges. +$config['kolab_auth_auditlog'] = false; + +// As set of rules to define the required rights on the target entry +// which allow an admin user to login as another user (the target). +// The effective rights value refers to either entry level attribute level rights: +// * entry:[read|add|delete] +// * attrib:<attribute-name>:[read|write|delete] +$config['kolab_auth_admin_rights'] = array( + // Roundcube task => required effective right + 'settings' => 'entry:read', + 'mail' => 'entry:delete', + 'addressbook' => 'entry:delete', + // or use a wildcard entry like this: + '*' => 'entry:read', +); + +// Enable plugins on a role-by-role basis. In this example, the 'acl' plugin +// is enabled for people with a 'cn=professional-user,dc=mykolab,dc=ch' role. +// +// Note that this does NOT mean the 'acl' plugin is disabled for other people. +$config['kolab_auth_role_plugins'] = Array( + 'cn=professional-user,dc=mykolab,dc=ch' => Array( + 'acl', + ), + ); + +// Settings on a role-by-role basis. In this example, the 'htmleditor' setting +// is enabled(1) for people with a 'cn=professional-user,dc=mykolab,dc=ch' role, +// and it cannot be overridden. Sample use-case: disable htmleditor for normal people, +// do not allow the setting to be controlled through the preferences, enable the +// html editor for professional users and allow them to override the setting in +// the preferences. +$config['kolab_auth_role_settings'] = Array( + 'cn=professional-user,dc=mykolab,dc=ch' => Array( + 'htmleditor' => Array( + 'mode' => 'override', + 'value' => 1, + 'allow_override' => true + ), + ), + ); + +// List of LDAP addressbooks (keys of ldap_public configuration array) +// for which base_dn variables (%dc, etc.) will be replaced according to authenticated user DN +// Note: special name '*' for all LDAP addressbooks +$config['kolab_auth_ldap_addressbooks'] = array('*'); + +// Enables storing/updating session tokens for free-busy token authentication +// See httpauth.allow_token option in Free-Busy service config. +// The option can be set to a number of seconds after which the token-session +// expires or to true (to get the configured Roundcube session time) +$config['freebusy_session_auth'] = null; + +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/config.inc.php.dist
Added
@@ -0,0 +1,97 @@ +<?php + +// The id of the LDAP address book (which refers to the $rcmail_config['ldap_public']) +// or complete addressbook definition array. +// -------------------------------------------------------------------- +// Note: Multi-domain (hosted) installations can resolve domain aliases +// by adding following settings in kolab_auth_addressbook spec.: +// +// 'domain_base_dn' => 'cn=kolab,cn=config', +// 'domain_filter' => '(&(objectclass=domainrelatedobject)(associateddomain=%s))', +// 'domain_name_attr' => 'associateddomain', +// +// With this %dc variable in base_dn and groups/base_dn will be +// replaced with DN string of resolved domain +//--------------------------------------------------------------------- +$config['kolab_auth_addressbook'] = ''; + +// This will overwrite defined filter +$config['kolab_auth_filter'] = '(&(objectClass=kolabInetOrgPerson)(|(uid=%u)(mail=%fu)(alias=%fu)))'; + +// Use this field (from fieldmap configuration) to get authentication ID. Don't use an array here! +$config['kolab_auth_login'] = 'email'; + +// Use these fields (from fieldmap configuration) for default identity. +// If the value array contains more than one field, first non-empty will be used +// Note: These aren't LDAP attributes, but field names in config +// Note: If there's more than one email address, as many identities will be created +$config['kolab_auth_name'] = array('name', 'cn'); +$config['kolab_auth_email'] = array('email'); +$config['kolab_auth_organization'] = array('organization'); + +// Role field (from fieldmap configuration) +$config['kolab_auth_role'] = 'role'; + +// Template for user names displayed in the UI. +// You can use all attributes from the 'fieldmap' property of the 'kolab_auth_addressbook' configuration +$config['kolab_auth_user_displayname'] = '{name} ({ou})'; + +// Login and password of the admin user. Enables "Login As" feature. +$config['kolab_auth_admin_login'] = ''; +$config['kolab_auth_admin_password'] = ''; + +// Enable audit logging for abuse of administrative privileges. +$config['kolab_auth_auditlog'] = false; + +// As set of rules to define the required rights on the target entry +// which allow an admin user to login as another user (the target). +// The effective rights value refers to either entry level attribute level rights: +// * entry:[read|add|delete] +// * attrib:<attribute-name>:[read|write|delete] +$config['kolab_auth_admin_rights'] = array( + // Roundcube task => required effective right + 'settings' => 'entry:read', + 'mail' => 'entry:delete', + 'addressbook' => 'entry:delete', + // or use a wildcard entry like this: + '*' => 'entry:read', +); + +// Enable plugins on a role-by-role basis. In this example, the 'acl' plugin +// is enabled for people with a 'cn=professional-user,dc=mykolab,dc=ch' role. +// +// Note that this does NOT mean the 'acl' plugin is disabled for other people. +$config['kolab_auth_role_plugins'] = Array( + 'cn=professional-user,dc=mykolab,dc=ch' => Array( + 'acl', + ), + ); + +// Settings on a role-by-role basis. In this example, the 'htmleditor' setting +// is enabled(1) for people with a 'cn=professional-user,dc=mykolab,dc=ch' role, +// and it cannot be overridden. Sample use-case: disable htmleditor for normal people, +// do not allow the setting to be controlled through the preferences, enable the +// html editor for professional users and allow them to override the setting in +// the preferences. +$config['kolab_auth_role_settings'] = Array( + 'cn=professional-user,dc=mykolab,dc=ch' => Array( + 'htmleditor' => Array( + 'mode' => 'override', + 'value' => 1, + 'allow_override' => true + ), + ), + ); + +// List of LDAP addressbooks (keys of ldap_public configuration array) +// for which base_dn variables (%dc, etc.) will be replaced according to authenticated user DN +// Note: special name '*' for all LDAP addressbooks +$config['kolab_auth_ldap_addressbooks'] = array('*'); + +// Enables storing/updating session tokens for free-busy token authentication +// See httpauth.allow_token option in Free-Busy service config. +// The option can be set to a number of seconds after which the token-session +// expires or to true (to get the configured Roundcube session time) +$config['freebusy_session_auth'] = null; + +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/kolab_auth.php
Added
@@ -0,0 +1,890 @@ +<?php + +/** + * Kolab Authentication (based on ldap_authentication plugin) + * + * Authenticates on LDAP server, finds canonized authentication ID for IMAP + * and for new users creates identity based on LDAP information. + * + * Supports impersonate feature (login as another user). To use this feature + * imap_auth_type/smtp_auth_type must be set to DIGEST-MD5 or PLAIN. + * + * @version @package_version@ + * @author Aleksander Machniak <machniak@kolabsys.com> + * + * Copyright (C) 2011-2013, Kolab Systems AG <contact@kolabsys.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 program. If not, see <http://www.gnu.org/licenses/>. + */ + +class kolab_auth extends rcube_plugin +{ + static $ldap; + private $username; + private $data = array(); + + public function init() + { + $rcmail = rcube::get_instance(); + + $this->load_config(); + $this->require_plugin('libkolab'); + + $this->add_hook('authenticate', array($this, 'authenticate')); + $this->add_hook('startup', array($this, 'startup')); + $this->add_hook('ready', array($this, 'ready')); + $this->add_hook('user_create', array($this, 'user_create')); + + // Hook for password change + $this->add_hook('password_ldap_bind', array($this, 'password_ldap_bind')); + + // Hooks related to "Login As" feature + $this->add_hook('template_object_loginform', array($this, 'login_form')); + $this->add_hook('storage_connect', array($this, 'imap_connect')); + $this->add_hook('managesieve_connect', array($this, 'imap_connect')); + $this->add_hook('smtp_connect', array($this, 'smtp_connect')); + $this->add_hook('identity_form', array($this, 'identity_form')); + + // Hook to modify some configuration, e.g. ldap + $this->add_hook('config_get', array($this, 'config_get')); + + // Hook to modify logging directory + $this->add_hook('write_log', array($this, 'write_log')); + $this->username = $_SESSION['username']; + + // Enable debug logs (per-user), when logged as another user + if (!empty($_SESSION['kolab_auth_admin']) && $rcmail->config->get('kolab_auth_auditlog')) { + $rcmail->config->set('debug_level', 1); + $rcmail->config->set('smtp_log', true); + $rcmail->config->set('log_logins', true); + $rcmail->config->set('log_session', true); + $rcmail->config->set('memcache_debug', true); + $rcmail->config->set('imap_debug', true); + $rcmail->config->set('ldap_debug', true); + $rcmail->config->set('smtp_debug', true); + $rcmail->config->set('sql_debug', true); + + // SQL debug need to be set directly on DB object + // setting config variable will not work here because + // the object is already initialized/configured + if ($db = $rcmail->get_dbh()) { + $db->set_debug(true); + } + } + } + + /** + * Ready hook handler + */ + public function ready($args) + { + $rcmail = rcube::get_instance(); + + // Store user unique identifier for freebusy_session_auth feature + if (!($uniqueid = $rcmail->config->get('kolab_uniqueid'))) { + $uniqueid = $_SESSION['kolab_auth_uniqueid']; + + if (!$uniqueid) { + // Find user record in LDAP + if (($ldap = self::ldap()) && $ldap->ready) { + if ($record = $ldap->get_user_record($rcmail->get_user_name(), $_SESSION['kolab_host'])) { + $uniqueid = $record['uniqueid']; + } + } + } + + if ($uniqueid) { + $uniqueid = md5($uniqueid); + $rcmail->user->save_prefs(array('kolab_uniqueid' => $uniqueid)); + } + } + + // Set/update freebusy_session_auth entry + if ($uniqueid && empty($_SESSION['kolab_auth_admin']) + && ($ttl = $rcmail->config->get('freebusy_session_auth')) + ) { + if ($ttl === true) { + $ttl = $rcmail->config->get('session_lifetime', 0) * 60; + + if (!$ttl) { + $ttl = 10 * 60; + } + } + + $rcmail->config->set('freebusy_auth_cache', 'db'); + $rcmail->config->set('freebusy_auth_cache_ttl', $ttl); + + if ($cache = $rcmail->get_cache_shared('freebusy_auth', false)) { + $key = md5($uniqueid . ':' . rcube_utils::remote_addr() . ':' . $rcmail->get_user_name()); + $value = $cache->get($key); + $deadline = new DateTime('now', new DateTimeZone('UTC')); + + // We don't want to do the cache update on every request + // do it once in a 1/10 of the ttl + if ($value) { + $value = new DateTime($value); + $value->sub(new DateInterval('PT' . intval($ttl * 9/10) . 'S')); + if ($value > $deadline) { + return; + } + } + + $deadline->add(new DateInterval('PT' . $ttl . 'S')); + + $cache->set($key, $deadline->format(DateTime::ISO8601)); + } + } + } + + /** + * Startup hook handler + */ + public function startup($args) + { + // Check access rights when logged in as another user + if (!empty($_SESSION['kolab_auth_admin']) && $args['task'] != 'login' && $args['task'] != 'logout') { + // access to specified task is forbidden, + // redirect to the first task on the list + if (!empty($_SESSION['kolab_auth_allowed_tasks'])) { + $tasks = (array)$_SESSION['kolab_auth_allowed_tasks']; + if (!in_array($args['task'], $tasks) && !in_array('*', $tasks)) { + header('Location: ?_task=' . array_shift($tasks)); + die; + } + + // add script that will remove disabled taskbar buttons + if (!in_array('*', $tasks)) { + $this->add_hook('render_page', array($this, 'render_page')); + } + } + } + + // load per-user settings + $this->load_user_role_plugins_and_settings(); + + return $args; + } + + /** + * Modify some configuration according to LDAP user record + */ + public function config_get($args) + { + // Replaces ldap_vars (%dc, etc) in public kolab ldap addressbooks + // config based on the users base_dn. (for multi domain support) + if ($args['name'] == 'ldap_public' && !empty($args['result'])) { + $rcmail = rcube::get_instance(); + $kolab_books = (array) $rcmail->config->get('kolab_auth_ldap_addressbooks'); + + foreach ($args['result'] as $name => $config) { + if (in_array($name, $kolab_books) || in_array('*', $kolab_books)) { + $args['result'][$name] = $this->patch_ldap_config($config); + } + } + } + else if ($args['name'] == 'kolab_users_directory' && !empty($args['result'])) { + $args['result'] = $this->patch_ldap_config($args['result']); + } + + return $args; + } + + /** + * Helper method to patch the given LDAP directory config with user-specific values + */ + protected function patch_ldap_config($config) + { + if (is_array($config)) { + $config['base_dn'] = self::parse_ldap_vars($config['base_dn']); + $config['search_base_dn'] = self::parse_ldap_vars($config['search_base_dn']); + $config['bind_dn'] = str_replace('%dn', $_SESSION['kolab_dn'], $config['bind_dn']); + + if (!empty($config['groups'])) { + $config['groups']['base_dn'] = self::parse_ldap_vars($config['groups']['base_dn']); + } + } + + return $config; + } + + /** + * Modifies list of plugins and settings according to + * specified LDAP roles + */ + public function load_user_role_plugins_and_settings($startup = false) + { + if (empty($_SESSION['user_roledns'])) { + return; + } + + $rcmail = rcube::get_instance(); + + // Example 'kolab_auth_role_plugins' = + // + // Array( + // '<role_dn>' => Array('plugin1', 'plugin2'), + // ); + // + // NOTE that <role_dn> may in fact be something like: 'cn=role,%dc' + + $role_plugins = $rcmail->config->get('kolab_auth_role_plugins'); + + // Example $rcmail_config['kolab_auth_role_settings'] = + // + // Array( + // '<role_dn>' => Array( + // '$setting' => Array( + // 'mode' => '(override|merge)', (default: override) + // 'value' => <>, + // 'allow_override' => (true|false) (default: false) + // ), + // ), + // ); + // + // NOTE that <role_dn> may in fact be something like: 'cn=role,%dc' + + $role_settings = $rcmail->config->get('kolab_auth_role_settings'); + + if (!empty($role_plugins)) { + foreach ($role_plugins as $role_dn => $plugins) { + $role_dn = self::parse_ldap_vars($role_dn); + if (!empty($role_plugins[$role_dn])) { + $role_plugins[$role_dn] = array_unique(array_merge((array)$role_plugins[$role_dn], $plugins)); + } else { + $role_plugins[$role_dn] = $plugins; + } + } + } + + if (!empty($role_settings)) { + foreach ($role_settings as $role_dn => $settings) { + $role_dn = self::parse_ldap_vars($role_dn); + if (!empty($role_settings[$role_dn])) { + $role_settings[$role_dn] = array_merge((array)$role_settings[$role_dn], $settings); + } else { + $role_settings[$role_dn] = $settings; + } + } + } + + foreach ($_SESSION['user_roledns'] as $role_dn) { + if (!empty($role_settings[$role_dn]) && is_array($role_settings[$role_dn])) { + foreach ($role_settings[$role_dn] as $setting_name => $setting) { + if (!isset($setting['mode'])) { + $setting['mode'] = 'override'; + } + + if ($setting['mode'] == "override") { + $rcmail->config->set($setting_name, $setting['value']); + } elseif ($setting['mode'] == "merge") { + $orig_setting = $rcmail->config->get($setting_name); + + if (!empty($orig_setting)) { + if (is_array($orig_setting)) { + $rcmail->config->set($setting_name, array_merge($orig_setting, $setting['value'])); + } + } else { + $rcmail->config->set($setting_name, $setting['value']); + } + } + + $dont_override = (array) $rcmail->config->get('dont_override'); + + if (empty($setting['allow_override'])) { + $rcmail->config->set('dont_override', array_merge($dont_override, array($setting_name))); + } + else { + if (in_array($setting_name, $dont_override)) { + $_dont_override = array(); + foreach ($dont_override as $_setting) { + if ($_setting != $setting_name) { + $_dont_override[] = $_setting; + } + } + $rcmail->config->set('dont_override', $_dont_override); + } + } + + if ($setting_name == 'skin') { + if ($rcmail->output->type == 'html') { + $rcmail->output->set_skin($setting['value']); + $rcmail->output->set_env('skin', $setting['value']); + } + } + } + } + + if (!empty($role_plugins[$role_dn])) { + foreach ((array)$role_plugins[$role_dn] as $plugin) { + $loaded = $this->api->load_plugin($plugin); + + // Some plugins e.g. kolab_2fa use 'startup' hook to + // register other hooks, but when called on 'authenticate' hook + // we're already after 'startup', so we'll call it directly + if ($loaded && $startup && $plugin == 'kolab_2fa' + && ($plugin = $this->api->get_plugin($plugin)) + ) { + $plugin->startup(array('task' => $rcmail->task, 'action' => $rcmail->action)); + } + } + } + } + } + + /** + * Logging method replacement to print debug/errors into + * a separate (sub)folder for each user + */ + public function write_log($args) + { + $rcmail = rcube::get_instance(); + + if ($rcmail->config->get('log_driver') == 'syslog') { + return $args; + } + + // log_driver == 'file' is assumed here + $log_dir = $rcmail->config->get('log_dir', RCUBE_INSTALL_PATH . 'logs'); + + // Append original username + target username for audit-logging + if ($rcmail->config->get('kolab_auth_auditlog') && !empty($_SESSION['kolab_auth_admin'])) { + $args['dir'] = $log_dir . '/' . strtolower($_SESSION['kolab_auth_admin']) . '/' . strtolower($this->username); + + // Attempt to create the directory + if (!is_dir($args['dir'])) { + @mkdir($args['dir'], 0750, true); + } + } + // Define the user log directory if a username is provided + else if ($rcmail->config->get('per_user_logging') && !empty($this->username) + && !stripos($log_dir, '/' . $this->username) // maybe already set by syncroton, skip + ) { + $user_log_dir = $log_dir . '/' . strtolower($this->username); + if (is_writable($user_log_dir)) { + $args['dir'] = $user_log_dir; + } + else if (!in_array($args['name'], array('errors', 'userlogins', 'sendmail'))) { + $args['abort'] = true; // don't log if unauthenticed or no per-user log dir + } + } + + return $args; + } + + /** + * Sets defaults for new user. + */ + public function user_create($args) + { + if (!empty($this->data['user_email'])) { + // addresses list is supported + if (array_key_exists('email_list', $args)) { + $email_list = array_unique($this->data['user_email']); + + // add organization to the list + if (!empty($this->data['user_organization'])) { + foreach ($email_list as $idx => $email) { + $email_list[$idx] = array( + 'organization' => $this->data['user_organization'], + 'email' => $email, + ); + } + } + + $args['email_list'] = $email_list; + } + else { + $args['user_email'] = $this->data['user_email'][0]; + } + } + + if (!empty($this->data['user_name'])) { + $args['user_name'] = $this->data['user_name']; + } + + return $args; + } + + /** + * Modifies login form adding additional "Login As" field + */ + public function login_form($args) + { + $this->add_texts('localization/'); + + $rcmail = rcube::get_instance(); + $admin_login = $rcmail->config->get('kolab_auth_admin_login'); + $group = $rcmail->config->get('kolab_auth_group'); + $role_attr = $rcmail->config->get('kolab_auth_role'); + + // Show "Login As" input + if (empty($admin_login) || (empty($group) && empty($role_attr))) { + return $args; + } + + // Don't add the extra field on 2FA form + if (strpos($args['content'], 'plugin.kolab-2fa-login')) { + return $args; + } + + $input = new html_inputfield(array('name' => '_loginas', 'id' => 'rcmloginas', + 'type' => 'text', 'autocomplete' => 'off')); + $row = html::tag('tr', null, + html::tag('td', 'title', html::label('rcmloginas', rcube::Q($this->gettext('loginas')))) + . html::tag('td', 'input', $input->show(trim(rcube_utils::get_input_value('_loginas', rcube_utils::INPUT_POST)))) + ); + // add icon style for Elastic + $style = html::tag('style', [], '#login-form .input-group .icon.loginas::before { content: "\f508"; } '); + $args['content'] = preg_replace('/<\/tbody>/i', $row . '</tbody>' . $style, $args['content']); + + return $args; + } + + /** + * Find user credentials In LDAP. + */ + public function authenticate($args) + { + // get username and host + $host = $args['host']; + $user = $args['user']; + $pass = $args['pass']; + $loginas = trim(rcube_utils::get_input_value('_loginas', rcube_utils::INPUT_POST)); + + if (empty($user) || (empty($pass) && empty($_SERVER['REMOTE_USER']))) { + $args['abort'] = true; + return $args; + } + + // temporarily set the current username to the one submitted + $this->username = $user; + + $ldap = self::ldap(); + if (!$ldap || !$ldap->ready) { + self::log_login_error($user, "LDAP not ready"); + + $args['abort'] = true; + $args['kolab_ldap_error'] = true; + + return $args; + } + + // Find user record in LDAP + $record = $ldap->get_user_record($user, $host); + + if (empty($record)) { + self::log_login_error($user, "No user record found"); + + $args['abort'] = true; + + return $args; + } + + $rcmail = rcube::get_instance(); + $admin_login = $rcmail->config->get('kolab_auth_admin_login'); + $admin_pass = $rcmail->config->get('kolab_auth_admin_password'); + $login_attr = $rcmail->config->get('kolab_auth_login'); + $name_attr = $rcmail->config->get('kolab_auth_name'); + $email_attr = $rcmail->config->get('kolab_auth_email'); + $org_attr = $rcmail->config->get('kolab_auth_organization'); + $role_attr = $rcmail->config->get('kolab_auth_role'); + $imap_attr = $rcmail->config->get('kolab_auth_mailhost'); + + if (!empty($role_attr) && !empty($record[$role_attr])) { + $_SESSION['user_roledns'] = (array)($record[$role_attr]); + } + + if (!empty($imap_attr) && !empty($record[$imap_attr])) { + $default_host = $rcmail->config->get('default_host'); + if (!empty($default_host)) { + rcube::write_log("errors", "Both default host and kolab_auth_mailhost set. Incompatible."); + } else { + $args['host'] = "tls://" . $record[$imap_attr]; + } + } + + // Login As... + if (!empty($loginas) && $admin_login) { + // Authenticate to LDAP + $result = $ldap->bind($record['dn'], $pass); + + if (!$result) { + self::log_login_error($user, "Unable to bind with '" . $record['dn'] . "'"); + + $args['abort'] = true; + + return $args; + } + + $isadmin = false; + $admin_rights = $rcmail->config->get('kolab_auth_admin_rights', array()); + + // @deprecated: fall-back to the old check if the original user has/belongs to administrative role/group + if (empty($admin_rights)) { + $group = $rcmail->config->get('kolab_auth_group'); + $role_dn = $rcmail->config->get('kolab_auth_role_value'); + + // check role attribute + if (!empty($role_attr) && !empty($role_dn) && !empty($record[$role_attr])) { + $role_dn = $ldap->parse_vars($role_dn, $user, $host); + if (in_array($role_dn, (array)$record[$role_attr])) { + $isadmin = true; + } + } + + // check group + if (!$isadmin && !empty($group)) { + $groups = $ldap->get_user_groups($record['dn'], $user, $host); + if (in_array($group, $groups)) { + $isadmin = true; + } + } + + if ($isadmin) { + // user has admin privileges privilage, get "login as" user credentials + $target_entry = $ldap->get_user_record($loginas, $host); + $allowed_tasks = $rcmail->config->get('kolab_auth_allowed_tasks'); + } + } + else { + // get "login as" user credentials + $target_entry = $ldap->get_user_record($loginas, $host); + + if (!empty($target_entry)) { + // get effective rights to determine login-as permissions + $effective_rights = (array)$ldap->effective_rights($target_entry['dn']); + + if (!empty($effective_rights)) { + // compat with out of date Net_LDAP3 + $effective_rights = array_change_key_case($effective_rights, CASE_LOWER); + + $effective_rights['attrib'] = $effective_rights['attributelevelrights']; + $effective_rights['entry'] = $effective_rights['entrylevelrights']; + + // compare the rights with the permissions mapping + $allowed_tasks = array(); + foreach ($admin_rights as $task => $perms) { + $perms_ = explode(':', $perms); + $type = array_shift($perms_); + $req = array_pop($perms_); + $attrib = array_pop($perms_); + + if (array_key_exists($type, $effective_rights)) { + if ($type == 'entry' && in_array($req, $effective_rights[$type])) { + $allowed_tasks[] = $task; + } + else if ($type == 'attrib' && array_key_exists($attrib, $effective_rights[$type]) && + in_array($req, $effective_rights[$type][$attrib])) { + $allowed_tasks[] = $task; + } + } + } + + $isadmin = !empty($allowed_tasks); + } + } + } + + // Save original user login for log (see below) + if ($login_attr) { + $origname = is_array($record[$login_attr]) ? $record[$login_attr][0] : $record[$login_attr]; + } + else { + $origname = $user; + } + + if (!$isadmin || empty($target_entry)) { + $this->add_texts('localization/'); + + $args['abort'] = true; + $args['error'] = $this->gettext(array( + 'name' => 'loginasnotallowed', + 'vars' => array('user' => rcube::Q($loginas)), + )); + + self::log_login_error($user, "No privileges to login as '" . $loginas . "'", $loginas); + + return $args; + } + + // replace $record with target entry + $record = $target_entry; + + $args['user'] = $this->username = $loginas; + + // Mark session to use SASL proxy for IMAP authentication + $_SESSION['kolab_auth_admin'] = strtolower($origname); + $_SESSION['kolab_auth_login'] = $rcmail->encrypt($admin_login); + $_SESSION['kolab_auth_password'] = $rcmail->encrypt($admin_pass); + $_SESSION['kolab_auth_allowed_tasks'] = $allowed_tasks; + } + + // Store UID and DN of logged user in session for use by other plugins + $_SESSION['kolab_uid'] = is_array($record['uid']) ? $record['uid'][0] : $record['uid']; + $_SESSION['kolab_dn'] = $record['dn']; + + // Store LDAP replacement variables used for current user + // This improves performance of load_user_role_plugins_and_settings() + // which is executed on every request (via startup hook) and where + // we don't like to use LDAP (connection + bind + search) + $_SESSION['kolab_auth_vars'] = $ldap->get_parse_vars(); + + // Store user unique identifier for freebusy_session_auth feature + $_SESSION['kolab_auth_uniqueid'] = is_array($record['uniqueid']) ? $record['uniqueid'][0] : $record['uniqueid']; + + // Store also host as we need it for get_user_reacod() in 'ready' hook handler + $_SESSION['kolab_host'] = $host; + + // Set user login + if ($login_attr) { + $this->data['user_login'] = is_array($record[$login_attr]) ? $record[$login_attr][0] : $record[$login_attr]; + } + if ($this->data['user_login']) { + $args['user'] = $this->username = $this->data['user_login']; + } + + // User name for identity (first log in) + foreach ((array)$name_attr as $field) { + $name = is_array($record[$field]) ? $record[$field][0] : $record[$field]; + if (!empty($name)) { + $this->data['user_name'] = $name; + break; + } + } + // User email(s) for identity (first log in) + foreach ((array)$email_attr as $field) { + $email = is_array($record[$field]) ? array_filter($record[$field]) : $record[$field]; + if (!empty($email)) { + $this->data['user_email'] = array_merge((array)$this->data['user_email'], (array)$email); + } + } + // Organization name for identity (first log in) + foreach ((array)$org_attr as $field) { + $organization = is_array($record[$field]) ? $record[$field][0] : $record[$field]; + if (!empty($organization)) { + $this->data['user_organization'] = $organization; + break; + } + } + + // Log "Login As" usage + if (!empty($origname)) { + rcube::write_log('userlogins', sprintf('Admin login for %s by %s from %s', + $args['user'], $origname, rcube_utils::remote_ip())); + } + + // load per-user settings/plugins + $this->load_user_role_plugins_and_settings(true); + + return $args; + } + + /** + * Set user DN for password change (password plugin with ldap_simple driver) + */ + public function password_ldap_bind($args) + { + $args['user_dn'] = $_SESSION['kolab_dn']; + + $rcmail = rcube::get_instance(); + + $rcmail->config->set('password_ldap_method', 'user'); + + return $args; + } + + /** + * Sets SASL Proxy login/password for IMAP and Managesieve auth + */ + public function imap_connect($args) + { + if (!empty($_SESSION['kolab_auth_admin'])) { + $rcmail = rcube::get_instance(); + $admin_login = $rcmail->decrypt($_SESSION['kolab_auth_login']); + $admin_pass = $rcmail->decrypt($_SESSION['kolab_auth_password']); + + $args['auth_cid'] = $admin_login; + $args['auth_pw'] = $admin_pass; + } + + return $args; + } + + /** + * Sets SASL Proxy login/password for SMTP auth + */ + public function smtp_connect($args) + { + if (!empty($_SESSION['kolab_auth_admin'])) { + $rcmail = rcube::get_instance(); + $admin_login = $rcmail->decrypt($_SESSION['kolab_auth_login']); + $admin_pass = $rcmail->decrypt($_SESSION['kolab_auth_password']); + + $args['smtp_auth_cid'] = $admin_login; + $args['smtp_auth_pw'] = $admin_pass; + } + + return $args; + } + + /** + * Hook to replace the plain text input field for email address by a drop-down list + * with all email addresses (including aliases) from this user's LDAP record. + */ + public function identity_form($args) + { + $rcmail = rcube::get_instance(); + $ident_level = intval($rcmail->config->get('identities_level', 0)); + + // do nothing if email address modification is disabled + if ($ident_level == 1 || $ident_level == 3) { + return $args; + } + + $ldap = self::ldap(); + if (!$ldap || !$ldap->ready || empty($_SESSION['kolab_dn'])) { + return $args; + } + + $emails = array(); + $user_record = $ldap->get_record($_SESSION['kolab_dn']); + + foreach ((array)$rcmail->config->get('kolab_auth_email', array()) as $col) { + $values = rcube_addressbook::get_col_values($col, $user_record, true); + if (!empty($values)) + $emails = array_merge($emails, array_filter($values)); + } + + // kolab_delegation might want to modify this addresses list + $plugin = $rcmail->plugins->exec_hook('kolab_auth_emails', array('emails' => $emails)); + $emails = $plugin['emails']; + + if (!empty($emails)) { + $args['form']['addressing']['content']['email'] = array( + 'type' => 'select', + 'options' => array_combine($emails, $emails), + ); + } + + return $args; + } + + /** + * Action executed before the page is rendered to add an onload script + * that will remove all taskbar buttons for disabled tasks + */ + public function render_page($args) + { + $rcmail = rcube::get_instance(); + $tasks = (array)$_SESSION['kolab_auth_allowed_tasks']; + $tasks[] = 'logout'; + + // disable buttons in taskbar + $script = " + \$('a').filter(function() { + var ev = \$(this).attr('onclick'); + return ev && ev.match(/'switch-task','([a-z]+)'/) + && \$.inArray(RegExp.\$1, " . json_encode($tasks) . ") < 0; + }).remove(); + "; + + $rcmail->output->add_script($script, 'docready'); + } + + /** + * Initializes LDAP object and connects to LDAP server + */ + public static function ldap() + { + self::$ldap = kolab_storage::ldap('kolab_auth_addressbook'); + + if (self::$ldap) { + self::$ldap->extend_fieldmap(array('uniqueid' => 'nsuniqueid')); + } + + return self::$ldap; + } + + /** + * Close LDAP connection + */ + public static function ldap_close() + { + if (self::$ldap) { + self::$ldap->close(); + self::$ldap = null; + } + } + + /** + * Parses LDAP DN string with replacing supported variables. + * See kolab_ldap::parse_vars() + * + * @param string $str LDAP DN string + * + * @return string Parsed DN string + */ + public static function parse_ldap_vars($str) + { + if (!empty($_SESSION['kolab_auth_vars'])) { + $str = strtr($str, $_SESSION['kolab_auth_vars']); + } + + return $str; + } + + /** + * Log failed logins + * + * @param string $username Username/Login + * @param string $message Error message (failure reason) + * @param string $login_as Username/Login of "login as" user + */ + public static function log_login_error($username, $message = null, $login_as = null) + { + $config = rcube::get_instance()->config; + + if ($config->get('log_logins')) { + // don't fill the log with complete input, which could + // have been prepared by a hacker + if (strlen($username) > 256) { + $username = substr($username, 0, 256) . '...'; + } + if (strlen($login_as) > 256) { + $login_as = substr($login_as, 0, 256) . '...'; + } + + if ($login_as) { + $username = sprintf('%s (as user %s)', $username, $login_as); + } + + // Don't log full session id for better security + $session_id = session_id(); + $session_id = $session_id ? substr($session_id, 0, 16) : 'no-session'; + + $message = sprintf( + "Failed login for %s from %s in session %s %s", + $username, + rcube_utils::remote_ip(), + $session_id, + $message ? "($message)" : '' + ); + + rcube::write_log('userlogins', $message); + + // disable log_logins to prevent from duplicate log entries + $config->set('log_logins', false); + } + } +}
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/bg_BG.inc
Added
@@ -0,0 +1,10 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Влизане като'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/cs_CZ.inc
Added
@@ -0,0 +1,11 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Přihlásit se jako'; +$labels['loginasnotallowed'] = 'Žádná práva pro přihlášení se jako $user'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/da_DK.inc
Added
@@ -0,0 +1,11 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Log ind som'; +$labels['loginasnotallowed'] = 'Har ikke privilegier til at logge ind som $user'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/de.inc
Added
@@ -0,0 +1,11 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Anmelden als'; +$labels['loginasnotallowed'] = 'Keine Privilegien zum Anmelden als $user'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/de_CH.inc
Added
@@ -0,0 +1,11 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Anmelden als'; +$labels['loginasnotallowed'] = 'Keine Privilegien zum Anmelden als $user'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/de_DE.inc
Added
@@ -0,0 +1,11 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Anmelden als'; +$labels['loginasnotallowed'] = 'Keine Privilegien zum Anmelden als $user'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/el.inc
Added
@@ -0,0 +1,10 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Είσοδος ως'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/en_US.inc
Added
@@ -0,0 +1,14 @@ +<?php + +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ + +$labels['loginas'] = 'Login As'; +$labels['loginasnotallowed'] = 'No privileges to login as $user'; + +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/es_AR.inc
Added
@@ -0,0 +1,11 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Ingresar como'; +$labels['loginasnotallowed'] = 'No tiene privilegios para ingresar como $user'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/es_ES.inc
Added
@@ -0,0 +1,11 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Iniciar sesión como'; +$labels['loginasnotallowed'] = 'No hay privilegios para iniciar sesión como $usuario'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/et_EE.inc
Added
@@ -0,0 +1,11 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Logi sisse kui'; +$labels['loginasnotallowed'] = 'Pole õigusi, et logida sisse kui $user'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/fi_FI.inc
Added
@@ -0,0 +1,11 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Kirjaudu tilillä'; +$labels['loginasnotallowed'] = 'Ei oikeuksia kirjautua käyttäjänä $user'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/fr_FR.inc
Added
@@ -0,0 +1,11 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Se connecter en tant que'; +$labels['loginasnotallowed'] = 'Pas d\'autorisation de se connecter en tant que $utilisateur'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/hu_HU.inc
Added
@@ -0,0 +1,10 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Bejelentkezés mint'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/it_IT.inc
Added
@@ -0,0 +1,11 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Login come'; +$labels['loginasnotallowed'] = 'Nessun privilegio al login come $user'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/ja_JP.inc
Added
@@ -0,0 +1,11 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'ログイン'; +$labels['loginasnotallowed'] = '$user としてログインする権限がありません'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/nl_NL.inc
Added
@@ -0,0 +1,11 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Aanmelden als'; +$labels['loginasnotallowed'] = 'Geen bevoegdheden om aan te melden als $user'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/pl_PL.inc
Added
@@ -0,0 +1,11 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Zaloguj jako'; +$labels['loginasnotallowed'] = 'Brak uprawnień do zalogowania jako $user'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/pt_BR.inc
Added
@@ -0,0 +1,10 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Logar como'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/ru_RU.inc
Added
@@ -0,0 +1,11 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Войти как'; +$labels['loginasnotallowed'] = 'Нет привилегий войти как $user'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/sv_SE.inc
Added
@@ -0,0 +1,11 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Logga in som'; +$labels['loginasnotallowed'] = 'Du har inte befogenhet att logga in som $user'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/th_TH.inc
Added
@@ -0,0 +1,11 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'เข้าระบบด้วยชื่อ..'; +$labels['loginasnotallowed'] = 'ไม่มีสิทธิเข้าระบบด้วยชื่อผู้ใช้ $user'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/uk_UA.inc
Added
@@ -0,0 +1,11 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = 'Увійти як користувач'; +$labels['loginasnotallowed'] = 'Немає привілеїв, увійти як $user'; +?>
View file
roundcubemail-1.4.13.tar.gz/plugins/kolab_auth/localization/zh_CN.inc
Added
@@ -0,0 +1,11 @@ +<?php +/** + * Localizations for the Kolab Auth plugin + * + * Copyright (C) 2014, Kolab Systems AG + * + * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/ + */ +$labels['loginas'] = '以xxx登录'; +$labels['loginasnotallowed'] = '无权限以 $user 登录'; +?>
View file
roundcubemail-1.4.11.20.tar.gz/plugins/libkolab/lib/kolab_attachments_handler.php -> roundcubemail-1.4.13.tar.gz/plugins/libkolab/lib/kolab_attachments_handler.php
Changed
@@ -114,8 +114,9 @@ $this->rc->upload_progress(); } - $recid = $id_prefix . rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC); + $id = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC); $uploadid = rcube_utils::get_input_value('_uploadid', rcube_utils::INPUT_GPC); + $recid = $id_prefix . ($id ?: 'new'); if (empty($_SESSION[$session_key]) || $_SESSION[$session_key]['id'] != $recid) { $_SESSION[$session_key] = array();
View file
roundcubemail-1.4.11.20.tar.gz/program/include/iniset.php -> roundcubemail-1.4.13.tar.gz/program/include/iniset.php
Changed
@@ -24,7 +24,7 @@ } // application constants -define('RCMAIL_VERSION', '1.4.11'); +define('RCMAIL_VERSION', '1.4.13'); define('RCMAIL_START', microtime(true)); if (!defined('INSTALL_PATH')) {
View file
roundcubemail-1.4.11.20.tar.gz/program/lib/Roundcube/bootstrap.php -> roundcubemail-1.4.13.tar.gz/program/lib/Roundcube/bootstrap.php
Changed
@@ -58,7 +58,7 @@ } // framework constants -define('RCUBE_VERSION', '1.4.11'); +define('RCUBE_VERSION', '1.4.13'); define('RCUBE_CHARSET', 'UTF-8'); define('RCUBE_TEMP_FILE_PREFIX', 'RCMTEMP');
View file
roundcubemail-1.4.11.20.tar.gz/program/lib/Roundcube/rcube_washtml.php -> roundcubemail-1.4.13.tar.gz/program/lib/Roundcube/rcube_washtml.php
Changed
@@ -338,7 +338,7 @@ if ($url = $this->wash_uri($match[2])) { $result .= ' ' . $attr->nodeName . '="' . $match[1] . '(' . htmlspecialchars($url, ENT_QUOTES, $this->config['charset']) . ')' - . substr($val, strlen($match[0])) . '"'; + . htmlspecialchars(substr($val, strlen($match[0])), ENT_QUOTES, $this->config['charset']) . '"'; continue; } }
View file
roundcubemail-1.4.11.20.tar.gz/program/lib/Roundcube/spellchecker/googie.php -> roundcubemail-1.4.13.tar.gz/program/lib/Roundcube/spellchecker/googie.php
Changed
@@ -26,6 +26,9 @@ */ class rcube_spellchecker_googie extends rcube_spellchecker_engine { + const GOOGIE_HOST = 'ssl://spell.roundcube.net'; + const GOOGIE_PORT = 443; + private $matches = array(); private $content; @@ -68,8 +71,9 @@ $path = $a_uri['path'] . ($a_uri['query'] ? '?'.$a_uri['query'] : '') . $this->lang; } else { - $this->error = "Missing 'spellcheck_uri' config option"; - return $this->matches = array(); + $host = self::GOOGIE_HOST; + $port = self::GOOGIE_PORT; + $path = '/tbproxy/spell?lang=' . $this->lang; } $path .= sprintf('&key=%06d', $_SESSION['user_id']);
View file
roundcubemail-1.4.11.20.tar.gz/public_html/index.php -> roundcubemail-1.4.13.tar.gz/public_html/index.php
Changed
@@ -3,7 +3,7 @@ /* +-----------------------------------------------------------------------+ | Roundcube Webmail IMAP Client | - | Version 1.4.11 | + | Version 1.4.13 | | | | Copyright (C) The Roundcube Dev Team | | |
View file
roundcubemail-1.4.11.20.tar.gz/tests/Framework/Washtml.php -> roundcubemail-1.4.13.tar.gz/tests/Framework/Washtml.php
Changed
@@ -448,6 +448,10 @@ '<!-- html ignored --><body x-washed="background"></body>' ], [ + '<html><body><img fill=\'asd:url(#asd)" src="x" onerror="alert(1)\' />', + '<body><img fill="asd:url(#asd)" src="x" onerror="alert(1)" /></body>' + ], + [ '<html><math href="javascript:alert(location);"><mi>clickme</mi></math>', '<!-- html ignored --><body><math x-washed="href"><mi>clickme</mi></math></body>', ],
View file
roundcubemail-1.4.11.20.tar.gz/vendor/autoload.php -> roundcubemail-1.4.13.tar.gz/vendor/autoload.php
Changed
@@ -4,4 +4,4 @@ require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInit9bb1f3e4f7cfef6c404d641f234e8092::getLoader(); +return ComposerAutoloaderInitd89bf3a6fb4183211eaea1c21a92faae::getLoader();
View file
roundcubemail-1.4.11.20.tar.gz/vendor/composer/ClassLoader.php -> roundcubemail-1.4.13.tar.gz/vendor/composer/ClassLoader.php
Changed
@@ -42,75 +42,30 @@ */ class ClassLoader { - /** @var ?string */ private $vendorDir; // PSR-4 - /** - * @var array[] - * @psalm-var array<string, array<string, int>> - */ private $prefixLengthsPsr4 = array(); - /** - * @var array[] - * @psalm-var array<string, array<int, string>> - */ private $prefixDirsPsr4 = array(); - /** - * @var array[] - * @psalm-var array<string, string> - */ private $fallbackDirsPsr4 = array(); // PSR-0 - /** - * @var array[] - * @psalm-var array<string, array<string, string[]>> - */ private $prefixesPsr0 = array(); - /** - * @var array[] - * @psalm-var array<string, string> - */ private $fallbackDirsPsr0 = array(); - /** @var bool */ private $useIncludePath = false; - - /** - * @var string[] - * @psalm-var array<string, string> - */ private $classMap = array(); - - /** @var bool */ private $classMapAuthoritative = false; - - /** - * @var bool[] - * @psalm-var array<string, bool> - */ private $missingClasses = array(); - - /** @var ?string */ private $apcuPrefix; - /** - * @var self[] - */ private static $registeredLoaders = array(); - /** - * @param ?string $vendorDir - */ public function __construct($vendorDir = null) { $this->vendorDir = $vendorDir; } - /** - * @return string[] - */ public function getPrefixes() { if (!empty($this->prefixesPsr0)) { @@ -120,47 +75,28 @@ return array(); } - /** - * @return array[] - * @psalm-return array<string, array<int, string>> - */ public function getPrefixesPsr4() { return $this->prefixDirsPsr4; } - /** - * @return array[] - * @psalm-return array<string, string> - */ public function getFallbackDirs() { return $this->fallbackDirsPsr0; } - /** - * @return array[] - * @psalm-return array<string, string> - */ public function getFallbackDirsPsr4() { return $this->fallbackDirsPsr4; } - /** - * @return string[] Array of classname => path - * @psalm-var array<string, string> - */ public function getClassMap() { return $this->classMap; } /** - * @param string[] $classMap Class to filename map - * @psalm-param array<string, string> $classMap - * - * @return void + * @param array $classMap Class to filename map */ public function addClassMap(array $classMap) { @@ -175,11 +111,9 @@ * Registers a set of PSR-0 directories for a given prefix, either * appending or prepending to the ones previously set for this prefix. * - * @param string $prefix The prefix - * @param string[]|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories - * - * @return void + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories */ public function add($prefix, $paths, $prepend = false) { @@ -222,13 +156,11 @@ * Registers a set of PSR-4 directories for a given namespace, either * appending or prepending to the ones previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param string[]|string $paths The PSR-4 base directories - * @param bool $prepend Whether to prepend the directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories * * @throws \InvalidArgumentException - * - * @return void */ public function addPsr4($prefix, $paths, $prepend = false) { @@ -272,10 +204,8 @@ * Registers a set of PSR-0 directories for a given prefix, * replacing any others previously set for this prefix. * - * @param string $prefix The prefix - * @param string[]|string $paths The PSR-0 base directories - * - * @return void + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories */ public function set($prefix, $paths) { @@ -290,12 +220,10 @@ * Registers a set of PSR-4 directories for a given namespace, * replacing any others previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param string[]|string $paths The PSR-4 base directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories * * @throws \InvalidArgumentException - * - * @return void */ public function setPsr4($prefix, $paths) { @@ -315,8 +243,6 @@ * Turns on searching the include path for class files. * * @param bool $useIncludePath - * - * @return void */ public function setUseIncludePath($useIncludePath) { @@ -339,8 +265,6 @@ * that have not been registered with the class map. * * @param bool $classMapAuthoritative - * - * @return void */ public function setClassMapAuthoritative($classMapAuthoritative) { @@ -361,8 +285,6 @@ * APCu prefix to use to cache found/not-found classes, if the extension is enabled. * * @param string|null $apcuPrefix - * - * @return void */ public function setApcuPrefix($apcuPrefix) { @@ -383,8 +305,6 @@ * Registers this instance as an autoloader. * * @param bool $prepend Whether to prepend the autoloader or not - * - * @return void */ public function register($prepend = false) { @@ -404,8 +324,6 @@ /** * Unregisters this instance as an autoloader. - * - * @return void */ public function unregister() { @@ -420,7 +338,7 @@ * Loads the given class or interface. * * @param string $class The name of the class - * @return true|null True if loaded, null otherwise + * @return bool|null True if loaded, null otherwise */ public function loadClass($class) { @@ -429,8 +347,6 @@ return true; } - - return null; } /** @@ -485,11 +401,6 @@ return self::$registeredLoaders; } - /** - * @param string $class - * @param string $ext - * @return string|false - */ private function findFileWithExtension($class, $ext) { // PSR-4 lookup @@ -561,10 +472,6 @@ * Scope isolated include. * * Prevents access to $this/self from included files. - * - * @param string $file - * @return void - * @private */ function includeFile($file) {
View file
roundcubemail-1.4.11.20.tar.gz/vendor/composer/InstalledVersions.php -> roundcubemail-1.4.13.tar.gz/vendor/composer/InstalledVersions.php
Changed
@@ -20,25 +20,784 @@ * * See also https://getcomposer.org/doc/07-runtime.md#installed-versions * - * To require its presence, you can require `composer-runtime-api ^2.0` + * To require it's presence, you can require `composer-runtime-api ^2.0` */ class InstalledVersions { - /** - * @var mixed[]|null - * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null - */ - private static $installed; - - /** - * @var bool|null - */ + private static $installed = array ( + 'root' => + array ( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'aliases' => + array ( + ), + 'reference' => '784eb80e67a3f47290e42cef12da8696cba60272', + 'name' => 'roundcube/roundcubemail', + ), + 'versions' => + array ( + 'caxy/php-htmldiff' => + array ( + 'pretty_version' => 'v0.1.9', + 'version' => '0.1.9.0', + 'aliases' => + array ( + ), + 'reference' => '4bad5c6a4ecc76954d37764e6a29273b6b7bf1f8', + ), + 'doctrine/instantiator' => + array ( + 'pretty_version' => '1.4.0', + 'version' => '1.4.0.0', + 'aliases' => + array ( + ), + 'reference' => 'd56bf6102915de5702778fe20f2de3b2fe570b5b', + ), + 'endroid/qr-code' => + array ( + 'pretty_version' => '1.6.6', + 'version' => '1.6.6.0', + 'aliases' => + array ( + ), + 'reference' => 'cef5d5b7b904d7bb0708eb744c35316364b65fa0', + ), + 'ezyang/htmlpurifier' => + array ( + 'pretty_version' => 'v4.14.0', + 'version' => '4.14.0.0', + 'aliases' => + array ( + ), + 'reference' => '12ab42bd6e742c70c0a52f7b82477fcd44e64b75', + ), + 'johndoh/contextmenu' => + array ( + 'pretty_version' => '3.2.1', + 'version' => '3.2.1.0', + 'aliases' => + array ( + ), + 'reference' => '602a3812922fb8f71814eb3b8d91e9b7859aab7e', + ), + 'kolab/calendar' => + array ( + 'pretty_version' => '3.5.10', + 'version' => '3.5.10.0', + 'aliases' => + array ( + ), + 'reference' => '45103d5bdee63f976c918f8cfcf20b400310bcb0', + ), + 'kolab/kolab_activesync' => + array ( + 'pretty_version' => '3.5.6', + 'version' => '3.5.6.0', + 'aliases' => + array ( + ), + 'reference' => '7e8c46290074fe6c1ab72bc9f6b90aa271ee16ef', + ), + 'kolab/kolab_addressbook' => + array ( + 'pretty_version' => '3.5.10', + 'version' => '3.5.10.0', + 'aliases' => + array ( + ), + 'reference' => '29195279f672640ffe38f70ddabe87b56172e889', + ), + 'kolab/kolab_auth' => + array ( + 'pretty_version' => '3.5.8', + 'version' => '3.5.8.0', + 'aliases' => + array ( + ), + 'reference' => 'ab0ed459f74a03f8eab6822652e084f0430a4f07', + ), + 'kolab/kolab_chat' => + array ( + 'pretty_version' => '3.5.4', + 'version' => '3.5.4.0', + 'aliases' => + array ( + ), + 'reference' => 'b2f85fcb8324b9961dd02fb3e3acd92be33b558e', + ), + 'kolab/kolab_config' => + array ( + 'pretty_version' => '3.4.0', + 'version' => '3.4.0.0', + 'aliases' => + array ( + ), + 'reference' => 'b31a76c1700679249fc222c46582ecbd1215f117', + ), + 'kolab/kolab_files' => + array ( + 'pretty_version' => '3.5.2', + 'version' => '3.5.2.0', + 'aliases' => + array ( + ), + 'reference' => '0439d3783b59d6e52f23e86046881fd0ca8c0bd5', + ), + 'kolab/kolab_folders' => + array ( + 'pretty_version' => '3.5.2', + 'version' => '3.5.2.0', + 'aliases' => + array ( + ), + 'reference' => 'c70560fcfe40bf1582ea79debf3ae2aebbe94688', + ), + 'kolab/kolab_notes' => + array ( + 'pretty_version' => '3.5.5', + 'version' => '3.5.5.0', + 'aliases' => + array ( + ), + 'reference' => '07297b8ea8b3827d0ba46801760854b0db560576', + ), + 'kolab/kolab_tags' => + array ( + 'pretty_version' => '3.5.2', + 'version' => '3.5.2.0', + 'aliases' => + array ( + ), + 'reference' => '62ffa5279d9f351941be6b23b0d0478aeff91bfd', + ), + 'kolab/libcalendaring' => + array ( + 'pretty_version' => '3.5.10', + 'version' => '3.5.10.0', + 'aliases' => + array ( + ), + 'reference' => 'b9ab21ae1a5b134a06c66d55372712630171a590', + ), + 'kolab/libkolab' => + array ( + 'pretty_version' => '3.5.10', + 'version' => '3.5.10.0', + 'aliases' => + array ( + ), + 'reference' => 'a8abbba8039ee3bdde7be1b6758893aeff0287d8', + ), + 'kolab/net_ldap3' => + array ( + 'pretty_version' => 'v1.1.3', + 'version' => '1.1.3.0', + 'aliases' => + array ( + ), + 'reference' => 'e1835e36fa5d3434f9804670fc3cdd16992ec66a', + ), + 'kolab/odfviewer' => + array ( + 'pretty_version' => '3.4.0', + 'version' => '3.4.0.0', + 'aliases' => + array ( + ), + 'reference' => '43f3c0cf314cb818f9bc96d6bd378793e22a4ed4', + ), + 'kolab/pdfviewer' => + array ( + 'pretty_version' => '3.4.0', + 'version' => '3.4.0.0', + 'aliases' => + array ( + ), + 'reference' => '3437085223a60d929fbf076c232008e4377407c1', + ), + 'kolab/tasklist' => + array ( + 'pretty_version' => '3.5.10', + 'version' => '3.5.10.0', + 'aliases' => + array ( + ), + 'reference' => '7ae02f72964925d19fb244754f9d3e9b20af677c', + ), + 'kub-at/php-simple-html-dom-parser' => + array ( + 'pretty_version' => '1.9.1', + 'version' => '1.9.1.0', + 'aliases' => + array ( + ), + 'reference' => 'ff22f98bfd9235115c128059076f3eb740d66913', + ), + 'masterminds/html5' => + array ( + 'pretty_version' => '2.5.0', + 'version' => '2.5.0.0', + 'aliases' => + array ( + ), + 'reference' => 'b5d892a4bd058d61f736935d32a9c248f11ccc93', + ), + 'myclabs/deep-copy' => + array ( + 'pretty_version' => '1.10.2', + 'version' => '1.10.2.0', + 'aliases' => + array ( + ), + 'reference' => '776f831124e9c62e1a2c601ecc52e776d8bb7220', + 'replaced' => + array ( + 0 => '1.10.2', + ), + ), + 'pear/auth_sasl' => + array ( + 'pretty_version' => 'v1.1.0', + 'version' => '1.1.0.0', + 'aliases' => + array ( + ), + 'reference' => 'db1ead3dc0bf986d2bab0dbc04d114800cf91dee', + ), + 'pear/console_commandline' => + array ( + 'pretty_version' => 'v1.2.4', + 'version' => '1.2.4.0', + 'aliases' => + array ( + ), + 'reference' => 'cce06166765c5da31f3e8c1acf42512c64344cdb', + ), + 'pear/console_getopt' => + array ( + 'pretty_version' => 'v1.4.3', + 'version' => '1.4.3.0', + 'aliases' => + array ( + ), + 'reference' => 'a41f8d3e668987609178c7c4a9fe48fecac53fa0', + ), + 'pear/crypt_gpg' => + array ( + 'pretty_version' => 'v1.6.6', + 'version' => '1.6.6.0', + 'aliases' => + array ( + ), + 'reference' => '18eb7b7c0822377804adafb53dafe6d15848f245', + ), + 'pear/http_request2' => + array ( + 'pretty_version' => 'v2.3.0', + 'version' => '2.3.0.0', + 'aliases' => + array ( + ), + 'reference' => '3599cf0fe455a4e281da464f6510bfc5c2ce54c4', + ), + 'pear/mail_mime' => + array ( + 'pretty_version' => '1.10.11', + 'version' => '1.10.11.0', + 'aliases' => + array ( + ), + 'reference' => 'd4fb9ce61201593d0f8c6db629c45e29c3409c14', + ), + 'pear/net_idna2' => + array ( + 'pretty_version' => 'v0.2.0', + 'version' => '0.2.0.0', + 'aliases' => + array ( + ), + 'reference' => '51734eaf8be2df58e8aad5835b9966459b2fb37c', + ), + 'pear/net_ldap2' => + array ( + 'pretty_version' => 'v2.2.0', + 'version' => '2.2.0.0', + 'aliases' => + array ( + ), + 'reference' => '38f1b22a96dfbd7ec53852f0e1e7ec1a9a5eb0e8', + ), + 'pear/net_sieve' => + array ( + 'pretty_version' => '1.4.5', + 'version' => '1.4.5.0', + 'aliases' => + array ( + ), + 'reference' => '94763e0fc6f39a9ebcd01e5e7a8250292804a50e', + ), + 'pear/net_smtp' => + array ( + 'pretty_version' => '1.8.1', + 'version' => '1.8.1.0', + 'aliases' => + array ( + ), + 'reference' => '8f93b34878ef16844c754d1a1211c1e3677fa07f', + ), + 'pear/net_socket' => + array ( + 'pretty_version' => 'v1.2.2', + 'version' => '1.2.2.0', + 'aliases' => + array ( + ), + 'reference' => 'bbe6a12bb4f7059dba161f6ddd43f369c0ec8d09', + ), + 'pear/net_url2' => + array ( + 'pretty_version' => 'v2.2.2', + 'version' => '2.2.2.0', + 'aliases' => + array ( + ), + 'reference' => '07fd055820dbf466ee3990abe96d0e40a8791f9d', + ), + 'pear/pear-core-minimal' => + array ( + 'pretty_version' => 'v1.10.11', + 'version' => '1.10.11.0', + 'aliases' => + array ( + ), + 'reference' => '68d0d32ada737153b7e93b8d3c710ebe70ac867d', + ), + 'pear/pear_exception' => + array ( + 'pretty_version' => 'v1.0.2', + 'version' => '1.0.2.0', + 'aliases' => + array ( + ), + 'reference' => 'b14fbe2ddb0b9f94f5b24cf08783d599f776fff0', + ), + 'phpdocumentor/reflection-common' => + array ( + 'pretty_version' => '2.2.0', + 'version' => '2.2.0.0', + 'aliases' => + array ( + ), + 'reference' => '1d01c49d4ed62f25aa84a747ad35d5a16924662b', + ), + 'phpdocumentor/reflection-docblock' => + array ( + 'pretty_version' => '5.3.0', + 'version' => '5.3.0.0', + 'aliases' => + array ( + ), + 'reference' => '622548b623e81ca6d78b721c5e029f4ce664f170', + ), + 'phpdocumentor/type-resolver' => + array ( + 'pretty_version' => '1.6.0', + 'version' => '1.6.0.0', + 'aliases' => + array ( + ), + 'reference' => '93ebd0014cab80c4ea9f5e297ea48672f1b87706', + ), + 'phpspec/prophecy' => + array ( + 'pretty_version' => 'v1.10.3', + 'version' => '1.10.3.0', + 'aliases' => + array ( + ), + 'reference' => '451c3cd1418cf640de218914901e51b064abb093', + ), + 'phpunit/php-code-coverage' => + array ( + 'pretty_version' => '4.0.8', + 'version' => '4.0.8.0', + 'aliases' => + array ( + ), + 'reference' => 'ef7b2f56815df854e66ceaee8ebe9393ae36a40d', + ), + 'phpunit/php-file-iterator' => + array ( + 'pretty_version' => '1.4.5', + 'version' => '1.4.5.0', + 'aliases' => + array ( + ), + 'reference' => '730b01bc3e867237eaac355e06a36b85dd93a8b4', + ), + 'phpunit/php-text-template' => + array ( + 'pretty_version' => '1.2.1', + 'version' => '1.2.1.0', + 'aliases' => + array ( + ), + 'reference' => '31f8b717e51d9a2afca6c9f046f5d69fc27c8686', + ), + 'phpunit/php-timer' => + array ( + 'pretty_version' => '1.0.9', + 'version' => '1.0.9.0', + 'aliases' => + array ( + ), + 'reference' => '3dcf38ca72b158baf0bc245e9184d3fdffa9c46f', + ), + 'phpunit/php-token-stream' => + array ( + 'pretty_version' => '2.0.2', + 'version' => '2.0.2.0', + 'aliases' => + array ( + ), + 'reference' => '791198a2c6254db10131eecfe8c06670700904db', + ), + 'phpunit/phpunit' => + array ( + 'pretty_version' => '5.7.27', + 'version' => '5.7.27.0', + 'aliases' => + array ( + ), + 'reference' => 'b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c', + ), + 'phpunit/phpunit-mock-objects' => + array ( + 'pretty_version' => '3.4.4', + 'version' => '3.4.4.0', + 'aliases' => + array ( + ), + 'reference' => 'a23b761686d50a560cc56233b9ecf49597cc9118', + ), + 'roundcube/plugin-installer' => + array ( + 'pretty_version' => '0.2.0', + 'version' => '0.2.0.0', + 'aliases' => + array ( + ), + 'reference' => '10148d050ee2db019d83113a479fb7716fd04d48', + ), + 'roundcube/roundcubemail' => + array ( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'aliases' => + array ( + ), + 'reference' => '784eb80e67a3f47290e42cef12da8696cba60272', + ), + 'rsky/pear-core-min' => + array ( + 'replaced' => + array ( + 0 => 'v1.10.11', + ), + ), + 'sabre/dav' => + array ( + 'pretty_version' => '2.1.11', + 'version' => '2.1.11.0', + 'aliases' => + array ( + ), + 'reference' => 'fa10928802aea9b3136519640aa3c3c59e9e1084', + ), + 'sabre/event' => + array ( + 'pretty_version' => '2.0.2', + 'version' => '2.0.2.0', + 'aliases' => + array ( + ), + 'reference' => '337b6f5e10ea6e0b21e22c7e5788dd3883ae73ff', + ), + 'sabre/http' => + array ( + 'pretty_version' => '3.0.5', + 'version' => '3.0.5.0', + 'aliases' => + array ( + ), + 'reference' => '6b06c03376219b3d608e1f878514ec105ed1b577', + ), + 'sabre/vobject' => + array ( + 'pretty_version' => '3.5.3', + 'version' => '3.5.3.0', + 'aliases' => + array ( + ), + 'reference' => '129d80533a9ec0d9cacfb50b51180c34edb6874c', + ), + 'sebastian/code-unit-reverse-lookup' => + array ( + 'pretty_version' => '1.0.2', + 'version' => '1.0.2.0', + 'aliases' => + array ( + ), + 'reference' => '1de8cd5c010cb153fcd68b8d0f64606f523f7619', + ), + 'sebastian/comparator' => + array ( + 'pretty_version' => '1.2.4', + 'version' => '1.2.4.0', + 'aliases' => + array ( + ), + 'reference' => '2b7424b55f5047b47ac6e5ccb20b2aea4011d9be', + ), + 'sebastian/diff' => + array ( + 'pretty_version' => '1.4.3', + 'version' => '1.4.3.0', + 'aliases' => + array ( + ), + 'reference' => '7f066a26a962dbe58ddea9f72a4e82874a3975a4', + ), + 'sebastian/environment' => + array ( + 'pretty_version' => '2.0.0', + 'version' => '2.0.0.0', + 'aliases' => + array ( + ), + 'reference' => '5795ffe5dc5b02460c3e34222fee8cbe245d8fac', + ), + 'sebastian/exporter' => + array ( + 'pretty_version' => '2.0.0', + 'version' => '2.0.0.0', + 'aliases' => + array ( + ), + 'reference' => 'ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4', + ), + 'sebastian/global-state' => + array ( + 'pretty_version' => '1.1.1', + 'version' => '1.1.1.0', + 'aliases' => + array ( + ), + 'reference' => 'bc37d50fea7d017d3d340f230811c9f1d7280af4', + ), + 'sebastian/object-enumerator' => + array ( + 'pretty_version' => '2.0.1', + 'version' => '2.0.1.0', + 'aliases' => + array ( + ), + 'reference' => '1311872ac850040a79c3c058bea3e22d0f09cbb7', + ), + 'sebastian/recursion-context' => + array ( + 'pretty_version' => '2.0.0', + 'version' => '2.0.0.0', + 'aliases' => + array ( + ), + 'reference' => '2c3ba150cbec723aa057506e73a8d33bdb286c9a', + ), + 'sebastian/resource-operations' => + array ( + 'pretty_version' => '1.0.0', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => 'ce990bb21759f94aeafd30209e8cfcdfa8bc3f52', + ), + 'sebastian/version' => + array ( + 'pretty_version' => '2.0.1', + 'version' => '2.0.1.0', + 'aliases' => + array ( + ), + 'reference' => '99732be0ddb3361e16ad77b68ba41efc8e979019', + ), + 'smarty/smarty' => + array ( + 'pretty_version' => 'v3.1.43', + 'version' => '3.1.43.0', + 'aliases' => + array ( + ), + 'reference' => '273f7e00fec034f6d61112552e9caf08d19565b7', + ), + 'symfony/polyfill-ctype' => + array ( + 'pretty_version' => 'v1.24.0', + 'version' => '1.24.0.0', + 'aliases' => + array ( + ), + 'reference' => '30885182c981ab175d4d034db0f6f469898070ab', + ), + 'symfony/yaml' => + array ( + 'pretty_version' => 'v4.4.36', + 'version' => '4.4.36.0', + 'aliases' => + array ( + ), + 'reference' => 'a19f7c44ba665fa9d9d415cc4493361381b93f9b', + ), + 'webmozart/assert' => + array ( + 'pretty_version' => '1.10.0', + 'version' => '1.10.0.0', + 'aliases' => + array ( + ), + 'reference' => '6964c76c7804814a842473e0c8fd15bab0f18e25', + ), + 'zf1/zend-cache' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => 'c3a6fc20f5d5c5ab7adc16f29f33eb5b2e00d86e', + ), + 'zf1/zend-config' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => '2a1e588782d74e22d73682dc71fa4a7e193d52c4', + ), + 'zf1/zend-controller' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => 'dee228b392a053106efcc1310c48537ce653046a', + ), + 'zf1/zend-exception' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => 'ca30959d3e2f522f481a3d1459386acf1aa4ca74', + ), + 'zf1/zend-json' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => 'dbf5d4b46bdf6299bf1f7c6b1ef7311e4299602f', + ), + 'zf1/zend-loader' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => '894dcfb8084488575d46e496e399f64aacd5761c', + ), + 'zf1/zend-locale' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => '336df96aebb0270fb682e6ee8bf0cc0781cc3edb', + ), + 'zf1/zend-log' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => '1c67db7a0eb288c100b23105dad21dbc09883300', + ), + 'zf1/zend-registry' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => '1737419285b800728c27063318509fb2d00057ba', + ), + 'zf1/zend-server' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => 'ce8242896b3d63a51f3984ef1d6ed9cc9c67e547', + ), + 'zf1/zend-uri' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => '73964522a8a5041798cc8edad1e81fa0879737f2', + ), + 'zf1/zend-validate' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => '5ceb707212abaaf92ccdd91270c6d37e07bf551b', + ), + 'zf1/zend-view' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => '22797ef472cd64806c1ebafa83b59e92f7532e25', + ), + 'zf1/zend-xml' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => 'd4f99144a0cf0c5e383f3fb765cdd7dfde7caab4', + ), + ), +); private static $canGetVendors; - - /** - * @var array[] - * @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> - */ private static $installedByVendor = array(); /** @@ -62,41 +821,18 @@ } /** - * Returns a list of all package names with a specific type e.g. 'library' - * - * @param string $type - * @return string[] - * @psalm-return list<string> - */ - public static function getInstalledPackagesByType($type) - { - $packagesByType = array(); - - foreach (self::getInstalled() as $installed) { - foreach ($installed['versions'] as $name => $package) { - if (isset($package['type']) && $package['type'] === $type) { - $packagesByType[] = $name; - } - } - } - - return $packagesByType; - } - - /** * Checks whether the given package is installed * * This also returns true if the package name is provided or replaced by another package * * @param string $packageName - * @param bool $includeDevRequirements * @return bool */ - public static function isInstalled($packageName, $includeDevRequirements = true) + public static function isInstalled($packageName) { foreach (self::getInstalled() as $installed) { if (isset($installed['versions'][$packageName])) { - return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); + return true; } } @@ -110,9 +846,10 @@ * * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') * - * @param VersionParser $parser Install composer/semver to have access to this class and functionality - * @param string $packageName - * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * * @return bool */ public static function satisfies(VersionParser $parser, $packageName, $constraint) @@ -223,25 +960,8 @@ } /** - * @param string $packageName - * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. - */ - public static function getInstallPath($packageName) - { - foreach (self::getInstalled() as $installed) { - if (!isset($installed['versions'][$packageName])) { - continue; - } - - return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; - } - - throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); - } - - /** * @return array - * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string} + * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[]} */ public static function getRootPackage() { @@ -253,39 +973,15 @@ /** * Returns the raw installed.php data for custom implementations * - * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. * @return array[] - * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} + * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[]}, versions: array<string, array{pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[]}>} */ public static function getRawData() { - @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); - - if (null === self::$installed) { - // only require the installed.php file if this file is loaded from its dumped location, - // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 - if (substr(__DIR__, -8, 1) !== 'C') { - self::$installed = include __DIR__ . '/installed.php'; - } else { - self::$installed = array(); - } - } - return self::$installed; } /** - * Returns the raw data of all installed.php which are currently loaded for custom implementations - * - * @return array[] - * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> - */ - public static function getAllRawData() - { - return self::getInstalled(); - } - - /** * Lets you reload the static array from another file * * This is only useful for complex integrations in which a project needs to use @@ -301,7 +997,7 @@ * @param array[] $data A vendor/composer/installed.php data set * @return void * - * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data + * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[]}, versions: array<string, array{pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[]}>} $data */ public static function reload($data) { @@ -311,7 +1007,7 @@ /** * @return array[] - * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> + * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[]}, versions: array<string, array{pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[]}>}> */ private static function getInstalled() { @@ -327,22 +1023,10 @@ $installed[] = self::$installedByVendor[$vendorDir]; } elseif (is_file($vendorDir.'/composer/installed.php')) { $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; - if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { - self::$installed = $installed[count($installed) - 1]; - } } } } - if (null === self::$installed) { - // only require the installed.php file if this file is loaded from its dumped location, - // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 - if (substr(__DIR__, -8, 1) !== 'C') { - self::$installed = require __DIR__ . '/installed.php'; - } else { - self::$installed = array(); - } - } $installed[] = self::$installed; return $installed;
View file
roundcubemail-1.4.11.20.tar.gz/vendor/composer/LICENSE -> roundcubemail-1.4.13.tar.gz/vendor/composer/LICENSE
Changed
@@ -1,4 +1,3 @@ - Copyright (c) Nils Adermann, Jordi Boggiano Permission is hereby granted, free of charge, to any person obtaining a copy @@ -18,4 +17,3 @@ 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. -
View file
roundcubemail-1.4.11.20.tar.gz/vendor/composer/autoload_classmap.php -> roundcubemail-1.4.13.tar.gz/vendor/composer/autoload_classmap.php
Changed
@@ -32,6 +32,19 @@ 'File_Iterator' => $vendorDir . '/phpunit/php-file-iterator/src/Iterator.php', 'File_Iterator_Facade' => $vendorDir . '/phpunit/php-file-iterator/src/Facade.php', 'File_Iterator_Factory' => $vendorDir . '/phpunit/php-file-iterator/src/Factory.php', + 'Net_LDAP2' => $vendorDir . '/pear/net_ldap2/Net/LDAP2.php', + 'Net_LDAP2_Entry' => $vendorDir . '/pear/net_ldap2/Net/LDAP2/Entry.php', + 'Net_LDAP2_Error' => $vendorDir . '/pear/net_ldap2/Net/LDAP2.php', + 'Net_LDAP2_Filter' => $vendorDir . '/pear/net_ldap2/Net/LDAP2/Filter.php', + 'Net_LDAP2_LDIF' => $vendorDir . '/pear/net_ldap2/Net/LDAP2/LDIF.php', + 'Net_LDAP2_RootDSE' => $vendorDir . '/pear/net_ldap2/Net/LDAP2/RootDSE.php', + 'Net_LDAP2_Schema' => $vendorDir . '/pear/net_ldap2/Net/LDAP2/Schema.php', + 'Net_LDAP2_SchemaCache' => $vendorDir . '/pear/net_ldap2/Net/LDAP2/SchemaCache.interface.php', + 'Net_LDAP2_Search' => $vendorDir . '/pear/net_ldap2/Net/LDAP2/Search.php', + 'Net_LDAP2_SimpleFileSchemaCache' => $vendorDir . '/pear/net_ldap2/Net/LDAP2/SimpleFileSchemaCache.php', + 'Net_LDAP2_Util' => $vendorDir . '/pear/net_ldap2/Net/LDAP2/Util.php', + 'Net_LDAP3' => $vendorDir . '/kolab/net_ldap3/lib/Net/LDAP3.php', + 'Net_LDAP3_Result' => $vendorDir . '/kolab/net_ldap3/lib/Net/LDAP3/Result.php', 'Net_Sieve' => $vendorDir . '/pear/net_sieve/Sieve.php', 'Net_URL2' => $vendorDir . '/pear/net_url2/Net/URL2.php', 'PEAR_Exception' => $vendorDir . '/pear/pear_exception/PEAR/Exception.php',
View file
roundcubemail-1.4.11.20.tar.gz/vendor/composer/autoload_namespaces.php -> roundcubemail-1.4.13.tar.gz/vendor/composer/autoload_namespaces.php
Changed
@@ -10,10 +10,12 @@ 'Zend_View' => array($vendorDir . '/zf1/zend-view/library'), 'Zend_Validate' => array($vendorDir . '/zf1/zend-validate/library'), 'Zend_Uri' => array($vendorDir . '/zf1/zend-uri/library'), + 'Zend_Server' => array($vendorDir . '/zf1/zend-server/library'), 'Zend_Registry' => array($vendorDir . '/zf1/zend-registry/library'), 'Zend_Log' => array($vendorDir . '/zf1/zend-log/library'), 'Zend_Locale' => array($vendorDir . '/zf1/zend-locale/library'), 'Zend_Loader' => array($vendorDir . '/zf1/zend-loader/library'), + 'Zend_Json' => array($vendorDir . '/zf1/zend-json/library'), 'Zend_Exception' => array($vendorDir . '/zf1/zend-exception/library'), 'Zend_Controller' => array($vendorDir . '/zf1/zend-controller/library'), 'Zend_Config' => array($vendorDir . '/zf1/zend-config/library'), @@ -24,7 +26,7 @@ 'KubAT\\PhpSimple\\HtmlDomParser' => array($vendorDir . '/kub-at/php-simple-html-dom-parser/src'), 'HTTP_Request2' => array($vendorDir . '/pear/http_request2'), 'HTMLPurifier' => array($vendorDir . '/ezyang/htmlpurifier/library'), - 'Console' => array($vendorDir . '/pear/console_commandline', $vendorDir . '/pear/console_getopt'), + 'Console' => array($vendorDir . '/pear/console_getopt', $vendorDir . '/pear/console_commandline'), 'Caxy\\HtmlDiff' => array($vendorDir . '/caxy/php-htmldiff/lib'), 'Auth' => array($vendorDir . '/pear/auth_sasl'), '' => array($vendorDir . '/pear/pear-core-minimal/src'),
View file
roundcubemail-1.4.11.20.tar.gz/vendor/composer/autoload_real.php -> roundcubemail-1.4.13.tar.gz/vendor/composer/autoload_real.php
Changed
@@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit9bb1f3e4f7cfef6c404d641f234e8092 +class ComposerAutoloaderInitd89bf3a6fb4183211eaea1c21a92faae { private static $loader; @@ -24,9 +24,9 @@ require __DIR__ . '/platform_check.php'; - spl_autoload_register(array('ComposerAutoloaderInit9bb1f3e4f7cfef6c404d641f234e8092', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInitd89bf3a6fb4183211eaea1c21a92faae', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); - spl_autoload_unregister(array('ComposerAutoloaderInit9bb1f3e4f7cfef6c404d641f234e8092', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInitd89bf3a6fb4183211eaea1c21a92faae', 'loadClassLoader')); $includePaths = require __DIR__ . '/include_paths.php'; $includePaths[] = get_include_path(); @@ -36,7 +36,7 @@ if ($useStaticLoader) { require __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInit9bb1f3e4f7cfef6c404d641f234e8092::getInitializer($loader)); + call_user_func(\Composer\Autoload\ComposerStaticInitd89bf3a6fb4183211eaea1c21a92faae::getInitializer($loader)); } else { $map = require __DIR__ . '/autoload_namespaces.php'; foreach ($map as $namespace => $path) { @@ -57,19 +57,19 @@ $loader->register(true); if ($useStaticLoader) { - $includeFiles = Composer\Autoload\ComposerStaticInit9bb1f3e4f7cfef6c404d641f234e8092::$files; + $includeFiles = Composer\Autoload\ComposerStaticInitd89bf3a6fb4183211eaea1c21a92faae::$files; } else { $includeFiles = require __DIR__ . '/autoload_files.php'; } foreach ($includeFiles as $fileIdentifier => $file) { - composerRequire9bb1f3e4f7cfef6c404d641f234e8092($fileIdentifier, $file); + composerRequired89bf3a6fb4183211eaea1c21a92faae($fileIdentifier, $file); } return $loader; } } -function composerRequire9bb1f3e4f7cfef6c404d641f234e8092($fileIdentifier, $file) +function composerRequired89bf3a6fb4183211eaea1c21a92faae($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { require $file;
View file
roundcubemail-1.4.11.20.tar.gz/vendor/composer/autoload_static.php -> roundcubemail-1.4.13.tar.gz/vendor/composer/autoload_static.php
Changed
@@ -4,7 +4,7 @@ namespace Composer\Autoload; -class ComposerStaticInit9bb1f3e4f7cfef6c404d641f234e8092 +class ComposerStaticInitd89bf3a6fb4183211eaea1c21a92faae { public static $files = array ( '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', @@ -140,6 +140,10 @@ array ( 0 => __DIR__ . '/..' . '/zf1/zend-uri/library', ), + 'Zend_Server' => + array ( + 0 => __DIR__ . '/..' . '/zf1/zend-server/library', + ), 'Zend_Registry' => array ( 0 => __DIR__ . '/..' . '/zf1/zend-registry/library', @@ -156,6 +160,10 @@ array ( 0 => __DIR__ . '/..' . '/zf1/zend-loader/library', ), + 'Zend_Json' => + array ( + 0 => __DIR__ . '/..' . '/zf1/zend-json/library', + ), 'Zend_Exception' => array ( 0 => __DIR__ . '/..' . '/zf1/zend-exception/library', @@ -218,8 +226,8 @@ array ( 'Console' => array ( - 0 => __DIR__ . '/..' . '/pear/console_commandline', - 1 => __DIR__ . '/..' . '/pear/console_getopt', + 0 => __DIR__ . '/..' . '/pear/console_getopt', + 1 => __DIR__ . '/..' . '/pear/console_commandline', ), 'Caxy\\HtmlDiff' => array ( @@ -266,6 +274,19 @@ 'File_Iterator' => __DIR__ . '/..' . '/phpunit/php-file-iterator/src/Iterator.php', 'File_Iterator_Facade' => __DIR__ . '/..' . '/phpunit/php-file-iterator/src/Facade.php', 'File_Iterator_Factory' => __DIR__ . '/..' . '/phpunit/php-file-iterator/src/Factory.php', + 'Net_LDAP2' => __DIR__ . '/..' . '/pear/net_ldap2/Net/LDAP2.php', + 'Net_LDAP2_Entry' => __DIR__ . '/..' . '/pear/net_ldap2/Net/LDAP2/Entry.php', + 'Net_LDAP2_Error' => __DIR__ . '/..' . '/pear/net_ldap2/Net/LDAP2.php', + 'Net_LDAP2_Filter' => __DIR__ . '/..' . '/pear/net_ldap2/Net/LDAP2/Filter.php', + 'Net_LDAP2_LDIF' => __DIR__ . '/..' . '/pear/net_ldap2/Net/LDAP2/LDIF.php', + 'Net_LDAP2_RootDSE' => __DIR__ . '/..' . '/pear/net_ldap2/Net/LDAP2/RootDSE.php', + 'Net_LDAP2_Schema' => __DIR__ . '/..' . '/pear/net_ldap2/Net/LDAP2/Schema.php', + 'Net_LDAP2_SchemaCache' => __DIR__ . '/..' . '/pear/net_ldap2/Net/LDAP2/SchemaCache.interface.php', + 'Net_LDAP2_Search' => __DIR__ . '/..' . '/pear/net_ldap2/Net/LDAP2/Search.php', + 'Net_LDAP2_SimpleFileSchemaCache' => __DIR__ . '/..' . '/pear/net_ldap2/Net/LDAP2/SimpleFileSchemaCache.php', + 'Net_LDAP2_Util' => __DIR__ . '/..' . '/pear/net_ldap2/Net/LDAP2/Util.php', + 'Net_LDAP3' => __DIR__ . '/..' . '/kolab/net_ldap3/lib/Net/LDAP3.php', + 'Net_LDAP3_Result' => __DIR__ . '/..' . '/kolab/net_ldap3/lib/Net/LDAP3/Result.php', 'Net_Sieve' => __DIR__ . '/..' . '/pear/net_sieve/Sieve.php', 'Net_URL2' => __DIR__ . '/..' . '/pear/net_url2/Net/URL2.php', 'PEAR_Exception' => __DIR__ . '/..' . '/pear/pear_exception/PEAR/Exception.php', @@ -910,11 +931,11 @@ public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit9bb1f3e4f7cfef6c404d641f234e8092::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit9bb1f3e4f7cfef6c404d641f234e8092::$prefixDirsPsr4; - $loader->prefixesPsr0 = ComposerStaticInit9bb1f3e4f7cfef6c404d641f234e8092::$prefixesPsr0; - $loader->fallbackDirsPsr0 = ComposerStaticInit9bb1f3e4f7cfef6c404d641f234e8092::$fallbackDirsPsr0; - $loader->classMap = ComposerStaticInit9bb1f3e4f7cfef6c404d641f234e8092::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInitd89bf3a6fb4183211eaea1c21a92faae::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitd89bf3a6fb4183211eaea1c21a92faae::$prefixDirsPsr4; + $loader->prefixesPsr0 = ComposerStaticInitd89bf3a6fb4183211eaea1c21a92faae::$prefixesPsr0; + $loader->fallbackDirsPsr0 = ComposerStaticInitd89bf3a6fb4183211eaea1c21a92faae::$fallbackDirsPsr0; + $loader->classMap = ComposerStaticInitd89bf3a6fb4183211eaea1c21a92faae::$classMap; }, null, ClassLoader::class); }
View file
roundcubemail-1.4.11.20.tar.gz/vendor/composer/include_paths.php -> roundcubemail-1.4.13.tar.gz/vendor/composer/include_paths.php
Changed
@@ -9,11 +9,12 @@ $vendorDir . '/pear/pear_exception', $vendorDir . '/pear/net_url2', $vendorDir . '/pear/http_request2', + $vendorDir . '/pear/console_getopt', + $vendorDir . '/pear/pear-core-minimal/src', + $vendorDir . '/pear/net_ldap2', $vendorDir . '/pear/auth_sasl', $vendorDir . '/pear/console_commandline', $vendorDir . '/pear/crypt_gpg', - $vendorDir . '/pear/console_getopt', - $vendorDir . '/pear/pear-core-minimal/src', $vendorDir . '/pear/mail_mime', $vendorDir . '/pear/net_idna2', $vendorDir . '/pear/net_socket',
View file
roundcubemail-1.4.11.20.tar.gz/vendor/composer/installed.json -> roundcubemail-1.4.13.tar.gz/vendor/composer/installed.json
Changed
@@ -303,7 +303,7 @@ "version_normalized": "3.5.10.0", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/calendar", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/calendar", "reference": "45103d5bdee63f976c918f8cfcf20b400310bcb0" }, "require": { @@ -349,7 +349,7 @@ "version_normalized": "3.5.6.0", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_activesync", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_activesync", "reference": "7e8c46290074fe6c1ab72bc9f6b90aa271ee16ef" }, "require": { @@ -388,7 +388,7 @@ "version_normalized": "3.5.10.0", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_addressbook", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_addressbook", "reference": "29195279f672640ffe38f70ddabe87b56172e889" }, "require": { @@ -422,12 +422,51 @@ "install-path": "../../plugins/kolab_addressbook" }, { + "name": "kolab/kolab_auth", + "version": "3.5.8", + "version_normalized": "3.5.8.0", + "dist": { + "type": "path", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_auth", + "reference": "ab0ed459f74a03f8eab6822652e084f0430a4f07" + }, + "require": { + "kolab/libkolab": ">=3.5.1", + "php": ">=5.3.0", + "roundcube/plugin-installer": ">=0.1.3" + }, + "type": "roundcube-plugin", + "installation-source": "dist", + "license": [ + "AGPLv3" + ], + "authors": [ + { + "name": "Thomas Bruederli", + "email": "bruederli@kolabsys.com", + "role": "Lead" + }, + { + "name": "Aleksander Machniak", + "email": "machniak@kolabsys.com", + "role": "Lead" + } + ], + "description": "Kolab authentication", + "homepage": "https://git.kolab.org/diffusion/RPK/", + "transport-options": { + "symlink": false, + "relative": false + }, + "install-path": "../../plugins/kolab_auth" + }, + { "name": "kolab/kolab_chat", "version": "3.5.4", "version_normalized": "3.5.4.0", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_chat", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_chat", "reference": "b2f85fcb8324b9961dd02fb3e3acd92be33b558e" }, "require": { @@ -461,7 +500,7 @@ "version_normalized": "3.4.0.0", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_config", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_config", "reference": "b31a76c1700679249fc222c46582ecbd1215f117" }, "require": { @@ -495,7 +534,7 @@ "version_normalized": "3.5.2.0", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_files", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_files", "reference": "0439d3783b59d6e52f23e86046881fd0ca8c0bd5" }, "require": { @@ -529,7 +568,7 @@ "version_normalized": "3.5.2.0", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_folders", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_folders", "reference": "c70560fcfe40bf1582ea79debf3ae2aebbe94688" }, "require": { @@ -563,7 +602,7 @@ "version_normalized": "3.5.5.0", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_notes", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_notes", "reference": "07297b8ea8b3827d0ba46801760854b0db560576" }, "require": { @@ -602,7 +641,7 @@ "version_normalized": "3.5.2.0", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/kolab_tags", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/kolab_tags", "reference": "62ffa5279d9f351941be6b23b0d0478aeff91bfd" }, "require": { @@ -636,7 +675,7 @@ "version_normalized": "3.5.10.0", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/libcalendaring", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/libcalendaring", "reference": "b9ab21ae1a5b134a06c66d55372712630171a590" }, "require": { @@ -675,7 +714,7 @@ "version_normalized": "3.5.10.0", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/libkolab", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/libkolab", "reference": "a8abbba8039ee3bdde7be1b6758893aeff0287d8" }, "require": { @@ -710,12 +749,69 @@ "install-path": "../../plugins/libkolab" }, { + "name": "kolab/net_ldap3", + "version": "v1.1.3", + "version_normalized": "1.1.3.0", + "source": { + "type": "git", + "url": "https://gitlab.com/roundcube/net_ldap3.git", + "reference": "e1835e36fa5d3434f9804670fc3cdd16992ec66a" + }, + "dist": { + "type": "zip", + "url": "https://gitlab.com/api/v4/projects/roundcube%2Fnet_ldap3/repository/archive.zip?sha=e1835e36fa5d3434f9804670fc3cdd16992ec66a", + "reference": "e1835e36fa5d3434f9804670fc3cdd16992ec66a", + "shasum": "" + }, + "require": { + "pear/net_ldap2": ">=2.0.12", + "php": ">=5.3.3" + }, + "time": "2019-10-21T11:18:59+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-3.0+" + ], + "authors": [ + { + "name": "Jeroen van Meeuwen", + "email": "vanmeeuwen@kolabsys.com", + "role": "Lead" + }, + { + "name": "Aleksander Machniak", + "email": "machniak@kolabsys.com", + "role": "Developer" + }, + { + "name": "Thomas Bruederli", + "email": "roundcube@gmail.com", + "role": "Developer" + } + ], + "description": "A successor of the PEAR:Net_LDAP2 module providing advanced functionality for accessing LDAP directories", + "homepage": "http://git.kolab.org/pear/Net_LDAP3/", + "keywords": [ + "PEAR", + "ldap", + "vlv" + ], + "install-path": "../kolab/net_ldap3" + }, + { "name": "kolab/odfviewer", "version": "3.4.0", "version_normalized": "3.4.0.0", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/odfviewer", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/odfviewer", "reference": "43f3c0cf314cb818f9bc96d6bd378793e22a4ed4" }, "require": { @@ -748,7 +844,7 @@ "version_normalized": "3.4.0.0", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/pdfviewer", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/pdfviewer", "reference": "3437085223a60d929fbf076c232008e4377407c1" }, "require": { @@ -781,7 +877,7 @@ "version_normalized": "3.5.10.0", "dist": { "type": "path", - "url": "/tmp/roundcubemail-1.4.11.20/roundcubemail-plugins-kolab-latest/plugins/tasklist", + "url": "/tmp/roundcubemail-1.4.13/roundcubemail-plugins-kolab-latest/plugins/tasklist", "reference": "7ae02f72964925d19fb244754f9d3e9b20af677c" }, "require": { @@ -1435,6 +1531,52 @@ "install-path": "../pear/net_idna2" }, { + "name": "pear/net_ldap2", + "version": "v2.2.0", + "version_normalized": "2.2.0.0", + "source": { + "type": "git", + "url": "https://github.com/pear/Net_LDAP2.git", + "reference": "38f1b22a96dfbd7ec53852f0e1e7ec1a9a5eb0e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pear/Net_LDAP2/zipball/38f1b22a96dfbd7ec53852f0e1e7ec1a9a5eb0e8", + "reference": "38f1b22a96dfbd7ec53852f0e1e7ec1a9a5eb0e8", + "shasum": "" + }, + "require": { + "ext-ldap": "*", + "pear/pear-core-minimal": "^1.10.1" + }, + "time": "2015-10-30T20:34:22+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "classmap": [ + "Net/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "." + ], + "license": [ + "LGPL-3.0" + ], + "description": "Object oriented interface for searching and manipulating LDAP-entries", + "homepage": "http://pear.php.net/package/Net_LDAP2", + "keywords": [ + "PEAR", + "ldap" + ], + "support": { + "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=Net_LDAP2", + "source": "https://github.com/pear/Net_LDAP2" + }, + "install-path": "../pear/net_ldap2" + }, + { "name": "pear/net_sieve", "version": "1.4.5", "version_normalized": "1.4.5.0", @@ -1934,17 +2076,17 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.5.1", - "version_normalized": "1.5.1.0", + "version": "1.6.0", + "version_normalized": "1.6.0.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae" + "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/a12f7e301eb7258bb68acd89d4aefa05c2906cae", - "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706", + "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706", "shasum": "" }, "require": { @@ -1955,7 +2097,7 @@ "ext-tokenizer": "*", "psalm/phar": "^4.8" }, - "time": "2021-10-02T14:08:47+00:00", + "time": "2022-01-04T19:58:01+00:00", "type": "library", "extra": { "branch-alias": { @@ -1981,7 +2123,7 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.1" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.0" }, "install-path": "../phpdocumentor/type-resolver" }, @@ -3420,17 +3562,17 @@ }, { "name": "smarty/smarty", - "version": "v3.1.40", - "version_normalized": "3.1.40.0", + "version": "v3.1.43", + "version_normalized": "3.1.43.0", "source": { "type": "git", "url": "https://github.com/smarty-php/smarty.git", - "reference": "9d4f8309ed49702e0d7152f9983c3a9c4b98eb9d" + "reference": "273f7e00fec034f6d61112552e9caf08d19565b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/smarty-php/smarty/zipball/9d4f8309ed49702e0d7152f9983c3a9c4b98eb9d", - "reference": "9d4f8309ed49702e0d7152f9983c3a9c4b98eb9d", + "url": "https://api.github.com/repos/smarty-php/smarty/zipball/273f7e00fec034f6d61112552e9caf08d19565b7", + "reference": "273f7e00fec034f6d61112552e9caf08d19565b7", "shasum": "" }, "require": { @@ -3440,7 +3582,7 @@ "phpunit/phpunit": "^7.5 || ^6.5 || ^5.7 || ^4.8", "smarty/smarty-lexer": "^3.1" }, - "time": "2021-10-13T10:04:31+00:00", + "time": "2022-01-10T09:52:40+00:00", "type": "library", "extra": { "branch-alias": { @@ -3480,32 +3622,35 @@ "forum": "http://www.smarty.net/forums/", "irc": "irc://irc.freenode.org/smarty", "issues": "https://github.com/smarty-php/smarty/issues", - "source": "https://github.com/smarty-php/smarty/tree/v3.1.40" + "source": "https://github.com/smarty-php/smarty/tree/v3.1.43" }, "install-path": "../smarty/smarty" }, { "name": "symfony/polyfill-ctype", - "version": "v1.23.0", - "version_normalized": "1.23.0.0", + "version": "v1.24.0", + "version_normalized": "1.24.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" + "reference": "30885182c981ab175d4d034db0f6f469898070ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", + "reference": "30885182c981ab175d4d034db0f6f469898070ab", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-ctype": "*" + }, "suggest": { "ext-ctype": "For best performance" }, - "time": "2021-02-19T12:13:01+00:00", + "time": "2021-10-20T20:35:02+00:00", "type": "library", "extra": { "branch-alias": { @@ -3548,7 +3693,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.24.0" }, "funding": [ { @@ -3568,17 +3713,17 @@ }, { "name": "symfony/yaml", - "version": "v4.4.34", - "version_normalized": "4.4.34.0", + "version": "v4.4.36", + "version_normalized": "4.4.36.0", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "2c309e258adeb9970229042be39b360d34986fad" + "reference": "a19f7c44ba665fa9d9d415cc4493361381b93f9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/2c309e258adeb9970229042be39b360d34986fad", - "reference": "2c309e258adeb9970229042be39b360d34986fad", + "url": "https://api.github.com/repos/symfony/yaml/zipball/a19f7c44ba665fa9d9d415cc4493361381b93f9b", + "reference": "a19f7c44ba665fa9d9d415cc4493361381b93f9b", "shasum": "" }, "require": { @@ -3594,7 +3739,7 @@ "suggest": { "symfony/console": "For validating YAML files using the lint command" }, - "time": "2021-11-18T18:49:23+00:00", + "time": "2021-11-25T16:40:00+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -3622,7 +3767,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v4.4.34" + "source": "https://github.com/symfony/yaml/tree/v4.4.36" }, "funding": [ { @@ -3893,6 +4038,53 @@ "install-path": "../zf1/zend-exception" }, { + "name": "zf1/zend-json", + "version": "1.12.20", + "version_normalized": "1.12.20.0", + "source": { + "type": "git", + "url": "https://github.com/zf1/zend-json.git", + "reference": "dbf5d4b46bdf6299bf1f7c6b1ef7311e4299602f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zf1/zend-json/zipball/dbf5d4b46bdf6299bf1f7c6b1ef7311e4299602f", + "reference": "dbf5d4b46bdf6299bf1f7c6b1ef7311e4299602f", + "shasum": "" + }, + "require": { + "php": ">=5.2.11", + "zf1/zend-exception": "self.version", + "zf1/zend-loader": "self.version", + "zf1/zend-server": "self.version", + "zf1/zend-xml": "self.version" + }, + "time": "2015-04-30T11:11:12+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Zend_Json": "library/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Zend Framework 1 Json package", + "homepage": "http://framework.zend.com/", + "keywords": [ + "ZF1", + "framework", + "json", + "zend" + ], + "support": { + "source": "https://github.com/zf1/zend-json/tree/release-1.12.11" + }, + "install-path": "../zf1/zend-json" + }, + { "name": "zf1/zend-loader", "version": "1.12.20", "version_normalized": "1.12.20.0", @@ -4080,6 +4272,50 @@ "install-path": "../zf1/zend-registry" }, { + "name": "zf1/zend-server", + "version": "1.12.20", + "version_normalized": "1.12.20.0", + "source": { + "type": "git", + "url": "https://github.com/zf1/zend-server.git", + "reference": "ce8242896b3d63a51f3984ef1d6ed9cc9c67e547" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zf1/zend-server/zipball/ce8242896b3d63a51f3984ef1d6ed9cc9c67e547", + "reference": "ce8242896b3d63a51f3984ef1d6ed9cc9c67e547", + "shasum": "" + }, + "require": { + "php": ">=5.2.11", + "zf1/zend-exception": "self.version" + }, + "time": "2015-04-30T11:11:32+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Zend_Server": "library/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Zend Framework 1 Server package", + "homepage": "http://framework.zend.com/", + "keywords": [ + "ZF1", + "framework", + "server", + "zend" + ], + "support": { + "source": "https://github.com/zf1/zend-server/tree/release-1.12.11" + }, + "install-path": "../zf1/zend-server" + }, + { "name": "zf1/zend-uri", "version": "1.12.20", "version_normalized": "1.12.20.0",
View file
roundcubemail-1.4.11.20.tar.gz/vendor/composer/installed.php -> roundcubemail-1.4.13.tar.gz/vendor/composer/installed.php
Changed
@@ -1,725 +1,773 @@ -<?php return array( - 'root' => array( - 'pretty_version' => 'dev-master', - 'version' => 'dev-master', - 'type' => 'library', - 'install_path' => __DIR__ . '/../../', - 'aliases' => array(), - 'reference' => '4e1358b4dc1a8116357657ae5c8738e855aea85a', - 'name' => 'roundcube/roundcubemail', - 'dev' => true, - ), - 'versions' => array( - 'caxy/php-htmldiff' => array( - 'pretty_version' => 'v0.1.9', - 'version' => '0.1.9.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../caxy/php-htmldiff', - 'aliases' => array(), - 'reference' => '4bad5c6a4ecc76954d37764e6a29273b6b7bf1f8', - 'dev_requirement' => false, - ), - 'doctrine/instantiator' => array( - 'pretty_version' => '1.4.0', - 'version' => '1.4.0.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../doctrine/instantiator', - 'aliases' => array(), - 'reference' => 'd56bf6102915de5702778fe20f2de3b2fe570b5b', - 'dev_requirement' => true, - ), - 'endroid/qr-code' => array( - 'pretty_version' => '1.6.6', - 'version' => '1.6.6.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../endroid/qr-code', - 'aliases' => array(), - 'reference' => 'cef5d5b7b904d7bb0708eb744c35316364b65fa0', - 'dev_requirement' => false, - ), - 'ezyang/htmlpurifier' => array( - 'pretty_version' => 'v4.14.0', - 'version' => '4.14.0.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../ezyang/htmlpurifier', - 'aliases' => array(), - 'reference' => '12ab42bd6e742c70c0a52f7b82477fcd44e64b75', - 'dev_requirement' => false, - ), - 'johndoh/contextmenu' => array( - 'pretty_version' => '3.2.1', - 'version' => '3.2.1.0', - 'type' => 'roundcube-plugin', - 'install_path' => __DIR__ . '/../../plugins/contextmenu', - 'aliases' => array(), - 'reference' => '602a3812922fb8f71814eb3b8d91e9b7859aab7e', - 'dev_requirement' => false, - ), - 'kolab/calendar' => array( - 'pretty_version' => '3.5.10', - 'version' => '3.5.10.0', - 'type' => 'roundcube-plugin', - 'install_path' => __DIR__ . '/../../plugins/calendar', - 'aliases' => array(), - 'reference' => '45103d5bdee63f976c918f8cfcf20b400310bcb0', - 'dev_requirement' => false, - ), - 'kolab/kolab_activesync' => array( - 'pretty_version' => '3.5.6', - 'version' => '3.5.6.0', - 'type' => 'roundcube-plugin', - 'install_path' => __DIR__ . '/../../plugins/kolab_activesync', - 'aliases' => array(), - 'reference' => '7e8c46290074fe6c1ab72bc9f6b90aa271ee16ef', - 'dev_requirement' => false, - ), - 'kolab/kolab_addressbook' => array( - 'pretty_version' => '3.5.10', - 'version' => '3.5.10.0', - 'type' => 'roundcube-plugin', - 'install_path' => __DIR__ . '/../../plugins/kolab_addressbook', - 'aliases' => array(), - 'reference' => '29195279f672640ffe38f70ddabe87b56172e889', - 'dev_requirement' => false, - ), - 'kolab/kolab_chat' => array( - 'pretty_version' => '3.5.4', - 'version' => '3.5.4.0', - 'type' => 'roundcube-plugin', - 'install_path' => __DIR__ . '/../../plugins/kolab_chat', - 'aliases' => array(), - 'reference' => 'b2f85fcb8324b9961dd02fb3e3acd92be33b558e', - 'dev_requirement' => false, - ), - 'kolab/kolab_config' => array( - 'pretty_version' => '3.4.0', - 'version' => '3.4.0.0', - 'type' => 'roundcube-plugin', - 'install_path' => __DIR__ . '/../../plugins/kolab_config', - 'aliases' => array(), - 'reference' => 'b31a76c1700679249fc222c46582ecbd1215f117', - 'dev_requirement' => false, - ), - 'kolab/kolab_files' => array( - 'pretty_version' => '3.5.2', - 'version' => '3.5.2.0', - 'type' => 'roundcube-plugin', - 'install_path' => __DIR__ . '/../../plugins/kolab_files', - 'aliases' => array(), - 'reference' => '0439d3783b59d6e52f23e86046881fd0ca8c0bd5', - 'dev_requirement' => false, - ), - 'kolab/kolab_folders' => array( - 'pretty_version' => '3.5.2', - 'version' => '3.5.2.0', - 'type' => 'roundcube-plugin', - 'install_path' => __DIR__ . '/../../plugins/kolab_folders', - 'aliases' => array(), - 'reference' => 'c70560fcfe40bf1582ea79debf3ae2aebbe94688', - 'dev_requirement' => false, - ), - 'kolab/kolab_notes' => array( - 'pretty_version' => '3.5.5', - 'version' => '3.5.5.0', - 'type' => 'roundcube-plugin', - 'install_path' => __DIR__ . '/../../plugins/kolab_notes', - 'aliases' => array(), - 'reference' => '07297b8ea8b3827d0ba46801760854b0db560576', - 'dev_requirement' => false, - ), - 'kolab/kolab_tags' => array( - 'pretty_version' => '3.5.2', - 'version' => '3.5.2.0', - 'type' => 'roundcube-plugin', - 'install_path' => __DIR__ . '/../../plugins/kolab_tags', - 'aliases' => array(), - 'reference' => '62ffa5279d9f351941be6b23b0d0478aeff91bfd', - 'dev_requirement' => false, - ), - 'kolab/libcalendaring' => array( - 'pretty_version' => '3.5.10', - 'version' => '3.5.10.0', - 'type' => 'roundcube-plugin', - 'install_path' => __DIR__ . '/../../plugins/libcalendaring', - 'aliases' => array(), - 'reference' => 'b9ab21ae1a5b134a06c66d55372712630171a590', - 'dev_requirement' => false, - ), - 'kolab/libkolab' => array( - 'pretty_version' => '3.5.10', - 'version' => '3.5.10.0', - 'type' => 'roundcube-plugin', - 'install_path' => __DIR__ . '/../../plugins/libkolab', - 'aliases' => array(), - 'reference' => 'a8abbba8039ee3bdde7be1b6758893aeff0287d8', - 'dev_requirement' => false, - ), - 'kolab/odfviewer' => array( - 'pretty_version' => '3.4.0', - 'version' => '3.4.0.0', - 'type' => 'roundcube-plugin', - 'install_path' => __DIR__ . '/../../plugins/odfviewer', - 'aliases' => array(), - 'reference' => '43f3c0cf314cb818f9bc96d6bd378793e22a4ed4', - 'dev_requirement' => false, - ), - 'kolab/pdfviewer' => array( - 'pretty_version' => '3.4.0', - 'version' => '3.4.0.0', - 'type' => 'roundcube-plugin', - 'install_path' => __DIR__ . '/../../plugins/pdfviewer', - 'aliases' => array(), - 'reference' => '3437085223a60d929fbf076c232008e4377407c1', - 'dev_requirement' => false, - ), - 'kolab/tasklist' => array( - 'pretty_version' => '3.5.10', - 'version' => '3.5.10.0', - 'type' => 'roundcube-plugin', - 'install_path' => __DIR__ . '/../../plugins/tasklist', - 'aliases' => array(), - 'reference' => '7ae02f72964925d19fb244754f9d3e9b20af677c', - 'dev_requirement' => false, - ), - 'kub-at/php-simple-html-dom-parser' => array( - 'pretty_version' => '1.9.1', - 'version' => '1.9.1.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../kub-at/php-simple-html-dom-parser', - 'aliases' => array(), - 'reference' => 'ff22f98bfd9235115c128059076f3eb740d66913', - 'dev_requirement' => false, - ), - 'masterminds/html5' => array( - 'pretty_version' => '2.5.0', - 'version' => '2.5.0.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../masterminds/html5', - 'aliases' => array(), - 'reference' => 'b5d892a4bd058d61f736935d32a9c248f11ccc93', - 'dev_requirement' => false, - ), - 'myclabs/deep-copy' => array( - 'pretty_version' => '1.10.2', - 'version' => '1.10.2.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../myclabs/deep-copy', - 'aliases' => array(), - 'reference' => '776f831124e9c62e1a2c601ecc52e776d8bb7220', - 'dev_requirement' => true, - 'replaced' => array( - 0 => '1.10.2', - ), - ), - 'pear/auth_sasl' => array( - 'pretty_version' => 'v1.1.0', - 'version' => '1.1.0.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../pear/auth_sasl', - 'aliases' => array(), - 'reference' => 'db1ead3dc0bf986d2bab0dbc04d114800cf91dee', - 'dev_requirement' => false, - ), - 'pear/console_commandline' => array( - 'pretty_version' => 'v1.2.4', - 'version' => '1.2.4.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../pear/console_commandline', - 'aliases' => array(), - 'reference' => 'cce06166765c5da31f3e8c1acf42512c64344cdb', - 'dev_requirement' => false, - ), - 'pear/console_getopt' => array( - 'pretty_version' => 'v1.4.3', - 'version' => '1.4.3.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../pear/console_getopt', - 'aliases' => array(), - 'reference' => 'a41f8d3e668987609178c7c4a9fe48fecac53fa0', - 'dev_requirement' => false, - ), - 'pear/crypt_gpg' => array( - 'pretty_version' => 'v1.6.6', - 'version' => '1.6.6.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../pear/crypt_gpg', - 'aliases' => array(), - 'reference' => '18eb7b7c0822377804adafb53dafe6d15848f245', - 'dev_requirement' => false, - ), - 'pear/http_request2' => array( - 'pretty_version' => 'v2.3.0', - 'version' => '2.3.0.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../pear/http_request2', - 'aliases' => array(), - 'reference' => '3599cf0fe455a4e281da464f6510bfc5c2ce54c4', - 'dev_requirement' => false, - ), - 'pear/mail_mime' => array( - 'pretty_version' => '1.10.11', - 'version' => '1.10.11.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../pear/mail_mime', - 'aliases' => array(), - 'reference' => 'd4fb9ce61201593d0f8c6db629c45e29c3409c14', - 'dev_requirement' => false, - ), - 'pear/net_idna2' => array( - 'pretty_version' => 'v0.2.0', - 'version' => '0.2.0.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../pear/net_idna2', - 'aliases' => array(), - 'reference' => '51734eaf8be2df58e8aad5835b9966459b2fb37c', - 'dev_requirement' => false, - ), - 'pear/net_sieve' => array( - 'pretty_version' => '1.4.5', - 'version' => '1.4.5.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../pear/net_sieve', - 'aliases' => array(), - 'reference' => '94763e0fc6f39a9ebcd01e5e7a8250292804a50e', - 'dev_requirement' => false, - ), - 'pear/net_smtp' => array( - 'pretty_version' => '1.8.1', - 'version' => '1.8.1.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../pear/net_smtp', - 'aliases' => array(), - 'reference' => '8f93b34878ef16844c754d1a1211c1e3677fa07f', - 'dev_requirement' => false, - ), - 'pear/net_socket' => array( - 'pretty_version' => 'v1.2.2', - 'version' => '1.2.2.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../pear/net_socket', - 'aliases' => array(), - 'reference' => 'bbe6a12bb4f7059dba161f6ddd43f369c0ec8d09', - 'dev_requirement' => false, - ), - 'pear/net_url2' => array( - 'pretty_version' => 'v2.2.2', - 'version' => '2.2.2.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../pear/net_url2', - 'aliases' => array(), - 'reference' => '07fd055820dbf466ee3990abe96d0e40a8791f9d', - 'dev_requirement' => false, - ), - 'pear/pear-core-minimal' => array( - 'pretty_version' => 'v1.10.11', - 'version' => '1.10.11.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../pear/pear-core-minimal', - 'aliases' => array(), - 'reference' => '68d0d32ada737153b7e93b8d3c710ebe70ac867d', - 'dev_requirement' => false, - ), - 'pear/pear_exception' => array( - 'pretty_version' => 'v1.0.2', - 'version' => '1.0.2.0', - 'type' => 'class', - 'install_path' => __DIR__ . '/../pear/pear_exception', - 'aliases' => array(), - 'reference' => 'b14fbe2ddb0b9f94f5b24cf08783d599f776fff0', - 'dev_requirement' => false, - ), - 'phpdocumentor/reflection-common' => array( - 'pretty_version' => '2.2.0', - 'version' => '2.2.0.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../phpdocumentor/reflection-common', - 'aliases' => array(), - 'reference' => '1d01c49d4ed62f25aa84a747ad35d5a16924662b', - 'dev_requirement' => true, - ), - 'phpdocumentor/reflection-docblock' => array( - 'pretty_version' => '5.3.0', - 'version' => '5.3.0.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../phpdocumentor/reflection-docblock', - 'aliases' => array(), - 'reference' => '622548b623e81ca6d78b721c5e029f4ce664f170', - 'dev_requirement' => true, - ), - 'phpdocumentor/type-resolver' => array( - 'pretty_version' => '1.5.1', - 'version' => '1.5.1.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../phpdocumentor/type-resolver', - 'aliases' => array(), - 'reference' => 'a12f7e301eb7258bb68acd89d4aefa05c2906cae', - 'dev_requirement' => true, - ), - 'phpspec/prophecy' => array( - 'pretty_version' => 'v1.10.3', - 'version' => '1.10.3.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../phpspec/prophecy', - 'aliases' => array(), - 'reference' => '451c3cd1418cf640de218914901e51b064abb093', - 'dev_requirement' => true, - ), - 'phpunit/php-code-coverage' => array( - 'pretty_version' => '4.0.8', - 'version' => '4.0.8.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../phpunit/php-code-coverage', - 'aliases' => array(), - 'reference' => 'ef7b2f56815df854e66ceaee8ebe9393ae36a40d', - 'dev_requirement' => true, - ), - 'phpunit/php-file-iterator' => array( - 'pretty_version' => '1.4.5', - 'version' => '1.4.5.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../phpunit/php-file-iterator', - 'aliases' => array(), - 'reference' => '730b01bc3e867237eaac355e06a36b85dd93a8b4', - 'dev_requirement' => true, - ), - 'phpunit/php-text-template' => array( - 'pretty_version' => '1.2.1', - 'version' => '1.2.1.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../phpunit/php-text-template', - 'aliases' => array(), - 'reference' => '31f8b717e51d9a2afca6c9f046f5d69fc27c8686', - 'dev_requirement' => true, - ), - 'phpunit/php-timer' => array( - 'pretty_version' => '1.0.9', - 'version' => '1.0.9.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../phpunit/php-timer', - 'aliases' => array(), - 'reference' => '3dcf38ca72b158baf0bc245e9184d3fdffa9c46f', - 'dev_requirement' => true, - ), - 'phpunit/php-token-stream' => array( - 'pretty_version' => '2.0.2', - 'version' => '2.0.2.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../phpunit/php-token-stream', - 'aliases' => array(), - 'reference' => '791198a2c6254db10131eecfe8c06670700904db', - 'dev_requirement' => true, - ), - 'phpunit/phpunit' => array( - 'pretty_version' => '5.7.27', - 'version' => '5.7.27.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../phpunit/phpunit', - 'aliases' => array(), - 'reference' => 'b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c', - 'dev_requirement' => true, - ), - 'phpunit/phpunit-mock-objects' => array( - 'pretty_version' => '3.4.4', - 'version' => '3.4.4.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../phpunit/phpunit-mock-objects', - 'aliases' => array(), - 'reference' => 'a23b761686d50a560cc56233b9ecf49597cc9118', - 'dev_requirement' => true, - ), - 'roundcube/plugin-installer' => array( - 'pretty_version' => '0.2.0', - 'version' => '0.2.0.0', - 'type' => 'composer-installer', - 'install_path' => __DIR__ . '/../roundcube/plugin-installer', - 'aliases' => array(), - 'reference' => '10148d050ee2db019d83113a479fb7716fd04d48', - 'dev_requirement' => false, - ), - 'roundcube/roundcubemail' => array( - 'pretty_version' => 'dev-master', - 'version' => 'dev-master', - 'type' => 'library', - 'install_path' => __DIR__ . '/../../', - 'aliases' => array(), - 'reference' => '4e1358b4dc1a8116357657ae5c8738e855aea85a', - 'dev_requirement' => false, - ), - 'rsky/pear-core-min' => array( - 'dev_requirement' => false, - 'replaced' => array( - 0 => 'v1.10.11', - ), - ), - 'sabre/dav' => array( - 'pretty_version' => '2.1.11', - 'version' => '2.1.11.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../sabre/dav', - 'aliases' => array(), - 'reference' => 'fa10928802aea9b3136519640aa3c3c59e9e1084', - 'dev_requirement' => false, - ), - 'sabre/event' => array( - 'pretty_version' => '2.0.2', - 'version' => '2.0.2.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../sabre/event', - 'aliases' => array(), - 'reference' => '337b6f5e10ea6e0b21e22c7e5788dd3883ae73ff', - 'dev_requirement' => false, - ), - 'sabre/http' => array( - 'pretty_version' => '3.0.5', - 'version' => '3.0.5.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../sabre/http', - 'aliases' => array(), - 'reference' => '6b06c03376219b3d608e1f878514ec105ed1b577', - 'dev_requirement' => false, - ), - 'sabre/vobject' => array( - 'pretty_version' => '3.5.3', - 'version' => '3.5.3.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../sabre/vobject', - 'aliases' => array(), - 'reference' => '129d80533a9ec0d9cacfb50b51180c34edb6874c', - 'dev_requirement' => false, - ), - 'sebastian/code-unit-reverse-lookup' => array( - 'pretty_version' => '1.0.2', - 'version' => '1.0.2.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../sebastian/code-unit-reverse-lookup', - 'aliases' => array(), - 'reference' => '1de8cd5c010cb153fcd68b8d0f64606f523f7619', - 'dev_requirement' => true, - ), - 'sebastian/comparator' => array( - 'pretty_version' => '1.2.4', - 'version' => '1.2.4.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../sebastian/comparator', - 'aliases' => array(), - 'reference' => '2b7424b55f5047b47ac6e5ccb20b2aea4011d9be', - 'dev_requirement' => true, - ), - 'sebastian/diff' => array( - 'pretty_version' => '1.4.3', - 'version' => '1.4.3.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../sebastian/diff', - 'aliases' => array(), - 'reference' => '7f066a26a962dbe58ddea9f72a4e82874a3975a4', - 'dev_requirement' => true, - ), - 'sebastian/environment' => array( - 'pretty_version' => '2.0.0', - 'version' => '2.0.0.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../sebastian/environment', - 'aliases' => array(), - 'reference' => '5795ffe5dc5b02460c3e34222fee8cbe245d8fac', - 'dev_requirement' => true, - ), - 'sebastian/exporter' => array( - 'pretty_version' => '2.0.0', - 'version' => '2.0.0.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../sebastian/exporter', - 'aliases' => array(), - 'reference' => 'ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4', - 'dev_requirement' => true, - ), - 'sebastian/global-state' => array( - 'pretty_version' => '1.1.1', - 'version' => '1.1.1.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../sebastian/global-state', - 'aliases' => array(), - 'reference' => 'bc37d50fea7d017d3d340f230811c9f1d7280af4', - 'dev_requirement' => true, - ), - 'sebastian/object-enumerator' => array( - 'pretty_version' => '2.0.1', - 'version' => '2.0.1.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../sebastian/object-enumerator', - 'aliases' => array(), - 'reference' => '1311872ac850040a79c3c058bea3e22d0f09cbb7', - 'dev_requirement' => true, - ), - 'sebastian/recursion-context' => array( - 'pretty_version' => '2.0.0', - 'version' => '2.0.0.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../sebastian/recursion-context', - 'aliases' => array(), - 'reference' => '2c3ba150cbec723aa057506e73a8d33bdb286c9a', - 'dev_requirement' => true, - ), - 'sebastian/resource-operations' => array( - 'pretty_version' => '1.0.0', - 'version' => '1.0.0.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../sebastian/resource-operations', - 'aliases' => array(), - 'reference' => 'ce990bb21759f94aeafd30209e8cfcdfa8bc3f52', - 'dev_requirement' => true, - ), - 'sebastian/version' => array( - 'pretty_version' => '2.0.1', - 'version' => '2.0.1.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../sebastian/version', - 'aliases' => array(), - 'reference' => '99732be0ddb3361e16ad77b68ba41efc8e979019', - 'dev_requirement' => true, - ), - 'smarty/smarty' => array( - 'pretty_version' => 'v3.1.40', - 'version' => '3.1.40.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../smarty/smarty', - 'aliases' => array(), - 'reference' => '9d4f8309ed49702e0d7152f9983c3a9c4b98eb9d', - 'dev_requirement' => false, - ), - 'symfony/polyfill-ctype' => array( - 'pretty_version' => 'v1.23.0', - 'version' => '1.23.0.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', - 'aliases' => array(), - 'reference' => '46cd95797e9df938fdd2b03693b5fca5e64b01ce', - 'dev_requirement' => true, - ), - 'symfony/yaml' => array( - 'pretty_version' => 'v4.4.34', - 'version' => '4.4.34.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../symfony/yaml', - 'aliases' => array(), - 'reference' => '2c309e258adeb9970229042be39b360d34986fad', - 'dev_requirement' => true, - ), - 'webmozart/assert' => array( - 'pretty_version' => '1.10.0', - 'version' => '1.10.0.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../webmozart/assert', - 'aliases' => array(), - 'reference' => '6964c76c7804814a842473e0c8fd15bab0f18e25', - 'dev_requirement' => true, - ), - 'zf1/zend-cache' => array( - 'pretty_version' => '1.12.20', - 'version' => '1.12.20.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../zf1/zend-cache', - 'aliases' => array(), - 'reference' => 'c3a6fc20f5d5c5ab7adc16f29f33eb5b2e00d86e', - 'dev_requirement' => false, - ), - 'zf1/zend-config' => array( - 'pretty_version' => '1.12.20', - 'version' => '1.12.20.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../zf1/zend-config', - 'aliases' => array(), - 'reference' => '2a1e588782d74e22d73682dc71fa4a7e193d52c4', - 'dev_requirement' => false, - ), - 'zf1/zend-controller' => array( - 'pretty_version' => '1.12.20', - 'version' => '1.12.20.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../zf1/zend-controller', - 'aliases' => array(), - 'reference' => 'dee228b392a053106efcc1310c48537ce653046a', - 'dev_requirement' => false, - ), - 'zf1/zend-exception' => array( - 'pretty_version' => '1.12.20', - 'version' => '1.12.20.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../zf1/zend-exception', - 'aliases' => array(), - 'reference' => 'ca30959d3e2f522f481a3d1459386acf1aa4ca74', - 'dev_requirement' => false, - ), - 'zf1/zend-loader' => array( - 'pretty_version' => '1.12.20', - 'version' => '1.12.20.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../zf1/zend-loader', - 'aliases' => array(), - 'reference' => '894dcfb8084488575d46e496e399f64aacd5761c', - 'dev_requirement' => false, - ), - 'zf1/zend-locale' => array( - 'pretty_version' => '1.12.20', - 'version' => '1.12.20.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../zf1/zend-locale', - 'aliases' => array(), - 'reference' => '336df96aebb0270fb682e6ee8bf0cc0781cc3edb', - 'dev_requirement' => false, - ), - 'zf1/zend-log' => array( - 'pretty_version' => '1.12.20', - 'version' => '1.12.20.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../zf1/zend-log', - 'aliases' => array(), - 'reference' => '1c67db7a0eb288c100b23105dad21dbc09883300', - 'dev_requirement' => false, - ), - 'zf1/zend-registry' => array( - 'pretty_version' => '1.12.20', - 'version' => '1.12.20.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../zf1/zend-registry', - 'aliases' => array(), - 'reference' => '1737419285b800728c27063318509fb2d00057ba', - 'dev_requirement' => false, - ), - 'zf1/zend-uri' => array( - 'pretty_version' => '1.12.20', - 'version' => '1.12.20.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../zf1/zend-uri', - 'aliases' => array(), - 'reference' => '73964522a8a5041798cc8edad1e81fa0879737f2', - 'dev_requirement' => false, - ), - 'zf1/zend-validate' => array( - 'pretty_version' => '1.12.20', - 'version' => '1.12.20.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../zf1/zend-validate', - 'aliases' => array(), - 'reference' => '5ceb707212abaaf92ccdd91270c6d37e07bf551b', - 'dev_requirement' => false, - ), - 'zf1/zend-view' => array( - 'pretty_version' => '1.12.20', - 'version' => '1.12.20.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../zf1/zend-view', - 'aliases' => array(), - 'reference' => '22797ef472cd64806c1ebafa83b59e92f7532e25', - 'dev_requirement' => false, - ), - 'zf1/zend-xml' => array( - 'pretty_version' => '1.12.20', - 'version' => '1.12.20.0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../zf1/zend-xml', - 'aliases' => array(), - 'reference' => 'd4f99144a0cf0c5e383f3fb765cdd7dfde7caab4', - 'dev_requirement' => false, - ), +<?php return array ( + 'root' => + array ( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'aliases' => + array ( ), + 'reference' => '784eb80e67a3f47290e42cef12da8696cba60272', + 'name' => 'roundcube/roundcubemail', + ), + 'versions' => + array ( + 'caxy/php-htmldiff' => + array ( + 'pretty_version' => 'v0.1.9', + 'version' => '0.1.9.0', + 'aliases' => + array ( + ), + 'reference' => '4bad5c6a4ecc76954d37764e6a29273b6b7bf1f8', + ), + 'doctrine/instantiator' => + array ( + 'pretty_version' => '1.4.0', + 'version' => '1.4.0.0', + 'aliases' => + array ( + ), + 'reference' => 'd56bf6102915de5702778fe20f2de3b2fe570b5b', + ), + 'endroid/qr-code' => + array ( + 'pretty_version' => '1.6.6', + 'version' => '1.6.6.0', + 'aliases' => + array ( + ), + 'reference' => 'cef5d5b7b904d7bb0708eb744c35316364b65fa0', + ), + 'ezyang/htmlpurifier' => + array ( + 'pretty_version' => 'v4.14.0', + 'version' => '4.14.0.0', + 'aliases' => + array ( + ), + 'reference' => '12ab42bd6e742c70c0a52f7b82477fcd44e64b75', + ), + 'johndoh/contextmenu' => + array ( + 'pretty_version' => '3.2.1', + 'version' => '3.2.1.0', + 'aliases' => + array ( + ), + 'reference' => '602a3812922fb8f71814eb3b8d91e9b7859aab7e', + ), + 'kolab/calendar' => + array ( + 'pretty_version' => '3.5.10', + 'version' => '3.5.10.0', + 'aliases' => + array ( + ), + 'reference' => '45103d5bdee63f976c918f8cfcf20b400310bcb0', + ), + 'kolab/kolab_activesync' => + array ( + 'pretty_version' => '3.5.6', + 'version' => '3.5.6.0', + 'aliases' => + array ( + ), + 'reference' => '7e8c46290074fe6c1ab72bc9f6b90aa271ee16ef', + ), + 'kolab/kolab_addressbook' => + array ( + 'pretty_version' => '3.5.10', + 'version' => '3.5.10.0', + 'aliases' => + array ( + ), + 'reference' => '29195279f672640ffe38f70ddabe87b56172e889', + ), + 'kolab/kolab_auth' => + array ( + 'pretty_version' => '3.5.8', + 'version' => '3.5.8.0', + 'aliases' => + array ( + ), + 'reference' => 'ab0ed459f74a03f8eab6822652e084f0430a4f07', + ), + 'kolab/kolab_chat' => + array ( + 'pretty_version' => '3.5.4', + 'version' => '3.5.4.0', + 'aliases' => + array ( + ), + 'reference' => 'b2f85fcb8324b9961dd02fb3e3acd92be33b558e', + ), + 'kolab/kolab_config' => + array ( + 'pretty_version' => '3.4.0', + 'version' => '3.4.0.0', + 'aliases' => + array ( + ), + 'reference' => 'b31a76c1700679249fc222c46582ecbd1215f117', + ), + 'kolab/kolab_files' => + array ( + 'pretty_version' => '3.5.2', + 'version' => '3.5.2.0', + 'aliases' => + array ( + ), + 'reference' => '0439d3783b59d6e52f23e86046881fd0ca8c0bd5', + ), + 'kolab/kolab_folders' => + array ( + 'pretty_version' => '3.5.2', + 'version' => '3.5.2.0', + 'aliases' => + array ( + ), + 'reference' => 'c70560fcfe40bf1582ea79debf3ae2aebbe94688', + ), + 'kolab/kolab_notes' => + array ( + 'pretty_version' => '3.5.5', + 'version' => '3.5.5.0', + 'aliases' => + array ( + ), + 'reference' => '07297b8ea8b3827d0ba46801760854b0db560576', + ), + 'kolab/kolab_tags' => + array ( + 'pretty_version' => '3.5.2', + 'version' => '3.5.2.0', + 'aliases' => + array ( + ), + 'reference' => '62ffa5279d9f351941be6b23b0d0478aeff91bfd', + ), + 'kolab/libcalendaring' => + array ( + 'pretty_version' => '3.5.10', + 'version' => '3.5.10.0', + 'aliases' => + array ( + ), + 'reference' => 'b9ab21ae1a5b134a06c66d55372712630171a590', + ), + 'kolab/libkolab' => + array ( + 'pretty_version' => '3.5.10', + 'version' => '3.5.10.0', + 'aliases' => + array ( + ), + 'reference' => 'a8abbba8039ee3bdde7be1b6758893aeff0287d8', + ), + 'kolab/net_ldap3' => + array ( + 'pretty_version' => 'v1.1.3', + 'version' => '1.1.3.0', + 'aliases' => + array ( + ), + 'reference' => 'e1835e36fa5d3434f9804670fc3cdd16992ec66a', + ), + 'kolab/odfviewer' => + array ( + 'pretty_version' => '3.4.0', + 'version' => '3.4.0.0', + 'aliases' => + array ( + ), + 'reference' => '43f3c0cf314cb818f9bc96d6bd378793e22a4ed4', + ), + 'kolab/pdfviewer' => + array ( + 'pretty_version' => '3.4.0', + 'version' => '3.4.0.0', + 'aliases' => + array ( + ), + 'reference' => '3437085223a60d929fbf076c232008e4377407c1', + ), + 'kolab/tasklist' => + array ( + 'pretty_version' => '3.5.10', + 'version' => '3.5.10.0', + 'aliases' => + array ( + ), + 'reference' => '7ae02f72964925d19fb244754f9d3e9b20af677c', + ), + 'kub-at/php-simple-html-dom-parser' => + array ( + 'pretty_version' => '1.9.1', + 'version' => '1.9.1.0', + 'aliases' => + array ( + ), + 'reference' => 'ff22f98bfd9235115c128059076f3eb740d66913', + ), + 'masterminds/html5' => + array ( + 'pretty_version' => '2.5.0', + 'version' => '2.5.0.0', + 'aliases' => + array ( + ), + 'reference' => 'b5d892a4bd058d61f736935d32a9c248f11ccc93', + ), + 'myclabs/deep-copy' => + array ( + 'pretty_version' => '1.10.2', + 'version' => '1.10.2.0', + 'aliases' => + array ( + ), + 'reference' => '776f831124e9c62e1a2c601ecc52e776d8bb7220', + 'replaced' => + array ( + 0 => '1.10.2', + ), + ), + 'pear/auth_sasl' => + array ( + 'pretty_version' => 'v1.1.0', + 'version' => '1.1.0.0', + 'aliases' => + array ( + ), + 'reference' => 'db1ead3dc0bf986d2bab0dbc04d114800cf91dee', + ), + 'pear/console_commandline' => + array ( + 'pretty_version' => 'v1.2.4', + 'version' => '1.2.4.0', + 'aliases' => + array ( + ), + 'reference' => 'cce06166765c5da31f3e8c1acf42512c64344cdb', + ), + 'pear/console_getopt' => + array ( + 'pretty_version' => 'v1.4.3', + 'version' => '1.4.3.0', + 'aliases' => + array ( + ), + 'reference' => 'a41f8d3e668987609178c7c4a9fe48fecac53fa0', + ), + 'pear/crypt_gpg' => + array ( + 'pretty_version' => 'v1.6.6', + 'version' => '1.6.6.0', + 'aliases' => + array ( + ), + 'reference' => '18eb7b7c0822377804adafb53dafe6d15848f245', + ), + 'pear/http_request2' => + array ( + 'pretty_version' => 'v2.3.0', + 'version' => '2.3.0.0', + 'aliases' => + array ( + ), + 'reference' => '3599cf0fe455a4e281da464f6510bfc5c2ce54c4', + ), + 'pear/mail_mime' => + array ( + 'pretty_version' => '1.10.11', + 'version' => '1.10.11.0', + 'aliases' => + array ( + ), + 'reference' => 'd4fb9ce61201593d0f8c6db629c45e29c3409c14', + ), + 'pear/net_idna2' => + array ( + 'pretty_version' => 'v0.2.0', + 'version' => '0.2.0.0', + 'aliases' => + array ( + ), + 'reference' => '51734eaf8be2df58e8aad5835b9966459b2fb37c', + ), + 'pear/net_ldap2' => + array ( + 'pretty_version' => 'v2.2.0', + 'version' => '2.2.0.0', + 'aliases' => + array ( + ), + 'reference' => '38f1b22a96dfbd7ec53852f0e1e7ec1a9a5eb0e8', + ), + 'pear/net_sieve' => + array ( + 'pretty_version' => '1.4.5', + 'version' => '1.4.5.0', + 'aliases' => + array ( + ), + 'reference' => '94763e0fc6f39a9ebcd01e5e7a8250292804a50e', + ), + 'pear/net_smtp' => + array ( + 'pretty_version' => '1.8.1', + 'version' => '1.8.1.0', + 'aliases' => + array ( + ), + 'reference' => '8f93b34878ef16844c754d1a1211c1e3677fa07f', + ), + 'pear/net_socket' => + array ( + 'pretty_version' => 'v1.2.2', + 'version' => '1.2.2.0', + 'aliases' => + array ( + ), + 'reference' => 'bbe6a12bb4f7059dba161f6ddd43f369c0ec8d09', + ), + 'pear/net_url2' => + array ( + 'pretty_version' => 'v2.2.2', + 'version' => '2.2.2.0', + 'aliases' => + array ( + ), + 'reference' => '07fd055820dbf466ee3990abe96d0e40a8791f9d', + ), + 'pear/pear-core-minimal' => + array ( + 'pretty_version' => 'v1.10.11', + 'version' => '1.10.11.0', + 'aliases' => + array ( + ), + 'reference' => '68d0d32ada737153b7e93b8d3c710ebe70ac867d', + ), + 'pear/pear_exception' => + array ( + 'pretty_version' => 'v1.0.2', + 'version' => '1.0.2.0', + 'aliases' => + array ( + ), + 'reference' => 'b14fbe2ddb0b9f94f5b24cf08783d599f776fff0', + ), + 'phpdocumentor/reflection-common' => + array ( + 'pretty_version' => '2.2.0', + 'version' => '2.2.0.0', + 'aliases' => + array ( + ), + 'reference' => '1d01c49d4ed62f25aa84a747ad35d5a16924662b', + ), + 'phpdocumentor/reflection-docblock' => + array ( + 'pretty_version' => '5.3.0', + 'version' => '5.3.0.0', + 'aliases' => + array ( + ), + 'reference' => '622548b623e81ca6d78b721c5e029f4ce664f170', + ), + 'phpdocumentor/type-resolver' => + array ( + 'pretty_version' => '1.6.0', + 'version' => '1.6.0.0', + 'aliases' => + array ( + ), + 'reference' => '93ebd0014cab80c4ea9f5e297ea48672f1b87706', + ), + 'phpspec/prophecy' => + array ( + 'pretty_version' => 'v1.10.3', + 'version' => '1.10.3.0', + 'aliases' => + array ( + ), + 'reference' => '451c3cd1418cf640de218914901e51b064abb093', + ), + 'phpunit/php-code-coverage' => + array ( + 'pretty_version' => '4.0.8', + 'version' => '4.0.8.0', + 'aliases' => + array ( + ), + 'reference' => 'ef7b2f56815df854e66ceaee8ebe9393ae36a40d', + ), + 'phpunit/php-file-iterator' => + array ( + 'pretty_version' => '1.4.5', + 'version' => '1.4.5.0', + 'aliases' => + array ( + ), + 'reference' => '730b01bc3e867237eaac355e06a36b85dd93a8b4', + ), + 'phpunit/php-text-template' => + array ( + 'pretty_version' => '1.2.1', + 'version' => '1.2.1.0', + 'aliases' => + array ( + ), + 'reference' => '31f8b717e51d9a2afca6c9f046f5d69fc27c8686', + ), + 'phpunit/php-timer' => + array ( + 'pretty_version' => '1.0.9', + 'version' => '1.0.9.0', + 'aliases' => + array ( + ), + 'reference' => '3dcf38ca72b158baf0bc245e9184d3fdffa9c46f', + ), + 'phpunit/php-token-stream' => + array ( + 'pretty_version' => '2.0.2', + 'version' => '2.0.2.0', + 'aliases' => + array ( + ), + 'reference' => '791198a2c6254db10131eecfe8c06670700904db', + ), + 'phpunit/phpunit' => + array ( + 'pretty_version' => '5.7.27', + 'version' => '5.7.27.0', + 'aliases' => + array ( + ), + 'reference' => 'b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c', + ), + 'phpunit/phpunit-mock-objects' => + array ( + 'pretty_version' => '3.4.4', + 'version' => '3.4.4.0', + 'aliases' => + array ( + ), + 'reference' => 'a23b761686d50a560cc56233b9ecf49597cc9118', + ), + 'roundcube/plugin-installer' => + array ( + 'pretty_version' => '0.2.0', + 'version' => '0.2.0.0', + 'aliases' => + array ( + ), + 'reference' => '10148d050ee2db019d83113a479fb7716fd04d48', + ), + 'roundcube/roundcubemail' => + array ( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'aliases' => + array ( + ), + 'reference' => '784eb80e67a3f47290e42cef12da8696cba60272', + ), + 'rsky/pear-core-min' => + array ( + 'replaced' => + array ( + 0 => 'v1.10.11', + ), + ), + 'sabre/dav' => + array ( + 'pretty_version' => '2.1.11', + 'version' => '2.1.11.0', + 'aliases' => + array ( + ), + 'reference' => 'fa10928802aea9b3136519640aa3c3c59e9e1084', + ), + 'sabre/event' => + array ( + 'pretty_version' => '2.0.2', + 'version' => '2.0.2.0', + 'aliases' => + array ( + ), + 'reference' => '337b6f5e10ea6e0b21e22c7e5788dd3883ae73ff', + ), + 'sabre/http' => + array ( + 'pretty_version' => '3.0.5', + 'version' => '3.0.5.0', + 'aliases' => + array ( + ), + 'reference' => '6b06c03376219b3d608e1f878514ec105ed1b577', + ), + 'sabre/vobject' => + array ( + 'pretty_version' => '3.5.3', + 'version' => '3.5.3.0', + 'aliases' => + array ( + ), + 'reference' => '129d80533a9ec0d9cacfb50b51180c34edb6874c', + ), + 'sebastian/code-unit-reverse-lookup' => + array ( + 'pretty_version' => '1.0.2', + 'version' => '1.0.2.0', + 'aliases' => + array ( + ), + 'reference' => '1de8cd5c010cb153fcd68b8d0f64606f523f7619', + ), + 'sebastian/comparator' => + array ( + 'pretty_version' => '1.2.4', + 'version' => '1.2.4.0', + 'aliases' => + array ( + ), + 'reference' => '2b7424b55f5047b47ac6e5ccb20b2aea4011d9be', + ), + 'sebastian/diff' => + array ( + 'pretty_version' => '1.4.3', + 'version' => '1.4.3.0', + 'aliases' => + array ( + ), + 'reference' => '7f066a26a962dbe58ddea9f72a4e82874a3975a4', + ), + 'sebastian/environment' => + array ( + 'pretty_version' => '2.0.0', + 'version' => '2.0.0.0', + 'aliases' => + array ( + ), + 'reference' => '5795ffe5dc5b02460c3e34222fee8cbe245d8fac', + ), + 'sebastian/exporter' => + array ( + 'pretty_version' => '2.0.0', + 'version' => '2.0.0.0', + 'aliases' => + array ( + ), + 'reference' => 'ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4', + ), + 'sebastian/global-state' => + array ( + 'pretty_version' => '1.1.1', + 'version' => '1.1.1.0', + 'aliases' => + array ( + ), + 'reference' => 'bc37d50fea7d017d3d340f230811c9f1d7280af4', + ), + 'sebastian/object-enumerator' => + array ( + 'pretty_version' => '2.0.1', + 'version' => '2.0.1.0', + 'aliases' => + array ( + ), + 'reference' => '1311872ac850040a79c3c058bea3e22d0f09cbb7', + ), + 'sebastian/recursion-context' => + array ( + 'pretty_version' => '2.0.0', + 'version' => '2.0.0.0', + 'aliases' => + array ( + ), + 'reference' => '2c3ba150cbec723aa057506e73a8d33bdb286c9a', + ), + 'sebastian/resource-operations' => + array ( + 'pretty_version' => '1.0.0', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => 'ce990bb21759f94aeafd30209e8cfcdfa8bc3f52', + ), + 'sebastian/version' => + array ( + 'pretty_version' => '2.0.1', + 'version' => '2.0.1.0', + 'aliases' => + array ( + ), + 'reference' => '99732be0ddb3361e16ad77b68ba41efc8e979019', + ), + 'smarty/smarty' => + array ( + 'pretty_version' => 'v3.1.43', + 'version' => '3.1.43.0', + 'aliases' => + array ( + ), + 'reference' => '273f7e00fec034f6d61112552e9caf08d19565b7', + ), + 'symfony/polyfill-ctype' => + array ( + 'pretty_version' => 'v1.24.0', + 'version' => '1.24.0.0', + 'aliases' => + array ( + ), + 'reference' => '30885182c981ab175d4d034db0f6f469898070ab', + ), + 'symfony/yaml' => + array ( + 'pretty_version' => 'v4.4.36', + 'version' => '4.4.36.0', + 'aliases' => + array ( + ), + 'reference' => 'a19f7c44ba665fa9d9d415cc4493361381b93f9b', + ), + 'webmozart/assert' => + array ( + 'pretty_version' => '1.10.0', + 'version' => '1.10.0.0', + 'aliases' => + array ( + ), + 'reference' => '6964c76c7804814a842473e0c8fd15bab0f18e25', + ), + 'zf1/zend-cache' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => 'c3a6fc20f5d5c5ab7adc16f29f33eb5b2e00d86e', + ), + 'zf1/zend-config' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => '2a1e588782d74e22d73682dc71fa4a7e193d52c4', + ), + 'zf1/zend-controller' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => 'dee228b392a053106efcc1310c48537ce653046a', + ), + 'zf1/zend-exception' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => 'ca30959d3e2f522f481a3d1459386acf1aa4ca74', + ), + 'zf1/zend-json' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => 'dbf5d4b46bdf6299bf1f7c6b1ef7311e4299602f', + ), + 'zf1/zend-loader' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => '894dcfb8084488575d46e496e399f64aacd5761c', + ), + 'zf1/zend-locale' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => '336df96aebb0270fb682e6ee8bf0cc0781cc3edb', + ), + 'zf1/zend-log' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => '1c67db7a0eb288c100b23105dad21dbc09883300', + ), + 'zf1/zend-registry' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => '1737419285b800728c27063318509fb2d00057ba', + ), + 'zf1/zend-server' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => 'ce8242896b3d63a51f3984ef1d6ed9cc9c67e547', + ), + 'zf1/zend-uri' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => '73964522a8a5041798cc8edad1e81fa0879737f2', + ), + 'zf1/zend-validate' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => '5ceb707212abaaf92ccdd91270c6d37e07bf551b', + ), + 'zf1/zend-view' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => '22797ef472cd64806c1ebafa83b59e92f7532e25', + ), + 'zf1/zend-xml' => + array ( + 'pretty_version' => '1.12.20', + 'version' => '1.12.20.0', + 'aliases' => + array ( + ), + 'reference' => 'd4f99144a0cf0c5e383f3fb765cdd7dfde7caab4', + ), + ), );
View file
roundcubemail-1.4.13.tar.gz/vendor/kolab/net_ldap3
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/kolab/net_ldap3/.arcconfig
Added
@@ -0,0 +1,3 @@ +{ + "phabricator.uri": "https://git.kolab.org" +}
View file
roundcubemail-1.4.13.tar.gz/vendor/kolab/net_ldap3/LICENSE
Added
@@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>.
View file
roundcubemail-1.4.13.tar.gz/vendor/kolab/net_ldap3/composer.json
Added
@@ -0,0 +1,32 @@ +{ + "name": "kolab/net_ldap3", + "description": "A successor of the PEAR:Net_LDAP2 module providing advanced functionality for accessing LDAP directories", + "type": "library", + "keywords": ["pear", "ldap", "vlv"], + "homepage": "http://git.kolab.org/pear/Net_LDAP3/", + "license": "GPL-3.0+", + "authors": [ + { + "name": "Jeroen van Meeuwen", + "email": "vanmeeuwen@kolabsys.com", + "role": "Lead" + }, + { + "name": "Aleksander Machniak", + "email": "machniak@kolabsys.com", + "role": "Developer" + }, + { + "name": "Thomas Bruederli", + "email": "roundcube@gmail.com", + "role": "Developer" + } + ], + "require": { + "php": ">=5.3.3", + "pear/net_ldap2": ">=2.0.12" + }, + "autoload": { + "classmap": ["lib/"] + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/kolab/net_ldap3/lib
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/kolab/net_ldap3/lib/Net
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/kolab/net_ldap3/lib/Net/LDAP3
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/kolab/net_ldap3/lib/Net/LDAP3.php
Added
@@ -0,0 +1,3209 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | Net/LDAP3.php | + | | + | Based on code created by the Roundcube Webmail team. | + | | + | Copyright (C) 2006-2014, The Roundcube Dev Team | + | Copyright (C) 2012-2014, Kolab Systems AG | + | | + | This program is free software: you can redistribute it and/or modify | + | it under the terms of the GNU General Public License as published by | + | the Free Software Foundation, either version 3 of the License, or | + | (at your option) any later version. | + | | + | This program 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 General Public License for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with this program. If not, see <http://www.gnu.org/licenses/>. | + | | + | PURPOSE: | + | Provide advanced functionality for accessing LDAP directories | + | | + +-----------------------------------------------------------------------+ + | Authors: Thomas Bruederli <roundcube@gmail.com> | + | Aleksander Machniak <machniak@kolabsys.com> | + | Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> | + +-----------------------------------------------------------------------+ +*/ + +require_once __DIR__ . '/LDAP3/Result.php'; + +/** + * Model class to access a LDAP directories + * + * @package Net_LDAP3 + */ +class Net_LDAP3 +{ + const CONTROL_EFFECTIVE_RIGHTS = '1.3.6.1.4.1.42.2.27.9.5.2'; + const CONTROL_SORT_REQUEST = '1.2.840.113556.1.4.473'; + const CONTROL_VLV_REQUEST = '2.16.840.1.113730.3.4.9'; + const CONTROL_VLV_RESPONSE = '2.16.840.1.113730.3.4.10'; + + public $conn; + public $vlv_active = false; + + private $attribute_level_rights_map = array( + "r" => "read", + "s" => "search", + "w" => "write", + "o" => "delete", + "c" => "compare", + "W" => "write", + "O" => "delete" + ); + + private $entry_level_rights_map = array( + "a" => "add", + "d" => "delete", + "n" => "modrdn", + "v" => "read" + ); + + /* + * Manipulate configuration through the config_set and config_get methods. + * Available options: + * 'debug' => false, + * 'hosts' => array(), + * 'port' => 389, + * 'use_tls' => false, + * 'ldap_version' => 3, // using LDAPv3 + * 'auth_method' => '', // SASL authentication method (for proxy auth), e.g. DIGEST-MD5 + * 'gssapi_cn' => null // Kerberos cache name (KRB5CCNAME) for SASL GSSAPI authentication + * 'numsub_filter' => '(objectClass=organizationalUnit)', // with VLV, we also use numSubOrdinates to query the total number of records. Set this filter to get all numSubOrdinates attributes for counting + * 'referrals' => false, // Sets the LDAP_OPT_REFERRALS option. Mostly used in multi-domain Active Directory setups + * 'network_timeout' => 10, // The timeout (in seconds) for connect + bind arrempts. This is only supported in PHP >= 5.3.0 with OpenLDAP 2.x + * 'sizelimit' => 0, // Enables you to limit the count of entries fetched. Setting this to 0 means no limit. + * 'timelimit' => 0, // Sets the number of seconds how long is spend on the search. Setting this to 0 means no limit. + * 'vlv' => false, // force VLV off + * 'config_root_dn' => 'cn=config', // Root DN to read config (e.g. vlv indexes) from + * 'service_bind_dn' => 'uid=kolab-service,ou=Special Users,dc=example,dc=org', + * 'service_bind_pw' => 'Welcome2KolabSystems', + * 'root_dn' => 'dc=example,dc=org', + */ + protected $config = array( + 'sizelimit' => 0, + 'timelimit' => 0, + 'config_root_dn' => 'cn=config', + ); + + protected $debug_level = false; + protected $list_page = 1; + protected $page_size = 10; + protected $icache = array(); + protected $cache; + + // Use public method config_set('log_hook', $callback) to have $callback be + // call_user_func'ed instead of the local log functions. + protected $_log_hook; + + // Use public method config_set('config_get_hook', $callback) to have + // $callback be call_user_func'ed instead of the local config_get function. + protected $_config_get_hook; + + // Use public method config_set('config_set_hook', $callback) to have + // $callback be call_user_func'ed instead of the local config_set function. + protected $_config_set_hook; + + // Not Yet Implemented + // Intended to allow hooking in for the purpose of caching. + protected $_result_hook; + + // Runtime. These are not the variables you're looking for. + protected $_current_bind_dn; + protected $_current_bind_pw; + protected $_current_host; + protected $_metadata; + protected $_vlv_indexes_and_searches; + + + /** + * Constructor + * + * @param array $config Configuration parameters. After initialization use + * the config_set() method. + */ + public function __construct($config = array()) + { + if (!empty($config) && is_array($config)) { + foreach ($config as $key => $value) { + $setter = 'config_set_' . $key; + if (method_exists($this, $setter)) { + $this->$setter($value); + } + else if (isset($this->$key)) { + $this->$key = $value; + } + else { + $this->config[$key] = $value; + } + } + } + } + + /** + * Add multiple entries to the directory information tree in one go. + */ + public function add_entries($entries, $attributes = array()) + { + // If $entries is an associative array, it's keys are DNs and its + // values are the attributes for that DN. + // + // If $entries is a non-associative array, the attributes are expected + // to be positional in $attributes. + + $result_set = array(); + + if (array_keys($entries) == range(0, count($entries) - 1)) { + // $entries is sequential + if (count($entries) !== count($attributes)) { + $this->_error("LDAP: Wrong entry/attribute count in " . __FUNCTION__); + return false; + } + + for ($i = 0; $i < count($entries); $i++) { + $result_set[$i] = $this->add_entry($entries[$i], $attributes[$i]); + } + } + else { + // $entries is associative + foreach ($entries as $entry_dn => $entry_attributes) { + if (array_keys($attributes) !== range(0, count($attributes)-1)) { + // $attributes is associative as well, let's merge these + // + // $entry_attributes takes precedence, so is in the second + // position in array_merge() + $entry_attributes = array_merge($attributes, $entry_attributes); + } + + $result_set[$entry_dn] = $this->add_entry($entry_dn, $entry_attributes); + } + } + + return $result_set; + } + + /** + * Add an entry to the directory information tree. + */ + public function add_entry($entry_dn, $attributes) + { + // TODO: + // - Get entry rdn attribute value from entry_dn and see if it exists in + // attributes -> issue warning if so (but not block the operation). + $this->_debug("Entry DN", $entry_dn); + $this->_debug("Attributes", $attributes); + + foreach ($attributes as $attr_name => $attr_value) { + if (empty($attr_value)) { + unset($attributes[$attr_name]); + } else if (is_array($attr_value)) { + $attributes[$attr_name] = array_values($attr_value); + } + } + + $this->_debug("C: Add $entry_dn: " . json_encode($attributes)); + + if (!ldap_add($this->conn, $entry_dn, $attributes)) { + $this->_debug("S: " . ldap_error($this->conn)); + $this->_warning("LDAP: Adding entry $entry_dn failed. " . ldap_error($this->conn)); + + return false; + } + + $this->_debug("S: OK"); + + return true; + } + + /** + * Add replication agreements and initialize the consumer(s) for + * $domain_root_dn. + * + * Searches the configured replicas for any of the current domain/config + * databases, and uses this information to configure the additional + * replication for the (new) domain database (at $domain_root_dn). + * + * Very specific to Netscape-based directory servers, and currently also + * very specific to multi-master replication. + */ + public function add_replication_agreements($domain_root_dn) + { + $replica_hosts = $this->list_replicas(); + + if (empty($replica_hosts)) { + return; + } + + $result = $this->search($this->config_get('config_root_dn'), "(&(objectclass=nsDS5Replica)(nsDS5ReplicaType=3))", "sub"); + + if (!$result) { + $this->_debug("No replication configuration found."); + return; + } + + // Preserve the number of replicated databases we have, because the replication ID + // can be calculated from the number of databases replicated, and the number of + // servers. + $num_replica_dbs = $result->count(); + $replicas = $result->entries(true); + $max_replica_agreements = 0; + + foreach ($replicas as $replica_dn => $replica_attrs) { + $result = $this->search($replica_dn, "(objectclass=nsDS5ReplicationAgreement)", "sub"); + if ($result) { + if ($max_replica_agreements < $result->count()) { + $max_replica_agreements = $result->count(); + $max_replica_agreements_dn = $replica_dn; + } + } + } + + $max_repl_id = $num_replica_dbs * count($replica_hosts); + + $this->_debug("The current maximum replication ID is $max_repl_id"); + $this->_debug("The current maximum number of replication agreements for any database is $max_replica_agreements (for $max_replica_agreements_dn)"); + $this->_debug("With " . count($replica_hosts) . " replicas, the next is " . ($max_repl_id + 1) . " and the last one is " . ($max_repl_id + count($replica_hosts))); + + // Then add the replication agreements + foreach ($replica_hosts as $num => $replica_host) { + $ldap = new Net_LDAP3($this->config); + $ldap->config_set('hosts', array($replica_host)); + $ldap->connect(); + $ldap->bind($this->_current_bind_dn, $this->_current_bind_pw); + + $attrs = array( + 'nsDS5ReplicaBindDN', + 'nsDS5ReplicaType', + 'nsds5ReplicaPurgeDelay', + 'nsDS5Flags' + ); + + $replica_attrs = $ldap->get_entry_attributes($replica_dn, $attrs); + $replica_attrs = array_merge((array) $replica_attrs, array( + 'cn' => 'replica', + 'objectclass' => array( + 'top', + 'nsds5replica', + 'extensibleobject', + ), + 'nsDS5ReplicaId' => ($max_repl_id + $num + 1), + 'nsDS5ReplicaRoot' => $domain_root_dn, + )); + + $new_replica_dn = 'cn=replica,cn="' . $domain_root_dn . '",cn=mapping tree,cn=config'; + + $this->_debug("Adding $new_replica_dn to $replica_host with attributes: " . var_export($replica_attrs, true)); + + $result = $ldap->add_entry($new_replica_dn, $replica_attrs); + + if (!$result) { + $this->_error("LDAP: Could not add replication configuration to database for $domain_root_dn on $replica_host"); + continue; + } + + $result = $ldap->search($replica_dn, "(objectclass=nsDS5ReplicationAgreement)", "sub"); + + if (!$result) { + $this->_error("LDAP: Host $replica_host does not have any replication agreements"); + continue; + } + + $entries = $result->entries(true); + $replica_agreement_tpl_dn = key($entries); + + $this->_debug("Using " . var_export($replica_agreement_tpl_dn, true) . " as the template for new replication agreements"); + + foreach ($replica_hosts as $replicate_to_host) { + // Skip the current server + if ($replicate_to_host == $replica_host) { + continue; + } + + $this->_debug("Adding a replication agreement for $domain_root_dn to $replicate_to_host on " . $replica_host); + + $attrs = array( + 'objectclass', + 'nsDS5ReplicaBindDN', + 'nsDS5ReplicaCredentials', + 'nsDS5ReplicaTransportInfo', + 'nsDS5ReplicaBindMethod', + 'nsDS5ReplicaHost', + 'nsDS5ReplicaPort' + ); + + $replica_agreement_attrs = $ldap->get_entry_attributes($replica_agreement_tpl_dn, $attrs); + $replica_agreement_attrs['cn'] = array_shift(explode('.', $replicate_to_host)) . str_replace(array('dc=',','), array('_',''), $domain_root_dn); + $replica_agreement_attrs['nsDS5ReplicaRoot'] = $domain_root_dn; + $replica_agreement_dn = "cn=" . $replica_agreement_attrs['cn'] . "," . $new_replica_dn; + + $this->_debug("Adding $replica_agreement_dn to $replica_host with attributes: " . var_export($replica_agreement_attrs, true)); + + $result = $ldap->add_entry($replica_agreement_dn, $replica_agreement_attrs); + + if (!$result) { + $this->_error("LDAP: Failed adding $replica_agreement_dn"); + } + } + } + + $server_id = implode('', array_diff($replica_hosts, $this->_server_id_not)); + + $this->_debug("About to trigger consumer initialization for replicas on current 'parent': $server_id"); + + $result = $this->search($this->config_get('config_root_dn'), "(&(objectclass=nsDS5ReplicationAgreement)(nsds5replicaroot=$domain_root_dn))", "sub"); + + if ($result) { + foreach ($result->entries(true) as $agreement_dn => $agreement_attrs) { + $this->modify_entry_attributes( + $agreement_dn, + array( + 'replace' => array( + 'nsds5BeginReplicaRefresh' => 'start', + ), + ) + ); + } + } + } + + public function attribute_details($attributes = array()) + { + $schema = $this->init_schema(); + + if (!$schema) { + return array(); + } + + $attribs = $schema->getAll('attributes'); + + $attributes_details = array(); + + foreach ($attributes as $attribute) { + if (array_key_exists($attribute, $attribs)) { + $attrib_details = $attribs[$attribute]; + + if (!empty($attrib_details['sup'])) { + foreach ($attrib_details['sup'] as $super_attrib) { + $_attrib_details = $attribs[$super_attrib]; + if (is_array($_attrib_details)) { + $attrib_details = array_merge($_attrib_details, $attrib_details); + } + } + } + } + else if (array_key_exists(strtolower($attribute), $attribs)) { + $attrib_details = $attribs[strtolower($attribute)]; + + if (!empty($attrib_details['sup'])) { + foreach ($attrib_details['sup'] as $super_attrib) { + $_attrib_details = $attribs[$super_attrib]; + if (is_array($_attrib_details)) { + $attrib_details = array_merge($_attrib_details, $attrib_details); + } + } + } + } + else { + $this->_warning("LDAP: No schema details exist for attribute $attribute (which is strange)"); + } + + // The relevant parts only, please + $attributes_details[$attribute] = array( + 'type' => !empty($attrib_details['single-value']) ? 'text' : 'list', + 'description' => $attrib_details['desc'], + 'syntax' => $attrib_details['syntax'], + 'max-length' => $attrib_details['max-length'] ?: false, + ); + } + + return $attributes_details; + } + + public function attributes_allowed($objectclasses = array()) + { + $this->_debug("Listing allowed_attributes for objectclasses", $objectclasses); + + if (!is_array($objectclasses) || empty($objectclasses)) { + return false; + } + + $schema = $this->init_schema(); + if (!$schema) { + return false; + } + + $may = array(); + $must = array(); + $superclasses = array(); + + foreach ($objectclasses as $objectclass) { + $superclass = $schema->superclass($objectclass); + if (!empty($superclass)) { + $superclasses = array_merge($superclass, $superclasses); + } + + $_may = $schema->may($objectclass); + $_must = $schema->must($objectclass); + + if (is_array($_may)) { + $may = array_merge($may, $_may); + } + if (is_array($_must)) { + $must = array_merge($must, $_must); + } + } + + $may = array_unique($may); + $must = array_unique($must); + $superclasses = array_unique($superclasses); + + return array('may' => $may, 'must' => $must, 'super' => $superclasses); + } + + public function classes_allowed() + { + $schema = $this->init_schema(); + if (!$schema) { + return false; + } + + $list = $schema->getAll('objectclasses'); + $classes = array(); + + foreach ($list as $class) { + $classes[] = $class['name']; + } + + return $classes; + } + + /** + * Bind connection with DN and password + * + * @param string $dn Bind DN + * @param string $pass Bind password + * + * @return boolean True on success, False on error + */ + public function bind($bind_dn, $bind_pw) + { + if (!$this->conn) { + return false; + } + + if ($bind_dn == $this->_current_bind_dn) { + return true; + } + + $this->_debug("C: Bind [dn: $bind_dn]"); + + if (@ldap_bind($this->conn, $bind_dn, $bind_pw)) { + $this->_debug("S: OK"); + $this->_current_bind_dn = $bind_dn; + $this->_current_bind_pw = $bind_pw; + + return true; + } + + $this->_debug("S: ".ldap_error($this->conn)); + $this->_error("LDAP: Bind failed for dn=$bind_dn. ".ldap_error($this->conn)); + + return false; + } + + /** + * Close connection to LDAP server + */ + public function close() + { + if ($this->conn) { + $this->_debug("C: Close"); + ldap_unbind($this->conn); + + $this->_current_bind_dn = null; + $this->_current_bind_pw = null; + $this->conn = null; + } + } + + /** + * Get the value of a configuration item. + * + * @param string $key Configuration key + * @param mixed $default Default value to return + */ + public function config_get($key, $default = null) + { + if (!empty($this->_config_get_hook)) { + return call_user_func_array($this->_config_get_hook, array($key, $value)); + } + else if (method_exists($this, "config_get_{$key}")) { + return call_user_func(array($this, "config_get_$key"), $value); + } + else if (!isset($this->config[$key])) { + return $default; + } + else { + return $this->config[$key]; + } + } + + /** + * Set a configuration item to value. + * + * @param string $key Configuration key + * @param mixed $value Configuration value + */ + public function config_set($key, $value = null) + { + if (is_array($key)) { + foreach ($key as $k => $v) { + $this->config_set($k, $v); + } + return; + } + + if (!empty($this->_config_set_hook)) { + call_user_func($this->_config_set_hook, array($key, $value)); + } + else if (method_exists($this, "config_set_{$key}")) { + call_user_func_array(array($this, "config_set_$key"), array($value)); + } + else if (property_exists($this, $key)) { + $this->$key = $value; + } + else { + // 'host' option is deprecated + if ($key == 'host') { + $this->config['hosts'] = (array) $value; + } + else { + $this->config[$key] = $value; + } + } + } + + /** + * Establish a connection to the LDAP server + */ + public function connect($host = null) + { + if (!function_exists('ldap_connect')) { + $this->_error("No ldap support in this PHP installation"); + return false; + } + + if (is_resource($this->conn)) { + $this->_debug("Connection already exists"); + return true; + } + + $hosts = !empty($host) ? $host : $this->config_get('hosts', array()); + $port = $this->config_get('port', 389); + + foreach ((array) $hosts as $host) { + $this->_debug("C: Connect [$host:$port]"); + + if ($lc = @ldap_connect($host, $port)) { + if ($this->config_get('use_tls', false) === true) { + if (!ldap_start_tls($lc)) { + $this->_debug("S: Could not start TLS. " . ldap_error($lc)); + continue; + } + } + + $this->_debug("S: OK"); + + $ldap_version = $this->config_get('ldap_version', 3); + $timeout = $this->config_get('network_timeout'); + $referrals = $this->config_get('referrals'); + + ldap_set_option($lc, LDAP_OPT_PROTOCOL_VERSION, $ldap_version); + + if ($timeout) { + ldap_set_option($lc, LDAP_OPT_NETWORK_TIMEOUT, $timeout); + } + + if ($referrals !== null) { + ldap_set_option($lc, LDAP_OPT_REFERRALS, (bool) $referrals); + } + + $this->_current_host = $host; + $this->conn = $lc; + + break; + } + + $this->_debug("S: NOT OK"); + } + + if (!is_resource($this->conn)) { + $this->_error("Could not connect to LDAP"); + return false; + } + + return true; + } + + /** + * Shortcut to ldap_delete() + */ + public function delete_entry($entry_dn) + { + $this->_debug("C: Delete $entry_dn"); + + if (ldap_delete($this->conn, $entry_dn) === false) { + $this->_debug("S: " . ldap_error($this->conn)); + $this->_warning("LDAP: Removing entry $entry_dn failed. " . ldap_error($this->conn)); + return false; + } + + $this->_debug("S: OK"); + + return true; + } + + /** + * Deletes specified entry and all entries in the tree + */ + public function delete_entry_recursive($entry_dn) + { + // searching for sub entries, but not scope sub, just one level + $result = $this->search($entry_dn, '(|(objectclass=*)(objectclass=ldapsubentry))', 'one'); + + if ($result) { + $entries = $result->entries(true); + + foreach (array_keys($entries) as $sub_dn) { + if (!$this->delete_entry_recursive($sub_dn)) { + return false; + } + } + } + + if (!$this->delete_entry($entry_dn)) { + return false; + } + + return true; + } + + /** + * Gets effective rights of an ldap entry + */ + public function effective_rights($subject) + { + if (!in_array(self::CONTROL_EFFECTIVE_RIGHTS, $this->supported_controls())) { + $this->_debug("LDAP: No getEffectiveRights control in supportedControls"); + return false; + } + + $entry_dn = $this->entry_dn($subject); + + if (!$entry_dn) { + $entry_dn = $this->config_get($subject . "_base_dn"); + } + + if (!$entry_dn) { + $entry_dn = $this->config_get("base_dn"); + } + + if (!$entry_dn) { + $entry_dn = $this->config_get("root_dn"); + } + + $this->_debug("effective_rights for subject $subject resolves to entry dn $entry_dn"); + + if (PHP_VERSION_ID >= 70300) { + // Note: This get_entry() have to request all attributes to be working + $result = $this->get_entry($entry_dn, array('*'), array( + array( + 'oid' => self::CONTROL_EFFECTIVE_RIGHTS, + 'value' => 'dn:' . $this->_current_bind_dn, + 'iscritical' => true, + ), + )); + + if (!empty($result)) { + $attributes = array( + 'dn' => $entry_dn, + 'attributelevelrights' => array(), + 'entrylevelrights' => array(), + ); + + foreach (array('aclrights', 'attributelevelrights', 'entrylevelrights') as $attr_name) { + if ($attr_value = $result[$attr_name]) { + switch ($attr_name) { + case 'aclrights': + $this->parse_aclrights($attributes, $attr_value); + break; + case 'attributelevelrights': + $attributes[$attr_name] = $this->parse_attribute_level_rights($attr_value); + break; + case 'entrylevelrights': + $attributes[$attr_name] = $this->parse_entry_level_rights($attr_value); + break; + } + } + } + + $this->_debug("LDAP: Effective rights:" . var_export($attributes, true)); + + return $attributes; + } + + return false; + } + + // Use ldapsearch command + return $this->effective_rights_mozldap($entry_dn); + } + + protected function effective_rights_mozldap($entry_dn) + { + $moz_ldapsearch = "/usr/lib64/mozldap/ldapsearch"; + if (!is_file($moz_ldapsearch)) { + $moz_ldapsearch = "/usr/lib/mozldap/ldapsearch"; + } + if (!is_file($moz_ldapsearch)) { + $moz_ldapsearch = null; + } + + if (empty($moz_ldapsearch)) { + $this->_error("Mozilla LDAP C SDK binary ldapsearch not found, cannot get effective rights"); + return null; + } + + $output = array(); + $command = Array( + $moz_ldapsearch, + '-x', + '-h', + preg_replace('|^[a-z]+://|i', '', $this->_current_host), + '-p', + $this->config_get('port', 389), + '-b', + escapeshellarg($entry_dn), + '-s', + 'base', + '-D', + escapeshellarg($this->_current_bind_dn), + '-w', + escapeshellarg($this->_current_bind_pw) + ); + + if ($this->vendor_name() == "Oracle Corporation") { + // For Oracle DSEE + $command[] = "-J"; + $command[] = escapeshellarg(self::CONTROL_EFFECTIVE_RIGHTS . ':true'); + $command[] = "-c"; + $command[] = escapeshellarg('dn:' . $this->_current_bind_dn); + } else { + // For 389 DS: + $command[] = "-J"; + $command[] = escapeshellarg(self::CONTROL_EFFECTIVE_RIGHTS . ':true:dn:' . $this->_current_bind_dn); + } + + // For both + $command[] = '"(objectclass=*)"'; + $command[] = '"*"'; + + if ($this->vendor_name() == "Oracle Corporation") { + // Oracle DSEE + $command[] = 'aclRights'; + } + + // remove password from debug log + $command_debug = $command; + $command_debug[13] = '*'; + + $command = implode(' ', $command); + $command_debug = implode(' ', $command_debug); + + $this->_debug("LDAP: Executing command: $command_debug"); + + exec($command, $output, $return_code); + + $this->_debug("LDAP: Command output:" . var_export($output, true)); + $this->_debug("Return code: " . $return_code); + + if ($return_code) { + $this->_error("Command $moz_ldapsearch returned error code: $return_code"); + return null; + } + + $lines = array(); + foreach ($output as $line_num => $line) { + if (substr($line, 0, 1) == " ") { + $lines[count($lines)-1] .= trim($line); + } + else { + $lines[] = trim($line); + } + } + + $attributes = array( + 'dn' => $subject_dn, + 'attributelevelrights' => array(), + 'entrylevelrights' => array(), + ); + + if ($this->vendor_name() == "Oracle Corporation") { + // Example for attribute level rights: + // aclRights;attributeLevel;$attr:$right:$bool,$right:$bool + // Example for entry level rights: + // aclRights;entryLevel: add:1,delete:1,read:1,write:1,proxy:1 + foreach ($lines as $line) { + $line_components = explode(':', $line); + $attribute_name = explode(';', array_shift($line_components)); + + if ($attribute_name[0] === "aclRights") { + $this->parse_aclrights($attributes, $line); + } + } + } else { + foreach ($lines as $line) { + $line_components = explode(':', $line); + $attribute_name = array_shift($line_components); + $attribute_value = trim(implode(':', $line_components)); + + switch ($attribute_name) { + case "attributeLevelRights": + $attributes['attributelevelrights'] = $this->parse_attribute_level_rights($attribute_value); + break; + case "entryLevelRights": + $attributes['entrylevelrights'] = $this->parse_entry_level_rights($attribute_value); + break; + } + } + } + + return $attributes; + } + + /** + * Resolve entry data to entry DN + * + * @param string $subject Entry string (e.g. entry DN or unique attribute value) + * @param array $attributes Additional attributes + * @param string $base_dn Optional base DN + * + * @return string Entry DN string + */ + public function entry_dn($subject, $attributes = array(), $base_dn = null) + { + $this->_debug("Net_LDAP3::entry_dn($subject)"); + $is_dn = ldap_explode_dn($subject, 1); + + if (is_array($is_dn) && array_key_exists("count", $is_dn) && $is_dn["count"] > 0) { + $this->_debug("$subject is a dn"); + return $subject; + } + + $this->_debug("$subject is not a dn"); + + if (strlen($subject) < 32 || preg_match('/[^a-fA-F0-9-]/', $subject)) { + $this->_debug("$subject is not a unique identifier"); + return; + } + + $unique_attr = $this->config_get('unique_attribute', 'nsuniqueid'); + + $this->_debug("Using unique_attribute " . var_export($unique_attr, true) . " at " . __FILE__ . ":" . __LINE__); + + $attributes = array_merge(array($unique_attr => $subject), (array)$attributes); + $subject = $this->entry_find_by_attribute($attributes, $base_dn); + + if (!empty($subject)) { + return key($subject); + } + } + + public function entry_find_by_attribute($attributes, $base_dn = null) + { + $this->_debug("Net_LDAP3::entry_find_by_attribute(\$attributes, \$base_dn) called with base_dn", $base_dn, "and attributes", $attributes); + + if (empty($attributes) || !is_array($attributes)) { + return false; + } + + if (empty($attributes[key($attributes)])) { + return false; + } + + $filter = count($attributes) ? "(&" : ""; + + foreach ($attributes as $key => $value) { + $filter .= "(" . $key . "=" . $value . ")"; + } + + $filter .= count($attributes) ? ")" : ""; + + if (empty($base_dn)) { + $base_dn = $this->config_get('root_dn'); + $this->_debug("Using base_dn from domain " . $this->domain . ": " . $base_dn); + } + + $result = $this->search($base_dn, $filter, 'sub', array_keys($attributes)); + + if ($result && $result->count() > 0) { + $this->_debug("Results found: " . implode(', ', array_keys($result->entries(true)))); + return $result->entries(true); + } + else { + $this->_debug("No result"); + return false; + } + } + + public function find_user_groups($member_dn) + { + $groups = array(); + $root_dn = $this->config_get('root_dn'); + + // TODO: Do not query for both, it's either one or the other + $entries = $this->search($root_dn, "(|" . + "(&(objectclass=groupofnames)(member=$member_dn))" . + "(&(objectclass=groupofuniquenames)(uniquemember=$member_dn))" . + ")" + ); + + if ($entries) { + $groups = array_keys($entries->entries(true)); + } + + return $groups; + } + + public function get_entry_attribute($subject_dn, $attribute) + { + $entry = $this->get_entry_attributes($subject_dn, (array)$attribute); + + return $entry[strtolower($attribute)]; + } + + /** + * Get a specific LDAP entry attributes + * + * @param string $dn Record identifier + * @param array $attributes Attributes to return + * + * @return array Hash array (keys in lower case) + */ + public function get_entry_attributes($subject_dn, $attributes) + { + $result = $this->get_entry($subject_dn, $attributes); + + if (!$result) { + return array(); + } + + if (!in_array('*', $attributes) && !in_array('dn', $attributes)) { + unset($result['dn']); + } + + // change keys case for historical reasons + return array_change_key_case($result, CASE_LOWER); + } + + /** + * Get a specific LDAP entry, identified by its DN + * + * @param string $dn Record identifier + * @param array $attributes Attributes to return + * @param array $controls LDAP Controls + * + * @return array Hash array (keys in original case) + */ + public function get_entry($dn, $attributes = array("*"), $controls = array()) + { + $rec = null; + + if ($this->conn) { + $this->_debug("C: Read [dn: $dn] [(objectclass=*)]"); + + if (!empty($controls)) { + $ldap_result = @ldap_read($this->conn, $dn, '(objectclass=*)', $attributes, 0, -1, -1, LDAP_DEREF_NEVER, $controls); + } + else { + $ldap_result = @ldap_read($this->conn, $dn, '(objectclass=*)', $attributes); + } + + if ($ldap_result) { + $this->_debug("S: OK"); + + if ($entry = ldap_first_entry($this->conn, $ldap_result)) { + $rec = ldap_get_attributes($this->conn, $entry); + } + } + else { + $this->_debug("S: ".ldap_error($this->conn)); + $this->_warning("LDAP: Failed to read $dn. " . ldap_error($this->conn)); + } + + if (!empty($rec)) { + $rec = self::normalize_entry($rec, true); + if ($dn) { + $rec['dn'] = $dn; // Add in the dn for the entry. + } + } + } + + return $rec; + } + + public function list_replicas() + { + $this->_debug("Finding replicas for this server."); + + // Search any host that is a replica for the current host + $replica_hosts = $this->config_get('replica_hosts', array()); + $root_dn = $this->config_get('config_root_dn'); + + if (!empty($replica_hosts)) { + return $replica_hosts; + } + + $ldap = new Net_LDAP3($this->config); + $ldap->connect(); + $ldap->bind($this->_current_bind_dn, $this->_current_bind_pw); + + $result = $ldap->search($root_dn, '(objectclass=nsds5replicationagreement)', 'sub', array('nsds5replicahost')); + + if (!$result) { + $this->_debug("No replicas configured"); + return $replica_hosts; + } + + $this->_debug("Replication agreements found: " . var_export($result->entries(true), true)); + + foreach ($result->entries(true) as $dn => $attrs) { + if (!in_array($attrs['nsds5replicahost'], $replica_hosts)) { + $replica_hosts[] = $attrs['nsds5replicahost']; + } + } + + // $replica_hosts now holds the IDs of servers we are currently NOT + // connected to. We might need this later in order to set + $this->_server_id_not = $replica_hosts; + + $this->_debug("So far, we have the following replicas: " . var_export($replica_hosts, true)); + + $ldap->close(); + + foreach ($replica_hosts as $replica_host) { + $ldap->config_set('hosts', array($replica_host)); + $ldap->connect(); + $ldap->bind($this->_current_bind_dn, $this->_current_bind_pw); + + $result = $ldap->search($root_dn, '(objectclass=nsds5replicationagreement)', 'sub', array('nsds5replicahost')); + if (!$result) { + $this->_debug("No replicas configured on $replica_host"); + $ldap->close(); + continue; + } + + foreach ($result->entries(true) as $dn => $attrs) { + if (!in_array($attrs['nsds5replicahost'], $replica_hosts)) { + $replica_hosts[] = $attrs['nsds5replicahost']; + } + } + + $ldap->close(); + } + + $this->config_set('replica_hosts', $replica_hosts); + + return $replica_hosts; + } + + public function login($username, $password, $domain = null, &$attributes = null) + { + $this->_debug("Net_LDAP3::login($username,***,$domain)"); + + $_bind_dn = $this->config_get('service_bind_dn'); + $_bind_pw = $this->config_get('service_bind_pw'); + + if (empty($_bind_dn)) { + $this->_debug("No valid service bind dn found."); + return null; + } + + if (empty($_bind_pw)) { + $this->_debug("No valid service bind password found."); + return null; + } + + $bound = $this->bind($_bind_dn, $_bind_pw); + + if (!$bound) { + $this->_debug("Could not bind with service bind credentials."); + return null; + } + + $entry_dn = $this->entry_dn($username); + + if (!empty($entry_dn)) { + $bound = $this->bind($entry_dn, $password); + + if (!$bound) { + $this->_error("LDAP: Could not bind with " . $entry_dn); + return null; + } + + // fetch user attributes if requested + if (!empty($attributes)) { + $attributes = $this->get_entry($entry_dn, $attributes); + } + + return $entry_dn; + } + + $base_dn = $this->config_get('root_dn'); + + if (empty($base_dn)) { + $this->_debug("Could not get a valid base dn to search."); + return null; + } + + $localpart = $username; + + if (empty($domain) ) { + if (count(explode('@', $username)) > 1) { + $_parts = explode('@', $username); + $localpart = $_parts[0]; + $domain = $_parts[1]; + } + else { + $localpart = $username; + $domain = ''; + } + } + + $realm = $domain; + $filter = $this->config_get("login_filter", null); + + if (empty($filter)) { + $filter = $this->config_get("filter", null); + } + if (empty($filter)) { + $filter = "(&(|(mail=%s)(mail=%U@%d)(alias=%s)(alias=%U@%d)(uid=%s))(objectclass=inetorgperson))"; + } + + $this->_debug("Net::LDAP3::login() original filter: " . $filter); + + $replace_patterns = array( + '/%s/' => $username, + '/%d/' => $domain, + '/%U/' => $localpart, + '/%r/' => $realm + ); + + $filter = preg_replace(array_keys($replace_patterns), array_values($replace_patterns), $filter); + + $this->_debug("Net::LDAP3::login() actual filter: " . $filter); + + $result = $this->search($base_dn, $filter, 'sub', $attributes); + + if (!$result) { + $this->_debug("Could not search $base_dn with $filter"); + return null; + } + + if ($result->count() > 1) { + $this->_debug("Multiple entries found."); + return null; + } + else if ($result->count() < 1) { + $this->_debug("No entries found."); + return null; + } + + $entries = $result->entries(true); + $entry_dn = key($entries); + + $bound = $this->bind($entry_dn, $password); + + if (!$bound) { + $this->_debug("Could not bind with " . $entry_dn); + return null; + } + + // replace attributes list with key-value data + if (!empty($attributes)) { + $attributes = $entries[$entry_dn]; + } + + return $entry_dn; + } + + public function list_group_members($dn, $entry = null, $recurse = true) + { + $this->_debug("Net_LDAP3::list_group_members($dn)"); + + if (is_array($entry) && in_array('objectclass', $entry)) { + if (!in_array(array('groupofnames', 'groupofuniquenames', 'groupofurls'), $entry['objectclass'])) { + $this->_debug("Called list_group_members on a non-group!"); + return array(); + } + } + else { + $entry = $this->get_entry_attributes($dn, array('member', 'uniquemember', 'memberurl', 'objectclass')); + + if (!$entry) { + return array(); + } + } + + $group_members = array(); + + foreach ((array)$entry['objectclass'] as $objectclass) { + switch (strtolower($objectclass)) { + case "groupofnames": + case "kolabgroupofnames": + $group_members = array_merge($group_members, $this->list_group_member($dn, $entry['member'], $recurse)); + break; + case "groupofuniquenames": + case "kolabgroupofuniquenames": + $group_members = array_merge($group_members, $this->list_group_uniquemember($dn, $entry['uniquemember'], $recurse)); + break; + case "groupofurls": + $group_members = array_merge($group_members, $this->list_group_memberurl($dn, $entry['memberurl'], $recurse)); + break; + } + } + + return array_values(array_filter($group_members)); + } + + public function modify_entry($subject_dn, $old_attrs, $new_attrs) + { + $this->_debug("OLD ATTRIBUTES", $old_attrs); + $this->_debug("NEW ATTRIBUTES", $new_attrs); + + // TODO: Get $rdn_attr - we have type_id in $new_attrs + $dn_components = ldap_explode_dn($subject_dn, 0); + $rdn_components = explode('=', $dn_components[0]); + $rdn_attr = $rdn_components[0]; + + $this->_debug("Net_LDAP3::modify_entry() using rdn attribute: " . $rdn_attr); + + $mod_array = array( + 'add' => array(), // For use with ldap_mod_add() + 'del' => array(), // For use with ldap_mod_del() + 'replace' => array(), // For use with ldap_mod_replace() + 'rename' => array(), // For use with ldap_rename() + ); + + // This is me cheating. Remove this special attribute. + if (array_key_exists('ou', $old_attrs) || array_key_exists('ou', $new_attrs)) { + $old_ou = is_array($old_attrs['ou']) ? array_shift($old_attrs['ou']) : $old_attrs['ou']; + $new_ou = is_array($new_attrs['ou']) ? array_shift($new_attrs['ou']) : $new_attrs['ou']; + unset($old_attrs['ou']); + unset($new_attrs['ou']); + } + else { + $old_ou = null; + $new_ou = null; + } + + // Compare each attribute value of the old attrs with the corresponding value + // in the new attrs, if any. + foreach ($old_attrs as $attr => $old_attr_value) { + if (is_array($old_attr_value)) { + if (count($old_attr_value) == 1) { + $old_attrs[$attr] = $old_attr_value[0]; + $old_attr_value = $old_attrs[$attr]; + } + } + + if (array_key_exists($attr, $new_attrs)) { + if (is_array($new_attrs[$attr])) { + if (count($new_attrs[$attr]) == 1) { + $new_attrs[$attr] = $new_attrs[$attr][0]; + } + } + + if (is_array($old_attrs[$attr]) && is_array($new_attrs[$attr])) { + $_sort1 = $new_attrs[$attr]; + sort($_sort1); + $_sort2 = $old_attr_value; + sort($_sort2); + } + else { + $_sort1 = true; + $_sort2 = false; + } + + if ($new_attrs[$attr] !== $old_attr_value && $_sort1 !== $_sort2) { + $this->_debug("Attribute $attr changed from " . var_export($old_attr_value, true) . " to " . var_export($new_attrs[$attr], true)); + if ($attr === $rdn_attr) { + $this->_debug("This attribute is the RDN attribute. Let's see if it is multi-valued, and if the original still exists in the new value."); + if (is_array($old_attrs[$attr])) { + if (!is_array($new_attrs[$attr])) { + if (in_array($new_attrs[$attr], $old_attrs[$attr])) { + // TODO: Need to remove all $old_attrs[$attr] values not equal to $new_attrs[$attr], and not equal to the current $rdn_attr value [0] + + $this->_debug("old attrs. is array, new attrs. is not array. new attr. exists in old attrs."); + + $rdn_attr_value = array_shift($old_attrs[$attr]); + $_attr_to_remove = array(); + + foreach ($old_attrs[$attr] as $value) { + if (strtolower($value) != strtolower($new_attrs[$attr])) { + $_attr_to_remove[] = $value; + } + } + + $this->_debug("Adding to delete attribute $attr values:" . implode(', ', $_attr_to_remove)); + + $mod_array['del'][$attr] = $_attr_to_remove; + + if (strtolower($new_attrs[$attr]) !== strtolower($rdn_attr_value)) { + $this->_debug("new attrs is not the same as the old rdn value, issuing a rename"); + $mod_array['rename']['dn'] = $subject_dn; + $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . self::quote_string($new_attrs[$attr], true); + } + } + else { + $this->_debug("new attrs is not the same as any of the old rdn value, issuing a full rename"); + $mod_array['rename']['dn'] = $subject_dn; + $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . self::quote_string($new_attrs[$attr], true); + } + } + else { + // TODO: See if the rdn attr. value is still in $new_attrs[$attr] + if (in_array($old_attrs[$attr][0], $new_attrs[$attr])) { + $this->_debug("Simply replacing attr $attr as rdn attr value is preserved."); + $mod_array['replace'][$attr] = $new_attrs[$attr]; + } + else { + // TODO: This fails. + $mod_array['rename']['dn'] = $subject_dn; + $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . self::quote_string($new_attrs[$attr][0], true); + $mod_array['del'][$attr] = $old_attrs[$attr][0]; + } + } + } + else { + if (!is_array($new_attrs[$attr])) { + $this->_debug("Renaming " . $old_attrs[$attr] . " to " . $new_attrs[$attr]); + $mod_array['rename']['dn'] = $subject_dn; + $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . self::quote_string($new_attrs[$attr], true); + } + else { + $this->_debug("Adding to replace"); + // An additional attribute value is being supplied. Just replace and continue. + $mod_array['replace'][$attr] = $new_attrs[$attr]; + continue; + } + } + } + else { + if (!isset($new_attrs[$attr]) || $new_attrs[$attr] === '' || (is_array($new_attrs[$attr]) && empty($new_attrs[$attr]))) { + switch ($attr) { + case "userpassword": + break; + default: + $this->_debug("Adding to del: $attr"); + $mod_array['del'][$attr] = (array)($old_attr_value); + break; + } + } + else { + $this->_debug("Adding to replace: $attr"); + $mod_array['replace'][$attr] = (array)($new_attrs[$attr]); + } + } + } + else { + $this->_debug("Attribute $attr unchanged"); + } + } + else { + // TODO: Since we're not shipping the entire object back and forth, and only post + // part of the data... we don't know what is actually removed (think modifiedtimestamp, etc.) + $this->_debug("Group attribute $attr not mentioned in \$new_attrs..., but not explicitly removed... by assumption"); + } + } + + foreach ($new_attrs as $attr => $value) { + // OU's parent base dn + if ($attr == 'base_dn') { + continue; + } + + if (is_array($value)) { + if (count($value) == 1) { + $new_attrs[$attr] = $value[0]; + $value = $new_attrs[$attr]; + } + } + + if (array_key_exists($attr, $old_attrs)) { + if (is_array($old_attrs[$attr])) { + if (count($old_attrs[$attr]) == 1) { + $old_attrs[$attr] = $old_attrs[$attr][0]; + } + } + + if (is_array($new_attrs[$attr]) && is_array($old_attrs[$attr])) { + $_sort1 = $old_attrs[$attr]; + sort($_sort1); + $_sort2 = $value; + sort($_sort2); + } + else { + $_sort1 = true; + $_sort2 = false; + } + + if ($value === null || $value === '' || (is_array($value) && empty($value))) { + if (!array_key_exists($attr, $mod_array['del'])) { + switch ($attr) { + case 'userpassword': + break; + default: + $this->_debug("Adding to del(2): $attr"); + $mod_array['del'][$attr] = (array)($old_attrs[$attr]); + break; + } + } + } + else { + if (!($old_attrs[$attr] === $value) && !($attr === $rdn_attr) && !($_sort1 === $_sort2)) { + if (!array_key_exists($attr, $mod_array['replace'])) { + $this->_debug("Adding to replace(2): $attr"); + $mod_array['replace'][$attr] = $value; + } + } + } + } + else { + if (!empty($value)) { + $mod_array['add'][$attr] = $value; + } + } + } + + if (empty($old_ou)) { + $subject_dn_components = ldap_explode_dn($subject_dn, 0); + unset($subject_dn_components["count"]); + $subject_rdn = array_shift($subject_dn_components); + $old_ou = implode(',', $subject_dn_components); + } + + $subject_dn = self::unified_dn($subject_dn); + $prefix = self::unified_dn('ou=' . $old_ou) . ','; + + // object is an organizational unit + if (strpos($subject_dn, $prefix) === 0) { + $root = substr($subject_dn, strlen($prefix)); // remove ou=*, + + if ((!empty($new_attrs['base_dn']) && strtolower($new_attrs['base_dn']) !== strtolower($root)) + || (strtolower($old_ou) !== strtolower($new_ou)) + ) { + if (!empty($new_attrs['base_dn'])) { + $root = $new_attrs['base_dn']; + } + + $mod_array['rename']['new_parent'] = $root; + $mod_array['rename']['dn'] = $subject_dn; + $mod_array['rename']['new_rdn'] = 'ou=' . self::quote_string($new_ou, true); + } + } + // not OU object, but changed ou attribute + else if (!empty($old_ou) && !empty($new_ou)) { + // unify DN strings for comparison + $old_ou = self::unified_dn($old_ou); + $new_ou = self::unified_dn($new_ou); + + if (strtolower($old_ou) !== strtolower($new_ou)) { + $mod_array['rename']['new_parent'] = $new_ou; + if (empty($mod_array['rename']['dn']) || empty($mod_array['rename']['new_rdn'])) { + $rdn_attr_value = self::quote_string($new_attrs[$rdn_attr], true); + $mod_array['rename']['dn'] = $subject_dn; + $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . $rdn_attr_value; + } + } + } + + $this->_debug($mod_array); + + $result = $this->modify_entry_attributes($subject_dn, $mod_array); + + if ($result) { + return $mod_array; + } + } + + /** + * Bind connection with (SASL-) user and password + * + * @param string $authc Authentication user + * @param string $pass Bind password + * @param string $authz Autorization user + * + * @return boolean True on success, False on error + */ + public function sasl_bind($authc = '', $pass = '', $authz = null) + { + if (!$this->conn) { + return false; + } + + if (!function_exists('ldap_sasl_bind')) { + $this->_error("LDAP: Unable to bind. ldap_sasl_bind() not exists"); + return false; + } + + if (!empty($authz)) { + $authz = 'u:' . $authz; + } + + $gssapi = $this->config_get('gssapi_cn'); + $method = $this->config_get('auth_method'); + + if (empty($method)) { + $method = 'DIGEST-MD5'; + } + + if ($gssapi && strcasecmp($method, 'GSSAPI') == 0) { + putenv("KRB5CCNAME=$gssapi"); + } + + $this->_debug("C: Bind [mech: $method, authc: $authc, authz: $authz, gssapi: $gssapi]"); + + if (ldap_sasl_bind($this->conn, null, $pass, $method, null, $authc, $authz)) { + $this->_debug("S: OK"); + return true; + } + + $this->_debug("S: ".ldap_error($this->conn)); + $this->_error("LDAP: Bind failed for authcid=$authc. ".ldap_error($this->conn)); + + return false; + } + + /** + * Execute LDAP search + * + * @param string $base_dn Base DN to use for searching + * @param string $filter Filter string to query + * @param string $scope The LDAP scope (list|sub|base) + * @param array $attrs List of entry attributes to read + * @param array $prop Hash array with query configuration properties: + * - sort: array of sort attributes (has to be in sync with the VLV index) + * - search: search string used for VLV controls + * @param bool $count_only Set to true if only entry count is requested + * + * @return mixed Net_LDAP3_Result object or number of entries (if $count_only=true) or False on failure + */ + public function search($base_dn, $filter = '(objectclass=*)', $scope = 'sub', $attrs = array('dn'), $props = array(), $count_only = false) + { + $controls = null; + + if (!array_key_exists('sort', $props)) { + $props['sort'] = false; + } + + if (!$this->conn) { + $this->_debug("No active connection for " . __CLASS__ . "::" . __FUNCTION__); + return false; + } + + // make sure attributes list is not empty + if (empty($attrs)) { + $attrs = array('dn'); + } + // make sure filter is not empty + if (empty($filter)) { + $filter = '(objectclass=*)'; + } + + $this->_debug("C: Search base dn: [$base_dn] scope [$scope] with filter [$filter]"); + + $function = self::scope_to_function($scope, $ns_function); + + if (!$count_only && ($sort = $this->find_vlv($base_dn, $filter, $scope, $props['sort']))) { + // when using VLV, we get the total count by... + // ...either reading numSubOrdinates attribute + if (($sub_filter = $this->config_get('numsub_filter')) && + ($result_count = @$ns_function($this->conn, $base_dn, $sub_filter, array('numSubOrdinates'), 0, 0, 0)) + ) { + $counts = ldap_get_entries($this->conn, $result_count); + for ($vlv_count = $j = 0; $j < $counts['count']; $j++) { + $vlv_count += $counts[$j]['numsubordinates'][0]; + } + $this->_debug("D: total numsubordinates = " . $vlv_count); + } + // ...or by parsing the controls in the response, and if that's not supported + // by fetching all records dn and counting them + else if (PHP_VERSION_ID < 70305 && !function_exists('ldap_parse_virtuallist_control')) { + // @FIXME: this search will ignore $props['search'] + $vlv_count = $this->search($base_dn, $filter, $scope, array('dn'), $props, true); + } + + $controls = $this->_vlv_set_controls($sort, $this->list_page, $this->page_size, + $this->_vlv_search($sort, $props['search'])); + + $this->vlv_active = (bool) $controls; + } + else { + $this->vlv_active = false; + } + + $sizelimit = (int) $this->config['sizelimit']; + $timelimit = (int) $this->config['timelimit']; + $phplimit = (int) @ini_get('max_execution_time'); + + // set LDAP time limit to be (one second) less than PHP time limit + // otherwise we have no chance to log the error below + if ($phplimit && $timelimit >= $phplimit) { + $timelimit = $phplimit - 1; + } + + $this->_debug("Using function $function on scope $scope (\$ns_function is $ns_function)"); + + if ($this->vlv_active) { + if (!empty($this->additional_filter)) { + $filter = "(&" . $filter . $this->additional_filter . ")"; + $this->_debug("C: (With VLV) Setting a filter (with additional filter) of " . $filter); + } + else { + $this->_debug("C: (With VLV) Setting a filter (without additional filter) of " . $filter); + } + } + else { + if (!empty($this->additional_filter)) { + $filter = "(&" . $filter . $this->additional_filter . ")"; + } + $this->_debug("C: (Without VLV) Setting a filter of " . $filter); + } + + $this->_debug("Executing search with return attributes: " . var_export($attrs, true)); + + if (is_array($controls)) { + $ldap_result = $function($this->conn, $base_dn, $filter, $attrs, 0, $sizelimit, $timelimit, LDAP_DEREF_NEVER, $controls); + } + else { + $ldap_result = @$function($this->conn, $base_dn, $filter, $attrs, 0, $sizelimit, $timelimit); + } + + if (!$ldap_result) { + $this->_warning("LDAP: $function failed for dn=$base_dn. " . ldap_error($this->conn)); + return false; + } + + // when running on a PHP with server controls support we can + // retrieve the total count from the LDAP search result + if ($this->vlv_active && (is_array($controls) || function_exists('ldap_parse_virtuallist_control'))) { + if (ldap_parse_result($this->conn, $ldap_result, $errcode, $matcheddn, $errmsg, $referrals, $serverctrls)) { + if (PHP_VERSION_ID >= 70300) { + $vlv_count = (int) $serverctrls[self::CONTROL_VLV_RESPONSE]['value']['count']; + // FIXME: I don't know this is the same offset value as in ldap_parse_virtuallist_control() below + // but anyway it looks like we do not use that value for anything + $last_offset = (int) $serverctrls[self::CONTROL_VLV_RESPONSE]['value']['target']; + } + else { + ldap_parse_virtuallist_control($this->conn, $serverctrls, $last_offset, $vlv_count, $vresult); + } + + $this->_debug("S: VLV result: last_offset=$last_offset; content_count=$vlv_count"); + } + else { + $this->_debug("S: ".($errmsg ? $errmsg : ldap_error($this->conn))); + } + } + else { + $this->_debug("S: ".ldap_count_entries($this->conn, $ldap_result)." record(s) found"); + } + + $result = new Net_LDAP3_Result($this->conn, $base_dn, $filter, $scope, $ldap_result); + + if (isset($last_offset)) { + $result->set('offset', $last_offset); + } + if (isset($vlv_count)) { + $result->set('count', $vlv_count); + } + + $result->set('vlv', $this->vlv_active); + + return $count_only ? $result->count() : $result; + } + + /** + * Similar to Net_LDAP3::search() but using a search array with multiple + * keys and values that to continue to use the VLV but with an original + * filter adding the search stuff to an additional filter. + * + * @see Net_LDAP3::search() + */ + public function search_entries($base_dn, $filter = '(objectclass=*)', $scope = 'sub', $attrs = array('dn'), $props = array()) + { + $this->_debug("Net_LDAP3::search_entries with search " . var_export($props, true)); + + if (is_array($props['search']) && array_key_exists('params', $props['search'])) { + $_search = $this->search_filter($props['search']); + $this->_debug("C: Search filter: $_search"); + + if (!empty($_search)) { + $this->additional_filter = $_search; + } + else { + $this->additional_filter = "(|"; + + foreach ($props['search'] as $attr => $value) { + $this->additional_filter .= "(" . $attr . "=" . $this->_fuzzy_search_prefix() . $value . $this->_fuzzy_search_suffix() . ")"; + } + + $this->additional_filter .= ")"; + } + + $this->_debug("C: Setting an additional filter " . $this->additional_filter); + } + + $search = $this->search($base_dn, $filter, $scope, $attrs, $props); + + $this->additional_filter = null; + + if (!$search) { + $this->_debug("Net_LDAP3: Search did not succeed!"); + return false; + } + + return $search; + } + + /** + * Create LDAP search filter string according to defined parameters. + */ + public function search_filter($search) + { + if (empty($search) || !is_array($search) || empty($search['params'])) { + return null; + } + + $operators = array('=', '~=', '>=', '<='); + $filter = ''; + + foreach ((array) $search['params'] as $field => $param) { + $value = (array) $param['value']; + + switch ((string)$param['type']) { + case 'prefix': + $prefix = ''; + $suffix = '*'; + break; + + case 'suffix': + $prefix = '*'; + $suffix = ''; + break; + + case 'exact': + case '=': + case '~=': + case '>=': + case '<=': + $prefix = ''; + $suffix = ''; + + // this is a common query to find entry by DN, make sure + // it is a unified DN so special characters are handled correctly + if ($field == 'entrydn') { + $value = array_map(array('Net_LDAP3', 'unified_dn'), $value); + } + + break; + + case 'exists': + $prefix = '*'; + $suffix = ''; + $param['value'] = ''; + break; + + case 'both': + default: + $prefix = '*'; + $suffix = '*'; + break; + } + + $operator = $param['type'] && in_array($param['type'], $operators) ? $param['type'] : '='; + + if (count($value) < 2) { + $value = array_pop($value); + } + + if (is_array($value)) { + $val_filter = array(); + foreach ($value as $val) { + $val = self::quote_string($val); + $val_filter[] = "(" . $field . $operator . $prefix . $val . $suffix . ")"; + } + $filter .= "(|" . implode($val_filter) . ")"; + } + else { + $value = self::quote_string($value); + $filter .= "(" . $field . $operator . $prefix . $value . $suffix . ")"; + } + } + + // join search parameters with specified operator ('OR' or 'AND') + if (count($search['params']) > 1) { + $filter = '(' . ($search['operator'] == 'AND' ? '&' : '|') . $filter . ')'; + } + + return $filter; + } + + /** + * Set properties for VLV-based paging + * + * @param number $page Page number to list (starting at 1) + * @param number $size Number of entries to display on one page + */ + public function set_vlv_page($page, $size = 10) + { + $this->list_page = $page; + $this->page_size = $size; + } + + /** + * Turn an LDAP entry into a regular PHP array with attributes as keys. + * + * @param array $entry Attributes array as retrieved from ldap_get_attributes() or ldap_get_entries() + * @param bool $flat Convert one-element-array values into strings + * + * @return array Hash array with attributes as keys + */ + public static function normalize_entry($entry, $flat = false) + { + $rec = array(); + + for ($i=0; $i < $entry['count']; $i++) { + $attr = $entry[$i]; + $_attr = strtolower($attr); + + for ($j=0; $j < $entry[$attr]['count']; $j++) { + $rec[$_attr][$j] = $entry[$attr][$j]; + } + + if ($flat && count($rec[$_attr]) == 1) { + $rec[$_attr] = $rec[$_attr][0]; + } + } + + return $rec; + } + + /** + * Normalize a ldap result by converting entry attribute arrays into single values + */ + public static function normalize_result($_result) + { + if (!is_array($_result)) { + return array(); + } + + $result = array(); + + for ($x = 0; $x < $_result['count']; $x++) { + $dn = $_result[$x]['dn']; + $entry = self::normalize_entry($_result[$x], true); + + if (!empty($entry['objectclass'])) { + if (is_array($entry['objectclass'])) { + $entry['objectclass'] = array_map('strtolower', $entry['objectclass']); + } + else { + $entry['objectclass'] = strtolower($entry['objectclass']); + } + } + + $result[$dn] = $entry; + } + + return $result; + } + + public static function scopeint2str($scope) + { + switch ($scope) { + case 2: + return 'sub'; + + case 1: + return 'one'; + + case 0: + return 'base'; + + default: + $this->_debug("Scope $scope is not a valid scope integer"); + } + } + + /** + * Choose the right PHP function according to scope property + * + * @param string $scope The LDAP scope (sub|base|list) + * @param string $ns_function Function to be used for numSubOrdinates queries + * @return string PHP function to be used to query directory + */ + public static function scope_to_function($scope, &$ns_function = null) + { + switch ($scope) { + case 'sub': + $function = $ns_function = 'ldap_search'; + break; + case 'base': + $function = $ns_function = 'ldap_read'; + break; + case 'one': + case 'list': + default: + $function = 'ldap_list'; + $ns_function = 'ldap_read'; + break; + } + + return $function; + } + + private function config_set_config_get_hook($callback) + { + $this->_config_get_hook = $callback; + } + + private function config_set_config_set_hook($callback) + { + $this->_config_set_hook = $callback; + } + + /** + * Sets the debug level both for this class and the ldap connection. + */ + private function config_set_debug($value) + { + $this->config['debug'] = (bool) $value; + ldap_set_option(null, LDAP_OPT_DEBUG_LEVEL, (int) $value); + } + + /** + * Sets a log hook that is called with every log message in this module. + */ + private function config_set_log_hook($callback) + { + $this->_log_hook = $callback; + } + + /** + * Find a matching VLV + */ + protected function find_vlv($base_dn, $filter, $scope, $sort_attrs = null) + { + if ($scope == 'base') { + return false; + } + + $vlv_indexes = $this->find_vlv_indexes_and_searches(); + + if (empty($vlv_indexes)) { + return false; + } + + $this->_debug("Existing vlv index and search information", $vlv_indexes); + + $filter = strtolower($filter); + $base_dn = self::unified_dn($base_dn); + + foreach ($vlv_indexes as $vlv_index) { + if (!empty($vlv_index[$base_dn])) { + $this->_debug("Found a VLV for base_dn: " . $base_dn); + if ($vlv_index[$base_dn]['filter'] == $filter) { + if ($vlv_index[$base_dn]['scope'] == $scope) { + $this->_debug("Scope and filter matches"); + + // Not passing any sort attributes means you don't care + if (!empty($sort_attrs)) { + $sort_attrs = array_map('strtolower', (array) $sort_attrs); + + foreach ($vlv_index[$base_dn]['sort'] as $sss_config) { + $sss_config = array_map('strtolower', $sss_config); + if (count(array_intersect($sort_attrs, $sss_config)) == count($sort_attrs)) { + $this->_debug("Sorting matches"); + + return $sort_attrs; + } + } + + $this->_debug("Sorting does not match"); + } + else { + $sort = array_filter((array) $vlv_index[$base_dn]['sort'][0]); + $this->_debug("Sorting unimportant"); + + return $sort; + } + } + else { + $this->_debug("Scope does not match"); + } + } + else { + $this->_debug("Filter does not match"); + } + } + } + + return false; + } + + /** + * Return VLV indexes and searches including necessary configuration + * details. + */ + protected function find_vlv_indexes_and_searches() + { + // Use of Virtual List View control has been specifically disabled. + if ($this->config['vlv'] === false) { + return false; + } + + // Virtual List View control has been configured in kolab.conf, for example; + // + // [ldap] + // vlv = [ + // { + // 'ou=People,dc=example,dc=org': { + // 'scope': 'sub', + // 'filter': '(objectclass=inetorgperson)', + // 'sort' : [ + // [ + // 'displayname', + // 'sn', + // 'givenname', + // 'cn' + // ] + // ] + // } + // }, + // { + // 'ou=Groups,dc=example,dc=org': { + // 'scope': 'sub', + // 'filter': '(objectclass=groupofuniquenames)', + // 'sort' : [ + // [ + // 'cn' + // ] + // ] + // } + // }, + // ] + // + if (is_array($this->config['vlv'])) { + return $this->config['vlv']; + } + + // We have done this dance before. + if ($this->_vlv_indexes_and_searches !== null) { + return $this->_vlv_indexes_and_searches; + } + + $this->_vlv_indexes_and_searches = array(); + + $config_root_dn = $this->config_get('config_root_dn'); + + if (empty($config_root_dn)) { + return array(); + } + + if ($cached_config = $this->get_cache_data('vlvconfig')) { + $this->_vlv_indexes_and_searches = $cached_config; + return $this->_vlv_indexes_and_searches; + } + + $search_filter = '(objectclass=vlvsearch)'; + $index_filter = '(objectclass=vlvindex)'; + + $this->_debug("C: Search base dn: [$config_root_dn] scope [sub] with filter [$search_filter]"); + + $search_result = ldap_search($this->conn, $config_root_dn, $search_filter, array('*'), 0, 0, 0); + + if ($search_result === false) { + $this->_debug("S: " . ldap_error($this->conn)); + return array(); + } + + $this->_debug("S: " . ldap_count_entries($this->conn, $search_result) . " record(s) found"); + + $vlv_searches = new Net_LDAP3_Result($this->conn, $config_root_dn, $search_filter, 'sub', $search_result); + + if ($vlv_searches->count() < 1) { + return array(); + } + + foreach ($vlv_searches->entries(true) as $vlv_search_dn => $vlv_search_attrs) { + // The attributes we are interested in are as follows: + $_vlv_base_dn = self::unified_dn($vlv_search_attrs['vlvbase']); + $_vlv_scope = $vlv_search_attrs['vlvscope']; + $_vlv_filter = $vlv_search_attrs['vlvfilter']; + + $this->_debug("C: Search base dn: [$vlv_search_dn] scope [sub] with filter [$index_filter]"); + + // Multiple indexes may exist + $index_result = ldap_search($this->conn, $vlv_search_dn, $index_filter, array('*'), 0, 0, 0); + + if ($index_result === false) { + $this->_debug("S: " . ldap_error($this->conn)); + continue; + } + + $this->_debug("S: " . ldap_count_entries($this->conn, $index_result) . " record(s) found"); + + $vlv_indexes = new Net_LDAP3_Result($this->conn, $vlv_search_dn, $index_filter, 'sub', $index_result); + $vlv_indexes = $vlv_indexes->entries(true); + + // Reset this one for each VLV search. + $_vlv_sort = array(); + + foreach ($vlv_indexes as $vlv_index_dn => $vlv_index_attrs) { + $_vlv_sort[] = explode(' ', trim($vlv_index_attrs['vlvsort'])); + } + + $this->_vlv_indexes_and_searches[] = array( + $_vlv_base_dn => array( + 'scope' => self::scopeint2str($_vlv_scope), + 'filter' => strtolower($_vlv_filter), + 'sort' => $_vlv_sort, + ), + ); + } + + // cache this + $this->set_cache_data('vlvconfig', $this->_vlv_indexes_and_searches); + + return $this->_vlv_indexes_and_searches; + } + + private function init_schema() + { + // use PEAR include if autoloading failed + if (!class_exists('Net_LDAP2')) { + require_once('Net/LDAP2.php'); + } + + $port = $this->config_get('port', 389); + $tls = $this->config_get('use_tls', false); + + foreach ((array) $this->config_get('hosts') as $host) { + $this->_debug("C: Connect [$host:$port]"); + + $_ldap_cfg = array( + 'host' => $host, + 'port' => $port, + 'tls' => $tls, + 'version' => 3, + 'binddn' => $this->config_get('service_bind_dn'), + 'bindpw' => $this->config_get('service_bind_pw') + ); + + $_ldap_schema_cache_cfg = array( + 'max_age' => 86400, + 'path' => sprintf('%s/%s-Net_LDAP2_Schema.cache', + sys_get_temp_dir() ?: '/tmp', str_replace('://', ':', $host) . (strpos($host, ":$port") ? '' : ":$port")), + ); + + $_ldap = Net_LDAP2::connect($_ldap_cfg); + + if (!is_a($_ldap, 'Net_LDAP2_Error')) { + $this->_debug("S: OK"); + break; + } + + $this->_debug("S: NOT OK"); + $this->_debug($_ldap->getMessage()); + } + + if (is_a($_ldap, 'Net_LDAP2_Error')) { + return null; + } + + $_ldap_schema_cache = new Net_LDAP2_SimpleFileSchemaCache($_ldap_schema_cache_cfg); + + $_ldap->registerSchemaCache($_ldap_schema_cache); + + // TODO: We should learn what LDAP tech. we're running against. + // Perhaps with a scope base objectclass recognize rootdse entry + $schema_root_dn = $this->config_get('schema_root_dn'); + + if (!$schema_root_dn) { + $_schema = $_ldap->schema(); + } + + return $_schema; + } + + protected function list_group_member($dn, $members, $recurse = true) + { + $this->_debug("Net_LDAP3::list_group_member($dn)"); + + $members = (array) $members; + $group_members = array(); + + // remove possible 'count' item + unset($members['count']); + + // Use the member attributes to return an array of member ldap objects + // NOTE that the member attribute is supposed to contain a DN + foreach ($members as $member) { + $member_entry = $this->get_entry_attributes($member, array('member', 'uniquemember', 'memberurl', 'objectclass')); + + if (empty($member_entry)) { + continue; + } + + $group_members[$member] = $member; + + if ($recurse) { + // Nested groups + $group_group_members = $this->list_group_members($member, $member_entry); + if ($group_group_members) { + $group_members = array_merge($group_group_members, $group_members); + } + } + } + + return array_filter($group_members); + } + + protected function list_group_uniquemember($dn, $uniquemembers, $recurse = true) + { + $this->_debug("Net_LDAP3::list_group_uniquemember($dn)", $entry); + + $uniquemembers = (array)($uniquemembers); + $group_members = array(); + + // remove possible 'count' item + unset($uniquemembers['count']); + + foreach ($uniquemembers as $member) { + $member_entry = $this->get_entry_attributes($member, array('member', 'uniquemember', 'memberurl', 'objectclass')); + + if (empty($member_entry)) { + continue; + } + + $group_members[$member] = $member; + + if ($recurse) { + // Nested groups + $group_group_members = $this->list_group_members($member, $member_entry); + if ($group_group_members) { + $group_members = array_merge($group_group_members, $group_members); + } + } + } + + return array_filter($group_members); + } + + protected function list_group_memberurl($dn, $memberurls, $recurse = true) + { + $this->_debug("Net_LDAP3::list_group_memberurl($dn)"); + + $group_members = array(); + $memberurls = (array) $memberurls; + $attributes = array('member', 'uniquemember', 'memberurl', 'objectclass'); + + // remove possible 'count' item + unset($memberurls['count']); + + foreach ($memberurls as $url) { + $ldap_uri = $this->parse_memberurl($url); + $result = $this->search($ldap_uri[3], $ldap_uri[6], 'sub', $attributes); + + if (!$result) { + continue; + } + + foreach ($result->entries(true) as $entry_dn => $_entry) { + $group_members[$entry_dn] = $entry_dn; + $this->_debug("Found " . $entry_dn); + + if ($recurse) { + // Nested group + $group_group_members = $this->list_group_members($entry_dn, $_entry); + if ($group_group_members) { + $group_members = array_merge($group_members, $group_group_members); + } + } + } + } + + return array_filter($group_members); + } + + /** + * memberUrl attribute parser + * + * @param string $url URL string + * + * @return array URL elements + */ + protected function parse_memberurl($url) + { + preg_match('/(.*):\/\/(.*)\/(.*)\?(.*)\?(.*)\?(.*)/', $url, $matches); + return $matches; + } + + protected function modify_entry_attributes($subject_dn, $attributes) + { + if (is_array($attributes['rename']) && !empty($attributes['rename'])) { + $olddn = $attributes['rename']['dn']; + $newrdn = $attributes['rename']['new_rdn']; + $new_parent = $attributes['rename']['new_parent']; + + $this->_debug("C: Rename $olddn to $newrdn,$new_parent"); + + // Note: for some reason the operation fails if RDN contains special characters + // and last argument of ldap_rename() is set to TRUE. That's why we use FALSE. + // However, we need to modify RDN attribute value later, otherwise it + // will contain an array of previous and current values + for ($i = 1; $i >= 0; $i--) { + $result = ldap_rename($this->conn, $olddn, $newrdn, $new_parent, $i == 1); + if ($result) { + break; + } + } + + if ($result) { + $this->_debug("S: OK"); + + if ($new_parent) { + $subject_dn = $newrdn . ',' . $new_parent; + } + else { + $old_parent_dn_components = ldap_explode_dn($olddn, 0); + unset($old_parent_dn_components['count']); + $old_rdn = array_shift($old_parent_dn_components); + $old_parent_dn = implode(',', $old_parent_dn_components); + $subject_dn = $newrdn . ',' . $old_parent_dn; + } + + // modify RDN attribute value, see note above + if (!$i && empty($attributes['replace'][$attr])) { + list($attr, $val) = explode('=', $newrdn, 2); + $attributes['replace'][$attr] = self::quote_string($val, true, true); + } + } + else { + $this->_debug("S: " . ldap_error($this->conn)); + $this->_warning("LDAP: Failed to rename $olddn to $newrdn,$new_parent. " . ldap_error($this->conn)); + return false; + } + } + + if (is_array($attributes['replace']) && !empty($attributes['replace'])) { + $this->_debug("C: Mod-Replace $subject_dn: " . json_encode($attributes['replace'])); + + $result = ldap_mod_replace($this->conn, $subject_dn, $attributes['replace']); + + if ($result) { + $this->_debug("S: OK"); + } + else { + $this->_debug("S: " . ldap_error($this->conn)); + $this->_warning("LDAP: Failed to replace attributes on $subject_dn: " . $this->_encode_attrs($attributes['replace'])); + return false; + } + } + + if (is_array($attributes['del']) && !empty($attributes['del'])) { + $this->_debug("C: Mod-Delete $subject_dn: " . json_encode($attributes['del'])); + + $result = ldap_mod_del($this->conn, $subject_dn, $attributes['del']); + + if ($result) { + $this->_debug("S: OK"); + } + else { + $this->_debug("S: " . ldap_error($this->conn)); + $this->_warning("LDAP: Failed to delete attributes on $subject_dn: " . $this->_encode_attrs($attributes['del'])); + return false; + } + } + + if (is_array($attributes['add']) && !empty($attributes['add'])) { + $this->_debug("C: Mod-Add $subject_dn: " . json_encode($attributes['add'])); + + $result = ldap_mod_add($this->conn, $subject_dn, $attributes['add']); + + if ($result) { + $this->_debug("S: OK"); + } + else { + $this->_debug("S: " . ldap_error($this->conn)); + $this->_warning("LDAP: Failed to add attributes on $subject_dn: " . $this->_encode_attrs($attributes['add'])); + return false; + } + } + + return true; + } + + protected function parse_aclrights(&$attributes, $attribute_value) + { + $components = explode(':', $attribute_value); + $_acl_target = array_shift($components); + $_acl_value = trim(implode(':', $components)); + $_acl_components = explode(';', $_acl_target); + + switch ($_acl_components[1]) { + case "entryLevel": + $attributes['entrylevelrights'] = Array(); + $_acl_value = explode(',', $_acl_value); + + foreach ($_acl_value as $right) { + list($method, $bool) = explode(':', $right); + if ($bool == "1" && !in_array($method, $attributes['entrylevelrights'])) { + $attributes['entrylevelrights'][] = $method; + } + } + + break; + + case "attributeLevel": + $attributes['attributelevelrights'][$_acl_components[2]] = Array(); + $_acl_value = explode(',', $_acl_value); + + foreach ($_acl_value as $right) { + list($method, $bool) = explode(':', $right); + if ($bool == "1" && !in_array($method, $attributes['attributelevelrights'][$_acl_components[2]])) { + $attributes['attributelevelrights'][$_acl_components[2]][] = $method; + } + } + + break; + + default: + break; + } + } + + protected function parse_attribute_level_rights($attribute_value) + { + $attribute_value = str_replace(", ", ",", $attribute_value); + $attribute_values = explode(",", $attribute_value); + $attribute_value = array(); + + foreach ($attribute_values as $access_right) { + $access_right_components = explode(":", $access_right); + $access_attribute = strtolower(array_shift($access_right_components)); + $access_value = array_shift($access_right_components); + + $attribute_value[$access_attribute] = array(); + + for ($i = 0; $i < strlen($access_value); $i++) { + $method = $this->attribute_level_rights_map[substr($access_value, $i, 1)]; + + if (!in_array($method, $attribute_value[$access_attribute])) { + $attribute_value[$access_attribute][] = $method; + } + } + } + + return $attribute_value; + } + + protected function parse_entry_level_rights($attribute_value) + { + $_attribute_value = array(); + + for ($i = 0; $i < strlen($attribute_value); $i++) { + $method = $this->entry_level_rights_map[substr($attribute_value, $i, 1)]; + + if (!in_array($method, $_attribute_value)) { + $_attribute_value[] = $method; + } + } + + return $_attribute_value; + } + + protected function supported_controls() + { + $metadata = $this->server_metadata(); + + return (array) $metadata['supportedcontrol']; + } + + protected function vendor_name() + { + $metadata = $this->server_metadata(); + + return (string) $metadata['vendorname']; + } + + protected function server_metadata() + { + if ($this->_metadata === null) { + $this->_debug("Obtaining LDAP server metadata"); + + $result = $this->get_entry('', array('vendorname', 'supportedcontrol')); + + if ($result) { + $this->_metadata = $result; + $this->_debug("LDAP Server metadata: " . var_export($result, true)); + } + else { + $this->_metadata = array(); + $this->_warning("LDAP: Failed to get server metadata"); + } + } + + return $this->_metadata; + } + + protected function _alert() + { + $this->__log(LOG_ALERT, func_get_args()); + } + + protected function _critical() + { + $this->__log(LOG_CRIT, func_get_args()); + } + + protected function _debug() + { + $this->__log(LOG_DEBUG, func_get_args()); + } + + protected function _emergency() + { + $this->__log(LOG_EMERG, func_get_args()); + } + + protected function _error() + { + $this->__log(LOG_ERR, func_get_args()); + } + + protected function _info() + { + $this->__log(LOG_INFO, func_get_args()); + } + + protected function _notice() + { + $this->__log(LOG_NOTICE, func_get_args()); + } + + protected function _warning() + { + $this->__log(LOG_WARNING, func_get_args()); + } + + /** + * Log a message. + */ + private function __log($level, $args) + { + $msg = array(); + + foreach ($args as $arg) { + $msg[] = !is_string($arg) ? var_export($arg, true) : $arg; + } + + if (!empty($this->_log_hook)) { + call_user_func_array($this->_log_hook, array($level, $msg)); + return; + } + + if ($this->debug_level > 0) { + syslog($level, implode("\n", $msg)); + } + } + + /** + * Convert attributes array into a string for logging + * Remove plain text passwords + */ + private function _encode_attrs($attributes) + { + if (isset($attributes['userpassword'])) { + $attributes['userpassword'] = '*'; + } + + return json_encode($attributes); + } + + /** + * Quotes attribute value string + * + * @param string $str Attribute value + * @param bool $dn True if the attribute is a DN + * @param bool $reverse Do reverse replacement + * + * @return string Quoted string + */ + public static function quote_string($str, $is_dn = false, $reverse = false) + { + // take first entry if array given + if (is_array($str)) { + $str = reset($str); + } + + if ($is_dn) { + $replace = array( + ',' => '\2c', + '=' => '\3d', + '+' => '\2b', + '<' => '\3c', + '>' => '\3e', + ';' => '\3b', + "\\"=> '\5c', + '"' => '\22', + '#' => '\23' + ); + } + else { + $replace = array( + '*' => '\2a', + '(' => '\28', + ')' => '\29', + "\\" => '\5c', + '/' => '\2f' + ); + } + + if ($reverse) { + return str_replace(array_values($replace), array_keys($replace), $str); + } + + return strtr($str, $replace); + } + + /** + * Unify DN string for comparison + * + * @para string $str DN string + * + * @return string Unified DN string + */ + public static function unified_dn($str) + { + $result = array(); + + foreach (explode(',', $str) as $token) { + list($attr, $value) = explode('=', $token, 2); + + $pos = 0; + while (preg_match('/\\\\[0-9a-fA-F]{2}/', $value, $matches, PREG_OFFSET_CAPTURE, $pos)) { + $char = chr(hexdec(substr($matches[0][0], 1))); + $pos = $matches[0][1]; + $value = substr_replace($value, $char, $pos, 3); + $pos += 1; + } + + $result[] = $attr . '=' . self::quote_string($value, true); + } + + return implode(',', $result); + } + + private function _fuzzy_search_prefix() + { + switch ($this->config_get("fuzzy_search", 2)) { + case 2: + return "*"; + break; + case 1: + case 0: + default: + return ""; + break; + } + } + + private function _fuzzy_search_suffix() + { + switch ($this->config_get("fuzzy_search", 2)) { + case 2: + return "*"; + break; + case 1: + return "*"; + case 0: + default: + return ""; + break; + } + } + + /** + * Return the search string value to be used in VLV controls + * + * @param array $sort List of attributes in vlv index + * @param array|string $search Search string or attribute => value hash + * + * @return string Search string + */ + private function _vlv_search($sort, $search) + { + if (!empty($this->additional_filter)) { + $this->_debug("Not setting a VLV search filter because we already have a filter"); + return; + } + + if (empty($search)) { + return; + } + + foreach ((array) $search as $attr => $value) { + if ($attr && !in_array(strtolower($attr), $sort)) { + $this->_debug("Cannot use VLV search using attribute not indexed: $attr (not in " . var_export($sort, true) . ")"); + return; + } + else { + return $value . $this->_fuzzy_search_suffix(); + } + } + } + + /** + * Set server controls for Virtual List View (paginated listing) + */ + private function _vlv_set_controls($sort, $list_page, $page_size, $search = null) + { + $sort_ctrl = array( + 'oid' => self::CONTROL_SORT_REQUEST, + 'value' => self::_sort_ber_encode($sort) + ); + + if (!empty($search)) { + $this->_debug("_vlv_set_controls to include search: " . var_export($search, true)); + } + + $vlv_ctrl = array( + 'oid' => self::CONTROL_VLV_REQUEST, + 'value' => self::_vlv_ber_encode( + $offset = ($list_page-1) * $page_size + 1, + $page_size, + $search + ), + 'iscritical' => true + ); + + $this->_debug("C: set controls sort=" . join(' ', unpack('H'.(strlen($sort_ctrl['value'])*2), $sort_ctrl['value'])) + . " (" . implode(',', (array) $sort) . ");" + . " vlv=" . join(' ', (unpack('H'.(strlen($vlv_ctrl['value'])*2), $vlv_ctrl['value']))) . " ($offset/$page_size)"); + + $controls = array($sort_ctrl, $vlv_ctrl); + + if (PHP_VERSION_ID >= 70305) { + return $controls; + } + + if (!ldap_set_option($this->conn, LDAP_OPT_SERVER_CONTROLS, $controls)) { + $this->_debug("S: ".ldap_error($this->conn)); + return false; + } + + return true; + } + + /** + * create ber encoding for sort control + * + * @param array List of cols to sort by + * @return string BER encoded option value + */ + private static function _sort_ber_encode($sortcols) + { + $str = ''; + foreach (array_reverse((array)$sortcols) as $col) { + $ber_val = self::_string2hex($col); + + // 30 = ber sequence with a length of octet value + // 04 = octet string with a length of the ascii value + $oct = self::_ber_addseq($ber_val, '04'); + $str = self::_ber_addseq($oct, '30') . $str; + } + + // now tack on sequence identifier and length + $str = self::_ber_addseq($str, '30'); + + return pack('H'.strlen($str), $str); + } + + /** + * Generate BER encoded string for Virtual List View option + * + * @param integer List offset (first record) + * @param integer Records per page + * @return string BER encoded option value + */ + private static function _vlv_ber_encode($offset, $rpp, $search = '') + { + // This string is ber-encoded, php will prefix this value with: + // 04 (octet string) and 10 (length of 16 bytes) + // the code behind this string is broken down as follows: + // 30 = ber sequence with a length of 0e (14) bytes following + // 02 = type integer (in two's complement form) with 2 bytes following (beforeCount): 01 00 (ie 0) + // 02 = type integer (in two's complement form) with 2 bytes following (afterCount): 01 18 (ie 25-1=24) + // a0 = type context-specific/constructed with a length of 06 (6) bytes following + // 02 = type integer with 2 bytes following (offset): 01 01 (ie 1) + // 02 = type integer with 2 bytes following (contentCount): 01 00 + + // whith a search string present: + // 81 = type context-specific/constructed with a length of 04 (4) bytes following (the length will change here) + // 81 indicates a user string is present where as a a0 indicates just a offset search + // 81 = type context-specific/constructed with a length of 06 (6) bytes following + + // the following info was taken from the ISO/IEC 8825-1:2003 x.690 standard re: the + // encoding of integer values (note: these values are in + // two-complement form so since offset will never be negative bit 8 of the + // leftmost octet should never by set to 1): + // 8.3.2: If the contents octets of an integer value encoding consist + // of more than one octet, then the bits of the first octet (rightmost) and bit 8 + // of the second (to the left of first octet) octet: + // a) shall not all be ones; and + // b) shall not all be zero + + if ($search) { + $search = preg_replace('/[^-[:alpha:] ,.()0-9]+/', '', $search); + $ber_val = self::_string2hex($search); + $str = self::_ber_addseq($ber_val, '81'); + } + else { + // construct the string from right to left + $str = "020100"; # contentCount + + // returns encoded integer value in hex format + $ber_val = self::_ber_encode_int($offset); + + // calculate octet length of $ber_val + $str = self::_ber_addseq($ber_val, '02') . $str; + + // now compute length over $str + $str = self::_ber_addseq($str, 'a0'); + } + + // now tack on records per page + $str = "020100" . self::_ber_addseq(self::_ber_encode_int($rpp-1), '02') . $str; + + // now tack on sequence identifier and length + $str = self::_ber_addseq($str, '30'); + + return pack('H'.strlen($str), $str); + } + + /** + * Add BER sequence with correct length and the given identifier + */ + private static function _ber_addseq($str, $identifier) + { + $len = dechex(strlen($str)/2); + if (strlen($len) % 2 != 0) { + $len = '0'.$len; + } + + return $identifier . $len . $str; + } + + /** + * Returns BER encoded integer value in hex format + */ + private static function _ber_encode_int($offset) + { + $val = dechex($offset); + $prefix = ''; + + // check if bit 8 of high byte is 1 + if (preg_match('/^[89abcdef]/', $val)) { + $prefix = '00'; + } + + if (strlen($val)%2 != 0) { + $prefix .= '0'; + } + + return $prefix . $val; + } + + /** + * Returns ascii string encoded in hex + */ + private static function _string2hex($str) + { + return implode(unpack("H*", $str)); + } + + /** + * Get global handle for cache access + * + * @return object Cache object + */ + public function get_cache() + { + if ($this->cache === true) { + // no memcache support in PHP + if (!class_exists('Memcache')) { + $this->cache = false; + return false; + } + + // add all configured hosts to pool + $pconnect = $this->config_get('memcache_pconnect'); + $hosts = $this->config_get('memcache_hosts'); + + if ($hosts) { + $this->cache = new Memcache; + $this->mc_available = 0; + + $hosts = explode(',', $hosts); + foreach ($hosts as $host) { + $host = trim($host); + if (substr($host, 0, 7) != 'unix://') { + list($host, $port) = explode(':', $host); + if (!$port) $port = 11211; + } + else { + $port = 0; + } + + $this->mc_available += intval($this->cache->addServer( + $host, $port, $pconnect, 1, 1, 15, false, array($this, 'memcache_failure'))); + } + + // test connection and failover (will result in $this->mc_available == 0 on complete failure) + $this->cache->increment('__CONNECTIONTEST__', 1); // NOP if key doesn't exist + } + + if (!$this->mc_available) { + $this->cache = false; + } + } + + return $this->cache; + } + + /** + * Callback for memcache failure + */ + public function memcache_failure($host, $port) + { + static $seen = array(); + + // only report once + if (!$seen["$host:$port"]++) { + $this->mc_available--; + $this->_error("LDAP: Memcache failure on host $host:$port"); + } + } + + /** + * Get cached data + * + * @param string $key Cache key + * + * @return mixed Cached value + */ + public function get_cache_data($key) + { + if ($cache = $this->get_cache()) { + return $cache->get($key); + } + } + + /** + * Store cached data + * + * @param string $key Cache key + * @param mixed $data Data + * @param int $ttl Cache TTL in seconds + * + * @return bool False on failure or when cache is disabled, True if data was saved succesfully + */ + public function set_cache_data($key, $data, $ttl = 3600) + { + if ($cache = $this->get_cache()) { + $flags = defined('MEMCACHE_COMPRESSED') ? MEMCACHE_COMPRESSED : 0; + if (!method_exists($cache, 'replace') || !$cache->replace($key, $data, $flags, $ttl)) { + return $cache->set($key, $data, $flags, $ttl); + } + else { + return true; + } + } + + return false; + } + + /** + * Translate a domain name into it's corresponding root dn. + * + * @param string $domain Domain name + * + * @return string|bool Domain root DN or False on error + */ + public function domain_root_dn($domain) + { + if (empty($domain)) { + return false; + } + + $ckey = 'domain.root::' . $domain; + if (array_key_exists($ckey, $this->icache)) { + return $this->icache[$ckey]; + } + + $this->_debug("Net_LDAP3::domain_root_dn($domain)"); + + if ($entry_attrs = $this->find_domain($domain)) { + $name_attribute = $this->config_get('domain_name_attribute'); + + if (empty($name_attribute)) { + $name_attribute = 'associateddomain'; + } + + if (is_array($entry_attrs)) { + if (!empty($entry_attrs['inetdomainbasedn'])) { + $domain_root_dn = $entry_attrs['inetdomainbasedn']; + } + else { + if (is_array($entry_attrs[$name_attribute])) { + $domain_root_dn = $this->_standard_root_dn($entry_attrs[$name_attribute][0]); + } + else { + $domain_root_dn = $this->_standard_root_dn($entry_attrs[$name_attribute]); + } + } + } + } + + if (empty($domain_root_dn)) { + $domain_root_dn = $this->_standard_root_dn($domain); + } + + $this->_debug("Net_LDAP3::domain_root_dn() result: $domain_root_dn"); + + return $this->icache[$ckey] = $domain_root_dn; + } + + /** + * Find domain by name + * + * @param string $domain Domain name + * @param array $attributes Result attributes + * + * @return array|bool Domain attributes (plus 'dn' attribute) or False if not found + */ + public function find_domain($domain, $attributes = array('*')) + { + if (empty($domain)) { + return false; + } + + $ckey = 'domain::' . $domain; + $ickey = $ckey . '::' . md5(implode(',', $attributes)); + + if (array_key_exists($ickey, $this->icache)) { + return $this->icache[$ickey]; + } + + $this->_debug("Net_LDAP3::find_domain($domain)"); + + // use cache + $domain_dn = $this->get_cache_data($ckey); + + if ($domain_dn) { + $result = $this->get_entry_attributes($domain_dn, $attributes); + + if (!empty($result)) { + $result['dn'] = $domain_dn; + } + else { + $result = false; + } + } + else if ($domain_base_dn = $this->config_get('domain_base_dn')) { + $domain_filter = $this->config_get('domain_filter'); + + if (strpos($domain_filter, '%s') !== false) { + $domain_filter = str_replace('%s', self::quote_string($domain), $domain_filter); + } + else { + $name_attribute = $this->config_get('domain_name_attribute'); + if (empty($name_attribute)) { + $name_attribute = 'associateddomain'; + } + + $domain_filter = "(&" . $domain_filter . "(" . $name_attribute . "=" . self::quote_string($domain) . "))"; + } + + if ($result = $this->search($domain_base_dn, $domain_filter, 'sub', $attributes)) { + $result = $result->entries(true); + $domain_dn = key($result); + + if (empty($domain_dn)) { + $result = false; + } + else { + $result = $result[$domain_dn]; + $result['dn'] = $domain_dn; + + // cache domain DN + $this->set_cache_data($ckey, $domain_dn); + } + } + } + + $this->_debug("Net_LDAP3::find_domain() result: " . var_export($result, true)); + + return $this->icache[$ickey] = $result; + } + + /** + * From a domain name, such as 'kanarip.com', create a standard root + * dn, such as 'dc=kanarip,dc=com'. + * + * As the parameter $associatedDomains, either pass it an array (such + * as may have been returned by ldap_get_entries() or perhaps + * ldap_list()), where the function will assume the first value + * ($array[0]) to be the uber-level domain name, or pass it a string + * such as 'kanarip.nl'. + * + * @return string + */ + protected function _standard_root_dn($associatedDomains) + { + if (is_array($associatedDomains)) { + // Usually, the associatedDomain in position 0 is the naming attribute associatedDomain + if ($associatedDomains['count'] > 1) { + // Issue a debug message here + $relevant_associatedDomain = $associatedDomains[0]; + } + else { + $relevant_associatedDomain = $associatedDomains[0]; + } + } + else { + $relevant_associatedDomain = $associatedDomains; + } + + return 'dc=' . implode(',dc=', explode('.', $relevant_associatedDomain)); + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/kolab/net_ldap3/lib/Net/LDAP3/Result.php
Added
@@ -0,0 +1,179 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | Net/LDAP3/Result.php | + | | + | Based on code created by the Roundcube Webmail team. | + | | + | Copyright (C) 2006-2014, The Roundcube Dev Team | + | Copyright (C) 2012-2014, Kolab Systems AG | + | | + | This program is free software: you can redistribute it and/or modify | + | it under the terms of the GNU General Public License as published by | + | the Free Software Foundation, either version 3 of the License, or | + | (at your option) any later version. | + | | + | This program 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 General Public License for more details. | + | | + | You should have received a copy of the GNU General Public License | + | along with this program. If not, see <http://www.gnu.org/licenses/>. | + | | + | PURPOSE: | + | Provide advanced functionality for accessing LDAP directories | + | | + +-----------------------------------------------------------------------+ + | Authors: Thomas Bruederli <roundcube@gmail.com> | + | Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> | + +-----------------------------------------------------------------------+ +*/ + +/** + * Model class representing an LDAP search result + * + * @package LDAP + */ +class Net_LDAP3_Result implements Iterator +{ + protected $conn; + protected $base_dn; + protected $filter; + protected $scope; + protected $result; + + private $count; + private $current; + private $iteratorkey = 0; + + /** + * Default constructor + * + * @param resource $conn LDAP link identifier + * @param string $base_dn Base DN used to get this result + * @param string $filter Filter query used to get this result + * @param string $scope Scope of the result + * @param resource $result LDAP result entry identifier + */ + function __construct($conn, $base_dn, $filter, $scope, $result) + { + $this->conn = $conn; + $this->base_dn = $base_dn; + $this->filter = $filter; + $this->scope = $scope; + $this->result = $result; + } + + /** + * Property value getter + * + * @param string $property Property name + * @param mixed $default Return value if proprty is not set + * + * @return mixed Property value + */ + public function get($property, $default = null) + { + return isset($this->$property) ? $this->$property : $default; + } + + /** + * Property value setter + * + * @param string $property Property name + * @param mixed $value Property value + */ + public function set($property, $value) + { + $this->$property = $value; + } + + /** + * Wrapper for ldap_sort() + * + * @param string $attr The attribute to use as a key in the sort + * + * @return bool True on success, False on failure + */ + public function sort($attr) + { + // @TODO: Don't use ldap_sort() it's deprecated since PHP7 + // and will be removed in future + return @ldap_sort($this->conn, $this->result, $attr); + } + + /** + * Get entries count + * + * @return int Number of entries in the result + */ + public function count() + { + if (!isset($this->count)) { + $this->count = ldap_count_entries($this->conn, $this->result); + } + + return $this->count; + } + + /** + * Wrapper for ldap_get_entries() + * + * @param bool $normalize Optionally normalize the entries to a list of hash arrays + * + * @return array List of LDAP entries + */ + public function entries($normalize = false) + { + $entries = ldap_get_entries($this->conn, $this->result); + + if ($normalize) { + return Net_LDAP3::normalize_result($entries); + } + + return $entries; + } + + /** + * Wrapper for ldap_get_dn() using the current entry pointer + */ + public function get_dn() + { + return $this->current ? ldap_get_dn($this->conn, $this->current) : null; + } + + + /*** Implement PHP 5 Iterator interface to make foreach work ***/ + + function current() + { + $attrib = ldap_get_attributes($this->conn, $this->current); + $attrib['dn'] = ldap_get_dn($this->conn, $this->current); + + return $attrib; + } + + function key() + { + return $this->iteratorkey; + } + + function rewind() + { + $this->iteratorkey = 0; + $this->current = ldap_first_entry($this->conn, $this->result); + } + + function next() + { + $this->iteratorkey++; + $this->current = ldap_next_entry($this->conn, $this->current); + } + + function valid() + { + return (bool)$this->current; + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/.gitignore
Added
@@ -0,0 +1,2 @@ +/tests/ldapconfig.ini +/dist
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/.travis.yml
Added
@@ -0,0 +1,25 @@ +language: php +sudo: false +php: + - 7 + - 5.6 + - 5.5 + - 5.4 +addons: + apt: + packages: + - ldap-utils + - slapd +before_script: + - phpenv config-add tests/travis/enable-ldap.ini + - pear upgrade pear-1.10.1 + - cat tests/ldapconfig.ini.dist | sed s/389/3389/ > tests/ldapconfig.ini + - mkdir /tmp/slapd + - slapd -f tests/ldif_data/slapd.conf -h ldap://localhost:3389 & + - sleep 3 + - ldapadd -h localhost:3389 -D cn=admin,dc=example,dc=com -w test -f tests/ldif_data/base.ldif + - ldapadd -h localhost:3389 -D cn=admin,dc=example,dc=com -w test -f tests/ldif_data/INITIAL_TESTDATA.ldif + +script: + - cd tests + - phpunit .
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/LICENSE
Added
@@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. \ No newline at end of file
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/Net
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/Net/LDAP2
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/Net/LDAP2.php
Added
@@ -0,0 +1,1802 @@ +<?php +/* vim: set expandtab tabstop=4 shiftwidth=4: */ +/** +* File containing the Net_LDAP2 interface class. +* +* PHP version 5 +* +* @category Net +* @package Net_LDAP2 +* @author Tarjej Huse <tarjei@bergfald.no> +* @author Jan Wagner <wagner@netsols.de> +* @author Del <del@babel.com.au> +* @author Benedikt Hallinger <beni@php.net> +* @copyright 2003-2007 Tarjej Huse, Jan Wagner, Del Elson, Benedikt Hallinger +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id$ +* @link http://pear.php.net/package/Net_LDAP2/ +*/ + +/** +* Package includes. +*/ +require_once 'PEAR.php'; +require_once 'Net/LDAP2/RootDSE.php'; +require_once 'Net/LDAP2/Schema.php'; +require_once 'Net/LDAP2/Entry.php'; +require_once 'Net/LDAP2/Search.php'; +require_once 'Net/LDAP2/Util.php'; +require_once 'Net/LDAP2/Filter.php'; +require_once 'Net/LDAP2/LDIF.php'; +require_once 'Net/LDAP2/SchemaCache.interface.php'; +require_once 'Net/LDAP2/SimpleFileSchemaCache.php'; + +/** +* Error constants for errors that are not LDAP errors. +*/ +define('NET_LDAP2_ERROR', 1000); + +/** +* Net_LDAP2 Version +*/ +define('NET_LDAP2_VERSION', '2.1.0'); + +/** +* Net_LDAP2 - manipulate LDAP servers the right way! +* +* @category Net +* @package Net_LDAP2 +* @author Tarjej Huse <tarjei@bergfald.no> +* @author Jan Wagner <wagner@netsols.de> +* @author Del <del@babel.com.au> +* @author Benedikt Hallinger <beni@php.net> +* @copyright 2003-2007 Tarjej Huse, Jan Wagner, Del Elson, Benedikt Hallinger +* @license http://www.gnu.org/copyleft/lesser.html LGPL +* @link http://pear.php.net/package/Net_LDAP2/ +*/ +class Net_LDAP2 extends PEAR +{ + /** + * Class configuration array + * + * host = the ldap host to connect to + * (may be an array of several hosts to try) + * port = the server port + * version = ldap version (defaults to v 3) + * starttls = when set, ldap_start_tls() is run after connecting. + * bindpw = no explanation needed + * binddn = the DN to bind as. + * basedn = ldap base + * options = hash of ldap options to set (opt => val) + * filter = default search filter + * scope = default search scope + * + * Newly added in 2.0.0RC4, for auto-reconnect: + * auto_reconnect = if set to true then the class will automatically + * attempt to reconnect to the LDAP server in certain + * failure conditionswhen attempting a search, or other + * LDAP operation. Defaults to false. Note that if you + * set this to true, calls to search() may block + * indefinitely if there is a catastrophic server failure. + * min_backoff = minimum reconnection delay period (in seconds). + * current_backoff = initial reconnection delay period (in seconds). + * max_backoff = maximum reconnection delay period (in seconds). + * + * @access protected + * @var array + */ + protected $_config = array('host' => 'localhost', + 'port' => 389, + 'version' => 3, + 'starttls' => false, + 'binddn' => '', + 'bindpw' => '', + 'basedn' => '', + 'options' => array(), + 'filter' => '(objectClass=*)', + 'scope' => 'sub', + 'auto_reconnect' => false, + 'min_backoff' => 1, + 'current_backoff' => 1, + 'max_backoff' => 32); + + /** + * List of hosts we try to establish a connection to + * + * @access protected + * @var array + */ + protected $_host_list = array(); + + /** + * List of hosts that are known to be down. + * + * @access protected + * @var array + */ + protected $_down_host_list = array(); + + /** + * LDAP resource link. + * + * @access protected + * @var resource + */ + protected $_link = false; + + /** + * Net_LDAP2_Schema object + * + * This gets set and returned by {@link schema()} + * + * @access protected + * @var object Net_LDAP2_Schema + */ + protected $_schema = null; + + /** + * Schema cacher function callback + * + * @see registerSchemaCache() + * @var string + */ + protected $_schema_cache = null; + + /** + * Cache for attribute encoding checks + * + * @access protected + * @var array Hash with attribute names as key and boolean value + * to determine whether they should be utf8 encoded or not. + */ + protected $_schemaAttrs = array(); + + /** + * Cache for rootDSE objects + * + * Hash with requested rootDSE attr names as key and rootDSE object as value + * + * Since the RootDSE object itself may request a rootDSE object, + * {@link rootDse()} caches successful requests. + * Internally, Net_LDAP2 needs several lookups to this object, so + * caching increases performance significally. + * + * @access protected + * @var array + */ + protected $_rootDSE_cache = array(); + + /** + * Returns the Net_LDAP2 Release version, may be called statically + * + * @static + * @return string Net_LDAP2 version + */ + public static function getVersion() + { + return NET_LDAP2_VERSION; + } + + /** + * Configure Net_LDAP2, connect and bind + * + * Use this method as starting point of using Net_LDAP2 + * to establish a connection to your LDAP server. + * + * Static function that returns either an error object or the new Net_LDAP2 + * object. Something like a factory. Takes a config array with the needed + * parameters. + * + * @param array $config Configuration array + * + * @access public + * @return Net_LDAP2_Error|Net_LDAP2 Net_LDAP2_Error or Net_LDAP2 object + */ + public static function connect($config = array()) + { + $ldap_check = self::checkLDAPExtension(); + if (self::iserror($ldap_check)) { + return $ldap_check; + } + + @$obj = new Net_LDAP2($config); + + // todo? better errorhandling for setConfig()? + + // connect and bind with credentials in config + $err = $obj->bind(); + if (self::isError($err)) { + return $err; + } + + return $obj; + } + + /** + * Net_LDAP2 constructor + * + * Sets the config array + * + * Please note that the usual way of getting Net_LDAP2 to work is + * to call something like: + * <code>$ldap = Net_LDAP2::connect($ldap_config);</code> + * + * @param array $config Configuration array + * + * @access protected + * @return void + * @see $_config + */ + public function __construct($config = array()) + { + parent::__construct('Net_LDAP2_Error'); + $this->setConfig($config); + } + + /** + * Sets the internal configuration array + * + * @param array $config Configuration array + * + * @access protected + * @return void + */ + protected function setConfig($config) + { + // + // Parameter check -- probably should raise an error here if config + // is not an array. + // + if (! is_array($config)) { + return; + } + + foreach ($config as $k => $v) { + if (isset($this->_config[$k])) { + $this->_config[$k] = $v; + } else { + // map old (Net_LDAP2) parms to new ones + switch($k) { + case "dn": + $this->_config["binddn"] = $v; + break; + case "password": + $this->_config["bindpw"] = $v; + break; + case "tls": + $this->_config["starttls"] = $v; + break; + case "base": + $this->_config["basedn"] = $v; + break; + } + } + } + + // + // Ensure the host list is an array. + // + if (is_array($this->_config['host'])) { + $this->_host_list = $this->_config['host']; + } else { + if (strlen($this->_config['host']) > 0) { + $this->_host_list = array($this->_config['host']); + } else { + $this->_host_list = array(); + // ^ this will cause an error in performConnect(), + // so the user is notified about the failure + } + } + + // + // Reset the down host list, which seems like a sensible thing to do + // if the config is being reset for some reason. + // + $this->_down_host_list = array(); + } + + /** + * Bind or rebind to the ldap-server + * + * This function binds with the given dn and password to the server. In case + * no connection has been made yet, it will be started and startTLS issued + * if appropiate. + * + * The internal bind configuration is not being updated, so if you call + * bind() without parameters, you can rebind with the credentials + * provided at first connecting to the server. + * + * @param string $dn Distinguished name for binding + * @param string $password Password for binding + * + * @access public + * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true + */ + public function bind($dn = null, $password = null) + { + // fetch current bind credentials + if (is_null($dn)) { + $dn = $this->_config["binddn"]; + } + if (is_null($password)) { + $password = $this->_config["bindpw"]; + } + + // Connect first, if we haven't so far. + // This will also bind us to the server. + if ($this->_link === false) { + // store old credentials so we can revert them later + // then overwrite config with new bind credentials + $olddn = $this->_config["binddn"]; + $oldpw = $this->_config["bindpw"]; + + // overwrite bind credentials in config + // so performConnect() knows about them + $this->_config["binddn"] = $dn; + $this->_config["bindpw"] = $password; + + // try to connect with provided credentials + $msg = $this->performConnect(); + + // reset to previous config + $this->_config["binddn"] = $olddn; + $this->_config["bindpw"] = $oldpw; + + // see if bind worked + if (self::isError($msg)) { + return $msg; + } + } else { + // do the requested bind as we are + // asked to bind manually + if (is_null($dn)) { + // anonymous bind + $msg = @ldap_bind($this->_link); + } else { + // privileged bind + $msg = @ldap_bind($this->_link, $dn, $password); + } + if (false === $msg) { + return PEAR::raiseError("Bind failed: " . + @ldap_error($this->_link), + @ldap_errno($this->_link)); + } + } + return true; + } + + /** + * Connect to the ldap-server + * + * This function connects to the LDAP server specified in + * the configuration, binds and set up the LDAP protocol as needed. + * + * @access protected + * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true + */ + protected function performConnect() + { + // Note: Connecting is briefly described in RFC1777. + // Basicly it works like this: + // 1. set up TCP connection + // 2. secure that connection if neccessary + // 3a. setLDAPVersion to tell server which version we want to speak + // 3b. perform bind + // 3c. setLDAPVersion to tell server which version we want to speak + // together with a test for supported versions + // 4. set additional protocol options + + // Return true if we are already connected. + if ($this->_link !== false) { + return true; + } + + // Connnect to the LDAP server if we are not connected. Note that + // with some LDAP clients, ldapperformConnect returns a link value even + // if no connection is made. We need to do at least one anonymous + // bind to ensure that a connection is actually valid. + // + // Ref: http://www.php.net/manual/en/function.ldap-connect.php + + // Default error message in case all connection attempts + // fail but no message is set + $current_error = new PEAR_Error('Unknown connection error'); + + // Catch empty $_host_list arrays. + if (!is_array($this->_host_list) || count($this->_host_list) == 0) { + $current_error = PEAR::raiseError('No Servers configured! Please '. + 'pass in an array of servers to Net_LDAP2'); + return $current_error; + } + + // Cycle through the host list. + foreach ($this->_host_list as $host) { + + // Ensure we have a valid string for host name + if (is_array($host)) { + $current_error = PEAR::raiseError('No Servers configured! '. + 'Please pass in an one dimensional array of servers to '. + 'Net_LDAP2! (multidimensional array detected!)'); + continue; + } + + // Skip this host if it is known to be down. + if (in_array($host, $this->_down_host_list)) { + continue; + } + + // Record the host that we are actually connecting to in case + // we need it later. + $this->_config['host'] = $host; + + // Attempt a connection. + $this->_link = @ldap_connect($host, $this->_config['port']); + if (false === $this->_link) { + $current_error = PEAR::raiseError('Could not connect to ' . + $host . ':' . $this->_config['port']); + $this->_down_host_list[] = $host; + continue; + } + + // If we're supposed to use TLS, do so before we try to bind, + // as some strict servers only allow binding via secure connections + if ($this->_config["starttls"] === true) { + if (self::isError($msg = $this->startTLS())) { + $current_error = $msg; + $this->_link = false; + $this->_down_host_list[] = $host; + continue; + } + } + + // Try to set the configured LDAP version on the connection if LDAP + // server needs that before binding (eg OpenLDAP). + // This could be necessary since rfc-1777 states that the protocol version + // has to be set at the bind request. + // We use force here which means that the test in the rootDSE is skipped; + // this is neccessary, because some strict LDAP servers only allow to + // read the LDAP rootDSE (which tells us the supported protocol versions) + // with authenticated clients. + // This may fail in which case we try again after binding. + // In this case, most probably the bind() or setLDAPVersion()-call + // below will also fail, providing error messages. + $version_set = false; + $ignored_err = $this->setLDAPVersion(0, true); + if (!self::isError($ignored_err)) { + $version_set = true; + } + + // Attempt to bind to the server. If we have credentials configured, + // we try to use them, otherwise its an anonymous bind. + // As stated by RFC-1777, the bind request should be the first + // operation to be performed after the connection is established. + // This may give an protocol error if the server does not support + // V2 binds and the above call to setLDAPVersion() failed. + // In case the above call failed, we try an V2 bind here and set the + // version afterwards (with checking to the rootDSE). + $msg = $this->bind(); + if (self::isError($msg)) { + // The bind failed, discard link and save error msg. + // Then record the host as down and try next one + if ($msg->getCode() == 0x02 && !$version_set) { + // provide a finer grained error message + // if protocol error arieses because of invalid version + $msg = new Net_LDAP2_Error($msg->getMessage(). + " (could not set LDAP protocol version to ". + $this->_config['version'].")", + $msg->getCode()); + } + $this->_link = false; + $current_error = $msg; + $this->_down_host_list[] = $host; + continue; + } + + // Set desired LDAP version if not successfully set before. + // Here, a check against the rootDSE is performed, so we get a + // error message if the server does not support the version. + // The rootDSE entry should tell us which LDAP versions are + // supported. However, some strict LDAP servers only allow + // bound suers to read the rootDSE. + if (!$version_set) { + if (self::isError($msg = $this->setLDAPVersion())) { + $current_error = $msg; + $this->_link = false; + $this->_down_host_list[] = $host; + continue; + } + } + + // Set LDAP parameters, now we know we have a valid connection. + if (isset($this->_config['options']) && + is_array($this->_config['options']) && + count($this->_config['options'])) { + foreach ($this->_config['options'] as $opt => $val) { + $err = $this->setOption($opt, $val); + if (self::isError($err)) { + $current_error = $err; + $this->_link = false; + $this->_down_host_list[] = $host; + continue 2; + } + } + } + + // At this stage we have connected, bound, and set up options, + // so we have a known good LDAP server. Time to go home. + return true; + } + + + // All connection attempts have failed, return the last error. + return $current_error; + } + + /** + * Reconnect to the ldap-server. + * + * In case the connection to the LDAP + * service has dropped out for some reason, this function will reconnect, + * and re-bind if a bind has been attempted in the past. It is probably + * most useful when the server list provided to the new() or connect() + * function is an array rather than a single host name, because in that + * case it will be able to connect to a failover or secondary server in + * case the primary server goes down. + * + * This doesn't return anything, it just tries to re-establish + * the current connection. It will sleep for the current backoff + * period (seconds) before attempting the connect, and if the + * connection fails it will double the backoff period, but not + * try again. If you want to ensure a reconnection during a + * transient period of server downtime then you need to call this + * function in a loop. + * + * @access protected + * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true + */ + protected function performReconnect() + { + + // Return true if we are already connected. + if ($this->_link !== false) { + return true; + } + + // Default error message in case all connection attempts + // fail but no message is set + $current_error = new PEAR_Error('Unknown connection error'); + + // Sleep for a backoff period in seconds. + sleep($this->_config['current_backoff']); + + // Retry all available connections. + $this->_down_host_list = array(); + $msg = $this->performConnect(); + + // Bail out if that fails. + if (self::isError($msg)) { + $this->_config['current_backoff'] = + $this->_config['current_backoff'] * 2; + if ($this->_config['current_backoff'] > $this->_config['max_backoff']) { + $this->_config['current_backoff'] = $this->_config['max_backoff']; + } + return $msg; + } + + // Now we should be able to safely (re-)bind. + $msg = $this->bind(); + if (self::isError($msg)) { + $this->_config['current_backoff'] = $this->_config['current_backoff'] * 2; + if ($this->_config['current_backoff'] > $this->_config['max_backoff']) { + $this->_config['current_backoff'] = $this->_config['max_backoff']; + } + + // _config['host'] should have had the last connected host stored in it + // by performConnect(). Since we are unable to bind to that host we can safely + // assume that it is down or has some other problem. + $this->_down_host_list[] = $this->_config['host']; + return $msg; + } + + // At this stage we have connected, bound, and set up options, + // so we have a known good LDAP server. Time to go home. + $this->_config['current_backoff'] = $this->_config['min_backoff']; + return true; + } + + /** + * Starts an encrypted session + * + * @access public + * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true + */ + public function startTLS() + { + /* Test to see if the server supports TLS first. + This is done via testing the extensions offered by the server. + The OID 1.3.6.1.4.1.1466.20037 tells us, if TLS is supported. + Note, that not all servers allow to feth either the rootDSE or + attributes over an unencrypted channel, so we must ignore errors. */ + $rootDSE = $this->rootDse(); + if (self::isError($rootDSE)) { + /* IGNORE this error, because server may refuse fetching the + RootDSE over an unencrypted connection. */ + //return $this->raiseError("Unable to fetch rootDSE entry ". + //"to see if TLS is supoported: ".$rootDSE->getMessage(), $rootDSE->getCode()); + } else { + /* Fetch suceeded, see, if the server supports TLS. Again, we + ignore errors, because the server may refuse to return + attributes over unencryted connections. */ + $supported_extensions = $rootDSE->getValue('supportedExtension'); + if (self::isError($supported_extensions)) { + /* IGNORE error, because server may refuse attribute + returning over an unencrypted connection. */ + //return $this->raiseError("Unable to fetch rootDSE attribute 'supportedExtension' ". + //"to see if TLS is supoported: ".$supported_extensions->getMessage(), $supported_extensions->getCode()); + } else { + // fetch succeedet, lets see if the server supports it. + // if not, then drop an error. If supported, then do nothing, + // because then we try to issue TLS afterwards. + if (!in_array('1.3.6.1.4.1.1466.20037', $supported_extensions)) { + return $this->raiseError("Server reports that it does not support TLS."); + } + } + } + + // Try to establish TLS. + if (false === @ldap_start_tls($this->_link)) { + // Starting TLS failed. This may be an error, or because + // the server does not support it but did not enable us to + // detect that above. + return $this->raiseError("TLS could not be started: " . + @ldap_error($this->_link), + @ldap_errno($this->_link)); + } else { + return true; // TLS is started now. + } + } + + /** + * alias function of startTLS() for perl-ldap interface + * + * @return void + * @see startTLS() + */ + public function start_tls() + { + $args = func_get_args(); + return call_user_func_array(array( $this, 'startTLS' ), $args); + } + + /** + * Close LDAP connection. + * + * Closes the connection. Use this when the session is over. + * + * @return void + */ + public function done() + { + $this->_Net_LDAP2(); + } + + /** + * Alias for {@link done()} + * + * @return void + * @see done() + */ + public function disconnect() + { + $this->done(); + } + + /** + * Destructor + * + * @access protected + */ + public function _Net_LDAP2() + { + @ldap_close($this->_link); + } + + /** + * Add a new entryobject to a directory. + * + * Use add to add a new Net_LDAP2_Entry object to the directory. + * This also links the entry to the connection used for the add, + * if it was a fresh entry ({@link Net_LDAP2_Entry::createFresh()}) + * + * @param Net_LDAP2_Entry $entry Net_LDAP2_Entry + * + * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true + */ + public function add($entry) + { + if (!$entry instanceof Net_LDAP2_Entry) { + return PEAR::raiseError('Parameter to Net_LDAP2::add() must be a Net_LDAP2_Entry object.'); + } + + // Continue attempting the add operation in a loop until we + // get a success, a definitive failure, or the world ends. + $foo = 0; + while (true) { + $link = $this->getLink(); + + if ($link === false) { + // We do not have a successful connection yet. The call to + // getLink() would have kept trying if we wanted one. Go + // home now. + return PEAR::raiseError("Could not add entry " . $entry->dn() . + " no valid LDAP connection could be found."); + } + + if (@ldap_add($link, $entry->dn(), $entry->getValues())) { + // entry successfully added, we should update its $ldap reference + // in case it is not set so far (fresh entry) + if (!$entry->getLDAP() instanceof Net_LDAP2) { + $entry->setLDAP($this); + } + // store, that the entry is present inside the directory + $entry->markAsNew(false); + return true; + } else { + // We have a failure. What type? We may be able to reconnect + // and try again. + $error_code = @ldap_errno($link); + $error_name = Net_LDAP2::errorMessage($error_code); + + if (($error_name === 'LDAP_OPERATIONS_ERROR') && + ($this->_config['auto_reconnect'])) { + + // The server has become disconnected before trying the + // operation. We should try again, possibly with a different + // server. + $this->_link = false; + $this->performReconnect(); + } else { + // Errors other than the above catched are just passed + // back to the user so he may react upon them. + return PEAR::raiseError("Could not add entry " . $entry->dn() . " " . + $error_name, + $error_code); + } + } + } + } + + /** + * Delete an entry from the directory + * + * The object may either be a string representing the dn or a Net_LDAP2_Entry + * object. When the boolean paramter recursive is set, all subentries of the + * entry will be deleted as well. + * + * @param string|Net_LDAP2_Entry $dn DN-string or Net_LDAP2_Entry + * @param boolean $recursive Should we delete all children recursive as well? + * + * @access public + * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true + */ + public function delete($dn, $recursive = false) + { + if ($dn instanceof Net_LDAP2_Entry) { + $dn = $dn->dn(); + } + if (false === is_string($dn)) { + return PEAR::raiseError("Parameter is not a string nor an entry object!"); + } + // Recursive delete searches for children and calls delete for them + if ($recursive) { + $result = @ldap_list($this->_link, $dn, '(objectClass=*)', array(null), 0, 0); + if (@ldap_count_entries($this->_link, $result)) { + $subentry = @ldap_first_entry($this->_link, $result); + $this->delete(@ldap_get_dn($this->_link, $subentry), true); + while ($subentry = @ldap_next_entry($this->_link, $subentry)) { + $this->delete(@ldap_get_dn($this->_link, $subentry), true); + } + } + } + + // Continue attempting the delete operation in a loop until we + // get a success, a definitive failure, or the world ends. + while (true) { + $link = $this->getLink(); + + if ($link === false) { + // We do not have a successful connection yet. The call to + // getLink() would have kept trying if we wanted one. Go + // home now. + return PEAR::raiseError("Could not add entry " . $dn . + " no valid LDAP connection could be found."); + } + + if (@ldap_delete($link, $dn)) { + // entry successfully deleted. + return true; + } else { + // We have a failure. What type? + // We may be able to reconnect and try again. + $error_code = @ldap_errno($link); + $error_name = Net_LDAP2::errorMessage($error_code); + + if ((Net_LDAP2::errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') && + ($this->_config['auto_reconnect'])) { + // The server has become disconnected before trying the + // operation. We should try again, possibly with a + // different server. + $this->_link = false; + $this->performReconnect(); + + } elseif ($error_code == 66) { + // Subentries present, server refused to delete. + // Deleting subentries is the clients responsibility, but + // since the user may not know of the subentries, we do not + // force that here but instead notify the developer so he + // may take actions himself. + return PEAR::raiseError("Could not delete entry $dn because of subentries. Use the recursive parameter to delete them."); + + } else { + // Errors other than the above catched are just passed + // back to the user so he may react upon them. + return PEAR::raiseError("Could not delete entry " . $dn . " " . + $error_name, + $error_code); + } + } + } + } + + /** + * Modify an ldapentry directly on the server + * + * This one takes the DN or a Net_LDAP2_Entry object and an array of actions. + * This array should be something like this: + * + * array('add' => array('attribute1' => array('val1', 'val2'), + * 'attribute2' => array('val1')), + * 'delete' => array('attribute1'), + * 'replace' => array('attribute1' => array('val1')), + * 'changes' => array('add' => ..., + * 'replace' => ..., + * 'delete' => array('attribute1', 'attribute2' => array('val1'))) + * + * The changes array is there so the order of operations can be influenced + * (the operations are done in order of appearance). + * The order of execution is as following: + * 1. adds from 'add' array + * 2. deletes from 'delete' array + * 3. replaces from 'replace' array + * 4. changes (add, replace, delete) in order of appearance + * All subarrays (add, replace, delete, changes) may be given at the same time. + * + * The function calls the corresponding functions of an Net_LDAP2_Entry + * object. A detailed description of array structures can be found there. + * + * Unlike the modification methods provided by the Net_LDAP2_Entry object, + * this method will instantly carry out an update() after each operation, + * thus modifying "directly" on the server. + * + * @param string|Net_LDAP2_Entry $entry DN-string or Net_LDAP2_Entry + * @param array $parms Array of changes + * + * @access public + * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true + */ + public function modify($entry, $parms = array()) + { + if (is_string($entry)) { + $entry = $this->getEntry($entry); + if (self::isError($entry)) { + return $entry; + } + } + if (!$entry instanceof Net_LDAP2_Entry) { + return PEAR::raiseError("Parameter is not a string nor an entry object!"); + } + + // Perform changes mentioned separately + foreach (array('add', 'delete', 'replace') as $action) { + if (isset($parms[$action])) { + $msg = $entry->$action($parms[$action]); + if (self::isError($msg)) { + return $msg; + } + $entry->setLDAP($this); + + // Because the @ldap functions are called inside Net_LDAP2_Entry::update(), + // we have to trap the error codes issued from that if we want to support + // reconnection. + while (true) { + $msg = $entry->update(); + + if (self::isError($msg)) { + // We have a failure. What type? We may be able to reconnect + // and try again. + $error_code = $msg->getCode(); + $error_name = Net_LDAP2::errorMessage($error_code); + + if ((Net_LDAP2::errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') && + ($this->_config['auto_reconnect'])) { + + // The server has become disconnected before trying the + // operation. We should try again, possibly with a different + // server. + $this->_link = false; + $this->performReconnect(); + + } else { + + // Errors other than the above catched are just passed + // back to the user so he may react upon them. + return PEAR::raiseError("Could not modify entry: ".$msg->getMessage()); + } + } else { + // modification succeedet, evaluate next change + break; + } + } + } + } + + // perform combined changes in 'changes' array + if (isset($parms['changes']) && is_array($parms['changes'])) { + foreach ($parms['changes'] as $action => $value) { + + // Because the @ldap functions are called inside Net_LDAP2_Entry::update, + // we have to trap the error codes issued from that if we want to support + // reconnection. + while (true) { + $msg = $this->modify($entry, array($action => $value)); + + if (self::isError($msg)) { + // We have a failure. What type? We may be able to reconnect + // and try again. + $error_code = $msg->getCode(); + $error_name = Net_LDAP2::errorMessage($error_code); + + if ((Net_LDAP2::errorMessage($error_code) === 'LDAP_OPERATIONS_ERROR') && + ($this->_config['auto_reconnect'])) { + + // The server has become disconnected before trying the + // operation. We should try again, possibly with a different + // server. + $this->_link = false; + $this->performReconnect(); + + } else { + // Errors other than the above catched are just passed + // back to the user so he may react upon them. + return $msg; + } + } else { + // modification succeedet, evaluate next change + break; + } + } + } + } + + return true; + } + + /** + * Run a ldap search query + * + * Search is used to query the ldap-database. + * $base and $filter may be ommitted. The one from config will + * then be used. $base is either a DN-string or an Net_LDAP2_Entry + * object in which case its DN willb e used. + * + * Params may contain: + * + * scope: The scope which will be used for searching + * base - Just one entry + * sub - The whole tree + * one - Immediately below $base + * sizelimit: Limit the number of entries returned (default: 0 = unlimited), + * timelimit: Limit the time spent for searching (default: 0 = unlimited), + * attrsonly: If true, the search will only return the attribute names, + * attributes: Array of attribute names, which the entry should contain. + * It is good practice to limit this to just the ones you need. + * [NOT IMPLEMENTED] + * deref: By default aliases are dereferenced to locate the base object for the search, but not when + * searching subordinates of the base object. This may be changed by specifying one of the + * following values: + * + * never - Do not dereference aliases in searching or in locating the base object of the search. + * search - Dereference aliases in subordinates of the base object in searching, but not in + * locating the base object of the search. + * find + * always + * + * Please note, that you cannot override server side limitations to sizelimit + * and timelimit: You can always only lower a given limit. + * + * @param string|Net_LDAP2_Entry $base LDAP searchbase + * @param string|Net_LDAP2_Filter $filter LDAP search filter or a Net_LDAP2_Filter object + * @param array $params Array of options + * + * @access public + * @return Net_LDAP2_Search|Net_LDAP2_Error Net_LDAP2_Search object or Net_LDAP2_Error object + * @todo implement search controls (sorting etc) + */ + public function search($base = null, $filter = null, $params = array()) + { + if (is_null($base)) { + $base = $this->_config['basedn']; + } + if ($base instanceof Net_LDAP2_Entry) { + $base = $base->dn(); // fetch DN of entry, making searchbase relative to the entry + } + if (is_null($filter)) { + $filter = $this->_config['filter']; + } + if ($filter instanceof Net_LDAP2_Filter) { + $filter = $filter->asString(); // convert Net_LDAP2_Filter to string representation + } + if (PEAR::isError($filter)) { + return $filter; + } + if (PEAR::isError($base)) { + return $base; + } + + /* setting searchparameters */ + (isset($params['sizelimit'])) ? $sizelimit = $params['sizelimit'] : $sizelimit = 0; + (isset($params['timelimit'])) ? $timelimit = $params['timelimit'] : $timelimit = 0; + (isset($params['attrsonly'])) ? $attrsonly = $params['attrsonly'] : $attrsonly = 0; + (isset($params['attributes'])) ? $attributes = $params['attributes'] : $attributes = array(); + + // Ensure $attributes to be an array in case only one + // attribute name was given as string + if (!is_array($attributes)) { + $attributes = array($attributes); + } + + // reorganize the $attributes array index keys + // sometimes there are problems with not consecutive indexes + $attributes = array_values($attributes); + + // scoping makes searches faster! + $scope = (isset($params['scope']) ? $params['scope'] : $this->_config['scope']); + + switch ($scope) { + case 'one': + $search_function = 'ldap_list'; + break; + case 'base': + $search_function = 'ldap_read'; + break; + default: + $search_function = 'ldap_search'; + } + + // Continue attempting the search operation until we get a success + // or a definitive failure. + while (true) { + $link = $this->getLink(); + $search = @call_user_func($search_function, + $link, + $base, + $filter, + $attributes, + $attrsonly, + $sizelimit, + $timelimit); + + if ($err = @ldap_errno($link)) { + if ($err == 32) { + // Errorcode 32 = no such object, i.e. a nullresult. + return $obj = new Net_LDAP2_Search ($search, $this, $attributes); + } elseif ($err == 4) { + // Errorcode 4 = sizelimit exeeded. + return $obj = new Net_LDAP2_Search ($search, $this, $attributes); + } elseif ($err == 87) { + // bad search filter + return $this->raiseError(Net_LDAP2::errorMessage($err) . "($filter)", $err); + } elseif (($err == 1) && ($this->_config['auto_reconnect'])) { + // Errorcode 1 = LDAP_OPERATIONS_ERROR but we can try a reconnect. + $this->_link = false; + $this->performReconnect(); + } else { + $msg = "\nParameters:\nBase: $base\nFilter: $filter\nScope: $scope"; + return $this->raiseError(Net_LDAP2::errorMessage($err) . $msg, $err); + } + } else { + return $obj = new Net_LDAP2_Search($search, $this, $attributes); + } + } + } + + /** + * Set an LDAP option + * + * @param string $option Option to set + * @param mixed $value Value to set Option to + * + * @access public + * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true + */ + public function setOption($option, $value) + { + if ($this->_link) { + if (defined($option)) { + if (@ldap_set_option($this->_link, constant($option), $value)) { + return true; + } else { + $err = @ldap_errno($this->_link); + if ($err) { + $msg = @ldap_err2str($err); + } else { + $err = NET_LDAP2_ERROR; + $msg = Net_LDAP2::errorMessage($err); + } + return $this->raiseError($msg, $err); + } + } else { + return $this->raiseError("Unkown Option requested"); + } + } else { + return $this->raiseError("Could not set LDAP option: No LDAP connection"); + } + } + + /** + * Get an LDAP option value + * + * @param string $option Option to get + * + * @access public + * @return Net_LDAP2_Error|string Net_LDAP2_Error or option value + */ + public function getOption($option) + { + if ($this->_link) { + if (defined($option)) { + if (@ldap_get_option($this->_link, constant($option), $value)) { + return $value; + } else { + $err = @ldap_errno($this->_link); + if ($err) { + $msg = @ldap_err2str($err); + } else { + $err = NET_LDAP2_ERROR; + $msg = Net_LDAP2::errorMessage($err); + } + return $this->raiseError($msg, $err); + } + } else { + $this->raiseError("Unkown Option requested"); + } + } else { + $this->raiseError("No LDAP connection"); + } + } + + /** + * Get the LDAP_PROTOCOL_VERSION that is used on the connection. + * + * A lot of ldap functionality is defined by what protocol version the ldap server speaks. + * This might be 2 or 3. + * + * @return int + */ + public function getLDAPVersion() + { + if ($this->_link) { + $version = $this->getOption("LDAP_OPT_PROTOCOL_VERSION"); + } else { + $version = $this->_config['version']; + } + return $version; + } + + /** + * Set the LDAP_PROTOCOL_VERSION that is used on the connection. + * + * @param int $version LDAP-version that should be used + * @param boolean $force If set to true, the check against the rootDSE will be skipped + * + * @return Net_LDAP2_Error|true Net_LDAP2_Error object or true + * @todo Checking via the rootDSE takes much time - why? fetching and instanciation is quick! + */ + public function setLDAPVersion($version = 0, $force = false) + { + if (!$version) { + $version = $this->_config['version']; + } + + // + // Check to see if the server supports this version first. + // + // Todo: Why is this so horribly slow? + // $this->rootDse() is very fast, as well as Net_LDAP2_RootDSE::fetch() + // seems like a problem at copiyng the object inside PHP?? + // Additionally, this is not always reproducable... + // + if (!$force) { + $rootDSE = $this->rootDse(); + if ($rootDSE instanceof Net_LDAP2_Error) { + return $rootDSE; + } else { + $supported_versions = $rootDSE->getValue('supportedLDAPVersion'); + if (is_string($supported_versions)) { + $supported_versions = array($supported_versions); + } + $check_ok = in_array($version, $supported_versions); + } + } + + if ($force || $check_ok) { + return $this->setOption("LDAP_OPT_PROTOCOL_VERSION", $version); + } else { + return $this->raiseError("LDAP Server does not support protocol version " . $version); + } + } + + + /** + * Tells if a DN does exist in the directory + * + * @param string|Net_LDAP2_Entry $dn The DN of the object to test + * + * @return boolean|Net_LDAP2_Error + */ + public function dnExists($dn) + { + if (PEAR::isError($dn)) { + return $dn; + } + if ($dn instanceof Net_LDAP2_Entry) { + $dn = $dn->dn(); + } + if (false === is_string($dn)) { + return PEAR::raiseError('Parameter $dn is not a string nor an entry object!'); + } + + // search LDAP for that DN by performing a baselevel search for any + // object. We can only find the DN in question this way, or nothing. + $s_opts = array( + 'scope' => 'base', + 'sizelimit' => 1, + 'attributes' => '1.1' // select no attrs + ); + $search = $this->search($dn, '(objectClass=*)', $s_opts); + + if (self::isError($search)) { + return $search; + } + + // retun wehter the DN exists; that is, we found an entry + return ($search->count() == 0)? false : true; + } + + + /** + * Get a specific entry based on the DN + * + * @param string $dn DN of the entry that should be fetched + * @param array $attr Array of Attributes to select. If ommitted, all attributes are fetched. + * + * @return Net_LDAP2_Entry|Net_LDAP2_Error Reference to a Net_LDAP2_Entry object or Net_LDAP2_Error object + * @todo Maybe check against the shema should be done to be sure the attribute type exists + */ + public function getEntry($dn, $attr = array()) + { + if (!is_array($attr)) { + $attr = array($attr); + } + $result = $this->search($dn, '(objectClass=*)', + array('scope' => 'base', 'attributes' => $attr)); + if (self::isError($result)) { + return $result; + } elseif ($result->count() == 0) { + return PEAR::raiseError('Could not fetch entry '.$dn.': no entry found'); + } + $entry = $result->shiftEntry(); + if (false == $entry) { + return PEAR::raiseError('Could not fetch entry (error retrieving entry from search result)'); + } + return $entry; + } + + /** + * Rename or move an entry + * + * This method will instantly carry out an update() after the move, + * so the entry is moved instantly. + * You can pass an optional Net_LDAP2 object. In this case, a cross directory + * move will be performed which deletes the entry in the source (THIS) directory + * and adds it in the directory $target_ldap. + * A cross directory move will switch the Entrys internal LDAP reference so + * updates to the entry will go to the new directory. + * + * Note that if you want to do a cross directory move, you need to + * pass an Net_LDAP2_Entry object, otherwise the attributes will be empty. + * + * @param string|Net_LDAP2_Entry $entry Entry DN or Entry object + * @param string $newdn New location + * @param Net_LDAP2 $target_ldap (optional) Target directory for cross server move; should be passed via reference + * + * @return Net_LDAP2_Error|true + */ + public function move($entry, $newdn, $target_ldap = null) + { + if (is_string($entry)) { + $entry_o = $this->getEntry($entry); + } else { + $entry_o = $entry; + } + if (!$entry_o instanceof Net_LDAP2_Entry) { + return PEAR::raiseError('Parameter $entry is expected to be a Net_LDAP2_Entry object! (If DN was passed, conversion failed)'); + } + if (null !== $target_ldap && !$target_ldap instanceof Net_LDAP2) { + return PEAR::raiseError('Parameter $target_ldap is expected to be a Net_LDAP2 object!'); + } + + if ($target_ldap && $target_ldap !== $this) { + // cross directory move + if (is_string($entry)) { + return PEAR::raiseError('Unable to perform cross directory move: operation requires a Net_LDAP2_Entry object'); + } + if ($target_ldap->dnExists($newdn)) { + return PEAR::raiseError('Unable to perform cross directory move: entry does exist in target directory'); + } + $entry_o->dn($newdn); + $res = $target_ldap->add($entry_o); + if (self::isError($res)) { + return PEAR::raiseError('Unable to perform cross directory move: '.$res->getMessage().' in target directory'); + } + $res = $this->delete($entry_o->currentDN()); + if (self::isError($res)) { + $res2 = $target_ldap->delete($entry_o); // undo add + if (self::isError($res2)) { + $add_error_string = 'Additionally, the deletion (undo add) of $entry in target directory failed.'; + } + return PEAR::raiseError('Unable to perform cross directory move: '.$res->getMessage().' in source directory. '.$add_error_string); + } + $entry_o->setLDAP($target_ldap); + return true; + } else { + // local move + $entry_o->dn($newdn); + $entry_o->setLDAP($this); + return $entry_o->update(); + } + } + + /** + * Copy an entry to a new location + * + * The entry will be immediately copied. + * Please note that only attributes you have + * selected will be copied. + * + * @param Net_LDAP2_Entry $entry Entry object + * @param string $newdn New FQF-DN of the entry + * + * @return Net_LDAP2_Error|Net_LDAP2_Entry Error Message or reference to the copied entry + */ + public function copy($entry, $newdn) + { + if (!$entry instanceof Net_LDAP2_Entry) { + return PEAR::raiseError('Parameter $entry is expected to be a Net_LDAP2_Entry object!'); + } + + $newentry = Net_LDAP2_Entry::createFresh($newdn, $entry->getValues()); + $result = $this->add($newentry); + + if ($result instanceof Net_LDAP2_Error) { + return $result; + } else { + return $newentry; + } + } + + + /** + * Returns the string for an ldap errorcode. + * + * Made to be able to make better errorhandling + * Function based on DB::errorMessage() + * Tip: The best description of the errorcodes is found here: + * http://www.directory-info.com/LDAP2/LDAPErrorCodes.html + * + * @param int $errorcode Error code + * + * @return string The errorstring for the error. + */ + public static function errorMessage($errorcode) + { + $errorMessages = array( + 0x00 => "LDAP_SUCCESS", + 0x01 => "LDAP_OPERATIONS_ERROR", + 0x02 => "LDAP_PROTOCOL_ERROR", + 0x03 => "LDAP_TIMELIMIT_EXCEEDED", + 0x04 => "LDAP_SIZELIMIT_EXCEEDED", + 0x05 => "LDAP_COMPARE_FALSE", + 0x06 => "LDAP_COMPARE_TRUE", + 0x07 => "LDAP_AUTH_METHOD_NOT_SUPPORTED", + 0x08 => "LDAP_STRONG_AUTH_REQUIRED", + 0x09 => "LDAP_PARTIAL_RESULTS", + 0x0a => "LDAP_REFERRAL", + 0x0b => "LDAP_ADMINLIMIT_EXCEEDED", + 0x0c => "LDAP_UNAVAILABLE_CRITICAL_EXTENSION", + 0x0d => "LDAP_CONFIDENTIALITY_REQUIRED", + 0x0e => "LDAP_SASL_BIND_INPROGRESS", + 0x10 => "LDAP_NO_SUCH_ATTRIBUTE", + 0x11 => "LDAP_UNDEFINED_TYPE", + 0x12 => "LDAP_INAPPROPRIATE_MATCHING", + 0x13 => "LDAP_CONSTRAINT_VIOLATION", + 0x14 => "LDAP_TYPE_OR_VALUE_EXISTS", + 0x15 => "LDAP_INVALID_SYNTAX", + 0x20 => "LDAP_NO_SUCH_OBJECT", + 0x21 => "LDAP_ALIAS_PROBLEM", + 0x22 => "LDAP_INVALID_DN_SYNTAX", + 0x23 => "LDAP_IS_LEAF", + 0x24 => "LDAP_ALIAS_DEREF_PROBLEM", + 0x30 => "LDAP_INAPPROPRIATE_AUTH", + 0x31 => "LDAP_INVALID_CREDENTIALS", + 0x32 => "LDAP_INSUFFICIENT_ACCESS", + 0x33 => "LDAP_BUSY", + 0x34 => "LDAP_UNAVAILABLE", + 0x35 => "LDAP_UNWILLING_TO_PERFORM", + 0x36 => "LDAP_LOOP_DETECT", + 0x3C => "LDAP_SORT_CONTROL_MISSING", + 0x3D => "LDAP_INDEX_RANGE_ERROR", + 0x40 => "LDAP_NAMING_VIOLATION", + 0x41 => "LDAP_OBJECT_CLASS_VIOLATION", + 0x42 => "LDAP_NOT_ALLOWED_ON_NONLEAF", + 0x43 => "LDAP_NOT_ALLOWED_ON_RDN", + 0x44 => "LDAP_ALREADY_EXISTS", + 0x45 => "LDAP_NO_OBJECT_CLASS_MODS", + 0x46 => "LDAP_RESULTS_TOO_LARGE", + 0x47 => "LDAP_AFFECTS_MULTIPLE_DSAS", + 0x50 => "LDAP_OTHER", + 0x51 => "LDAP_SERVER_DOWN", + 0x52 => "LDAP_LOCAL_ERROR", + 0x53 => "LDAP_ENCODING_ERROR", + 0x54 => "LDAP_DECODING_ERROR", + 0x55 => "LDAP_TIMEOUT", + 0x56 => "LDAP_AUTH_UNKNOWN", + 0x57 => "LDAP_FILTER_ERROR", + 0x58 => "LDAP_USER_CANCELLED", + 0x59 => "LDAP_PARAM_ERROR", + 0x5a => "LDAP_NO_MEMORY", + 0x5b => "LDAP_CONNECT_ERROR", + 0x5c => "LDAP_NOT_SUPPORTED", + 0x5d => "LDAP_CONTROL_NOT_FOUND", + 0x5e => "LDAP_NO_RESULTS_RETURNED", + 0x5f => "LDAP_MORE_RESULTS_TO_RETURN", + 0x60 => "LDAP_CLIENT_LOOP", + 0x61 => "LDAP_REFERRAL_LIMIT_EXCEEDED", + 1000 => "Unknown Net_LDAP2 Error" + ); + + return isset($errorMessages[$errorcode]) ? + $errorMessages[$errorcode] : + $errorMessages[NET_LDAP2_ERROR] . ' (' . $errorcode . ')'; + } + + /** + * Gets a rootDSE object + * + * This either fetches a fresh rootDSE object or returns it from + * the internal cache for performance reasons, if possible. + * + * @param array $attrs Array of attributes to search for + * + * @access public + * @return Net_LDAP2_Error|Net_LDAP2_RootDSE Net_LDAP2_Error or Net_LDAP2_RootDSE object + */ + public function rootDse($attrs = null) + { + if ($attrs !== null && !is_array($attrs)) { + return PEAR::raiseError('Parameter $attr is expected to be an array!'); + } + + $attrs_signature = serialize($attrs); + + // see if we need to fetch a fresh object, or if we already + // requested this object with the same attributes + if (true || !array_key_exists($attrs_signature, $this->_rootDSE_cache)) { + $rootdse = Net_LDAP2_RootDSE::fetch($this, $attrs); + if ($rootdse instanceof Net_LDAP2_Error) { + return $rootdse; + } + + // search was ok, store rootDSE in cache + $this->_rootDSE_cache[$attrs_signature] = $rootdse; + } + return $this->_rootDSE_cache[$attrs_signature]; + } + + /** + * Alias function of rootDse() for perl-ldap interface + * + * @access public + * @see rootDse() + * @return Net_LDAP2_Error|Net_LDAP2_RootDSE + */ + public function root_dse() + { + $args = func_get_args(); + return call_user_func_array(array($this, 'rootDse'), $args); + } + + /** + * Get a schema object + * + * @param string $dn (optional) Subschema entry dn + * + * @access public + * @return Net_LDAP2_Schema|Net_LDAP2_Error Net_LDAP2_Schema or Net_LDAP2_Error object + */ + public function schema($dn = null) + { + // Schema caching by Knut-Olav Hoven + // If a schema caching object is registered, we use that to fetch + // a schema object. + // See registerSchemaCache() for more info on this. + if ($this->_schema === null) { + if ($this->_schema_cache) { + $cached_schema = $this->_schema_cache->loadSchema(); + if ($cached_schema instanceof Net_LDAP2_Error) { + return $cached_schema; // route error to client + } else { + if ($cached_schema instanceof Net_LDAP2_Schema) { + $this->_schema = $cached_schema; + } + } + } + } + + // Fetch schema, if not tried before and no cached version available. + // If we are already fetching the schema, we will skip fetching. + if ($this->_schema === null) { + // store a temporary error message so subsequent calls to schema() can + // detect, that we are fetching the schema already. + // Otherwise we will get an infinite loop at Net_LDAP2_Schema::fetch() + $this->_schema = new Net_LDAP2_Error('Schema not initialized'); + $this->_schema = Net_LDAP2_Schema::fetch($this, $dn); + + // If schema caching is active, advise the cache to store the schema + if ($this->_schema_cache) { + $caching_result = $this->_schema_cache->storeSchema($this->_schema); + if ($caching_result instanceof Net_LDAP2_Error) { + return $caching_result; // route error to client + } + } + } + return $this->_schema; + } + + /** + * Enable/disable persistent schema caching + * + * Sometimes it might be useful to allow your scripts to cache + * the schema information on disk, so the schema is not fetched + * every time the script runs which could make your scripts run + * faster. + * + * This method allows you to register a custom object that + * implements your schema cache. Please see the SchemaCache interface + * (SchemaCache.interface.php) for informations on how to implement this. + * To unregister the cache, pass null as $cache parameter. + * + * For ease of use, Net_LDAP2 provides a simple file based cache + * which is used in the example below. You may use this, for example, + * to store the schema in a linux tmpfs which results in the schema + * beeing cached inside the RAM which allows nearly instant access. + * <code> + * // Create the simple file cache object that comes along with Net_LDAP2 + * $mySchemaCache_cfg = array( + * 'path' => '/tmp/Net_LDAP2_Schema.cache', + * 'max_age' => 86400 // max age is 24 hours (in seconds) + * ); + * $mySchemaCache = new Net_LDAP2_SimpleFileSchemaCache($mySchemaCache_cfg); + * $ldap = new Net_LDAP2::connect(...); + * $ldap->registerSchemaCache($mySchemaCache); // enable caching + * // now each call to $ldap->schema() will get the schema from disk! + * </code> + * + * @param Net_LDAP2_SchemaCache|null $cache Object implementing the Net_LDAP2_SchemaCache interface + * + * @return true|Net_LDAP2_Error + */ + public function registerSchemaCache($cache) { + if (is_null($cache) + || (is_object($cache) && in_array('Net_LDAP2_SchemaCache', class_implements($cache))) ) { + $this->_schema_cache = $cache; + return true; + } else { + return new Net_LDAP2_Error('Custom schema caching object is either no '. + 'valid object or does not implement the Net_LDAP2_SchemaCache interface!'); + } + } + + + /** + * Checks if phps ldap-extension is loaded + * + * If it is not loaded, it tries to load it manually using PHPs dl(). + * It knows both windows-dll and *nix-so. + * + * @static + * @return Net_LDAP2_Error|true + */ + public static function checkLDAPExtension() + { + if (!extension_loaded('ldap') && !@dl('ldap.' . PHP_SHLIB_SUFFIX)) { + return new Net_LDAP2_Error("It seems that you do not have the ldap-extension installed. Please install it before using the Net_LDAP2 package."); + } else { + return true; + } + } + + /** + * Encodes given attributes from ISO-8859-1 to UTF-8 if needed by schema + * + * This function takes attributes in an array and then checks against the schema if they need + * UTF8 encoding. If that is so, they will be encoded. An encoded array will be returned and + * can be used for adding or modifying. + * + * $attributes is expected to be an array with keys describing + * the attribute names and the values as the value of this attribute: + * <code>$attributes = array('cn' => 'foo', 'attr2' => array('mv1', 'mv2'));</code> + * + * @param array $attributes Array of attributes + * + * @access public + * @return array|Net_LDAP2_Error Array of UTF8 encoded attributes or Error + */ + public function utf8Encode($attributes) + { + return $this->utf8($attributes, 'utf8_encode'); + } + + /** + * Decodes the given attribute values from UTF-8 to ISO-8859-1 if needed by schema + * + * $attributes is expected to be an array with keys describing + * the attribute names and the values as the value of this attribute: + * <code>$attributes = array('cn' => 'foo', 'attr2' => array('mv1', 'mv2'));</code> + * + * @param array $attributes Array of attributes + * + * @access public + * @see utf8Encode() + * @return array|Net_LDAP2_Error Array with decoded attribute values or Error + */ + public function utf8Decode($attributes) + { + return $this->utf8($attributes, 'utf8_decode'); + } + + /** + * Encodes or decodes UTF-8/ISO-8859-1 attribute values if needed by schema + * + * @param array $attributes Array of attributes + * @param array $function Function to apply to attribute values + * + * @access protected + * @return array|Net_LDAP2_Error Array of attributes with function applied to values or Error + */ + protected function utf8($attributes, $function) + { + if (!is_array($attributes) || array_key_exists(0, $attributes)) { + return PEAR::raiseError('Parameter $attributes is expected to be an associative array'); + } + + if (!$this->_schema) { + $this->_schema = $this->schema(); + } + + if (!$this->_link || self::isError($this->_schema) || !function_exists($function)) { + return $attributes; + } + + if (is_array($attributes) && count($attributes) > 0) { + + foreach ($attributes as $k => $v) { + + if (!isset($this->_schemaAttrs[$k])) { + + $attr = $this->_schema->get('attribute', $k); + if (self::isError($attr)) { + continue; + } + + // Encoding is needed if this is a DIR_STR. We assume also + // needed encoding in case the schema contains no syntax + // information (he does not need to, see rfc2252, 4.2) + if (!array_key_exists('syntax', $attr) || false !== strpos($attr['syntax'], '1.3.6.1.4.1.1466.115.121.1.15')) { + $encode = true; + } else { + $encode = false; + } + $this->_schemaAttrs[$k] = $encode; + + } else { + $encode = $this->_schemaAttrs[$k]; + } + + if ($encode) { + if (is_array($v)) { + foreach ($v as $ak => $av) { + $v[$ak] = call_user_func($function, $av); + } + } else { + $v = call_user_func($function, $v); + } + } + $attributes[$k] = $v; + } + } + return $attributes; + } + + /** + * Get the LDAP link resource. It will loop attempting to + * re-establish the connection if the connection attempt fails and + * auto_reconnect has been turned on (see the _config array documentation). + * + * @access public + * @return resource LDAP link + */ + public function getLink() + { + if ($this->_config['auto_reconnect']) { + while (true) { + // + // Return the link handle if we are already connected. Otherwise + // try to reconnect. + // + if ($this->_link !== false) { + return $this->_link; + } else { + $this->performReconnect(); + } + } + } + return $this->_link; + } +} + +/** +* Net_LDAP2_Error implements a class for reporting portable LDAP error messages. +* +* @category Net +* @package Net_LDAP2 +* @author Tarjej Huse <tarjei@bergfald.no> +* @license http://www.gnu.org/copyleft/lesser.html LGPL +* @link http://pear.php.net/package/Net_LDAP22/ +*/ +class Net_LDAP2_Error extends PEAR_Error +{ + /** + * Net_LDAP2_Error constructor. + * + * @param string $message String with error message. + * @param integer $code Net_LDAP2 error code + * @param integer $mode what "error mode" to operate in + * @param mixed $level what error level to use for $mode & PEAR_ERROR_TRIGGER + * @param mixed $debuginfo additional debug info, such as the last query + * + * @access public + * @see PEAR_Error + */ + public function __construct($message = 'Net_LDAP2_Error', $code = NET_LDAP2_ERROR, $mode = PEAR_ERROR_RETURN, + $level = E_USER_NOTICE, $debuginfo = null) + { + if (is_int($code)) { + parent::__construct($message . ': ' . Net_LDAP2::errorMessage($code), $code, $mode, $level, $debuginfo); + } else { + parent::__construct("$message: $code", NET_LDAP2_ERROR, $mode, $level, $debuginfo); + } + } +} + +?>
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/Net/LDAP2/Entry.php
Added
@@ -0,0 +1,1096 @@ +<?php +/* vim: set expandtab tabstop=4 shiftwidth=4: */ +/** +* File containing the Net_LDAP2_Entry interface class. +* +* PHP version 5 +* +* @category Net +* @package Net_LDAP2 +* @author Jan Wagner <wagner@netsols.de> +* @author Tarjej Huse <tarjei@bergfald.no> +* @author Benedikt Hallinger <beni@php.net> +* @copyright 2009 Tarjej Huse, Jan Wagner, Benedikt Hallinger +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id$ +* @link http://pear.php.net/package/Net_LDAP2/ +*/ + +/** +* Includes +*/ +require_once 'PEAR.php'; +require_once 'Net/LDAP2/Util.php'; + +/** +* Object representation of a directory entry +* +* This class represents a directory entry. You can add, delete, replace +* attributes and their values, rename the entry, delete the entry. +* +* @category Net +* @package Net_LDAP2 +* @author Jan Wagner <wagner@netsols.de> +* @author Tarjej Huse <tarjei@bergfald.no> +* @author Benedikt Hallinger <beni@php.net> +* @license http://www.gnu.org/copyleft/lesser.html LGPL +* @link http://pear.php.net/package/Net_LDAP2/ +*/ +class Net_LDAP2_Entry extends PEAR +{ + /** + * Entry ressource identifier + * + * @access protected + * @var ressource + */ + protected $_entry = null; + + /** + * LDAP ressource identifier + * + * @access protected + * @var ressource + */ + protected $_link = null; + + /** + * Net_LDAP2 object + * + * This object will be used for updating and schema checking + * + * @access protected + * @var object Net_LDAP2 + */ + protected $_ldap = null; + + /** + * Distinguished name of the entry + * + * @access protected + * @var string + */ + protected $_dn = null; + + /** + * Attributes + * + * @access protected + * @var array + */ + protected $_attributes = array(); + + /** + * Original attributes before any modification + * + * @access protected + * @var array + */ + protected $_original = array(); + + + /** + * Map of attribute names + * + * @access protected + * @var array + */ + protected $_map = array(); + + + /** + * Is this a new entry? + * + * @access protected + * @var boolean + */ + protected $_new = true; + + /** + * New distinguished name + * + * @access protected + * @var string + */ + protected $_newdn = null; + + /** + * Shall the entry be deleted? + * + * @access protected + * @var boolean + */ + protected $_delete = false; + + /** + * Map with changes to the entry + * + * @access protected + * @var array + */ + protected $_changes = array("add" => array(), + "delete" => array(), + "replace" => array() + ); + /** + * Internal Constructor + * + * Constructor of the entry. Sets up the distinguished name and the entries + * attributes. + * You should not call this method manually! Use {@link Net_LDAP2_Entry::createFresh()} + * or {@link Net_LDAP2_Entry::createConnected()} instead! + * + * @param Net_LDAP2|ressource|array $ldap Net_LDAP2 object, ldap-link ressource or array of attributes + * @param string|ressource $entry Either a DN or a LDAP-Entry ressource + * + * @access protected + * @return none + */ + public function __construct($ldap, $entry = null) + { + parent::__construct('Net_LDAP2_Error'); + + // set up entry resource or DN + if (is_resource($entry)) { + $this->_entry = $entry; + } else { + $this->_dn = $entry; + } + + // set up LDAP link + if ($ldap instanceof Net_LDAP2) { + $this->_ldap = $ldap; + $this->_link = $ldap->getLink(); + } elseif (is_resource($ldap)) { + $this->_link = $ldap; + } elseif (is_array($ldap)) { + // Special case: here $ldap is an array of attributes, + // this means, we have no link. This is a "virtual" entry. + // We just set up the attributes so one can work with the object + // as expected, but an update() fails unless setLDAP() is called. + $this->setAttributes($ldap); + } + + // if this is an entry existing in the directory, + // then set up as old and fetch attrs + if (is_resource($this->_entry) && is_resource($this->_link)) { + $this->_new = false; + $this->_dn = @ldap_get_dn($this->_link, $this->_entry); + $this->setAttributes(); // fetch attributes from server + } + } + + /** + * Creates a fresh entry that may be added to the directory later on + * + * Use this method, if you want to initialize a fresh entry. + * + * The method should be called statically: $entry = Net_LDAP2_Entry::createFresh(); + * You should put a 'objectClass' attribute into the $attrs so the directory server + * knows which object you want to create. However, you may omit this in case you + * don't want to add this entry to a directory server. + * + * The attributes parameter is as following: + * <code> + * $attrs = array( 'attribute1' => array('value1', 'value2'), + * 'attribute2' => 'single value' + * ); + * </code> + * + * @param string $dn DN of the Entry + * @param array $attrs Attributes of the entry + * + * @static + * @return Net_LDAP2_Entry|Net_LDAP2_Error + */ + public static function createFresh($dn, $attrs = array()) + { + if (!is_array($attrs)) { + return PEAR::raiseError("Unable to create fresh entry: Parameter \$attrs needs to be an array!"); + } + + $entry = new Net_LDAP2_Entry($attrs, $dn); + return $entry; + } + + /** + * Creates a Net_LDAP2_Entry object out of an ldap entry resource + * + * Use this method, if you want to initialize an entry object that is + * already present in some directory and that you have read manually. + * + * Please note, that if you want to create an entry object that represents + * some already existing entry, you should use {@link createExisting()}. + * + * The method should be called statically: $entry = Net_LDAP2_Entry::createConnected(); + * + * @param Net_LDAP2 $ldap Net_LDA2 object + * @param resource $entry PHP LDAP entry resource + * + * @static + * @return Net_LDAP2_Entry|Net_LDAP2_Error + */ + public static function createConnected($ldap, $entry) + { + if (!$ldap instanceof Net_LDAP2) { + return PEAR::raiseError("Unable to create connected entry: Parameter \$ldap needs to be a Net_LDAP2 object!"); + } + if (!is_resource($entry)) { + return PEAR::raiseError("Unable to create connected entry: Parameter \$entry needs to be a ldap entry resource!"); + } + + $entry = new Net_LDAP2_Entry($ldap, $entry); + return $entry; + } + + /** + * Creates an Net_LDAP2_Entry object that is considered already existing + * + * Use this method, if you want to modify an already existing entry + * without fetching it first. + * In most cases however, it is better to fetch the entry via Net_LDAP2->getEntry()! + * + * Please note that you should take care if you construct entries manually with this + * because you may get weird synchronisation problems. + * The attributes and values as well as the entry itself are considered existent + * which may produce errors if you try to modify an entry which doesn't really exist + * or if you try to overwrite some attribute with an value already present. + * + * This method is equal to calling createFresh() and after that markAsNew(FALSE). + * + * The method should be called statically: $entry = Net_LDAP2_Entry::createExisting(); + * + * The attributes parameter is as following: + * <code> + * $attrs = array( 'attribute1' => array('value1', 'value2'), + * 'attribute2' => 'single value' + * ); + * </code> + * + * @param string $dn DN of the Entry + * @param array $attrs Attributes of the entry + * + * @static + * @return Net_LDAP2_Entry|Net_LDAP2_Error + */ + public static function createExisting($dn, $attrs = array()) + { + if (!is_array($attrs)) { + return PEAR::raiseError("Unable to create entry object: Parameter \$attrs needs to be an array!"); + } + + $entry = Net_LDAP2_Entry::createFresh($dn, $attrs); + if ($entry instanceof Net_LDAP2_Error) { + return $entry; + } else { + $entry->markAsNew(false); + return $entry; + } + } + + /** + * Get or set the distinguished name of the entry + * + * If called without an argument the current (or the new DN if set) DN gets returned. + * If you provide an DN, this entry is moved to the new location specified if a DN existed. + * If the DN was not set, the DN gets initialized. Call {@link update()} to actually create + * the new Entry in the directory. + * To fetch the current active DN after setting a new DN but before an update(), you can use + * {@link currentDN()} to retrieve the DN that is currently active. + * + * Please note that special characters (eg german umlauts) should be encoded using utf8_encode(). + * You may use {@link Net_LDAP2_Util::canonical_dn()} for properly encoding of the DN. + * + * @param string $dn New distinguished name + * + * @access public + * @return string|true Distinguished name (or true if a new DN was provided) + */ + public function dn($dn = null) + { + if (false == is_null($dn)) { + if (is_null($this->_dn) ) { + $this->_dn = $dn; + } else { + $this->_newdn = $dn; + } + return true; + } + return (isset($this->_newdn) ? $this->_newdn : $this->currentDN()); + } + + /** + * Renames or moves the entry + * + * This is just a convinience alias to {@link dn()} + * to make your code more meaningful. + * + * @param string $newdn The new DN + * + * @return true + */ + public function move($newdn) + { + return $this->dn($newdn); + } + + /** + * Sets the internal attributes array + * + * This fetches the values for the attributes from the server. + * The attribute Syntax will be checked so binary attributes will be returned + * as binary values. + * + * Attributes may be passed directly via the $attributes parameter to setup this + * entry manually. This overrides attribute fetching from the server. + * + * @param array $attributes Attributes to set for this entry + * + * @access protected + * @return void + */ + protected function setAttributes($attributes = null) + { + /* + * fetch attributes from the server + */ + if (is_null($attributes) && is_resource($this->_entry) && is_resource($this->_link)) { + // fetch schema + if ($this->_ldap instanceof Net_LDAP2) { + $schema = $this->_ldap->schema(); + } + // fetch attributes + $attributes = array(); + do { + if (empty($attr)) { + $ber = null; + $attr = @ldap_first_attribute($this->_link, $this->_entry, $ber); + } else { + $attr = @ldap_next_attribute($this->_link, $this->_entry, $ber); + } + if ($attr) { + $func = 'ldap_get_values'; // standard function to fetch value + + // Try to get binary values as binary data + if ($schema instanceof Net_LDAP2_Schema) { + if ($schema->isBinary($attr)) { + $func = 'ldap_get_values_len'; + } + } + // fetch attribute value (needs error checking?) + $attributes[$attr] = $func($this->_link, $this->_entry, $attr); + } + } while ($attr); + } + + /* + * set attribute data directly, if passed + */ + if (is_array($attributes) && count($attributes) > 0) { + if (isset($attributes["count"]) && is_numeric($attributes["count"])) { + unset($attributes["count"]); + } + foreach ($attributes as $k => $v) { + // attribute names should not be numeric + if (is_numeric($k)) { + continue; + } + // map generic attribute name to real one + $this->_map[strtolower($k)] = $k; + // attribute values should be in an array + if (false == is_array($v)) { + $v = array($v); + } + // remove the value count (comes from ldap server) + if (isset($v["count"])) { + unset($v["count"]); + } + $this->_attributes[$k] = $v; + } + } + + // save a copy for later use + $this->_original = $this->_attributes; + } + + /** + * Get the values of all attributes in a hash + * + * The returned hash has the form + * <code>array('attributename' => 'single value', + * 'attributename' => array('value1', value2', value3'))</code> + * Only attributes present at the entry will be returned. + * + * @access public + * @return array Hash of all attributes with their values + */ + public function getValues() + { + $attrs = array(); + foreach ($this->_attributes as $attr => $value) { + $attrs[$attr] = $this->getValue($attr); + } + return $attrs; + } + + /** + * Get the value of a specific attribute + * + * The first parameter is the name of the attribute + * The second parameter influences the way the value is returned: + * 'single': only the first value is returned as string + * 'all': all values are returned in an array + * 'default': in all other cases an attribute value with a single value is + * returned as string, if it has multiple values it is returned + * as an array + * + * If the attribute is not set at this entry (no value or not defined in + * schema), "false" is returned when $option is 'single', an empty string if + * 'default', and an empty array when 'all'. + * + * You may use Net_LDAP2_Schema->checkAttribute() to see if the attribute + * is defined for the objectClasses of this entry. + * + * @param string $attr Attribute name + * @param string $option Option + * + * @access public + * @return string|array + */ + public function getValue($attr, $option = null) + { + $attr = $this->getAttrName($attr); + + // return depending on set $options + if (!array_key_exists($attr, $this->_attributes)) { + // attribute not set + switch ($option) { + case 'single': + $value = false; + break; + case 'all': + $value = array(); + break; + default: + $value = ''; + } + + } else { + // attribute present + switch ($option) { + case 'single': + $value = $this->_attributes[$attr][0]; + break; + case 'all': + $value = $this->_attributes[$attr]; + break; + default: + $value = $this->_attributes[$attr]; + if (count($value) == 1) { + $value = array_shift($value); + } + } + + } + + return $value; + } + + /** + * Alias function of getValue for perl-ldap interface + * + * @see getValue() + * @return string|array|PEAR_Error + */ + public function get_value() + { + $args = func_get_args(); + return call_user_func_array(array( $this, 'getValue' ), $args); + } + + /** + * Returns an array of attributes names + * + * @access public + * @return array Array of attribute names + */ + public function attributes() + { + return array_keys($this->_attributes); + } + + /** + * Returns whether an attribute exists or not + * + * @param string $attr Attribute name + * + * @access public + * @return boolean + */ + public function exists($attr) + { + $attr = $this->getAttrName($attr); + return array_key_exists($attr, $this->_attributes); + } + + /** + * Adds a new attribute or a new value to an existing attribute + * + * The paramter has to be an array of the form: + * array('attributename' => 'single value', + * 'attributename' => array('value1', 'value2)) + * When the attribute already exists the values will be added, else the + * attribute will be created. These changes are local to the entry and do + * not affect the entry on the server until update() is called. + * + * Note, that you can add values of attributes that you haven't selected, but if + * you do so, {@link getValue()} and {@link getValues()} will only return the + * values you added, _NOT_ all values present on the server. To avoid this, just refetch + * the entry after calling {@link update()} or select the attribute. + * + * @param array $attr Attributes to add + * + * @access public + * @return true|Net_LDAP2_Error + */ + public function add($attr = array()) + { + if (false == is_array($attr)) { + return PEAR::raiseError("Parameter must be an array"); + } + if ($this->isNew()) { + $this->setAttributes($attr); + } + foreach ($attr as $k => $v) { + $k = $this->getAttrName($k); + if (false == is_array($v)) { + // Do not add empty values + if ($v == null) { + continue; + } else { + $v = array($v); + } + } + // add new values to existing attribute or add new attribute + if ($this->exists($k)) { + $this->_attributes[$k] = array_unique(array_merge($this->_attributes[$k], $v)); + } else { + $this->_map[strtolower($k)] = $k; + $this->_attributes[$k] = $v; + } + // save changes for update() + if (!isset($this->_changes["add"][$k])) { + $this->_changes["add"][$k] = array(); + } + $this->_changes["add"][$k] = array_unique(array_merge($this->_changes["add"][$k], $v)); + } + + $return = true; + return $return; + } + + /** + * Deletes an whole attribute or a value or the whole entry + * + * The parameter can be one of the following: + * + * "attributename" - The attribute as a whole will be deleted + * array("attributename1", "attributename2) - All given attributes will be + * deleted + * array("attributename" => "value") - The value will be deleted + * array("attributename" => array("value1", "value2") - The given values + * will be deleted + * If $attr is null or omitted , then the whole Entry will be deleted! + * + * These changes are local to the entry and do + * not affect the entry on the server until {@link update()} is called. + * + * Please note that you must select the attribute (at $ldap->search() for example) + * to be able to delete values of it, Otherwise {@link update()} will silently fail + * and remove nothing. + * + * @param string|array $attr Attributes to delete (NULL or missing to delete whole entry) + * + * @access public + * @return true + */ + public function delete($attr = null) + { + if (is_null($attr)) { + $this->_delete = true; + return true; + } + if (is_string($attr)) { + $attr = array($attr); + } + // Make the assumption that attribute names cannot be numeric, + // therefore this has to be a simple list of attribute names to delete + if (is_numeric(key($attr))) { + foreach ($attr as $name) { + if (is_array($name)) { + // someone mixed modes (list mode but specific values given!) + $del_attr_name = array_search($name, $attr); + $this->delete(array($del_attr_name => $name)); + } else { + // mark for update() if this attr was not marked before + $name = $this->getAttrName($name); + if ($this->exists($name)) { + $this->_changes["delete"][$name] = null; + unset($this->_attributes[$name]); + } + } + } + } else { + // Here we have a hash with "attributename" => "value to delete" + foreach ($attr as $name => $values) { + if (is_int($name)) { + // someone mixed modes and gave us just an attribute name + $this->delete($values); + } else { + // mark for update() if this attr was not marked before; + // this time it must consider the selected values also + $name = $this->getAttrName($name); + if ($this->exists($name)) { + if (false == is_array($values)) { + $values = array($values); + } + // save values to be deleted + if (empty($this->_changes["delete"][$name])) { + $this->_changes["delete"][$name] = array(); + } + $this->_changes["delete"][$name] = + array_unique(array_merge($this->_changes["delete"][$name], $values)); + foreach ($values as $value) { + // find the key for the value that should be deleted + $key = array_search($value, $this->_attributes[$name]); + if (false !== $key) { + // delete the value + unset($this->_attributes[$name][$key]); + } + } + } + } + } + } + $return = true; + return $return; + } + + /** + * Replaces attributes or its values + * + * The parameter has to an array of the following form: + * array("attributename" => "single value", + * "attribute2name" => array("value1", "value2"), + * "deleteme1" => null, + * "deleteme2" => "") + * If the attribute does not yet exist it will be added instead (see also $force). + * If the attribue value is null, the attribute will de deleted. + * + * These changes are local to the entry and do + * not affect the entry on the server until {@link update()} is called. + * + * In some cases you are not allowed to read the attributes value (for + * example the ActiveDirectory attribute unicodePwd) but are allowed to + * replace the value. In this case replace() would assume that the attribute + * is not in the directory yet and tries to add it which will result in an + * LDAP_TYPE_OR_VALUE_EXISTS error. + * To force replace mode instead of add, you can set $force to true. + * + * @param array $attr Attributes to replace + * @param bool $force Force replacing mode in case we can't read the attr value but are allowed to replace it + * + * @access public + * @return true|Net_LDAP2_Error + */ + public function replace($attr = array(), $force = false) + { + if (false == is_array($attr)) { + return PEAR::raiseError("Parameter must be an array"); + } + foreach ($attr as $k => $v) { + $k = $this->getAttrName($k); + if (false == is_array($v)) { + // delete attributes with empty values; treat ints as string + if (is_int($v)) { + $v = "$v"; + } + if ($v == null) { + $this->delete($k); + continue; + } else { + $v = array($v); + } + } + // existing attributes will get replaced + if ($this->exists($k) || $force) { + $this->_changes["replace"][$k] = $v; + $this->_attributes[$k] = $v; + } else { + // new ones just get added + $this->add(array($k => $v)); + } + } + $return = true; + return $return; + } + + /** + * Update the entry on the directory server + * + * This will evaluate all changes made so far and send them + * to the directory server. + * Please note, that if you make changes to objectclasses wich + * have mandatory attributes set, update() will currently fail. + * Remove the entry from the server and readd it as new in such cases. + * This also will deal with problems with setting structural object classes. + * + * @param Net_LDAP2 $ldap If passed, a call to setLDAP() is issued prior update, thus switching the LDAP-server. This is for perl-ldap interface compliance + * + * @access public + * @return true|Net_LDAP2_Error + * @todo Entry rename with a DN containing special characters needs testing! + */ + public function update($ldap = null) + { + if ($ldap) { + $msg = $this->setLDAP($ldap); + if (Net_LDAP2::isError($msg)) { + return PEAR::raiseError('You passed an invalid $ldap variable to update()'); + } + } + + // ensure we have a valid LDAP object + $ldap = $this->getLDAP(); + if (!$ldap instanceof Net_LDAP2) { + return PEAR::raiseError("The entries LDAP object is not valid"); + } + + // Get and check link + $link = $ldap->getLink(); + if (!is_resource($link)) { + return PEAR::raiseError("Could not update entry: internal LDAP link is invalid"); + } + + /* + * Delete the entry + */ + if (true === $this->_delete) { + return $ldap->delete($this); + } + + /* + * New entry + */ + if (true === $this->_new) { + $msg = $ldap->add($this); + if (Net_LDAP2::isError($msg)) { + return $msg; + } + $this->_new = false; + $this->_changes['add'] = array(); + $this->_changes['delete'] = array(); + $this->_changes['replace'] = array(); + $this->_original = $this->_attributes; + + // In case the "new" entry was moved after creation, we must + // adjust the internal DNs as the entry was already created + // with the most current DN. + if (false == is_null($this->_newdn)) { + $this->_dn = $this->_newdn; + $this->_newdn = null; + } + + $return = true; + return $return; + } + + /* + * Rename/move entry + */ + if (false == is_null($this->_newdn)) { + if ($ldap->getLDAPVersion() !== 3) { + return PEAR::raiseError("Renaming/Moving an entry is only supported in LDAPv3"); + } + // make dn relative to parent (needed for ldap rename) + $parent = Net_LDAP2_Util::ldap_explode_dn($this->_newdn, array('casefolding' => 'none', 'reverse' => false, 'onlyvalues' => false)); + if (Net_LDAP2::isError($parent)) { + return $parent; + } + $child = array_shift($parent); + // maybe the dn consist of a multivalued RDN, we must build the dn in this case + // because the $child-RDN is an array! + if (is_array($child)) { + $child = Net_LDAP2_Util::canonical_dn($child); + } + $parent = Net_LDAP2_Util::canonical_dn($parent); + + // rename/move + if (false == @ldap_rename($link, $this->_dn, $child, $parent, false)) { + + return PEAR::raiseError("Entry not renamed: " . + @ldap_error($link), @ldap_errno($link)); + } + // reflect changes to local copy + $this->_dn = $this->_newdn; + $this->_newdn = null; + } + + /* + * Retrieve a entry that has all attributes we need so that the list of changes to build is created accurately + */ + $fullEntry = $ldap->getEntry( $this->dn() ); + if ( Net_LDAP2::isError($fullEntry) ) { + return PEAR::raiseError("Could not retrieve a full set of attributes to reconcile changes with"); + } + $modifications = array(); + + // ADD + foreach ($this->_changes["add"] as $attr => $value) { + // if attribute exists, we need to combine old and new values + if ($fullEntry->exists($attr)) { + $currentValue = $fullEntry->getValue($attr, "all"); + $value = array_merge( $currentValue, $value ); + } + + $modifications[$attr] = $value; + } + + // DELETE + foreach ($this->_changes["delete"] as $attr => $value) { + // In LDAPv3 you need to specify the old values for deleting + if (is_null($value) && $ldap->getLDAPVersion() === 3) { + $value = $fullEntry->getValue($attr); + } + if (!is_array($value)) { + $value = array($value); + } + + // Find out what is missing from $value and exclude it + $currentValue = isset($modifications[$attr]) ? $modifications[$attr] : $fullEntry->getValue($attr, "all"); + $modifications[$attr] = array_values( array_diff( $currentValue, $value ) ); + } + + // REPLACE + foreach ($this->_changes["replace"] as $attr => $value) { + $modifications[$attr] = $value; + } + + // COMMIT + if (false === @ldap_modify($link, $this->dn(), $modifications)) { + return PEAR::raiseError("Could not modify the entry: " . @ldap_error($link), @ldap_errno($link)); + } + + // all went well, so _original (server) becomes _attributes (local copy), reset _changes too... + $this->_changes['add'] = array(); + $this->_changes['delete'] = array(); + $this->_changes['replace'] = array(); + $this->_original = $this->_attributes; + + $return = true; + return $return; + } + + /** + * Returns the right attribute name + * + * @param string $attr Name of attribute + * + * @access protected + * @return string The right name of the attribute + */ + protected function getAttrName($attr) + { + $name = strtolower($attr); + if (array_key_exists($name, $this->_map)) { + $attr = $this->_map[$name]; + } + return $attr; + } + + /** + * Returns a reference to the LDAP-Object of this entry + * + * @access public + * @return Net_LDAP2|Net_LDAP2_Error Reference to the Net_LDAP2 Object (the connection) or Net_LDAP2_Error + */ + public function getLDAP() + { + if (!$this->_ldap instanceof Net_LDAP2) { + $err = new PEAR_Error('LDAP is not a valid Net_LDAP2 object'); + return $err; + } else { + return $this->_ldap; + } + } + + /** + * Sets a reference to the LDAP-Object of this entry + * + * After setting a Net_LDAP2 object, calling update() will use that object for + * updating directory contents. Use this to dynamicly switch directorys. + * + * @param Net_LDAP2 $ldap Net_LDAP2 object that this entry should be connected to + * + * @access public + * @return true|Net_LDAP2_Error + */ + public function setLDAP($ldap) + { + if (!$ldap instanceof Net_LDAP2) { + return PEAR::raiseError("LDAP is not a valid Net_LDAP2 object"); + } else { + $this->_ldap = $ldap; + return true; + } + } + + /** + * Marks the entry as new/existing. + * + * If an Entry is marked as new, it will be added to the directory + * when calling {@link update()}. + * If the entry is marked as old ($mark = false), then the entry is + * assumed to be present in the directory server wich results in + * modification when calling {@link update()}. + * + * @param boolean $mark Value to set, defaults to "true" + * + * @return void + */ + public function markAsNew($mark = true) + { + $this->_new = ($mark)? true : false; + } + + /** + * Applies a regular expression onto a single- or multivalued attribute (like preg_match()) + * + * This method behaves like PHPs preg_match() but with some exceptions. + * If you want to retrieve match information, then you MUST pass the + * $matches parameter via reference! otherwise you will get no matches. + * Since it is possible to have multi valued attributes the $matches + * array will have a additionally numerical dimension (one for each value): + * <code> + * $matches = array( + * 0 => array (usual preg_match() returnarray), + * 1 => array (usual preg_match() returnarray) + * ) + * </code> + * Please note, that $matches will be initialized to an empty array inside. + * + * Usage example: + * <code> + * $result = $entry->preg_match('/089(\d+)/', 'telephoneNumber', $matches); + * if ( $result === true ){ + * echo "First match: ".$matches[0][1]; // Match of value 1, content of first bracket + * } else { + * if ( Net_LDAP2::isError($result) ) { + * echo "Error: ".$result->getMessage(); + * } else { + * echo "No match found."; + * } + * } + * </code> + * + * Please note that it is important to test for an Net_LDAP2_Error, because objects are + * evaluating to true by default, thus if an error occured, and you only check using "==" then + * you get misleading results. Use the "identical" (===) operator to test for matches to + * avoid this as shown above. + * + * @param string $regex The regular expression + * @param string $attr_name The attribute to search in + * @param array $matches (optional, PASS BY REFERENCE!) Array to store matches in + * + * @return boolean|Net_LDAP2_Error TRUE, if we had a match in one of the values, otherwise false. Net_LDAP2_Error in case something went wrong + */ + public function pregMatch($regex, $attr_name, $matches = array()) + { + $matches = array(); + + // fetch attribute values + $attr = $this->getValue($attr_name, 'all'); + + // perform preg_match() on all values + $match = false; + foreach ($attr as $thisvalue) { + $matches_int = array(); + if (preg_match($regex, $thisvalue, $matches_int)) { + $match = true; + array_push($matches, $matches_int); // store matches in reference + } + } + return $match; + } + + /** + * Alias of {@link pregMatch()} for compatibility to Net_LDAP 1 + * + * @see pregMatch() + * @return boolean|Net_LDAP2_Error + */ + public function preg_match() + { + $args = func_get_args(); + return call_user_func_array(array( $this, 'pregMatch' ), $args); + } + + /** + * Tells if the entry is consiedered as new (not present in the server) + * + * Please note, that this doesn't tell you if the entry is present on the server. + * Use {@link Net_LDAP2::dnExists()} to see if an entry is already there. + * + * @return boolean + */ + public function isNew() + { + return $this->_new; + } + + + /** + * Is this entry going to be deleted once update() is called? + * + * @return boolean + */ + public function willBeDeleted() + { + return $this->_delete; + } + + /** + * Is this entry going to be moved once update() is called? + * + * @return boolean + */ + public function willBeMoved() + { + return ($this->dn() !== $this->currentDN()); + } + + /** + * Returns always the original DN + * + * If an entry will be moved but {@link update()} was not called, + * {@link dn()} will return the new DN. This method however, returns + * always the current active DN. + * + * @return string + */ + public function currentDN() + { + return $this->_dn; + } + + /** + * Returns the attribute changes to be carried out once update() is called + * + * @return array + */ + public function getChanges() + { + return $this->_changes; + } +} +?>
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/Net/LDAP2/Filter.php
Added
@@ -0,0 +1,675 @@ +<?php +/* vim: set expandtab tabstop=4 shiftwidth=4: */ +/** +* File containing the Net_LDAP2_Filter interface class. +* +* PHP version 5 +* +* @category Net +* @package Net_LDAP2 +* @author Benedikt Hallinger <beni@php.net> +* @copyright 2009 Benedikt Hallinger +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id$ +* @link http://pear.php.net/package/Net_LDAP2/ +*/ + +/** +* Includes +*/ +require_once 'PEAR.php'; +require_once 'Net/LDAP2/Util.php'; +require_once 'Net/LDAP2/Entry.php'; + +/** +* Object representation of a part of a LDAP filter. +* +* This Class is not completely compatible to the PERL interface! +* +* The purpose of this class is, that users can easily build LDAP filters +* without having to worry about right escaping etc. +* A Filter is built using several independent filter objects +* which are combined afterwards. This object works in two +* modes, depending how the object is created. +* If the object is created using the {@link create()} method, then this is a leaf-object. +* If the object is created using the {@link combine()} method, then this is a container object. +* +* LDAP filters are defined in RFC-2254 and can be found under +* {@link http://www.ietf.org/rfc/rfc2254.txt} +* +* Here a quick copy&paste example: +* <code> +* $filter0 = Net_LDAP2_Filter::create('stars', 'equals', '***'); +* $filter_not0 = Net_LDAP2_Filter::combine('not', $filter0); +* +* $filter1 = Net_LDAP2_Filter::create('gn', 'begins', 'bar'); +* $filter2 = Net_LDAP2_Filter::create('gn', 'ends', 'baz'); +* $filter_comp = Net_LDAP2_Filter::combine('or',array($filter_not0, $filter1, $filter2)); +* +* echo $filter_comp->asString(); +* // This will output: (|(!(stars=\0x5c0x2a\0x5c0x2a\0x5c0x2a))(gn=bar*)(gn=*baz)) +* // The stars in $filter0 are treaten as real stars unless you disable escaping. +* </code> +* +* @category Net +* @package Net_LDAP2 +* @author Benedikt Hallinger <beni@php.net> +* @license http://www.gnu.org/copyleft/lesser.html LGPL +* @link http://pear.php.net/package/Net_LDAP2/ +*/ +class Net_LDAP2_Filter extends PEAR +{ + /** + * Storage for combination of filters + * + * This variable holds a array of filter objects + * that should be combined by this filter object. + * + * @access protected + * @var array + */ + protected $_subfilters = array(); + + /** + * Match of this filter + * + * If this is a leaf filter, then a matching rule is stored, + * if it is a container, then it is a logical operator + * + * @access protected + * @var string + */ + protected $_match; + + /** + * Single filter + * + * If we operate in leaf filter mode, + * then the constructing method stores + * the filter representation here + * + * @acces private + * @var string + */ + protected $_filter; + + /** + * Create a new Net_LDAP2_Filter object and parse $filter. + * + * This is for PERL Net::LDAP interface. + * Construction of Net_LDAP2_Filter objects should happen through either + * {@link create()} or {@link combine()} which give you more control. + * However, you may use the perl iterface if you already have generated filters. + * + * @param string $filter LDAP filter string + * + * @see parse() + */ + public function __construct($filter = false) + { + // The optional parameter must remain here, because otherwise create() crashes + if (false !== $filter) { + $filter_o = self::parse($filter); + if (PEAR::isError($filter_o)) { + $this->_filter = $filter_o; // assign error, so asString() can report it + } else { + $this->_filter = $filter_o->asString(); + } + } + } + + /** + * Constructor of a new part of a LDAP filter. + * + * The following matching rules exists: + * - equals: One of the attributes values is exactly $value + * Please note that case sensitiviness is depends on the + * attributes syntax configured in the server. + * - begins: One of the attributes values must begin with $value + * - ends: One of the attributes values must end with $value + * - contains: One of the attributes values must contain $value + * - present | any: The attribute can contain any value but must be existent + * - greater: The attributes value is greater than $value + * - less: The attributes value is less than $value + * - greaterOrEqual: The attributes value is greater or equal than $value + * - lessOrEqual: The attributes value is less or equal than $value + * - approx: One of the attributes values is similar to $value + * + * Negation ("not") can be done by prepending the above operators with the + * "not" or "!" keyword, see example below. + * + * If $escape is set to true (default) then $value will be escaped + * properly. If it is set to false then $value will be treaten as raw filter value string. + * You should escape yourself using {@link Net_LDAP2_Util::escape_filter_value()}! + * + * Examples: + * <code> + * // This will find entries that contain an attribute "sn" that ends with "foobar": + * $filter = Net_LDAP2_Filter::create('sn', 'ends', 'foobar'); + * + * // This will find entries that contain an attribute "sn" that has any value set: + * $filter = Net_LDAP2_Filter::create('sn', 'any'); + * + * // This will build a negated equals filter: + * $filter = Net_LDAP2_Filter::create('sn', 'not equals', 'foobar'); + * </code> + * + * @param string $attr_name Name of the attribute the filter should apply to + * @param string $match Matching rule (equals, begins, ends, contains, greater, less, greaterOrEqual, lessOrEqual, approx, any) + * @param string $value (optional) if given, then this is used as a filter + * @param boolean $escape Should $value be escaped? (default: yes, see {@link Net_LDAP2_Util::escape_filter_value()} for detailed information) + * + * @return Net_LDAP2_Filter|Net_LDAP2_Error + */ + public static function create($attr_name, $match, $value = '', $escape = true) + { + $leaf_filter = new Net_LDAP2_Filter(); + if ($escape) { + $array = Net_LDAP2_Util::escape_filter_value(array($value)); + $value = $array[0]; + } + + $match = strtolower($match); + + // detect negation + $neg_matches = array(); + $negate_filter = false; + if (preg_match('/^(?:not|!)[\s_-](.+)/', $match, $neg_matches)) { + $negate_filter = true; + $match = $neg_matches[1]; + } + + // build basic filter + switch ($match) { + case 'equals': + case '=': + case '==': + $leaf_filter->_filter = '(' . $attr_name . '=' . $value . ')'; + break; + case 'begins': + $leaf_filter->_filter = '(' . $attr_name . '=' . $value . '*)'; + break; + case 'ends': + $leaf_filter->_filter = '(' . $attr_name . '=*' . $value . ')'; + break; + case 'contains': + $leaf_filter->_filter = '(' . $attr_name . '=*' . $value . '*)'; + break; + case 'greater': + case '>': + $leaf_filter->_filter = '(' . $attr_name . '>' . $value . ')'; + break; + case 'less': + case '<': + $leaf_filter->_filter = '(' . $attr_name . '<' . $value . ')'; + break; + case 'greaterorequal': + case '>=': + $leaf_filter->_filter = '(' . $attr_name . '>=' . $value . ')'; + break; + case 'lessorequal': + case '<=': + $leaf_filter->_filter = '(' . $attr_name . '<=' . $value . ')'; + break; + case 'approx': + case '~=': + $leaf_filter->_filter = '(' . $attr_name . '~=' . $value . ')'; + break; + case 'any': + case 'present': // alias that may improve user code readability + $leaf_filter->_filter = '(' . $attr_name . '=*)'; + break; + default: + return PEAR::raiseError('Net_LDAP2_Filter create error: matching rule "' . $match . '" not known!'); + } + + // negate if requested + if ($negate_filter) { + $leaf_filter = Net_LDAP2_Filter::combine('!', $leaf_filter); + } + + return $leaf_filter; + } + + /** + * Combine two or more filter objects using a logical operator + * + * This static method combines two or more filter objects and returns one single + * filter object that contains all the others. + * Call this method statically: $filter = Net_LDAP2_Filter::combine('or', array($filter1, $filter2)) + * If the array contains filter strings instead of filter objects, we will try to parse them. + * + * @param string $log_op The locical operator. May be "and", "or", "not" or the subsequent logical equivalents "&", "|", "!" + * @param array|Net_LDAP2_Filter $filters array with Net_LDAP2_Filter objects + * + * @return Net_LDAP2_Filter|Net_LDAP2_Error + * @static + */ + public static function &combine($log_op, $filters) + { + if (PEAR::isError($filters)) { + return $filters; + } + + // substitude named operators to logical operators + if ($log_op == 'and') $log_op = '&'; + if ($log_op == 'or') $log_op = '|'; + if ($log_op == 'not') $log_op = '!'; + + // tests for sane operation + if ($log_op == '!') { + // Not-combination, here we only accept one filter object or filter string + if ($filters instanceof Net_LDAP2_Filter) { + $filters = array($filters); // force array + } elseif (is_string($filters)) { + $filter_o = self::parse($filters); + if (PEAR::isError($filter_o)) { + $err = PEAR::raiseError('Net_LDAP2_Filter combine error: '.$filter_o->getMessage()); + return $err; + } else { + $filters = array($filter_o); + } + } elseif (is_array($filters)) { + if (count($filters) != 1) { + $err = PEAR::raiseError('Net_LDAP2_Filter combine error: operator is "not" but $filter is an array!'); + return $err; + } elseif (!($filters[0] instanceof Net_LDAP2_Filter)) { + $err = PEAR::raiseError('Net_LDAP2_Filter combine error: operator is "not" but $filter is not a valid Net_LDAP2_Filter nor a filter string!'); + return $err; + } + } else { + $err = PEAR::raiseError('Net_LDAP2_Filter combine error: operator is "not" but $filter is not a valid Net_LDAP2_Filter nor a filter string!'); + return $err; + } + } elseif ($log_op == '&' || $log_op == '|') { + if (!is_array($filters) || count($filters) < 2) { + $err = PEAR::raiseError('Net_LDAP2_Filter combine error: parameter $filters is not an array or contains less than two Net_LDAP2_Filter objects!'); + return $err; + } + } else { + $err = PEAR::raiseError('Net_LDAP2_Filter combine error: logical operator is not known!'); + return $err; + } + + $combined_filter = new Net_LDAP2_Filter(); + foreach ($filters as $key => $testfilter) { // check for errors + if (PEAR::isError($testfilter)) { + return $testfilter; + } elseif (is_string($testfilter)) { + // string found, try to parse into an filter object + $filter_o = self::parse($testfilter); + if (PEAR::isError($filter_o)) { + return $filter_o; + } else { + $filters[$key] = $filter_o; + } + } elseif (!$testfilter instanceof Net_LDAP2_Filter) { + $err = PEAR::raiseError('Net_LDAP2_Filter combine error: invalid object passed in array $filters!'); + return $err; + } + } + + $combined_filter->_subfilters = $filters; + $combined_filter->_match = $log_op; + return $combined_filter; + } + + /** + * Parse FILTER into a Net_LDAP2_Filter object + * + * This parses an filter string into Net_LDAP2_Filter objects. + * + * @param string $FILTER The filter string + * + * @access static + * @return Net_LDAP2_Filter|Net_LDAP2_Error + * @todo Leaf-mode: Do we need to escape at all? what about *-chars?check for the need of encoding values, tackle problems (see code comments) + */ + public static function parse($FILTER) + { + if (preg_match('/^\((.+?)\)$/', $FILTER, $matches)) { + // Check for right bracket syntax: count of unescaped opening + // brackets must match count of unescaped closing brackets. + // At this stage we may have: + // 1. one filter component with already removed outer brackets + // 2. one or more subfilter components + $c_openbracks = preg_match_all('/(?<!\\\\)\(/' , $matches[1], $notrelevant); + $c_closebracks = preg_match_all('/(?<!\\\\)\)/' , $matches[1], $notrelevant); + if ($c_openbracks != $c_closebracks) { + return PEAR::raiseError("Filter parsing error: invalid filter syntax - opening brackets do not match close brackets!"); + } + + if (in_array(substr($matches[1], 0, 1), array('!', '|', '&'))) { + // Subfilter processing: pass subfilters to parse() and combine + // the objects using the logical operator detected + // we have now something like "&(...)(...)(...)" but at least one part ("!(...)"). + // Each subfilter could be an arbitary complex subfilter. + + // extract logical operator and filter arguments + $log_op = substr($matches[1], 0, 1); + $remaining_component = substr($matches[1], 1); + + // split $remaining_component into individual subfilters + // we cannot use split() for this, because we do not know the + // complexiness of the subfilter. Thus, we look trough the filter + // string and just recognize ending filters at the first level. + // We record the index number of the char and use that information + // later to split the string. + $sub_index_pos = array(); + $prev_char = ''; // previous character looked at + $level = 0; // denotes the current bracket level we are, + // >1 is too deep, 1 is ok, 0 is outside any + // subcomponent + for ($curpos = 0; $curpos < strlen($remaining_component); $curpos++) { + $cur_char = substr($remaining_component, $curpos, 1); + + // rise/lower bracket level + if ($cur_char == '(' && $prev_char != '\\') { + $level++; + } elseif ($cur_char == ')' && $prev_char != '\\') { + $level--; + } + + if ($cur_char == '(' && $prev_char == ')' && $level == 1) { + array_push($sub_index_pos, $curpos); // mark the position for splitting + } + $prev_char = $cur_char; + } + + // now perform the splits. To get also the last part, we + // need to add the "END" index to the split array + array_push($sub_index_pos, strlen($remaining_component)); + $subfilters = array(); + $oldpos = 0; + foreach ($sub_index_pos as $s_pos) { + $str_part = substr($remaining_component, $oldpos, $s_pos - $oldpos); + array_push($subfilters, $str_part); + $oldpos = $s_pos; + } + + // some error checking... + if (count($subfilters) == 1) { + // only one subfilter found + } elseif (count($subfilters) > 1) { + // several subfilters found + if ($log_op == "!") { + return PEAR::raiseError("Filter parsing error: invalid filter syntax - NOT operator detected but several arguments given!"); + } + } else { + // this should not happen unless the user specified a wrong filter + return PEAR::raiseError("Filter parsing error: invalid filter syntax - got operator '$log_op' but no argument!"); + } + + // Now parse the subfilters into objects and combine them using the operator + $subfilters_o = array(); + foreach ($subfilters as $s_s) { + $o = self::parse($s_s); + if (PEAR::isError($o)) { + return $o; + } else { + array_push($subfilters_o, self::parse($s_s)); + } + } + + $filter_o = self::combine($log_op, $subfilters_o); + return $filter_o; + + } else { + // This is one leaf filter component, do some syntax checks, then escape and build filter_o + // $matches[1] should be now something like "foo=bar" + + // detect multiple leaf components + // [TODO] Maybe this will make problems with filters containing brackets inside the value + if (stristr($matches[1], ')(')) { + return PEAR::raiseError("Filter parsing error: invalid filter syntax - multiple leaf components detected!"); + } else { + $filter_parts = Net_LDAP2_Util::split_attribute_string($matches[1], true, true); + if (count($filter_parts) != 3) { + return PEAR::raiseError("Filter parsing error: invalid filter syntax - unknown matching rule used"); + } else { + $filter_o = new Net_LDAP2_Filter(); + // [TODO]: Do we need to escape at all? what about *-chars user provide and that should remain special? + // I think, those prevent escaping! We need to check against PERL Net::LDAP! + // $value_arr = Net_LDAP2_Util::escape_filter_value(array($filter_parts[2])); + // $value = $value_arr[0]; + $value = $filter_parts[2]; + $filter_o->_filter = '('.$filter_parts[0].$filter_parts[1].$value.')'; + return $filter_o; + } + } + } + } else { + // ERROR: Filter components must be enclosed in round brackets + return PEAR::raiseError("Filter parsing error: invalid filter syntax - filter components must be enclosed in round brackets"); + } + } + + /** + * Get the string representation of this filter + * + * This method runs through all filter objects and creates + * the string representation of the filter. If this + * filter object is a leaf filter, then it will return + * the string representation of this filter. + * + * @return string|Net_LDAP2_Error + */ + public function asString() + { + if ($this->isLeaf()) { + $return = $this->_filter; + } else { + $return = ''; + foreach ($this->_subfilters as $filter) { + $return = $return.$filter->asString(); + } + $return = '(' . $this->_match . $return . ')'; + } + return $return; + } + + /** + * Alias for perl interface as_string() + * + * @see asString() + * @return string|Net_LDAP2_Error + */ + public function as_string() + { + return $this->asString(); + } + + /** + * Print the text representation of the filter to FH, or the currently selected output handle if FH is not given + * + * This method is only for compatibility to the perl interface. + * However, the original method was called "print" but due to PHP language restrictions, + * we can't have a print() method. + * + * @param resource $FH (optional) A filehandle resource + * + * @return true|Net_LDAP2_Error + */ + public function printMe($FH = false) + { + if (!is_resource($FH)) { + if (PEAR::isError($FH)) { + return $FH; + } + $filter_str = $this->asString(); + if (PEAR::isError($filter_str)) { + return $filter_str; + } else { + print($filter_str); + } + } else { + $filter_str = $this->asString(); + if (PEAR::isError($filter_str)) { + return $filter_str; + } else { + $res = @fwrite($FH, $this->asString()); + if ($res == false) { + return PEAR::raiseError("Unable to write filter string to filehandle \$FH!"); + } + } + } + return true; + } + + /** + * This can be used to escape a string to provide a valid LDAP-Filter. + * + * LDAP will only recognise certain characters as the + * character istself if they are properly escaped. This is + * what this method does. + * The method can be called statically, so you can use it outside + * for your own purposes (eg for escaping only parts of strings) + * + * In fact, this is just a shorthand to {@link Net_LDAP2_Util::escape_filter_value()}. + * For upward compatibiliy reasons you are strongly encouraged to use the escape + * methods provided by the Net_LDAP2_Util class. + * + * @param string $value Any string who should be escaped + * + * @static + * @return string The string $string, but escaped + * @deprecated Do not use this method anymore, instead use Net_LDAP2_Util::escape_filter_value() directly + */ + public static function escape($value) + { + $return = Net_LDAP2_Util::escape_filter_value(array($value)); + return $return[0]; + } + + /** + * Is this a container or a leaf filter object? + * + * @access protected + * @return boolean + */ + protected function isLeaf() + { + if (count($this->_subfilters) > 0) { + return false; // Container! + } else { + return true; // Leaf! + } + } + + /** + * Filter entries using this filter or see if a filter matches + * + * @todo Currently slow and naive implementation with preg_match, could be optimized (esp. begins, ends filters etc) + * @todo Currently only "="-based matches (equals, begins, ends, contains, any) implemented; Implement all the stuff! + * @todo Implement expert code with schema checks in case $entry is connected to a directory + * @param array|Net_LDAP2_Entry The entry (or array with entries) to check + * @param array If given, the array will be appended with entries who matched the filter. Return value is true if any entry matched. + * @return int|Net_LDAP2_Error Returns the number of matched entries or error + */ + function matches(&$entries, &$results=array()) { + $numOfMatches = 0; + + if (!is_array($entries)) { + $all_entries = array(&$entries); + } else { + $all_entries = &$entries; + } + + foreach ($all_entries as $entry) { + // look at the current entry and see if filter matches + + $entry_matched = false; + // if this is not a single component, do calculate all subfilters, + // then assert the partial results with the given combination modifier + if (!$this->isLeaf()) { + + // get partial results from subfilters + $partial_results = array(); + foreach ($this->_subfilters as $filter) { + $partial_results[] = $filter->matches($entry); + } + + // evaluate partial results using this filters combination rule + switch ($this->_match) { + case '!': + // result is the neagtive result of the assertion + $entry_matched = !$partial_results[0]; + break; + + case '&': + // all partial results have to be boolean-true + $entry_matched = !in_array(false, $partial_results); + break; + + case '|': + // at least one partial result has to be true + $entry_matched = in_array(true, $partial_results); + break; + } + + } else { + // Leaf filter: assert given entry + // [TODO]: Could be optimized to avoid preg_match especially with "ends", "begins" etc + + // Translate the LDAP-match to some preg_match expression and evaluate it + list($attribute, $match, $assertValue) = $this->getComponents(); + switch ($match) { + case '=': + $regexp = '/^'.str_replace('*', '.*', $assertValue).'$/i'; // not case sensitive unless specified by schema + $entry_matched = $entry->pregMatch($regexp, $attribute); + break; + + // ------------------------------------- + // [TODO]: implement <, >, <=, >= and =~ + // ------------------------------------- + + default: + $err = PEAR::raiseError("Net_LDAP2_Filter match error: unsupported match rule '$match'!"); + return $err; + } + + } + + // process filter matching result + if ($entry_matched) { + $numOfMatches++; + $results[] = $entry; + } + + } + + return $numOfMatches; + } + + + /** + * Retrieve this leaf-filters attribute, match and value component. + * + * For leaf filters, this returns array(attr, match, value). + * Match is be the logical operator, not the text representation, + * eg "=" instead of "equals". Note that some operators are really + * a combination of operator+value with wildcard, like + * "begins": That will return "=" with the value "value*"! + * + * For non-leaf filters this will drop an error. + * + * @todo $this->_match is not always available and thus not usable here; it would be great if it would set in the factory methods and constructor. + * @return array|Net_LDAP2_Error + */ + function getComponents() { + if ($this->isLeaf()) { + $raw_filter = preg_replace('/^\(|\)$/', '', $this->_filter); + $parts = Net_LDAP2_Util::split_attribute_string($raw_filter, true, true); + if (count($parts) != 3) { + return PEAR::raiseError("Net_LDAP2_Filter getComponents() error: invalid filter syntax - unknown matching rule used"); + } else { + return $parts; + } + } else { + return PEAR::raiseError('Net_LDAP2_Filter getComponents() call is invalid for non-leaf filters!'); + } + } + + +} +?>
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/Net/LDAP2/LDIF.php
Added
@@ -0,0 +1,925 @@ +<?php +/* vim: set expandtab tabstop=4 shiftwidth=4: */ +/** +* File containing the Net_LDAP2_LDIF interface class. +* +* PHP version 5 +* +* @category Net +* @package Net_LDAP2 +* @author Benedikt Hallinger <beni@php.net> +* @copyright 2009 Benedikt Hallinger +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id$ +* @link http://pear.php.net/package/Net_LDAP2/ +*/ + +/** +* Includes +*/ +require_once 'PEAR.php'; +require_once 'Net/LDAP2.php'; +require_once 'Net/LDAP2/Entry.php'; +require_once 'Net/LDAP2/Util.php'; + +/** +* LDIF capabilitys for Net_LDAP2, closely taken from PERLs Net::LDAP +* +* It provides a means to convert between Net_LDAP2_Entry objects and LDAP entries +* represented in LDIF format files. Reading and writing are supported and may +* manipulate single entries or lists of entries. +* +* Usage example: +* <code> +* // Read and parse an ldif-file into Net_LDAP2_Entry objects +* // and print out the DNs. Store the entries for later use. +* require 'Net/LDAP2/LDIF.php'; +* $options = array( +* 'onerror' => 'die' +* ); +* $entries = array(); +* $ldif = new Net_LDAP2_LDIF('test.ldif', 'r', $options); +* do { +* $entry = $ldif->read_entry(); +* $dn = $entry->dn(); +* echo " done building entry: $dn\n"; +* array_push($entries, $entry); +* } while (!$ldif->eof()); +* $ldif->done(); +* +* +* // write those entries to another file +* $ldif = new Net_LDAP2_LDIF('test.out.ldif', 'w', $options); +* $ldif->write_entry($entries); +* $ldif->done(); +* </code> +* +* @category Net +* @package Net_LDAP2 +* @author Benedikt Hallinger <beni@php.net> +* @license http://www.gnu.org/copyleft/lesser.html LGPL +* @link http://pear.php.net/package/Net_LDAP22/ +* @see http://www.ietf.org/rfc/rfc2849.txt +* @todo Error handling should be PEARified +* @todo LDAPv3 controls are not implemented yet +*/ +class Net_LDAP2_LDIF extends PEAR +{ + /** + * Options + * + * @access protected + * @var array + */ + protected $_options = array('encode' => 'base64', + 'onerror' => null, + 'change' => 0, + 'lowercase' => 0, + 'sort' => 0, + 'version' => null, + 'wrap' => 78, + 'raw' => '' + ); + + /** + * Errorcache + * + * @access protected + * @var array + */ + protected $_error = array('error' => null, + 'line' => 0 + ); + + /** + * Filehandle for read/write + * + * @access protected + * @var array + */ + protected $_FH = null; + + /** + * Says, if we opened the filehandle ourselves + * + * @access protected + * @var array + */ + protected $_FH_opened = false; + + /** + * Linecounter for input file handle + * + * @access protected + * @var array + */ + protected $_input_line = 0; + + /** + * counter for processed entries + * + * @access protected + * @var int + */ + protected $_entrynum = 0; + + /** + * Mode we are working in + * + * Either 'r', 'a' or 'w' + * + * @access protected + * @var string + */ + protected $_mode = false; + + /** + * Tells, if the LDIF version string was already written + * + * @access protected + * @var boolean + */ + protected $_version_written = false; + + /** + * Cache for lines that have build the current entry + * + * @access protected + * @var boolean + */ + protected $_lines_cur = array(); + + /** + * Cache for lines that will build the next entry + * + * @access protected + * @var boolean + */ + protected $_lines_next = array(); + + /** + * Open LDIF file for reading or for writing + * + * new (FILE): + * Open the file read-only. FILE may be the name of a file + * or an already open filehandle. + * If the file doesn't exist, it will be created if in write mode. + * + * new (FILE, MODE, OPTIONS): + * Open the file with the given MODE (see PHPs fopen()), eg "w" or "a". + * FILE may be the name of a file or an already open filehandle. + * PERLs Net_LDAP2 "FILE|" mode does not work curently. + * + * OPTIONS is an associative array and may contain: + * encode => 'none' | 'canonical' | 'base64' + * Some DN values in LDIF cannot be written verbatim and have to be encoded in some way: + * 'none' No encoding. + * 'canonical' See "canonical_dn()" in Net::LDAP::Util. + * 'base64' Use base64. (default, this differs from the Perl interface. + * The perl default is "none"!) + * + * onerror => 'die' | 'warn' | NULL + * Specify what happens when an error is detected. + * 'die' Net_LDAP2_LDIF will croak with an appropriate message. + * 'warn' Net_LDAP2_LDIF will warn (echo) with an appropriate message. + * NULL Net_LDAP2_LDIF will not warn (default), use error(). + * + * change => 1 + * Write entry changes to the LDIF file instead of the entries itself. I.e. write LDAP + * operations acting on the entries to the file instead of the entries contents. + * This writes the changes usually carried out by an update() to the LDIF file. + * + * lowercase => 1 + * Convert attribute names to lowercase when writing. + * + * sort => 1 + * Sort attribute names when writing entries according to the rule: + * objectclass first then all other attributes alphabetically sorted by attribute name + * + * version => '1' + * Set the LDIF version to write to the resulting LDIF file. + * According to RFC 2849 currently the only legal value for this option is 1. + * When this option is set Net_LDAP2_LDIF tries to adhere more strictly to + * the LDIF specification in RFC2489 in a few places. + * The default is NULL meaning no version information is written to the LDIF file. + * + * wrap => 78 + * Number of columns where output line wrapping shall occur. + * Default is 78. Setting it to 40 or lower inhibits wrapping. + * + * raw => REGEX + * Use REGEX to denote the names of attributes that are to be + * considered binary in search results if writing entries. + * Example: raw => "/(?i:^jpegPhoto|;binary)/i" + * + * @param string|ressource $file Filename or filehandle + * @param string $mode Mode to open filename + * @param array $options Options like described above + */ + public function __construct($file, $mode = 'r', $options = array()) + { + parent::__construct('Net_LDAP2_Error'); // default error class + + // First, parse options + // todo: maybe implement further checks on possible values + foreach ($options as $option => $value) { + if (!array_key_exists($option, $this->_options)) { + $this->dropError('Net_LDAP2_LDIF error: option '.$option.' not known!'); + return; + } else { + $this->_options[$option] = strtolower($value); + } + } + + // setup LDIF class + $this->version($this->_options['version']); + + // setup file mode + if (!preg_match('/^[rwa]\+?$/', $mode)) { + $this->dropError('Net_LDAP2_LDIF error: file mode '.$mode.' not supported!'); + } else { + $this->_mode = $mode; + + // setup filehandle + if (is_resource($file)) { + // TODO: checks on mode possible? + $this->_FH =& $file; + } else { + $imode = substr($this->_mode, 0, 1); + if ($imode == 'r') { + if (!file_exists($file)) { + $this->dropError('Unable to open '.$file.' for read: file not found'); + $this->_mode = false; + } + if (!is_readable($file)) { + $this->dropError('Unable to open '.$file.' for read: permission denied'); + $this->_mode = false; + } + } + + if (($imode == 'w' || $imode == 'a')) { + if (file_exists($file)) { + if (!is_writable($file)) { + $this->dropError('Unable to open '.$file.' for write: permission denied'); + $this->_mode = false; + } + } else { + if (!@touch($file)) { + $this->dropError('Unable to create '.$file.' for write: permission denied'); + $this->_mode = false; + } + } + } + + if ($this->_mode) { + $this->_FH = @fopen($file, $this->_mode); + if (false === $this->_FH) { + // Fallback; should never be reached if tests above are good enough! + $this->dropError('Net_LDAP2_LDIF error: Could not open file '.$file); + } else { + $this->_FH_opened = true; + } + } + } + } + } + + /** + * Read one entry from the file and return it as a Net::LDAP::Entry object. + * + * @return Net_LDAP2_Entry + */ + public function read_entry() + { + // read fresh lines, set them as current lines and create the entry + $attrs = $this->next_lines(true); + if (count($attrs) > 0) { + $this->_lines_cur = $attrs; + } + return $this->current_entry(); + } + + /** + * Returns true when the end of the file is reached. + * + * @return boolean + */ + public function eof() + { + return feof($this->_FH); + } + + /** + * Write the entry or entries to the LDIF file. + * + * If you want to build an LDIF file containing several entries AND + * you want to call write_entry() several times, you must open the filehandle + * in append mode ("a"), otherwise you will always get the last entry only. + * + * @param Net_LDAP2_Entry|array $entries Entry or array of entries + * + * @return void + * @todo implement operations on whole entries (adding a whole entry) + */ + public function write_entry($entries) + { + if (!is_array($entries)) { + $entries = array($entries); + } + + foreach ($entries as $entry) { + $this->_entrynum++; + if (!$entry instanceof Net_LDAP2_Entry) { + $this->dropError('Net_LDAP2_LDIF error: entry '.$this->_entrynum.' is not an Net_LDAP2_Entry object'); + } else { + if ($this->_options['change']) { + // LDIF change mode + // fetch change information from entry + $entry_attrs_changes = $entry->getChanges(); + $num_of_changes = count($entry_attrs_changes['add']) + + count($entry_attrs_changes['replace']) + + count($entry_attrs_changes['delete']); + + + $is_changed = ($num_of_changes > 0 || $entry->willBeDeleted() || $entry->willBeMoved()); + + // write version if not done yet + // also write DN of entry + if ($is_changed) { + if (!$this->_version_written) { + $this->write_version(); + } + $this->writeDN($entry->currentDN()); + } + + // process changes + // TODO: consider DN add! + if ($entry->willBeDeleted()) { + $this->writeLine("changetype: delete".PHP_EOL); + } elseif ($entry->willBeMoved()) { + $this->writeLine("changetype: modrdn".PHP_EOL); + $olddn = Net_LDAP2_Util::ldap_explode_dn($entry->currentDN(), array('casefold' => 'none')); // maybe gives a bug if using multivalued RDNs + $oldrdn = array_shift($olddn); + $oldparent = implode(',', $olddn); + $newdn = Net_LDAP2_Util::ldap_explode_dn($entry->dn(), array('casefold' => 'none')); // maybe gives a bug if using multivalued RDNs + $rdn = array_shift($newdn); + $parent = implode(',', $newdn); + $this->writeLine("newrdn: ".$rdn.PHP_EOL); + $this->writeLine("deleteoldrdn: 1".PHP_EOL); + if ($parent !== $oldparent) { + $this->writeLine("newsuperior: ".$parent.PHP_EOL); + } + // TODO: What if the entry has attribute changes as well? + // I think we should check for that and make a dummy + // entry with the changes that is written to the LDIF file + } elseif ($num_of_changes > 0) { + // write attribute change data + $this->writeLine("changetype: modify".PHP_EOL); + foreach ($entry_attrs_changes as $changetype => $entry_attrs) { + foreach ($entry_attrs as $attr_name => $attr_values) { + $this->writeLine("$changetype: $attr_name".PHP_EOL); + if ($attr_values !== null) $this->writeAttribute($attr_name, $attr_values, $changetype); + $this->writeLine("-".PHP_EOL); + } + } + } + + // finish this entrys data if we had changes + if ($is_changed) { + $this->finishEntry(); + } + } else { + // LDIF-content mode + // fetch attributes for further processing + $entry_attrs = $entry->getValues(); + + // sort and put objectclass-attrs to first position + if ($this->_options['sort']) { + ksort($entry_attrs); + if (array_key_exists('objectclass', $entry_attrs)) { + $oc = $entry_attrs['objectclass']; + unset($entry_attrs['objectclass']); + $entry_attrs = array_merge(array('objectclass' => $oc), $entry_attrs); + } + } + + // write data + if (!$this->_version_written) { + $this->write_version(); + } + $this->writeDN($entry->dn()); + foreach ($entry_attrs as $attr_name => $attr_values) { + $this->writeAttribute($attr_name, $attr_values); + } + $this->finishEntry(); + } + } + } + } + + /** + * Write version to LDIF + * + * If the object's version is defined, this method allows to explicitely write the version before an entry is written. + * If not called explicitely, it gets called automatically when writing the first entry. + * + * @return void + */ + public function write_version() + { + $this->_version_written = true; + if (!is_null($this->version())) { + return $this->writeLine('version: '.$this->version().PHP_EOL, 'Net_LDAP2_LDIF error: unable to write version'); + } + } + + /** + * Get or set LDIF version + * + * If called without arguments it returns the version of the LDIF file or NULL if no version has been set. + * If called with an argument it sets the LDIF version to VERSION. + * According to RFC 2849 currently the only legal value for VERSION is 1. + * + * @param int $version (optional) LDIF version to set + * + * @return int + */ + public function version($version = null) + { + if ($version !== null) { + if ($version != 1) { + $this->dropError('Net_LDAP2_LDIF error: illegal LDIF version set'); + } else { + $this->_options['version'] = $version; + } + } + return $this->_options['version']; + } + + /** + * Returns the file handle the Net_LDAP2_LDIF object reads from or writes to. + * + * You can, for example, use this to fetch the content of the LDIF file yourself + * + * @return null|resource + */ + public function &handle() + { + if (!is_resource($this->_FH)) { + $this->dropError('Net_LDAP2_LDIF error: invalid file resource'); + $null = null; + return $null; + } else { + return $this->_FH; + } + } + + /** + * Clean up + * + * This method signals that the LDIF object is no longer needed. + * You can use this to free up some memory and close the file handle. + * The file handle is only closed, if it was opened from Net_LDAP2_LDIF. + * + * @return void + */ + public function done() + { + // close FH if we opened it + if ($this->_FH_opened) { + fclose($this->handle()); + } + + // free variables + foreach (get_object_vars($this) as $name => $value) { + unset($this->$name); + } + } + + /** + * Returns last error message if error was found. + * + * Example: + * <code> + * $ldif->someAction(); + * if ($ldif->error()) { + * echo "Error: ".$ldif->error()." at input line: ".$ldif->error_lines(); + * } + * </code> + * + * @param boolean $as_string If set to true, only the message is returned + * + * @return false|Net_LDAP2_Error + */ + public function error($as_string = false) + { + if (Net_LDAP2::isError($this->_error['error'])) { + return ($as_string)? $this->_error['error']->getMessage() : $this->_error['error']; + } else { + return false; + } + } + + /** + * Returns lines that resulted in error. + * + * Perl returns an array of faulty lines in list context, + * but we always just return an int because of PHPs language. + * + * @return int + */ + public function error_lines() + { + return $this->_error['line']; + } + + /** + * Returns the current Net::LDAP::Entry object. + * + * @return Net_LDAP2_Entry|false + */ + public function current_entry() + { + return $this->parseLines($this->current_lines()); + } + + /** + * Parse LDIF lines of one entry into an Net_LDAP2_Entry object + * + * @param array $lines LDIF lines for one entry + * + * @return Net_LDAP2_Entry|false Net_LDAP2_Entry object for those lines + * @todo what about file inclusions and urls? "jpegphoto:< file:///usr/local/directory/photos/fiona.jpg" + */ + public function parseLines($lines) + { + // parse lines into an array of attributes and build the entry + $attributes = array(); + $dn = false; + foreach ($lines as $line) { + if (preg_match('/^(\w+(;binary)?)(:|::|:<)\s(.+)$/', $line, $matches)) { + $attr =& $matches[1] . $matches[2]; + $delim =& $matches[3]; + $data =& $matches[4]; + + if ($delim == ':') { + // normal data + $attributes[$attr][] = $data; + } elseif ($delim == '::') { + // base64 data + $attributes[$attr][] = base64_decode($data); + } elseif ($delim == ':<') { + // file inclusion + // TODO: Is this the job of the LDAP-client or the server? + $this->dropError('File inclusions are currently not supported'); + //$attributes[$attr][] = ...; + } else { + // since the pattern above, the delimeter cannot be something else. + $this->dropError('Net_LDAP2_LDIF parsing error: invalid syntax at parsing entry line: '.$line); + continue; + } + + if (strtolower($attr) == 'dn') { + // DN line detected + $dn = $attributes[$attr][0]; // save possibly decoded DN + unset($attributes[$attr]); // remove wrongly added "dn: " attribute + } + } else { + // line not in "attr: value" format -> ignore + // maybe we should rise an error here, but this should be covered by + // next_lines() already. A problem arises, if users try to feed data of + // several entries to this method - the resulting entry will + // get wrong attributes. However, this is already mentioned in the + // methods documentation above. + } + } + + if (false === $dn) { + $this->dropError('Net_LDAP2_LDIF parsing error: unable to detect DN for entry'); + return false; + } else { + $newentry = Net_LDAP2_Entry::createFresh($dn, $attributes); + return $newentry; + } + } + + /** + * Returns the lines that generated the current Net::LDAP::Entry object. + * + * Note that this returns an empty array if no lines have been read so far. + * + * @return array Array of lines + */ + public function current_lines() + { + return $this->_lines_cur; + } + + /** + * Returns the lines that will generate the next Net::LDAP::Entry object. + * + * If you set $force to TRUE then you can iterate over the lines that build + * up entries manually. Otherwise, iterating is done using {@link read_entry()}. + * Force will move the file pointer forward, thus returning the next entries lines. + * + * Wrapped lines will be unwrapped. Comments are stripped. + * + * @param boolean $force Set this to true if you want to iterate over the lines manually + * + * @return array + */ + public function next_lines($force = false) + { + // if we already have those lines, just return them, otherwise read + if (count($this->_lines_next) == 0 || $force) { + $this->_lines_next = array(); // empty in case something was left (if used $force) + $entry_done = false; + $fh = &$this->handle(); + $commentmode = false; // if we are in an comment, for wrapping purposes + $datalines_read = 0; // how many lines with data we have read + + while (!$entry_done && !$this->eof()) { + $this->_input_line++; + // Read line. Remove line endings, we want only data; + // this is okay since ending spaces should be encoded + $data = rtrim(fgets($fh)); + if ($data === false) { + // error only, if EOF not reached after fgets() call + if (!$this->eof()) { + $this->dropError('Net_LDAP2_LDIF error: error reading from file at input line '.$this->_input_line, $this->_input_line); + } + break; + } else { + if (count($this->_lines_next) > 0 && preg_match('/^$/', $data)) { + // Entry is finished if we have an empty line after we had data + $entry_done = true; + + // Look ahead if the next EOF is nearby. Comments and empty + // lines at the file end may cause problems otherwise + $current_pos = ftell($fh); + $data = fgets($fh); + while (!feof($fh)) { + if (preg_match('/^\s*$/', $data) || preg_match('/^#/', $data)) { + // only empty lines or comments, continue to seek + // TODO: Known bug: Wrappings for comments are okay but are treaten as + // error, since we do not honor comment mode here. + // This should be a very theoretically case, however + // i am willing to fix this if really necessary. + $this->_input_line++; + $current_pos = ftell($fh); + $data = fgets($fh); + } else { + // Data found if non emtpy line and not a comment!! + // Rewind to position prior last read and stop lookahead + fseek($fh, $current_pos); + break; + } + } + // now we have either the file pointer at the beginning of + // a new data position or at the end of file causing feof() to return true + + } else { + // build lines + if (preg_match('/^version:\s(.+)$/', $data, $match)) { + // version statement, set version + $this->version($match[1]); + } elseif (preg_match('/^\w+(;binary)?::?\s.+$/', $data)) { + // normal attribute: add line + $commentmode = false; + $this->_lines_next[] = trim($data); + $datalines_read++; + } elseif (preg_match('/^\s(.+)$/', $data, $matches)) { + // wrapped data: unwrap if not in comment mode + // note that the \s above is some more liberal than + // the RFC requests as it also matches tabs etc. + if (!$commentmode) { + if ($datalines_read == 0) { + // first line of entry: wrapped data is illegal + $this->dropError('Net_LDAP2_LDIF error: illegal wrapping at input line '.$this->_input_line, $this->_input_line); + } else { + $last = array_pop($this->_lines_next); + $last = $last.$matches[1]; + $this->_lines_next[] = $last; + $datalines_read++; + } + } + } elseif (preg_match('/^#/', $data)) { + // LDIF comments + $commentmode = true; + } elseif (preg_match('/^\s*$/', $data)) { + // empty line but we had no data for this + // entry, so just ignore this line + $commentmode = false; + } else { + $this->dropError('Net_LDAP2_LDIF error: invalid syntax at input line '.$this->_input_line, $this->_input_line); + continue; + } + + } + } + } + } + return $this->_lines_next; + } + + /** + * Convert an attribute and value to LDIF string representation + * + * It honors correct encoding of values according to RFC 2849. + * Line wrapping will occur at the configured maximum but only if + * the value is greater than 40 chars. + * + * @param string $attr_name Name of the attribute + * @param string $attr_value Value of the attribute + * + * @access protected + * @return string LDIF string for that attribute and value + */ + protected function convertAttribute($attr_name, $attr_value) + { + // Handle empty attribute or process + if (strlen($attr_value) == 0) { + $attr_value = " "; + } else { + $base64 = false; + // ASCII-chars that are NOT safe for the + // start and for being inside the value. + // These are the int values of those chars. + $unsafe_init = array(0, 10, 13, 32, 58, 60); + $unsafe = array(0, 10, 13); + + // Test for illegal init char + $init_ord = ord(substr($attr_value, 0, 1)); + if ($init_ord > 127 || in_array($init_ord, $unsafe_init)) { + $base64 = true; + } + + // Test for illegal content char + for ($i = 0; $i < strlen($attr_value); $i++) { + $char_ord = ord(substr($attr_value, $i, 1)); + if ($char_ord > 127 || in_array($char_ord, $unsafe)) { + $base64 = true; + } + } + + // Test for ending space + if (substr($attr_value, -1) == ' ') { + $base64 = true; + } + + // If converting is needed, do it + // Either we have some special chars or a matching "raw" regex + if ($base64 || ($this->_options['raw'] && preg_match($this->_options['raw'], $attr_name))) { + $attr_name .= ':'; + $attr_value = base64_encode($attr_value); + } + + // Lowercase attr names if requested + if ($this->_options['lowercase']) $attr_name = strtolower($attr_name); + + // Handle line wrapping + if ($this->_options['wrap'] > 40 && strlen($attr_value) > $this->_options['wrap']) { + $attr_value = wordwrap($attr_value, $this->_options['wrap'], PHP_EOL." ", true); + } + } + + return $attr_name.': '.$attr_value; + } + + /** + * Convert an entries DN to LDIF string representation + * + * It honors correct encoding of values according to RFC 2849. + * + * @param string $dn UTF8-Encoded DN + * + * @access protected + * @return string LDIF string for that DN + * @todo I am not sure, if the UTF8 stuff is correctly handled right now + */ + protected function convertDN($dn) + { + $base64 = false; + // ASCII-chars that are NOT safe for the + // start and for being inside the dn. + // These are the int values of those chars. + $unsafe_init = array(0, 10, 13, 32, 58, 60); + $unsafe = array(0, 10, 13); + + // Test for illegal init char + $init_ord = ord(substr($dn, 0, 1)); + if ($init_ord >= 127 || in_array($init_ord, $unsafe_init)) { + $base64 = true; + } + + // Test for illegal content char + for ($i = 0; $i < strlen($dn); $i++) { + $char = substr($dn, $i, 1); + if (ord($char) >= 127 || in_array($init_ord, $unsafe)) { + $base64 = true; + } + } + + // Test for ending space + if (substr($dn, -1) == ' ') { + $base64 = true; + } + + // if converting is needed, do it + return ($base64)? 'dn:: '.base64_encode($dn) : 'dn: '.$dn; + } + + /** + * Writes an attribute to the filehandle + * + * @param string $attr_name Name of the attribute + * @param string|array $attr_values Single attribute value or array with attribute values + * + * @access protected + * @return void + */ + protected function writeAttribute($attr_name, $attr_values) + { + // write out attribute content + if (!is_array($attr_values)) { + $attr_values = array($attr_values); + } + foreach ($attr_values as $attr_val) { + $line = $this->convertAttribute($attr_name, $attr_val).PHP_EOL; + $this->writeLine($line, 'Net_LDAP2_LDIF error: unable to write attribute '.$attr_name.' of entry '.$this->_entrynum); + } + } + + /** + * Writes a DN to the filehandle + * + * @param string $dn DN to write + * + * @access protected + * @return void + */ + protected function writeDN($dn) + { + // prepare DN + if ($this->_options['encode'] == 'base64') { + $dn = $this->convertDN($dn).PHP_EOL; + } elseif ($this->_options['encode'] == 'canonical') { + $dn = Net_LDAP2_Util::canonical_dn($dn, array('casefold' => 'none')).PHP_EOL; + } else { + $dn = $dn.PHP_EOL; + } + $this->writeLine($dn, 'Net_LDAP2_LDIF error: unable to write DN of entry '.$this->_entrynum); + } + + /** + * Finishes an LDIF entry + * + * @access protected + * @return void + */ + protected function finishEntry() + { + $this->writeLine(PHP_EOL, 'Net_LDAP2_LDIF error: unable to close entry '.$this->_entrynum); + } + + /** + * Just write an arbitary line to the filehandle + * + * @param string $line Content to write + * @param string $error If error occurs, drop this message + * + * @access protected + * @return true|false + */ + protected function writeLine($line, $error = 'Net_LDAP2_LDIF error: unable to write to filehandle') + { + if (is_resource($this->handle()) && fwrite($this->handle(), $line, strlen($line)) === false) { + $this->dropError($error); + return false; + } else { + return true; + } + } + + /** + * Optionally raises an error and pushes the error on the error cache + * + * @param string $msg Errortext + * @param int $line Line in the LDIF that caused the error + * + * @access protected + * @return void + */ + protected function dropError($msg, $line = null) + { + $this->_error['error'] = new Net_LDAP2_Error($msg); + if ($line !== null) $this->_error['line'] = $line; + + if ($this->_options['onerror'] == 'die') { + die($msg.PHP_EOL); + } elseif ($this->_options['onerror'] == 'warn') { + echo $msg.PHP_EOL; + } + } +} +?>
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/Net/LDAP2/RootDSE.php
Added
@@ -0,0 +1,240 @@ +<?php +/* vim: set expandtab tabstop=4 shiftwidth=4: */ +/** +* File containing the Net_LDAP2_RootDSE interface class. +* +* PHP version 5 +* +* @category Net +* @package Net_LDAP2 +* @author Jan Wagner <wagner@netsols.de> +* @copyright 2009 Jan Wagner +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id$ +* @link http://pear.php.net/package/Net_LDAP2/ +*/ + +/** +* Includes +*/ +require_once 'PEAR.php'; + +/** +* Getting the rootDSE entry of a LDAP server +* +* @category Net +* @package Net_LDAP2 +* @author Jan Wagner <wagner@netsols.de> +* @license http://www.gnu.org/copyleft/lesser.html LGPL +* @link http://pear.php.net/package/Net_LDAP22/ +*/ +class Net_LDAP2_RootDSE extends PEAR +{ + /** + * @access protected + * @var object Net_LDAP2_Entry + **/ + protected $_entry; + + /** + * Class constructor + * + * @param Net_LDAP2_Entry &$entry Net_LDAP2_Entry object of the RootDSE + */ + public function __construct(&$entry) + { + $this->_entry = $entry; + } + + /** + * Fetches a RootDSE object from an LDAP connection + * + * @param Net_LDAP2 $ldap Directory from which the RootDSE should be fetched + * @param array $attrs Array of attributes to search for + * + * @access static + * @return Net_LDAP2_RootDSE|Net_LDAP2_Error + */ + public static function fetch($ldap, $attrs = null) + { + if (!$ldap instanceof Net_LDAP2) { + return PEAR::raiseError("Unable to fetch Schema: Parameter \$ldap must be a Net_LDAP2 object!"); + } + + if (is_array($attrs) && count($attrs) > 0 ) { + $attributes = $attrs; + } else { + $attributes = array('vendorName', + 'vendorVersion', + 'namingContexts', + 'altServer', + 'supportedExtension', + 'supportedControl', + 'supportedSASLMechanisms', + 'supportedLDAPVersion', + 'subschemaSubentry' ); + } + $result = $ldap->search('', '(objectClass=*)', array('attributes' => $attributes, 'scope' => 'base')); + if (self::isError($result)) { + return $result; + } + $entry = $result->shiftEntry(); + if (false === $entry) { + return PEAR::raiseError('Could not fetch RootDSE entry'); + } + $ret = new Net_LDAP2_RootDSE($entry); + return $ret; + } + + /** + * Gets the requested attribute value + * + * Same usuage as {@link Net_LDAP2_Entry::getValue()} + * + * @param string $attr Attribute name + * @param array $options Array of options + * + * @access public + * @return mixed Net_LDAP2_Error object or attribute values + * @see Net_LDAP2_Entry::get_value() + */ + public function getValue($attr = '', $options = '') + { + return $this->_entry->get_value($attr, $options); + } + + /** + * Alias function of getValue() for perl-ldap interface + * + * @see getValue() + * @return mixed + */ + public function get_value() + { + $args = func_get_args(); + return call_user_func_array(array( &$this, 'getValue' ), $args); + } + + /** + * Determines if the extension is supported + * + * @param array $oids Array of oids to check + * + * @access public + * @return boolean + */ + public function supportedExtension($oids) + { + return $this->checkAttr($oids, 'supportedExtension'); + } + + /** + * Alias function of supportedExtension() for perl-ldap interface + * + * @see supportedExtension() + * @return boolean + */ + public function supported_extension() + { + $args = func_get_args(); + return call_user_func_array(array( &$this, 'supportedExtension'), $args); + } + + /** + * Determines if the version is supported + * + * @param array $versions Versions to check + * + * @access public + * @return boolean + */ + public function supportedVersion($versions) + { + return $this->checkAttr($versions, 'supportedLDAPVersion'); + } + + /** + * Alias function of supportedVersion() for perl-ldap interface + * + * @see supportedVersion() + * @return boolean + */ + public function supported_version() + { + $args = func_get_args(); + return call_user_func_array(array(&$this, 'supportedVersion'), $args); + } + + /** + * Determines if the control is supported + * + * @param array $oids Control oids to check + * + * @access public + * @return boolean + */ + public function supportedControl($oids) + { + return $this->checkAttr($oids, 'supportedControl'); + } + + /** + * Alias function of supportedControl() for perl-ldap interface + * + * @see supportedControl() + * @return boolean + */ + public function supported_control() + { + $args = func_get_args(); + return call_user_func_array(array(&$this, 'supportedControl' ), $args); + } + + /** + * Determines if the sasl mechanism is supported + * + * @param array $mechlist SASL mechanisms to check + * + * @access public + * @return boolean + */ + public function supportedSASLMechanism($mechlist) + { + return $this->checkAttr($mechlist, 'supportedSASLMechanisms'); + } + + /** + * Alias function of supportedSASLMechanism() for perl-ldap interface + * + * @see supportedSASLMechanism() + * @return boolean + */ + public function supported_sasl_mechanism() + { + $args = func_get_args(); + return call_user_func_array(array(&$this, 'supportedSASLMechanism'), $args); + } + + /** + * Checks for existance of value in attribute + * + * @param array $values values to check + * @param string $attr attribute name + * + * @access protected + * @return boolean + */ + protected function checkAttr($values, $attr) + { + if (!is_array($values)) $values = array($values); + + foreach ($values as $value) { + if (!@in_array($value, $this->get_value($attr, 'all'))) { + return false; + } + } + return true; + } +} + +?>
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/Net/LDAP2/Schema.php
Added
@@ -0,0 +1,622 @@ +<?php +/* vim: set expandtab tabstop=4 shiftwidth=4: */ +/** +* File containing the Net_LDAP2_Schema interface class. +* +* PHP version 5 +* +* @category Net +* @package Net_LDAP2 +* @author Jan Wagner <wagner@netsols.de> +* @author Benedikt Hallinger <beni@php.net> +* @copyright 2009 Jan Wagner, Benedikt Hallinger +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id$ +* @link http://pear.php.net/package/Net_LDAP2/ +* @todo see the comment at the end of the file +*/ + +/** +* Includes +*/ +require_once 'PEAR.php'; + +/** +* Syntax definitions +* +* Please don't forget to add binary attributes to isBinary() below +* to support proper value fetching from Net_LDAP2_Entry +*/ +define('NET_LDAP2_SYNTAX_BOOLEAN', '1.3.6.1.4.1.1466.115.121.1.7'); +define('NET_LDAP2_SYNTAX_DIRECTORY_STRING', '1.3.6.1.4.1.1466.115.121.1.15'); +define('NET_LDAP2_SYNTAX_DISTINGUISHED_NAME', '1.3.6.1.4.1.1466.115.121.1.12'); +define('NET_LDAP2_SYNTAX_INTEGER', '1.3.6.1.4.1.1466.115.121.1.27'); +define('NET_LDAP2_SYNTAX_JPEG', '1.3.6.1.4.1.1466.115.121.1.28'); +define('NET_LDAP2_SYNTAX_NUMERIC_STRING', '1.3.6.1.4.1.1466.115.121.1.36'); +define('NET_LDAP2_SYNTAX_OID', '1.3.6.1.4.1.1466.115.121.1.38'); +define('NET_LDAP2_SYNTAX_OCTET_STRING', '1.3.6.1.4.1.1466.115.121.1.40'); + +/** +* Load an LDAP Schema and provide information +* +* This class takes a Subschema entry, parses this information +* and makes it available in an array. Most of the code has been +* inspired by perl-ldap( http://perl-ldap.sourceforge.net). +* You will find portions of their implementation in here. +* +* @category Net +* @package Net_LDAP2 +* @author Jan Wagner <wagner@netsols.de> +* @author Benedikt Hallinger <beni@php.net> +* @license http://www.gnu.org/copyleft/lesser.html LGPL +* @link http://pear.php.net/package/Net_LDAP22/ +*/ +class Net_LDAP2_Schema extends PEAR +{ + /** + * Map of entry types to ldap attributes of subschema entry + * + * @access public + * @var array + */ + public $types = array( + 'attribute' => 'attributeTypes', + 'ditcontentrule' => 'dITContentRules', + 'ditstructurerule' => 'dITStructureRules', + 'matchingrule' => 'matchingRules', + 'matchingruleuse' => 'matchingRuleUse', + 'nameform' => 'nameForms', + 'objectclass' => 'objectClasses', + 'syntax' => 'ldapSyntaxes' + ); + + /** + * Array of entries belonging to this type + * + * @access protected + * @var array + */ + protected $_attributeTypes = array(); + protected $_matchingRules = array(); + protected $_matchingRuleUse = array(); + protected $_ldapSyntaxes = array(); + protected $_objectClasses = array(); + protected $_dITContentRules = array(); + protected $_dITStructureRules = array(); + protected $_nameForms = array(); + + + /** + * hash of all fetched oids + * + * @access protected + * @var array + */ + protected $_oids = array(); + + /** + * Tells if the schema is initialized + * + * @access protected + * @var boolean + * @see parse(), get() + */ + protected $_initialized = false; + + + /** + * Constructor of the class + * + * @access protected + */ + public function __construct() + { + parent::__construct('Net_LDAP2_Error'); // default error class + } + + /** + * Fetch the Schema from an LDAP connection + * + * @param Net_LDAP2 $ldap LDAP connection + * @param string $dn (optional) Subschema entry dn + * + * @access public + * @return Net_LDAP2_Schema|NET_LDAP2_Error + */ + public static function fetch($ldap, $dn = null) + { + if (!$ldap instanceof Net_LDAP2) { + return PEAR::raiseError("Unable to fetch Schema: Parameter \$ldap must be a Net_LDAP2 object!"); + } + + $schema_o = new Net_LDAP2_Schema(); + + if (is_null($dn)) { + // get the subschema entry via root dse + $dse = $ldap->rootDSE(array('subschemaSubentry')); + if (false == Net_LDAP2::isError($dse)) { + $base = $dse->getValue('subschemaSubentry', 'single'); + if (!Net_LDAP2::isError($base)) { + $dn = $base; + } + } + } + + // Support for buggy LDAP servers (e.g. Siemens DirX 6.x) that incorrectly + // call this entry subSchemaSubentry instead of subschemaSubentry. + // Note the correct case/spelling as per RFC 2251. + if (is_null($dn)) { + // get the subschema entry via root dse + $dse = $ldap->rootDSE(array('subSchemaSubentry')); + if (false == Net_LDAP2::isError($dse)) { + $base = $dse->getValue('subSchemaSubentry', 'single'); + if (!Net_LDAP2::isError($base)) { + $dn = $base; + } + } + } + + // Final fallback case where there is no subschemaSubentry attribute + // in the root DSE (this is a bug for an LDAP v3 server so report this + // to your LDAP vendor if you get this far). + if (is_null($dn)) { + $dn = 'cn=Subschema'; + } + + // fetch the subschema entry + $result = $ldap->search($dn, '(objectClass=*)', + array('attributes' => array_values($schema_o->types), + 'scope' => 'base')); + if (Net_LDAP2::isError($result)) { + return PEAR::raiseError('Could not fetch Subschema entry: '.$result->getMessage()); + } + + $entry = $result->shiftEntry(); + if (!$entry instanceof Net_LDAP2_Entry) { + if ($entry instanceof Net_LDAP2_Error) { + return PEAR::raiseError('Could not fetch Subschema entry: '.$entry->getMessage()); + } else { + return PEAR::raiseError('Could not fetch Subschema entry (search returned '.$result->count().' entries. Check parameter \'basedn\')'); + } + } + + $schema_o->parse($entry); + return $schema_o; + } + + /** + * Return a hash of entries for the given type + * + * Returns a hash of entry for the givene type. Types may be: + * objectclasses, attributes, ditcontentrules, ditstructurerules, matchingrules, + * matchingruleuses, nameforms, syntaxes + * + * @param string $type Type to fetch + * + * @access public + * @return array|Net_LDAP2_Error Array or Net_LDAP2_Error + */ + public function &getAll($type) + { + $map = array('objectclasses' => &$this->_objectClasses, + 'attributes' => &$this->_attributeTypes, + 'ditcontentrules' => &$this->_dITContentRules, + 'ditstructurerules' => &$this->_dITStructureRules, + 'matchingrules' => &$this->_matchingRules, + 'matchingruleuses' => &$this->_matchingRuleUse, + 'nameforms' => &$this->_nameForms, + 'syntaxes' => &$this->_ldapSyntaxes ); + + $key = strtolower($type); + $ret = ((key_exists($key, $map)) ? $map[$key] : PEAR::raiseError("Unknown type $type")); + return $ret; + } + + /** + * Return a specific entry + * + * @param string $type Type of name + * @param string $name Name or OID to fetch + * + * @access public + * @return mixed Entry or Net_LDAP2_Error + */ + public function &get($type, $name) + { + if ($this->_initialized) { + $type = strtolower($type); + if (false == key_exists($type, $this->types)) { + return PEAR::raiseError("No such type $type"); + } + + $name = strtolower($name); + $type_var = &$this->{'_' . $this->types[$type]}; + + if (key_exists($name, $type_var)) { + return $type_var[$name]; + } elseif (key_exists($name, $this->_oids) && $this->_oids[$name]['type'] == $type) { + return $this->_oids[$name]; + } else { + return PEAR::raiseError("Could not find $type $name"); + } + } else { + $return = null; + return $return; + } + } + + + /** + * Fetches attributes that MAY be present in the given objectclass + * + * @param string $oc Name or OID of objectclass + * + * @access public + * @return array|Net_LDAP2_Error Array with attributes or Net_LDAP2_Error + */ + public function may($oc) + { + return $this->_getAttr($oc, 'may'); + } + + /** + * Fetches attributes that MUST be present in the given objectclass + * + * @param string $oc Name or OID of objectclass + * + * @access public + * @return array|Net_LDAP2_Error Array with attributes or Net_LDAP2_Error + */ + public function must($oc) + { + return $this->_getAttr($oc, 'must'); + } + + /** + * Fetches the given attribute from the given objectclass + * + * @param string $oc Name or OID of objectclass + * @param string $attr Name of attribute to fetch + * + * @access protected + * @return array|Net_LDAP2_Error The attribute or Net_LDAP2_Error + */ + protected function _getAttr($oc, $attr) + { + $oc = strtolower($oc); + if (key_exists($oc, $this->_objectClasses) && key_exists($attr, $this->_objectClasses[$oc])) { + return $this->_objectClasses[$oc][$attr]; + } elseif (key_exists($oc, $this->_oids) && + $this->_oids[$oc]['type'] == 'objectclass' && + key_exists($attr, $this->_oids[$oc])) { + return $this->_oids[$oc][$attr]; + } else { + return PEAR::raiseError("Could not find $attr attributes for $oc "); + } + } + + /** + * Returns the name(s) of the immediate superclass(es) + * + * @param string $oc Name or OID of objectclass + * + * @access public + * @return array|Net_LDAP2_Error Array of names or Net_LDAP2_Error + */ + public function superclass($oc) + { + $o = $this->get('objectclass', $oc); + if (Net_LDAP2::isError($o)) { + return $o; + } + return (key_exists('sup', $o) ? $o['sup'] : array()); + } + + /** + * Parses the schema of the given Subschema entry + * + * @param Net_LDAP2_Entry &$entry Subschema entry + * + * @access public + * @return void + */ + public function parse(&$entry) + { + foreach ($this->types as $type => $attr) { + // initialize map type to entry + $type_var = '_' . $attr; + $this->{$type_var} = array(); + + // get values for this type + if ($entry->exists($attr)) { + $values = $entry->getValue($attr); + if (is_array($values)) { + foreach ($values as $value) { + + unset($schema_entry); // this was a real mess without it + + // get the schema entry + $schema_entry = $this->_parse_entry($value); + + // set the type + $schema_entry['type'] = $type; + + // save a ref in $_oids + $this->_oids[$schema_entry['oid']] = &$schema_entry; + + // save refs for all names in type map + $names = $schema_entry['aliases']; + array_push($names, $schema_entry['name']); + foreach ($names as $name) { + $this->{$type_var}[strtolower($name)] = &$schema_entry; + } + } + } + } + } + $this->_initialized = true; + } + + /** + * Parses an attribute value into a schema entry + * + * @param string $value Attribute value + * + * @access protected + * @return array|false Schema entry array or false + */ + protected function &_parse_entry($value) + { + // tokens that have no value associated + $noValue = array('single-value', + 'obsolete', + 'collective', + 'no-user-modification', + 'abstract', + 'structural', + 'auxiliary'); + + // tokens that can have multiple values + $multiValue = array('must', 'may', 'sup'); + + $schema_entry = array('aliases' => array()); // initilization + + $tokens = $this->_tokenize($value); // get an array of tokens + + // remove surrounding brackets + if ($tokens[0] == '(') array_shift($tokens); + if ($tokens[count($tokens) - 1] == ')') array_pop($tokens); // -1 doesnt work on arrays :-( + + $schema_entry['oid'] = array_shift($tokens); // first token is the oid + + // cycle over the tokens until none are left + while (count($tokens) > 0) { + $token = strtolower(array_shift($tokens)); + if (in_array($token, $noValue)) { + $schema_entry[$token] = 1; // single value token + } else { + // this one follows a string or a list if it is multivalued + if (($schema_entry[$token] = array_shift($tokens)) == '(') { + // this creates the list of values and cycles through the tokens + // until the end of the list is reached ')' + $schema_entry[$token] = array(); + while ($tmp = array_shift($tokens)) { + if ($tmp == ')') break; + if ($tmp != '$') array_push($schema_entry[$token], $tmp); + } + } + // create a array if the value should be multivalued but was not + if (in_array($token, $multiValue) && !is_array($schema_entry[$token])) { + $schema_entry[$token] = array($schema_entry[$token]); + } + } + } + // get max length from syntax + if (key_exists('syntax', $schema_entry)) { + if (preg_match('/{(\d+)}/', $schema_entry['syntax'], $matches)) { + $schema_entry['max_length'] = $matches[1]; + } + } + // force a name + if (empty($schema_entry['name'])) { + $schema_entry['name'] = $schema_entry['oid']; + } + // make one name the default and put the other ones into aliases + if (is_array($schema_entry['name'])) { + $aliases = $schema_entry['name']; + $schema_entry['name'] = array_shift($aliases); + $schema_entry['aliases'] = $aliases; + } + return $schema_entry; + } + + /** + * Tokenizes the given value into an array of tokens + * + * @param string $value String to parse + * + * @access protected + * @return array Array of tokens + */ + protected function _tokenize($value) + { + $tokens = array(); // array of tokens + $matches = array(); // matches[0] full pattern match, [1,2,3] subpatterns + + // this one is taken from perl-ldap, modified for php + $pattern = "/\s* (?:([()]) | ([^'\s()]+) | '((?:[^']+|'[^\s)])*)') \s*/x"; + + /** + * This one matches one big pattern wherin only one of the three subpatterns matched + * We are interested in the subpatterns that matched. If it matched its value will be + * non-empty and so it is a token. Tokens may be round brackets, a string, or a string + * enclosed by ' + */ + preg_match_all($pattern, $value, $matches); + + for ($i = 0; $i < count($matches[0]); $i++) { // number of tokens (full pattern match) + for ($j = 1; $j < 4; $j++) { // each subpattern + if (null != trim($matches[$j][$i])) { // pattern match in this subpattern + $tokens[$i] = trim($matches[$j][$i]); // this is the token + } + } + } + return $tokens; + } + + /** + * Returns wether a attribute syntax is binary or not + * + * This method gets used by Net_LDAP2_Entry to decide which + * PHP function needs to be used to fetch the value in the + * proper format (e.g. binary or string) + * + * @param string $attribute The name of the attribute (eg.: 'sn') + * + * @access public + * @return boolean + */ + public function isBinary($attribute) + { + $return = false; // default to false + + // This list contains all syntax that should be treaten as + // containing binary values + // The Syntax Definitons go into constants at the top of this page + $syntax_binary = array( + NET_LDAP2_SYNTAX_OCTET_STRING, + NET_LDAP2_SYNTAX_JPEG + ); + + // Check Syntax + $attr_s = $this->get('attribute', $attribute); + if (Net_LDAP2::isError($attr_s)) { + // Attribute not found in schema + $return = false; // consider attr not binary + } elseif (isset($attr_s['syntax']) && in_array($attr_s['syntax'], $syntax_binary)) { + // Syntax is defined as binary in schema + $return = true; + } else { + // Syntax not defined as binary, or not found + // if attribute is a subtype, check superior attribute syntaxes + if (isset($attr_s['sup'])) { + foreach ($attr_s['sup'] as $superattr) { + $return = $this->isBinary($superattr); + if ($return) { + break; // stop checking parents since we are binary + } + } + } + } + + return $return; + } + + /** + * See if an schema element exists + * + * @param string $type Type of name, see get() + * @param string $name Name or OID + * + * @return boolean + */ + public function exists($type, $name) + { + $entry = $this->get($type, $name); + if ($entry instanceof Net_LDAP2_ERROR) { + return false; + } else { + return true; + } + } + + /** + * See if an attribute is defined in the schema + * + * @param string $attribute Name or OID of the attribute + * @return boolean + */ + public function attributeExists($attribute) + { + return $this->exists('attribute', $attribute); + } + + /** + * See if an objectClass is defined in the schema + * + * @param string $ocl Name or OID of the objectClass + * @return boolean + */ + public function objectClassExists($ocl) + { + return $this->exists('objectclass', $ocl); + } + + + /** + * See to which ObjectClasses an attribute is assigned + * + * The objectclasses are sorted into the keys 'may' and 'must'. + * + * @param string $attribute Name or OID of the attribute + * + * @return array|Net_LDAP2_Error Associative array with OCL names or Error + */ + public function getAssignedOCLs($attribute) + { + $may = array(); + $must = array(); + + // Test if the attribute type is defined in the schema, + // if so, retrieve real name for lookups + $attr_entry = $this->get('attribute', $attribute); + if ($attr_entry instanceof Net_LDAP2_ERROR) { + return PEAR::raiseError("Attribute $attribute not defined in schema: ".$attr_entry->getMessage()); + } else { + $attribute = $attr_entry['name']; + } + + + // We need to get all defined OCLs for this. + $ocls = $this->getAll('objectclasses'); + foreach ($ocls as $ocl => $ocl_data) { + // Fetch the may and must attrs and see if our searched attr is contained. + // If so, record it in the corresponding array. + $ocl_may_attrs = $this->may($ocl); + $ocl_must_attrs = $this->must($ocl); + if (is_array($ocl_may_attrs) && in_array($attribute, $ocl_may_attrs)) { + array_push($may, $ocl_data['name']); + } + if (is_array($ocl_must_attrs) && in_array($attribute, $ocl_must_attrs)) { + array_push($must, $ocl_data['name']); + } + } + + return array('may' => $may, 'must' => $must); + } + + /** + * See if an attribute is available in a set of objectClasses + * + * @param string $attribute Attribute name or OID + * @param array $ocls Names of OCLs to check for + * + * @return boolean TRUE, if the attribute is defined for at least one of the OCLs + */ + public function checkAttribute($attribute, $ocls) + { + foreach ($ocls as $ocl) { + $ocl_entry = $this->get('objectclass', $ocl); + $ocl_may_attrs = $this->may($ocl); + $ocl_must_attrs = $this->must($ocl); + if (is_array($ocl_may_attrs) && in_array($attribute, $ocl_may_attrs)) { + return true; + } + if (is_array($ocl_must_attrs) && in_array($attribute, $ocl_must_attrs)) { + return true; + } + } + return false; // no ocl for the ocls found. + } +} +?> \ No newline at end of file
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/Net/LDAP2/SchemaCache.interface.php
Added
@@ -0,0 +1,59 @@ +<?php +/* vim: set expandtab tabstop=4 shiftwidth=4: */ +/** +* File containing the Net_LDAP2_SchemaCache interface class. +* +* PHP version 5 +* +* @category Net +* @package Net_LDAP2 +* @author Benedikt Hallinger <beni@php.net> +* @copyright 2009 Benedikt Hallinger +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id$ +* @link http://pear.php.net/package/Net_LDAP2/ +*/ + +/** +* Interface describing a custom schema cache object +* +* To implement a custom schema cache, one must implement this interface and +* pass the instanciated object to Net_LDAP2s registerSchemaCache() method. +*/ +interface Net_LDAP2_SchemaCache +{ + /** + * Return the schema object from the cache + * + * Net_LDAP2 will consider anything returned invalid, except + * a valid Net_LDAP2_Schema object. + * In case you return a Net_LDAP2_Error, this error will be routed + * to the return of the $ldap->schema() call. + * If you return something else, Net_LDAP2 will + * fetch a fresh Schema object from the LDAP server. + * + * You may want to implement a cache aging mechanism here too. + * + * @return Net_LDAP2_Schema|Net_LDAP2_Error|false + */ + public function loadSchema(); + + /** + * Store a schema object in the cache + * + * This method will be called, if Net_LDAP2 has fetched a fresh + * schema object from LDAP and wants to init or refresh the cache. + * + * In case of errors you may return a Net_LDAP2_Error which will + * be routet to the client. + * Note that doing this prevents, that the schema object fetched from LDAP + * will be given back to the client, so only return errors if storing + * of the cache is something crucial (e.g. for doing something else with it). + * Normaly you dont want to give back errors in which case Net_LDAP2 needs to + * fetch the schema once per script run and instead use the error + * returned from loadSchema(). + * + * @return true|Net_LDAP2_Error + */ + public function storeSchema($schema); +}
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/Net/LDAP2/Search.php
Added
@@ -0,0 +1,631 @@ +<?php +/* vim: set expandtab tabstop=4 shiftwidth=4: */ +/** +* File containing the Net_LDAP2_Search interface class. +* +* PHP version 5 +* +* @category Net +* @package Net_LDAP2 +* @author Tarjej Huse <tarjei@bergfald.no> +* @author Benedikt Hallinger <beni@php.net> +* @copyright 2009 Tarjej Huse, Benedikt Hallinger +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id$ +* @link http://pear.php.net/package/Net_LDAP2/ +*/ + +/** +* Includes +*/ +require_once 'PEAR.php'; + +/** +* Result set of an LDAP search +* +* @category Net +* @package Net_LDAP2 +* @author Tarjej Huse <tarjei@bergfald.no> +* @author Benedikt Hallinger <beni@php.net> +* @license http://www.gnu.org/copyleft/lesser.html LGPL +* @link http://pear.php.net/package/Net_LDAP22/ +*/ +class Net_LDAP2_Search extends PEAR implements Iterator +{ + /** + * Search result identifier + * + * @access protected + * @var resource + */ + protected $_search; + + /** + * LDAP resource link + * + * @access protected + * @var resource + */ + protected $_link; + + /** + * Net_LDAP2 object + * + * A reference of the Net_LDAP2 object for passing to Net_LDAP2_Entry + * + * @access protected + * @var object Net_LDAP2 + */ + protected $_ldap; + + /** + * Result entry identifier + * + * @access protected + * @var resource + */ + protected $_entry = null; + + /** + * The errorcode the search got + * + * Some errorcodes might be of interest, but might not be best handled as errors. + * examples: 4 - LDAP_SIZELIMIT_EXCEEDED - indicates a huge search. + * Incomplete results are returned. If you just want to check if there's anything in the search. + * than this is a point to handle. + * 32 - no such object - search here returns a count of 0. + * + * @access protected + * @var int + */ + protected $_errorCode = 0; // if not set - sucess! + + /** + * Cache for all entries already fetched from iterator interface + * + * @access protected + * @var array + */ + protected $_iteratorCache = array(); + + /** + * What attributes we searched for + * + * The $attributes array contains the names of the searched attributes and gets + * passed from $Net_LDAP2->search() so the Net_LDAP2_Search object can tell + * what attributes was searched for ({@link searchedAttrs()) + * + * This variable gets set from the constructor and returned + * from {@link searchedAttrs()} + * + * @access protected + * @var array + */ + protected $_searchedAttrs = array(); + + /** + * Cache variable for storing entries fetched internally + * + * This currently is not used by all functions and need consolidation. + * + * @access protected + * @var array + */ + protected $_entry_cache = false; + + /** + * Cache variable for count() + * + * @see count() + * @access protected + * @var int + */ + protected $_count_cache = null; + + /** + * Constructor + * + * @param resource $search Search result identifier + * @param Net_LDAP2|resource $ldap Net_LDAP2 object or just a LDAP-Link resource + * @param array $attributes (optional) Array with searched attribute names. (see {@link $_searchedAttrs}) + * + * @access public + */ + public function __construct($search, $ldap, $attributes = array()) + { + parent::__construct('Net_LDAP2_Error'); + + $this->setSearch($search); + + if ($ldap instanceof Net_LDAP2) { + $this->_ldap = $ldap; + $this->setLink($this->_ldap->getLink()); + } else { + $this->setLink($ldap); + } + + $this->_errorCode = @ldap_errno($this->_link); + + if (is_array($attributes) && !empty($attributes)) { + $this->_searchedAttrs = $attributes; + } + } + + /** + * Returns an array of entry objects. + * + * @return array Array of entry objects. + */ + public function entries() + { + $entries = array(); + + if (false === $this->_entry_cache) { + // cache is empty: fetch from LDAP + while ($entry = $this->shiftEntry()) { + $entries[] = $entry; + } + $this->_entry_cache = $entries; // store result in cache + } + + return $this->_entry_cache; + } + + /** + * Get the next entry in the searchresult from LDAP server. + * + * This will return a valid Net_LDAP2_Entry object or false, so + * you can use this method to easily iterate over the entries inside + * a while loop. + * + * @return Net_LDAP2_Entry|false Reference to Net_LDAP2_Entry object or false + */ + public function shiftEntry() + { + if (is_null($this->_entry)) { + if(!$this->_entry = @ldap_first_entry($this->_link, $this->_search)) { + $false = false; + return $false; + } + $entry = Net_LDAP2_Entry::createConnected($this->_ldap, $this->_entry); + if ($entry instanceof PEAR_Error) $entry = false; + } else { + if (!$this->_entry = @ldap_next_entry($this->_link, $this->_entry)) { + $false = false; + return $false; + } + $entry = Net_LDAP2_Entry::createConnected($this->_ldap, $this->_entry); + if ($entry instanceof PEAR_Error) $entry = false; + } + return $entry; + } + + /** + * Alias function of shiftEntry() for perl-ldap interface + * + * @see shiftEntry() + * @return Net_LDAP2_Entry|false + */ + public function shift_entry() + { + $args = func_get_args(); + return call_user_func_array(array( $this, 'shiftEntry' ), $args); + } + + /** + * Retrieve the next entry in the searchresult, but starting from last entry + * + * This is the opposite to {@link shiftEntry()} and is also very useful + * to be used inside a while loop. + * + * @return Net_LDAP2_Entry|false + */ + public function popEntry() + { + if (false === $this->_entry_cache) { + // fetch entries into cache if not done so far + $this->_entry_cache = $this->entries(); + } + + $return = array_pop($this->_entry_cache); + return (null === $return)? false : $return; + } + + /** + * Alias function of popEntry() for perl-ldap interface + * + * @see popEntry() + * @return Net_LDAP2_Entry|false + */ + public function pop_entry() + { + $args = func_get_args(); + return call_user_func_array(array( $this, 'popEntry' ), $args); + } + + /** + * Return entries sorted as array + * + * This returns a array with sorted entries and the values. + * Sorting is done with PHPs {@link array_multisort()}. + * This method relies on {@link as_struct()} to fetch the raw data of the entries. + * + * Please note that attribute names are case sensitive! + * + * Usage example: + * <code> + * // to sort entries first by location, then by surename, but descending: + * $entries = $search->sorted_as_struct(array('locality','sn'), SORT_DESC); + * </code> + * + * @param array $attrs Array of attribute names to sort; order from left to right. + * @param int $order Ordering direction, either constant SORT_ASC or SORT_DESC + * + * @return array|Net_LDAP2_Error Array with sorted entries or error + * @todo what about server side sorting as specified in http://www.ietf.org/rfc/rfc2891.txt? + */ + public function sorted_as_struct($attrs = array('cn'), $order = SORT_ASC) + { + /* + * Old Code, suitable and fast for single valued sorting + * This code should be used if we know that single valued sorting is desired, + * but we need some method to get that knowledge... + */ + /* + $attrs = array_reverse($attrs); + foreach ($attrs as $attribute) { + if (!ldap_sort($this->_link, $this->_search, $attribute)){ + $this->raiseError("Sorting failed for Attribute " . $attribute); + } + } + + $results = ldap_get_entries($this->_link, $this->_search); + + unset($results['count']); //for tidier output + if ($order) { + return array_reverse($results); + } else { + return $results; + }*/ + + /* + * New code: complete "client side" sorting + */ + // first some parameterchecks + if (!is_array($attrs)) { + return PEAR::raiseError("Sorting failed: Parameterlist must be an array!"); + } + if ($order != SORT_ASC && $order != SORT_DESC) { + return PEAR::raiseError("Sorting failed: sorting direction not understood! (neither constant SORT_ASC nor SORT_DESC)"); + } + + // fetch the entries data + $entries = $this->as_struct(); + + // now sort each entries attribute values + // this is neccessary because later we can only sort by one value, + // so we need the highest or lowest attribute now, depending on the + // selected ordering for that specific attribute + foreach ($entries as $dn => $entry) { + foreach ($entry as $attr_name => $attr_values) { + sort($entries[$dn][$attr_name]); + if ($order == SORT_DESC) { + array_reverse($entries[$dn][$attr_name]); + } + } + } + + // reformat entrys array for later use with array_multisort() + $to_sort = array(); // <- will be a numeric array similar to ldap_get_entries + foreach ($entries as $dn => $entry_attr) { + $row = array(); + $row['dn'] = $dn; + foreach ($entry_attr as $attr_name => $attr_values) { + $row[$attr_name] = $attr_values; + } + $to_sort[] = $row; + } + + // Build columns for array_multisort() + // each requested attribute is one row + $columns = array(); + foreach ($attrs as $attr_name) { + foreach ($to_sort as $key => $row) { + $columns[$attr_name][$key] =& $to_sort[$key][$attr_name][0]; + } + } + + // sort the colums with array_multisort, if there is something + // to sort and if we have requested sort columns + if (!empty($to_sort) && !empty($columns)) { + $sort_params = ''; + foreach ($attrs as $attr_name) { + $sort_params .= '$columns[\''.$attr_name.'\'], '.$order.', '; + } + eval("array_multisort($sort_params \$to_sort);"); // perform sorting + } + + return $to_sort; + } + + /** + * Return entries sorted as objects + * + * This returns a array with sorted Net_LDAP2_Entry objects. + * The sorting is actually done with {@link sorted_as_struct()}. + * + * Please note that attribute names are case sensitive! + * Also note, that it is (depending on server capabilitys) possible to let + * the server sort your results. This happens through search controls + * and is described in detail at {@link http://www.ietf.org/rfc/rfc2891.txt} + * + * Usage example: + * <code> + * // to sort entries first by location, then by surename, but descending: + * $entries = $search->sorted(array('locality','sn'), SORT_DESC); + * </code> + * + * @param array $attrs Array of sort attributes to sort; order from left to right. + * @param int $order Ordering direction, either constant SORT_ASC or SORT_DESC + * + * @return array|Net_LDAP2_Error Array with sorted Net_LDAP2_Entries or error + * @todo Entry object construction could be faster. Maybe we could use one of the factorys instead of fetching the entry again + */ + public function sorted($attrs = array('cn'), $order = SORT_ASC) + { + $return = array(); + $sorted = $this->sorted_as_struct($attrs, $order); + if (PEAR::isError($sorted)) { + return $sorted; + } + foreach ($sorted as $key => $row) { + $entry = $this->_ldap->getEntry($row['dn'], $this->searchedAttrs()); + if (!PEAR::isError($entry)) { + array_push($return, $entry); + } else { + return $entry; + } + } + return $return; + } + + /** + * Return entries as array + * + * This method returns the entries and the selected attributes values as + * array. + * The first array level contains all found entries where the keys are the + * DNs of the entries. The second level arrays contian the entries attributes + * such that the keys is the lowercased name of the attribute and the values + * are stored in another indexed array. Note that the attribute values are stored + * in an array even if there is no or just one value. + * + * The array has the following structure: + * <code> + * $return = array( + * 'cn=foo,dc=example,dc=com' => array( + * 'sn' => array('foo'), + * 'multival' => array('val1', 'val2', 'valN') + * ) + * 'cn=bar,dc=example,dc=com' => array( + * 'sn' => array('bar'), + * 'multival' => array('val1', 'valN') + * ) + * ) + * </code> + * + * @return array associative result array as described above + */ + public function as_struct() + { + $return = array(); + $entries = $this->entries(); + foreach ($entries as $entry) { + $attrs = array(); + $entry_attributes = $entry->attributes(); + foreach ($entry_attributes as $attr_name) { + $attr_values = $entry->getValue($attr_name, 'all'); + if (!is_array($attr_values)) { + $attr_values = array($attr_values); + } + $attrs[$attr_name] = $attr_values; + } + $return[$entry->dn()] = $attrs; + } + return $return; + } + + /** + * Set the search objects resource link + * + * @param resource $search Search result identifier + * + * @access public + * @return void + */ + public function setSearch($search) + { + $this->_search = $search; + } + + /** + * Set the ldap ressource link + * + * @param resource $link Link identifier + * + * @access public + * @return void + */ + public function setLink($link) + { + $this->_link = $link; + } + + /** + * Returns the number of entries in the searchresult + * + * @return int Number of entries in search. + */ + public function count() + { + // this catches the situation where OL returned errno 32 = no such object! + if (!$this->_search) { + return 0; + } + // ldap_count_entries is slow (see pear bug #18752) with large results, + // so we cache the result internally. + if ($this->_count_cache === null) { + $this->_count_cache = @ldap_count_entries($this->_link, $this->_search); + } + + return $this->_count_cache; + } + + /** + * Get the errorcode the object got in its search. + * + * @return int The ldap error number. + */ + public function getErrorCode() + { + return $this->_errorCode; + } + + /** + * Destructor + * + * @access protected + */ + public function _Net_LDAP2_Search() + { + @ldap_free_result($this->_search); + } + + /** + * Closes search result + * + * @return void + */ + public function done() + { + $this->_Net_LDAP2_Search(); + } + + /** + * Return the attribute names this search selected + * + * @return array + * @see $_searchedAttrs + * @access protected + */ + protected function searchedAttrs() + { + return $this->_searchedAttrs; + } + + /** + * Tells if this search exceeds a sizelimit + * + * @return boolean + */ + public function sizeLimitExceeded() + { + return ($this->getErrorCode() == 4); + } + + + /* + * SPL Iterator interface methods. + * This interface allows to use Net_LDAP2_Search + * objects directly inside a foreach loop! + */ + /** + * SPL Iterator interface: Return the current element. + * + * The SPL Iterator interface allows you to fetch entries inside + * a foreach() loop: <code>foreach ($search as $dn => $entry) { ...</code> + * + * Of course, you may call {@link current()}, {@link key()}, {@link next()}, + * {@link rewind()} and {@link valid()} yourself. + * + * If the search throwed an error, it returns false. + * False is also returned, if the end is reached + * In case no call to next() was made, we will issue one, + * thus returning the first entry. + * + * @return Net_LDAP2_Entry|false + */ + public function current() + { + if (count($this->_iteratorCache) == 0) { + $this->next(); + reset($this->_iteratorCache); + } + $entry = current($this->_iteratorCache); + return ($entry instanceof Net_LDAP2_Entry)? $entry : false; + } + + /** + * SPL Iterator interface: Return the identifying key (DN) of the current entry. + * + * @see current() + * @return string|false DN of the current entry; false in case no entry is returned by current() + */ + public function key() + { + $entry = $this->current(); + return ($entry instanceof Net_LDAP2_Entry)? $entry->dn() :false; + } + + /** + * SPL Iterator interface: Move forward to next entry. + * + * After a call to {@link next()}, {@link current()} will return + * the next entry in the result set. + * + * @see current() + * @return void + */ + public function next() + { + // fetch next entry. + // if we have no entrys anymore, we add false (which is + // returned by shiftEntry()) so current() will complain. + if (count($this->_iteratorCache) - 1 <= $this->count()) { + $this->_iteratorCache[] = $this->shiftEntry(); + } + + // move on array pointer to current element. + // even if we have added all entries, this will + // ensure proper operation in case we rewind() + next($this->_iteratorCache); + } + + /** + * SPL Iterator interface: Check if there is a current element after calls to {@link rewind()} or {@link next()}. + * + * Used to check if we've iterated to the end of the collection. + * + * @see current() + * @return boolean FALSE if there's nothing more to iterate over + */ + public function valid() + { + return ($this->current() instanceof Net_LDAP2_Entry); + } + + /** + * SPL Iterator interface: Rewind the Iterator to the first element. + * + * After rewinding, {@link current()} will return the first entry in the result set. + * + * @see current() + * @return void + */ + public function rewind() + { + reset($this->_iteratorCache); + } +} + +?>
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/Net/LDAP2/SimpleFileSchemaCache.php
Added
@@ -0,0 +1,97 @@ +<?php +/* vim: set expandtab tabstop=4 shiftwidth=4: */ +/** +* File containing the example simple file based Schema Caching class. +* +* PHP version 5 +* +* @category Net +* @package Net_LDAP2 +* @author Benedikt Hallinger <beni@php.net> +* @copyright 2009 Benedikt Hallinger +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id$ +* @link http://pear.php.net/package/Net_LDAP2/ +*/ + +/** +* A simple file based schema cacher with cache aging. +* +* Once the cache is too old, the loadSchema() method will return false, so +* Net_LDAP2 will fetch a fresh object from the LDAP server that will +* overwrite the current (outdated) old cache. +*/ +class Net_LDAP2_SimpleFileSchemaCache implements Net_LDAP2_SchemaCache +{ + /** + * Internal config of this cache + * + * @see Net_LDAP2_SimpleFileSchemaCache() + * @var array + */ + protected $config = array( + 'path' => '/tmp/Net_LDAP_Schema.cache', + 'max_age' => 1200 + ); + + /** + * Initialize the simple cache + * + * Config is as following: + * path Complete path to the cache file. + * max_age Maximum age of cache in seconds, 0 means "endlessly". + * + * @param array $cfg Config array + */ + public function __construct($cfg) + { + foreach ($cfg as $key => $value) { + if (array_key_exists($key, $this->config)) { + if (gettype($this->config[$key]) != gettype($value)) { + $this->getCore()->dropFatalError(__CLASS__.": Could not set config! Key $key does not match type ".gettype($this->config[$key])."!"); + } + $this->config[$key] = $value; + } else { + $this->getCore()->dropFatalError(__CLASS__.": Could not set config! Key $key is not defined!"); + } + } + } + + /** + * Return the schema object from the cache + * + * If file is existent and cache has not expired yet, + * then the cache is deserialized and returned. + * + * @return Net_LDAP2_Schema|Net_LDAP2_Error|false + */ + public function loadSchema() + { + $return = false; // Net_LDAP2 will load schema from LDAP + if (file_exists($this->config['path'])) { + $cache_maxage = filemtime($this->config['path']) + $this->config['max_age']; + if (time() <= $cache_maxage || $this->config['max_age'] == 0) { + $return = unserialize(file_get_contents($this->config['path'])); + } + } + return $return; + } + + /** + * Store a schema object in the cache + * + * This method will be called, if Net_LDAP2 has fetched a fresh + * schema object from LDAP and wants to init or refresh the cache. + * + * To invalidate the cache and cause Net_LDAP2 to refresh the cache, + * you can call this method with null or false as value. + * The next call to $ldap->schema() will then refresh the caches object. + * + * @param mixed $schema The object that should be cached + * @return true|Net_LDAP2_Error|false + */ + public function storeSchema($schema) { + file_put_contents($this->config['path'], serialize($schema)); + return true; + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/Net/LDAP2/Util.php
Added
@@ -0,0 +1,620 @@ +<?php +/* vim: set expandtab tabstop=4 shiftwidth=4: */ +/** +* File containing the Net_LDAP2_Util interface class. +* +* PHP version 5 +* +* @category Net +* @package Net_LDAP2 +* @author Benedikt Hallinger <beni@php.net> +* @copyright 2009 Benedikt Hallinger +* @license http://www.gnu.org/licenses/lgpl-3.0.txt LGPLv3 +* @version SVN: $Id$ +* @link http://pear.php.net/package/Net_LDAP2/ +*/ + +/** +* Includes +*/ +require_once 'PEAR.php'; + +/** +* Utility Class for Net_LDAP2 +* +* This class servers some functionality to the other classes of Net_LDAP2 but most of +* the methods can be used separately as well. +* +* @category Net +* @package Net_LDAP2 +* @author Benedikt Hallinger <beni@php.net> +* @license http://www.gnu.org/copyleft/lesser.html LGPL +* @link http://pear.php.net/package/Net_LDAP22/ +*/ +class Net_LDAP2_Util extends PEAR +{ + /** + * Constructor + * + * @access public + */ + public function __construct() + { + // We do nothing here, since all methods can be called statically. + // In Net_LDAP <= 0.7, we needed a instance of Util, because + // it was possible to do utf8 encoding and decoding, but this + // has been moved to the LDAP class. The constructor remains only + // here to document the downward compatibility of creating an instance. + } + + /** + * Explodes the given DN into its elements + * + * {@link http://www.ietf.org/rfc/rfc2253.txt RFC 2253} says, a Distinguished Name is a sequence + * of Relative Distinguished Names (RDNs), which themselves + * are sets of Attributes. For each RDN a array is constructed where the RDN part is stored. + * + * For example, the DN 'OU=Sales+CN=J. Smith,DC=example,DC=net' is exploded to: + * <kbd>array( [0] => array([0] => 'OU=Sales', [1] => 'CN=J. Smith'), [2] => 'DC=example', [3] => 'DC=net' )</kbd> + * + * [NOT IMPLEMENTED] DNs might also contain values, which are the bytes of the BER encoding of + * the X.500 AttributeValue rather than some LDAP string syntax. These values are hex-encoded + * and prefixed with a #. To distinguish such BER values, ldap_explode_dn uses references to + * the actual values, e.g. '1.3.6.1.4.1.1466.0=#04024869,DC=example,DC=com' is exploded to: + * [ { '1.3.6.1.4.1.1466.0' => "\004\002Hi" }, { 'DC' => 'example' }, { 'DC' => 'com' } ]; + * See {@link http://www.vijaymukhi.com/vmis/berldap.htm} for more information on BER. + * + * It also performs the following operations on the given DN: + * - Unescape "\" followed by ",", "+", """, "\", "<", ">", ";", "#", "=", " ", or a hexpair + * and strings beginning with "#". + * - Removes the leading 'OID.' characters if the type is an OID instead of a name. + * - If an RDN contains multiple parts, the parts are re-ordered so that the attribute type names are in alphabetical order. + * + * OPTIONS is a list of name/value pairs, valid options are: + * casefold Controls case folding of attribute types names. + * Attribute values are not affected by this option. + * The default is to uppercase. Valid values are: + * lower Lowercase attribute types names. + * upper Uppercase attribute type names. This is the default. + * none Do not change attribute type names. + * reverse If TRUE, the RDN sequence is reversed. + * onlyvalues If TRUE, then only attributes values are returned ('foo' instead of 'cn=foo') + * + + * @param string $dn The DN that should be exploded + * @param array $options Options to use + * + * @static + * @return array Parts of the exploded DN + * @todo implement BER + */ + public static function ldap_explode_dn($dn, $options = array('casefold' => 'upper')) + { + if (!isset($options['onlyvalues'])) $options['onlyvalues'] = false; + if (!isset($options['reverse'])) $options['reverse'] = false; + if (!isset($options['casefold'])) $options['casefold'] = 'upper'; + + // Escaping of DN and stripping of "OID." + $dn = self::canonical_dn($dn, array('casefold' => $options['casefold'])); + + // splitting the DN + $dn_array = preg_split('/(?<=[^\\\\]),/', $dn); + + // clear wrong splitting (possibly we have split too much) + // /!\ Not clear, if this is neccessary here + //$dn_array = self::correct_dn_splitting($dn_array, ','); + + // construct subarrays for multivalued RDNs and unescape DN value + // also convert to output format and apply casefolding + foreach ($dn_array as $key => $value) { + $value_u = self::unescape_dn_value($value); + $rdns = self::split_rdn_multival($value_u[0]); + if (count($rdns) > 1) { + // MV RDN! + foreach ($rdns as $subrdn_k => $subrdn_v) { + // Casefolding + if ($options['casefold'] == 'upper') { + $subrdn_v = preg_replace_callback( + "/^\w+=/", + function ($matches) { + return strtoupper($matches[0]); + }, + $subrdn_v + ); + } else if ($options['casefold'] == 'lower') { + $subrdn_v = preg_replace_callback( + "/^\w+=/", + function ($matches) { + return strtolower($matches[0]); + }, + $subrdn_v + ); + } + + if ($options['onlyvalues']) { + preg_match('/(.+?)(?<!\\\\)=(.+)/', $subrdn_v, $matches); + $rdn_ocl = $matches[1]; + $rdn_val = $matches[2]; + $unescaped = self::unescape_dn_value($rdn_val); + $rdns[$subrdn_k] = $unescaped[0]; + } else { + $unescaped = self::unescape_dn_value($subrdn_v); + $rdns[$subrdn_k] = $unescaped[0]; + } + } + + $dn_array[$key] = $rdns; + } else { + // normal RDN + + // Casefolding + if ($options['casefold'] == 'upper') { + $value = preg_replace_callback( + "/^\w+=/", + function ($matches) { + return strtoupper($matches[0]); + }, + $value + ); + } else if ($options['casefold'] == 'lower') { + $value = preg_replace_callback( + "/^\w+=/", + function ($matches) { + return strtolower($matches[0]); + }, + $value + ); + } + + if ($options['onlyvalues']) { + preg_match('/(.+?)(?<!\\\\)=(.+)/', $value, $matches); + $dn_ocl = $matches[1]; + $dn_val = $matches[2]; + $unescaped = self::unescape_dn_value($dn_val); + $dn_array[$key] = $unescaped[0]; + } else { + $unescaped = self::unescape_dn_value($value); + $dn_array[$key] = $unescaped[0]; + } + } + } + + if ($options['reverse']) { + return array_reverse($dn_array); + } else { + return $dn_array; + } + } + + /** + * Escapes a DN value according to RFC 2253 + * + * Escapes the given VALUES according to RFC 2253 so that they can be safely used in LDAP DNs. + * The characters ",", "+", """, "\", "<", ">", ";", "#", "=" with a special meaning in RFC 2252 + * are preceeded by ba backslash. Control characters with an ASCII code < 32 are represented as \hexpair. + * Finally all leading and trailing spaces are converted to sequences of \20. + * + * @param array $values An array containing the DN values that should be escaped + * + * @static + * @return array The array $values, but escaped + */ + public static function escape_dn_value($values = array()) + { + // Parameter validation + if (!is_array($values)) { + $values = array($values); + } + + foreach ($values as $key => $val) { + // Escaping of filter meta characters + $val = str_replace('\\', '\\\\', $val); + $val = str_replace(',', '\,', $val); + $val = str_replace('+', '\+', $val); + $val = str_replace('"', '\"', $val); + $val = str_replace('<', '\<', $val); + $val = str_replace('>', '\>', $val); + $val = str_replace(';', '\;', $val); + $val = str_replace('#', '\#', $val); + $val = str_replace('=', '\=', $val); + + // ASCII < 32 escaping + $val = self::asc2hex32($val); + + // Convert all leading and trailing spaces to sequences of \20. + if (preg_match('/^(\s*)(.+?)(\s*)$/', $val, $matches)) { + $val = $matches[2]; + for ($i = 0; $i < strlen($matches[1]); $i++) { + $val = '\20'.$val; + } + for ($i = 0; $i < strlen($matches[3]); $i++) { + $val = $val.'\20'; + } + } + + if (null === $val) $val = '\0'; // apply escaped "null" if string is empty + + $values[$key] = $val; + } + + return $values; + } + + /** + * Undoes the conversion done by escape_dn_value(). + * + * Any escape sequence starting with a baskslash - hexpair or special character - + * will be transformed back to the corresponding character. + * + * @param array $values Array of DN Values + * + * @return array Same as $values, but unescaped + * @static + */ + public static function unescape_dn_value($values = array()) + { + // Parameter validation + if (!is_array($values)) { + $values = array($values); + } + + foreach ($values as $key => $val) { + // strip slashes from special chars + $val = str_replace('\\\\', '\\', $val); + $val = str_replace('\,', ',', $val); + $val = str_replace('\+', '+', $val); + $val = str_replace('\"', '"', $val); + $val = str_replace('\<', '<', $val); + $val = str_replace('\>', '>', $val); + $val = str_replace('\;', ';', $val); + $val = str_replace('\#', '#', $val); + $val = str_replace('\=', '=', $val); + + // Translate hex code into ascii + $values[$key] = self::hex2asc($val); + } + + return $values; + } + + /** + * Returns the given DN in a canonical form + * + * Returns false if DN is not a valid Distinguished Name. + * DN can either be a string or an array + * as returned by ldap_explode_dn, which is useful when constructing a DN. + * The DN array may have be indexed (each array value is a OCL=VALUE pair) + * or associative (array key is OCL and value is VALUE). + * + * It performs the following operations on the given DN: + * - Removes the leading 'OID.' characters if the type is an OID instead of a name. + * - Escapes all RFC 2253 special characters (",", "+", """, "\", "<", ">", ";", "#", "="), slashes ("/"), and any other character where the ASCII code is < 32 as \hexpair. + * - Converts all leading and trailing spaces in values to be \20. + * - If an RDN contains multiple parts, the parts are re-ordered so that the attribute type names are in alphabetical order. + * + * OPTIONS is a list of name/value pairs, valid options are: + * casefold Controls case folding of attribute type names. + * Attribute values are not affected by this option. The default is to uppercase. + * Valid values are: + * lower Lowercase attribute type names. + * upper Uppercase attribute type names. This is the default. + * none Do not change attribute type names. + * [NOT IMPLEMENTED] mbcescape If TRUE, characters that are encoded as a multi-octet UTF-8 sequence will be escaped as \(hexpair){2,*}. + * reverse If TRUE, the RDN sequence is reversed. + * separator Separator to use between RDNs. Defaults to comma (','). + * + * Note: The empty string "" is a valid DN, so be sure not to do a "$can_dn == false" test, + * because an empty string evaluates to false. Use the "===" operator instead. + * + * @param array|string $dn The DN + * @param array $options Options to use + * + * @static + * @return false|string The canonical DN or FALSE + * @todo implement option mbcescape + */ + public static function canonical_dn($dn, $options = array('casefold' => 'upper', 'separator' => ',')) + { + if ($dn === '') return $dn; // empty DN is valid! + + // options check + if (!isset($options['reverse'])) { + $options['reverse'] = false; + } else { + $options['reverse'] = true; + } + if (!isset($options['casefold'])) $options['casefold'] = 'upper'; + if (!isset($options['separator'])) $options['separator'] = ','; + + + if (!is_array($dn)) { + // It is not clear to me if the perl implementation splits by the user defined + // separator or if it just uses this separator to construct the new DN + $dn = preg_split('/(?<=[^\\\\])'.$options['separator'].'/', $dn); + + // clear wrong splitting (possibly we have split too much) + $dn = self::correct_dn_splitting($dn, $options['separator']); + } else { + // Is array, check, if the array is indexed or associative + $assoc = false; + foreach ($dn as $dn_key => $dn_part) { + if (!is_int($dn_key)) { + $assoc = true; + } + } + // convert to indexed, if associative array detected + if ($assoc) { + $newdn = array(); + foreach ($dn as $dn_key => $dn_part) { + if (is_array($dn_part)) { + ksort($dn_part, SORT_STRING); // we assume here, that the rdn parts are also associative + $newdn[] = $dn_part; // copy array as-is, so we can resolve it later + } else { + $newdn[] = $dn_key.'='.$dn_part; + } + } + $dn =& $newdn; + } + } + + // Escaping and casefolding + foreach ($dn as $pos => $dnval) { + if (is_array($dnval)) { + // subarray detected, this means very surely, that we had + // a multivalued dn part, which must be resolved + $dnval_new = ''; + foreach ($dnval as $subkey => $subval) { + // build RDN part + if (!is_int($subkey)) { + $subval = $subkey.'='.$subval; + } + $subval_processed = self::canonical_dn($subval); + if (false === $subval_processed) return false; + $dnval_new .= $subval_processed.'+'; + } + $dn[$pos] = substr($dnval_new, 0, -1); // store RDN part, strip last plus + } else { + // try to split multivalued RDNS into array + $rdns = self::split_rdn_multival($dnval); + if (count($rdns) > 1) { + // Multivalued RDN was detected! + // The RDN value is expected to be correctly split by split_rdn_multival(). + // It's time to sort the RDN and build the DN! + $rdn_string = ''; + sort($rdns, SORT_STRING); // Sort RDN keys alphabetically + foreach ($rdns as $rdn) { + $subval_processed = self::canonical_dn($rdn); + if (false === $subval_processed) return false; + $rdn_string .= $subval_processed.'+'; + } + + $dn[$pos] = substr($rdn_string, 0, -1); // store RDN part, strip last plus + + } else { + // no multivalued RDN! + // split at first unescaped "=" + $dn_comp = preg_split('/(?<=[^\\\\])=/', $rdns[0], 2); + $ocl = ltrim($dn_comp[0]); // trim left whitespaces 'cause of "cn=foo, l=bar" syntax (whitespace after comma) + $val = $dn_comp[1]; + + // strip 'OID.', otherwise apply casefolding and escaping + if (substr(strtolower($ocl), 0, 4) == 'oid.') { + $ocl = substr($ocl, 4); + } else { + if ($options['casefold'] == 'upper') $ocl = strtoupper($ocl); + if ($options['casefold'] == 'lower') $ocl = strtolower($ocl); + $ocl = self::escape_dn_value(array($ocl)); + $ocl = $ocl[0]; + } + + // escaping of dn-value + $val = self::escape_dn_value(array($val)); + $val = str_replace('/', '\/', $val[0]); + + $dn[$pos] = $ocl.'='.$val; + } + } + } + + if ($options['reverse']) $dn = array_reverse($dn); + return implode($options['separator'], $dn); + } + + /** + * Escapes the given VALUES according to RFC 2254 so that they can be safely used in LDAP filters. + * + * Any control characters with an ACII code < 32 as well as the characters with special meaning in + * LDAP filters "*", "(", ")", and "\" (the backslash) are converted into the representation of a + * backslash followed by two hex digits representing the hexadecimal value of the character. + * + * @param array $values Array of values to escape + * + * @static + * @return array Array $values, but escaped + */ + public static function escape_filter_value($values = array()) + { + // Parameter validation + if (!is_array($values)) { + $values = array($values); + } + + foreach ($values as $key => $val) { + // Escaping of filter meta characters + $val = str_replace('\\', '\5c', $val); + $val = str_replace('*', '\2a', $val); + $val = str_replace('(', '\28', $val); + $val = str_replace(')', '\29', $val); + + // ASCII < 32 escaping + $val = self::asc2hex32($val); + + if (null === $val) $val = '\0'; // apply escaped "null" if string is empty + + $values[$key] = $val; + } + + return $values; + } + + /** + * Undoes the conversion done by {@link escape_filter_value()}. + * + * Converts any sequences of a backslash followed by two hex digits into the corresponding character. + * + * @param array $values Array of values to escape + * + * @static + * @return array Array $values, but unescaped + */ + public static function unescape_filter_value($values = array()) + { + // Parameter validation + if (!is_array($values)) { + $values = array($values); + } + + foreach ($values as $key => $value) { + // Translate hex code into ascii + $values[$key] = self::hex2asc($value); + } + + return $values; + } + + /** + * Converts all ASCII chars < 32 to "\HEX" + * + * @param string $string String to convert + * + * @static + * @return string + */ + public static function asc2hex32($string) + { + for ($i = 0; $i < strlen($string); $i++) { + $char = substr($string, $i, 1); + if (ord($char) < 32) { + $hex = dechex(ord($char)); + if (strlen($hex) == 1) $hex = '0'.$hex; + $string = str_replace($char, '\\'.$hex, $string); + } + } + return $string; + } + + /** + * Converts all Hex expressions ("\HEX") to their original ASCII characters + * + * @param string $string String to convert + * + * @static + * @author beni@php.net, heavily based on work from DavidSmith@byu.net + * @return string + */ + public static function hex2asc($string) + { + $string = preg_replace_callback( + "/\\\[0-9A-Fa-f]{2}/", + function ($matches) { + return chr(hexdec($matches[0])); + }, + $string + ); + return $string; + } + + /** + * Split an multivalued RDN value into an Array + * + * A RDN can contain multiple values, spearated by a plus sign. + * This function returns each separate ocl=value pair of the RDN part. + * + * If no multivalued RDN is detected, an array containing only + * the original rdn part is returned. + * + * For example, the multivalued RDN 'OU=Sales+CN=J. Smith' is exploded to: + * <kbd>array([0] => 'OU=Sales', [1] => 'CN=J. Smith')</kbd> + * + * The method trys to be smart if it encounters unescaped "+" characters, but may fail, + * so ensure escaped "+"es in attr names and attr values. + * + * [BUG] If you have a multivalued RDN with unescaped plus characters + * and there is a unescaped plus sign at the end of an value followed by an + * attribute name containing an unescaped plus, then you will get wrong splitting: + * $rdn = 'OU=Sales+C+N=J. Smith'; + * returns: + * array('OU=Sales+C', 'N=J. Smith'); + * The "C+" is treaten as value of the first pair instead as attr name of the second pair. + * To prevent this, escape correctly. + * + * @param string $rdn Part of an (multivalued) escaped RDN (eg. ou=foo OR ou=foo+cn=bar) + * + * @static + * @return array Array with the components of the multivalued RDN or Error + */ + public static function split_rdn_multival($rdn) + { + $rdns = preg_split('/(?<!\\\\)\+/', $rdn); + $rdns = self::correct_dn_splitting($rdns, '+'); + return array_values($rdns); + } + + /** + * Splits an attribute=value syntax into an array + * + * If escaped delimeters are used, they are returned escaped as well. + * The split will occur at the first unescaped delimeter character. + * In case an invalid delimeter is given, no split will be performed and an + * one element array gets returned. + * Optional also filter-assertion delimeters can be considered (>, <, >=, <=, ~=). + * + * @param string $attr Attribute and Value Syntax ("foo=bar") + * @param boolean $extended If set to true, also filter-assertion delimeter will be matched + * @param boolean $withDelim If set to true, the return array contains the delimeter at index 1, putting the value to index 2 + * + * @return array Indexed array: 0=attribute name, 1=attribute value OR ($withDelim=true): 0=attr, 1=delimeter, 2=value + */ + public static function split_attribute_string($attr, $extended=false, $withDelim=false) + { + if ($withDelim) $withDelim = PREG_SPLIT_DELIM_CAPTURE; + + if (!$extended) { + return preg_split('/(?<!\\\\)(=)/', $attr, 2, $withDelim); + } else { + return preg_split('/(?<!\\\\)(>=|<=|>|<|~=|=)/', $attr, 2, $withDelim); + } + } + + /** + * Corrects splitting of dn parts + * + * @param array $dn Raw DN array + * @param array $separator Separator that was used when splitting + * + * @return array Corrected array + * @access protected + */ + protected static function correct_dn_splitting($dn = array(), $separator = ',') + { + foreach ($dn as $key => $dn_value) { + $dn_value = $dn[$key]; // refresh value (foreach caches!) + // if the dn_value is not in attr=value format, then we had an + // unescaped separator character inside the attr name or the value. + // We assume, that it was the attribute value. + // [TODO] To solve this, we might ask the schema. Keep in mind, that UTIL class + // must remain independent from the other classes or connections. + if (!preg_match('/.+(?<!\\\\)=.+/', $dn_value)) { + unset($dn[$key]); + if (array_key_exists($key-1, $dn)) { + $dn[$key-1] = $dn[$key-1].$separator.$dn_value; // append to previous attr value + } else { + $dn[$key+1] = $dn_value.$separator.$dn[$key+1]; // first element: prepend to next attr name + } + } + } + return array_values($dn); + } +} + +?>
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/composer.json
Added
@@ -0,0 +1,25 @@ +{ + "name": "pear/net_ldap2", + "description": "Object oriented interface for searching and manipulating LDAP-entries", + "license": "LGPL-3.0", + "type": "library", + "keywords": [ + "pear", + "ldap" + ], + "homepage": "http://pear.php.net/package/Net_LDAP2", + "support": { + "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=Net_LDAP2", + "source": "https://github.com/pear/Net_LDAP2" + }, + "require": { + "pear/pear-core-minimal": "^1.10.1", + "ext-ldap": "*" + }, + "include-path": ["."], + "autoload": { + "classmap": [ + "Net/" + ] + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/doc
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/doc/README.txt
Added
@@ -0,0 +1,17 @@ +This is my own implementation of some classes for manipulation LDAP-entries in +a directory. + +The classes methods and structure are based on Perls Net::LDAP +(see perl-ldap.sf.net). The test.php file shuld provide you with enough +examples to do the most basic things. + +The largest difference between the perl implementation and this one (apart +from the fact that all array/list structures are different due to differences +in the two languages) is that instead of the method new you'll have to use the +method connect() instead. + +Patches and comments are most welcome! +Please submit them via PEARS Bug tracking feature or via mail +to one of Net_LDAP2s developers. Use unified context diffs if possible! + +The Net_LDAP2 Team \ No newline at end of file
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/doc/RootDSE.txt
Added
@@ -0,0 +1,57 @@ +First of all connect as usual. (Some servers require authentication to get the +RootDSE entry) + +$config = array( 'host' => 'localhost' ); +$ldap = Net_LDAP2::connect( $config ); +if( Net_LDAP2::isError( $ldap ) ) die( $ldap->getMessage() ); + +Now we can get the entry: + +$dse = $ldap->rootDSE(); +if( Net_LDAP2::isError( $dse ) die( $dse->getMessage() ); + +You can give an array of attributes to fetch as an parameter ro rootDSE(). +If none are given these ones are fetched: + +namingContexts +altServer +supportedExtension +supportedControl +supportedSASLMechanisms +supportedLDAPVersion +subschemaSubentry + +Then you can work with the object: + +$basedn = $dse->getValue( 'namingContexts' ); + +if( $dse->supportedVersion( 3 ) == 3 ) { + do_something_only_ldap_v3_can_do(); +} + +Public functions: + +getValue( string ) + +get the value of this attribute. same syntax as Net_LDAP2_Entry::get_value() + +supportedControl( oid ) +supportedExtension( oid ) + +check if the given control/extension is supported by the server + +supportedSASLMechanism( mechanism ) + +check if the given sasl mechanism is supported by the server + +supportedVersion( version ) + +check if the given ldap version is supported by the serve + +These are alias functions of the above, to make the api perl-ldap compatible. + +get_value() +supported_control() +supported_extension() +supported_sasl_mechanism() +supported_version()
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/doc/Schema.txt
Added
@@ -0,0 +1,64 @@ +Examples: + +First of all connect to your server as usual. (Some servers require +authentication to get the Subschema entry) + +$config = array( 'host' => 'localhost' ); +$ldap = Net_LDAP2::connect( $config ); +if( Net_LDAP2::isError( $ldap ) ) die ( $ldap->getMessage() ) + +Then we can get the schema. + +$schema = $ldap->schema(); +if( Net_LDAP2::isError( $schema ) ) die ( $schema->getMessage() ); + +You can give a parameter to $ldap->schema() which sets the Subschema Entry dn. +If it is omitted, the entry dn will be fetched internally via rootDSE(). +If that fails it will be set to "cn=Subschema". + +$schema = $ldap->schema( 'cn=Subschema' ); + +Now you can work with the schema and retrieve information: + +$attrs = $schema->getAll( 'attributes' ); + +This returns an array with all attributes and their information such as syntax, +equality, max_length etc. Look at the returned array to see what information was +passed. + +Valid options to getAll() are: + +objectclasses +attributes +ditcontentrules +ditstructurerules +matchingrules +matchingruleuses +nameforms +syntaxes + +If you know the the name of an attribute or objectclass you can get the +information directly. + +$attr = $schema->get('attribute', 'userPassword'); +$oc = $schema->get('objectclass', 'posixAccount'); + +The first parameter determines the type of entry to be fetched and can be one +of: + +attribute +ditcontentrule +ditstructurerule +matchingrule +matchingruleuse +nameform +objectclass +syntax + +The second parameter can be the name or the oid of the entry. + +You can retrieve a list of required and optional attributes of an object class +via must( $oc ) or may( $oc ). Both return a list of attributes in an array. + +$required = $schema->must( 'posixAccount' ); +$optional = $schema->may( 'posixAccount' );
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/doc/examples
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/doc/examples/add_entry.php
Added
@@ -0,0 +1,53 @@ +<?php +/** +* This is a short example on how to add a new entry to your +* directory using Net_LDAP2. +*/ + +// We use the connecting.php example to get a link to our server. +// This file will also include all required basic Net_LDAP2 classes. +include_once 'connecting.php'; + +// Okay, we should have a valid link now. +// We must define the DN of the new entry. The DN is the +// global unique path to the data in the directory server, +// similar to a path name in your filesystem. +// Since we want to be a little flexible, we make the base +// dynamic, so it is enough to change the base-dn in your +// $ldap_config array. +$dn = 'cn=Foo Bar,'.$ldap_config['base']; + + +// It is a good idea to first look if the entry, that should be added, +// is already present: +if ($ldap->dnExists($dn)) { + die('Could not add entry! Entry already exists!'); +} + +// The entry does not exist so far, we can safely add him. +// But first, we must construct the entry. +// This is, because Net_LDAP2 was build to make changes only +// locally (in your script), not directly on the server. +$attributes = array( + 'sn' => 'Foo', + 'gn' => 'Bar', + 'mail' => array('foo@example.org', 'bar@example2.org'), + 'employeeNumber' => 123456 +); +$new_entry = Net_LDAP2_Entry::createFresh($dn, $attributes); + +// Finally add the entry in the server: +$result = $ldap->add($new_entry); +if (Net_LDAP2::isError($result)) { + die('Unable to add entry: '.$result->getMessage()); +} + +// The entry is now present in the directory server. +// Additionally, it is linked to the $ldap connection used for the add(), +// so you may call $entry->modify() (and friends) and $entry->update() +// without the need for passing an $ldap object. +// This is only the case if the entry was not linked to an Net_LDAP2 object +// before, so if the entry object would be fetched from a $ldap object +// and then added to $ldap_2, the link of the entry remains to $ldap, +// thus any update() will be performed on directory1 ($ldap). +?> \ No newline at end of file
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/doc/examples/connecting.php
Added
@@ -0,0 +1,44 @@ +<?php +/** +* This file shows you how to connect to a ldap server using Net_LDAP2. +* +* It also establishes connections for the other examples; +* they include this file to get a ldap link. +*/ + +// Class includes; this assumes Net_LDAP2 installed in PHPs include path +// or under subfolder "Net" in the local directory. +require_once 'Net/LDAP2.php'; + +// Configuration +// host can be a single server (string) or multiple ones - if we define more +// servers here (array), we can implement a basic fail over scenario. +// If no credentials (binddn and bindpw) are given, Net_LDAP2 establishes +// an anonymous bind. +// See the documentation for more information on the configuration items! +$ldap_config = array( +// 'host' => 'ldap.example.org', + 'host' => array('ldap1.example.org', 'ldap2.example.org'), +// 'binddn' => 'cn=admin,o=example,dc=org', +// 'bindpw' => 'your-secret-password', + 'tls' => false, + 'base' => 'o=example,dc=org', + 'port' => 389, + 'version' => 3, + 'filter' => '(cn=*)', + 'scope' => 'sub' +); + +// Connect to configured ldap server +$ldap = Net_LDAP2::connect($ldap_config); + +// It is important to check for errors. +// Nearly every method of Net_LDAP2 returns a Net_LDAP2_Error object +// if something went wrong. Through this object, you can retrieve detailed +// information on what exactly happened. +// +// Here we drop a die with the error message, so the other example +// files will not be calles unless we have a valid link. +if (Net_LDAP2::isError($ldap)) { + die('BIND FAILED: '.$ldap->getMessage()); +} \ No newline at end of file
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/doc/examples/fetch_entry.php
Added
@@ -0,0 +1,38 @@ +<?php +/** +* This is a short example on how to fetch a specific entry in the +* directory using Net_LDAP2. +*/ + +// We use the connecting.php example to get a link to our server. +// This file will also include all required basic Net_LDAP2 classes. +include_once 'connecting.php'; + +// Okay, we should have a valid link now. +// Lets fetch an entry! We want to know the admins first and last name. +// If we need additional attributes later, we must refetch the entry. +// It is a good practice to only select the attributes really needed. +// Since we want to be a little flexible, we make the base +// dynamic, so it is enough to change the base-dn in your +// $ldap_config array. +$entry = $ldap->getEntry('cn=admin,'.$ldap_config['base'], array('gn', 'sn')); + +// Error checking is important! +if (Net_LDAP2::isError($entry)) { + die('Could not fetch entry: '.$entry->getMessage()); +} + +// Now fetch the data from the entry +$surename = $entry->getValue('sn', 'single'); +if (Net_LDAP2::isError($surename)) { + die('Unable to get surename: '.$surename->getMessage()); +} +$givenname = $entry->getValue('gn', 'single'); +if (Net_LDAP2::isError($givenname)) { + die('Unable to get surename: '.$givenname->getMessage()); +} + +// Finally output the data of the entry: +// This will give something like "Name of cn=admin,o=example,dc=org: Foo Bar" +echo 'Name of '.$entry->DN().': '.$givenname.' '.$surename; +?> \ No newline at end of file
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/doc/examples/modify_entry.php
Added
@@ -0,0 +1,64 @@ +<?php +/** +* This is a short example on how to modify a specific entry in the +* directory using Net_LDAP2. +* +* There is an alternative way of doing this; please have a look at +* examples/modify_entry2.php +*/ + +// We use the fetch_entry.php example to get the LDAP-Entry +// which we will modify now. +include_once 'fetch_entry.php'; + +// Okay, we should have a valid Net_LDAP2_Entry object that represents +// a real existing entry in our directory. +// The changes are only locally made and executed on the server +// at the end of the script. + +// What we do now is to add two new attributes, one with two values +// Note that we can add attribute values which we haven't selected +// at fetching/searching the entry - but if we do that and +// call getValues(), we will only see the values added and NOT all +// attributes present on the server! +$result = $entry->add(array( + 'mail' => array('foo@example.org', 'test2@example.org'), + 'telephoneNumber' => '1234567890' +)); +if (Net_LDAP2::isError($result)) { + die('Unable to add attribute: '.$result->getMessage()); +} + +// Now we modify the first value +// Note, that we must give all old values, otherwise the attribute +// will be deleted. We specify the new absolute attribute state +$result = $entry->replace(array('mail' => array('test1@example.org', 'test2@example.org'))); +if (Net_LDAP2::isError($result)) { + die('Unable to modify attribute: '.$result->getMessage()); +} + +// And now we delete the second attribute value +// We must provide the old value, so the ldap server knows, +// which value we want to be deleted +$result = $entry->delete(array('mail' => 'test2@example.org')); +if (Net_LDAP2::isError($result)) { + die('Unable to delete attribute value: '.$result->getMessage()); +} + +// Finally, we delete the whole attribute 'telephoneNumber': +$result = $entry->delete('telephoneNumber'); +if (Net_LDAP2::isError($result)) { + die('Unable to delete attribute: '.$result->getMessage()); +} + +// Now it is time to transfer the changes to the ldap +// directory. However, for security reasons, this line is +// commented out. + +/* +$result = $entry->update(); +if (Net_LDAP2::isError($result)) { + die('Unable to update entry: '.$result->getMessage()); +} +*/ +?> \ No newline at end of file
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/doc/examples/modify_entry2.php
Added
@@ -0,0 +1,60 @@ +<?php +/** +* This is a short example on how to modify a specific entry in the +* directory using Net_LDAP2. +* The way described here is the more compact one but may be useful too. +* The diference is, that this way we use the $ldap object to modify +* the entry directly on the server. +*/ + +// We use the fetch_entry.php example to get the LDAP-Entry +// which we will modify now. +include_once 'fetch_entry.php'; + +// Okay, we should have a valid Net_LDAP2_Entry object that represents +// a real existing entry in our directory. + +// What we do now is to specify some actions that should be performed. +// Note, that the same rules as in the long version discussed in modify_entry.php +// aplly here too, so for replacing attributes, we must specify the absolute new state. +$changes = array( + 'add' => array( + 'mail' => array('foo@example.org', 'test2@example.org'), + 'telephoneNumber' => '1234567890' + ), + 'replace' => array( + 'mail' => array('test1@example.org', 'test2@example.org') + ), + + 'delete' => array( + 'mail' => 'test2@example.org', + 'telephoneNumber' => null // the null value is important here, since array + ) // mode (indexed, associative) is needed to be homogenous +); + +// Now it is time to transfer the changes to the ldap +// directory. However, for security reasons, these lines +// are commented out. +// You have two options to carry out the changes, with a small but often +// very important difference: +// The first call will carry out the actions in the order "add->delete->replace", +// while the latter will perform the changes in the order you define. +// (add->replace->delete, in our example) + + +/* +// METHOD 1: ORDER = add->delete->replace +$result = $ldap->modify($entry, $changes); +if (Net_LDAP2::isError($result)) { + die('Unable to update entry: '.$result->getMessage()); +} +*/ + +/* +// METHOD 2: ORDER = add->replace->delete +$result = $ldap->modify($entry, array('changes' => $changes)); +if (Net_LDAP2::isError($result)) { + die('Unable to update entry: '.$result->getMessage()); +} +*/ +?>
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/doc/examples/schema_cache.php
Added
@@ -0,0 +1,163 @@ +<?php +/** +* This is a short example on how to use the schema cache facility. +* Schema caching allows you to store the fetched schema on disk +* (or wherever you want, depending on the cache class used) so +* initialisation of Net_LDAP2 becomes a little faster. +* +* Two examples will be showed here: +* 1. how to use the packaged file based cache +* 2. how to write a custom cache class +*/ + +// Class includes; this assumes Net_LDAP2 installed in PHPs include path +// or under subfolder "Net" in the local directory. +require_once 'Net/LDAP2.php'; + +// Configuration +// host can be a single server (string) or multiple ones - if we define more +// servers here (array), we can implement a basic fail over scenario. +// If no credentials (binddn and bindpw) are given, Net_LDAP2 establishes +// an anonymous bind. +// See the documentation for more information on the configuration items! +$ldap_config = array( +// 'host' => 'ldap.example.org', + 'host' => array('ldap1.example.org', 'ldap2.example.org'), +// 'binddn' => 'cn=admin,o=example,dc=org', +// 'bindpw' => 'your-secret-password', + 'tls' => false, + 'base' => 'o=example,dc=org', + 'port' => 389, + 'version' => 3, + 'filter' => '(cn=*)', + 'scope' => 'sub' +); + + +/* +* EXAMPLE 1: How to use the packaged file based cach +* This cache class stores the schema object on disk once Net_LDAP2 +* initially fetched it from the LDAP server. This will make Net_LDAP2 +* use the disk version instead of loading the schema from LDAP +* unless the schema object becomes too old. +*/ + +// Configuring the schema cacher +// see the source code of SimpleFileSchemaCache.php for config options +// An interesting idea is, to store the file in some tmpfs mount, which will +// result in storing the schema cache in memory instead of disk. +$mySchemaCache_cfg = array( + 'path' => '/tmp/Net_LDAP2_Schema.cache', // place to put cache file + 'max_age' => 86400 // max age is 24 hours (in seconds) +); + +// Initialize cache with the config +$mySchemaCache = new Net_LDAP2_SimpleFileSchemaCache($mySchemaCache_cfg); + +// As usual, connect to configured ldap server +$ldap = Net_LDAP2::connect($ldap_config); +if (Net_LDAP2::isError($ldap)) { + die('BIND FAILED: '.$ldap->getMessage()); +} + +// and finally register our initialized cache object +$res = $ldap->registerSchemaCache($mySchemaCache); +if (Net_LDAP2::isError($res)) { + die('REGISTER CACHE FAILED: '.$res->getMessage()); +} + +// Here we go, Net_LDAP2 will fetch the schema once and then use the disk version. + + + + + +/* +* EXAMPLE 2: How to write a custom cache class +* Writing a custom cache class is easy. You just have to wipe out a +* class that implements the SchemaCache interface. +* How a cache class must look like is documented in the interface +* definition file: SchemaCache.interface.php +* Here we will write a small hacky cache that stores the schema +* in the php session. This gives us a nice per-user cache that +* survives for the php session. This cache will obviously not +* be so performant as the SimpleFileSchemaCache but may be +* useful for other purposes. +*/ + +// Firstly, we need our custom schema class... +class MySessionSchemaCache implements Net_LDAP2_SchemaCache { + /** + * Initilize the cache + * + * Here we do nothing. You can use the class constructor for everything you + * want, but typically it is used to configure the caches config. + */ + public function MySessionSchemaCache () { + // nothing to see here, move along... + } + + /** + * Load schema from session + * + * For the sake of simplicity we dont implement a cache aging here. + * This is not a big problem, since php sessions shouldnt last endlessly. + * + * @return Net_LDAP2_Schema|Net_LDAP2_Error|false + */ + public function loadSchema() { + // Lets see if we have a session, otherwise we cant use this cache + // and drop some error that will be returned by Net_LDAP2->schema(). + // Minor errors should be indicated by returning false, so Net_LDAP2 + // can continue its work. This will result in the same behavior as + // no schema cache would have been registered. + if (!isset($_SESSION)) { + return new Net_LDAP2_Error(__CLASS__.": No PHP Session initialized.". + " This cache needs an open PHP session."); + } + + // Here the session is valid, so we return the stores schema. + // If we cant find the schema (because cahce is empty),w e return + // false to inidicate a minor error to Net_LDAP2. + // This causes it to fetch a fresh object from LDAP. + if (array_key_exists(__CLASS__, $_SESSION) + && $_SESSION[__CLASS__] instanceof Net_LDAP2_SchemaCache) { + return $_SESSION[__CLASS__]; + } else { + return false; + } + } + + /** + * Store the schema object in session + * + * @return true|Net_LDAP2_Error + */ + public function storeSchema($schema) { + // Just dump the given object into the session + // unless in loadSchema(), it is important to only return + // Net_LDAP2_Error objects if something crucial went wrong. + // If you feel that you want to return an error object, be sure + // that you have read the comments in Net_LDAP2_SchemaCache.interface.php + // or you will seriously hurt the performance of your application!!!! + $_SESSION[__CLASS__] = $schema; + return true; + } +} + + +// Ok, now we have our finished cache object. Now initialize and register it +// the usual way: +$mySchemaCache = new MySessionSchemaCache(); + +$ldap = Net_LDAP2::connect($ldap_config); +if (Net_LDAP2::isError($ldap)) { + die('BIND FAILED: '.$ldap->getMessage()); +} + +$res = $ldap->registerSchemaCache($mySchemaCache); +if (Net_LDAP2::isError($res)) { + die('REGISTER CACHE FAILED: '.$res->getMessage()); +} + +// Now, the Schema is cached in the PHP session :)
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/doc/examples/search_entries.php
Added
@@ -0,0 +1,78 @@ +<?php +/** +* This is a short example on how to search for entries in your +* directory using Net_LDAP2. +*/ + +// We use the connecting.php example to get a link to our server. +// This file will also include all required basic Net_LDAP2 classes. +include_once 'connecting.php'; + +// Okay, we should have a valid link now. +// We must now define a filter that defines, which +// entries we want to have returned. +// We use the Net_LDAP2_Filter class for this purpose, +// because so we don't need to worry about +// RFC-2254 ;) +// In this example, we want all users with first names +// starting with "bened" and the last names ending with "ger". +// Additionally, we want to exclude all users with names +// containing "smith", which will be done throug a "negation". + +// Basic filter building +$filter_sn = Net_LDAP2_Filter::create('gn', 'begins', 'bened'); +$filter_gn = Net_LDAP2_Filter::create('sn', 'ends', 'ger'); + +// Building and negating the "no smith" filter component +// this must be done in two steps, because +// you are able to negate EVERY filter, not just leave filters. +// the $filter_smith will not be used afterwards and is only +// necessary for negation here. +$filter_smith = Net_LDAP2_Filter::create('sn', 'contains','smith'); +$filter_nosmith = Net_LDAP2_Filter::combine('not', $filter_smith); + +// Now combine all filter components to build our search filter +$filter = Net_LDAP2_Filter::combine('and', array($filter_sn, $filter_gn, $filter_nosmith)); + + +// The filter is ready now, so we can +// use this filter now to search for entries. +// The scope we use is "sub", meaning "all entries below the search base". +// The base is "null", meaning the base defined in $ldap_config. This is similar +// to call $ldap->search($ldap_config['base'], ... +$requested_attributes = array('sn','gn','telephonenumber'); +$search = $ldap->search(null, $filter, array('attributes' => $requested_attributes)); +if (Net_LDAP2::isError($search)) { + die('LDAP search failed: '.$search->getMessage()); +} + +// Lets see what entries we got and print the names and telephone numbers: +if ($search->count() > 0) { + echo "Found ".$search->count().' entries:<br>'; + + // Note, this is is only one of several ways to fetch entries! + // You can also retrieve all entries in an array with + // $entries = $search->entries() + // or the same thing sorted: + // $entries = $search->sorted() + // Since Net_LDAP2 you can also use a foreach loop: + // foreach ($search as $dn => $entry) { + while ($entry = $search->shiftEntry()) { + $surename = $entry->getValue('sn', 'single'); + if (Net_LDAP2::isError($surename)) { + die('Unable to get surename: '.$surename->getMessage()); + } + $givenname = $entry->getValue('gn', 'single'); + if (Net_LDAP2::isError($givenname)) { + die('Unable to get givenname: '.$givenname->getMessage()); + } + $phone = $entry->getValue('telephonenumber', 'single'); + if (Net_LDAP2::isError($phone)) { + die('Unable to get phone number: '.$phone->getMessage()); + } + echo "<br>$givenname $surename: $phone"; + } +} else { + die('Sorry, no entries found!'); +} +?>
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/doc/manual.html
Added
@@ -0,0 +1,248 @@ +<html> +<head> + <title>Net_LDAP2 Manual</title> + <style type="text/css"> + pre { border: 1px solid #000000; background-color:#EBEBEB; padding:5px; } + </style> +</head> +<body> +<h1>Net_LDAP2 Manual</h1> +Welcome to the Net_LDAP2 user manual! here you have a quick introduction on +how to use Net_LDAP2 to acces your directory server with php. +<p><font color="red">Note that this manual is only a brief introduction and also may be outdated. +The official manual is available at the <a href="http://pear.php.net/package/Net_LDAP2/docs">PEAR project website.</a> +The reason this manual remains here is, that it may be useful in cases you don't have internet +acces at the moment.</font></p> + +<h2>First step: Connect</h2> +<p> +To do this, use the Net_LDAP2::connect function like this: + +<p><pre> +require_once('Net_LDAP22/LDAP2.php'); + +$config = array ( + 'binddn' => 'uid=tarjei,dc=php,dc=net', + 'bindpw' => 'secret', + 'basedn' => dc=php,dc=net + ); + +$ldap = Net_LDAP2::connect($config); +</pre></p> +</p> +<p> +But what are valid values in the config array? +<ul>Here's a quick table: (defaults) + <li><b>binddn</b> = the DN to bind as. (none)</li> + <li><b>bindpw</b> = Password of the user specified by 'binddn' (none)</li> + <li><b>host</b> = the ldap host to connect to (localhost)</li> + <li><b>base</b> = ldap base, this is usually the Entry point of your directory (none)</li> + <li><b>port</b> = the server port (389)</li> + <li><b>starttls</b> = when set, ldap_start_tls() is run after connecting. (false)</li> + <li><b>version</b> = ldap version (defaults to v 3) </li> + <li><b>filter</b> = default search filter (objectclass=*)</li> + <li><b>scope</b> = default search scope (sub)</li> +</ul> +We'll get back to these later. +</p> + + + +<h2>Errorhandling</h2> +<p> +Now you should have the base ldapobject stored in the variable "$ldap". +But, what if it is an error? Net_LDAP2 returns a Net_LDAP2_error object (basicly a +pear_error object) when an error occurs. So wherever you need to check an error, do like this: +<p><pre> +$ldap = Net_LDAP2::connect($config); // copied from above! + +if (Net_LDAP2::isError($ldap)) { + print $ldap->getMessage(); // this will tell you what went wrong! +} + +</pre></p> +</p> +<p> +Two things to note: + +<br>1) The function is_a() might be faster: +<p><pre> +if (is_a($ldap,'net_ldap_error')) { +// do the same as above +} +</pre></p> +In PHP5 you must use the instanceof operator instead of is_a(). + +<br>2) Net_LDAP2_Error can also return an errornumber. These numbers are standardized. A good description of what they mean is found there: +http://www.directory-info.com/LDAP2/LDAPErrorCodes.html +</p> + + + +<h2>Searching (basics)</h2> +<p> +Most of the work you do on an ldapserver is in searching, +for example, you search for your boss's password or his wife's phonenumber. +<br>Searching an ldapserver is a bit like doing SQL and a lot not like it at all.</br> +Think of the directory as some sort of "telephone book". +Basically, searches are performed by applying a "filter" to objects under a +specific "base" in the directory. Additionally, there is a "scope" applied to the search, +so you can specify the recursion level in the directory tree. +</p> +<p> +<h3>Base:</h3> +The "base" is the point under the directory where you want to search under. +To search for all people under php.net, you may use: "ou=People,dc=php,dc=net". +But if you want just to search the devs, you can use "ou=dev,ou=People,dc=php,dc=net". +</p> +<p> +<h3>Filter:</h3> Filters define what you are looking for. They "filter out" unwanted entries. +<br>Filters start with a ( and end with a ). There is a lot to be said about filters, most is better said by examples: + +<br><br><b>(&(objectclass=posixAccount)(uid=boss)) :</b> The object has to satisfy both filters. +I.e. an object that is both boss and an posixAccount. If you had another object +with uid=boss but that wasn't an postixaccount it would be excluded. +<br><b>(|(uid=boss)(uid=secretary)) :</b> Either the boss or the secretary. +Note that both logical operators are placed before the filters not between the +two conditions as you might used to from sql. +<br><b>(&(objectclass=posixAccount)(|(uid=boss)(uid=secretary))) :</b> +Here they must have the posixAccount objectclass as well. + +<b>(objectclass=*) :</b> All objects must have an objectclass, so this is the simplest way of saying everything. + +<b>(uid=t*) :</b> With the right indexes on the server, you may search the substring of an attriute. Here; all users with the first name beginning with a "T". + +<br>Please note, that Net_LDAP2 provides a filter class for simplier generation and combination of filters. +You should use that class unless you know how filters work. This will save you a lot of trouble, +since there are some encoding issues with ldap-filters. If you want to provide the filter yourself, +you should also have a look to <a href="http://www.ietf.org/rfc/rfc1558.txt">RFC #1558</a> defining LDAP-Filters. +</p> + +<p> +<h3>Searchscope</h3> +The scope of an search may be three things: +<ul> + <li><b>'base'</b> = Just the entry in question.</li> + <li><b>'sub'</b> = All subentries.</li> + <li><b>'one'</b> = All entries just below the searchbase.</li> +</ul> + +Searching with scope 'base' may be handy for getting just one entry. But then again, that's what the getEntry function does. +</p> + +<p> +<h3>Searching some entries</h3> +We know now, how to search, so we will test out our new knowledge. +We want to search all person entries whose second name starts with "Ha", but only developers. +Later we want to know the name and the telephone number of the persons. +<pre> +$filter = '(&(objectclass=person)(sn=Ha*))'; +$searchbase = 'ou=dev,ou=People,dc=php,dc=net'; +$options = array( + 'scope' => 'sub', // all entries below the searchbase (recursive all subtrees from there) + 'attributes' => array('sn','gn','telephonenumber') // what attributes to select + ); +$search = $ldap->search($searchbase, $filter, $options); +</pre> +$search should now be an Net_LDAP2_Search object. +<br>Okay, now we assume that everything was fine (in production, test for error!). +We have several options now. +We can fetch the found entries at once sorted ($search->sorted()) or unsorted ($search->entries()), or we can read +the objects one by one inside a loop using $search->shiftEntry(). See the class documentation of Net_LDAP2_Search +for more details. +</p> + +<h2>Entries</h2> +<p> +This describes how to get an entry and modifying it. +If we just want one single entry, it may be useful to directly fetch that entry instead +of searching it manually. To do this you can use Net_LDAP2s "getEntry()" method: +<pre> +$dn = 'cn=Foo Bar,ou=dev,ou=People,dc=php,dc=net'; +$entry = $ldap->getEntry($dn, array('sn','gn','telephonenumber')); +</pre> +</p> +With this entry object you now can perform some actions like fetching the contents of attributes: +<pre> +$telephonenumber = $entry->getValue('telephonenumber','single'); +</pre> +Or you can modify a attribute: +<pre> +$entry->replace("telephonenumber" => "0123456789"); // replace the attributes values with the new number +$entry->update(); // update temporarily modified entry on the server +</pre> +Of course there are much more other possibilitys. Please note that adding and deleting +whole entrys is performed through the Net_LDAP2 class and not with the Net_LDAP2_Entry class. + +<h2>Schemas</h2> +You may also use Net_LDAP2 to find out what schemas your ldap-server supports. Here's an example of how: +<pre> +$schema = $ldap->schema(); +</pre> +Now you got a schemaobject. +To read from this schemaobject, you have several methods defined in the class Net_LDAP2_Schema. +<br>For example, to find out which attributes are required for inetOrgPerson, you do this: +<pre> +$required = $schema->must( 'inetOrgUser' ); + +print_r($required); +/* The output of this will be: +Array +( + [0] => sn + [1] => cn +) +*/ +</pre> + +Ok, but what kind of attribute is sn? Let's check: +<pre> +$att = $schema->get('attribute','sn'); + +print_r($att); +/* The output of this will be: +Array +( + [aliases] => Array + ( + [0] => surname + ) + + [oid] => 2.5.4.4 + [name] => sn + [desc] => RFC2256: last (family) name(s) for which the entity is known by + [sup] => Array + ( + [0] => name + ) + [type] => attribute +) +*/ +</pre> +Hmm, ok, the sup part is important. It means that surname derives it's syntax from another attribute, +the name attribute. So , we need to check that as well. +<br>We do: +<pre> +$att_dep = $schema->get('attribute',$att['sup'][0]); + +print_r($att_dep); +/* The output of this will be: +Array +( + [aliases] => Array + ( + ) + + [oid] => 2.5.4.41 + [name] => name + [desc] => RFC2256: common supertype of name attributes + [equality] => caseIgnoreMatch + [substr] => caseIgnoreSubstringsMatch + [syntax] => 1.3.6.1.4.1.1466.115.121.1.15{32768} + [max_length] => 32768 + [type] => attribute +) +*/ +</pre> +From this we find out that the attribute has a maxlength of 32768 characters +and has the syntax 1.3.6.1.4.1.1466.115.121.1.15{32768}.
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/doc/utf8.txt
Added
@@ -0,0 +1,20 @@ +UTF8 and Net_LDAP2: + +It is hard to know exactly what entries need utf8 every time you need them, +so here's the simple way to salvation: + +Net_LDAP2 will check internally if utf8 is needed. + +Code: + // $attr is some text a user entered with funny characters in it. + // If $attr should not be utfized (f.x. userPassword) then utf8Encode + // will not encode the attribute. + $attr = $ldap->utf8Encode($attr); + // now insert the correctly encoded attribute into the directory. + $entry->modify($attr); + + // later when you access the attributes of that user, decode the ones + // that have to be decoded. + $attr = $ldap->utf8Decode( $entry->attributes() ); + +Thanks to Jan for the code.
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/package.xml
Added
@@ -0,0 +1,862 @@ +<?xml version="1.0" encoding="UTF-8"?> +<package packagerversion="1.4.11" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 +http://pear.php.net/dtd/tasks-1.0.xsd +http://pear.php.net/dtd/package-2.0 +http://pear.php.net/dtd/package-2.0.xsd"> + <name>Net_LDAP2</name> + <channel>pear.php.net</channel> + <extends>Net_LDAP</extends> + <summary>Object oriented interface for searching and manipulating LDAP-entries</summary> + <description>Net_LDAP2 is the successor of Net_LDAP which is a clone of Perls Net::LDAP + object interface to directory servers. It does contain most of Net::LDAPs + features but has some own too. + With Net_LDAP2 you have: + * A simple object-oriented interface to connections, searches entries and filters. + * Support for TLS and LDAP v3. + * Simple modification, deletion and creation of LDAP entries. + * Support for schema handling. + + Net_LDAP2 layers itself on top of PHP's existing ldap extensions. + </description> + <lead> + <name>Benedikt Hallinger</name> + <user>beni</user> + <email>beni@php.net</email> + <active>yes</active> + </lead> + + <!-- Information for this release --> + <date>2015-10-30</date> + <version> + <release>2.2.0</release> + <api>2.2.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>LGPLv3 License</license> + <notes> + * Fix bug #20969: Fatal error with PEAR 1.10.0 / constructor visiblity + * Add support for PHP 7 + * Improve unit tests + </notes> + <contents> + <dir name="/"> + <dir name="Net"> + <file name="LDAP2.php" role="php" /> + <dir name="LDAP2"> + <file name="Entry.php" role="php" /> + <file name="Filter.php" role="php" /> + <file name="RootDSE.php" role="php" /> + <file name="Schema.php" role="php" /> + <file name="Search.php" role="php" /> + <file name="Util.php" role="php" /> + <file name="LDIF.php" role="php" /> + <file name="SchemaCache.interface.php" role="php" /> + <file name="SimpleFileSchemaCache.php" role="php" /> + </dir> <!-- /LDAP2 --> + </dir> <!-- /Net --> + <dir name="doc"> + <file name="manual.html" role="doc" /> + <file name="README.txt" role="doc" /> + <file name="RootDSE.txt" role="doc" /> + <file name="Schema.txt" role="doc" /> + <file name="utf8.txt" role="doc" /> + <file name="examples/connecting.php" role="doc" /> + <file name="examples/fetch_entry.php" role="doc" /> + <file name="examples/search_entries.php" role="doc" /> + <file name="examples/add_entry.php" role="doc" /> + <file name="examples/modify_entry.php" role="doc" /> + <file name="examples/modify_entry2.php" role="doc" /> + <file name="examples/schema_cache.php" role="doc" /> + </dir> <!-- /doc --> + <dir name="tests"> + <file name="phpunit.xml" role="test" /> + <file name="Net_LDAP2_TestBase.php" role="test" /> + <file name="Net_LDAP2_EntryTest.php" role="test" /> + <file name="Net_LDAP2_FilterTest.php" role="test" /> + <file name="Net_LDAP2_RootDSETest.php" role="test" /> + <file name="Net_LDAP2_SearchTest.php" role="test" /> + <file name="Net_LDAP2Test.php" role="test" /> + <file name="Net_LDAP2_UtilTest.php" role="test" /> + <file name="Net_LDAP2_LDIFTest.php" role="test" /> + <file name="ldapconfig.ini.dist" role="test" /> + <file name="ldapldifconfig.ini.dist" role="test" /> + <file name="ldif_data/base.ldif" role="test" /> + <file name="ldif_data/malformed_syntax.ldif" role="test" /> + <file name="ldif_data/malformed_syntax.ldif" role="test" /> + <file name="ldif_data/malformed_wrapping.ldif" role="test" /> + <file name="ldif_data/slapd.conf" role="test" /> + <file name="ldif_data/sorted_w40.ldif" role="test" /> + <file name="ldif_data/sorted_w50.ldif" role="test" /> + <file name="ldif_data/unsorted_w30.ldif" role="test" /> + <file name="ldif_data/unsorted_w50.ldif" role="test" /> + <file name="ldif_data/unsorted_w50_WIN.ldif" role="test" /> + <file name="ldif_data/changes.ldif" role="test" /> + </dir> <!-- /tests --> + </dir> <!-- / --> + </contents> + <dependencies> + <required> + <php> + <min>5.4</min> + </php> + <pearinstaller> + <min>1.10.1</min> + </pearinstaller> + <extension> + <name>ldap</name> + </extension> + </required> + </dependencies> + <phprelease /> + + <!-- CHANGELOG --> + <changelog> + <release> + <version> + <release>0.1</release> + <api>0.1</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <date>2003-06-23</date> + <license>LGPL License</license> + <notes>Initial release + </notes> + </release> + <release> + <version> + <release>0.2</release> + <api>0.2</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <date>2003-08-23</date> + <license>LGPL License</license> + <notes>Fixed a lot of bugs that jumped in during the pearification process + </notes> + </release> + <release> + <version> + <release>0.3</release> + <api>0.3</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <date>2003-09-21</date> + <license>LGPL License</license> + <notes>More bug squashing! Much better errorhandling in the ->search() function. + Also, all errors that create a Pear_error now includes the errornumber if + appropriate (i.e. it was an ldap generated error). + </notes> + </release> + <release> + <version> + <release>0.4</release> + <api>0.4</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <date>2003-10-01</date> + <license>LGPL License</license> + <notes>Many more bugfixes. Jan Wagner fixed the shift_entry function. + Also a new Net_LDAP_Entry::modify function has been added that goes far making a simple way to modify entries. + </notes> + </release> + <release> + <version> + <release>0.5</release> + <api>0.5</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <date>2003-10-11</date> + <license>LGPL License</license> + <notes>Jan Wagner Contributed a new RootDSE object and a Schema object and some fixes to the Net_LDAP::search() method + The new Net_ldap_entry::modify() method seems to work very nice now. + </notes> + </release> + <release> + <version> + <release>0.6</release> + <api>0.6</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <date>2003-10-17</date> + <license>LGPL License</license> + <notes>New Net_LDAP::ArrayUTF8Decode and Net_LDAP::ArrayUTF8Encode functions. These are used by the Net_LDAP::Entry objects to ensure that things work ok. + </notes> + </release> + <release> + <version> + <release>0.6.3</release> + <api>0.6.3</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <date>2003-11-12</date> + <license>LGPL License</license> + <notes>It seems that 0.6.2 was out too fast. So this is mainly a bugfix release: + - Removed remaining Net_LDAP::UTF8Encode and Net_LDAP::UTF8Decode calls in Net_LDAP_Entry, + which stopped attributes() and get_entry() from working + - The UTF8 functions somehow got outside the Net_LDAP class ... FIXED. + - The usuage example of the last release was wrong. We decided to move UTF8 handling into Net_LDAP. + Handling should be done this way: + + $attr = $ldap->utf8Encode($attr); + $entry->modify($attr); + $attr = $ldap->utf8Decode( $entry->attributes() ); + - This means Net_LDAP_Util is useless right now, but will be extended in the future. + - Jan did a complete overhaul of the phpdoc stuff. Everything seems to be fine now with phpDocumentor. + </notes> + </release> + <release> + <date>2007-02-05</date> + <version> + <release>0.7.0</release> + <api>0.7.0</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>LGPL License</license> + <notes>This long awaited release of Net_LDAP features more stability and new functionality. + The main changes are: + - Rewrite of much of the code (including some api changes!) + - LOTS of fixed bugs! + - New class for easy filter handling (Net_LDAP_Filter) + - Sorting support for searchresults (including multivalued sorting!) + - Searched Entries can now be fetched as_struct() (array)! + - Some memory optimizations + + Please note also that Net_LDAPs configuration changed slightly. Please see $_config in LDAP.php for the new parameters. + </notes> + </release> + <release> + <date>2007-02-23</date> + <version> + <release>0.7.1</release> + <api>0.7.0</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>LGPL License</license> + <notes>This is not just a bugfix release of 0.7.0 but also introduces some internal optimisations: + - Fixed a connection bug whith LDAP V3 only servers + - clearer sanitizing of the host config parameter + </notes> + </release> + <release> + <date>2007-05-07</date> + <version> + <release>0.7.2</release> + <api>0.7.2</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>LGPL License</license> + <notes>This release features some internal code movements to be more compatible to PERL::Net_LDAP. + The movements include: + * Removed UTF8 en-/decoding stuff from Net_LDAP_Utils class since this was moved to Net_LDAP class in 0.6.6 + * Moved Filter encoding from Net_LDAP_Filter to Net_LDAP_Util + * Moved ldap_explode_dn_escaped() from Net_LDAP_Entry to Net_LDAP_Util + * Added perls functions from Net_LDAP::Util to our Util class, but they still need some work + Please note that ldap_explode_dn_escaped() is not available from Net_LDAP_Entry anymore. + + Additionally some new functionality has been introduced: + * You can now apply regular expressions directly to a entrys attributes + and don't need to fetch the attribute values manually. + * Net_LDAP_Schema can check if a attributes syntax is binary + + The following bugs have been resolved: + * Connections to LDAP servers that forbid anonymous binds are possible again + * The JPEG attribute is now properly returned as binary value instead of string + * If the array describing selected attributes in searches didn't contain consecutive keys, there was a problem sometimes + * Some PHP5 return issues + </notes> + </release> + <release> + <date>2007-06-12</date> + <version> + <release>0.7.3</release> + <api>0.7.2</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>LGPL License</license> + <notes>This release introduces some example files showing you in detail how to work with Net_LDAP. + Additionally, a bug at recursive deletion of an entry is fixed and the Net_LDAP_Filter + class is slightly optimized. + </notes> + </release> + <release> + <date>2007-06-20</date> + <version> + <release>1.0.0RC1</release> + <api>1.0.0RC1</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>LGPL License</license> + <notes>Again some small Bugfixes, most notably a bug within $ldap->modify() that occured when using the + combined 'changes' array. + Besides that, $search->popEntry() and the corresponding alias pop_entry() has been implemented. + Net_LDAP_Util::unescape_filter_value() is available too now and Net_LDAP_Util::escape_filter_value() + can handle ASCII chars smaller than 32. Above that, Net_LDAP_Util::canonical_dn() has been fully implemented. + A new method createFresh() was added to Net_LDAP_Entry, so creation of initial entries is more + standardized and clearer. + A new example is available, describing the $ldap->modify() method. + The add_entry.php example was updated, it shows the use of Net_LDAP_Entry::createFresh(). + $ldap->add() links unlinked entries now to the connection used for the add. + Some new additional utility functions are available in Net_LDAP_Util to assist you in handling attributes and dns. + The LDAP-Rename command now uses this functions to deal with DN escaping issues. + Please note that ldap_explode_dn_escaped() is not available from Net_LDAP_Util anymore; it got superseeded by Net_LDAP_Util::ldap_explode_dn(). + </notes> + </release> + <release> + <date>2007-06-28</date> + <version> + <release>1.0.0RC2</release> + <api>1.0.0RC2</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>LGPL License</license> + <notes>Net_LDAP->dnExists() uses the Util class now, which makes it safer. + A new move() method is available from Net_LDAP. + Please note, that the copy() method was removed from the Net_LDAP_Entry class since + people would expect attribute moving because of the overall API of Net_LDAP. + Instead use the more failsafer copy() from Net_LDAP. + </notes> + </release> + <release> + <date>2007-07-24</date> + <version> + <release>1.0.0RC3</release> + <api>1.0.0RC3</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>LGPL License</license> + <notes> + Fixed a bug with dnExists() that was caused mainly by bad behavior of Net_LDAP_UTIL::ldap_explode_dn(). + Fixed a bug with call time pass-by-reference if calling $entry->update(); however this inflicted a API change: + The parameter $ldap is not available anymore, you need to use $entry->setLDAP() prior update now if you want to change the LDAP + object. This brought us a more logical API now, since Entry operations should be performed by the Net_LDAP object. + </notes> + </release> + <release> + <date>2007-09-18</date> + <version> + <release>1.0.0RC4</release> + <api>1.0.0RC4</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>LGPL License</license> + <notes> + - Fixed some minor bugs of RC3 + - Reintroduced $ldap parameter for + $entry-<update(), but it is not prefferred to use this way. + The Parameter is there for perl interface compatibility + </notes> + </release> + <release> + <date>2007-10-29</date> + <version> + <release>1.0.0</release> + <api>1.0.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>LGPL License</license> + <notes> + After more than four years of development, we are very proud to announce the + ~ FIRST STABLE Net_LDAP RELEASE 1.0.0 ~ + Net_LDAP ist tested now and should be stable enough for production use. + The API is finished so far, no changes should be neccessary in the future. + + Changes to Release candidate 4: + - Implemented PHPUnit tests + - Fixed some minor bugs of RC4 (including the schema loading warning-generation) + - Fixed several bugs in Net_LDAP_Util + - Improved Net_LDAP_Filter and Net_LDAP_Util error handling and code cleanness + - Completely implemented Net_LDAP_Filter perl interface + - Improved several doc comments and fixed some spelling errors + </notes> + </release> + <release> + <date>2008-01-14</date> + <version> + <release>1.1.0a1</release> + <api>1.1.0a1</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>LGPL License</license> + <notes> + * Added LDIF reading and writing support + * Fixed minor issues of 1.0.0 release + </notes> + </release> + <release> + <date>2008-01-21</date> + <version> + <release>1.1.0a2</release> + <api>1.1.0a2</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>LGPL License</license> + <notes> + * Added parseLines() to Net_LDAP_LDIF for more convinience + * Added some handy methods to Net_LDAP_Entry + * Enhanced tests + </notes> + </release> + <release> + <date>2008-02-27</date> + <version> + <release>1.1.0</release> + <api>1.1.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>LGPL License</license> + <notes>* Fixed a little bug at cross directory move + * Fixed a bug when deleting a subtree containing several subentries that failed if + one called dnExists() prior calling delete() + * Fixed some minor bugs at NeT_LDAP->move() and Net_LDAP->dnExists() + * Added Net_LDAP tests + * Changed API of Net_LDAP->copy() to only accept Net_LDAP_Entry objects, because with DNs + Attribute values will be lost + /!\ This is the last release of Net_LDAP supporting PHP4 /!\ + </notes> + </release> + <release> + <date>2008-03-19</date> + <version> + <release>2.0.0RC1</release> + <api>2.0.0RC1</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>LGPL License</license> + <notes>/!\ This release is PHP5 only, replacing the Net_LDAP package. + If you still need PHP4 support, use Net_LDAP instead. + * Implemented iterable search results so one can use foreach() with Net_LDAP2_Search objects + * Fixed a problem with Net_LDAP2_LDIF and files with DOS line endings + </notes> + </release> + <release> + <date>2008-03-20</date> + <version> + <release>2.0.0RC2</release> + <api>2.0.0RC2</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>LGPL License</license> + <notes> +* Implemented PHP5 language stuff (thanks to Torsten Roehr for his helpful patches) +* Changed Net_LDAP2->_markAsNew() to public access, since this is required by the api +and may be useful to developers too +* Changed API to create schema object, there is now a factory. Net_LDAP2->schema() calls +that factory now instead of fetching the Schema itself +* Changed API to create rootDSE object, there is now a factory. Net_LDAP2->rootDSE() calls +that factory now instead of fetching the rootDSE itself +* Net_LDAP2_Entry has a new factory constructor: createConnected() can be used to +establish a new Net_LDAP2_Entry object that represents an already existing entry inside +some directory + </notes> + </release> + <release> + <date>2008-06-04</date> + <version> + <release>2.0.0RC3</release> + <api>2.0.0RC3</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>LGPL License</license> + <notes> +* New constructor factory for Entry objects: createExisting() +* Several small improvements +* New method Entry->isNew() +* Net_LDAP2->search() and Net_LDAP2->dnExists() can handle entry objects now +* Added "present" matching rule as stated by RFC 2254 (is an alias of the former "any") +* Bugfix in filter class for approx matching and not combination +* Bugfix for Schema->isBinary() bug if unknown attribute type is requested + </notes> + </release> + <release> + <date>2008-10-16</date> + <version> + <release>2.0.0RC4</release> + <api>2.0.0RC4</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>LGPL License</license> + <notes> +* Net_LDAP2_Filter::create*() methods are declared static now +* Net_LDAP2 is able to reconnect now in case link is down during operation (thanks Del) +* Complex updates fail: under some circumstances, $entry->update() will fail. This is +caused by mandatory attributes set and the internal behaviour of Net_LDAP2. A +workaround is documented in the code and in the user manual. +* Bugfixes in Dels patches. Soemtimes there where endless loops and deleting entries +did not always succeed. +* Bugfix to reset unicodePwd (Active Directory): a new $force parameter was introduced to Net_LDAP2_Entry->replace() +that forces "replace" mode. If not set and attribute is empty (or could not be read like in the AD case) +replace() resulted in Net_LDAP2 thinking it should add the attribute. This can now be overriden. +* Bugfix in unit tests: the Net_LDAP2Test suite had huge memory consumtion caused by a little error in +Net_LDAP2->checkLDAPExtension(). If that method is called before any Net_LDAP class was instanciated, a PEAR +error is returned instead of the documented Net_LDAP2_Error which causes the unit test to plot out very much +debug information. + </notes> + </release> + <release> + <date>2009-01-09</date> + <version> + <release>2.0.0RC5</release> + <api>2.0.0RC5</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>LGPL License</license> + <notes> +* Fixed a little issue with repetive adding the same attribute value +* Fixed Bug #14886 that caused problems with OpenLDAP and V3 only connects +* Fixed Bug #14903 and #15494, now bind attempt is also encrypted if TLS is requested +* Fixed issue with repetitve adding or deleting values causing Net_LDAP to send the same change multiple times +* Fixed Bug #15364 that caused a problem with setting the ldap version if only one version is supported by server + </notes> + </release> + <release> + <date>2009-05-08</date> + <version> + <release>2.0.0RC6</release> + <api>2.0.0RC6</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>LGPL License</license> + <notes> +* Bugfix in LDIF writer concerning needless base64 encoding of values +* New schema caching facility +* PHPCS fixes, some comment changes and general code cleanup + </notes> + </release> + <release> + <date>2009-05-28</date> + <version> + <release>2.0.0</release> + <api>2.0.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>LGPL License</license> + <notes> +* Fixed bug #16242 (arguments for createFresh in wrong order when calling Net_LDAP2_Entry::createFresh()) +* Fixed bug #16253 (strict checking of isError()) + </notes> + </release> + <release> + <date>2009-06-15</date> + <version> + <release>2.0.1</release> + <api>2.0.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>LGPL License</license> + <notes> +* Fixed Bugs #16272 and #16278 (Problem in starttls function) + </notes> + </release> + <release> + <date>2009-06-29</date> + <version> + <release>2.0.2</release> + <api>2.0.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>LGPL License</license> + <notes> +* Fixed some bugs that rendered the new schema caching facility unusable + </notes> + </release> + <release> + <date>2009-07-03</date> + <version> + <release>2.0.3</release> + <api>2.0.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>LGPL License</license> + <notes> +* Fixed LDAP RFC-1777 violation: bind has to be performed prior setting LDAP version +* Fixed wrong version reported from version() + </notes> + </release> + <release> + <date>2009-07-08</date> + <version> + <release>2.0.4</release> + <api>2.0.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>LGPL License</license> + <notes> +* Fixed Bug #16404 (Bind fails at OpenLDAP with protocol error) + </notes> + </release> + <release> + <date>2009-07-14</date> + <version> + <release>2.0.5</release> + <api>2.0.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>LGPL License</license> + <notes> +* Fixed bug #16438 (SimplefileSchemaCache could not be configured due to wrong var name) + </notes> + </release> + <release> + <date>2009-08-04</date> + <version> + <release>2.0.6</release> + <api>2.0.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>LGPLv3 License</license> + <notes> +* switched LICENSE to LGPL v3 +* added some documentation + </notes> + </release> + <release> + <date>2009-10-28</date> + <version> + <release>2.0.7</release> + <api>2.0.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>LGPLv3 License</license> + <notes> +* Corrected bug #16738 (Problem with Net_LDAP2_Filter::parse() with complex filter, when first subfilter was an combined filter too) + </notes> + </release> + <release> + <version> + <release>2.0.8</release> + <api>2.0.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <date>2010-02-12</date> + <license>LGPLv3 License</license> + <notes> +* Fixed Bug #16940 (Net_LDAP2::startTLS should ignore errors before ldap_start_tls() being called) +* Fixed Bug #17023 (improper handling of wrapped lines in LDIF files) + </notes> + </release> + <release> + <date>2010-02-16</date> + <version> + <release>2.0.8</release> + <api>2.0.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>LGPLv3 License</license> + <notes> +* Fixed Bug #16940 (Net_LDAP2::startTLS should ignore errors before ldap_start_tls() being called) +* Fixed Bug #17023 (improper handling of wrapped lines in LDIF files) +* Fixed Bug #17057 (problem with parsing certain NOT-Filters) + </notes> + </release> + <release> + <date>2010-02-16</date> + <version> + <release>2.0.9</release> + <api>2.0.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>LGPLv3 License</license> + <notes> + * fixed package (package.xml was unclean so 2.0.8 wouldnt install) + </notes> + </release> + <release> + <date>2010-08-23</date> + <version> + <release>2.0.10</release> + <api>2.0.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>LGPLv3 License</license> + <notes> +* Added schema handling methods to make schema checks more easily accessible +* Bugfix for #17245. The check in the code was not working properly. Schema checking is considered the users responsibility. + If now an attribute is requested that is not set at the entry, an empty string is returned. +* Bugfix for #17770. Some Net_LDAP2 files were included with relative path ("Util.php"), not absolute ("Net/LDAP2/Util.php"). +* Bugfix for #17314. LDIF support for attributes with modifiers ("attr1;binary"). + </notes> + </release> + <release> + <date>2011-01-19</date> + <version> + <release>2.0.11</release> + <api>2.0.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>LGPLv3 License</license> + <notes> +* (doc issue) Fix for #17861: Missing komma in example +* Fix for #18202: Adding attributes to a Fresh Entry saving and laterly updating fails + </notes> + </release> + <release> + <date>2011-10-27</date> + <version> + <release>2.0.12</release> + <api>2.0.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>LGPLv3 License</license> + <notes> + * inmproved performance with large search results + * Fixed some minor issues with Net_LDAP2_Filter and Net_LDAP2->dnExists() + * Added NOT filter to Net_LDAP2_Filter::create() so negating is more easily now + </notes> + </release> + <release> + <date>2013-12-09</date> + <version> + <release>2.1.0</release> + <api>2.0.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>LGPLv3 License</license> + <notes> + * New feature: Filter::matches() can do simple filtering on entry sets (supported: equals, contain, begin, end, any; NOT, AND, OR. Filtering is simple based on regexp, no schema checks and matchRules yet!) + * Fixed minor bugs in Filter, LDAP and Entry class + * Util::split_attribute_string(): Added support for extended match operators from filters + * Util::split_attribute_string(): Added support for delimeter retrieval + </notes> + </release> + + <release> + <date>2015-10-30</date> + <version> + <release>2.2.0</release> + <api>2.2.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>LGPLv3 License</license> + <notes> + * Fix bug #20969: Fatal error with PEAR 1.10.0 / constructor visiblity + * Add support for PHP 7 + * Improve unit tests + </notes> + </release> + </changelog> +</package>
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/HOWTO_SETUP_OPENLDAP_TESTCASE.txt
Added
@@ -0,0 +1,64 @@ ++----------------------------------------+ +| Howto for a OpenLDAP based test server | ++----------------------------------------+ + + +PREFACE +======= + +This file describes briefly, how you can set up an OpenLDAP-based +test server where you can run the tests on. +The test cases and ini-files match this guide, so after following it, +you can readily start to run all tests out of the box. + + /!\ DO NOT DO THIS ON A PRODUCTION MACHINE OR /!\ + /!\ ONE CONNECTED TO THE INTERNET /!\ + +If you already have a test server in place, then: + - You don't need to install or configure OpenLDAP + - Adjust the DN in Net_LDAP2/trunk/tests/ldif_data/INITIAL_TESTDATA.ldif + to match your tree + - Adjust your ldapconfig.ini to match your servers setup + + + + +THE GUIDE +========= + +0. PHP, phpunit +Of course you will need this to run the tests... + + +1. Install and configure OpenLDAP +Config: + - base: dc=example,dc=com + - admin: admin (will map to cn=admin,dc=example,dc=com) + - admin-password: test + +Needed schemas: core, inetorgperson +Note that the core schema is usually already present and you have good chances +that the inetorgperson one is there too. +You can apply the schema ldifs after the initial install of openldap with ldapadd: + Net_LDAP2/trunk/tests$ ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/inetorgperson.ldif + +A note for debian users: +Since some recent version the installer does not ask for the baseDN anymore. +Before using apt to install, you may need to manipulate the /etc/hosts, so the +command `dnsdomainname` will return 'example.com'. Then just do `apt-get install slapd`. +The other solution is to adjust all ldif files here and also the test case php scripts. + + +2. Import basic Net_LDAP2 test data +Net_LDAP2 provides an basic LDIF file that maps to the test cases initial config: + Net_LDAP2/trunk/tests$ ldapadd -D cn=admin,dc=example,dc=com -W -H ldapi:/// -f ldif_data/INITIAL_TESTDATA.ldif + + +3. configure test suite +Copy the default config to a real one: + Net_LDAP2/trunk/tests$ cp ldapconfig.ini.dist ldapconfig.ini + + +4. run the tests + - all tests: Net_LDAP2/trunk/tests$ phpunit AllTests.php + - a specific test: Net_LDAP2/trunk/tests$ phpunit Net_LDAP2_UtilTest.php
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/Net_LDAP2Test.php
Added
@@ -0,0 +1,896 @@ +<?php +require_once __DIR__ . '/Net_LDAP2_TestBase.php'; +require_once 'Net/LDAP2.php'; +require_once 'Net/LDAP2/Entry.php'; + +/** + * Test class for Net_LDAP2. + * Generated by PHPUnit_Util_Skeleton on 2007-10-09 at 10:32:36. + */ +class Net_LDAP2Test extends Net_LDAP2_TestBase { + /** + * Stores the LDAP configuration + */ + var $ldapcfg = false; + + /** + * Load ldap config and adjust appropriately + * + * @access protected + */ + protected function setUp() { + $this->ldapcfg = $this->getTestConfig(); + } + + /** + * Tears down the fixture, for example, close a network connection. + * This method is called after a test is executed. + * + * @access protected + */ + protected function tearDown() { + } + + /** + * This checks if a valid LDAP testconfig is present and loads it. + * + * If so, it is loaded and returned as array. If not, false is returned. + * + * @return false|array + */ + public function getTestConfig() { + $config = false; + $file = dirname(__FILE__).'/ldapconfig.ini'; + if (file_exists($file) && is_readable($file)) { + $config = parse_ini_file($file, true); + } else { + return false; + } + // validate ini + $v_error = $file.' is probably invalid. Did you quoted values correctly?'; + $this->assertTrue(array_key_exists('global', $config), $v_error); + $this->assertTrue(array_key_exists('test', $config), $v_error); + $this->assertEquals(7, count($config['global']), $v_error); + $this->assertEquals(7, count($config['test']), $v_error); + + // reformat things a bit, for convinience + $config['global']['server_binddn'] = + $config['global']['server_binddn'].','.$config['global']['server_base_dn']; + $config['test']['existing_attrmv'] = explode('|', $config['test']['existing_attrmv']); + return $config; + } + + /** + * Establishes a working connection + * + * @return Net_LDAP2 + */ + public function &connect() { + // Check extension + if (true !== Net_LDAP2::checkLDAPExtension()) { + $this->markTestSkipped('PHP LDAP extension not found or not loadable. Skipped Test.'); + } + + // Simple working connect and privilegued bind + $lcfg = array( + 'host' => $this->ldapcfg['global']['server_address'], + 'port' => $this->ldapcfg['global']['server_port'], + 'basedn' => $this->ldapcfg['global']['server_base_dn'], + 'binddn' => $this->ldapcfg['global']['server_binddn'], + 'bindpw' => $this->ldapcfg['global']['server_bindpw'], + 'filter' => '(ou=*)', + ); + $ldap = Net_LDAP2::connect($lcfg); + $this->assertInstanceOf('Net_LDAP2', $ldap, 'Connect failed but was supposed to work. Check credentials and host address. If those are correct, file a bug!'); + return $ldap; + } + +/* ---------- TESTS ---------- */ + + /** + * testCheckLDAPExtension(). + * + * @todo can we unload modules at runtime?? + */ + public function testCheckLDAPExtension() { + if (extension_loaded('ldap')) { + // If extension is already loaded, then we must get true. + $this->assertTrue(Net_LDAP2::checkLDAPExtension()); + } else { + // If not, we should be able to load it - but may fail + $this->assertThat(Net_LDAP2::checkLDAPExtension(), + $this->logicalOr($this->isInstanceOf('Net_LDAP2_Error'), $this->equalTo(true))); + } + } + + /** + * Tests if getVersion() works correctly + */ + public function testGetVersion() { + $this->assertTrue(defined('NET_LDAP2_VERSION')); + $this->assertEquals(NET_LDAP2_VERSION, Net_LDAP2::getVersion()); + } + + /** + * Tests if the server can connect and bind correctly + */ + public function testConnectAndPrivileguedBind() { + // Check extension + if (true !== Net_LDAP2::checkLDAPExtension()) { + $this->markTestSkipped('PHP LDAP extension not found or not loadable. Skipped Test.'); + } + + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + // This connect is supposed to fail + $lcfg = array( + 'host' => '0.0.0.1', + ); + $ldap = Net_LDAP2::connect($lcfg); + $this->assertInstanceOf('Net_LDAP2_Error', $ldap, 'Connect succeeded but was supposed to fail!'); + + // Failing with multiple hosts + $lcfg = array( + 'host' => array('0.0.0.1', '0.0.0.2'), + ); + $ldap = Net_LDAP2::connect($lcfg); + $this->assertInstanceOf('Net_LDAP2_Error', $ldap, 'Connect succeeded but was supposed to fail!'); + + // Simple working connect and privilegued bind + $ldap = $this->connect(); + + // Working connect and privilegued bind with first host down + $lcfg = array( + 'host' => array( + '0.0.0.1', + $this->ldapcfg['global']['server_address'] + ), + 'port' => $this->ldapcfg['global']['server_port'], + 'binddn' => $this->ldapcfg['global']['server_binddn'], + 'bindpw' => $this->ldapcfg['global']['server_bindpw'], + ); + $ldap = Net_LDAP2::connect($lcfg); + $this->assertInstanceOf('Net_LDAP2', $ldap, 'Connect failed but was supposed to work. Check credentials and host address. If those are correct, file a bug!'); + } + } + + /** + * Tests if the server can connect and bind anonymously, if supported (->cfg and ldap mode) + */ + public function testConnectAndAnonymousBind() { + // Check extension + if (true !== Net_LDAP2::checkLDAPExtension()) { + $this->markTestSkipped('PHP LDAP extension not found or not loadable. Skipped Test.'); + } + + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } elseif ($this->ldapcfg['global']['server_cap_anonymous'] == true) { + // Simple working connect and anonymous bind + $lcfg = array( + 'host' => $this->ldapcfg['global']['server_address'], + 'port' => $this->ldapcfg['global']['server_port'], + ); + $ldap = Net_LDAP2::connect($lcfg); + $this->assertInstanceOf('Net_LDAP2', $ldap, 'Connect failed but was supposed to work. Check address and if server supports anonymous bind. If those are correct, file a bug!'); + } else { + $this->markTestSkipped('Server does not support anonymous bind (see ldapconfig.ini). Skipping test.'); + } + } + + /** + * testStartTLS() if server supports it + */ + public function testStartTLS() { + // Check extension + if (true !== Net_LDAP2::checkLDAPExtension()) { + $this->markTestSkipped('PHP LDAP extension not found or not loadable. Skipped Test.'); + } + + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } elseif ($this->ldapcfg['global']['server_cap_tls'] == true) { + // Simple working connect and privilegued bind + $lcfg = array( + 'host' => $this->ldapcfg['global']['server_address'], + 'port' => $this->ldapcfg['global']['server_port'], + 'binddn' => $this->ldapcfg['global']['server_binddn'].','.$this->ldapcfg['global']['server_binddn'], + 'bindpw' => $this->ldapcfg['global']['server_bindpw'], + 'starttls' => true + ); + $ldap = Net_LDAP2::connect(); + $this->assertInstanceOf('Net_LDAP2', $ldap, 'Connect failed but was supposed to work. Check credentials and host address. If those are correct, file a bug!'); + } else { + $this->markTestSkipped('Server does not support TLS (see ldapconfig.ini). Skipping test.'); + } + } + + /** + * Test if adding and deleting a fresh entry works + */ + public function testAdd() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $ldap = $this->connect(); + + // Adding a fresh entry + $cn = 'Net-LDAP-TestEntry'; + $dn = 'cn='.$cn.','.$this->ldapcfg['global']['server_base_dn']; + $fresh_entry = Net_LDAP2_Entry::createFresh($dn, + array( + 'objectClass' => array('top','person'), + 'cn' => $cn, + 'sn' => 'TestEntry' + ) + ); + $this->assertInstanceOf('Net_LDAP2_Entry', $fresh_entry); + $this->assertTrue($ldap->add($fresh_entry)); + + // Deleting this Entry + $this->assertTrue($ldap->delete($fresh_entry), 'Deletion of entry failed!'); + } + } + + /** + * testDelete(). + * + * Basic deletion is tested in testAdd(), so here we just test if + * advanced deletion tasks work properly. + */ + public function testDelete() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $ldap = $this->connect(); + // some parameter checks + $this->assertInstanceOf('Net_LDAP2_Error', $ldap->delete(1234)); + $this->assertInstanceOf('Net_LDAP2_Error', $ldap->delete($ldap)); + + // in order to test subtree deletion, we need some little tree + // which we need to establish first + $base = $this->ldapcfg['global']['server_base_dn']; + $testdn = 'ou=Net_LDAP2_Test_subdelete,'.$base; + + $ou = Net_LDAP2_Entry::createFresh($testdn, + array( + 'objectClass' => array('top','organizationalUnit'), + 'ou' => 'Net_LDAP2_Test_subdelete' + )); + $ou_1 = Net_LDAP2_Entry::createFresh('ou=test1,'.$testdn, + array( + 'objectClass' => array('top','organizationalUnit'), + 'ou' => 'test1' + )); + $ou_1_l1 = Net_LDAP2_Entry::createFresh('l=subtest,ou=test1,'.$testdn, + array( + 'objectClass' => array('top','locality'), + 'l' => 'test1' + )); + $ou_2 = Net_LDAP2_Entry::createFresh('ou=test2,'.$testdn, + array( + 'objectClass' => array('top','organizationalUnit'), + 'ou' => 'test2' + )); + $ou_3 = Net_LDAP2_Entry::createFresh('ou=test3,'.$testdn, + array( + 'objectClass' => array('top','organizationalUnit'), + 'ou' => 'test3' + )); + $this->assertTrue($ldap->add($ou)); + $this->assertTrue($ldap->add($ou_1)); + $this->assertTrue($ldap->add($ou_1_l1)); + $this->assertTrue($ldap->add($ou_2)); + $this->assertTrue($ldap->add($ou_3)); + $this->assertTrue($ldap->dnExists($ou->dn())); + $this->assertTrue($ldap->dnExists($ou_1->dn())); + $this->assertTrue($ldap->dnExists($ou_1_l1->dn())); + $this->assertTrue($ldap->dnExists($ou_2->dn())); + $this->assertTrue($ldap->dnExists($ou_3->dn())); + // Tree established now. We can run some tests now :D + + // Try to delete some non existent entry inside that subtree (fails) + $this->assertInstanceOf('Net_LDAP2_Error', $ldap->delete( + 'cn=not_existent,ou=test1,'.$testdn)); + + // Try to delete main test ou without recursive set (fails too) + $this->assertInstanceOf('Net_LDAP2_Error', $ldap->delete($testdn)); + + // Retry with subtree delete, this should work + $this->assertTrue($ldap->delete($testdn, true)); + + // The DN is not allowed to exist anymore + $this->assertFalse($ldap->dnExists($testdn)); + } + } + + /** + * testModify(). + */ + public function testModify() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $ldap = $this->connect(); + // We need a test entry: + $local_entry = Net_LDAP2_Entry::createFresh( + 'ou=Net_LDAP2_Test_modify,'.$this->ldapcfg['global']['server_base_dn'], + array( + 'objectClass' => array('top','organizationalUnit'), + 'ou' => 'Net_LDAP2_Test_modify', + 'street' => 'Beniroad', + 'telephoneNumber' => array('1234', '5678'), + 'postalcode' => '12345', + 'postalAddress' => 'someAddress', + 'facsimileTelephoneNumber' => array('123','456') + )); + $this->assertTrue($ldap->add($local_entry)); + $this->assertTrue($ldap->dnExists($local_entry->dn())); + + // Prepare some changes + $changes = array( + 'add' => array( + 'businessCategory' => array('foocat', 'barcat'), + 'description' => 'testval' + ), + 'delete' => array('postalAddress'), + 'replace' => array('telephoneNumber' => array('345', '567')), + 'changes' => array( + 'replace' => array('street' => 'Highway to Hell'), + 'add' => array('l' => 'someLocality'), + 'delete' => array( + 'postalcode', + 'facsimileTelephoneNumber' => array('123')) + ) + ); + + // Perform those changes + $this->assertTrue($ldap->modify($local_entry, $changes)); + + // verify correct attribute changes + $actual_entry = $ldap->getEntry($local_entry->dn(), array( + 'objectClass', 'ou','postalAddress', 'street', 'telephoneNumber', 'postalcode', + 'facsimileTelephoneNumber', 'l', 'businessCategory', 'description')); + $this->assertInstanceOf('Net_LDAP2_Entry', $actual_entry); + $expected_attributes = array( + 'objectClass' => array('top', 'organizationalUnit'), + 'ou' => 'Net_LDAP2_Test_modify', + 'street' => 'Highway to Hell', + 'l' => 'someLocality', + 'telephoneNumber' => array('345', '567'), + 'businessCategory' => array('foocat', 'barcat'), + 'description' => 'testval', + 'facsimileTelephoneNumber' => '456' + ); + + $local_attributes = $local_entry->getValues(); + $actual_attributes = $actual_entry->getValues(); + + // to enable easy check, we need to sort the + // values of the remaining multival attrs as + // well as the attribute names + ksort($expected_attributes); + ksort($local_attributes); + ksort($actual_attributes); + sort($expected_attributes['businessCategory']); + sort($local_attributes['businessCategory']); + sort($actual_attributes['businessCategory']); + + // cleanup directory + $this->assertTrue($ldap->delete($actual_entry), + 'Cleanup of test entry failed. Please remove manually: '.$local_entry->dn()); + + // The attributes must match the expected values. + // Both, the entry inside the directory and our + // apps local copy must reflect the same values + $this->assertEquals($expected_attributes, $actual_attributes, 'The directory entries attributes are not OK!'); + $this->assertEquals($expected_attributes, $local_attributes, 'The local entries attributes are not OK!'); + } + } + + /** + * testSearch(). + */ + public function testSearch() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $ldap = $this->connect(); + + // some testdata, so we can test sizelimit + $base = $this->ldapcfg['global']['server_base_dn']; + $ou1 = Net_LDAP2_Entry::createFresh('ou=Net_LDAP2_Test_search1,'.$base, + array( + 'objectClass' => array('top','organizationalUnit'), + 'ou' => 'Net_LDAP2_Test_search1' + )); + $ou1_1 = Net_LDAP2_Entry::createFresh('ou=Net_LDAP2_Test_search1_1,'.$ou1->dn(), + array( + 'objectClass' => array('top','organizationalUnit'), + 'ou' => 'Net_LDAP2_Test_search2' + )); + $ou2 = Net_LDAP2_Entry::createFresh('ou=Net_LDAP2_Test_search2,'.$base, + array( + 'objectClass' => array('top','organizationalUnit'), + 'ou' => 'Net_LDAP2_Test_search2' + )); + $this->assertTrue($ldap->add($ou1)); + $this->assertTrue($ldap->dnExists($ou1->dn())); + $this->assertTrue($ldap->add($ou1_1)); + $this->assertTrue($ldap->dnExists($ou1_1->dn())); + $this->assertTrue($ldap->add($ou2)); + $this->assertTrue($ldap->dnExists($ou2->dn())); + + + // Search for testfilter, should at least return our two test entries + $res = $ldap->search(null, '(ou=Net_LDAP2*)', + array('attributes' => '1.1') + ); + $this->assertInstanceOf('Net_LDAP2_Search', $res); + $this->assertThat($res->count(), $this->greaterThanOrEqual(2)); + + // Same, but with Net_LDAP2_Filter object + $filtero = Net_LDAP2_Filter::create('ou', 'begins', 'Net_LDAP2'); + $this->assertInstanceOf('Net_LDAP2_Filter', $filtero); + $res = $ldap->search(null, $filtero, + array('attributes' => '1.1') + ); + $this->assertInstanceOf('Net_LDAP2_Search', $res); + $this->assertThat($res->count(), $this->greaterThanOrEqual(2)); + + // Search using default filter for base-onelevel scope + // should at least return our two test entries + $res = $ldap->search(null, null, + array('scope' => 'one', 'attributes' => '1.1') + ); + $this->assertInstanceOf('Net_LDAP2_Search', $res); + $this->assertThat($res->count(), $this->greaterThanOrEqual(2)); + + // Base-search using custom base (string) + // should only return the test entry $ou1 and not the entry below it. + $res = $ldap->search($ou1->dn(), null, + array('scope' => 'base', 'attributes' => '1.1') + ); + $this->assertInstanceOf('Net_LDAP2_Search', $res); + $this->assertEquals(1, $res->count()); + + // Search using custom base, this time using an entry object + // This tests if passing an entry object as base works + // should only return the test entry $ou1 + $res = $ldap->search($ou1, '(ou=*)', + array('scope' => 'base', 'attributes' => '1.1') + ); + $this->assertInstanceOf('Net_LDAP2_Search', $res); + $this->assertEquals(1, $res->count()); + + // Search using default filter for base-onelevel scope with sizelimit + // should of course return more than one entry, + // but not more than sizelimit + $res = $ldap->search(null, null, + array('scope' => 'one', 'sizelimit' => 1, 'attributes' => '1.1') + ); + $this->assertInstanceOf('Net_LDAP2_Search', $res); + $this->assertEquals(1, $res->count()); + $this->assertTrue($res->sizeLimitExceeded()); // sizelimit should be exceeded now + + // Bad filter + $res = $ldap->search(null, 'somebadfilter', + array('attributes' => '1.1') + ); + $this->assertInstanceOf('Net_LDAP2_Error', $res); + + // Bad base + $res = $ldap->search('badbase', null, + array('attributes' => '1.1') + ); + $this->assertInstanceOf('Net_LDAP2_Error', $res); + + // Passing Error object as base and as filter object + $error = new Net_LDAP2_Error('Testerror'); + $res = $ldap->search($error, null, // error base + array('attributes' => '1.1') + ); + $this->assertInstanceOf('Net_LDAP2_Error', $res); + $res = $ldap->search(null, $error, // error filter + array('attributes' => '1.1') + ); + $this->assertInstanceOf('Net_LDAP2_Error', $res); + + // Nullresult + $res = $ldap->search(null, '(cn=nevermatching_filter)', + array('scope' => 'base', 'attributes' => '1.1') + ); + $this->assertInstanceOf('Net_LDAP2_Search', $res); + $this->assertEquals(0, $res->count()); + + + // cleanup + $this->assertTrue($ldap->delete($ou1_1), 'Cleanup failed, please delete manually'); + $this->assertTrue($ldap->delete($ou1), 'Cleanup failed, please delete manually'); + $this->assertTrue($ldap->delete($ou2), 'Cleanup failed, please delete manually'); + } + } + + /** + * @todo Implement testSetOption(). + */ + public function testSetOption() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $this->markTestIncomplete("This test has not been implemented yet."); + } + } + + /** + * @todo Implement testGetOption(). + */ + public function testGetOption() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $this->markTestIncomplete("This test has not been implemented yet."); + } + } + + /** + * @todo Implement testGetLDAPVersion(). + */ + public function testGetLDAPVersion() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $this->markTestIncomplete("This test has not been implemented yet."); + } + } + + /** + * @todo Implement testSetLDAPVersion(). + */ + public function testSetLDAPVersion() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $this->markTestIncomplete("This test has not been implemented yet."); + } + } + + /** + * testDnExists(). + */ + public function testDnExists() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $ldap = $this->connect(); + $dn = $this->ldapcfg['test']['existing_entry'].','.$this->ldapcfg['global']['server_base_dn']; + + // Testing existing and not existing DN; neither should produce an error + $this->assertTrue($ldap->dnExists($dn)); + $this->assertFalse($ldap->dnExists('cn=not_existent,'.$dn)); + + // Passing an Entry object (should work) + // It should return false, because don't add the test entry + $base = $this->ldapcfg['global']['server_base_dn']; + $ou1 = Net_LDAP2_Entry::createFresh('ou=Net_LDAP2_Test_search1,'.$base, + array( + 'objectClass' => array('top','organizationalUnit'), + 'ou' => 'Net_LDAP2_Test_search1' + )); + $this->assertFalse($ldap->dnExists($ou1)); + + // Passing an float instead of a string + $this->assertInstanceOf('Net_LDAP2_Error', $ldap->dnExists(1.234)); + + // Pasing an error object + $error = new Net_LDAP2_Error('Testerror'); + $this->assertInstanceOf('Net_LDAP2_Error', $ldap->dnExists($error)); + } + } + + /** + * testGetEntry(). + */ + public function testGetEntry() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $ldap = $this->connect(); + $dn = $this->ldapcfg['test']['existing_entry'].','.$this->ldapcfg['global']['server_base_dn']; + + // existing DN + $this->assertInstanceOf('Net_LDAP2_Entry', $ldap->getEntry($dn), "$dn was supposed to be found. Please check your ldapconfig.ini!"); + + // Not existing DN + $this->assertInstanceOf('Net_LDAP2_Error', + $ldap->getEntry('cn=notexistent,'.$this->ldapcfg['global']['server_base_dn'])); + } + } + + /** + * testMove(). + */ + public function testMove() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $ldap = $this->connect(); + + // For Moving tests, we need some little tree again + $base = $this->ldapcfg['global']['server_base_dn']; + $testdn = 'ou=Net_LDAP2_Test_moves,'.$base; + + $ou = Net_LDAP2_Entry::createFresh($testdn, + array( + 'objectClass' => array('top','organizationalUnit'), + 'ou' => 'Net_LDAP2_Test_moves' + )); + $ou_1 = Net_LDAP2_Entry::createFresh('ou=source,'.$testdn, + array( + 'objectClass' => array('top','organizationalUnit'), + 'ou' => 'source' + )); + $ou_1_l1 = Net_LDAP2_Entry::createFresh('l=moveitem,ou=source,'.$testdn, + array( + 'objectClass' => array('top','locality'), + 'l' => 'moveitem', + 'description' => 'movetest' + )); + $ou_2 = Net_LDAP2_Entry::createFresh('ou=target,'.$testdn, + array( + 'objectClass' => array('top','organizationalUnit'), + 'ou' => 'target' + )); + $ou_3 = Net_LDAP2_Entry::createFresh('ou=target_otherdir,'.$testdn, + array( + 'objectClass' => array('top','organizationalUnit'), + 'ou' => 'target_otherdir' + )); + $this->assertTrue($ldap->add($ou)); + $this->assertTrue($ldap->add($ou_1)); + $this->assertTrue($ldap->add($ou_1_l1)); + $this->assertTrue($ldap->add($ou_2)); + $this->assertTrue($ldap->add($ou_3)); + $this->assertTrue($ldap->dnExists($ou->dn())); + $this->assertTrue($ldap->dnExists($ou_1->dn())); + $this->assertTrue($ldap->dnExists($ou_1_l1->dn())); + $this->assertTrue($ldap->dnExists($ou_2->dn())); + $this->assertTrue($ldap->dnExists($ou_3->dn())); + // Tree established + + // Local rename + $olddn = $ou_1_l1->currentDN(); + $this->assertTrue($ldap->move($ou_1_l1, + str_replace('moveitem', 'move_item', $ou_1_l1->dn()))); + $this->assertTrue($ldap->dnExists($ou_1_l1->dn())); + $this->assertFalse($ldap->dnExists($olddn)); + + // Local move + $olddn = $ou_1_l1->currentDN(); + $this->assertTrue($ldap->move($ou_1_l1, 'l=move_item,'.$ou_2->dn())); + $this->assertTrue($ldap->dnExists($ou_1_l1->dn())); + $this->assertFalse($ldap->dnExists($olddn)); + + // Local move backward, with rename + // Here we use the DN of the object, to test DN conversion. + // Note that this will outdate the object since it does not + // has knowledge about the move. + $olddn = $ou_1_l1->currentDN(); + $newdn = 'l=moveditem,'.$ou_2->dn(); + $this->assertTrue($ldap->move($olddn, $newdn)); + $this->assertTrue($ldap->dnExists($newdn)); + $this->assertFalse($ldap->dnExists($olddn)); + $ou_1_l1 = $ldap->getEntry($newdn); // Refetch since the objects DN was outdated + + // Fake-cross directory move using two separate + // links to the same directory. + // This other directory is represented by ou=target_otherdir + $ldap2 = $this->connect(); + $olddn = $ou_1_l1->currentDN(); + $this->assertTrue($ldap->move($ou_1_l1, 'l=movedcrossdir,'.$ou_3->dn(), $ldap2)); + $this->assertFalse($ldap->dnExists($olddn)); + $this->assertTrue($ldap2->dnExists($ou_1_l1->dn())); + + // Try to move over an existing entry + $this->assertInstanceOf('Net_LDAP2_Error', $ldap->move($ou_2, $ou_3->dn(), $ldap2)); + + // Try cross directory move without providing an valid entry but a DN + $this->assertInstanceOf('Net_LDAP2_Error', + $ldap->move($ou_1_l1->dn(), 'l=movedcrossdir2,'.$ou_2->dn(), $ldap2)); + + // Try passing an invalid entry object + $this->assertInstanceOf('Net_LDAP2_Error', + $ldap->move($ldap, 'l=move_item,'.$ou_2->dn())); + + // Try passing an invalid ldap object + $this->assertInstanceOf('Net_LDAP2_Error', + $ldap->move($ou_1_l1, 'l=move_item,'.$ou_2->dn(), $ou_1)); + + // cleanup test tree + $this->assertTrue($ldap->delete($testdn, true), "Could not delete $testdn, please cleanup manually"); + + } + } + + /** + * testCopy(). + */ + public function testCopy() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $ldap = $this->connect(); + + // some testdata... + $base = $this->ldapcfg['global']['server_base_dn']; + $ou1 = Net_LDAP2_Entry::createFresh('ou=Net_LDAP2_Test_pool,'.$base, + array( + 'objectClass' => array('top','organizationalUnit'), + 'ou' => 'Net_LDAP2_Test_copy' + )); + $ou2 = Net_LDAP2_Entry::createFresh('ou=Net_LDAP2_Test_tgt,'.$base, + array( + 'objectClass' => array('top','organizationalUnit'), + 'ou' => 'Net_LDAP2_Test_copy' + )); + $this->assertTrue($ldap->add($ou1)); + $this->assertTrue($ldap->dnExists($ou1->dn())); + $this->assertTrue($ldap->add($ou2)); + $this->assertTrue($ldap->dnExists($ou2->dn())); + $entry = Net_LDAP2_Entry::createFresh('l=cptest,'.$ou1->dn(), + array( + 'objectClass' => array('top','locality'), + 'l' => 'cptest' + )); + $this->assertTrue($ldap->add($entry)); + $this->assertTrue($ldap->dnExists($entry->dn())); + + // copy over the entry to another tree with rename + $entrycp = $ldap->copy($entry, 'l=test_copied,'.$ou2->dn()); + $this->assertInstanceOf('Net_LDAP2_Entry', $entrycp); + $this->assertNotEquals($entry->dn(), $entrycp->dn()); + $this->assertTrue($ldap->dnExists($entrycp->dn())); + + // copy same again (fails, entry exists) + $entrycp_f = $ldap->copy($entry, 'l=test_copied,'.$ou2->dn()); + $this->assertInstanceOf('Net_LDAP2_Error', $entrycp_f); + + // use only DNs to copy (fails) + $entrycp = $ldap->copy($entry->dn(), 'l=test_copied2,'.$ou2->dn()); + + //cleanup + $this->assertTrue($ldap->delete($ou1, true)); + $this->assertTrue($ldap->delete($ou2, true)); + } + } + + /** + * testIsError(). + */ + public function testIsError() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $error = PEAR::raiseError('TestError'); + $this->assertTrue(Net_LDAP2::isError($error)); + $this->assertFalse(Net_LDAP2::isError('noerror')); + } + } + + /** + * checks retrival of RootDSE object + */ + public function testRootDse() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $ldap = $this->connect(); + $this->assertInstanceOf('Net_LDAP2_RootDSE', $ldap->rootDSE()); + } + } + + /** + * Checks retrival of schema through LDAP object + */ + public function testSchema() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $ldap = $this->connect(); + $this->assertInstanceOf('Net_LDAP2_Schema', $ldap->schema()); + } + } + + /** + * testUtf8Encode() + */ + public function testUtf8Encode() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $ldap = $this->connect(); + $utf8 = array('cn' => 'this needs utf8: '.base64_decode('w7bDpMO8')); //öäü + $no_utf8 = array('cn' => 'this needs no utf8'); + + $this->assertNotEquals($utf8, $ldap->utf8Encode($utf8)); + $this->assertEquals($no_utf8, $ldap->utf8Encode($no_utf8)); + + // wrong parameter + $this->assertInstanceOf('Net_LDAP2_Error', $ldap->utf8Encode('foobar')); + $this->assertInstanceOf('Net_LDAP2_Error', $ldap->utf8Encode(array('foobar'))); + } + } + + /** + * testUtf8Decode(). + */ + public function testUtf8Decode() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $ldap = $this->connect(); + $entry = $ldap->getEntry($this->ldapcfg['test']['existing_entry'].','.$this->ldapcfg['global']['server_base_dn'], + array($this->ldapcfg['test']['utf8_attr'], $this->ldapcfg['test']['noutf8_attr'])); + $this->assertInstanceOf('Net_LDAP2_Entry', $entry, 'Unable to fetch test entry, check ldapconfig.ini'); + $raw_utf8 = array($this->ldapcfg['test']['utf8_attr'] => $entry->getValue($this->ldapcfg['test']['utf8_attr'], 'single')); + $this->assertTrue(is_string($raw_utf8[$this->ldapcfg['test']['utf8_attr']])); + $no_utf8 = array($this->ldapcfg['test']['noutf8_attr'] => $entry->getValue($this->ldapcfg['test']['noutf8_attr'], 'single')); + $this->assertTrue(is_string($no_utf8[$this->ldapcfg['test']['noutf8_attr']])); + + $this->assertNotEquals($raw_utf8, $ldap->utf8Decode($raw_utf8)); + $this->assertEquals($no_utf8, $ldap->utf8Decode($no_utf8)); + + // wrong parameter + $this->assertInstanceOf('Net_LDAP2_Error', $ldap->utf8Decode('foobar')); + $this->assertInstanceOf('Net_LDAP2_Error', $ldap->utf8Decode(array('foobar'))); + } + } + + /** + * testGetLink(). + */ + public function testGetLink() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $ldap = $this->connect(); + $this->assertTrue(is_resource($ldap->getLink())); + } + } + + /** + * Test for bug #18202: "Adding attributes to a Fresh Entry saving and laterly updating fails" + */ + public function testEntryAddIsNotPersistent() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $ldap = $this->connect(); + + // setup test entry + $cn = 'Net_LDAP2_Test_bug_18202'; + $dn = 'cn='.$cn.','.$this->ldapcfg['global']['server_base_dn']; + $data = array( + 'objectClass' => array('top', 'inetOrgPerson'), + 'givenName' => 'bug 18202', + 'sn' => 'testentry', + 'cn' => $cn + ); + + // Test case + $entry = Net_LDAP2_Entry::createFresh($dn, $data); + $this->assertInstanceOf('Net_LDAP2_Entry', $entry); + $this->assertTrue( $entry->add(array('uid' => 'Fu Bar')) ); + $this->assertTrue( $ldap->add($entry) ); + $this->assertTrue( $entry->replace(array('uid' => 'Foo Bar')) ); + $this->assertTrue( $result = $entry->update() ); + + // cleanup + $this->assertTrue($ldap->delete($entry), + 'Cleanup of test entry failed. Please remove manually: '.$entry->dn()); + } + } + +} +?>
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/Net_LDAP2_EntryTest.php
Added
@@ -0,0 +1,320 @@ +<?php +require_once 'Net_LDAP2Test.php'; // for config methods +require_once __DIR__ . '/Net_LDAP2_TestBase.php'; + +require_once 'Net/LDAP2/Entry.php'; +require_once 'Net/LDAP2/Entry.php'; + +/** + * Test class for Net_LDAP2_Entry. + * Generated by PHPUnit_Util_Skeleton on 2007-10-09 at 10:33:12. + */ +class Net_LDAP2_EntryTest extends Net_LDAP2_TestBase { + /** + * Stores the LDAP configuration + */ + var $ldapcfg = false; + + /** + * Runs the test methods of this class. + * + * @access public + * @static + */ + public static function main() { + require_once "PHPUnit/TextUI/TestRunner.php"; + + $suite = new PHPUnit_Framework_TestSuite("Net_LDAP2_EntryTest"); + $result = PHPUnit_TextUI_TestRunner::run($suite); + } + + /** + * Sets up the fixture, for example, open a network connection. + * This method is called before a test is executed. + * + * @access protected + */ + protected function setUp() { + $this->ldapcfg = $this->getTestConfig(); + } + + /** + * Tears down the fixture, for example, close a network connection. + * This method is called after a test is executed. + * + * @access protected + */ + protected function tearDown() { + } + + /** + * This checks if a valid LDAP testconfig is present and loads it. + * + * If so, it is loaded and returned as array. If not, false is returned. + * + * @return false|array + */ + public function getTestConfig() { + $config = false; + $file = dirname(__FILE__).'/ldapconfig.ini'; + if (file_exists($file) && is_readable($file)) { + $config = parse_ini_file($file, true); + } else { + return false; + } + // validate ini + $v_error = $file.' is probably invalid. Did you quoted values correctly?'; + $this->assertTrue(array_key_exists('global', $config), $v_error); + $this->assertTrue(array_key_exists('test', $config), $v_error); + $this->assertEquals(7, count($config['global']), $v_error); + $this->assertEquals(7, count($config['test']), $v_error); + + // reformat things a bit, for convinience + $config['global']['server_binddn'] = + $config['global']['server_binddn'].','.$config['global']['server_base_dn']; + $config['test']['existing_attrmv'] = explode('|', $config['test']['existing_attrmv']); + return $config; + } + + /** + * Establishes a working connection + * + * @return Net_LDAP2 + */ + public function &connect() { + // Check extension + if (true !== Net_LDAP2::checkLDAPExtension()) { + $this->markTestSkipped('PHP LDAP extension not found or not loadable. Skipped Test.'); + } + + // Simple working connect and privilegued bind + $lcfg = array( + 'host' => $this->ldapcfg['global']['server_address'], + 'port' => $this->ldapcfg['global']['server_port'], + 'basedn' => $this->ldapcfg['global']['server_base_dn'], + 'binddn' => $this->ldapcfg['global']['server_binddn'], + 'bindpw' => $this->ldapcfg['global']['server_bindpw'], + 'filter' => '(ou=*)', + ); + $ldap = Net_LDAP2::connect($lcfg); + $this->assertInstanceOf('Net_LDAP2', $ldap, 'Connect failed but was supposed to work. Check credentials and host address. If those are correct, file a bug!'); + return $ldap; + } + +/* ---------- TESTS ---------- */ + + /** + * @todo Implement testCreateFresh(). + */ + public function testCreateFresh() { + // test failing creation + $t = Net_LDAP2_Entry::createFresh("cn=test", "I should be an array"); + $this->assertTrue(Net_LDAP2::isError($t), 'Creating fresh entry succeeded but was supposed to fail!'); + + // test failing creation + $t = Net_LDAP2_Entry::createFresh("cn=test", + array( + 'attr1' => 'single', + 'attr2' => array('mv1', 'mv2') + ) + ); + $this->assertInstanceOf('Net_LDAP2_Entry', $t, 'Creating fresh entry failed but was supposed to succeed!'); + } + + /** + * @todo Implement testCreateExisting(). + */ + public function testCreateExisting() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * Test currentDN and API of move + */ + public function testCurrentDN() { + $entry = Net_LDAP2_Entry::createFresh('cn=footest,ou=example,dc=com', array('cn' => 'foo')); + + // test initial state + $this->assertEquals($entry->dn(), $entry->currentDN()); // equal DNs + $this->assertFalse($entry->willBeMoved()); + + // prepare move + $entry->dn('cn=newDN,ou=example,dc=com'); + + // test again + $this->assertNotEquals($entry->dn(), $entry->currentDN()); // equal DNs + $this->assertTrue($entry->willBeMoved()); + } + + /** + * @todo Implement testDn(). + */ + public function testDn() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement test_setAttributes(). + */ + public function test_setAttributes() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testGetValues(). + */ + public function testGetValues() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testGetValue(). + */ + public function testGetValue() { + // make up some local entry + $entry = Net_LDAP2_Entry::createFresh("cn=test", + array( + 'attr1' => 'single', + 'attr2' => array('mv1', 'mv2') + ) + ); + + // test default behavior + $this->assertEquals('single', $entry->getValue('attr1')); + $this->assertEquals(array('mv1', 'mv2'), $entry->getValue('attr2')); + $this->assertEquals(false, $entry->getValue('nonexistent')); + + // test option "single" + $this->assertEquals('single', $entry->getValue('attr1', 'single')); + $this->assertEquals('mv1', $entry->getValue('attr2', 'single')); + $this->assertEquals(false, $entry->getValue('nonexistent', 'single')); + + // test option "all" + $this->assertEquals(array('single'), $entry->getValue('attr1', 'all')); + $this->assertEquals(array('mv1', 'mv2'), $entry->getValue('attr2', 'all')); + $this->assertEquals(array(), $entry->getValue('nonexistent', 'all')); + } + + /** + * @todo Implement testGet_value(). + */ + public function testGet_value() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testAttributes(). + */ + public function testAttributes() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testExists(). + */ + public function testExists() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testAdd(). + */ + public function testAdd() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testDelete(). + */ + public function testDelete() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testReplace(). + */ + public function testReplace() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testUpdate(). + */ + public function testUpdate() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement test_getAttrName(). + */ + public function test_getAttrName() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testGetLDAP(). + */ + public function testGetLDAP() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testSetLDAP(). + */ + public function testSetLDAP() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testPreg_match(). + */ + public function testPreg_match() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } +} +?>
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/Net_LDAP2_FilterTest.php
Added
@@ -0,0 +1,506 @@ +<?php +require_once __DIR__ . '/Net_LDAP2_TestBase.php'; +require_once 'Net/LDAP2/Filter.php'; + +/** + * Test class for Net_LDAP2_Filter. + * Generated by PHPUnit_Util_Skeleton on 2007-10-09 at 10:34:23. + */ +class Net_LDAP2_FilterTest extends Net_LDAP2_TestBase { + /** + * @var string default filter string to test with + */ + var $filter_str = '(&(cn=foo)(ou=bar))'; + + /** + * Runs the test methods of this class. + * + * @access public + * @static + */ + public static function main() { + require_once "PHPUnit/TextUI/TestRunner.php"; + + $suite = new PHPUnit_Framework_TestSuite("Net_LDAP2_FilterTest"); + $result = PHPUnit_TextUI_TestRunner::run($suite); + } + + /** + * Sets up the fixture, for example, open a network connection. + * This method is called before a test is executed. + * + * @access protected + */ + protected function setUp() { + } + + /** + * Tears down the fixture, for example, close a network connection. + * This method is called after a test is executed. + * + * @access protected + */ + protected function tearDown() { + } + + /** + * This tests the perl compatible creation of filters through parsing of an filter string + */ + public function testCreatePerlCompatible() { + $filter_o = new Net_LDAP2_Filter($this->filter_str); + $this->assertInstanceOf('Net_LDAP2_Filter', $filter_o); + $this->assertEquals($this->filter_str, $filter_o->asString()); + + $filter_o_err = new Net_LDAP2_Filter('some bad filter'); + $this->assertInstanceOf('PEAR_Error', $filter_o_err->asString()); + } + + /** + * Test correct parsing of filter strings through parse() + */ + public function testParse() { + $parsed_dmg = Net_LDAP2_Filter::parse('some_damaged_filter_str'); + $this->assertInstanceOf('PEAR_Error', $parsed_dmg); + + $parsed_dmg2 = Net_LDAP2_Filter::parse('(invalid=filter)(because=~no-surrounding brackets)'); + $this->assertInstanceOf('PEAR_Error', $parsed_dmg2); + + $parsed_dmg3 = Net_LDAP2_Filter::parse('((invalid=filter)(because=log_op is missing))'); + $this->assertInstanceOf('PEAR_Error', $parsed_dmg3); + + $parsed_dmg4 = Net_LDAP2_Filter::parse('(invalid-because-becauseinvalidoperator)'); + $this->assertInstanceOf('PEAR_Error', $parsed_dmg4); + + $parsed_dmg5 = Net_LDAP2_Filter::parse('(&(filterpart>=ok)(part2=~ok)(filterpart3_notok---becauseinvalidoperator))'); + $this->assertInstanceOf('PEAR_Error', $parsed_dmg5); + + // To verify bug #19364 is fixed + $parsed_dmg6 = Net_LDAP2_Filter::parse('(|((invalid-because-too-many-open-parens=x)(a=c))'); + $this->assertInstanceOf('PEAR_Error', $parsed_dmg6); + $parsed_dmg7 = Net_LDAP2_Filter::parse('(|(invalid-because-too-many-close-parens=x)(a=c)))'); + $this->assertInstanceOf('PEAR_Error', $parsed_dmg7); + + $parsed1 = Net_LDAP2_Filter::parse($this->filter_str); + $this->assertInstanceOf('Net_LDAP2_Filter', $parsed1); + $this->assertEquals($this->filter_str, $parsed1->asString()); + + // To verify bug #16738 is fixed. + // In 2.0.6 there was a problem with the splitting of the filter parts if the next part was also an combined filter + $parsed2_str = "(&(&(objectClass=posixgroup)(objectClass=foogroup))(uniquemember=uid=eeggs,ou=people,o=foo))"; + $parsed2 = Net_LDAP2_Filter::parse($parsed2_str); + $this->assertInstanceOf('Net_LDAP2_Filter', $parsed2); + $this->assertEquals($parsed2_str, $parsed2->asString()); + + // To verify bug #17057 is fixed + // In 2.0.7 there was a problem parsing certain not-combined filter strings. + $parsed3_str = "(!(jpegPhoto=*))"; + $parsed3 = Net_LDAP2_Filter::parse($parsed3_str); + $this->assertInstanceOf('Net_LDAP2_Filter', $parsed3); + $this->assertEquals($parsed3_str, $parsed3->asString()); + + $parsed3_complex_str = "(&(someAttr=someValue)(!(jpegPhoto=*)))"; + $parsed3_complex = Net_LDAP2_Filter::parse($parsed3_complex_str); + $this->assertInstanceOf('Net_LDAP2_Filter', $parsed3_complex); + $this->assertEquals($parsed3_complex_str, $parsed3_complex->asString()); + + } + + + /** + * This tests the basic create() method of creating filters + */ + public function testCreate() { + // Test values and an array containing the filter + // creating methods and an regex to test the resulting filter + $testattr = 'testattr'; + $testval = 'testval'; + $combinations = array( + 'equals' => "/\($testattr=$testval\)/", + 'equals' => "/\($testattr=$testval\)/", + 'begins' => "/\($testattr=$testval\*\)/", + 'ends' => "/\($testattr=\*$testval\)/", + 'contains' => "/\($testattr=\*$testval\*\)/", + 'greater' => "/\($testattr>$testval\)/", + 'less' => "/\($testattr<$testval\)/", + 'greaterorequal' => "/\($testattr>=$testval\)/", + 'lessorequal' => "/\($testattr<=$testval\)/", + 'approx' => "/\($testattr~=$testval\)/", + 'any' => "/\($testattr=\*\)/" + ); + // generate negating tests with supported operator combinations + foreach ($combinations as $match => $regex) { + $regex = preg_replace('#^/|/$#', '', $regex); // treat regex, so we can extend it easily + $combinations['not '.$match] = "/\(!$regex\)/"; + $combinations['not_'.$match] = "/\(!$regex\)/"; + $combinations['not-'.$match] = "/\(!$regex\)/"; + $combinations['! '.$match] = "/\(!$regex\)/"; + $combinations['!_'.$match] = "/\(!$regex\)/"; + $combinations['!-'.$match] = "/\(!$regex\)/"; + } + + // perform tests + foreach ($combinations as $match => $regex) { + // escaping is tested in util class + $filter = Net_LDAP2_Filter::create($testattr, $match, $testval, false); + + $this->assertInstanceOf('Net_LDAP2_Filter', $filter); + $this->assertRegExp($regex, $filter->asString(), "Filter generation failed for MatchType: $match"); + } + + // test creating failure + $filter = Net_LDAP2_Filter::create($testattr, 'test_undefined_matchingrule', $testval); + $this->assertInstanceOf('PEAR_Error', $filter); + } + + /** + * Tests, if asString() works + */ + public function testAsString() { + $filter = Net_LDAP2_Filter::create('foo', 'equals', 'bar'); + $this->assertInstanceOf('Net_LDAP2_Filter', $filter); + $this->assertEquals('(foo=bar)', $filter->asString()); + $this->assertEquals('(foo=bar)', $filter->as_string()); + } + + /** + * Tests, if printMe() works + */ + public function testPrintMe() { + if (substr(strtolower(PHP_OS), 0,3) == 'win') { + $testfile = '/tmp/Net_LDAP2_Filter_printMe-Testfile'; + } else { + $testfile = 'c:\Net_LDAP2_Filter_printMe-Testfile'; + } + $filter = Net_LDAP2_Filter::create('testPrintMe', 'equals', 'ok'); + $this->assertInstanceOf('Net_LDAP2_Filter', $filter); + + // print success: + ob_start(); + $printresult = $filter->printMe(); + ob_end_clean(); + $this->assertTrue($printresult); + + // PrintMe if Filehandle is an error (e.g. if some PEAR-File db is used): + $err = new PEAR_Error(); + $this->assertInstanceOf('PEAR_Error', $filter->printMe($err)); + + // PrintMe if filter is damaged, + // $filter_dmg is used below too, to test printing to a file with + // damaged filter + $filter_dmg = new Net_LDAP2_Filter('damaged_filter_string'); + + // write success: + $file = @fopen($testfile, 'w'); + if (is_writable($testfile) && $file) { + $this->assertTrue($filter->printMe($file)); + $this->assertInstanceOf('PEAR_Error', $filter_dmg->printMe($file)); // dmg. filter + @fclose($file); + } else { + $this->markTestSkipped("$testfile could not be opened in write mode, skipping write test"); + } + // write failure: + $file = @fopen($testfile, 'r'); + if (is_writable($testfile) && $file) { + $this->assertInstanceOf('PEAR_Error', $filter->printMe($file)); + @fclose($file); + @unlink($testfile); + } else { + $this->markTestSkipped("$testfile could not be opened in read mode, skipping write test"); + } + } + + /** + * This tests the basic cobination of filters + */ + public function testCombine() { + // Setup + $filter0 = Net_LDAP2_Filter::create('foo', 'equals', 'bar'); + $this->assertInstanceOf('Net_LDAP2_Filter', $filter0); + + $filter1 = Net_LDAP2_Filter::create('bar', 'equals', 'foo'); + $this->assertInstanceOf('Net_LDAP2_Filter', $filter1); + + $filter2 = Net_LDAP2_Filter::create('you', 'equals', 'me'); + $this->assertInstanceOf('Net_LDAP2_Filter', $filter2); + + $filter3 = new Net_LDAP2_Filter('(perlinterface=used)'); + $this->assertInstanceOf('Net_LDAP2_Filter', $filter3); + + // Negation test + $filter_not1 = Net_LDAP2_Filter::combine('not', $filter0); + $this->assertInstanceOf('Net_LDAP2_Filter', $filter_not1, 'Negation failed for literal NOT'); + $this->assertEquals('(!(foo=bar))', $filter_not1->asString()); + + $filter_not2 = Net_LDAP2_Filter::combine('!', $filter0); + $this->assertInstanceOf('Net_LDAP2_Filter', $filter_not2, 'Negation failed for logical NOT'); + $this->assertEquals('(!(foo=bar))', $filter_not2->asString()); + + $filter_not3 = Net_LDAP2_Filter::combine('!', $filter0->asString()); + $this->assertInstanceOf('Net_LDAP2_Filter', $filter_not3, 'Negation failed for logical NOT'); + $this->assertEquals('(!'.$filter0->asString().')', $filter_not3->asString()); + + + // Combination test: OR + $filter_comb_or1 = Net_LDAP2_Filter::combine('or', array($filter1, $filter2)); + $this->assertInstanceOf('Net_LDAP2_Filter', $filter_comb_or1, 'Combination failed for literal OR'); + $this->assertEquals('(|(bar=foo)(you=me))', $filter_comb_or1->asString()); + + $filter_comb_or2 = Net_LDAP2_Filter::combine('|', array($filter1, $filter2)); + $this->assertInstanceOf('Net_LDAP2_Filter', $filter_comb_or2, 'combination failed for logical OR'); + $this->assertEquals('(|(bar=foo)(you=me))', $filter_comb_or2->asString()); + + + // Combination test: AND + $filter_comb_and1 = Net_LDAP2_Filter::combine('and', array($filter1, $filter2)); + $this->assertInstanceOf('Net_LDAP2_Filter', $filter_comb_and1, 'Combination failed for literal AND'); + $this->assertEquals('(&(bar=foo)(you=me))', $filter_comb_and1->asString()); + + $filter_comb_and2 = Net_LDAP2_Filter::combine('&', array($filter1, $filter2)); + $this->assertInstanceOf('Net_LDAP2_Filter', $filter_comb_and2, 'combination failed for logical AND'); + $this->assertEquals('(&(bar=foo)(you=me))', $filter_comb_and2->asString()); + + + // Combination test: using filter created with perl interface + $filter_comb_perl1 = Net_LDAP2_Filter::combine('and', array($filter1, $filter3)); + $this->assertInstanceOf('Net_LDAP2_Filter', $filter_comb_perl1, 'Combination failed for literal AND'); + $this->assertEquals('(&(bar=foo)(perlinterface=used))', $filter_comb_perl1->asString()); + + $filter_comb_perl2 = Net_LDAP2_Filter::combine('&', array($filter1, $filter3)); + $this->assertInstanceOf('Net_LDAP2_Filter', $filter_comb_perl2, 'combination failed for logical AND'); + $this->assertEquals('(&(bar=foo)(perlinterface=used))', $filter_comb_perl2->asString()); + + + // Combination test: using filter_str instead of object + $filter_comb_fstr1 = Net_LDAP2_Filter::combine('and', array($filter1, '(filter_str=foo)')); + $this->assertInstanceOf('Net_LDAP2_Filter', $filter_comb_fstr1, 'Combination failed for literal AND using filter_str'); + $this->assertEquals('(&(bar=foo)(filter_str=foo))', $filter_comb_fstr1->asString()); + + + // Combination test: deep combination + $filter_comp_deep = Net_LDAP2_Filter::combine('and',array($filter2, $filter_not1, $filter_comb_or1, $filter_comb_perl1)); + $this->assertInstanceOf('Net_LDAP2_Filter', $filter_comp_deep, 'Deep combination failed!'); + $this->assertEquals('(&(you=me)(!(foo=bar))(|(bar=foo)(you=me))(&(bar=foo)(perlinterface=used)))', $filter_comp_deep->AsString()); + + + // Test failure in combination + $damaged_filter = Net_LDAP2_Filter::create('foo', 'test_undefined_matchingrule', 'bar'); + $this->assertInstanceOf('PEAR_Error', $damaged_filter); + $filter_not_dmg0 = Net_LDAP2_Filter::combine('not', $damaged_filter); + $this->assertInstanceOf('PEAR_Error', $filter_not_dmg0); + + $filter_not_dmg0s = Net_LDAP2_Filter::combine('not', 'damaged_filter_str'); + $this->assertInstanceOf('PEAR_Error', $filter_not_dmg0s); + + $filter_not_multi = Net_LDAP2_Filter::combine('not', array($filter0, $filter1)); + $this->assertInstanceOf('PEAR_Error', $filter_not_multi); + + $filter_not_dmg1 = Net_LDAP2_Filter::combine('not', null); + $this->assertInstanceOf('PEAR_Error', $filter_not_dmg1); + + $filter_not_dmg2 = Net_LDAP2_Filter::combine('and', $filter_not1); + $this->assertInstanceOf('PEAR_Error', $filter_not_dmg2); + + $filter_not_dmg3 = Net_LDAP2_Filter::combine('and', array($filter_not1)); + $this->assertInstanceOf('PEAR_Error', $filter_not_dmg3); + + $filter_not_dmg4 = Net_LDAP2_Filter::combine('and', $filter_not1); + $this->assertInstanceOf('PEAR_Error', $filter_not_dmg4); + + $filter_not_dmg5 = Net_LDAP2_Filter::combine('or', array($filter_not1)); + $this->assertInstanceOf('PEAR_Error', $filter_not_dmg5); + + $filter_not_dmg5 = Net_LDAP2_Filter::combine('some_unknown_method', array($filter_not1)); + $this->assertInstanceOf('PEAR_Error', $filter_not_dmg5); + + $filter_not_dmg6 = Net_LDAP2_Filter::combine('and', array($filter_not1, 'some_invalid_filterstring')); + $this->assertInstanceOf('PEAR_Error', $filter_not_dmg6); + + $filter_not_dmg7 = Net_LDAP2_Filter::combine('and', array($filter_not1, $damaged_filter)); + $this->assertInstanceOf('PEAR_Error', $filter_not_dmg7); + + $filter_not_dmg8 = Net_LDAP2_Filter::combine('and', array($filter_not1, null)); + $this->assertInstanceOf('PEAR_Error', $filter_not_dmg8); + } + + /** + * Test getComponents() + */ + public function testGetComponents() { + // make up some filters to test + $filter = Net_LDAP2_Filter::create('foo', 'equals', 'bar'); + $this->assertEquals(array('foo', '=', 'bar'), $filter->getComponents()); + + $filter = Net_LDAP2_Filter::create('foo', 'begins', 'bar'); + $this->assertEquals(array('foo', '=', 'bar*'), $filter->getComponents()); + + $filter = Net_LDAP2_Filter::create('foo', 'ends', 'bar'); + $this->assertEquals(array('foo', '=', '*bar'), $filter->getComponents()); + + $filter = Net_LDAP2_Filter::create('foo', 'contains', 'bar'); + $this->assertEquals(array('foo', '=', '*bar*'), $filter->getComponents()); + + $filter = Net_LDAP2_Filter::create('foo', 'any'); + $this->assertEquals(array('foo', '=', '*'), $filter->getComponents()); + + $filter = Net_LDAP2_Filter::create('foo', 'greater', '1234'); + $this->assertEquals(array('foo', '>', '1234'), $filter->getComponents()); + + $filter = Net_LDAP2_Filter::create('foo', 'less', '1234'); + $this->assertEquals(array('foo', '<', '1234'), $filter->getComponents()); + + $filter = Net_LDAP2_Filter::create('foo', 'greaterOrEqual', '1234'); + $this->assertEquals(array('foo', '>=', '1234'), $filter->getComponents()); + + $filter = Net_LDAP2_Filter::create('foo', 'lessOrEqual', '1234'); + $this->assertEquals(array('foo', '<=', '1234'), $filter->getComponents()); + + $filter = Net_LDAP2_Filter::create('foo', 'approx', '1234'); + $this->assertEquals(array('foo', '~=', '1234'), $filter->getComponents()); + + + // negative testing: non-leaf filter + $filter = Net_LDAP2_Filter::combine('and', array(Net_LDAP2_Filter::create('foo', 'any'), Net_LDAP2_Filter::create('foo', 'equals', 'bar'))); + $this->assertInstanceOf('PEAR_Error', $filter->getComponents()); + + } + + /** + * Test match() + */ + public function testMatch() { + // make up some local test entry + $entry1 = Net_LDAP2_Entry::createFresh('cn=Simpson Homer,l=springfield,c=usa', + array( + 'cn' => 'Simpson Homer', + 'sn' => 'Simpson', + 'givenName' => 'Homer', + 'fingers' => 5, + 'hairColor' => 'black', + 'donutsConsumed' => 4521875663232, + 'height' => '175', + 'mail' => 'homer@iLikeBlueToweredHair.com', + 'objectClass' => array('top', 'person', 'inetOrgPerson', 'myFancyTestClass'), + ) + ); + $entry2 = Net_LDAP2_Entry::createFresh('cn=Simpson Bart,l=springfield,c=usa', + array( + 'cn' => 'Simpson Bart', + 'sn' => 'Simpson', + 'givenName' => 'Bart', + 'fingers' => 5, + 'hairColor' => 'yellow', + 'height' => '120', + 'mail' => 'bart@iHateSchool.com', + 'objectClass' => array('top', 'person', 'inetOrgPerson', 'myFancyTestClass'), + ) + ); + $entry3 = Net_LDAP2_Entry::createFresh('cn=Brockman Kent,l=springfield,c=usa', + array( + 'cn' => 'Brockman Kent', + 'sn' => 'Brockman', + 'givenName' => 'Kent', + 'fingers' => 5, + 'hairColor' => 'white', + 'height' => '185', + 'mail' => 'kent.brockman@channel6.com', + 'objectClass' => array('top', 'person', 'inetOrgPerson', 'myFancyTestClass'), + ) + ); + + $allEntries = array($entry1, $entry2, $entry3); + + // Simple matching on single entry + $filter = Net_LDAP2_Filter::create('cn', 'equals', 'Simpson Homer'); + $this->assertEquals(1, $filter->matches($entry1)); + $filter = Net_LDAP2_Filter::create('cn', 'equals', 'son'); + $this->assertEquals(0, $filter->matches($entry1)); + + $filter = Net_LDAP2_Filter::create('mail', 'begins', 'Hom'); + $this->assertEquals(1, $filter->matches($entry1)); + + $filter = Net_LDAP2_Filter::create('objectClass', 'contains', 'org'); // note the lowercase of 'org', as DirSTR is usually syntax CaseIgnore + $this->assertEquals(1, $filter->matches($entry1)); + + // Simple negative tests on single entry + $filter = Net_LDAP2_Filter::create('givenName', 'equals', 'Lisa-is-nonexistent'); + $this->assertEquals(0, $filter->matches($entry1)); + + // Simple tests with multiple entries + $filter = Net_LDAP2_Filter::create('cn', 'begins', 'Nomatch'); + $this->assertEquals(0, $filter->matches($allEntries)); + + $filter = Net_LDAP2_Filter::create('cn', 'begins', 'Simpson Ho'); + $this->assertEquals(1, $filter->matches($allEntries)); + + $filter = Net_LDAP2_Filter::create('cn', 'begins', 'Simpson'); + $this->assertEquals(2, $filter->matches($allEntries)); + + // test with retrieving the resulting entries + $filter = Net_LDAP2_Filter::create('cn', 'begins', 'Simpson Ho'); + $filterresult = array(); + $this->assertEquals(1, $filter->matches($allEntries, $filterresult)); + $this->assertEquals(count($filterresult), $filter->matches($allEntries, $filterresult), "returned result and result counter differ!"); + $this->assertEquals($entry1->dn(), array_shift($filterresult)->dn(), "Filtered entry does not equal expected entry! filter='".$filter->asString()."'"); + + // make sure return values are consistent with input and that all entries are found + $filter = Net_LDAP2_Filter::parse('(objectClass=*)'); + $filterresult = array(); + $this->assertEquals(count($allEntries), $filter->matches($allEntries, $filterresult), "returned result does not match input data count"); + $this->assertEquals(count($filterresult), $filter->matches($allEntries, $filterresult), "returned result and result counter differ!"); + + // Test for compliant "any" filtering: + // Only entries should be returned, that have the attribute + // Negation: Only Entries that don't have the attribute set at all + $filter = Net_LDAP2_Filter::create('donutsConsumed', 'any'); // only homer consume donuts + $filterresult = array(); + $this->assertEquals(1, $filter->matches($allEntries, $filterresult)); + $this->assertEquals($entry1->dn(), array_shift($filterresult)->dn(), "Filtered entry does not equal expected entry! filter='".$filter->asString()."'"); + + $filter = Net_LDAP2_Filter::combine('not', $filter); // all but homer consume donuts + $this->assertEquals(count($allEntries)-1, $filter->matches($allEntries, $filterresult), "Filtered entry does not equal expected entry! filter='".$filter->asString()."'"); + + // NOT combination test + $filter = Net_LDAP2_Filter::create('givenName', 'not equals', 'Homer'); + $filterresult = array(); + $this->assertEquals(2, $filter->matches($allEntries, $filterresult)); + $this->assertEquals($entry2->dn(), array_shift($filterresult)->dn(), "Filtered entry does not equal expected entry! filter='".$filter->asString()."'"); + $this->assertEquals($entry3->dn(), array_shift($filterresult)->dn(), "Filtered entry does not equal expected entry! filter='".$filter->asString()."'"); + + // OR combination test + $filter1 = Net_LDAP2_Filter::create('sn', 'equals', 'Simpson'); + $filter2 = Net_LDAP2_Filter::create('givenName', 'equals', 'Kent'); + $filter_or = Net_LDAP2_Filter::combine('or', array($filter1, $filter2)); + $filterresult = array(); + $this->assertEquals(3, $filter_or->matches($allEntries, $filterresult)); + + // AND combination test + $filter1 = Net_LDAP2_Filter::create('sn', 'equals', 'Simpson'); + $filter2 = Net_LDAP2_Filter::create('givenName', 'equals', 'Bart'); + $filter_and = Net_LDAP2_Filter::combine('and', array($filter1, $filter2)); + $filterresult = array(); + $filter_and->matches($allEntries, $filterresult); + $this->assertEquals(1, $filter_and->matches($allEntries, $filterresult), "AND Filter failed '".$filter_and->asString()."'"); + + // AND, NOT and OR combined test + $filter1 = Net_LDAP2_Filter::combine('or', array( + Net_LDAP2_Filter::create('hairColor', 'equals', 'white'), // kent or... + Net_LDAP2_Filter::create('hairColor', 'equals', 'black') // ...homer + )); + $filter2 = Net_LDAP2_Filter::create('givenName', 'not equals', 'Homer'); // all except homer + $filter_final = Net_LDAP2_Filter::combine('and', array($filter1, $filter2)); + $this->assertEquals(2, $filter1->matches($allEntries)); // kent and homer + $this->assertEquals(2, $filter2->matches($allEntries)); // kent and bart + $filterresult = array(); + $this->assertEquals(1, $filter_final->matches($allEntries, $filterresult)); // should leave only kent + $this->assertEquals($entry3->dn(), array_shift($filterresult)->dn(), "Filtered entry does not equal expected entry! filter='".$filter_final->asString()."'"); + + // [TODO]: Further tests for >, <, >=, <= and ~=, when they are implemented. + // ...until then: negative testing for those cases + foreach (array('>', '<', '>=', '<=', '~=') as $to) { + $filter = Net_LDAP2_Filter::parse("(fingers${to}5)"); + $this->assertInstanceOf('PEAR_Error', $filter->matches($allEntries), "Valid operator succeeded: WRITE THE TESTCASE FOR IT!"); + } + } + +} +?>
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/Net_LDAP2_LDIFTest.php
Added
@@ -0,0 +1,689 @@ +<?php +//@encoding iso-8859-1 +require_once __DIR__ . '/Net_LDAP2_TestBase.php'; +require_once 'Net/LDAP2/LDIF.php'; + +/** + * Test class for Net_LDAP2_LDIF. + * Generated by PHPUnit_Util_Skeleton on 2007-12-20 at 10:11:52. + */ +class Net_LDAP2_LDIFTest extends Net_LDAP2_TestBase { + /** + * Default config for tests. + * + * The config is bound to the ldif test file + * tests/ldif_data/unsorted_w50.ldif + * so don't change or tests will fail + * + * @var array + */ + var $defaultConfig = array( + 'onerror' => 'undef', + 'encode' => 'base64', + 'wrap' => 50, + 'change' => 0, + 'sort' => 0, + 'version' => 1 // mimic pre 2.0.0RC5 behavior, so test files need no adjusting + ); + + /** + * Test entries data + * + * Please do not just modify these values, they + * are closely related to the LDIF test data. + * + * @var string + */ + var $testentries_data = array( + 'cn=test1,ou=example,dc=com' => array( + 'cn' => 'test1', + 'attr3' => array('foo', 'bar'), + 'attr1' => 12345, + 'attr4' => 'brrrzztt', + 'objectclass' => 'oc1', + 'attr2' => array('1234', 'baz')), + + 'cn=test blabla,ou=example,dc=com' => array( + 'cn' => 'test blabla', + 'attr3' => array('foo', 'bar'), + 'attr1' => 12345, + 'attr4' => 'blablaöäü', + 'objectclass' => 'oc2', + 'attr2' => array('1234', 'baz'), + 'verylong' => 'fhu08rhvt7b478vt5hv78h45nfgt45h78t34hhhhhhhhhv5bg8h6ttttttttt3489t57nhvgh4788trhg8999vnhtgthgui65hgb5789thvngwr789cghm738'), + + 'cn=test öäü,ou=example,dc=com' => array( + 'cn' => 'test öäü', + 'attr3' => array('foo', 'bar'), + 'attr1' => 12345, + 'attr4' => 'blablaöäü', + 'objectclass' => 'oc3', + 'attr2' => array('1234', 'baz'), + 'attr5' => 'endspace ', + 'attr6' => ':badinitchar'), + + ':cn=endspace,dc=com ' => array( + 'cn' => 'endspace') + ); + + /** + * Test file written to + * + * @var string + */ + var $outfile = 'test.out.ldif'; + + /** + * Test entries + * + * They will be created in main() + * + * @var array + */ + var $testentries = array(); + + /** + * Runs the test methods of this class. + * + * @access public + * @static + */ + public static function main() { + require_once "PHPUnit/TextUI/TestRunner.php"; + + $suite = new PHPUnit_Framework_TestSuite("Net_LDAP2_LDIFTest"); + $result = PHPUnit_TextUI_TestRunner::run($suite); + } + + /** + * Open some outfile and ensure correct rights + * + * @access protected + */ + protected function setUp() { + // initialize test entries + $this->testentries = array(); + foreach ($this->testentries_data as $dn => $attrs) { + $entry = Net_LDAP2_Entry::createfresh($dn, $attrs); + $this->assertInstanceOf('Net_LDAP2_Entry', $entry, 'ERROR inittializing test entries'); + array_push($this->testentries, $entry); + } + + // create outfile if not exists and enforce proper access rights + if (file_exists($this->outfile)) @unlink($this->outfile); + $this->assertTrue(touch($this->outfile), 'Init error: Unable to create '.$this->outfile); + $this->assertTrue(chmod($this->outfile, 0644), 'Init error: Unable to chmod(0644) '.$this->outfile); + } + + /** + * Remove the outfile + * + * @access protected + */ + protected function tearDown() { + // uncomment this if you debug the test cases so you will have output available + if (file_exists($this->outfile)) @unlink($this->outfile); + } + + /** + * Construction tests + * + * Construct LDIF object and see if we can get a handle + */ + public function testConstruction() { + $supported_modes = array('r', 'w', 'a'); + $plus = array('', '+'); + + // Test all open modes, + // all of them should return a correct handle + foreach ($supported_modes as $mode) { + foreach ($plus as $p) { + $ldif = new Net_LDAP2_LDIF($this->outfile, $mode, $this->defaultConfig); + $this->assertTrue(is_resource($ldif->handle())); + } + } + + // Test illegal option passing + $ldif = new Net_LDAP2_LDIF($this->outfile, $mode, array('somebad' => 'option')); + $this->assertInstanceOf('Net_LDAP2_Error', $ldif->error()); + + // Test passing custom handle + $handle = fopen($this->outfile, 'r'); + $ldif = new Net_LDAP2_LDIF($handle, $mode, $this->defaultConfig); + $this->assertTrue(is_resource($ldif->handle())); + + // Reading test with invalid file mode + $ldif = new Net_LDAP2_LDIF($this->outfile, 'y', $this->defaultConfig); + $this->assertNull($ldif->handle()); + $this->assertInstanceOf('Net_LDAP2_Error', $ldif->error()); + + // Reading test with nonexistent file + $ldif = new Net_LDAP2_LDIF('some/nonexistent/file_for_net_ldap_ldif', 'r', $this->defaultConfig); + $this->assertNull($ldif->handle()); + $this->assertInstanceOf('Net_LDAP2_Error', $ldif->error()); + + // writing to nonexistent file + $ldif = new Net_LDAP2_LDIF('testfile_for_net_ldap_ldif', 'w', $this->defaultConfig); + $this->assertTrue(is_resource($ldif->handle())); + @unlink('testfile_for_net_ldap_ldif'); + + // writing to nonexistent path + $ldif = new Net_LDAP2_LDIF('some/nonexistent/file_for_net_ldap_ldif', 'w', $this->defaultConfig); + $this->assertNull($ldif->handle()); + $this->assertInstanceOf('Net_LDAP2_Error', $ldif->error()); + + // writing to existing file but without permission + // note: chmod should succeed since we do that in setUp() + if (chmod($this->outfile, 0444)) { + $ldif = new Net_LDAP2_LDIF($this->outfile, 'w', $this->defaultConfig); + $this->assertNull($ldif->handle()); + $this->assertInstanceOf('Net_LDAP2_Error', $ldif->error()); + } else { + $this->markTestSkipped("Could not chmod ".$this->outfile.", write test without permission skipped"); + } + } + + /** + * Tests if entries from an LDIF file are correctly constructed + */ + public function testRead_entry() { + /* + * UNIX line endings + */ + $ldif = new Net_LDAP2_LDIF(dirname(__FILE__).'/ldif_data/unsorted_w50.ldif', 'r', $this->defaultConfig); + $this->assertTrue(is_resource($ldif->handle())); + + $entries = array(); + do { + $entry = $ldif->read_entry(); + $this->assertFalse((boolean)$ldif->error(), 'failed building entry from LDIF: '.$ldif->error(true)); + $this->assertInstanceOf('Net_LDAP2_Entry', $entry); + array_push($entries, $entry); + } while (!$ldif->eof()); + + $this->compareEntries($this->testentries, $entries); + + /* + * Windows line endings + */ + $ldif = new Net_LDAP2_LDIF(dirname(__FILE__).'/ldif_data/unsorted_w50_WIN.ldif', 'r', $this->defaultConfig); + $this->assertTrue(is_resource($ldif->handle())); + + $entries = array(); + do { + $entry = $ldif->read_entry(); + $this->assertFalse((boolean)$ldif->error(), 'failed building entry from LDIF: '.$ldif->error(true)); + $this->assertInstanceOf('Net_LDAP2_Entry', $entry); + array_push($entries, $entry); + } while (!$ldif->eof()); + + $this->compareEntries($this->testentries, $entries); + } + + /** + * Tests if entries are correctly written + * + * This tests converting entries to LDIF lines, wrapping, encoding, etc + */ + public function testWrite_entry() { + $testconf = $this->defaultConfig; + + /* + * test wrapped operation + */ + $testconf['wrap'] = 50; + $testconf['sort'] = 0; + $expected = array_map('conv_lineend', file(dirname(__FILE__).'/ldif_data/unsorted_w50.ldif')); + // strip 4 starting lines because of comments in the file header: + array_shift($expected);array_shift($expected); + array_shift($expected);array_shift($expected); + + // Write LDIF + $ldif = new Net_LDAP2_LDIF($this->outfile, 'w', $testconf); + $this->assertTrue(is_resource($ldif->handle())); + $ldif->write_entry($this->testentries); + $this->assertFalse((boolean)$ldif->error(), 'Failed writing entry to '.$this->outfile.': '.$ldif->error(true)); + $ldif->done(); + + // Compare files + $this->assertEquals($expected, file($this->outfile)); + + + $testconf['wrap'] = 30; + $testconf['sort'] = 0; + $expected = array_map('conv_lineend', file(dirname(__FILE__).'/ldif_data/unsorted_w30.ldif')); + // strip 4 starting lines because of comments in the file header: + array_shift($expected);array_shift($expected); + array_shift($expected);array_shift($expected); + + // Write LDIF + $ldif = new Net_LDAP2_LDIF($this->outfile, 'w', $testconf); + $this->assertTrue(is_resource($ldif->handle())); + $ldif->write_entry($this->testentries); + $this->assertFalse((boolean)$ldif->error(), 'Failed writing entry to '.$this->outfile.': '.$ldif->error(true)); + $ldif->done(); + + // Compare files + $this->assertEquals($expected, file($this->outfile)); + + + + /* + * Test unwrapped operation + */ + $testconf['wrap'] = 40; + $testconf['sort'] = 1; + $expected = array_map('conv_lineend', file(dirname(__FILE__).'/ldif_data/sorted_w40.ldif')); + // strip 4 starting lines because of comments in the file header: + array_shift($expected);array_shift($expected); + array_shift($expected);array_shift($expected); + + // Write LDIF + $ldif = new Net_LDAP2_LDIF($this->outfile, 'w', $testconf); + $this->assertTrue(is_resource($ldif->handle())); + $ldif->write_entry($this->testentries); + $this->assertFalse((boolean)$ldif->error(), 'Failed writing entry to '.$this->outfile.': '.$ldif->error(true)); + $ldif->done(); + + // Compare files + $this->assertEquals($expected, file($this->outfile)); + + + $testconf['wrap'] = 50; + $testconf['sort'] = 1; + $expected = array_map('conv_lineend', file(dirname(__FILE__).'/ldif_data/sorted_w50.ldif')); + // strip 4 starting lines because of comments in the file header: + array_shift($expected);array_shift($expected); + array_shift($expected);array_shift($expected); + + // Write LDIF + $ldif = new Net_LDAP2_LDIF($this->outfile, 'w', $testconf); + $this->assertTrue(is_resource($ldif->handle())); + $ldif->write_entry($this->testentries); + $this->assertFalse((boolean)$ldif->error(), 'Failed writing entry to '.$this->outfile.': '.$ldif->error(true)); + $ldif->done(); + + // Compare files + $this->assertEquals($expected, file($this->outfile)); + + + /* + * Test raw option + */ + $testconf['wrap'] = 50; + $testconf['sort'] = 1; + $testconf['raw'] = '/attr6/'; + $expected = array_map('conv_lineend', file(dirname(__FILE__).'/ldif_data/sorted_w50.ldif')); + // strip 4 starting lines because of comments in the file header: + array_shift($expected);array_shift($expected); + array_shift($expected);array_shift($expected); + + // Write LDIF + $ldif = new Net_LDAP2_LDIF($this->outfile, 'w', $testconf); + $this->assertTrue(is_resource($ldif->handle())); + $ldif->write_entry($this->testentries); + $this->assertFalse((boolean)$ldif->error(), 'Failed writing entry to '.$this->outfile.': '.$ldif->error(true)); + $ldif->done(); + + // Compare files, with expected attr adjusted + $this->assertEquals($expected, file($this->outfile)); + + + /* + * Test writing with non entry as parameter + */ + $ldif = new Net_LDAP2_LDIF($this->outfile, 'w'); + $this->assertTrue(is_resource($ldif->handle())); + $ldif->write_entry('malformed_parameter'); + $this->assertTrue((boolean)$ldif->error()); + } + + /** + * Test version writing + * + * In the default config, we supply a version which causes the ldif writer to + * spill out a version int. However, since 2.0.0RC5, the default behavior changed, + * so that no version is written by default (compatibility to perl interface). + * The following code tests that new behavior. + */ + public function testWriteVersion() { + $testconf = $this->defaultConfig; + + $expected = array_map('conv_lineend', file(dirname(__FILE__).'/ldif_data/unsorted_w50.ldif')); + // strip 4 starting lines because of comments in the file header: + array_shift($expected);array_shift($expected); + array_shift($expected);array_shift($expected); + + // strip 1 additional line (the "version: 1" line that should not be written now) + // and adjust test config + array_shift($expected); + unset($testconf['version']); + + // Write LDIF + $ldif = new Net_LDAP2_LDIF($this->outfile, 'w', $testconf); + $this->assertTrue(is_resource($ldif->handle())); + $ldif->write_entry($this->testentries); + $this->assertFalse((boolean)$ldif->error(), 'Failed writing entry to '.$this->outfile.': '.$ldif->error(true)); + $ldif->done(); + + // Compare files + $this->assertEquals($expected, file($this->outfile)); + } + + /** + * Round trip test: Read LDIF, parse to entries, write that to LDIF and compare both files + */ + public function testReadWriteRead() { + $ldif = new Net_LDAP2_LDIF(dirname(__FILE__).'/ldif_data/unsorted_w50.ldif', 'r', $this->defaultConfig); + $this->assertTrue(is_resource($ldif->handle())); + + // Read LDIF + $entries = array(); + do { + $entry = $ldif->read_entry(); + $this->assertFalse((boolean)$ldif->error(), 'failed building entry from LDIF: '.$ldif->error(true)); + $this->assertInstanceOf('Net_LDAP2_Entry', $entry); + array_push($entries, $entry); + } while (!$ldif->eof()); + $ldif->done(); + + // Write LDIF + $ldif = new Net_LDAP2_LDIF($this->outfile, 'w', $this->defaultConfig); + $this->assertTrue(is_resource($ldif->handle())); + $ldif->write_entry($entries); + $this->assertFalse((boolean)$ldif->error(), 'Failed writing entry to '.$this->outfile.': '.$ldif->error(true)); + $ldif->done(); + + // Compare files + $expected = array_map('conv_lineend', file(dirname(__FILE__).'/ldif_data/unsorted_w50.ldif')); + // strip 4 starting lines because of comments in the file header: + array_shift($expected);array_shift($expected); + array_shift($expected);array_shift($expected); + $this->assertEquals($expected, file($this->outfile)); + } + + /** + * Tests writing change files with no changes + */ + public function testWrite_entryChangesEmpty() { + $testentries = array( + Net_LDAP2_Entry::createFresh('cn=foo,ou=example,dc=com', array('cn' => 'foo')), + Net_LDAP2_Entry::createFresh('cn=footest,ou=example,dc=com', array('cn' => 'foo')) + ); + + $testconf = $this->defaultConfig; + $testconf['change'] = 1; + + $ldif = new Net_LDAP2_LDIF($this->outfile, 'w', $testconf); + $this->assertTrue(is_resource($ldif->handle())); + $ldif->write_entry($testentries); + $this->assertFalse((boolean)$ldif->error(), 'Failed writing entry to '.$this->outfile.': '.$ldif->error(true)); + $ldif->done(); + $this->assertEquals(0, filesize($this->outfile)); + + } + + /** + * Tests if entry changes are correctly written + */ + public function testWrite_entryChanges() { + $testentries = $this->testentries; + $testentries[] = Net_LDAP2_Entry::createFresh('cn=foo,ou=example,dc=com', array('cn' => 'foo')); + $testentries[] = Net_LDAP2_Entry::createFresh('cn=footest,ou=example,dc=com', array('cn' => 'foo')); + $this->assertEquals(6, count($testentries), "Init error: Expected count of test entries wrong, check test datasetup!"); + + $testconf = $this->defaultConfig; + $testconf['change'] = 1; + + //prepare some changes + $testentries[0]->delete('attr1'); // del whole attr + $testentries[0]->delete(array('attr2' => 'baz')); // del spec. value + $testentries[0]->delete(array('attr4', 'attr3' => 'bar')); // del mixed + + // prepare some replaces and adds + $testentries[2]->replace(array('attr1' => 'newvaluefor1')); + $testentries[2]->replace(array('attr2' => array('newvalue1for2', 'newvalue2for2'))); + $testentries[2]->replace(array('attr3' => '')); // will result in delete + $testentries[2]->replace(array('newattr' => 'foo')); // will result in add + + // delete whole entry + $testentries[3]->delete(); + + // rename and move + $testentries[4]->dn('cn=Bar,ou=example,dc=com'); + $testentries[5]->dn('cn=foobartest,ou=newexample,dc=com'); + + // make sure we correctly get changes back from the API + foreach ($testentries as $te) { + $this->assertGreaterThanOrEqual(2, count($te->getChanges()), + 'Probable BUG in Net_LDAP2_Entry detected! Changed entries do not report those changes back! (entry: '.$te->dn().')'); + } + + // carry out write + $ldif = new Net_LDAP2_LDIF($this->outfile, 'w', $testconf); + $this->assertTrue(is_resource($ldif->handle())); + $ldif->write_entry($testentries); + $this->assertFalse((boolean)$ldif->error(), 'Failed writing entry to '.$this->outfile.': '.$ldif->error(true)); + $this->assertGreaterThan(0, filesize($this->outfile), "File '".$this->outfile."' is empty but should have content!"); + $ldif->done(); + + // compare results + $expected = array_map('conv_lineend', file(dirname(__FILE__).'/ldif_data/changes.ldif')); + // strip 4 starting lines because of comments in the file header: + array_shift($expected);array_shift($expected); + array_shift($expected);array_shift($expected); + $writtenFileContents = array_map('conv_lineend', file($this->outfile)); + $this->assertEquals($expected, $writtenFileContents, "Written file does not equal expected contents (".realpath($this->outfile).")"); + } + + /** + * Tests if syntax errors are detected + * + * The used LDIF files have several damaged entries but always one + * correct too, to test if Net_LDAP2_LDIF is continue reading as it should + * Each Entry must have 2 correct attributes. + */ + public function testSyntaxerrors() { + // Test malformed encoding + // I think we can ignore this test, because if the LDIF is not encoded properly, we + // might be able to successfully fetch the entries data. However, it is possible + // that it will be corrupted, but thats not our fault then. + // If we should catch that error, we must adjust Net_LDAP2_LDIF::next_lines(). + /* + $ldif = new Net_LDAP2_LDIF(dirname(__FILE__).'/ldif_data/malformed_encoding.ldif', 'r', $this->defaultConfig); + $this->assertFalse((boolean)$ldif->error()); + $entries = array(); + do { + $entry = $ldif->read_entry(); + if ($entry) { + // the correct attributes need to be parsed + $this->assertThat(count(array_keys($entry->getValues())), $this->equalTo(2)); + $entries[] = $entry; + } + } while (!$ldif->eof()); + $this->assertTrue((boolean)$ldif->error()); + $this->assertThat($ldif->error_lines(), $this->greaterThan(1)); + $this->assertThat(count($entries), $this->equalTo(1)); + */ + + // Test malformed syntax + $ldif = new Net_LDAP2_LDIF(dirname(__FILE__).'/ldif_data/malformed_syntax.ldif', 'r', $this->defaultConfig); + $this->assertFalse((boolean)$ldif->error()); + $entries = array(); + do { + $entry = $ldif->read_entry(); + if ($entry) { + // the correct attributes need to be parsed + $this->assertThat(count(array_keys($entry->getValues())), $this->equalTo(2)); + $entries[] = $entry; + } + } while (!$ldif->eof()); + $this->assertTrue((boolean)$ldif->error()); + $this->assertThat($ldif->error_lines(), $this->greaterThan(1)); + $this->assertThat(count($entries), $this->equalTo(2)); + + // test bad wrapping + $ldif = new Net_LDAP2_LDIF(dirname(__FILE__).'/ldif_data/malformed_wrapping.ldif', 'r', $this->defaultConfig); + $this->assertFalse((boolean)$ldif->error()); + $entries = array(); + do { + $entry = $ldif->read_entry(); + if ($entry) { + // the correct attributes need to be parsed + $this->assertThat(count(array_keys($entry->getValues())), $this->equalTo(2)); + $entries[] = $entry; + } + } while (!$ldif->eof()); + $this->assertTrue((boolean)$ldif->error()); + $this->assertThat($ldif->error_lines(), $this->greaterThan(1)); + $this->assertThat(count($entries), $this->equalTo(2)); + } + + /** + * Test error dropping functionality + */ + public function testError() { + // NO error: + $ldif = new Net_LDAP2_LDIF(dirname(__FILE__).'/ldif_data/unsorted_w50.ldif', 'r', $this->defaultConfig); + $this->assertFalse((boolean)$ldif->error()); + + // Error giving error msg and line number: + $ldif = new Net_LDAP2_LDIF(dirname(__FILE__).'/some_not_existing/path/for/net_ldap_ldif', 'r', $this->defaultConfig); + $this->assertTrue((boolean)$ldif->error()); + $this->assertInstanceOf('Net_LDAP2_Error', $ldif->error()); + $this->assertInternalType('string', $ldif->error(true)); + $this->assertInternalType('int', $ldif->error_lines()); + $this->assertThat(strlen($ldif->error(true)), $this->greaterThan(0)); + + // Test for line number reporting + $ldif = new Net_LDAP2_LDIF(dirname(__FILE__).'/ldif_data/malformed_syntax.ldif', 'r', $this->defaultConfig); + $this->assertFalse((boolean)$ldif->error()); + do { $entry = $ldif->read_entry(); } while (!$ldif->eof()); + $this->assertTrue((boolean)$ldif->error()); + $this->assertThat($ldif->error_lines(), $this->greaterThan(1)); + } + + /** + * Tests current_lines() and next_lines(). + * + * This should always return the same lines unless forced + */ + public function testLineMethods() { + $ldif = new Net_LDAP2_LDIF(dirname(__FILE__).'/ldif_data/unsorted_w50.ldif', 'r', $this->defaultConfig); + $this->assertFalse((boolean)$ldif->error()); + $this->assertEquals(array(), $ldif->current_lines(), 'Net_LDAP2_LDIF initialization error!'); + + // read first lines + $lines = $ldif->next_lines(); + $this->assertFalse((boolean)$ldif->error(), 'unable to read first lines'); + + // read the first lines several times and test + for ($i = 0; $i <= 10; $i++) { + $r_lines = $ldif->next_lines(); + $this->assertFalse((boolean)$ldif->error()); + $this->assertEquals($lines, $r_lines); + } + + // now force to iterate and see if the content changes + $r_lines = $ldif->next_lines(true); + $this->assertFalse((boolean)$ldif->error()); + $this->assertNotEquals($lines, $r_lines); + + // it could be confusing to some people, but calling + // current_entry would not work now, like the description + // of the method says. + $no_entry = $ldif->current_lines(); + $this->assertEquals(array(), $no_entry); + } + + /** + * Tests current_entry(). This should always return the same object + */ + public function testCurrent_entry() { + $ldif = new Net_LDAP2_LDIF(dirname(__FILE__).'/ldif_data/unsorted_w50.ldif', 'r', $this->defaultConfig); + $this->assertFalse((boolean)$ldif->error()); + + // read first entry + $entry = $ldif->read_entry(); + $this->assertFalse((boolean)$ldif->error(), 'First entry failed: '.$ldif->error(true)); + + // test if current_Entry remains the first one + for ($i = 0; $i <= 10; $i++) { + $e = $ldif->current_entry(); + $this->assertFalse((boolean)$ldif->error(), $ldif->error(true)); + $this->assertEquals($entry, $e); + } + } + + + + + + /** + * Compare Net_LDAP2_Entries + * + * This helper function compares two entries (or array of entries) + * and tells if they are equal. They are equal if all DNs from + * the first crowd exist in the second AND each attribute is present + * and equal at the respicitve entry. + * The search is case sensitive. + * + * @param array|Net_LDAP2_Entry $entry1 + * @param array|Net_LDAP2_Entry $entry2 + * @return true|false + */ + function compareEntries($entry1, $entry2) { + if (!is_array($entry1)) $entry1 = array($entry1); + if (!is_array($entry2)) $entry2 = array($entry2); + + $entries_data1 = array(); + $entries_data2 = array(); + + // step 1: extract and sort data + foreach ($entry1 as $e) { + $values = $e->getValues(); + foreach ($values as $attr_name => $attr_values) { + if (!is_array($attr_values)) $attr_values = array($attr_values); + $values[$attr_name] = $attr_values; + } + $entries_data1[$e->dn()] = $values; + } + foreach ($entry2 as $e) { + $values = $e->getValues(); + foreach ($values as $attr_name => $attr_values) { + if (!is_array($attr_values)) $attr_values = array($attr_values); + $values[$attr_name] = $attr_values; + } + $entries_data2[$e->dn()] = $values; + } + + // step 2: compare DNs (entries) + $this->assertEquals(array_keys($entries_data1), array_keys($entries_data2), 'Entries DNs not equal! (missing entry or wrong DN)'); + + // step 3: look for attribute existence and compare values + foreach ($entries_data1 as $dn => $attributes) { + $this->assertEquals($entries_data1[$dn], $entries_data2[$dn], 'Entries '.$dn.' attributes are not equal'); + foreach ($attributes as $attr_name => $attr_values) { + $this->assertEquals(0, count(array_diff($entries_data1[$dn][$attr_name], $entries_data2[$dn][$attr_name])), 'Entries '.$dn.' attribute '.$attr_name.' values are not equal'); + } + } + + return true; + } + +} + +if (!function_exists('conv_lineend')) { + /** + * Function transfers line endings to current OS + * + * This is neccessary to make write tests platform indendent. + * + * @param string $line Line + * @return string + */ + function conv_lineend($line) { + return rtrim($line).PHP_EOL; + } +} +?>
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/Net_LDAP2_RootDSETest.php
Added
@@ -0,0 +1,152 @@ +<?php +require_once __DIR__ . '/Net_LDAP2_TestBase.php'; +require_once 'Net/LDAP2/RootDSE.php'; + +/** + * Test class for Net_LDAP2_RootDSE. + * Generated by PHPUnit_Util_Skeleton on 2007-10-09 at 10:47:05. + */ +class Net_LDAP2_RootDSETest extends Net_LDAP2_TestBase { + /** + * Runs the test methods of this class. + * + * @access public + * @static + */ + public static function main() { + require_once "PHPUnit/TextUI/TestRunner.php"; + + $suite = new PHPUnit_Framework_TestSuite("Net_LDAP2_RootDSETest"); + $result = PHPUnit_TextUI_TestRunner::run($suite); + } + + /** + * Sets up the fixture, for example, open a network connection. + * This method is called before a test is executed. + * + * @access protected + */ + protected function setUp() { + $this->markTestIncomplete('Test not implemented yet.'); + } + + /** + * Tears down the fixture, for example, close a network connection. + * This method is called after a test is executed. + * + * @access protected + */ + protected function tearDown() { + } + + /** + * @todo Implement testGetValue(). + */ + public function testGetValue() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testGet_value(). + */ + public function testGet_value() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testSupportedExtension(). + */ + public function testSupportedExtension() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testSupported_extension(). + */ + public function testSupported_extension() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testSupportedVersion(). + */ + public function testSupportedVersion() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testSupported_version(). + */ + public function testSupported_version() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testSupportedControl(). + */ + public function testSupportedControl() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testSupported_control(). + */ + public function testSupported_control() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testSupportedSASLMechanism(). + */ + public function testSupportedSASLMechanism() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testSupported_sasl_mechanism(). + */ + public function testSupported_sasl_mechanism() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement test_checkAttr(). + */ + public function test_checkAttr() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } +} +?>
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/Net_LDAP2_SearchTest.php
Added
@@ -0,0 +1,363 @@ +<?php +require_once __DIR__ . '/Net_LDAP2_TestBase.php'; +require_once 'Net/LDAP2.php'; +require_once 'Net/LDAP2/Search.php'; + +/** + * Test class for Net_LDAP2_Search. + * Generated by PHPUnit_Util_Skeleton on 2007-10-09 at 10:46:51. + */ +class Net_LDAP2_SearchTest extends Net_LDAP2_TestBase { + /** + * Stores the LDAP configuration + */ + var $ldapcfg = false; + + /** + * Sets up the fixture, for example, open a network connection. + * This method is called before a test is executed. + * + * @access protected + */ + protected function setUp() { + $this->ldapcfg = $this->getTestConfig(); + } + + /** + * Tears down the fixture, for example, close a network connection. + * This method is called after a test is executed. + * + * @access protected + */ + protected function tearDown() { + } + + /** + * This checks if a valid LDAP testconfig is present and loads it. + * + * If so, it is loaded and returned as array. If not, false is returned. + * + * @return false|array + */ + public function getTestConfig() { + $config = false; + $file = dirname(__FILE__).'/ldapconfig.ini'; + if (file_exists($file) && is_readable($file)) { + $config = parse_ini_file($file, true); + } else { + return false; + } + // validate ini + $v_error = $file.' is probably invalid. Did you quoted values correctly?'; + $this->assertTrue(array_key_exists('global', $config), $v_error); + $this->assertTrue(array_key_exists('test', $config), $v_error); + $this->assertEquals(7, count($config['global']), $v_error); + $this->assertEquals(7, count($config['test']), $v_error); + + // reformat things a bit, for convinience + $config['global']['server_binddn'] = + $config['global']['server_binddn'].','.$config['global']['server_base_dn']; + $config['test']['existing_attrmv'] = explode('|', $config['test']['existing_attrmv']); + return $config; + } + + /** + * Establishes a working connection + * + * @return Net_LDAP2 + */ + public function &connect() { + // Check extension + if (true !== Net_LDAP2::checkLDAPExtension()) { + $this->markTestSkipped('PHP LDAP extension not found or not loadable. Skipped Test.'); + } + + // Simple working connect and privilegued bind + $lcfg = array( + 'host' => $this->ldapcfg['global']['server_address'], + 'port' => $this->ldapcfg['global']['server_port'], + 'basedn' => $this->ldapcfg['global']['server_base_dn'], + 'binddn' => $this->ldapcfg['global']['server_binddn'], + 'bindpw' => $this->ldapcfg['global']['server_bindpw'], + 'filter' => '(ou=*)', + ); + $ldap = Net_LDAP2::connect($lcfg); + $this->assertInstanceOf('Net_LDAP2', $ldap, 'Connect failed but was supposed to work. Check credentials and host address. If those are correct, file a bug!'); + return $ldap; + } + + /** + * @todo Implement testEntries(). + */ + public function testEntries() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testShiftEntry(). + */ + public function testShiftEntry() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testShift_entry(). + */ + public function testShift_entry() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testPopEntry(). + */ + public function testPopEntry() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testPop_entry(). + */ + public function testPop_entry() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testSorted_as_struct(). + */ + public function testSorted_as_struct() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testSorted(). + */ + public function testSorted() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testAs_struct(). + */ + public function testAs_struct() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testSetSearch(). + */ + public function testSetSearch() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testSetLink(). + */ + public function testSetLink() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testCount(). + */ + public function testCount() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testGetErrorCode(). + */ + public function testGetErrorCode() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement test_Net_LDAP2_Search(). + */ + public function test_Net_LDAP2_Search() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement testDone(). + */ + public function testDone() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * @todo Implement test_searchedAttrs(). + */ + public function test_searchedAttrs() { + // Remove the following line when you implement this test. + $this->markTestIncomplete( + "This test has not been implemented yet." + ); + } + + /** + * tests SPL iterator + */ + public function testSPLIterator() { + if (!$this->ldapcfg) { + $this->markTestSkipped('No ldapconfig.ini found. Skipping test!'); + } else { + $ldap = $this->connect(); + + // some testdata, so we have some entries to search for + $base = $this->ldapcfg['global']['server_base_dn']; + $ou1 = Net_LDAP2_Entry::createFresh('ou=Net_LDAP2_Test_search1,'.$base, + array( + 'objectClass' => array('top','organizationalUnit'), + 'ou' => 'Net_LDAP2_Test_search1' + )); + $ou2 = Net_LDAP2_Entry::createFresh('ou=Net_LDAP2_Test_search2,'.$base, + array( + 'objectClass' => array('top','organizationalUnit'), + 'ou' => 'Net_LDAP2_Test_search2' + )); + $this->assertTrue($ldap->add($ou1)); + $this->assertTrue($ldap->dnExists($ou1->dn())); + $this->assertTrue($ldap->add($ou2)); + $this->assertTrue($ldap->dnExists($ou2->dn())); + + /* + * search and test each method + */ + $search = $ldap->search(null, '(ou=Net_LDAP2*)'); + $this->assertInstanceOf('Net_LDAP2_Search', $search); + $this->assertEquals(2, $search->count()); + + // current() is supposed to return first valid element + $e1 = $search->current(); + $this->assertInstanceOf('Net_LDAP2_Entry', $e1); + $this->assertEquals($e1->dn(), $search->key()); + $this->assertTrue($search->valid()); + + // shift to next entry + $search->next(); + $e2 = $search->current(); + $this->assertInstanceOf('Net_LDAP2_Entry', $e2); + $this->assertEquals($e2->dn(), $search->key()); + $this->assertTrue($search->valid()); + + // shift to non existent third entry + $search->next(); + $this->assertFalse($search->current()); + $this->assertFalse($search->key()); + $this->assertFalse($search->valid()); + + // rewind and test, + // which should return the first entry a second time + $search->rewind(); + $e1_1 = $search->current(); + $this->assertInstanceOf('Net_LDAP2_Entry', $e1_1); + $this->assertEquals($e1_1->dn(), $search->key()); + $this->assertTrue($search->valid()); + $this->assertEquals($e1->dn(), $e1_1->dn()); + + // Dont rewind but call current, should return first entry again + $e1_2 = $search->current(); + $this->assertInstanceOf('Net_LDAP2_Entry', $e1_2); + $this->assertEquals($e1_2->dn(), $search->key()); + $this->assertTrue($search->valid()); + $this->assertEquals($e1->dn(), $e1_2->dn()); + + // rewind again and test, + // which should return the first entry a third time + $search->rewind(); + $e1_3 = $search->current(); + $this->assertInstanceOf('Net_LDAP2_Entry', $e1_3); + $this->assertEquals($e1_3->dn(), $search->key()); + $this->assertTrue($search->valid()); + $this->assertEquals($e1->dn(), $e1_3->dn()); + + /* + * Try methods on empty search result + */ + $search = $ldap->search(null, '(ou=Net_LDAP2Test_NotExistentEntry)'); + $this->assertInstanceOf('Net_LDAP2_Search', $search); + $this->assertEquals(0, $search->count()); + $this->assertFalse($search->current()); + $this->assertFalse($search->key()); + $this->assertFalse($search->valid()); + $search->next(); + $this->assertFalse($search->current()); + $this->assertFalse($search->key()); + $this->assertFalse($search->valid()); + + /* + * search and simple iterate through the testentries. + * then, rewind and do it again several times + */ + $search2 = $ldap->search(null, '(ou=Net_LDAP2*)'); + $this->assertInstanceOf('Net_LDAP2_Search', $search2); + $this->assertEquals(2, $search2->count()); + for ($i = 0; $i <= 5; $i++) { + $counter = 0; + foreach ($search2 as $dn => $entry) { + $counter++; + + // check on type + $this->assertInstanceOf('Net_LDAP2_Entry', $entry); + + // check on key + $this->assertThat(strlen($dn), $this->greaterThan(1)); + $this->assertEquals($dn, $entry->dn()); + } + $this->assertEquals($search2->count(), $counter, "Failed at loop $i"); + + // revert to start + $search2->rewind(); + } + + /* + * Cleanup + */ + $this->assertTrue($ldap->delete($ou1), 'Cleanup failed, please delete manually'); + $this->assertTrue($ldap->delete($ou2), 'Cleanup failed, please delete manually'); + } + } +} +?>
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/Net_LDAP2_TestBase.php
Added
@@ -0,0 +1,12 @@ +<?php +class Net_LDAP2_TestBase extends PHPUnit_Framework_TestCase +{ + public static function assertTrue($condition, $msg = null) + { + if ($condition instanceof Net_LDAP2_Error) { + self::fail('Error: ' . $condition->getMessage()); + } + return parent::assertTrue($condition, $msg); + } +} +?>
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/Net_LDAP2_UtilTest.php
Added
@@ -0,0 +1,385 @@ +<?php +require_once __DIR__ . '/Net_LDAP2_TestBase.php'; +require_once 'Net/LDAP2/Util.php'; + +/** + * Test class for Net_LDAP2_Util. + * Generated by PHPUnit_Util_Skeleton on 2007-10-09 at 10:33:22. + */ +class Net_LDAP2_UtilTest extends Net_LDAP2_TestBase { + /** + * Runs the test methods of this class. + * + * @access public + * @static + */ + public static function main() { + require_once "PHPUnit/TextUI/TestRunner.php"; + + $suite = new PHPUnit_Framework_TestSuite("Net_LDAP2_UtilTest"); + $result = PHPUnit_TextUI_TestRunner::run($suite); + } + + /** + * Sets up the fixture, for example, open a network connection. + * This method is called before a test is executed. + * + * @access protected + */ + protected function setUp() { + } + + /** + * Tears down the fixture, for example, close a network connection. + * This method is called after a test is executed. + * + * @access protected + */ + protected function tearDown() { + } + + /** + * Test escape_dn_value() + */ + public function testEscape_dn_value() { + $dnval = ' '.chr(22).' t,e+s"t,\\v<a>l;u#e=! '; + $expected = '\20\20\16 t\,e\+s\"t\,\\\\v\<a\>l\;u\#e\=!\20\20\20\20'; + + // string call + $this->assertEquals(array($expected), Net_LDAP2_Util::escape_dn_value($dnval)); + + // array call + $this->assertEquals(array($expected), Net_LDAP2_Util::escape_dn_value(array($dnval))); + + // multiple arrays + $this->assertEquals(array($expected, $expected, $expected), Net_LDAP2_Util::escape_dn_value(array($dnval,$dnval,$dnval))); + } + + /** + * Test unescape_dn_value() + */ + public function testUnescape_dn_value() { + $dnval = '\\20\\20\\16\\20t\\,e\\+s \\"t\\,\\\\v\\<a\\>l\\;u\\#e\\=!\\20\\20\\20\\20'; + $expected = ' '.chr(22).' t,e+s "t,\\v<a>l;u#e=! '; + + // string call + $this->assertEquals(array($expected), Net_LDAP2_Util::unescape_dn_value($dnval)); + + // array call + $this->assertEquals(array($expected), Net_LDAP2_Util::unescape_dn_value(array($dnval))); + + // multiple arrays + $this->assertEquals(array($expected, $expected, $expected), Net_LDAP2_Util::unescape_dn_value(array($dnval,$dnval,$dnval))); + } + + /** + * Test escaping of filter values + */ + public function testEscape_filter_value() { + $expected = 't\28e,s\29t\2av\5cal\1eue'; + $filterval = 't(e,s)t*v\\al'.chr(30).'ue'; + + // string call + $this->assertEquals(array($expected), Net_LDAP2_Util::escape_filter_value($filterval)); + + // array call + $this->assertEquals(array($expected), Net_LDAP2_Util::escape_filter_value(array($filterval))); + + // multiple arrays + $this->assertEquals(array($expected, $expected, $expected), Net_LDAP2_Util::escape_filter_value(array($filterval,$filterval,$filterval))); + } + + /** + * Test unescaping of filter values + */ + public function testUnescape_filter_value() { + $expected = 't(e,s)t*v\\al'.chr(30).'ue'; + $filterval = 't\28e,s\29t\2av\5cal\1eue'; + + // string call + $this->assertEquals(array($expected), Net_LDAP2_Util::unescape_filter_value($filterval)); + + // array call + $this->assertEquals(array($expected), Net_LDAP2_Util::unescape_filter_value(array($filterval))); + + // multiple arrays + $this->assertEquals(array($expected, $expected, $expected), Net_LDAP2_Util::unescape_filter_value(array($filterval,$filterval,$filterval))); + } + + /** + * Test asc2hex32() + */ + public function testAsc2hex32() { + + $expected = '\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13\14\15\16\17\18\19\1a\1b\1c\1d\1e\1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~'; + $str = ''; + for ($i = 0; $i < 127; $i++) { + $str .= chr($i); + } + $this->assertEquals($expected, Net_LDAP2_Util::asc2hex32($str)); + } + + /** + * Test HEX unescaping + */ + public function testHex2asc() { + $expected = ''; + for ($i = 0; $i < 127; $i++) { + $expected .= chr($i); + } + + $str = '\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13\14\15\16\17\18\19\1a\1b\1c\1d\1e\1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~'; + $this->assertEquals($expected, Net_LDAP2_Util::hex2asc($str)); + } + + /** + * Tests split_rdn_multival() + * + * In addition to the above test of the basic split correction, + * we test here the functionality of mutlivalued RDNs + */ + public function testSplit_rdn_multival() { + // One value + $rdn = 'CN=J. Smith'; + $expected = array('CN=J. Smith'); + $split = Net_LDAP2_Util::split_rdn_multival($rdn); + $this->assertEquals($expected, $split); + + // Two values + $rdn = 'OU=Sales+CN=J. Smith'; + $expected = array('OU=Sales', 'CN=J. Smith'); + $split = Net_LDAP2_Util::split_rdn_multival($rdn); + $this->assertEquals($expected, $split); + + // Several multivals + $rdn = 'OU=Sales+CN=J. Smith+L=London+C=England'; + $expected = array('OU=Sales', 'CN=J. Smith', 'L=London', 'C=England'); + $split = Net_LDAP2_Util::split_rdn_multival($rdn); + $this->assertEquals($expected, $split); + + // Unescaped "+" in value + $rdn = 'OU=Sa+les+CN=J. Smith'; + $expected = array('OU=Sa+les', 'CN=J. Smith'); + $split = Net_LDAP2_Util::split_rdn_multival($rdn); + $this->assertEquals($expected, $split); + + // Unescaped "+" in attr name + $rdn = 'O+U=Sales+CN=J. Smith'; + $expected = array('O+U=Sales', 'CN=J. Smith'); + $split = Net_LDAP2_Util::split_rdn_multival($rdn); + $this->assertEquals($expected, $split); + + // Unescaped "+" in attr name + value + $rdn = 'O+U=Sales+CN=J. Sm+ith'; + $expected = array('O+U=Sales', 'CN=J. Sm+ith'); + $split = Net_LDAP2_Util::split_rdn_multival($rdn); + $this->assertEquals($expected, $split); + + // Unescaped "+" in attr name, but not first attr + // this documents a known bug. However, unfortunately we cant + // know wether the "C+" belongs to value "Sales" or attribute "C+N". + // To solve this, we must ask the schema which we do not right now. + // The problem is located in _correct_dn_splitting() + $rdn = 'OU=Sales+C+N=J. Smith'; + $expected = array('OU=Sales+C', 'N=J. Smith'); // The "C+" is treaten as value of "OU" + $split = Net_LDAP2_Util::split_rdn_multival($rdn); + $this->assertEquals($expected, $split); + + // Escaped "+" in attr name and value + $rdn = 'O\+U=Sales+CN=J. Sm\+ith'; + $expected = array('O\+U=Sales', 'CN=J. Sm\+ith'); + $split = Net_LDAP2_Util::split_rdn_multival($rdn); + $this->assertEquals($expected, $split); + } + + /** + * Tests attribute splitting ('foo=bar' => array('foo', 'bar')) + */ + public function testSplit_attribute_string() { + $attr_str = "foo=bar"; + + // properly + $expected = array('foo', 'bar'); + $split = Net_LDAP2_Util::split_attribute_string($attr_str); + $this->assertEquals($expected, $split); + + // escaped "=" + $attr_str = "fo\=o=b\=ar"; + $expected = array('fo\=o', 'b\=ar'); + $split = Net_LDAP2_Util::split_attribute_string($attr_str); + $this->assertEquals($expected, $split); + + // escaped "=" and unescaped = later on + $attr_str = "fo\=o=b=ar"; + $expected = array('fo\=o', 'b=ar'); + $split = Net_LDAP2_Util::split_attribute_string($attr_str); + $this->assertEquals($expected, $split); + } + + /** + * Tests Ldap_explode_dn() + */ + public function testLdap_explode_dn() { + $dn = 'OU=Sales+CN=J. Smith,dc=example,dc=net'; + $expected_casefold_none = array( + array('CN=J. Smith', 'OU=Sales'), + 'dc=example', + 'dc=net' + ); + $expected_casefold_upper = array( + array('CN=J. Smith', 'OU=Sales'), + 'DC=example', + 'DC=net' + ); + $expected_casefold_lower = array( + array('cn=J. Smith', 'ou=Sales'), + 'dc=example', + 'dc=net' + ); + + $expected_onlyvalues = array( + array( 'J. Smith', 'Sales'), + 'example', + 'net' + ); + $expected_reverse = array_reverse($expected_casefold_upper); + + + $dn_exploded_cnone = Net_LDAP2_Util::ldap_explode_dn($dn, array('casefold' => 'none')); + $this->assertEquals($expected_casefold_none, $dn_exploded_cnone, 'Option casefold none failed'); + + $dn_exploded_cupper = Net_LDAP2_Util::ldap_explode_dn($dn, array('casefold' => 'upper')); + $this->assertEquals($expected_casefold_upper, $dn_exploded_cupper, 'Option casefold upper failed'); + + $dn_exploded_clower = Net_LDAP2_Util::ldap_explode_dn($dn, array('casefold' => 'lower')); + $this->assertEquals($expected_casefold_lower, $dn_exploded_clower, 'Option casefold lower failed'); + + $dn_exploded_onlyval = Net_LDAP2_Util::ldap_explode_dn($dn, array('onlyvalues' => true)); + $this->assertEquals($expected_onlyvalues, $dn_exploded_onlyval, 'Option onlyval failed'); + + $dn_exploded_reverse = Net_LDAP2_Util::ldap_explode_dn($dn, array('reverse' => true)); + $this->assertEquals($expected_reverse, $dn_exploded_reverse, 'Option reverse failed'); + } + + /** + * Tests if canonical_dn() works + * + * Note: This tests depend on the default options of canonical_dn(). + */ + public function testCanonical_dn() { + // test empty dn (is valid according to rfc) + $this->assertEquals('', Net_LDAP2_Util::canonical_dn('')); + + // default options with common dn + $testdn = 'cn=beni,DC=php,c=net'; + $expected = 'CN=beni,DC=php,C=net'; + $this->assertEquals($expected, Net_LDAP2_Util::canonical_dn($testdn)); + + // casefold tests with common dn + $expected_up = 'CN=beni,DC=php,C=net'; + $expected_lo = 'cn=beni,dc=php,c=net'; + $expected_no = 'cn=beni,DC=php,c=net'; + $this->assertEquals($expected_up, Net_LDAP2_Util::canonical_dn($testdn, array('casefold' => 'upper'))); + $this->assertEquals($expected_lo, Net_LDAP2_Util::canonical_dn($testdn, array('casefold' => 'lower'))); + $this->assertEquals($expected_no, Net_LDAP2_Util::canonical_dn($testdn, array('casefold' => 'none'))); + + // reverse + $expected_rev = 'C=net,DC=php,CN=beni'; + $this->assertEquals($expected_rev, Net_LDAP2_Util::canonical_dn($testdn, array('reverse' => true)), 'Option reverse failed'); + + // DN as arrays + $dn_index = array('cn=beni', 'dc=php', 'c=net'); + $dn_assoc = array('cn' => 'beni', 'dc' => 'php', 'c' => 'net'); + $expected = 'CN=beni,DC=php,C=net'; + $this->assertEquals($expected, Net_LDAP2_Util::canonical_dn($dn_index)); + $this->assertEquals($expected, Net_LDAP2_Util::canonical_dn($dn_assoc)); + + // DN with multiple rdn value + $testdn = 'ou=dev+cn=beni,DC=php,c=net'; + $testdn_index = array(array('ou=dev','cn=beni'),'DC=php','c=net'); + $testdn_assoc = array(array('ou' => 'dev','cn' => 'beni'),'DC' => 'php','c' => 'net'); + $expected = 'CN=beni+OU=dev,DC=php,C=net'; + $this->assertEquals($expected, Net_LDAP2_Util::canonical_dn($testdn)); + $this->assertEquals($expected, Net_LDAP2_Util::canonical_dn($testdn_assoc)); + $this->assertEquals($expected, Net_LDAP2_Util::canonical_dn($expected)); + + // test DN with OID + $testdn = 'OID.2.5.4.3=beni,dc=php,c=net'; + $expected = '2.5.4.3=beni,DC=php,C=net'; + $this->assertEquals($expected, Net_LDAP2_Util::canonical_dn($testdn)); + + // test with leading and ending spaces + $testdn = 'cn= beni ,DC=php,c=net'; + $expected = 'CN=\20\20beni\20\20,DC=php,C=net'; + $this->assertEquals($expected, Net_LDAP2_Util::canonical_dn($testdn)); + + // test with to-be escaped characters in attr value + $specialchars = array( + ',' => '\,', + '+' => '\+', + '"' => '\"', + '\\' => '\\\\', + '<' => '\<', + '>' => '\>', + ';' => '\;', + '#' => '\#', + '=' => '\=', + chr(18) => '\12', + '/' => '\/' + ); + foreach ($specialchars as $char => $escape) { + $test_string = 'CN=be'.$char.'ni,DC=ph'.$char.'p,C=net'; + $test_index = array('CN=be'.$char.'ni', 'DC=ph'.$char.'p', 'C=net'); + $test_assoc = array('CN' => 'be'.$char.'ni', 'DC' => 'ph'.$char.'p', 'C' => 'net'); + $expected = 'CN=be'.$escape.'ni,DC=ph'.$escape.'p,C=net'; + + $this->assertEquals($expected, Net_LDAP2_Util::canonical_dn($test_string), 'String escaping test ('.$char.') failed'); + $this->assertEquals($expected, Net_LDAP2_Util::canonical_dn($test_index), 'Indexed array escaping test ('.$char.') failed'); + $this->assertEquals($expected, Net_LDAP2_Util::canonical_dn($test_assoc), 'Associative array encoding test ('.$char.') failed'); + } + } + + /** + * Test if split_attribute_string() works + */ + public function testSplitAttributeString() { + // test default behavour + $this->assertEquals(array('fooAttr', 'barValue'), Net_LDAP2_Util::split_attribute_string("fooAttr=barValue")); + $this->assertEquals(array('fooAttr', '=barValue'), Net_LDAP2_Util::split_attribute_string("fooAttr==barValue")); + $this->assertEquals(array('fooAttr', 'bar=Value'), Net_LDAP2_Util::split_attribute_string("fooAttr=bar=Value")); + $this->assertEquals(array('foo\=Attr', 'barValue'), Net_LDAP2_Util::split_attribute_string("foo\=Attr=barValue")); + $this->assertEquals(array('fooAttr', 'bar\=Value'), Net_LDAP2_Util::split_attribute_string("fooAttr=bar\=Value")); + + // test default behaviour with delim + $this->assertEquals(array('fooAttr', '=', 'barValue'), Net_LDAP2_Util::split_attribute_string("fooAttr=barValue", false, true)); + $this->assertEquals(array('fooAttr', '=', '=barValue'), Net_LDAP2_Util::split_attribute_string("fooAttr==barValue", false, true)); + $this->assertEquals(array('fooAttr', '=', 'bar=Value'), Net_LDAP2_Util::split_attribute_string("fooAttr=bar=Value", false, true)); + $this->assertEquals(array('foo\=Attr', '=', 'barValue'), Net_LDAP2_Util::split_attribute_string("foo\=Attr=barValue", false, true)); + + // test basic extended splitting and delimter return + $test_delimeters = array('=', '~=', '>', '>=', '<','<='); + foreach ($test_delimeters as $td) { + // default behavior with simple parameters + $this->assertEquals(array('fooAttr', 'barValue'), Net_LDAP2_Util::split_attribute_string("fooAttr${td}barValue", true), "AttrString='fooAttr${td}barValue'; sep='$td'"); + $this->assertEquals(array('fooAttr', 'barValue'), Net_LDAP2_Util::split_attribute_string("fooAttr${td}barValue", true, false)); + + // test proper escaping + $tde = addcslashes($td, '=~><'); + $this->assertEquals(array("foo${tde}Attr", 'barValue'), Net_LDAP2_Util::split_attribute_string("foo${tde}Attr${td}barValue", true)); + } + + // negative test case: perform no split + $this->assertEquals(array('fooAttr barValue'), Net_LDAP2_Util::split_attribute_string('fooAttr barValue')); + $this->assertEquals(array('fooAttr barValue'), Net_LDAP2_Util::split_attribute_string('fooAttr barValue', true, true)); + $this->assertEquals(array('fooAttr>barValue'), Net_LDAP2_Util::split_attribute_string('fooAttr>barValue')); // extended splitting used, but not activated + + // negative testcase: wrong escaping used + $this->assertEquals(array('fooAttr\>', 'barValue'), Net_LDAP2_Util::split_attribute_string('fooAttr\>=barValue', false, false)); + $this->assertEquals(array('fooAttr\>', '=', 'barValue'), Net_LDAP2_Util::split_attribute_string('fooAttr\>=barValue', true, true)); + $this->assertEquals(array('fooAttr', '>', '\=barValue'), Net_LDAP2_Util::split_attribute_string('fooAttr>\=barValue', true, true)); + $this->assertEquals(array('fooAttr\>\=barValue'), Net_LDAP2_Util::split_attribute_string('fooAttr\>\=barValue', true, true)); + + } + +} +?>
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/ldapconfig.ini.dist
Added
@@ -0,0 +1,51 @@ +; +---------------------------------------------------------------------------+ +; | This is a configuration file for Net_LDAP2s tests. | +; | To activate the tests, you need to adjust the configuration to | +; | your needs and copy it over to "ldapconfig.conf". Place the | +; | file inside the directory holding all the test programs. | +; | | +; | Note, that this tests assume a working LDAP server. | +; | If you don't have such a server, you may use the | +; | LDIF based mock server. Head to 'ldapldifconfig.ini.dist'. | +; | | +; | The syntax of this file is really easy and similar to other .ini-files. | +; | Remember to quote strings containing non-alphanumeric characters. | +; +---------------------------------------------------------------------------+ + + +; Global section +; server_cap_tls: is the server ssl capable? +; server_cap_anonymous: is the server allowing anonymous access? +; server_base_dn: BaseDN at which your DIT starts. Ensure that the +; binding user has all rights to add, delete and +; modifying entries as well as creating and deleting +; some subtree (ou=...) below the base. +; server_*: I think those following are self-explanatory +; server_binddn: Relative to base_dn below +[global] +server_cap_tls = false +server_cap_anonymous = true +server_base_dn = "dc=example,dc=com" +server_address = localhost +server_port = 389 +server_binddn = "cn=admin" +server_bindpw = test + + +; Definitions for the tests. Adjust to suit the needs of your test server. +; existing_entry: RDN for an entry that must exist (relative to base). +; The following attribute tests are performed on this entry. +; existing_attrs: Name of an existing attribute (single valued) +; existing_attrsv: Value of this attribute +; existing_attrm: Name of an existing attribute (multi valued) +; existing_attrmv: Values of this attribute, "|" delimited +; utf8_attr: Name of attribute with UTF8 value +; noutf8_attr: Name of attribute without UTF8 value +[test] +existing_entry = "cn=existing" +existing_attrs = sn +existing_attrsv = testentry +existing_attrm = mail +existing_attrmv = "test.entry@example.com|te@example.com" +utf8_attr = ou +noutf8_attr = givenName
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/ldapldifconfig.ini.dist
Added
@@ -0,0 +1,17 @@ +; +---------------------------------------------------------------------------+ +; | This is a configuration file for Net_LDAP2LDIFs tests. | +; | To activate the tests, you need to adjust the configuration to | +; | your needs and copy it over to "ldapldifconfig.conf". Place the | +; | file inside the directory holding all the test programs. | +; | | +; | Note, that this tests assumes a correct LDIF file. | +; | By default, one of the test sets will be used. | +; | | +; | The syntax of this file is really easy and similar to other .ini-files. | +; | Remember to quote strings containing non-alphanumeric characters. | +; +---------------------------------------------------------------------------+ + + +; /!\ IMOPORTANT NOTE: THE LDIF BASED MOCK SERVER IS NOT IMPLEMENTED SO FAR! /!\ +; This file is just here for later use and a reminder. Just ignore it so far +; unless you are implementing tests :) \ No newline at end of file
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/ldif_data
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/ldif_data/INITIAL_TESTDATA.ldif
Added
@@ -0,0 +1,13 @@ +dn: cn=existing,dc=example,dc=com +objectClass: inetOrgPerson +objectClass: organizationalPerson +objectClass: person +objectClass: top +cn: existing +sn: testentry +mail: test.entry@example.com +mail: te@example.com +ou:: UGFsbcO2 +givenName: i am +description: A test entry for PEAR::Net_LDAP2 +
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/ldif_data/base.ldif
Added
@@ -0,0 +1,7 @@ +# ldapadd -x -h localhost -p 389 -D "cn=admin,dc=test,dc=com" -w secret -f base.ldif + +dn: dc=example,dc=com +objectClass: dcObject +objectClass: organizationalUnit +#dc: test +ou: Test \ No newline at end of file
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/ldif_data/changes.ldif
Added
@@ -0,0 +1,44 @@ +# +# This is a LDIF file to test writing changes of entries +# +# +version: 1 +dn: cn=test1,ou=example,dc=com +changetype: modify +delete: attr1 +- +delete: attr2 +attr2: baz +- +delete: attr4 +- + +dn:: Y249dGVzdCD25Pwsb3U9ZXhhbXBsZSxkYz1jb20= +changetype: modify +add: newattr +newattr: foo +- +delete: attr3 +- +replace: attr1 +attr1: newvaluefor1 +- +replace: attr2 +attr2: newvalue1for2 +attr2: newvalue2for2 +- + +dn:: OmNuPWVuZHNwYWNlLGRjPWNvbSA= +changetype: delete + +dn: cn=foo,ou=example,dc=com +changetype: modrdn +newrdn: cn=Bar +deleteoldrdn: 1 + +dn: cn=footest,ou=example,dc=com +changetype: modrdn +newrdn: cn=foobartest +deleteoldrdn: 1 +newsuperior: ou=newexample,dc=com +
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/ldif_data/malformed_encoding.ldif
Added
@@ -0,0 +1,19 @@ +# +# This is a LDIF file to test encoding failure +# + +# unencoded DN +version: 1 +dn: cn=testöäü,ou=example,dc=com +objectclass: oc1 + +# unencoded attr value +version: 1 +dn: cn=test2,ou=example,dc=com +objectclass: testöäü +cn: test2 + +# entry ok +version: 1 +dn: cn=test,ou=example,dc=com +objectclass: oc1
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/ldif_data/malformed_syntax.ldif
Added
@@ -0,0 +1,20 @@ +# +# This is a LDIF file to test syntax error +# + +# wrong syntax (space too less at val of objectclass) +dn: cn=test1,ou=example,dc=com +objectclass:oc1 +cn: test1 +attr3: foo + +# wrong syntax (no DN given) +objectclass:oc1 +cn: test_invalid +attr3: foo + +# entry ok +version: 1 +dn: cn=test3,ou=example,dc=com +objectclass: oc1 +attr3: foo
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/ldif_data/malformed_wrapping.ldif
Added
@@ -0,0 +1,24 @@ +# +# This is a LDIF file to test wrapping failure +# + +# wrong wrapping (entry must fail because DN is damaged): +# (note, that there must eb an empty line below this comment, otherwise +# the DN line is treaten as wrapped comment) + + dn: cn=test1,ou=example,dc=com +objectclass: oc1 +cn: test1 + +# wrong syntax (literal line but no wrapped content) +dn: cn=test2,ou=example,dc=com +objectclass:oc1 +cn: test2 +some_wrong_literal_line +attr3: foo + +# entry ok +version: 1 +dn: cn=test,ou=example,dc=com +objectclass: oc1 +cn: test
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/ldif_data/slapd.conf
Added
@@ -0,0 +1,17 @@ +# See slapd.conf(5) for details on configuration options. +include /etc/ldap/schema/core.schema +include /etc/ldap/schema/cosine.schema +include /etc/ldap/schema/inetorgperson.schema +include /etc/ldap/schema/nis.schema + +pidfile /tmp/slapd/slapd.pid +argsfile /tmp/slapd/slapd.args + +modulepath /usr/lib/openldap + +database ldif +directory /tmp/slapd + +suffix "dc=example,dc=com" +rootdn "cn=admin,dc=example,dc=com" +rootpw {SSHA}AIzygLSXlArhAMzddUriXQxf7UlkqopP
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/ldif_data/sorted_w40.ldif
Added
@@ -0,0 +1,41 @@ +# +# This is a LDIF file to test reading capabilitys +# It was created using options: sort=1, wrap=40 +# +version: 1 +dn: cn=test1,ou=example,dc=com +objectclass: oc1 +attr1: 12345 +attr2: 1234 +attr2: baz +attr3: foo +attr3: bar +attr4: brrrzztt +cn: test1 + +dn: cn=test blabla,ou=example,dc=com +objectclass: oc2 +attr1: 12345 +attr2: 1234 +attr2: baz +attr3: foo +attr3: bar +attr4:: YmxhYmxh9uT8 +cn: test blabla +verylong: fhu08rhvt7b478vt5hv78h45nfgt45h78t34hhhhhhhhhv5bg8h6ttttttttt3489t57nhvgh4788trhg8999vnhtgthgui65hgb5789thvngwr789cghm738 + +dn:: Y249dGVzdCD25Pwsb3U9ZXhhbXBsZSxkYz1jb20= +objectclass: oc3 +attr1: 12345 +attr2: 1234 +attr2: baz +attr3: foo +attr3: bar +attr4:: YmxhYmxh9uT8 +attr5:: ZW5kc3BhY2Ug +attr6:: OmJhZGluaXRjaGFy +cn:: dGVzdCD25Pw= + +dn:: OmNuPWVuZHNwYWNlLGRjPWNvbSA= +cn: endspace +
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/ldif_data/sorted_w50.ldif
Added
@@ -0,0 +1,43 @@ +# +# This is a LDIF file to test reading capabilitys +# It was created using options: sort=1, wrap=50 +# +version: 1 +dn: cn=test1,ou=example,dc=com +objectclass: oc1 +attr1: 12345 +attr2: 1234 +attr2: baz +attr3: foo +attr3: bar +attr4: brrrzztt +cn: test1 + +dn: cn=test blabla,ou=example,dc=com +objectclass: oc2 +attr1: 12345 +attr2: 1234 +attr2: baz +attr3: foo +attr3: bar +attr4:: YmxhYmxh9uT8 +cn: test blabla +verylong: fhu08rhvt7b478vt5hv78h45nfgt45h78t34hhhhhhhhhv5bg8 + h6ttttttttt3489t57nhvgh4788trhg8999vnhtgthgui65hgb + 5789thvngwr789cghm738 + +dn:: Y249dGVzdCD25Pwsb3U9ZXhhbXBsZSxkYz1jb20= +objectclass: oc3 +attr1: 12345 +attr2: 1234 +attr2: baz +attr3: foo +attr3: bar +attr4:: YmxhYmxh9uT8 +attr5:: ZW5kc3BhY2Ug +attr6:: OmJhZGluaXRjaGFy +cn:: dGVzdCD25Pw= + +dn:: OmNuPWVuZHNwYWNlLGRjPWNvbSA= +cn: endspace +
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/ldif_data/unsorted_w30.ldif
Added
@@ -0,0 +1,41 @@ +# +# This is a LDIF file to test reading capabilitys +# It was created using options: sort=0, wrap=30 +# +version: 1 +dn: cn=test1,ou=example,dc=com +cn: test1 +attr3: foo +attr3: bar +attr1: 12345 +attr4: brrrzztt +objectclass: oc1 +attr2: 1234 +attr2: baz + +dn: cn=test blabla,ou=example,dc=com +cn: test blabla +attr3: foo +attr3: bar +attr1: 12345 +attr4:: YmxhYmxh9uT8 +objectclass: oc2 +attr2: 1234 +attr2: baz +verylong: fhu08rhvt7b478vt5hv78h45nfgt45h78t34hhhhhhhhhv5bg8h6ttttttttt3489t57nhvgh4788trhg8999vnhtgthgui65hgb5789thvngwr789cghm738 + +dn:: Y249dGVzdCD25Pwsb3U9ZXhhbXBsZSxkYz1jb20= +cn:: dGVzdCD25Pw= +attr3: foo +attr3: bar +attr1: 12345 +attr4:: YmxhYmxh9uT8 +objectclass: oc3 +attr2: 1234 +attr2: baz +attr5:: ZW5kc3BhY2Ug +attr6:: OmJhZGluaXRjaGFy + +dn:: OmNuPWVuZHNwYWNlLGRjPWNvbSA= +cn: endspace +
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/ldif_data/unsorted_w50.ldif
Added
@@ -0,0 +1,43 @@ +# +# This is a LDIF file to test reading capabilitys +# It was created using options: sort=0, wrap=50 +# +version: 1 +dn: cn=test1,ou=example,dc=com +cn: test1 +attr3: foo +attr3: bar +attr1: 12345 +attr4: brrrzztt +objectclass: oc1 +attr2: 1234 +attr2: baz + +dn: cn=test blabla,ou=example,dc=com +cn: test blabla +attr3: foo +attr3: bar +attr1: 12345 +attr4:: YmxhYmxh9uT8 +objectclass: oc2 +attr2: 1234 +attr2: baz +verylong: fhu08rhvt7b478vt5hv78h45nfgt45h78t34hhhhhhhhhv5bg8 + h6ttttttttt3489t57nhvgh4788trhg8999vnhtgthgui65hgb + 5789thvngwr789cghm738 + +dn:: Y249dGVzdCD25Pwsb3U9ZXhhbXBsZSxkYz1jb20= +cn:: dGVzdCD25Pw= +attr3: foo +attr3: bar +attr1: 12345 +attr4:: YmxhYmxh9uT8 +objectclass: oc3 +attr2: 1234 +attr2: baz +attr5:: ZW5kc3BhY2Ug +attr6:: OmJhZGluaXRjaGFy + +dn:: OmNuPWVuZHNwYWNlLGRjPWNvbSA= +cn: endspace +
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/ldif_data/unsorted_w50_WIN.ldif
Added
@@ -0,0 +1,43 @@ +# +# This is a LDIF file to test reading capabilitys with WINDOWS line endings +# It was created using options: sort=0, wrap=50 +# +version: 1 +dn: cn=test1,ou=example,dc=com +cn: test1 +attr3: foo +attr3: bar +attr1: 12345 +attr4: brrrzztt +objectclass: oc1 +attr2: 1234 +attr2: baz + +dn: cn=test blabla,ou=example,dc=com +cn: test blabla +attr3: foo +attr3: bar +attr1: 12345 +attr4:: YmxhYmxh9uT8 +objectclass: oc2 +attr2: 1234 +attr2: baz +verylong: fhu08rhvt7b478vt5hv78h45nfgt45h78t34hhhhhhhhhv5bg8 + h6ttttttttt3489t57nhvgh4788trhg8999vnhtgthgui65hgb + 5789thvngwr789cghm738 + +dn:: Y249dGVzdCD25Pwsb3U9ZXhhbXBsZSxkYz1jb20= +cn:: dGVzdCD25Pw= +attr3: foo +attr3: bar +attr1: 12345 +attr4:: YmxhYmxh9uT8 +objectclass: oc3 +attr2: 1234 +attr2: baz +attr5:: ZW5kc3BhY2Ug +attr6:: OmJhZGluaXRjaGFy + +dn:: OmNuPWVuZHNwYWNlLGRjPWNvbSA= +cn: endspace +
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/phpunit.xml
Added
@@ -0,0 +1,5 @@ +<phpunit strict="false"> + <php> + <includePath>..</includePath> + </php> +</phpunit>
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/travis
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/pear/net_ldap2/tests/travis/enable-ldap.ini
Added
@@ -0,0 +1,1 @@ +extension=ldap.so
View file
roundcubemail-1.4.13.tar.gz/vendor/phpdocumentor/type-resolver/src/PseudoTypes/IntegerRange.php
Added
@@ -0,0 +1,61 @@ +<?php + +declare(strict_types=1); + +/** + * This file is part of phpDocumentor. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\PseudoTypes; + +use phpDocumentor\Reflection\PseudoType; +use phpDocumentor\Reflection\Type; +use phpDocumentor\Reflection\Types\Integer; + +/** + * Value Object representing the type 'int'. + * + * @psalm-immutable + */ +final class IntegerRange extends Integer implements PseudoType +{ + /** @var string */ + private $minValue; + + /** @var string */ + private $maxValue; + + public function __construct(string $minValue, string $maxValue) + { + $this->minValue = $minValue; + $this->maxValue = $maxValue; + } + + public function underlyingType(): Type + { + return new Integer(); + } + + public function getMinValue(): string + { + return $this->minValue; + } + + public function getMaxValue(): string + { + return $this->maxValue; + } + + /** + * Returns a rendered output of the Type as it would be used in a DocBlock. + */ + public function __toString(): string + { + return 'int<' . $this->minValue . ', ' . $this->maxValue . '>'; + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/phpdocumentor/type-resolver/src/PseudoTypes/List_.php
Added
@@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +/** + * This file is part of phpDocumentor. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\PseudoTypes; + +use phpDocumentor\Reflection\PseudoType; +use phpDocumentor\Reflection\Type; +use phpDocumentor\Reflection\Types\Array_; +use phpDocumentor\Reflection\Types\Integer; +use phpDocumentor\Reflection\Types\Mixed_; + +/** + * Value Object representing the type 'list'. + * + * @psalm-immutable + */ +final class List_ extends Array_ implements PseudoType +{ + public function underlyingType(): Type + { + return new Array_(); + } + + public function __construct(?Type $valueType = null) + { + parent::__construct($valueType, new Integer()); + } + + /** + * Returns a rendered output of the Type as it would be used in a DocBlock. + */ + public function __toString(): string + { + if ($this->valueType instanceof Mixed_) { + return 'list'; + } + + return 'list<' . $this->valueType . '>'; + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/phpdocumentor/type-resolver/src/PseudoTypes/NegativeInteger.php
Added
@@ -0,0 +1,39 @@ +<?php + +declare(strict_types=1); + +/** + * This file is part of phpDocumentor. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\PseudoTypes; + +use phpDocumentor\Reflection\PseudoType; +use phpDocumentor\Reflection\Type; +use phpDocumentor\Reflection\Types\Integer; + +/** + * Value Object representing the type 'int'. + * + * @psalm-immutable + */ +final class NegativeInteger extends Integer implements PseudoType +{ + public function underlyingType(): Type + { + return new Integer(); + } + + /** + * Returns a rendered output of the Type as it would be used in a DocBlock. + */ + public function __toString(): string + { + return 'negative-int'; + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/phpdocumentor/type-resolver/src/PseudoTypes/Numeric_.php
Added
@@ -0,0 +1,47 @@ +<?php + +declare(strict_types=1); + +/** + * This file is part of phpDocumentor. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + * @link http://phpdoc.org + */ + +namespace phpDocumentor\Reflection\PseudoTypes; + +use phpDocumentor\Reflection\PseudoType; +use phpDocumentor\Reflection\Type; +use phpDocumentor\Reflection\Types\AggregatedType; +use phpDocumentor\Reflection\Types\Compound; +use phpDocumentor\Reflection\Types\Float_; +use phpDocumentor\Reflection\Types\Integer; + +/** + * Value Object representing the 'numeric' pseudo-type, which is either a numeric-string, integer or float. + * + * @psalm-immutable + */ +final class Numeric_ extends AggregatedType implements PseudoType +{ + public function __construct() + { + AggregatedType::__construct([new NumericString(), new Integer(), new Float_()], '|'); + } + + public function underlyingType(): Type + { + return new Compound([new NumericString(), new Integer(), new Float_()]); + } + + /** + * Returns a rendered output of the Type as it would be used in a DocBlock. + */ + public function __toString(): string + { + return 'numeric'; + } +}
View file
roundcubemail-1.4.11.20.tar.gz/vendor/phpdocumentor/type-resolver/src/PseudoTypes/PositiveInteger.php -> roundcubemail-1.4.13.tar.gz/vendor/phpdocumentor/type-resolver/src/PseudoTypes/PositiveInteger.php
Changed
@@ -18,7 +18,7 @@ use phpDocumentor\Reflection\Types\Integer; /** - * Value Object representing the type 'string'. + * Value Object representing the type 'int'. * * @psalm-immutable */
View file
roundcubemail-1.4.11.20.tar.gz/vendor/phpdocumentor/type-resolver/src/TypeResolver.php -> roundcubemail-1.4.13.tar.gz/vendor/phpdocumentor/type-resolver/src/TypeResolver.php
Changed
@@ -15,6 +15,8 @@ use ArrayIterator; use InvalidArgumentException; +use phpDocumentor\Reflection\PseudoTypes\IntegerRange; +use phpDocumentor\Reflection\PseudoTypes\List_; use phpDocumentor\Reflection\Types\Array_; use phpDocumentor\Reflection\Types\ArrayKey; use phpDocumentor\Reflection\Types\ClassString; @@ -37,8 +39,10 @@ use function class_exists; use function class_implements; use function count; +use function current; use function end; use function in_array; +use function is_numeric; use function key; use function preg_split; use function strpos; @@ -81,10 +85,12 @@ 'non-empty-lowercase-string' => PseudoTypes\NonEmptyLowercaseString::class, 'non-empty-string' => PseudoTypes\NonEmptyString::class, 'numeric-string' => PseudoTypes\NumericString::class, + 'numeric' => PseudoTypes\Numeric_::class, 'trait-string' => PseudoTypes\TraitString::class, 'int' => Types\Integer::class, 'integer' => Types\Integer::class, 'positive-int' => PseudoTypes\PositiveInteger::class, + 'negative-int' => PseudoTypes\NegativeInteger::class, 'bool' => Types\Boolean::class, 'boolean' => Types\Boolean::class, 'real' => Types\Float_::class, @@ -110,6 +116,7 @@ 'parent' => Types\Parent_::class, 'iterable' => Types\Iterable_::class, 'never' => Types\Never_::class, + 'list' => PseudoTypes\List_::class, ]; /** @@ -255,6 +262,8 @@ if ($classType !== null) { if ((string) $classType === 'class-string') { $types[] = $this->resolveClassString($tokens, $context); + } elseif ((string) $classType === 'int') { + $types[] = $this->resolveIntRange($tokens); } elseif ((string) $classType === 'interface-string') { $types[] = $this->resolveInterfaceString($tokens, $context); } else { @@ -271,6 +280,10 @@ } elseif ($token === self::OPERATOR_ARRAY) { end($types); $last = key($types); + if ($last === null) { + throw new InvalidArgumentException('Unexpected array operator'); + } + $lastItem = $types[$last]; if ($lastItem instanceof Expression) { $lastItem = $lastItem->getValueType(); @@ -315,7 +328,7 @@ ); } } elseif (count($types) === 1) { - return $types[0]; + return current($types); } if ($compoundToken === '|') { @@ -478,6 +491,75 @@ } /** + * Resolves integer ranges + * + * @param ArrayIterator<int, (string|null)> $tokens + */ + private function resolveIntRange(ArrayIterator $tokens): Type + { + $tokens->next(); + + $token = ''; + $minValue = null; + $maxValue = null; + $commaFound = false; + $tokenCounter = 0; + while ($tokens->valid()) { + $tokenCounter++; + $token = $tokens->current(); + if ($token === null) { + throw new RuntimeException( + 'Unexpected nullable character' + ); + } + + $token = trim($token); + + if ($token === '>') { + break; + } + + if ($token === ',') { + $commaFound = true; + } + + if ($commaFound === false && $minValue === null) { + if (is_numeric($token) || $token === 'max' || $token === 'min') { + $minValue = $token; + } + } + + if ($commaFound === true && $maxValue === null) { + if (is_numeric($token) || $token === 'max' || $token === 'min') { + $maxValue = $token; + } + } + + $tokens->next(); + } + + if ($token !== '>') { + if (empty($token)) { + throw new RuntimeException( + 'interface-string: ">" is missing' + ); + } + + throw new RuntimeException( + 'Unexpected character "' . $token . '", ">" is missing' + ); + } + + if (!$minValue || !$maxValue || $tokenCounter > 4) { + throw new RuntimeException( + 'int<min,max> has not the correct format' + ); + } + + return new IntegerRange($minValue, $maxValue); + } + + /** * Resolves class string * * @param ArrayIterator<int, (string|null)> $tokens @@ -521,10 +603,11 @@ { $isArray = ((string) $classType === 'array'); $isIterable = ((string) $classType === 'iterable'); + $isList = ((string) $classType === 'list'); // allow only "array", "iterable" or class name before "<" if ( - !$isArray && !$isIterable + !$isArray && !$isIterable && !$isList && (!$classType instanceof Object_ || $classType->getFqsen() === null) ) { throw new RuntimeException( @@ -538,7 +621,7 @@ $keyType = null; $token = $tokens->current(); - if ($token !== null && trim($token) === ',') { + if ($token !== null && trim($token) === ',' && !$isList) { // if we have a comma, then we just parsed the key type, not the value type $keyType = $valueType; if ($isArray) { @@ -596,6 +679,10 @@ return new Iterable_($valueType, $keyType); } + if ($isList) { + return new List_($valueType); + } + if ($classType instanceof Object_) { return $this->makeCollectionFromObject($classType, $valueType, $keyType); }
View file
roundcubemail-1.4.11.20.tar.gz/vendor/phpdocumentor/type-resolver/src/Types/Array_.php -> roundcubemail-1.4.13.tar.gz/vendor/phpdocumentor/type-resolver/src/Types/Array_.php
Changed
@@ -24,6 +24,6 @@ * * @psalm-immutable */ -final class Array_ extends AbstractList +class Array_ extends AbstractList { }
View file
roundcubemail-1.4.11.20.tar.gz/vendor/smarty/smarty/CHANGELOG.md -> roundcubemail-1.4.13.tar.gz/vendor/smarty/smarty/CHANGELOG.md
Changed
@@ -6,6 +6,21 @@ ## [Unreleased] +## [3.1.43] - 2022-01-10 + +### Security +- Prevent evasion of the `static_classes` security policy. This addresses CVE-2021-21408 + +## [3.1.42] - 2022-01-10 + +### Security +- Prevent arbitrary PHP code execution through maliciously crafted expression for the math function. This addresses CVE-2021-29454 + +## [3.1.41] - 2022-01-09 + +### Security +- Rewrote the mailto function to not use `eval` when encoding with javascript + ## [3.1.40] - 2021-10-13 ### Changed
View file
roundcubemail-1.4.11.20.tar.gz/vendor/smarty/smarty/lexer/smarty_internal_templateparser.y -> roundcubemail-1.4.13.tar.gz/vendor/smarty/smarty/lexer/smarty_internal_templateparser.y
Changed
@@ -758,6 +758,9 @@ value(res) ::= varindexed(vi) DOUBLECOLON static_class_access(r). { + if ($this->security && $this->security->static_classes !== array()) { + $this->compiler->trigger_template_error('dynamic static class not allowed by security setting'); + } $prefixVar = $this->compiler->getNewPrefixVariable(); if (vi['var'] === '\'smarty\'') { $this->compiler->appendPrefixCode("<?php {$prefixVar} = ". $this->compiler->compileTag('private_special_variable',array(),vi['smarty_internal_index']).';?>');
View file
roundcubemail-1.4.11.20.tar.gz/vendor/smarty/smarty/libs/Smarty.class.php -> roundcubemail-1.4.13.tar.gz/vendor/smarty/smarty/libs/Smarty.class.php
Changed
@@ -111,7 +111,7 @@ /** * smarty version */ - const SMARTY_VERSION = '3.1.40'; + const SMARTY_VERSION = '3.1.43'; /** * define variable scopes */
View file
roundcubemail-1.4.11.20.tar.gz/vendor/smarty/smarty/libs/plugins/function.mailto.php -> roundcubemail-1.4.13.tar.gz/vendor/smarty/smarty/libs/plugins/function.mailto.php
Changed
@@ -94,22 +94,19 @@ ); return; } - // FIXME: (rodneyrehm) document.write() excues me what? 1998 has passed! if ($encode === 'javascript') { - $string = 'document.write(\'<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>\');'; + $string = '<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>'; $js_encode = ''; for ($x = 0, $_length = strlen($string); $x < $_length; $x++) { $js_encode .= '%' . bin2hex($string[ $x ]); } - return '<script type="text/javascript">eval(unescape(\'' . $js_encode . '\'))</script>'; + return '<script type="text/javascript">document.write(unescape(\'' . $js_encode . '\'))</script>'; } elseif ($encode === 'javascript_charcode') { $string = '<a href="mailto:' . $address . '" ' . $extra . '>' . $text . '</a>'; - for ($x = 0, $y = strlen($string); $x < $y; $x++) { + for ($x = 0, $_length = strlen($string); $x < $_length; $x++) { $ord[] = ord($string[ $x ]); } - $_ret = "<script type=\"text/javascript\" language=\"javascript\">\n" . "{document.write(String.fromCharCode(" . - implode(',', $ord) . "))" . "}\n" . "</script>\n"; - return $_ret; + return '<script type="text/javascript">document.write(String.fromCharCode(' . implode(',', $ord) . '))</script>'; } elseif ($encode === 'hex') { preg_match('!^(.*)(\?.*)$!', $address, $match); if (!empty($match[ 2 ])) {
View file
roundcubemail-1.4.11.20.tar.gz/vendor/smarty/smarty/libs/plugins/function.math.php -> roundcubemail-1.4.13.tar.gz/vendor/smarty/smarty/libs/plugins/function.math.php
Changed
@@ -28,7 +28,12 @@ 'int' => true, 'abs' => true, 'ceil' => true, + 'acos' => true, + 'acosh' => true, 'cos' => true, + 'cosh' => true, + 'deg2rad' => true, + 'rad2deg' => true, 'exp' => true, 'floor' => true, 'log' => true, @@ -39,27 +44,51 @@ 'pow' => true, 'rand' => true, 'round' => true, + 'asin' => true, + 'asinh' => true, 'sin' => true, + 'sinh' => true, 'sqrt' => true, 'srand' => true, - 'tan' => true + 'atan' => true, + 'atanh' => true, + 'tan' => true, + 'tanh' => true ); + // be sure equation parameter is present if (empty($params[ 'equation' ])) { trigger_error("math: missing equation parameter", E_USER_WARNING); return; } $equation = $params[ 'equation' ]; + + // Remove whitespaces + $equation = preg_replace('/\s+/', '', $equation); + + // Adapted from https://www.php.net/manual/en/function.eval.php#107377 + $number = '(?:\d+(?:[,.]\d+)?|pi|π)'; // What is a number + $functionsOrVars = '((?:0x[a-fA-F0-9]+)|([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*))'; + $operators = '[+\/*\^%-]'; // Allowed math operators + $regexp = '/^(('.$number.'|'.$functionsOrVars.'|('.$functionsOrVars.'\s*\((?1)+\)|\((?1)+\)))(?:'.$operators.'(?2))?)+$/'; + + if (!preg_match($regexp, $equation)) { + trigger_error("math: illegal characters", E_USER_WARNING); + return; + } + // make sure parenthesis are balanced if (substr_count($equation, '(') !== substr_count($equation, ')')) { trigger_error("math: unbalanced parenthesis", E_USER_WARNING); return; } + // disallow backticks if (strpos($equation, '`') !== false) { trigger_error("math: backtick character not allowed in equation", E_USER_WARNING); return; } + // also disallow dollar signs if (strpos($equation, '$') !== false) { trigger_error("math: dollar signs not allowed in equation", E_USER_WARNING); @@ -96,6 +125,7 @@ } $smarty_math_result = null; eval("\$smarty_math_result = " . $equation . ";"); + if (empty($params[ 'format' ])) { if (empty($params[ 'assign' ])) { return $smarty_math_result;
View file
roundcubemail-1.4.11.20.tar.gz/vendor/smarty/smarty/libs/sysplugins/smarty_internal_templateparser.php -> roundcubemail-1.4.13.tar.gz/vendor/smarty/smarty/libs/sysplugins/smarty_internal_templateparser.php
Changed
@@ -2837,6 +2837,10 @@ // line 765 "../smarty/lexer/smarty_internal_templateparser.y" public function yy_r95() { + if ($this->security && $this->security->static_classes !== array()) { + $this->compiler->trigger_template_error('dynamic static class not allowed by security setting'); + } + $prefixVar = $this->compiler->getNewPrefixVariable(); if ($this->yystack[ $this->yyidx + -2 ]->minor[ 'var' ] === '\'smarty\'') { $this->compiler->appendPrefixCode("<?php {$prefixVar} = " .
View file
roundcubemail-1.4.11.20.tar.gz/vendor/symfony/polyfill-ctype/Ctype.php -> roundcubemail-1.4.13.tar.gz/vendor/symfony/polyfill-ctype/Ctype.php
Changed
@@ -25,13 +25,13 @@ * * @see https://php.net/ctype-alnum * - * @param string|int $text + * @param mixed $text * * @return bool */ public static function ctype_alnum($text) { - $text = self::convert_int_to_char_for_ctype($text); + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text); } @@ -41,13 +41,13 @@ * * @see https://php.net/ctype-alpha * - * @param string|int $text + * @param mixed $text * * @return bool */ public static function ctype_alpha($text) { - $text = self::convert_int_to_char_for_ctype($text); + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text); } @@ -57,13 +57,13 @@ * * @see https://php.net/ctype-cntrl * - * @param string|int $text + * @param mixed $text * * @return bool */ public static function ctype_cntrl($text) { - $text = self::convert_int_to_char_for_ctype($text); + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^\x00-\x1f\x7f]/', $text); } @@ -73,13 +73,13 @@ * * @see https://php.net/ctype-digit * - * @param string|int $text + * @param mixed $text * * @return bool */ public static function ctype_digit($text) { - $text = self::convert_int_to_char_for_ctype($text); + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text); } @@ -89,13 +89,13 @@ * * @see https://php.net/ctype-graph * - * @param string|int $text + * @param mixed $text * * @return bool */ public static function ctype_graph($text) { - $text = self::convert_int_to_char_for_ctype($text); + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text); } @@ -105,13 +105,13 @@ * * @see https://php.net/ctype-lower * - * @param string|int $text + * @param mixed $text * * @return bool */ public static function ctype_lower($text) { - $text = self::convert_int_to_char_for_ctype($text); + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text); } @@ -121,13 +121,13 @@ * * @see https://php.net/ctype-print * - * @param string|int $text + * @param mixed $text * * @return bool */ public static function ctype_print($text) { - $text = self::convert_int_to_char_for_ctype($text); + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text); } @@ -137,13 +137,13 @@ * * @see https://php.net/ctype-punct * - * @param string|int $text + * @param mixed $text * * @return bool */ public static function ctype_punct($text) { - $text = self::convert_int_to_char_for_ctype($text); + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text); } @@ -153,13 +153,13 @@ * * @see https://php.net/ctype-space * - * @param string|int $text + * @param mixed $text * * @return bool */ public static function ctype_space($text) { - $text = self::convert_int_to_char_for_ctype($text); + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text); } @@ -169,13 +169,13 @@ * * @see https://php.net/ctype-upper * - * @param string|int $text + * @param mixed $text * * @return bool */ public static function ctype_upper($text) { - $text = self::convert_int_to_char_for_ctype($text); + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text); } @@ -185,13 +185,13 @@ * * @see https://php.net/ctype-xdigit * - * @param string|int $text + * @param mixed $text * * @return bool */ public static function ctype_xdigit($text) { - $text = self::convert_int_to_char_for_ctype($text); + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text); } @@ -204,11 +204,12 @@ * (negative values have 256 added in order to allow characters in the Extended ASCII range). * Any other integer is interpreted as a string containing the decimal digits of the integer. * - * @param string|int $int + * @param mixed $int + * @param string $function * * @return mixed */ - private static function convert_int_to_char_for_ctype($int) + private static function convert_int_to_char_for_ctype($int, $function) { if (!\is_int($int)) { return $int; @@ -218,6 +219,10 @@ return (string) $int; } + if (\PHP_VERSION_ID >= 80100) { + @trigger_error($function.'(): Argument of type int will be interpreted as string in the future', \E_USER_DEPRECATED); + } + if ($int < 0) { $int += 256; }
View file
roundcubemail-1.4.11.20.tar.gz/vendor/symfony/polyfill-ctype/composer.json -> roundcubemail-1.4.13.tar.gz/vendor/symfony/polyfill-ctype/composer.json
Changed
@@ -18,6 +18,9 @@ "require": { "php": ">=7.1" }, + "provide": { + "ext-ctype": "*" + }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Ctype\\": "" }, "files": [ "bootstrap.php" ]
View file
roundcubemail-1.4.11.20.tar.gz/vendor/symfony/yaml/Inline.php -> roundcubemail-1.4.13.tar.gz/vendor/symfony/yaml/Inline.php
Changed
@@ -653,7 +653,7 @@ // no break case '+' === $scalar[0] || '-' === $scalar[0] || '.' === $scalar[0] || is_numeric($scalar[0]): if (Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar)) { - $scalar = str_replace('_', '', (string) $scalar); + $scalar = str_replace('_', '', $scalar); } switch (true) {
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/LICENSE.txt
Added
@@ -0,0 +1,27 @@ +Copyright (c) 2005-2015, Zend Technologies USA, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of Zend Technologies USA, Inc. nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/README.md
Added
@@ -0,0 +1,22 @@ +Zend Framework 1 for Composer +============================= + +This package is a part of the Zend Framework 1. Each component was separated and put into its own composer package. Some modifications were made for improved [Composer](http://getcomposer.org/) integration. This package can also be found at [Packagist](http://packagist.org/packages/zf1). + +## Why? + +**Size!** Zend Framework is very large and contains a huge amount of files (over 72000 files in the main repository!). If you're only using a part of the framework, using the separated packages will greatly reduce the amount of files. This will make setup faster and easier on your disks. + +**Autoloading!** Explicit `require_once` calls in the source code has been commented out to rely on composer autoloading, this reduces the number of included files to a minimum. + +**Migration!** Zend Framework 2 has been around for a while now, and migrating all your projects takes a lot of time. Using these packages makes it easier to migrate each component separately. Also, some packages doesn't exist in zf2 (such as the zend-search-lucene), now you can continue using that package without requiring the entire framework. + +If you're using major parts of the framework, I would recommend checking out the [zendframework1 package](https://github.com/bombayworks/zendframework1), which contains the entire framework optimized for composer usage. + +## How to use + +Add `"zf1/zend-json": "~1.12"` to the require section of your composer.json, include the composer autoloader and you're good to go. + +## Broken dependencies? + +Dependencies have been set automatically based on the [requirements from the zend framework manual](http://framework.zend.com/manual/1.12/en/requirements.introduction.html), if you find any broken dependencies please submit an issue. \ No newline at end of file
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/composer.json
Added
@@ -0,0 +1,24 @@ +{ + "name": "zf1/zend-json", + "description": "Zend Framework 1 Json package", + "keywords": [ + "framework", + "zf1", + "zend", + "json" + ], + "homepage": "http://framework.zend.com/", + "license": "BSD-3-Clause", + "require": { + "php": ">=5.2.11", + "zf1/zend-exception": "self.version", + "zf1/zend-loader": "self.version", + "zf1/zend-server": "self.version", + "zf1/zend-xml": "self.version" + }, + "autoload": { + "psr-0": { + "Zend_Json": "library/" + } + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json.php
Added
@@ -0,0 +1,442 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * Zend_Json_Expr. + * + * @see Zend_Json_Expr + */ +// require_once 'Zend/Json/Expr.php'; + +/** @see Zend_Xml_Security */ +// require_once 'Zend/Xml/Security.php'; + +/** + * Class for encoding to and decoding from JSON. + * + * @category Zend + * @package Zend_Json + * @uses Zend_Json_Expr + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Json +{ + /** + * How objects should be encoded -- arrays or as StdClass. TYPE_ARRAY is 1 + * so that it is a boolean true value, allowing it to be used with + * ext/json's functions. + */ + const TYPE_ARRAY = 1; + const TYPE_OBJECT = 0; + + /** + * To check the allowed nesting depth of the XML tree during xml2json conversion. + * + * @var int + */ + public static $maxRecursionDepthAllowed=25; + + /** + * @var bool + */ + public static $useBuiltinEncoderDecoder = false; + + /** + * Decodes the given $encodedValue string which is + * encoded in the JSON format + * + * Uses ext/json's json_decode if available. + * + * @param string $encodedValue Encoded in JSON format + * @param int $objectDecodeType Optional; flag indicating how to decode + * objects. See {@link Zend_Json_Decoder::decode()} for details. + * @return mixed + */ + public static function decode($encodedValue, $objectDecodeType = Zend_Json::TYPE_ARRAY) + { + $encodedValue = (string) $encodedValue; + if (function_exists('json_decode') && self::$useBuiltinEncoderDecoder !== true) { + $decode = json_decode($encodedValue, $objectDecodeType); + + // php < 5.3 + if (!function_exists('json_last_error')) { + if (strtolower($encodedValue) === 'null') { + return null; + } elseif ($decode === null) { + // require_once 'Zend/Json/Exception.php'; + throw new Zend_Json_Exception('Decoding failed'); + } + // php >= 5.3 + } elseif (($jsonLastErr = json_last_error()) != JSON_ERROR_NONE) { + // require_once 'Zend/Json/Exception.php'; + switch ($jsonLastErr) { + case JSON_ERROR_DEPTH: + throw new Zend_Json_Exception('Decoding failed: Maximum stack depth exceeded'); + case JSON_ERROR_CTRL_CHAR: + throw new Zend_Json_Exception('Decoding failed: Unexpected control character found'); + case JSON_ERROR_SYNTAX: + throw new Zend_Json_Exception('Decoding failed: Syntax error'); + default: + throw new Zend_Json_Exception('Decoding failed'); + } + } + + return $decode; + } + + // require_once 'Zend/Json/Decoder.php'; + return Zend_Json_Decoder::decode($encodedValue, $objectDecodeType); + } + + /** + * Encode the mixed $valueToEncode into the JSON format + * + * Encodes using ext/json's json_encode() if available. + * + * NOTE: Object should not contain cycles; the JSON format + * does not allow object reference. + * + * NOTE: Only public variables will be encoded + * + * NOTE: Encoding native javascript expressions are possible using Zend_Json_Expr. + * You can enable this by setting $options['enableJsonExprFinder'] = true + * + * @see Zend_Json_Expr + * + * @param mixed $valueToEncode + * @param boolean $cycleCheck Optional; whether or not to check for object recursion; off by default + * @param array $options Additional options used during encoding + * @return string JSON encoded object + */ + public static function encode($valueToEncode, $cycleCheck = false, $options = array()) + { + if (is_object($valueToEncode)) { + if (method_exists($valueToEncode, 'toJson')) { + return $valueToEncode->toJson(); + } elseif (method_exists($valueToEncode, 'toArray')) { + return self::encode($valueToEncode->toArray(), $cycleCheck, $options); + } + } + + // Pre-encoding look for Zend_Json_Expr objects and replacing by tmp ids + $javascriptExpressions = array(); + if(isset($options['enableJsonExprFinder']) + && ($options['enableJsonExprFinder'] == true) + ) { + /** + * @see Zend_Json_Encoder + */ + // require_once "Zend/Json/Encoder.php"; + $valueToEncode = self::_recursiveJsonExprFinder($valueToEncode, $javascriptExpressions); + } + + // Encoding + if (function_exists('json_encode') && self::$useBuiltinEncoderDecoder !== true) { + $encodedResult = json_encode($valueToEncode); + } else { + // require_once 'Zend/Json/Encoder.php'; + $encodedResult = Zend_Json_Encoder::encode($valueToEncode, $cycleCheck, $options); + } + + //only do post-proccessing to revert back the Zend_Json_Expr if any. + if (count($javascriptExpressions) > 0) { + $count = count($javascriptExpressions); + for($i = 0; $i < $count; $i++) { + $magicKey = $javascriptExpressions[$i]['magicKey']; + $value = $javascriptExpressions[$i]['value']; + + $encodedResult = str_replace( + //instead of replacing "key:magicKey", we replace directly magicKey by value because "key" never changes. + '"' . $magicKey . '"', + $value, + $encodedResult + ); + } + } + + return $encodedResult; + } + + /** + * Check & Replace Zend_Json_Expr for tmp ids in the valueToEncode + * + * Check if the value is a Zend_Json_Expr, and if replace its value + * with a magic key and save the javascript expression in an array. + * + * NOTE this method is recursive. + * + * NOTE: This method is used internally by the encode method. + * + * @see encode + * @param array|object|Zend_Json_Expr $value a string - object property to be encoded + * @param array $javascriptExpressions + * @param null $currentKey + * + * @internal param mixed $valueToCheck + * @return void + */ + protected static function _recursiveJsonExprFinder(&$value, array &$javascriptExpressions, $currentKey = null) + { + if ($value instanceof Zend_Json_Expr) { + // TODO: Optimize with ascii keys, if performance is bad + $magicKey = "____" . $currentKey . "_" . (count($javascriptExpressions)); + $javascriptExpressions[] = array( + + //if currentKey is integer, encodeUnicodeString call is not required. + "magicKey" => (is_int($currentKey)) ? $magicKey : Zend_Json_Encoder::encodeUnicodeString($magicKey), + "value" => $value->__toString(), + ); + $value = $magicKey; + } elseif (is_array($value)) { + foreach ($value as $k => $v) { + $value[$k] = self::_recursiveJsonExprFinder($value[$k], $javascriptExpressions, $k); + } + } elseif (is_object($value)) { + foreach ($value as $k => $v) { + $value->$k = self::_recursiveJsonExprFinder($value->$k, $javascriptExpressions, $k); + } + } + return $value; + } + + /** + * Return the value of an XML attribute text or the text between + * the XML tags + * + * In order to allow Zend_Json_Expr from xml, we check if the node + * matchs the pattern that try to detect if it is a new Zend_Json_Expr + * if it matches, we return a new Zend_Json_Expr instead of a text node + * + * @param SimpleXMLElement $simpleXmlElementObject + * @return Zend_Json_Expr|string + */ + protected static function _getXmlValue($simpleXmlElementObject) { + $pattern = '/^[\s]*new Zend_Json_Expr[\s]*\([\s]*[\"\']{1}(.*)[\"\']{1}[\s]*\)[\s]*$/'; + $matchings = array(); + $match = preg_match ($pattern, $simpleXmlElementObject, $matchings); + if ($match) { + return new Zend_Json_Expr($matchings[1]); + } else { + return (trim(strval($simpleXmlElementObject))); + } + } + /** + * _processXml - Contains the logic for xml2json + * + * The logic in this function is a recursive one. + * + * The main caller of this function (i.e. fromXml) needs to provide + * only the first two parameters i.e. the SimpleXMLElement object and + * the flag for ignoring or not ignoring XML attributes. The third parameter + * will be used internally within this function during the recursive calls. + * + * This function converts the SimpleXMLElement object into a PHP array by + * calling a recursive (protected static) function in this class. Once all + * the XML elements are stored in the PHP array, it is returned to the caller. + * + * Throws a Zend_Json_Exception if the XML tree is deeper than the allowed limit. + * + * @param SimpleXMLElement $simpleXmlElementObject + * @param boolean $ignoreXmlAttributes + * @param integer $recursionDepth + * @return array + */ + protected static function _processXml($simpleXmlElementObject, $ignoreXmlAttributes, $recursionDepth=0) + { + // Keep an eye on how deeply we are involved in recursion. + if ($recursionDepth > self::$maxRecursionDepthAllowed) { + // XML tree is too deep. Exit now by throwing an exception. + // require_once 'Zend/Json/Exception.php'; + throw new Zend_Json_Exception( + "Function _processXml exceeded the allowed recursion depth of " . + self::$maxRecursionDepthAllowed); + } // End of if ($recursionDepth > self::$maxRecursionDepthAllowed) + + $children = $simpleXmlElementObject->children(); + $name = $simpleXmlElementObject->getName(); + $value = self::_getXmlValue($simpleXmlElementObject); + $attributes = (array) $simpleXmlElementObject->attributes(); + + if (count($children) == 0) { + if (!empty($attributes) && !$ignoreXmlAttributes) { + foreach ($attributes['@attributes'] as $k => $v) { + $attributes['@attributes'][$k]= self::_getXmlValue($v); + } + if (!empty($value)) { + $attributes['@text'] = $value; + } + return array($name => $attributes); + } else { + return array($name => $value); + } + } else { + $childArray= array(); + foreach ($children as $child) { + $childname = $child->getName(); + $element = self::_processXml($child,$ignoreXmlAttributes,$recursionDepth+1); + if (array_key_exists($childname, $childArray)) { + if (empty($subChild[$childname])) { + $childArray[$childname] = array($childArray[$childname]); + $subChild[$childname] = true; + } + $childArray[$childname][] = $element[$childname]; + } else { + $childArray[$childname] = $element[$childname]; + } + } + if (!empty($attributes) && !$ignoreXmlAttributes) { + foreach ($attributes['@attributes'] as $k => $v) { + $attributes['@attributes'][$k] = self::_getXmlValue($v); + } + $childArray['@attributes'] = $attributes['@attributes']; + } + if (!empty($value)) { + $childArray['@text'] = $value; + } + return array($name => $childArray); + } + } + + /** + * fromXml - Converts XML to JSON + * + * Converts a XML formatted string into a JSON formatted string. + * The value returned will be a string in JSON format. + * + * The caller of this function needs to provide only the first parameter, + * which is an XML formatted String. The second parameter is optional, which + * lets the user to select if the XML attributes in the input XML string + * should be included or ignored in xml2json conversion. + * + * This function converts the XML formatted string into a PHP array by + * calling a recursive (protected static) function in this class. Then, it + * converts that PHP array into JSON by calling the "encode" static funcion. + * + * Throws a Zend_Json_Exception if the input not a XML formatted string. + * NOTE: Encoding native javascript expressions via Zend_Json_Expr is not possible. + * + * @static + * @access public + * @param string $xmlStringContents XML String to be converted + * @param boolean $ignoreXmlAttributes Include or exclude XML attributes in + * the xml2json conversion process. + * @return mixed - JSON formatted string on success + * @throws Zend_Json_Exception + */ + public static function fromXml($xmlStringContents, $ignoreXmlAttributes=true) + { + // Load the XML formatted string into a Simple XML Element object. + $simpleXmlElementObject = Zend_Xml_Security::scan($xmlStringContents); + + // If it is not a valid XML content, throw an exception. + if ($simpleXmlElementObject == null) { + // require_once 'Zend/Json/Exception.php'; + throw new Zend_Json_Exception('Function fromXml was called with an invalid XML formatted string.'); + } // End of if ($simpleXmlElementObject == null) + + $resultArray = null; + + // Call the recursive function to convert the XML into a PHP array. + $resultArray = self::_processXml($simpleXmlElementObject, $ignoreXmlAttributes); + + // Convert the PHP array to JSON using Zend_Json encode method. + // It is just that simple. + $jsonStringOutput = self::encode($resultArray); + return($jsonStringOutput); + } + + + + /** + * Pretty-print JSON string + * + * Use 'format' option to select output format - currently html and txt supported, txt is default + * Use 'indent' option to override the indentation string set in the format - by default for the 'txt' format it's a tab + * + * @param string $json Original JSON string + * @param array $options Encoding options + * @return string + */ + public static function prettyPrint($json, $options = array()) + { + $tokens = preg_split('|([\{\}\]\[,])|', $json, -1, PREG_SPLIT_DELIM_CAPTURE); + $result = ''; + $indent = 0; + + $format= 'txt'; + + $ind = "\t"; + + if (isset($options['format'])) { + $format = $options['format']; + } + + switch ($format) { + case 'html': + $lineBreak = '<br />'; + $ind = ' '; + break; + default: + case 'txt': + $lineBreak = "\n"; + $ind = "\t"; + break; + } + + // override the defined indent setting with the supplied option + if (isset($options['indent'])) { + $ind = $options['indent']; + } + + $inLiteral = false; + foreach($tokens as $token) { + if($token == '') { + continue; + } + + $prefix = str_repeat($ind, $indent); + if (!$inLiteral && ($token == '{' || $token == '[')) { + $indent++; + if (($result != '') && ($result[(strlen($result)-1)] == $lineBreak)) { + $result .= $prefix; + } + $result .= $token . $lineBreak; + } elseif (!$inLiteral && ($token == '}' || $token == ']')) { + $indent--; + $prefix = str_repeat($ind, $indent); + $result .= $lineBreak . $prefix . $token; + } elseif (!$inLiteral && $token == ',') { + $result .= $token . $lineBreak; + } else { + $result .= ( $inLiteral ? '' : $prefix ) . $token; + + // Count # of unescaped double-quotes in token, subtract # of + // escaped double-quotes and if the result is odd then we are + // inside a string literal + if ((substr_count($token, "\"")-substr_count($token, "\\\"")) % 2 != 0) { + $inLiteral = !$inLiteral; + } + } + } + return $result; + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json/Decoder.php
Added
@@ -0,0 +1,581 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * @see Zend_Json + */ +// require_once 'Zend/Json.php'; + +/** + * Decode JSON encoded string to PHP variable constructs + * + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Json_Decoder +{ + /** + * Parse tokens used to decode the JSON object. These are not + * for public consumption, they are just used internally to the + * class. + */ + const EOF = 0; + const DATUM = 1; + const LBRACE = 2; + const LBRACKET = 3; + const RBRACE = 4; + const RBRACKET = 5; + const COMMA = 6; + const COLON = 7; + + /** + * Use to maintain a "pointer" to the source being decoded + * + * @var string + */ + protected $_source; + + /** + * Caches the source length + * + * @var int + */ + protected $_sourceLength; + + /** + * The offset within the souce being decoded + * + * @var int + * + */ + protected $_offset; + + /** + * The current token being considered in the parser cycle + * + * @var int + */ + protected $_token; + + /** + * Flag indicating how objects should be decoded + * + * @var int + * @access protected + */ + protected $_decodeType; + + /** + * Constructor + * + * @param string $source String source to decode + * @param int $decodeType How objects should be decoded -- see + * {@link Zend_Json::TYPE_ARRAY} and {@link Zend_Json::TYPE_OBJECT} for + * valid values + * @return void + */ + protected function __construct($source, $decodeType) + { + // Set defaults + $this->_source = self::decodeUnicodeString($source); + $this->_sourceLength = strlen($this->_source); + $this->_token = self::EOF; + $this->_offset = 0; + + // Normalize and set $decodeType + if (!in_array($decodeType, array(Zend_Json::TYPE_ARRAY, Zend_Json::TYPE_OBJECT))) + { + $decodeType = Zend_Json::TYPE_ARRAY; + } + $this->_decodeType = $decodeType; + + // Set pointer at first token + $this->_getNextToken(); + } + + /** + * Decode a JSON source string + * + * Decodes a JSON encoded string. The value returned will be one of the + * following: + * - integer + * - float + * - boolean + * - null + * - StdClass + * - array + * - array of one or more of the above types + * + * By default, decoded objects will be returned as associative arrays; to + * return a StdClass object instead, pass {@link Zend_Json::TYPE_OBJECT} to + * the $objectDecodeType parameter. + * + * Throws a Zend_Json_Exception if the source string is null. + * + * @static + * @access public + * @param string $source String to be decoded + * @param int $objectDecodeType How objects should be decoded; should be + * either or {@link Zend_Json::TYPE_ARRAY} or + * {@link Zend_Json::TYPE_OBJECT}; defaults to TYPE_ARRAY + * @return mixed + * @throws Zend_Json_Exception + */ + public static function decode($source = null, $objectDecodeType = Zend_Json::TYPE_ARRAY) + { + if (null === $source) { + // require_once 'Zend/Json/Exception.php'; + throw new Zend_Json_Exception('Must specify JSON encoded source for decoding'); + } elseif (!is_string($source)) { + // require_once 'Zend/Json/Exception.php'; + throw new Zend_Json_Exception('Can only decode JSON encoded strings'); + } + + $decoder = new self($source, $objectDecodeType); + + return $decoder->_decodeValue(); + } + + + /** + * Recursive driving rountine for supported toplevel tops + * + * @return mixed + */ + protected function _decodeValue() + { + switch ($this->_token) { + case self::DATUM: + $result = $this->_tokenValue; + $this->_getNextToken(); + return($result); + break; + case self::LBRACE: + return($this->_decodeObject()); + break; + case self::LBRACKET: + return($this->_decodeArray()); + break; + default: + return null; + break; + } + } + + /** + * Decodes an object of the form: + * { "attribute: value, "attribute2" : value,...} + * + * If Zend_Json_Encoder was used to encode the original object then + * a special attribute called __className which specifies a class + * name that should wrap the data contained within the encoded source. + * + * Decodes to either an array or StdClass object, based on the value of + * {@link $_decodeType}. If invalid $_decodeType present, returns as an + * array. + * + * @return array|StdClass + */ + protected function _decodeObject() + { + $members = array(); + $tok = $this->_getNextToken(); + + while ($tok && $tok != self::RBRACE) { + if ($tok != self::DATUM || ! is_string($this->_tokenValue)) { + // require_once 'Zend/Json/Exception.php'; + throw new Zend_Json_Exception('Missing key in object encoding: ' . $this->_source); + } + + $key = $this->_tokenValue; + $tok = $this->_getNextToken(); + + if ($tok != self::COLON) { + // require_once 'Zend/Json/Exception.php'; + throw new Zend_Json_Exception('Missing ":" in object encoding: ' . $this->_source); + } + + $tok = $this->_getNextToken(); + $members[$key] = $this->_decodeValue(); + $tok = $this->_token; + + if ($tok == self::RBRACE) { + break; + } + + if ($tok != self::COMMA) { + // require_once 'Zend/Json/Exception.php'; + throw new Zend_Json_Exception('Missing "," in object encoding: ' . $this->_source); + } + + $tok = $this->_getNextToken(); + } + + switch ($this->_decodeType) { + case Zend_Json::TYPE_OBJECT: + // Create new StdClass and populate with $members + $result = new StdClass(); + foreach ($members as $key => $value) { + if ($key === '') { + $key = '_empty_'; + } + $result->$key = $value; + } + break; + case Zend_Json::TYPE_ARRAY: + default: + $result = $members; + break; + } + + $this->_getNextToken(); + return $result; + } + + /** + * Decodes a JSON array format: + * [element, element2,...,elementN] + * + * @return array + */ + protected function _decodeArray() + { + $result = array(); + $starttok = $tok = $this->_getNextToken(); // Move past the '[' + $index = 0; + + while ($tok && $tok != self::RBRACKET) { + $result[$index++] = $this->_decodeValue(); + + $tok = $this->_token; + + if ($tok == self::RBRACKET || !$tok) { + break; + } + + if ($tok != self::COMMA) { + // require_once 'Zend/Json/Exception.php'; + throw new Zend_Json_Exception('Missing "," in array encoding: ' . $this->_source); + } + + $tok = $this->_getNextToken(); + } + + $this->_getNextToken(); + return($result); + } + + + /** + * Removes whitepsace characters from the source input + */ + protected function _eatWhitespace() + { + if (preg_match( + '/([\t\b\f\n\r ])*/s', + $this->_source, + $matches, + PREG_OFFSET_CAPTURE, + $this->_offset) + && $matches[0][1] == $this->_offset) + { + $this->_offset += strlen($matches[0][0]); + } + } + + + /** + * Retrieves the next token from the source stream + * + * @return int Token constant value specified in class definition + */ + protected function _getNextToken() + { + $this->_token = self::EOF; + $this->_tokenValue = null; + $this->_eatWhitespace(); + + if ($this->_offset >= $this->_sourceLength) { + return(self::EOF); + } + + $str = $this->_source; + $str_length = $this->_sourceLength; + $i = $this->_offset; + $start = $i; + + switch ($str{$i}) { + case '{': + $this->_token = self::LBRACE; + break; + case '}': + $this->_token = self::RBRACE; + break; + case '[': + $this->_token = self::LBRACKET; + break; + case ']': + $this->_token = self::RBRACKET; + break; + case ',': + $this->_token = self::COMMA; + break; + case ':': + $this->_token = self::COLON; + break; + case '"': + $result = ''; + do { + $i++; + if ($i >= $str_length) { + break; + } + + $chr = $str{$i}; + + if ($chr == '\\') { + $i++; + if ($i >= $str_length) { + break; + } + $chr = $str{$i}; + switch ($chr) { + case '"' : + $result .= '"'; + break; + case '\\': + $result .= '\\'; + break; + case '/' : + $result .= '/'; + break; + case 'b' : + $result .= "\x08"; + break; + case 'f' : + $result .= "\x0c"; + break; + case 'n' : + $result .= "\x0a"; + break; + case 'r' : + $result .= "\x0d"; + break; + case 't' : + $result .= "\x09"; + break; + case '\'' : + $result .= '\''; + break; + default: + // require_once 'Zend/Json/Exception.php'; + throw new Zend_Json_Exception("Illegal escape " + . "sequence '" . $chr . "'"); + } + } elseif($chr == '"') { + break; + } else { + $result .= $chr; + } + } while ($i < $str_length); + + $this->_token = self::DATUM; + //$this->_tokenValue = substr($str, $start + 1, $i - $start - 1); + $this->_tokenValue = $result; + break; + case 't': + if (($i+ 3) < $str_length && substr($str, $start, 4) == "true") { + $this->_token = self::DATUM; + } + $this->_tokenValue = true; + $i += 3; + break; + case 'f': + if (($i+ 4) < $str_length && substr($str, $start, 5) == "false") { + $this->_token = self::DATUM; + } + $this->_tokenValue = false; + $i += 4; + break; + case 'n': + if (($i+ 3) < $str_length && substr($str, $start, 4) == "null") { + $this->_token = self::DATUM; + } + $this->_tokenValue = NULL; + $i += 3; + break; + } + + if ($this->_token != self::EOF) { + $this->_offset = $i + 1; // Consume the last token character + return($this->_token); + } + + $chr = $str{$i}; + if ($chr == '-' || $chr == '.' || ($chr >= '0' && $chr <= '9')) { + if (preg_match('/-?([0-9])*(\.[0-9]*)?((e|E)((-|\+)?)[0-9]+)?/s', + $str, $matches, PREG_OFFSET_CAPTURE, $start) && $matches[0][1] == $start) { + + $datum = $matches[0][0]; + + if (is_numeric($datum)) { + if (preg_match('/^0\d+$/', $datum)) { + // require_once 'Zend/Json/Exception.php'; + throw new Zend_Json_Exception("Octal notation not supported by JSON (value: $datum)"); + } else { + $val = intval($datum); + $fVal = floatval($datum); + $this->_tokenValue = ($val == $fVal ? $val : $fVal); + } + } else { + // require_once 'Zend/Json/Exception.php'; + throw new Zend_Json_Exception("Illegal number format: $datum"); + } + + $this->_token = self::DATUM; + $this->_offset = $start + strlen($datum); + } + } else { + // require_once 'Zend/Json/Exception.php'; + throw new Zend_Json_Exception('Illegal Token'); + } + + return($this->_token); + } + + /** + * Decode Unicode Characters from \u0000 ASCII syntax. + * + * This algorithm was originally developed for the + * Solar Framework by Paul M. Jones + * + * @link http://solarphp.com/ + * @link http://svn.solarphp.com/core/trunk/Solar/Json.php + * @param string $value + * @return string + */ + public static function decodeUnicodeString($chrs) + { + $delim = substr($chrs, 0, 1); + $utf8 = ''; + $strlen_chrs = strlen($chrs); + + for($i = 0; $i < $strlen_chrs; $i++) { + + $substr_chrs_c_2 = substr($chrs, $i, 2); + $ord_chrs_c = ord($chrs[$i]); + + switch (true) { + case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $i, 6)): + // single, escaped unicode character + $utf16 = chr(hexdec(substr($chrs, ($i + 2), 2))) + . chr(hexdec(substr($chrs, ($i + 4), 2))); + $utf8 .= self::_utf162utf8($utf16); + $i += 5; + break; + case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): + $utf8 .= $chrs{$i}; + break; + case ($ord_chrs_c & 0xE0) == 0xC0: + // characters U-00000080 - U-000007FF, mask 110XXXXX + //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $i, 2); + ++$i; + break; + case ($ord_chrs_c & 0xF0) == 0xE0: + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $i, 3); + $i += 2; + break; + case ($ord_chrs_c & 0xF8) == 0xF0: + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $i, 4); + $i += 3; + break; + case ($ord_chrs_c & 0xFC) == 0xF8: + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $i, 5); + $i += 4; + break; + case ($ord_chrs_c & 0xFE) == 0xFC: + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $i, 6); + $i += 5; + break; + } + } + + return $utf8; + } + + /** + * Convert a string from one UTF-16 char to one UTF-8 char. + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * This method is from the Solar Framework by Paul M. Jones + * + * @link http://solarphp.com + * @param string $utf16 UTF-16 character + * @return string UTF-8 character + */ + protected static function _utf162utf8($utf16) + { + // Check for mb extension otherwise do by hand. + if( function_exists('mb_convert_encoding') ) { + return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); + } + + $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); + + switch (true) { + case ((0x7F & $bytes) == $bytes): + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x7F & $bytes); + + case (0x07FF & $bytes) == $bytes: + // return a 2-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xC0 | (($bytes >> 6) & 0x1F)) + . chr(0x80 | ($bytes & 0x3F)); + + case (0xFFFF & $bytes) == $bytes: + // return a 3-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xE0 | (($bytes >> 12) & 0x0F)) + . chr(0x80 | (($bytes >> 6) & 0x3F)) + . chr(0x80 | ($bytes & 0x3F)); + } + + // ignoring UTF-32 for now, sorry + return ''; + } +} +
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json/Encoder.php
Added
@@ -0,0 +1,578 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * Encode PHP constructs to JSON + * + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Json_Encoder +{ + /** + * Whether or not to check for possible cycling + * + * @var boolean + */ + protected $_cycleCheck; + + /** + * Additional options used during encoding + * + * @var array + */ + protected $_options = array(); + + /** + * Array of visited objects; used to prevent cycling. + * + * @var array + */ + protected $_visited = array(); + + /** + * Constructor + * + * @param boolean $cycleCheck Whether or not to check for recursion when encoding + * @param array $options Additional options used during encoding + * @return void + */ + protected function __construct($cycleCheck = false, $options = array()) + { + $this->_cycleCheck = $cycleCheck; + $this->_options = $options; + } + + /** + * Use the JSON encoding scheme for the value specified + * + * @param mixed $value The value to be encoded + * @param boolean $cycleCheck Whether or not to check for possible object recursion when encoding + * @param array $options Additional options used during encoding + * @return string The encoded value + */ + public static function encode($value, $cycleCheck = false, $options = array()) + { + $encoder = new self(($cycleCheck) ? true : false, $options); + return $encoder->_encodeValue($value); + } + + /** + * Recursive driver which determines the type of value to be encoded + * and then dispatches to the appropriate method. $values are either + * - objects (returns from {@link _encodeObject()}) + * - arrays (returns from {@link _encodeArray()}) + * - basic datums (e.g. numbers or strings) (returns from {@link _encodeDatum()}) + * + * @param mixed $value The value to be encoded + * @return string Encoded value + */ + protected function _encodeValue(&$value) + { + if (is_object($value)) { + return $this->_encodeObject($value); + } else if (is_array($value)) { + return $this->_encodeArray($value); + } + + return $this->_encodeDatum($value); + } + + + + /** + * Encode an object to JSON by encoding each of the public properties + * + * A special property is added to the JSON object called '__className' + * that contains the name of the class of $value. This is used to decode + * the object on the client into a specific class. + * + * @param object $value + * @return string + * @throws Zend_Json_Exception If recursive checks are enabled and the object has been serialized previously + */ + protected function _encodeObject(&$value) + { + if ($this->_cycleCheck) { + if ($this->_wasVisited($value)) { + + if (isset($this->_options['silenceCyclicalExceptions']) + && $this->_options['silenceCyclicalExceptions']===true) { + + return '"* RECURSION (' . get_class($value) . ') *"'; + + } else { + // require_once 'Zend/Json/Exception.php'; + throw new Zend_Json_Exception( + 'Cycles not supported in JSON encoding, cycle introduced by ' + . 'class "' . get_class($value) . '"' + ); + } + } + + $this->_visited[] = $value; + } + + $props = ''; + if (method_exists($value, 'toJson')) { + $props =',' . preg_replace("/^\{(.*)\}$/","\\1",$value->toJson()); + } else { + if ($value instanceof IteratorAggregate) { + $propCollection = $value->getIterator(); + } elseif ($value instanceof Iterator) { + $propCollection = $value; + } else { + $propCollection = get_object_vars($value); + } + + foreach ($propCollection as $name => $propValue) { + if (isset($propValue)) { + $props .= ',' + . $this->_encodeString($name) + . ':' + . $this->_encodeValue($propValue); + } + } + } + $className = get_class($value); + return '{"__className":' . $this->_encodeString($className) + . $props . '}'; + } + + + /** + * Determine if an object has been serialized already + * + * @param mixed $value + * @return boolean + */ + protected function _wasVisited(&$value) + { + if (in_array($value, $this->_visited, true)) { + return true; + } + + return false; + } + + + /** + * JSON encode an array value + * + * Recursively encodes each value of an array and returns a JSON encoded + * array string. + * + * Arrays are defined as integer-indexed arrays starting at index 0, where + * the last index is (count($array) -1); any deviation from that is + * considered an associative array, and will be encoded as such. + * + * @param array& $array + * @return string + */ + protected function _encodeArray(&$array) + { + $tmpArray = array(); + + // Check for associative array + if (!empty($array) && (array_keys($array) !== range(0, count($array) - 1))) { + // Associative array + $result = '{'; + foreach ($array as $key => $value) { + $key = (string) $key; + $tmpArray[] = $this->_encodeString($key) + . ':' + . $this->_encodeValue($value); + } + $result .= implode(',', $tmpArray); + $result .= '}'; + } else { + // Indexed array + $result = '['; + $length = count($array); + for ($i = 0; $i < $length; $i++) { + $tmpArray[] = $this->_encodeValue($array[$i]); + } + $result .= implode(',', $tmpArray); + $result .= ']'; + } + + return $result; + } + + + /** + * JSON encode a basic data type (string, number, boolean, null) + * + * If value type is not a string, number, boolean, or null, the string + * 'null' is returned. + * + * @param mixed& $value + * @return string + */ + protected function _encodeDatum(&$value) + { + $result = 'null'; + + if (is_int($value) || is_float($value)) { + $result = (string) $value; + $result = str_replace(",", ".", $result); + } elseif (is_string($value)) { + $result = $this->_encodeString($value); + } elseif (is_bool($value)) { + $result = $value ? 'true' : 'false'; + } + + return $result; + } + + + /** + * JSON encode a string value by escaping characters as necessary + * + * @param string& $value + * @return string + */ + protected function _encodeString(&$string) + { + // Escape these characters with a backslash: + // " \ / \n \r \t \b \f + $search = array('\\', "\n", "\t", "\r", "\b", "\f", '"', '/'); + $replace = array('\\\\', '\\n', '\\t', '\\r', '\\b', '\\f', '\"', '\\/'); + $string = str_replace($search, $replace, $string); + + // Escape certain ASCII characters: + // 0x08 => \b + // 0x0c => \f + $string = str_replace(array(chr(0x08), chr(0x0C)), array('\b', '\f'), $string); + $string = self::encodeUnicodeString($string); + + return '"' . $string . '"'; + } + + + /** + * Encode the constants associated with the ReflectionClass + * parameter. The encoding format is based on the class2 format + * + * @param ReflectionClass $cls + * @return string Encoded constant block in class2 format + */ + private static function _encodeConstants(ReflectionClass $cls) + { + $result = "constants : {"; + $constants = $cls->getConstants(); + + $tmpArray = array(); + if (!empty($constants)) { + foreach ($constants as $key => $value) { + $tmpArray[] = "$key: " . self::encode($value); + } + + $result .= implode(', ', $tmpArray); + } + + return $result . "}"; + } + + + /** + * Encode the public methods of the ReflectionClass in the + * class2 format + * + * @param ReflectionClass $cls + * @return string Encoded method fragment + * + */ + private static function _encodeMethods(ReflectionClass $cls) + { + $methods = $cls->getMethods(); + $result = 'methods:{'; + + $started = false; + foreach ($methods as $method) { + if (! $method->isPublic() || !$method->isUserDefined()) { + continue; + } + + if ($started) { + $result .= ','; + } + $started = true; + + $result .= '' . $method->getName(). ':function('; + + if ('__construct' != $method->getName()) { + $parameters = $method->getParameters(); + $paramCount = count($parameters); + $argsStarted = false; + + $argNames = "var argNames=["; + foreach ($parameters as $param) { + if ($argsStarted) { + $result .= ','; + } + + $result .= $param->getName(); + + if ($argsStarted) { + $argNames .= ','; + } + + $argNames .= '"' . $param->getName() . '"'; + + $argsStarted = true; + } + $argNames .= "];"; + + $result .= "){" + . $argNames + . 'var result = ZAjaxEngine.invokeRemoteMethod(' + . "this, '" . $method->getName() + . "',argNames,arguments);" + . 'return(result);}'; + } else { + $result .= "){}"; + } + } + + return $result . "}"; + } + + + /** + * Encode the public properties of the ReflectionClass in the class2 + * format. + * + * @param ReflectionClass $cls + * @return string Encode properties list + * + */ + private static function _encodeVariables(ReflectionClass $cls) + { + $properties = $cls->getProperties(); + $propValues = get_class_vars($cls->getName()); + $result = "variables:{"; + $cnt = 0; + + $tmpArray = array(); + foreach ($properties as $prop) { + if (! $prop->isPublic()) { + continue; + } + + $tmpArray[] = $prop->getName() + . ':' + . self::encode($propValues[$prop->getName()]); + } + $result .= implode(',', $tmpArray); + + return $result . "}"; + } + + /** + * Encodes the given $className into the class2 model of encoding PHP + * classes into JavaScript class2 classes. + * NOTE: Currently only public methods and variables are proxied onto + * the client machine + * + * @param string $className The name of the class, the class must be + * instantiable using a null constructor + * @param string $package Optional package name appended to JavaScript + * proxy class name + * @return string The class2 (JavaScript) encoding of the class + * @throws Zend_Json_Exception + */ + public static function encodeClass($className, $package = '') + { + $cls = new ReflectionClass($className); + if (! $cls->isInstantiable()) { + // require_once 'Zend/Json/Exception.php'; + throw new Zend_Json_Exception("$className must be instantiable"); + } + + return "Class.create('$package$className',{" + . self::_encodeConstants($cls) ."," + . self::_encodeMethods($cls) ."," + . self::_encodeVariables($cls) .'});'; + } + + + /** + * Encode several classes at once + * + * Returns JSON encoded classes, using {@link encodeClass()}. + * + * @param array $classNames + * @param string $package + * @return string + */ + public static function encodeClasses(array $classNames, $package = '') + { + $result = ''; + foreach ($classNames as $className) { + $result .= self::encodeClass($className, $package); + } + + return $result; + } + + /** + * Encode Unicode Characters to \u0000 ASCII syntax. + * + * This algorithm was originally developed for the + * Solar Framework by Paul M. Jones + * + * @link http://solarphp.com/ + * @link http://svn.solarphp.com/core/trunk/Solar/Json.php + * @param string $value + * @return string + */ + public static function encodeUnicodeString($value) + { + $strlen_var = strlen($value); + $ascii = ""; + + /** + * Iterate over every character in the string, + * escaping with a slash or encoding to UTF-8 where necessary + */ + for($i = 0; $i < $strlen_var; $i++) { + $ord_var_c = ord($value[$i]); + + switch (true) { + case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): + // characters U-00000000 - U-0000007F (same as ASCII) + $ascii .= $value[$i]; + break; + + case (($ord_var_c & 0xE0) == 0xC0): + // characters U-00000080 - U-000007FF, mask 110XXXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, ord($value[$i + 1])); + $i += 1; + $utf16 = self::_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($value[$i + 1]), + ord($value[$i + 2])); + $i += 2; + $utf16 = self::_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($value[$i + 1]), + ord($value[$i + 2]), + ord($value[$i + 3])); + $i += 3; + $utf16 = self::_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFC) == 0xF8): + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($value[$i + 1]), + ord($value[$i + 2]), + ord($value[$i + 3]), + ord($value[$i + 4])); + $i += 4; + $utf16 = self::_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($value[$i + 1]), + ord($value[$i + 2]), + ord($value[$i + 3]), + ord($value[$i + 4]), + ord($value[$i + 5])); + $i += 5; + $utf16 = self::_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + } + } + + return $ascii; + } + + /** + * Convert a string from one UTF-8 char to one UTF-16 char. + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * This method is from the Solar Framework by Paul M. Jones + * + * @link http://solarphp.com + * @param string $utf8 UTF-8 character + * @return string UTF-16 character + */ + protected static function _utf82utf16($utf8) + { + // Check for mb extension otherwise do by hand. + if( function_exists('mb_convert_encoding') ) { + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + } + + switch (strlen($utf8)) { + case 1: + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return $utf8; + + case 2: + // return a UTF-16 character from a 2-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x07 & (ord($utf8{0}) >> 2)) + . chr((0xC0 & (ord($utf8{0}) << 6)) + | (0x3F & ord($utf8{1}))); + + case 3: + // return a UTF-16 character from a 3-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr((0xF0 & (ord($utf8{0}) << 4)) + | (0x0F & (ord($utf8{1}) >> 2))) + . chr((0xC0 & (ord($utf8{1}) << 6)) + | (0x7F & ord($utf8{2}))); + } + + // ignoring UTF-32 for now, sorry + return ''; + } +} +
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json/Exception.php
Added
@@ -0,0 +1,37 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + + +/** + * Zend_Exception + */ +// require_once 'Zend/Exception.php'; + + +/** + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Json_Exception extends Zend_Exception +{} +
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json/Expr.php
Added
@@ -0,0 +1,80 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Json + * @subpackage Expr + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * Class for Zend_Json encode method. + * + * This class simply holds a string with a native Javascript Expression, + * so objects | arrays to be encoded with Zend_Json can contain native + * Javascript Expressions. + * + * Example: + * <code> + * $foo = array( + * 'integer' =>9, + * 'string' =>'test string', + * 'function' => Zend_Json_Expr( + * 'function(){ window.alert("javascript function encoded by Zend_Json") }' + * ), + * ); + * + * Zend_Json::encode($foo, false, array('enableJsonExprFinder' => true)); + * // it will returns json encoded string: + * // {"integer":9,"string":"test string","function":function(){window.alert("javascript function encoded by Zend_Json")}} + * </code> + * + * @category Zend + * @package Zend_Json + * @subpackage Expr + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Json_Expr +{ + /** + * Storage for javascript expression. + * + * @var string + */ + protected $_expression; + + /** + * Constructor + * + * @param string $expression the expression to hold. + * @return void + */ + public function __construct($expression) + { + $this->_expression = (string) $expression; + } + + /** + * Cast to string + * + * @return string holded javascript expression. + */ + public function __toString() + { + return $this->_expression; + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json/Server
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json/Server.php
Added
@@ -0,0 +1,568 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * @see Zend_Server_Abstract + */ +// require_once 'Zend/Server/Abstract.php'; + +/** + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Json_Server extends Zend_Server_Abstract +{ + /**#@+ + * Version Constants + */ + const VERSION_1 = '1.0'; + const VERSION_2 = '2.0'; + /**#@-*/ + + /** + * Flag: whether or not to auto-emit the response + * @var bool + */ + protected $_autoEmitResponse = true; + + /** + * @var bool Flag; allow overwriting existing methods when creating server definition + */ + protected $_overwriteExistingMethods = true; + + /** + * Request object + * @var Zend_Json_Server_Request + */ + protected $_request; + + /** + * Response object + * @var Zend_Json_Server_Response + */ + protected $_response; + + /** + * SMD object + * @var Zend_Json_Server_Smd + */ + protected $_serviceMap; + + /** + * SMD class accessors + * @var array + */ + protected $_smdMethods; + + /** + * @var Zend_Server_Description + */ + protected $_table; + + /** + * Attach a function or callback to the server + * + * @param string|array $function Valid PHP callback + * @param string $namespace Ignored + * @return Zend_Json_Server + */ + public function addFunction($function, $namespace = '') + { + if (!is_string($function) && (!is_array($function) || (2 > count($function)))) { + // require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception('Unable to attach function; invalid'); + } + + if (!is_callable($function)) { + // require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception('Unable to attach function; does not exist'); + } + + $argv = null; + if (2 < func_num_args()) { + $argv = func_get_args(); + $argv = array_slice($argv, 2); + } + + // require_once 'Zend/Server/Reflection.php'; + if (is_string($function)) { + $method = Zend_Server_Reflection::reflectFunction($function, $argv, $namespace); + } else { + $class = array_shift($function); + $action = array_shift($function); + $reflection = Zend_Server_Reflection::reflectClass($class, $argv, $namespace); + $methods = $reflection->getMethods(); + $found = false; + foreach ($methods as $method) { + if ($action == $method->getName()) { + $found = true; + break; + } + } + if (!$found) { + $this->fault('Method not found', -32601); + return $this; + } + } + + $definition = $this->_buildSignature($method); + $this->_addMethodServiceMap($definition); + + return $this; + } + + /** + * Register a class with the server + * + * @param string $class + * @param string $namespace Ignored + * @param mixed $argv Ignored + * @return Zend_Json_Server + */ + public function setClass($class, $namespace = '', $argv = null) + { + $argv = null; + if (3 < func_num_args()) { + $argv = func_get_args(); + $argv = array_slice($argv, 3); + } + + // require_once 'Zend/Server/Reflection.php'; + $reflection = Zend_Server_Reflection::reflectClass($class, $argv, $namespace); + + foreach ($reflection->getMethods() as $method) { + $definition = $this->_buildSignature($method, $class); + $this->_addMethodServiceMap($definition); + } + return $this; + } + + /** + * Indicate fault response + * + * @param string $fault + * @param int $code + * @return false + */ + public function fault($fault = null, $code = 404, $data = null) + { + // require_once 'Zend/Json/Server/Error.php'; + $error = new Zend_Json_Server_Error($fault, $code, $data); + $this->getResponse()->setError($error); + return $error; + } + + /** + * Handle request + * + * @param Zend_Json_Server_Request $request + * @return null|Zend_Json_Server_Response + */ + public function handle($request = false) + { + if ((false !== $request) && (!$request instanceof Zend_Json_Server_Request)) { + // require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception('Invalid request type provided; cannot handle'); + } elseif ($request) { + $this->setRequest($request); + } + + // Handle request + $this->_handle(); + + // Get response + $response = $this->_getReadyResponse(); + + // Emit response? + if ($this->autoEmitResponse()) { + echo $response; + return; + } + + // or return it? + return $response; + } + + /** + * Load function definitions + * + * @param array|Zend_Server_Definition $definition + * @return void + */ + public function loadFunctions($definition) + { + if (!is_array($definition) && (!$definition instanceof Zend_Server_Definition)) { + // require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception('Invalid definition provided to loadFunctions()'); + } + + foreach ($definition as $key => $method) { + $this->_table->addMethod($method, $key); + $this->_addMethodServiceMap($method); + } + } + + public function setPersistence($mode) + { + } + + /** + * Set request object + * + * @param Zend_Json_Server_Request $request + * @return Zend_Json_Server + */ + public function setRequest(Zend_Json_Server_Request $request) + { + $this->_request = $request; + return $this; + } + + /** + * Get JSON-RPC request object + * + * @return Zend_Json_Server_Request + */ + public function getRequest() + { + if (null === ($request = $this->_request)) { + // require_once 'Zend/Json/Server/Request/Http.php'; + $this->setRequest(new Zend_Json_Server_Request_Http()); + } + return $this->_request; + } + + /** + * Set response object + * + * @param Zend_Json_Server_Response $response + * @return Zend_Json_Server + */ + public function setResponse(Zend_Json_Server_Response $response) + { + $this->_response = $response; + return $this; + } + + /** + * Get response object + * + * @return Zend_Json_Server_Response + */ + public function getResponse() + { + if (null === ($response = $this->_response)) { + // require_once 'Zend/Json/Server/Response/Http.php'; + $this->setResponse(new Zend_Json_Server_Response_Http()); + } + return $this->_response; + } + + /** + * Set flag indicating whether or not to auto-emit response + * + * @param bool $flag + * @return Zend_Json_Server + */ + public function setAutoEmitResponse($flag) + { + $this->_autoEmitResponse = (bool) $flag; + return $this; + } + + /** + * Will we auto-emit the response? + * + * @return bool + */ + public function autoEmitResponse() + { + return $this->_autoEmitResponse; + } + + // overloading for SMD metadata + /** + * Overload to accessors of SMD object + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + if (preg_match('/^(set|get)/', $method, $matches)) { + if (in_array($method, $this->_getSmdMethods())) { + if ('set' == $matches[1]) { + $value = array_shift($args); + $this->getServiceMap()->$method($value); + return $this; + } else { + return $this->getServiceMap()->$method(); + } + } + } + return null; + } + + /** + * Retrieve SMD object + * + * @return Zend_Json_Server_Smd + */ + public function getServiceMap() + { + if (null === $this->_serviceMap) { + // require_once 'Zend/Json/Server/Smd.php'; + $this->_serviceMap = new Zend_Json_Server_Smd(); + } + return $this->_serviceMap; + } + + /** + * Add service method to service map + * + * @param Zend_Server_Reflection_Function $method + * @return void + */ + protected function _addMethodServiceMap(Zend_Server_Method_Definition $method) + { + $serviceInfo = array( + 'name' => $method->getName(), + 'return' => $this->_getReturnType($method), + ); + $params = $this->_getParams($method); + $serviceInfo['params'] = $params; + $serviceMap = $this->getServiceMap(); + if (false !== $serviceMap->getService($serviceInfo['name'])) { + $serviceMap->removeService($serviceInfo['name']); + } + $serviceMap->addService($serviceInfo); + } + + /** + * Translate PHP type to JSON type + * + * @param string $type + * @return string + */ + protected function _fixType($type) + { + return $type; + } + + /** + * Get default params from signature + * + * @param array $args + * @param array $params + * @return array + */ + protected function _getDefaultParams(array $args, array $params) + { + $defaultParams = array_slice($params, count($args)); + foreach ($defaultParams as $param) { + $value = null; + if (array_key_exists('default', $param)) { + $value = $param['default']; + } + array_push($args, $value); + } + return $args; + } + + /** + * Get method param type + * + * @param Zend_Server_Reflection_Function_Abstract $method + * @return string|array + */ + protected function _getParams(Zend_Server_Method_Definition $method) + { + $params = array(); + foreach ($method->getPrototypes() as $prototype) { + foreach ($prototype->getParameterObjects() as $key => $parameter) { + if (!isset($params[$key])) { + $params[$key] = array( + 'type' => $parameter->getType(), + 'name' => $parameter->getName(), + 'optional' => $parameter->isOptional(), + ); + if (null !== ($default = $parameter->getDefaultValue())) { + $params[$key]['default'] = $default; + } + $description = $parameter->getDescription(); + if (!empty($description)) { + $params[$key]['description'] = $description; + } + continue; + } + $newType = $parameter->getType(); + if (!is_array($params[$key]['type'])) { + if ($params[$key]['type'] == $newType) { + continue; + } + $params[$key]['type'] = (array) $params[$key]['type']; + } elseif (in_array($newType, $params[$key]['type'])) { + continue; + } + array_push($params[$key]['type'], $parameter->getType()); + } + } + return $params; + } + + /** + * Set response state + * + * @return Zend_Json_Server_Response + */ + protected function _getReadyResponse() + { + $request = $this->getRequest(); + $response = $this->getResponse(); + + $response->setServiceMap($this->getServiceMap()); + if (null !== ($id = $request->getId())) { + $response->setId($id); + } + if (null !== ($version = $request->getVersion())) { + $response->setVersion($version); + } + + return $response; + } + + /** + * Get method return type + * + * @param Zend_Server_Reflection_Function_Abstract $method + * @return string|array + */ + protected function _getReturnType(Zend_Server_Method_Definition $method) + { + $return = array(); + foreach ($method->getPrototypes() as $prototype) { + $return[] = $prototype->getReturnType(); + } + if (1 == count($return)) { + return $return[0]; + } + return $return; + } + + /** + * Retrieve list of allowed SMD methods for proxying + * + * @return array + */ + protected function _getSmdMethods() + { + if (null === $this->_smdMethods) { + $this->_smdMethods = array(); + // require_once 'Zend/Json/Server/Smd.php'; + $methods = get_class_methods('Zend_Json_Server_Smd'); + foreach ($methods as $key => $method) { + if (!preg_match('/^(set|get)/', $method)) { + continue; + } + if (strstr($method, 'Service')) { + continue; + } + $this->_smdMethods[] = $method; + } + } + return $this->_smdMethods; + } + + /** + * Internal method for handling request + * + * @return void + */ + protected function _handle() + { + $request = $this->getRequest(); + + if (!$request->isMethodError() && (null === $request->getMethod())) { + return $this->fault('Invalid Request', -32600); + } + + if ($request->isMethodError()) { + return $this->fault('Invalid Request', -32600); + } + + $method = $request->getMethod(); + if (!$this->_table->hasMethod($method)) { + return $this->fault('Method not found', -32601); + } + + $params = $request->getParams(); + $invocable = $this->_table->getMethod($method); + $serviceMap = $this->getServiceMap(); + $service = $serviceMap->getService($method); + $serviceParams = $service->getParams(); + + if (count($params) < count($serviceParams)) { + $params = $this->_getDefaultParams($params, $serviceParams); + } + + //Make sure named parameters are passed in correct order + if ( is_string( key( $params ) ) ) { + + $callback = $invocable->getCallback(); + if ('function' == $callback->getType()) { + $reflection = new ReflectionFunction( $callback->getFunction() ); + $refParams = $reflection->getParameters(); + } else { + + $reflection = new ReflectionMethod( + $callback->getClass(), + $callback->getMethod() + ); + $refParams = $reflection->getParameters(); + } + + $orderedParams = array(); + foreach( $reflection->getParameters() as $refParam ) { + if( isset( $params[ $refParam->getName() ] ) ) { + $orderedParams[ $refParam->getName() ] = $params[ $refParam->getName() ]; + } elseif( $refParam->isOptional() ) { + $orderedParams[ $refParam->getName() ] = $refParam->getDefaultValue(); + } else { + throw new Zend_Server_Exception( + 'Method ' . $request->getMethod() . ' is missing required parameter: ' . $refParam->getName() + ); + } + } + $params = $orderedParams; + } + + try { + $result = $this->_dispatch($invocable, $params); + } catch (Exception $e) { + return $this->fault($e->getMessage(), $e->getCode(), $e); + } + + $this->getResponse()->setResult($result); + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json/Server/Cache.php
Added
@@ -0,0 +1,102 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Json + * @subpackage Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** Zend_Server_Cache */ +// require_once 'Zend/Server/Cache.php'; + +/** + * Zend_Json_Server_Cache: cache Zend_Json_Server server definition and SMD + * + * @category Zend + * @package Zend_Json + * @subpackage Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Json_Server_Cache extends Zend_Server_Cache +{ + /** + * Cache a service map description (SMD) to a file + * + * Returns true on success, false on failure + * + * @param string $filename + * @param Zend_Json_Server $server + * @return boolean + */ + public static function saveSmd($filename, Zend_Json_Server $server) + { + if (!is_string($filename) + || (!file_exists($filename) && !is_writable(dirname($filename)))) + { + return false; + } + + if (0 === @file_put_contents($filename, $server->getServiceMap()->toJson())) { + return false; + } + + return true; + } + + /** + * Retrieve a cached SMD + * + * On success, returns the cached SMD (a JSON string); an failure, returns + * boolean false. + * + * @param string $filename + * @return string|false + */ + public static function getSmd($filename) + { + if (!is_string($filename) + || !file_exists($filename) + || !is_readable($filename)) + { + return false; + } + + + if (false === ($smd = @file_get_contents($filename))) { + return false; + } + + return $smd; + } + + /** + * Delete a file containing a cached SMD + * + * @param string $filename + * @return bool + */ + public static function deleteSmd($filename) + { + if (is_string($filename) && file_exists($filename)) { + unlink($filename); + return true; + } + + return false; + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json/Server/Error.php
Added
@@ -0,0 +1,198 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Json_Server_Error +{ + const ERROR_PARSE = -32768; + const ERROR_INVALID_REQUEST = -32600; + const ERROR_INVALID_METHOD = -32601; + const ERROR_INVALID_PARAMS = -32602; + const ERROR_INTERNAL = -32603; + const ERROR_OTHER = -32000; + + /** + * Allowed error codes + * @var array + */ + protected $_allowedCodes = array( + self::ERROR_PARSE, + self::ERROR_INVALID_REQUEST, + self::ERROR_INVALID_METHOD, + self::ERROR_INVALID_PARAMS, + self::ERROR_INTERNAL, + self::ERROR_OTHER, + ); + + /** + * Current code + * @var int + */ + protected $_code = -32000; + + /** + * Error data + * @var mixed + */ + protected $_data; + + /** + * Error message + * @var string + */ + protected $_message; + + /** + * Constructor + * + * @param string $message + * @param int $code + * @param mixed $data + * @return void + */ + public function __construct($message = null, $code = -32000, $data = null) + { + $this->setMessage($message) + ->setCode($code) + ->setData($data); + } + + /** + * Set error code + * + * @param int $code + * @return Zend_Json_Server_Error + */ + public function setCode($code) + { + if (!is_scalar($code)) { + return $this; + } + + $code = (int) $code; + if (in_array($code, $this->_allowedCodes)) { + $this->_code = $code; + } elseif (in_array($code, range(-32099, -32000))) { + $this->_code = $code; + } + + return $this; + } + + /** + * Get error code + * + * @return int|null + */ + public function getCode() + { + return $this->_code; + } + + /** + * Set error message + * + * @param string $message + * @return Zend_Json_Server_Error + */ + public function setMessage($message) + { + if (!is_scalar($message)) { + return $this; + } + + $this->_message = (string) $message; + return $this; + } + + /** + * Get error message + * + * @return string + */ + public function getMessage() + { + return $this->_message; + } + + /** + * Set error data + * + * @param mixed $data + * @return Zend_Json_Server_Error + */ + public function setData($data) + { + $this->_data = $data; + return $this; + } + + /** + * Get error data + * + * @return mixed + */ + public function getData() + { + return $this->_data; + } + + /** + * Cast error to array + * + * @return array + */ + public function toArray() + { + return array( + 'code' => $this->getCode(), + 'message' => $this->getMessage(), + 'data' => $this->getData(), + ); + } + + /** + * Cast error to JSON + * + * @return string + */ + public function toJson() + { + // require_once 'Zend/Json.php'; + return Zend_Json::encode($this->toArray()); + } + + /** + * Cast to string (JSON) + * + * @return string + */ + public function __toString() + { + return $this->toJson(); + } +} +
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json/Server/Exception.php
Added
@@ -0,0 +1,36 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** Zend_Json_Exception */ +// require_once 'Zend/Json/Exception.php'; + +/** + * Zend_Json_Server exceptions + * + * @uses Zend_Json_Exception + * @package Zend_Json + * @subpackage Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Json_Server_Exception extends Zend_Json_Exception +{ +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json/Server/Request
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json/Server/Request.php
Added
@@ -0,0 +1,289 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Json + * @subpackage Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * @category Zend + * @package Zend_Json + * @subpackage Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Json_Server_Request +{ + /** + * Request ID + * @var mixed + */ + protected $_id; + + /** + * Flag + * @var bool + */ + protected $_isMethodError = false; + + /** + * Requested method + * @var string + */ + protected $_method; + + /** + * Regex for method + * @var string + */ + protected $_methodRegex = '/^[a-z][a-z0-9_.]*$/i'; + + /** + * Request parameters + * @var array + */ + protected $_params = array(); + + /** + * JSON-RPC version of request + * @var string + */ + protected $_version = '1.0'; + + /** + * Set request state + * + * @param array $options + * @return Zend_Json_Server_Request + */ + public function setOptions(array $options) + { + $methods = get_class_methods($this); + foreach ($options as $key => $value) { + $method = 'set' . ucfirst($key); + if (in_array($method, $methods)) { + $this->$method($value); + } elseif ($key == 'jsonrpc') { + $this->setVersion($value); + } + } + return $this; + } + + /** + * Add a parameter to the request + * + * @param mixed $value + * @param string $key + * @return Zend_Json_Server_Request + */ + public function addParam($value, $key = null) + { + if ((null === $key) || !is_string($key)) { + $index = count($this->_params); + $this->_params[$index] = $value; + } else { + $this->_params[$key] = $value; + } + + return $this; + } + + /** + * Add many params + * + * @param array $params + * @return Zend_Json_Server_Request + */ + public function addParams(array $params) + { + foreach ($params as $key => $value) { + $this->addParam($value, $key); + } + return $this; + } + + /** + * Overwrite params + * + * @param array $params + * @return Zend_Json_Server_Request + */ + public function setParams(array $params) + { + $this->_params = array(); + return $this->addParams($params); + } + + /** + * Retrieve param by index or key + * + * @param int|string $index + * @return mixed|null Null when not found + */ + public function getParam($index) + { + if (array_key_exists($index, $this->_params)) { + return $this->_params[$index]; + } + + return null; + } + + /** + * Retrieve parameters + * + * @return array + */ + public function getParams() + { + return $this->_params; + } + + /** + * Set request method + * + * @param string $name + * @return Zend_Json_Server_Request + */ + public function setMethod($name) + { + if (!preg_match($this->_methodRegex, $name)) { + $this->_isMethodError = true; + } else { + $this->_method = $name; + } + return $this; + } + + /** + * Get request method name + * + * @return string + */ + public function getMethod() + { + return $this->_method; + } + + /** + * Was a bad method provided? + * + * @return bool + */ + public function isMethodError() + { + return $this->_isMethodError; + } + + /** + * Set request identifier + * + * @param mixed $name + * @return Zend_Json_Server_Request + */ + public function setId($name) + { + $this->_id = (string) $name; + return $this; + } + + /** + * Retrieve request identifier + * + * @return mixed + */ + public function getId() + { + return $this->_id; + } + + /** + * Set JSON-RPC version + * + * @param string $version + * @return Zend_Json_Server_Request + */ + public function setVersion($version) + { + if ('2.0' == $version) { + $this->_version = '2.0'; + } else { + $this->_version = '1.0'; + } + return $this; + } + + /** + * Retrieve JSON-RPC version + * + * @return string + */ + public function getVersion() + { + return $this->_version; + } + + /** + * Set request state based on JSON + * + * @param string $json + * @return void + */ + public function loadJson($json) + { + // require_once 'Zend/Json.php'; + $options = Zend_Json::decode($json); + $this->setOptions($options); + } + + /** + * Cast request to JSON + * + * @return string + */ + public function toJson() + { + $jsonArray = array( + 'method' => $this->getMethod() + ); + if (null !== ($id = $this->getId())) { + $jsonArray['id'] = $id; + } + $params = $this->getParams(); + if (!empty($params)) { + $jsonArray['params'] = $params; + } + if ('2.0' == $this->getVersion()) { + $jsonArray['jsonrpc'] = '2.0'; + } + + // require_once 'Zend/Json.php'; + return Zend_Json::encode($jsonArray); + } + + /** + * Cast request to string (JSON) + * + * @return string + */ + public function __toString() + { + return $this->toJson(); + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json/Server/Request/Http.php
Added
@@ -0,0 +1,66 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * @see Zend_Json_Server_Request + */ +// require_once 'Zend/Json/Server/Request.php'; + +/** + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Json_Server_Request_Http extends Zend_Json_Server_Request +{ + /** + * Raw JSON pulled from POST body + * @var string + */ + protected $_rawJson; + + /** + * Constructor + * + * Pull JSON request from raw POST body and use to populate request. + * + * @return void + */ + public function __construct() + { + $json = file_get_contents('php://input'); + $this->_rawJson = $json; + if (!empty($json)) { + $this->loadJson($json); + } + } + + /** + * Get JSON from raw POST body + * + * @return string + */ + public function getRawJson() + { + return $this->_rawJson; + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json/Server/Response
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json/Server/Response.php
Added
@@ -0,0 +1,249 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Json + * @subpackage Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * @category Zend + * @package Zend_Json + * @subpackage Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Json_Server_Response +{ + /** + * Response error + * @var null|Zend_Json_Server_Error + */ + protected $_error; + + /** + * Request ID + * @var mixed + */ + protected $_id; + + /** + * Result + * @var mixed + */ + protected $_result; + + /** + * Service map + * @var Zend_Json_Server_Smd + */ + protected $_serviceMap; + + /** + * JSON-RPC version + * @var string + */ + protected $_version; + + /** + * Set result + * + * @param mixed $value + * @return Zend_Json_Server_Response + */ + public function setResult($value) + { + $this->_result = $value; + return $this; + } + + /** + * Get result + * + * @return mixed + */ + public function getResult() + { + return $this->_result; + } + + // RPC error, if response results in fault + /** + * Set result error + * + * @param Zend_Json_Server_Error $error + * @return Zend_Json_Server_Response + */ + public function setError(Zend_Json_Server_Error $error) + { + $this->_error = $error; + return $this; + } + + /** + * Get response error + * + * @return null|Zend_Json_Server_Error + */ + public function getError() + { + return $this->_error; + } + + /** + * Is the response an error? + * + * @return bool + */ + public function isError() + { + return $this->getError() instanceof Zend_Json_Server_Error; + } + + /** + * Set request ID + * + * @param mixed $name + * @return Zend_Json_Server_Response + */ + public function setId($name) + { + $this->_id = $name; + return $this; + } + + /** + * Get request ID + * + * @return mixed + */ + public function getId() + { + return $this->_id; + } + + /** + * Set JSON-RPC version + * + * @param string $version + * @return Zend_Json_Server_Response + */ + public function setVersion($version) + { + $version = is_array($version) + ? implode(' ', $version) + : $version; + if ((string)$version == '2.0') { + $this->_version = '2.0'; + } else { + $this->_version = null; + } + return $this; + } + + /** + * Retrieve JSON-RPC version + * + * @return string + */ + public function getVersion() + { + return $this->_version; + } + + /** + * Cast to JSON + * + * @return string + */ + public function toJson() + { + if ($this->isError()) { + $response = array( + 'error' => $this->getError()->toArray(), + 'id' => $this->getId(), + ); + } else { + $response = array( + 'result' => $this->getResult(), + 'id' => $this->getId(), + ); + } + + if (null !== ($version = $this->getVersion())) { + $response['jsonrpc'] = $version; + } + + // require_once 'Zend/Json.php'; + return Zend_Json::encode($response); + } + + /** + * Retrieve args + * + * @return mixed + */ + public function getArgs() + { + return $this->_args; + } + + /** + * Set args + * + * @param mixed $args + * @return self + */ + public function setArgs($args) + { + $this->_args = $args; + return $this; + } + + /** + * Set service map object + * + * @param Zend_Json_Server_Smd $serviceMap + * @return Zend_Json_Server_Response + */ + public function setServiceMap($serviceMap) + { + $this->_serviceMap = $serviceMap; + return $this; + } + + /** + * Retrieve service map + * + * @return Zend_Json_Server_Smd|null + */ + public function getServiceMap() + { + return $this->_serviceMap; + } + + /** + * Cast to string (JSON) + * + * @return string + */ + public function __toString() + { + return $this->toJson(); + } +} +
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json/Server/Response/Http.php
Added
@@ -0,0 +1,81 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * @see Zend_Json_Server_Response + */ +// require_once 'Zend/Json/Server/Response.php'; + +/** + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Json_Server_Response_Http extends Zend_Json_Server_Response +{ + /** + * Emit JSON + * + * Send appropriate HTTP headers. If no Id, then return an empty string. + * + * @return string + */ + public function toJson() + { + $this->sendHeaders(); + if (!$this->isError() && null === $this->getId()) { + return ''; + } + + return parent::toJson(); + } + + /** + * Send headers + * + * If headers are already sent, do nothing. If null ID, send HTTP 204 + * header. Otherwise, send content type header based on content type of + * service map. + * + * @return void + */ + public function sendHeaders() + { + if (headers_sent()) { + return; + } + + if (!$this->isError() && (null === $this->getId())) { + header('HTTP/1.1 204 No Content'); + return; + } + + if (null === ($smd = $this->getServiceMap())) { + return; + } + + $contentType = $smd->getContentType(); + if (!empty($contentType)) { + header('Content-Type: ' . $contentType); + } + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json/Server/Smd
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json/Server/Smd.php
Added
@@ -0,0 +1,480 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Json + * @subpackage Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * @category Zend + * @package Zend_Json + * @subpackage Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Json_Server_Smd +{ + const ENV_JSONRPC_1 = 'JSON-RPC-1.0'; + const ENV_JSONRPC_2 = 'JSON-RPC-2.0'; + const SMD_VERSION = '2.0'; + + /** + * Content type + * @var string + */ + protected $_contentType = 'application/json'; + + /** + * Content type regex + * @var string + */ + protected $_contentTypeRegex = '#[a-z]+/[a-z][a-z-]+#i'; + + /** + * Service description + * @var string + */ + protected $_description; + + /** + * Generate Dojo-compatible SMD + * @var bool + */ + protected $_dojoCompatible = false; + + /** + * Current envelope + * @var string + */ + protected $_envelope = self::ENV_JSONRPC_1; + + /** + * Allowed envelope types + * @var array + */ + protected $_envelopeTypes = array( + self::ENV_JSONRPC_1, + self::ENV_JSONRPC_2, + ); + + /** + * Service id + * @var string + */ + protected $_id; + + /** + * Services offerred + * @var array + */ + protected $_services = array(); + + /** + * Service target + * @var string + */ + protected $_target; + + /** + * Global transport + * @var string + */ + protected $_transport = 'POST'; + + /** + * Allowed transport types + * @var array + */ + protected $_transportTypes = array('POST'); + + /** + * Set object state via options + * + * @param array $options + * @return Zend_Json_Server_Smd + */ + public function setOptions(array $options) + { + $methods = get_class_methods($this); + foreach ($options as $key => $value) { + $method = 'set' . ucfirst($key); + if (in_array($method, $methods)) { + $this->$method($value); + } + } + return $this; + } + + /** + * Set transport + * + * @param string $transport + * @return Zend_Json_Server_Smd + */ + public function setTransport($transport) + { + if (!in_array($transport, $this->_transportTypes)) { + // require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception(sprintf('Invalid transport "%s" specified', $transport)); + } + $this->_transport = $transport; + return $this; + } + + /** + * Get transport + * + * @return string + */ + public function getTransport() + { + return $this->_transport; + } + + /** + * Set envelope + * + * @param string $envelopeType + * @return Zend_Json_Server_Smd + */ + public function setEnvelope($envelopeType) + { + if (!in_array($envelopeType, $this->_envelopeTypes)) { + // require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception(sprintf('Invalid envelope type "%s"', $envelopeType)); + } + $this->_envelope = $envelopeType; + return $this; + } + + /** + * Retrieve envelope + * + * @return string + */ + public function getEnvelope() + { + return $this->_envelope; + } + + // Content-Type of response; default to application/json + /** + * Set content type + * + * @param string $type + * @return Zend_Json_Server_Smd + */ + public function setContentType($type) + { + if (!preg_match($this->_contentTypeRegex, $type)) { + // require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception(sprintf('Invalid content type "%s" specified', $type)); + } + $this->_contentType = $type; + return $this; + } + + /** + * Retrieve content type + * + * @return string + */ + public function getContentType() + { + return $this->_contentType; + } + + /** + * Set service target + * + * @param string $target + * @return Zend_Json_Server_Smd + */ + public function setTarget($target) + { + $this->_target = (string) $target; + return $this; + } + + /** + * Retrieve service target + * + * @return string + */ + public function getTarget() + { + return $this->_target; + } + + /** + * Set service ID + * + * @param string $Id + * @return Zend_Json_Server_Smd + */ + public function setId($id) + { + $this->_id = (string) $id; + return $this->_id; + } + + /** + * Get service id + * + * @return string + */ + public function getId() + { + return $this->_id; + } + + /** + * Set service description + * + * @param string $description + * @return Zend_Json_Server_Smd + */ + public function setDescription($description) + { + $this->_description = (string) $description; + return $this->_description; + } + + /** + * Get service description + * + * @return string + */ + public function getDescription() + { + return $this->_description; + } + + /** + * Indicate whether or not to generate Dojo-compatible SMD + * + * @param bool $flag + * @return Zend_Json_Server_Smd + */ + public function setDojoCompatible($flag) + { + $this->_dojoCompatible = (bool) $flag; + return $this; + } + + /** + * Is this a Dojo compatible SMD? + * + * @return bool + */ + public function isDojoCompatible() + { + return $this->_dojoCompatible; + } + + /** + * Add Service + * + * @param Zend_Json_Server_Smd_Service|array $service + * @return void + */ + public function addService($service) + { + // require_once 'Zend/Json/Server/Smd/Service.php'; + + if ($service instanceof Zend_Json_Server_Smd_Service) { + $name = $service->getName(); + } elseif (is_array($service)) { + $service = new Zend_Json_Server_Smd_Service($service); + $name = $service->getName(); + } else { + // require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception('Invalid service passed to addService()'); + } + + if (array_key_exists($name, $this->_services)) { + // require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception('Attempt to register a service already registered detected'); + } + $this->_services[$name] = $service; + return $this; + } + + /** + * Add many services + * + * @param array $services + * @return Zend_Json_Server_Smd + */ + public function addServices(array $services) + { + foreach ($services as $service) { + $this->addService($service); + } + return $this; + } + + /** + * Overwrite existing services with new ones + * + * @param array $services + * @return Zend_Json_Server_Smd + */ + public function setServices(array $services) + { + $this->_services = array(); + return $this->addServices($services); + } + + /** + * Get service object + * + * @param string $name + * @return false|Zend_Json_Server_Smd_Service + */ + public function getService($name) + { + if (array_key_exists($name, $this->_services)) { + return $this->_services[$name]; + } + return false; + } + + /** + * Return services + * + * @return array + */ + public function getServices() + { + return $this->_services; + } + + /** + * Remove service + * + * @param string $name + * @return boolean + */ + public function removeService($name) + { + if (array_key_exists($name, $this->_services)) { + unset($this->_services[$name]); + return true; + } + return false; + } + + /** + * Cast to array + * + * @return array + */ + public function toArray() + { + if ($this->isDojoCompatible()) { + return $this->toDojoArray(); + } + + $transport = $this->getTransport(); + $envelope = $this->getEnvelope(); + $contentType = $this->getContentType(); + $SMDVersion = self::SMD_VERSION; + $service = compact('transport', 'envelope', 'contentType', 'SMDVersion'); + + if (null !== ($target = $this->getTarget())) { + $service['target'] = $target; + } + if (null !== ($id = $this->getId())) { + $service['id'] = $id; + } + + $services = $this->getServices(); + if (!empty($services)) { + $service['services'] = array(); + foreach ($services as $name => $svc) { + $svc->setEnvelope($envelope); + $service['services'][$name] = $svc->toArray(); + } + $service['methods'] = $service['services']; + } + + return $service; + } + + /** + * Export to DOJO-compatible SMD array + * + * @return array + */ + public function toDojoArray() + { + $SMDVersion = '.1'; + $serviceType = 'JSON-RPC'; + $service = compact('SMDVersion', 'serviceType'); + + $target = $this->getTarget(); + + $services = $this->getServices(); + if (!empty($services)) { + $service['methods'] = array(); + foreach ($services as $name => $svc) { + $method = array( + 'name' => $name, + 'serviceURL' => $target, + ); + $params = array(); + foreach ($svc->getParams() as $param) { + $paramName = array_key_exists('name', $param) ? $param['name'] : $param['type']; + $params[] = array( + 'name' => $paramName, + 'type' => $param['type'], + ); + } + if (!empty($params)) { + $method['parameters'] = $params; + } + $service['methods'][] = $method; + } + } + + return $service; + } + + /** + * Cast to JSON + * + * @return string + */ + public function toJson() + { + // require_once 'Zend/Json.php'; + return Zend_Json::encode($this->toArray()); + } + + /** + * Cast to string (JSON) + * + * @return string + */ + public function __toString() + { + return $this->toJson(); + } +} +
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-json/library/Zend/Json/Server/Smd/Service.php
Added
@@ -0,0 +1,473 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @see Zend_Json_Server_Smd + */ +// require_once 'Zend/Json/Server/Smd.php'; + +/** + * Create Service Mapping Description for a method + * + * @package Zend_Json + * @subpackage Server + * @version $Id$ + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Json_Server_Smd_Service +{ + /**#@+ + * Service metadata + * @var string + */ + protected $_envelope = Zend_Json_Server_Smd::ENV_JSONRPC_1; + protected $_name; + protected $_return; + protected $_target; + protected $_transport = 'POST'; + /**#@-*/ + + /** + * Allowed envelope types + * @var array + */ + protected $_envelopeTypes = array( + Zend_Json_Server_Smd::ENV_JSONRPC_1, + Zend_Json_Server_Smd::ENV_JSONRPC_2, + ); + + /** + * Regex for names + * @var string + */ + protected $_nameRegex = '/^[a-z][a-z0-9._]+$/i'; + + /** + * Parameter option types + * @var array + */ + protected $_paramOptionTypes = array( + 'name' => 'is_string', + 'optional' => 'is_bool', + 'default' => null, + 'description' => 'is_string', + ); + + /** + * Service params + * @var array + */ + protected $_params = array(); + + /** + * Mapping of parameter types to JSON-RPC types + * @var array + */ + protected $_paramMap = array( + 'any' => 'any', + 'arr' => 'array', + 'array' => 'array', + 'assoc' => 'object', + 'bool' => 'boolean', + 'boolean' => 'boolean', + 'dbl' => 'float', + 'double' => 'float', + 'false' => 'boolean', + 'float' => 'float', + 'hash' => 'object', + 'integer' => 'integer', + 'int' => 'integer', + 'mixed' => 'any', + 'nil' => 'null', + 'null' => 'null', + 'object' => 'object', + 'string' => 'string', + 'str' => 'string', + 'struct' => 'object', + 'true' => 'boolean', + 'void' => 'null', + ); + + /** + * Allowed transport types + * @var array + */ + protected $_transportTypes = array( + 'POST', + ); + + /** + * Constructor + * + * @param string|array $spec + * @return void + * @throws Zend_Json_Server_Exception if no name provided + */ + public function __construct($spec) + { + if (is_string($spec)) { + $this->setName($spec); + } elseif (is_array($spec)) { + $this->setOptions($spec); + } + + if (null == $this->getName()) { + // require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception('SMD service description requires a name; none provided'); + } + } + + /** + * Set object state + * + * @param array $options + * @return Zend_Json_Server_Smd_Service + */ + public function setOptions(array $options) + { + $methods = get_class_methods($this); + foreach ($options as $key => $value) { + if ('options' == strtolower($key)) { + continue; + } + $method = 'set' . ucfirst($key); + if (in_array($method, $methods)) { + $this->$method($value); + } + } + return $this; + } + + /** + * Set service name + * + * @param string $name + * @return Zend_Json_Server_Smd_Service + * @throws Zend_Json_Server_Exception + */ + public function setName($name) + { + $name = (string) $name; + if (!preg_match($this->_nameRegex, $name)) { + // require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception(sprintf('Invalid name "%s" provided for service; must follow PHP method naming conventions', $name)); + } + $this->_name = $name; + return $this; + } + + /** + * Retrieve name + * + * @return string + */ + public function getName() + { + return $this->_name; + } + + /** + * Set Transport + * + * Currently limited to POST + * + * @param string $transport + * @return Zend_Json_Server_Smd_Service + */ + public function setTransport($transport) + { + if (!in_array($transport, $this->_transportTypes)) { + // require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception(sprintf('Invalid transport "%s"; please select one of (%s)', $transport, implode(', ', $this->_transportTypes))); + } + + $this->_transport = $transport; + return $this; + } + + /** + * Get transport + * + * @return string + */ + public function getTransport() + { + return $this->_transport; + } + + /** + * Set service target + * + * @param string $target + * @return Zend_Json_Server_Smd_Service + */ + public function setTarget($target) + { + $this->_target = (string) $target; + return $this; + } + + /** + * Get service target + * + * @return string + */ + public function getTarget() + { + return $this->_target; + } + + /** + * Set envelope type + * + * @param string $envelopeType + * @return Zend_Json_Server_Smd_Service + */ + public function setEnvelope($envelopeType) + { + if (!in_array($envelopeType, $this->_envelopeTypes)) { + // require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception(sprintf('Invalid envelope type "%s"; please specify one of (%s)', $envelopeType, implode(', ', $this->_envelopeTypes))); + } + + $this->_envelope = $envelopeType; + return $this; + } + + /** + * Get envelope type + * + * @return string + */ + public function getEnvelope() + { + return $this->_envelope; + } + + /** + * Add a parameter to the service + * + * @param string|array $type + * @param array $options + * @param int|null $order + * @return Zend_Json_Server_Smd_Service + */ + public function addParam($type, array $options = array(), $order = null) + { + if (is_string($type)) { + $type = $this->_validateParamType($type); + } elseif (is_array($type)) { + foreach ($type as $key => $paramType) { + $type[$key] = $this->_validateParamType($paramType); + } + } else { + // require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception('Invalid param type provided'); + } + + $paramOptions = array( + 'type' => $type, + ); + foreach ($options as $key => $value) { + if (in_array($key, array_keys($this->_paramOptionTypes))) { + if (null !== ($callback = $this->_paramOptionTypes[$key])) { + if (!$callback($value)) { + continue; + } + } + $paramOptions[$key] = $value; + } + } + + $this->_params[] = array( + 'param' => $paramOptions, + 'order' => $order, + ); + + return $this; + } + + /** + * Add params + * + * Each param should be an array, and should include the key 'type'. + * + * @param array $params + * @return Zend_Json_Server_Smd_Service + */ + public function addParams(array $params) + { + ksort($params); + foreach ($params as $options) { + if (!is_array($options)) { + continue; + } + if (!array_key_exists('type', $options)) { + continue; + } + $type = $options['type']; + $order = (array_key_exists('order', $options)) ? $options['order'] : null; + $this->addParam($type, $options, $order); + } + return $this; + } + + /** + * Overwrite all parameters + * + * @param array $params + * @return Zend_Json_Server_Smd_Service + */ + public function setParams(array $params) + { + $this->_params = array(); + return $this->addParams($params); + } + + /** + * Get all parameters + * + * Returns all params in specified order. + * + * @return array + */ + public function getParams() + { + $params = array(); + $index = 0; + foreach ($this->_params as $param) { + if (null === $param['order']) { + if (array_search($index, array_keys($params), true)) { + ++$index; + } + $params[$index] = $param['param']; + ++$index; + } else { + $params[$param['order']] = $param['param']; + } + } + ksort($params); + return $params; + } + + /** + * Set return type + * + * @param string|array $type + * @return Zend_Json_Server_Smd_Service + */ + public function setReturn($type) + { + if (is_string($type)) { + $type = $this->_validateParamType($type, true); + } elseif (is_array($type)) { + foreach ($type as $key => $returnType) { + $type[$key] = $this->_validateParamType($returnType, true); + } + } else { + // require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception('Invalid param type provided ("' . gettype($type) .'")'); + } + $this->_return = $type; + return $this; + } + + /** + * Get return type + * + * @return string|array + */ + public function getReturn() + { + return $this->_return; + } + + /** + * Cast service description to array + * + * @return array + */ + public function toArray() + { + $name = $this->getName(); + $envelope = $this->getEnvelope(); + $target = $this->getTarget(); + $transport = $this->getTransport(); + $parameters = $this->getParams(); + $returns = $this->getReturn(); + + if (empty($target)) { + return compact('envelope', 'transport', 'parameters', 'returns'); + } + + return $paramInfo = compact('envelope', 'target', 'transport', 'parameters', 'returns'); + } + + /** + * Return JSON encoding of service + * + * @return string + */ + public function toJson() + { + $service = array($this->getName() => $this->toArray()); + + // require_once 'Zend/Json.php'; + return Zend_Json::encode($service); + } + + /** + * Cast to string + * + * @return string + */ + public function __toString() + { + return $this->toJson(); + } + + /** + * Validate parameter type + * + * @param string $type + * @return true + * @throws Zend_Json_Server_Exception + */ + protected function _validateParamType($type, $isReturn = false) + { + if (!is_string($type)) { + // require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception('Invalid param type provided ("' . $type .'")'); + } + + if (!array_key_exists($type, $this->_paramMap)) { + $type = 'object'; + } + + $paramType = $this->_paramMap[$type]; + if (!$isReturn && ('null' == $paramType)) { + // require_once 'Zend/Json/Server/Exception.php'; + throw new Zend_Json_Server_Exception('Invalid param type provided ("' . $type . '")'); + } + + return $paramType; + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/LICENSE.txt
Added
@@ -0,0 +1,27 @@ +Copyright (c) 2005-2015, Zend Technologies USA, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of Zend Technologies USA, Inc. nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/README.md
Added
@@ -0,0 +1,22 @@ +Zend Framework 1 for Composer +============================= + +This package is a part of the Zend Framework 1. Each component was separated and put into its own composer package. Some modifications were made for improved [Composer](http://getcomposer.org/) integration. This package can also be found at [Packagist](http://packagist.org/packages/zf1). + +## Why? + +**Size!** Zend Framework is very large and contains a huge amount of files (over 72000 files in the main repository!). If you're only using a part of the framework, using the separated packages will greatly reduce the amount of files. This will make setup faster and easier on your disks. + +**Autoloading!** Explicit `require_once` calls in the source code has been commented out to rely on composer autoloading, this reduces the number of included files to a minimum. + +**Migration!** Zend Framework 2 has been around for a while now, and migrating all your projects takes a lot of time. Using these packages makes it easier to migrate each component separately. Also, some packages doesn't exist in zf2 (such as the zend-search-lucene), now you can continue using that package without requiring the entire framework. + +If you're using major parts of the framework, I would recommend checking out the [zendframework1 package](https://github.com/bombayworks/zendframework1), which contains the entire framework optimized for composer usage. + +## How to use + +Add `"zf1/zend-server": "~1.12"` to the require section of your composer.json, include the composer autoloader and you're good to go. + +## Broken dependencies? + +Dependencies have been set automatically based on the [requirements from the zend framework manual](http://framework.zend.com/manual/1.12/en/requirements.introduction.html), if you find any broken dependencies please submit an issue. \ No newline at end of file
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/composer.json
Added
@@ -0,0 +1,21 @@ +{ + "name": "zf1/zend-server", + "description": "Zend Framework 1 Server package", + "keywords": [ + "framework", + "zf1", + "zend", + "server" + ], + "homepage": "http://framework.zend.com/", + "license": "BSD-3-Clause", + "require": { + "php": ">=5.2.11", + "zf1/zend-exception": "self.version" + }, + "autoload": { + "psr-0": { + "Zend_Server": "library/" + } + } +} \ No newline at end of file
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Abstract.php
Added
@@ -0,0 +1,242 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** Zend_Server_Interface */ +// require_once 'Zend/Server/Interface.php'; + +/** + * Zend_Server_Definition + */ +// require_once 'Zend/Server/Definition.php'; + +/** + * Zend_Server_Method_Definition + */ +// require_once 'Zend/Server/Method/Definition.php'; + +/** + * Zend_Server_Method_Callback + */ +// require_once 'Zend/Server/Method/Callback.php'; + +/** + * Zend_Server_Method_Prototype + */ +// require_once 'Zend/Server/Method/Prototype.php'; + +/** + * Zend_Server_Method_Parameter + */ +// require_once 'Zend/Server/Method/Parameter.php'; + +/** + * Zend_Server_Abstract + * + * @category Zend + * @package Zend_Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +abstract class Zend_Server_Abstract implements Zend_Server_Interface +{ + /** + * @deprecated + * @var array List of PHP magic methods (lowercased) + */ + protected static $magic_methods = array( + '__call', + '__clone', + '__construct', + '__destruct', + '__get', + '__isset', + '__set', + '__set_state', + '__sleep', + '__tostring', + '__unset', + '__wakeup', + ); + + /** + * @var bool Flag; whether or not overwriting existing methods is allowed + */ + protected $_overwriteExistingMethods = false; + + /** + * @var Zend_Server_Definition + */ + protected $_table; + + /** + * Constructor + * + * Setup server description + * + * @return void + */ + public function __construct() + { + $this->_table = new Zend_Server_Definition(); + $this->_table->setOverwriteExistingMethods($this->_overwriteExistingMethods); + } + + /** + * Returns a list of registered methods + * + * Returns an array of method definitions. + * + * @return Zend_Server_Definition + */ + public function getFunctions() + { + return $this->_table; + } + + /** + * Lowercase a string + * + * Lowercase's a string by reference + * + * @deprecated + * @param string $string value + * @param string $key + * @return string Lower cased string + */ + public static function lowerCase(&$value, &$key) + { + trigger_error(__CLASS__ . '::' . __METHOD__ . '() is deprecated and will be removed in a future version', E_USER_NOTICE); + return $value = strtolower($value); + } + + /** + * Build callback for method signature + * + * @param Zend_Server_Reflection_Function_Abstract $reflection + * @return Zend_Server_Method_Callback + */ + protected function _buildCallback(Zend_Server_Reflection_Function_Abstract $reflection) + { + $callback = new Zend_Server_Method_Callback(); + if ($reflection instanceof Zend_Server_Reflection_Method) { + $callback->setType($reflection->isStatic() ? 'static' : 'instance') + ->setClass($reflection->getDeclaringClass()->getName()) + ->setMethod($reflection->getName()); + } elseif ($reflection instanceof Zend_Server_Reflection_Function) { + $callback->setType('function') + ->setFunction($reflection->getName()); + } + return $callback; + } + + /** + * Build a method signature + * + * @param Zend_Server_Reflection_Function_Abstract $reflection + * @param null|string|object $class + * @return Zend_Server_Method_Definition + * @throws Zend_Server_Exception on duplicate entry + */ + protected function _buildSignature(Zend_Server_Reflection_Function_Abstract $reflection, $class = null) + { + $ns = $reflection->getNamespace(); + $name = $reflection->getName(); + $method = empty($ns) ? $name : $ns . '.' . $name; + + if (!$this->_overwriteExistingMethods && $this->_table->hasMethod($method)) { + // require_once 'Zend/Server/Exception.php'; + throw new Zend_Server_Exception('Duplicate method registered: ' . $method); + } + + $definition = new Zend_Server_Method_Definition(); + $definition->setName($method) + ->setCallback($this->_buildCallback($reflection)) + ->setMethodHelp($reflection->getDescription()) + ->setInvokeArguments($reflection->getInvokeArguments()); + + foreach ($reflection->getPrototypes() as $proto) { + $prototype = new Zend_Server_Method_Prototype(); + $prototype->setReturnType($this->_fixType($proto->getReturnType())); + foreach ($proto->getParameters() as $parameter) { + $param = new Zend_Server_Method_Parameter(array( + 'type' => $this->_fixType($parameter->getType()), + 'name' => $parameter->getName(), + 'optional' => $parameter->isOptional(), + )); + if ($parameter->isDefaultValueAvailable()) { + $param->setDefaultValue($parameter->getDefaultValue()); + } + $prototype->addParameter($param); + } + $definition->addPrototype($prototype); + } + if (is_object($class)) { + $definition->setObject($class); + } + $this->_table->addMethod($definition); + return $definition; + } + + /** + * Dispatch method + * + * @param Zend_Server_Method_Definition $invocable + * @param array $params + * @return mixed + */ + protected function _dispatch(Zend_Server_Method_Definition $invocable, array $params) + { + $callback = $invocable->getCallback(); + $type = $callback->getType(); + + if ('function' == $type) { + $function = $callback->getFunction(); + return call_user_func_array($function, $params); + } + + $class = $callback->getClass(); + $method = $callback->getMethod(); + + if ('static' == $type) { + return call_user_func_array(array($class, $method), $params); + } + + $object = $invocable->getObject(); + if (!is_object($object)) { + $invokeArgs = $invocable->getInvokeArguments(); + if (!empty($invokeArgs)) { + $reflection = new ReflectionClass($class); + $object = $reflection->newInstanceArgs($invokeArgs); + } else { + $object = new $class; + } + } + return call_user_func_array(array($object, $method), $params); + } + + /** + * Map PHP type to protocol type + * + * @param string $type + * @return string + */ + abstract protected function _fixType($type); +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Cache.php
Added
@@ -0,0 +1,147 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * Zend_Server_Cache: cache server definitions + * + * @category Zend + * @package Zend_Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Server_Cache +{ + /** + * @var array Methods to skip when caching server + */ + protected static $_skipMethods = array(); + + /** + * Cache a file containing the dispatch list. + * + * Serializes the server definition stores the information + * in $filename. + * + * Returns false on any error (typically, inability to write to file), true + * on success. + * + * @param string $filename + * @param Zend_Server_Interface $server + * @return bool + */ + public static function save($filename, Zend_Server_Interface $server) + { + if (!is_string($filename) + || (!file_exists($filename) && !is_writable(dirname($filename)))) + { + return false; + } + + $methods = $server->getFunctions(); + + if ($methods instanceof Zend_Server_Definition) { + $definition = new Zend_Server_Definition(); + foreach ($methods as $method) { + if (in_array($method->getName(), self::$_skipMethods)) { + continue; + } + $definition->addMethod($method); + } + $methods = $definition; + } + + if (0 === @file_put_contents($filename, serialize($methods))) { + return false; + } + + return true; + } + + /** + * Load server definition from a file + * + * Unserializes a stored server definition from $filename. Returns false if + * it fails in any way, true on success. + * + * Useful to prevent needing to build the server definition on each + * request. Sample usage: + * + * <code> + * if (!Zend_Server_Cache::get($filename, $server)) { + * // require_once 'Some/Service/Class.php'; + * // require_once 'Another/Service/Class.php'; + * + * // Attach Some_Service_Class with namespace 'some' + * $server->attach('Some_Service_Class', 'some'); + * + * // Attach Another_Service_Class with namespace 'another' + * $server->attach('Another_Service_Class', 'another'); + * + * Zend_Server_Cache::save($filename, $server); + * } + * + * $response = $server->handle(); + * echo $response; + * </code> + * + * @param string $filename + * @param Zend_Server_Interface $server + * @return bool + */ + public static function get($filename, Zend_Server_Interface $server) + { + if (!is_string($filename) + || !file_exists($filename) + || !is_readable($filename)) + { + return false; + } + + + if (false === ($dispatch = @file_get_contents($filename))) { + return false; + } + + if (false === ($dispatchArray = @unserialize($dispatch))) { + return false; + } + + $server->loadFunctions($dispatchArray); + + return true; + } + + /** + * Remove a cache file + * + * @param string $filename + * @return boolean + */ + public static function delete($filename) + { + if (is_string($filename) && file_exists($filename)) { + unlink($filename); + return true; + } + + return false; + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Definition.php
Added
@@ -0,0 +1,267 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * Server methods metadata + * + * @todo Implement iterator + * @category Zend + * @package Zend_Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Server_Definition implements Countable, Iterator +{ + /** + * @var array Array of Zend_Server_Method_Definition objects + */ + protected $_methods = array(); + + /** + * @var bool Whether or not overwriting existing methods is allowed + */ + protected $_overwriteExistingMethods = false; + + /** + * Constructor + * + * @param null|array $methods + * @return void + */ + public function __construct($methods = null) + { + if (is_array($methods)) { + $this->setMethods($methods); + } + } + + /** + * Set flag indicating whether or not overwriting existing methods is allowed + * + * @param mixed $flag + * @return void + */ + public function setOverwriteExistingMethods($flag) + { + $this->_overwriteExistingMethods = (bool) $flag; + return $this; + } + + /** + * Add method to definition + * + * @param array|Zend_Server_Method_Definition $method + * @param null|string $name + * @return Zend_Server_Definition + * @throws Zend_Server_Exception if duplicate or invalid method provided + */ + public function addMethod($method, $name = null) + { + if (is_array($method)) { + // require_once 'Zend/Server/Method/Definition.php'; + $method = new Zend_Server_Method_Definition($method); + } elseif (!$method instanceof Zend_Server_Method_Definition) { + // require_once 'Zend/Server/Exception.php'; + throw new Zend_Server_Exception('Invalid method provided'); + } + + if (is_numeric($name)) { + $name = null; + } + if (null !== $name) { + $method->setName($name); + } else { + $name = $method->getName(); + } + if (null === $name) { + // require_once 'Zend/Server/Exception.php'; + throw new Zend_Server_Exception('No method name provided'); + } + + if (!$this->_overwriteExistingMethods && array_key_exists($name, $this->_methods)) { + // require_once 'Zend/Server/Exception.php'; + throw new Zend_Server_Exception(sprintf('Method by name of "%s" already exists', $name)); + } + $this->_methods[$name] = $method; + return $this; + } + + /** + * Add multiple methods + * + * @param array $methods Array of Zend_Server_Method_Definition objects or arrays + * @return Zend_Server_Definition + */ + public function addMethods(array $methods) + { + foreach ($methods as $key => $method) { + $this->addMethod($method, $key); + } + return $this; + } + + /** + * Set all methods at once (overwrite) + * + * @param array $methods Array of Zend_Server_Method_Definition objects or arrays + * @return Zend_Server_Definition + */ + public function setMethods(array $methods) + { + $this->clearMethods(); + $this->addMethods($methods); + return $this; + } + + /** + * Does the definition have the given method? + * + * @param string $method + * @return bool + */ + public function hasMethod($method) + { + return array_key_exists($method, $this->_methods); + } + + /** + * Get a given method definition + * + * @param string $method + * @return null|Zend_Server_Method_Definition + */ + public function getMethod($method) + { + if ($this->hasMethod($method)) { + return $this->_methods[$method]; + } + return false; + } + + /** + * Get all method definitions + * + * @return array Array of Zend_Server_Method_Definition objects + */ + public function getMethods() + { + return $this->_methods; + } + + /** + * Remove a method definition + * + * @param string $method + * @return Zend_Server_Definition + */ + public function removeMethod($method) + { + if ($this->hasMethod($method)) { + unset($this->_methods[$method]); + } + return $this; + } + + /** + * Clear all method definitions + * + * @return Zend_Server_Definition + */ + public function clearMethods() + { + $this->_methods = array(); + return $this; + } + + /** + * Cast definition to an array + * + * @return array + */ + public function toArray() + { + $methods = array(); + foreach ($this->getMethods() as $key => $method) { + $methods[$key] = $method->toArray(); + } + return $methods; + } + + /** + * Countable: count of methods + * + * @return int + */ + public function count() + { + return count($this->_methods); + } + + /** + * Iterator: current item + * + * @return mixed + */ + public function current() + { + return current($this->_methods); + } + + /** + * Iterator: current item key + * + * @return int|string + */ + public function key() + { + return key($this->_methods); + } + + /** + * Iterator: advance to next method + * + * @return void + */ + public function next() + { + return next($this->_methods); + } + + /** + * Iterator: return to first method + * + * @return void + */ + public function rewind() + { + return reset($this->_methods); + } + + /** + * Iterator: is the current index valid? + * + * @return bool + */ + public function valid() + { + return (bool) $this->current(); + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Exception.php
Added
@@ -0,0 +1,35 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * Zend_Exception + */ +// require_once 'Zend/Exception.php'; + +/** + * Zend_Server_Reflection exceptions + * + * @package Zend_Server + * @subpackage Reflection + * @version $Id$ + */ +class Zend_Server_Exception extends Zend_Exception +{ +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Interface.php
Added
@@ -0,0 +1,118 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * Zend_Server_Interface + * + * @category Zend + * @package Zend_Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +interface Zend_Server_Interface +{ + /** + * Attach a function as a server method + * + * Namespacing is primarily for xmlrpc, but may be used with other + * implementations to prevent naming collisions. + * + * @param string $function + * @param string $namespace + * @param null|array Optional array of arguments to pass to callbacks at + * dispatch. + * @return void + */ + public function addFunction($function, $namespace = ''); + + /** + * Attach a class to a server + * + * The individual implementations should probably allow passing a variable + * number of arguments in, so that developers may define custom runtime + * arguments to pass to server methods. + * + * Namespacing is primarily for xmlrpc, but could be used for other + * implementations as well. + * + * @param mixed $class Class name or object instance to examine and attach + * to the server. + * @param string $namespace Optional namespace with which to prepend method + * names in the dispatch table. + * methods in the class will be valid callbacks. + * @param null|array Optional array of arguments to pass to callbacks at + * dispatch. + * @return void + */ + public function setClass($class, $namespace = '', $argv = null); + + /** + * Generate a server fault + * + * @param mixed $fault + * @param int $code + * @return mixed + */ + public function fault($fault = null, $code = 404); + + /** + * Handle a request + * + * Requests may be passed in, or the server may automagically determine the + * request based on defaults. Dispatches server request to appropriate + * method and returns a response + * + * @param mixed $request + * @return mixed + */ + public function handle($request = false); + + /** + * Return a server definition array + * + * Returns a server definition array as created using + * {@link * Zend_Server_Reflection}. Can be used for server introspection, + * documentation, or persistence. + * + * @access public + * @return array + */ + public function getFunctions(); + + /** + * Load server definition + * + * Used for persistence; loads a construct as returned by {@link getFunctions()}. + * + * @param array $array + * @return void + */ + public function loadFunctions($definition); + + /** + * Set server persistence + * + * @todo Determine how to implement this + * @param int $mode + * @return void + */ + public function setPersistence($mode); +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Method
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Method/Callback.php
Added
@@ -0,0 +1,205 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Server + * @subpackage Method + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * Method callback metadata + * + * @category Zend + * @package Zend_Server + * @subpackage Method + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Server_Method_Callback +{ + /** + * @var string Class name for class method callback + */ + protected $_class; + + /** + * @var string Function name for function callback + */ + protected $_function; + + /** + * @var string Method name for class method callback + */ + protected $_method; + + /** + * @var string Callback type + */ + protected $_type; + + /** + * @var array Valid callback types + */ + protected $_types = array('function', 'static', 'instance'); + + /** + * Constructor + * + * @param null|array $options + * @return void + */ + public function __construct($options = null) + { + if ((null !== $options) && is_array($options)) { + $this->setOptions($options); + } + } + + /** + * Set object state from array of options + * + * @param array $options + * @return Zend_Server_Method_Callback + */ + public function setOptions(array $options) + { + foreach ($options as $key => $value) { + $method = 'set' . ucfirst($key); + if (method_exists($this, $method)) { + $this->$method($value); + } + } + return $this; + } + + /** + * Set callback class + * + * @param string $class + * @return Zend_Server_Method_Callback + */ + public function setClass($class) + { + if (is_object($class)) { + $class = get_class($class); + } + $this->_class = $class; + return $this; + } + + /** + * Get callback class + * + * @return string|null + */ + public function getClass() + { + return $this->_class; + } + + /** + * Set callback function + * + * @param string $function + * @return Zend_Server_Method_Callback + */ + public function setFunction($function) + { + $this->_function = (string) $function; + $this->setType('function'); + return $this; + } + + /** + * Get callback function + * + * @return null|string + */ + public function getFunction() + { + return $this->_function; + } + + /** + * Set callback class method + * + * @param string $method + * @return Zend_Server_Method_Callback + */ + public function setMethod($method) + { + $this->_method = $method; + return $this; + } + + /** + * Get callback class method + * + * @return null|string + */ + public function getMethod() + { + return $this->_method; + } + + /** + * Set callback type + * + * @param string $type + * @return Zend_Server_Method_Callback + * @throws Zend_Server_Exception + */ + public function setType($type) + { + if (!in_array($type, $this->_types)) { + // require_once 'Zend/Server/Exception.php'; + throw new Zend_Server_Exception('Invalid method callback type passed to ' . __CLASS__ . '::' . __METHOD__); + } + $this->_type = $type; + return $this; + } + + /** + * Get callback type + * + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * Cast callback to array + * + * @return array + */ + public function toArray() + { + $type = $this->getType(); + $array = array( + 'type' => $type, + ); + if ('function' == $type) { + $array['function'] = $this->getFunction(); + } else { + $array['class'] = $this->getClass(); + $array['method'] = $this->getMethod(); + } + return $array; + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Method/Definition.php
Added
@@ -0,0 +1,293 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Server + * @subpackage Method + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * Method definition metadata + * + * @category Zend + * @package Zend_Server + * @subpackage Method + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Server_Method_Definition +{ + /** + * @var Zend_Server_Method_Callback + */ + protected $_callback; + + /** + * @var array + */ + protected $_invokeArguments = array(); + + /** + * @var string + */ + protected $_methodHelp = ''; + + /** + * @var string + */ + protected $_name; + + /** + * @var null|object + */ + protected $_object; + + /** + * @var array Array of Zend_Server_Method_Prototype objects + */ + protected $_prototypes = array(); + + /** + * Constructor + * + * @param null|array $options + * @return void + */ + public function __construct($options = null) + { + if ((null !== $options) && is_array($options)) { + $this->setOptions($options); + } + } + + /** + * Set object state from options + * + * @param array $options + * @return Zend_Server_Method_Definition + */ + public function setOptions(array $options) + { + foreach ($options as $key => $value) { + $method = 'set' . ucfirst($key); + if (method_exists($this, $method)) { + $this->$method($value); + } + } + return $this; + } + + /** + * Set method name + * + * @param string $name + * @return Zend_Server_Method_Definition + */ + public function setName($name) + { + $this->_name = (string) $name; + return $this; + } + + /** + * Get method name + * + * @return string + */ + public function getName() + { + return $this->_name; + } + + /** + * Set method callback + * + * @param array|Zend_Server_Method_Callback $callback + * @return Zend_Server_Method_Definition + */ + public function setCallback($callback) + { + if (is_array($callback)) { + // require_once 'Zend/Server/Method/Callback.php'; + $callback = new Zend_Server_Method_Callback($callback); + } elseif (!$callback instanceof Zend_Server_Method_Callback) { + // require_once 'Zend/Server/Exception.php'; + throw new Zend_Server_Exception('Invalid method callback provided'); + } + $this->_callback = $callback; + return $this; + } + + /** + * Get method callback + * + * @return Zend_Server_Method_Callback + */ + public function getCallback() + { + return $this->_callback; + } + + /** + * Add prototype to method definition + * + * @param array|Zend_Server_Method_Prototype $prototype + * @return Zend_Server_Method_Definition + */ + public function addPrototype($prototype) + { + if (is_array($prototype)) { + // require_once 'Zend/Server/Method/Prototype.php'; + $prototype = new Zend_Server_Method_Prototype($prototype); + } elseif (!$prototype instanceof Zend_Server_Method_Prototype) { + // require_once 'Zend/Server/Exception.php'; + throw new Zend_Server_Exception('Invalid method prototype provided'); + } + $this->_prototypes[] = $prototype; + return $this; + } + + /** + * Add multiple prototypes at once + * + * @param array $prototypes Array of Zend_Server_Method_Prototype objects or arrays + * @return Zend_Server_Method_Definition + */ + public function addPrototypes(array $prototypes) + { + foreach ($prototypes as $prototype) { + $this->addPrototype($prototype); + } + return $this; + } + + /** + * Set all prototypes at once (overwrites) + * + * @param array $prototypes Array of Zend_Server_Method_Prototype objects or arrays + * @return Zend_Server_Method_Definition + */ + public function setPrototypes(array $prototypes) + { + $this->_prototypes = array(); + $this->addPrototypes($prototypes); + return $this; + } + + /** + * Get all prototypes + * + * @return array $prototypes Array of Zend_Server_Method_Prototype objects or arrays + */ + public function getPrototypes() + { + return $this->_prototypes; + } + + /** + * Set method help + * + * @param string $methodHelp + * @return Zend_Server_Method_Definition + */ + public function setMethodHelp($methodHelp) + { + $this->_methodHelp = (string) $methodHelp; + return $this; + } + + /** + * Get method help + * + * @return string + */ + public function getMethodHelp() + { + return $this->_methodHelp; + } + + /** + * Set object to use with method calls + * + * @param object $object + * @return Zend_Server_Method_Definition + */ + public function setObject($object) + { + if (!is_object($object) && (null !== $object)) { + // require_once 'Zend/Server/Exception.php'; + throw new Zend_Server_Exception('Invalid object passed to ' . __CLASS__ . '::' . __METHOD__); + } + $this->_object = $object; + return $this; + } + + /** + * Get object to use with method calls + * + * @return null|object + */ + public function getObject() + { + return $this->_object; + } + + /** + * Set invoke arguments + * + * @param array $invokeArguments + * @return Zend_Server_Method_Definition + */ + public function setInvokeArguments(array $invokeArguments) + { + $this->_invokeArguments = $invokeArguments; + return $this; + } + + /** + * Retrieve invoke arguments + * + * @return array + */ + public function getInvokeArguments() + { + return $this->_invokeArguments; + } + + /** + * Serialize to array + * + * @return array + */ + public function toArray() + { + $prototypes = $this->getPrototypes(); + $signatures = array(); + foreach ($prototypes as $prototype) { + $signatures[] = $prototype->toArray(); + } + + return array( + 'name' => $this->getName(), + 'callback' => $this->getCallback()->toArray(), + 'prototypes' => $signatures, + 'methodHelp' => $this->getMethodHelp(), + 'invokeArguments' => $this->getInvokeArguments(), + 'object' => $this->getObject(), + ); + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Method/Parameter.php
Added
@@ -0,0 +1,214 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Server + * @subpackage Method + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * Method parameter metadata + * + * @category Zend + * @package Zend_Server + * @subpackage Method + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Server_Method_Parameter +{ + /** + * @var mixed Default parameter value + */ + protected $_defaultValue; + + /** + * @var string Parameter description + */ + protected $_description = ''; + + /** + * @var string Parameter variable name + */ + protected $_name; + + /** + * @var bool Is parameter optional? + */ + protected $_optional = false; + + /** + * @var string Parameter type + */ + protected $_type = 'mixed'; + + /** + * Constructor + * + * @param null|array $options + * @return void + */ + public function __construct($options = null) + { + if (is_array($options)) { + $this->setOptions($options); + } + } + + /** + * Set object state from array of options + * + * @param array $options + * @return Zend_Server_Method_Parameter + */ + public function setOptions(array $options) + { + foreach ($options as $key => $value) { + $method = 'set' . ucfirst($key); + if (method_exists($this, $method)) { + $this->$method($value); + } + } + return $this; + } + + /** + * Set default value + * + * @param mixed $defaultValue + * @return Zend_Server_Method_Parameter + */ + public function setDefaultValue($defaultValue) + { + $this->_defaultValue = $defaultValue; + return $this; + } + + /** + * Retrieve default value + * + * @return mixed + */ + public function getDefaultValue() + { + return $this->_defaultValue; + } + + /** + * Set description + * + * @param string $description + * @return Zend_Server_Method_Parameter + */ + public function setDescription($description) + { + $this->_description = (string) $description; + return $this; + } + + /** + * Retrieve description + * + * @return string + */ + public function getDescription() + { + return $this->_description; + } + + /** + * Set name + * + * @param string $name + * @return Zend_Server_Method_Parameter + */ + public function setName($name) + { + $this->_name = (string) $name; + return $this; + } + + /** + * Retrieve name + * + * @return string + */ + public function getName() + { + return $this->_name; + } + + /** + * Set optional flag + * + * @param bool $flag + * @return Zend_Server_Method_Parameter + */ + public function setOptional($flag) + { + $this->_optional = (bool) $flag; + return $this; + } + + /** + * Is the parameter optional? + * + * @return bool + */ + public function isOptional() + { + return $this->_optional; + } + + /** + * Set parameter type + * + * @param string $type + * @return Zend_Server_Method_Parameter + */ + public function setType($type) + { + $this->_type = (string) $type; + return $this; + } + + /** + * Retrieve parameter type + * + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * Cast to array + * + * @return array + */ + public function toArray() + { + return array( + 'type' => $this->getType(), + 'name' => $this->getName(), + 'optional' => $this->isOptional(), + 'defaultValue' => $this->getDefaultValue(), + 'description' => $this->getDescription(), + ); + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Method/Prototype.php
Added
@@ -0,0 +1,208 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Server + * @subpackage Method + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ + +/** + * Method prototype metadata + * + * @category Zend + * @package Zend_Server + * @subpackage Method + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Server_Method_Prototype +{ + /** + * @var string Return type + */ + protected $_returnType = 'void'; + + /** + * @var array Map parameter names to parameter index + */ + protected $_parameterNameMap = array(); + + /** + * @var array Method parameters + */ + protected $_parameters = array(); + + /** + * Constructor + * + * @param null|array $options + * @return void + */ + public function __construct($options = null) + { + if ((null !== $options) && is_array($options)) { + $this->setOptions($options); + } + } + + /** + * Set return value + * + * @param string $returnType + * @return Zend_Server_Method_Prototype + */ + public function setReturnType($returnType) + { + $this->_returnType = $returnType; + return $this; + } + + /** + * Retrieve return type + * + * @return string + */ + public function getReturnType() + { + return $this->_returnType; + } + + /** + * Add a parameter + * + * @param string $parameter + * @return Zend_Server_Method_Prototype + */ + public function addParameter($parameter) + { + if ($parameter instanceof Zend_Server_Method_Parameter) { + $this->_parameters[] = $parameter; + if (null !== ($name = $parameter->getName())) { + $this->_parameterNameMap[$name] = count($this->_parameters) - 1; + } + } else { + // require_once 'Zend/Server/Method/Parameter.php'; + $parameter = new Zend_Server_Method_Parameter(array( + 'type' => (string) $parameter, + )); + $this->_parameters[] = $parameter; + } + return $this; + } + + /** + * Add parameters + * + * @param array $parameter + * @return Zend_Server_Method_Prototype + */ + public function addParameters(array $parameters) + { + foreach ($parameters as $parameter) { + $this->addParameter($parameter); + } + return $this; + } + + /** + * Set parameters + * + * @param array $parameters + * @return Zend_Server_Method_Prototype + */ + public function setParameters(array $parameters) + { + $this->_parameters = array(); + $this->_parameterNameMap = array(); + $this->addParameters($parameters); + return $this; + } + + /** + * Retrieve parameters as list of types + * + * @return array + */ + public function getParameters() + { + $types = array(); + foreach ($this->_parameters as $parameter) { + $types[] = $parameter->getType(); + } + return $types; + } + + /** + * Get parameter objects + * + * @return array + */ + public function getParameterObjects() + { + return $this->_parameters; + } + + /** + * Retrieve a single parameter by name or index + * + * @param string|int $index + * @return null|Zend_Server_Method_Parameter + */ + public function getParameter($index) + { + if (!is_string($index) && !is_numeric($index)) { + return null; + } + if (array_key_exists($index, $this->_parameterNameMap)) { + $index = $this->_parameterNameMap[$index]; + } + if (array_key_exists($index, $this->_parameters)) { + return $this->_parameters[$index]; + } + return null; + } + + /** + * Set object state from array + * + * @param array $options + * @return Zend_Server_Method_Prototype + */ + public function setOptions(array $options) + { + foreach ($options as $key => $value) { + $method = 'set' . ucfirst($key); + if (method_exists($this, $method)) { + $this->$method($value); + } + } + return $this; + } + + /** + * Serialize to array + * + * @return array + */ + public function toArray() + { + return array( + 'returnType' => $this->getReturnType(), + 'parameters' => $this->getParameters(), + ); + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Reflection
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Reflection.php
Added
@@ -0,0 +1,111 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * Zend_Server_Reflection_Function + */ +// require_once 'Zend/Server/Reflection/Function.php'; + +/** + * Zend_Server_Reflection_Class + */ +// require_once 'Zend/Server/Reflection/Class.php'; + +/** + * Reflection for determining method signatures to use with server classes + * + * @category Zend + * @package Zend_Server + * @subpackage Reflection + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +class Zend_Server_Reflection +{ + /** + * Perform class reflection to create dispatch signatures + * + * Creates a {@link Zend_Server_Reflection_Class} object for the class or + * object provided. + * + * If extra arguments should be passed to dispatchable methods, these may + * be provided as an array to $argv. + * + * @param string|object $class Class name or object + * @param null|array $argv Optional arguments to be used during the method call + * @param string $namespace Optional namespace with which to prefix the + * method name (used for the signature key). Primarily to avoid collisions, + * also for XmlRpc namespacing + * @return Zend_Server_Reflection_Class + * @throws Zend_Server_Reflection_Exception + */ + public static function reflectClass($class, $argv = false, $namespace = '') + { + if (is_object($class)) { + $reflection = new ReflectionObject($class); + } elseif (class_exists($class)) { + $reflection = new ReflectionClass($class); + } else { + // require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid class or object passed to attachClass()'); + } + + if ($argv && !is_array($argv)) { + // require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid argv argument passed to reflectClass'); + } + + return new Zend_Server_Reflection_Class($reflection, $namespace, $argv); + } + + /** + * Perform function reflection to create dispatch signatures + * + * Creates dispatch prototypes for a function. It returns a + * {@link Zend_Server_Reflection_Function} object. + * + * If extra arguments should be passed to the dispatchable function, these + * may be provided as an array to $argv. + * + * @param string $function Function name + * @param null|array $argv Optional arguments to be used during the method call + * @param string $namespace Optional namespace with which to prefix the + * function name (used for the signature key). Primarily to avoid + * collisions, also for XmlRpc namespacing + * @return Zend_Server_Reflection_Function + * @throws Zend_Server_Reflection_Exception + */ + public static function reflectFunction($function, $argv = false, $namespace = '') + { + if (!is_string($function) || !function_exists($function)) { + // require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid function "' . $function . '" passed to reflectFunction'); + } + + + if ($argv && !is_array($argv)) { + // require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid argv argument passed to reflectClass'); + } + + return new Zend_Server_Reflection_Function(new ReflectionFunction($function), $namespace, $argv); + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Reflection/Class.php
Added
@@ -0,0 +1,198 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * Zend_Server_Reflection_Method + */ +// require_once 'Zend/Server/Reflection/Method.php'; + +/** + * Class/Object reflection + * + * Proxies calls to a ReflectionClass object, and decorates getMethods() by + * creating its own list of {@link Zend_Server_Reflection_Method}s. + * + * @category Zend + * @package Zend_Server + * @subpackage Reflection + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +class Zend_Server_Reflection_Class +{ + /** + * Optional configuration parameters; accessible via {@link __get} and + * {@link __set()} + * @var array + */ + protected $_config = array(); + + /** + * Array of {@link Zend_Server_Reflection_Method}s + * @var array + */ + protected $_methods = array(); + + /** + * Namespace + * @var string + */ + protected $_namespace = null; + + /** + * ReflectionClass object + * @var ReflectionClass + */ + protected $_reflection; + + /** + * Constructor + * + * Create array of dispatchable methods, each a + * {@link Zend_Server_Reflection_Method}. Sets reflection object property. + * + * @param ReflectionClass $reflection + * @param string $namespace + * @param mixed $argv + * @return void + */ + public function __construct(ReflectionClass $reflection, $namespace = null, $argv = false) + { + $this->_reflection = $reflection; + $this->setNamespace($namespace); + + foreach ($reflection->getMethods() as $method) { + // Don't aggregate magic methods + if ('__' == substr($method->getName(), 0, 2)) { + continue; + } + + if ($method->isPublic()) { + // Get signatures and description + $this->_methods[] = new Zend_Server_Reflection_Method($this, $method, $this->getNamespace(), $argv); + } + } + } + + /** + * Proxy reflection calls + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + if (method_exists($this->_reflection, $method)) { + return call_user_func_array(array($this->_reflection, $method), $args); + } + + // require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid reflection method'); + } + + /** + * Retrieve configuration parameters + * + * Values are retrieved by key from {@link $_config}. Returns null if no + * value found. + * + * @param string $key + * @return mixed + */ + public function __get($key) + { + if (isset($this->_config[$key])) { + return $this->_config[$key]; + } + + return null; + } + + /** + * Set configuration parameters + * + * Values are stored by $key in {@link $_config}. + * + * @param string $key + * @param mixed $value + * @return void + */ + public function __set($key, $value) + { + $this->_config[$key] = $value; + } + + /** + * Return array of dispatchable {@link Zend_Server_Reflection_Method}s. + * + * @access public + * @return array + */ + public function getMethods() + { + return $this->_methods; + } + + /** + * Get namespace for this class + * + * @return string + */ + public function getNamespace() + { + return $this->_namespace; + } + + /** + * Set namespace for this class + * + * @param string $namespace + * @return void + */ + public function setNamespace($namespace) + { + if (empty($namespace)) { + $this->_namespace = ''; + return; + } + + if (!is_string($namespace) || !preg_match('/[a-z0-9_\.]+/i', $namespace)) { + // require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid namespace'); + } + + $this->_namespace = $namespace; + } + + /** + * Wakeup from serialization + * + * Reflection needs explicit instantiation to work correctly. Re-instantiate + * reflection object on wakeup. + * + * @return void + */ + public function __wakeup() + { + $this->_reflection = new ReflectionClass($this->getName()); + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Reflection/Exception.php
Added
@@ -0,0 +1,38 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @see Zend_Server_Exception + */ +// require_once 'Zend/Server/Exception.php'; + +/** + * Zend_Server_Reflection exceptions + * + * @category Zend + * @package Zend_Server + * @subpackage Reflection + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +class Zend_Server_Reflection_Exception extends Zend_Server_Exception +{ +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Reflection/Function
Added
+(directory)
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Reflection/Function.php
Added
@@ -0,0 +1,39 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * Zend_Server_Reflection_Function_Abstract + */ +// require_once 'Zend/Server/Reflection/Function/Abstract.php'; + +/** + * Function Reflection + * + * @uses Zend_Server_Reflection_Function_Abstract + * @category Zend + * @package Zend_Server + * @subpackage Reflection + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +class Zend_Server_Reflection_Function extends Zend_Server_Reflection_Function_Abstract +{ +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Reflection/Function/Abstract.php
Added
@@ -0,0 +1,514 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * Zend_Server_Reflection_Node + */ +// require_once 'Zend/Server/Reflection/Node.php'; + +/** + * Zend_Server_Reflection_Parameter + */ +// require_once 'Zend/Server/Reflection/Parameter.php'; + +/** + * Zend_Server_Reflection_Prototype + */ +// require_once 'Zend/Server/Reflection/Prototype.php'; + +/** + * Function/Method Reflection + * + * Decorates a ReflectionFunction. Allows setting and retrieving an alternate + * 'service' name (i.e., the name to be used when calling via a service), + * setting and retrieving the description (originally set using the docblock + * contents), retrieving the callback and callback type, retrieving additional + * method invocation arguments, and retrieving the + * method {@link Zend_Server_Reflection_Prototype prototypes}. + * + * @category Zend + * @package Zend_Server + * @subpackage Reflection + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +abstract class Zend_Server_Reflection_Function_Abstract +{ + /** + * @var ReflectionFunction + */ + protected $_reflection; + + /** + * Additional arguments to pass to method on invocation + * @var array + */ + protected $_argv = array(); + + /** + * Used to store extra configuration for the method (typically done by the + * server class, e.g., to indicate whether or not to instantiate a class). + * Associative array; access is as properties via {@link __get()} and + * {@link __set()} + * @var array + */ + protected $_config = array(); + + /** + * Declaring class (needed for when serialization occurs) + * @var string + */ + protected $_class; + + /** + * Function/method description + * @var string + */ + protected $_description = ''; + + /** + * Namespace with which to prefix function/method name + * @var string + */ + protected $_namespace; + + /** + * Prototypes + * @var array + */ + protected $_prototypes = array(); + + private $_return; + private $_returnDesc; + private $_paramDesc; + private $_sigParams; + private $_sigParamsDepth; + + /** + * Constructor + * + * @param ReflectionFunction $r + */ + public function __construct(Reflector $r, $namespace = null, $argv = array()) + { + // In PHP 5.1.x, ReflectionMethod extends ReflectionFunction. In 5.2.x, + // both extend ReflectionFunctionAbstract. So, we can't do normal type + // hinting in the prototype, but instead need to do some explicit + // testing here. + if ((!$r instanceof ReflectionFunction) + && (!$r instanceof ReflectionMethod)) { + // require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid reflection class'); + } + $this->_reflection = $r; + + // Determine namespace + if (null !== $namespace){ + $this->setNamespace($namespace); + } + + // Determine arguments + if (is_array($argv)) { + $this->_argv = $argv; + } + + // If method call, need to store some info on the class + if ($r instanceof ReflectionMethod) { + $this->_class = $r->getDeclaringClass()->getName(); + } + + // Perform some introspection + $this->_reflect(); + } + + /** + * Create signature node tree + * + * Recursive method to build the signature node tree. Increments through + * each array in {@link $_sigParams}, adding every value of the next level + * to the current value (unless the current value is null). + * + * @param Zend_Server_Reflection_Node $parent + * @param int $level + * @return void + */ + protected function _addTree(Zend_Server_Reflection_Node $parent, $level = 0) + { + if ($level >= $this->_sigParamsDepth) { + return; + } + + foreach ($this->_sigParams[$level] as $value) { + $node = new Zend_Server_Reflection_Node($value, $parent); + if ((null !== $value) && ($this->_sigParamsDepth > $level + 1)) { + $this->_addTree($node, $level + 1); + } + } + } + + /** + * Build the signature tree + * + * Builds a signature tree starting at the return values and descending + * through each method argument. Returns an array of + * {@link Zend_Server_Reflection_Node}s. + * + * @return array + */ + protected function _buildTree() + { + $returnTree = array(); + foreach ((array) $this->_return as $value) { + $node = new Zend_Server_Reflection_Node($value); + $this->_addTree($node); + $returnTree[] = $node; + } + + return $returnTree; + } + + /** + * Build method signatures + * + * Builds method signatures using the array of return types and the array of + * parameters types + * + * @param array $return Array of return types + * @param string $returnDesc Return value description + * @param array $params Array of arguments (each an array of types) + * @param array $paramDesc Array of parameter descriptions + * @return array + */ + protected function _buildSignatures($return, $returnDesc, $paramTypes, $paramDesc) + { + $this->_return = $return; + $this->_returnDesc = $returnDesc; + $this->_paramDesc = $paramDesc; + $this->_sigParams = $paramTypes; + $this->_sigParamsDepth = count($paramTypes); + $signatureTrees = $this->_buildTree(); + $signatures = array(); + + $endPoints = array(); + foreach ($signatureTrees as $root) { + $tmp = $root->getEndPoints(); + if (empty($tmp)) { + $endPoints = array_merge($endPoints, array($root)); + } else { + $endPoints = array_merge($endPoints, $tmp); + } + } + + foreach ($endPoints as $node) { + if (!$node instanceof Zend_Server_Reflection_Node) { + continue; + } + + $signature = array(); + do { + array_unshift($signature, $node->getValue()); + $node = $node->getParent(); + } while ($node instanceof Zend_Server_Reflection_Node); + + $signatures[] = $signature; + } + + // Build prototypes + $params = $this->_reflection->getParameters(); + foreach ($signatures as $signature) { + $return = new Zend_Server_Reflection_ReturnValue(array_shift($signature), $this->_returnDesc); + $tmp = array(); + foreach ($signature as $key => $type) { + $param = new Zend_Server_Reflection_Parameter($params[$key], $type, (isset($this->_paramDesc[$key]) ? $this->_paramDesc[$key] : null)); + $param->setPosition($key); + $tmp[] = $param; + } + + $this->_prototypes[] = new Zend_Server_Reflection_Prototype($return, $tmp); + } + } + + /** + * Use code reflection to create method signatures + * + * Determines the method help/description text from the function DocBlock + * comment. Determines method signatures using a combination of + * ReflectionFunction and parsing of DocBlock @param and @return values. + * + * @param ReflectionFunction $function + * @return array + */ + protected function _reflect() + { + $function = $this->_reflection; + $helpText = ''; + $signatures = array(); + $returnDesc = ''; + $paramCount = $function->getNumberOfParameters(); + $paramCountRequired = $function->getNumberOfRequiredParameters(); + $parameters = $function->getParameters(); + $docBlock = $function->getDocComment(); + + if (!empty($docBlock)) { + // Get help text + if (preg_match(':/\*\*\s*\r?\n\s*\*\s(.*?)\r?\n\s*\*(\s@|/):s', $docBlock, $matches)) + { + $helpText = $matches[1]; + $helpText = preg_replace('/(^\s*\*\s)/m', '', $helpText); + $helpText = preg_replace('/\r?\n\s*\*\s*(\r?\n)*/s', "\n", $helpText); + $helpText = trim($helpText); + } + + // Get return type(s) and description + $return = 'void'; + if (preg_match('/@return\s+(\S+)/', $docBlock, $matches)) { + $return = explode('|', $matches[1]); + if (preg_match('/@return\s+\S+\s+(.*?)(@|\*\/)/s', $docBlock, $matches)) + { + $value = $matches[1]; + $value = preg_replace('/\s?\*\s/m', '', $value); + $value = preg_replace('/\s{2,}/', ' ', $value); + $returnDesc = trim($value); + } + } + + // Get param types and description + if (preg_match_all('/@param\s+([^\s]+)/m', $docBlock, $matches)) { + $paramTypesTmp = $matches[1]; + if (preg_match_all('/@param\s+\S+\s+(\$\S+)\s+(.*?)(?=@|\*\/)/s', $docBlock, $matches)) + { + $paramDesc = $matches[2]; + foreach ($paramDesc as $key => $value) { + $value = preg_replace('/\s?\*\s/m', '', $value); + $value = preg_replace('/\s{2,}/', ' ', $value); + $paramDesc[$key] = trim($value); + } + } + } + } else { + $helpText = $function->getName(); + $return = 'void'; + + // Try and auto-determine type, based on reflection + $paramTypesTmp = array(); + foreach ($parameters as $i => $param) { + $paramType = 'mixed'; + if ($param->isArray()) { + $paramType = 'array'; + } + $paramTypesTmp[$i] = $paramType; + } + } + + // Set method description + $this->setDescription($helpText); + + // Get all param types as arrays + if (!isset($paramTypesTmp) && (0 < $paramCount)) { + $paramTypesTmp = array_fill(0, $paramCount, 'mixed'); + } elseif (!isset($paramTypesTmp)) { + $paramTypesTmp = array(); + } elseif (count($paramTypesTmp) < $paramCount) { + $start = $paramCount - count($paramTypesTmp); + for ($i = $start; $i < $paramCount; ++$i) { + $paramTypesTmp[$i] = 'mixed'; + } + } + + // Get all param descriptions as arrays + if (!isset($paramDesc) && (0 < $paramCount)) { + $paramDesc = array_fill(0, $paramCount, ''); + } elseif (!isset($paramDesc)) { + $paramDesc = array(); + } elseif (count($paramDesc) < $paramCount) { + $start = $paramCount - count($paramDesc); + for ($i = $start; $i < $paramCount; ++$i) { + $paramDesc[$i] = ''; + } + } + + if (count($paramTypesTmp) != $paramCount) { + // require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception( + 'Variable number of arguments is not supported for services (except optional parameters). ' + . 'Number of function arguments in ' . $function->getDeclaringClass()->getName() . '::' + . $function->getName() . '() must correspond to actual number of arguments described in the ' + . 'docblock.'); + } + + $paramTypes = array(); + foreach ($paramTypesTmp as $i => $param) { + $tmp = explode('|', $param); + if ($parameters[$i]->isOptional()) { + array_unshift($tmp, null); + } + $paramTypes[] = $tmp; + } + + $this->_buildSignatures($return, $returnDesc, $paramTypes, $paramDesc); + } + + + /** + * Proxy reflection calls + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + if (method_exists($this->_reflection, $method)) { + return call_user_func_array(array($this->_reflection, $method), $args); + } + + // require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid reflection method ("' .$method. '")'); + } + + /** + * Retrieve configuration parameters + * + * Values are retrieved by key from {@link $_config}. Returns null if no + * value found. + * + * @param string $key + * @return mixed + */ + public function __get($key) + { + if (isset($this->_config[$key])) { + return $this->_config[$key]; + } + + return null; + } + + /** + * Set configuration parameters + * + * Values are stored by $key in {@link $_config}. + * + * @param string $key + * @param mixed $value + * @return void + */ + public function __set($key, $value) + { + $this->_config[$key] = $value; + } + + /** + * Set method's namespace + * + * @param string $namespace + * @return void + */ + public function setNamespace($namespace) + { + if (empty($namespace)) { + $this->_namespace = ''; + return; + } + + if (!is_string($namespace) || !preg_match('/[a-z0-9_\.]+/i', $namespace)) { + // require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid namespace'); + } + + $this->_namespace = $namespace; + } + + /** + * Return method's namespace + * + * @return string + */ + public function getNamespace() + { + return $this->_namespace; + } + + /** + * Set the description + * + * @param string $string + * @return void + */ + public function setDescription($string) + { + if (!is_string($string)) { + // require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid description'); + } + + $this->_description = $string; + } + + /** + * Retrieve the description + * + * @return void + */ + public function getDescription() + { + return $this->_description; + } + + /** + * Retrieve all prototypes as array of + * {@link Zend_Server_Reflection_Prototype Zend_Server_Reflection_Prototypes} + * + * @return array + */ + public function getPrototypes() + { + return $this->_prototypes; + } + + /** + * Retrieve additional invocation arguments + * + * @return array + */ + public function getInvokeArguments() + { + return $this->_argv; + } + + /** + * Wakeup from serialization + * + * Reflection needs explicit instantiation to work correctly. Re-instantiate + * reflection object on wakeup. + * + * @return void + */ + public function __wakeup() + { + if ($this->_reflection instanceof ReflectionMethod) { + $class = new ReflectionClass($this->_class); + $this->_reflection = new ReflectionMethod($class->newInstance(), $this->getName()); + } else { + $this->_reflection = new ReflectionFunction($this->getName()); + } + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Reflection/Method.php
Added
@@ -0,0 +1,110 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * Zend_Server_Reflection_Function_Abstract + */ +// require_once 'Zend/Server/Reflection/Function/Abstract.php'; + +/** + * Method Reflection + * + * @uses Zend_Server_Reflection_Function_Abstract + * @category Zend + * @package Zend_Server + * @subpackage Reflection + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +class Zend_Server_Reflection_Method extends Zend_Server_Reflection_Function_Abstract +{ + /** + * Parent class name + * @var string + */ + protected $_class; + + /** + * Parent class reflection + * @var Zend_Server_Reflection_Class + */ + protected $_classReflection; + + /** + * Constructor + * + * @param Zend_Server_Reflection_Class $class + * @param ReflectionMethod $r + * @param string $namespace + * @param array $argv + * @return void + */ + public function __construct(Zend_Server_Reflection_Class $class, ReflectionMethod $r, $namespace = null, $argv = array()) + { + $this->_classReflection = $class; + $this->_reflection = $r; + + $classNamespace = $class->getNamespace(); + + // Determine namespace + if (!empty($namespace)) { + $this->setNamespace($namespace); + } elseif (!empty($classNamespace)) { + $this->setNamespace($classNamespace); + } + + // Determine arguments + if (is_array($argv)) { + $this->_argv = $argv; + } + + // If method call, need to store some info on the class + $this->_class = $class->getName(); + + // Perform some introspection + $this->_reflect(); + } + + /** + * Return the reflection for the class that defines this method + * + * @return Zend_Server_Reflection_Class + */ + public function getDeclaringClass() + { + return $this->_classReflection; + } + + /** + * Wakeup from serialization + * + * Reflection needs explicit instantiation to work correctly. Re-instantiate + * reflection object on wakeup. + * + * @return void + */ + public function __wakeup() + { + $this->_classReflection = new Zend_Server_Reflection_Class(new ReflectionClass($this->_class), $this->getNamespace(), $this->getInvokeArguments()); + $this->_reflection = new ReflectionMethod($this->_classReflection->getName(), $this->getName()); + } + +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Reflection/Node.php
Added
@@ -0,0 +1,201 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * Node Tree class for Zend_Server reflection operations + * + * @category Zend + * @package Zend_Server + * @subpackage Reflection + * @version $Id$ + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Server_Reflection_Node +{ + /** + * Node value + * @var mixed + */ + protected $_value = null; + + /** + * Array of child nodes (if any) + * @var array + */ + protected $_children = array(); + + /** + * Parent node (if any) + * @var Zend_Server_Reflection_Node + */ + protected $_parent = null; + + /** + * Constructor + * + * @param mixed $value + * @param Zend_Server_Reflection_Node $parent Optional + * @return Zend_Server_Reflection_Node + */ + public function __construct($value, Zend_Server_Reflection_Node $parent = null) + { + $this->_value = $value; + if (null !== $parent) { + $this->setParent($parent, true); + } + + return $this; + } + + /** + * Set parent node + * + * @param Zend_Server_Reflection_Node $node + * @param boolean $new Whether or not the child node is newly created + * and should always be attached + * @return void + */ + public function setParent(Zend_Server_Reflection_Node $node, $new = false) + { + $this->_parent = $node; + + if ($new) { + $node->attachChild($this); + return; + } + } + + /** + * Create and attach a new child node + * + * @param mixed $value + * @access public + * @return Zend_Server_Reflection_Node New child node + */ + public function createChild($value) + { + $child = new self($value, $this); + + return $child; + } + + /** + * Attach a child node + * + * @param Zend_Server_Reflection_Node $node + * @return void + */ + public function attachChild(Zend_Server_Reflection_Node $node) + { + $this->_children[] = $node; + + if ($node->getParent() !== $this) { + $node->setParent($this); + } + } + + /** + * Return an array of all child nodes + * + * @return array + */ + public function getChildren() + { + return $this->_children; + } + + /** + * Does this node have children? + * + * @return boolean + */ + public function hasChildren() + { + return count($this->_children) > 0; + } + + /** + * Return the parent node + * + * @return null|Zend_Server_Reflection_Node + */ + public function getParent() + { + return $this->_parent; + } + + /** + * Return the node's current value + * + * @return mixed + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the node value + * + * @param mixed $value + * @return void + */ + public function setValue($value) + { + $this->_value = $value; + } + + /** + * Retrieve the bottommost nodes of this node's tree + * + * Retrieves the bottommost nodes of the tree by recursively calling + * getEndPoints() on all children. If a child is null, it returns the parent + * as an end point. + * + * @return array + */ + public function getEndPoints() + { + $endPoints = array(); + if (!$this->hasChildren()) { + return $endPoints; + } + + foreach ($this->_children as $child) { + $value = $child->getValue(); + + if (null === $value) { + $endPoints[] = $this; + } elseif ((null !== $value) + && $child->hasChildren()) + { + $childEndPoints = $child->getEndPoints(); + if (!empty($childEndPoints)) { + $endPoints = array_merge($endPoints, $childEndPoints); + } + } elseif ((null !== $value) && !$child->hasChildren()) { + $endPoints[] = $child; + } + } + + return $endPoints; + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Reflection/Parameter.php
Added
@@ -0,0 +1,161 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * Parameter Reflection + * + * Decorates a ReflectionParameter to allow setting the parameter type + * + * @category Zend + * @package Zend_Server + * @subpackage Reflection + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +class Zend_Server_Reflection_Parameter +{ + /** + * @var ReflectionParameter + */ + protected $_reflection; + + /** + * Parameter position + * @var int + */ + protected $_position; + + /** + * Parameter type + * @var string + */ + protected $_type; + + /** + * Parameter description + * @var string + */ + protected $_description; + + /** + * Constructor + * + * @param ReflectionParameter $r + * @param string $type Parameter type + * @param string $description Parameter description + */ + public function __construct(ReflectionParameter $r, $type = 'mixed', $description = '') + { + $this->_reflection = $r; + $this->setType($type); + $this->setDescription($description); + } + + /** + * Proxy reflection calls + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + if (method_exists($this->_reflection, $method)) { + return call_user_func_array(array($this->_reflection, $method), $args); + } + + // require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid reflection method'); + } + + /** + * Retrieve parameter type + * + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * Set parameter type + * + * @param string|null $type + * @return void + */ + public function setType($type) + { + if (!is_string($type) && (null !== $type)) { + // require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid parameter type'); + } + + $this->_type = $type; + } + + /** + * Retrieve parameter description + * + * @return string + */ + public function getDescription() + { + return $this->_description; + } + + /** + * Set parameter description + * + * @param string|null $description + * @return void + */ + public function setDescription($description) + { + if (!is_string($description) && (null !== $description)) { + // require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid parameter description'); + } + + $this->_description = $description; + } + + /** + * Set parameter position + * + * @param int $index + * @return void + */ + public function setPosition($index) + { + $this->_position = (int) $index; + } + + /** + * Return parameter position + * + * @return int + */ + public function getPosition() + { + return $this->_position; + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Reflection/Prototype.php
Added
@@ -0,0 +1,103 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * Zend_Server_Reflection_ReturnValue + */ +// require_once 'Zend/Server/Reflection/ReturnValue.php'; + +/** + * Zend_Server_Reflection_Parameter + */ +// require_once 'Zend/Server/Reflection/Parameter.php'; + +/** + * Method/Function prototypes + * + * Contains accessors for the return value and all method arguments. + * + * @category Zend + * @package Zend_Server + * @subpackage Reflection + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +class Zend_Server_Reflection_Prototype +{ + /** + * Constructor + * + * @param Zend_Server_Reflection_ReturnValue $return + * @param array $params + * @return void + */ + public function __construct(Zend_Server_Reflection_ReturnValue $return, $params = null) + { + $this->_return = $return; + + if (!is_array($params) && (null !== $params)) { + // require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid parameters'); + } + + if (is_array($params)) { + foreach ($params as $param) { + if (!$param instanceof Zend_Server_Reflection_Parameter) { + // require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('One or more params are invalid'); + } + } + } + + $this->_params = $params; + } + + /** + * Retrieve return type + * + * @return string + */ + public function getReturnType() + { + return $this->_return->getType(); + } + + /** + * Retrieve the return value object + * + * @access public + * @return Zend_Server_Reflection_ReturnValue + */ + public function getReturnValue() + { + return $this->_return; + } + + /** + * Retrieve method parameters + * + * @return array Array of {@link Zend_Server_Reflection_Parameter}s + */ + public function getParameters() + { + return $this->_params; + } +}
View file
roundcubemail-1.4.13.tar.gz/vendor/zf1/zend-server/library/Zend/Server/Reflection/ReturnValue.php
Added
@@ -0,0 +1,110 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Server + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * Return value reflection + * + * Stores the return value type and description + * + * @category Zend + * @package Zend_Server + * @subpackage Reflection + * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id$ + */ +class Zend_Server_Reflection_ReturnValue +{ + /** + * Return value type + * @var string + */ + protected $_type; + + /** + * Return value description + * @var string + */ + protected $_description; + + /** + * Constructor + * + * @param string $type Return value type + * @param string $description Return value type + */ + public function __construct($type = 'mixed', $description = '') + { + $this->setType($type); + $this->setDescription($description); + } + + /** + * Retrieve parameter type + * + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * Set parameter type + * + * @param string|null $type + * @return void + */ + public function setType($type) + { + if (!is_string($type) && (null !== $type)) { + // require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid parameter type'); + } + + $this->_type = $type; + } + + /** + * Retrieve parameter description + * + * @return string + */ + public function getDescription() + { + return $this->_description; + } + + /** + * Set parameter description + * + * @param string|null $description + * @return void + */ + public function setDescription($description) + { + if (!is_string($description) && (null !== $description)) { + // require_once 'Zend/Server/Reflection/Exception.php'; + throw new Zend_Server_Reflection_Exception('Invalid parameter description'); + } + + $this->_description = $description; + } +}
View file
roundcubemail.dsc
Changed
@@ -2,7 +2,7 @@ Source: roundcubemail Binary: roundcubemail Architecture: all -Version: 1:1.4.11.20-0~kolab1 +Version: 1:1.4.13-0~kolab1 Maintainer: Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> Uploaders: Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> Homepage: http://www.roundcube.net/ @@ -14,5 +14,5 @@ roundcubemail deb web extra roundcubemail-core deb web extra Files: - 00000000000000000000000000000000 0 roundcubemail-1.4.11.20.tar.gz + 00000000000000000000000000000000 0 roundcubemail-1.4.13.tar.gz 00000000000000000000000000000000 0 debian.tar.gz
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.