summaryrefslogtreecommitdiff
path: root/lib/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'lib/plugins')
-rw-r--r--lib/plugins/acl/lang/cs/lang.php1
-rw-r--r--lib/plugins/acl/lang/de-informal/lang.php2
-rw-r--r--lib/plugins/acl/lang/el/lang.php1
-rw-r--r--lib/plugins/acl/lang/en/help.txt9
-rw-r--r--lib/plugins/acl/lang/fr/lang.php1
-rw-r--r--lib/plugins/acl/lang/gl/lang.php2
-rw-r--r--lib/plugins/acl/lang/ja/lang.php1
-rw-r--r--lib/plugins/acl/lang/ko/help.txt11
-rw-r--r--lib/plugins/acl/lang/ko/lang.php13
-rw-r--r--lib/plugins/acl/lang/nl/help.txt9
-rw-r--r--lib/plugins/acl/lang/pt-br/lang.php1
-rw-r--r--lib/plugins/acl/lang/ru/lang.php1
-rw-r--r--lib/plugins/acl/lang/sv/lang.php1
-rw-r--r--lib/plugins/acl/lang/vi/help.txt24
-rw-r--r--lib/plugins/acl/plugin.info.txt2
-rw-r--r--lib/plugins/acl/script.js8
-rw-r--r--lib/plugins/acl/style.css57
-rw-r--r--lib/plugins/auth.php441
-rw-r--r--lib/plugins/authad/adLDAP/adLDAP.php951
-rw-r--r--lib/plugins/authad/adLDAP/classes/adLDAPComputers.php153
-rw-r--r--lib/plugins/authad/adLDAP/classes/adLDAPContacts.php294
-rw-r--r--lib/plugins/authad/adLDAP/classes/adLDAPExchange.php390
-rw-r--r--lib/plugins/authad/adLDAP/classes/adLDAPFolders.php179
-rw-r--r--lib/plugins/authad/adLDAP/classes/adLDAPGroups.php631
-rw-r--r--lib/plugins/authad/adLDAP/classes/adLDAPUsers.php682
-rw-r--r--lib/plugins/authad/adLDAP/classes/adLDAPUtils.php264
-rw-r--r--lib/plugins/authad/adLDAP/collections/adLDAPCollection.php137
-rw-r--r--lib/plugins/authad/adLDAP/collections/adLDAPComputerCollection.php46
-rw-r--r--lib/plugins/authad/adLDAP/collections/adLDAPContactCollection.php46
-rw-r--r--lib/plugins/authad/adLDAP/collections/adLDAPGroupCollection.php46
-rw-r--r--lib/plugins/authad/adLDAP/collections/adLDAPUserCollection.php46
-rw-r--r--lib/plugins/authad/auth.php541
-rw-r--r--lib/plugins/authad/conf/default.php14
-rw-r--r--lib/plugins/authad/conf/metadata.php14
-rw-r--r--lib/plugins/authad/lang/bg/settings.php18
-rw-r--r--lib/plugins/authad/lang/cs/settings.php18
-rw-r--r--lib/plugins/authad/lang/de-informal/settings.php20
-rw-r--r--lib/plugins/authad/lang/de/settings.php19
-rw-r--r--lib/plugins/authad/lang/en/settings.php14
-rw-r--r--lib/plugins/authad/lang/eo/settings.php17
-rw-r--r--lib/plugins/authad/lang/fi/settings.php6
-rw-r--r--lib/plugins/authad/lang/fr/settings.php18
-rw-r--r--lib/plugins/authad/lang/it/settings.php5
-rw-r--r--lib/plugins/authad/lang/ja/settings.php6
-rw-r--r--lib/plugins/authad/lang/ko/settings.php18
-rw-r--r--lib/plugins/authad/lang/lv/settings.php6
-rw-r--r--lib/plugins/authad/lang/nl/settings.php17
-rw-r--r--lib/plugins/authad/lang/pt-br/settings.php18
-rw-r--r--lib/plugins/authad/lang/ru/settings.php6
-rw-r--r--lib/plugins/authad/lang/sv/settings.php11
-rw-r--r--lib/plugins/authad/lang/zh-tw/settings.php18
-rw-r--r--lib/plugins/authad/lang/zh/settings.php18
-rw-r--r--lib/plugins/authad/plugin.info.txt7
-rw-r--r--lib/plugins/authldap/auth.php540
-rw-r--r--lib/plugins/authldap/conf/default.php20
-rw-r--r--lib/plugins/authldap/conf/metadata.php19
-rw-r--r--lib/plugins/authldap/lang/bg/settings.php19
-rw-r--r--lib/plugins/authldap/lang/cs/settings.php21
-rw-r--r--lib/plugins/authldap/lang/de-informal/settings.php28
-rw-r--r--lib/plugins/authldap/lang/de/settings.php22
-rw-r--r--lib/plugins/authldap/lang/en/settings.php23
-rw-r--r--lib/plugins/authldap/lang/eo/settings.php20
-rw-r--r--lib/plugins/authldap/lang/fi/settings.php6
-rw-r--r--lib/plugins/authldap/lang/fr/settings.php21
-rw-r--r--lib/plugins/authldap/lang/it/settings.php5
-rw-r--r--lib/plugins/authldap/lang/ja/settings.php6
-rw-r--r--lib/plugins/authldap/lang/ko/settings.php21
-rw-r--r--lib/plugins/authldap/lang/lv/settings.php6
-rw-r--r--lib/plugins/authldap/lang/nl/settings.php20
-rw-r--r--lib/plugins/authldap/lang/pt-br/settings.php26
-rw-r--r--lib/plugins/authldap/lang/ru/settings.php6
-rw-r--r--lib/plugins/authldap/lang/sv/settings.php16
-rw-r--r--lib/plugins/authldap/lang/zh-tw/settings.php21
-rw-r--r--lib/plugins/authldap/lang/zh/settings.php21
-rw-r--r--lib/plugins/authldap/plugin.info.txt7
-rw-r--r--lib/plugins/authmysql/auth.php975
-rw-r--r--lib/plugins/authmysql/conf/default.php34
-rw-r--r--lib/plugins/authmysql/conf/metadata.php34
-rw-r--r--lib/plugins/authmysql/lang/bg/settings.php17
-rw-r--r--lib/plugins/authmysql/lang/cs/settings.php41
-rw-r--r--lib/plugins/authmysql/lang/de-informal/settings.php43
-rw-r--r--lib/plugins/authmysql/lang/de/settings.php42
-rw-r--r--lib/plugins/authmysql/lang/en/settings.php39
-rw-r--r--lib/plugins/authmysql/lang/eo/settings.php40
-rw-r--r--lib/plugins/authmysql/lang/fi/settings.php6
-rw-r--r--lib/plugins/authmysql/lang/fr/settings.php41
-rw-r--r--lib/plugins/authmysql/lang/it/settings.php5
-rw-r--r--lib/plugins/authmysql/lang/ja/settings.php41
-rw-r--r--lib/plugins/authmysql/lang/ko/settings.php41
-rw-r--r--lib/plugins/authmysql/lang/lv/settings.php6
-rw-r--r--lib/plugins/authmysql/lang/nl/settings.php40
-rw-r--r--lib/plugins/authmysql/lang/pt-br/settings.php41
-rw-r--r--lib/plugins/authmysql/lang/ru/settings.php41
-rw-r--r--lib/plugins/authmysql/lang/sv/settings.php25
-rw-r--r--lib/plugins/authmysql/lang/zh-tw/settings.php41
-rw-r--r--lib/plugins/authmysql/lang/zh/settings.php41
-rw-r--r--lib/plugins/authmysql/plugin.info.txt7
-rw-r--r--lib/plugins/authpgsql/auth.php418
-rw-r--r--lib/plugins/authpgsql/conf/default.php33
-rw-r--r--lib/plugins/authpgsql/conf/metadata.php33
-rw-r--r--lib/plugins/authpgsql/lang/bg/settings.php12
-rw-r--r--lib/plugins/authpgsql/lang/cs/settings.php37
-rw-r--r--lib/plugins/authpgsql/lang/de-informal/settings.php39
-rw-r--r--lib/plugins/authpgsql/lang/de/settings.php38
-rw-r--r--lib/plugins/authpgsql/lang/en/settings.php33
-rw-r--r--lib/plugins/authpgsql/lang/eo/settings.php36
-rw-r--r--lib/plugins/authpgsql/lang/fi/settings.php6
-rw-r--r--lib/plugins/authpgsql/lang/fr/settings.php37
-rw-r--r--lib/plugins/authpgsql/lang/it/settings.php5
-rw-r--r--lib/plugins/authpgsql/lang/ja/settings.php37
-rw-r--r--lib/plugins/authpgsql/lang/ko/settings.php37
-rw-r--r--lib/plugins/authpgsql/lang/lv/settings.php6
-rw-r--r--lib/plugins/authpgsql/lang/nl/settings.php36
-rw-r--r--lib/plugins/authpgsql/lang/pt-br/settings.php37
-rw-r--r--lib/plugins/authpgsql/lang/ru/settings.php6
-rw-r--r--lib/plugins/authpgsql/lang/sv/settings.php28
-rw-r--r--lib/plugins/authpgsql/lang/zh-tw/settings.php37
-rw-r--r--lib/plugins/authpgsql/lang/zh/settings.php37
-rw-r--r--lib/plugins/authpgsql/plugin.info.txt7
-rw-r--r--lib/plugins/authplain/auth.php354
-rw-r--r--lib/plugins/authplain/plugin.info.txt7
-rw-r--r--lib/plugins/config/_test/configuration.test.php33
-rw-r--r--lib/plugins/config/_test/data/config.php16
-rw-r--r--lib/plugins/config/_test/data/metadata.php13
-rw-r--r--lib/plugins/config/admin.php4
-rw-r--r--lib/plugins/config/lang/cs/lang.php1
-rw-r--r--lib/plugins/config/lang/de-informal/lang.php145
-rw-r--r--lib/plugins/config/lang/de/lang.php19
-rw-r--r--lib/plugins/config/lang/el/lang.php105
-rw-r--r--lib/plugins/config/lang/en/intro.txt2
-rw-r--r--lib/plugins/config/lang/fi/lang.php6
-rw-r--r--lib/plugins/config/lang/fr/lang.php1
-rw-r--r--lib/plugins/config/lang/gl/lang.php22
-rw-r--r--lib/plugins/config/lang/it/lang.php1
-rw-r--r--lib/plugins/config/lang/ja/lang.php7
-rw-r--r--lib/plugins/config/lang/ko/intro.txt4
-rw-r--r--lib/plugins/config/lang/ko/lang.php59
-rw-r--r--lib/plugins/config/lang/lv/lang.php1
-rw-r--r--lib/plugins/config/lang/nl/lang.php2
-rw-r--r--lib/plugins/config/lang/pt-br/lang.php1
-rw-r--r--lib/plugins/config/lang/ru/lang.php1
-rw-r--r--lib/plugins/config/lang/sv/lang.php100
-rw-r--r--lib/plugins/config/lang/zh-tw/lang.php26
-rw-r--r--lib/plugins/config/plugin.info.txt2
-rw-r--r--lib/plugins/config/settings/config.class.php267
-rw-r--r--lib/plugins/config/settings/config.metadata.php21
-rw-r--r--lib/plugins/config/settings/extra.class.php48
-rw-r--r--lib/plugins/config/style.css13
-rw-r--r--lib/plugins/info/lang/sl/lang.php12
-rw-r--r--lib/plugins/info/plugin.info.txt2
-rw-r--r--lib/plugins/info/syntax.php9
-rw-r--r--lib/plugins/plugin/admin.php3
-rw-r--r--lib/plugins/plugin/lang/ar/lang.php2
-rw-r--r--lib/plugins/plugin/lang/cs/lang.php1
-rw-r--r--lib/plugins/plugin/lang/de-informal/lang.php2
-rw-r--r--lib/plugins/plugin/lang/el/lang.php1
-rw-r--r--lib/plugins/plugin/lang/fr/lang.php1
-rw-r--r--lib/plugins/plugin/lang/gl/lang.php2
-rw-r--r--lib/plugins/plugin/lang/hi/lang.php1
-rw-r--r--lib/plugins/plugin/lang/ja/lang.php1
-rw-r--r--lib/plugins/plugin/lang/ko/admin_plugin.txt4
-rw-r--r--lib/plugins/plugin/lang/ko/lang.php21
-rw-r--r--lib/plugins/plugin/lang/pl/lang.php2
-rw-r--r--lib/plugins/plugin/lang/pt-br/lang.php1
-rw-r--r--lib/plugins/plugin/lang/ru/lang.php1
-rw-r--r--lib/plugins/plugin/lang/sv/lang.php2
-rw-r--r--lib/plugins/plugin/lang/zh-tw/lang.php2
-rw-r--r--lib/plugins/plugin/plugin.info.txt2
-rw-r--r--lib/plugins/popularity/lang/cs/lang.php1
-rw-r--r--lib/plugins/popularity/lang/de-informal/lang.php2
-rw-r--r--lib/plugins/popularity/lang/el/lang.php1
-rw-r--r--lib/plugins/popularity/lang/fr/lang.php1
-rw-r--r--lib/plugins/popularity/lang/gl/lang.php2
-rw-r--r--lib/plugins/popularity/lang/ja/lang.php1
-rw-r--r--lib/plugins/popularity/lang/ko/intro.txt6
-rw-r--r--lib/plugins/popularity/lang/ko/lang.php15
-rw-r--r--lib/plugins/popularity/lang/ko/submitted.txt2
-rw-r--r--lib/plugins/popularity/lang/pt-br/lang.php1
-rw-r--r--lib/plugins/popularity/lang/ru/lang.php1
-rw-r--r--lib/plugins/popularity/lang/sv/lang.php1
-rw-r--r--lib/plugins/popularity/lang/zh-tw/intro.txt4
-rw-r--r--lib/plugins/popularity/lang/zh-tw/lang.php2
-rw-r--r--lib/plugins/popularity/plugin.info.txt2
-rw-r--r--lib/plugins/revert/admin.php15
-rw-r--r--lib/plugins/revert/lang/cs/lang.php1
-rw-r--r--lib/plugins/revert/lang/de-informal/lang.php2
-rw-r--r--lib/plugins/revert/lang/el/lang.php1
-rw-r--r--lib/plugins/revert/lang/fr/lang.php1
-rw-r--r--lib/plugins/revert/lang/gl/lang.php2
-rw-r--r--lib/plugins/revert/lang/ja/lang.php1
-rw-r--r--lib/plugins/revert/lang/ko/intro.txt4
-rw-r--r--lib/plugins/revert/lang/ko/lang.php21
-rw-r--r--lib/plugins/revert/lang/pt-br/lang.php1
-rw-r--r--lib/plugins/revert/lang/ru/lang.php1
-rw-r--r--lib/plugins/revert/lang/sv/lang.php1
-rw-r--r--lib/plugins/revert/lang/zh-tw/lang.php2
-rw-r--r--lib/plugins/revert/plugin.info.txt2
-rw-r--r--lib/plugins/safefnrecode/plugin.info.txt2
-rw-r--r--lib/plugins/syntax.php106
-rw-r--r--lib/plugins/testing/plugin.info.txt2
-rw-r--r--lib/plugins/usermanager/admin.php29
-rw-r--r--lib/plugins/usermanager/lang/ca-valencia/lang.php2
-rw-r--r--lib/plugins/usermanager/lang/cs/lang.php1
-rw-r--r--lib/plugins/usermanager/lang/de-informal/lang.php2
-rw-r--r--lib/plugins/usermanager/lang/el/lang.php1
-rw-r--r--lib/plugins/usermanager/lang/fr/lang.php1
-rw-r--r--lib/plugins/usermanager/lang/gl/lang.php2
-rw-r--r--lib/plugins/usermanager/lang/ja/lang.php9
-rw-r--r--lib/plugins/usermanager/lang/ko/add.txt2
-rw-r--r--lib/plugins/usermanager/lang/ko/delete.txt2
-rw-r--r--lib/plugins/usermanager/lang/ko/edit.txt2
-rw-r--r--lib/plugins/usermanager/lang/ko/intro.txt2
-rw-r--r--lib/plugins/usermanager/lang/ko/lang.php33
-rw-r--r--lib/plugins/usermanager/lang/ko/list.txt2
-rw-r--r--lib/plugins/usermanager/lang/nl/lang.php2
-rw-r--r--lib/plugins/usermanager/lang/pt-br/lang.php1
-rw-r--r--lib/plugins/usermanager/lang/ru/lang.php1
-rw-r--r--lib/plugins/usermanager/lang/sv/lang.php1
-rw-r--r--lib/plugins/usermanager/lang/zh-tw/lang.php4
-rw-r--r--lib/plugins/usermanager/plugin.info.txt2
220 files changed, 9888 insertions, 582 deletions
diff --git a/lib/plugins/acl/lang/cs/lang.php b/lib/plugins/acl/lang/cs/lang.php
index feb160a02..a4e59287a 100644
--- a/lib/plugins/acl/lang/cs/lang.php
+++ b/lib/plugins/acl/lang/cs/lang.php
@@ -12,6 +12,7 @@
* @author zbynek.krivka@seznam.cz
* @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com>
* @author Jakub A. Těšínský (j@kub.cz)
+ * @author mkucera66@seznam.cz
*/
$lang['admin_acl'] = 'Správa přístupových práv';
$lang['acl_group'] = 'Skupina';
diff --git a/lib/plugins/acl/lang/de-informal/lang.php b/lib/plugins/acl/lang/de-informal/lang.php
index 05f7df037..45a993982 100644
--- a/lib/plugins/acl/lang/de-informal/lang.php
+++ b/lib/plugins/acl/lang/de-informal/lang.php
@@ -8,6 +8,8 @@
* @author Matthias Schulte <dokuwiki@lupo49.de>
* @author Christian Wichmann <nospam@zone0.de>
* @author Pierre Corell <info@joomla-praxis.de>
+ * @author Frank Loizzi <contact@software.bacal.de>
+ * @author Volker Bödker <volker@boedker.de>
*/
$lang['admin_acl'] = 'Zugangsverwaltung';
$lang['acl_group'] = 'Gruppe';
diff --git a/lib/plugins/acl/lang/el/lang.php b/lib/plugins/acl/lang/el/lang.php
index e1cd26755..516d7bdf5 100644
--- a/lib/plugins/acl/lang/el/lang.php
+++ b/lib/plugins/acl/lang/el/lang.php
@@ -14,6 +14,7 @@
* @author Konstantinos Koryllos <koryllos@gmail.com>
* @author George Petsagourakis <petsagouris@gmail.com>
* @author Petros Vidalis <pvidalis@gmail.com>
+ * @author Vasileios Karavasilis vasileioskaravasilis@gmail.com
*/
$lang['admin_acl'] = 'Διαχείριση Δικαιωμάτων Πρόσβασης';
$lang['acl_group'] = 'Ομάδα';
diff --git a/lib/plugins/acl/lang/en/help.txt b/lib/plugins/acl/lang/en/help.txt
index 2b80cc4c7..e865bbb23 100644
--- a/lib/plugins/acl/lang/en/help.txt
+++ b/lib/plugins/acl/lang/en/help.txt
@@ -1,12 +1,9 @@
=== Quick Help: ===
On this page you can add and remove permissions for namespaces and pages in your wiki.
-
-The left pane displays all available namespaces and pages.
-
-The form above allows you to see and modify the permissions of a selected user or group.
-
-In the table below all currently set access control rules are shown. You can use it to quickly delete or change multiple rules.
+ * The left pane displays all available namespaces and pages.
+ * The form above allows you to see and modify the permissions of a selected user or group.
+ * In the table below all currently set access control rules are shown. You can use it to quickly delete or change multiple rules.
Reading the [[doku>acl|official documentation on ACL]] might help you to fully understand how access control works in DokuWiki.
diff --git a/lib/plugins/acl/lang/fr/lang.php b/lib/plugins/acl/lang/fr/lang.php
index e52bf51a0..538dd14d3 100644
--- a/lib/plugins/acl/lang/fr/lang.php
+++ b/lib/plugins/acl/lang/fr/lang.php
@@ -25,6 +25,7 @@
* @author Yannick Aure <yannick.aure@gmail.com>
* @author Olivier DUVAL <zorky00@gmail.com>
* @author Anael Mobilia <contrib@anael.eu>
+ * @author Bruno Veilleux <bruno.vey@gmail.com>
*/
$lang['admin_acl'] = 'Gestion de la liste des contrôles d\'accès (ACL)';
$lang['acl_group'] = 'Groupe';
diff --git a/lib/plugins/acl/lang/gl/lang.php b/lib/plugins/acl/lang/gl/lang.php
index 537e03eef..3325bfd07 100644
--- a/lib/plugins/acl/lang/gl/lang.php
+++ b/lib/plugins/acl/lang/gl/lang.php
@@ -4,7 +4,7 @@
*
* @author Medúlio <medulio@ciberirmandade.org>
* @author Oscar M. Lage <r0sk10@gmail.com>
- * @author Leandro Regueiro <leandro.regueiro@gmail.com>
+ * @author Rodrigo Rega <rodrigorega@gmail.com>
*/
$lang['admin_acl'] = 'Xestión da Lista de Control de Acceso (ACL)';
$lang['acl_group'] = 'Grupo';
diff --git a/lib/plugins/acl/lang/ja/lang.php b/lib/plugins/acl/lang/ja/lang.php
index 5bebb58a9..0dd4d09c6 100644
--- a/lib/plugins/acl/lang/ja/lang.php
+++ b/lib/plugins/acl/lang/ja/lang.php
@@ -9,6 +9,7 @@
* @author Daniel Dupriest <kououken@gmail.com>
* @author Kazutaka Miyasaka <kazmiya@gmail.com>
* @author Taisuke Shimamoto <dentostar@gmail.com>
+ * @author Satoshi Sahara <sahara.satoshi@gmail.com>
*/
$lang['admin_acl'] = 'アクセスコントロール管理';
$lang['acl_group'] = 'グループ';
diff --git a/lib/plugins/acl/lang/ko/help.txt b/lib/plugins/acl/lang/ko/help.txt
index 6a15b7a2e..0386b5990 100644
--- a/lib/plugins/acl/lang/ko/help.txt
+++ b/lib/plugins/acl/lang/ko/help.txt
@@ -1,11 +1,8 @@
=== 빠른 도움말: ===
현재 문서에서 위키 이름공간과 문서에 대한 접근 권한을 추가하거나 삭제할 수 있습니다.
+* 왼쪽 영역에는 선택 가능한 이름공간과 문서 목록을 보여줍니다.
+* 위쪽 입력 양식에서 선택된 사용자와 그룹의 접근 권한을 보거나 바꿀 수 있습니다.
+* 아래 테이블에서 현재 설정된 모든 접근 제어 규칙을 볼 수 있으며, 즉시 여러 규칙을 삭제하거나 바꿀 수 있습니다.
-왼쪽 영역에는 선택 가능한 이름공간과 문서 목록을 보여줍니다.
-
-위쪽 입력 양식에서 선택된 사용자와 그룹의 접근 권한을 보거나 바꿀 수 있습니다.
-
-아래 테이블에서 현재 설정된 모든 접근 제어 규칙을 볼 수 있으며, 즉시 여러 규칙을 삭제하거나 바꿀 수 있습니다.
-
-DokuWiki에서 접근 제어가 어떻게 동작되는지 알아보려면 [[doku>acl|ACL 공식 문서]]를 읽어보기 바랍니다. \ No newline at end of file
+DokuWiki에서 접근 제어가 어떻게 동작되는지 알아보려면 [[doku>acl|ACL 공식 문서]]를 읽어보시기 바랍니다. \ No newline at end of file
diff --git a/lib/plugins/acl/lang/ko/lang.php b/lib/plugins/acl/lang/ko/lang.php
index 5d2662ef8..7c1e9a43d 100644
--- a/lib/plugins/acl/lang/ko/lang.php
+++ b/lib/plugins/acl/lang/ko/lang.php
@@ -1,16 +1,15 @@
<?php
/**
- * korean language file
+ * Korean language file
*
- * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Gohr <andi@splitbrain.org>
* @author Anika Henke <anika@selfthinker.org>
* @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
* @author jk Lee
* @author dongnak@gmail.com
* @author Song Younghwan <purluno@gmail.com>
- * @author SONG Younghwan <purluno@gmail.com>
- * @author Seung-Chul Yoo <dryoo@live.com>
+ * @author Seung-Chul Yoo <dryoo@live.com>
* @author erial2@gmail.com
* @author Myeongjin <aranet100@gmail.com>
*/
@@ -25,8 +24,8 @@ $lang['p_user_id'] = '<b class="acluser">%s</b> 사용자는 현재
$lang['p_user_ns'] = '<b class="acluser">%s</b> 사용자는 현재 <b class="aclns">%s</b>: <i>%s</i> 이름공간 접근이 가능합니다.';
$lang['p_group_id'] = '<b class="aclgroup">%s</b> 그룹 구성원은 현재 <b class="aclpage">%s</b>: <i>%s</i> 문서 접근이 가능합니다.';
$lang['p_group_ns'] = '<b class="aclgroup">%s</b> 그룹 구성원은 현재 <b class="aclns">%s</b>: <i>%s</i> 이름공간 접근이 가능합니다.';
-$lang['p_choose_id'] = '<b class="aclpage">%s</b> 문서 접근 권한을 보거나 바꾸려면 <b>사용자</b>나 <b>그룹</b>을 위 양식에 입력하기 바랍니다.';
-$lang['p_choose_ns'] = '<b class="aclns">%s</b> 이름공간 접근 권한을 보거나 바꾸려면 <b>사용자</b>나 <b>그룹</b>을 위 양식에 입력하기 바랍니다.';
+$lang['p_choose_id'] = '<b class="aclpage">%s</b> 문서 접근 권한을 보거나 바꾸려면 <b>사용자</b>나 <b>그룹</b>을 위 양식에 입력하세요.';
+$lang['p_choose_ns'] = '<b class="aclns">%s</b> 이름공간 접근 권한을 보거나 바꾸려면 <b>사용자</b>나 <b>그룹</b>을 위 양식에 입력하세요.';
$lang['p_inherited'] = '참고: 권한이 명시적으로 설정되지 않았으므로 다른 그룹이나 상위 이름공간으로부터 가져왔습니다.';
$lang['p_isadmin'] = '참고: 슈퍼유저로 설정되어 있으므로 선택된 그룹이나 사용자는 언제나 모든 접근 권한을 가집니다.';
$lang['p_include'] = '더 높은 접근 권한은 하위를 포함합니다. 문서가 아닌 이름공간에는 만들기, 올리기, 삭제 권한만 적용됩니다.';
@@ -41,4 +40,4 @@ $lang['acl_perm4'] = '만들기';
$lang['acl_perm8'] = '올리기';
$lang['acl_perm16'] = '삭제';
$lang['acl_new'] = '새 항목 추가';
-$lang['acl_mod'] = '선택 항목 수정';
+$lang['acl_mod'] = '항목 수정';
diff --git a/lib/plugins/acl/lang/nl/help.txt b/lib/plugins/acl/lang/nl/help.txt
index 255f21ba0..14c78e20a 100644
--- a/lib/plugins/acl/lang/nl/help.txt
+++ b/lib/plugins/acl/lang/nl/help.txt
@@ -1,11 +1,8 @@
=== Snelle hulp: ===
Op deze pagina kun je bevoegdheden toevoegen en verwijderen voor namespaces en pagina's in je wiki.
-
-Het linkerpaneel geeft alle beschikbare namespaces en pagina's weer.
-
-In het formulier hierboven kun je bevoegdheden zien en aanpassen voor een selecteerde gebruiker of groep.
-
-In de tabel hieronder worden alle momenteel ingestelde toegangsregels weergegeven. Je kunt hier snel regels wijzigen of verwijderen.
+ * Het linkerpaneel geeft alle beschikbare namespaces en pagina's weer.
+ * In het formulier hierboven kun je bevoegdheden zien en aanpassen voor een selecteerde gebruiker of groep.
+ * In de tabel hieronder worden alle momenteel ingestelde toegangsregels weergegeven. Je kunt hier snel regels wijzigen of verwijderen.
Lees de [[doku>acl|documentatie over ACLs]] om de mogelijkheden volledig te begrijpen.
diff --git a/lib/plugins/acl/lang/pt-br/lang.php b/lib/plugins/acl/lang/pt-br/lang.php
index a0c997600..c49b430f8 100644
--- a/lib/plugins/acl/lang/pt-br/lang.php
+++ b/lib/plugins/acl/lang/pt-br/lang.php
@@ -19,6 +19,7 @@
* @author Sergio Motta sergio@cisne.com.br
* @author Isaias Masiero Filho <masiero@masiero.org>
* @author Balaco Baco <balacobaco@imap.cc>
+ * @author Victor Westmann <victor.westmann@gmail.com>
*/
$lang['admin_acl'] = 'Administração da Lista de Controles de Acesso';
$lang['acl_group'] = 'Grupo';
diff --git a/lib/plugins/acl/lang/ru/lang.php b/lib/plugins/acl/lang/ru/lang.php
index 15ba78ef6..2501c00e2 100644
--- a/lib/plugins/acl/lang/ru/lang.php
+++ b/lib/plugins/acl/lang/ru/lang.php
@@ -16,6 +16,7 @@
* @author Ladyko Andrey <fylh@succexy.spb.ru>
* @author Eugene <windy.wanderer@gmail.com>
* @author Johnny Utah <pcpa@cyberpunk.su>
+ * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua)
*/
$lang['admin_acl'] = 'Управление списками контроля доступа';
$lang['acl_group'] = 'Группа';
diff --git a/lib/plugins/acl/lang/sv/lang.php b/lib/plugins/acl/lang/sv/lang.php
index 7f963d5e1..388672fc0 100644
--- a/lib/plugins/acl/lang/sv/lang.php
+++ b/lib/plugins/acl/lang/sv/lang.php
@@ -16,6 +16,7 @@
* @author Peter Åström <eaustreum@gmail.com>
* @author Håkan Sandell <hakan.sandell@home.se>
* @author mikael@mallander.net
+ * @author Smorkster Andersson smorkster@gmail.com
*/
$lang['admin_acl'] = 'Hantera behörighetslistan (ACL)';
$lang['acl_group'] = 'Grupp';
diff --git a/lib/plugins/acl/lang/vi/help.txt b/lib/plugins/acl/lang/vi/help.txt
index 23e258678..816e5ee71 100644
--- a/lib/plugins/acl/lang/vi/help.txt
+++ b/lib/plugins/acl/lang/vi/help.txt
@@ -1,12 +1,12 @@
-=== Trợ giúp nhanh: ===
-
-Trang này giúp bạn thêm hoặc xóa quyền được cấp cho 1 thư mục hoặc trang wiki của bạn.
-
-Của sổ bên trái hiển thị tất cả các thư mục và trang văn bản.
-
-Khung trên đây cho phép bạn xem và sửa quyền của một nhóm hoặc thành viên đã chọn.
-
-Bảng bên dưới hiển thị tất cả các quyền được cấp. Bạn có thể sửa hoặc hóa các quyền đó một cách nhanh chóng.
-
-Đọc [[doku>acl|tài liệu chính thức về ACL]] sẽ giúp bạn hiểu hơn về cách phân quyền ở DokuWiki.
-
+=== Trợ giúp nhanh: ===
+
+Trang này giúp bạn thêm hoặc xóa quyền được cấp cho 1 thư mục hoặc trang wiki của bạn.
+
+Của sổ bên trái hiển thị tất cả các thư mục và trang văn bản.
+
+Khung trên đây cho phép bạn xem và sửa quyền của một nhóm hoặc thành viên đã chọn.
+
+Bảng bên dưới hiển thị tất cả các quyền được cấp. Bạn có thể sửa hoặc hóa các quyền đó một cách nhanh chóng.
+
+Đọc [[doku>acl|tài liệu chính thức về ACL]] sẽ giúp bạn hiểu hơn về cách phân quyền ở DokuWiki.
+
diff --git a/lib/plugins/acl/plugin.info.txt b/lib/plugins/acl/plugin.info.txt
index 42babd71c..029dc82e7 100644
--- a/lib/plugins/acl/plugin.info.txt
+++ b/lib/plugins/acl/plugin.info.txt
@@ -1,7 +1,7 @@
base acl
author Andreas Gohr
email andi@splitbrain.org
-date 2012-09-06
+date 2013-02-17
name ACL Manager
desc Manage Page Access Control Lists
url http://dokuwiki.org/plugin:acl
diff --git a/lib/plugins/acl/script.js b/lib/plugins/acl/script.js
index 0ba91cdc9..c3763dc8d 100644
--- a/lib/plugins/acl/script.js
+++ b/lib/plugins/acl/script.js
@@ -117,11 +117,3 @@ var dw_acl = {
};
jQuery(dw_acl.init);
-
-var acl = {
- init: DEPRECATED_WRAP(dw_acl.init, dw_acl),
- userselhandler: DEPRECATED_WRAP(dw_acl.userselhandler, dw_acl),
- loadinfo: DEPRECATED_WRAP(dw_acl.loadinfo, dw_acl),
- parseatt: DEPRECATED_WRAP(dw_acl.parseatt, dw_acl),
- treehandler: DEPRECATED_WRAP(dw_acl.treehandler, dw_acl)
-};
diff --git a/lib/plugins/acl/style.css b/lib/plugins/acl/style.css
index f4277c341..d8f0b53f3 100644
--- a/lib/plugins/acl/style.css
+++ b/lib/plugins/acl/style.css
@@ -1,5 +1,5 @@
-div#acl_manager div#acl__tree {
+#acl__tree {
font-size: 90%;
width: 25%;
height: 300px;
@@ -8,61 +8,61 @@ div#acl_manager div#acl__tree {
border: 1px solid __border__;
text-align: left;
}
-[dir=rtl] div#acl_manager div#acl__tree {
+[dir=rtl] #acl__tree {
float: right;
text-align: right;
}
-div#acl_manager div#acl__tree a.cur {
+#acl__tree a.cur {
background-color: __highlight__;
font-weight: bold;
}
-div#acl_manager div#acl__tree ul {
+#acl__tree ul {
list-style-type: none;
margin: 0;
padding: 0;
}
-div#acl_manager div#acl__tree li {
+#acl__tree li {
padding-left: 1em;
list-style-image: none;
}
-[dir=rtl] div#acl_manager div#acl__tree li {
+[dir=rtl] #acl__tree li {
padding-left: 0em;
padding-right: 1em;
}
-div#acl_manager div#acl__tree ul img {
+#acl__tree ul img {
margin-right: 0.25em;
cursor: pointer;
}
-[dir=rtl] div#acl_manager div#acl__tree ul img {
+[dir=rtl] #acl__tree ul img {
margin-left: 0.25em;
margin-right: 0em;
}
-div#acl_manager div#acl__detail {
+#acl__detail {
width: 73%;
height: 300px;
float: right;
overflow: auto;
}
-[dir=rtl] div#acl_manager div#acl__detail {
+[dir=rtl] #acl__detail {
float: left;
}
-div#acl_manager div#acl__detail fieldset {
+#acl__detail fieldset {
width: 90%;
}
-div#acl_manager div#acl__detail div#acl__user {
+#acl__detail div#acl__user {
border: 1px solid __border__;
padding: 0.5em;
margin-bottom: 0.6em;
}
-div#acl_manager table.inline {
+#acl_manager table.inline {
width: 100%;
margin: 0;
}
@@ -75,59 +75,60 @@ div#acl_manager table.inline {
text-align: right;
}
-div#acl_manager .aclgroup {
+#acl_manager .aclgroup {
background: transparent url(pix/group.png) 0px 1px no-repeat;
padding: 1px 0px 1px 18px;
}
-[dir=rtl] div#acl_manager .aclgroup {
+[dir=rtl] #acl_manager .aclgroup {
background: transparent url(pix/group.png) right 1px no-repeat;
padding: 1px 18px 1px 0px;
display: inline-block; /* needed for IE7 */
}
-div#acl_manager .acluser {
+#acl_manager .acluser {
background: transparent url(pix/user.png) 0px 1px no-repeat;
padding: 1px 0px 1px 18px;
}
-[dir=rtl] div#acl_manager .acluser {
+[dir=rtl] #acl_manager .acluser {
background: transparent url(pix/user.png) right 1px no-repeat;
padding: 1px 18px 1px 0px;
display: inline-block; /* needed for IE7 */
}
-div#acl_manager .aclpage {
+#acl_manager .aclpage {
background: transparent url(pix/page.png) 0px 1px no-repeat;
padding: 1px 0px 1px 18px;
}
-[dir=rtl] div#acl_manager .aclpage {
+[dir=rtl] #acl_manager .aclpage {
background: transparent url(pix/page.png) right 1px no-repeat;
padding: 1px 18px 1px 0px;
display: inline-block; /* needed for IE7 */
}
-div#acl_manager .aclns {
+#acl_manager .aclns {
background: transparent url(pix/ns.png) 0px 1px no-repeat;
padding: 1px 0px 1px 18px;
}
-[dir=rtl] div#acl_manager .aclns {
+[dir=rtl] #acl_manager .aclns {
background: transparent url(pix/ns.png) right 1px no-repeat;
padding: 1px 18px 1px 0px;
display: inline-block; /* needed for IE7 */
}
-div#acl_manager label.disabled {
- color: __text_neu__!important;
+#acl_manager label.disabled {
+ opacity: .5;
+ cursor: auto;
}
#acl_manager label {
- text-align: left;
- font-weight: normal;
- display: inline;
+ text-align: left;
+ font-weight: normal;
+ display: inline;
}
#acl_manager table {
- margin-left: 10%;
- width: 80%;
+ margin-left: 10%;
+ width: 80%;
}
#acl_manager table tr {
diff --git a/lib/plugins/auth.php b/lib/plugins/auth.php
new file mode 100644
index 000000000..ec8ed7e58
--- /dev/null
+++ b/lib/plugins/auth.php
@@ -0,0 +1,441 @@
+<?php
+// must be run within Dokuwiki
+if(!defined('DOKU_INC')) die();
+
+/**
+ * Auth Plugin Prototype
+ *
+ * foundation authorisation class
+ * all auth classes should inherit from this class
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @author Jan Schumann <js@jschumann-it.com>
+ */
+class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
+ public $success = true;
+
+ /**
+ * Possible things an auth backend module may be able to
+ * do. The things a backend can do need to be set to true
+ * in the constructor.
+ */
+ protected $cando = array(
+ 'addUser' => false, // can Users be created?
+ 'delUser' => false, // can Users be deleted?
+ 'modLogin' => false, // can login names be changed?
+ 'modPass' => false, // can passwords be changed?
+ 'modName' => false, // can real names be changed?
+ 'modMail' => false, // can emails be changed?
+ 'modGroups' => false, // can groups be changed?
+ 'getUsers' => false, // can a (filtered) list of users be retrieved?
+ 'getUserCount' => false, // can the number of users be retrieved?
+ 'getGroups' => false, // can a list of available groups be retrieved?
+ 'external' => false, // does the module do external auth checking?
+ 'logout' => true, // can the user logout again? (eg. not possible with HTTP auth)
+ );
+
+ /**
+ * Constructor.
+ *
+ * Carry out sanity checks to ensure the object is
+ * able to operate. Set capabilities in $this->cando
+ * array here
+ *
+ * For future compatibility, sub classes should always include a call
+ * to parent::__constructor() in their constructors!
+ *
+ * Set $this->success to false if checks fail
+ *
+ * @author Christopher Smith <chris@jalakai.co.uk>
+ */
+ public function __construct() {
+ // the base class constructor does nothing, derived class
+ // constructors do the real work
+ }
+
+ /**
+ * Capability check. [ DO NOT OVERRIDE ]
+ *
+ * Checks the capabilities set in the $this->cando array and
+ * some pseudo capabilities (shortcutting access to multiple
+ * ones)
+ *
+ * ususal capabilities start with lowercase letter
+ * shortcut capabilities start with uppercase letter
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param string $cap the capability to check
+ * @return bool
+ */
+ public function canDo($cap) {
+ switch($cap) {
+ case 'Profile':
+ // can at least one of the user's properties be changed?
+ return ($this->cando['modPass'] ||
+ $this->cando['modName'] ||
+ $this->cando['modMail']);
+ break;
+ case 'UserMod':
+ // can at least anything be changed?
+ return ($this->cando['modPass'] ||
+ $this->cando['modName'] ||
+ $this->cando['modMail'] ||
+ $this->cando['modLogin'] ||
+ $this->cando['modGroups'] ||
+ $this->cando['modMail']);
+ break;
+ default:
+ // print a helping message for developers
+ if(!isset($this->cando[$cap])) {
+ msg("Check for unknown capability '$cap' - Do you use an outdated Plugin?", -1);
+ }
+ return $this->cando[$cap];
+ }
+ }
+
+ /**
+ * Trigger the AUTH_USERDATA_CHANGE event and call the modification function. [ DO NOT OVERRIDE ]
+ *
+ * You should use this function instead of calling createUser, modifyUser or
+ * deleteUsers directly. The event handlers can prevent the modification, for
+ * example for enforcing a user name schema.
+ *
+ * @author Gabriel Birke <birke@d-scribe.de>
+ * @param string $type Modification type ('create', 'modify', 'delete')
+ * @param array $params Parameters for the createUser, modifyUser or deleteUsers method. The content of this array depends on the modification type
+ * @return mixed Result from the modification function or false if an event handler has canceled the action
+ */
+ public function triggerUserMod($type, $params) {
+ $validTypes = array(
+ 'create' => 'createUser',
+ 'modify' => 'modifyUser',
+ 'delete' => 'deleteUsers'
+ );
+ if(empty($validTypes[$type]))
+ return false;
+ $eventdata = array('type' => $type, 'params' => $params, 'modification_result' => null);
+ $evt = new Doku_Event('AUTH_USER_CHANGE', $eventdata);
+ if($evt->advise_before(true)) {
+ $result = call_user_func_array(array($this, $validTypes[$type]), $params);
+ $evt->data['modification_result'] = $result;
+ }
+ $evt->advise_after();
+ unset($evt);
+ return $result;
+ }
+
+ /**
+ * Log off the current user [ OPTIONAL ]
+ *
+ * Is run in addition to the ususal logoff method. Should
+ * only be needed when trustExternal is implemented.
+ *
+ * @see auth_logoff()
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+ public function logOff() {
+ }
+
+ /**
+ * Do all authentication [ OPTIONAL ]
+ *
+ * Set $this->cando['external'] = true when implemented
+ *
+ * If this function is implemented it will be used to
+ * authenticate a user - all other DokuWiki internals
+ * will not be used for authenticating, thus
+ * implementing the checkPass() function is not needed
+ * anymore.
+ *
+ * The function can be used to authenticate against third
+ * party cookies or Apache auth mechanisms and replaces
+ * the auth_login() function
+ *
+ * The function will be called with or without a set
+ * username. If the Username is given it was called
+ * from the login form and the given credentials might
+ * need to be checked. If no username was given it
+ * the function needs to check if the user is logged in
+ * by other means (cookie, environment).
+ *
+ * The function needs to set some globals needed by
+ * DokuWiki like auth_login() does.
+ *
+ * @see auth_login()
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ * @param string $user Username
+ * @param string $pass Cleartext Password
+ * @param bool $sticky Cookie should not expire
+ * @return bool true on successful auth
+ */
+ public function trustExternal($user, $pass, $sticky = false) {
+ /* some example:
+
+ global $USERINFO;
+ global $conf;
+ $sticky ? $sticky = true : $sticky = false; //sanity check
+
+ // do the checking here
+
+ // set the globals if authed
+ $USERINFO['name'] = 'FIXME';
+ $USERINFO['mail'] = 'FIXME';
+ $USERINFO['grps'] = array('FIXME');
+ $_SERVER['REMOTE_USER'] = $user;
+ $_SESSION[DOKU_COOKIE]['auth']['user'] = $user;
+ $_SESSION[DOKU_COOKIE]['auth']['pass'] = $pass;
+ $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO;
+ return true;
+
+ */
+ }
+
+ /**
+ * Check user+password [ MUST BE OVERRIDDEN ]
+ *
+ * Checks if the given user exists and the given
+ * plaintext password is correct
+ *
+ * May be ommited if trustExternal is used.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param string $user the user name
+ * @param string $pass the clear text password
+ * @return bool
+ */
+ public function checkPass($user, $pass) {
+ msg("no valid authorisation system in use", -1);
+ return false;
+ }
+
+ /**
+ * Return user info [ MUST BE OVERRIDDEN ]
+ *
+ * Returns info about the given user needs to contain
+ * at least these fields:
+ *
+ * name string full name of the user
+ * mail string email addres of the user
+ * grps array list of groups the user is in
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param string $user the user name
+ * @return array containing user data or false
+ */
+ public function getUserData($user) {
+ if(!$this->cando['external']) msg("no valid authorisation system in use", -1);
+ return false;
+ }
+
+ /**
+ * Create a new User [implement only where required/possible]
+ *
+ * Returns false if the user already exists, null when an error
+ * occurred and true if everything went well.
+ *
+ * The new user HAS TO be added to the default group by this
+ * function!
+ *
+ * Set addUser capability when implemented
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param string $user
+ * @param string $pass
+ * @param string $name
+ * @param string $mail
+ * @param null|array $grps
+ * @return bool|null
+ */
+ public function createUser($user, $pass, $name, $mail, $grps = null) {
+ msg("authorisation method does not allow creation of new users", -1);
+ return null;
+ }
+
+ /**
+ * Modify user data [implement only where required/possible]
+ *
+ * Set the mod* capabilities according to the implemented features
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @param string $user nick of the user to be changed
+ * @param array $changes array of field/value pairs to be changed (password will be clear text)
+ * @return bool
+ */
+ public function modifyUser($user, $changes) {
+ msg("authorisation method does not allow modifying of user data", -1);
+ return false;
+ }
+
+ /**
+ * Delete one or more users [implement only where required/possible]
+ *
+ * Set delUser capability when implemented
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @param array $users
+ * @return int number of users deleted
+ */
+ public function deleteUsers($users) {
+ msg("authorisation method does not allow deleting of users", -1);
+ return false;
+ }
+
+ /**
+ * Return a count of the number of user which meet $filter criteria
+ * [should be implemented whenever retrieveUsers is implemented]
+ *
+ * Set getUserCount capability when implemented
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @param array $filter array of field/pattern pairs, empty array for no filter
+ * @return int
+ */
+ public function getUserCount($filter = array()) {
+ msg("authorisation method does not provide user counts", -1);
+ return 0;
+ }
+
+ /**
+ * Bulk retrieval of user data [implement only where required/possible]
+ *
+ * Set getUsers capability when implemented
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @param int $start index of first user to be returned
+ * @param int $limit max number of users to be returned
+ * @param array $filter array of field/pattern pairs, null for no filter
+ * @return array list of userinfo (refer getUserData for internal userinfo details)
+ */
+ public function retrieveUsers($start = 0, $limit = -1, $filter = null) {
+ msg("authorisation method does not support mass retrieval of user data", -1);
+ return array();
+ }
+
+ /**
+ * Define a group [implement only where required/possible]
+ *
+ * Set addGroup capability when implemented
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @param string $group
+ * @return bool
+ */
+ public function addGroup($group) {
+ msg("authorisation method does not support independent group creation", -1);
+ return false;
+ }
+
+ /**
+ * Retrieve groups [implement only where required/possible]
+ *
+ * Set getGroups capability when implemented
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @param int $start
+ * @param int $limit
+ * @return array
+ */
+ public function retrieveGroups($start = 0, $limit = 0) {
+ msg("authorisation method does not support group list retrieval", -1);
+ return array();
+ }
+
+ /**
+ * Return case sensitivity of the backend [OPTIONAL]
+ *
+ * When your backend is caseinsensitive (eg. you can login with USER and
+ * user) then you need to overwrite this method and return false
+ *
+ * @return bool
+ */
+ public function isCaseSensitive() {
+ return true;
+ }
+
+ /**
+ * Sanitize a given username [OPTIONAL]
+ *
+ * This function is applied to any user name that is given to
+ * the backend and should also be applied to any user name within
+ * the backend before returning it somewhere.
+ *
+ * This should be used to enforce username restrictions.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param string $user username
+ * @return string the cleaned username
+ */
+ public function cleanUser($user) {
+ return $user;
+ }
+
+ /**
+ * Sanitize a given groupname [OPTIONAL]
+ *
+ * This function is applied to any groupname that is given to
+ * the backend and should also be applied to any groupname within
+ * the backend before returning it somewhere.
+ *
+ * This should be used to enforce groupname restrictions.
+ *
+ * Groupnames are to be passed without a leading '@' here.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param string $group groupname
+ * @return string the cleaned groupname
+ */
+ public function cleanGroup($group) {
+ return $group;
+ }
+
+ /**
+ * Check Session Cache validity [implement only where required/possible]
+ *
+ * DokuWiki caches user info in the user's session for the timespan defined
+ * in $conf['auth_security_timeout'].
+ *
+ * This makes sure slow authentication backends do not slow down DokuWiki.
+ * This also means that changes to the user database will not be reflected
+ * on currently logged in users.
+ *
+ * To accommodate for this, the user manager plugin will touch a reference
+ * file whenever a change is submitted. This function compares the filetime
+ * of this reference file with the time stored in the session.
+ *
+ * This reference file mechanism does not reflect changes done directly in
+ * the backend's database through other means than the user manager plugin.
+ *
+ * Fast backends might want to return always false, to force rechecks on
+ * each page load. Others might want to use their own checking here. If
+ * unsure, do not override.
+ *
+ * @param string $user - The username
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @return bool
+ */
+ public function useSessionCache($user) {
+ global $conf;
+ return ($_SESSION[DOKU_COOKIE]['auth']['time'] >= @filemtime($conf['cachedir'].'/sessionpurge'));
+ }
+
+ /**
+ * Overrides the standard config loading to integrate old auth module style configs
+ *
+ * @deprecated 2012-11-09
+ */
+ public function loadConfig() {
+ global $conf;
+ $plugin = $this->getPluginName();
+ $oldname = preg_replace('/^auth/', '', $plugin);
+
+ $default = $this->readDefaultSettings();
+ $oldconf = array();
+ if(isset($conf['auth'][$oldname])) $oldconf = (array) $conf['auth'][$oldname];
+ $conf['plugin'][$plugin] = array_merge($default, $oldconf, (array) $conf['plugin'][$plugin]);
+
+ $this->conf =& $conf['plugin'][$plugin];
+ $this->configloaded = true;
+ }
+}
diff --git a/lib/plugins/authad/adLDAP/adLDAP.php b/lib/plugins/authad/adLDAP/adLDAP.php
new file mode 100644
index 000000000..a8f33b47e
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/adLDAP.php
@@ -0,0 +1,951 @@
+<?php
+/**
+ * PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY
+ * Version 4.0.4
+ *
+ * PHP Version 5 with SSL and LDAP support
+ *
+ * Written by Scott Barnett, Richard Hyland
+ * email: scott@wiggumworld.com, adldap@richardhyland.com
+ * http://adldap.sourceforge.net/
+ *
+ * Copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ *
+ * We'd appreciate any improvements or additions to be submitted back
+ * to benefit the entire community :)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * @category ToolsAndUtilities
+ * @package adLDAP
+ * @author Scott Barnett, Richard Hyland
+ * @copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html LGPLv2.1
+ * @revision $Revision: 169 $
+ * @version 4.0.4
+ * @link http://adldap.sourceforge.net/
+ */
+
+/**
+* Main adLDAP class
+*
+* Can be initialised using $adldap = new adLDAP();
+*
+* Something to keep in mind is that Active Directory is a permissions
+* based directory. If you bind as a domain user, you can't fetch as
+* much information on other users as you could as a domain admin.
+*
+* Before asking questions, please read the Documentation at
+* http://adldap.sourceforge.net/wiki/doku.php?id=api
+*/
+require_once(dirname(__FILE__) . '/collections/adLDAPCollection.php');
+require_once(dirname(__FILE__) . '/classes/adLDAPGroups.php');
+require_once(dirname(__FILE__) . '/classes/adLDAPUsers.php');
+require_once(dirname(__FILE__) . '/classes/adLDAPFolders.php');
+require_once(dirname(__FILE__) . '/classes/adLDAPUtils.php');
+require_once(dirname(__FILE__) . '/classes/adLDAPContacts.php');
+require_once(dirname(__FILE__) . '/classes/adLDAPExchange.php');
+require_once(dirname(__FILE__) . '/classes/adLDAPComputers.php');
+
+class adLDAP {
+
+ /**
+ * Define the different types of account in AD
+ */
+ const ADLDAP_NORMAL_ACCOUNT = 805306368;
+ const ADLDAP_WORKSTATION_TRUST = 805306369;
+ const ADLDAP_INTERDOMAIN_TRUST = 805306370;
+ const ADLDAP_SECURITY_GLOBAL_GROUP = 268435456;
+ const ADLDAP_DISTRIBUTION_GROUP = 268435457;
+ const ADLDAP_SECURITY_LOCAL_GROUP = 536870912;
+ const ADLDAP_DISTRIBUTION_LOCAL_GROUP = 536870913;
+ const ADLDAP_FOLDER = 'OU';
+ const ADLDAP_CONTAINER = 'CN';
+
+ /**
+ * The default port for LDAP non-SSL connections
+ */
+ const ADLDAP_LDAP_PORT = '389';
+ /**
+ * The default port for LDAPS SSL connections
+ */
+ const ADLDAP_LDAPS_PORT = '636';
+
+ /**
+ * The account suffix for your domain, can be set when the class is invoked
+ *
+ * @var string
+ */
+ protected $accountSuffix = "@mydomain.local";
+
+ /**
+ * The base dn for your domain
+ *
+ * If this is set to null then adLDAP will attempt to obtain this automatically from the rootDSE
+ *
+ * @var string
+ */
+ protected $baseDn = "DC=mydomain,DC=local";
+
+ /**
+ * Port used to talk to the domain controllers.
+ *
+ * @var int
+ */
+ protected $adPort = self::ADLDAP_LDAP_PORT;
+
+ /**
+ * Array of domain controllers. Specifiy multiple controllers if you
+ * would like the class to balance the LDAP queries amongst multiple servers
+ *
+ * @var array
+ */
+ protected $domainControllers = array("dc01.mydomain.local");
+
+ /**
+ * Optional account with higher privileges for searching
+ * This should be set to a domain admin account
+ *
+ * @var string
+ * @var string
+ */
+ protected $adminUsername = NULL;
+ protected $adminPassword = NULL;
+
+ /**
+ * AD does not return the primary group. http://support.microsoft.com/?kbid=321360
+ * This tweak will resolve the real primary group.
+ * Setting to false will fudge "Domain Users" and is much faster. Keep in mind though that if
+ * someone's primary group is NOT domain users, this is obviously going to mess up the results
+ *
+ * @var bool
+ */
+ protected $realPrimaryGroup = true;
+
+ /**
+ * Use SSL (LDAPS), your server needs to be setup, please see
+ * http://adldap.sourceforge.net/wiki/doku.php?id=ldap_over_ssl
+ *
+ * @var bool
+ */
+ protected $useSSL = false;
+
+ /**
+ * Use TLS
+ * If you wish to use TLS you should ensure that $useSSL is set to false and vice-versa
+ *
+ * @var bool
+ */
+ protected $useTLS = false;
+
+ /**
+ * Use SSO
+ * To indicate to adLDAP to reuse password set by the brower through NTLM or Kerberos
+ *
+ * @var bool
+ */
+ protected $useSSO = false;
+
+ /**
+ * When querying group memberships, do it recursively
+ * eg. User Fred is a member of Group A, which is a member of Group B, which is a member of Group C
+ * user_ingroup("Fred","C") will returns true with this option turned on, false if turned off
+ *
+ * @var bool
+ */
+ protected $recursiveGroups = true;
+
+ // You should not need to edit anything below this line
+ //******************************************************************************************
+
+ /**
+ * Connection and bind default variables
+ *
+ * @var mixed
+ * @var mixed
+ */
+ protected $ldapConnection;
+ protected $ldapBind;
+
+ /**
+ * Get the active LDAP Connection
+ *
+ * @return resource
+ */
+ public function getLdapConnection() {
+ if ($this->ldapConnection) {
+ return $this->ldapConnection;
+ }
+ return false;
+ }
+
+ /**
+ * Get the bind status
+ *
+ * @return bool
+ */
+ public function getLdapBind() {
+ return $this->ldapBind;
+ }
+
+ /**
+ * Get the current base DN
+ *
+ * @return string
+ */
+ public function getBaseDn() {
+ return $this->baseDn;
+ }
+
+ /**
+ * The group class
+ *
+ * @var adLDAPGroups
+ */
+ protected $groupClass;
+
+ /**
+ * Get the group class interface
+ *
+ * @return adLDAPGroups
+ */
+ public function group() {
+ if (!$this->groupClass) {
+ $this->groupClass = new adLDAPGroups($this);
+ }
+ return $this->groupClass;
+ }
+
+ /**
+ * The user class
+ *
+ * @var adLDAPUsers
+ */
+ protected $userClass;
+
+ /**
+ * Get the userclass interface
+ *
+ * @return adLDAPUsers
+ */
+ public function user() {
+ if (!$this->userClass) {
+ $this->userClass = new adLDAPUsers($this);
+ }
+ return $this->userClass;
+ }
+
+ /**
+ * The folders class
+ *
+ * @var adLDAPFolders
+ */
+ protected $folderClass;
+
+ /**
+ * Get the folder class interface
+ *
+ * @return adLDAPFolders
+ */
+ public function folder() {
+ if (!$this->folderClass) {
+ $this->folderClass = new adLDAPFolders($this);
+ }
+ return $this->folderClass;
+ }
+
+ /**
+ * The utils class
+ *
+ * @var adLDAPUtils
+ */
+ protected $utilClass;
+
+ /**
+ * Get the utils class interface
+ *
+ * @return adLDAPUtils
+ */
+ public function utilities() {
+ if (!$this->utilClass) {
+ $this->utilClass = new adLDAPUtils($this);
+ }
+ return $this->utilClass;
+ }
+
+ /**
+ * The contacts class
+ *
+ * @var adLDAPContacts
+ */
+ protected $contactClass;
+
+ /**
+ * Get the contacts class interface
+ *
+ * @return adLDAPContacts
+ */
+ public function contact() {
+ if (!$this->contactClass) {
+ $this->contactClass = new adLDAPContacts($this);
+ }
+ return $this->contactClass;
+ }
+
+ /**
+ * The exchange class
+ *
+ * @var adLDAPExchange
+ */
+ protected $exchangeClass;
+
+ /**
+ * Get the exchange class interface
+ *
+ * @return adLDAPExchange
+ */
+ public function exchange() {
+ if (!$this->exchangeClass) {
+ $this->exchangeClass = new adLDAPExchange($this);
+ }
+ return $this->exchangeClass;
+ }
+
+ /**
+ * The computers class
+ *
+ * @var adLDAPComputers
+ */
+ protected $computersClass;
+
+ /**
+ * Get the computers class interface
+ *
+ * @return adLDAPComputers
+ */
+ public function computer() {
+ if (!$this->computerClass) {
+ $this->computerClass = new adLDAPComputers($this);
+ }
+ return $this->computerClass;
+ }
+
+ /**
+ * Getters and Setters
+ */
+
+ /**
+ * Set the account suffix
+ *
+ * @param string $accountSuffix
+ * @return void
+ */
+ public function setAccountSuffix($accountSuffix)
+ {
+ $this->accountSuffix = $accountSuffix;
+ }
+
+ /**
+ * Get the account suffix
+ *
+ * @return string
+ */
+ public function getAccountSuffix()
+ {
+ return $this->accountSuffix;
+ }
+
+ /**
+ * Set the domain controllers array
+ *
+ * @param array $domainControllers
+ * @return void
+ */
+ public function setDomainControllers(array $domainControllers)
+ {
+ $this->domainControllers = $domainControllers;
+ }
+
+ /**
+ * Get the list of domain controllers
+ *
+ * @return void
+ */
+ public function getDomainControllers()
+ {
+ return $this->domainControllers;
+ }
+
+ /**
+ * Sets the port number your domain controller communicates over
+ *
+ * @param int $adPort
+ */
+ public function setPort($adPort)
+ {
+ $this->adPort = $adPort;
+ }
+
+ /**
+ * Gets the port number your domain controller communicates over
+ *
+ * @return int
+ */
+ public function getPort()
+ {
+ return $this->adPort;
+ }
+
+ /**
+ * Set the username of an account with higher priviledges
+ *
+ * @param string $adminUsername
+ * @return void
+ */
+ public function setAdminUsername($adminUsername)
+ {
+ $this->adminUsername = $adminUsername;
+ }
+
+ /**
+ * Get the username of the account with higher priviledges
+ *
+ * This will throw an exception for security reasons
+ */
+ public function getAdminUsername()
+ {
+ throw new adLDAPException('For security reasons you cannot access the domain administrator account details');
+ }
+
+ /**
+ * Set the password of an account with higher priviledges
+ *
+ * @param string $adminPassword
+ * @return void
+ */
+ public function setAdminPassword($adminPassword)
+ {
+ $this->adminPassword = $adminPassword;
+ }
+
+ /**
+ * Get the password of the account with higher priviledges
+ *
+ * This will throw an exception for security reasons
+ */
+ public function getAdminPassword()
+ {
+ throw new adLDAPException('For security reasons you cannot access the domain administrator account details');
+ }
+
+ /**
+ * Set whether to detect the true primary group
+ *
+ * @param bool $realPrimaryGroup
+ * @return void
+ */
+ public function setRealPrimaryGroup($realPrimaryGroup)
+ {
+ $this->realPrimaryGroup = $realPrimaryGroup;
+ }
+
+ /**
+ * Get the real primary group setting
+ *
+ * @return bool
+ */
+ public function getRealPrimaryGroup()
+ {
+ return $this->realPrimaryGroup;
+ }
+
+ /**
+ * Set whether to use SSL
+ *
+ * @param bool $useSSL
+ * @return void
+ */
+ public function setUseSSL($useSSL)
+ {
+ $this->useSSL = $useSSL;
+ // Set the default port correctly
+ if($this->useSSL) {
+ $this->setPort(self::ADLDAP_LDAPS_PORT);
+ }
+ else {
+ $this->setPort(self::ADLDAP_LDAP_PORT);
+ }
+ }
+
+ /**
+ * Get the SSL setting
+ *
+ * @return bool
+ */
+ public function getUseSSL()
+ {
+ return $this->useSSL;
+ }
+
+ /**
+ * Set whether to use TLS
+ *
+ * @param bool $useTLS
+ * @return void
+ */
+ public function setUseTLS($useTLS)
+ {
+ $this->useTLS = $useTLS;
+ }
+
+ /**
+ * Get the TLS setting
+ *
+ * @return bool
+ */
+ public function getUseTLS()
+ {
+ return $this->useTLS;
+ }
+
+ /**
+ * Set whether to use SSO
+ * Requires ldap_sasl_bind support. Be sure --with-ldap-sasl is used when configuring PHP otherwise this function will be undefined.
+ *
+ * @param bool $useSSO
+ * @return void
+ */
+ public function setUseSSO($useSSO)
+ {
+ if ($useSSO === true && !$this->ldapSaslSupported()) {
+ throw new adLDAPException('No LDAP SASL support for PHP. See: http://www.php.net/ldap_sasl_bind');
+ }
+ $this->useSSO = $useSSO;
+ }
+
+ /**
+ * Get the SSO setting
+ *
+ * @return bool
+ */
+ public function getUseSSO()
+ {
+ return $this->useSSO;
+ }
+
+ /**
+ * Set whether to lookup recursive groups
+ *
+ * @param bool $recursiveGroups
+ * @return void
+ */
+ public function setRecursiveGroups($recursiveGroups)
+ {
+ $this->recursiveGroups = $recursiveGroups;
+ }
+
+ /**
+ * Get the recursive groups setting
+ *
+ * @return bool
+ */
+ public function getRecursiveGroups()
+ {
+ return $this->recursiveGroups;
+ }
+
+ /**
+ * Default Constructor
+ *
+ * Tries to bind to the AD domain over LDAP or LDAPs
+ *
+ * @param array $options Array of options to pass to the constructor
+ * @throws Exception - if unable to bind to Domain Controller
+ * @return bool
+ */
+ function __construct($options = array()) {
+ // You can specifically overide any of the default configuration options setup above
+ if (count($options) > 0) {
+ if (array_key_exists("account_suffix",$options)){ $this->accountSuffix = $options["account_suffix"]; }
+ if (array_key_exists("base_dn",$options)){ $this->baseDn = $options["base_dn"]; }
+ if (array_key_exists("domain_controllers",$options)){
+ if (!is_array($options["domain_controllers"])) {
+ throw new adLDAPException('[domain_controllers] option must be an array');
+ }
+ $this->domainControllers = $options["domain_controllers"];
+ }
+ if (array_key_exists("admin_username",$options)){ $this->adminUsername = $options["admin_username"]; }
+ if (array_key_exists("admin_password",$options)){ $this->adminPassword = $options["admin_password"]; }
+ if (array_key_exists("real_primarygroup",$options)){ $this->realPrimaryGroup = $options["real_primarygroup"]; }
+ if (array_key_exists("use_ssl",$options)){ $this->setUseSSL($options["use_ssl"]); }
+ if (array_key_exists("use_tls",$options)){ $this->useTLS = $options["use_tls"]; }
+ if (array_key_exists("recursive_groups",$options)){ $this->recursiveGroups = $options["recursive_groups"]; }
+ if (array_key_exists("ad_port",$options)){ $this->setPort($options["ad_port"]); }
+ if (array_key_exists("sso",$options)) {
+ $this->setUseSSO($options["sso"]);
+ if (!$this->ldapSaslSupported()) {
+ $this->setUseSSO(false);
+ }
+ }
+ }
+
+ if ($this->ldapSupported() === false) {
+ throw new adLDAPException('No LDAP support for PHP. See: http://www.php.net/ldap');
+ }
+
+ return $this->connect();
+ }
+
+ /**
+ * Default Destructor
+ *
+ * Closes the LDAP connection
+ *
+ * @return void
+ */
+ function __destruct() {
+ $this->close();
+ }
+
+ /**
+ * Connects and Binds to the Domain Controller
+ *
+ * @return bool
+ */
+ public function connect()
+ {
+ // Connect to the AD/LDAP server as the username/password
+ $domainController = $this->randomController();
+ if ($this->useSSL) {
+ $this->ldapConnection = ldap_connect("ldaps://" . $domainController, $this->adPort);
+ } else {
+ $this->ldapConnection = ldap_connect($domainController, $this->adPort);
+ }
+
+ // Set some ldap options for talking to AD
+ ldap_set_option($this->ldapConnection, LDAP_OPT_PROTOCOL_VERSION, 3);
+ ldap_set_option($this->ldapConnection, LDAP_OPT_REFERRALS, 0);
+
+ if ($this->useTLS) {
+ ldap_start_tls($this->ldapConnection);
+ }
+
+ // Bind as a domain admin if they've set it up
+ if ($this->adminUsername !== NULL && $this->adminPassword !== NULL) {
+ $this->ldapBind = @ldap_bind($this->ldapConnection, $this->adminUsername . $this->accountSuffix, $this->adminPassword);
+ if (!$this->ldapBind) {
+ if ($this->useSSL && !$this->useTLS) {
+ // If you have problems troubleshooting, remove the @ character from the ldapldapBind command above to get the actual error message
+ throw new adLDAPException('Bind to Active Directory failed. Either the LDAPs connection failed or the login credentials are incorrect. AD said: ' . $this->getLastError());
+ }
+ else {
+ throw new adLDAPException('Bind to Active Directory failed. Check the login credentials and/or server details. AD said: ' . $this->getLastError());
+ }
+ }
+ }
+ if ($this->useSSO && $_SERVER['REMOTE_USER'] && $this->adminUsername === null && $_SERVER['KRB5CCNAME']) {
+ putenv("KRB5CCNAME=" . $_SERVER['KRB5CCNAME']);
+ $this->ldapBind = @ldap_sasl_bind($this->ldapConnection, NULL, NULL, "GSSAPI");
+ if (!$this->ldapBind){
+ throw new adLDAPException('Rebind to Active Directory failed. AD said: ' . $this->getLastError());
+ }
+ else {
+ return true;
+ }
+ }
+
+
+ if ($this->baseDn == NULL) {
+ $this->baseDn = $this->findBaseDn();
+ }
+
+ return true;
+ }
+
+ /**
+ * Closes the LDAP connection
+ *
+ * @return void
+ */
+ public function close() {
+ if ($this->ldapConnection) {
+ @ldap_close($this->ldapConnection);
+ }
+ }
+
+ /**
+ * Validate a user's login credentials
+ *
+ * @param string $username A user's AD username
+ * @param string $password A user's AD password
+ * @param bool optional $preventRebind
+ * @return bool
+ */
+ public function authenticate($username, $password, $preventRebind = false) {
+ // Prevent null binding
+ if ($username === NULL || $password === NULL) { return false; }
+ if (empty($username) || empty($password)) { return false; }
+
+ // Allow binding over SSO for Kerberos
+ if ($this->useSSO && $_SERVER['REMOTE_USER'] && $_SERVER['REMOTE_USER'] == $username && $this->adminUsername === NULL && $_SERVER['KRB5CCNAME']) {
+ putenv("KRB5CCNAME=" . $_SERVER['KRB5CCNAME']);
+ $this->ldapBind = @ldap_sasl_bind($this->ldapConnection, NULL, NULL, "GSSAPI");
+ if (!$this->ldapBind) {
+ throw new adLDAPException('Rebind to Active Directory failed. AD said: ' . $this->getLastError());
+ }
+ else {
+ return true;
+ }
+ }
+
+ // Bind as the user
+ $ret = true;
+ $this->ldapBind = @ldap_bind($this->ldapConnection, $username . $this->accountSuffix, $password);
+ if (!$this->ldapBind){
+ $ret = false;
+ }
+
+ // Cnce we've checked their details, kick back into admin mode if we have it
+ if ($this->adminUsername !== NULL && !$preventRebind) {
+ $this->ldapBind = @ldap_bind($this->ldapConnection, $this->adminUsername . $this->accountSuffix , $this->adminPassword);
+ if (!$this->ldapBind){
+ // This should never happen in theory
+ throw new adLDAPException('Rebind to Active Directory failed. AD said: ' . $this->getLastError());
+ }
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Find the Base DN of your domain controller
+ *
+ * @return string
+ */
+ public function findBaseDn()
+ {
+ $namingContext = $this->getRootDse(array('defaultnamingcontext'));
+ return $namingContext[0]['defaultnamingcontext'][0];
+ }
+
+ /**
+ * Get the RootDSE properties from a domain controller
+ *
+ * @param array $attributes The attributes you wish to query e.g. defaultnamingcontext
+ * @return array
+ */
+ public function getRootDse($attributes = array("*", "+")) {
+ if (!$this->ldapBind){ return (false); }
+
+ $sr = @ldap_read($this->ldapConnection, NULL, 'objectClass=*', $attributes);
+ $entries = @ldap_get_entries($this->ldapConnection, $sr);
+ return $entries;
+ }
+
+ /**
+ * Get last error from Active Directory
+ *
+ * This function gets the last message from Active Directory
+ * This may indeed be a 'Success' message but if you get an unknown error
+ * it might be worth calling this function to see what errors were raised
+ *
+ * return string
+ */
+ public function getLastError() {
+ return @ldap_error($this->ldapConnection);
+ }
+
+ /**
+ * Detect LDAP support in php
+ *
+ * @return bool
+ */
+ protected function ldapSupported()
+ {
+ if (!function_exists('ldap_connect')) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Detect ldap_sasl_bind support in PHP
+ *
+ * @return bool
+ */
+ protected function ldapSaslSupported()
+ {
+ if (!function_exists('ldap_sasl_bind')) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Schema
+ *
+ * @param array $attributes Attributes to be queried
+ * @return array
+ */
+ public function adldap_schema($attributes){
+
+ // LDAP doesn't like NULL attributes, only set them if they have values
+ // If you wish to remove an attribute you should set it to a space
+ // TO DO: Adapt user_modify to use ldap_mod_delete to remove a NULL attribute
+ $mod=array();
+
+ // Check every attribute to see if it contains 8bit characters and then UTF8 encode them
+ array_walk($attributes, array($this, 'encode8bit'));
+
+ if ($attributes["address_city"]){ $mod["l"][0]=$attributes["address_city"]; }
+ if ($attributes["address_code"]){ $mod["postalCode"][0]=$attributes["address_code"]; }
+ //if ($attributes["address_country"]){ $mod["countryCode"][0]=$attributes["address_country"]; } // use country codes?
+ if ($attributes["address_country"]){ $mod["c"][0]=$attributes["address_country"]; }
+ if ($attributes["address_pobox"]){ $mod["postOfficeBox"][0]=$attributes["address_pobox"]; }
+ if ($attributes["address_state"]){ $mod["st"][0]=$attributes["address_state"]; }
+ if ($attributes["address_street"]){ $mod["streetAddress"][0]=$attributes["address_street"]; }
+ if ($attributes["company"]){ $mod["company"][0]=$attributes["company"]; }
+ if ($attributes["change_password"]){ $mod["pwdLastSet"][0]=0; }
+ if ($attributes["department"]){ $mod["department"][0]=$attributes["department"]; }
+ if ($attributes["description"]){ $mod["description"][0]=$attributes["description"]; }
+ if ($attributes["display_name"]){ $mod["displayName"][0]=$attributes["display_name"]; }
+ if ($attributes["email"]){ $mod["mail"][0]=$attributes["email"]; }
+ if ($attributes["expires"]){ $mod["accountExpires"][0]=$attributes["expires"]; } //unix epoch format?
+ if ($attributes["firstname"]){ $mod["givenName"][0]=$attributes["firstname"]; }
+ if ($attributes["home_directory"]){ $mod["homeDirectory"][0]=$attributes["home_directory"]; }
+ if ($attributes["home_drive"]){ $mod["homeDrive"][0]=$attributes["home_drive"]; }
+ if ($attributes["initials"]){ $mod["initials"][0]=$attributes["initials"]; }
+ if ($attributes["logon_name"]){ $mod["userPrincipalName"][0]=$attributes["logon_name"]; }
+ if ($attributes["manager"]){ $mod["manager"][0]=$attributes["manager"]; } //UNTESTED ***Use DistinguishedName***
+ if ($attributes["office"]){ $mod["physicalDeliveryOfficeName"][0]=$attributes["office"]; }
+ if ($attributes["password"]){ $mod["unicodePwd"][0]=$this->user()->encodePassword($attributes["password"]); }
+ if ($attributes["profile_path"]){ $mod["profilepath"][0]=$attributes["profile_path"]; }
+ if ($attributes["script_path"]){ $mod["scriptPath"][0]=$attributes["script_path"]; }
+ if ($attributes["surname"]){ $mod["sn"][0]=$attributes["surname"]; }
+ if ($attributes["title"]){ $mod["title"][0]=$attributes["title"]; }
+ if ($attributes["telephone"]){ $mod["telephoneNumber"][0]=$attributes["telephone"]; }
+ if ($attributes["mobile"]){ $mod["mobile"][0]=$attributes["mobile"]; }
+ if ($attributes["pager"]){ $mod["pager"][0]=$attributes["pager"]; }
+ if ($attributes["ipphone"]){ $mod["ipphone"][0]=$attributes["ipphone"]; }
+ if ($attributes["web_page"]){ $mod["wWWHomePage"][0]=$attributes["web_page"]; }
+ if ($attributes["fax"]){ $mod["facsimileTelephoneNumber"][0]=$attributes["fax"]; }
+ if ($attributes["enabled"]){ $mod["userAccountControl"][0]=$attributes["enabled"]; }
+ if ($attributes["homephone"]){ $mod["homephone"][0]=$attributes["homephone"]; }
+
+ // Distribution List specific schema
+ if ($attributes["group_sendpermission"]){ $mod["dlMemSubmitPerms"][0]=$attributes["group_sendpermission"]; }
+ if ($attributes["group_rejectpermission"]){ $mod["dlMemRejectPerms"][0]=$attributes["group_rejectpermission"]; }
+
+ // Exchange Schema
+ if ($attributes["exchange_homemdb"]){ $mod["homeMDB"][0]=$attributes["exchange_homemdb"]; }
+ if ($attributes["exchange_mailnickname"]){ $mod["mailNickname"][0]=$attributes["exchange_mailnickname"]; }
+ if ($attributes["exchange_proxyaddress"]){ $mod["proxyAddresses"][0]=$attributes["exchange_proxyaddress"]; }
+ if ($attributes["exchange_usedefaults"]){ $mod["mDBUseDefaults"][0]=$attributes["exchange_usedefaults"]; }
+ if ($attributes["exchange_policyexclude"]){ $mod["msExchPoliciesExcluded"][0]=$attributes["exchange_policyexclude"]; }
+ if ($attributes["exchange_policyinclude"]){ $mod["msExchPoliciesIncluded"][0]=$attributes["exchange_policyinclude"]; }
+ if ($attributes["exchange_addressbook"]){ $mod["showInAddressBook"][0]=$attributes["exchange_addressbook"]; }
+ if ($attributes["exchange_altrecipient"]){ $mod["altRecipient"][0]=$attributes["exchange_altrecipient"]; }
+ if ($attributes["exchange_deliverandredirect"]){ $mod["deliverAndRedirect"][0]=$attributes["exchange_deliverandredirect"]; }
+
+ // This schema is designed for contacts
+ if ($attributes["exchange_hidefromlists"]){ $mod["msExchHideFromAddressLists"][0]=$attributes["exchange_hidefromlists"]; }
+ if ($attributes["contact_email"]){ $mod["targetAddress"][0]=$attributes["contact_email"]; }
+
+ //echo ("<pre>"); print_r($mod);
+ /*
+ // modifying a name is a bit fiddly
+ if ($attributes["firstname"] && $attributes["surname"]){
+ $mod["cn"][0]=$attributes["firstname"]." ".$attributes["surname"];
+ $mod["displayname"][0]=$attributes["firstname"]." ".$attributes["surname"];
+ $mod["name"][0]=$attributes["firstname"]." ".$attributes["surname"];
+ }
+ */
+
+ if (count($mod)==0){ return (false); }
+ return ($mod);
+ }
+
+ /**
+ * Convert 8bit characters e.g. accented characters to UTF8 encoded characters
+ */
+ protected function encode8Bit(&$item, $key) {
+ $encode = false;
+ if (is_string($item)) {
+ for ($i=0; $i<strlen($item); $i++) {
+ if (ord($item[$i]) >> 7) {
+ $encode = true;
+ }
+ }
+ }
+ if ($encode === true && $key != 'password') {
+ $item = utf8_encode($item);
+ }
+ }
+
+ /**
+ * Select a random domain controller from your domain controller array
+ *
+ * @return string
+ */
+ protected function randomController()
+ {
+ mt_srand(doubleval(microtime()) * 100000000); // For older PHP versions
+ /*if (sizeof($this->domainControllers) > 1) {
+ $adController = $this->domainControllers[array_rand($this->domainControllers)];
+ // Test if the controller is responding to pings
+ $ping = $this->pingController($adController);
+ if ($ping === false) {
+ // Find the current key in the domain controllers array
+ $key = array_search($adController, $this->domainControllers);
+ // Remove it so that we don't end up in a recursive loop
+ unset($this->domainControllers[$key]);
+ // Select a new controller
+ return $this->randomController();
+ }
+ else {
+ return ($adController);
+ }
+ } */
+ return $this->domainControllers[array_rand($this->domainControllers)];
+ }
+
+ /**
+ * Test basic connectivity to controller
+ *
+ * @return bool
+ */
+ protected function pingController($host) {
+ $port = $this->adPort;
+ fsockopen($host, $port, $errno, $errstr, 10);
+ if ($errno > 0) {
+ return false;
+ }
+ return true;
+ }
+
+}
+
+/**
+* adLDAP Exception Handler
+*
+* Exceptions of this type are thrown on bind failure or when SSL is required but not configured
+* Example:
+* try {
+* $adldap = new adLDAP();
+* }
+* catch (adLDAPException $e) {
+* echo $e;
+* exit();
+* }
+*/
+class adLDAPException extends Exception {}
+
+?> \ No newline at end of file
diff --git a/lib/plugins/authad/adLDAP/classes/adLDAPComputers.php b/lib/plugins/authad/adLDAP/classes/adLDAPComputers.php
new file mode 100644
index 000000000..71b24a04f
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/classes/adLDAPComputers.php
@@ -0,0 +1,153 @@
+<?php
+/**
+ * PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY
+ * Version 4.0.4
+ *
+ * PHP Version 5 with SSL and LDAP support
+ *
+ * Written by Scott Barnett, Richard Hyland
+ * email: scott@wiggumworld.com, adldap@richardhyland.com
+ * http://adldap.sourceforge.net/
+ *
+ * Copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ *
+ * We'd appreciate any improvements or additions to be submitted back
+ * to benefit the entire community :)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * @category ToolsAndUtilities
+ * @package adLDAP
+ * @subpackage Computers
+ * @author Scott Barnett, Richard Hyland
+ * @copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html LGPLv2.1
+ * @revision $Revision: 97 $
+ * @version 4.0.4
+ * @link http://adldap.sourceforge.net/
+ */
+require_once(dirname(__FILE__) . '/../adLDAP.php');
+require_once(dirname(__FILE__) . '/../collections/adLDAPComputerCollection.php');
+
+/**
+* COMPUTER MANAGEMENT FUNCTIONS
+*/
+class adLDAPComputers {
+
+ /**
+ * The current adLDAP connection via dependency injection
+ *
+ * @var adLDAP
+ */
+ protected $adldap;
+
+ public function __construct(adLDAP $adldap) {
+ $this->adldap = $adldap;
+ }
+
+ /**
+ * Get information about a specific computer. Returned in a raw array format from AD
+ *
+ * @param string $computerName The name of the computer
+ * @param array $fields Attributes to return
+ * @return array
+ */
+ public function info($computerName, $fields = NULL)
+ {
+ if ($computerName === NULL) { return false; }
+ if (!$this->adldap->getLdapBind()) { return false; }
+
+ $filter = "(&(objectClass=computer)(cn=" . $computerName . "))";
+ if ($fields === NULL) {
+ $fields = array("memberof","cn","displayname","dnshostname","distinguishedname","objectcategory","operatingsystem","operatingsystemservicepack","operatingsystemversion");
+ }
+ $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+ $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+ return $entries;
+ }
+
+ /**
+ * Find information about the computers. Returned in a raw array format from AD
+ *
+ * @param string $computerName The name of the computer
+ * @param array $fields Array of parameters to query
+ * @return mixed
+ */
+ public function infoCollection($computerName, $fields = NULL)
+ {
+ if ($computerName === NULL) { return false; }
+ if (!$this->adldap->getLdapBind()) { return false; }
+
+ $info = $this->info($computerName, $fields);
+
+ if ($info !== false) {
+ $collection = new adLDAPComputerCollection($info, $this->adldap);
+ return $collection;
+ }
+ return false;
+ }
+
+ /**
+ * Check if a computer is in a group
+ *
+ * @param string $computerName The name of the computer
+ * @param string $group The group to check
+ * @param bool $recursive Whether to check recursively
+ * @return array
+ */
+ public function inGroup($computerName, $group, $recursive = NULL)
+ {
+ if ($computerName === NULL) { return false; }
+ if ($group === NULL) { return false; }
+ if (!$this->adldap->getLdapBind()) { return false; }
+ if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // use the default option if they haven't set it
+
+ //get a list of the groups
+ $groups = $this->groups($computerName, array("memberof"), $recursive);
+
+ //return true if the specified group is in the group list
+ if (in_array($group, $groups)){
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the groups a computer is in
+ *
+ * @param string $computerName The name of the computer
+ * @param bool $recursive Whether to check recursively
+ * @return array
+ */
+ public function groups($computerName, $recursive = NULL)
+ {
+ if ($computerName === NULL) { return false; }
+ if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } //use the default option if they haven't set it
+ if (!$this->adldap->getLdapBind()){ return false; }
+
+ //search the directory for their information
+ $info = @$this->info($computerName, array("memberof", "primarygroupid"));
+ $groups = $this->adldap->utilities()->niceNames($info[0]["memberof"]); //presuming the entry returned is our guy (unique usernames)
+
+ if ($recursive === true) {
+ foreach ($groups as $id => $groupName){
+ $extraGroups = $this->adldap->group()->recursiveGroups($groupName);
+ $groups = array_merge($groups, $extraGroups);
+ }
+ }
+
+ return $groups;
+ }
+
+}
+?> \ No newline at end of file
diff --git a/lib/plugins/authad/adLDAP/classes/adLDAPContacts.php b/lib/plugins/authad/adLDAP/classes/adLDAPContacts.php
new file mode 100644
index 000000000..addd3e5f0
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/classes/adLDAPContacts.php
@@ -0,0 +1,294 @@
+<?php
+/**
+ * PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY
+ * Version 4.0.4
+ *
+ * PHP Version 5 with SSL and LDAP support
+ *
+ * Written by Scott Barnett, Richard Hyland
+ * email: scott@wiggumworld.com, adldap@richardhyland.com
+ * http://adldap.sourceforge.net/
+ *
+ * Copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ *
+ * We'd appreciate any improvements or additions to be submitted back
+ * to benefit the entire community :)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * @category ToolsAndUtilities
+ * @package adLDAP
+ * @subpackage Contacts
+ * @author Scott Barnett, Richard Hyland
+ * @copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html LGPLv2.1
+ * @revision $Revision: 97 $
+ * @version 4.0.4
+ * @link http://adldap.sourceforge.net/
+ */
+
+require_once(dirname(__FILE__) . '/../adLDAP.php');
+require_once(dirname(__FILE__) . '/../collections/adLDAPContactCollection.php');
+
+class adLDAPContacts {
+ /**
+ * The current adLDAP connection via dependency injection
+ *
+ * @var adLDAP
+ */
+ protected $adldap;
+
+ public function __construct(adLDAP $adldap) {
+ $this->adldap = $adldap;
+ }
+
+ //*****************************************************************************************************************
+ // CONTACT FUNCTIONS
+ // * Still work to do in this area, and new functions to write
+
+ /**
+ * Create a contact
+ *
+ * @param array $attributes The attributes to set to the contact
+ * @return bool
+ */
+ public function create($attributes)
+ {
+ // Check for compulsory fields
+ if (!array_key_exists("display_name", $attributes)) { return "Missing compulsory field [display_name]"; }
+ if (!array_key_exists("email", $attributes)) { return "Missing compulsory field [email]"; }
+ if (!array_key_exists("container", $attributes)) { return "Missing compulsory field [container]"; }
+ if (!is_array($attributes["container"])) { return "Container attribute must be an array."; }
+
+ // Translate the schema
+ $add = $this->adldap->adldap_schema($attributes);
+
+ // Additional stuff only used for adding contacts
+ $add["cn"][0] = $attributes["display_name"];
+ $add["objectclass"][0] = "top";
+ $add["objectclass"][1] = "person";
+ $add["objectclass"][2] = "organizationalPerson";
+ $add["objectclass"][3] = "contact";
+ if (!isset($attributes['exchange_hidefromlists'])) {
+ $add["msExchHideFromAddressLists"][0] = "TRUE";
+ }
+
+ // Determine the container
+ $attributes["container"] = array_reverse($attributes["container"]);
+ $container= "OU=" . implode(",OU=", $attributes["container"]);
+
+ // Add the entry
+ $result = @ldap_add($this->adldap->getLdapConnection(), "CN=" . $this->adldap->utilities()->escapeCharacters($add["cn"][0]) . ", " . $container . "," . $this->adldap->getBaseDn(), $add);
+ if ($result != true) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Determine the list of groups a contact is a member of
+ *
+ * @param string $distinguisedname The full DN of a contact
+ * @param bool $recursive Recursively check groups
+ * @return array
+ */
+ public function groups($distinguishedName, $recursive = NULL)
+ {
+ if ($distinguishedName === NULL) { return false; }
+ if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } //use the default option if they haven't set it
+ if (!$this->adldap->getLdapBind()){ return false; }
+
+ // Search the directory for their information
+ $info = @$this->info($distinguishedName, array("memberof", "primarygroupid"));
+ $groups = $this->adldap->utilities()->niceNames($info[0]["memberof"]); //presuming the entry returned is our contact
+
+ if ($recursive === true){
+ foreach ($groups as $id => $groupName){
+ $extraGroups = $this->adldap->group()->recursiveGroups($groupName);
+ $groups = array_merge($groups, $extraGroups);
+ }
+ }
+
+ return $groups;
+ }
+
+ /**
+ * Get contact information. Returned in a raw array format from AD
+ *
+ * @param string $distinguisedname The full DN of a contact
+ * @param array $fields Attributes to be returned
+ * @return array
+ */
+ public function info($distinguishedName, $fields = NULL)
+ {
+ if ($distinguishedName === NULL) { return false; }
+ if (!$this->adldap->getLdapBind()) { return false; }
+
+ $filter = "distinguishedName=" . $distinguishedName;
+ if ($fields === NULL) {
+ $fields = array("distinguishedname", "mail", "memberof", "department", "displayname", "telephonenumber", "primarygroupid", "objectsid");
+ }
+ $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+ $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+ if ($entries[0]['count'] >= 1) {
+ // AD does not return the primary group in the ldap query, we may need to fudge it
+ if ($this->adldap->getRealPrimaryGroup() && isset($entries[0]["primarygroupid"][0]) && isset($entries[0]["primarygroupid"][0])){
+ //$entries[0]["memberof"][]=$this->group_cn($entries[0]["primarygroupid"][0]);
+ $entries[0]["memberof"][] = $this->adldap->group()->getPrimaryGroup($entries[0]["primarygroupid"][0], $entries[0]["objectsid"][0]);
+ } else {
+ $entries[0]["memberof"][] = "CN=Domain Users,CN=Users," . $this->adldap->getBaseDn();
+ }
+ }
+
+ $entries[0]["memberof"]["count"]++;
+ return $entries;
+ }
+
+ /**
+ * Find information about the contacts. Returned in a raw array format from AD
+ *
+ * @param string $distinguishedName The full DN of a contact
+ * @param array $fields Array of parameters to query
+ * @return mixed
+ */
+ public function infoCollection($distinguishedName, $fields = NULL)
+ {
+ if ($distinguishedName === NULL) { return false; }
+ if (!$this->adldap->getLdapBind()) { return false; }
+
+ $info = $this->info($distinguishedName, $fields);
+
+ if ($info !== false) {
+ $collection = new adLDAPContactCollection($info, $this->adldap);
+ return $collection;
+ }
+ return false;
+ }
+
+ /**
+ * Determine if a contact is a member of a group
+ *
+ * @param string $distinguisedName The full DN of a contact
+ * @param string $group The group name to query
+ * @param bool $recursive Recursively check groups
+ * @return bool
+ */
+ public function inGroup($distinguisedName, $group, $recursive = NULL)
+ {
+ if ($distinguisedName === NULL) { return false; }
+ if ($group === NULL) { return false; }
+ if (!$this->adldap->getLdapBind()) { return false; }
+ if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } //use the default option if they haven't set it
+
+ // Get a list of the groups
+ $groups = $this->groups($distinguisedName, array("memberof"), $recursive);
+
+ // Return true if the specified group is in the group list
+ if (in_array($group, $groups)){
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Modify a contact
+ *
+ * @param string $distinguishedName The contact to query
+ * @param array $attributes The attributes to modify. Note if you set the enabled attribute you must not specify any other attributes
+ * @return bool
+ */
+ public function modify($distinguishedName, $attributes) {
+ if ($distinguishedName === NULL) { return "Missing compulsory field [distinguishedname]"; }
+
+ // Translate the update to the LDAP schema
+ $mod = $this->adldap->adldap_schema($attributes);
+
+ // Check to see if this is an enabled status update
+ if (!$mod) {
+ return false;
+ }
+
+ // Do the update
+ $result = ldap_modify($this->adldap->getLdapConnection(), $distinguishedName, $mod);
+ if ($result == false) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Delete a contact
+ *
+ * @param string $distinguishedName The contact dn to delete (please be careful here!)
+ * @return array
+ */
+ public function delete($distinguishedName)
+ {
+ $result = $this->folder()->delete($distinguishedName);
+ if ($result != true) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Return a list of all contacts
+ *
+ * @param bool $includeDescription Include a description of a contact
+ * @param string $search The search parameters
+ * @param bool $sorted Whether to sort the results
+ * @return array
+ */
+ public function all($includeDescription = false, $search = "*", $sorted = true) {
+ if (!$this->adldap->getLdapBind()) { return false; }
+
+ // Perform the search and grab all their details
+ $filter = "(&(objectClass=contact)(cn=" . $search . "))";
+ $fields = array("displayname","distinguishedname");
+ $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+ $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+ $usersArray = array();
+ for ($i=0; $i<$entries["count"]; $i++){
+ if ($includeDescription && strlen($entries[$i]["displayname"][0])>0){
+ $usersArray[$entries[$i]["distinguishedname"][0]] = $entries[$i]["displayname"][0];
+ } elseif ($includeDescription){
+ $usersArray[$entries[$i]["distinguishedname"][0]] = $entries[$i]["distinguishedname"][0];
+ } else {
+ array_push($usersArray, $entries[$i]["distinguishedname"][0]);
+ }
+ }
+ if ($sorted) {
+ asort($usersArray);
+ }
+ return $usersArray;
+ }
+
+ /**
+ * Mail enable a contact
+ * Allows email to be sent to them through Exchange
+ *
+ * @param string $distinguishedname The contact to mail enable
+ * @param string $emailaddress The email address to allow emails to be sent through
+ * @param string $mailnickname The mailnickname for the contact in Exchange. If NULL this will be set to the display name
+ * @return bool
+ */
+ public function contactMailEnable($distinguishedName, $emailAddress, $mailNickname = NULL){
+ return $this->adldap->exchange()->contactMailEnable($distinguishedName, $emailAddress, $mailNickname);
+ }
+
+
+}
+?>
diff --git a/lib/plugins/authad/adLDAP/classes/adLDAPExchange.php b/lib/plugins/authad/adLDAP/classes/adLDAPExchange.php
new file mode 100644
index 000000000..dd0c6de05
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/classes/adLDAPExchange.php
@@ -0,0 +1,390 @@
+<?php
+/**
+ * PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY
+ * Version 4.0.4
+ *
+ * PHP Version 5 with SSL and LDAP support
+ *
+ * Written by Scott Barnett, Richard Hyland
+ * email: scott@wiggumworld.com, adldap@richardhyland.com
+ * http://adldap.sourceforge.net/
+ *
+ * Copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ *
+ * We'd appreciate any improvements or additions to be submitted back
+ * to benefit the entire community :)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * @category ToolsAndUtilities
+ * @package adLDAP
+ * @subpackage Exchange
+ * @author Scott Barnett, Richard Hyland
+ * @copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html LGPLv2.1
+ * @revision $Revision: 97 $
+ * @version 4.0.4
+ * @link http://adldap.sourceforge.net/
+ */
+require_once(dirname(__FILE__) . '/../adLDAP.php');
+
+/**
+* MICROSOFT EXCHANGE FUNCTIONS
+*/
+class adLDAPExchange {
+ /**
+ * The current adLDAP connection via dependency injection
+ *
+ * @var adLDAP
+ */
+ protected $adldap;
+
+ public function __construct(adLDAP $adldap) {
+ $this->adldap = $adldap;
+ }
+
+ /**
+ * Create an Exchange account
+ *
+ * @param string $username The username of the user to add the Exchange account to
+ * @param array $storageGroup The mailbox, Exchange Storage Group, for the user account, this must be a full CN
+ * If the storage group has a different base_dn to the adLDAP configuration, set it using $base_dn
+ * @param string $emailAddress The primary email address to add to this user
+ * @param string $mailNickname The mail nick name. If mail nickname is blank, the username will be used
+ * @param bool $mdbUseDefaults Indicates whether the store should use the default quota, rather than the per-mailbox quota.
+ * @param string $baseDn Specify an alternative base_dn for the Exchange storage group
+ * @param bool $isGUID Is the username passed a GUID or a samAccountName
+ * @return bool
+ */
+ public function createMailbox($username, $storageGroup, $emailAddress, $mailNickname=NULL, $useDefaults=TRUE, $baseDn=NULL, $isGUID=false)
+ {
+ if ($username === NULL){ return "Missing compulsory field [username]"; }
+ if ($storageGroup === NULL) { return "Missing compulsory array [storagegroup]"; }
+ if (!is_array($storageGroup)) { return "[storagegroup] must be an array"; }
+ if ($emailAddress === NULL) { return "Missing compulsory field [emailAddress]"; }
+
+ if ($baseDn === NULL) {
+ $baseDn = $this->adldap->getBaseDn();
+ }
+
+ $container = "CN=" . implode(",CN=", $storageGroup);
+
+ if ($mailNickname === NULL) {
+ $mailNickname = $username;
+ }
+ $mdbUseDefaults = $this->adldap->utilities()->boolToString($useDefaults);
+
+ $attributes = array(
+ 'exchange_homemdb'=>$container.",".$baseDn,
+ 'exchange_proxyaddress'=>'SMTP:' . $emailAddress,
+ 'exchange_mailnickname'=>$mailNickname,
+ 'exchange_usedefaults'=>$mdbUseDefaults
+ );
+ $result = $this->adldap->user()->modify($username, $attributes, $isGUID);
+ if ($result == false) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Add an X400 address to Exchange
+ * See http://tools.ietf.org/html/rfc1685 for more information.
+ * An X400 Address looks similar to this X400:c=US;a= ;p=Domain;o=Organization;s=Doe;g=John;
+ *
+ * @param string $username The username of the user to add the X400 to to
+ * @param string $country Country
+ * @param string $admd Administration Management Domain
+ * @param string $pdmd Private Management Domain (often your AD domain)
+ * @param string $org Organization
+ * @param string $surname Surname
+ * @param string $givenName Given name
+ * @param bool $isGUID Is the username passed a GUID or a samAccountName
+ * @return bool
+ */
+ public function addX400($username, $country, $admd, $pdmd, $org, $surname, $givenName, $isGUID=false)
+ {
+ if ($username === NULL){ return "Missing compulsory field [username]"; }
+
+ $proxyValue = 'X400:';
+
+ // Find the dn of the user
+ $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
+ if ($user[0]["dn"] === NULL) { return false; }
+ $userDn = $user[0]["dn"];
+
+ // We do not have to demote an email address from the default so we can just add the new proxy address
+ $attributes['exchange_proxyaddress'] = $proxyValue . 'c=' . $country . ';a=' . $admd . ';p=' . $pdmd . ';o=' . $org . ';s=' . $surname . ';g=' . $givenName . ';';
+
+ // Translate the update to the LDAP schema
+ $add = $this->adldap->adldap_schema($attributes);
+
+ if (!$add) { return false; }
+
+ // Do the update
+ // Take out the @ to see any errors, usually this error might occur because the address already
+ // exists in the list of proxyAddresses
+ $result = @ldap_mod_add($this->adldap->getLdapConnection(), $userDn, $add);
+ if ($result == false) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Add an address to Exchange
+ *
+ * @param string $username The username of the user to add the Exchange account to
+ * @param string $emailAddress The email address to add to this user
+ * @param bool $default Make this email address the default address, this is a bit more intensive as we have to demote any existing default addresses
+ * @param bool $isGUID Is the username passed a GUID or a samAccountName
+ * @return bool
+ */
+ public function addAddress($username, $emailAddress, $default = FALSE, $isGUID = false)
+ {
+ if ($username === NULL) { return "Missing compulsory field [username]"; }
+ if ($emailAddress === NULL) { return "Missing compulsory fields [emailAddress]"; }
+
+ $proxyValue = 'smtp:';
+ if ($default === true) {
+ $proxyValue = 'SMTP:';
+ }
+
+ // Find the dn of the user
+ $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
+ if ($user[0]["dn"] === NULL){ return false; }
+ $userDn = $user[0]["dn"];
+
+ // We need to scan existing proxy addresses and demote the default one
+ if (is_array($user[0]["proxyaddresses"]) && $default === true) {
+ $modAddresses = array();
+ for ($i=0;$i<sizeof($user[0]['proxyaddresses']);$i++) {
+ if (strstr($user[0]['proxyaddresses'][$i], 'SMTP:') !== false) {
+ $user[0]['proxyaddresses'][$i] = str_replace('SMTP:', 'smtp:', $user[0]['proxyaddresses'][$i]);
+ }
+ if ($user[0]['proxyaddresses'][$i] != '') {
+ $modAddresses['proxyAddresses'][$i] = $user[0]['proxyaddresses'][$i];
+ }
+ }
+ $modAddresses['proxyAddresses'][(sizeof($user[0]['proxyaddresses'])-1)] = 'SMTP:' . $emailAddress;
+
+ $result = @ldap_mod_replace($this->adldap->getLdapConnection(), $userDn, $modAddresses);
+ if ($result == false) {
+ return false;
+ }
+
+ return true;
+ }
+ else {
+ // We do not have to demote an email address from the default so we can just add the new proxy address
+ $attributes['exchange_proxyaddress'] = $proxyValue . $emailAddress;
+
+ // Translate the update to the LDAP schema
+ $add = $this->adldap->adldap_schema($attributes);
+
+ if (!$add) {
+ return false;
+ }
+
+ // Do the update
+ // Take out the @ to see any errors, usually this error might occur because the address already
+ // exists in the list of proxyAddresses
+ $result = @ldap_mod_add($this->adldap->getLdapConnection(), $userDn,$add);
+ if ($result == false) {
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ /**
+ * Remove an address to Exchange
+ * If you remove a default address the account will no longer have a default,
+ * we recommend changing the default address first
+ *
+ * @param string $username The username of the user to add the Exchange account to
+ * @param string $emailAddress The email address to add to this user
+ * @param bool $isGUID Is the username passed a GUID or a samAccountName
+ * @return bool
+ */
+ public function deleteAddress($username, $emailAddress, $isGUID=false)
+ {
+ if ($username === NULL) { return "Missing compulsory field [username]"; }
+ if ($emailAddress === NULL) { return "Missing compulsory fields [emailAddress]"; }
+
+ // Find the dn of the user
+ $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
+ if ($user[0]["dn"] === NULL) { return false; }
+ $userDn = $user[0]["dn"];
+
+ if (is_array($user[0]["proxyaddresses"])) {
+ $mod = array();
+ for ($i=0;$i<sizeof($user[0]['proxyaddresses']);$i++) {
+ if (strstr($user[0]['proxyaddresses'][$i], 'SMTP:') !== false && $user[0]['proxyaddresses'][$i] == 'SMTP:' . $emailAddress) {
+ $mod['proxyAddresses'][0] = 'SMTP:' . $emailAddress;
+ }
+ elseif (strstr($user[0]['proxyaddresses'][$i], 'smtp:') !== false && $user[0]['proxyaddresses'][$i] == 'smtp:' . $emailAddress) {
+ $mod['proxyAddresses'][0] = 'smtp:' . $emailAddress;
+ }
+ }
+
+ $result = @ldap_mod_del($this->adldap->getLdapConnection(), $userDn,$mod);
+ if ($result == false) {
+ return false;
+ }
+
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ /**
+ * Change the default address
+ *
+ * @param string $username The username of the user to add the Exchange account to
+ * @param string $emailAddress The email address to make default
+ * @param bool $isGUID Is the username passed a GUID or a samAccountName
+ * @return bool
+ */
+ public function primaryAddress($username, $emailAddress, $isGUID = false)
+ {
+ if ($username === NULL) { return "Missing compulsory field [username]"; }
+ if ($emailAddress === NULL) { return "Missing compulsory fields [emailAddress]"; }
+
+ // Find the dn of the user
+ $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
+ if ($user[0]["dn"] === NULL){ return false; }
+ $userDn = $user[0]["dn"];
+
+ if (is_array($user[0]["proxyaddresses"])) {
+ $modAddresses = array();
+ for ($i=0;$i<sizeof($user[0]['proxyaddresses']);$i++) {
+ if (strstr($user[0]['proxyaddresses'][$i], 'SMTP:') !== false) {
+ $user[0]['proxyaddresses'][$i] = str_replace('SMTP:', 'smtp:', $user[0]['proxyaddresses'][$i]);
+ }
+ if ($user[0]['proxyaddresses'][$i] == 'smtp:' . $emailAddress) {
+ $user[0]['proxyaddresses'][$i] = str_replace('smtp:', 'SMTP:', $user[0]['proxyaddresses'][$i]);
+ }
+ if ($user[0]['proxyaddresses'][$i] != '') {
+ $modAddresses['proxyAddresses'][$i] = $user[0]['proxyaddresses'][$i];
+ }
+ }
+
+ $result = @ldap_mod_replace($this->adldap->getLdapConnection(), $userDn, $modAddresses);
+ if ($result == false) {
+ return false;
+ }
+
+ return true;
+ }
+
+ }
+
+ /**
+ * Mail enable a contact
+ * Allows email to be sent to them through Exchange
+ *
+ * @param string $distinguishedName The contact to mail enable
+ * @param string $emailAddress The email address to allow emails to be sent through
+ * @param string $mailNickname The mailnickname for the contact in Exchange. If NULL this will be set to the display name
+ * @return bool
+ */
+ public function contactMailEnable($distinguishedName, $emailAddress, $mailNickname = NULL)
+ {
+ if ($distinguishedName === NULL) { return "Missing compulsory field [distinguishedName]"; }
+ if ($emailAddress === NULL) { return "Missing compulsory field [emailAddress]"; }
+
+ if ($mailNickname !== NULL) {
+ // Find the dn of the user
+ $user = $this->adldap->contact()->info($distinguishedName, array("cn","displayname"));
+ if ($user[0]["displayname"] === NULL) { return false; }
+ $mailNickname = $user[0]['displayname'][0];
+ }
+
+ $attributes = array("email"=>$emailAddress,"contact_email"=>"SMTP:" . $emailAddress,"exchange_proxyaddress"=>"SMTP:" . $emailAddress,"exchange_mailnickname" => $mailNickname);
+
+ // Translate the update to the LDAP schema
+ $mod = $this->adldap->adldap_schema($attributes);
+
+ // Check to see if this is an enabled status update
+ if (!$mod) { return false; }
+
+ // Do the update
+ $result = ldap_modify($this->adldap->getLdapConnection(), $distinguishedName, $mod);
+ if ($result == false) { return false; }
+
+ return true;
+ }
+
+ /**
+ * Returns a list of Exchange Servers in the ConfigurationNamingContext of the domain
+ *
+ * @param array $attributes An array of the AD attributes you wish to return
+ * @return array
+ */
+ public function servers($attributes = array('cn','distinguishedname','serialnumber'))
+ {
+ if (!$this->adldap->getLdapBind()){ return false; }
+
+ $configurationNamingContext = $this->adldap->getRootDse(array('configurationnamingcontext'));
+ $sr = @ldap_search($this->adldap->getLdapConnection(), $configurationNamingContext[0]['configurationnamingcontext'][0],'(&(objectCategory=msExchExchangeServer))', $attributes);
+ $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+ return $entries;
+ }
+
+ /**
+ * Returns a list of Storage Groups in Exchange for a given mail server
+ *
+ * @param string $exchangeServer The full DN of an Exchange server. You can use exchange_servers() to find the DN for your server
+ * @param array $attributes An array of the AD attributes you wish to return
+ * @param bool $recursive If enabled this will automatically query the databases within a storage group
+ * @return array
+ */
+ public function storageGroups($exchangeServer, $attributes = array('cn','distinguishedname'), $recursive = NULL)
+ {
+ if (!$this->adldap->getLdapBind()){ return false; }
+ if ($exchangeServer === NULL) { return "Missing compulsory field [exchangeServer]"; }
+ if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); }
+
+ $filter = '(&(objectCategory=msExchStorageGroup))';
+ $sr = @ldap_search($this->adldap->getLdapConnection(), $exchangeServer, $filter, $attributes);
+ $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+ if ($recursive === true) {
+ for ($i=0; $i<$entries['count']; $i++) {
+ $entries[$i]['msexchprivatemdb'] = $this->storageDatabases($entries[$i]['distinguishedname'][0]);
+ }
+ }
+
+ return $entries;
+ }
+
+ /**
+ * Returns a list of Databases within any given storage group in Exchange for a given mail server
+ *
+ * @param string $storageGroup The full DN of an Storage Group. You can use exchange_storage_groups() to find the DN
+ * @param array $attributes An array of the AD attributes you wish to return
+ * @return array
+ */
+ public function storageDatabases($storageGroup, $attributes = array('cn','distinguishedname','displayname')) {
+ if (!$this->adldap->getLdapBind()){ return false; }
+ if ($storageGroup === NULL) { return "Missing compulsory field [storageGroup]"; }
+
+ $filter = '(&(objectCategory=msExchPrivateMDB))';
+ $sr = @ldap_search($this->adldap->getLdapConnection(), $storageGroup, $filter, $attributes);
+ $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+ return $entries;
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/plugins/authad/adLDAP/classes/adLDAPFolders.php b/lib/plugins/authad/adLDAP/classes/adLDAPFolders.php
new file mode 100644
index 000000000..55120152d
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/classes/adLDAPFolders.php
@@ -0,0 +1,179 @@
+<?php
+/**
+ * PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY
+ * Version 4.0.4
+ *
+ * PHP Version 5 with SSL and LDAP support
+ *
+ * Written by Scott Barnett, Richard Hyland
+ * email: scott@wiggumworld.com, adldap@richardhyland.com
+ * http://adldap.sourceforge.net/
+ *
+ * Copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ *
+ * We'd appreciate any improvements or additions to be submitted back
+ * to benefit the entire community :)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * @category ToolsAndUtilities
+ * @package adLDAP
+ * @subpackage Folders
+ * @author Scott Barnett, Richard Hyland
+ * @copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html LGPLv2.1
+ * @revision $Revision: 97 $
+ * @version 4.0.4
+ * @link http://adldap.sourceforge.net/
+ */
+require_once(dirname(__FILE__) . '/../adLDAP.php');
+
+/**
+* FOLDER / OU MANAGEMENT FUNCTIONS
+*/
+class adLDAPFolders {
+ /**
+ * The current adLDAP connection via dependency injection
+ *
+ * @var adLDAP
+ */
+ protected $adldap;
+
+ public function __construct(adLDAP $adldap) {
+ $this->adldap = $adldap;
+ }
+
+ /**
+ * Delete a distinguished name from Active Directory
+ * You should never need to call this yourself, just use the wrapper functions user_delete and contact_delete
+ *
+ * @param string $dn The distinguished name to delete
+ * @return bool
+ */
+ public function delete($dn){
+ $result = ldap_delete($this->adldap->getLdapConnection(), $dn);
+ if ($result != true) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns a folder listing for a specific OU
+ * See http://adldap.sourceforge.net/wiki/doku.php?id=api_folder_functions
+ *
+ * @param array $folderName An array to the OU you wish to list.
+ * If set to NULL will list the root, strongly recommended to set
+ * $recursive to false in that instance!
+ * @param string $dnType The type of record to list. This can be ADLDAP_FOLDER or ADLDAP_CONTAINER.
+ * @param bool $recursive Recursively search sub folders
+ * @param bool $type Specify a type of object to search for
+ * @return array
+ */
+ public function listing($folderName = NULL, $dnType = adLDAP::ADLDAP_FOLDER, $recursive = NULL, $type = NULL)
+ {
+ if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } //use the default option if they haven't set it
+ if (!$this->adldap->getLdapBind()) { return false; }
+
+ $filter = '(&';
+ if ($type !== NULL) {
+ switch ($type) {
+ case 'contact':
+ $filter .= '(objectClass=contact)';
+ break;
+ case 'computer':
+ $filter .= '(objectClass=computer)';
+ break;
+ case 'group':
+ $filter .= '(objectClass=group)';
+ break;
+ case 'folder':
+ $filter .= '(objectClass=organizationalUnit)';
+ break;
+ case 'container':
+ $filter .= '(objectClass=container)';
+ break;
+ case 'domain':
+ $filter .= '(objectClass=builtinDomain)';
+ break;
+ default:
+ $filter .= '(objectClass=user)';
+ break;
+ }
+ }
+ else {
+ $filter .= '(objectClass=*)';
+ }
+ // If the folder name is null then we will search the root level of AD
+ // This requires us to not have an OU= part, just the base_dn
+ $searchOu = $this->adldap->getBaseDn();
+ if (is_array($folderName)) {
+ $ou = $dnType . "=" . implode("," . $dnType . "=", $folderName);
+ $filter .= '(!(distinguishedname=' . $ou . ',' . $this->adldap->getBaseDn() . ')))';
+ $searchOu = $ou . ',' . $this->adldap->getBaseDn();
+ }
+ else {
+ $filter .= '(!(distinguishedname=' . $this->adldap->getBaseDn() . ')))';
+ }
+
+ if ($recursive === true) {
+ $sr = ldap_search($this->adldap->getLdapConnection(), $searchOu, $filter, array('objectclass', 'distinguishedname', 'samaccountname'));
+ $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+ if (is_array($entries)) {
+ return $entries;
+ }
+ }
+ else {
+ $sr = ldap_list($this->adldap->getLdapConnection(), $searchOu, $filter, array('objectclass', 'distinguishedname', 'samaccountname'));
+ $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+ if (is_array($entries)) {
+ return $entries;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Create an organizational unit
+ *
+ * @param array $attributes Default attributes of the ou
+ * @return bool
+ */
+ public function create($attributes)
+ {
+ if (!is_array($attributes)){ return "Attributes must be an array"; }
+ if (!is_array($attributes["container"])) { return "Container attribute must be an array."; }
+ if (!array_key_exists("ou_name",$attributes)) { return "Missing compulsory field [ou_name]"; }
+ if (!array_key_exists("container",$attributes)) { return "Missing compulsory field [container]"; }
+
+ $attributes["container"] = array_reverse($attributes["container"]);
+
+ $add=array();
+ $add["objectClass"] = "organizationalUnit";
+ $add["OU"] = $attributes['ou_name'];
+ $containers = "";
+ if (count($attributes['container']) > 0) {
+ $containers = "OU=" . implode(",OU=", $attributes["container"]) . ",";
+ }
+
+ $containers = "OU=" . implode(",OU=", $attributes["container"]);
+ $result = ldap_add($this->adldap->getLdapConnection(), "OU=" . $add["OU"] . ", " . $containers . $this->adldap->getBaseDn(), $add);
+ if ($result != true) {
+ return false;
+ }
+
+ return true;
+ }
+
+}
+
+?> \ No newline at end of file
diff --git a/lib/plugins/authad/adLDAP/classes/adLDAPGroups.php b/lib/plugins/authad/adLDAP/classes/adLDAPGroups.php
new file mode 100644
index 000000000..05e4cc93b
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/classes/adLDAPGroups.php
@@ -0,0 +1,631 @@
+<?php
+/**
+ * PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY
+ * Version 4.0.4
+ *
+ * PHP Version 5 with SSL and LDAP support
+ *
+ * Written by Scott Barnett, Richard Hyland
+ * email: scott@wiggumworld.com, adldap@richardhyland.com
+ * http://adldap.sourceforge.net/
+ *
+ * Copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ *
+ * We'd appreciate any improvements or additions to be submitted back
+ * to benefit the entire community :)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * @category ToolsAndUtilities
+ * @package adLDAP
+ * @subpackage Groups
+ * @author Scott Barnett, Richard Hyland
+ * @copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html LGPLv2.1
+ * @revision $Revision: 97 $
+ * @version 4.0.4
+ * @link http://adldap.sourceforge.net/
+ */
+require_once(dirname(__FILE__) . '/../adLDAP.php');
+require_once(dirname(__FILE__) . '/../collections/adLDAPGroupCollection.php');
+
+/**
+* GROUP FUNCTIONS
+*/
+class adLDAPGroups {
+ /**
+ * The current adLDAP connection via dependency injection
+ *
+ * @var adLDAP
+ */
+ protected $adldap;
+
+ public function __construct(adLDAP $adldap) {
+ $this->adldap = $adldap;
+ }
+
+ /**
+ * Add a group to a group
+ *
+ * @param string $parent The parent group name
+ * @param string $child The child group name
+ * @return bool
+ */
+ public function addGroup($parent,$child){
+
+ // Find the parent group's dn
+ $parentGroup = $this->ginfo($parent, array("cn"));
+ if ($parentGroup[0]["dn"] === NULL){
+ return false;
+ }
+ $parentDn = $parentGroup[0]["dn"];
+
+ // Find the child group's dn
+ $childGroup = $this->info($child, array("cn"));
+ if ($childGroup[0]["dn"] === NULL){
+ return false;
+ }
+ $childDn = $childGroup[0]["dn"];
+
+ $add = array();
+ $add["member"] = $childDn;
+
+ $result = @ldap_mod_add($this->adldap->getLdapConnection(), $parentDn, $add);
+ if ($result == false) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Add a user to a group
+ *
+ * @param string $group The group to add the user to
+ * @param string $user The user to add to the group
+ * @param bool $isGUID Is the username passed a GUID or a samAccountName
+ * @return bool
+ */
+ public function addUser($group, $user, $isGUID = false)
+ {
+ // Adding a user is a bit fiddly, we need to get the full DN of the user
+ // and add it using the full DN of the group
+
+ // Find the user's dn
+ $userDn = $this->adldap->user()->dn($user, $isGUID);
+ if ($userDn === false) {
+ return false;
+ }
+
+ // Find the group's dn
+ $groupInfo = $this->info($group, array("cn"));
+ if ($groupInfo[0]["dn"] === NULL) {
+ return false;
+ }
+ $groupDn = $groupInfo[0]["dn"];
+
+ $add = array();
+ $add["member"] = $userDn;
+
+ $result = @ldap_mod_add($this->adldap->getLdapConnection(), $groupDn, $add);
+ if ($result == false) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Add a contact to a group
+ *
+ * @param string $group The group to add the contact to
+ * @param string $contactDn The DN of the contact to add
+ * @return bool
+ */
+ public function addContact($group, $contactDn)
+ {
+ // To add a contact we take the contact's DN
+ // and add it using the full DN of the group
+
+ // Find the group's dn
+ $groupInfo = $this->info($group, array("cn"));
+ if ($groupInfo[0]["dn"] === NULL) {
+ return false;
+ }
+ $groupDn = $groupInfo[0]["dn"];
+
+ $add = array();
+ $add["member"] = $contactDn;
+
+ $result = @ldap_mod_add($this->adldap->getLdapConnection(), $groupDn, $add);
+ if ($result == false) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Create a group
+ *
+ * @param array $attributes Default attributes of the group
+ * @return bool
+ */
+ public function create($attributes)
+ {
+ if (!is_array($attributes)){ return "Attributes must be an array"; }
+ if (!array_key_exists("group_name", $attributes)){ return "Missing compulsory field [group_name]"; }
+ if (!array_key_exists("container", $attributes)){ return "Missing compulsory field [container]"; }
+ if (!array_key_exists("description", $attributes)){ return "Missing compulsory field [description]"; }
+ if (!is_array($attributes["container"])){ return "Container attribute must be an array."; }
+ $attributes["container"] = array_reverse($attributes["container"]);
+
+ //$member_array = array();
+ //$member_array[0] = "cn=user1,cn=Users,dc=yourdomain,dc=com";
+ //$member_array[1] = "cn=administrator,cn=Users,dc=yourdomain,dc=com";
+
+ $add = array();
+ $add["cn"] = $attributes["group_name"];
+ $add["samaccountname"] = $attributes["group_name"];
+ $add["objectClass"] = "Group";
+ $add["description"] = $attributes["description"];
+ //$add["member"] = $member_array; UNTESTED
+
+ $container = "OU=" . implode(",OU=", $attributes["container"]);
+ $result = ldap_add($this->adldap->getLdapConnection(), "CN=" . $add["cn"] . ", " . $container . "," . $this->adldap->getBaseDn(), $add);
+ if ($result != true) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Delete a group account
+ *
+ * @param string $group The group to delete (please be careful here!)
+ *
+ * @return array
+ */
+ public function delete($group) {
+ if (!$this->adldap->getLdapBind()){ return false; }
+ if ($group === null){ return "Missing compulsory field [group]"; }
+
+ $groupInfo = $this->info($group, array("*"));
+ $dn = $groupInfo[0]['distinguishedname'][0];
+ $result = $this->adldap->folder()->delete($dn);
+ if ($result !== true) {
+ return false;
+ } return true;
+ }
+
+ /**
+ * Remove a group from a group
+ *
+ * @param string $parent The parent group name
+ * @param string $child The child group name
+ * @return bool
+ */
+ public function removeGroup($parent , $child)
+ {
+
+ // Find the parent dn
+ $parentGroup = $this->info($parent, array("cn"));
+ if ($parentGroup[0]["dn"] === NULL) {
+ return false;
+ }
+ $parentDn = $parentGroup[0]["dn"];
+
+ // Find the child dn
+ $childGroup = $this->info($child, array("cn"));
+ if ($childGroup[0]["dn"] === NULL) {
+ return false;
+ }
+ $childDn = $childGroup[0]["dn"];
+
+ $del = array();
+ $del["member"] = $childDn;
+
+ $result = @ldap_mod_del($this->adldap->getLdapConnection(), $parentDn, $del);
+ if ($result == false) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Remove a user from a group
+ *
+ * @param string $group The group to remove a user from
+ * @param string $user The AD user to remove from the group
+ * @param bool $isGUID Is the username passed a GUID or a samAccountName
+ * @return bool
+ */
+ public function removeUser($group, $user, $isGUID = false)
+ {
+
+ // Find the parent dn
+ $groupInfo = $this->info($group, array("cn"));
+ if ($groupInfo[0]["dn"] === NULL){
+ return false;
+ }
+ $groupDn = $groupInfo[0]["dn"];
+
+ // Find the users dn
+ $userDn = $this->adldap->user()->dn($user, $isGUID);
+ if ($userDn === false) {
+ return false;
+ }
+
+ $del = array();
+ $del["member"] = $userDn;
+
+ $result = @ldap_mod_del($this->adldap->getLdapConnection(), $groupDn, $del);
+ if ($result == false) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Remove a contact from a group
+ *
+ * @param string $group The group to remove a user from
+ * @param string $contactDn The DN of a contact to remove from the group
+ * @return bool
+ */
+ public function removeContact($group, $contactDn)
+ {
+
+ // Find the parent dn
+ $groupInfo = $this->info($group, array("cn"));
+ if ($groupInfo[0]["dn"] === NULL) {
+ return false;
+ }
+ $groupDn = $groupInfo[0]["dn"];
+
+ $del = array();
+ $del["member"] = $contactDn;
+
+ $result = @ldap_mod_del($this->adldap->getLdapConnection(), $groupDn, $del);
+ if ($result == false) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Return a list of groups in a group
+ *
+ * @param string $group The group to query
+ * @param bool $recursive Recursively get groups
+ * @return array
+ */
+ public function inGroup($group, $recursive = NULL)
+ {
+ if (!$this->adldap->getLdapBind()){ return false; }
+ if ($recursive === NULL){ $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it
+
+ // Search the directory for the members of a group
+ $info = $this->info($group, array("member","cn"));
+ $groups = $info[0]["member"];
+ if (!is_array($groups)) {
+ return false;
+ }
+
+ $groupArray = array();
+
+ for ($i=0; $i<$groups["count"]; $i++){
+ $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($groups[$i]) . "))";
+ $fields = array("samaccountname", "distinguishedname", "objectClass");
+ $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+ $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+ // not a person, look for a group
+ if ($entries['count'] == 0 && $recursive == true) {
+ $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($groups[$i]) . "))";
+ $fields = array("distinguishedname");
+ $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+ $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+ if (!isset($entries[0]['distinguishedname'][0])) {
+ continue;
+ }
+ $subGroups = $this->inGroup($entries[0]['distinguishedname'][0], $recursive);
+ if (is_array($subGroups)) {
+ $groupArray = array_merge($groupArray, $subGroups);
+ $groupArray = array_unique($groupArray);
+ }
+ continue;
+ }
+
+ $groupArray[] = $entries[0]['distinguishedname'][0];
+ }
+ return $groupArray;
+ }
+
+ /**
+ * Return a list of members in a group
+ *
+ * @param string $group The group to query
+ * @param bool $recursive Recursively get group members
+ * @return array
+ */
+ public function members($group, $recursive = NULL)
+ {
+ if (!$this->adldap->getLdapBind()){ return false; }
+ if ($recursive === NULL){ $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it
+ // Search the directory for the members of a group
+ $info = $this->info($group, array("member","cn"));
+ $users = $info[0]["member"];
+ if (!is_array($users)) {
+ return false;
+ }
+
+ $userArray = array();
+
+ for ($i=0; $i<$users["count"]; $i++){
+ $filter = "(&(objectCategory=person)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($users[$i]) . "))";
+ $fields = array("samaccountname", "distinguishedname", "objectClass");
+ $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+ $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+ // not a person, look for a group
+ if ($entries['count'] == 0 && $recursive == true) {
+ $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($users[$i]) . "))";
+ $fields = array("samaccountname");
+ $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+ $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+ if (!isset($entries[0]['samaccountname'][0])) {
+ continue;
+ }
+ $subUsers = $this->members($entries[0]['samaccountname'][0], $recursive);
+ if (is_array($subUsers)) {
+ $userArray = array_merge($userArray, $subUsers);
+ $userArray = array_unique($userArray);
+ }
+ continue;
+ }
+ else if ($entries['count'] == 0) {
+ continue;
+ }
+
+ if ((!isset($entries[0]['samaccountname'][0]) || $entries[0]['samaccountname'][0] === NULL) && $entries[0]['distinguishedname'][0] !== NULL) {
+ $userArray[] = $entries[0]['distinguishedname'][0];
+ }
+ else if ($entries[0]['samaccountname'][0] !== NULL) {
+ $userArray[] = $entries[0]['samaccountname'][0];
+ }
+ }
+ return $userArray;
+ }
+
+ /**
+ * Group Information. Returns an array of raw information about a group.
+ * The group name is case sensitive
+ *
+ * @param string $groupName The group name to retrieve info about
+ * @param array $fields Fields to retrieve
+ * @return array
+ */
+ public function info($groupName, $fields = NULL)
+ {
+ if ($groupName === NULL) { return false; }
+ if (!$this->adldap->getLdapBind()) { return false; }
+
+ if (stristr($groupName, '+')) {
+ $groupName = stripslashes($groupName);
+ }
+
+ $filter = "(&(objectCategory=group)(name=" . $this->adldap->utilities()->ldapSlashes($groupName) . "))";
+ if ($fields === NULL) {
+ $fields = array("member","memberof","cn","description","distinguishedname","objectcategory","samaccountname");
+ }
+ $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+ $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+ return $entries;
+ }
+
+ /**
+ * Group Information. Returns an collection
+ * The group name is case sensitive
+ *
+ * @param string $groupName The group name to retrieve info about
+ * @param array $fields Fields to retrieve
+ * @return adLDAPGroupCollection
+ */
+ public function infoCollection($groupName, $fields = NULL)
+ {
+ if ($groupName === NULL) { return false; }
+ if (!$this->adldap->getLdapBind()) { return false; }
+
+ $info = $this->info($groupName, $fields);
+ if ($info !== false) {
+ $collection = new adLDAPGroupCollection($info, $this->adldap);
+ return $collection;
+ }
+ return false;
+ }
+
+ /**
+ * Return a complete list of "groups in groups"
+ *
+ * @param string $group The group to get the list from
+ * @return array
+ */
+ public function recursiveGroups($group)
+ {
+ if ($group === NULL) { return false; }
+
+ $stack = array();
+ $processed = array();
+ $retGroups = array();
+
+ array_push($stack, $group); // Initial Group to Start with
+ while (count($stack) > 0) {
+ $parent = array_pop($stack);
+ array_push($processed, $parent);
+
+ $info = $this->info($parent, array("memberof"));
+
+ if (isset($info[0]["memberof"]) && is_array($info[0]["memberof"])) {
+ $groups = $info[0]["memberof"];
+ if ($groups) {
+ $groupNames = $this->adldap->utilities()->niceNames($groups);
+ $retGroups = array_merge($retGroups, $groupNames); //final groups to return
+ foreach ($groupNames as $id => $groupName) {
+ if (!in_array($groupName, $processed)) {
+ array_push($stack, $groupName);
+ }
+ }
+ }
+ }
+ }
+
+ return $retGroups;
+ }
+
+ /**
+ * Returns a complete list of the groups in AD based on a SAM Account Type
+ *
+ * @param string $sAMAaccountType The account type to return
+ * @param bool $includeDescription Whether to return a description
+ * @param string $search Search parameters
+ * @param bool $sorted Whether to sort the results
+ * @return array
+ */
+ public function search($sAMAaccountType = adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP, $includeDescription = false, $search = "*", $sorted = true) {
+ if (!$this->adldap->getLdapBind()) { return false; }
+
+ $filter = '(&(objectCategory=group)';
+ if ($sAMAaccountType !== null) {
+ $filter .= '(samaccounttype='. $sAMAaccountType .')';
+ }
+ $filter .= '(cn=' . $search . '))';
+ // Perform the search and grab all their details
+ $fields = array("samaccountname", "description");
+ $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+ $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+ $groupsArray = array();
+ for ($i=0; $i<$entries["count"]; $i++){
+ if ($includeDescription && strlen($entries[$i]["description"][0]) > 0 ) {
+ $groupsArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["description"][0];
+ }
+ else if ($includeDescription){
+ $groupsArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
+ }
+ else {
+ array_push($groupsArray, $entries[$i]["samaccountname"][0]);
+ }
+ }
+ if ($sorted) {
+ asort($groupsArray);
+ }
+ return $groupsArray;
+ }
+
+ /**
+ * Returns a complete list of all groups in AD
+ *
+ * @param bool $includeDescription Whether to return a description
+ * @param string $search Search parameters
+ * @param bool $sorted Whether to sort the results
+ * @return array
+ */
+ public function all($includeDescription = false, $search = "*", $sorted = true){
+ $groupsArray = $this->search(null, $includeDescription, $search, $sorted);
+ return $groupsArray;
+ }
+
+ /**
+ * Returns a complete list of security groups in AD
+ *
+ * @param bool $includeDescription Whether to return a description
+ * @param string $search Search parameters
+ * @param bool $sorted Whether to sort the results
+ * @return array
+ */
+ public function allSecurity($includeDescription = false, $search = "*", $sorted = true){
+ $groupsArray = $this->search(adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP, $includeDescription, $search, $sorted);
+ return $groupsArray;
+ }
+
+ /**
+ * Returns a complete list of distribution lists in AD
+ *
+ * @param bool $includeDescription Whether to return a description
+ * @param string $search Search parameters
+ * @param bool $sorted Whether to sort the results
+ * @return array
+ */
+ public function allDistribution($includeDescription = false, $search = "*", $sorted = true){
+ $groupsArray = $this->search(adLDAP::ADLDAP_DISTRIBUTION_GROUP, $includeDescription, $search, $sorted);
+ return $groupsArray;
+ }
+
+ /**
+ * Coping with AD not returning the primary group
+ * http://support.microsoft.com/?kbid=321360
+ *
+ * This is a re-write based on code submitted by Bruce which prevents the
+ * need to search each security group to find the true primary group
+ *
+ * @param string $gid Group ID
+ * @param string $usersid User's Object SID
+ * @return mixed
+ */
+ public function getPrimaryGroup($gid, $usersid)
+ {
+ if ($gid === NULL || $usersid === NULL) { return false; }
+ $sr = false;
+
+ $gsid = substr_replace($usersid, pack('V',$gid), strlen($usersid)-4,4);
+ $filter = '(objectsid=' . $this->adldap->utilities()->getTextSID($gsid).')';
+ $fields = array("samaccountname","distinguishedname");
+ $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+ $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+ if (isset($entries[0]['distinguishedname'][0])) {
+ return $entries[0]['distinguishedname'][0];
+ }
+ return false;
+ }
+
+ /**
+ * Coping with AD not returning the primary group
+ * http://support.microsoft.com/?kbid=321360
+ *
+ * For some reason it's not possible to search on primarygrouptoken=XXX
+ * If someone can show otherwise, I'd like to know about it :)
+ * this way is resource intensive and generally a pain in the @#%^
+ *
+ * @deprecated deprecated since version 3.1, see get get_primary_group
+ * @param string $gid Group ID
+ * @return string
+ */
+ public function cn($gid){
+ if ($gid === NULL) { return false; }
+ $sr = false;
+ $r = '';
+
+ $filter = "(&(objectCategory=group)(samaccounttype=" . adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP . "))";
+ $fields = array("primarygrouptoken", "samaccountname", "distinguishedname");
+ $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+ $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+ for ($i=0; $i<$entries["count"]; $i++){
+ if ($entries[$i]["primarygrouptoken"][0] == $gid) {
+ $r = $entries[$i]["distinguishedname"][0];
+ $i = $entries["count"];
+ }
+ }
+
+ return $r;
+ }
+}
+?>
diff --git a/lib/plugins/authad/adLDAP/classes/adLDAPUsers.php b/lib/plugins/authad/adLDAP/classes/adLDAPUsers.php
new file mode 100644
index 000000000..96a93b512
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/classes/adLDAPUsers.php
@@ -0,0 +1,682 @@
+<?php
+/**
+ * PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY
+ * Version 4.0.4
+ *
+ * PHP Version 5 with SSL and LDAP support
+ *
+ * Written by Scott Barnett, Richard Hyland
+ * email: scott@wiggumworld.com, adldap@richardhyland.com
+ * http://adldap.sourceforge.net/
+ *
+ * Copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ *
+ * We'd appreciate any improvements or additions to be submitted back
+ * to benefit the entire community :)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * @category ToolsAndUtilities
+ * @package adLDAP
+ * @subpackage User
+ * @author Scott Barnett, Richard Hyland
+ * @copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html LGPLv2.1
+ * @revision $Revision: 97 $
+ * @version 4.0.4
+ * @link http://adldap.sourceforge.net/
+ */
+require_once(dirname(__FILE__) . '/../adLDAP.php');
+require_once(dirname(__FILE__) . '/../collections/adLDAPUserCollection.php');
+
+/**
+* USER FUNCTIONS
+*/
+class adLDAPUsers {
+ /**
+ * The current adLDAP connection via dependency injection
+ *
+ * @var adLDAP
+ */
+ protected $adldap;
+
+ public function __construct(adLDAP $adldap) {
+ $this->adldap = $adldap;
+ }
+
+ /**
+ * Validate a user's login credentials
+ *
+ * @param string $username A user's AD username
+ * @param string $password A user's AD password
+ * @param bool optional $prevent_rebind
+ * @return bool
+ */
+ public function authenticate($username, $password, $preventRebind = false) {
+ return $this->adldap->authenticate($username, $password, $preventRebind);
+ }
+
+ /**
+ * Create a user
+ *
+ * If you specify a password here, this can only be performed over SSL
+ *
+ * @param array $attributes The attributes to set to the user account
+ * @return bool
+ */
+ public function create($attributes)
+ {
+ // Check for compulsory fields
+ if (!array_key_exists("username", $attributes)){ return "Missing compulsory field [username]"; }
+ if (!array_key_exists("firstname", $attributes)){ return "Missing compulsory field [firstname]"; }
+ if (!array_key_exists("surname", $attributes)){ return "Missing compulsory field [surname]"; }
+ if (!array_key_exists("email", $attributes)){ return "Missing compulsory field [email]"; }
+ if (!array_key_exists("container", $attributes)){ return "Missing compulsory field [container]"; }
+ if (!is_array($attributes["container"])){ return "Container attribute must be an array."; }
+
+ if (array_key_exists("password",$attributes) && (!$this->adldap->getUseSSL() && !$this->adldap->getUseTLS())){
+ throw new adLDAPException('SSL must be configured on your webserver and enabled in the class to set passwords.');
+ }
+
+ if (!array_key_exists("display_name", $attributes)) {
+ $attributes["display_name"] = $attributes["firstname"] . " " . $attributes["surname"];
+ }
+
+ // Translate the schema
+ $add = $this->adldap->adldap_schema($attributes);
+
+ // Additional stuff only used for adding accounts
+ $add["cn"][0] = $attributes["display_name"];
+ $add["samaccountname"][0] = $attributes["username"];
+ $add["objectclass"][0] = "top";
+ $add["objectclass"][1] = "person";
+ $add["objectclass"][2] = "organizationalPerson";
+ $add["objectclass"][3] = "user"; //person?
+ //$add["name"][0]=$attributes["firstname"]." ".$attributes["surname"];
+
+ // Set the account control attribute
+ $control_options = array("NORMAL_ACCOUNT");
+ if (!$attributes["enabled"]) {
+ $control_options[] = "ACCOUNTDISABLE";
+ }
+ $add["userAccountControl"][0] = $this->accountControl($control_options);
+
+ // Determine the container
+ $attributes["container"] = array_reverse($attributes["container"]);
+ $container = "OU=" . implode(", OU=",$attributes["container"]);
+
+ // Add the entry
+ $result = @ldap_add($this->adldap->getLdapConnection(), "CN=" . $add["cn"][0] . ", " . $container . "," . $this->adldap->getBaseDn(), $add);
+ if ($result != true) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Account control options
+ *
+ * @param array $options The options to convert to int
+ * @return int
+ */
+ protected function accountControl($options)
+ {
+ $val=0;
+
+ if (is_array($options)) {
+ if (in_array("SCRIPT",$options)){ $val=$val+1; }
+ if (in_array("ACCOUNTDISABLE",$options)){ $val=$val+2; }
+ if (in_array("HOMEDIR_REQUIRED",$options)){ $val=$val+8; }
+ if (in_array("LOCKOUT",$options)){ $val=$val+16; }
+ if (in_array("PASSWD_NOTREQD",$options)){ $val=$val+32; }
+ //PASSWD_CANT_CHANGE Note You cannot assign this permission by directly modifying the UserAccountControl attribute.
+ //For information about how to set the permission programmatically, see the "Property flag descriptions" section.
+ if (in_array("ENCRYPTED_TEXT_PWD_ALLOWED",$options)){ $val=$val+128; }
+ if (in_array("TEMP_DUPLICATE_ACCOUNT",$options)){ $val=$val+256; }
+ if (in_array("NORMAL_ACCOUNT",$options)){ $val=$val+512; }
+ if (in_array("INTERDOMAIN_TRUST_ACCOUNT",$options)){ $val=$val+2048; }
+ if (in_array("WORKSTATION_TRUST_ACCOUNT",$options)){ $val=$val+4096; }
+ if (in_array("SERVER_TRUST_ACCOUNT",$options)){ $val=$val+8192; }
+ if (in_array("DONT_EXPIRE_PASSWORD",$options)){ $val=$val+65536; }
+ if (in_array("MNS_LOGON_ACCOUNT",$options)){ $val=$val+131072; }
+ if (in_array("SMARTCARD_REQUIRED",$options)){ $val=$val+262144; }
+ if (in_array("TRUSTED_FOR_DELEGATION",$options)){ $val=$val+524288; }
+ if (in_array("NOT_DELEGATED",$options)){ $val=$val+1048576; }
+ if (in_array("USE_DES_KEY_ONLY",$options)){ $val=$val+2097152; }
+ if (in_array("DONT_REQ_PREAUTH",$options)){ $val=$val+4194304; }
+ if (in_array("PASSWORD_EXPIRED",$options)){ $val=$val+8388608; }
+ if (in_array("TRUSTED_TO_AUTH_FOR_DELEGATION",$options)){ $val=$val+16777216; }
+ }
+ return $val;
+ }
+
+ /**
+ * Delete a user account
+ *
+ * @param string $username The username to delete (please be careful here!)
+ * @param bool $isGUID Is the username a GUID or a samAccountName
+ * @return array
+ */
+ public function delete($username, $isGUID = false)
+ {
+ $userinfo = $this->info($username, array("*"), $isGUID);
+ $dn = $userinfo[0]['distinguishedname'][0];
+ $result = $this->adldap->folder()->delete($dn);
+ if ($result != true) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Groups the user is a member of
+ *
+ * @param string $username The username to query
+ * @param bool $recursive Recursive list of groups
+ * @param bool $isGUID Is the username passed a GUID or a samAccountName
+ * @return array
+ */
+ public function groups($username, $recursive = NULL, $isGUID = false)
+ {
+ if ($username === NULL) { return false; }
+ if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it
+ if (!$this->adldap->getLdapBind()) { return false; }
+
+ // Search the directory for their information
+ $info = @$this->info($username, array("memberof", "primarygroupid"), $isGUID);
+ $groups = $this->adldap->utilities()->niceNames($info[0]["memberof"]); // Presuming the entry returned is our guy (unique usernames)
+
+ if ($recursive === true){
+ foreach ($groups as $id => $groupName){
+ $extraGroups = $this->adldap->group()->recursiveGroups($groupName);
+ $groups = array_merge($groups, $extraGroups);
+ }
+ }
+
+ return $groups;
+ }
+
+ /**
+ * Find information about the users. Returned in a raw array format from AD
+ *
+ * @param string $username The username to query
+ * @param array $fields Array of parameters to query
+ * @param bool $isGUID Is the username passed a GUID or a samAccountName
+ * @return array
+ */
+ public function info($username, $fields = NULL, $isGUID = false)
+ {
+ if ($username === NULL) { return false; }
+ if (!$this->adldap->getLdapBind()) { return false; }
+
+ if ($isGUID === true) {
+ $username = $this->adldap->utilities()->strGuidToHex($username);
+ $filter = "objectguid=" . $username;
+ }
+ else if (strstr($username, "@")) {
+ $filter = "userPrincipalName=" . $username;
+ }
+ else {
+ $filter = "samaccountname=" . $username;
+ }
+ $filter = "(&(objectCategory=person)({$filter}))";
+ if ($fields === NULL) {
+ $fields = array("samaccountname","mail","memberof","department","displayname","telephonenumber","primarygroupid","objectsid");
+ }
+ if (!in_array("objectsid", $fields)) {
+ $fields[] = "objectsid";
+ }
+ $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+ $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+ if (isset($entries[0])) {
+ if ($entries[0]['count'] >= 1) {
+ if (in_array("memberof", $fields)) {
+ // AD does not return the primary group in the ldap query, we may need to fudge it
+ if ($this->adldap->getRealPrimaryGroup() && isset($entries[0]["primarygroupid"][0]) && isset($entries[0]["objectsid"][0])){
+ //$entries[0]["memberof"][]=$this->group_cn($entries[0]["primarygroupid"][0]);
+ $entries[0]["memberof"][] = $this->adldap->group()->getPrimaryGroup($entries[0]["primarygroupid"][0], $entries[0]["objectsid"][0]);
+ } else {
+ $entries[0]["memberof"][] = "CN=Domain Users,CN=Users," . $this->adldap->getBaseDn();
+ }
+ if (!isset($entries[0]["memberof"]["count"])) {
+ $entries[0]["memberof"]["count"] = 0;
+ }
+ $entries[0]["memberof"]["count"]++;
+ }
+ }
+
+ return $entries;
+ }
+ return false;
+ }
+
+ /**
+ * Find information about the users. Returned in a raw array format from AD
+ *
+ * @param string $username The username to query
+ * @param array $fields Array of parameters to query
+ * @param bool $isGUID Is the username passed a GUID or a samAccountName
+ * @return mixed
+ */
+ public function infoCollection($username, $fields = NULL, $isGUID = false)
+ {
+ if ($username === NULL) { return false; }
+ if (!$this->adldap->getLdapBind()) { return false; }
+
+ $info = $this->info($username, $fields, $isGUID);
+
+ if ($info !== false) {
+ $collection = new adLDAPUserCollection($info, $this->adldap);
+ return $collection;
+ }
+ return false;
+ }
+
+ /**
+ * Determine if a user is in a specific group
+ *
+ * @param string $username The username to query
+ * @param string $group The name of the group to check against
+ * @param bool $recursive Check groups recursively
+ * @param bool $isGUID Is the username passed a GUID or a samAccountName
+ * @return bool
+ */
+ public function inGroup($username, $group, $recursive = NULL, $isGUID = false)
+ {
+ if ($username === NULL) { return false; }
+ if ($group === NULL) { return false; }
+ if (!$this->adldap->getLdapBind()) { return false; }
+ if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it
+
+ // Get a list of the groups
+ $groups = $this->groups($username, $recursive, $isGUID);
+
+ // Return true if the specified group is in the group list
+ if (in_array($group, $groups)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Determine a user's password expiry date
+ *
+ * @param string $username The username to query
+ * @param book $isGUID Is the username passed a GUID or a samAccountName
+ * @requires bcmath http://www.php.net/manual/en/book.bc.php
+ * @return array
+ */
+ public function passwordExpiry($username, $isGUID = false)
+ {
+ if ($username === NULL) { return "Missing compulsory field [username]"; }
+ if (!$this->adldap->getLdapBind()) { return false; }
+ if (!function_exists('bcmod')) { throw new adLDAPException("Missing function support [bcmod] http://www.php.net/manual/en/book.bc.php"); };
+
+ $userInfo = $this->info($username, array("pwdlastset", "useraccountcontrol"), $isGUID);
+ $pwdLastSet = $userInfo[0]['pwdlastset'][0];
+ $status = array();
+
+ if ($userInfo[0]['useraccountcontrol'][0] == '66048') {
+ // Password does not expire
+ return "Does not expire";
+ }
+ if ($pwdLastSet === '0') {
+ // Password has already expired
+ return "Password has expired";
+ }
+
+ // Password expiry in AD can be calculated from TWO values:
+ // - User's own pwdLastSet attribute: stores the last time the password was changed
+ // - Domain's maxPwdAge attribute: how long passwords last in the domain
+ //
+ // Although Microsoft chose to use a different base and unit for time measurements.
+ // This function will convert them to Unix timestamps
+ $sr = ldap_read($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), 'objectclass=*', array('maxPwdAge'));
+ if (!$sr) {
+ return false;
+ }
+ $info = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+ $maxPwdAge = $info[0]['maxpwdage'][0];
+
+
+ // See MSDN: http://msdn.microsoft.com/en-us/library/ms974598.aspx
+ //
+ // pwdLastSet contains the number of 100 nanosecond intervals since January 1, 1601 (UTC),
+ // stored in a 64 bit integer.
+ //
+ // The number of seconds between this date and Unix epoch is 11644473600.
+ //
+ // maxPwdAge is stored as a large integer that represents the number of 100 nanosecond
+ // intervals from the time the password was set before the password expires.
+ //
+ // We also need to scale this to seconds but also this value is a _negative_ quantity!
+ //
+ // If the low 32 bits of maxPwdAge are equal to 0 passwords do not expire
+ //
+ // Unfortunately the maths involved are too big for PHP integers, so I've had to require
+ // BCMath functions to work with arbitrary precision numbers.
+ if (bcmod($maxPwdAge, 4294967296) === '0') {
+ return "Domain does not expire passwords";
+ }
+
+ // Add maxpwdage and pwdlastset and we get password expiration time in Microsoft's
+ // time units. Because maxpwd age is negative we need to subtract it.
+ $pwdExpire = bcsub($pwdLastSet, $maxPwdAge);
+
+ // Convert MS's time to Unix time
+ $status['expiryts'] = bcsub(bcdiv($pwdExpire, '10000000'), '11644473600');
+ $status['expiryformat'] = date('Y-m-d H:i:s', bcsub(bcdiv($pwdExpire, '10000000'), '11644473600'));
+
+ return $status;
+ }
+
+ /**
+ * Modify a user
+ *
+ * @param string $username The username to query
+ * @param array $attributes The attributes to modify. Note if you set the enabled attribute you must not specify any other attributes
+ * @param bool $isGUID Is the username passed a GUID or a samAccountName
+ * @return bool
+ */
+ public function modify($username, $attributes, $isGUID = false)
+ {
+ if ($username === NULL) { return "Missing compulsory field [username]"; }
+ if (array_key_exists("password", $attributes) && !$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()) {
+ throw new adLDAPException('SSL/TLS must be configured on your webserver and enabled in the class to set passwords.');
+ }
+
+ // Find the dn of the user
+ $userDn = $this->dn($username, $isGUID);
+ if ($userDn === false) {
+ return false;
+ }
+
+ // Translate the update to the LDAP schema
+ $mod = $this->adldap->adldap_schema($attributes);
+
+ // Check to see if this is an enabled status update
+ if (!$mod && !array_key_exists("enabled", $attributes)){
+ return false;
+ }
+
+ // Set the account control attribute (only if specified)
+ if (array_key_exists("enabled", $attributes)){
+ if ($attributes["enabled"]){
+ $controlOptions = array("NORMAL_ACCOUNT");
+ }
+ else {
+ $controlOptions = array("NORMAL_ACCOUNT", "ACCOUNTDISABLE");
+ }
+ $mod["userAccountControl"][0] = $this->accountControl($controlOptions);
+ }
+
+ // Do the update
+ $result = @ldap_modify($this->adldap->getLdapConnection(), $userDn, $mod);
+ if ($result == false) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Disable a user account
+ *
+ * @param string $username The username to disable
+ * @param bool $isGUID Is the username passed a GUID or a samAccountName
+ * @return bool
+ */
+ public function disable($username, $isGUID = false)
+ {
+ if ($username === NULL) { return "Missing compulsory field [username]"; }
+ $attributes = array("enabled" => 0);
+ $result = $this->modify($username, $attributes, $isGUID);
+ if ($result == false) { return false; }
+
+ return true;
+ }
+
+ /**
+ * Enable a user account
+ *
+ * @param string $username The username to enable
+ * @param bool $isGUID Is the username passed a GUID or a samAccountName
+ * @return bool
+ */
+ public function enable($username, $isGUID = false)
+ {
+ if ($username === NULL) { return "Missing compulsory field [username]"; }
+ $attributes = array("enabled" => 1);
+ $result = $this->modify($username, $attributes, $isGUID);
+ if ($result == false) { return false; }
+
+ return true;
+ }
+
+ /**
+ * Set the password of a user - This must be performed over SSL
+ *
+ * @param string $username The username to modify
+ * @param string $password The new password
+ * @param bool $isGUID Is the username passed a GUID or a samAccountName
+ * @return bool
+ */
+ public function password($username, $password, $isGUID = false)
+ {
+ if ($username === NULL) { return false; }
+ if ($password === NULL) { return false; }
+ if (!$this->adldap->getLdapBind()) { return false; }
+ if (!$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()) {
+ throw new adLDAPException('SSL must be configured on your webserver and enabled in the class to set passwords.');
+ }
+
+ $userDn = $this->dn($username, $isGUID);
+ if ($userDn === false) {
+ return false;
+ }
+
+ $add=array();
+ $add["unicodePwd"][0] = $this->encodePassword($password);
+
+ $result = @ldap_mod_replace($this->adldap->getLdapConnection(), $userDn, $add);
+ if ($result === false){
+ $err = ldap_errno($this->adldap->getLdapConnection());
+ if ($err) {
+ $msg = 'Error ' . $err . ': ' . ldap_err2str($err) . '.';
+ if($err == 53) {
+ $msg .= ' Your password might not match the password policy.';
+ }
+ throw new adLDAPException($msg);
+ }
+ else {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Encode a password for transmission over LDAP
+ *
+ * @param string $password The password to encode
+ * @return string
+ */
+ public function encodePassword($password)
+ {
+ $password="\"".$password."\"";
+ $encoded="";
+ for ($i=0; $i <strlen($password); $i++){ $encoded.="{$password{$i}}\000"; }
+ return $encoded;
+ }
+
+ /**
+ * Obtain the user's distinguished name based on their userid
+ *
+ *
+ * @param string $username The username
+ * @param bool $isGUID Is the username passed a GUID or a samAccountName
+ * @return string
+ */
+ public function dn($username, $isGUID=false)
+ {
+ $user = $this->info($username, array("cn"), $isGUID);
+ if ($user[0]["dn"] === NULL) {
+ return false;
+ }
+ $userDn = $user[0]["dn"];
+ return $userDn;
+ }
+
+ /**
+ * Return a list of all users in AD
+ *
+ * @param bool $includeDescription Return a description of the user
+ * @param string $search Search parameter
+ * @param bool $sorted Sort the user accounts
+ * @return array
+ */
+ public function all($includeDescription = false, $search = "*", $sorted = true)
+ {
+ if (!$this->adldap->getLdapBind()) { return false; }
+
+ // Perform the search and grab all their details
+ $filter = "(&(objectClass=user)(samaccounttype=" . adLDAP::ADLDAP_NORMAL_ACCOUNT .")(objectCategory=person)(cn=" . $search . "))";
+ $fields = array("samaccountname","displayname");
+ $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+ $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+ $usersArray = array();
+ for ($i=0; $i<$entries["count"]; $i++){
+ if ($includeDescription && strlen($entries[$i]["displayname"][0])>0){
+ $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["displayname"][0];
+ } elseif ($includeDescription){
+ $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
+ } else {
+ array_push($usersArray, $entries[$i]["samaccountname"][0]);
+ }
+ }
+ if ($sorted) {
+ asort($usersArray);
+ }
+ return $usersArray;
+ }
+
+ /**
+ * Converts a username (samAccountName) to a GUID
+ *
+ * @param string $username The username to query
+ * @return string
+ */
+ public function usernameToGuid($username)
+ {
+ if (!$this->adldap->getLdapBind()){ return false; }
+ if ($username === null){ return "Missing compulsory field [username]"; }
+
+ $filter = "samaccountname=" . $username;
+ $fields = array("objectGUID");
+ $sr = @ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+ if (ldap_count_entries($this->adldap->getLdapConnection(), $sr) > 0) {
+ $entry = @ldap_first_entry($this->adldap->getLdapConnection(), $sr);
+ $guid = @ldap_get_values_len($this->adldap->getLdapConnection(), $entry, 'objectGUID');
+ $strGUID = $this->adldap->utilities()->binaryToText($guid[0]);
+ return $strGUID;
+ }
+ return false;
+ }
+
+ /**
+ * Return a list of all users in AD that have a specific value in a field
+ *
+ * @param bool $includeDescription Return a description of the user
+ * @param string $searchField Field to search search for
+ * @param string $searchFilter Value to search for in the specified field
+ * @param bool $sorted Sort the user accounts
+ * @return array
+ */
+ public function find($includeDescription = false, $searchField = false, $searchFilter = false, $sorted = true){
+ if (!$this->adldap->getLdapBind()){ return false; }
+
+ // Perform the search and grab all their details
+ $searchParams = "";
+ if ($searchField) {
+ $searchParams = "(" . $searchField . "=" . $searchFilter . ")";
+ }
+ $filter = "(&(objectClass=user)(samaccounttype=" . adLDAP::ADLDAP_NORMAL_ACCOUNT .")(objectCategory=person)" . $searchParams . ")";
+ $fields = array("samaccountname","displayname");
+ $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
+ $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
+
+ $usersArray = array();
+ for ($i=0; $i < $entries["count"]; $i++) {
+ if ($includeDescription && strlen($entries[$i]["displayname"][0]) > 0) {
+ $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["displayname"][0];
+ }
+ else if ($includeDescription) {
+ $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
+ }
+ else {
+ array_push($usersArray, $entries[$i]["samaccountname"][0]);
+ }
+ }
+ if ($sorted){
+ asort($usersArray);
+ }
+ return ($usersArray);
+ }
+
+ /**
+ * Move a user account to a different OU
+ *
+ * @param string $username The username to move (please be careful here!)
+ * @param array $container The container or containers to move the user to (please be careful here!).
+ * accepts containers in 1. parent 2. child order
+ * @return array
+ */
+ public function move($username, $container)
+ {
+ if (!$this->adldap->getLdapBind()) { return false; }
+ if ($username === null) { return "Missing compulsory field [username]"; }
+ if ($container === null) { return "Missing compulsory field [container]"; }
+ if (!is_array($container)) { return "Container must be an array"; }
+
+ $userInfo = $this->info($username, array("*"));
+ $dn = $userInfo[0]['distinguishedname'][0];
+ $newRDn = "cn=" . $username;
+ $container = array_reverse($container);
+ $newContainer = "ou=" . implode(",ou=",$container);
+ $newBaseDn = strtolower($newContainer) . "," . $this->adldap->getBaseDn();
+ $result = @ldap_rename($this->adldap->getLdapConnection(), $dn, $newRDn, $newBaseDn, true);
+ if ($result !== true) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Get the last logon time of any user as a Unix timestamp
+ *
+ * @param string $username
+ * @return long $unixTimestamp
+ */
+ public function getLastLogon($username) {
+ if (!$this->adldap->getLdapBind()) { return false; }
+ if ($username === null) { return "Missing compulsory field [username]"; }
+ $userInfo = $this->info($username, array("lastLogonTimestamp"));
+ $lastLogon = adLDAPUtils::convertWindowsTimeToUnixTime($userInfo[0]['lastLogonTimestamp'][0]);
+ return $lastLogon;
+ }
+
+}
+?>
diff --git a/lib/plugins/authad/adLDAP/classes/adLDAPUtils.php b/lib/plugins/authad/adLDAP/classes/adLDAPUtils.php
new file mode 100644
index 000000000..f039a4290
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/classes/adLDAPUtils.php
@@ -0,0 +1,264 @@
+<?php
+/**
+ * PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY
+ * Version 4.0.4
+ *
+ * PHP Version 5 with SSL and LDAP support
+ *
+ * Written by Scott Barnett, Richard Hyland
+ * email: scott@wiggumworld.com, adldap@richardhyland.com
+ * http://adldap.sourceforge.net/
+ *
+ * Copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ *
+ * We'd appreciate any improvements or additions to be submitted back
+ * to benefit the entire community :)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * @category ToolsAndUtilities
+ * @package adLDAP
+ * @subpackage Utils
+ * @author Scott Barnett, Richard Hyland
+ * @copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html LGPLv2.1
+ * @revision $Revision: 97 $
+ * @version 4.0.4
+ * @link http://adldap.sourceforge.net/
+ */
+require_once(dirname(__FILE__) . '/../adLDAP.php');
+
+/**
+* UTILITY FUNCTIONS
+*/
+class adLDAPUtils {
+ const ADLDAP_VERSION = '4.0.4';
+
+ /**
+ * The current adLDAP connection via dependency injection
+ *
+ * @var adLDAP
+ */
+ protected $adldap;
+
+ public function __construct(adLDAP $adldap) {
+ $this->adldap = $adldap;
+ }
+
+
+ /**
+ * Take an LDAP query and return the nice names, without all the LDAP prefixes (eg. CN, DN)
+ *
+ * @param array $groups
+ * @return array
+ */
+ public function niceNames($groups)
+ {
+
+ $groupArray = array();
+ for ($i=0; $i<$groups["count"]; $i++){ // For each group
+ $line = $groups[$i];
+
+ if (strlen($line)>0) {
+ // More presumptions, they're all prefixed with CN=
+ // so we ditch the first three characters and the group
+ // name goes up to the first comma
+ $bits=explode(",", $line);
+ $groupArray[] = substr($bits[0], 3, (strlen($bits[0])-3));
+ }
+ }
+ return $groupArray;
+ }
+
+ /**
+ * Escape characters for use in an ldap_create function
+ *
+ * @param string $str
+ * @return string
+ */
+ public function escapeCharacters($str) {
+ $str = str_replace(",", "\,", $str);
+ return $str;
+ }
+
+ /**
+ * Escape strings for the use in LDAP filters
+ *
+ * DEVELOPERS SHOULD BE DOING PROPER FILTERING IF THEY'RE ACCEPTING USER INPUT
+ * Ported from Perl's Net::LDAP::Util escape_filter_value
+ *
+ * @param string $str The string the parse
+ * @author Port by Andreas Gohr <andi@splitbrain.org>
+ * @return string
+ */
+ public function ldapSlashes($str){
+ return preg_replace('/([\x00-\x1F\*\(\)\\\\])/e',
+ '"\\\\\".join("",unpack("H2","$1"))',
+ $str);
+ }
+
+ /**
+ * Converts a string GUID to a hexdecimal value so it can be queried
+ *
+ * @param string $strGUID A string representation of a GUID
+ * @return string
+ */
+ public function strGuidToHex($strGUID)
+ {
+ $strGUID = str_replace('-', '', $strGUID);
+
+ $octet_str = '\\' . substr($strGUID, 6, 2);
+ $octet_str .= '\\' . substr($strGUID, 4, 2);
+ $octet_str .= '\\' . substr($strGUID, 2, 2);
+ $octet_str .= '\\' . substr($strGUID, 0, 2);
+ $octet_str .= '\\' . substr($strGUID, 10, 2);
+ $octet_str .= '\\' . substr($strGUID, 8, 2);
+ $octet_str .= '\\' . substr($strGUID, 14, 2);
+ $octet_str .= '\\' . substr($strGUID, 12, 2);
+ //$octet_str .= '\\' . substr($strGUID, 16, strlen($strGUID));
+ for ($i=16; $i<=(strlen($strGUID)-2); $i++) {
+ if (($i % 2) == 0) {
+ $octet_str .= '\\' . substr($strGUID, $i, 2);
+ }
+ }
+
+ return $octet_str;
+ }
+
+ /**
+ * Convert a binary SID to a text SID
+ *
+ * @param string $binsid A Binary SID
+ * @return string
+ */
+ public function getTextSID($binsid) {
+ $hex_sid = bin2hex($binsid);
+ $rev = hexdec(substr($hex_sid, 0, 2));
+ $subcount = hexdec(substr($hex_sid, 2, 2));
+ $auth = hexdec(substr($hex_sid, 4, 12));
+ $result = "$rev-$auth";
+
+ for ($x=0;$x < $subcount; $x++) {
+ $subauth[$x] =
+ hexdec($this->littleEndian(substr($hex_sid, 16 + ($x * 8), 8)));
+ $result .= "-" . $subauth[$x];
+ }
+
+ // Cheat by tacking on the S-
+ return 'S-' . $result;
+ }
+
+ /**
+ * Converts a little-endian hex number to one that hexdec() can convert
+ *
+ * @param string $hex A hex code
+ * @return string
+ */
+ public function littleEndian($hex)
+ {
+ $result = '';
+ for ($x = strlen($hex) - 2; $x >= 0; $x = $x - 2) {
+ $result .= substr($hex, $x, 2);
+ }
+ return $result;
+ }
+
+ /**
+ * Converts a binary attribute to a string
+ *
+ * @param string $bin A binary LDAP attribute
+ * @return string
+ */
+ public function binaryToText($bin)
+ {
+ $hex_guid = bin2hex($bin);
+ $hex_guid_to_guid_str = '';
+ for($k = 1; $k <= 4; ++$k) {
+ $hex_guid_to_guid_str .= substr($hex_guid, 8 - 2 * $k, 2);
+ }
+ $hex_guid_to_guid_str .= '-';
+ for($k = 1; $k <= 2; ++$k) {
+ $hex_guid_to_guid_str .= substr($hex_guid, 12 - 2 * $k, 2);
+ }
+ $hex_guid_to_guid_str .= '-';
+ for($k = 1; $k <= 2; ++$k) {
+ $hex_guid_to_guid_str .= substr($hex_guid, 16 - 2 * $k, 2);
+ }
+ $hex_guid_to_guid_str .= '-' . substr($hex_guid, 16, 4);
+ $hex_guid_to_guid_str .= '-' . substr($hex_guid, 20);
+ return strtoupper($hex_guid_to_guid_str);
+ }
+
+ /**
+ * Converts a binary GUID to a string GUID
+ *
+ * @param string $binaryGuid The binary GUID attribute to convert
+ * @return string
+ */
+ public function decodeGuid($binaryGuid)
+ {
+ if ($binaryGuid === null){ return "Missing compulsory field [binaryGuid]"; }
+
+ $strGUID = $this->binaryToText($binaryGuid);
+ return $strGUID;
+ }
+
+ /**
+ * Convert a boolean value to a string
+ * You should never need to call this yourself
+ *
+ * @param bool $bool Boolean value
+ * @return string
+ */
+ public function boolToStr($bool)
+ {
+ return ($bool) ? 'TRUE' : 'FALSE';
+ }
+
+ /**
+ * Convert 8bit characters e.g. accented characters to UTF8 encoded characters
+ */
+ public function encode8Bit(&$item, $key) {
+ $encode = false;
+ if (is_string($item)) {
+ for ($i=0; $i<strlen($item); $i++) {
+ if (ord($item[$i]) >> 7) {
+ $encode = true;
+ }
+ }
+ }
+ if ($encode === true && $key != 'password') {
+ $item = utf8_encode($item);
+ }
+ }
+
+ /**
+ * Get the current class version number
+ *
+ * @return string
+ */
+ public function getVersion() {
+ return self::ADLDAP_VERSION;
+ }
+
+ /**
+ * Round a Windows timestamp down to seconds and remove the seconds between 1601-01-01 and 1970-01-01
+ *
+ * @param long $windowsTime
+ * @return long $unixTime
+ */
+ public static function convertWindowsTimeToUnixTime($windowsTime) {
+ $unixTime = round($windowsTime / 10000000) - 11644477200;
+ return $unixTime;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/lib/plugins/authad/adLDAP/collections/adLDAPCollection.php b/lib/plugins/authad/adLDAP/collections/adLDAPCollection.php
new file mode 100644
index 000000000..c0a2eb2fa
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/collections/adLDAPCollection.php
@@ -0,0 +1,137 @@
+<?php
+/**
+ * PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY
+ * Version 4.0.4
+ *
+ * PHP Version 5 with SSL and LDAP support
+ *
+ * Written by Scott Barnett, Richard Hyland
+ * email: scott@wiggumworld.com, adldap@richardhyland.com
+ * http://adldap.sourceforge.net/
+ *
+ * Copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ *
+ * We'd appreciate any improvements or additions to be submitted back
+ * to benefit the entire community :)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * @category ToolsAndUtilities
+ * @package adLDAP
+ * @subpackage Collection
+ * @author Scott Barnett, Richard Hyland
+ * @copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html LGPLv2.1
+ * @revision $Revision: 97 $
+ * @version 4.0.4
+ * @link http://adldap.sourceforge.net/
+*/
+
+abstract class adLDAPCollection
+{
+ /**
+ * The current adLDAP connection via dependency injection
+ *
+ * @var adLDAP
+ */
+ protected $adldap;
+
+ /**
+ * The current object being modifed / called
+ *
+ * @var mixed
+ */
+ protected $currentObject;
+
+ /**
+ * The raw info array from Active Directory
+ *
+ * @var array
+ */
+ protected $info;
+
+ public function __construct($info, adLDAP $adldap)
+ {
+ $this->setInfo($info);
+ $this->adldap = $adldap;
+ }
+
+ /**
+ * Set the raw info array from Active Directory
+ *
+ * @param array $info
+ */
+ public function setInfo(array $info)
+ {
+ if ($this->info && sizeof($info) >= 1) {
+ unset($this->info);
+ }
+ $this->info = $info;
+ }
+
+ /**
+ * Magic get method to retrieve data from the raw array in a formatted way
+ *
+ * @param string $attribute
+ * @return mixed
+ */
+ public function __get($attribute)
+ {
+ if (isset($this->info[0]) && is_array($this->info[0])) {
+ foreach ($this->info[0] as $keyAttr => $valueAttr) {
+ if (strtolower($keyAttr) == strtolower($attribute)) {
+ if ($this->info[0][strtolower($attribute)]['count'] == 1) {
+ return $this->info[0][strtolower($attribute)][0];
+ }
+ else {
+ $array = array();
+ foreach ($this->info[0][strtolower($attribute)] as $key => $value) {
+ if ((string)$key != 'count') {
+ $array[$key] = $value;
+ }
+ }
+ return $array;
+ }
+ }
+ }
+ }
+ else {
+ return NULL;
+ }
+ }
+
+ /**
+ * Magic set method to update an attribute
+ *
+ * @param string $attribute
+ * @param string $value
+ * @return bool
+ */
+ abstract public function __set($attribute, $value);
+
+ /**
+ * Magic isset method to check for the existence of an attribute
+ *
+ * @param string $attribute
+ * @return bool
+ */
+ public function __isset($attribute) {
+ if (isset($this->info[0]) && is_array($this->info[0])) {
+ foreach ($this->info[0] as $keyAttr => $valueAttr) {
+ if (strtolower($keyAttr) == strtolower($attribute)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
+?>
diff --git a/lib/plugins/authad/adLDAP/collections/adLDAPComputerCollection.php b/lib/plugins/authad/adLDAP/collections/adLDAPComputerCollection.php
new file mode 100644
index 000000000..4f11d8f41
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/collections/adLDAPComputerCollection.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY
+ * Version 4.0.4
+ *
+ * PHP Version 5 with SSL and LDAP support
+ *
+ * Written by Scott Barnett, Richard Hyland
+ * email: scott@wiggumworld.com, adldap@richardhyland.com
+ * http://adldap.sourceforge.net/
+ *
+ * Copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ *
+ * We'd appreciate any improvements or additions to be submitted back
+ * to benefit the entire community :)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * @category ToolsAndUtilities
+ * @package adLDAP
+ * @subpackage ComputerCollection
+ * @author Scott Barnett, Richard Hyland
+ * @copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html LGPLv2.1
+ * @revision $Revision: 97 $
+ * @version 4.0.4
+ * @link http://adldap.sourceforge.net/
+*/
+
+class adLDAPComputerCollection extends adLDAPCollection
+{
+
+ public function __set($attribute, $value)
+ {
+
+ }
+}
+?>
diff --git a/lib/plugins/authad/adLDAP/collections/adLDAPContactCollection.php b/lib/plugins/authad/adLDAP/collections/adLDAPContactCollection.php
new file mode 100644
index 000000000..d42fe6d4c
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/collections/adLDAPContactCollection.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY
+ * Version 4.0.4
+ *
+ * PHP Version 5 with SSL and LDAP support
+ *
+ * Written by Scott Barnett, Richard Hyland
+ * email: scott@wiggumworld.com, adldap@richardhyland.com
+ * http://adldap.sourceforge.net/
+ *
+ * Copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ *
+ * We'd appreciate any improvements or additions to be submitted back
+ * to benefit the entire community :)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * @category ToolsAndUtilities
+ * @package adLDAP
+ * @subpackage ContactCollection
+ * @author Scott Barnett, Richard Hyland
+ * @copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html LGPLv2.1
+ * @revision $Revision: 97 $
+ * @version 4.0.4
+ * @link http://adldap.sourceforge.net/
+*/
+
+class adLDAPContactCollection extends adLDAPCollection
+{
+
+ public function __set($attribute, $value)
+ {
+
+ }
+}
+?>
diff --git a/lib/plugins/authad/adLDAP/collections/adLDAPGroupCollection.php b/lib/plugins/authad/adLDAP/collections/adLDAPGroupCollection.php
new file mode 100644
index 000000000..cff12fc20
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/collections/adLDAPGroupCollection.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY
+ * Version 4.0.4
+ *
+ * PHP Version 5 with SSL and LDAP support
+ *
+ * Written by Scott Barnett, Richard Hyland
+ * email: scott@wiggumworld.com, adldap@richardhyland.com
+ * http://adldap.sourceforge.net/
+ *
+ * Copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ *
+ * We'd appreciate any improvements or additions to be submitted back
+ * to benefit the entire community :)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * @category ToolsAndUtilities
+ * @package adLDAP
+ * @subpackage GroupCollection
+ * @author Scott Barnett, Richard Hyland
+ * @copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html LGPLv2.1
+ * @revision $Revision: 97 $
+ * @version 4.0.4
+ * @link http://adldap.sourceforge.net/
+*/
+
+class adLDAPGroupCollection extends adLDAPCollection
+{
+
+ public function __set($attribute, $value)
+ {
+
+ }
+}
+?>
diff --git a/lib/plugins/authad/adLDAP/collections/adLDAPUserCollection.php b/lib/plugins/authad/adLDAP/collections/adLDAPUserCollection.php
new file mode 100644
index 000000000..801d90296
--- /dev/null
+++ b/lib/plugins/authad/adLDAP/collections/adLDAPUserCollection.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY
+ * Version 4.0.4
+ *
+ * PHP Version 5 with SSL and LDAP support
+ *
+ * Written by Scott Barnett, Richard Hyland
+ * email: scott@wiggumworld.com, adldap@richardhyland.com
+ * http://adldap.sourceforge.net/
+ *
+ * Copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ *
+ * We'd appreciate any improvements or additions to be submitted back
+ * to benefit the entire community :)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * @category ToolsAndUtilities
+ * @package adLDAP
+ * @subpackage UserCollection
+ * @author Scott Barnett, Richard Hyland
+ * @copyright (c) 2006-2012 Scott Barnett, Richard Hyland
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html LGPLv2.1
+ * @revision $Revision: 97 $
+ * @version 4.0.4
+ * @link http://adldap.sourceforge.net/
+*/
+
+class adLDAPUserCollection extends adLDAPCollection
+{
+
+ public function __set($attribute, $value)
+ {
+
+ }
+}
+?>
diff --git a/lib/plugins/authad/auth.php b/lib/plugins/authad/auth.php
new file mode 100644
index 000000000..fcbd2eeef
--- /dev/null
+++ b/lib/plugins/authad/auth.php
@@ -0,0 +1,541 @@
+<?php
+// must be run within Dokuwiki
+if(!defined('DOKU_INC')) die();
+
+require_once(DOKU_PLUGIN.'authad/adLDAP/adLDAP.php');
+
+/**
+ * Active Directory authentication backend for DokuWiki
+ *
+ * This makes authentication with a Active Directory server much easier
+ * than when using the normal LDAP backend by utilizing the adLDAP library
+ *
+ * Usage:
+ * Set DokuWiki's local.protected.php auth setting to read
+ *
+ * $conf['authtype'] = 'authad';
+ *
+ * $conf['plugin']['authad']['account_suffix'] = '@my.domain.org';
+ * $conf['plugin']['authad']['base_dn'] = 'DC=my,DC=domain,DC=org';
+ * $conf['plugin']['authad']['domain_controllers'] = 'srv1.domain.org,srv2.domain.org';
+ *
+ * //optional:
+ * $conf['plugin']['authad']['sso'] = 1;
+ * $conf['plugin']['authad']['admin_username'] = 'root';
+ * $conf['plugin']['authad']['admin_password'] = 'pass';
+ * $conf['plugin']['authad']['real_primarygroup'] = 1;
+ * $conf['plugin']['authad']['use_ssl'] = 1;
+ * $conf['plugin']['authad']['use_tls'] = 1;
+ * $conf['plugin']['authad']['debug'] = 1;
+ * // warn user about expiring password this many days in advance:
+ * $conf['plugin']['authad']['expirywarn'] = 5;
+ *
+ * // get additional information to the userinfo array
+ * // add a list of comma separated ldap contact fields.
+ * $conf['plugin']['authad']['additional'] = 'field1,field2';
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author James Van Lommel <jamesvl@gmail.com>
+ * @link http://www.nosq.com/blog/2005/08/ldap-activedirectory-and-dokuwiki/
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @author Jan Schumann <js@schumann-it.com>
+ */
+class auth_plugin_authad extends DokuWiki_Auth_Plugin {
+
+ /**
+ * @var array hold connection data for a specific AD domain
+ */
+ protected $opts = array();
+
+ /**
+ * @var array open connections for each AD domain, as adLDAP objects
+ */
+ protected $adldap = array();
+
+ /**
+ * @var bool message state
+ */
+ protected $msgshown = false;
+
+ /**
+ * @var array user listing cache
+ */
+ protected $users = array();
+
+ /**
+ * @var array filter patterns for listing users
+ */
+ protected $_pattern = array();
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ global $INPUT;
+ parent::__construct();
+
+ // we load the config early to modify it a bit here
+ $this->loadConfig();
+
+ // additional information fields
+ if(isset($this->conf['additional'])) {
+ $this->conf['additional'] = str_replace(' ', '', $this->conf['additional']);
+ $this->conf['additional'] = explode(',', $this->conf['additional']);
+ } else $this->conf['additional'] = array();
+
+ // ldap extension is needed
+ if(!function_exists('ldap_connect')) {
+ if($this->conf['debug'])
+ msg("AD Auth: PHP LDAP extension not found.", -1);
+ $this->success = false;
+ return;
+ }
+
+ // Prepare SSO
+ if(!utf8_check($_SERVER['REMOTE_USER'])) {
+ $_SERVER['REMOTE_USER'] = utf8_encode($_SERVER['REMOTE_USER']);
+ }
+ if($_SERVER['REMOTE_USER'] && $this->conf['sso']) {
+ $_SERVER['REMOTE_USER'] = $this->cleanUser($_SERVER['REMOTE_USER']);
+
+ // we need to simulate a login
+ if(empty($_COOKIE[DOKU_COOKIE])) {
+ $INPUT->set('u', $_SERVER['REMOTE_USER']);
+ $INPUT->set('p', 'sso_only');
+ }
+ }
+
+ // other can do's are changed in $this->_loadServerConfig() base on domain setup
+ $this->cando['modName'] = true;
+ $this->cando['modMail'] = true;
+ }
+
+ /**
+ * Load domain config on capability check
+ *
+ * @param string $cap
+ * @return bool
+ */
+ public function canDo($cap) {
+ //capabilities depend on config, which may change depending on domain
+ $domain = $this->_userDomain($_SERVER['REMOTE_USER']);
+ $this->_loadServerConfig($domain);
+ return parent::canDo($cap);
+ }
+
+ /**
+ * Check user+password [required auth function]
+ *
+ * Checks if the given user exists and the given
+ * plaintext password is correct by trying to bind
+ * to the LDAP server
+ *
+ * @author James Van Lommel <james@nosq.com>
+ * @param string $user
+ * @param string $pass
+ * @return bool
+ */
+ public function checkPass($user, $pass) {
+ if($_SERVER['REMOTE_USER'] &&
+ $_SERVER['REMOTE_USER'] == $user &&
+ $this->conf['sso']
+ ) return true;
+
+ $adldap = $this->_adldap($this->_userDomain($user));
+ if(!$adldap) return false;
+
+ return $adldap->authenticate($this->_userName($user), $pass);
+ }
+
+ /**
+ * Return user info [required auth function]
+ *
+ * Returns info about the given user needs to contain
+ * at least these fields:
+ *
+ * name string full name of the user
+ * mail string email address of the user
+ * grps array list of groups the user is in
+ *
+ * This AD specific function returns the following
+ * addional fields:
+ *
+ * dn string distinguished name (DN)
+ * uid string samaccountname
+ * lastpwd int timestamp of the date when the password was set
+ * expires true if the password expires
+ * expiresin int seconds until the password expires
+ * any fields specified in the 'additional' config option
+ *
+ * @author James Van Lommel <james@nosq.com>
+ * @param string $user
+ * @return array
+ */
+ public function getUserData($user) {
+ global $conf;
+ global $lang;
+ global $ID;
+ $adldap = $this->_adldap($this->_userDomain($user));
+ if(!$adldap) return false;
+
+ if($user == '') return array();
+
+ $fields = array('mail', 'displayname', 'samaccountname', 'lastpwd', 'pwdlastset', 'useraccountcontrol');
+
+ // add additional fields to read
+ $fields = array_merge($fields, $this->conf['additional']);
+ $fields = array_unique($fields);
+ $fields = array_filter($fields);
+
+ //get info for given user
+ $result = $adldap->user()->info($this->_userName($user), $fields);
+ if($result == false){
+ return array();
+ }
+
+ //general user info
+ $info['name'] = $result[0]['displayname'][0];
+ $info['mail'] = $result[0]['mail'][0];
+ $info['uid'] = $result[0]['samaccountname'][0];
+ $info['dn'] = $result[0]['dn'];
+ //last password set (Windows counts from January 1st 1601)
+ $info['lastpwd'] = $result[0]['pwdlastset'][0] / 10000000 - 11644473600;
+ //will it expire?
+ $info['expires'] = !($result[0]['useraccountcontrol'][0] & 0x10000); //ADS_UF_DONT_EXPIRE_PASSWD
+
+ // additional information
+ foreach($this->conf['additional'] as $field) {
+ if(isset($result[0][strtolower($field)])) {
+ $info[$field] = $result[0][strtolower($field)][0];
+ }
+ }
+
+ // handle ActiveDirectory memberOf
+ $info['grps'] = $adldap->user()->groups($this->_userName($user),(bool) $this->opts['recursive_groups']);
+
+ if(is_array($info['grps'])) {
+ foreach($info['grps'] as $ndx => $group) {
+ $info['grps'][$ndx] = $this->cleanGroup($group);
+ }
+ }
+
+ // always add the default group to the list of groups
+ if(!is_array($info['grps']) || !in_array($conf['defaultgroup'], $info['grps'])) {
+ $info['grps'][] = $conf['defaultgroup'];
+ }
+
+ // add the user's domain to the groups
+ $domain = $this->_userDomain($user);
+ if($domain && !in_array("domain-$domain", (array) $info['grps'])) {
+ $info['grps'][] = $this->cleanGroup("domain-$domain");
+ }
+
+ // check expiry time
+ if($info['expires'] && $this->conf['expirywarn']){
+ $expiry = $adldap->user()->passwordExpiry($user);
+ if(is_array($expiry)){
+ $info['expiresat'] = $expiry['expiryts'];
+ $info['expiresin'] = round(($info['expiresat'] - time())/(24*60*60));
+
+ // if this is the current user, warn him (once per request only)
+ if(($_SERVER['REMOTE_USER'] == $user) &&
+ ($info['expiresin'] <= $this->conf['expirywarn']) &&
+ !$this->msgshown
+ ) {
+ $msg = sprintf($lang['authpwdexpire'], $info['expiresin']);
+ if($this->canDo('modPass')) {
+ $url = wl($ID, array('do'=> 'profile'));
+ $msg .= ' <a href="'.$url.'">'.$lang['btn_profile'].'</a>';
+ }
+ msg($msg);
+ $this->msgshown = true;
+ }
+ }
+ }
+
+ return $info;
+ }
+
+ /**
+ * Make AD group names usable by DokuWiki.
+ *
+ * Removes backslashes ('\'), pound signs ('#'), and converts spaces to underscores.
+ *
+ * @author James Van Lommel (jamesvl@gmail.com)
+ * @param string $group
+ * @return string
+ */
+ public function cleanGroup($group) {
+ $group = str_replace('\\', '', $group);
+ $group = str_replace('#', '', $group);
+ $group = preg_replace('[\s]', '_', $group);
+ $group = utf8_strtolower(trim($group));
+ return $group;
+ }
+
+ /**
+ * Sanitize user names
+ *
+ * Normalizes domain parts, does not modify the user name itself (unlike cleanGroup)
+ *
+ * @author Andreas Gohr <gohr@cosmocode.de>
+ * @param string $user
+ * @return string
+ */
+ public function cleanUser($user) {
+ $domain = '';
+
+ // get NTLM or Kerberos domain part
+ list($dom, $user) = explode('\\', $user, 2);
+ if(!$user) $user = $dom;
+ if($dom) $domain = $dom;
+ list($user, $dom) = explode('@', $user, 2);
+ if($dom) $domain = $dom;
+
+ // clean up both
+ $domain = utf8_strtolower(trim($domain));
+ $user = utf8_strtolower(trim($user));
+
+ // is this a known, valid domain? if not discard
+ if(!is_array($this->conf[$domain])) {
+ $domain = '';
+ }
+
+ // reattach domain
+ if($domain) $user = "$user@$domain";
+ return $user;
+ }
+
+ /**
+ * Most values in LDAP are case-insensitive
+ *
+ * @return bool
+ */
+ public function isCaseSensitive() {
+ return false;
+ }
+
+ /**
+ * Bulk retrieval of user data
+ *
+ * @author Dominik Eckelmann <dokuwiki@cosmocode.de>
+ * @param int $start index of first user to be returned
+ * @param int $limit max number of users to be returned
+ * @param array $filter array of field/pattern pairs, null for no filter
+ * @return array userinfo (refer getUserData for internal userinfo details)
+ */
+ public function retrieveUsers($start = 0, $limit = -1, $filter = array()) {
+ $adldap = $this->_adldap(null);
+ if(!$adldap) return false;
+
+ if($this->users === null) {
+ //get info for given user
+ $result = $adldap->user()->all();
+ if (!$result) return array();
+ $this->users = array_fill_keys($result, false);
+ }
+
+ $i = 0;
+ $count = 0;
+ $this->_constructPattern($filter);
+ $result = array();
+
+ foreach($this->users as $user => &$info) {
+ if($i++ < $start) {
+ continue;
+ }
+ if($info === false) {
+ $info = $this->getUserData($user);
+ }
+ if($this->_filter($user, $info)) {
+ $result[$user] = $info;
+ if(($limit >= 0) && (++$count >= $limit)) break;
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Modify user data
+ *
+ * @param string $user nick of the user to be changed
+ * @param array $changes array of field/value pairs to be changed
+ * @return bool
+ */
+ public function modifyUser($user, $changes) {
+ $return = true;
+ $adldap = $this->_adldap($this->_userDomain($user));
+ if(!$adldap) return false;
+
+ // password changing
+ if(isset($changes['pass'])) {
+ try {
+ $return = $adldap->user()->password($this->_userName($user),$changes['pass']);
+ } catch (adLDAPException $e) {
+ if ($this->conf['debug']) msg('AD Auth: '.$e->getMessage(), -1);
+ $return = false;
+ }
+ if(!$return) msg('AD Auth: failed to change the password. Maybe the password policy was not met?', -1);
+ }
+
+ // changing user data
+ $adchanges = array();
+ if(isset($changes['name'])) {
+ // get first and last name
+ $parts = explode(' ', $changes['name']);
+ $adchanges['surname'] = array_pop($parts);
+ $adchanges['firstname'] = join(' ', $parts);
+ $adchanges['display_name'] = $changes['name'];
+ }
+ if(isset($changes['mail'])) {
+ $adchanges['email'] = $changes['mail'];
+ }
+ if(count($adchanges)) {
+ try {
+ $return = $return & $adldap->user()->modify($this->_userName($user),$adchanges);
+ } catch (adLDAPException $e) {
+ if ($this->conf['debug']) msg('AD Auth: '.$e->getMessage(), -1);
+ $return = false;
+ }
+ }
+
+ return $return;
+ }
+
+ /**
+ * Initialize the AdLDAP library and connect to the server
+ *
+ * When you pass null as domain, it will reuse any existing domain.
+ * Eg. the one of the logged in user. It falls back to the default
+ * domain if no current one is available.
+ *
+ * @param string|null $domain The AD domain to use
+ * @return adLDAP|bool true if a connection was established
+ */
+ protected function _adldap($domain) {
+ if(is_null($domain) && is_array($this->opts)) {
+ $domain = $this->opts['domain'];
+ }
+
+ $this->opts = $this->_loadServerConfig((string) $domain);
+ if(isset($this->adldap[$domain])) return $this->adldap[$domain];
+
+ // connect
+ try {
+ $this->adldap[$domain] = new adLDAP($this->opts);
+ return $this->adldap[$domain];
+ } catch(adLDAPException $e) {
+ if($this->conf['debug']) {
+ msg('AD Auth: '.$e->getMessage(), -1);
+ }
+ $this->success = false;
+ $this->adldap[$domain] = null;
+ }
+ return false;
+ }
+
+ /**
+ * Get the domain part from a user
+ *
+ * @param $user
+ * @return string
+ */
+ public function _userDomain($user) {
+ list(, $domain) = explode('@', $user, 2);
+ return $domain;
+ }
+
+ /**
+ * Get the user part from a user
+ *
+ * @param $user
+ * @return string
+ */
+ public function _userName($user) {
+ list($name) = explode('@', $user, 2);
+ return $name;
+ }
+
+ /**
+ * Fetch the configuration for the given AD domain
+ *
+ * @param string $domain current AD domain
+ * @return array
+ */
+ protected function _loadServerConfig($domain) {
+ // prepare adLDAP standard configuration
+ $opts = $this->conf;
+
+ $opts['domain'] = $domain;
+
+ // add possible domain specific configuration
+ if($domain && is_array($this->conf[$domain])) foreach($this->conf[$domain] as $key => $val) {
+ $opts[$key] = $val;
+ }
+
+ // handle multiple AD servers
+ $opts['domain_controllers'] = explode(',', $opts['domain_controllers']);
+ $opts['domain_controllers'] = array_map('trim', $opts['domain_controllers']);
+ $opts['domain_controllers'] = array_filter($opts['domain_controllers']);
+
+ // compatibility with old option name
+ if(empty($opts['admin_username']) && !empty($opts['ad_username'])) $opts['admin_username'] = $opts['ad_username'];
+ if(empty($opts['admin_password']) && !empty($opts['ad_password'])) $opts['admin_password'] = $opts['ad_password'];
+
+ // we can change the password if SSL is set
+ if($opts['use_ssl'] || $opts['use_tls']) {
+ $this->cando['modPass'] = true;
+ } else {
+ $this->cando['modPass'] = false;
+ }
+
+ // adLDAP expects empty user/pass as NULL, we're less strict FS#2781
+ if(empty($opts['admin_username'])) $opts['admin_username'] = null;
+ if(empty($opts['admin_password'])) $opts['admin_password'] = null;
+
+ // user listing needs admin priviledges
+ if(!empty($opts['admin_username']) && !empty($opts['admin_password'])) {
+ $this->cando['getUsers'] = true;
+ } else {
+ $this->cando['getUsers'] = false;
+ }
+
+ return $opts;
+ }
+
+ /**
+ * Check provided user and userinfo for matching patterns
+ *
+ * The patterns are set up with $this->_constructPattern()
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @param string $user
+ * @param array $info
+ * @return bool
+ */
+ protected function _filter($user, $info) {
+ foreach($this->_pattern as $item => $pattern) {
+ if($item == 'user') {
+ if(!preg_match($pattern, $user)) return false;
+ } else if($item == 'grps') {
+ if(!count(preg_grep($pattern, $info['grps']))) return false;
+ } else {
+ if(!preg_match($pattern, $info[$item])) return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Create a pattern for $this->_filter()
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @param array $filter
+ */
+ protected function _constructPattern($filter) {
+ $this->_pattern = array();
+ foreach($filter as $item => $pattern) {
+ $this->_pattern[$item] = '/'.str_replace('/', '\/', $pattern).'/i'; // allow regex characters
+ }
+ }
+}
diff --git a/lib/plugins/authad/conf/default.php b/lib/plugins/authad/conf/default.php
new file mode 100644
index 000000000..f71202cfc
--- /dev/null
+++ b/lib/plugins/authad/conf/default.php
@@ -0,0 +1,14 @@
+<?php
+
+$conf['account_suffix'] = '';
+$conf['base_dn'] = '';
+$conf['domain_controllers'] = '';
+$conf['sso'] = 0;
+$conf['admin_username'] = '';
+$conf['admin_password'] = '';
+$conf['real_primarygroup'] = 0;
+$conf['use_ssl'] = 0;
+$conf['use_tls'] = 0;
+$conf['debug'] = 0;
+$conf['expirywarn'] = 0;
+$conf['additional'] = '';
diff --git a/lib/plugins/authad/conf/metadata.php b/lib/plugins/authad/conf/metadata.php
new file mode 100644
index 000000000..fbc3f163c
--- /dev/null
+++ b/lib/plugins/authad/conf/metadata.php
@@ -0,0 +1,14 @@
+<?php
+
+$meta['account_suffix'] = array('string');
+$meta['base_dn'] = array('string');
+$meta['domain_controllers'] = array('string');
+$meta['sso'] = array('onoff');
+$meta['admin_username'] = array('string');
+$meta['admin_password'] = array('password');
+$meta['real_primarygroup'] = array('onoff');
+$meta['use_ssl'] = array('onoff');
+$meta['use_tls'] = array('onoff');
+$meta['debug'] = array('onoff');
+$meta['expirywarn'] = array('numeric', '_min'=>0);
+$meta['additional'] = array('string');
diff --git a/lib/plugins/authad/lang/bg/settings.php b/lib/plugins/authad/lang/bg/settings.php
new file mode 100644
index 000000000..877810c4e
--- /dev/null
+++ b/lib/plugins/authad/lang/bg/settings.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Bulgarian language file
+ *
+ * @author Kiril <neohidra@gmail.com>
+ */
+$lang['account_suffix'] = 'Наставка на акаунта Ви. Например <code>@някакъв.домейн.org</code>';
+$lang['base_dn'] = 'Вашият основен DN. Например <code>DC=моят,DC=домейн,DC=org</code>';
+$lang['domain_controllers'] = 'Domain controller списък, разделете сървърите със запетая. Например <code>сървър1.домейн.org,сървър2.домейн.org</code>';
+$lang['admin_username'] = 'Привилегирован Active Directory потребител с достъп до данните на останалите потребители. Не е задължително, но е необходимо за някои функционалности като изпращането на имейл за абонаменти.';
+$lang['admin_password'] = 'Паролата на горния потребител.';
+$lang['sso'] = 'Да се ползва ли еднократно вписване чрез Kerberos или NTLM?';
+$lang['real_primarygroup'] = 'Да се извлича ли истинската група вместо да се предполага "Domain Users" (по-бавно)';
+$lang['use_ssl'] = 'Ползване на SSL свързаност? Не отбелязвайте TLS (по-долу) ако включите опцията.';
+$lang['use_tls'] = 'Ползване на TLS свързаност? Не отбелязвайте SSL (по-горе) ако включите опцията.';
+$lang['debug'] = 'Показване на допълнителна debug информация при грешка?';
+$lang['expirywarn'] = 'Предупреждаване на потребителите Х дни преди изтичане валидността на паролата им. Въведете 0 за изключване.';
+$lang['additional'] = 'Списък с допълнителни AD атрибути за извличане от потребителските данни (разделяйте ги със запетая). Ползва се от няколко приставки.'; \ No newline at end of file
diff --git a/lib/plugins/authad/lang/cs/settings.php b/lib/plugins/authad/lang/cs/settings.php
new file mode 100644
index 000000000..71f83afda
--- /dev/null
+++ b/lib/plugins/authad/lang/cs/settings.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Czech language file
+ *
+ * @author mkucera66@seznam.cz
+ */
+$lang['account_suffix'] = 'Přípona vašeho účtu, tj. <code>@moje.domena.org</code>';
+$lang['base_dn'] = 'Vaše doménové jméno DN. tj. <code>DC=moje,DC=domena,DC=org</code>';
+$lang['domain_controllers'] = 'Čárkou oddělenových kontrol=rů, tj. <code>srv1.domena.org,srv2.domena.org</code>';
+$lang['admin_username'] = 'Privilegovaný uživatel Active Directory s přístupem ke všem datům. Volitelně, ale nutné pro určité akce typu zasílání mailů.';
+$lang['admin_password'] = 'Heslo uživatele výše';
+$lang['sso'] = 'Chcete přihlašování Single-Sign-On pomocí jádra Kerberos nebo NTLM ( autentizační protokol obvyklý ve Windows)?';
+$lang['real_primarygroup'] = 'Má být zjištěna primární skupina namísto vyhodnocení hodnoty "doménoví uživatelé" (pomalejší)';
+$lang['use_ssl'] = 'Použít spojení SSL? Pokud ano, nevyužívejte TLS níže.';
+$lang['use_tls'] = 'Použít spojení TLS? Pokud ano, nevyužívejte SSL výše.';
+$lang['debug'] = 'Zobrazit dodatečné debugovací výstupy při chybách?';
+$lang['expirywarn'] = 'Dny mezi varováním o vyprčšení hesla uživatele a jeho vypršením. 0 znaší vypnuto.';
+$lang['additional'] = 'Čárkou oddělený seznam dodatečných atributů získávaných z uživatelských dat. Využito některými pluginy.';
diff --git a/lib/plugins/authad/lang/de-informal/settings.php b/lib/plugins/authad/lang/de-informal/settings.php
new file mode 100644
index 000000000..a458617b8
--- /dev/null
+++ b/lib/plugins/authad/lang/de-informal/settings.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * German (informal) language file
+ *
+ * @author Frank Loizzi <contact@software.bacal.de>
+ * @author Matthias Schulte <dokuwiki@lupo49.de>
+ * @author Volker Bödker <volker@boedker.de>
+ */
+$lang['account_suffix'] = 'Dein Account-Suffix. Z.B. <code>@my.domain.org</code>';
+$lang['base_dn'] = 'Dein Base-DN. Z.B. <code>DC=my,DC=domain,DC=org</code>';
+$lang['domain_controllers'] = 'Eine Komma-separierte Liste von Domänen-Controllern. Z.B. <code>srv1.domain.org,srv2.domain.org</code>';
+$lang['admin_username'] = 'Ein privilegierter Active Directory-Benutzer mit Zugriff zu allen anderen Benutzerdaten. Optional, aber wird benötigt für Aktionen wie z. B. dass Senden von Benachrichtigungs-Mails.';
+$lang['admin_password'] = 'Das Passwort des obigen Benutzers.';
+$lang['sso'] = 'Soll Single-Sign-On via Kerberos oder NTLM benutzt werden?';
+$lang['real_primarygroup'] = 'Soll die echte primäre Gruppe aufgelöst werden anstelle der Annahme "Domain Users" (langsamer)';
+$lang['use_ssl'] = 'SSL-Verbindung benutzen? Falls ja, TLS unterhalb nicht aktivieren.';
+$lang['use_tls'] = 'TLS-Verbindung benutzen? Falls ja, SSL oberhalb nicht aktivieren.';
+$lang['debug'] = 'Zusätzliche Debug-Informationen bei Fehlern anzeigen?';
+$lang['expirywarn'] = 'Tage im Voraus um Benutzer über ablaufende Passwörter zu informieren. 0 zum Ausschalten.';
+$lang['additional'] = 'Eine Komma-separierte Liste von zusätzlichen AD-Attributen, die von den Benutzerobjekten abgefragt werden. Wird von einigen Plugins benutzt.';
diff --git a/lib/plugins/authad/lang/de/settings.php b/lib/plugins/authad/lang/de/settings.php
new file mode 100644
index 000000000..f4e86dedd
--- /dev/null
+++ b/lib/plugins/authad/lang/de/settings.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * German (informal) language file
+ *
+ * @author Frank Loizzi <contact@software.bacal.de>
+ * @author Matthias Schulte <dokuwiki@lupo49.de>
+ */
+$lang['account_suffix'] = 'Ihr Account-Suffix. Z. B. <code>@my.domain.org</code>';
+$lang['base_dn'] = 'Ihr Base-DN. Z. B. <code>DC=my,DC=domain,DC=org</code>';
+$lang['domain_controllers'] = 'Eine Komma-separierte Liste von Domänen-Controllern. Z. B. <code>srv1.domain.org,srv2.domain.org</code>';
+$lang['admin_username'] = 'Ein priviligierter Active Directory-Benutzer mit Zugriff zu allen anderen Benutzerdaten. Optional, aber wird benötigt für Aktionen wie z. B. dass Senden von Benachrichtigungs-Mails.';
+$lang['admin_password'] = 'Das Passwort des obigen Benutzers.';
+$lang['sso'] = 'Soll Single-Sign-On via Kerberos oder NTLM benutzt werden?';
+$lang['real_primarygroup'] = 'Soll die echte primäre Gruppe aufgelöst werden anstelle der Annahme "Domain Users" (langsamer)';
+$lang['use_ssl'] = 'SSL-Verbindung benutzen? Falls ja, TLS unterhalb nicht aktivieren.';
+$lang['use_tls'] = 'TLS-Verbindung benutzen? Falls ja, SSL oberhalb nicht aktivieren.';
+$lang['debug'] = 'Zusätzliche Debug-Informationen bei Fehlern anzeigen?';
+$lang['expirywarn'] = 'Tage im Voraus um Benutzer über ablaufende Passwörter zu informieren. 0 zum Ausschalten.';
+$lang['additional'] = 'Eine Komma-separierte Liste von zusätzlichen AD-Attributen, die von den Benutzerobjekten abgefragt werden. Wird von einigen Plugins benutzt.';
diff --git a/lib/plugins/authad/lang/en/settings.php b/lib/plugins/authad/lang/en/settings.php
new file mode 100644
index 000000000..aff49550b
--- /dev/null
+++ b/lib/plugins/authad/lang/en/settings.php
@@ -0,0 +1,14 @@
+<?php
+
+$lang['account_suffix'] = 'Your account suffix. Eg. <code>@my.domain.org</code>';
+$lang['base_dn'] = 'Your base DN. Eg. <code>DC=my,DC=domain,DC=org</code>';
+$lang['domain_controllers'] = 'A comma separated list of Domain controllers. Eg. <code>srv1.domain.org,srv2.domain.org</code>';
+$lang['admin_username'] = 'A privileged Active Directory user with access to all other user\'s data. Optional, but needed for certain actions like sending subscription mails.';
+$lang['admin_password'] = 'The password of the above user.';
+$lang['sso'] = 'Should Single-Sign-On via Kerberos or NTLM be used?';
+$lang['real_primarygroup'] = 'Should the real primary group be resolved instead of assuming "Domain Users" (slower)';
+$lang['use_ssl'] = 'Use SSL connection? If used, do not enable TLS below.';
+$lang['use_tls'] = 'Use TLS connection? If used, do not enable SSL above.';
+$lang['debug'] = 'Display additional debugging output on errors?';
+$lang['expirywarn'] = 'Days in advance to warn user about expiring password. 0 to disable.';
+$lang['additional'] = 'A comma separated list of additional AD attributes to fetch from user data. Used by some plugins.';
diff --git a/lib/plugins/authad/lang/eo/settings.php b/lib/plugins/authad/lang/eo/settings.php
new file mode 100644
index 000000000..8bd34b439
--- /dev/null
+++ b/lib/plugins/authad/lang/eo/settings.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Esperanto language file
+ *
+ */
+$lang['account_suffix'] = 'Via konto-aldonaĵo, ekz. <code>@mia.domajno.lando</code>';
+$lang['base_dn'] = 'Via baza DN, ekz. <code>DC=mia,DC=domajno,DC=lando</code>';
+$lang['domain_controllers'] = 'Komodisigita listo de domajno-serviloj, ekz. <code>srv1.domajno.lando,srv2.domajno.lando</code>';
+$lang['admin_username'] = 'Privilegiita Aktiv-Dosieruja uzanto kun aliro al ĉiuj uzantaj datumoj. Libervole, sed necesa por iuj agadoj kiel sendi abonan retpoŝton.';
+$lang['admin_password'] = 'La pasvorto de tiu uzanto.';
+$lang['sso'] = 'Ĉu uzi Sola Aliro tra Kerberos aŭ NTLM?';
+$lang['real_primarygroup'] = 'Ĉu trovi la veran ĉefan grupon anstataŭ supozi "Domajnuzantoj" (pli malrapida)?';
+$lang['use_ssl'] = 'Ĉu uzi SSL-konekton? Se jes, ne aktivigu TLS sube.';
+$lang['use_tls'] = 'Ĉu uzi TLS-konekton? Se jes, ne aktivigu SSL supre.';
+$lang['debug'] = 'Ĉu montri aldonajn informojn dum eraroj?';
+$lang['expirywarn'] = 'Tagoj da antaŭaverto pri malvalidiĝonta pasvorto. 0 por malebligi.';
+$lang['additional'] = 'Komodisigita listo de aldonaj AD-atributoj por preni el uzantaj datumoj. Uzita de iuj kromaĵoj.';
diff --git a/lib/plugins/authad/lang/fi/settings.php b/lib/plugins/authad/lang/fi/settings.php
new file mode 100644
index 000000000..d3aa13e07
--- /dev/null
+++ b/lib/plugins/authad/lang/fi/settings.php
@@ -0,0 +1,6 @@
+<?php
+/**
+ * Finnish language file
+ *
+ * @author Otto Vainio <otto@valjakko.net>
+ */
diff --git a/lib/plugins/authad/lang/fr/settings.php b/lib/plugins/authad/lang/fr/settings.php
new file mode 100644
index 000000000..5480a3d44
--- /dev/null
+++ b/lib/plugins/authad/lang/fr/settings.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * French language file
+ *
+ * @author Bruno Veilleux <bruno.vey@gmail.com>
+ */
+$lang['account_suffix'] = 'Le suffixe de votre compte. Ex.: <code>@mon.domaine.org</code>';
+$lang['base_dn'] = 'Votre nom de domaine de base. <code>DC=mon,DC=domaine,DC=org</code>';
+$lang['domain_controllers'] = 'Une liste de contrôleurs de domaine séparés par des virgules. Ex.: <code>srv1.domaine.org,srv2.domaine.org</code>';
+$lang['admin_username'] = 'Un utilisateur Active Directory avec accès aux données de tous les autres utilisateurs. Facultatif, mais nécessaire pour certaines actions telles que l\'envoi de courriels d\'abonnement.';
+$lang['admin_password'] = 'Le mot de passe de l\'utilisateur ci-dessus.';
+$lang['sso'] = 'Est-ce que la connexion unique (Single-Sign-On) par Kerberos ou NTLM doit être utilisée?';
+$lang['real_primarygroup'] = 'Est-ce que le véritable groupe principal doit être résolu au lieu de présumer "Domain Users" (plus lent)?';
+$lang['use_ssl'] = 'Utiliser une connexion SSL? Si utilisée, n\'activez pas TLS ci-dessous.';
+$lang['use_tls'] = 'Utiliser une connexion TLS? Si utilisée, n\'activez pas SSL ci-dessus.';
+$lang['debug'] = 'Afficher des informations de débogage supplémentaires pour les erreurs?';
+$lang['expirywarn'] = 'Jours d\'avance pour l\'avertissement envoyé aux utilisateurs lorsque leur mot de passe va expirer. 0 pour désactiver.';
+$lang['additional'] = 'Une liste séparée par des virgules d\'attributs AD supplémentaires à récupérer dans les données utilisateur. Utilisée par certains modules.';
diff --git a/lib/plugins/authad/lang/it/settings.php b/lib/plugins/authad/lang/it/settings.php
new file mode 100644
index 000000000..10ae72f87
--- /dev/null
+++ b/lib/plugins/authad/lang/it/settings.php
@@ -0,0 +1,5 @@
+<?php
+/**
+ * Italian language file
+ *
+ */
diff --git a/lib/plugins/authad/lang/ja/settings.php b/lib/plugins/authad/lang/ja/settings.php
new file mode 100644
index 000000000..fdc6fc434
--- /dev/null
+++ b/lib/plugins/authad/lang/ja/settings.php
@@ -0,0 +1,6 @@
+<?php
+/**
+ * Japanese language file
+ *
+ * @author Satoshi Sahara <sahara.satoshi@gmail.com>
+ */
diff --git a/lib/plugins/authad/lang/ko/settings.php b/lib/plugins/authad/lang/ko/settings.php
new file mode 100644
index 000000000..f2bf52681
--- /dev/null
+++ b/lib/plugins/authad/lang/ko/settings.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Korean language file
+ *
+ * @author Myeongjin <aranet100@gmail.com>
+ */
+$lang['account_suffix'] = '계정 접미어. 예를 들어 <code>@my.domain.org</code>';
+$lang['base_dn'] = '기본 DN. 예를 들어 <code>DC=my,DC=domain,DC=org</code>';
+$lang['domain_controllers'] = '도메인 컨트롤러의 쉼표로 구분한 목록. 예를 들어 <code>srv1.domain.org,srv2.domain.org</code>';
+$lang['admin_username'] = '다른 모든 사용자의 데이터에 접근할 수 있는 권한이 있는 Active Directory 사용자. 선택적이지만 구독 메일을 보내는 등의 특정 작업에 필요합니다.';
+$lang['admin_password'] = '위 사용자의 비밀번호.';
+$lang['sso'] = 'Kerberos나 NTLM을 통해 Single-Sign-On을 사용해야 합니까?';
+$lang['real_primarygroup'] = '실제 기본 그룹은 "도메인 사용자"를 가정하는 대신 해결될 것입니다 (느림)';
+$lang['use_ssl'] = 'SSL 연결을 사용합니까? 사용한다면 아래 TLS을 활성화하지 마세요.';
+$lang['use_tls'] = 'TLS 연결을 사용합니까? 사용한다면 위 SSL을 활성화하지 마세요.';
+$lang['debug'] = '오류에 대한 추가적인 디버그 정보를 보이겠습니까?';
+$lang['expirywarn'] = '미리 비밀번호 만료를 사용자에게 경고할 날짜. 0일 경우 비활성화합니다.';
+$lang['additional'] = '사용자 데이터에서 가져올 추가적인 AD 속성의 쉼표로 구분한 목록. 일부 플러그인이 사용합니다.';
diff --git a/lib/plugins/authad/lang/lv/settings.php b/lib/plugins/authad/lang/lv/settings.php
new file mode 100644
index 000000000..ced5dabf8
--- /dev/null
+++ b/lib/plugins/authad/lang/lv/settings.php
@@ -0,0 +1,6 @@
+<?php
+/**
+ * Latvian, Lettish language file
+ *
+ * @author Aivars Miška <allefm@gmail.com>
+ */
diff --git a/lib/plugins/authad/lang/nl/settings.php b/lib/plugins/authad/lang/nl/settings.php
new file mode 100644
index 000000000..933566d18
--- /dev/null
+++ b/lib/plugins/authad/lang/nl/settings.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Dutch language file
+ *
+ */
+$lang['account_suffix'] = 'Je account domeinnaam. Bijv <code>@mijn.domein.org</code>';
+$lang['base_dn'] = 'Je basis DN. Bijv. <code>DC=mijn,DC=domein,DC=org</code>';
+$lang['domain_controllers'] = 'Eeen commagesepareerde lijst van domeinservers. Bijv. <code>srv1.domein.org,srv2.domein.org</code>';
+$lang['admin_username'] = 'Een geprivilegeerde Active Directory gebruiker die bij alle gebruikersgegevens kan komen. Optioneel, maar kan nodig zijn voor bepaalde acties, zoals het versturen van abonnementsmailtjes.';
+$lang['admin_password'] = 'Het wachtwoord van bovernvermelde gebruiker.';
+$lang['sso'] = 'Wordt voor Single-Sign-on Kerberos of NTLM gebruikt?';
+$lang['real_primarygroup'] = 'Moet de echte primaire groep worden opgezocht in plaats van het aannemen van "Domeingebruikers" (langzamer)';
+$lang['use_ssl'] = 'SSL verbinding gebruiken? Zo ja, gebruik dan TLS hieronder niet.';
+$lang['use_tls'] = 'TLS verbinding gebruiken? Zo ja, activeer dan niet de SSL verbinding hierboven.';
+$lang['debug'] = 'Aanvullende debug informatie tonen bij fouten?';
+$lang['expirywarn'] = 'Waarschuwingstermijn voor vervallen wachtwoord. 0 om te deactiveren.';
+$lang['additional'] = 'Commagesepareerde lijst van aanvullend uit AD op te halen attributen. Gebruikt door sommige plugins.';
diff --git a/lib/plugins/authad/lang/pt-br/settings.php b/lib/plugins/authad/lang/pt-br/settings.php
new file mode 100644
index 000000000..308d122dd
--- /dev/null
+++ b/lib/plugins/authad/lang/pt-br/settings.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Brazilian Portuguese language file
+ *
+ * @author Victor Westmann <victor.westmann@gmail.com>
+ */
+$lang['account_suffix'] = 'Sufixo de sua conta. Eg. <code>@meu.domínio.org</code>';
+$lang['base_dn'] = 'Sua base DN. Eg. <code>DC=meu,DC=domínio,DC=org</code>';
+$lang['domain_controllers'] = 'Uma lista de controles de domínios separada por vírgulas. Eg. <code>srv1.domínio.org,srv2.domínio.org</code>';
+$lang['admin_username'] = 'Um usuário com privilégios do Active Directory com acesso a todos os dados dos outros usuários. Opcional, mas necessário para certas ações como enviar emails de inscrição.';
+$lang['admin_password'] = 'A senha do usuário acima.';
+$lang['sso'] = 'Usar Single-Sign-On através do Kerberos ou NTLM?';
+$lang['real_primarygroup'] = 'Deverá o grupo real primário ser resolvido ao invés de assumir "Usuários de domínio" (mais lento) ';
+$lang['use_ssl'] = 'Usar conexão SSL? Se usar, não habilitar TLS abaixo.';
+$lang['use_tls'] = 'Usar conexão TLS? se usar, não habilitar SSL acima.';
+$lang['debug'] = 'Mostrar saída adicional de depuração em mensagens de erros?';
+$lang['expirywarn'] = 'Dias com antecedência para avisar o usuário de uma senha que vai expirar. 0 para desabilitar.';
+$lang['additional'] = 'Uma lista separada de vírgulas de atributos adicionais AD para pegar dados de usuários. Usados por alguns plugins.';
diff --git a/lib/plugins/authad/lang/ru/settings.php b/lib/plugins/authad/lang/ru/settings.php
new file mode 100644
index 000000000..4c394080e
--- /dev/null
+++ b/lib/plugins/authad/lang/ru/settings.php
@@ -0,0 +1,6 @@
+<?php
+/**
+ * Russian language file
+ *
+ * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua)
+ */
diff --git a/lib/plugins/authad/lang/sv/settings.php b/lib/plugins/authad/lang/sv/settings.php
new file mode 100644
index 000000000..b1eb1cb96
--- /dev/null
+++ b/lib/plugins/authad/lang/sv/settings.php
@@ -0,0 +1,11 @@
+<?php
+/**
+ * Swedish language file
+ *
+ * @author Smorkster Andersson smorkster@gmail.com
+ */
+$lang['account_suffix'] = 'Ditt konto suffix. T.ex. <code>min.domän.org</code>';
+$lang['admin_password'] = 'Lösenord för användare ovan.';
+$lang['sso'] = 'Ska Single-Sign-On via Kerberos eller NTLM användas?';
+$lang['use_ssl'] = 'Använda SSL anslutning? Om använd, möjliggör inte TLS nedan.';
+$lang['use_tls'] = 'Använda TLS anslutning? Om använd, möjliggör inte SSL ovan.';
diff --git a/lib/plugins/authad/lang/zh-tw/settings.php b/lib/plugins/authad/lang/zh-tw/settings.php
new file mode 100644
index 000000000..c46e5f96f
--- /dev/null
+++ b/lib/plugins/authad/lang/zh-tw/settings.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Chinese Traditional language file
+ *
+ * @author syaoranhinata@gmail.com
+ */
+$lang['account_suffix'] = '您的帳號後綴。如: <code>@my.domain.org</code>';
+$lang['base_dn'] = '您的基本識別名。如: <code>DC=my,DC=domain,DC=org</code>';
+$lang['domain_controllers'] = '以逗號分隔的域名控制器列表。如: <code>srv1.domain.org,srv2.domain.org</code>';
+$lang['admin_username'] = 'Active Directory 的特權使用者,可以查看所有使用者的數據。(非必要,但對發送訂閱郵件等活動來說,這是必須的。)';
+$lang['admin_password'] = '上述使用者的密碼。';
+$lang['sso'] = '是否使用 Kerberos 或 NTLM 的單一登入系統 (Single-Sign-On)?';
+$lang['real_primarygroup'] = '是否視作真正的主要群組,而不是假設為網域使用者 (比較慢)';
+$lang['use_ssl'] = '使用 SSL 連接嗎?如果要使用,請不要啟用下方的 TLS。';
+$lang['use_tls'] = '使用 TLS 連接嗎?如果要使用,請不要啟用上方的 SSL。';
+$lang['debug'] = '有錯誤時,顯示額外除錯資訊嗎?';
+$lang['expirywarn'] = '提前多少天警告使用者密碼即將到期。輸入0表示停用。';
+$lang['additional'] = '從使用者數據中取得額外 AD 屬性列表,以供某些附加元件使用。列表以逗號分隔。';
diff --git a/lib/plugins/authad/lang/zh/settings.php b/lib/plugins/authad/lang/zh/settings.php
new file mode 100644
index 000000000..0ad8d4e4f
--- /dev/null
+++ b/lib/plugins/authad/lang/zh/settings.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Chinese language file
+ *
+ * @author lainme <lainme993@gmail.com>
+ */
+$lang['account_suffix'] = '您的账户后缀。例如 <code>@my.domain.org</code>';
+$lang['base_dn'] = '您的基本分辨名。例如 <code>DC=my,DC=domain,DC=org</code>';
+$lang['domain_controllers'] = '逗号分隔的域名控制器列表。例如 <code>srv1.domain.org,srv2.domain.org</code>';
+$lang['admin_username'] = '一个活动目录的特权用户,可以查看其他所有用户的数据。可选,但对某些活动例如发送订阅邮件是必须的。';
+$lang['admin_password'] = '上述用户的密码。';
+$lang['sso'] = '是否使用经由 Kerberos 和 NTLM 的 Single-Sign-On?';
+$lang['real_primarygroup'] = ' 是否解析真实的主要组,而不是假设为“域用户” (较慢)';
+$lang['use_ssl'] = '使用 SSL 连接?如果是,不要激活下面的 TLS。';
+$lang['use_tls'] = '使用 TLS 连接?如果是 ,不要激活上面的 SSL。';
+$lang['debug'] = '有错误时显示额外的调试信息?';
+$lang['expirywarn'] = '提前多少天警告用户密码即将到期。0 则禁用。';
+$lang['additional'] = '需要从用户数据中获取的额外 AD 属性的列表,以逗号分隔。用于某些插件。';
diff --git a/lib/plugins/authad/plugin.info.txt b/lib/plugins/authad/plugin.info.txt
new file mode 100644
index 000000000..996813bc5
--- /dev/null
+++ b/lib/plugins/authad/plugin.info.txt
@@ -0,0 +1,7 @@
+base authad
+author Andreas Gohr
+email andi@splitbrain.org
+date 2013-04-25
+name Active Directory auth plugin
+desc Provides authentication against a Microsoft Active Directory
+url http://www.dokuwiki.org/plugin:authad
diff --git a/lib/plugins/authldap/auth.php b/lib/plugins/authldap/auth.php
new file mode 100644
index 000000000..6a967a6d4
--- /dev/null
+++ b/lib/plugins/authldap/auth.php
@@ -0,0 +1,540 @@
+<?php
+// must be run within Dokuwiki
+if(!defined('DOKU_INC')) die();
+
+/**
+ * LDAP authentication backend
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @author Chris Smith <chris@jalakaic.co.uk>
+ * @author Jan Schumann <js@schumann-it.com>
+ */
+class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
+ /* @var resource $con holds the LDAP connection*/
+ protected $con = null;
+
+ /* @var int $bound What type of connection does already exist? */
+ protected $bound = 0; // 0: anonymous, 1: user, 2: superuser
+
+ /* @var array $users User data cache */
+ protected $users = null;
+
+ /* @var array $_pattern User filter pattern */
+ protected $_pattern = null;
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ parent::__construct();
+
+ // ldap extension is needed
+ if(!function_exists('ldap_connect')) {
+ $this->_debug("LDAP err: PHP LDAP extension not found.", -1, __LINE__, __FILE__);
+ $this->success = false;
+ return;
+ }
+
+ // auth_ldap currently just handles authentication, so no
+ // capabilities are set
+ }
+
+ /**
+ * Check user+password
+ *
+ * Checks if the given user exists and the given
+ * plaintext password is correct by trying to bind
+ * to the LDAP server
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param string $user
+ * @param string $pass
+ * @return bool
+ */
+ public function checkPass($user, $pass) {
+ // reject empty password
+ if(empty($pass)) return false;
+ if(!$this->_openLDAP()) return false;
+
+ // indirect user bind
+ if($this->getConf('binddn') && $this->getConf('bindpw')) {
+ // use superuser credentials
+ if(!@ldap_bind($this->con, $this->getConf('binddn'), $this->getConf('bindpw'))) {
+ $this->_debug('LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ return false;
+ }
+ $this->bound = 2;
+ } else if($this->getConf('binddn') &&
+ $this->getConf('usertree') &&
+ $this->getConf('userfilter')
+ ) {
+ // special bind string
+ $dn = $this->_makeFilter(
+ $this->getConf('binddn'),
+ array('user'=> $user, 'server'=> $this->getConf('server'))
+ );
+
+ } else if(strpos($this->getConf('usertree'), '%{user}')) {
+ // direct user bind
+ $dn = $this->_makeFilter(
+ $this->getConf('usertree'),
+ array('user'=> $user, 'server'=> $this->getConf('server'))
+ );
+
+ } else {
+ // Anonymous bind
+ if(!@ldap_bind($this->con)) {
+ msg("LDAP: can not bind anonymously", -1);
+ $this->_debug('LDAP anonymous bind: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ return false;
+ }
+ }
+
+ // Try to bind to with the dn if we have one.
+ if(!empty($dn)) {
+ // User/Password bind
+ if(!@ldap_bind($this->con, $dn, $pass)) {
+ $this->_debug("LDAP: bind with $dn failed", -1, __LINE__, __FILE__);
+ $this->_debug('LDAP user dn bind: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ return false;
+ }
+ $this->bound = 1;
+ return true;
+ } else {
+ // See if we can find the user
+ $info = $this->getUserData($user, true);
+ if(empty($info['dn'])) {
+ return false;
+ } else {
+ $dn = $info['dn'];
+ }
+
+ // Try to bind with the dn provided
+ if(!@ldap_bind($this->con, $dn, $pass)) {
+ $this->_debug("LDAP: bind with $dn failed", -1, __LINE__, __FILE__);
+ $this->_debug('LDAP user bind: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ return false;
+ }
+ $this->bound = 1;
+ return true;
+ }
+ }
+
+ /**
+ * Return user info
+ *
+ * Returns info about the given user needs to contain
+ * at least these fields:
+ *
+ * name string full name of the user
+ * mail string email addres of the user
+ * grps array list of groups the user is in
+ *
+ * This LDAP specific function returns the following
+ * addional fields:
+ *
+ * dn string distinguished name (DN)
+ * uid string Posix User ID
+ * inbind bool for internal use - avoid loop in binding
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @author Trouble
+ * @author Dan Allen <dan.j.allen@gmail.com>
+ * @author <evaldas.auryla@pheur.org>
+ * @author Stephane Chazelas <stephane.chazelas@emerson.com>
+ *
+ * @param string $user
+ * @param bool $inbind authldap specific, true if in bind phase
+ * @return array containing user data or false
+ */
+ public function getUserData($user, $inbind = false) {
+ global $conf;
+ if(!$this->_openLDAP()) return false;
+
+ // force superuser bind if wanted and not bound as superuser yet
+ if($this->getConf('binddn') && $this->getConf('bindpw') && $this->bound < 2) {
+ // use superuser credentials
+ if(!@ldap_bind($this->con, $this->getConf('binddn'), $this->getConf('bindpw'))) {
+ $this->_debug('LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ return false;
+ }
+ $this->bound = 2;
+ } elseif($this->bound == 0 && !$inbind) {
+ // in some cases getUserData is called outside the authentication workflow
+ // eg. for sending email notification on subscribed pages. This data might not
+ // be accessible anonymously, so we try to rebind the current user here
+ list($loginuser, $loginsticky, $loginpass) = auth_getCookie();
+ if($loginuser && $loginpass) {
+ $loginpass = PMA_blowfish_decrypt($loginpass, auth_cookiesalt(!$loginsticky));
+ $this->checkPass($loginuser, $loginpass);
+ }
+ }
+
+ $info['user'] = $user;
+ $info['server'] = $this->getConf('server');
+
+ //get info for given user
+ $base = $this->_makeFilter($this->getConf('usertree'), $info);
+ if($this->getConf('userfilter')) {
+ $filter = $this->_makeFilter($this->getConf('userfilter'), $info);
+ } else {
+ $filter = "(ObjectClass=*)";
+ }
+
+ $sr = $this->_ldapsearch($this->con, $base, $filter, $this->getConf('userscope'));
+ $result = @ldap_get_entries($this->con, $sr);
+ $this->_debug('LDAP user search: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ $this->_debug('LDAP search at: '.htmlspecialchars($base.' '.$filter), 0, __LINE__, __FILE__);
+
+ // Don't accept more or less than one response
+ if(!is_array($result) || $result['count'] != 1) {
+ return false; //user not found
+ }
+
+ $user_result = $result[0];
+ ldap_free_result($sr);
+
+ // general user info
+ $info['dn'] = $user_result['dn'];
+ $info['gid'] = $user_result['gidnumber'][0];
+ $info['mail'] = $user_result['mail'][0];
+ $info['name'] = $user_result['cn'][0];
+ $info['grps'] = array();
+
+ // overwrite if other attribs are specified.
+ if(is_array($this->getConf('mapping'))) {
+ foreach($this->getConf('mapping') as $localkey => $key) {
+ if(is_array($key)) {
+ // use regexp to clean up user_result
+ list($key, $regexp) = each($key);
+ if($user_result[$key]) foreach($user_result[$key] as $grp) {
+ if(preg_match($regexp, $grp, $match)) {
+ if($localkey == 'grps') {
+ $info[$localkey][] = $match[1];
+ } else {
+ $info[$localkey] = $match[1];
+ }
+ }
+ }
+ } else {
+ $info[$localkey] = $user_result[$key][0];
+ }
+ }
+ }
+ $user_result = array_merge($info, $user_result);
+
+ //get groups for given user if grouptree is given
+ if($this->getConf('grouptree') || $this->getConf('groupfilter')) {
+ $base = $this->_makeFilter($this->getConf('grouptree'), $user_result);
+ $filter = $this->_makeFilter($this->getConf('groupfilter'), $user_result);
+ $sr = $this->_ldapsearch($this->con, $base, $filter, $this->getConf('groupscope'), array($this->getConf('groupkey')));
+ $this->_debug('LDAP group search: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ $this->_debug('LDAP search at: '.htmlspecialchars($base.' '.$filter), 0, __LINE__, __FILE__);
+
+ if(!$sr) {
+ msg("LDAP: Reading group memberships failed", -1);
+ return false;
+ }
+ $result = ldap_get_entries($this->con, $sr);
+ ldap_free_result($sr);
+
+ if(is_array($result)) foreach($result as $grp) {
+ if(!empty($grp[$this->getConf('groupkey')][0])) {
+ $this->_debug('LDAP usergroup: '.htmlspecialchars($grp[$this->getConf('groupkey')][0]), 0, __LINE__, __FILE__);
+ $info['grps'][] = $grp[$this->getConf('groupkey')][0];
+ }
+ }
+ }
+
+ // always add the default group to the list of groups
+ if(!$info['grps'] or !in_array($conf['defaultgroup'], $info['grps'])) {
+ $info['grps'][] = $conf['defaultgroup'];
+ }
+ return $info;
+ }
+
+ /**
+ * Most values in LDAP are case-insensitive
+ *
+ * @return bool
+ */
+ public function isCaseSensitive() {
+ return false;
+ }
+
+ /**
+ * Bulk retrieval of user data
+ *
+ * @author Dominik Eckelmann <dokuwiki@cosmocode.de>
+ * @param int $start index of first user to be returned
+ * @param int $limit max number of users to be returned
+ * @param array $filter array of field/pattern pairs, null for no filter
+ * @return array of userinfo (refer getUserData for internal userinfo details)
+ */
+ function retrieveUsers($start = 0, $limit = -1, $filter = array()) {
+ if(!$this->_openLDAP()) return false;
+
+ if(is_null($this->users)) {
+ // Perform the search and grab all their details
+ if($this->getConf('userfilter')) {
+ $all_filter = str_replace('%{user}', '*', $this->getConf('userfilter'));
+ } else {
+ $all_filter = "(ObjectClass=*)";
+ }
+ $sr = ldap_search($this->con, $this->getConf('usertree'), $all_filter);
+ $entries = ldap_get_entries($this->con, $sr);
+ $users_array = array();
+ for($i = 0; $i < $entries["count"]; $i++) {
+ array_push($users_array, $entries[$i]["uid"][0]);
+ }
+ asort($users_array);
+ $result = $users_array;
+ if(!$result) return array();
+ $this->users = array_fill_keys($result, false);
+ }
+ $i = 0;
+ $count = 0;
+ $this->_constructPattern($filter);
+ $result = array();
+
+ foreach($this->users as $user => &$info) {
+ if($i++ < $start) {
+ continue;
+ }
+ if($info === false) {
+ $info = $this->getUserData($user);
+ }
+ if($this->_filter($user, $info)) {
+ $result[$user] = $info;
+ if(($limit >= 0) && (++$count >= $limit)) break;
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Make LDAP filter strings.
+ *
+ * Used by auth_getUserData to make the filter
+ * strings for grouptree and groupfilter
+ *
+ * @author Troels Liebe Bentsen <tlb@rapanden.dk>
+ * @param string $filter ldap search filter with placeholders
+ * @param array $placeholders placeholders to fill in
+ * @return string
+ */
+ protected function _makeFilter($filter, $placeholders) {
+ preg_match_all("/%{([^}]+)/", $filter, $matches, PREG_PATTERN_ORDER);
+ //replace each match
+ foreach($matches[1] as $match) {
+ //take first element if array
+ if(is_array($placeholders[$match])) {
+ $value = $placeholders[$match][0];
+ } else {
+ $value = $placeholders[$match];
+ }
+ $value = $this->_filterEscape($value);
+ $filter = str_replace('%{'.$match.'}', $value, $filter);
+ }
+ return $filter;
+ }
+
+ /**
+ * return true if $user + $info match $filter criteria, false otherwise
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ *
+ * @param string $user the user's login name
+ * @param array $info the user's userinfo array
+ * @return bool
+ */
+ protected function _filter($user, $info) {
+ foreach($this->_pattern as $item => $pattern) {
+ if($item == 'user') {
+ if(!preg_match($pattern, $user)) return false;
+ } else if($item == 'grps') {
+ if(!count(preg_grep($pattern, $info['grps']))) return false;
+ } else {
+ if(!preg_match($pattern, $info[$item])) return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Set the filter pattern
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ *
+ * @param $filter
+ * @return void
+ */
+ protected function _constructPattern($filter) {
+ $this->_pattern = array();
+ foreach($filter as $item => $pattern) {
+ $this->_pattern[$item] = '/'.str_replace('/', '\/', $pattern).'/i'; // allow regex characters
+ }
+ }
+
+ /**
+ * Escape a string to be used in a LDAP filter
+ *
+ * Ported from Perl's Net::LDAP::Util escape_filter_value
+ *
+ * @author Andreas Gohr
+ * @param string $string
+ * @return string
+ */
+ protected function _filterEscape($string) {
+ return preg_replace(
+ '/([\x00-\x1F\*\(\)\\\\])/e',
+ '"\\\\\".join("",unpack("H2","$1"))',
+ $string
+ );
+ }
+
+ /**
+ * Opens a connection to the configured LDAP server and sets the wanted
+ * option on the connection
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+ protected function _openLDAP() {
+ if($this->con) return true; // connection already established
+
+ $this->bound = 0;
+
+ $port = $this->getConf('port');
+ $bound = false;
+ $servers = explode(',', $this->getConf('server'));
+ foreach($servers as $server) {
+ $server = trim($server);
+ $this->con = @ldap_connect($server, $port);
+ if(!$this->con) {
+ continue;
+ }
+
+ /*
+ * When OpenLDAP 2.x.x is used, ldap_connect() will always return a resource as it does
+ * not actually connect but just initializes the connecting parameters. The actual
+ * connect happens with the next calls to ldap_* funcs, usually with ldap_bind().
+ *
+ * So we should try to bind to server in order to check its availability.
+ */
+
+ //set protocol version and dependend options
+ if($this->getConf('version')) {
+ if(!@ldap_set_option(
+ $this->con, LDAP_OPT_PROTOCOL_VERSION,
+ $this->getConf('version')
+ )
+ ) {
+ msg('Setting LDAP Protocol version '.$this->getConf('version').' failed', -1);
+ $this->_debug('LDAP version set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ } else {
+ //use TLS (needs version 3)
+ if($this->getConf('starttls')) {
+ if(!@ldap_start_tls($this->con)) {
+ msg('Starting TLS failed', -1);
+ $this->_debug('LDAP TLS set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ }
+ }
+ // needs version 3
+ if($this->getConf('referrals')) {
+ if(!@ldap_set_option(
+ $this->con, LDAP_OPT_REFERRALS,
+ $this->getConf('referrals')
+ )
+ ) {
+ msg('Setting LDAP referrals to off failed', -1);
+ $this->_debug('LDAP referal set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ }
+ }
+ }
+ }
+
+ //set deref mode
+ if($this->getConf('deref')) {
+ if(!@ldap_set_option($this->con, LDAP_OPT_DEREF, $this->getConf('deref'))) {
+ msg('Setting LDAP Deref mode '.$this->getConf('deref').' failed', -1);
+ $this->_debug('LDAP deref set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
+ }
+ }
+ /* As of PHP 5.3.0 we can set timeout to speedup skipping of invalid servers */
+ if(defined('LDAP_OPT_NETWORK_TIMEOUT')) {
+ ldap_set_option($this->con, LDAP_OPT_NETWORK_TIMEOUT, 1);
+ }
+
+ if($this->getConf('binddn') && $this->getConf('bindpw')) {
+ $bound = @ldap_bind($this->con, $this->getConf('binddn'), $this->getConf('bindpw'));
+ $this->bound = 2;
+ } else {
+ $bound = @ldap_bind($this->con);
+ }
+ if($bound) {
+ break;
+ }
+ }
+
+ if(!$bound) {
+ msg("LDAP: couldn't connect to LDAP server", -1);
+ return false;
+ }
+
+ $this->cando['getUsers'] = true;
+ return true;
+ }
+
+ /**
+ * Wraps around ldap_search, ldap_list or ldap_read depending on $scope
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param resource $link_identifier
+ * @param string $base_dn
+ * @param string $filter
+ * @param string $scope can be 'base', 'one' or 'sub'
+ * @param null $attributes
+ * @param int $attrsonly
+ * @param int $sizelimit
+ * @param int $timelimit
+ * @param int $deref
+ * @return resource
+ */
+ protected function _ldapsearch($link_identifier, $base_dn, $filter, $scope = 'sub', $attributes = null,
+ $attrsonly = 0, $sizelimit = 0) {
+ if(is_null($attributes)) $attributes = array();
+
+ if($scope == 'base') {
+ return @ldap_read(
+ $link_identifier, $base_dn, $filter, $attributes,
+ $attrsonly, $sizelimit
+ );
+ } elseif($scope == 'one') {
+ return @ldap_list(
+ $link_identifier, $base_dn, $filter, $attributes,
+ $attrsonly, $sizelimit
+ );
+ } else {
+ return @ldap_search(
+ $link_identifier, $base_dn, $filter, $attributes,
+ $attrsonly, $sizelimit
+ );
+ }
+ }
+
+ /**
+ * Wrapper around msg() but outputs only when debug is enabled
+ *
+ * @param string $message
+ * @param int $err
+ * @param int $line
+ * @param string $file
+ * @return void
+ */
+ protected function _debug($message, $err, $line, $file) {
+ if(!$this->getConf('debug')) return;
+ msg($message, $err, $line, $file);
+ }
+
+}
diff --git a/lib/plugins/authldap/conf/default.php b/lib/plugins/authldap/conf/default.php
new file mode 100644
index 000000000..2c295eeeb
--- /dev/null
+++ b/lib/plugins/authldap/conf/default.php
@@ -0,0 +1,20 @@
+<?php
+
+$conf['server'] = '';
+$conf['port'] = 389;
+$conf['usertree'] = '';
+$conf['grouptree'] = '';
+$conf['userfilter'] = '';
+$conf['groupfilter'] = '';
+$conf['version'] = 2;
+$conf['starttls'] = 0;
+$conf['referrals'] = 0;
+$conf['deref'] = 0;
+$conf['binddn'] = '';
+$conf['bindpw'] = '';
+//$conf['mapping']['name'] unsupported in config manager
+//$conf['mapping']['grps'] unsupported in config manager
+$conf['userscope'] = 'sub';
+$conf['groupscope'] = 'sub';
+$conf['groupkey'] = 'cn';
+$conf['debug'] = 0; \ No newline at end of file
diff --git a/lib/plugins/authldap/conf/metadata.php b/lib/plugins/authldap/conf/metadata.php
new file mode 100644
index 000000000..a3256628c
--- /dev/null
+++ b/lib/plugins/authldap/conf/metadata.php
@@ -0,0 +1,19 @@
+<?php
+$meta['server'] = array('string');
+$meta['port'] = array('numeric');
+$meta['usertree'] = array('string');
+$meta['grouptree'] = array('string');
+$meta['userfilter'] = array('string');
+$meta['groupfilter'] = array('string');
+$meta['version'] = array('numeric');
+$meta['starttls'] = array('onoff');
+$meta['referrals'] = array('onoff');
+$meta['deref'] = array('multichoice','_choices' => array(0,1,2,3));
+$meta['binddn'] = array('string');
+$meta['bindpw'] = array('password');
+//$meta['mapping']['name'] unsupported in config manager
+//$meta['mapping']['grps'] unsupported in config manager
+$meta['userscope'] = array('multichoice','_choices' => array('sub','one','base'));
+$meta['groupscope'] = array('multichoice','_choices' => array('sub','one','base'));
+$meta['groupkey'] = array('string');
+$meta['debug'] = array('onoff'); \ No newline at end of file
diff --git a/lib/plugins/authldap/lang/bg/settings.php b/lib/plugins/authldap/lang/bg/settings.php
new file mode 100644
index 000000000..644672ca7
--- /dev/null
+++ b/lib/plugins/authldap/lang/bg/settings.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Bulgarian language file
+ *
+ * @author Kiril <neohidra@gmail.com>
+ */
+$lang['server'] = 'Вашият LDAP сървър. Име на хоста (<code>localhost</code>) или целият URL адрес (<code>ldap://сървър.tld:389</code>)';
+$lang['port'] = 'Порт на LDAP сървъра, ако не сте въвели целия URL адрес по-горе';
+$lang['usertree'] = 'Къде да се търси за потребителски акаунти. Например <code>ou=People, dc=server, dc=tld</code>';
+$lang['grouptree'] = 'Къде да се търси за потребителски групи. Например <code>ou=Group, dc=server, dc=tld</code>';
+$lang['userfilter'] = 'LDAP филтър за търсене на потребителски акаунти. Например <code>(&amp;(uid=%{user})(objectClass=posixAccount))</code>';
+$lang['groupfilter'] = 'LDAP филтър за търсене на потребителски групи. Например <code>(&amp;(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>';
+$lang['version'] = 'Коя версия на протокола да се ползва? Вероятно ще се наложи да зададете <code>3</code>';
+$lang['starttls'] = 'Ползване на TLS свързаност?';
+$lang['referrals'] = 'Да бъдат ли следвани препратките (препращанията)?';
+$lang['bindpw'] = 'Парола за горния потребител';
+$lang['userscope'] = 'Ограничаване на обхвата за търсене на потребители';
+$lang['groupscope'] = 'Ограничаване на обхвата за търсене на потребителски групи';
+$lang['debug'] = 'Показване на допълнителна debug информация при грешка'; \ No newline at end of file
diff --git a/lib/plugins/authldap/lang/cs/settings.php b/lib/plugins/authldap/lang/cs/settings.php
new file mode 100644
index 000000000..783d2a3ae
--- /dev/null
+++ b/lib/plugins/authldap/lang/cs/settings.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * Czech language file
+ *
+ * @author mkucera66@seznam.cz
+ */
+$lang['server'] = 'Váš server LDAP. Buď jméno hosta (<code>localhost</code>) nebo plně kvalifikovaný popis URL (<code>ldap://server.tld:389</code>)';
+$lang['port'] = 'Port serveru LDAP. Pokud není, bude využito URL výše';
+$lang['usertree'] = 'Kde najít uživatelské účty, tj. <code>ou=Lide, dc=server, dc=tld</code>';
+$lang['grouptree'] = 'Kde najít uživatelské skupiny, tj. <code>ou=Skupina, dc=server, dc=tld</code>';
+$lang['userfilter'] = 'Filter LDAPu pro vyhledávání uživatelských účtů, tj. <code>(&amp;(uid=%{user})(objectClass=posixAccount))</code>';
+$lang['groupfilter'] = 'Filter LDAPu pro vyhledávání uživatelských skupin, tj. <code>(&amp;(uid=%{user})(objectClass=posixAccount))</code>';
+$lang['version'] = 'Verze použitého protokolu. Můžete potřebovat jej nastavit na <code>3</code>';
+$lang['starttls'] = 'Využít spojení TLS?';
+$lang['referrals'] = 'Přeposílat odkazy?';
+$lang['binddn'] = 'Doménový název DN volitelně připojeného uživatele, pokus anonymní připojení není vyhovující, tj. <code>cn=admin, dc=muj, dc=domov</code>';
+$lang['bindpw'] = 'Heslo uživatele výše';
+$lang['userscope'] = 'Omezení rozsahu vyhledávání uživatele';
+$lang['groupscope'] = 'Omezení rozsahu vyhledávání skupiny';
+$lang['groupkey'] = 'Atribut šlenství uživatele ve skupinách (namísto standardních AD skupin), tj. skupina z oddělení nebo telefonní číslo';
+$lang['debug'] = 'Zobrazit dodatečné debugovací informace';
diff --git a/lib/plugins/authldap/lang/de-informal/settings.php b/lib/plugins/authldap/lang/de-informal/settings.php
new file mode 100644
index 000000000..15e4d8129
--- /dev/null
+++ b/lib/plugins/authldap/lang/de-informal/settings.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * German informal language file
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Matthias Schulte <dokuwiki@lupo49.de>
+ * @author Volker Bödker <volker@boedker.de>
+ */
+$lang['server'] = 'Adresse zum LDAP-Server. Entweder als Hostname (<code>localhost</code>) oder als FQDN (<code>ldap://server.tld:389</code>).';
+$lang['port'] = 'Port des LDAP-Servers, falls kein Port angegeben wurde.';
+$lang['usertree'] = 'Zweig, in dem die die Benutzeraccounts gespeichert sind. Zum Beispiel: <code>ou=People, dc=server, dc=tld</code>.';
+$lang['grouptree'] = 'Zweig, in dem die Benutzergruppen gespeichert sind. Zum Beispiel: <code>ou=Group, dc=server, dc=tld</code>.';
+$lang['userfilter'] = 'LDAP-Filter, um die Benutzeraccounts zu suchen. Zum Beispiel: <code>(&amp;(uid=%{user})(objectClass=posixAccount))</code>.';
+$lang['groupfilter'] = 'LDAP-Filter, um die Benutzergruppen zu suchen. Zum Beispiel: <code>(&amp;(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>.';
+$lang['version'] = 'Zu verwendende Protokollversion von LDAP.';
+$lang['starttls'] = 'Verbindung über TLS aufbauen?';
+$lang['referrals'] = 'Weiterverfolgen von LDAP-Referrals (Verweise)?';
+$lang['deref'] = 'Wie sollen Aliasse derefernziert werden?';
+$lang['binddn'] = 'DN eines optionalen Benutzers, wenn der anonyme Zugriff nicht ausreichend ist. Zum Beispiel: <code>cn=admin, dc=my, dc=home</code>.';
+$lang['bindpw'] = 'Passwort des angegebenen Benutzers.';
+$lang['userscope'] = 'Die Suchweite nach Benutzeraccounts.';
+$lang['groupscope'] = 'Die Suchweite nach Benutzergruppen.';
+$lang['groupkey'] = 'Gruppieren der Benutzeraccounts anhand eines beliebigen Benutzerattributes z. B. Telefonnummer oder Abteilung, anstelle der Standard-Gruppen).';
+$lang['debug'] = 'Debug-Informationen beim Auftreten von Fehlern anzeigen?';
+$lang['deref_o_0'] = 'LDAP_DEREF_NIEMALS';
+$lang['deref_o_1'] = 'LDAP_DEREF_SUCHEN';
+$lang['deref_o_2'] = 'LDAP_DEREF_FINDEN';
+$lang['deref_o_3'] = 'LDAP_DEREF_IMMER';
diff --git a/lib/plugins/authldap/lang/de/settings.php b/lib/plugins/authldap/lang/de/settings.php
new file mode 100644
index 000000000..b237201d8
--- /dev/null
+++ b/lib/plugins/authldap/lang/de/settings.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ * German language file
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Matthias Schulte <dokuwiki@lupo49.de>
+ */
+$lang['server'] = 'Adresse zum LDAP-Server. Entweder als Hostname (<code>localhost</code>) oder als FQDN (<code>ldap://server.tld:389</code>).';
+$lang['port'] = 'Port des LDAP-Servers, falls kein Port angegeben wurde.';
+$lang['usertree'] = 'Zweig, in dem die die Benutzeraccounts gespeichert sind. Zum Beispiel: <code>ou=People, dc=server, dc=tld</code>.';
+$lang['grouptree'] = 'Zweig, in dem die Benutzergruppen gespeichert sind. Zum Beispiel: <code>ou=Group, dc=server, dc=tld</code>.';
+$lang['userfilter'] = 'LDAP-Filter, um die Benutzeraccounts zu suchen. Zum Beispiel: <code>(&amp;(uid=%{user})(objectClass=posixAccount))</code>.';
+$lang['groupfilter'] = 'LDAP-Filter, um die Benutzergruppen zu suchen. Zum Beispiel: <code>(&amp;(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>.';
+$lang['version'] = 'Zu verwendende Protokollversion von LDAP.';
+$lang['starttls'] = 'Verbindung über TLS aufbauen?';
+$lang['referrals'] = 'Weiterverfolgen von LDAP-Referrals (Verweise)?';
+$lang['binddn'] = 'DN eines optionalen Benutzers, wenn der anonyme Zugriff nicht ausreichend ist. Zum Beispiel: <code>cn=admin, dc=my, dc=home</code>.';
+$lang['bindpw'] = 'Passwort des angegebenen Benutzers.';
+$lang['userscope'] = 'Die Suchweite nach Benutzeraccounts.';
+$lang['groupscope'] = 'Die Suchweite nach Benutzergruppen.';
+$lang['groupkey'] = 'Gruppieren der Benutzeraccounts anhand eines beliebigen Benutzerattributes z. B. Telefonnummer oder Abteilung, anstelle der Standard-Gruppen).';
+$lang['debug'] = 'Debug-Informationen beim Auftreten von Fehlern anzeigen?';
diff --git a/lib/plugins/authldap/lang/en/settings.php b/lib/plugins/authldap/lang/en/settings.php
new file mode 100644
index 000000000..e3f385f99
--- /dev/null
+++ b/lib/plugins/authldap/lang/en/settings.php
@@ -0,0 +1,23 @@
+<?php
+$lang['server'] = 'Your LDAP server. Either hostname (<code>localhost</code>) or full qualified URL (<code>ldap://server.tld:389</code>)';
+$lang['port'] = 'LDAP server port if no full URL was given above';
+$lang['usertree'] = 'Where to find the user accounts. Eg. <code>ou=People, dc=server, dc=tld</code>';
+$lang['grouptree'] = 'Where to find the user groups. Eg. <code>ou=Group, dc=server, dc=tld</code>';
+$lang['userfilter'] = 'LDAP filter to search for user accounts. Eg. <code>(&amp;(uid=%{user})(objectClass=posixAccount))</code>';
+$lang['groupfilter'] = 'LDAP filter to search for groups. Eg. <code>(&amp;(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>';
+$lang['version'] = 'The protocol version to use. You may need to set this to <code>3</code>';
+$lang['starttls'] = 'Use TLS connections?';
+$lang['referrals'] = 'Shall referrals be followed?';
+$lang['deref'] = 'How to dereference aliases?';
+$lang['binddn'] = 'DN of an optional bind user if anonymous bind is not sufficient. Eg. <code>cn=admin, dc=my, dc=home</code>';
+$lang['bindpw'] = 'Password of above user';
+$lang['userscope'] = 'Limit search scope for user search';
+$lang['groupscope'] = 'Limit search scope for group search';
+$lang['groupkey'] = 'Group membership from any user attribute (instead of standard AD groups) e.g. group from department or telephone number';
+$lang['debug'] = 'Display additional debug information on errors';
+
+
+$lang['deref_o_0'] = 'LDAP_DEREF_NEVER';
+$lang['deref_o_1'] = 'LDAP_DEREF_SEARCHING';
+$lang['deref_o_2'] = 'LDAP_DEREF_FINDING';
+$lang['deref_o_3'] = 'LDAP_DEREF_ALWAYS'; \ No newline at end of file
diff --git a/lib/plugins/authldap/lang/eo/settings.php b/lib/plugins/authldap/lang/eo/settings.php
new file mode 100644
index 000000000..2863a1125
--- /dev/null
+++ b/lib/plugins/authldap/lang/eo/settings.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * Esperanto language file
+ *
+ */
+$lang['server'] = 'Via LDAP-servilo. Aŭ servila nomo (<code>localhost</code>) aŭ plene detala URL (<code>ldap://servilo.lando:389</code>)';
+$lang['port'] = 'LDAP-servila pordego, se vi supre ne indikis la plenan URL';
+$lang['usertree'] = 'Kie trovi uzantajn kontojn, ekz. <code>ou=Personoj, dc=servilo, dc=lando</code>';
+$lang['grouptree'] = 'Kie trovi uzantogrupojn, ekz. <code>ou=Grupo, dc=servilo, dc=lando</code>';
+$lang['userfilter'] = 'LDAP-filtrilo por serĉi uzantokontojn, ekz. <code>(&amp;(uid=%{user})(objectClass=posixAccount))</code>';
+$lang['groupfilter'] = 'LDAP-filtrilo por serĉi grupojn, ekz. <code>(&amp;(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>';
+$lang['version'] = 'La uzenda protokolversio. Eble necesas indiki <code>3</code>';
+$lang['starttls'] = 'Ĉu uzi TLS-konektojn?';
+$lang['referrals'] = 'Ĉu sekvi referencojn?';
+$lang['binddn'] = 'DN de opcie bindita uzanto, se anonima bindado ne sufiĉas, ekz. <code>cn=admin, dc=mia, dc=hejmo</code>';
+$lang['bindpw'] = 'Pasvorto de tiu uzanto';
+$lang['userscope'] = 'Limigi serĉospacon de uzantaj serĉoj';
+$lang['groupscope'] = 'Limigi serĉospacon por grupaj serĉoj';
+$lang['groupkey'] = 'Grupa membreco de iu uzanta atributo (anstataŭ standardaj AD-grupoj), ekz. grupo de departemento aŭ telefonnumero';
+$lang['debug'] = 'Ĉu montri aldonajn erarinformojn?';
diff --git a/lib/plugins/authldap/lang/fi/settings.php b/lib/plugins/authldap/lang/fi/settings.php
new file mode 100644
index 000000000..d3aa13e07
--- /dev/null
+++ b/lib/plugins/authldap/lang/fi/settings.php
@@ -0,0 +1,6 @@
+<?php
+/**
+ * Finnish language file
+ *
+ * @author Otto Vainio <otto@valjakko.net>
+ */
diff --git a/lib/plugins/authldap/lang/fr/settings.php b/lib/plugins/authldap/lang/fr/settings.php
new file mode 100644
index 000000000..3df09eb7c
--- /dev/null
+++ b/lib/plugins/authldap/lang/fr/settings.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * French language file
+ *
+ * @author Bruno Veilleux <bruno.vey@gmail.com>
+ */
+$lang['server'] = 'Votre serveur LDAP. Soit le nom d\'hôte (<code>localhost</code>) ou l\'URL complète (<code>ldap://serveur.dom:389</code>)';
+$lang['port'] = 'Port du serveur LDAP si l\'URL complète n\'a pas été indiquée ci-dessus';
+$lang['usertree'] = 'Où trouver les comptes utilisateur. Ex.: <code>ou=Utilisateurs, dc=serveur, dc=dom</code>';
+$lang['grouptree'] = 'Où trouver les groupes d\'utilisateurs. Ex.: <code>ou=Groupes, dc=serveur, dc=dom</code>';
+$lang['userfilter'] = 'Filtre LDAP pour rechercher les comptes utilisateur. Ex.: <code>(&amp;(uid=%{user})(objectClass=posixAccount))</code>';
+$lang['groupfilter'] = 'Filtre LDAP pour rechercher les groupes. Ex.: <code>(&amp;(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>';
+$lang['version'] = 'La version de protocole à utiliser. Il se peut que vous deviez utiliser <code>3</code>';
+$lang['starttls'] = 'Utiliser les connexions TLS?';
+$lang['referrals'] = 'Suivre les références?';
+$lang['binddn'] = 'Nom de domaine d\'un utilisateur de connexion facultatif si une connexion anonyme n\'est pas suffisante. Ex. : <code>cn=admin, dc=mon, dc=accueil</code>';
+$lang['bindpw'] = 'Mot de passe de l\'utilisateur ci-dessus.';
+$lang['userscope'] = 'Limiter la portée de recherche d\'utilisateurs';
+$lang['groupscope'] = 'Limiter la portée de recherche de groupes';
+$lang['groupkey'] = 'Affiliation aux groupes à partir de n\'importe quel attribut utilisateur (au lieu des groupes AD standards), p. ex. groupes par département ou numéro de téléphone';
+$lang['debug'] = 'Afficher des informations de bégogage supplémentaires pour les erreurs';
diff --git a/lib/plugins/authldap/lang/it/settings.php b/lib/plugins/authldap/lang/it/settings.php
new file mode 100644
index 000000000..10ae72f87
--- /dev/null
+++ b/lib/plugins/authldap/lang/it/settings.php
@@ -0,0 +1,5 @@
+<?php
+/**
+ * Italian language file
+ *
+ */
diff --git a/lib/plugins/authldap/lang/ja/settings.php b/lib/plugins/authldap/lang/ja/settings.php
new file mode 100644
index 000000000..fdc6fc434
--- /dev/null
+++ b/lib/plugins/authldap/lang/ja/settings.php
@@ -0,0 +1,6 @@
+<?php
+/**
+ * Japanese language file
+ *
+ * @author Satoshi Sahara <sahara.satoshi@gmail.com>
+ */
diff --git a/lib/plugins/authldap/lang/ko/settings.php b/lib/plugins/authldap/lang/ko/settings.php
new file mode 100644
index 000000000..7f7efe8d0
--- /dev/null
+++ b/lib/plugins/authldap/lang/ko/settings.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * Korean language file
+ *
+ * @author Myeongjin <aranet100@gmail.com>
+ */
+$lang['server'] = 'LDAP 서버. 호스트 이름(<code>localhost</code>)이나 전체 자격 URL(<code>ldap://server.tld:389</code>) 중 하나';
+$lang['port'] = '위에 주어진 전체 URL이 없을 때의 LDAP 서버 포트';
+$lang['usertree'] = '사용자 계정을 찾을 장소. 예를 들어 <code>ou=People, dc=server, dc=tld</code>';
+$lang['grouptree'] = '사용자 그룹을 찾을 장소. 예를 들어 <code>ou=Group, dc=server, dc=tld</code>';
+$lang['userfilter'] = '사용자 계정을 찾을 LDAP 필터. 예를 들어 <code>(&amp;(uid=%{user})(objectClass=posixAccount))</code>';
+$lang['groupfilter'] = '그룹을 찾을 LDAP 필터. 예를 들어 <code>(&amp;(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>';
+$lang['version'] = '사용할 프로토콜 버전. <code>3</code>으로 설정해야 할 수도 있습니다';
+$lang['starttls'] = 'TLS 연결을 사용하겠습니까?';
+$lang['referrals'] = '참고(referrals)를 허용하겠습니까? ';
+$lang['binddn'] = '익명 바인드가 충분하지 않으면 선택적인 바인드 사용자의 DN. 예를 들어 <code>cn=admin, dc=my, dc=home</code>';
+$lang['bindpw'] = '위 사용자의 비밀번호';
+$lang['userscope'] = '사용자 찾기에 대한 찾기 범위 제한';
+$lang['groupscope'] = '그룹 찾기에 대한 찾기 범위 제한';
+$lang['groupkey'] = '(표준 AD 그룹 대신) 사용자 속성에서 그룹 구성원. 예를 들어 부서나 전화에서 그룹';
+$lang['debug'] = '오류에 대한 추가적인 디버그 정보를 보이기';
diff --git a/lib/plugins/authldap/lang/lv/settings.php b/lib/plugins/authldap/lang/lv/settings.php
new file mode 100644
index 000000000..ced5dabf8
--- /dev/null
+++ b/lib/plugins/authldap/lang/lv/settings.php
@@ -0,0 +1,6 @@
+<?php
+/**
+ * Latvian, Lettish language file
+ *
+ * @author Aivars Miška <allefm@gmail.com>
+ */
diff --git a/lib/plugins/authldap/lang/nl/settings.php b/lib/plugins/authldap/lang/nl/settings.php
new file mode 100644
index 000000000..274c3b7fc
--- /dev/null
+++ b/lib/plugins/authldap/lang/nl/settings.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * Dutch language file
+ *
+ */
+$lang['server'] = 'Je LDAP server. Ofwel servernaam (<code>localhost</code>) of volledige URL (<code>ldap://server.tld:389</code>)';
+$lang['port'] = 'LDAP server poort als hiervoor geen volledige URL is opgegeven';
+$lang['usertree'] = 'Locatie van de gebruikersaccounts. Bijv. <code>ou=Personen,dc=server,dc=tld</code>';
+$lang['grouptree'] = 'Locatie van de gebruikersgroepen. Bijv. <code>ou=Group,dc=server,dc=tld</code>';
+$lang['userfilter'] = 'LDAP gebruikersfilter. Bijv. <code>(&amp;(uid=%{user})(objectClass=posixAccount))</code>';
+$lang['groupfilter'] = 'LDAP groepsfilter. Bijv. <code>(&amp;(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>';
+$lang['version'] = 'Te gebruiken protocolversie. Je zou het moeten kunnen instellen op <code>3</code>';
+$lang['starttls'] = 'Gebruiken TLS verbindingen';
+$lang['referrals'] = 'Moeten verwijzingen worden gevolg';
+$lang['binddn'] = 'DN van een optionele bind gebruiker als anonieme bind niet genoeg is. Bijv. <code>cn=beheer, dc=mijn, dc=thuis</code>';
+$lang['bindpw'] = 'Wachtwoord van bovenstaande gebruiker';
+$lang['userscope'] = 'Beperken scope van zoekfuncties voor gebruikers';
+$lang['groupscope'] = 'Beperken scope van zoekfuncties voor groepen';
+$lang['groupkey'] = 'Groepslidmaatschap van enig gebruikersattribuut (in plaats van standaard AD groepen), bijv. groep van afdeling of telefoonnummer';
+$lang['debug'] = 'Tonen van aanvullende debuginformatie bij fouten';
diff --git a/lib/plugins/authldap/lang/pt-br/settings.php b/lib/plugins/authldap/lang/pt-br/settings.php
new file mode 100644
index 000000000..70b68b289
--- /dev/null
+++ b/lib/plugins/authldap/lang/pt-br/settings.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * Brazilian Portuguese language file
+ *
+ * @author Victor Westmann <victor.westmann@gmail.com>
+ */
+$lang['server'] = 'Seu servidor LDAP. Ou hostname (<code>localhost</code>) ou uma URL completa (<code>ldap://server.tld:389</code>)';
+$lang['port'] = 'Porta LDAP do servidor se nenhuma URL completa tiver sido fornecida acima';
+$lang['usertree'] = 'Onde encontrar as contas de usuários. Eg. <code>ou=Pessoas, dc=servidor, dc=tld</code>';
+$lang['grouptree'] = 'Onde encontrar os grupos de usuários. Eg. <code>ou=Pessoas, dc=servidor, dc=tld</code>';
+$lang['userfilter'] = 'Filtro do LDAP para procurar por contas de usuários. Eg. <code>(&amp;(uid=%{user})(objectClass=posixAccount))</code>';
+$lang['groupfilter'] = 'Filtro do LDAP 0ara procurar por grupos. Eg. <code>(&amp;(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>';
+$lang['version'] = 'A versão do protocolo para usar. Você talvez deva definir isto para <code>3</code>';
+$lang['starttls'] = 'Usar conexões TLS?';
+$lang['referrals'] = 'Permitir referências serem seguidas?';
+$lang['deref'] = 'Como respeitar aliases ?';
+$lang['binddn'] = 'DN de um vínculo opcional de usuário se vínculo anônimo não for suficiente. Eg. <code>cn=admin, dc=my, dc=home</code>';
+$lang['bindpw'] = 'Senha do usuário acima';
+$lang['userscope'] = 'Limitar escopo da busca para busca de usuário';
+$lang['groupscope'] = 'Limitar escopo da busca para busca de grupo';
+$lang['groupkey'] = 'Membro de grupo vem de qualquer atributo do usuário (ao invés de grupos padrões AD) e.g. departamento de grupo ou número de telefone';
+$lang['debug'] = 'Mostrar informações adicionais de depuração em erros';
+$lang['deref_o_0'] = 'LDAP_DEREF_NEVER';
+$lang['deref_o_1'] = 'LDAP_DEREF_SEARCHING';
+$lang['deref_o_2'] = 'LDAP_DEREF_FINDING';
+$lang['deref_o_3'] = 'LDAP_DEREF_ALWAYS';
diff --git a/lib/plugins/authldap/lang/ru/settings.php b/lib/plugins/authldap/lang/ru/settings.php
new file mode 100644
index 000000000..4c394080e
--- /dev/null
+++ b/lib/plugins/authldap/lang/ru/settings.php
@@ -0,0 +1,6 @@
+<?php
+/**
+ * Russian language file
+ *
+ * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua)
+ */
diff --git a/lib/plugins/authldap/lang/sv/settings.php b/lib/plugins/authldap/lang/sv/settings.php
new file mode 100644
index 000000000..0fdcad147
--- /dev/null
+++ b/lib/plugins/authldap/lang/sv/settings.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Swedish language file
+ *
+ * @author Smorkster Andersson smorkster@gmail.com
+ */
+$lang['server'] = 'Din LDAO server. Antingen värdnamn (<code>localhost</code>) eller giltig full URL (<code>ldap://server.tld:389</code>)';
+$lang['port'] = 'LDAP server port, om det inte angavs full URL ovan';
+$lang['usertree'] = 'Specificera var användarkonton finns. T.ex. <code>ou=Användare, dc=server, dc=tld</code>';
+$lang['grouptree'] = 'Specificera var grupper finns. T.ex. <code>ou=Grupp, dc=server, dc=tld</code>';
+$lang['userfilter'] = 'LDAP filter för att söka efter användarkonton. T.ex. <code>(&amp;(uid=%{user})(objectClass=posixAccount))</code>';
+$lang['groupfilter'] = 'LDAP filter för att söka efter grupper. T.ex. <code>(&amp;(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>';
+$lang['version'] = 'Version av protokoll att använda. Du kan behöva sätta detta till <code>3</code>';
+$lang['bindpw'] = 'Lösenord för användare ovan';
+$lang['groupkey'] = 'Gruppmedlemskap från något användarattribut (istället för standard AD grupp) t.ex. grupp från avdelning eller telefonnummer';
+$lang['debug'] = 'Visa ytterligare felsökningsinformation vid fel';
diff --git a/lib/plugins/authldap/lang/zh-tw/settings.php b/lib/plugins/authldap/lang/zh-tw/settings.php
new file mode 100644
index 000000000..e93190516
--- /dev/null
+++ b/lib/plugins/authldap/lang/zh-tw/settings.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * Chinese Traditional language file
+ *
+ * @author syaoranhinata@gmail.com
+ */
+$lang['server'] = '您的 LDAP 伺服器。填寫主機名稱 (<code>localhost</code>) 或完整的 URL (<code>ldap://server.tld:389</code>)';
+$lang['port'] = 'LDAP 伺服器端口 (若上方沒填寫完整的 URL)';
+$lang['usertree'] = '到哪裏尋找使用者帳號?如: <code>ou=People, dc=server, dc=tld</code>';
+$lang['grouptree'] = '到哪裏尋找使用者群組?如: <code>ou=Group, dc=server, dc=tld</code>';
+$lang['userfilter'] = '用於搜索使用者賬號的 LDAP 篩選器。如: <code>(&(uid=%{user})(objectClass=posixAccount))</code>';
+$lang['groupfilter'] = '用於搜索群組的 LDAP 篩選器。例如 <code>(&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>';
+$lang['version'] = '使用的通訊協定版本。您可能要設置為 <code>3</code>';
+$lang['starttls'] = '使用 TLS 連接嗎?';
+$lang['referrals'] = '是否允許引用 (referrals)?';
+$lang['binddn'] = '非必要綁定使用者 (optional bind user) 的 DN (匿名綁定不能滿足要求時使用)。如: <code>cn=admin, dc=my, dc=home</code>';
+$lang['bindpw'] = '上述使用者的密碼';
+$lang['userscope'] = '限制使用者搜索的範圍';
+$lang['groupscope'] = '限制群組搜索的範圍';
+$lang['groupkey'] = '以其他使用者屬性 (而非標準 AD 群組) 來把使用者分組,例如以部門或電話號碼分類';
+$lang['debug'] = '有錯誤時,顯示額外除錯資訊';
diff --git a/lib/plugins/authldap/lang/zh/settings.php b/lib/plugins/authldap/lang/zh/settings.php
new file mode 100644
index 000000000..3f38deae9
--- /dev/null
+++ b/lib/plugins/authldap/lang/zh/settings.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * Chinese language file
+ *
+ * @author lainme <lainme993@gmail.com>
+ */
+$lang['server'] = '您的 LDAP 服务器。填写主机名 (<code>localhost</code>) 或者完整的 URL (<code>ldap://server.tld:389</code>)';
+$lang['port'] = 'LDAP 服务器端口 (如果上面没有给出完整的 URL)';
+$lang['usertree'] = '何处查找用户账户。例如 <code>ou=People, dc=server, dc=tld</code>';
+$lang['grouptree'] = '何处查找用户组。例如 <code>ou=Group, dc=server, dc=tld</code>';
+$lang['userfilter'] = '用于搜索用户账户的 LDAP 筛选器。例如 <code>(&(uid=%{user})(objectClass=posixAccount))</code>';
+$lang['groupfilter'] = '用于搜索组的 LDAP 筛选器。例如 <code>(&(objectClass=posixGroup)(|(gidNumber=%{gid})(memberUID=%{user})))</code>';
+$lang['version'] = '使用的协议版本。您或许需要设置为 <code>3</code>';
+$lang['starttls'] = '使用 TLS 连接?';
+$lang['referrals'] = '是否允许引用 (referrals)?';
+$lang['binddn'] = '一个可选的绑定用户的 DN (如果匿名绑定不满足要求)。例如 <code>cn=admin, dc=my, dc=home</code>';
+$lang['bindpw'] = '上述用户的密码';
+$lang['userscope'] = '限制用户搜索的范围';
+$lang['groupscope'] = '限制组搜索的范围';
+$lang['groupkey'] = '根据任何用户属性得来的组成员(而不是标准的 AD 组),例如根据部门或者电话号码得到的组。';
+$lang['debug'] = '有错误时显示额外的调试信息';
diff --git a/lib/plugins/authldap/plugin.info.txt b/lib/plugins/authldap/plugin.info.txt
new file mode 100644
index 000000000..94809a75b
--- /dev/null
+++ b/lib/plugins/authldap/plugin.info.txt
@@ -0,0 +1,7 @@
+base authldap
+author Andreas Gohr
+email andi@splitbrain.org
+date 2013-04-19
+name ldap auth plugin
+desc Provides authentication against am LDAP server
+url http://www.dokuwiki.org/plugin:authldap
diff --git a/lib/plugins/authmysql/auth.php b/lib/plugins/authmysql/auth.php
new file mode 100644
index 000000000..036644a67
--- /dev/null
+++ b/lib/plugins/authmysql/auth.php
@@ -0,0 +1,975 @@
+<?php
+// must be run within Dokuwiki
+if(!defined('DOKU_INC')) die();
+
+/**
+ * MySQL authentication backend
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @author Matthias Grimm <matthias.grimmm@sourceforge.net>
+ * @author Jan Schumann <js@schumann-it.com>
+ */
+class auth_plugin_authmysql extends DokuWiki_Auth_Plugin {
+ /** @var resource holds the database connection */
+ protected $dbcon = 0;
+ /** @var int database version*/
+ protected $dbver = 0;
+ /** @var int database revision */
+ protected $dbrev = 0;
+ /** @var int database subrevision */
+ protected $dbsub = 0;
+
+ /**
+ * Constructor
+ *
+ * checks if the mysql interface is available, otherwise it will
+ * set the variable $success of the basis class to false
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ */
+ public function __construct() {
+ parent::__construct();
+
+ if(!function_exists('mysql_connect')) {
+ $this->_debug("MySQL err: PHP MySQL extension not found.", -1, __LINE__, __FILE__);
+ $this->success = false;
+ return;
+ }
+
+ // set capabilities based upon config strings set
+ if(!$this->getConf('server') || !$this->getConf('user') || !$this->getConf('database')) {
+ $this->_debug("MySQL err: insufficient configuration.", -1, __LINE__, __FILE__);
+
+ $this->success = false;
+ return;
+ }
+
+ $this->cando['addUser'] = $this->_chkcnf(
+ array(
+ 'getUserInfo',
+ 'getGroups',
+ 'addUser',
+ 'getUserID',
+ 'getGroupID',
+ 'addGroup',
+ 'addUserGroup'
+ ), true
+ );
+ $this->cando['delUser'] = $this->_chkcnf(
+ array(
+ 'getUserID',
+ 'delUser',
+ 'delUserRefs'
+ ), true
+ );
+ $this->cando['modLogin'] = $this->_chkcnf(
+ array(
+ 'getUserID',
+ 'updateUser',
+ 'UpdateTarget'
+ ), true
+ );
+ $this->cando['modPass'] = $this->cando['modLogin'];
+ $this->cando['modName'] = $this->cando['modLogin'];
+ $this->cando['modMail'] = $this->cando['modLogin'];
+ $this->cando['modGroups'] = $this->_chkcnf(
+ array(
+ 'getUserID',
+ 'getGroups',
+ 'getGroupID',
+ 'addGroup',
+ 'addUserGroup',
+ 'delGroup',
+ 'getGroupID',
+ 'delUserGroup'
+ ), true
+ );
+ /* getGroups is not yet supported
+ $this->cando['getGroups'] = $this->_chkcnf(array('getGroups',
+ 'getGroupID'),false); */
+ $this->cando['getUsers'] = $this->_chkcnf(
+ array(
+ 'getUsers',
+ 'getUserInfo',
+ 'getGroups'
+ ), false
+ );
+ $this->cando['getUserCount'] = $this->_chkcnf(array('getUsers'), false);
+
+ if($this->getConf('debug') >= 2) {
+ $candoDebug = '';
+ foreach($this->cando as $cd => $value) {
+ if($value) { $value = 'yes'; } else { $value = 'no'; }
+ $candoDebug .= $cd . ": " . $value . " | ";
+ }
+ $this->_debug("authmysql cando: " . $candoDebug, 0, __LINE__, __FILE__);
+ }
+ }
+
+ /**
+ * Check if the given config strings are set
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ * @param array $keys
+ * @param bool $wop is this a check for a write operation?
+ * @return bool
+ */
+ protected function _chkcnf($keys, $wop = false) {
+ foreach($keys as $key) {
+ if(!$this->getConf($key)) return false;
+ }
+
+ /* write operation and lock array filled with tables names? */
+ if($wop && (!is_array($this->getConf('TablesToLock')) ||
+ !count($this->getConf('TablesToLock')))
+ ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks if the given user exists and the given plaintext password
+ * is correct. Furtheron it might be checked wether the user is
+ * member of the right group
+ *
+ * Depending on which SQL string is defined in the config, password
+ * checking is done here (getpass) or by the database (passcheck)
+ *
+ * @param string $user user who would like access
+ * @param string $pass user's clear text password to check
+ * @return bool
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ */
+ public function checkPass($user, $pass) {
+ global $conf;
+ $rc = false;
+
+ if($this->_openDB()) {
+ $sql = str_replace('%{user}', $this->_escape($user), $this->getConf('checkPass'));
+ $sql = str_replace('%{pass}', $this->_escape($pass), $sql);
+ $sql = str_replace('%{dgroup}', $this->_escape($conf['defaultgroup']), $sql);
+ $result = $this->_queryDB($sql);
+
+ if($result !== false && count($result) == 1) {
+ if($this->getConf('forwardClearPass') == 1)
+ $rc = true;
+ else
+ $rc = auth_verifyPassword($pass, $result[0]['pass']);
+ }
+ $this->_closeDB();
+ }
+ return $rc;
+ }
+
+ /**
+ * Return user info
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $user user login to get data for
+ * @return array|bool
+ */
+ public function getUserData($user) {
+ if($this->_openDB()) {
+ $this->_lockTables("READ");
+ $info = $this->_getUserInfo($user);
+ $this->_unlockTables();
+ $this->_closeDB();
+ } else
+ $info = false;
+ return $info;
+ }
+
+ /**
+ * Create a new User. Returns false if the user already exists,
+ * null when an error occurred and true if everything went well.
+ *
+ * The new user will be added to the default group by this
+ * function if grps are not specified (default behaviour).
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $user nick of the user
+ * @param string $pwd clear text password
+ * @param string $name full name of the user
+ * @param string $mail email address
+ * @param array $grps array of groups the user should become member of
+ * @return bool|null
+ */
+ public function createUser($user, $pwd, $name, $mail, $grps = null) {
+ global $conf;
+
+ if($this->_openDB()) {
+ if(($info = $this->_getUserInfo($user)) !== false)
+ return false; // user already exists
+
+ // set defaultgroup if no groups were given
+ if($grps == null)
+ $grps = array($conf['defaultgroup']);
+
+ $this->_lockTables("WRITE");
+ $pwd = $this->getConf('forwardClearPass') ? $pwd : auth_cryptPassword($pwd);
+ $rc = $this->_addUser($user, $pwd, $name, $mail, $grps);
+ $this->_unlockTables();
+ $this->_closeDB();
+ if($rc) return true;
+ }
+ return null; // return error
+ }
+
+ /**
+ * Modify user data
+ *
+ * An existing user dataset will be modified. Changes are given in an array.
+ *
+ * The dataset update will be rejected if the user name should be changed
+ * to an already existing one.
+ *
+ * The password must be provides unencrypted. Pasword cryption is done
+ * automatically if configured.
+ *
+ * If one or more groups could't be updated, an error would be set. In
+ * this case the dataset might already be changed and we can't rollback
+ * the changes. Transactions would be really usefull here.
+ *
+ * modifyUser() may be called without SQL statements defined that are
+ * needed to change group membership (for example if only the user profile
+ * should be modified). In this case we asure that we don't touch groups
+ * even $changes['grps'] is set by mistake.
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $user nick of the user to be changed
+ * @param array $changes array of field/value pairs to be changed (password will be clear text)
+ * @return bool true on success, false on error
+ */
+ public function modifyUser($user, $changes) {
+ $rc = false;
+
+ if(!is_array($changes) || !count($changes))
+ return true; // nothing to change
+
+ if($this->_openDB()) {
+ $this->_lockTables("WRITE");
+
+ if(($uid = $this->_getUserID($user))) {
+ $rc = $this->_updateUserInfo($changes, $uid);
+
+ if($rc && isset($changes['grps']) && $this->cando['modGroups']) {
+ $groups = $this->_getGroups($user);
+ $grpadd = array_diff($changes['grps'], $groups);
+ $grpdel = array_diff($groups, $changes['grps']);
+
+ foreach($grpadd as $group)
+ if(($this->_addUserToGroup($user, $group, 1)) == false)
+ $rc = false;
+
+ foreach($grpdel as $group)
+ if(($this->_delUserFromGroup($user, $group)) == false)
+ $rc = false;
+ }
+ }
+
+ $this->_unlockTables();
+ $this->_closeDB();
+ }
+ return $rc;
+ }
+
+ /**
+ * [public function]
+ *
+ * Remove one or more users from the list of registered users
+ *
+ * @param array $users array of users to be deleted
+ * @return int the number of users deleted
+ *
+ * @author Christopher Smith <chris@jalakai.co.uk>
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ */
+ function deleteUsers($users) {
+ $count = 0;
+
+ if($this->_openDB()) {
+ if(is_array($users) && count($users)) {
+ $this->_lockTables("WRITE");
+ foreach($users as $user) {
+ if($this->_delUser($user))
+ $count++;
+ }
+ $this->_unlockTables();
+ }
+ $this->_closeDB();
+ }
+ return $count;
+ }
+
+ /**
+ * Counts users which meet certain $filter criteria.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param array $filter filter criteria in item/pattern pairs
+ * @return int count of found users
+ */
+ public function getUserCount($filter = array()) {
+ $rc = 0;
+
+ if($this->_openDB()) {
+ $sql = $this->_createSQLFilter($this->getConf('getUsers'), $filter);
+
+ if($this->dbver >= 4) {
+ $sql = substr($sql, 6); /* remove 'SELECT' or 'select' */
+ $sql = "SELECT SQL_CALC_FOUND_ROWS".$sql." LIMIT 1";
+ $this->_queryDB($sql);
+ $result = $this->_queryDB("SELECT FOUND_ROWS()");
+ $rc = $result[0]['FOUND_ROWS()'];
+ } else if(($result = $this->_queryDB($sql)))
+ $rc = count($result);
+
+ $this->_closeDB();
+ }
+ return $rc;
+ }
+
+ /**
+ * Bulk retrieval of user data
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param int $first index of first user to be returned
+ * @param int $limit max number of users to be returned
+ * @param array|string $filter array of field/pattern pairs
+ * @return array userinfo (refer getUserData for internal userinfo details)
+ */
+ public function retrieveUsers($first = 0, $limit = 10, $filter = array()) {
+ $out = array();
+
+ if($this->_openDB()) {
+ $this->_lockTables("READ");
+ $sql = $this->_createSQLFilter($this->getConf('getUsers'), $filter);
+ $sql .= " ".$this->getConf('SortOrder')." LIMIT $first, $limit";
+ $result = $this->_queryDB($sql);
+
+ if(!empty($result)) {
+ foreach($result as $user)
+ if(($info = $this->_getUserInfo($user['user'])))
+ $out[$user['user']] = $info;
+ }
+
+ $this->_unlockTables();
+ $this->_closeDB();
+ }
+ return $out;
+ }
+
+ /**
+ * Give user membership of a group
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $user
+ * @param string $group
+ * @return bool true on success, false on error
+ */
+ protected function joinGroup($user, $group) {
+ $rc = false;
+
+ if($this->_openDB()) {
+ $this->_lockTables("WRITE");
+ $rc = $this->_addUserToGroup($user, $group);
+ $this->_unlockTables();
+ $this->_closeDB();
+ }
+ return $rc;
+ }
+
+ /**
+ * Remove user from a group
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $user user that leaves a group
+ * @param string $group group to leave
+ * @return bool
+ */
+ protected function leaveGroup($user, $group) {
+ $rc = false;
+
+ if($this->_openDB()) {
+ $this->_lockTables("WRITE");
+ $rc = $this->_delUserFromGroup($user, $group);
+ $this->_unlockTables();
+ $this->_closeDB();
+ }
+ return $rc;
+ }
+
+ /**
+ * MySQL is case-insensitive
+ */
+ public function isCaseSensitive() {
+ return false;
+ }
+
+ /**
+ * Adds a user to a group.
+ *
+ * If $force is set to true non existing groups would be created.
+ *
+ * The database connection must already be established. Otherwise
+ * this function does nothing and returns 'false'. It is strongly
+ * recommended to call this function only after all participating
+ * tables (group and usergroup) have been locked.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $user user to add to a group
+ * @param string $group name of the group
+ * @param bool $force create missing groups
+ * @return bool true on success, false on error
+ */
+ protected function _addUserToGroup($user, $group, $force = false) {
+ $newgroup = 0;
+
+ if(($this->dbcon) && ($user)) {
+ $gid = $this->_getGroupID($group);
+ if(!$gid) {
+ if($force) { // create missing groups
+ $sql = str_replace('%{group}', $this->_escape($group), $this->getConf('addGroup'));
+ $gid = $this->_modifyDB($sql);
+ $newgroup = 1; // group newly created
+ }
+ if(!$gid) return false; // group didn't exist and can't be created
+ }
+
+ $sql = $this->getConf('addUserGroup');
+ if(strpos($sql, '%{uid}') !== false) {
+ $uid = $this->_getUserID($user);
+ $sql = str_replace('%{uid}', $this->_escape($uid), $sql);
+ }
+ $sql = str_replace('%{user}', $this->_escape($user), $sql);
+ $sql = str_replace('%{gid}', $this->_escape($gid), $sql);
+ $sql = str_replace('%{group}', $this->_escape($group), $sql);
+ if($this->_modifyDB($sql) !== false) return true;
+
+ if($newgroup) { // remove previously created group on error
+ $sql = str_replace('%{gid}', $this->_escape($gid), $this->getConf('delGroup'));
+ $sql = str_replace('%{group}', $this->_escape($group), $sql);
+ $this->_modifyDB($sql);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Remove user from a group
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $user user that leaves a group
+ * @param string $group group to leave
+ * @return bool true on success, false on error
+ */
+ protected function _delUserFromGroup($user, $group) {
+ $rc = false;
+
+ if(($this->dbcon) && ($user)) {
+ $sql = $this->getConf('delUserGroup');
+ if(strpos($sql, '%{uid}') !== false) {
+ $uid = $this->_getUserID($user);
+ $sql = str_replace('%{uid}', $this->_escape($uid), $sql);
+ }
+ $gid = $this->_getGroupID($group);
+ if($gid) {
+ $sql = str_replace('%{user}', $this->_escape($user), $sql);
+ $sql = str_replace('%{gid}', $this->_escape($gid), $sql);
+ $sql = str_replace('%{group}', $this->_escape($group), $sql);
+ $rc = $this->_modifyDB($sql) == 0 ? true : false;
+ }
+ }
+ return $rc;
+ }
+
+ /**
+ * Retrieves a list of groups the user is a member off.
+ *
+ * The database connection must already be established
+ * for this function to work. Otherwise it will return
+ * false.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $user user whose groups should be listed
+ * @return bool|array false on error, all groups on success
+ */
+ protected function _getGroups($user) {
+ $groups = array();
+
+ if($this->dbcon) {
+ $sql = str_replace('%{user}', $this->_escape($user), $this->getConf('getGroups'));
+ $result = $this->_queryDB($sql);
+
+ if($result !== false && count($result)) {
+ foreach($result as $row)
+ $groups[] = $row['group'];
+ }
+ return $groups;
+ }
+ return false;
+ }
+
+ /**
+ * Retrieves the user id of a given user name
+ *
+ * The database connection must already be established
+ * for this function to work. Otherwise it will return
+ * false.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $user user whose id is desired
+ * @return mixed user id
+ */
+ protected function _getUserID($user) {
+ if($this->dbcon) {
+ $sql = str_replace('%{user}', $this->_escape($user), $this->getConf('getUserID'));
+ $result = $this->_queryDB($sql);
+ return $result === false ? false : $result[0]['id'];
+ }
+ return false;
+ }
+
+ /**
+ * Adds a new User to the database.
+ *
+ * The database connection must already be established
+ * for this function to work. Otherwise it will return
+ * false.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $user login of the user
+ * @param string $pwd encrypted password
+ * @param string $name full name of the user
+ * @param string $mail email address
+ * @param array $grps array of groups the user should become member of
+ * @return bool
+ */
+ protected function _addUser($user, $pwd, $name, $mail, $grps) {
+ if($this->dbcon && is_array($grps)) {
+ $sql = str_replace('%{user}', $this->_escape($user), $this->getConf('addUser'));
+ $sql = str_replace('%{pass}', $this->_escape($pwd), $sql);
+ $sql = str_replace('%{name}', $this->_escape($name), $sql);
+ $sql = str_replace('%{email}', $this->_escape($mail), $sql);
+ $uid = $this->_modifyDB($sql);
+ $gid = false;
+ $group = '';
+
+ if($uid) {
+ foreach($grps as $group) {
+ $gid = $this->_addUserToGroup($user, $group, 1);
+ if($gid === false) break;
+ }
+
+ if($gid !== false){
+ return true;
+ } else {
+ /* remove the new user and all group relations if a group can't
+ * be assigned. Newly created groups will remain in the database
+ * and won't be removed. This might create orphaned groups but
+ * is not a big issue so we ignore this problem here.
+ */
+ $this->_delUser($user);
+ $this->_debug("MySQL err: Adding user '$user' to group '$group' failed.", -1, __LINE__, __FILE__);
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Deletes a given user and all his group references.
+ *
+ * The database connection must already be established
+ * for this function to work. Otherwise it will return
+ * false.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $user user whose id is desired
+ * @return bool
+ */
+ protected function _delUser($user) {
+ if($this->dbcon) {
+ $uid = $this->_getUserID($user);
+ if($uid) {
+ $sql = str_replace('%{uid}', $this->_escape($uid), $this->getConf('delUserRefs'));
+ $this->_modifyDB($sql);
+ $sql = str_replace('%{uid}', $this->_escape($uid), $this->getConf('delUser'));
+ $sql = str_replace('%{user}', $this->_escape($user), $sql);
+ $this->_modifyDB($sql);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * getUserInfo
+ *
+ * Gets the data for a specific user The database connection
+ * must already be established for this function to work.
+ * Otherwise it will return 'false'.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $user user's nick to get data for
+ * @return bool|array false on error, user info on success
+ */
+ protected function _getUserInfo($user) {
+ $sql = str_replace('%{user}', $this->_escape($user), $this->getConf('getUserInfo'));
+ $result = $this->_queryDB($sql);
+ if($result !== false && count($result)) {
+ $info = $result[0];
+ $info['grps'] = $this->_getGroups($user);
+ return $info;
+ }
+ return false;
+ }
+
+ /**
+ * Updates the user info in the database
+ *
+ * Update a user data structure in the database according changes
+ * given in an array. The user name can only be changes if it didn't
+ * exists already. If the new user name exists the update procedure
+ * will be aborted. The database keeps unchanged.
+ *
+ * The database connection has already to be established for this
+ * function to work. Otherwise it will return 'false'.
+ *
+ * The password will be crypted if necessary.
+ *
+ * @param array $changes array of items to change as pairs of item and value
+ * @param mixed $uid user id of dataset to change, must be unique in DB
+ * @return bool true on success or false on error
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ */
+ protected function _updateUserInfo($changes, $uid) {
+ $sql = $this->getConf('updateUser')." ";
+ $cnt = 0;
+ $err = 0;
+
+ if($this->dbcon) {
+ foreach($changes as $item => $value) {
+ if($item == 'user') {
+ if(($this->_getUserID($changes['user']))) {
+ $err = 1; /* new username already exists */
+ break; /* abort update */
+ }
+ if($cnt++ > 0) $sql .= ", ";
+ $sql .= str_replace('%{user}', $value, $this->getConf('UpdateLogin'));
+ } else if($item == 'name') {
+ if($cnt++ > 0) $sql .= ", ";
+ $sql .= str_replace('%{name}', $value, $this->getConf('UpdateName'));
+ } else if($item == 'pass') {
+ if(!$this->getConf('forwardClearPass'))
+ $value = auth_cryptPassword($value);
+ if($cnt++ > 0) $sql .= ", ";
+ $sql .= str_replace('%{pass}', $value, $this->getConf('UpdatePass'));
+ } else if($item == 'mail') {
+ if($cnt++ > 0) $sql .= ", ";
+ $sql .= str_replace('%{email}', $value, $this->getConf('UpdateEmail'));
+ }
+ }
+
+ if($err == 0) {
+ if($cnt > 0) {
+ $sql .= " ".str_replace('%{uid}', $uid, $this->getConf('UpdateTarget'));
+ if(get_class($this) == 'auth_mysql') $sql .= " LIMIT 1"; //some PgSQL inheritance comp.
+ $this->_modifyDB($sql);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Retrieves the group id of a given group name
+ *
+ * The database connection must already be established
+ * for this function to work. Otherwise it will return
+ * false.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $group group name which id is desired
+ * @return mixed group id
+ */
+ protected function _getGroupID($group) {
+ if($this->dbcon) {
+ $sql = str_replace('%{group}', $this->_escape($group), $this->getConf('getGroupID'));
+ $result = $this->_queryDB($sql);
+ return $result === false ? false : $result[0]['id'];
+ }
+ return false;
+ }
+
+ /**
+ * Opens a connection to a database and saves the handle for further
+ * usage in the object. The successful call to this functions is
+ * essential for most functions in this object.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @return bool
+ */
+ protected function _openDB() {
+ if(!$this->dbcon) {
+ $con = @mysql_connect($this->getConf('server'), $this->getConf('user'), $this->getConf('password'));
+ if($con) {
+ if((mysql_select_db($this->getConf('database'), $con))) {
+ if((preg_match('/^(\d+)\.(\d+)\.(\d+).*/', mysql_get_server_info($con), $result)) == 1) {
+ $this->dbver = $result[1];
+ $this->dbrev = $result[2];
+ $this->dbsub = $result[3];
+ }
+ $this->dbcon = $con;
+ if($this->getConf('charset')) {
+ mysql_query('SET CHARACTER SET "'.$this->getConf('charset').'"', $con);
+ }
+ return true; // connection and database successfully opened
+ } else {
+ mysql_close($con);
+ $this->_debug("MySQL err: No access to database {$this->getConf('database')}.", -1, __LINE__, __FILE__);
+ }
+ } else {
+ $this->_debug(
+ "MySQL err: Connection to {$this->getConf('user')}@{$this->getConf('server')} not possible.",
+ -1, __LINE__, __FILE__
+ );
+ }
+
+ return false; // connection failed
+ }
+ return true; // connection already open
+ }
+
+ /**
+ * Closes a database connection.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ */
+ protected function _closeDB() {
+ if($this->dbcon) {
+ mysql_close($this->dbcon);
+ $this->dbcon = 0;
+ }
+ }
+
+ /**
+ * Sends a SQL query to the database and transforms the result into
+ * an associative array.
+ *
+ * This function is only able to handle queries that returns a
+ * table such as SELECT.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $query SQL string that contains the query
+ * @return array with the result table
+ */
+ protected function _queryDB($query) {
+ if($this->getConf('debug') >= 2) {
+ msg('MySQL query: '.hsc($query), 0, __LINE__, __FILE__);
+ }
+
+ $resultarray = array();
+ if($this->dbcon) {
+ $result = @mysql_query($query, $this->dbcon);
+ if($result) {
+ while(($t = mysql_fetch_assoc($result)) !== false)
+ $resultarray[] = $t;
+ mysql_free_result($result);
+ return $resultarray;
+ }
+ $this->_debug('MySQL err: '.mysql_error($this->dbcon), -1, __LINE__, __FILE__);
+ }
+ return false;
+ }
+
+ /**
+ * Sends a SQL query to the database
+ *
+ * This function is only able to handle queries that returns
+ * either nothing or an id value such as INPUT, DELETE, UPDATE, etc.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $query SQL string that contains the query
+ * @return int|bool insert id or 0, false on error
+ */
+ protected function _modifyDB($query) {
+ if($this->getConf('debug') >= 2) {
+ msg('MySQL query: '.hsc($query), 0, __LINE__, __FILE__);
+ }
+
+ if($this->dbcon) {
+ $result = @mysql_query($query, $this->dbcon);
+ if($result) {
+ $rc = mysql_insert_id($this->dbcon); //give back ID on insert
+ if($rc !== false) return $rc;
+ }
+ $this->_debug('MySQL err: '.mysql_error($this->dbcon), -1, __LINE__, __FILE__);
+ }
+ return false;
+ }
+
+ /**
+ * Locked a list of tables for exclusive access so that modifications
+ * to the database can't be disturbed by other threads. The list
+ * could be set with $conf['plugin']['authmysql']['TablesToLock'] = array()
+ *
+ * If aliases for tables are used in SQL statements, also this aliases
+ * must be locked. For eg. you use a table 'user' and the alias 'u' in
+ * some sql queries, the array must looks like this (order is important):
+ * array("user", "user AS u");
+ *
+ * MySQL V3 is not able to handle transactions with COMMIT/ROLLBACK
+ * so that this functionality is simulated by this function. Nevertheless
+ * it is not as powerful as transactions, it is a good compromise in safty.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $mode could be 'READ' or 'WRITE'
+ * @return bool
+ */
+ protected function _lockTables($mode) {
+ if($this->dbcon) {
+ $ttl = $this->getConf('TablesToLock');
+ if(is_array($ttl) && !empty($ttl)) {
+ if($mode == "READ" || $mode == "WRITE") {
+ $sql = "LOCK TABLES ";
+ $cnt = 0;
+ foreach($ttl as $table) {
+ if($cnt++ != 0) $sql .= ", ";
+ $sql .= "$table $mode";
+ }
+ $this->_modifyDB($sql);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Unlock locked tables. All existing locks of this thread will be
+ * abrogated.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ */
+ protected function _unlockTables() {
+ if($this->dbcon) {
+ $this->_modifyDB("UNLOCK TABLES");
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Transforms the filter settings in an filter string for a SQL database
+ * The database connection must already be established, otherwise the
+ * original SQL string without filter criteria will be returned.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $sql SQL string to which the $filter criteria should be added
+ * @param array $filter array of filter criteria as pairs of item and pattern
+ * @return string SQL string with attached $filter criteria on success, original SQL string on error
+ */
+ protected function _createSQLFilter($sql, $filter) {
+ $SQLfilter = "";
+ $cnt = 0;
+
+ if($this->dbcon) {
+ foreach($filter as $item => $pattern) {
+ $tmp = '%'.$this->_escape($pattern).'%';
+ if($item == 'user') {
+ if($cnt++ > 0) $SQLfilter .= " AND ";
+ $SQLfilter .= str_replace('%{user}', $tmp, $this->getConf('FilterLogin'));
+ } else if($item == 'name') {
+ if($cnt++ > 0) $SQLfilter .= " AND ";
+ $SQLfilter .= str_replace('%{name}', $tmp, $this->getConf('FilterName'));
+ } else if($item == 'mail') {
+ if($cnt++ > 0) $SQLfilter .= " AND ";
+ $SQLfilter .= str_replace('%{email}', $tmp, $this->getConf('FilterEmail'));
+ } else if($item == 'grps') {
+ if($cnt++ > 0) $SQLfilter .= " AND ";
+ $SQLfilter .= str_replace('%{group}', $tmp, $this->getConf('FilterGroup'));
+ }
+ }
+
+ // we have to check SQLfilter here and must not use $cnt because if
+ // any of cnf['Filter????'] is not defined, a malformed SQL string
+ // would be generated.
+
+ if(strlen($SQLfilter)) {
+ $glue = strpos(strtolower($sql), "where") ? " AND " : " WHERE ";
+ $sql = $sql.$glue.$SQLfilter;
+ }
+ }
+
+ return $sql;
+ }
+
+ /**
+ * Escape a string for insertion into the database
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ * @param string $string The string to escape
+ * @param boolean $like Escape wildcard chars as well?
+ * @return string
+ */
+ protected function _escape($string, $like = false) {
+ if($this->dbcon) {
+ $string = mysql_real_escape_string($string, $this->dbcon);
+ } else {
+ $string = addslashes($string);
+ }
+ if($like) {
+ $string = addcslashes($string, '%_');
+ }
+ return $string;
+ }
+
+ /**
+ * Wrapper around msg() but outputs only when debug is enabled
+ *
+ * @param string $message
+ * @param int $err
+ * @param int $line
+ * @param string $file
+ * @return void
+ */
+ protected function _debug($message, $err, $line, $file) {
+ if(!$this->getConf('debug')) return;
+ msg($message, $err, $line, $file);
+ }
+}
diff --git a/lib/plugins/authmysql/conf/default.php b/lib/plugins/authmysql/conf/default.php
new file mode 100644
index 000000000..427bea273
--- /dev/null
+++ b/lib/plugins/authmysql/conf/default.php
@@ -0,0 +1,34 @@
+<?php
+
+$conf['charset'] = 'utf8';
+$conf['server'] = '';
+$conf['user'] = '';
+$conf['password'] = '';
+$conf['database'] = '';
+$conf['debug'] = 0;
+$conf['forwardClearPass'] = 0;
+$conf['TablesToLock'] = array();
+$conf['checkPass'] = '';
+$conf['getUserInfo'] = '';
+$conf['getGroups'] = '';
+$conf['getUsers'] = '';
+$conf['FilterLogin'] = '';
+$conf['FilterName'] = '';
+$conf['FilterEmail'] = '';
+$conf['FilterGroup'] = '';
+$conf['SortOrder'] = '';
+$conf['addUser'] = '';
+$conf['addGroup'] = '';
+$conf['addUserGroup'] = '';
+$conf['delGroup'] = '';
+$conf['getUserID'] = '';
+$conf['delUser'] = '';
+$conf['delUserRefs'] = '';
+$conf['updateUser'] = '';
+$conf['UpdateLogin'] = '';
+$conf['UpdatePass'] = '';
+$conf['UpdateEmail'] = '';
+$conf['UpdateName'] = '';
+$conf['UpdateTarget'] = '';
+$conf['delUserGroup'] = '';
+$conf['getGroupID'] = ''; \ No newline at end of file
diff --git a/lib/plugins/authmysql/conf/metadata.php b/lib/plugins/authmysql/conf/metadata.php
new file mode 100644
index 000000000..05d150fdf
--- /dev/null
+++ b/lib/plugins/authmysql/conf/metadata.php
@@ -0,0 +1,34 @@
+<?php
+
+$meta['server'] = array('string');
+$meta['user'] = array('string');
+$meta['password'] = array('password');
+$meta['database'] = array('string');
+$meta['charset'] = array('string');
+$meta['debug'] = array('multichoice','_choices' => array(0,1,2));
+$meta['forwardClearPass'] = array('onoff');
+$meta['TablesToLock'] = array('array');
+$meta['checkPass'] = array('');
+$meta['getUserInfo'] = array('');
+$meta['getGroups'] = array('');
+$meta['getUsers'] = array('');
+$meta['FilterLogin'] = array('string');
+$meta['FilterName'] = array('string');
+$meta['FilterEmail'] = array('string');
+$meta['FilterGroup'] = array('string');
+$meta['SortOrder'] = array('string');
+$meta['addUser'] = array('');
+$meta['addGroup'] = array('');
+$meta['addUserGroup'] = array('');
+$meta['delGroup'] = array('');
+$meta['getUserID'] = array('');
+$meta['delUser'] = array('');
+$meta['delUserRefs'] = array('');
+$meta['updateUser'] = array('string');
+$meta['UpdateLogin'] = array('string');
+$meta['UpdatePass'] = array('string');
+$meta['UpdateEmail'] = array('string');
+$meta['UpdateName'] = array('string');
+$meta['UpdateTarget'] = array('string');
+$meta['delUserGroup'] = array('');
+$meta['getGroupID'] = array(''); \ No newline at end of file
diff --git a/lib/plugins/authmysql/lang/bg/settings.php b/lib/plugins/authmysql/lang/bg/settings.php
new file mode 100644
index 000000000..fcc7f625d
--- /dev/null
+++ b/lib/plugins/authmysql/lang/bg/settings.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Bulgarian language file
+ *
+ * @author Kiril <neohidra@gmail.com>
+ */
+$lang['server'] = 'Вашият MySQL сървър';
+$lang['user'] = 'MySQL потребителско име';
+$lang['password'] = 'Парола за горния потребител';
+$lang['database'] = 'Име на базата от данни';
+$lang['charset'] = 'Набор от знаци, който се ползва в базата от данни';
+$lang['debug'] = 'Показване на допълнителна debug информация';
+
+
+$lang['debug_o_0'] = 'не';
+$lang['debug_o_1'] = 'само при грешка';
+$lang['debug_o_2'] = 'за всяко SQL запитване'; \ No newline at end of file
diff --git a/lib/plugins/authmysql/lang/cs/settings.php b/lib/plugins/authmysql/lang/cs/settings.php
new file mode 100644
index 000000000..7fedefbbb
--- /dev/null
+++ b/lib/plugins/authmysql/lang/cs/settings.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Czech language file
+ *
+ * @author mkucera66@seznam.cz
+ */
+$lang['server'] = 'Váš server MySQL';
+$lang['user'] = 'Uživatelské jméno pro MySQL';
+$lang['password'] = 'Heslo tohoto uživatele';
+$lang['database'] = 'Použtá databáze';
+$lang['charset'] = 'znaková sada použitá v databázi';
+$lang['debug'] = 'Zobrazit dodatečné debugovací informace';
+$lang['forwardClearPass'] = 'Posílat uživatelské heslo jako čistý text do příkazů SQL namísto využití volby passcrypt.';
+$lang['TablesToLock'] = 'Čárkou oddělený seznam tabulek, které mohou být zamčené během operací zápisu';
+$lang['checkPass'] = 'Příkaz SQL pro kontrolu hesel';
+$lang['getUserInfo'] = 'Příkaz SQL pro získání informací o uživateli';
+$lang['getGroups'] = 'Příkaz SQL pro získání uživatelovy skupiny';
+$lang['getUsers'] = 'Příkaz SQL pro seznam všech uživatelů';
+$lang['FilterLogin'] = 'Příkaz SQL pro filtrování uživatelů podle přihlašovacího jména';
+$lang['FilterName'] = 'Příkaz SQL pro filtrování uživatelů podle celého jména';
+$lang['FilterEmail'] = 'Příkaz SQL pro filtrování uživatelů podle adres emailů';
+$lang['FilterGroup'] = 'Příkaz SQL pro filtrování uživatelů podle členství ve skupinách';
+$lang['SortOrder'] = 'Příkaz SQL pro řazení uživatelů';
+$lang['addUser'] = 'Příkaz SQL pro přidání nového uživatele';
+$lang['addGroup'] = 'Příkaz SQL pro přidání nové skupiny';
+$lang['addUserGroup'] = 'Příkaz SQL pro přidání uživatele do existující skupiny';
+$lang['delGroup'] = 'Příkaz SQL pro vymazání skupiny';
+$lang['getUserID'] = 'Příkaz SQL pro získání primárního klíče uživatele';
+$lang['delUser'] = 'Příkaz SQL pro vymazání uživatele';
+$lang['delUserRefs'] = 'Příkaz SQL pro odstranění členství uživatele se všech skupin';
+$lang['updateUser'] = 'Příkaz SQL pro aktualizaci uživatelského profilu';
+$lang['UpdateLogin'] = 'Klauzule pro aktualizaci přihlačovacího jména uživatele';
+$lang['UpdatePass'] = 'Klauzule pro aktualizaci hesla uživatele';
+$lang['UpdateEmail'] = 'Klauzule pro aktualizaci emailové adresy uživatele';
+$lang['UpdateName'] = 'Klauzule pro aktualizaci celého jména uživatele';
+$lang['UpdateTarget'] = 'Omezující klauzule pro identifikaci uživatele při aktualizaci';
+$lang['delUserGroup'] = 'Příkaz SQL pro zrušení členství uživatele v dané skupině';
+$lang['getGroupID'] = 'Příkaz SQL pro získání primárního klíče skupiny';
+$lang['debug_o_0'] = 'nic';
+$lang['debug_o_1'] = 'pouze při chybách';
+$lang['debug_o_2'] = 'všechny dotazy SQL';
diff --git a/lib/plugins/authmysql/lang/de-informal/settings.php b/lib/plugins/authmysql/lang/de-informal/settings.php
new file mode 100644
index 000000000..540979cf4
--- /dev/null
+++ b/lib/plugins/authmysql/lang/de-informal/settings.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * German informal language file
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Matthias Schulte <dokuwiki@lupo49.de>
+ * @author Volker Bödker <volker@boedker.de>
+ */
+$lang['server'] = 'MySQL-Server';
+$lang['user'] = 'Benutzername für den Zugriff auf den MySQL-Server.';
+$lang['password'] = 'Passwort des angegebenen Benutzers.';
+$lang['database'] = 'Zu verwendende Datenbank.';
+$lang['charset'] = 'Verwendetes Character-Set in der Datenbank.';
+$lang['debug'] = 'Debug-Informationen anzeigen?';
+$lang['forwardClearPass'] = 'Passwort der DokuWiki-Benutzer im Klartext an die Datenbank übergeben? (Im Normalfall wird die passcrypt-Option angewendet.)';
+$lang['TablesToLock'] = 'Eine Komma-separierte Liste von Tabellen, die vor Schreiboperationen gesperrt werden müssen.';
+$lang['checkPass'] = 'SQL-Kommando zum Überprüfen von Passwörtern.';
+$lang['getUserInfo'] = 'SQL-Kommando um Benutzerinformationen auszulesen.';
+$lang['getGroups'] = 'SQL-Kommando um Gruppen eines Benutzers auszulesen.';
+$lang['getUsers'] = 'SQL-Kommando um alle Benutzer auszulesen.';
+$lang['FilterLogin'] = 'SQL-Bedingung um Benutzer anhand ihres Anmeldenamens zu filtern.';
+$lang['FilterName'] = 'SQL-Bedingung um Benutzer anhand ihres Namens zu filtern.';
+$lang['FilterEmail'] = 'SQL-Bedingung um Benutzer anhand ihrer E-Mail-Adresse zu filtern.';
+$lang['FilterGroup'] = 'SQL-Bedingung um Benutzer anhand ihrer Gruppenzugehörigkeit zu filtern.';
+$lang['SortOrder'] = 'SQL-Bedingung um anhand der die Benutzerliste sortiert wird.';
+$lang['addUser'] = 'SQL-Kommando um einen neuen Benutzer anzulegen.';
+$lang['addGroup'] = 'SQL-Kommando um eine neue Gruppe anzulegen.';
+$lang['addUserGroup'] = 'SQL-Kommando um einen Benutzer zu einer Gruppe hinzuzufügen.';
+$lang['delGroup'] = 'SQL-Kommando um eine Gruppe zu löschen.';
+$lang['getUserID'] = 'SQL-Kommando um den Primärschlüssel des Benutzers auszulesen.';
+$lang['delUser'] = 'SQL-Kommando um einen Benutzer zu löschen.';
+$lang['delUserRefs'] = 'SQL-Kommando um einen Benutzer aus allen Gruppen zu entfernen.';
+$lang['updateUser'] = 'SQL-Kommando um das Profil eines Benutzers zu aktualisieren.';
+$lang['UpdateLogin'] = 'SQL-Bedingung um den Anmeldenamen eines Benutzers zu ändern.';
+$lang['UpdatePass'] = 'SQL-Bedingung um das Passwort eines Benutzers zu ändern.';
+$lang['UpdateEmail'] = 'SQL-Bedingung um die E-Mail-Adresse eines Benutzers zu ändern.';
+$lang['UpdateName'] = 'SQL-Bedingung um den Namen eines Benutzers zu ändern.';
+$lang['UpdateTarget'] = 'SQL-Bedingung zur eindeutigen Identifikation des Benutzers.';
+$lang['delUserGroup'] = 'SQL-Kommando um einen Benutzer aus einer angegeben Gruppe zu entfernen.';
+$lang['getGroupID'] = 'SQL-Kommando um den Primärschlüssel einer Gruppe auszulesen.';
+$lang['debug_o_0'] = 'Keine.';
+$lang['debug_o_1'] = 'Nur Fehler.';
+$lang['debug_o_2'] = 'Alle SQL-Abfragen.';
diff --git a/lib/plugins/authmysql/lang/de/settings.php b/lib/plugins/authmysql/lang/de/settings.php
new file mode 100644
index 000000000..97ba06a9d
--- /dev/null
+++ b/lib/plugins/authmysql/lang/de/settings.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * German language file
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Matthias Schulte <dokuwiki@lupo49.de>
+ */
+$lang['server'] = 'MySQL-Server';
+$lang['user'] = 'Benutzername für den Zugriff auf den MySQL-Server.';
+$lang['password'] = 'Passwort des angegebenen Benutzers.';
+$lang['database'] = 'Zu verwendende Datenbank.';
+$lang['charset'] = 'Verwendetes Character-Set in der Datenbank.';
+$lang['debug'] = 'Debug-Informationen anzeigen?';
+$lang['forwardClearPass'] = 'Passwort der DokuWiki-Benutzer im Klartext an die Datenbank übergeben? (Im Normalfall wird die passcrypt-Option angewendet.)';
+$lang['TablesToLock'] = 'Eine Komma-separierte Liste von Tabellen, die vor Schreiboperationen gesperrt werden müssen.';
+$lang['checkPass'] = 'SQL-Kommando zum Überprüfen von Passwörtern.';
+$lang['getUserInfo'] = 'SQL-Kommando um Benutzerinformationen auszulesen.';
+$lang['getGroups'] = 'SQL-Kommando um Gruppen eines Benutzers auszulesen.';
+$lang['getUsers'] = 'SQL-Kommando um alle Benutzer auszulesen.';
+$lang['FilterLogin'] = 'SQL-Bedingung um Benutzer anhand ihres Anmeldenamens zu filtern.';
+$lang['FilterName'] = 'SQL-Bedingung um Benutzer anhand ihres Namens zu filtern.';
+$lang['FilterEmail'] = 'SQL-Bedingung um Benutzer anhand ihrer E-Mail-Adresse zu filtern.';
+$lang['FilterGroup'] = 'SQL-Bedingung um Benutzer anhand ihrer Gruppenzugehörigkeit zu filtern.';
+$lang['SortOrder'] = 'SQL-Bedingung um anhand der die Benutzerliste sortiert wird.';
+$lang['addUser'] = 'SQL-Kommando um einen neuen Benutzer anzulegen.';
+$lang['addGroup'] = 'SQL-Kommando um eine neue Gruppe anzulegen.';
+$lang['addUserGroup'] = 'SQL-Kommando um einen Benutzer zu einer Gruppe hinzuzufügen.';
+$lang['delGroup'] = 'SQL-Kommando um eine Gruppe zu löschen.';
+$lang['getUserID'] = 'SQL-Kommando um den Primärschlüssel des Benutzers auszulesen.';
+$lang['delUser'] = 'SQL-Kommando um einen Benutzer zu löschen.';
+$lang['delUserRefs'] = 'SQL-Kommando um einen Benutzer aus allen Gruppen zu entfernen.';
+$lang['updateUser'] = 'SQL-Kommando um das Profil eines Benutzers zu aktualisieren.';
+$lang['UpdateLogin'] = 'SQL-Bedingung um den Anmeldenamen eines Benutzers zu ändern.';
+$lang['UpdatePass'] = 'SQL-Bedingung um das Passwort eines Benutzers zu ändern.';
+$lang['UpdateEmail'] = 'SQL-Bedingung um die E-Mail-Adresse eines Benutzers zu ändern.';
+$lang['UpdateName'] = 'SQL-Bedingung um den Namen eines Benutzers zu ändern.';
+$lang['UpdateTarget'] = 'SQL-Bedingung zur eindeutigen Identifikation des Benutzers.';
+$lang['delUserGroup'] = 'SQL-Kommando um einen Benutzer aus einer angegeben Gruppe zu entfernen.';
+$lang['getGroupID'] = 'SQL-Kommando um den Primärschlüssel einer Gruppe auszulesen.';
+$lang['debug_o_0'] = 'Keine.';
+$lang['debug_o_1'] = 'Nur Fehler.';
+$lang['debug_o_2'] = 'Alle SQL-Abfragen.';
diff --git a/lib/plugins/authmysql/lang/en/settings.php b/lib/plugins/authmysql/lang/en/settings.php
new file mode 100644
index 000000000..77e4806b9
--- /dev/null
+++ b/lib/plugins/authmysql/lang/en/settings.php
@@ -0,0 +1,39 @@
+<?php
+
+$lang['server'] = 'Your MySQL server';
+$lang['user'] = 'MySQL user name';
+$lang['password'] = 'Password for above user';
+$lang['database'] = 'Database to use';
+$lang['charset'] = 'Character set used in database';
+$lang['debug'] = 'Display additional debug information';
+$lang['forwardClearPass'] = 'Pass user passwords as cleartext to the SQL statements below, instead of using the passcrypt option';
+$lang['TablesToLock'] = 'Comma separated list of tables that should be locked on write operations';
+$lang['checkPass'] = 'SQL statement for checking passwords';
+$lang['getUserInfo'] = 'SQL statement for retrieving user information';
+$lang['getGroups'] = 'SQL statement for retrieving a user\'s group memberships';
+$lang['getUsers'] = 'SQL statement to list all users';
+$lang['FilterLogin'] = 'SQL clause for filtering users by login name';
+$lang['FilterName'] = 'SQL clause for filtering users by full name';
+$lang['FilterEmail'] = 'SQL clause for filtering users by email address';
+$lang['FilterGroup'] = 'SQL clause for filtering users by group membership';
+$lang['SortOrder'] = 'SQL clause to sort users';
+$lang['addUser'] = 'SQL statement to add a new user';
+$lang['addGroup'] = 'SQL statement to add a new group';
+$lang['addUserGroup'] = 'SQL statment to add a user to an existing group';
+$lang['delGroup'] = 'SQL statement to remove a group';
+$lang['getUserID'] = 'SQL statement to get the primary key of a user';
+$lang['delUser'] = 'SQL statement to delete a user';
+$lang['delUserRefs'] = 'SQL statement to remove a user from all groups';
+$lang['updateUser'] = 'SQL statement to update a user profile';
+$lang['UpdateLogin'] = 'Update clause for updating the user\'s login name';
+$lang['UpdatePass'] = 'Update clause for updating the user\'s password';
+$lang['UpdateEmail'] = 'Update clause for updating the user\'s email address';
+$lang['UpdateName'] = 'Update clause for updating the user\'s full name';
+$lang['UpdateTarget'] = 'Limit clause to identify the user when updating';
+$lang['delUserGroup'] = 'SQL statement to remove a user from a given group';
+$lang['getGroupID'] = 'SQL statement to get the primary key of a given group';
+
+
+$lang['debug_o_0'] = 'none';
+$lang['debug_o_1'] = 'on errors only';
+$lang['debug_o_2'] = 'all SQL queries'; \ No newline at end of file
diff --git a/lib/plugins/authmysql/lang/eo/settings.php b/lib/plugins/authmysql/lang/eo/settings.php
new file mode 100644
index 000000000..907c761f8
--- /dev/null
+++ b/lib/plugins/authmysql/lang/eo/settings.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Esperanto language file
+ *
+ */
+$lang['server'] = 'Via MySQL-servilo';
+$lang['user'] = 'MySQL uzantonomo';
+$lang['password'] = 'Pasvorto por tiu uzanto';
+$lang['database'] = 'Uzenda datumbazo';
+$lang['charset'] = 'Uzata tiparo en la datumbazo';
+$lang['debug'] = 'Ĉu montri aldonajn erarinformojn?';
+$lang['forwardClearPass'] = 'Ĉu transdoni pasvortojn klartekste al la SQL-frazoj sube anstataŭ uzi pasvortan kaŝon';
+$lang['TablesToLock'] = 'Komodisigita listo de tabeloj, al kiuj ne eblu skribi';
+$lang['checkPass'] = 'SQL-frazo por testi pasvortojn';
+$lang['getUserInfo'] = 'SQL-frazo por ricevi uzantajn informojn';
+$lang['getGroups'] = 'SQL-frazo por ricevi la grupmembrecojn de uzanto';
+$lang['getUsers'] = 'SQL-frazo por listigi ĉiujn uzantojn';
+$lang['FilterLogin'] = 'SQL-frazo por filtri uzantojn je ensaluta nomo';
+$lang['FilterName'] = 'SQL-frazo por filtri uzantojn je plena nomo';
+$lang['FilterEmail'] = 'SQL-frazo por filtri uzantojn je retpoŝtadreso';
+$lang['FilterGroup'] = 'SQL-frazo por filtri uzantojn je grupmembreco';
+$lang['SortOrder'] = 'SQL-frazo por ordigi uzantojn';
+$lang['addUser'] = 'SQL-frazo por aldoni novan uzanton';
+$lang['addGroup'] = 'SQL-frazo por aldoni novan grupon';
+$lang['addUserGroup'] = 'SQL-frazo por aldoni uzanton al ekzistanta grupo';
+$lang['delGroup'] = 'SQL-frazo por forigi grupon';
+$lang['getUserID'] = 'SQL-frazo por ricevi la ĉefan ŝlosilon de uzanto';
+$lang['delUser'] = 'SQL-frazo por forigi uzanton';
+$lang['delUserRefs'] = 'SQL-frazo por forigi uzanton el ĉiuj grupoj';
+$lang['updateUser'] = 'SQL-frazo por aktualigi uzantan profilon';
+$lang['UpdateLogin'] = 'Aktualiga frazo por uzanta ensalutnomo';
+$lang['UpdatePass'] = 'Aktualiga frazo por uzanta pasvorto';
+$lang['UpdateEmail'] = 'Aktualiga frazo por uzanta retpoŝtadreso';
+$lang['UpdateName'] = 'Aktualiga frazo por plena uzanta nomo';
+$lang['UpdateTarget'] = 'Limiga frazo por identigi la uzanton dum aktualigado';
+$lang['delUserGroup'] = 'SQL-frazo por forigi uzanton el indikita grupo';
+$lang['getGroupID'] = 'SQL-frazo por ricevi la ĉefan ŝlosilon de indikita grupo';
+$lang['debug_o_0'] = 'neniu';
+$lang['debug_o_1'] = 'nur dum eraroj';
+$lang['debug_o_2'] = 'ĉiuj SQL-serĉoj';
diff --git a/lib/plugins/authmysql/lang/fi/settings.php b/lib/plugins/authmysql/lang/fi/settings.php
new file mode 100644
index 000000000..d3aa13e07
--- /dev/null
+++ b/lib/plugins/authmysql/lang/fi/settings.php
@@ -0,0 +1,6 @@
+<?php
+/**
+ * Finnish language file
+ *
+ * @author Otto Vainio <otto@valjakko.net>
+ */
diff --git a/lib/plugins/authmysql/lang/fr/settings.php b/lib/plugins/authmysql/lang/fr/settings.php
new file mode 100644
index 000000000..dfb79b545
--- /dev/null
+++ b/lib/plugins/authmysql/lang/fr/settings.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * French language file
+ *
+ * @author Bruno Veilleux <bruno.vey@gmail.com>
+ */
+$lang['server'] = 'Votre serveur MySQL';
+$lang['user'] = 'Nom d\'utilisateur MySQL';
+$lang['password'] = 'Mot de passe pour l\'utilisateur ci-dessus';
+$lang['database'] = 'Base de données à utiliser';
+$lang['charset'] = 'Jeu de caractères utilisé dans la base de données';
+$lang['debug'] = 'Afficher des informations de débogage supplémentaires';
+$lang['forwardClearPass'] = 'Passer les mots de passe aux requêtes SQL ci-dessous en cleartext plutôt qu\'avec l\'option passcrypt';
+$lang['TablesToLock'] = 'Liste séparée par des virgules des tables devant être verrouillées par les opérations d\'écriture';
+$lang['checkPass'] = 'Requête SQL pour la vérification des mots de passe';
+$lang['getUserInfo'] = 'Requête SQL pour la récupération des informations d\'un utilisateur';
+$lang['getGroups'] = 'Requête SQL pour la récupération des groupes d\'un utilisateur';
+$lang['getUsers'] = 'Requête SQL pour énumérer tous les utilisateurs';
+$lang['FilterLogin'] = 'Clause SQL pour filtrer les utilisateurs par identifiant';
+$lang['FilterName'] = 'Clause SQL pour filtrer les utilisateurs par nom complet';
+$lang['FilterEmail'] = 'Clause SQL pour filtrer les utilisateurs par adresse électronique';
+$lang['FilterGroup'] = 'Clause SQL pour filtrer les utilisateurs par groupes';
+$lang['SortOrder'] = 'Clause SQL pour trier les utilisateurs';
+$lang['addUser'] = 'Requête SQL pour ajouter un nouvel utilisateur';
+$lang['addGroup'] = 'Requête SQL pour ajouter un nouveau groupe';
+$lang['addUserGroup'] = 'Requête SQL pour ajouter un utilisateur à un groupe existant';
+$lang['delGroup'] = 'Requête SQL pour retirer un groupe';
+$lang['getUserID'] = 'Requête SQL pour obtenir la clé primaire d\'un utilisateur';
+$lang['delUser'] = 'Requête SQL pour supprimer un utilisateur';
+$lang['delUserRefs'] = 'Requête SQL pour retirer un utilisateur de tous les groupes';
+$lang['updateUser'] = 'Requête SQL pour mettre à jour le profil d\'un utilisateur';
+$lang['UpdateLogin'] = 'Clause de mise à jour pour mettre à jour l\'identifiant d\'un utilisateur';
+$lang['UpdatePass'] = 'Clause de mise à jour pour mettre à jour le mot de passe d\'un utilisateur';
+$lang['UpdateEmail'] = 'Clause de mise à jour pour mettre à jour l\'adresse électronique d\'un utilisateur';
+$lang['UpdateName'] = 'Clause de mise à jour pour mettre à jour le nom complet d\'un utilisateur';
+$lang['UpdateTarget'] = 'Clause de limite pour identifier l\'utilisateur durant une mise à jour';
+$lang['delUserGroup'] = 'Requête SQL pour retirer un utilisateur d\'un groupe donné';
+$lang['getGroupID'] = 'Requête SQL pour obtenir la clé primaire d\'un groupe donné';
+$lang['debug_o_0'] = 'aucun';
+$lang['debug_o_1'] = 'sur erreur seulement';
+$lang['debug_o_2'] = 'toutes les requêtes SQL';
diff --git a/lib/plugins/authmysql/lang/it/settings.php b/lib/plugins/authmysql/lang/it/settings.php
new file mode 100644
index 000000000..10ae72f87
--- /dev/null
+++ b/lib/plugins/authmysql/lang/it/settings.php
@@ -0,0 +1,5 @@
+<?php
+/**
+ * Italian language file
+ *
+ */
diff --git a/lib/plugins/authmysql/lang/ja/settings.php b/lib/plugins/authmysql/lang/ja/settings.php
new file mode 100644
index 000000000..45f938fec
--- /dev/null
+++ b/lib/plugins/authmysql/lang/ja/settings.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Japanese language file
+ *
+ * @author Satoshi Sahara <sahara.satoshi@gmail.com>
+ */
+$lang['server'] = 'MySQL のホスト名';
+$lang['user'] = 'MySQL 接続用ユーザー名';
+$lang['password'] = 'MySQL 接続用ユーザーのパスワード';
+$lang['database'] = '使用するデータベース名';
+$lang['charset'] = 'データベースの文字コード';
+$lang['debug'] = 'デバック情報を表示する';
+$lang['forwardClearPass'] = '以下で定義する SQL ステートメントにおいて, パスワード変数 %{pass} を平文とする(DokiWiki側で暗号化しない)';
+$lang['TablesToLock'] = '書き込み時にロックするテーブル(コンマ区切りで列挙)';
+$lang['checkPass'] = 'パスワードの照合に用いる SQL ステートメント';
+$lang['getUserInfo'] = 'ユーザー情報の取得に用いる SQL ステートメント';
+$lang['getGroups'] = 'ユーザーが所属する全てのグループの取得に用いる SQL ステートメント';
+$lang['getUsers'] = 'ユーザーリストを取得する SQL ステートメント';
+$lang['FilterLogin'] = 'ユーザーリストをログイン名で絞り込む SQL 句';
+$lang['FilterName'] = 'ユーザーリストをフルネームで絞り込む SQL 句';
+$lang['FilterEmail'] = 'ユーザーリストをメールアドレスで絞り込む SQL 句';
+$lang['FilterGroup'] = 'ユーザーリストを所属グループで絞り込む SQL 句';
+$lang['SortOrder'] = 'ユーザーリストのソート方法を指定する SQL 句';
+$lang['addUser'] = '新規ユーザーを追加する SQL ステートメント';
+$lang['addGroup'] = '新規グループを追加する SQL ステートメント';
+$lang['addUserGroup'] = 'ユーザーをグループに配属する SQL ステートメント';
+$lang['delGroup'] = 'グループを削除する SQL ステートメント';
+$lang['getUserID'] = 'ユーザーIDの取得に用いる SQL ステートメント';
+$lang['delUser'] = 'ユーザーを削除する SQL ステートメント';
+$lang['delUserRefs'] = 'ユーザーのグループ所属を全て取り消す SQL ステートメント';
+$lang['updateUser'] = 'ユーザー情報を変更する SQL ステートメント';
+$lang['UpdateLogin'] = '変更後のログイン名を指定する SQL 句';
+$lang['UpdatePass'] = '変更後のパスワードを指定する SQL 句';
+$lang['UpdateEmail'] = '変更後のメールアドレスを指定する SQL 句';
+$lang['UpdateName'] = '変更後のフルネームを指定する SQL 句';
+$lang['UpdateTarget'] = '変更対象のユーザを特定するための SQL 句';
+$lang['delUserGroup'] = 'ユーザーをグループから除名する SQL ステートメント';
+$lang['getGroupID'] = 'グループIDの取得に用いる SQL ステートメント';
+$lang['debug_o_0'] = '表示しない';
+$lang['debug_o_1'] = 'エラー発生時のみ表示';
+$lang['debug_o_2'] = '全ての SQLクエリで表示';
diff --git a/lib/plugins/authmysql/lang/ko/settings.php b/lib/plugins/authmysql/lang/ko/settings.php
new file mode 100644
index 000000000..c5518b8cc
--- /dev/null
+++ b/lib/plugins/authmysql/lang/ko/settings.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Korean language file
+ *
+ * @author Myeongjin <aranet100@gmail.com>
+ */
+$lang['server'] = 'MySQL 서버';
+$lang['user'] = 'MySQL 사용자 이름';
+$lang['password'] = '위 사용자의 비밀번호';
+$lang['database'] = '사용할 데이터베이스';
+$lang['charset'] = '데이터베이스에 사용하는 문자 집합';
+$lang['debug'] = '추가적인 디버그 정보 보이기';
+$lang['forwardClearPass'] = 'passcrypt 옵션을 사용하는 대신 아래 SQL 문에 일반 텍스트로 사용자 비밀번호를 전달';
+$lang['TablesToLock'] = '쓰기 작업에 잠궈야 하는 테이블의 쉼표로 구분한 목록';
+$lang['checkPass'] = '비밀번호를 확인하기 위한 SQL 문';
+$lang['getUserInfo'] = '사용자 정보를 가져오기 위한 SQL 문';
+$lang['getGroups'] = '사용자의 그룹 구성원을 가져오기 위한 SQL 문';
+$lang['getUsers'] = '모든 사용자를 나타낼 SQL 문';
+$lang['FilterLogin'] = '로그인 이름 별로 사용자를 필터하기 위한 SQL 조항';
+$lang['FilterName'] = '전체 이름 별로 사용자를 필터하기 위한 SQL 조항';
+$lang['FilterEmail'] = '이메일 주소 별로 사용자를 필터하기 위한 SQL 조항';
+$lang['FilterGroup'] = '그룹 구성원 별로 사용자를 필터하기 위한 SQL 조항';
+$lang['SortOrder'] = '사용자를 정렬할 SQL 조항';
+$lang['addUser'] = '새 사용자를 추가할 SQL 문';
+$lang['addGroup'] = '새 그룹을 추가할 SQL 문';
+$lang['addUserGroup'] = '기존 그룹에 사용자를 추가할 SQL 문';
+$lang['delGroup'] = '그룹을 제거할 SQL 문';
+$lang['getUserID'] = '사용자의 기본 키를 얻을 SQL 문';
+$lang['delUser'] = '사용자를 삭제할 SQL 문';
+$lang['delUserRefs'] = '모든 그룹에서 사용자를 제거할 SQL 문';
+$lang['updateUser'] = '사용자 프로필을 업데이트할 SQL 문';
+$lang['UpdateLogin'] = '사용자의 로그인 이름을 업데이트하기 위한 Update 조항';
+$lang['UpdatePass'] = '사용자의 비밀번호를 업데이트하기 위한 Update 조항';
+$lang['UpdateEmail'] = '사용자의 이메일 주소를 업데이트하기 위한 Update 조항';
+$lang['UpdateName'] = '사용자의 전체 이름을 업데이트하기 위한 Update 조항';
+$lang['UpdateTarget'] = '업데이트할 때 사용자를 식별할 Limit 조항';
+$lang['delUserGroup'] = '주어진 그룹에서 사용자를 제거할 SQL 문';
+$lang['getGroupID'] = '주어진 그룹의 기본 키를 얻을 SQL 문';
+$lang['debug_o_0'] = '없음';
+$lang['debug_o_1'] = '오류에만';
+$lang['debug_o_2'] = '모든 SQL 쿼리';
diff --git a/lib/plugins/authmysql/lang/lv/settings.php b/lib/plugins/authmysql/lang/lv/settings.php
new file mode 100644
index 000000000..ced5dabf8
--- /dev/null
+++ b/lib/plugins/authmysql/lang/lv/settings.php
@@ -0,0 +1,6 @@
+<?php
+/**
+ * Latvian, Lettish language file
+ *
+ * @author Aivars Miška <allefm@gmail.com>
+ */
diff --git a/lib/plugins/authmysql/lang/nl/settings.php b/lib/plugins/authmysql/lang/nl/settings.php
new file mode 100644
index 000000000..dc85b7eee
--- /dev/null
+++ b/lib/plugins/authmysql/lang/nl/settings.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Dutch language file
+ *
+ */
+$lang['server'] = 'Je MySQL server';
+$lang['user'] = 'MySql gebruikersnaam';
+$lang['password'] = 'Wachtwoord van bovenstaande gebruiker';
+$lang['database'] = 'Te gebruiken database';
+$lang['charset'] = 'Tekenset voor database';
+$lang['debug'] = 'Tonen aanvullende debuginformatie';
+$lang['forwardClearPass'] = 'Wachtwoorden als leesbare tekst in SQL commando\'s opnemen in plaats van versleutelde tekens';
+$lang['TablesToLock'] = 'Commagesepareerde lijst van tabellen die gelocked moeten worden bij schrijfacties';
+$lang['checkPass'] = 'SQL commando voor verifiëren van wachtwoorden';
+$lang['getUserInfo'] = 'SQL commando voor ophalen gebruikersinformatie';
+$lang['getGroups'] = 'SQL commando voor ophalen groepslidmaatschappen';
+$lang['getUsers'] = 'SQL commando voor tonen alle gebruikers';
+$lang['FilterLogin'] = 'SQL clausule voor filteren gebruikers op inlognaam';
+$lang['FilterName'] = 'SQL clausule voor filteren gebruikers op volledige naam';
+$lang['FilterEmail'] = 'SQL clausule voor filteren gebruikers op e-mailadres';
+$lang['FilterGroup'] = 'SQL clausule voor filteren gebruikers op groepslidmaatschap';
+$lang['SortOrder'] = 'SQL clausule voor sorteren gebruikers';
+$lang['addUser'] = 'SQL commando om een gebruiker toe te voegen';
+$lang['addGroup'] = 'SQL commando om een groep toe te voegen';
+$lang['addUserGroup'] = 'SQL commando om een gebruiker aan een groep toe te voegen';
+$lang['delGroup'] = 'SQL commando om een groep te verwijderen';
+$lang['getUserID'] = 'SQL commando om de de primaire sleutel van een gebruiker op te halen';
+$lang['delUser'] = 'SQL commando om een gebruiker te verwijderen';
+$lang['delUserRefs'] = 'SQL commando om een gebruiker uit alle groepen te verwijderen';
+$lang['updateUser'] = 'SQL commando om een gebruikersprofiel bij te werken';
+$lang['UpdateLogin'] = 'Bijwerkcommando om een inlognaam bij te werken';
+$lang['UpdatePass'] = 'Bijwerkcommando om een wachtwoord bij te werken';
+$lang['UpdateEmail'] = 'Bijwerkcommando om een e-mailadres bij te werken';
+$lang['UpdateName'] = 'Bijwerkcommando om een volledige naam te werken';
+$lang['UpdateTarget'] = 'Beperkingsclausule om gebruiker te identificeren voor bijwerken';
+$lang['delUserGroup'] = 'SQL commando om een gebruiker uit een bepaalde te verwijderen';
+$lang['getGroupID'] = 'SQL commando om de primaire sletel van een bepaalde groep op te halen';
+$lang['debug_o_0'] = 'geen';
+$lang['debug_o_1'] = 'alleen bij fouten';
+$lang['debug_o_2'] = 'alle SQL queries';
diff --git a/lib/plugins/authmysql/lang/pt-br/settings.php b/lib/plugins/authmysql/lang/pt-br/settings.php
new file mode 100644
index 000000000..5febedd13
--- /dev/null
+++ b/lib/plugins/authmysql/lang/pt-br/settings.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Brazilian Portuguese language file
+ *
+ * @author Victor Westmann <victor.westmann@gmail.com>
+ */
+$lang['server'] = 'Seu servidor MySQL';
+$lang['user'] = 'usuário MySQL';
+$lang['password'] = 'Senha do usuário acima';
+$lang['database'] = 'Base de dados para usar';
+$lang['charset'] = 'Codificação de caracter usado na base de dados';
+$lang['debug'] = 'Mostrar informações adicionais de depuração';
+$lang['forwardClearPass'] = 'Passar senhas de usuários como texto puro para comandos SQL abaixo, ao invés de usar opção passcrypt';
+$lang['TablesToLock'] = 'Lista separada por vírgulas para tabelas que devem estar travadas em operações de escrita';
+$lang['checkPass'] = 'Comandos SQL para verificar senhas';
+$lang['getUserInfo'] = 'Comando SQL para obter informações de usuário';
+$lang['getGroups'] = 'Comando SQL para obter as credenciais de grupo de um usuário';
+$lang['getUsers'] = 'Comando SQL para listar todos os usuários';
+$lang['FilterLogin'] = 'Comando SQL para filtrar usuários pelo login';
+$lang['FilterName'] = 'Cláusula SQL para filtrar usuários por nome completo';
+$lang['FilterEmail'] = 'Cláusula SQL para filtrar usuários por endereço de email';
+$lang['FilterGroup'] = 'Cláusula SQL para filtrar usuários por membros de grupos';
+$lang['SortOrder'] = 'Cláusula SQL para ordenar usuários';
+$lang['addUser'] = 'Comando SQL para adicionar um novo usuário';
+$lang['addGroup'] = 'Comando SQL para adicionar um novo grupo';
+$lang['addUserGroup'] = 'Comando SQL para adicionar um usuário a um determinado grupo';
+$lang['delGroup'] = 'Comando SQL para remover um grupo';
+$lang['getUserID'] = 'Comando SQL para obter a chave primária de um usuário';
+$lang['delUser'] = 'Comando SQL para apagar um usuário';
+$lang['delUserRefs'] = 'Comando SQL para apagar um usuário de todos os grupos';
+$lang['updateUser'] = 'Comando SQL para atualizar perfil de usuário';
+$lang['UpdateLogin'] = 'Comando SQL para atualizar o login de um usuário';
+$lang['UpdatePass'] = 'Cláusula de atualização para atualizar senha de usuário';
+$lang['UpdateEmail'] = 'Cláusula de atualização para atualizar email do usuário';
+$lang['UpdateName'] = 'Cláusula de atualização para atualizar nome completo do usuário';
+$lang['UpdateTarget'] = 'Limitar cláusula para identificar usuário quando estiver atualizando';
+$lang['delUserGroup'] = 'Comando SQL para remover um usuário de um grupo determinado';
+$lang['getGroupID'] = 'Comando SQL para obter a chave primária de um grupo determinado';
+$lang['debug_o_0'] = 'nenhum';
+$lang['debug_o_1'] = 'apenas em erros';
+$lang['debug_o_2'] = 'todas as queries SQL';
diff --git a/lib/plugins/authmysql/lang/ru/settings.php b/lib/plugins/authmysql/lang/ru/settings.php
new file mode 100644
index 000000000..066598331
--- /dev/null
+++ b/lib/plugins/authmysql/lang/ru/settings.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Russian language file
+ *
+ * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua)
+ */
+$lang['server'] = 'Ваш MySQL-сервер';
+$lang['user'] = 'Имя пользователя MySQL';
+$lang['password'] = 'Пароль пользователя MySQL';
+$lang['database'] = 'Имя базы данных';
+$lang['charset'] = 'Используемый набор символов в базе данных';
+$lang['debug'] = 'Отображение дополнительной отладочной информации';
+$lang['forwardClearPass'] = 'Передача пароля пользователя открытым текстом, вместо зашифрованной формы в используемом выражении SQL';
+$lang['TablesToLock'] = 'Имена таблиц (через запятую), которые необходимо ограничение для записи';
+$lang['checkPass'] = 'Выражение SQL, осуществляющее проверку пароля';
+$lang['getUserInfo'] = 'Выражение SQL, осуществляющее извлечение информации о пользователе';
+$lang['getGroups'] = 'Выражение SQL, осуществляющее извлечение информации о членстве пользователе в группах';
+$lang['getUsers'] = 'Выражение SQL, осуществляющее извлечение полного списка пользователей';
+$lang['FilterLogin'] = 'Выражение SQL, осуществляющее фильтрацию пользователей по пользовательскому имени';
+$lang['FilterName'] = 'Выражение SQL, осуществляющее фильтрацию пользователей по полному имени';
+$lang['FilterEmail'] = 'Выражение SQL, осуществляющее фильтрацию пользователей по адресу электронной почты';
+$lang['FilterGroup'] = 'Выражение SQL, осуществляющее фильтрацию пользователей согласно членству в группе';
+$lang['SortOrder'] = 'Выражение SQL, осуществляющее сортировку пользователей';
+$lang['addUser'] = 'Выражение SQL, осуществляющее добавление нового опльзователя';
+$lang['addGroup'] = 'Выражение SQL, осуществляющее добавление новой группы';
+$lang['addUserGroup'] = 'Выражение SQL, осуществляющее добавление пользователя в существующую группу';
+$lang['delGroup'] = 'Выражение SQL, осуществляющее удаление группы';
+$lang['getUserID'] = 'Выражение SQL, обеспечивающее получение первичного ключа пользователя';
+$lang['delUser'] = 'Выражение SQL, осуществляющее удаление пользователя';
+$lang['delUserRefs'] = 'Выражение SQL, осуществляющее удаление пользователя из всех групп';
+$lang['updateUser'] = 'Выражение SQL, осуществляющее обновление профиля пользователя';
+$lang['UpdateLogin'] = 'Условие для обновления имени пользователя';
+$lang['UpdatePass'] = 'Условие для обновления пароля пользователя';
+$lang['UpdateEmail'] = 'Условие для обновления адреса электронной почты пользователя';
+$lang['UpdateName'] = 'Условие для обновления полного имени пользователя';
+$lang['UpdateTarget'] = 'Условие для идентификации пользователя при обновлении';
+$lang['delUserGroup'] = 'Выражение SQL, осуществляющее удаление пользователя из указанной группы';
+$lang['getGroupID'] = 'Выражение SQL, обеспечивающее получение первичного ключа указанной группы';
+$lang['debug_o_0'] = 'ни один из вариантов';
+$lang['debug_o_1'] = 'только при возникновении ошибок';
+$lang['debug_o_2'] = 'все SQL-запросы';
diff --git a/lib/plugins/authmysql/lang/sv/settings.php b/lib/plugins/authmysql/lang/sv/settings.php
new file mode 100644
index 000000000..027c64025
--- /dev/null
+++ b/lib/plugins/authmysql/lang/sv/settings.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * Swedish language file
+ *
+ * @author Smorkster Andersson smorkster@gmail.com
+ */
+$lang['server'] = 'Din MySQL server';
+$lang['user'] = 'Användarnamn för MySQL';
+$lang['password'] = 'Lösenord för användare ovan';
+$lang['database'] = 'Databas att använda';
+$lang['debug'] = 'Visa ytterligare felsökningsinformation';
+$lang['forwardClearPass'] = 'Skicka användares lösenord i klartext till SQL sats nedan, istället för att använda passcrypt alternativet';
+$lang['checkPass'] = 'SQL sats för kontroll av lösenord';
+$lang['getUserInfo'] = 'SQL sats för att hämta användarinformation';
+$lang['getGroups'] = 'SQL sats för att hämta en användares gruppmedlemskap';
+$lang['getUsers'] = 'SQL sats för att lista alla användare';
+$lang['addUser'] = 'SQL sats för att lägga till en användare';
+$lang['addGroup'] = 'SQL sats för att lägga till en grupp';
+$lang['addUserGroup'] = 'SQL sats för att lägga till en användare i en existerande grupp';
+$lang['delGroup'] = 'SQL sats för att ta bort en grupp';
+$lang['delUser'] = 'SQL sats för att ta bort en användare';
+$lang['delUserRefs'] = 'SQL sats för att ta bort en användare från alla grupper';
+$lang['updateUser'] = 'SQL sats för att uppdatera en användarprofil';
+$lang['delUserGroup'] = 'SQL sats för att ta bort en användare från en angiven grupp';
+$lang['debug_o_0'] = 'ingen';
diff --git a/lib/plugins/authmysql/lang/zh-tw/settings.php b/lib/plugins/authmysql/lang/zh-tw/settings.php
new file mode 100644
index 000000000..95d068150
--- /dev/null
+++ b/lib/plugins/authmysql/lang/zh-tw/settings.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Chinese Traditional language file
+ *
+ * @author syaoranhinata@gmail.com
+ */
+$lang['server'] = '您的 MySQL 伺服器';
+$lang['user'] = 'MySQL 使用者名稱';
+$lang['password'] = '上述使用者的密碼';
+$lang['database'] = '使用的資料庫';
+$lang['charset'] = '資料庫使用的字符集';
+$lang['debug'] = '顯示額外除錯資訊';
+$lang['forwardClearPass'] = '以明文形式,把使用者密碼傳送给下列的 SQL 語句,而不使用 passcrypt 密碼加密選項';
+$lang['TablesToLock'] = '在寫操作時需要鎖定的數據表列表,以逗號分隔';
+$lang['checkPass'] = '檢查密碼的 SQL 語句';
+$lang['getUserInfo'] = '獲取使用者訊息的 SQL 語句';
+$lang['getGroups'] = '獲取使用者群組成員身份的 SQL 語句';
+$lang['getUsers'] = '把所有使用者列出的 SQL 語句';
+$lang['FilterLogin'] = '根據登入名稱來篩選使用者的 SQL 子句';
+$lang['FilterName'] = '根據全名來篩選使用者的 SQL 子句';
+$lang['FilterEmail'] = '根據電郵地址來篩選使用者的 SQL 子句';
+$lang['FilterGroup'] = '根據群組成員身份來篩選使用者的 SQL 子句';
+$lang['SortOrder'] = '對使用者排序的 SQL 子句';
+$lang['addUser'] = '增加新使用者的 SQL 語句';
+$lang['addGroup'] = '增加新群組的 SQL 語句';
+$lang['addUserGroup'] = '把使用者新增至現有群組的 SQL 語句';
+$lang['delGroup'] = '把群組刪除的 SQL 語句';
+$lang['getUserID'] = '取得使用者主鍵的 SQL 語句';
+$lang['delUser'] = '把使用者刪除的 SQL 語句';
+$lang['delUserRefs'] = '把使用者從所有群組裏刪除的 SQL 語句';
+$lang['updateUser'] = '更新使用者訊息的 SQL 語句';
+$lang['UpdateLogin'] = '更新使用者登入名稱的 Update 子句';
+$lang['UpdatePass'] = '更新帳號密碼的 Update 子句';
+$lang['UpdateEmail'] = '更新使用者電郵地址的 Update 子句';
+$lang['UpdateName'] = '更新使用者全名的 Update 子句';
+$lang['UpdateTarget'] = '在更新時識別使用者的 Limit 子句';
+$lang['delUserGroup'] = '把使用者從指定群組中刪除的 SQL 語句';
+$lang['getGroupID'] = '取得指定群組主鍵的 SQL 語句';
+$lang['debug_o_0'] = '無';
+$lang['debug_o_1'] = '僅在有錯誤時';
+$lang['debug_o_2'] = '所有 SQL 查詢';
diff --git a/lib/plugins/authmysql/lang/zh/settings.php b/lib/plugins/authmysql/lang/zh/settings.php
new file mode 100644
index 000000000..772f75ecd
--- /dev/null
+++ b/lib/plugins/authmysql/lang/zh/settings.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Chinese language file
+ *
+ * @author lainme <lainme993@gmail.com>
+ */
+$lang['server'] = '您的 MySQL 服务器';
+$lang['user'] = 'MySQL 用户名';
+$lang['password'] = '上述用户的密码';
+$lang['database'] = '使用的数据库';
+$lang['charset'] = '数据库中使用的字符集';
+$lang['debug'] = '显示额外调试信息';
+$lang['forwardClearPass'] = '将用户密码以明文形式传送给下面的 SQL 语句,而不使用 passcrypt 密码加密选项';
+$lang['TablesToLock'] = '在写操作时需要锁定的数据表列表,以逗号分隔';
+$lang['checkPass'] = '检查密码的 SQL 语句';
+$lang['getUserInfo'] = '获取用户信息的 SQL 语句';
+$lang['getGroups'] = '或许用户的组成员身份的 SQL 语句';
+$lang['getUsers'] = '列出所有用户的 SQL 语句';
+$lang['FilterLogin'] = '根据登录名筛选用户的 SQL 子句';
+$lang['FilterName'] = '根据全名筛选用户的 SQL 子句';
+$lang['FilterEmail'] = '根据电子邮件地址筛选用户的 SQL 子句';
+$lang['FilterGroup'] = '根据组成员身份筛选用户的 SQL 子句';
+$lang['SortOrder'] = '对用户排序的 SQL 子句';
+$lang['addUser'] = '添加新用户的 SQL 语句';
+$lang['addGroup'] = '添加新组的 SQL 语句';
+$lang['addUserGroup'] = '将用户添加到现有组的 SQL 语句';
+$lang['delGroup'] = '删除组的 SQL 语句';
+$lang['getUserID'] = '获取用户主键的 SQL 语句';
+$lang['delUser'] = '删除用户的 SQL 语句';
+$lang['delUserRefs'] = '从所有组中删除一个用户的 SQL 语句';
+$lang['updateUser'] = '更新用户信息的 SQL 语句';
+$lang['UpdateLogin'] = '更新用户登录名的 Update 子句';
+$lang['UpdatePass'] = '更新用户密码的 Update 子句';
+$lang['UpdateEmail'] = '更新用户电子邮件地址的 Update 子句';
+$lang['UpdateName'] = '更新用户全名的 Update 子句';
+$lang['UpdateTarget'] = '更新时识别用户的 Limit 子句';
+$lang['delUserGroup'] = '从指定组删除用户的 SQL 语句';
+$lang['getGroupID'] = '获取指定组主键的 SQL 语句';
+$lang['debug_o_0'] = '无';
+$lang['debug_o_1'] = '仅在有错误时';
+$lang['debug_o_2'] = '所有 SQL 查询';
diff --git a/lib/plugins/authmysql/plugin.info.txt b/lib/plugins/authmysql/plugin.info.txt
new file mode 100644
index 000000000..16fe27e74
--- /dev/null
+++ b/lib/plugins/authmysql/plugin.info.txt
@@ -0,0 +1,7 @@
+base authmysql
+author Andreas Gohr
+email andi@splitbrain.org
+date 2013-02-16
+name mysql auth plugin
+desc Provides authentication against a MySQL Server
+url http://www.dokuwiki.org/plugin:authmysql
diff --git a/lib/plugins/authpgsql/auth.php b/lib/plugins/authpgsql/auth.php
new file mode 100644
index 000000000..3f8ff3249
--- /dev/null
+++ b/lib/plugins/authpgsql/auth.php
@@ -0,0 +1,418 @@
+<?php
+// must be run within Dokuwiki
+if(!defined('DOKU_INC')) die();
+
+/**
+ * PostgreSQL authentication backend
+ *
+ * This class inherits much functionality from the MySQL class
+ * and just reimplements the Postgres specific parts.
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @author Matthias Grimm <matthias.grimmm@sourceforge.net>
+ * @author Jan Schumann <js@schumann-it.com>
+ */
+class auth_plugin_authpgsql extends auth_plugin_authmysql {
+
+ /**
+ * Constructor
+ *
+ * checks if the pgsql interface is available, otherwise it will
+ * set the variable $success of the basis class to false
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+ public function __construct() {
+ // we don't want the stuff the MySQL constructor does, but the grandparent might do something
+ DokuWiki_Auth_Plugin::__construct();
+
+ if(!function_exists('pg_connect')) {
+ $this->_debug("PgSQL err: PHP Postgres extension not found.", -1, __LINE__, __FILE__);
+ $this->success = false;
+ return;
+ }
+
+ $this->loadConfig();
+
+ // set capabilities based upon config strings set
+ if(empty($this->conf['user']) ||
+ empty($this->conf['password']) || empty($this->conf['database'])
+ ) {
+ $this->_debug("PgSQL err: insufficient configuration.", -1, __LINE__, __FILE__);
+ $this->success = false;
+ return;
+ }
+
+ $this->cando['addUser'] = $this->_chkcnf(
+ array(
+ 'getUserInfo',
+ 'getGroups',
+ 'addUser',
+ 'getUserID',
+ 'getGroupID',
+ 'addGroup',
+ 'addUserGroup'
+ )
+ );
+ $this->cando['delUser'] = $this->_chkcnf(
+ array(
+ 'getUserID',
+ 'delUser',
+ 'delUserRefs'
+ )
+ );
+ $this->cando['modLogin'] = $this->_chkcnf(
+ array(
+ 'getUserID',
+ 'updateUser',
+ 'UpdateTarget'
+ )
+ );
+ $this->cando['modPass'] = $this->cando['modLogin'];
+ $this->cando['modName'] = $this->cando['modLogin'];
+ $this->cando['modMail'] = $this->cando['modLogin'];
+ $this->cando['modGroups'] = $this->_chkcnf(
+ array(
+ 'getUserID',
+ 'getGroups',
+ 'getGroupID',
+ 'addGroup',
+ 'addUserGroup',
+ 'delGroup',
+ 'getGroupID',
+ 'delUserGroup'
+ )
+ );
+ /* getGroups is not yet supported
+ $this->cando['getGroups'] = $this->_chkcnf(array('getGroups',
+ 'getGroupID')); */
+ $this->cando['getUsers'] = $this->_chkcnf(
+ array(
+ 'getUsers',
+ 'getUserInfo',
+ 'getGroups'
+ )
+ );
+ $this->cando['getUserCount'] = $this->_chkcnf(array('getUsers'));
+ }
+
+ /**
+ * Check if the given config strings are set
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param array $keys
+ * @param bool $wop
+ * @return bool
+ */
+ protected function _chkcnf($keys, $wop = false) {
+ foreach($keys as $key) {
+ if(empty($this->conf[$key])) return false;
+ }
+ return true;
+ }
+
+ /**
+ * Counts users which meet certain $filter criteria.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param array $filter filter criteria in item/pattern pairs
+ * @return int count of found users.
+ */
+ public function getUserCount($filter = array()) {
+ $rc = 0;
+
+ if($this->_openDB()) {
+ $sql = $this->_createSQLFilter($this->conf['getUsers'], $filter);
+
+ // no equivalent of SQL_CALC_FOUND_ROWS in pgsql?
+ if(($result = $this->_queryDB($sql))) {
+ $rc = count($result);
+ }
+ $this->_closeDB();
+ }
+ return $rc;
+ }
+
+ /**
+ * Bulk retrieval of user data
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param int $first index of first user to be returned
+ * @param int $limit max number of users to be returned
+ * @param array $filter array of field/pattern pairs
+ * @return array userinfo (refer getUserData for internal userinfo details)
+ */
+ public function retrieveUsers($first = 0, $limit = 10, $filter = array()) {
+ $out = array();
+
+ if($this->_openDB()) {
+ $this->_lockTables("READ");
+ $sql = $this->_createSQLFilter($this->conf['getUsers'], $filter);
+ $sql .= " ".$this->conf['SortOrder']." LIMIT $limit OFFSET $first";
+ $result = $this->_queryDB($sql);
+
+ foreach($result as $user)
+ if(($info = $this->_getUserInfo($user['user'])))
+ $out[$user['user']] = $info;
+
+ $this->_unlockTables();
+ $this->_closeDB();
+ }
+ return $out;
+ }
+
+ // @inherit function joinGroup($user, $group)
+ // @inherit function leaveGroup($user, $group) {
+
+ /**
+ * Adds a user to a group.
+ *
+ * If $force is set to true non existing groups would be created.
+ *
+ * The database connection must already be established. Otherwise
+ * this function does nothing and returns 'false'.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ * @param string $user user to add to a group
+ * @param string $group name of the group
+ * @param bool $force create missing groups
+ * @return bool true on success, false on error
+ */
+ protected function _addUserToGroup($user, $group, $force = false) {
+ $newgroup = 0;
+
+ if(($this->dbcon) && ($user)) {
+ $gid = $this->_getGroupID($group);
+ if(!$gid) {
+ if($force) { // create missing groups
+ $sql = str_replace('%{group}', addslashes($group), $this->conf['addGroup']);
+ $this->_modifyDB($sql);
+ //group should now exists try again to fetch it
+ $gid = $this->_getGroupID($group);
+ $newgroup = 1; // group newly created
+ }
+ }
+ if(!$gid) return false; // group didn't exist and can't be created
+
+ $sql = $this->conf['addUserGroup'];
+ if(strpos($sql, '%{uid}') !== false) {
+ $uid = $this->_getUserID($user);
+ $sql = str_replace('%{uid}', addslashes($uid), $sql);
+ }
+ $sql = str_replace('%{user}', addslashes($user), $sql);
+ $sql = str_replace('%{gid}', addslashes($gid), $sql);
+ $sql = str_replace('%{group}', addslashes($group), $sql);
+ if($this->_modifyDB($sql) !== false) return true;
+
+ if($newgroup) { // remove previously created group on error
+ $sql = str_replace('%{gid}', addslashes($gid), $this->conf['delGroup']);
+ $sql = str_replace('%{group}', addslashes($group), $sql);
+ $this->_modifyDB($sql);
+ }
+ }
+ return false;
+ }
+
+ // @inherit function _delUserFromGroup($user $group)
+ // @inherit function _getGroups($user)
+ // @inherit function _getUserID($user)
+
+ /**
+ * Adds a new User to the database.
+ *
+ * The database connection must already be established
+ * for this function to work. Otherwise it will return
+ * 'false'.
+ *
+ * @param string $user login of the user
+ * @param string $pwd encrypted password
+ * @param string $name full name of the user
+ * @param string $mail email address
+ * @param array $grps array of groups the user should become member of
+ * @return bool
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ */
+ protected function _addUser($user, $pwd, $name, $mail, $grps) {
+ if($this->dbcon && is_array($grps)) {
+ $sql = str_replace('%{user}', addslashes($user), $this->conf['addUser']);
+ $sql = str_replace('%{pass}', addslashes($pwd), $sql);
+ $sql = str_replace('%{name}', addslashes($name), $sql);
+ $sql = str_replace('%{email}', addslashes($mail), $sql);
+ if($this->_modifyDB($sql)) {
+ $uid = $this->_getUserID($user);
+ } else {
+ return false;
+ }
+
+ $group = '';
+ $gid = false;
+
+ if($uid) {
+ foreach($grps as $group) {
+ $gid = $this->_addUserToGroup($user, $group, 1);
+ if($gid === false) break;
+ }
+
+ if($gid !== false){
+ return true;
+ } else {
+ /* remove the new user and all group relations if a group can't
+ * be assigned. Newly created groups will remain in the database
+ * and won't be removed. This might create orphaned groups but
+ * is not a big issue so we ignore this problem here.
+ */
+ $this->_delUser($user);
+ $this->_debug("PgSQL err: Adding user '$user' to group '$group' failed.", -1, __LINE__, __FILE__);
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Opens a connection to a database and saves the handle for further
+ * usage in the object. The successful call to this functions is
+ * essential for most functions in this object.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @return bool
+ */
+ protected function _openDB() {
+ if(!$this->dbcon) {
+ $dsn = $this->conf['server'] ? 'host='.$this->conf['server'] : '';
+ $dsn .= ' port='.$this->conf['port'];
+ $dsn .= ' dbname='.$this->conf['database'];
+ $dsn .= ' user='.$this->conf['user'];
+ $dsn .= ' password='.$this->conf['password'];
+
+ $con = @pg_connect($dsn);
+ if($con) {
+ $this->dbcon = $con;
+ return true; // connection and database successfully opened
+ } else {
+ $this->_debug(
+ "PgSQL err: Connection to {$this->conf['user']}@{$this->conf['server']} not possible.",
+ -1, __LINE__, __FILE__
+ );
+ }
+ return false; // connection failed
+ }
+ return true; // connection already open
+ }
+
+ /**
+ * Closes a database connection.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ */
+ protected function _closeDB() {
+ if($this->dbcon) {
+ pg_close($this->dbcon);
+ $this->dbcon = 0;
+ }
+ }
+
+ /**
+ * Sends a SQL query to the database and transforms the result into
+ * an associative array.
+ *
+ * This function is only able to handle queries that returns a
+ * table such as SELECT.
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $query SQL string that contains the query
+ * @return array the result table
+ */
+ protected function _queryDB($query) {
+ $resultarray = array();
+ if($this->dbcon) {
+ $result = @pg_query($this->dbcon, $query);
+ if($result) {
+ while(($t = pg_fetch_assoc($result)) !== false)
+ $resultarray[] = $t;
+ pg_free_result($result);
+ return $resultarray;
+ } else{
+ $this->_debug('PgSQL err: '.pg_last_error($this->dbcon), -1, __LINE__, __FILE__);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Executes an update or insert query. This differs from the
+ * MySQL one because it does NOT return the last insertID
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+ protected function _modifyDB($query) {
+ if($this->dbcon) {
+ $result = @pg_query($this->dbcon, $query);
+ if($result) {
+ pg_free_result($result);
+ return true;
+ }
+ $this->_debug('PgSQL err: '.pg_last_error($this->dbcon), -1, __LINE__, __FILE__);
+ }
+ return false;
+ }
+
+ /**
+ * Start a transaction
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ *
+ * @param string $mode could be 'READ' or 'WRITE'
+ * @return bool
+ */
+ protected function _lockTables($mode) {
+ if($this->dbcon) {
+ $this->_modifyDB('BEGIN');
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Commit a transaction
+ *
+ * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
+ */
+ protected function _unlockTables() {
+ if($this->dbcon) {
+ $this->_modifyDB('COMMIT');
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Escape a string for insertion into the database
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ *
+ * @param string $string The string to escape
+ * @param bool $like Escape wildcard chars as well?
+ * @return string
+ */
+ protected function _escape($string, $like = false) {
+ $string = pg_escape_string($string);
+ if($like) {
+ $string = addcslashes($string, '%_');
+ }
+ return $string;
+ }
+} \ No newline at end of file
diff --git a/lib/plugins/authpgsql/conf/default.php b/lib/plugins/authpgsql/conf/default.php
new file mode 100644
index 000000000..7f78280f9
--- /dev/null
+++ b/lib/plugins/authpgsql/conf/default.php
@@ -0,0 +1,33 @@
+<?php
+
+$conf['server'] = '';
+$conf['port'] = 5432;
+$conf['user'] = '';
+$conf['password'] = '';
+$conf['database'] = '';
+$conf['debug'] = 0;
+$conf['forwardClearPass'] = 0;
+$conf['checkPass'] = '';
+$conf['getUserInfo'] = '';
+$conf['getGroups'] = '';
+$conf['getUsers'] = '';
+$conf['FilterLogin'] = '';
+$conf['FilterName'] = '';
+$conf['FilterEmail'] = '';
+$conf['FilterGroup'] = '';
+$conf['SortOrder'] = '';
+$conf['addUser'] = '';
+$conf['addGroup'] = '';
+$conf['addUserGroup'] = '';
+$conf['delGroup'] = '';
+$conf['getUserID'] = '';
+$conf['delUser'] = '';
+$conf['delUserRefs'] = '';
+$conf['updateUser'] = '';
+$conf['UpdateLogin'] = '';
+$conf['UpdatePass'] = '';
+$conf['UpdateEmail'] = '';
+$conf['UpdateName'] = '';
+$conf['UpdateTarget'] = '';
+$conf['delUserGroup'] = '';
+$conf['getGroupID'] = ''; \ No newline at end of file
diff --git a/lib/plugins/authpgsql/conf/metadata.php b/lib/plugins/authpgsql/conf/metadata.php
new file mode 100644
index 000000000..d52a17865
--- /dev/null
+++ b/lib/plugins/authpgsql/conf/metadata.php
@@ -0,0 +1,33 @@
+<?php
+
+$meta['server'] = array('string');
+$meta['port'] = array('numeric');
+$meta['user'] = array('string');
+$meta['password'] = array('password');
+$meta['database'] = array('string');
+$meta['debug'] = array('onoff');
+$meta['forwardClearPass'] = array('onoff');
+$meta['checkPass'] = array('');
+$meta['getUserInfo'] = array('');
+$meta['getGroups'] = array('');
+$meta['getUsers'] = array('');
+$meta['FilterLogin'] = array('string');
+$meta['FilterName'] = array('string');
+$meta['FilterEmail'] = array('string');
+$meta['FilterGroup'] = array('string');
+$meta['SortOrder'] = array('string');
+$meta['addUser'] = array('');
+$meta['addGroup'] = array('');
+$meta['addUserGroup'] = array('');
+$meta['delGroup'] = array('');
+$meta['getUserID'] = array('');
+$meta['delUser'] = array('');
+$meta['delUserRefs'] = array('');
+$meta['updateUser'] = array('string');
+$meta['UpdateLogin'] = array('string');
+$meta['UpdatePass'] = array('string');
+$meta['UpdateEmail'] = array('string');
+$meta['UpdateName'] = array('string');
+$meta['UpdateTarget'] = array('string');
+$meta['delUserGroup'] = array('');
+$meta['getGroupID'] = array(''); \ No newline at end of file
diff --git a/lib/plugins/authpgsql/lang/bg/settings.php b/lib/plugins/authpgsql/lang/bg/settings.php
new file mode 100644
index 000000000..0defdc4ff
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/bg/settings.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Bulgarian language file
+ *
+ * @author Kiril <neohidra@gmail.com>
+ */
+$lang['server'] = 'Вашият PostgreSQL сървър';
+$lang['port'] = 'Порт за PostgreSQL сървъра';
+$lang['user'] = 'PostgreSQL потребител';
+$lang['password'] = 'Парола за горния потребител';
+$lang['database'] = 'Име на базата от данни';
+$lang['debug'] = 'Показване на допълнителна debug информация'; \ No newline at end of file
diff --git a/lib/plugins/authpgsql/lang/cs/settings.php b/lib/plugins/authpgsql/lang/cs/settings.php
new file mode 100644
index 000000000..06abe86f4
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/cs/settings.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Czech language file
+ *
+ * @author mkucera66@seznam.cz
+ */
+$lang['server'] = 'Váš server PostgreSQL';
+$lang['port'] = 'Port vašeho serveru PostgreSQL';
+$lang['user'] = 'Uživatelské jméno pro PostgreSQL';
+$lang['password'] = 'Heslo tohoto uživatele';
+$lang['database'] = 'Použtá databáze';
+$lang['debug'] = 'Zobrazit dodatečné debugovací informace';
+$lang['forwardClearPass'] = 'Posílat uživatelské heslo jako čistý text do příkazů SQL namísto využití volby passcrypt.';
+$lang['checkPass'] = 'Příkaz SQL pro kontrolu hesel';
+$lang['getUserInfo'] = 'Příkaz SQL pro získání informací o uživateli';
+$lang['getGroups'] = 'Příkaz SQL pro získání členství uživatele ve skupinách';
+$lang['getUsers'] = 'Příkaz SQL pro seznam všech uživatelů';
+$lang['FilterLogin'] = 'Příkaz SQL pro filtrování uživatelů podle přihlašovacího jména';
+$lang['FilterName'] = 'Příkaz SQL pro filtrování uživatelů podle celého jména';
+$lang['FilterEmail'] = 'Příkaz SQL pro filtrování uživatelů podle adres emailů';
+$lang['FilterGroup'] = 'Příkaz SQL pro filtrování uživatelů podle členství ve skupinách';
+$lang['SortOrder'] = 'Příkaz SQL pro řazení uživatelů';
+$lang['addUser'] = 'Příkaz SQL pro řazení uživatelů';
+$lang['addGroup'] = 'Příkaz SQL pro přidání nové skupiny';
+$lang['addUserGroup'] = 'Příkaz SQL pro přidání uživatele do existující skupiny';
+$lang['delGroup'] = 'Příkaz SQL pro vymazání skupiny';
+$lang['getUserID'] = 'Příkaz SQL pro získání primárního klíče uživatele';
+$lang['delUser'] = 'Příkaz SQL pro vymazání uživatele';
+$lang['delUserRefs'] = 'Příkaz SQL pro odstranění členství uživatele se všech skupin';
+$lang['updateUser'] = 'Příkaz SQL pro aktualizaci uživatelského profilu';
+$lang['UpdateLogin'] = 'Klauzule pro aktualizaci přihlačovacího jména uživatele';
+$lang['UpdatePass'] = 'Klauzule pro aktualizaci hesla uživatele';
+$lang['UpdateEmail'] = 'Klauzule pro aktualizaci emailové adresy uživatele';
+$lang['UpdateName'] = 'Klauzule pro aktualizaci celého jména uživatele';
+$lang['UpdateTarget'] = 'Omezující klauzule pro identifikaci uživatele při aktualizaci';
+$lang['delUserGroup'] = 'Příkaz SQL pro zrušení členství uživatele v dané skupině';
+$lang['getGroupID'] = 'Příkaz SQL pro získání primárního klíče skupiny';
diff --git a/lib/plugins/authpgsql/lang/de-informal/settings.php b/lib/plugins/authpgsql/lang/de-informal/settings.php
new file mode 100644
index 000000000..d864d14d4
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/de-informal/settings.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * German language file
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Matthias Schulte <dokuwiki@lupo49.de>
+ * @author Volker Bödker <volker@boedker.de>
+ */
+$lang['server'] = 'PostgreSQL-Server';
+$lang['port'] = 'Port des PostgreSQL-Servers.';
+$lang['user'] = 'Benutzername für den Zugriff auf den PostgreSQL-Server.';
+$lang['password'] = 'Passwort des angegebenen Benutzers.';
+$lang['database'] = 'Zu verwendende Datenbank.';
+$lang['debug'] = 'Debug-Informationen anzeigen?';
+$lang['forwardClearPass'] = 'Passwort der DokuWiki-Benutzer im Klartext an die Datenbank übergeben? (Im Normalfall wird die passcrypt-Option angewendet.)';
+$lang['checkPass'] = 'SQL-Kommando zum Überprüfen von Passwörtern.';
+$lang['getUserInfo'] = 'SQL-Kommando um Benutzerinformationen auszulesen.';
+$lang['getGroups'] = 'SQL-Kommando um Gruppen eines Benutzers auszulesen.';
+$lang['getUsers'] = 'SQL-Kommando um alle Benutzer auszulesen.';
+$lang['FilterLogin'] = 'SQL-Bedingung um Benutzer anhand ihres Anmeldenamens zu filtern.';
+$lang['FilterName'] = 'SQL-Bedingung um Benutzer anhand ihres Namens zu filtern.';
+$lang['FilterEmail'] = 'SQL-Bedingung um Benutzer anhand ihrer E-Mail-Adresse zu filtern.';
+$lang['FilterGroup'] = 'SQL-Bedingung um Benutzer anhand ihrer Gruppenzugehörigkeit zu filtern.';
+$lang['SortOrder'] = 'SQL-Bedingung um anhand der die Benutzerliste sortiert wird.';
+$lang['addUser'] = 'SQL-Kommando um einen neuen Benutzer anzulegen.';
+$lang['addGroup'] = 'SQL-Kommando um eine neue Gruppe anzulegen.';
+$lang['addUserGroup'] = 'SQL-Kommando um einen Benutzer zu einer Gruppe hinzuzufügen.';
+$lang['delGroup'] = 'SQL-Kommando um eine Gruppe zu löschen.';
+$lang['getUserID'] = 'SQL-Kommando um den Primärschlüssel des Benutzers auszulesen.';
+$lang['delUser'] = 'SQL-Kommando um einen Benutzer zu löschen.';
+$lang['delUserRefs'] = 'SQL-Kommando um einen Benutzer aus allen Gruppen zu entfernen.';
+$lang['updateUser'] = 'SQL-Kommando um das Profil eines Benutzers zu aktualisieren.';
+$lang['UpdateLogin'] = 'SQL-Bedingung um den Anmeldenamen eines Benutzers zu ändern.';
+$lang['UpdatePass'] = 'SQL-Bedingung um das Passwort eines Benutzers zu ändern.';
+$lang['UpdateEmail'] = 'SQL-Bedingung um die E-Mail-Adresse eines Benutzers zu ändern.';
+$lang['UpdateName'] = 'SQL-Bedingung um den Namen eines Benutzers zu ändern.';
+$lang['UpdateTarget'] = 'SQL-Bedingung zur eindeutigen Identifikation des Benutzers.';
+$lang['delUserGroup'] = 'SQL-Kommando um einen Benutzer aus einer angegeben Gruppe zu entfernen.';
+$lang['getGroupID'] = 'SQL-Kommando um den Primärschlüssel einer Gruppe auszulesen.';
diff --git a/lib/plugins/authpgsql/lang/de/settings.php b/lib/plugins/authpgsql/lang/de/settings.php
new file mode 100644
index 000000000..4c80245d6
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/de/settings.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * German language file
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Matthias Schulte <dokuwiki@lupo49.de>
+ */
+$lang['server'] = 'PostgreSQL-Server';
+$lang['port'] = 'Port des PostgreSQL-Servers.';
+$lang['user'] = 'Benutzername für den Zugriff auf den PostgreSQL-Server.';
+$lang['password'] = 'Passwort des angegebenen Benutzers.';
+$lang['database'] = 'Zu verwendende Datenbank.';
+$lang['debug'] = 'Debug-Informationen anzeigen?';
+$lang['forwardClearPass'] = 'Passwort der DokuWiki-Benutzer im Klartext an die Datenbank übergeben? (Im Normalfall wird die passcrypt-Option angewendet.)';
+$lang['checkPass'] = 'SQL-Kommando zum Überprüfen von Passwörtern.';
+$lang['getUserInfo'] = 'SQL-Kommando um Benutzerinformationen auszulesen.';
+$lang['getGroups'] = 'SQL-Kommando um Gruppen eines Benutzers auszulesen.';
+$lang['getUsers'] = 'SQL-Kommando um alle Benutzer auszulesen.';
+$lang['FilterLogin'] = 'SQL-Bedingung um Benutzer anhand ihres Anmeldenamens zu filtern.';
+$lang['FilterName'] = 'SQL-Bedingung um Benutzer anhand ihres Namens zu filtern.';
+$lang['FilterEmail'] = 'SQL-Bedingung um Benutzer anhand ihrer E-Mail-Adresse zu filtern.';
+$lang['FilterGroup'] = 'SQL-Bedingung um Benutzer anhand ihrer Gruppenzugehörigkeit zu filtern.';
+$lang['SortOrder'] = 'SQL-Bedingung um anhand der die Benutzerliste sortiert wird.';
+$lang['addUser'] = 'SQL-Kommando um einen neuen Benutzer anzulegen.';
+$lang['addGroup'] = 'SQL-Kommando um eine neue Gruppe anzulegen.';
+$lang['addUserGroup'] = 'SQL-Kommando um einen Benutzer zu einer Gruppe hinzuzufügen.';
+$lang['delGroup'] = 'SQL-Kommando um eine Gruppe zu löschen.';
+$lang['getUserID'] = 'SQL-Kommando um den Primärschlüssel des Benutzers auszulesen.';
+$lang['delUser'] = 'SQL-Kommando um einen Benutzer zu löschen.';
+$lang['delUserRefs'] = 'SQL-Kommando um einen Benutzer aus allen Gruppen zu entfernen.';
+$lang['updateUser'] = 'SQL-Kommando um das Profil eines Benutzers zu aktualisieren.';
+$lang['UpdateLogin'] = 'SQL-Bedingung um den Anmeldenamen eines Benutzers zu ändern.';
+$lang['UpdatePass'] = 'SQL-Bedingung um das Passwort eines Benutzers zu ändern.';
+$lang['UpdateEmail'] = 'SQL-Bedingung um die E-Mail-Adresse eines Benutzers zu ändern.';
+$lang['UpdateName'] = 'SQL-Bedingung um den Namen eines Benutzers zu ändern.';
+$lang['UpdateTarget'] = 'SQL-Bedingung zur eindeutigen Identifikation des Benutzers.';
+$lang['delUserGroup'] = 'SQL-Kommando um einen Benutzer aus einer angegeben Gruppe zu entfernen.';
+$lang['getGroupID'] = 'SQL-Kommando um den Primärschlüssel einer Gruppe auszulesen.';
diff --git a/lib/plugins/authpgsql/lang/en/settings.php b/lib/plugins/authpgsql/lang/en/settings.php
new file mode 100644
index 000000000..e67235cfa
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/en/settings.php
@@ -0,0 +1,33 @@
+<?php
+
+$lang['server'] = 'Your PostgreSQL server';
+$lang['port'] = 'Your PostgreSQL server\'s port';
+$lang['user'] = 'PostgreSQL user name';
+$lang['password'] = 'Password for above user';
+$lang['database'] = 'Database to use';
+$lang['debug'] = 'Display additional debug information';
+$lang['forwardClearPass'] = 'Pass user passwords as cleartext to the SQL statements below, instead of using the passcrypt option';
+$lang['checkPass'] = 'SQL statement for checking passwords';
+$lang['getUserInfo'] = 'SQL statement for retrieving user information';
+$lang['getGroups'] = 'SQL statement for retrieving a user\'s group memberships';
+$lang['getUsers'] = 'SQL statement to list all users';
+$lang['FilterLogin'] = 'SQL clause for filtering users by login name';
+$lang['FilterName'] = 'SQL clause for filtering users by full name';
+$lang['FilterEmail'] = 'SQL clause for filtering users by email address';
+$lang['FilterGroup'] = 'SQL clause for filtering users by group membership';
+$lang['SortOrder'] = 'SQL clause to sort users';
+$lang['addUser'] = 'SQL statement to add a new user';
+$lang['addGroup'] = 'SQL statement to add a new group';
+$lang['addUserGroup'] = 'SQL statment to add a user to an existing group';
+$lang['delGroup'] = 'SQL statement to remove a group';
+$lang['getUserID'] = 'SQL statement to get the primary key of a user';
+$lang['delUser'] = 'SQL statement to delete a user';
+$lang['delUserRefs'] = 'SQL statement to remove a user from all groups';
+$lang['updateUser'] = 'SQL statement to update a user profile';
+$lang['UpdateLogin'] = 'Update clause for updating the user\'s login name';
+$lang['UpdatePass'] = 'Update clause for updating the user\'s password';
+$lang['UpdateEmail'] = 'Update clause for updating the user\'s email address';
+$lang['UpdateName'] = 'Update clause for updating the user\'s full name';
+$lang['UpdateTarget'] = 'Limit clause to identify the user when updating';
+$lang['delUserGroup'] = 'SQL statement to remove a user from a given group';
+$lang['getGroupID'] = 'SQL statement to get the primary key of a given group';
diff --git a/lib/plugins/authpgsql/lang/eo/settings.php b/lib/plugins/authpgsql/lang/eo/settings.php
new file mode 100644
index 000000000..dbdfdd41b
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/eo/settings.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Esperanto language file
+ *
+ */
+$lang['server'] = 'Via PostgreSQL-servilo';
+$lang['port'] = 'Via PostgreSQL-servila pordego';
+$lang['user'] = 'PostgreSQL-uzantonomo';
+$lang['password'] = 'Pasvorto por tiu uzanto';
+$lang['database'] = 'Uzenda datumbazo';
+$lang['debug'] = 'Ĉu indiki aldonajn erarinformojn';
+$lang['forwardClearPass'] = 'Ĉu transdoni pasvortojn klartekste al la SQL-frazoj sube anstataŭ uzi pasvortan kaŝon';
+$lang['checkPass'] = 'SQL-frazo por testi pasvortojn';
+$lang['getUserInfo'] = 'SQL-frazo por ricevi uzantajn informojn';
+$lang['getGroups'] = 'SQL-frazo por ricevi la grupmembrecojn de uzanto';
+$lang['getUsers'] = 'SQL-frazo por listigi ĉiujn uzantojn';
+$lang['FilterLogin'] = 'SQL-frazo por filtri uzantojn je ensaluta nomo';
+$lang['FilterName'] = 'SQL-frazo por filtri uzantojn je plena nomo';
+$lang['FilterEmail'] = 'SQL-frazo por filtri uzantojn je retpoŝtadreso';
+$lang['FilterGroup'] = 'SQL-frazo por filtri uzantojn je grupmembreco';
+$lang['SortOrder'] = 'SQL-frazo por ordigi uzantojn';
+$lang['addUser'] = 'SQL-frazo por aldoni novan uzanton';
+$lang['addGroup'] = 'SQL-frazo por aldoni novan grupon';
+$lang['addUserGroup'] = 'SQL-frazo por aldoni uzanton al ekzistanta grupo';
+$lang['delGroup'] = 'SQL-frazo por forigi grupon';
+$lang['getUserID'] = 'SQL-frazo por ricevi la ĉefan ŝlosilon de uzanto';
+$lang['delUser'] = 'SQL-frazo por forigi uzanton';
+$lang['delUserRefs'] = 'SQL-frazo por forigi uzanton el ĉiuj grupoj';
+$lang['updateUser'] = 'SQL-frazo por aktualigi uzantan profilon';
+$lang['UpdateLogin'] = 'Aktualiga frazo por uzanta ensalutnomo';
+$lang['UpdatePass'] = 'Aktualiga frazo por uzanta pasvorto';
+$lang['UpdateEmail'] = 'Aktualiga frazo por uzanta retpoŝtadreso';
+$lang['UpdateName'] = 'Aktualiga frazo por plena uzanta nomo';
+$lang['UpdateTarget'] = 'Limiga frazo por identigi la uzanton dum aktualigado';
+$lang['delUserGroup'] = 'SQL-frazo por forigi uzanton el indikita grupo';
+$lang['getGroupID'] = 'SQL-frazo por ricevi la ĉefan ŝlosilon de indikita grupo';
diff --git a/lib/plugins/authpgsql/lang/fi/settings.php b/lib/plugins/authpgsql/lang/fi/settings.php
new file mode 100644
index 000000000..d3aa13e07
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/fi/settings.php
@@ -0,0 +1,6 @@
+<?php
+/**
+ * Finnish language file
+ *
+ * @author Otto Vainio <otto@valjakko.net>
+ */
diff --git a/lib/plugins/authpgsql/lang/fr/settings.php b/lib/plugins/authpgsql/lang/fr/settings.php
new file mode 100644
index 000000000..ec425bd49
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/fr/settings.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * French language file
+ *
+ * @author Bruno Veilleux <bruno.vey@gmail.com>
+ */
+$lang['server'] = 'Votre serveur PostgreSQL';
+$lang['port'] = 'Le port de votre serveur PostgreSQL';
+$lang['user'] = 'Nom d\'utilisateur PostgreSQL';
+$lang['password'] = 'Mot de passe pour l\'utilisateur ci-dessus';
+$lang['database'] = 'Base de données à utiliser';
+$lang['debug'] = 'Afficher des informations de débogage supplémentaires';
+$lang['forwardClearPass'] = 'Passer les mots de passe aux requêtes SQL ci-dessous en cleartext plutôt qu\'avec l\'option passcrypt';
+$lang['checkPass'] = 'Requête SQL pour la vérification des mots de passe';
+$lang['getUserInfo'] = 'Requête SQL pour la récupération des informations d\'un utilisateur';
+$lang['getGroups'] = 'Requête SQL pour la récupération des groupes d\'un utilisateur';
+$lang['getUsers'] = 'Requête SQL pour énumérer tous les utilisateurs';
+$lang['FilterLogin'] = 'Clause SQL pour filtrer les utilisateurs par identifiant';
+$lang['FilterName'] = 'Clause SQL pour filtrer les utilisateurs par nom complet';
+$lang['FilterEmail'] = 'Clause SQL pour filtrer les utilisateurs par adresse électronique';
+$lang['FilterGroup'] = 'Clause SQL pour filtrer les utilisateurs par groupes';
+$lang['SortOrder'] = 'Clause SQL pour trier les utilisateurs';
+$lang['addUser'] = 'Requête SQL pour ajouter un nouvel utilisateur';
+$lang['addGroup'] = 'Requête SQL pour ajouter un nouveau groupe';
+$lang['addUserGroup'] = 'Requête SQL pour ajouter un utilisateur à un groupe existant';
+$lang['delGroup'] = 'Requête SQL pour retirer un groupe';
+$lang['getUserID'] = 'Requête SQL pour obtenir la clé primaire d\'un utilisateur';
+$lang['delUser'] = 'Requête SQL pour supprimer un utilisateur';
+$lang['delUserRefs'] = 'Requête SQL pour retirer un utilisateur de tous les groupes';
+$lang['updateUser'] = 'Requête SQL pour mettre à jour le profil d\'un utilisateur';
+$lang['UpdateLogin'] = 'Clause de mise à jour pour mettre à jour l\'identifiant d\'un utilisateur';
+$lang['UpdatePass'] = 'Clause de mise à jour pour mettre à jour le mot de passe d\'un utilisateur';
+$lang['UpdateEmail'] = 'Clause de mise à jour pour mettre à jour l\'adresse électronique d\'un utilisateur';
+$lang['UpdateName'] = 'Clause de mise à jour pour mettre à jour le nom complet d\'un utilisateur';
+$lang['UpdateTarget'] = 'Clause de limite pour identifier l\'utilisateur durant une mise à jour';
+$lang['delUserGroup'] = 'Requête SQL pour retirer un utilisateur d\'un groupe donné';
+$lang['getGroupID'] = 'Requête SQL pour obtenir la clé primaire d\'un groupe donné';
diff --git a/lib/plugins/authpgsql/lang/it/settings.php b/lib/plugins/authpgsql/lang/it/settings.php
new file mode 100644
index 000000000..10ae72f87
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/it/settings.php
@@ -0,0 +1,5 @@
+<?php
+/**
+ * Italian language file
+ *
+ */
diff --git a/lib/plugins/authpgsql/lang/ja/settings.php b/lib/plugins/authpgsql/lang/ja/settings.php
new file mode 100644
index 000000000..4883caa4c
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/ja/settings.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Japanese language file
+ *
+ * @author Satoshi Sahara <sahara.satoshi@gmail.com>
+ */
+$lang['server'] = 'PostgreSQL のサーバー名';
+$lang['port'] = 'PostgreSQL サーバーのポート番号';
+$lang['user'] = 'PostgreSQL 接続用ユーザー名';
+$lang['password'] = 'PostgreSQL 接続用ユーザーのパスワード';
+$lang['database'] = '使用するデータベース名';
+$lang['debug'] = 'デバック情報を表示する';
+$lang['forwardClearPass'] = '以下で定義する SQL ステートメントにおいて, パスワード変数 %{pass} を平文とする(DokiWiki側で暗号化しない)';
+$lang['checkPass'] = 'パスワードの照合に用いる SQL ステートメント';
+$lang['getUserInfo'] = 'ユーザー情報の取得に用いる SQL ステートメント';
+$lang['getGroups'] = 'ユーザーが所属する全てのグループの取得に用いる SQL ステートメント';
+$lang['getUsers'] = 'ユーザーリストを取得する SQL ステートメント';
+$lang['FilterLogin'] = 'ユーザーリストをログイン名で絞り込む SQL 句';
+$lang['FilterName'] = 'ユーザーリストをフルネームで絞り込む SQL 句';
+$lang['FilterEmail'] = 'ユーザーリストをメールアドレスで絞り込む SQL 句';
+$lang['FilterGroup'] = 'ユーザーリストを所属グループで絞り込む SQL 句';
+$lang['SortOrder'] = 'ユーザーリストのソート方法を指定する SQL 句';
+$lang['addUser'] = '新規ユーザーを追加する SQL ステートメント';
+$lang['addGroup'] = '新規グループを追加する SQL ステートメント';
+$lang['addUserGroup'] = 'ユーザーをグループに配属する SQL ステートメント';
+$lang['delGroup'] = 'グループを削除する SQL ステートメント';
+$lang['getUserID'] = 'ユーザーIDの取得に用いる SQL ステートメン';
+$lang['delUser'] = 'ユーザーを削除する SQL ステートメント';
+$lang['delUserRefs'] = 'ユーザーのグループ所属を全て取り消す SQL ステートメント';
+$lang['updateUser'] = 'ユーザー情報を変更する SQL ステートメント';
+$lang['UpdateLogin'] = '変更後のログイン名を指定する SQL 句';
+$lang['UpdatePass'] = '変更後のパスワードを指定する SQL 句';
+$lang['UpdateEmail'] = '変更後のメールアドレスを指定する SQL 句';
+$lang['UpdateName'] = '変更後のフルネームを指定する SQL 句';
+$lang['UpdateTarget'] = '変更対象のユーザを特定するための SQL 句';
+$lang['delUserGroup'] = 'ユーザーをグループから除名する SQL ステートメント';
+$lang['getGroupID'] = 'グループIDの取得に用いる SQL ステートメント';
diff --git a/lib/plugins/authpgsql/lang/ko/settings.php b/lib/plugins/authpgsql/lang/ko/settings.php
new file mode 100644
index 000000000..d21e81cd6
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/ko/settings.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Korean language file
+ *
+ * @author Myeongjin <aranet100@gmail.com>
+ */
+$lang['server'] = 'PostgreSQL 서버';
+$lang['port'] = 'PostgreSQL 서버의 포트';
+$lang['user'] = 'PostgreSQL 사용자 이름';
+$lang['password'] = '위 사용자의 비밀번호';
+$lang['database'] = '사용할 데이터베이스';
+$lang['debug'] = '추가적인 디버그 정보 보이기';
+$lang['forwardClearPass'] = 'passcrypt 옵션을 사용하는 대신 아래 SQL 문에 일반 텍스트로 사용자 비밀번호를 전달';
+$lang['checkPass'] = '비밀번호를 확인하기 위한 SQL 문';
+$lang['getUserInfo'] = '사용자 정보를 가져오기 위한 SQL 문';
+$lang['getGroups'] = '사용자의 그룹 구성원을 가져오기 위한 SQL 문';
+$lang['getUsers'] = '모든 사용자를 나타낼 SQL 문';
+$lang['FilterLogin'] = '로그인 이름 별로 사용자를 필터하기 위한 SQL 조항';
+$lang['FilterName'] = '전체 이름 별로 사용자를 필터하기 위한 SQL 조항';
+$lang['FilterEmail'] = '이메일 주소 별로 사용자를 필터하기 위한 SQL 조항';
+$lang['FilterGroup'] = '그룹 구성원 별로 사용자를 필터하기 위한 SQL 조항';
+$lang['SortOrder'] = '사용자를 정렬할 SQL 조항';
+$lang['addUser'] = '새 사용자를 추가할 SQL 문';
+$lang['addGroup'] = '새 그룹을 추가할 SQL 문';
+$lang['addUserGroup'] = '기존 그룹에 사용자를 추가할 SQL 문';
+$lang['delGroup'] = '그룹을 제거할 SQL 문';
+$lang['getUserID'] = '사용자의 기본 키를 얻을 SQL 문';
+$lang['delUser'] = '사용자를 삭제할 SQL 문';
+$lang['delUserRefs'] = '모든 그룹에서 사용자를 제거할 SQL 문';
+$lang['updateUser'] = '사용자 프로필을 업데이트할 SQL 문';
+$lang['UpdateLogin'] = '사용자의 로그인 이름을 업데이트하기 위한 Update 조항';
+$lang['UpdatePass'] = '사용자의 비밀번호를 업데이트하기 위한 Update 조항';
+$lang['UpdateEmail'] = '사용자의 이메일 주소를 업데이트하기 위한 Update 조항';
+$lang['UpdateName'] = '사용자의 전체 이름을 업데이트하기 위한 Update 조항';
+$lang['UpdateTarget'] = '업데이트할 때 사용자를 식별할 Limit 조항';
+$lang['delUserGroup'] = '주어진 그룹에서 사용자를 제거할 SQL 문';
+$lang['getGroupID'] = '주어진 그룹의 기본 키를 얻을 SQL 문';
diff --git a/lib/plugins/authpgsql/lang/lv/settings.php b/lib/plugins/authpgsql/lang/lv/settings.php
new file mode 100644
index 000000000..ced5dabf8
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/lv/settings.php
@@ -0,0 +1,6 @@
+<?php
+/**
+ * Latvian, Lettish language file
+ *
+ * @author Aivars Miška <allefm@gmail.com>
+ */
diff --git a/lib/plugins/authpgsql/lang/nl/settings.php b/lib/plugins/authpgsql/lang/nl/settings.php
new file mode 100644
index 000000000..4e6c007c6
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/nl/settings.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Dutch language file
+ *
+ */
+$lang['server'] = 'Je PostgrSQL server';
+$lang['port'] = 'Je PostgreSQL server poort';
+$lang['user'] = 'PostgrSQL gebruikersnaam';
+$lang['password'] = 'Wachtwoord voor bovenstaande gebruiker';
+$lang['database'] = 'Te gebruiken database';
+$lang['debug'] = 'Tonen aanvullende debuginformatie';
+$lang['forwardClearPass'] = 'Wachtwoorden als leesbare tekst in SQL commando\'s opnemen in plaats van versleutelde tekens';
+$lang['checkPass'] = 'SQL commando voor verifiëren wachtwoorden';
+$lang['getUserInfo'] = 'SQL commando voor ophalen gebruikersinformatie';
+$lang['getGroups'] = 'SQL commando voor ophalen groepslidmaatschappen van gebruikers';
+$lang['getUsers'] = 'SQL commando voor tonen alle gebruikers';
+$lang['FilterLogin'] = 'SQL commando voor filteren gebruikers op inlognaam';
+$lang['FilterName'] = 'SQL commando voor filteren gebruikers op volledige naam';
+$lang['FilterEmail'] = 'SQL commando voor filteren gebruikers op e-mailadres';
+$lang['FilterGroup'] = 'SQL commando voor filteren gebruikers op groepslidmaatschap';
+$lang['SortOrder'] = 'SQL commando voor sorteren gebruikers';
+$lang['addUser'] = 'SQL commando voor toevoegen nieuwe gebruiker';
+$lang['addGroup'] = 'SQL commando voor toevoegen nieuwe groep';
+$lang['addUserGroup'] = 'SQL commando voor toevoegen gebruiker aan bestaande groep';
+$lang['delGroup'] = 'SQL commando voor verwijderen groep';
+$lang['getUserID'] = 'SQL commando om de primaire sleutel van een gebruiker op te halen';
+$lang['delUser'] = 'SQL commando voor verwijderen gebruiker';
+$lang['delUserRefs'] = 'SQL commando om een gebruiker uit alle groepen te verwijderen';
+$lang['updateUser'] = 'SQL commando om een gebruikersprofiel bij te werken';
+$lang['UpdateLogin'] = 'SQL commando om een inlognaam bij te werken';
+$lang['UpdatePass'] = 'SQL commando om een wachtwoord bij te werken';
+$lang['UpdateEmail'] = 'SQL commando om een e-mailadres bij te werken';
+$lang['UpdateName'] = 'SQL commando om een volledige naam bij te werken';
+$lang['UpdateTarget'] = 'Beperkingsclausule om gebruiker te identificeren voor bijwerken';
+$lang['delUserGroup'] = 'SQL commando om een gebruiker uit een bepaalde groep te verwijderen';
+$lang['getGroupID'] = 'SQL commando om de primaire sleutel van een bepaalde groep op te halen';
diff --git a/lib/plugins/authpgsql/lang/pt-br/settings.php b/lib/plugins/authpgsql/lang/pt-br/settings.php
new file mode 100644
index 000000000..d91e9c8e5
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/pt-br/settings.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Brazilian Portuguese language file
+ *
+ * @author Victor Westmann <victor.westmann@gmail.com>
+ */
+$lang['server'] = 'Seu servidor PostgreSQL';
+$lang['port'] = 'Sua porta do servidor PostgreSQL';
+$lang['user'] = 'Nome de usuário PostgreSQL';
+$lang['password'] = 'Senha do usuário acima';
+$lang['database'] = 'Base de dados para usar';
+$lang['debug'] = 'Mostrar informações adicionais de depuração';
+$lang['forwardClearPass'] = 'Transmitir senhas de usuário como texto puro para comandos SQL abaixo, ao invés de usar a opção passcrypt';
+$lang['checkPass'] = 'Comando SQL para verificar senhas';
+$lang['getUserInfo'] = 'Comando SQL para obter informações do usuário';
+$lang['getGroups'] = 'Comando SQL para obter as credenciais de um usuário de um determinado grupo';
+$lang['getUsers'] = 'Comando SQL para listar todos os usuários';
+$lang['FilterLogin'] = 'Cláusula SQL para filtrar usuários pelo nome de login';
+$lang['FilterName'] = 'Cláusula SQL para filtrar usuários pelo nome completo';
+$lang['FilterEmail'] = 'Cláusula SQL para filtrar usuários pelo endereço de email';
+$lang['FilterGroup'] = 'Cláusula SQL para filtrar usuários pelo grupo que pertencem';
+$lang['SortOrder'] = 'Comando SQL para adicionar novo grupo';
+$lang['addUser'] = 'Comando SQL para adicionar novo usuário';
+$lang['addGroup'] = 'Comando SQL para adicionar novo grupo';
+$lang['addUserGroup'] = 'Comando SQL para adicionar um usuário a um grupo existente';
+$lang['delGroup'] = 'Comando SQL para remover um grupo';
+$lang['getUserID'] = 'Comando SQL para obter chave primária de usuário';
+$lang['delUser'] = 'Comando SQL para apagar usuário';
+$lang['delUserRefs'] = 'Comando SQL para remover um usuário de todos os grupos';
+$lang['updateUser'] = 'Comando SQL para atualizar perfil de usuário';
+$lang['UpdateLogin'] = 'Atualizar cláusula para atualizar o login do usuário';
+$lang['UpdatePass'] = 'Atualizar cláusula para atualizar a senha do usuário';
+$lang['UpdateEmail'] = 'Atualizar cláusula para atualizar o endereço de email';
+$lang['UpdateName'] = 'Atualizar cláusula para atualizar o nome completo do usuário';
+$lang['UpdateTarget'] = 'Limitar cláusula para identificar quando um usuário estiver atualizando';
+$lang['delUserGroup'] = 'Comando SQL para remover um usuário de um determinado grupo';
+$lang['getGroupID'] = 'Comando SQL para obter a chave primária de um determinado grupo';
diff --git a/lib/plugins/authpgsql/lang/ru/settings.php b/lib/plugins/authpgsql/lang/ru/settings.php
new file mode 100644
index 000000000..4c394080e
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/ru/settings.php
@@ -0,0 +1,6 @@
+<?php
+/**
+ * Russian language file
+ *
+ * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua)
+ */
diff --git a/lib/plugins/authpgsql/lang/sv/settings.php b/lib/plugins/authpgsql/lang/sv/settings.php
new file mode 100644
index 000000000..27cb2601d
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/sv/settings.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Swedish language file
+ *
+ * @author Smorkster Andersson smorkster@gmail.com
+ */
+$lang['server'] = 'Din PostgreSQL server';
+$lang['port'] = 'Din PostgreSQL servers port';
+$lang['user'] = 'PostgreSQL användarnamn';
+$lang['password'] = 'Lösenord för användaren ovan';
+$lang['database'] = 'Databas att använda';
+$lang['debug'] = 'Visa ytterligare felsökningsinformation';
+$lang['forwardClearPass'] = 'Skicka lösenord för användare som klartext till SQL satserna nedan, istället för att använda krypteringsalternativet';
+$lang['checkPass'] = 'SQL sats för kontroll av lösenord';
+$lang['getUserInfo'] = 'SQL sats för att hämta användarinformation';
+$lang['getGroups'] = 'SQL sats för att hämta en användares gruppmedlemskap';
+$lang['getUsers'] = 'SQL sats för att lista alla användare';
+$lang['FilterLogin'] = 'SQL klausul för att filtrera användare efter inloggningsnamn';
+$lang['FilterName'] = 'SQL klausul för att filtrera användare efter fullt namn';
+$lang['FilterEmail'] = 'SQL klausul för att filtrera användare efter e-post adress';
+$lang['addUser'] = 'SQL sats för att lägga till en ny användare';
+$lang['addGroup'] = 'SQL sats för att lägga till en ny grupp';
+$lang['addUserGroup'] = 'SQL sats för att lägga till en användare i en existerande grupp';
+$lang['delGroup'] = 'SQL sats för att ta bort en grupp';
+$lang['delUser'] = 'SQL sats för att ta bort en användare';
+$lang['delUserRefs'] = 'SQL sats för att ta bort en användare från alla grupper';
+$lang['updateUser'] = 'SQL sats för att uppdatera en användarprofil';
+$lang['delUserGroup'] = 'SQL sats för att ta bort en användare från angiven grupp';
diff --git a/lib/plugins/authpgsql/lang/zh-tw/settings.php b/lib/plugins/authpgsql/lang/zh-tw/settings.php
new file mode 100644
index 000000000..6a04214ad
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/zh-tw/settings.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Chinese Traditional language file
+ *
+ * @author syaoranhinata@gmail.com
+ */
+$lang['server'] = '您的 PostgreSQL 伺服器';
+$lang['port'] = '您的 PostgreSQL 伺服器端口';
+$lang['user'] = 'PostgreSQL 使用者名稱';
+$lang['password'] = '上述使用者的密碼';
+$lang['database'] = '使用的資料庫';
+$lang['debug'] = '顯示額外除錯資訊';
+$lang['forwardClearPass'] = '以明文形式,把使用者密碼傳送给下列的 SQL 語句,而不使用 passcrypt 密碼加密選項';
+$lang['checkPass'] = '檢查密碼的 SQL 語句';
+$lang['getUserInfo'] = '獲取使用者訊息的 SQL 語句';
+$lang['getGroups'] = '獲取使用者群組成員身份的 SQL 語句';
+$lang['getUsers'] = '把所有使用者列出的 SQL 語句';
+$lang['FilterLogin'] = '根據登入名稱來篩選使用者的 SQL 子句';
+$lang['FilterName'] = '根據全名來篩選使用者的 SQL 子句';
+$lang['FilterEmail'] = '根據電郵地址來篩選使用者的 SQL 子句';
+$lang['FilterGroup'] = '根據群組成員身份來篩選使用者的 SQL 子句';
+$lang['SortOrder'] = '對使用者排序的 SQL 子句';
+$lang['addUser'] = '增加新使用者的 SQL 語句';
+$lang['addGroup'] = '增加新群組的 SQL 語句';
+$lang['addUserGroup'] = '把使用者新增至現有群組的 SQL 語句';
+$lang['delGroup'] = '把群組刪除的 SQL 語句';
+$lang['getUserID'] = '取得使用者主鍵的 SQL 語句';
+$lang['delUser'] = '把使用者刪除的 SQL 語句';
+$lang['delUserRefs'] = '把使用者從所有群組裏刪除的 SQL 語句';
+$lang['updateUser'] = '更新使用者訊息的 SQL 語句';
+$lang['UpdateLogin'] = '更新使用者登入名稱的 Update 子句';
+$lang['UpdatePass'] = '更新帳號密碼的 Update 子句';
+$lang['UpdateEmail'] = '更新使用者電郵地址的 Update 子句';
+$lang['UpdateName'] = '更新使用者全名的 Update 子句';
+$lang['UpdateTarget'] = '在更新時識別使用者的 Limit 子句';
+$lang['delUserGroup'] = '把使用者從指定群組中刪除的 SQL 語句';
+$lang['getGroupID'] = '取得指定群組主鍵的 SQL 語句';
diff --git a/lib/plugins/authpgsql/lang/zh/settings.php b/lib/plugins/authpgsql/lang/zh/settings.php
new file mode 100644
index 000000000..dc7223d89
--- /dev/null
+++ b/lib/plugins/authpgsql/lang/zh/settings.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Chinese language file
+ *
+ * @author lainme <lainme993@gmail.com>
+ */
+$lang['server'] = '您的 PostgreSQL 服务器';
+$lang['port'] = '您的 PostgreSQL 服务器端口';
+$lang['user'] = 'PostgreSQL 用户名';
+$lang['password'] = '上述用户的密码';
+$lang['database'] = '使用的数据库';
+$lang['debug'] = '显示额外调试信息';
+$lang['forwardClearPass'] = '将用户密码以明文形式传送给下面的 SQL 语句,而不使用 passcrypt 密码加密选项';
+$lang['checkPass'] = '检查密码的 SQL 语句';
+$lang['getUserInfo'] = '获取用户信息的 SQL 语句';
+$lang['getGroups'] = '获取用户的组成员身份的 SQL 语句';
+$lang['getUsers'] = '列出所有用户的 SQL 语句';
+$lang['FilterLogin'] = '根据登录名筛选用户的 SQL 子句';
+$lang['FilterName'] = '根据全名筛选用户的 SQL 子句';
+$lang['FilterEmail'] = '根据电子邮件地址筛选用户的 SQL 子句';
+$lang['FilterGroup'] = '根据组成员身份筛选用户的 SQL 子句';
+$lang['SortOrder'] = '对用户排序的 SQL 子句';
+$lang['addUser'] = '添加新用户的 SQL 语句';
+$lang['addGroup'] = '添加新组的 SQL 语句';
+$lang['addUserGroup'] = '将用户添加到现有组的 SQL 语句';
+$lang['delGroup'] = '删除组的 SQL 语句';
+$lang['getUserID'] = '获取用户主键的 SQL 语句';
+$lang['delUser'] = '删除用户的 SQL 语句';
+$lang['delUserRefs'] = '从所有组中删除一个用户的 SQL 语句';
+$lang['updateUser'] = '更新用户信息的 SQL 语句';
+$lang['UpdateLogin'] = '更新用户登录名的 Update 子句';
+$lang['UpdatePass'] = '更新用户密码的 Update 子句';
+$lang['UpdateEmail'] = '更新用户电子邮件地址的 Update 子句';
+$lang['UpdateName'] = '更新用户全名的 Update 子句';
+$lang['UpdateTarget'] = '更新时识别用户的 Limit 子句';
+$lang['delUserGroup'] = '从指定组删除用户的 SQL 语句';
+$lang['getGroupID'] = '获取指定组主键的 SQL 语句';
diff --git a/lib/plugins/authpgsql/plugin.info.txt b/lib/plugins/authpgsql/plugin.info.txt
new file mode 100644
index 000000000..af33cec3e
--- /dev/null
+++ b/lib/plugins/authpgsql/plugin.info.txt
@@ -0,0 +1,7 @@
+base authpgsql
+author Andreas Gohr
+email andi@splitbrain.org
+date 2013-02-16
+name PostgreSQL auth plugin
+desc Provides authentication against a PostgreSQL database
+url http://www.dokuwiki.org/plugin:authpgsql
diff --git a/lib/plugins/authplain/auth.php b/lib/plugins/authplain/auth.php
new file mode 100644
index 000000000..8c4ce0dd9
--- /dev/null
+++ b/lib/plugins/authplain/auth.php
@@ -0,0 +1,354 @@
+<?php
+// must be run within Dokuwiki
+if(!defined('DOKU_INC')) die();
+
+/**
+ * Plaintext authentication backend
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @author Jan Schumann <js@schumann-it.com>
+ */
+class auth_plugin_authplain extends DokuWiki_Auth_Plugin {
+ /** @var array user cache */
+ protected $users = null;
+
+ /** @var array filter pattern */
+ protected $_pattern = array();
+
+ /**
+ * Constructor
+ *
+ * Carry out sanity checks to ensure the object is
+ * able to operate. Set capabilities.
+ *
+ * @author Christopher Smith <chris@jalakai.co.uk>
+ */
+ public function __construct() {
+ parent::__construct();
+ global $config_cascade;
+
+ if(!@is_readable($config_cascade['plainauth.users']['default'])) {
+ $this->success = false;
+ } else {
+ if(@is_writable($config_cascade['plainauth.users']['default'])) {
+ $this->cando['addUser'] = true;
+ $this->cando['delUser'] = true;
+ $this->cando['modLogin'] = true;
+ $this->cando['modPass'] = true;
+ $this->cando['modName'] = true;
+ $this->cando['modMail'] = true;
+ $this->cando['modGroups'] = true;
+ }
+ $this->cando['getUsers'] = true;
+ $this->cando['getUserCount'] = true;
+ }
+ }
+
+ /**
+ * Check user+password
+ *
+ * Checks if the given user exists and the given
+ * plaintext password is correct
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param string $user
+ * @param string $pass
+ * @return bool
+ */
+ public function checkPass($user, $pass) {
+ $userinfo = $this->getUserData($user);
+ if($userinfo === false) return false;
+
+ return auth_verifyPassword($pass, $this->users[$user]['pass']);
+ }
+
+ /**
+ * Return user info
+ *
+ * Returns info about the given user needs to contain
+ * at least these fields:
+ *
+ * name string full name of the user
+ * mail string email addres of the user
+ * grps array list of groups the user is in
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param string $user
+ * @return array|bool
+ */
+ public function getUserData($user) {
+ if($this->users === null) $this->_loadUserData();
+ return isset($this->users[$user]) ? $this->users[$user] : false;
+ }
+
+ /**
+ * Create a new User
+ *
+ * Returns false if the user already exists, null when an error
+ * occurred and true if everything went well.
+ *
+ * The new user will be added to the default group by this
+ * function if grps are not specified (default behaviour).
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @author Chris Smith <chris@jalakai.co.uk>
+ *
+ * @param string $user
+ * @param string $pwd
+ * @param string $name
+ * @param string $mail
+ * @param array $grps
+ * @return bool|null|string
+ */
+ public function createUser($user, $pwd, $name, $mail, $grps = null) {
+ global $conf;
+ global $config_cascade;
+
+ // user mustn't already exist
+ if($this->getUserData($user) !== false) return false;
+
+ $pass = auth_cryptPassword($pwd);
+
+ // set default group if no groups specified
+ if(!is_array($grps)) $grps = array($conf['defaultgroup']);
+
+ // prepare user line
+ $groups = join(',', $grps);
+ $userline = join(':', array($user, $pass, $name, $mail, $groups))."\n";
+
+ if(io_saveFile($config_cascade['plainauth.users']['default'], $userline, true)) {
+ $this->users[$user] = compact('pass', 'name', 'mail', 'grps');
+ return $pwd;
+ }
+
+ msg(
+ 'The '.$config_cascade['plainauth.users']['default'].
+ ' file is not writable. Please inform the Wiki-Admin', -1
+ );
+ return null;
+ }
+
+ /**
+ * Modify user data
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ * @param string $user nick of the user to be changed
+ * @param array $changes array of field/value pairs to be changed (password will be clear text)
+ * @return bool
+ */
+ public function modifyUser($user, $changes) {
+ global $ACT;
+ global $config_cascade;
+
+ // sanity checks, user must already exist and there must be something to change
+ if(($userinfo = $this->getUserData($user)) === false) return false;
+ if(!is_array($changes) || !count($changes)) return true;
+
+ // update userinfo with new data, remembering to encrypt any password
+ $newuser = $user;
+ foreach($changes as $field => $value) {
+ if($field == 'user') {
+ $newuser = $value;
+ continue;
+ }
+ if($field == 'pass') $value = auth_cryptPassword($value);
+ $userinfo[$field] = $value;
+ }
+
+ $groups = join(',', $userinfo['grps']);
+ $userline = join(':', array($newuser, $userinfo['pass'], $userinfo['name'], $userinfo['mail'], $groups))."\n";
+
+ if(!$this->deleteUsers(array($user))) {
+ msg('Unable to modify user data. Please inform the Wiki-Admin', -1);
+ return false;
+ }
+
+ if(!io_saveFile($config_cascade['plainauth.users']['default'], $userline, true)) {
+ msg('There was an error modifying your user data. You should register again.', -1);
+ // FIXME, user has been deleted but not recreated, should force a logout and redirect to login page
+ $ACT = 'register';
+ return false;
+ }
+
+ $this->users[$newuser] = $userinfo;
+ return true;
+ }
+
+ /**
+ * Remove one or more users from the list of registered users
+ *
+ * @author Christopher Smith <chris@jalakai.co.uk>
+ * @param array $users array of users to be deleted
+ * @return int the number of users deleted
+ */
+ public function deleteUsers($users) {
+ global $config_cascade;
+
+ if(!is_array($users) || empty($users)) return 0;
+
+ if($this->users === null) $this->_loadUserData();
+
+ $deleted = array();
+ foreach($users as $user) {
+ if(isset($this->users[$user])) $deleted[] = preg_quote($user, '/');
+ }
+
+ if(empty($deleted)) return 0;
+
+ $pattern = '/^('.join('|', $deleted).'):/';
+ io_deleteFromFile($config_cascade['plainauth.users']['default'], $pattern, true);
+
+ // reload the user list and count the difference
+ $count = count($this->users);
+ $this->_loadUserData();
+ $count -= count($this->users);
+ return $count;
+ }
+
+ /**
+ * Return a count of the number of user which meet $filter criteria
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ *
+ * @param array $filter
+ * @return int
+ */
+ public function getUserCount($filter = array()) {
+
+ if($this->users === null) $this->_loadUserData();
+
+ if(!count($filter)) return count($this->users);
+
+ $count = 0;
+ $this->_constructPattern($filter);
+
+ foreach($this->users as $user => $info) {
+ $count += $this->_filter($user, $info);
+ }
+
+ return $count;
+ }
+
+ /**
+ * Bulk retrieval of user data
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ *
+ * @param int $start index of first user to be returned
+ * @param int $limit max number of users to be returned
+ * @param array $filter array of field/pattern pairs
+ * @return array userinfo (refer getUserData for internal userinfo details)
+ */
+ public function retrieveUsers($start = 0, $limit = 0, $filter = array()) {
+
+ if($this->users === null) $this->_loadUserData();
+
+ ksort($this->users);
+
+ $i = 0;
+ $count = 0;
+ $out = array();
+ $this->_constructPattern($filter);
+
+ foreach($this->users as $user => $info) {
+ if($this->_filter($user, $info)) {
+ if($i >= $start) {
+ $out[$user] = $info;
+ $count++;
+ if(($limit > 0) && ($count >= $limit)) break;
+ }
+ $i++;
+ }
+ }
+
+ return $out;
+ }
+
+ /**
+ * Only valid pageid's (no namespaces) for usernames
+ *
+ * @param string $user
+ * @return string
+ */
+ public function cleanUser($user) {
+ global $conf;
+ return cleanID(str_replace(':', $conf['sepchar'], $user));
+ }
+
+ /**
+ * Only valid pageid's (no namespaces) for groupnames
+ *
+ * @param string $group
+ * @return string
+ */
+ public function cleanGroup($group) {
+ global $conf;
+ return cleanID(str_replace(':', $conf['sepchar'], $group));
+ }
+
+ /**
+ * Load all user data
+ *
+ * loads the user file into a datastructure
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+ protected function _loadUserData() {
+ global $config_cascade;
+
+ $this->users = array();
+
+ if(!@file_exists($config_cascade['plainauth.users']['default'])) return;
+
+ $lines = file($config_cascade['plainauth.users']['default']);
+ foreach($lines as $line) {
+ $line = preg_replace('/#.*$/', '', $line); //ignore comments
+ $line = trim($line);
+ if(empty($line)) continue;
+
+ $row = explode(":", $line, 5);
+ $groups = array_values(array_filter(explode(",", $row[4])));
+
+ $this->users[$row[0]]['pass'] = $row[1];
+ $this->users[$row[0]]['name'] = urldecode($row[2]);
+ $this->users[$row[0]]['mail'] = $row[3];
+ $this->users[$row[0]]['grps'] = $groups;
+ }
+ }
+
+ /**
+ * return true if $user + $info match $filter criteria, false otherwise
+ *
+ * @author Chris Smith <chris@jalakai.co.uk>
+ *
+ * @param string $user User login
+ * @param array $info User's userinfo array
+ * @return bool
+ */
+ protected function _filter($user, $info) {
+ foreach($this->_pattern as $item => $pattern) {
+ if($item == 'user') {
+ if(!preg_match($pattern, $user)) return false;
+ } else if($item == 'grps') {
+ if(!count(preg_grep($pattern, $info['grps']))) return false;
+ } else {
+ if(!preg_match($pattern, $info[$item])) return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * construct a filter pattern
+ *
+ * @param array $filter
+ */
+ protected function _constructPattern($filter) {
+ $this->_pattern = array();
+ foreach($filter as $item => $pattern) {
+ $this->_pattern[$item] = '/'.str_replace('/', '\/', $pattern).'/i'; // allow regex characters
+ }
+ }
+} \ No newline at end of file
diff --git a/lib/plugins/authplain/plugin.info.txt b/lib/plugins/authplain/plugin.info.txt
new file mode 100644
index 000000000..8d9d3a82d
--- /dev/null
+++ b/lib/plugins/authplain/plugin.info.txt
@@ -0,0 +1,7 @@
+base authplain
+author Andreas Gohr
+email andi@splitbrain.org
+date 2012-11-09
+name auth plugin
+desc Provides authentication against local password storage
+url http://www.dokuwiki.org/plugin:authplain
diff --git a/lib/plugins/config/_test/configuration.test.php b/lib/plugins/config/_test/configuration.test.php
new file mode 100644
index 000000000..b808ad505
--- /dev/null
+++ b/lib/plugins/config/_test/configuration.test.php
@@ -0,0 +1,33 @@
+<?php
+
+class plugin_config_configuration_test extends DokuWikiTest {
+
+ private $config = '';
+ private $meta = '';
+
+ function __construct() {
+ $this->config = dirname(__FILE__).'/data/config.php';
+ $this->meta = dirname(__FILE__).'/data/metadata.php';
+ require_once(dirname(__FILE__).'/../settings/config.class.php');
+ }
+
+ function test_readconfig() {
+ $confmgr = new configuration($this->meta);
+
+ $conf = $confmgr->_read_config($this->config);
+
+ //print_r($conf);
+
+ $this->assertEquals('42', $conf['int1']);
+ $this->assertEquals('6*7', $conf['int2']);
+
+ $this->assertEquals('Hello World', $conf['str1']);
+ $this->assertEquals('G\'day World', $conf['str2']);
+ $this->assertEquals('Hello World', $conf['str3']);
+ $this->assertEquals("Hello 'World'", $conf['str4']);
+ $this->assertEquals('Hello "World"', $conf['str5']);
+
+ $this->assertEquals(array('foo', 'bar', 'baz'), $conf['arr1']);
+ }
+
+}
diff --git a/lib/plugins/config/_test/data/config.php b/lib/plugins/config/_test/data/config.php
new file mode 100644
index 000000000..83255f937
--- /dev/null
+++ b/lib/plugins/config/_test/data/config.php
@@ -0,0 +1,16 @@
+<?php
+
+
+$conf['int1'] = 42;
+$conf['int2'] = 6*7;
+
+$conf['str1'] = 'Hello World';
+$conf['str2'] = 'G\'day World';
+$conf['str3'] = "Hello World";
+$conf['str4'] = "Hello 'World'";
+$conf['str5'] = "Hello \"World\"";
+
+$conf['arr1'] = array('foo','bar', 'baz');
+
+$conf['foo']['bar'] = 'x1';
+$conf['foo']['baz'] = 'x2';
diff --git a/lib/plugins/config/_test/data/metadata.php b/lib/plugins/config/_test/data/metadata.php
new file mode 100644
index 000000000..12902e525
--- /dev/null
+++ b/lib/plugins/config/_test/data/metadata.php
@@ -0,0 +1,13 @@
+<?php
+
+$meta['int1'] = array('numeric');
+$meta['int2'] = array('numeric');
+
+$meta['str1'] = array('string');
+$meta['str2'] = array('string');
+$meta['str3'] = array('string');
+$meta['str4'] = array('string');
+$meta['str5'] = array('string');
+
+$meta['arr1'] = array('array');
+
diff --git a/lib/plugins/config/admin.php b/lib/plugins/config/admin.php
index 0d314d2e6..cbe9d336a 100644
--- a/lib/plugins/config/admin.php
+++ b/lib/plugins/config/admin.php
@@ -65,8 +65,10 @@ class admin_plugin_config extends DokuWiki_Admin_Plugin {
// save state & force a page reload to get the new settings to take effect
$_SESSION['PLUGIN_CONFIG'] = array('state' => 'updated', 'time' => time());
$this->_close_session();
- header("Location: ".wl($ID,array('do'=>'admin','page'=>'config'),true,'&'));
+ send_redirect(wl($ID,array('do'=>'admin','page'=>'config'),true,'&'));
exit();
+ } elseif(!$this->_error) {
+ $this->_config->touch_settings(); // just touch to refresh cache
}
$this->_close_session();
diff --git a/lib/plugins/config/lang/cs/lang.php b/lib/plugins/config/lang/cs/lang.php
index 383afebb4..d35ebec9b 100644
--- a/lib/plugins/config/lang/cs/lang.php
+++ b/lib/plugins/config/lang/cs/lang.php
@@ -12,6 +12,7 @@
* @author zbynek.krivka@seznam.cz
* @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com>
* @author Jakub A. Těšínský (j@kub.cz)
+ * @author mkucera66@seznam.cz
*/
$lang['menu'] = 'Správa nastavení';
$lang['error'] = 'Nastavení nebyla změněna kvůli alespoň jedné neplatné položce,
diff --git a/lib/plugins/config/lang/de-informal/lang.php b/lib/plugins/config/lang/de-informal/lang.php
index d86c2d809..10fa363dc 100644
--- a/lib/plugins/config/lang/de-informal/lang.php
+++ b/lib/plugins/config/lang/de-informal/lang.php
@@ -8,58 +8,62 @@
* @author Matthias Schulte <dokuwiki@lupo49.de>
* @author Christian Wichmann <nospam@zone0.de>
* @author Pierre Corell <info@joomla-praxis.de>
+ * @author Frank Loizzi <contact@software.bacal.de>
+ * @author Mateng Schimmerlos <mateng@firemail.de>
+ * @author Volker Bödker <volker@boedker.de>
*/
-$lang['menu'] = 'Einstellungen';
-$lang['error'] = 'Einstellungen wurden nicht aktualisiert auf Grund eines ungültigen Wertes. Bitte überprüfe deine Änderungen und versuche es erneut.<br />Die/der ungültige(n) Wert(e) werden durch eine rote Umrandung hervorgehoben.';
-$lang['updated'] = 'Einstellungen erfolgreich aktualisiert.';
+$lang['menu'] = 'Konfiguration';
+$lang['error'] = 'Konfiguration wurde nicht aktualisiert auf Grund eines ungültigen Wertes. Bitte überprüfe deine Änderungen und versuche es erneut.<br />Die/der ungültige(n) Wert(e) werden durch eine rote Umrandung hervorgehoben.';
+$lang['updated'] = 'Konfiguration erfolgreich aktualisiert.';
$lang['nochoice'] = '(keine andere Option möglich)';
-$lang['locked'] = 'Die Einstellungsdatei kann nicht aktualisiert werden. Wenn dies unbeabsichtigt ist stelle sicher, dass der Name und die Zugriffsrechte der Einstellungsdatei richtig sind.';
+$lang['locked'] = 'Die Konfigurationsdatei kann nicht aktualisiert werden. Wenn dies unbeabsichtigt ist stelle sicher, dass der Name und die Zugriffsrechte der Konfigurationsdatei richtig sind.';
$lang['danger'] = '**Achtung**: Eine Änderung dieser Einstellung kann dein Wiki und das Einstellungsmenü unerreichbar machen.';
$lang['warning'] = 'Achtung: Eine Änderungen dieser Option kann zu unbeabsichtigtem Verhalten führen.';
$lang['security'] = 'Sicherheitswarnung: Eine Änderungen dieser Option können ein Sicherheitsrisiko bedeuten.';
-$lang['_configuration_manager'] = 'Einstellungen';
-$lang['_header_dokuwiki'] = 'DokuWiki-Einstellungen';
-$lang['_header_plugin'] = 'Plugin-Einstellungen';
-$lang['_header_template'] = 'Vorlageneinstellungen';
-$lang['_header_undefined'] = 'unbestimmte Einstellungen';
-$lang['_basic'] = 'Grundeinstellungen';
-$lang['_display'] = 'Darstellungs-Einstellungen';
-$lang['_authentication'] = 'Bestätigungseinstellungen';
-$lang['_anti_spam'] = 'Anti-Spam-Einstellungen';
-$lang['_editing'] = 'Bearbeitungseinstellungen';
-$lang['_links'] = 'Link-Einstellungen';
-$lang['_media'] = 'Media-Einstellungen';
+$lang['_configuration_manager'] = 'Konfiguration';
+$lang['_header_dokuwiki'] = 'DokuWiki-Konfiguration';
+$lang['_header_plugin'] = 'Plugin-Konfiguration';
+$lang['_header_template'] = 'Template-Konfiguration';
+$lang['_header_undefined'] = 'Unbekannte Werte';
+$lang['_basic'] = 'Grund-Konfiguration';
+$lang['_display'] = 'Darstellungs-Konfiguration';
+$lang['_authentication'] = 'Authentifizierung-Konfiguration';
+$lang['_anti_spam'] = 'Anti-Spam-Konfiguration';
+$lang['_editing'] = 'Bearbeitungs-Konfiguration';
+$lang['_links'] = 'Links-Konfiguration';
+$lang['_media'] = 'Medien-Konfiguration';
$lang['_notifications'] = 'Benachrichtigungs-Konfiguration';
$lang['_syndication'] = 'Syndication-Konfiguration (RSS)';
-$lang['_advanced'] = 'erweiterte Einstellungen';
-$lang['_network'] = 'Netzwerk-Einstellungen';
-$lang['_plugin_sufix'] = 'Plugin-Einstellungen';
-$lang['_template_sufix'] = 'Vorlageneinstellungen';
+$lang['_advanced'] = 'Erweiterte Konfiguration';
+$lang['_network'] = 'Netzwerk-Konfiguration';
+$lang['_plugin_sufix'] = 'Plugin-Konfiguration';
+$lang['_template_sufix'] = 'Template-Konfiguration';
$lang['_msg_setting_undefined'] = 'Keine Konfigurationsmetadaten.';
$lang['_msg_setting_no_class'] = 'Keine Konfigurationsklasse.';
$lang['_msg_setting_no_default'] = 'Kein Standardwert.';
-$lang['fmode'] = 'Zugriffsrechte bei Dateierstellung';
-$lang['dmode'] = 'Zugriffsrechte bei Verzeichniserstellung';
-$lang['lang'] = 'Sprache';
-$lang['basedir'] = 'Installationsverzeichnis';
-$lang['baseurl'] = 'Installationspfad (URL)';
-$lang['savedir'] = 'Ordner zum Speichern von Daten';
-$lang['cookiedir'] = 'Cookie Pfad. Leer lassen, um die Standard-Url zu belassen.';
-$lang['start'] = 'Name der Startseite';
$lang['title'] = 'Wiki Titel';
+$lang['start'] = 'Name der Startseite';
+$lang['lang'] = 'Sprache';
$lang['template'] = 'Vorlage';
$lang['tagline'] = 'Tag-Linie (nur, wenn vom Template unterstützt)';
$lang['sidebar'] = 'Name der Sidebar-Seite (nur, wenn vom Template unterstützt)), ein leeres Feld deaktiviert die Sidebar';
$lang['license'] = 'Unter welcher Lizenz sollte Ihr Inhalt veröffentlicht werden?';
-$lang['fullpath'] = 'Zeige vollen Pfad der Datei in Fußzeile an';
+$lang['savedir'] = 'Ordner zum Speichern von Daten';
+$lang['basedir'] = 'Installationsverzeichnis';
+$lang['baseurl'] = 'Installationspfad (URL)';
+$lang['cookiedir'] = 'Cookie Pfad. Leer lassen, um die Standard-Url zu belassen.';
+$lang['dmode'] = 'Zugriffsrechte bei Verzeichniserstellung';
+$lang['fmode'] = 'Zugriffsrechte bei Dateierstellung';
+$lang['allowdebug'] = 'Debug-Ausgaben erlauben <b>Abschalten wenn nicht benötigt!</b>';
$lang['recent'] = 'letzte Änderungen';
+$lang['recent_days'] = 'Wie viele Änderungen sollen vorgehalten werden? (Tage)';
$lang['breadcrumbs'] = 'Anzahl der Einträge im "Krümelpfad"';
$lang['youarehere'] = 'Hierarchische Pfadnavigation verwenden';
+$lang['fullpath'] = 'Zeige vollen Pfad der Datei in Fußzeile an';
$lang['typography'] = 'Mach drucktechnische Ersetzungen';
-$lang['htmlok'] = 'Erlaube eingebettetes HTML';
-$lang['phpok'] = 'Erlaube eingebettetes PHP';
$lang['dformat'] = 'Datumsformat (siehe PHPs <a href="http://www.php.net/strftime">strftime</a> Funktion)';
$lang['signature'] = 'Signatur';
+$lang['showuseras'] = 'Was angezeigt werden soll, wenn der Benutzer, der zuletzt eine Seite bearbeitet hat, angezeigt wird';
$lang['toptoclevel'] = 'Inhaltsverzeichnis bei dieser Überschriftengröße beginnen';
$lang['tocminheads'] = 'Mindestanzahl der Überschriften die entscheidet, ob ein Inhaltsverzeichnis erscheinen soll';
$lang['maxtoclevel'] = 'Maximale Überschriftsgröße für Inhaltsverzeichnis';
@@ -67,16 +71,8 @@ $lang['maxseclevel'] = 'Abschnitte bis zu dieser Stufe einzeln editier
$lang['camelcase'] = 'CamelCase-Verlinkungen verwenden';
$lang['deaccent'] = 'Seitennamen bereinigen';
$lang['useheading'] = 'Erste Überschrift als Seitennamen verwenden';
-$lang['refcheck'] = 'Auf Verwendung beim Löschen von Media-Dateien testen';
-$lang['refshow'] = 'Wie viele Verwendungsorte der Media-Datei zeigen';
-$lang['allowdebug'] = 'Debug-Ausgaben erlauben <b>Abschalten wenn nicht benötigt!</b>';
-$lang['mediarevisions'] = 'Media-Revisionen (ältere Versionen) aktivieren?';
-$lang['usewordblock'] = 'Blockiere Spam basierend auf der Wortliste';
-$lang['indexdelay'] = 'Zeit bevor Suchmaschinenindexierung erlaubt ist';
-$lang['relnofollow'] = 'rel="nofollow" verwenden';
-$lang['mailguard'] = 'E-Mail-Adressen schützen';
-$lang['iexssprotect'] = 'Hochgeladene Dateien auf bösartigen JavaScript- und HTML-Code untersuchen';
-$lang['showuseras'] = 'Was angezeigt werden soll, wenn der Benutzer, der zuletzt eine Seite bearbeitet hat, angezeigt wird';
+$lang['sneaky_index'] = 'Standardmäßig zeigt DokuWiki alle Namensräume in der Indexansicht an. Bei Aktivierung dieser Einstellung werden alle Namensräume versteckt, in welchen der Benutzer keine Leserechte hat. Dies könnte dazu führen, dass lesbare Unternamensräume versteckt werden. Dies kann die Indexansicht bei bestimmten Zugangskontrolleinstellungen unbenutzbar machen.';
+$lang['hidepages'] = 'Seiten verstecken (Regulärer Ausdruck)';
$lang['useacl'] = 'Benutze Zugangskontrollliste';
$lang['autopasswd'] = 'Automatisch erzeugte Passwörter';
$lang['authtype'] = 'Authentifizierungsmethode';
@@ -85,62 +81,69 @@ $lang['defaultgroup'] = 'Standardgruppe';
$lang['superuser'] = 'Administrator - Eine Gruppe oder Nutzer mit vollem Zugriff auf alle Seiten und Administrationswerkzeuge.';
$lang['manager'] = 'Manager - Eine Gruppe oder Nutzer mit Zugriff auf einige Administrationswerkzeuge.';
$lang['profileconfirm'] = 'Änderungen am Benutzerprofil mit Passwort bestätigen';
+$lang['rememberme'] = 'Permanente Login-Cookies erlauben (Auf diesem Computer eingeloggt bleiben)';
$lang['disableactions'] = 'Deaktiviere DokuWiki\'s Zugriffe';
$lang['disableactions_check'] = 'Check';
$lang['disableactions_subscription'] = 'Bestellen/Abbestellen';
$lang['disableactions_wikicode'] = 'Zeige Quelle/Exportiere Rohdaten';
$lang['disableactions_other'] = 'Weitere Aktionen (durch Komma getrennt)';
-$lang['sneaky_index'] = 'Standardmäßig zeigt DokuWiki alle Namensräume in der Indexansicht an. Bei Aktivierung dieser Einstellung werden alle Namensräume versteckt, in welchen der Benutzer keine Leserechte hat. Dies könnte dazu führen, dass lesbare Unternamensräume versteckt werden. Dies kann die Indexansicht bei bestimmten Zugangskontrolleinstellungen unbenutzbar machen.';
$lang['auth_security_timeout'] = 'Zeitüberschreitung bei der Authentifizierung (Sekunden)';
$lang['securecookie'] = 'Sollen Cookies, die via HTTPS gesetzt wurden nur per HTTPS versendet werden? Deaktiviere diese Option, wenn nur der Login deines Wikis mit SSL gesichert ist, aber das Betrachten des Wikis ungesichert geschieht.';
$lang['remote'] = 'Aktiviert den externen API-Zugang. Diese Option erlaubt es externen Anwendungen von außen auf die XML-RPC-Schnittstelle oder anderweitigen Schnittstellen zuzugreifen.';
$lang['remoteuser'] = 'Zugriff auf die externen Schnittstellen durch kommaseparierte Angabe von Benutzern oder Gruppen einschränken. Ein leeres Feld erlaubt Zugriff für jeden.';
-$lang['updatecheck'] = 'Automatisch auf Updates und Sicherheitswarnungen prüfen? DokuWiki muss sich dafür mit update.dokuwiki.org verbinden.';
-$lang['userewrite'] = 'Benutze schöne URLs';
-$lang['useslash'] = 'Benutze Schrägstrich als Namensraumtrenner in URLs';
+$lang['usewordblock'] = 'Blockiere Spam basierend auf der Wortliste';
+$lang['relnofollow'] = 'rel="nofollow" verwenden';
+$lang['indexdelay'] = 'Zeit bevor Suchmaschinenindexierung erlaubt ist';
+$lang['mailguard'] = 'E-Mail-Adressen schützen';
+$lang['iexssprotect'] = 'Hochgeladene Dateien auf bösartigen JavaScript- und HTML-Code untersuchen';
$lang['usedraft'] = 'Speichere automatisch Entwürfe während der Bearbeitung';
-$lang['sepchar'] = 'Worttrenner für Seitennamen in URLs';
-$lang['canonical'] = 'Immer Links mit vollständigen URLs erzeugen';
-$lang['fnencode'] = 'Methode um nicht-ASCII Dateinamen zu kodieren.';
-$lang['autoplural'] = 'Bei Links automatisch nach vorhandenen Pluralformen suchen';
-$lang['compression'] = 'Komprimierungsmethode für alte Seitenrevisionen';
-$lang['cachetime'] = 'Maximale Cachespeicherung (Sekunden)';
+$lang['htmlok'] = 'Erlaube eingebettetes HTML';
+$lang['phpok'] = 'Erlaube eingebettetes PHP';
$lang['locktime'] = 'Maximales Alter für Seitensperren (Sekunden)';
+$lang['cachetime'] = 'Maximale Cachespeicherung (Sekunden)';
+$lang['target____wiki'] = 'Zielfenstername für interne Links';
+$lang['target____interwiki'] = 'Zielfenstername für InterWiki-Links';
+$lang['target____extern'] = 'Zielfenstername für externe Links';
+$lang['target____media'] = 'Zielfenstername für Medienlinks';
+$lang['target____windows'] = 'Zielfenstername für Windows-Freigaben-Links';
+$lang['mediarevisions'] = 'Media-Revisionen (ältere Versionen) aktivieren?';
+$lang['refcheck'] = 'Auf Verwendung beim Löschen von Media-Dateien testen';
+$lang['refshow'] = 'Wie viele Verwendungsorte der Media-Datei zeigen';
+$lang['gdlib'] = 'GD Lib Version';
+$lang['im_convert'] = 'Pfad zu ImageMagicks-Konvertierwerkzeug';
+$lang['jpg_quality'] = 'JPEG Kompressionsqualität (0-100)';
$lang['fetchsize'] = 'Maximale Größe (in Bytes), die fetch.php von extern herunterladen darf';
+$lang['subscribers'] = 'E-Mail-Abos zulassen';
+$lang['subscribe_time'] = 'Zeit nach der Zusammenfassungs- und Änderungslisten-E-Mails verschickt werden; Dieser Wert sollte kleiner als die in recent_days konfigurierte Zeit sein.';
$lang['notify'] = 'Sende Änderungsbenachrichtigungen an diese E-Mail-Adresse.';
$lang['registernotify'] = 'Sende Information bei neu registrierten Benutzern an diese E-Mail-Adresse.';
$lang['mailfrom'] = 'Absenderadresse für automatisch erzeugte E-Mails';
$lang['mailprefix'] = 'Präfix für E-Mail-Betreff beim automatischen Versand von Benachrichtigungen';
$lang['htmlmail'] = 'Versendet optisch angenehmere, aber größere E-Mails im HTML-Format (multipart). Deaktivieren, um Text-Mails zu versenden.';
+$lang['sitemap'] = 'Erzeuge Google Sitemaps (Tage)';
+$lang['rss_type'] = 'XML-Feed-Format';
+$lang['rss_linkto'] = 'XML-Feed verlinken auf';
+$lang['rss_content'] = 'Was soll in XML-Feedinhalten angezeigt werden?';
+$lang['rss_update'] = 'Aktualisierungsintervall für XML-Feeds (Sekunden)';
+$lang['rss_show_summary'] = 'Bearbeitungs-Zusammenfassung im XML-Feed anzeigen';
+$lang['rss_media'] = 'Welche Änderungen sollen im XML-Feed angezeigt werden?';
+$lang['updatecheck'] = 'Automatisch auf Updates und Sicherheitswarnungen prüfen? DokuWiki muss sich dafür mit update.dokuwiki.org verbinden.';
+$lang['userewrite'] = 'Benutze schöne URLs';
+$lang['useslash'] = 'Benutze Schrägstrich als Namensraumtrenner in URLs';
+$lang['sepchar'] = 'Worttrenner für Seitennamen in URLs';
+$lang['canonical'] = 'Immer Links mit vollständigen URLs erzeugen';
+$lang['fnencode'] = 'Methode um nicht-ASCII Dateinamen zu kodieren.';
+$lang['autoplural'] = 'Bei Links automatisch nach vorhandenen Pluralformen suchen';
+$lang['compression'] = 'Komprimierungsmethode für alte Seitenrevisionen';
$lang['gzip_output'] = 'Seiten mit gzip komprimiert ausliefern';
-$lang['gdlib'] = 'GD Lib Version';
-$lang['im_convert'] = 'Pfad zu ImageMagicks-Konvertierwerkzeug';
-$lang['jpg_quality'] = 'JPEG Kompressionsqualität (0-100)';
-$lang['subscribers'] = 'E-Mail-Abos zulassen';
-$lang['subscribe_time'] = 'Zeit nach der Zusammenfassungs- und Änderungslisten-E-Mails verschickt werden; Dieser Wert sollte kleiner als die in recent_days konfigurierte Zeit sein.';
$lang['compress'] = 'JavaScript und Stylesheets komprimieren';
$lang['cssdatauri'] = 'Größe in Bytes, bis zu der Bilder in css-Dateien referenziert werden können, um HTTP-Anfragen zu minimieren. Diese Technik funktioniert nicht im IE 7 und älter! <code>400</code> bis <code>600</code> Bytes sind gute Werte. Setze <code>0</code> für inaktive Funktion.';
-$lang['hidepages'] = 'Seiten verstecken (Regulärer Ausdruck)';
$lang['send404'] = 'Sende "HTTP 404/Seite nicht gefunden" für nicht existierende Seiten';
-$lang['sitemap'] = 'Erzeuge Google Sitemaps (Tage)';
$lang['broken_iua'] = 'Falls die Funktion ignore_user_abort auf deinem System nicht funktioniert, könnte der Such-Index nicht funktionieren. IIS+PHP/CGI ist bekannt dafür. Siehe auch <a href="http://bugs.splitbrain.org/?do=details&amp;task_id=852">Bug 852</a>.';
$lang['xsendfile'] = 'Den X-Sendfile-Header nutzen, um Dateien direkt vom Webserver ausliefern zu lassen? Dein Webserver muss dies unterstützen!';
$lang['renderer_xhtml'] = 'Standard-Renderer für die normale (XHTML) Wiki-Ausgabe.';
$lang['renderer__core'] = '%s (DokuWiki Kern)';
$lang['renderer__plugin'] = '%s (Erweiterung)';
-$lang['rememberme'] = 'Permanente Login-Cookies erlauben (Auf diesem Computer eingeloggt bleiben)';
-$lang['rss_type'] = 'XML-Feed-Format';
-$lang['rss_linkto'] = 'XML-Feed verlinken auf';
-$lang['rss_content'] = 'Was soll in XML-Feedinhalten angezeigt werden?';
-$lang['rss_update'] = 'Aktualisierungsintervall für XML-Feeds (Sekunden)';
-$lang['recent_days'] = 'Wie viele Änderungen sollen vorgehalten werden? (Tage)';
-$lang['rss_show_summary'] = 'Bearbeitungs-Zusammenfassung im XML-Feed anzeigen';
-$lang['rss_media'] = 'Welche Änderungen sollen im XML-Feed angezeigt werden?';
-$lang['target____wiki'] = 'Zielfenstername für interne Links';
-$lang['target____interwiki'] = 'Zielfenstername für InterWiki-Links';
-$lang['target____extern'] = 'Zielfenstername für externe Links';
-$lang['target____media'] = 'Zielfenstername für Medienlinks';
-$lang['target____windows'] = 'Zielfenstername für Windows-Freigaben-Links';
$lang['dnslookups'] = 'DokuWiki löst die IP-Adressen von Benutzern zu deren Hostnamen auf. Wenn du einen langsamen, unbrauchbaren DNS-Server verwendest oder die Funktion nicht benötigst, dann sollte diese Option deaktivert sein.';
$lang['proxy____host'] = 'Proxyadresse';
$lang['proxy____port'] = 'Proxyport';
diff --git a/lib/plugins/config/lang/de/lang.php b/lib/plugins/config/lang/de/lang.php
index bcbc061a3..dd29f8038 100644
--- a/lib/plugins/config/lang/de/lang.php
+++ b/lib/plugins/config/lang/de/lang.php
@@ -17,14 +17,13 @@
* @author Paul Lachewsky <kaeptn.haddock@gmail.com>
* @author Pierre Corell <info@joomla-praxis.de>
* @author Matthias Schulte <dokuwiki@lupo49.de>
+ * @author Mateng Schimmerlos <mateng@firemail.de>
*/
$lang['menu'] = 'Konfiguration';
-$lang['error'] = 'Die Einstellungen wurden wegen einer fehlerhaften Eingabe nicht gespeichert.
-<br />Bitte überprüfen sie die rot umrandeten Eingaben und speichern Sie erneut.';
+$lang['error'] = 'Die Einstellungen wurden wegen einer fehlerhaften Eingabe nicht gespeichert.<br /> Bitte überprüfen sie die rot umrandeten Eingaben und speichern Sie erneut.';
$lang['updated'] = 'Einstellungen erfolgreich gespeichert.';
$lang['nochoice'] = '(keine Auswahlmöglichkeiten vorhanden)';
-$lang['locked'] = 'Die Konfigurationsdatei kann nicht geändert werden, wenn dies unbeabsichtigt ist
- <br />überprüfen Sie, dass die Dateiberechtigungen korrekt gesetzt sind.';
+$lang['locked'] = 'Die Konfigurationsdatei kann nicht geändert werden. Wenn dies unbeabsichtigt ist, <br />überprüfen Sie, ob die Dateiberechtigungen korrekt gesetzt sind.';
$lang['danger'] = 'Vorsicht: Die Änderung dieser Option könnte Ihr Wiki und das Konfigurationsmenü unzugänglich machen.';
$lang['warning'] = 'Hinweis: Die Änderung dieser Option könnte unbeabsichtigtes Verhalten hervorrufen.';
$lang['security'] = 'Sicherheitswarnung: Die Änderung dieser Option könnte ein Sicherheitsrisiko darstellen.';
@@ -32,13 +31,13 @@ $lang['_configuration_manager'] = 'Konfiguration';
$lang['_header_dokuwiki'] = 'DokuWiki-Konfiguration';
$lang['_header_plugin'] = 'Plugin-Konfiguration';
$lang['_header_template'] = 'Template-Konfiguration';
-$lang['_header_undefined'] = 'Unbekannte Einstellungen';
+$lang['_header_undefined'] = 'Unbekannte Werte';
$lang['_basic'] = 'Grund-Konfiguration';
-$lang['_display'] = 'Anzeige-Konfiguration';
+$lang['_display'] = 'Darstellungs-Konfiguration';
$lang['_authentication'] = 'Authentifizierungs-Konfiguration';
$lang['_anti_spam'] = 'Anti-Spam-Konfiguration';
$lang['_editing'] = 'Bearbeitungs-Konfiguration';
-$lang['_links'] = 'Link-Konfiguration';
+$lang['_links'] = 'Links-Konfiguration';
$lang['_media'] = 'Medien-Konfiguration';
$lang['_notifications'] = 'Benachrichtigungs-Konfiguration';
$lang['_syndication'] = 'Syndication-Konfiguration (RSS)';
@@ -49,8 +48,8 @@ $lang['_template_sufix'] = 'Template-Konfiguration';
$lang['_msg_setting_undefined'] = 'Keine Konfigurationsmetadaten.';
$lang['_msg_setting_no_class'] = 'Keine Konfigurationsklasse.';
$lang['_msg_setting_no_default'] = 'Kein Standardwert.';
-$lang['fmode'] = 'Rechte für neue Dateien';
-$lang['dmode'] = 'Rechte für neue Verzeichnisse';
+$lang['fmode'] = 'Berechtigungen für neue Dateien';
+$lang['dmode'] = 'Berechtigungen für neue Verzeichnisse';
$lang['lang'] = 'Sprache';
$lang['basedir'] = 'Installationsverzeichnis';
$lang['baseurl'] = 'Installationspfad (URL)';
@@ -198,7 +197,7 @@ $lang['xsendfile_o_0'] = 'nicht benutzen';
$lang['xsendfile_o_1'] = 'Proprietärer lighttpd-Header (vor Release 1.5)';
$lang['xsendfile_o_2'] = 'Standard X-Sendfile-Header';
$lang['xsendfile_o_3'] = 'Proprietärer Nginx X-Accel-Redirect-Header';
-$lang['showuseras_o_loginname'] = 'Loginname';
+$lang['showuseras_o_loginname'] = 'Login-Name';
$lang['showuseras_o_username'] = 'Vollständiger Name des Benutzers';
$lang['showuseras_o_email'] = 'E-Mail-Adresse des Benutzers (je nach Mailguard-Einstellung verschleiert)';
$lang['showuseras_o_email_link'] = 'E-Mail-Adresse des Benutzers als mailto:-Link';
diff --git a/lib/plugins/config/lang/el/lang.php b/lib/plugins/config/lang/el/lang.php
index 093212664..d2801e507 100644
--- a/lib/plugins/config/lang/el/lang.php
+++ b/lib/plugins/config/lang/el/lang.php
@@ -12,6 +12,7 @@
* @author Konstantinos Koryllos <koryllos@gmail.com>
* @author George Petsagourakis <petsagouris@gmail.com>
* @author Petros Vidalis <pvidalis@gmail.com>
+ * @author Vasileios Karavasilis vasileioskaravasilis@gmail.com
*/
$lang['menu'] = 'Ρυθμίσεις';
$lang['error'] = 'Οι ρυθμίσεις σας δεν έγιναν δεκτές λόγω λανθασμένης τιμής κάποιας ρύθμισης. Διορθώστε την λάθος τιμή και προσπαθήστε ξανά.
@@ -34,6 +35,8 @@ $lang['_anti_spam'] = 'Ρυθμίσεις Anti-Spam';
$lang['_editing'] = 'Ρυθμίσεις Σύνταξης σελίδων';
$lang['_links'] = 'Ρυθμίσεις Συνδέσμων';
$lang['_media'] = 'Ρυθμίσεις Αρχείων';
+$lang['_notifications'] = 'Ρυθμίσεις ενημερώσεων';
+$lang['_syndication'] = 'Ρυθμίσεις σύνδεσης';
$lang['_advanced'] = 'Ρυθμίσεις για Προχωρημένους';
$lang['_network'] = 'Ρυθμίσεις Δικτύου';
$lang['_plugin_sufix'] = 'Ρυθμίσεις Επεκτάσεων';
@@ -41,26 +44,29 @@ $lang['_template_sufix'] = 'Ρυθμίσεις Προτύπων παρου
$lang['_msg_setting_undefined'] = 'Δεν έχουν οριστεί metadata.';
$lang['_msg_setting_no_class'] = 'Δεν έχει οριστεί κλάση.';
$lang['_msg_setting_no_default'] = 'Δεν υπάρχει τιμή εξ ορισμού.';
-$lang['fmode'] = 'Δικαιώματα πρόσβασης δημιουργούμενων αρχείων';
-$lang['dmode'] = 'Δικαιώματα πρόσβασης δημιουργούμενων φακέλων';
+$lang['title'] = 'Τίτλος Wiki';
+$lang['start'] = 'Ονομασία αρχικής σελίδας';
$lang['lang'] = 'Γλώσσα';
+$lang['template'] = 'Πρότυπο προβολής';
+$lang['tagline'] = 'Tagline';
+$lang['sidebar'] = 'Sidebar page name';
+$lang['license'] = 'Κάτω από ποια άδεια θέλετε να δημοσιευτεί το υλικό σας?';
+$lang['savedir'] = 'Φάκελος για την αποθήκευση δεδομένων';
$lang['basedir'] = 'Αρχικός Φάκελος';
$lang['baseurl'] = 'Αρχικό URL';
-$lang['savedir'] = 'Φάκελος για την αποθήκευση δεδομένων';
$lang['cookiedir'] = 'Διαδρομή cookie. Αφήστε την κενή για την χρησιμοποίηση της αρχικής URL.';
-$lang['start'] = 'Ονομασία αρχικής σελίδας';
-$lang['title'] = 'Τίτλος Wiki';
-$lang['template'] = 'Πρότυπο προβολής';
-$lang['license'] = 'Κάτω από ποια άδεια θέλετε να δημοσιευτεί το υλικό σας?';
-$lang['fullpath'] = 'Εμφάνιση πλήρους διαδρομής σελίδας στην υποκεφαλίδα';
+$lang['dmode'] = 'Δικαιώματα πρόσβασης δημιουργούμενων φακέλων';
+$lang['fmode'] = 'Δικαιώματα πρόσβασης δημιουργούμενων αρχείων';
+$lang['allowdebug'] = 'Δεδομένα εκσφαλμάτωσης (debug) <b>απενεργοποιήστε τα εάν δεν τα έχετε ανάγκη!</b>';
$lang['recent'] = 'Αριθμός πρόσφατων αλλαγών ανά σελίδα';
+$lang['recent_days'] = 'Πόσο παλιές αλλαγές να εμφανίζονται (ημέρες)';
$lang['breadcrumbs'] = 'Αριθμός συνδέσμων ιστορικού';
$lang['youarehere'] = 'Εμφάνιση ιεραρχικής προβολής τρέχουσας σελίδας';
+$lang['fullpath'] = 'Εμφάνιση πλήρους διαδρομής σελίδας στην υποκεφαλίδα';
$lang['typography'] = 'Μετατροπή ειδικών χαρακτήρων στο τυπογραφικό ισοδύναμό τους';
-$lang['htmlok'] = 'Να επιτρέπεται η ενσωμάτωση HTML';
-$lang['phpok'] = 'Να επιτρέπεται η ενσωμάτωση PHP';
$lang['dformat'] = 'Μορφή ημερομηνίας (βλέπε την <a href="http://www.php.net/strftime">strftime</a> function της PHP)';
$lang['signature'] = 'Υπογραφή';
+$lang['showuseras'] = 'Τι να εμφανίζεται όταν φαίνεται ο χρήστης που τροποποίησε τελευταίος μία σελίδα';
$lang['toptoclevel'] = 'Ανώτατο επίπεδο πίνακα περιεχομένων σελίδας';
$lang['tocminheads'] = 'Ελάχιστος αριθμός κεφαλίδων για την δημιουργία πίνακα περιεχομένων - TOC';
$lang['maxtoclevel'] = 'Μέγιστο επίπεδο για πίνακα περιεχομένων σελίδας';
@@ -68,15 +74,8 @@ $lang['maxseclevel'] = 'Μέγιστο επίπεδο για εμφά
$lang['camelcase'] = 'Χρήση CamelCase στους συνδέσμους';
$lang['deaccent'] = 'Αφαίρεση σημείων στίξης από ονόματα σελίδων';
$lang['useheading'] = 'Χρήση κεφαλίδας πρώτου επιπέδου σαν τίτλο συνδέσμων';
-$lang['refcheck'] = 'Πριν τη διαγραφή ενός αρχείου να ελέγχεται η ύπαρξη σελίδων που το χρησιμοποιούν';
-$lang['refshow'] = 'Εμφανιζόμενος αριθμός σελίδων που χρησιμοποιούν ένα αρχείο';
-$lang['allowdebug'] = 'Δεδομένα εκσφαλμάτωσης (debug) <b>απενεργοποιήστε τα εάν δεν τα έχετε ανάγκη!</b>';
-$lang['usewordblock'] = 'Χρήστη λίστα απαγορευμένων λέξεων για καταπολέμηση του spam';
-$lang['indexdelay'] = 'Χρόνος αναμονής προτού επιτραπεί σε μηχανές αναζήτησης να ευρετηριάσουν μια τροποποιημένη σελίδα (sec)';
-$lang['relnofollow'] = 'Χρήση rel="nofollow"';
-$lang['mailguard'] = 'Κωδικοποίηση e-mail διευθύνσεων';
-$lang['iexssprotect'] = 'Έλεγχος μεταφορτώσεων για πιθανώς επικίνδυνο κώδικα JavaScript ή HTML';
-$lang['showuseras'] = 'Τι να εμφανίζεται όταν φαίνεται ο χρήστης που τροποποίησε τελευταίος μία σελίδα';
+$lang['sneaky_index'] = 'Εξ ορισμού, η εφαρμογή DokuWiki δείχνει όλους τους φακέλους στην προβολή Καταλόγου. Ενεργοποιώντας αυτή την επιλογή, δεν θα εμφανίζονται οι φάκελοι για τους οποίους ο χρήστης δεν έχει δικαιώματα ανάγνωσης αλλά και οι υπο-φάκελοί τους ανεξαρτήτως δικαιωμάτων πρόσβασης.';
+$lang['hidepages'] = 'Φίλτρο απόκρυψης σελίδων (regular expressions)';
$lang['useacl'] = 'Χρήση Λίστας Δικαιωμάτων Πρόσβασης (ACL)';
$lang['autopasswd'] = 'Αυτόματη δημιουργία κωδικού χρήστη';
$lang['authtype'] = 'Τύπος πιστοποίησης στοιχείων χρήστη';
@@ -85,58 +84,70 @@ $lang['defaultgroup'] = 'Προεπιλεγμένη ομάδα χρησ
$lang['superuser'] = 'Υπερ-χρήστης - μία ομάδα ή ένας χρήστης με πλήρη δικαιώματα πρόσβασης σε όλες τις σελίδες και όλες τις λειτουργίες ανεξάρτητα από τις ρυθμίσεις των Λιστών Δικαιωμάτων Πρόσβασης (ACL)';
$lang['manager'] = 'Διαχειριστής - μία ομάδα ή ένας χρήστης με δικαιώματα πρόσβασης σε ορισμένες από τις λειτουργίες της εφαρμογής';
$lang['profileconfirm'] = 'Να απαιτείται ο κωδικός χρήστη για την επιβεβαίωση αλλαγών στο προφίλ χρήστη';
+$lang['rememberme'] = 'Να επιτρέπονται τα cookies λογαρισμού χρήστη αορίστου χρόνου (Απομνημόνευση στοιχείων λογαριασμού)';
$lang['disableactions'] = 'Απενεργοποίηση λειτουργιών DokuWiki';
$lang['disableactions_check'] = 'Έλεγχος';
$lang['disableactions_subscription'] = 'Εγγραφή/Διαγραφή χρήστη';
$lang['disableactions_wikicode'] = 'Προβολή κώδικα σελίδας';
$lang['disableactions_other'] = 'Άλλες λειτουργίες (διαχωρίστε τις με κόμμα)';
-$lang['sneaky_index'] = 'Εξ ορισμού, η εφαρμογή DokuWiki δείχνει όλους τους φακέλους στην προβολή Καταλόγου. Ενεργοποιώντας αυτή την επιλογή, δεν θα εμφανίζονται οι φάκελοι για τους οποίους ο χρήστης δεν έχει δικαιώματα ανάγνωσης αλλά και οι υπο-φάκελοί τους ανεξαρτήτως δικαιωμάτων πρόσβασης.';
$lang['auth_security_timeout'] = 'Διάρκεια χρόνου για ασφάλεια πιστοποίησης (δευτερόλεπτα)';
$lang['securecookie'] = 'Τα cookies που έχουν οριστεί μέσω HTTPS πρέπει επίσης να αποστέλλονται μόνο μέσω HTTPS από τον φυλλομετρητή? Απενεργοποιήστε αυτή την επιλογή όταν μόνο η είσοδος στο wiki σας διασφαλίζεται μέσω SSL αλλά η περιήγηση γίνεται και χωρίς αυτό.';
+$lang['remote'] = 'Ενεργοποίησης απομακρυσμένης προγραμματιστικής διεπαφής εφαρμογών (API). Με αυτό τον τρόπο επιτρέπεται η πρόσβαση στο wiki με το XML-RPC ή με άλλα πρωτόκολλα επικοινωνίας.';
+$lang['remoteuser'] = 'Απενεργοποίησης απομακρυσμένης προγραμματιστικής διεπαφής εφαρμογών (API). Αφήστε το κενό για να είναι δυνατή η πρόσβαση στον οποιοδήποτε.';
+$lang['usewordblock'] = 'Χρήστη λίστα απαγορευμένων λέξεων για καταπολέμηση του spam';
+$lang['relnofollow'] = 'Χρήση rel="nofollow"';
+$lang['indexdelay'] = 'Χρόνος αναμονής προτού επιτραπεί σε μηχανές αναζήτησης να ευρετηριάσουν μια τροποποιημένη σελίδα (sec)';
+$lang['mailguard'] = 'Κωδικοποίηση e-mail διευθύνσεων';
+$lang['iexssprotect'] = 'Έλεγχος μεταφορτώσεων για πιθανώς επικίνδυνο κώδικα JavaScript ή HTML';
+$lang['usedraft'] = 'Αυτόματη αποθήκευση αντιγράφων κατά την τροποποίηση σελίδων';
+$lang['htmlok'] = 'Να επιτρέπεται η ενσωμάτωση HTML';
+$lang['phpok'] = 'Να επιτρέπεται η ενσωμάτωση PHP';
+$lang['locktime'] = 'Μέγιστος χρόνος κλειδώματος αρχείου υπό τροποποίηση (sec)';
+$lang['cachetime'] = 'Μέγιστη ηλικία cache (sec)';
+$lang['target____wiki'] = 'Παράθυρο-στόχος για εσωτερικούς συνδέσμους';
+$lang['target____interwiki'] = 'Παράθυρο-στόχος για συνδέσμους interwiki';
+$lang['target____extern'] = 'Παράθυρο-στόχος για εξωτερικούς σθνδέσμους';
+$lang['target____media'] = 'Παράθυρο-στόχος για συνδέσμους αρχείων';
+$lang['target____windows'] = 'Παράθυρο-στόχος για συνδέσμους σε Windows shares';
+$lang['mediarevisions'] = 'Ενεργοποίηση Mediarevisions;';
+$lang['refcheck'] = 'Πριν τη διαγραφή ενός αρχείου να ελέγχεται η ύπαρξη σελίδων που το χρησιμοποιούν';
+$lang['refshow'] = 'Εμφανιζόμενος αριθμός σελίδων που χρησιμοποιούν ένα αρχείο';
+$lang['gdlib'] = 'Έκδοση βιβλιοθήκης GD';
+$lang['im_convert'] = 'Διαδρομή προς το εργαλείο μετατροπής εικόνων του ImageMagick';
+$lang['jpg_quality'] = 'Ποιότητα συμπίεσης JPG (0-100)';
+$lang['fetchsize'] = 'Μέγιστο μέγεθος (σε bytes) εξωτερικού αρχείου που επιτρέπεται να μεταφέρει η fetch.php';
+$lang['subscribers'] = 'Να επιτρέπεται η εγγραφή στην ενημέρωση αλλαγών σελίδας';
+$lang['subscribe_time'] = 'Χρόνος μετά τον οποίο οι λίστες ειδοποιήσεων και τα συνοπτικά θα αποστέλλονται (δευτερόλεπτα). Αυτό θα πρέπει να είναι μικρότερο από τον χρόνο που έχει η ρύθμιση recent_days.';
+$lang['notify'] = 'Αποστολή ενημέρωσης για αλλαγές σε αυτή την e-mail διεύθυνση';
+$lang['registernotify'] = 'Αποστολή ενημερωτικών μηνυμάτων σε αυτή την e-mail διεύθυνση κατά την εγγραφή νέων χρηστών';
+$lang['mailfrom'] = 'e-mail διεύθυνση αποστολέα για μηνύματα από την εφαρμογή';
+$lang['mailprefix'] = 'Πρόθεμα θέματος που να χρησιμοποιείται για τα αυτόματα μηνύματα ηλεκτρονικού ταχυδρομείου.';
+$lang['htmlmail'] = 'Αποστολή οπτικά καλύτερου, αλλά μεγαλύτερου σε μέγεθος email με χρήση HTML. Απενεργοποιήστε το για αποστέλλονται μόνο email απλού κειμένου.';
+$lang['sitemap'] = 'Δημιουργία Google sitemap (ημέρες)';
+$lang['rss_type'] = 'Τύπος XML feed';
+$lang['rss_linkto'] = 'Τύπος συνδέσμων στο XML feed';
+$lang['rss_content'] = 'Τι να εμφανίζεται στα XML feed items?';
+$lang['rss_update'] = 'Χρόνος ανανέωσης XML feed (sec)';
+$lang['rss_show_summary'] = 'Να εμφανίζεται σύνοψη του XML feed στον τίτλο';
+$lang['rss_media'] = 'Τι είδους αλλαγές πρέπει να εμφανίζονται στο XLM feed;';
$lang['updatecheck'] = 'Έλεγχος για ύπαρξη νέων εκδόσεων και ενημερώσεων ασφαλείας της εφαρμογής? Απαιτείται η σύνδεση με το update.dokuwiki.org για να λειτουργήσει σωστά αυτή η επιλογή.';
$lang['userewrite'] = 'Χρήση ωραίων URLs';
$lang['useslash'] = 'Χρήση slash σαν διαχωριστικό φακέλων στα URLs';
-$lang['usedraft'] = 'Αυτόματη αποθήκευση αντιγράφων κατά την τροποποίηση σελίδων';
$lang['sepchar'] = 'Διαχωριστικός χαρακτήρας για κανονικοποίηση ονόματος σελίδας';
$lang['canonical'] = 'Πλήρη και κανονικοποιημένα URLs';
$lang['fnencode'] = 'Μέθοδος κωδικοποίησης για ονόματα αρχείων μη-ASCII';
$lang['autoplural'] = 'Ταίριασμα πληθυντικού στους συνδέσμους';
$lang['compression'] = 'Μέθοδος συμπίεσης για αρχεία attic';
-$lang['cachetime'] = 'Μέγιστη ηλικία cache (sec)';
-$lang['locktime'] = 'Μέγιστος χρόνος κλειδώματος αρχείου υπό τροποποίηση (sec)';
-$lang['fetchsize'] = 'Μέγιστο μέγεθος (σε bytes) εξωτερικού αρχείου που επιτρέπεται να μεταφέρει η fetch.php';
-$lang['notify'] = 'Αποστολή ενημέρωσης για αλλαγές σε αυτή την e-mail διεύθυνση';
-$lang['registernotify'] = 'Αποστολή ενημερωτικών μηνυμάτων σε αυτή την e-mail διεύθυνση κατά την εγγραφή νέων χρηστών';
-$lang['mailfrom'] = 'e-mail διεύθυνση αποστολέα για μηνύματα από την εφαρμογή';
-$lang['mailprefix'] = 'Πρόθεμα θέματος που να χρησιμοποιείται για τα αυτόματα μηνύματα ηλεκτρονικού ταχυδρομείου.';
$lang['gzip_output'] = 'Χρήση gzip Content-Encoding για την xhtml';
-$lang['gdlib'] = 'Έκδοση βιβλιοθήκης GD';
-$lang['im_convert'] = 'Διαδρομή προς το εργαλείο μετατροπής εικόνων του ImageMagick';
-$lang['jpg_quality'] = 'Ποιότητα συμπίεσης JPG (0-100)';
-$lang['subscribers'] = 'Να επιτρέπεται η εγγραφή στην ενημέρωση αλλαγών σελίδας';
-$lang['subscribe_time'] = 'Χρόνος μετά τον οποίο οι λίστες ειδοποιήσεων και τα συνοπτικά θα αποστέλλονται (δευτερόλεπτα). Αυτό θα πρέπει να είναι μικρότερο από τον χρόνο που έχει η ρύθμιση recent_days.';
$lang['compress'] = 'Συμπίεση αρχείων CSS και javascript';
$lang['cssdatauri'] = 'Το μέγεθος σε bytes στο οποίο οι εικόνες που αναφέρονται σε CSS αρχεία θα πρέπει να είναι ενσωματωμένες για τη μείωση των απαιτήσεων μιας κεφαλίδας αίτησης HTTP . Αυτή η τεχνική δεν θα λειτουργήσει σε IE <8! <code> 400 </code> με <code> 600 </code> bytes είναι μια καλή τιμή. Ορίστε την τιμή <code> 0 </code> για να το απενεργοποιήσετε.';
-$lang['hidepages'] = 'Φίλτρο απόκρυψης σελίδων (regular expressions)';
$lang['send404'] = 'Αποστολή "HTTP 404/Page Not Found" για σελίδες που δεν υπάρχουν';
-$lang['sitemap'] = 'Δημιουργία Google sitemap (ημέρες)';
$lang['broken_iua'] = 'Η συνάρτηση ignore_user_abort δεν λειτουργεί σωστά στο σύστημά σας? Σε αυτή την περίπτωση μπορεί να μην δουλεύει σωστά η λειτουργία Καταλόγου. Ο συνδυασμός IIS+PHP/CGI είναι γνωστό ότι έχει τέτοιο πρόβλημα. Δείτε και <a href="http://bugs.splitbrain.org/?do=details&amp;task_id=852">Bug 852</a> για λεπτομέρειες.';
$lang['xsendfile'] = 'Χρήση της κεφαλίδας X-Sendfile από τον εξυπηρετητή κατά την φόρτωση στατικών αρχείων? Ο εξυπηρετητής σας πρέπει να υποστηρίζει αυτή την δυνατότητα.';
$lang['renderer_xhtml'] = 'Πρόγραμμα δημιουργίας βασικής (xhtml) εξόδου wiki.';
$lang['renderer__core'] = '%s (βασικός κώδικας dokuwiki)';
$lang['renderer__plugin'] = '%s (επέκταση)';
-$lang['rememberme'] = 'Να επιτρέπονται τα cookies λογαρισμού χρήστη αορίστου χρόνου (Απομνημόνευση στοιχείων λογαριασμού)';
-$lang['rss_type'] = 'Τύπος XML feed';
-$lang['rss_linkto'] = 'Τύπος συνδέσμων στο XML feed';
-$lang['rss_content'] = 'Τι να εμφανίζεται στα XML feed items?';
-$lang['rss_update'] = 'Χρόνος ανανέωσης XML feed (sec)';
-$lang['recent_days'] = 'Πόσο παλιές αλλαγές να εμφανίζονται (ημέρες)';
-$lang['rss_show_summary'] = 'Να εμφανίζεται σύνοψη του XML feed στον τίτλο';
-$lang['target____wiki'] = 'Παράθυρο-στόχος για εσωτερικούς συνδέσμους';
-$lang['target____interwiki'] = 'Παράθυρο-στόχος για συνδέσμους interwiki';
-$lang['target____extern'] = 'Παράθυρο-στόχος για εξωτερικούς σθνδέσμους';
-$lang['target____media'] = 'Παράθυρο-στόχος για συνδέσμους αρχείων';
-$lang['target____windows'] = 'Παράθυρο-στόχος για συνδέσμους σε Windows shares';
+$lang['dnslookups'] = 'Το DokuWiki θα ψάξει τα ονόματα υπολογιστών που αντιστοιχούν σε διευθύνσεις IP των χρηστών που γράφουν στις σελίδες. Αν ο DNS είναι αργός, δεν δουλεύει ή δεν χρειάζεστε αυτή την λειτουργία, απενεργοποιήστε την.';
$lang['proxy____host'] = 'Διακομιστής Proxy';
$lang['proxy____port'] = 'Θύρα Proxy';
$lang['proxy____user'] = 'Όνομα χρήστη Proxy';
diff --git a/lib/plugins/config/lang/en/intro.txt b/lib/plugins/config/lang/en/intro.txt
index c83a80205..7cf46cee3 100644
--- a/lib/plugins/config/lang/en/intro.txt
+++ b/lib/plugins/config/lang/en/intro.txt
@@ -4,6 +4,6 @@ Use this page to control the settings of your DokuWiki installation. For help o
Settings shown with a light red background are protected and can not be altered with this plugin. Settings shown with a blue background are the default values and settings shown with a white background have been set locally for this particular installation. Both blue and white settings can be altered.
-Remember to press the **SAVE** button before leaving this page otherwise your changes will be lost.
+Remember to press the **Save** button before leaving this page otherwise your changes will be lost.
diff --git a/lib/plugins/config/lang/fi/lang.php b/lib/plugins/config/lang/fi/lang.php
index f3c57d10e..990852f99 100644
--- a/lib/plugins/config/lang/fi/lang.php
+++ b/lib/plugins/config/lang/fi/lang.php
@@ -30,6 +30,7 @@ $lang['_editing'] = 'Sivumuokkauksen asetukset';
$lang['_links'] = 'Linkkien asetukset';
$lang['_media'] = 'Media-asetukset';
$lang['_notifications'] = 'Ilmoitus-asetukset';
+$lang['_syndication'] = 'Syöteasetukset';
$lang['_advanced'] = 'Lisäasetukset';
$lang['_network'] = 'Verkkoasetukset';
$lang['_plugin_sufix'] = 'liitännäisen asetukset';
@@ -85,6 +86,8 @@ $lang['disableactions_wikicode'] = 'Näytä lähdekoodi/Vie raakana';
$lang['disableactions_other'] = 'Muut toiminnot (pilkulla erotettuna)';
$lang['auth_security_timeout'] = 'Autentikoinnin aikakatkaisu (sekunteja)';
$lang['securecookie'] = 'Lähetetäänkö HTTPS:n kautta asetetut evästetiedot HTTPS-yhteydellä? Kytke pois, jos vain wikisi kirjautuminen on suojattu SSL:n avulla, mutta muuten wikiä käytetään ilman suojausta.';
+$lang['remote'] = 'Kytke "remote API" käyttöön. Tämä sallii muiden sovellusten päästä wikiin XML-RPC:n avulla';
+$lang['remoteuser'] = 'Salli "remote API" pääsy vain pilkulla erotetuille ryhmille tai käyttäjille tässä. Jätä tyhjäksi, jos haluat sallia käytön kaikille.';
$lang['usewordblock'] = 'Estä spam sanalistan avulla';
$lang['relnofollow'] = 'Käytä rel="nofollow" ulkoisille linkeille';
$lang['indexdelay'] = 'Aikaraja indeksoinnille (sek)';
@@ -113,12 +116,14 @@ $lang['notify'] = 'Lähetä muutosilmoitukset tähän osoitteesee
$lang['registernotify'] = 'Lähetä ilmoitus uusista rekisteröitymisistä tähän osoitteeseen';
$lang['mailfrom'] = 'Sähköpostiosoite automaattisia postituksia varten';
$lang['mailprefix'] = 'Etuliite automaattisesti lähetettyihin dähköposteihin';
+$lang['htmlmail'] = 'Lähetä paremman näköisiä, mutta isompia HTML multipart sähköposteja. Ota pois päältä, jos haluat vain tekstimuotoisia posteja.';
$lang['sitemap'] = 'Luo Google sitemap (päiviä)';
$lang['rss_type'] = 'XML-syötteen tyyppi';
$lang['rss_linkto'] = 'XML-syöte kytkeytyy';
$lang['rss_content'] = 'Mitä XML-syöte näyttää?';
$lang['rss_update'] = 'XML-syötteen päivitystahti (sek)';
$lang['rss_show_summary'] = 'XML-syöte näyttää yhteenvedon otsikossa';
+$lang['rss_media'] = 'Millaiset muutokset pitäisi olla mukana XML-syötteessä.';
$lang['updatecheck'] = 'Tarkista päivityksiä ja turvavaroituksia? Tätä varten DokuWikin pitää ottaa yhteys update.dokuwiki.orgiin.';
$lang['userewrite'] = 'Käytä siivottuja URLeja';
$lang['useslash'] = 'Käytä kauttaviivaa nimiavaruuksien erottimena URL-osoitteissa';
@@ -137,6 +142,7 @@ $lang['xsendfile'] = 'Käytä X-Sendfile otsikkoa, kun web-palvelin
$lang['renderer_xhtml'] = 'Renderöinti, jota käytetään wikin pääasialliseen (xhtml) tulostukseen';
$lang['renderer__core'] = '%s (dokuwiki core)';
$lang['renderer__plugin'] = '%s (liitännäinen)';
+$lang['dnslookups'] = 'DokuWiki tarkistaa sivun päivittäjän koneen IP-osoitteen isäntänimen. Kytke pois, jos käytät hidasta tai toimimatonta DNS-palvelinta, tai et halua tätä ominaisuutta.';
$lang['proxy____host'] = 'Proxy-palvelimen nimi';
$lang['proxy____port'] = 'Proxy portti';
$lang['proxy____user'] = 'Proxy käyttäjän nimi';
diff --git a/lib/plugins/config/lang/fr/lang.php b/lib/plugins/config/lang/fr/lang.php
index c4b521497..f9e89f603 100644
--- a/lib/plugins/config/lang/fr/lang.php
+++ b/lib/plugins/config/lang/fr/lang.php
@@ -20,6 +20,7 @@
* @author Yannick Aure <yannick.aure@gmail.com>
* @author Olivier DUVAL <zorky00@gmail.com>
* @author Anael Mobilia <contrib@anael.eu>
+ * @author Bruno Veilleux <bruno.vey@gmail.com>
*/
$lang['menu'] = 'Paramètres de configuration';
$lang['error'] = 'Paramètres non modifiés en raison d\'une valeur invalide, vérifiez vos réglages puis réessayez. <br />Les valeurs erronées sont entourées d\'une bordure rouge.';
diff --git a/lib/plugins/config/lang/gl/lang.php b/lib/plugins/config/lang/gl/lang.php
index 5ba3be2ec..21fe17452 100644
--- a/lib/plugins/config/lang/gl/lang.php
+++ b/lib/plugins/config/lang/gl/lang.php
@@ -4,7 +4,7 @@
*
* @author Medúlio <medulio@ciberirmandade.org>
* @author Oscar M. Lage <r0sk10@gmail.com>
- * @author Leandro Regueiro <leandro.regueiro@gmail.com>
+ * @author Rodrigo Rega <rodrigorega@gmail.com>
*/
$lang['menu'] = 'Opcións de Configuración';
$lang['error'] = 'Configuración non actualizada debido a un valor inválido, por favor revisa os teus trocos e volta envialos de novo.
@@ -28,8 +28,8 @@ $lang['_anti_spam'] = 'Configuración de Anti-Correo-lixo';
$lang['_editing'] = 'Configuración de Edición';
$lang['_links'] = 'Configuración de Ligazóns';
$lang['_media'] = 'Configuración de Media';
-$lang['_notifications'] = 'Configuración de notificación';
-$lang['_syndication'] = 'Configuración de afiliación';
+$lang['_notifications'] = 'Opcións de Notificación';
+$lang['_syndication'] = 'Opcións de Sindicación';
$lang['_advanced'] = 'Configuración Avanzada';
$lang['_network'] = 'Configuración de Rede';
$lang['_plugin_sufix'] = 'Configuración de Extensións';
@@ -41,8 +41,8 @@ $lang['title'] = 'Título do Wiki';
$lang['start'] = 'Nome da páxina inicial';
$lang['lang'] = 'Idioma';
$lang['template'] = 'Sobreplanta';
-$lang['tagline'] = 'Slogan (se o modelo o admite)';
-$lang['sidebar'] = 'Nome da páxina de barra lateral (se o modelo o admite), se o campo está baleiro desactívase a barra lateral';
+$lang['tagline'] = 'Tagline (si a plantilla o soporta)';
+$lang['sidebar'] = 'Nome de páxina da barra lateral (si a platilla o soporta), o campo en baleiro deshabilita a barra lateral';
$lang['license'] = 'Baixo de que licenza será ceibado o teu contido?';
$lang['savedir'] = 'Directorio no que se gardarán os datos';
$lang['basedir'] = 'Directorio base';
@@ -85,8 +85,8 @@ $lang['disableactions_wikicode'] = 'Ver fonte/Exportar Datos Raw';
$lang['disableactions_other'] = 'Outras accións (separadas por comas)';
$lang['auth_security_timeout'] = 'Tempo Límite de Seguridade de Autenticación (segundos)';
$lang['securecookie'] = 'Deben enviarse só vía HTTPS polo navegador as cookies configuradas vía HTTPS? Desactiva esta opción cando só o inicio de sesión do teu wiki estea asegurado con SSL pero a navegación do mesmo se faga de xeito inseguro.';
-$lang['remote'] = 'Activar o sistema de API remota. Isto permítelle a outras aplicacións acceder ao wiki a través de XML-RPC ou outros mecanismos.';
-$lang['remoteuser'] = 'Restrinxir o acceso remoto á API aos grupos ou usuarios separados por comas especificados aquí. Déixeo baleiro para concederlle acceso a todos.';
+$lang['remote'] = 'Permite o uso do sistema API remoto. Isto permite a outras aplicacións acceder ao wiki mediante XML-RPC ou outros mecanismos.';
+$lang['remoteuser'] = 'Restrinxe o uso remoto da API aos grupos ou usuarios indicados, separados por comas. Deixar baleiro para dar acceso a todo o mundo.';
$lang['usewordblock'] = 'Bloquear correo-lixo segundo unha lista de verbas';
$lang['relnofollow'] = 'Utilizar rel="nofollow" nas ligazóns externas';
$lang['indexdelay'] = 'Retardo denantes de indexar (seg)';
@@ -115,14 +115,14 @@ $lang['notify'] = 'Enviar notificacións de trocos a este enderez
$lang['registernotify'] = 'Enviar información de novos usuarios rexistrados a este enderezo de correo-e';
$lang['mailfrom'] = 'Enderezo de correo-e a usar para as mensaxes automáticas';
$lang['mailprefix'] = 'Prefixo de asunto de correo-e para as mensaxes automáticas';
-$lang['htmlmail'] = 'Enviar mensaxes de e-mail HTML multiparte con mellor aspecto, pero de tamaño maior. Desactivar para as mensaxes de só texto plano.';
+$lang['htmlmail'] = 'Enviar correos electrónicos HTML multiparte máis estéticos, pero máis grande en tamaño. Deshabilitar para mandar correos electrónicos en texto claro.';
$lang['sitemap'] = 'Xerar mapa do sitio co Google (días)';
$lang['rss_type'] = 'Tipo de corrente RSS XML';
$lang['rss_linkto'] = 'A corrente XML liga para';
$lang['rss_content'] = 'Que queres amosar nos elementos da corrente XML?';
$lang['rss_update'] = 'Intervalo de actualización da corrente XML (seg.)';
$lang['rss_show_summary'] = 'Amosar sumario no título da corrente XML';
-$lang['rss_media'] = 'Que tipo de cambios se deben mostrar na fonte XML?';
+$lang['rss_media'] = 'Qué tipo de cambios deben ser listados no feed XML?';
$lang['updatecheck'] = 'Comprobar se hai actualizacións e avisos de seguridade? O DokuWiki precisa contactar con update.dokuwiki.org para executar esta característica.';
$lang['userewrite'] = 'Utilizar URLs amigábeis';
$lang['useslash'] = 'Utilizar a barra inclinada (/) como separador de nome de espazo nos URLs';
@@ -133,14 +133,14 @@ $lang['autoplural'] = 'Comprobar formas plurais nas ligazóns';
$lang['compression'] = 'Método de compresión para arquivos attic';
$lang['gzip_output'] = 'Utilizar Contido-Codificación gzip para o xhtml';
$lang['compress'] = 'Saída compacta de CSS e Javascript';
-$lang['cssdatauri'] = 'Tamaño en bytes ata o cal as imaxes referenciadas nos ficheiros CSS se deben incorporar directamente na folla de estilos para reducir o exceso de cabeceiras de solicitudes HTTP. Esta técnica non funciona con IE 7 ou inferior! Valores entre <code>400</code> e <code>600</code> son axeitados. Defina <code>0</code> para desactivar.';
+$lang['cssdatauri'] = 'Tamaño en bytes ata o cal as imaxes referenciadas nos CSS serán incrustadas na folla de estilos para disminuir o tamaño das cabeceiras das solicitudes HTTP. Esta técnica non funcionará en IE 7 ou anteriores! entre <code>400</code> e <code>600</code> bytes é un valor axeitado. Establecer a <code>0</code> para deshabilitar.';
$lang['send404'] = 'Enviar "HTTP 404/Páxina non atopada" para as páxinas inexistentes';
$lang['broken_iua'] = 'Rachou a función ignore_user_abort no teu sistema? Isto podería causar que o índice de procura non funcione. Coñécese que o IIS+PHP/CGI ráchaa. Bótalle un ollo ao <a href="http://bugs.splitbrain.org/?do=details&amp;task_id=852">Bug 852</a> para obter máis información.';
$lang['xsendfile'] = 'Empregar a cabeceira X-Sendfile para que o servidor web envie arquivos estáticos? O teu servidor web precisa soportar isto.';
$lang['renderer_xhtml'] = 'Intérprete a empregar para a saída principal (XHTML) do Wiki';
$lang['renderer__core'] = '%s (núcleo do Dokuwiki)';
$lang['renderer__plugin'] = '%s (extensión)';
-$lang['dnslookups'] = 'DokuWiki buscará os nomes de máquina ou enderezos IP remotos dos usuarios que editen páxinas. Se ten un servidor DNS lento ou que non funciona ou en caso de non querer esta característica, desactive esta opción.';
+$lang['dnslookups'] = 'DokuWiki resolverá os nomes de host das direccións IP dos usuarios que editan as páxinas. Si contas un servidor DNS lento, que non funciona ou non che interesa esta característica, deshabilita esta opción';
$lang['proxy____host'] = 'Nome do servidor Proxy';
$lang['proxy____port'] = 'Porto do Proxy';
$lang['proxy____user'] = 'Nome de usuario do Proxy';
diff --git a/lib/plugins/config/lang/it/lang.php b/lib/plugins/config/lang/it/lang.php
index 751e5ee95..62dd00f0c 100644
--- a/lib/plugins/config/lang/it/lang.php
+++ b/lib/plugins/config/lang/it/lang.php
@@ -39,6 +39,7 @@ $lang['_editing'] = 'Impostazioni Modifica';
$lang['_links'] = 'Impostazioni Collegamenti';
$lang['_media'] = 'Impostazioni File';
$lang['_notifications'] = 'Impostazioni di notifica';
+$lang['_syndication'] = 'Impostazioni di collaborazione';
$lang['_advanced'] = 'Impostazioni Avanzate';
$lang['_network'] = 'Impostazioni Rete';
$lang['_plugin_sufix'] = 'Impostazioni Plugin';
diff --git a/lib/plugins/config/lang/ja/lang.php b/lib/plugins/config/lang/ja/lang.php
index a89123f8c..807436cca 100644
--- a/lib/plugins/config/lang/ja/lang.php
+++ b/lib/plugins/config/lang/ja/lang.php
@@ -9,6 +9,7 @@
* @author Daniel Dupriest <kououken@gmail.com>
* @author Kazutaka Miyasaka <kazmiya@gmail.com>
* @author Taisuke Shimamoto <dentostar@gmail.com>
+ * @author Satoshi Sahara <sahara.satoshi@gmail.com>
*/
$lang['menu'] = 'サイト設定';
$lang['error'] = '不正な値が存在するため、設定は更新されませんでした。入力値を確認してから、再度更新してください。
@@ -72,7 +73,7 @@ $lang['camelcase'] = 'キャメルケースリンク';
$lang['deaccent'] = 'ページ名アクセント';
$lang['useheading'] = '最初の見出しをページ名とする';
$lang['sneaky_index'] = 'デフォルトでは索引にすべての名前空間を表示しますが、この機能はユーザーに閲覧権限のない名前空間を非表示にします。ただし、閲覧が可能な副名前空間まで表示されなくなるため、ACLの設定が適正でない場合は索引機能が使えなくなる場合があります。';
-$lang['hidepages'] = '非公開ページ(Regex)';
+$lang['hidepages'] = '検索、サイトマップ、その他の自動インデックスの結果に表示しないページ(Regex)';
$lang['useacl'] = 'アクセス管理を行う(ACL)';
$lang['autopasswd'] = 'パスワードの自動生成(ACL)';
$lang['authtype'] = '認証方法(ACL)';
@@ -119,6 +120,7 @@ $lang['notify'] = '変更を通知するメールアドレス';
$lang['registernotify'] = '新規ユーザー登録を通知するメールアドレス';
$lang['mailfrom'] = 'メール送信時の送信元アドレス';
$lang['mailprefix'] = '自動メールの題名に使用する接頭語';
+$lang['htmlmail'] = 'メールをテキスト形式ではなく、HTML形式で送信する。';
$lang['sitemap'] = 'Googleサイトマップ作成頻度(日数)';
$lang['rss_type'] = 'RSSフィード形式';
$lang['rss_linkto'] = 'RSS内リンク先';
@@ -143,6 +145,7 @@ $lang['xsendfile'] = 'ウェブサーバーが静的ファイルを
$lang['renderer_xhtml'] = 'Wikiの出力(xhtml)にレンダラーを使用する';
$lang['renderer__core'] = '%s (Dokuwikiコア)';
$lang['renderer__plugin'] = '%s (プラグイン)';
+$lang['dnslookups'] = 'ページを編集しているユーザーのIPアドレスからホスト名を逆引きする。利用できるDNSサーバーがない、あるいはこの機能が不要な場合にはオフにします。';
$lang['proxy____host'] = 'プロキシ - サーバー名';
$lang['proxy____port'] = 'プロキシ - ポート';
$lang['proxy____user'] = 'プロキシ - ユーザー名';
@@ -156,7 +159,7 @@ $lang['ftp____user'] = 'FTP ユーザー名(セーフモード対策
$lang['ftp____pass'] = 'FTP パスワード(セーフモード対策)';
$lang['ftp____root'] = 'FTP ルートディレクトリ(セーフモード対策)';
$lang['license_o_'] = '選択されていません';
-$lang['typography_o_0'] = '無し';
+$lang['typography_o_0'] = '変換しない';
$lang['typography_o_1'] = '二重引用符(ダブルクオート)のみ';
$lang['typography_o_2'] = 'すべての引用符(動作しない場合があります)';
$lang['userewrite_o_0'] = '使用しない';
diff --git a/lib/plugins/config/lang/ko/intro.txt b/lib/plugins/config/lang/ko/intro.txt
index 5ef34df64..b9eb763a4 100644
--- a/lib/plugins/config/lang/ko/intro.txt
+++ b/lib/plugins/config/lang/ko/intro.txt
@@ -2,6 +2,6 @@
DokuWiki 설치할 때 설정을 바꾸기 위해 사용하는 페이지입니다. 각 설정에 대한 자세한 도움말이 필요하다면 [[doku>ko:config|설정 문서 (한국어)]]와 [[doku>config|설정 문서 (영어)]]를 참고하세요.
-플러그인에 대한 자세한 정보가 필요하다면 [[doku>plugin:config|플러그인 설정]] 문서를 참고하세요. 빨간 배경색으로 보이는 설정은 이 플러그인에서 바꾸지 못하도록 되어있습니다. 파란 배경색으로 보이는 설정은 기본 설정값을 가지고 있습니다. 하얀 배경색으로 보이는 설정은 특별한 설치를 위해 설정되어 있습니다. 파란색과 하얀색 배경으로 된 설정은 수정이 가능합니다.
+플러그인에 대한 자세한 정보가 필요하다면 [[doku>plugin:config|플러그인 설정]] 문서를 참고하세요. 빨간 배경색으로 보이는 설정은 이 플러그인에서 바꾸지 못하도록 되어있습니다. 파란 배경색으로 보이는 설정은 기본 설정값을 가지고 있습니다. 하얀 배경색으로 보이는 설정은 특별한 설치를 위해 설정되어 있습니다. 파란색과 하얀색 배경으로 된 설정은 바꿀 수 있습니다.
-이 페이지를 끝내기 전에 **저장** 버튼을 누르지 않으면 설정값은 적용되지 않습니다.
+이 페이지를 떠나기 전에 **저장** 버튼을 누르지 않으면 바뀐 값은 적용되지 않습니다. \ No newline at end of file
diff --git a/lib/plugins/config/lang/ko/lang.php b/lib/plugins/config/lang/ko/lang.php
index cd2cc6d6c..da155bcef 100644
--- a/lib/plugins/config/lang/ko/lang.php
+++ b/lib/plugins/config/lang/ko/lang.php
@@ -1,25 +1,24 @@
<?php
/**
- * korean language file
+ * Korean language file
*
- * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author jk Lee
* @author dongnak@gmail.com
* @author Song Younghwan <purluno@gmail.com>
- * @author SONG Younghwan <purluno@gmail.com>
- * @author Seung-Chul Yoo <dryoo@live.com>
+ * @author Seung-Chul Yoo <dryoo@live.com>
* @author erial2@gmail.com
* @author Myeongjin <aranet100@gmail.com>
*/
$lang['menu'] = '환경 설정';
-$lang['error'] = '잘못된 값 때문에 설정을 바꿀 수 없습니다. 수정한 값을 검토하고 확인을 누르세요.
+$lang['error'] = '잘못된 값 때문에 설정을 바꿀 수 없습니다. 바뀜을 검토하고 확인을 누르세요.
<br />잘못된 값은 빨간 선으로 둘러싸여 있습니다.';
$lang['updated'] = '설정이 성공적으로 바뀌었습니다.';
-$lang['nochoice'] = '(다른 선택이 불가능합니다.)';
-$lang['locked'] = '환경 설정 파일을 수정할 수 없습니다. 의도한 행동이 아니라면,<br />
-파일 이름과 권한이 맞는지 확인하기 바랍니다. ';
-$lang['danger'] = '위험: 이 옵션을 잘못 수정하면 환경설정 메뉴를 사용할 수 없을 수도 있습니다.';
-$lang['warning'] = '경고: 이 옵션을 잘못 수정하면 잘못 동작할 수 있습니다.';
+$lang['nochoice'] = '(다른 선택이 불가능합니다)';
+$lang['locked'] = '환경 설정 파일을 바꿀 수 없습니다. 의도한 행동이 아니라면,<br />
+파일 이름과 권한이 맞는지 확인하세요.';
+$lang['danger'] = '위험: 이 옵션을 잘못 바꾸면 환경 설정 메뉴를 사용할 수 없을 수도 있습니다.';
+$lang['warning'] = '경고: 이 옵션을 잘못 바꾸면 잘못 동작할 수 있습니다.';
$lang['security'] = '보안 경고: 이 옵션은 보안에 위험이 있을 수 있습니다.';
$lang['_configuration_manager'] = '환경 설정 관리자';
$lang['_header_dokuwiki'] = 'DokuWiki 설정';
@@ -47,24 +46,24 @@ $lang['start'] = '각 이름공간에서 사용할 시작 문서
$lang['lang'] = '인터페이스 언어';
$lang['template'] = '템플릿 (위키 디자인)';
$lang['tagline'] = '태그 라인 (템플릿이 지원할 때에 한함)';
-$lang['sidebar'] = '사이드바 문서 이름 (템플릿이 지원할 때에 한함). 비워두면 사이드바를 비활성화';
+$lang['sidebar'] = '사이드바 문서 이름 (템플릿이 지원할 때에 한함), 비워두면 사이드바를 비활성화';
$lang['license'] = '콘텐츠에 어떤 라이선스를 적용하겠습니까?';
-$lang['savedir'] = '데이타 저장 디렉토리';
+$lang['savedir'] = '데이터 저장 디렉토리';
$lang['basedir'] = '서버 경로 (예를 들어 <code>/dokuwiki/</code>). 자동 감지를 하려면 비우세요.';
$lang['baseurl'] = '서버 URL (예를 들어 <code>http://www.yourserver.com</code>). 자동 감지를 하려면 비우세요.';
$lang['cookiedir'] = '쿠키 위치. 비워두면 기본 URL 위치로 지정됩니다.';
$lang['dmode'] = '디렉토리 만들기 모드';
$lang['fmode'] = '파일 만들기 모드';
-$lang['allowdebug'] = '디버그 허용 <b>필요하지 않으면 금지!</b>';
+$lang['allowdebug'] = '디버그 허용 <b>필요하지 않으면 비활성화하세요!</b>';
$lang['recent'] = '최근 바뀐 문서당 항목 수';
-$lang['recent_days'] = '최근 바뀐 문서 기준 시간 (날짜)';
+$lang['recent_days'] = '최근 바뀐 문서 기준 시간 (일)';
$lang['breadcrumbs'] = '위치 "추적" 수. 0으로 설정하면 비활성화합니다.';
-$lang['youarehere'] = '계층형 위치 추적 (다음 위의 옵션을 비활성화하고 싶습니다)';
+$lang['youarehere'] = '계층형 위치 추적 (다음 위의 옵션을 비활성화하게 됩니다)';
$lang['fullpath'] = '문서 하단에 전체 경로 보여주기';
$lang['typography'] = '기호 대체';
$lang['dformat'] = '날짜 형식 (PHP <a href="http://www.php.net/strftime">strftime</a> 기능 참고)';
$lang['signature'] = '편집기에서 서명 버튼을 누를 때 삽입할 내용';
-$lang['showuseras'] = '마지막에 문서를 수정한 사용자를 보여줄지 여부';
+$lang['showuseras'] = '마지막에 문서를 편집한 사용자를 보여줄지 여부';
$lang['toptoclevel'] = '목차 최상위 항목';
$lang['tocminheads'] = '목차 표시 여부를 결정할 최소한의 문단 제목 항목의 수';
$lang['maxtoclevel'] = '목차 최대 단계';
@@ -86,8 +85,8 @@ $lang['profileconfirm'] = '개인 정보를 바꿀 때 비밀번호 다
$lang['rememberme'] = '항상 로그인 정보 저장 허용 (기억하기)';
$lang['disableactions'] = 'DokuWiki 활동 비활성화';
$lang['disableactions_check'] = '검사';
-$lang['disableactions_subscription'] = '구독 신청/해지';
-$lang['disableactions_wikicode'] = '내용 보기/원본 내보대기';
+$lang['disableactions_subscription'] = '구독 신청/구독 취소';
+$lang['disableactions_wikicode'] = '내용 보기/원본 내보내기';
$lang['disableactions_other'] = '다른 활동 (쉼표로 구분)';
$lang['auth_security_timeout'] = '인증 보안 초과 시간 (초)';
$lang['securecookie'] = 'HTTPS로 보내진 쿠키는 HTTPS에만 적용 할까요? 위키의 로그인 페이지만 SSL로 암호화하고 위키 문서는 그렇지 않은 경우 비활성화 합니다.';
@@ -103,12 +102,12 @@ $lang['htmlok'] = 'HTML 내장 허용';
$lang['phpok'] = 'PHP 내장 허용';
$lang['locktime'] = '최대 파일 잠금 시간(초)';
$lang['cachetime'] = '최대 캐시 생존 시간 (초)';
-$lang['target____wiki'] = '내부 링크에 대한 타겟 창';
+$lang['target____wiki'] = '안쪽 링크에 대한 타겟 창';
$lang['target____interwiki'] = '인터위키 링크에 대한 타겟 창';
$lang['target____extern'] = '바깥 링크에 대한 타겟 창';
$lang['target____media'] = '미디어 링크에 대한 타겟 창';
$lang['target____windows'] = '창 링크에 대한 타겟 창';
-$lang['mediarevisions'] = '미디어 버전 관리를 사용하겠습니까?';
+$lang['mediarevisions'] = '미디어 판 관리를 사용하겠습니까?';
$lang['refcheck'] = '미디어 파일을 삭제하기 전에 사용하고 있는지 검사';
$lang['refshow'] = '위의 설정이 활성화되었을 때 보여줄 미디어 참고 수';
$lang['gdlib'] = 'GD 라이브러리 버전';
@@ -121,11 +120,11 @@ $lang['notify'] = '항상 이 이메일 주소로 바뀜 알림
$lang['registernotify'] = '항상 새 사용자한테 이 이메일 주소로 정보를 보냄';
$lang['mailfrom'] = '자동으로 보내지는 메일 발신자';
$lang['mailprefix'] = '자동으로 보내지는 메일의 제목 말머리 내용. 비웠을 경우 위키 제목 사용';
-$lang['htmlmail'] = '용량은 조금 더 크지만 보기 좋은 HTML 태그가 포함된 메일을 발송합니다. 텍스트만의 메일을 보내고자하면 비활성화하세요.';
-$lang['sitemap'] = '구글 사이트맵 생성 (날짜). 0일 경우 비활성화';
+$lang['htmlmail'] = '용량은 조금 더 크지만 보기 좋은 HTML 태그가 포함된 메일을 보냅니다. 텍스트만의 메일을 보내고자하면 비활성화하세요.';
+$lang['sitemap'] = '구글 사이트맵 생성 날짜 빈도. 0일 경우 비활성화합니다';
$lang['rss_type'] = 'XML 피드 타입';
$lang['rss_linkto'] = 'XML 피드 링크 정보';
-$lang['rss_content'] = 'XML 피드 항목에 표시되는 내용은?';
+$lang['rss_content'] = 'XML 피드 항목에 표시되는 내용은 무엇입니까?';
$lang['rss_update'] = 'XML 피드 업데이트 주기 (초)';
$lang['rss_show_summary'] = 'XML 피드 제목에서 요약 보여주기';
$lang['rss_media'] = '어떤 규격으로 XML 피드를 받아보시겠습니까?';
@@ -134,19 +133,19 @@ $lang['userewrite'] = '멋진 URL 사용';
$lang['useslash'] = 'URL에서 이름 구분자로 슬래시 문자 사용';
$lang['sepchar'] = '문서 이름 단어 구분자';
$lang['canonical'] = '완전한 canonical URL 사용';
-$lang['fnencode'] = '아스키가 아닌 파일 이름을 인코딩 하는 방법.';
+$lang['fnencode'] = 'ASCII가 아닌 파일 이름을 인코딩 하는 방법.';
$lang['autoplural'] = '링크 연결시 복수 양식 검사';
$lang['compression'] = '첨부 파일 압축 방법 선택';
$lang['gzip_output'] = 'xhml 내용 gzip 압축 사용';
$lang['compress'] = '최적화된 CSS, 자바스크립트 출력';
$lang['cssdatauri'] = '그림이 렌더링될 최대 용량 크기를 CSS에 규정해야 HTTP 요청 헤더 오버헤드 크기를 감소시킬 수 있습니다. 이 기술은 IE 7 이하에서는 작동하지 않습니다! <code>400</code>에서 <code>600</code> 정도면 좋은 효율을 가져옵니다. <code>0</code>로 지정할 경우 비활성화 됩니다.';
$lang['send404'] = '존재하지 않는 페이지에 대해 "HTTP 404/Page Not Found" 응답';
-$lang['broken_iua'] = '설치된 시스템에서 ignore_user_abort 기능에 문제가 있습니까? 문제가 있다면 색인이 정상적으로 동작하지 않습니다. 이 기능이 IIS+PHP/CGI에서 문제가 있는 것으로 알려졌습니다. 자세한 정보는 <a href="http://bugs.dokuwiki.org/?do=details&amp;task_id=852">버그 852</a>를 참고하기 바랍니다.';
+$lang['broken_iua'] = '설치된 시스템에서 ignore_user_abort 기능에 문제가 있습니까? 문제가 있다면 색인이 정상적으로 동작하지 않습니다. 이 기능이 IIS+PHP/CGI에서 문제가 있는 것으로 알려졌습니다. 자세한 정보는 <a href="http://bugs.dokuwiki.org/?do=details&amp;task_id=852">버그 852</a>를 참고하시기 바랍니다.';
$lang['xsendfile'] = '웹 서버가 정적 파일을 제공하도록 X-Sendfile 헤더를 사용하겠습니까? 웹 서버가 이 기능을 지원해야 합니다.';
$lang['renderer_xhtml'] = '주 (xhtml) 위키 출력 처리기';
-$lang['renderer__core'] = '%s (DokuWiki 내부 기능)';
+$lang['renderer__core'] = '%s (DokuWiki 내부)';
$lang['renderer__plugin'] = '%s (플러그인)';
-$lang['dnslookups'] = '이 옵션을 활성화하면 도쿠위키가 문서를 수정하는 사용자의 호스트 네임과 원격 IP 주소를 확인합니다. 서버가 느리거나, DNS를 운영하지 않거나 이 기능을 원치 않으면 비활성화 시켜주세요.';
+$lang['dnslookups'] = '이 옵션을 활성화하면 DokuWiki가 문서를 편집하는 사용자의 호스트 네임과 원격 IP 주소를 확인합니다. 서버가 느리거나, DNS를 운영하지 않거나 이 기능을 원치 않으면 비활성화하세요';
$lang['proxy____host'] = '프록시 서버 이름';
$lang['proxy____port'] = '프록시 서버 포트';
$lang['proxy____user'] = '프록시 사용자 이름';
@@ -166,7 +165,7 @@ $lang['typography_o_2'] = '모든 가능한 인용 부호 (동작 안될
$lang['userewrite_o_0'] = '사용 안함';
$lang['userewrite_o_1'] = '.htaccess';
$lang['userewrite_o_2'] = 'DokuWiki 내부 기능';
-$lang['deaccent_o_0'] = '사용 안함';
+$lang['deaccent_o_0'] = '끄기';
$lang['deaccent_o_1'] = '악센트 제거';
$lang['deaccent_o_2'] = '라틴문자화';
$lang['gdlib_o_0'] = 'GD 라이브러리 사용 불가';
@@ -193,8 +192,8 @@ $lang['xsendfile_o_1'] = '비공개 lighttpd 헤더 (1.5 이전 버전)'
$lang['xsendfile_o_2'] = '표준 X-Sendfile 헤더';
$lang['xsendfile_o_3'] = '비공개 Nginx X-Accel-Redirect 헤더';
$lang['showuseras_o_loginname'] = '로그인 이름';
-$lang['showuseras_o_username'] = '사용자 이름';
-$lang['showuseras_o_email'] = '사용자 이메일 주소 (메일 주소 보호 설정에 따라 안보일 수 있음)';
+$lang['showuseras_o_username'] = '사용자의 전체 이름';
+$lang['showuseras_o_email'] = '사용자의 이메일 주소 (메일 주소 보호 설정에 따라 안보일 수 있음)';
$lang['showuseras_o_email_link'] = 'mailto: link로 표현될 사용자 이메일 주소';
$lang['useheading_o_0'] = '아니오';
$lang['useheading_o_navigation'] = '둘러보기에만';
diff --git a/lib/plugins/config/lang/lv/lang.php b/lib/plugins/config/lang/lv/lang.php
index 50031d5e5..3adfd1871 100644
--- a/lib/plugins/config/lang/lv/lang.php
+++ b/lib/plugins/config/lang/lv/lang.php
@@ -26,6 +26,7 @@ $lang['_anti_spam'] = 'Pretspama iestatījumi';
$lang['_editing'] = 'Labošanas iestatījumi';
$lang['_links'] = 'Saišu iestatījumi';
$lang['_media'] = 'Mēdiju iestatījumi';
+$lang['_notifications'] = 'Brīdinājumu iestatījumi';
$lang['_advanced'] = 'Smalkāka iestatīšana';
$lang['_network'] = 'Tīkla iestatījumi';
$lang['_plugin_sufix'] = 'moduļa iestatījumi';
diff --git a/lib/plugins/config/lang/nl/lang.php b/lib/plugins/config/lang/nl/lang.php
index 85dc2c4c7..26ea3d8c1 100644
--- a/lib/plugins/config/lang/nl/lang.php
+++ b/lib/plugins/config/lang/nl/lang.php
@@ -63,7 +63,7 @@ $lang['allowdebug'] = 'Debug toestaan <b>uitzetten indien niet noodza
$lang['recent'] = 'Het aantal regels in Recente wijzigingen';
$lang['recent_days'] = 'Hoeveel recente wijzigingen bewaren (dagen)';
$lang['breadcrumbs'] = 'Aantal broodkruimels. Zet dit op 0 om uit te schakelen.';
-$lang['youarehere'] = 'Gebruik hierarchische broodkruimels (waarschijnlijk wil je dan de optie hierboven uitschakelen)';
+$lang['youarehere'] = 'Gebruik hiërarchische broodkruimels (waarschijnlijk wil je dan de optie hierboven uitschakelen)';
$lang['fullpath'] = 'Volledig pad van pagina\'s in de footer weergeven';
$lang['typography'] = 'Breng typografische wijzigingen aan';
$lang['dformat'] = 'Datum formaat (zie de PHP <a href="http://www.php.net/strftime">strftime</a> functie)';
diff --git a/lib/plugins/config/lang/pt-br/lang.php b/lib/plugins/config/lang/pt-br/lang.php
index 7151713d8..85218439a 100644
--- a/lib/plugins/config/lang/pt-br/lang.php
+++ b/lib/plugins/config/lang/pt-br/lang.php
@@ -16,6 +16,7 @@
* @author Sergio Motta sergio@cisne.com.br
* @author Isaias Masiero Filho <masiero@masiero.org>
* @author Balaco Baco <balacobaco@imap.cc>
+ * @author Victor Westmann <victor.westmann@gmail.com>
*/
$lang['menu'] = 'Configurações do DokuWiki';
$lang['error'] = 'As configurações não foram atualizadas devido a um valor inválido. Por favor, reveja suas alterações e reenvie-as.<br />O(s) valor(es) incorreto(s) serão exibidos contornados por uma borda vermelha.';
diff --git a/lib/plugins/config/lang/ru/lang.php b/lib/plugins/config/lang/ru/lang.php
index 36e04686d..42cbbd35a 100644
--- a/lib/plugins/config/lang/ru/lang.php
+++ b/lib/plugins/config/lang/ru/lang.php
@@ -17,6 +17,7 @@
* @author Ladyko Andrey <fylh@succexy.spb.ru>
* @author Eugene <windy.wanderer@gmail.com>
* @author Johnny Utah <pcpa@cyberpunk.su>
+ * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua)
*/
$lang['menu'] = 'Настройки вики';
$lang['error'] = 'Настройки не были сохранены из-за ошибки в одном из значений. Пожалуйста, проверьте свои изменения и попробуйте ещё раз.<br />Неправильные значения будут обведены красной рамкой.';
diff --git a/lib/plugins/config/lang/sv/lang.php b/lib/plugins/config/lang/sv/lang.php
index 3d8392840..d59b4b17e 100644
--- a/lib/plugins/config/lang/sv/lang.php
+++ b/lib/plugins/config/lang/sv/lang.php
@@ -16,6 +16,7 @@
* @author Peter Åström <eaustreum@gmail.com>
* @author Håkan Sandell <hakan.sandell@home.se>
* @author mikael@mallander.net
+ * @author Smorkster Andersson smorkster@gmail.com
*/
$lang['menu'] = 'Hantera inställningar';
$lang['error'] = 'Inställningarna uppdaterades inte på grund av ett felaktigt värde. Titta igenom dina ändringar och försök sedan spara igen.
@@ -39,6 +40,8 @@ $lang['_anti_spam'] = 'Inställningar för anti-spam';
$lang['_editing'] = 'Inställningar för redigering';
$lang['_links'] = 'Inställningar för länkar';
$lang['_media'] = 'Inställningar för medier';
+$lang['_notifications'] = 'Noterings inställningar';
+$lang['_syndication'] = 'Syndikats inställningar';
$lang['_advanced'] = 'Avancerade inställningar';
$lang['_network'] = 'Nätverksinställningar';
$lang['_plugin_sufix'] = '(inställningar för insticksmodul)';
@@ -46,25 +49,27 @@ $lang['_template_sufix'] = '(inställningar för mall)';
$lang['_msg_setting_undefined'] = 'Ingen inställningsmetadata.';
$lang['_msg_setting_no_class'] = 'Ingen inställningsklass.';
$lang['_msg_setting_no_default'] = 'Inget standardvärde.';
-$lang['fmode'] = 'Filskydd för nya filer';
-$lang['dmode'] = 'Filskydd för nya kataloger';
-$lang['lang'] = 'Språk';
-$lang['basedir'] = 'Grundkatalog';
-$lang['baseurl'] = 'Grund-webbadress';
-$lang['savedir'] = 'Katalog för att spara data';
-$lang['start'] = 'Startsidans namn';
$lang['title'] = 'Wikins namn';
+$lang['start'] = 'Startsidans namn';
+$lang['lang'] = 'Språk';
$lang['template'] = 'Mall';
$lang['license'] = 'Under vilken licens skall ditt innehåll publiceras?';
-$lang['fullpath'] = 'Visa fullständig sökväg i sidfoten';
+$lang['savedir'] = 'Katalog för att spara data';
+$lang['basedir'] = 'Grundkatalog';
+$lang['baseurl'] = 'Grund-webbadress';
+$lang['cookiedir'] = 'Cookie sökväg. Lämna blankt för att använda basurl.';
+$lang['dmode'] = 'Filskydd för nya kataloger';
+$lang['fmode'] = 'Filskydd för nya filer';
+$lang['allowdebug'] = 'Tillåt felsökning <b>stäng av om det inte behövs!</b>';
$lang['recent'] = 'Antal poster under "Nyligen ändrat"';
+$lang['recent_days'] = 'Hur många ändringar som ska sparas (dagar)';
$lang['breadcrumbs'] = 'Antal spår';
$lang['youarehere'] = 'Hierarkiska spår';
+$lang['fullpath'] = 'Visa fullständig sökväg i sidfoten';
$lang['typography'] = 'Aktivera typografiska ersättningar';
-$lang['htmlok'] = 'Tillåt inbäddad HTML';
-$lang['phpok'] = 'Tillåt inbäddad PHP';
$lang['dformat'] = 'Datumformat (se PHP:s <a href="http://www.php.net/strftime">strftime</a>-funktion)';
$lang['signature'] = 'Signatur';
+$lang['showuseras'] = 'Vad som skall visas när man visar den användare som senast redigerade en sida';
$lang['toptoclevel'] = 'Toppnivå för innehållsförteckning';
$lang['tocminheads'] = 'Minimalt antal rubriker för att avgöra om innehållsförteckning byggs';
$lang['maxtoclevel'] = 'Maximal nivå för innehållsförteckning';
@@ -72,15 +77,8 @@ $lang['maxseclevel'] = 'Maximal nivå för redigering av rubriker';
$lang['camelcase'] = 'Använd CamelCase för länkar';
$lang['deaccent'] = 'Rena sidnamn';
$lang['useheading'] = 'Använda första rubriken som sidnamn';
-$lang['refcheck'] = 'Kontrollera referenser till mediafiler';
-$lang['refshow'] = 'Antal mediareferenser som ska visas';
-$lang['allowdebug'] = 'Tillåt felsökning <b>stäng av om det inte behövs!</b>';
-$lang['usewordblock'] = 'Blockera spam baserat på ordlista';
-$lang['indexdelay'] = 'Tidsfördröjning före indexering (sek)';
-$lang['relnofollow'] = 'Använd rel="nofollow" för externa länkar';
-$lang['mailguard'] = 'Koda e-postadresser';
-$lang['iexssprotect'] = 'Kontrollera om uppladdade filer innehåller eventuellt skadlig JavaScript eller HTML-kod';
-$lang['showuseras'] = 'Vad som skall visas när man visar den användare som senast redigerade en sida';
+$lang['sneaky_index'] = 'Som standard visar DokuWiki alla namnrymder på indexsidan. Genom att aktivera det här valet döljer man namnrymder som användaren inte har behörighet att läsa. Det kan leda till att man döljer åtkomliga undernamnrymder, och gör indexet oanvändbart med vissa ACL-inställningar.';
+$lang['hidepages'] = 'Dölj matchande sidor (reguljära uttryck)';
$lang['useacl'] = 'Använd behörighetslista (ACL)';
$lang['autopasswd'] = 'Autogenerera lösenord';
$lang['authtype'] = 'System för autentisering';
@@ -89,60 +87,69 @@ $lang['defaultgroup'] = 'Förvald grupp';
$lang['superuser'] = 'Huvudadministratör - en grupp eller en användare med full tillgång till alla sidor och funktioner, oavsett behörighetsinställningars';
$lang['manager'] = 'Administratör -- en grupp eller användare med tillgång till vissa administrativa funktioner.';
$lang['profileconfirm'] = 'Bekräfta ändringarna i profilen med lösenordet';
+$lang['rememberme'] = 'Tillåt permanenta inloggningscookies (kom ihåg mig)';
$lang['disableactions'] = 'Stäng av funktioner i DokuWiki';
$lang['disableactions_check'] = 'Kontroll';
$lang['disableactions_subscription'] = 'Prenumerera/Säg upp prenumeration';
$lang['disableactions_wikicode'] = 'Visa källkod/Exportera råtext';
$lang['disableactions_other'] = 'Andra funktioner (kommaseparerade)';
-$lang['sneaky_index'] = 'Som standard visar DokuWiki alla namnrymder på indexsidan. Genom att aktivera det här valet döljer man namnrymder som användaren inte har behörighet att läsa. Det kan leda till att man döljer åtkomliga undernamnrymder, och gör indexet oanvändbart med vissa ACL-inställningar.';
$lang['auth_security_timeout'] = 'Autentisieringssäkerhets timeout (sekunder)';
$lang['securecookie'] = 'Skall cookies som sätts via HTTPS endast skickas via HTTPS från webbläsaren? Avaktivera detta alternativ endast om inloggningen till din wiki är säkrad med SSL men läsning av wikin är osäkrad.';
-$lang['updatecheck'] = 'Kontrollera uppdateringar och säkerhetsvarningar? DokuWiki behöver kontakta update.dokuwiki.org för den här funktionen.';
-$lang['userewrite'] = 'Använd rena webbadresser';
-$lang['useslash'] = 'Använd snedstreck för att separera namnrymder i webbadresser';
+$lang['usewordblock'] = 'Blockera spam baserat på ordlista';
+$lang['relnofollow'] = 'Använd rel="nofollow" för externa länkar';
+$lang['indexdelay'] = 'Tidsfördröjning före indexering (sek)';
+$lang['mailguard'] = 'Koda e-postadresser';
+$lang['iexssprotect'] = 'Kontrollera om uppladdade filer innehåller eventuellt skadlig JavaScript eller HTML-kod';
$lang['usedraft'] = 'Spara utkast automatiskt under redigering';
-$lang['sepchar'] = 'Ersätt blanktecken i webbadresser med';
-$lang['canonical'] = 'Använd fullständiga webbadresser';
-$lang['autoplural'] = 'Leta efter pluralformer av länkar';
-$lang['compression'] = 'Metod för komprimering av gamla versioner';
-$lang['cachetime'] = 'Maximal livslängd för cache (sek)';
+$lang['htmlok'] = 'Tillåt inbäddad HTML';
+$lang['phpok'] = 'Tillåt inbäddad PHP';
$lang['locktime'] = 'Maximal livslängd för fillåsning (sek)';
+$lang['cachetime'] = 'Maximal livslängd för cache (sek)';
+$lang['target____wiki'] = 'Målfönster för interna länkar';
+$lang['target____interwiki'] = 'Målfönster för interwiki-länkar';
+$lang['target____extern'] = 'Målfönster för externa länkar';
+$lang['target____media'] = 'Målfönster för medialänkar';
+$lang['target____windows'] = 'Målfönster för windowslänkar';
+$lang['refcheck'] = 'Kontrollera referenser till mediafiler';
+$lang['refshow'] = 'Antal mediareferenser som ska visas';
+$lang['gdlib'] = 'Version av GD-biblioteket';
+$lang['im_convert'] = 'Sökväg till ImageMagicks konverteringsverktyg';
+$lang['jpg_quality'] = 'Kvalitet för JPG-komprimering (0-100)';
$lang['fetchsize'] = 'Maximal storlek (bytes) som fetch.php får ladda ned externt';
+$lang['subscribers'] = 'Aktivera stöd för prenumeration på ändringar';
$lang['notify'] = 'Skicka meddelande om ändrade sidor till den här e-postadressen';
$lang['registernotify'] = 'Skicka meddelande om nyregistrerade användare till en här e-postadressen';
$lang['mailfrom'] = 'Avsändaradress i automatiska e-postmeddelanden';
$lang['mailprefix'] = 'Prefix i början på ämnesraden vid automatiska e-postmeddelanden';
+$lang['sitemap'] = 'Skapa Google sitemap (dagar)';
+$lang['rss_type'] = 'Typ av XML-flöde';
+$lang['rss_linkto'] = 'XML-flöde pekar på';
+$lang['rss_content'] = 'Vad ska visas för saker i XML-flödet?';
+$lang['rss_update'] = 'Uppdateringsintervall för XML-flöde (sek)';
+$lang['rss_show_summary'] = 'XML-flöde visar sammanfattning i rubriken';
+$lang['rss_media'] = 'Vilka ändringar ska listas i XML flödet?';
+$lang['updatecheck'] = 'Kontrollera uppdateringar och säkerhetsvarningar? DokuWiki behöver kontakta update.dokuwiki.org för den här funktionen.';
+$lang['userewrite'] = 'Använd rena webbadresser';
+$lang['useslash'] = 'Använd snedstreck för att separera namnrymder i webbadresser';
+$lang['sepchar'] = 'Ersätt blanktecken i webbadresser med';
+$lang['canonical'] = 'Använd fullständiga webbadresser';
+$lang['fnencode'] = 'Metod för kodning av icke-ASCII filnamn.';
+$lang['autoplural'] = 'Leta efter pluralformer av länkar';
+$lang['compression'] = 'Metod för komprimering av gamla versioner';
$lang['gzip_output'] = 'Använd gzip Content-Encoding för xhtml';
-$lang['gdlib'] = 'Version av GD-biblioteket';
-$lang['im_convert'] = 'Sökväg till ImageMagicks konverteringsverktyg';
-$lang['jpg_quality'] = 'Kvalitet för JPG-komprimering (0-100)';
-$lang['subscribers'] = 'Aktivera stöd för prenumeration på ändringar';
$lang['compress'] = 'Komprimera CSS och javascript';
-$lang['hidepages'] = 'Dölj matchande sidor (reguljära uttryck)';
$lang['send404'] = 'Skicka "HTTP 404/Page Not Found" för sidor som inte finns';
-$lang['sitemap'] = 'Skapa Google sitemap (dagar)';
$lang['broken_iua'] = 'Är funktionen ignore_user_abort trasig på ditt system? Det kan i så fall leda till att indexering av sökningar inte fungerar. Detta är ett känt problem med IIS+PHP/CGI. Se <a href="http://bugs.splitbrain.org/?do=details&amp;task_id=852">Bug 852</a> för mer info.';
$lang['xsendfile'] = 'Använd X-Sendfile huvudet för att låta webservern leverera statiska filer? Din webserver behöver stöd för detta.';
$lang['renderer_xhtml'] = 'Generera för användning i huvudwikipresentation (xhtml)';
$lang['renderer__core'] = '%s (dokuwiki core)';
$lang['renderer__plugin'] = '%s (plugin)';
-$lang['rememberme'] = 'Tillåt permanenta inloggningscookies (kom ihåg mig)';
-$lang['rss_type'] = 'Typ av XML-flöde';
-$lang['rss_linkto'] = 'XML-flöde pekar på';
-$lang['rss_content'] = 'Vad ska visas för saker i XML-flödet?';
-$lang['rss_update'] = 'Uppdateringsintervall för XML-flöde (sek)';
-$lang['recent_days'] = 'Hur många ändringar som ska sparas (dagar)';
-$lang['rss_show_summary'] = 'XML-flöde visar sammanfattning i rubriken';
-$lang['target____wiki'] = 'Målfönster för interna länkar';
-$lang['target____interwiki'] = 'Målfönster för interwiki-länkar';
-$lang['target____extern'] = 'Målfönster för externa länkar';
-$lang['target____media'] = 'Målfönster för medialänkar';
-$lang['target____windows'] = 'Målfönster för windowslänkar';
$lang['proxy____host'] = 'Proxyserver';
$lang['proxy____port'] = 'Proxyport';
$lang['proxy____user'] = 'Användarnamn för proxy';
$lang['proxy____pass'] = 'Lösenord för proxy';
$lang['proxy____ssl'] = 'Använd ssl för anslutning till proxy';
+$lang['proxy____except'] = 'Regular expression för matchning av URL som proxy ska hoppa över.';
$lang['safemodehack'] = 'Aktivera safemode hack';
$lang['ftp____host'] = 'FTP-server för safemode hack';
$lang['ftp____port'] = 'FTP-port för safemode hack';
@@ -190,3 +197,4 @@ $lang['useheading_o_0'] = 'Aldrig';
$lang['useheading_o_navigation'] = 'Endst navigering';
$lang['useheading_o_content'] = 'Endast innehåll i wiki';
$lang['useheading_o_1'] = 'Alltid';
+$lang['readdircache'] = 'Max ålder för readdir cache (sek)';
diff --git a/lib/plugins/config/lang/zh-tw/lang.php b/lib/plugins/config/lang/zh-tw/lang.php
index 8f5b16220..cc6e0246e 100644
--- a/lib/plugins/config/lang/zh-tw/lang.php
+++ b/lib/plugins/config/lang/zh-tw/lang.php
@@ -46,9 +46,9 @@ $lang['title'] = '本 wiki 的標題';
$lang['start'] = '開始頁面的名稱';
$lang['lang'] = '語系';
$lang['template'] = '樣板';
-$lang['tagline'] = '副標題 (若模板支援此功能)';
-$lang['sidebar'] = '側欄的頁面名稱 (若模板支援此功能) 。若把它留空,則會停用側欄';
-$lang['license'] = '您希望您的內容為何種授權方式?';
+$lang['tagline'] = '副標題 (若樣板支援此功能)';
+$lang['sidebar'] = '側欄的頁面名稱 (若樣板支援此功能) 。若把它留空,則會停用側欄';
+$lang['license'] = '您希望您的內容採用哪種授權方式?';
$lang['savedir'] = '儲存資料的目錄';
$lang['basedir'] = '根目錄';
$lang['baseurl'] = '根路徑 (URL)';
@@ -58,8 +58,8 @@ $lang['fmode'] = '檔案建立模式';
$lang['allowdebug'] = '允許除錯 <b>(不需要請停用!)</b>';
$lang['recent'] = '最近更新';
$lang['recent_days'] = '儲存多少天內的變更';
-$lang['breadcrumbs'] = '導覽鏈數量';
-$lang['youarehere'] = '顯示階層式導覽鏈';
+$lang['breadcrumbs'] = '導覽路徑數量。輸入0表示停用。';
+$lang['youarehere'] = '顯示階層式導覽路徑 (若要用此功能,建議停用上方的選項)';
$lang['fullpath'] = '顯示完整的路徑於頁面底部';
$lang['typography'] = '進行字元替換';
$lang['dformat'] = '日期格式 (參見 PHP 的 <a href="http://www.php.net/strftime">strftime</a> 函數)';
@@ -71,7 +71,7 @@ $lang['maxtoclevel'] = '目錄表顯示的最大層級';
$lang['maxseclevel'] = '可編輯段落的最大層級';
$lang['camelcase'] = '對連結使用 CamelCase';
$lang['deaccent'] = '清理頁面名稱';
-$lang['useheading'] = '使用第一個標題作為頁面名稱';
+$lang['useheading'] = '使用第一個標題作頁面名稱';
$lang['sneaky_index'] = '預設情況下,DokuWiki 會在索引頁會顯示所有分類名稱。啟用此選項,會隱藏使用者沒有閱讀權限的頁面,但也可能將他可以閱讀的子頁面一併隱藏。在特定 ACL 設定下,這可能導致索引無法使用。';
$lang['hidepages'] = '隱藏匹配的界面 (正規式)';
$lang['useacl'] = '使用存取控制名單';
@@ -121,7 +121,7 @@ $lang['registernotify'] = '寄送新使用者註冊資訊到這個電郵
$lang['mailfrom'] = '自動發送郵件時使用的郵件地址';
$lang['mailprefix'] = '自動發送郵件時使用的標題前綴';
$lang['htmlmail'] = '發送更加美觀,但體積會更大的 HTML 多部份電郵。若停用它,表示只發送純文字電郵。';
-$lang['sitemap'] = '產生 Google 站台地圖 (以多少天計算) 。輸入0表示停用';
+$lang['sitemap'] = '產生 Google 網站地圖 (以多少天計算) 。輸入0表示停用';
$lang['rss_type'] = 'XML feed 類型';
$lang['rss_linkto'] = 'XML feed 連結到';
$lang['rss_content'] = 'XML feed 項目中顯示什麼呢?';
@@ -130,7 +130,7 @@ $lang['rss_show_summary'] = '於標題中顯示簡要的 XML feed';
$lang['rss_media'] = '在 XML feed 中應列出哪些變更?';
$lang['updatecheck'] = '檢查更新與安全性警告?DokuWiki 需要聯繫 update.dokuwiki.org 才能使用此功能。';
$lang['userewrite'] = '使用好看的 URL';
-$lang['useslash'] = '在 URL 中使用斜線作為分類名稱的分隔字元';
+$lang['useslash'] = '在 URL 中使用斜線作分類名稱的分隔字元';
$lang['sepchar'] = '頁面名稱中單字的分隔字元';
$lang['canonical'] = '使用最典型的 URL';
$lang['fnencode'] = '非 ASCII 文件名稱的編輯方法。';
@@ -140,12 +140,12 @@ $lang['gzip_output'] = '對 xhtml 使用 gzip 內容編碼';
$lang['compress'] = '壓縮 CSS 與 JavaScript 的輸出';
$lang['cssdatauri'] = '假如 CSS 中所引用的圖片小於該數字大小(bytes),圖片將被直接嵌入 CSS 中,以減少 HTTP Request 的發送。 IE 7 及以下的版本並不支援此功能。推薦把此數值設定成 <code>400</code> 至 <code>600</code> bytes 之間。若輸入 <code>0</code> 則停用此功能。';
$lang['send404'] = '存取不存在的頁面時送出 "HTTP 404/Page Not Found"';
-$lang['broken_iua'] = 'ignore_user_abort 功能失效了?這有可能導致搜索索引不可用。IIS+PHP/CGI 已損壞。請參閱 <a href=\"http://bugs.splitbrain.org/?do=details&task_id=852\">Bug 852</a> 獲取更多信息。';
-$lang['xsendfile'] = '使用 X-Sendfile 頭讓服務器發送狀態文件?您的服務器需要支持該功能。';
-$lang['renderer_xhtml'] = '主要wiki輸出 (xhtml) 的渲染器';
+$lang['broken_iua'] = 'ignore_user_abort 功能失效了?這有可能導致搜索索引不可用。IIS+PHP/CGI 已損壞。請參閱 <a href=\"http://bugs.splitbrain.org/?do=details&task_id=852\">Bug 852</a> 獲取更多訊息。';
+$lang['xsendfile'] = '使用 X-Sendfile 頭讓網頁伺服器發送狀態文件?您的網頁伺服器需要支持該功能。';
+$lang['renderer_xhtml'] = '主要 wiki 輸出 (xhtml) 的渲染器';
$lang['renderer__core'] = '%s (dokuwiki 核心)';
$lang['renderer__plugin'] = '%s (附加元件)';
-$lang['dnslookups'] = 'Dokuwiki 將查詢使用者編輯頁面的遠程 IP 位址主機名稱。若您的 DNS 服務器速度較慢、失效,或者您不想要此功能,请停用此選項';
+$lang['dnslookups'] = 'Dokuwiki 將查詢使用者編輯頁面的遠程 IP 位址主機名稱。若您的 DNS 伺服器速度較慢、失效,或者您不想要此功能,请停用此選項';
$lang['proxy____host'] = 'Proxy 伺服器名稱';
$lang['proxy____port'] = 'Proxy 連接埠';
$lang['proxy____user'] = 'Proxy 使用者名稱';
@@ -188,7 +188,7 @@ $lang['compression_o_0'] = '無';
$lang['compression_o_gz'] = 'gzip';
$lang['compression_o_bz2'] = 'bz2';
$lang['xsendfile_o_0'] = '不使用';
-$lang['xsendfile_o_1'] = '專有 lighttpd 標頭 (1.5 發布前)';
+$lang['xsendfile_o_1'] = '專有 lighttpd 標頭 (1.5 發佈前)';
$lang['xsendfile_o_2'] = '標準 X-Sendfile 標頭';
$lang['xsendfile_o_3'] = '專有 Nginx X-Accel-Redirect 標頭';
$lang['showuseras_o_loginname'] = '登入名稱';
diff --git a/lib/plugins/config/plugin.info.txt b/lib/plugins/config/plugin.info.txt
index 1f9968154..510be3be4 100644
--- a/lib/plugins/config/plugin.info.txt
+++ b/lib/plugins/config/plugin.info.txt
@@ -1,7 +1,7 @@
base config
author Christopher Smith
email chris@jalakai.co.uk
-date 2012-09-08
+date 2013-02-24
name Configuration Manager
desc Manage Dokuwiki's Configuration Settings
url http://dokuwiki.org/plugin:config
diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php
index a30a0605b..8eb99284d 100644
--- a/lib/plugins/config/settings/config.class.php
+++ b/lib/plugins/config/settings/config.class.php
@@ -6,6 +6,9 @@
* @author Ben Coburn <btcoburn@silicodon.net>
*/
+
+if(!defined('CM_KEYMARKER')) define('CM_KEYMARKER','____');
+
if (!class_exists('configuration')) {
class configuration {
@@ -17,6 +20,7 @@ if (!class_exists('configuration')) {
var $_metadata = array(); // holds metadata describing the settings
var $setting = array(); // array of setting objects
var $locked = false; // configuration is considered locked if it can't be updated
+ var $show_disabled_plugins = false;
// configuration filenames
var $_default_files = array();
@@ -35,6 +39,7 @@ if (!class_exists('configuration')) {
msg('No configuration metadata found at - '.htmlspecialchars($datafile),-1);
return;
}
+ $meta = array();
include($datafile);
if (isset($config['varname'])) $this->_name = $config['varname'];
@@ -45,14 +50,8 @@ if (!class_exists('configuration')) {
$this->_local_files = $config_cascade['main']['local'];
$this->_protected_files = $config_cascade['main']['protected'];
-# if (isset($file['default'])) $this->_default_file = $file['default'];
-# if (isset($file['local'])) $this->_local_file = $file['local'];
-# if (isset($file['protected'])) $this->_protected_file = $file['protected'];
-
$this->locked = $this->_is_locked();
-
$this->_metadata = array_merge($meta, $this->get_plugintpl_metadata($conf['template']));
-
$this->retrieve_settings();
}
@@ -68,19 +67,25 @@ if (!class_exists('configuration')) {
$keys = array_merge(array_keys($this->_metadata),array_keys($default), array_keys($local), array_keys($protected));
$keys = array_unique($keys);
+ $param = null;
foreach ($keys as $key) {
if (isset($this->_metadata[$key])) {
$class = $this->_metadata[$key][0];
- $class = ($class && class_exists('setting_'.$class)) ? 'setting_'.$class : 'setting';
- if ($class=='setting') {
- $this->setting[] = new setting_no_class($key,$param);
+
+ if($class && class_exists('setting_'.$class)){
+ $class = 'setting_'.$class;
+ } else {
+ if($class != '') {
+ $this->setting[] = new setting_no_class($key,$param);
+ }
+ $class = 'setting';
}
$param = $this->_metadata[$key];
array_shift($param);
} else {
$class = 'setting_undefined';
- $param = NULL;
+ $param = null;
}
if (!in_array($class, $no_default_check) && !isset($default[$key])) {
@@ -130,6 +135,15 @@ if (!class_exists('configuration')) {
return true;
}
+ /**
+ * Update last modified time stamp of the config file
+ */
+ function touch_settings(){
+ if ($this->locked) return false;
+ $file = end($this->_local_files);
+ return @touch($file);
+ }
+
function _read_config_group($files) {
$config = array();
foreach ($files as $file) {
@@ -147,7 +161,6 @@ if (!class_exists('configuration')) {
if (!$file) return array();
$config = array();
-# $file = eval('return '.$file.';');
if ($this->_format == 'php') {
@@ -161,14 +174,32 @@ if (!class_exists('configuration')) {
preg_match_all($pattern,$contents,$matches,PREG_SET_ORDER);
for ($i=0; $i<count($matches); $i++) {
+ $value = $matches[$i][2];
+
// correct issues with the incoming data
// FIXME ... for now merge multi-dimensional array indices using ____
$key = preg_replace('/.\]\[./',CM_KEYMARKER,$matches[$i][1]);
- // remove quotes from quoted strings & unescape escaped data
- $value = preg_replace('/^(\'|")(.*)(?<!\\\\)\1$/s','$2',$matches[$i][2]);
- $value = strtr($value, array('\\\\'=>'\\','\\\''=>'\'','\\"'=>'"'));
+
+ // handle arrays
+ if(preg_match('/^array ?\((.*)\)/', $value, $match)){
+ $arr = explode(',', $match[1]);
+
+ // remove quotes from quoted strings & unescape escaped data
+ $len = count($arr);
+ for($j=0; $j<$len; $j++){
+ $arr[$j] = trim($arr[$j]);
+ $arr[$j] = preg_replace('/^(\'|")(.*)(?<!\\\\)\1$/s','$2',$arr[$j]);
+ $arr[$j] = strtr($arr[$j], array('\\\\'=>'\\','\\\''=>'\'','\\"'=>'"'));
+ }
+
+ $value = $arr;
+ }else{
+ // remove quotes from quoted strings & unescape escaped data
+ $value = preg_replace('/^(\'|")(.*)(?<!\\\\)\1$/s','$2',$value);
+ $value = strtr($value, array('\\\\'=>'\\','\\\''=>'\'','\\"'=>'"'));
+ }
$config[$key] = $value;
}
@@ -195,9 +226,6 @@ if (!class_exists('configuration')) {
function _out_footer() {
$out = '';
if ($this->_format == 'php') {
- # if ($this->_protected_file) {
- # $out .= "\n@include(".$this->_protected_file.");\n";
- # }
$out .= "\n// end auto-generated content\n";
}
@@ -209,7 +237,6 @@ if (!class_exists('configuration')) {
function _is_locked() {
if (!$this->_local_files) return true;
-# $local = eval('return '.$this->_local_file.';');
$local = $this->_local_files[0];
if (!is_writable(dirname($local))) return true;
@@ -241,7 +268,7 @@ if (!class_exists('configuration')) {
function get_plugin_list() {
if (is_null($this->_plugin_list)) {
- $list = plugin_list('',true); // all plugins, including disabled ones
+ $list = plugin_list('',$this->show_disabled_plugins);
// remove this plugin from the list
$idx = array_search('config',$list);
@@ -332,21 +359,21 @@ if (!class_exists('setting')) {
class setting {
var $_key = '';
- var $_default = NULL;
- var $_local = NULL;
- var $_protected = NULL;
+ var $_default = null;
+ var $_local = null;
+ var $_protected = null;
var $_pattern = '';
var $_error = false; // only used by those classes which error check
- var $_input = NULL; // only used by those classes which error check
+ var $_input = null; // only used by those classes which error check
var $_cautionList = array(
'basedir' => 'danger', 'baseurl' => 'danger', 'savedir' => 'danger', 'cookiedir' => 'danger', 'useacl' => 'danger', 'authtype' => 'danger', 'superuser' => 'danger', 'userewrite' => 'danger',
'start' => 'warning', 'camelcase' => 'warning', 'deaccent' => 'warning', 'sepchar' => 'warning', 'compression' => 'warning', 'xsendfile' => 'warning', 'renderer_xhtml' => 'warning', 'fnencode' => 'warning',
- 'allowdebug' => 'security', 'htmlok' => 'security', 'phpok' => 'security', 'iexssprotect' => 'security', 'xmlrpc' => 'security', 'fullpath' => 'security'
+ 'allowdebug' => 'security', 'htmlok' => 'security', 'phpok' => 'security', 'iexssprotect' => 'security', 'remote' => 'security', 'fullpath' => 'security'
);
- function setting($key, $params=NULL) {
+ function setting($key, $params=null) {
$this->_key = $key;
if (is_array($params)) {
@@ -366,10 +393,12 @@ if (!class_exists('setting')) {
}
/**
- * update setting with user provided value $input
- * if value fails error check, save it
+ * update changed setting with user provided value $input
+ * - if changed value fails error check, save it to $this->_input (to allow echoing later)
+ * - if changed value passes error check, set $this->_local to the new value
*
- * @return boolean true if changed, false otherwise (incl. on error)
+ * @param mixed $input the new value
+ * @return boolean true if changed, false otherwise (incl. on error)
*/
function update($input) {
if (is_null($input)) return false;
@@ -407,7 +436,7 @@ if (!class_exists('setting')) {
}
$key = htmlspecialchars($this->_key);
- $value = htmlspecialchars($value);
+ $value = formText($value);
$label = '<label for="config___'.$key.'">'.$this->prompt($plugin).'</label>';
$input = '<textarea rows="3" cols="40" id="config___'.$key.'" name="config['.$key.']" class="edit" '.$disable.'>'.$value.'</textarea>';
@@ -425,10 +454,9 @@ if (!class_exists('setting')) {
$out = '';
if ($fmt=='php') {
- // translation string needs to be improved FIXME
$tr = array("\\" => '\\\\', "'" => '\\\'');
- $out = '$'.$var."['".$this->_out_key()."'] = '".strtr($this->_local, $tr)."';\n";
+ $out = '$'.$var."['".$this->_out_key()."'] = '".strtr( cleanText($this->_local), $tr)."';\n";
}
return $out;
@@ -466,6 +494,110 @@ if (!class_exists('setting')) {
}
}
+
+if (!class_exists('setting_array')) {
+ class setting_array extends setting {
+
+ /**
+ * Create an array from a string
+ *
+ * @param $string
+ * @return array
+ */
+ protected function _from_string($string){
+ $array = explode(',', $string);
+ $array = array_map('trim', $array);
+ $array = array_filter($array);
+ $array = array_unique($array);
+ return $array;
+ }
+
+ /**
+ * Create a string from an array
+ *
+ * @param $array
+ * @return string
+ */
+ protected function _from_array($array){
+ return join(', ', (array) $array);
+ }
+
+ /**
+ * update setting with user provided value $input
+ * if value fails error check, save it
+ *
+ * @param string $input
+ * @return bool true if changed, false otherwise (incl. on error)
+ */
+ function update($input) {
+ if (is_null($input)) return false;
+ if ($this->is_protected()) return false;
+
+ $input = $this->_from_string($input);
+
+ $value = is_null($this->_local) ? $this->_default : $this->_local;
+ if ($value == $input) return false;
+
+ foreach($input as $item){
+ if ($this->_pattern && !preg_match($this->_pattern,$item)) {
+ $this->_error = true;
+ $this->_input = $input;
+ return false;
+ }
+ }
+
+ $this->_local = $input;
+ return true;
+ }
+
+ protected function _escape($string) {
+ $tr = array("\\" => '\\\\', "'" => '\\\'');
+ return "'".strtr( cleanText($string), $tr)."'";
+ }
+
+ /**
+ * generate string to save setting value to file according to $fmt
+ */
+ function out($var, $fmt='php') {
+
+ if ($this->is_protected()) return '';
+ if (is_null($this->_local) || ($this->_default == $this->_local)) return '';
+
+ $out = '';
+
+ if ($fmt=='php') {
+ $vals = array_map(array($this, '_escape'), $this->_local);
+ $out = '$'.$var."['".$this->_out_key()."'] = array(".join(', ',$vals).");\n";
+ }
+
+ return $out;
+ }
+
+ function html(&$plugin, $echo=false) {
+ $value = '';
+ $disable = '';
+
+ if ($this->is_protected()) {
+ $value = $this->_protected;
+ $disable = 'disabled="disabled"';
+ } else {
+ if ($echo && $this->_error) {
+ $value = $this->_input;
+ } else {
+ $value = is_null($this->_local) ? $this->_default : $this->_local;
+ }
+ }
+
+ $key = htmlspecialchars($this->_key);
+ $value = htmlspecialchars($this->_from_array($value));
+
+ $label = '<label for="config___'.$key.'">'.$this->prompt($plugin).'</label>';
+ $input = '<input id="config___'.$key.'" name="config['.$key.']" type="text" class="edit" value="'.$value.'" '.$disable.'/>';
+ return array($label,$input);
+ }
+ }
+}
+
if (!class_exists('setting_string')) {
class setting_string extends setting {
function html(&$plugin, $echo=false) {
@@ -532,6 +664,7 @@ if (!class_exists('setting_email')) {
class setting_email extends setting_string {
var $_pattern = SETTING_EMAIL_PATTERN; // no longer required, retained for backward compatibility - FIXME, may not be necessary
var $_multiple = false;
+ var $_placeholders = false;
/**
* update setting with user provided value $input
@@ -545,15 +678,36 @@ if (!class_exists('setting_email')) {
$value = is_null($this->_local) ? $this->_default : $this->_local;
if ($value == $input) return false;
+ if($input === ''){
+ $this->_local = $input;
+ return true;
+ }
+ $mail = $input;
+
+ if($this->_placeholders){
+ // replace variables with pseudo values
+ $mail = str_replace('@USER@','joe',$mail);
+ $mail = str_replace('@NAME@','Joe Schmoe',$mail);
+ $mail = str_replace('@MAIL@','joe@example.com',$mail);
+ }
+ // multiple mail addresses?
if ($this->_multiple) {
- $mails = array_filter(array_map('trim', explode(',', $input)));
+ $mails = array_filter(array_map('trim', explode(',', $mail)));
} else {
- $mails = array($input);
+ $mails = array($mail);
}
+ // check them all
foreach ($mails as $mail) {
- if (!mail_isvalid($mail)) {
+ // only check the address part
+ if(preg_match('#(.*?)<(.*?)>#', $mail, $matches)){
+ $addr = $matches[2];
+ }else{
+ $addr = $mail;
+ }
+
+ if (!mail_isvalid($addr)) {
$this->_error = true;
$this->_input = $input;
return false;
@@ -566,46 +720,15 @@ if (!class_exists('setting_email')) {
}
}
+/**
+ * @deprecated 2013-02-16
+ */
if (!class_exists('setting_richemail')) {
class setting_richemail extends setting_email {
-
- /**
- * update setting with user provided value $input
- * if value fails error check, save it
- *
- * @return boolean true if changed, false otherwise (incl. on error)
- */
- function update($input) {
- if (is_null($input)) return false;
- if ($this->is_protected()) return false;
-
- $value = is_null($this->_local) ? $this->_default : $this->_local;
- if ($value == $input) return false;
-
- // replace variables with pseudo values
- $test = $input;
- $test = str_replace('@USER@','joe',$test);
- $test = str_replace('@NAME@','Joe Schmoe',$test);
- $test = str_replace('@MAIL@','joe@example.com',$test);
-
- // now only check the address part
- if(preg_match('#(.*?)<(.*?)>#',$test,$matches)){
- $text = trim($matches[1]);
- $addr = $matches[2];
- }else{
- $addr = $test;
- }
-
- if ($test !== '' && !mail_isvalid($addr)) {
- $this->_error = true;
- $this->_input = $input;
- return false;
- }
-
- $this->_local = $input;
- return true;
- }
-
+ function update($input) {
+ $this->_placeholders = true;
+ return parent::update($input);
+ }
}
}
diff --git a/lib/plugins/config/settings/config.metadata.php b/lib/plugins/config/settings/config.metadata.php
index 89824381b..22e76a013 100644
--- a/lib/plugins/config/settings/config.metadata.php
+++ b/lib/plugins/config/settings/config.metadata.php
@@ -20,9 +20,7 @@
* 'numericopt' - like above, but accepts empty values
* 'onoff' - checkbox input, setting output 0|1
* 'multichoice' - select input (single choice), setting output with quotes, required _choices parameter
- * 'email' - text input, input must conform to email address format, setting output in quotes
- * 'richemail' - text input, input must conform to email address format but accepts variables and
- * emails with a real name prepended (when email address is given in <>)
+ * 'email' - text input, input must conform to email address format
* 'password' - password input, minimal input validation, setting output text in quotes, maybe encoded
* according to the _code parameter
* 'dirchoice' - as multichoice, selection choices based on folders found at location specified in _dir
@@ -32,6 +30,9 @@
* separated list of checked choices
* 'fieldset' - used to group configuration settings, but is not itself a setting. To make this clear in
* the language files the keys for this type should start with '_'.
+ * 'array' - a simple (one dimensional) array of string values, shown as comma separated list in the
+ * config manager but saved as PHP array(). Values may not contain commas themselves.
+ * _pattern matching on the array values supported.
*
* Single Setting (source: settings/extra.class.php)
* -------------------------------------------------
@@ -69,14 +70,6 @@ $config['varname'] = 'conf'; // name of the config variable, sans $
// this value can be overriden when calling save_settings() method
$config['heading'] = 'Dokuwiki\'s Main Configuration File - Local Settings';
-/* DEPRECATED
-// ---------------[ setting files ]--------------------------------------
-// these values can be string expressions, they will be eval'd before use
-$file['local'] = "DOKU_CONF.'local.php'"; // mandatory (file doesn't have to exist)
-$file['default'] = "DOKU_CONF.'dokuwiki.php'"; // optional
-$file['protected'] = "DOKU_CONF.'local.protected.php'"; // optional
- */
-
// test value (FIXME, remove before publishing)
//$meta['test'] = array('multichoice','_choices' => array(''));
@@ -126,7 +119,7 @@ $meta['_authentication'] = array('fieldset');
$meta['useacl'] = array('onoff');
$meta['autopasswd'] = array('onoff');
$meta['authtype'] = array('authtype');
-$meta['passcrypt'] = array('multichoice','_choices' => array('smd5','md5','apr1','sha1','ssha','lsmd5','crypt','mysql','my411','kmd5','pmd5','hmd5','mediawiki','bcrypt','sha512'));
+$meta['passcrypt'] = array('multichoice','_choices' => array('smd5','md5','apr1','sha1','ssha','lsmd5','crypt','mysql','my411','kmd5','pmd5','hmd5','mediawiki','bcrypt','djangomd5','djangosha1','sha512'));
$meta['defaultgroup']= array('string');
$meta['superuser'] = array('string');
$meta['manager'] = array('string');
@@ -174,8 +167,8 @@ $meta['_notifications'] = array('fieldset');
$meta['subscribers'] = array('onoff');
$meta['subscribe_time'] = array('numeric');
$meta['notify'] = array('email', '_multiple' => true);
-$meta['registernotify'] = array('email');
-$meta['mailfrom'] = array('richemail');
+$meta['registernotify'] = array('email', '_multiple' => true);
+$meta['mailfrom'] = array('email', '_placeholders' => true);
$meta['mailprefix'] = array('string');
$meta['htmlmail'] = array('onoff');
diff --git a/lib/plugins/config/settings/extra.class.php b/lib/plugins/config/settings/extra.class.php
index b4e35b1cc..e4b97eb01 100644
--- a/lib/plugins/config/settings/extra.class.php
+++ b/lib/plugins/config/settings/extra.class.php
@@ -43,16 +43,50 @@ if (!class_exists('setting_authtype')) {
class setting_authtype extends setting_multichoice {
function initialize($default,$local,$protected) {
+ global $plugin_controller;
- // populate $this->_choices with a list of available auth mechanisms
- $authtypes = glob(DOKU_INC.'inc/auth/*.class.php');
- $authtypes = preg_replace('#^.*/([^/]*)\.class\.php$#i','$1', $authtypes);
- $authtypes = array_diff($authtypes, array('basic'));
- sort($authtypes);
+ // retrieve auth types provided by plugins
+ foreach ($plugin_controller->getList('auth') as $plugin) {
+ $this->_choices[] = $plugin;
+ }
- $this->_choices = $authtypes;
+ parent::initialize($default,$local,$protected);
+ }
- parent::initialize($default,$local,$protected);
+ function update($input) {
+ global $plugin_controller;
+
+ // is an update possible/requested?
+ $local = $this->_local; // save this, parent::update() may change it
+ if (!parent::update($input)) return false; // nothing changed or an error caught by parent
+ $this->_local = $local; // restore original, more error checking to come
+
+ // attempt to load the plugin
+ $auth_plugin = $plugin_controller->load('auth', $input);
+
+ // @TODO: throw an error in plugin controller instead of returning null
+ if (is_null($auth_plugin)) {
+ $this->_error = true;
+ msg('Cannot load Auth Plugin "' . $input . '"', -1);
+ return false;
+ }
+
+ // verify proper instantiation (is this really a plugin?) @TODO use instanceof? implement interface?
+ if (is_object($auth_plugin) && !method_exists($auth_plugin, 'getPluginName')) {
+ $this->_error = true;
+ msg('Cannot create Auth Plugin "' . $input . '"', -1);
+ return false;
+ }
+
+ // did we change the auth type? logout
+ global $conf;
+ if($conf['authtype'] != $input) {
+ msg('Authentication system changed. Please re-login.');
+ auth_logoff();
+ }
+
+ $this->_local = $input;
+ return true;
}
}
}
diff --git a/lib/plugins/config/style.css b/lib/plugins/config/style.css
index 1be94feb9..054021ed8 100644
--- a/lib/plugins/config/style.css
+++ b/lib/plugins/config/style.css
@@ -104,6 +104,10 @@
height: 4em;
}
+#config__manager td textarea.edit:focus {
+ height: 10em;
+}
+
#config__manager tr .input,
#config__manager tr input,
#config__manager tr textarea,
@@ -150,15 +154,6 @@
}
-/* IE6 correction */
-* html #config__manager .selection label {
- padding-top: 2px;
-}
-
-#config__manager .selection input.checkbox {
- padding-left: 0.7em;
-}
-
#config__manager .other {
clear: both;
padding-top: 0.5em;
diff --git a/lib/plugins/info/lang/sl/lang.php b/lib/plugins/info/lang/sl/lang.php
deleted file mode 100644
index 62936947c..000000000
--- a/lib/plugins/info/lang/sl/lang.php
+++ /dev/null
@@ -1,12 +0,0 @@
-<?php
-/**
- * English language file
- *
- * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
- * @author Guillaume Turri <guillaume.turri@gmail.com>
- */
-
-$lang['encoding'] = 'utf-8';
-$lang['direction'] = 'ltr';
-$lang['onHidden'] = 'Click to display ⇲';
-$lang['onVisible'] = 'Click to hide ⇱';
diff --git a/lib/plugins/info/plugin.info.txt b/lib/plugins/info/plugin.info.txt
index 5c7d583c0..053743639 100644
--- a/lib/plugins/info/plugin.info.txt
+++ b/lib/plugins/info/plugin.info.txt
@@ -1,7 +1,7 @@
base info
author Andreas Gohr
email andi@splitbrain.org
-date 2012-02-04
+date 2013-02-16
name Info Plugin
desc Displays information about various DokuWiki internals
url http://dokuwiki.org/plugin:info
diff --git a/lib/plugins/info/syntax.php b/lib/plugins/info/syntax.php
index d813aa23a..5e7543603 100644
--- a/lib/plugins/info/syntax.php
+++ b/lib/plugins/info/syntax.php
@@ -60,9 +60,6 @@ class syntax_plugin_info extends DokuWiki_Syntax_Plugin {
if($format == 'xhtml'){
//handle various info stuff
switch ($data[0]){
- case 'version':
- $renderer->doc .= getVersion();
- break;
case 'syntaxmodes':
$renderer->doc .= $this->_syntaxmodes_xhtml();
break;
@@ -84,6 +81,12 @@ class syntax_plugin_info extends DokuWiki_Syntax_Plugin {
case 'helperplugins':
$this->_plugins_xhtml('helper', $renderer);
break;
+ case 'authplugins':
+ $this->_plugins_xhtml('auth', $renderer);
+ break;
+ case 'remoteplugins':
+ $this->_plugins_xhtml('remote', $renderer);
+ break;
case 'helpermethods':
$this->_helpermethods_xhtml($renderer);
break;
diff --git a/lib/plugins/plugin/admin.php b/lib/plugins/plugin/admin.php
index 8b1ee3c7d..de4de6aef 100644
--- a/lib/plugins/plugin/admin.php
+++ b/lib/plugins/plugin/admin.php
@@ -61,11 +61,12 @@ class admin_plugin_plugin extends DokuWiki_Admin_Plugin {
* handle user request
*/
function handle() {
+ global $INPUT;
// enable direct access to language strings
$this->setupLocale();
- $fn = $_REQUEST['fn'];
+ $fn = $INPUT->param('fn');
if (is_array($fn)) {
$this->cmd = key($fn);
$this->plugin = is_array($fn[$this->cmd]) ? key($fn[$this->cmd]) : null;
diff --git a/lib/plugins/plugin/lang/ar/lang.php b/lib/plugins/plugin/lang/ar/lang.php
index 8327e5ce3..a1a778131 100644
--- a/lib/plugins/plugin/lang/ar/lang.php
+++ b/lib/plugins/plugin/lang/ar/lang.php
@@ -50,4 +50,4 @@ $lang['enabled'] = 'الاضافة %s فُعلت. ';
$lang['notenabled'] = 'تعذر تفعيل الاضافة %s، تحقق من اذونات الملف.';
$lang['disabled'] = 'عُطلت الإضافة %s.';
$lang['notdisabled'] = 'تعذر تعطيل الإضافة %s، تحقق من اذونات الملف.';
-$lang['packageinstalled'] = 'حزمة الإضافة (%d plugin(s): %Xs) ثبتت بنجاج.';
+$lang['packageinstalled'] = 'حزمة الإضافة (%d plugin(s): %s) ثبتت بنجاج.';
diff --git a/lib/plugins/plugin/lang/cs/lang.php b/lib/plugins/plugin/lang/cs/lang.php
index 20a015cd4..98fae12c7 100644
--- a/lib/plugins/plugin/lang/cs/lang.php
+++ b/lib/plugins/plugin/lang/cs/lang.php
@@ -13,6 +13,7 @@
* @author zbynek.krivka@seznam.cz
* @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com>
* @author Jakub A. Těšínský (j@kub.cz)
+ * @author mkucera66@seznam.cz
*/
$lang['menu'] = 'Správa pluginů';
$lang['download'] = 'Stáhnout a instalovat plugin';
diff --git a/lib/plugins/plugin/lang/de-informal/lang.php b/lib/plugins/plugin/lang/de-informal/lang.php
index abcdf2c83..5d1649434 100644
--- a/lib/plugins/plugin/lang/de-informal/lang.php
+++ b/lib/plugins/plugin/lang/de-informal/lang.php
@@ -8,6 +8,8 @@
* @author Matthias Schulte <post@lupo49.de>
* @author Christian Wichmann <nospam@zone0.de>
* @author Pierre Corell <info@joomla-praxis.de>
+ * @author Frank Loizzi <contact@software.bacal.de>
+ * @author Volker Bödker <volker@boedker.de>
*/
$lang['menu'] = 'Plugins verwalten';
$lang['download'] = 'Herunterladen und installieren einer neuen Erweiterung';
diff --git a/lib/plugins/plugin/lang/el/lang.php b/lib/plugins/plugin/lang/el/lang.php
index bd6dc2013..4a6f1dbfd 100644
--- a/lib/plugins/plugin/lang/el/lang.php
+++ b/lib/plugins/plugin/lang/el/lang.php
@@ -12,6 +12,7 @@
* @author Konstantinos Koryllos <koryllos@gmail.com>
* @author George Petsagourakis <petsagouris@gmail.com>
* @author Petros Vidalis <pvidalis@gmail.com>
+ * @author Vasileios Karavasilis vasileioskaravasilis@gmail.com
*/
$lang['menu'] = 'Διαχείριση Επεκτάσεων';
$lang['download'] = 'Κατεβάστε και εγκαταστήστε μια νέα επέκταση (plugin)';
diff --git a/lib/plugins/plugin/lang/fr/lang.php b/lib/plugins/plugin/lang/fr/lang.php
index 06cd1ab8d..2926225ed 100644
--- a/lib/plugins/plugin/lang/fr/lang.php
+++ b/lib/plugins/plugin/lang/fr/lang.php
@@ -20,6 +20,7 @@
* @author Yannick Aure <yannick.aure@gmail.com>
* @author Olivier DUVAL <zorky00@gmail.com>
* @author Anael Mobilia <contrib@anael.eu>
+ * @author Bruno Veilleux <bruno.vey@gmail.com>
*/
$lang['menu'] = 'Gestion des extensions';
$lang['download'] = 'Télécharger et installer une nouvelle extension';
diff --git a/lib/plugins/plugin/lang/gl/lang.php b/lib/plugins/plugin/lang/gl/lang.php
index fecdf9425..b3da44096 100644
--- a/lib/plugins/plugin/lang/gl/lang.php
+++ b/lib/plugins/plugin/lang/gl/lang.php
@@ -4,7 +4,7 @@
*
* @author Medúlio <medulio@ciberirmandade.org>
* @author Oscar M. Lage <r0sk10@gmail.com>
- * @author Leandro Regueiro <leandro.regueiro@gmail.com>
+ * @author Rodrigo Rega <rodrigorega@gmail.com>
*/
$lang['menu'] = 'Xestionar Extensións';
$lang['download'] = 'Descargar e instalar unha nova extensión';
diff --git a/lib/plugins/plugin/lang/hi/lang.php b/lib/plugins/plugin/lang/hi/lang.php
index ab29c6550..67b177256 100644
--- a/lib/plugins/plugin/lang/hi/lang.php
+++ b/lib/plugins/plugin/lang/hi/lang.php
@@ -6,7 +6,6 @@
* @author yndesai@gmail.com
*/
$lang['unknown'] = 'अज्ञात';
-$lang['deleted'] = 'मिटाया हुआ';
$lang['date'] = 'दिनांक:';
$lang['author'] = 'लेखक:';
$lang['error'] = 'अज्ञात त्रुटि हुइ';
diff --git a/lib/plugins/plugin/lang/ja/lang.php b/lib/plugins/plugin/lang/ja/lang.php
index d366806c3..73f295157 100644
--- a/lib/plugins/plugin/lang/ja/lang.php
+++ b/lib/plugins/plugin/lang/ja/lang.php
@@ -9,6 +9,7 @@
* @author Daniel Dupriest <kououken@gmail.com>
* @author Kazutaka Miyasaka <kazmiya@gmail.com>
* @author Taisuke Shimamoto <dentostar@gmail.com>
+ * @author Satoshi Sahara <sahara.satoshi@gmail.com>
*/
$lang['menu'] = 'プラグイン管理';
$lang['download'] = 'プラグインのダウンロードとインストール';
diff --git a/lib/plugins/plugin/lang/ko/admin_plugin.txt b/lib/plugins/plugin/lang/ko/admin_plugin.txt
index b553d622b..7cbd08f7a 100644
--- a/lib/plugins/plugin/lang/ko/admin_plugin.txt
+++ b/lib/plugins/plugin/lang/ko/admin_plugin.txt
@@ -1,5 +1,3 @@
====== 플러그인 관리 ======
-이 페이지에서 Dokuwiki [[doku>plugins|플러그인]]에 관련된 모든 관리 작업을 합니다. 플러그인을 다운로드하거나 설치하기 위해서는 웹 서버가 플러그인 디렉토리에 대해 쓰기 권한을 가지고 있어야 합니다.
-
-
+이 페이지에서 Dokuwiki [[doku>plugins|플러그인]]에 관련된 모든 관리 작업을 합니다. 플러그인을 다운로드하거나 설치하기 위해서는 웹 서버가 플러그인 디렉토리에 대해 쓰기 권한을 가지고 있어야 합니다. \ No newline at end of file
diff --git a/lib/plugins/plugin/lang/ko/lang.php b/lib/plugins/plugin/lang/ko/lang.php
index 4fc6fd1d9..447fe667b 100644
--- a/lib/plugins/plugin/lang/ko/lang.php
+++ b/lib/plugins/plugin/lang/ko/lang.php
@@ -1,13 +1,12 @@
<?php
/**
- * korean language file
+ * Korean language file
*
- * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author jk Lee
* @author dongnak@gmail.com
* @author Song Younghwan <purluno@gmail.com>
- * @author SONG Younghwan <purluno@gmail.com>
- * @author Seung-Chul Yoo <dryoo@live.com>
+ * @author Seung-Chul Yoo <dryoo@live.com>
* @author erial2@gmail.com
* @author Myeongjin <aranet100@gmail.com>
*/
@@ -32,7 +31,7 @@ $lang['update_none'] = '업데이트를 찾을 수 없습니다.';
$lang['deleting'] = '삭제 중 ...';
$lang['deleted'] = '%s 플러그인이 삭제되었습니다.';
$lang['downloading'] = '다운로드 중 ...';
-$lang['downloaded'] = '%s 플러그인이 성공적으로 설치되었습니다.';
+$lang['downloaded'] = '%s 플러그인이 성공적으로 설치되었습니다';
$lang['downloads'] = '다음 플러그인이 성공적으로 설치되었습니다:';
$lang['download_none'] = '플러그인이 없거나 다운로드 또는 설치 중에 알 수 없는 문제가 발생했습니다.';
$lang['plugin'] = '플러그인:';
@@ -46,13 +45,13 @@ $lang['author'] = '만든이:';
$lang['www'] = '웹:';
$lang['error'] = '알 수 없는 문제가 발생했습니다.';
$lang['error_download'] = '플러그인 파일을 다운로드 할 수 없습니다: %s';
-$lang['error_badurl'] = '잘못된 URL 같습니다 - URL에서 파일 이름을 알 수 없습니다.';
-$lang['error_dircreate'] = '다운로드를 받기 위한 임시 디렉토리를 만들 수 없습니다.';
-$lang['error_decompress'] = '플러그인 관리자가 다운로드 받은 파일을 압축을 풀 수 없습니다. 잘못 다운로드 받았을 수도 있으니 다시 한번 시도해보기 바랍니다. 또는 압축 포맷을 알 수 없는 경우에는 다운로드한 후 수동으로 직접 설치하기 바랍니다.';
+$lang['error_badurl'] = '잘못된 URL 같습니다 - URL에서 파일 이름을 알 수 없습니다';
+$lang['error_dircreate'] = '다운로드를 받기 위한 임시 디렉토리를 만들 수 없습니다';
+$lang['error_decompress'] = '플러그인 관리자가 다운로드 받은 파일을 압축을 풀 수 없습니다. 잘못 다운로드 받았을 수도 있으니 다시 한번 시도하거나 압축 포맷을 알 수 없는 경우에는 다운로드한 후 수동으로 직접 설치하세요.';
$lang['error_copy'] = '플러그인을 설치하는 동안 파일 복사하는 데 오류가 발생했습니다. <em>%s</em>: 디스크가 꽉 찼거나 파일 접근 권한이 잘못된 경우입니다. 플러그인 설치가 부분적으로만 이루어졌을 것입니다. 설치가 불완전합니다.';
-$lang['error_delete'] = '<em>%s</em> 플러그인을 삭제하는 동안 오류가 발생했습니다. 대부분의 경우 불완전한 파일이거나 디렉토리 접근 권한이 잘못된 경우입니다.';
+$lang['error_delete'] = '<em>%s</em> 플러그인을 삭제하는 동안 오류가 발생했습니다. 대부분의 경우 불완전한 파일이거나 디렉토리 접근 권한이 잘못된 경우입니다';
$lang['enabled'] = '%s 플러그인을 활성화했습니다.';
-$lang['notenabled'] = '%s 플러그인을 활성화할 수 없습니다. 파일 권한을 확인하십시오.';
+$lang['notenabled'] = '%s 플러그인을 활성화할 수 없습니다. 파일 권한을 확인하세요.';
$lang['disabled'] = '%s 플러그인을 비활성화했습니다.';
-$lang['notdisabled'] = '%s 플러그인을 비활성화할 수 없습니다. 파일 권한을 확인하십시오.';
+$lang['notdisabled'] = '%s 플러그인을 비활성화할 수 없습니다. 파일 권한을 확인하하세요.';
$lang['packageinstalled'] = '플러그인 패키지(플러그인 %d개: %s)가 성공적으로 설치되었습니다.';
diff --git a/lib/plugins/plugin/lang/pl/lang.php b/lib/plugins/plugin/lang/pl/lang.php
index 1d3bbbc03..faaa69630 100644
--- a/lib/plugins/plugin/lang/pl/lang.php
+++ b/lib/plugins/plugin/lang/pl/lang.php
@@ -60,4 +60,4 @@ $lang['enabled'] = 'Wtyczka %s włączona.';
$lang['notenabled'] = 'Nie udało się uruchomić wtyczki %s, sprawdź uprawnienia dostępu do plików.';
$lang['disabled'] = 'Wtyczka %s wyłączona.';
$lang['notdisabled'] = 'Nie udało się wyłączyć wtyczki %s, sprawdź uprawnienia dostępu do plików.';
-$lang['packageinstalled'] = 'Pakiet wtyczek (%d wtyczki:% s) zainstalowany pomyślnie.';
+$lang['packageinstalled'] = 'Pakiet wtyczek (%d wtyczki: %s) zainstalowany pomyślnie.';
diff --git a/lib/plugins/plugin/lang/pt-br/lang.php b/lib/plugins/plugin/lang/pt-br/lang.php
index 26e73f4fc..437b6ca57 100644
--- a/lib/plugins/plugin/lang/pt-br/lang.php
+++ b/lib/plugins/plugin/lang/pt-br/lang.php
@@ -16,6 +16,7 @@
* @author Sergio Motta sergio@cisne.com.br
* @author Isaias Masiero Filho <masiero@masiero.org>
* @author Balaco Baco <balacobaco@imap.cc>
+ * @author Victor Westmann <victor.westmann@gmail.com>
*/
$lang['menu'] = 'Gerenciar Plug-ins';
$lang['download'] = 'Baixar e instalar um novo plug-in';
diff --git a/lib/plugins/plugin/lang/ru/lang.php b/lib/plugins/plugin/lang/ru/lang.php
index f011c9954..7b9579e96 100644
--- a/lib/plugins/plugin/lang/ru/lang.php
+++ b/lib/plugins/plugin/lang/ru/lang.php
@@ -17,6 +17,7 @@
* @author Ladyko Andrey <fylh@succexy.spb.ru>
* @author Eugene <windy.wanderer@gmail.com>
* @author Johnny Utah <pcpa@cyberpunk.su>
+ * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua)
*/
$lang['menu'] = 'Управление плагинами';
$lang['download'] = 'Скачать и установить новый плагин';
diff --git a/lib/plugins/plugin/lang/sv/lang.php b/lib/plugins/plugin/lang/sv/lang.php
index 5892e42b5..a8578c03c 100644
--- a/lib/plugins/plugin/lang/sv/lang.php
+++ b/lib/plugins/plugin/lang/sv/lang.php
@@ -16,6 +16,7 @@
* @author Peter Åström <eaustreum@gmail.com>
* @author Håkan Sandell <hakan.sandell@home.se>
* @author mikael@mallander.net
+ * @author Smorkster Andersson smorkster@gmail.com
*/
$lang['menu'] = 'Hantera insticksmoduler';
$lang['download'] = 'Ladda ned och installera en ny insticksmodul';
@@ -61,3 +62,4 @@ $lang['enabled'] = 'Tilläggsmodulen %s är aktiverad.';
$lang['notenabled'] = 'Tilläggsmodulen %s kunde inte aktiveras, kontrollera filrättigheterna.';
$lang['disabled'] = 'Tiläggsmodulen %s är avaktiverad.';
$lang['notdisabled'] = 'Tilläggsmodulen %s kunde inte avaktiveras, kontrollera filrättigheterna.';
+$lang['packageinstalled'] = 'Tilläggs paket (%d tillägg: %s) har installerats.';
diff --git a/lib/plugins/plugin/lang/zh-tw/lang.php b/lib/plugins/plugin/lang/zh-tw/lang.php
index 7b38a02c8..56149e79e 100644
--- a/lib/plugins/plugin/lang/zh-tw/lang.php
+++ b/lib/plugins/plugin/lang/zh-tw/lang.php
@@ -56,4 +56,4 @@ $lang['enabled'] = '附加元件 %s 已啟用。';
$lang['notenabled'] = '附加元件 %s 無法啟用,請檢查檔案權限。';
$lang['disabled'] = '附加元件 %s 已停用。';
$lang['notdisabled'] = '附加元件 %s 無法停用,請檢查檔案權限。';
-$lang['packageinstalled'] = '附加元件 (%d 附加元件%s: %s) 已安裝好。';
+$lang['packageinstalled'] = '附加元件 (%d 附加元件: %s) 已安裝好。';
diff --git a/lib/plugins/plugin/plugin.info.txt b/lib/plugins/plugin/plugin.info.txt
index c2f72d998..cdf866842 100644
--- a/lib/plugins/plugin/plugin.info.txt
+++ b/lib/plugins/plugin/plugin.info.txt
@@ -1,7 +1,7 @@
base plugin
author Christopher Smith
email chris@jalakai.co.uk
-date 2012-09-08
+date 2013-02-20
name Plugin Manager plugin
desc Manage and install plugins
url http://www.dokuwiki.org/plugin:plugin
diff --git a/lib/plugins/popularity/lang/cs/lang.php b/lib/plugins/popularity/lang/cs/lang.php
index 0b0dbae7f..ee090a131 100644
--- a/lib/plugins/popularity/lang/cs/lang.php
+++ b/lib/plugins/popularity/lang/cs/lang.php
@@ -10,6 +10,7 @@
* @author zbynek.krivka@seznam.cz
* @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com>
* @author Jakub A. Těšínský (j@kub.cz)
+ * @author mkucera66@seznam.cz
*/
$lang['name'] = 'Průzkum používání (může chviličku trvat, než se natáhne)';
$lang['submit'] = 'Odeslat data';
diff --git a/lib/plugins/popularity/lang/de-informal/lang.php b/lib/plugins/popularity/lang/de-informal/lang.php
index 40e6c4343..0abf90b0b 100644
--- a/lib/plugins/popularity/lang/de-informal/lang.php
+++ b/lib/plugins/popularity/lang/de-informal/lang.php
@@ -8,6 +8,8 @@
* @author Matthias Schulte <post@lupo49.de>
* @author Christian Wichmann <nospam@zone0.de>
* @author Pierre Corell <info@joomla-praxis.de>
+ * @author Frank Loizzi <contact@software.bacal.de>
+ * @author Volker Bödker <volker@boedker.de>
*/
$lang['name'] = 'Popularitätsrückmeldung (kann eine Weile dauern, bis es fertig geladen wurde)';
$lang['submit'] = 'Sende Daten';
diff --git a/lib/plugins/popularity/lang/el/lang.php b/lib/plugins/popularity/lang/el/lang.php
index 32558b060..10268a4c3 100644
--- a/lib/plugins/popularity/lang/el/lang.php
+++ b/lib/plugins/popularity/lang/el/lang.php
@@ -5,6 +5,7 @@
* @author Konstantinos Koryllos <koryllos@gmail.com>
* @author George Petsagourakis <petsagouris@gmail.com>
* @author Petros Vidalis <pvidalis@gmail.com>
+ * @author Vasileios Karavasilis vasileioskaravasilis@gmail.com
*/
$lang['name'] = 'Αναφορά Δημοτικότητας (ίσως αργήσει λίγο να εμφανιστεί)';
$lang['submit'] = 'Αποστολή Δεδομένων';
diff --git a/lib/plugins/popularity/lang/fr/lang.php b/lib/plugins/popularity/lang/fr/lang.php
index d5bc92081..b7e053197 100644
--- a/lib/plugins/popularity/lang/fr/lang.php
+++ b/lib/plugins/popularity/lang/fr/lang.php
@@ -17,6 +17,7 @@
* @author Yannick Aure <yannick.aure@gmail.com>
* @author Olivier DUVAL <zorky00@gmail.com>
* @author Anael Mobilia <contrib@anael.eu>
+ * @author Bruno Veilleux <bruno.vey@gmail.com>
*/
$lang['name'] = 'Enquête de popularité (peut nécessiter un certain temps pour être chargée)';
$lang['submit'] = 'Envoyer les données';
diff --git a/lib/plugins/popularity/lang/gl/lang.php b/lib/plugins/popularity/lang/gl/lang.php
index 8032fccb0..86cd34db6 100644
--- a/lib/plugins/popularity/lang/gl/lang.php
+++ b/lib/plugins/popularity/lang/gl/lang.php
@@ -4,7 +4,7 @@
*
* @author Medúlio <medulio@ciberirmandade.org>
* @author Oscar M. Lage <r0sk10@gmail.com>
- * @author Leandro Regueiro <leandro.regueiro@gmail.com>
+ * @author Rodrigo Rega <rodrigorega@gmail.com>
*/
$lang['name'] = 'Resposta de Popularidade (pode demorar un tempo a cargar)';
$lang['submit'] = 'Enviar Datos';
diff --git a/lib/plugins/popularity/lang/ja/lang.php b/lib/plugins/popularity/lang/ja/lang.php
index f5e280db5..774785511 100644
--- a/lib/plugins/popularity/lang/ja/lang.php
+++ b/lib/plugins/popularity/lang/ja/lang.php
@@ -7,6 +7,7 @@
* @author Kazutaka Miyasaka <kazmiya@gmail.com>
* @author Yuji Takenaka <webmaster@davilin.com>
* @author Taisuke Shimamoto <dentostar@gmail.com>
+ * @author Satoshi Sahara <sahara.satoshi@gmail.com>
*/
$lang['name'] = '利用状況調査(ロードに少し時間が掛かります)';
$lang['submit'] = 'データ送信';
diff --git a/lib/plugins/popularity/lang/ko/intro.txt b/lib/plugins/popularity/lang/ko/intro.txt
index b9e66094e..c75c57ba5 100644
--- a/lib/plugins/popularity/lang/ko/intro.txt
+++ b/lib/plugins/popularity/lang/ko/intro.txt
@@ -2,8 +2,8 @@
설치된 위키의 익명 정보를 DokuWiki 개발자에게 보냅니다. 이 [[doku>popularity|도구]]는 DokuWiki가 실제 사용자에게 어떻게 사용되는지 DokuWiki 개발자에게 알려줌으로써 이 후 개발 시 참고가 됩니다.
-설치된 위키가 커짐에 따라서 이 과정을 반복할 필요가 있습니다. 반복된 데이타는 익명 ID로 구별되어집니다.
+설치된 위키가 커짐에 따라서 이 과정을 반복할 필요가 있습니다. 반복된 데이터는 익명 ID로 구별되어집니다.
-전송 데이타는 설치 DokuWiki 버전, 문서와 파일 수, 크기, 설치 플러그인, 설치 PHP 정보등을 포함하고 있습니다.
+보내려는 데이터는 설치 DokuWiki 버전, 문서와 파일 수, 크기, 설치 플러그인, 설치 PHP 정보등을 포함하고 있습니다.
-실제 보내질 자료는 아래와 같습니다. 정보를 보내려면 "자료 보내기" 버튼을 클릭합니다. \ No newline at end of file
+실제 보내질 자료는 아래와 같습니다. 정보를 보내려면 "자료 보내기" 버튼을 클릭하세요. \ No newline at end of file
diff --git a/lib/plugins/popularity/lang/ko/lang.php b/lib/plugins/popularity/lang/ko/lang.php
index 5e6966402..3463f4f8e 100644
--- a/lib/plugins/popularity/lang/ko/lang.php
+++ b/lib/plugins/popularity/lang/ko/lang.php
@@ -2,18 +2,17 @@
/**
* Korean language file
*
- * @author jk lee
+ * @author jk Lee
* @author dongnak@gmail.com
* @author Song Younghwan <purluno@gmail.com>
- * @author SONG Younghwan <purluno@gmail.com>
- * @author Seung-Chul Yoo <dryoo@live.com>
+ * @author Seung-Chul Yoo <dryoo@live.com>
* @author erial2@gmail.com
* @author Myeongjin <aranet100@gmail.com>
*/
-$lang['name'] = '인기도 조사 (불러오는데 시간이 걸릴 수 있습니다.)';
+$lang['name'] = '인기도 조사 (불러오는 데 시간이 걸릴 수 있습니다)';
$lang['submit'] = '자료 보내기';
$lang['autosubmit'] = '자료를 자동으로 매달 한번씩 보내기';
-$lang['submissionFailed'] = '다음과 같은 이유로 자료 전송에 실패했습니다:';
-$lang['submitDirectly'] = '아래의 양식에 맞춰 수동으로 작성된 자료를 보낼 수 있습니다';
-$lang['autosubmitError'] = '다음과 같은 이유로 자동 자료 전송에 실패했습니다:';
-$lang['lastSent'] = '자료가 전송되었습니다';
+$lang['submissionFailed'] = '다음과 같은 이유로 자료 보내기에 실패했습니다:';
+$lang['submitDirectly'] = '아래의 양식에 맞춰 수동으로 작성된 자료를 보낼 수 있습니다.';
+$lang['autosubmitError'] = '다음과 같은 이유로 자동 자료 보내기에 실패했습니다:';
+$lang['lastSent'] = '자료를 보냈습니다';
diff --git a/lib/plugins/popularity/lang/ko/submitted.txt b/lib/plugins/popularity/lang/ko/submitted.txt
index 12f0efe45..37cfbd8f2 100644
--- a/lib/plugins/popularity/lang/ko/submitted.txt
+++ b/lib/plugins/popularity/lang/ko/submitted.txt
@@ -1,3 +1,3 @@
====== 인기도 조사 ======
-자료 전송이 성공적으로 완료되었습니다. \ No newline at end of file
+자료를 성공적으로 보냈습니다. \ No newline at end of file
diff --git a/lib/plugins/popularity/lang/pt-br/lang.php b/lib/plugins/popularity/lang/pt-br/lang.php
index 44d811d81..c2ec36145 100644
--- a/lib/plugins/popularity/lang/pt-br/lang.php
+++ b/lib/plugins/popularity/lang/pt-br/lang.php
@@ -15,6 +15,7 @@
* @author Sergio Motta sergio@cisne.com.br
* @author Isaias Masiero Filho <masiero@masiero.org>
* @author Balaco Baco <balacobaco@imap.cc>
+ * @author Victor Westmann <victor.westmann@gmail.com>
*/
$lang['name'] = 'Retorno de popularidade (pode demorar um pouco para carregar)';
$lang['submit'] = 'Enviar dados';
diff --git a/lib/plugins/popularity/lang/ru/lang.php b/lib/plugins/popularity/lang/ru/lang.php
index 0e29c795d..a7f33156f 100644
--- a/lib/plugins/popularity/lang/ru/lang.php
+++ b/lib/plugins/popularity/lang/ru/lang.php
@@ -14,6 +14,7 @@
* @author Ladyko Andrey <fylh@succexy.spb.ru>
* @author Eugene <windy.wanderer@gmail.com>
* @author Johnny Utah <pcpa@cyberpunk.su>
+ * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua)
*/
$lang['name'] = 'Сбор информации о популярности (для загрузки может потребоваться некоторое время)';
$lang['submit'] = 'Отправить данные';
diff --git a/lib/plugins/popularity/lang/sv/lang.php b/lib/plugins/popularity/lang/sv/lang.php
index 8be542e7f..90d820ba0 100644
--- a/lib/plugins/popularity/lang/sv/lang.php
+++ b/lib/plugins/popularity/lang/sv/lang.php
@@ -13,6 +13,7 @@
* @author Peter Åström <eaustreum@gmail.com>
* @author Håkan Sandell <hakan.sandell@home.se>
* @author mikael@mallander.net
+ * @author Smorkster Andersson smorkster@gmail.com
*/
$lang['name'] = 'Popularitets-feedback (det kan ta en stund att ladda sidan)';
$lang['submit'] = 'Sänd data';
diff --git a/lib/plugins/popularity/lang/zh-tw/intro.txt b/lib/plugins/popularity/lang/zh-tw/intro.txt
index 2a6337237..5ba42c5b9 100644
--- a/lib/plugins/popularity/lang/zh-tw/intro.txt
+++ b/lib/plugins/popularity/lang/zh-tw/intro.txt
@@ -1,8 +1,8 @@
====== 人氣回饋 ======
-本工具會從您的 wiki 站台收集訊息,並以匿名的方式發送給 DokuWiki 的開發者。這有助於他們了解使用者們如何使用 DokuWiki ,並能基於實際統計資料對未來開發做出更準確的決策。
+本工具會從您的 wiki 網站收集訊息,並以匿名的方式發送給 DokuWiki 的開發者。這有助於他們了解使用者們如何使用 DokuWiki ,並能基於實際統計資料對未來開發做出更準確的決策。
-我們鼓勵您經常重複這個步驟,讓開發者了解您的 wiki 站台的成長情形。您的資料集將會被標識為一個匿名的識別碼 (ID) 。
+我們鼓勵您經常重複這個步驟,讓開發者了解您的 wiki 網站的成長情形。您的資料集將會被標識為一個匿名的識別碼 (ID) 。
收集的資料包括 DokuWiki 版本、頁面數量、檔案大小、安裝的附加元件,以及伺服器的 PHP 資訊。
diff --git a/lib/plugins/popularity/lang/zh-tw/lang.php b/lib/plugins/popularity/lang/zh-tw/lang.php
index 890c23bfa..b34efe995 100644
--- a/lib/plugins/popularity/lang/zh-tw/lang.php
+++ b/lib/plugins/popularity/lang/zh-tw/lang.php
@@ -12,7 +12,7 @@
* @author syaoranhinata@gmail.com
* @author Ichirou Uchiki <syaoranhinata@gmail.com>
*/
-$lang['name'] = '人氣回饋(可能需要一些時間載入)';
+$lang['name'] = '人氣回饋 (可能需要一些時間載入) ';
$lang['submit'] = '發送資料';
$lang['autosubmit'] = '每月自動發送';
$lang['submissionFailed'] = '由於以下原因,資料無法發送:';
diff --git a/lib/plugins/popularity/plugin.info.txt b/lib/plugins/popularity/plugin.info.txt
index 2f1451c4a..17f3110c4 100644
--- a/lib/plugins/popularity/plugin.info.txt
+++ b/lib/plugins/popularity/plugin.info.txt
@@ -1,7 +1,7 @@
base popularity
author Andreas Gohr
email andi@splitbrain.org
-date 2012-10-07
+date 2012-11-29
name Popularity Feedback Plugin
desc Send anonymous data about your wiki to the developers.
url http://www.dokuwiki.org/plugin:popularity
diff --git a/lib/plugins/revert/admin.php b/lib/plugins/revert/admin.php
index fcdaa230d..ccad6e9de 100644
--- a/lib/plugins/revert/admin.php
+++ b/lib/plugins/revert/admin.php
@@ -44,15 +44,16 @@ class admin_plugin_revert extends DokuWiki_Admin_Plugin {
* output appropriate html
*/
function html() {
+ global $INPUT;
- echo $this->plugin_locale_xhtml('intro');
+ echo $this->locale_xhtml('intro');
$this->_searchform();
- if(is_array($_REQUEST['revert']) && checkSecurityToken()){
- $this->_revert($_REQUEST['revert'],$_REQUEST['filter']);
- }elseif(isset($_REQUEST['filter'])){
- $this->_list($_REQUEST['filter']);
+ if(is_array($INPUT->param('revert')) && checkSecurityToken()){
+ $this->_revert($INPUT->arr('revert'),$INPUT->str('filter'));
+ }elseif($INPUT->has('filter')){
+ $this->_list($INPUT->str('filter'));
}
}
@@ -60,10 +61,10 @@ class admin_plugin_revert extends DokuWiki_Admin_Plugin {
* Display the form for searching spam pages
*/
function _searchform(){
- global $lang;
+ global $lang, $INPUT;
echo '<form action="" method="post"><div class="no">';
echo '<label>'.$this->getLang('filter').': </label>';
- echo '<input type="text" name="filter" class="edit" value="'.hsc($_REQUEST['filter']).'" />';
+ echo '<input type="text" name="filter" class="edit" value="'.hsc($INPUT->str('filter')).'" />';
echo ' <input type="submit" class="button" value="'.$lang['btn_search'].'" />';
echo ' <span>'.$this->getLang('note1').'</span>';
echo '</div></form><br /><br />';
diff --git a/lib/plugins/revert/lang/cs/lang.php b/lib/plugins/revert/lang/cs/lang.php
index dd8d7845c..eef3295ba 100644
--- a/lib/plugins/revert/lang/cs/lang.php
+++ b/lib/plugins/revert/lang/cs/lang.php
@@ -13,6 +13,7 @@
* @author zbynek.krivka@seznam.cz
* @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com>
* @author Jakub A. Těšínský (j@kub.cz)
+ * @author mkucera66@seznam.cz
*/
$lang['menu'] = 'Obnova zaspamovaných stránek';
$lang['filter'] = 'Hledat zaspamované stránky';
diff --git a/lib/plugins/revert/lang/de-informal/lang.php b/lib/plugins/revert/lang/de-informal/lang.php
index c199bb55b..b702e7727 100644
--- a/lib/plugins/revert/lang/de-informal/lang.php
+++ b/lib/plugins/revert/lang/de-informal/lang.php
@@ -8,6 +8,8 @@
* @author Matthias Schulte <post@lupo49.de>
* @author Christian Wichmann <nospam@zone0.de>
* @author Pierre Corell <info@joomla-praxis.de>
+ * @author Frank Loizzi <contact@software.bacal.de>
+ * @author Volker Bödker <volker@boedker.de>
*/
$lang['menu'] = 'Zurückstellungsmanager';
$lang['filter'] = 'Durchsuche als Spam markierte Seiten';
diff --git a/lib/plugins/revert/lang/el/lang.php b/lib/plugins/revert/lang/el/lang.php
index 63454e4e9..c6e8bd56c 100644
--- a/lib/plugins/revert/lang/el/lang.php
+++ b/lib/plugins/revert/lang/el/lang.php
@@ -10,6 +10,7 @@
* @author Konstantinos Koryllos <koryllos@gmail.com>
* @author George Petsagourakis <petsagouris@gmail.com>
* @author Petros Vidalis <pvidalis@gmail.com>
+ * @author Vasileios Karavasilis vasileioskaravasilis@gmail.com
*/
$lang['menu'] = 'Αποκατάσταση κακόβουλων αλλαγών σελίδων';
$lang['filter'] = 'Αναζήτηση σελίδων που περιέχουν spam';
diff --git a/lib/plugins/revert/lang/fr/lang.php b/lib/plugins/revert/lang/fr/lang.php
index 07b012e38..a063c8996 100644
--- a/lib/plugins/revert/lang/fr/lang.php
+++ b/lib/plugins/revert/lang/fr/lang.php
@@ -18,6 +18,7 @@
* @author Yannick Aure <yannick.aure@gmail.com>
* @author Olivier DUVAL <zorky00@gmail.com>
* @author Anael Mobilia <contrib@anael.eu>
+ * @author Bruno Veilleux <bruno.vey@gmail.com>
*/
$lang['menu'] = 'Gestionnaire des réversions';
$lang['filter'] = 'Trouver les pages spammées ';
diff --git a/lib/plugins/revert/lang/gl/lang.php b/lib/plugins/revert/lang/gl/lang.php
index ad4fe4045..0e376d9a7 100644
--- a/lib/plugins/revert/lang/gl/lang.php
+++ b/lib/plugins/revert/lang/gl/lang.php
@@ -4,7 +4,7 @@
*
* @author Medúlio <medulio@ciberirmandade.org>
* @author Oscar M. Lage <r0sk10@gmail.com>
- * @author Leandro Regueiro <leandro.regueiro@gmail.com>
+ * @author Rodrigo Rega <rodrigorega@gmail.com>
*/
$lang['menu'] = 'Xestor de Reversión';
$lang['filter'] = 'Procurar páxinas con correo-lixo';
diff --git a/lib/plugins/revert/lang/ja/lang.php b/lib/plugins/revert/lang/ja/lang.php
index bb5a9c150..7ef850ea7 100644
--- a/lib/plugins/revert/lang/ja/lang.php
+++ b/lib/plugins/revert/lang/ja/lang.php
@@ -6,6 +6,7 @@
* @author Daniel Dupriest <kououken@gmail.com>
* @author Kazutaka Miyasaka <kazmiya@gmail.com>
* @author Taisuke Shimamoto <dentostar@gmail.com>
+ * @author Satoshi Sahara <sahara.satoshi@gmail.com>
*/
$lang['menu'] = '復元管理';
$lang['filter'] = 'スパムを受けたページを検索';
diff --git a/lib/plugins/revert/lang/ko/intro.txt b/lib/plugins/revert/lang/ko/intro.txt
index 30813fe49..7aa618ba6 100644
--- a/lib/plugins/revert/lang/ko/intro.txt
+++ b/lib/plugins/revert/lang/ko/intro.txt
@@ -1,3 +1,3 @@
-====== 복구 관리자 ======
+====== 되돌리기 관리자 ======
-스팸 공격으로 부터 자동으로 복구하는데 이 페이지가 도움이 될 수 있습니다. 스팸 공격받은 문서 목록을 찾으려면 문자열을 입력하기 바랍니다 (예를 들어 스팸 URL), 그 후 찾은 문서가 스팸 공격을 받았는지 확인하고 복구합니다.
+스팸 공격으로부터 자동으로 되돌리는데 이 페이지가 도움이 될 수 있습니다. 스팸 공격받은 문서 목록을 찾으려면 문자열을 입력하고(예를 들어 스팸 URL) 나서 찾은 문서가 스팸 공격을 받았는지 확인하고 되돌리세요. \ No newline at end of file
diff --git a/lib/plugins/revert/lang/ko/lang.php b/lib/plugins/revert/lang/ko/lang.php
index 90cba9bce..f944361b8 100644
--- a/lib/plugins/revert/lang/ko/lang.php
+++ b/lib/plugins/revert/lang/ko/lang.php
@@ -2,20 +2,19 @@
/**
* Korean language file
*
- * @author jk lee
+ * @author jk Lee
* @author dongnak@gmail.com
* @author Song Younghwan <purluno@gmail.com>
- * @author SONG Younghwan <purluno@gmail.com>
- * @author Seung-Chul Yoo <dryoo@live.com>
+ * @author Seung-Chul Yoo <dryoo@live.com>
* @author erial2@gmail.com
* @author Myeongjin <aranet100@gmail.com>
*/
-$lang['menu'] = '복구 관리자';
+$lang['menu'] = '되돌리기 관리자';
$lang['filter'] = '스팸 문서 찾기';
-$lang['revert'] = '선택한 문서 복구';
-$lang['reverted'] = '%s 버전을 %s 버전으로 복구';
-$lang['removed'] = '%s 삭제';
-$lang['revstart'] = '복구 작업을 시작합니다. 오랜 시간이 걸릴 수 있습니다. 완료되기 전에 스크립트 시간 초과가 발생한다면 더 작은 작업으로 나누어서 복구하기 바랍니다.';
-$lang['revstop'] = '복구 작업이 성공적으로 끝났습니다.';
-$lang['note1'] = '참고: 대소문자 구별하여 찾습니다.';
-$lang['note2'] = '참고: 이 문서는 <i>%s</i> 스팸 단어를 포함하지 않은 최근 이전 버전으로 복구됩니다. ';
+$lang['revert'] = '선택한 문서 되돌리기';
+$lang['reverted'] = '%s 판을 %s 판으로 되돌림';
+$lang['removed'] = '%s 삭제함';
+$lang['revstart'] = '되돌리기 작업을 시작합니다. 오랜 시간이 걸릴 수 있습니다. 완료되기 전에 스크립트 시간 초과가 발생한다면 더 작은 작업으로 나누어서 되돌리시기 바랍니다.';
+$lang['revstop'] = '되돌리기 작업이 성공적으로 끝났습니다.';
+$lang['note1'] = '참고: 대소문자를 구별해 찾습니다';
+$lang['note2'] = '참고: 이 문서는 <i>%s</i> 스팸 단어를 포함하지 않은 최근 이전 판으로 되돌립니다. ';
diff --git a/lib/plugins/revert/lang/pt-br/lang.php b/lib/plugins/revert/lang/pt-br/lang.php
index c4a2f742b..b74e0408f 100644
--- a/lib/plugins/revert/lang/pt-br/lang.php
+++ b/lib/plugins/revert/lang/pt-br/lang.php
@@ -16,6 +16,7 @@
* @author Sergio Motta sergio@cisne.com.br
* @author Isaias Masiero Filho <masiero@masiero.org>
* @author Balaco Baco <balacobaco@imap.cc>
+ * @author Victor Westmann <victor.westmann@gmail.com>
*/
$lang['menu'] = 'Gerenciador de reversões';
$lang['filter'] = 'Procura por páginas com spam';
diff --git a/lib/plugins/revert/lang/ru/lang.php b/lib/plugins/revert/lang/ru/lang.php
index 4abe37e6a..817bd1064 100644
--- a/lib/plugins/revert/lang/ru/lang.php
+++ b/lib/plugins/revert/lang/ru/lang.php
@@ -15,6 +15,7 @@
* @author Ladyko Andrey <fylh@succexy.spb.ru>
* @author Eugene <windy.wanderer@gmail.com>
* @author Johnny Utah <pcpa@cyberpunk.su>
+ * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua)
*/
$lang['menu'] = 'Менеджер откаток';
$lang['filter'] = 'Поиск спам-страниц';
diff --git a/lib/plugins/revert/lang/sv/lang.php b/lib/plugins/revert/lang/sv/lang.php
index 29c6702eb..4a727b339 100644
--- a/lib/plugins/revert/lang/sv/lang.php
+++ b/lib/plugins/revert/lang/sv/lang.php
@@ -15,6 +15,7 @@
* @author Peter Åström <eaustreum@gmail.com>
* @author Håkan Sandell <hakan.sandell@home.se>
* @author mikael@mallander.net
+ * @author Smorkster Andersson smorkster@gmail.com
*/
$lang['menu'] = 'Hantera återställningar';
$lang['filter'] = 'Sök efter spamsidor';
diff --git a/lib/plugins/revert/lang/zh-tw/lang.php b/lib/plugins/revert/lang/zh-tw/lang.php
index afd858455..88a77f7a1 100644
--- a/lib/plugins/revert/lang/zh-tw/lang.php
+++ b/lib/plugins/revert/lang/zh-tw/lang.php
@@ -15,7 +15,7 @@
$lang['menu'] = '還原管理';
$lang['filter'] = '搜索包含垃圾訊息的頁面';
$lang['revert'] = '還原選取的頁面';
-$lang['reverted'] = '%s 已還原為版本 %s';
+$lang['reverted'] = '%s 已還原成版本 %s';
$lang['removed'] = '%s 已移除';
$lang['revstart'] = '已開始還原操作。有可能需要很長時間。如果程式執行逾時,請嘗試分次還原少量內容。';
$lang['revstop'] = '還原程序已完成。';
diff --git a/lib/plugins/revert/plugin.info.txt b/lib/plugins/revert/plugin.info.txt
index 205fe9177..984a531b3 100644
--- a/lib/plugins/revert/plugin.info.txt
+++ b/lib/plugins/revert/plugin.info.txt
@@ -1,7 +1,7 @@
base revert
author Andreas Gohr
email andi@splitbrain.org
-date 2012-08-05
+date 2013-03-09
name Revert Manager
desc Allows you to mass revert recent edits
url http://dokuwiki.org/plugin:revert
diff --git a/lib/plugins/safefnrecode/plugin.info.txt b/lib/plugins/safefnrecode/plugin.info.txt
index 2b42399b0..3c6249d73 100644
--- a/lib/plugins/safefnrecode/plugin.info.txt
+++ b/lib/plugins/safefnrecode/plugin.info.txt
@@ -1,7 +1,7 @@
base safefnrecode
author Andreas Gohr
email andi@splitbrain.org
-date 2011-04-06
+date 2012-07-28
name safefnrecode plugin
desc Changes existing page and foldernames for the change in the safe filename encoding
url http://www.dokuwiki.org/plugin:safefnrecode
diff --git a/lib/plugins/syntax.php b/lib/plugins/syntax.php
index 552cc747a..b7839b2b2 100644
--- a/lib/plugins/syntax.php
+++ b/lib/plugins/syntax.php
@@ -226,56 +226,76 @@ class DokuWiki_Syntax_Plugin extends Doku_Parser_Mode {
$this->localised = true;
}
- // configuration methods
- /**
- * getConf($setting)
- *
- * use this function to access plugin configuration variables
- */
- function getConf($setting){
-
- if (!$this->configloaded){ $this->loadConfig(); }
-
- return $this->conf[$setting];
- }
-
- /**
- * loadConfig()
- * merges the plugin's default settings with any local settings
- * this function is automatically called through getConf()
- */
- function loadConfig(){
- global $conf;
-
- $defaults = $this->readDefaultSettings();
- $plugin = $this->getPluginName();
-
- foreach ($defaults as $key => $value) {
- if (isset($conf['plugin'][$plugin][$key])) continue;
- $conf['plugin'][$plugin][$key] = $value;
+ // configuration methods
+ /**
+ * getConf($setting)
+ *
+ * use this function to access plugin configuration variables
+ */
+ function getConf($setting) {
+
+ if(!$this->configloaded) { $this->loadConfig(); }
+
+ return $this->conf[$setting];
+ }
+
+ /**
+ * loadConfig()
+ * merges the plugin's default settings with any local settings
+ * this function is automatically called through getConf()
+ */
+ function loadConfig() {
+ global $conf;
+
+ $defaults = $this->readDefaultSettings();
+ $plugin = $this->getPluginName();
+
+ foreach($defaults as $key => $value) {
+ if(isset($conf['plugin'][$plugin][$key])) continue;
+ $conf['plugin'][$plugin][$key] = $value;
+ }
+
+ $this->configloaded = true;
+ $this->conf =& $conf['plugin'][$plugin];
}
- $this->configloaded = true;
- $this->conf =& $conf['plugin'][$plugin];
- }
+ /**
+ * read the plugin's default configuration settings from conf/default.php
+ * this function is automatically called through getConf()
+ *
+ * @return array setting => value
+ */
+ function readDefaultSettings() {
- /**
- * read the plugin's default configuration settings from conf/default.php
- * this function is automatically called through getConf()
- *
- * @return array setting => value
- */
- function readDefaultSettings() {
+ $path = DOKU_PLUGIN.$this->getPluginName().'/conf/';
+ $conf = array();
- $path = DOKU_PLUGIN.$this->getPluginName().'/conf/';
- $conf = array();
+ if(@file_exists($path.'default.php')) {
+ include($path.'default.php');
+ }
- if (@file_exists($path.'default.php')) {
- include($path.'default.php');
+ return $conf;
}
- return $conf;
- }
+ /**
+ * Loads a given helper plugin (if enabled)
+ *
+ * @author Esther Brunner <wikidesign@gmail.com>
+ *
+ * @param string $name name of plugin to load
+ * @param bool $msg if a message should be displayed in case the plugin is not available
+ *
+ * @return object helper plugin object
+ */
+ function loadHelper($name, $msg = true) {
+ if(!plugin_isdisabled($name)) {
+ $obj = plugin_load('helper', $name);
+ } else {
+ $obj = null;
+ }
+ if(is_null($obj) && $msg) msg("Helper plugin $name is not available or invalid.", -1);
+ return $obj;
+ }
/**
* Allow the plugin to prevent DokuWiki from reusing an instance
diff --git a/lib/plugins/testing/plugin.info.txt b/lib/plugins/testing/plugin.info.txt
index c78c07739..64ab0b62e 100644
--- a/lib/plugins/testing/plugin.info.txt
+++ b/lib/plugins/testing/plugin.info.txt
@@ -1,7 +1,7 @@
base testing
author Tobias Sarnowski
email tobias@trustedco.de
-date 2012-04-26
+date 2012-07-28
name Testing Plugin
desc Used to test the test framework. Should always be disabled.
url http://www.dokuwiki.org/plugin:testing
diff --git a/lib/plugins/usermanager/admin.php b/lib/plugins/usermanager/admin.php
index cf8963e64..445836a50 100644
--- a/lib/plugins/usermanager/admin.php
+++ b/lib/plugins/usermanager/admin.php
@@ -73,11 +73,12 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
* handle user request
*/
function handle() {
+ global $INPUT;
if (is_null($this->_auth)) return false;
// extract the command and any specific parameters
// submit button name is of the form - fn[cmd][param(s)]
- $fn = $_REQUEST['fn'];
+ $fn = $INPUT->param('fn');
if (is_array($fn)) {
$cmd = key($fn);
@@ -88,8 +89,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
}
if ($cmd != "search") {
- if (!empty($_REQUEST['start']))
- $this->_start = $_REQUEST['start'];
+ $this->_start = $INPUT->int('start', 0);
$this->_filter = $this->_retrieveFilter();
}
@@ -345,6 +345,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
}
function _addUser(){
+ global $INPUT;
if (!checkSecurityToken()) return false;
if (!$this->_auth->canDo('addUser')) return false;
@@ -353,8 +354,8 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
if ($this->_auth->canDo('modPass')){
if (empty($pass)){
- if(!empty($_REQUEST['usernotify'])){
- $pass = auth_pwgen();
+ if($INPUT->has('usernotify')){
+ $pass = auth_pwgen($user);
} else {
msg($this->lang['add_fail'], -1);
return false;
@@ -393,7 +394,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
msg($this->lang['add_ok'], 1);
- if (!empty($_REQUEST['usernotify']) && $pass) {
+ if ($INPUT->has('usernotify') && $pass) {
$this->_notifyUser($user,$pass);
}
} else {
@@ -407,13 +408,13 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
* Delete user
*/
function _deleteUser(){
- global $conf;
+ global $conf, $INPUT;
if (!checkSecurityToken()) return false;
if (!$this->_auth->canDo('delUser')) return false;
- $selected = $_REQUEST['delete'];
- if (!is_array($selected) || empty($selected)) return false;
+ $selected = $INPUT->arr('delete');
+ if (empty($selected)) return false;
$selected = array_keys($selected);
if(in_array($_SERVER['REMOTE_USER'], $selected)) {
@@ -463,13 +464,13 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
* Modify user (modified user data has been recieved)
*/
function _modifyUser(){
- global $conf;
+ global $conf, $INPUT;
if (!checkSecurityToken()) return false;
if (!$this->_auth->canDo('UserMod')) return false;
// get currently valid user data
- $olduser = cleanID(preg_replace('/.*:/','',$_REQUEST['userid_old']));
+ $olduser = cleanID(preg_replace('/.*:/','',$INPUT->str('userid_old')));
$oldinfo = $this->_auth->getUserData($olduser);
// get new user data subject to change
@@ -494,8 +495,8 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
}
// generate password if left empty and notification is on
- if(!empty($_REQUEST['usernotify']) && empty($newpass)){
- $newpass = auth_pwgen();
+ if($INPUT->has('usernotify') && empty($newpass)){
+ $newpass = auth_pwgen($olduser);
}
if (!empty($newpass) && $this->_auth->canDo('modPass'))
@@ -510,7 +511,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
if ($ok = $this->_auth->triggerUserMod('modify', array($olduser, $changes))) {
msg($this->lang['update_ok'],1);
- if (!empty($_REQUEST['usernotify']) && $newpass) {
+ if ($INPUT->has('usernotify') && $newpass) {
$notify = empty($changes['user']) ? $olduser : $newuser;
$this->_notifyUser($notify,$newpass);
}
diff --git a/lib/plugins/usermanager/lang/ca-valencia/lang.php b/lib/plugins/usermanager/lang/ca-valencia/lang.php
index 5b0c628ed..c39c2f9b3 100644
--- a/lib/plugins/usermanager/lang/ca-valencia/lang.php
+++ b/lib/plugins/usermanager/lang/ca-valencia/lang.php
@@ -33,7 +33,7 @@ $lang['delete_ok'] = '%d usuaris borrats';
$lang['delete_fail'] = 'Erro borrant %d.';
$lang['update_ok'] = 'Usuari actualisat correctament';
$lang['update_fail'] = 'Erro actualisant usuari';
-$lang['update_exists'] = 'Erro canviant el nom de l\'usuari, el nom d\'usuari que ha donat ya existix (els demés canvis s\'aplicaran).';
+$lang['update_exists'] = 'Erro canviant el nom de l\'usuari (%s), el nom d\'usuari que ha donat ya existix (els demés canvis s\'aplicaran).';
$lang['start'] = 'primera';
$lang['prev'] = 'anterior';
$lang['next'] = 'següent';
diff --git a/lib/plugins/usermanager/lang/cs/lang.php b/lib/plugins/usermanager/lang/cs/lang.php
index 6de408e14..9fc3a5e75 100644
--- a/lib/plugins/usermanager/lang/cs/lang.php
+++ b/lib/plugins/usermanager/lang/cs/lang.php
@@ -12,6 +12,7 @@
* @author zbynek.krivka@seznam.cz
* @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com>
* @author Jakub A. Těšínský (j@kub.cz)
+ * @author mkucera66@seznam.cz
*/
$lang['menu'] = 'Správa uživatelů';
$lang['noauth'] = '(autentizace uživatelů není k dispozici)';
diff --git a/lib/plugins/usermanager/lang/de-informal/lang.php b/lib/plugins/usermanager/lang/de-informal/lang.php
index e53781c77..791cfa74f 100644
--- a/lib/plugins/usermanager/lang/de-informal/lang.php
+++ b/lib/plugins/usermanager/lang/de-informal/lang.php
@@ -8,6 +8,8 @@
* @author Matthias Schulte <dokuwiki@lupo49.de>
* @author Christian Wichmann <nospam@zone0.de>
* @author Pierre Corell <info@joomla-praxis.de>
+ * @author Frank Loizzi <contact@software.bacal.de>
+ * @author Volker Bödker <volker@boedker.de>
*/
$lang['menu'] = 'Benutzerverwaltung';
$lang['noauth'] = '(Benutzeranmeldung ist nicht verfügbar)';
diff --git a/lib/plugins/usermanager/lang/el/lang.php b/lib/plugins/usermanager/lang/el/lang.php
index 4b4d95379..da7c8fb0f 100644
--- a/lib/plugins/usermanager/lang/el/lang.php
+++ b/lib/plugins/usermanager/lang/el/lang.php
@@ -11,6 +11,7 @@
* @author Konstantinos Koryllos <koryllos@gmail.com>
* @author George Petsagourakis <petsagouris@gmail.com>
* @author Petros Vidalis <pvidalis@gmail.com>
+ * @author Vasileios Karavasilis vasileioskaravasilis@gmail.com
*/
$lang['menu'] = 'Διαχείριση Χρηστών';
$lang['noauth'] = '(η είσοδος χρηστών δεν είναι δυνατή)';
diff --git a/lib/plugins/usermanager/lang/fr/lang.php b/lib/plugins/usermanager/lang/fr/lang.php
index 7e602d0ce..40e878bbb 100644
--- a/lib/plugins/usermanager/lang/fr/lang.php
+++ b/lib/plugins/usermanager/lang/fr/lang.php
@@ -19,6 +19,7 @@
* @author Yannick Aure <yannick.aure@gmail.com>
* @author Olivier DUVAL <zorky00@gmail.com>
* @author Anael Mobilia <contrib@anael.eu>
+ * @author Bruno Veilleux <bruno.vey@gmail.com>
*/
$lang['menu'] = 'Gestion des utilisateurs';
$lang['noauth'] = '(authentification de l\'utilisateur non disponible)';
diff --git a/lib/plugins/usermanager/lang/gl/lang.php b/lib/plugins/usermanager/lang/gl/lang.php
index fb965985f..f3a7ef281 100644
--- a/lib/plugins/usermanager/lang/gl/lang.php
+++ b/lib/plugins/usermanager/lang/gl/lang.php
@@ -4,7 +4,7 @@
*
* @author Medúlio <medulio@ciberirmandade.org>
* @author Oscar M. Lage <r0sk10@gmail.com>
- * @author Leandro Regueiro <leandro.regueiro@gmail.com>
+ * @author Rodrigo Rega <rodrigorega@gmail.com>
*/
$lang['menu'] = 'Xestor de Usuarios';
$lang['noauth'] = '(autenticación de usuarios non dispoñible)';
diff --git a/lib/plugins/usermanager/lang/ja/lang.php b/lib/plugins/usermanager/lang/ja/lang.php
index b5fd556dc..1510d1eb0 100644
--- a/lib/plugins/usermanager/lang/ja/lang.php
+++ b/lib/plugins/usermanager/lang/ja/lang.php
@@ -7,6 +7,7 @@
* @author Daniel Dupriest <kououken@gmail.com>
* @author Kazutaka Miyasaka <kazmiya@gmail.com>
* @author Taisuke Shimamoto <dentostar@gmail.com>
+ * @author Satoshi Sahara <sahara.satoshi@gmail.com>
*/
$lang['menu'] = 'ユーザー管理';
$lang['noauth'] = '(ユーザー認証が無効です)';
@@ -41,10 +42,10 @@ $lang['prev'] = '前へ';
$lang['next'] = '次へ';
$lang['last'] = '最後';
$lang['edit_usermissing'] = '選択したユーザーは見つかりません。削除もしくは変更された可能性があります。';
-$lang['user_notify'] = '通知するユーザー';
-$lang['note_notify'] = 'ユーザーが新しいパスワードを設定した場合のみ、通知メールが送信されます。';
-$lang['note_group'] = 'グループを指定しない場合は、既定のグループ(%s)に登録されいます。';
-$lang['note_pass'] = 'パスワードを空欄とした場合は、パスワードを自動的に生成します。この場合、ユーザーへの通知が有効となります。';
+$lang['user_notify'] = 'ユーザーに通知する';
+$lang['note_notify'] = '通知メールは、ユーザーに新たなパスワードが設定された場合のみ送信されます。';
+$lang['note_group'] = 'グループを指定しない場合は、既定のグループ(%s)に配属されます。';
+$lang['note_pass'] = 'パスワードを空欄とした場合は、(”ユーザーに通知する”がチェックされていなくとも)自動生成したパスワードの通知がユーザー宛てに送信されます。';
$lang['add_ok'] = 'ユーザーを登録しました';
$lang['add_fail'] = 'ユーザーの登録に失敗しました';
$lang['notify_ok'] = '通知メールを送信しました';
diff --git a/lib/plugins/usermanager/lang/ko/add.txt b/lib/plugins/usermanager/lang/ko/add.txt
index 578ba5636..845d8090a 100644
--- a/lib/plugins/usermanager/lang/ko/add.txt
+++ b/lib/plugins/usermanager/lang/ko/add.txt
@@ -1 +1 @@
-===== 사용자 추가 =====
+===== 사용자 추가 ===== \ No newline at end of file
diff --git a/lib/plugins/usermanager/lang/ko/delete.txt b/lib/plugins/usermanager/lang/ko/delete.txt
index 1e9c0ba73..52b8209a1 100644
--- a/lib/plugins/usermanager/lang/ko/delete.txt
+++ b/lib/plugins/usermanager/lang/ko/delete.txt
@@ -1 +1 @@
-===== 사용자 삭제 =====
+===== 사용자 삭제 ===== \ No newline at end of file
diff --git a/lib/plugins/usermanager/lang/ko/edit.txt b/lib/plugins/usermanager/lang/ko/edit.txt
index ebb5bb002..a938c5b2e 100644
--- a/lib/plugins/usermanager/lang/ko/edit.txt
+++ b/lib/plugins/usermanager/lang/ko/edit.txt
@@ -1 +1 @@
-===== 사용자 정보 편집 =====
+===== 사용자 정보 편집 ===== \ No newline at end of file
diff --git a/lib/plugins/usermanager/lang/ko/intro.txt b/lib/plugins/usermanager/lang/ko/intro.txt
index 8c8bfa5b9..d75680c71 100644
--- a/lib/plugins/usermanager/lang/ko/intro.txt
+++ b/lib/plugins/usermanager/lang/ko/intro.txt
@@ -1 +1 @@
-====== 사용자 관리 ======
+====== 사용자 관리 ====== \ No newline at end of file
diff --git a/lib/plugins/usermanager/lang/ko/lang.php b/lib/plugins/usermanager/lang/ko/lang.php
index 58f9bf14a..57bfbc4a2 100644
--- a/lib/plugins/usermanager/lang/ko/lang.php
+++ b/lib/plugins/usermanager/lang/ko/lang.php
@@ -1,19 +1,18 @@
<?php
/**
- * korean language file
+ * Korean language file
*
* @author jk Lee
* @author dongnak@gmail.com
* @author Song Younghwan <purluno@gmail.com>
- * @author SONG Younghwan <purluno@gmail.com>
- * @author Seung-Chul Yoo <dryoo@live.com>
+ * @author Seung-Chul Yoo <dryoo@live.com>
* @author erial2@gmail.com
* @author Myeongjin <aranet100@gmail.com>
*/
$lang['menu'] = '사용자 관리자';
-$lang['noauth'] = '(사용자 인증이 불가능합니다.)';
-$lang['nosupport'] = '(사용자 관리가 지원되지 않습니다.)';
-$lang['badauth'] = '잘못된 인증 메카니즘';
+$lang['noauth'] = '(사용자 인증이 불가능합니다)';
+$lang['nosupport'] = '(사용자 관리가 지원되지 않습니다)';
+$lang['badauth'] = '인증 메카니즘이 잘못되었습니다';
$lang['user_id'] = '사용자';
$lang['user_pass'] = '비밀번호';
$lang['user_name'] = '실제 이름';
@@ -24,20 +23,20 @@ $lang['value'] = '값';
$lang['add'] = '추가';
$lang['delete'] = '삭제';
$lang['delete_selected'] = '선택 삭제';
-$lang['edit'] = '수정';
-$lang['edit_prompt'] = '이 사용자 수정';
+$lang['edit'] = '편집';
+$lang['edit_prompt'] = '이 사용자 편집';
$lang['modify'] = '바뀜 저장';
$lang['search'] = '찾기';
$lang['search_prompt'] = '찾기 실행';
$lang['clear'] = '찾기 필터 초기화';
$lang['filter'] = '필터';
-$lang['summary'] = '찾은 사용자 %3$d 중 %1$d-%2$d 보기. 전체 사용자 %4$d명.';
-$lang['nonefound'] = '찾은 사용자가 없습니다. 전체 사용자 %d명.';
+$lang['summary'] = '찾은 사용자 %3$d 중 %1$d-%2$d을(를) 봅니다. 전체 사용자는 %4$d명입니다.';
+$lang['nonefound'] = '찾은 사용자가 없습니다. 전체 사용자는 %d명입니다.';
$lang['delete_ok'] = '사용자 %d명이 삭제되었습니다';
$lang['delete_fail'] = '사용자 %d명의 삭제가 실패했습니다.';
-$lang['update_ok'] = '사용자 정보를 성공적으로 바꾸었습니다.';
-$lang['update_fail'] = '사용자 정보를 바꾸는 데 실패했습니다.';
-$lang['update_exists'] = '사용자 이름을 바꾸기는 데 실패했습니다. 사용자 이름(%s)이 이미 존재합니다. (다른 항목의 바뀜은 적용됩니다.)';
+$lang['update_ok'] = '사용자 정보를 성공적으로 바꾸었습니다';
+$lang['update_fail'] = '사용자 정보를 바꾸는 데 실패했습니다';
+$lang['update_exists'] = '사용자 이름을 바꾸는 데 실패했습니다. 사용자 이름(%s)이 이미 존재합니다. (다른 항목의 바뀜은 적용됩니다.)';
$lang['start'] = '시작';
$lang['prev'] = '이전';
$lang['next'] = '다음';
@@ -47,7 +46,7 @@ $lang['user_notify'] = '사용자에게 알림';
$lang['note_notify'] = '사용자에게 새로운 비밀번호를 준 경우에만 알림 이메일이 보내집니다.';
$lang['note_group'] = '새로운 사용자는 어떤 그룹도 설정하지 않은 경우에 기본 그룹(%s)에 추가됩니다.';
$lang['note_pass'] = '사용자 통지가 지정되어 있을 때 필드에 아무 값도 입력하지 않으면 비밀번호가 자동으로 만들어집니다.';
-$lang['add_ok'] = '사용자가 성공적으로 추가되었습니다.';
-$lang['add_fail'] = '사용자 추가가 실패했습니다.';
-$lang['notify_ok'] = '알림 이메일이 성공적으로 발송되었습니다. ';
-$lang['notify_fail'] = '알림 이메일 발송이 실패했습니다.';
+$lang['add_ok'] = '사용자를 성공적으로 추가했습니다';
+$lang['add_fail'] = '사용자 추가를 실패했습니다';
+$lang['notify_ok'] = '알림 이메일을 성공적으로 보냈습니다';
+$lang['notify_fail'] = '알림 이메일을 보낼 수 없습니다';
diff --git a/lib/plugins/usermanager/lang/ko/list.txt b/lib/plugins/usermanager/lang/ko/list.txt
index 93fa3d6f2..2a1b45bfb 100644
--- a/lib/plugins/usermanager/lang/ko/list.txt
+++ b/lib/plugins/usermanager/lang/ko/list.txt
@@ -1 +1 @@
-===== 사용자 목록 =====
+===== 사용자 목록 ===== \ No newline at end of file
diff --git a/lib/plugins/usermanager/lang/nl/lang.php b/lib/plugins/usermanager/lang/nl/lang.php
index 8f30ce3ea..e960e9a14 100644
--- a/lib/plugins/usermanager/lang/nl/lang.php
+++ b/lib/plugins/usermanager/lang/nl/lang.php
@@ -17,7 +17,7 @@
*/
$lang['menu'] = 'Gebruikersmanager';
$lang['noauth'] = '(gebruikersauthenticatie niet beschikbaar)';
-$lang['nosupport'] = '(gebruikersmanagement niet ondersteund)';
+$lang['nosupport'] = '(gebruikersbeheer niet ondersteund)';
$lang['badauth'] = 'ongeldige authenticatiemethode';
$lang['user_id'] = 'Gebruiker';
$lang['user_pass'] = 'Wachtwoord';
diff --git a/lib/plugins/usermanager/lang/pt-br/lang.php b/lib/plugins/usermanager/lang/pt-br/lang.php
index 285231f35..637be8860 100644
--- a/lib/plugins/usermanager/lang/pt-br/lang.php
+++ b/lib/plugins/usermanager/lang/pt-br/lang.php
@@ -16,6 +16,7 @@
* @author Sergio Motta sergio@cisne.com.br
* @author Isaias Masiero Filho <masiero@masiero.org>
* @author Balaco Baco <balacobaco@imap.cc>
+ * @author Victor Westmann <victor.westmann@gmail.com>
*/
$lang['menu'] = 'Gerenciamento de Usuários';
$lang['noauth'] = '(o gerenciamento de usuários não está disponível)';
diff --git a/lib/plugins/usermanager/lang/ru/lang.php b/lib/plugins/usermanager/lang/ru/lang.php
index eb9f26be6..29cee6576 100644
--- a/lib/plugins/usermanager/lang/ru/lang.php
+++ b/lib/plugins/usermanager/lang/ru/lang.php
@@ -17,6 +17,7 @@
* @author Ladyko Andrey <fylh@succexy.spb.ru>
* @author Eugene <windy.wanderer@gmail.com>
* @author Johnny Utah <pcpa@cyberpunk.su>
+ * @author Ivan I. Udovichenko (sendtome@mymailbox.pp.ua)
*/
$lang['menu'] = 'Управление пользователями';
$lang['noauth'] = '(авторизация пользователей недоступна)';
diff --git a/lib/plugins/usermanager/lang/sv/lang.php b/lib/plugins/usermanager/lang/sv/lang.php
index bd747927e..f8b530d90 100644
--- a/lib/plugins/usermanager/lang/sv/lang.php
+++ b/lib/plugins/usermanager/lang/sv/lang.php
@@ -15,6 +15,7 @@
* @author Peter Åström <eaustreum@gmail.com>
* @author Håkan Sandell <hakan.sandell@home.se>
* @author mikael@mallander.net
+ * @author Smorkster Andersson smorkster@gmail.com
*/
$lang['menu'] = 'Hantera användare';
$lang['noauth'] = '(användarautentisering ej tillgänlig)';
diff --git a/lib/plugins/usermanager/lang/zh-tw/lang.php b/lib/plugins/usermanager/lang/zh-tw/lang.php
index 1db35cc82..980d974cc 100644
--- a/lib/plugins/usermanager/lang/zh-tw/lang.php
+++ b/lib/plugins/usermanager/lang/zh-tw/lang.php
@@ -33,7 +33,7 @@ $lang['modify'] = '儲存變更';
$lang['search'] = '搜尋';
$lang['search_prompt'] = '開始搜尋';
$lang['clear'] = '重設篩選條件';
-$lang['filter'] = '篩選條件(Filter)';
+$lang['filter'] = '篩選條件 (Filter)';
$lang['summary'] = '顯示帳號 %1$d-%2$d,共 %3$d 筆符合。共有 %4$d 個帳號。';
$lang['nonefound'] = '找不到帳號。共有 %d 個帳號。';
$lang['delete_ok'] = '已刪除 %d 個帳號';
@@ -49,7 +49,7 @@ $lang['edit_usermissing'] = '找不到選取的帳號,可能已被刪除
$lang['user_notify'] = '通知使用者';
$lang['note_notify'] = '通知信只會在指定使用者新密碼時寄送。';
$lang['note_group'] = '如果沒有指定群組,新使用者將會列入至預設群組(%s)當中。';
-$lang['note_pass'] = '如果沒有輸入這個欄位而且有勾選通知使用者,則會自動產生一組密碼。';
+$lang['note_pass'] = '如果勾選了通知使用者,而沒有輸入這個欄位,則會自動產生一組密碼。';
$lang['add_ok'] = '已新增使用者';
$lang['add_fail'] = '無法新增使用者';
$lang['notify_ok'] = '通知信已寄出';
diff --git a/lib/plugins/usermanager/plugin.info.txt b/lib/plugins/usermanager/plugin.info.txt
index f4495bb19..1f8c2282b 100644
--- a/lib/plugins/usermanager/plugin.info.txt
+++ b/lib/plugins/usermanager/plugin.info.txt
@@ -1,7 +1,7 @@
base usermanager
author Chris Smith
email chris@jalakai.co.uk
-date 2012-09-08
+date 2013-02-20
name User Manager
desc Manage users
url http://dokuwiki.org/plugin:usermanager