summaryrefslogtreecommitdiff
path: root/lib/plugins
diff options
context:
space:
mode:
authorGuy Brand <gb@unistra.fr>2013-03-06 14:08:08 +0100
committerGuy Brand <gb@unistra.fr>2013-03-06 14:08:08 +0100
commit23678e344b4ddcad14254c106ecb93af174fdaa0 (patch)
treea5c787e4d87313a7fb6f18cb4c78bf210d92d60c /lib/plugins
parent847cef0a6bfd2ff9dc54e1fc140f5ba0ece0017a (diff)
parent5721a1547938df76003c6d91ea003dc1c70abd94 (diff)
downloadrpg-23678e344b4ddcad14254c106ecb93af174fdaa0.tar.gz
rpg-23678e344b4ddcad14254c106ecb93af174fdaa0.tar.bz2
Merge branch 'master' into stable
Diffstat (limited to 'lib/plugins')
-rw-r--r--lib/plugins/acl/admin.php7
-rw-r--r--lib/plugins/acl/lang/ca/lang.php1
-rw-r--r--lib/plugins/acl/lang/cs/lang.php1
-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/es/lang.php1
-rw-r--r--lib/plugins/acl/lang/fa/lang.php1
-rw-r--r--lib/plugins/acl/lang/fr/help.txt10
-rw-r--r--lib/plugins/acl/lang/fr/lang.php27
-rw-r--r--lib/plugins/acl/lang/gl/lang.php1
-rw-r--r--lib/plugins/acl/lang/kk/lang.php4
-rw-r--r--lib/plugins/acl/lang/ko/help.txt2
-rw-r--r--lib/plugins/acl/lang/ko/lang.php2
-rw-r--r--lib/plugins/acl/lang/nl/help.txt9
-rw-r--r--lib/plugins/acl/lang/tr/lang.php1
-rw-r--r--lib/plugins/acl/lang/vi/help.txt24
-rw-r--r--lib/plugins/acl/lang/zh-tw/help.txt8
-rw-r--r--lib/plugins/acl/lang/zh-tw/lang.php21
-rw-r--r--lib/plugins/acl/script.js8
-rw-r--r--lib/plugins/acl/style.css57
-rw-r--r--lib/plugins/action.php2
-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.php516
-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/en/settings.php14
-rw-r--r--lib/plugins/authad/lang/it/settings.php5
-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.php534
-rw-r--r--lib/plugins/authldap/conf/default.php19
-rw-r--r--lib/plugins/authldap/conf/metadata.php18
-rw-r--r--lib/plugins/authldap/lang/en/settings.php16
-rw-r--r--lib/plugins/authldap/lang/it/settings.php5
-rw-r--r--lib/plugins/authldap/lang/zh/settings.php20
-rw-r--r--lib/plugins/authldap/plugin.info.txt7
-rw-r--r--lib/plugins/authmysql/auth.php961
-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/en/settings.php39
-rw-r--r--lib/plugins/authmysql/lang/it/settings.php5
-rw-r--r--lib/plugins/authmysql/lang/zh/settings.php40
-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/en/settings.php33
-rw-r--r--lib/plugins/authpgsql/lang/it/settings.php5
-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.php358
-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/ar/lang.php101
-rw-r--r--lib/plugins/config/lang/ca/lang.php96
-rw-r--r--lib/plugins/config/lang/cs/lang.php14
-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/es/lang.php1
-rw-r--r--lib/plugins/config/lang/fa/lang.php1
-rw-r--r--lib/plugins/config/lang/fr/intro.txt6
-rw-r--r--lib/plugins/config/lang/fr/lang.php175
-rw-r--r--lib/plugins/config/lang/gl/lang.php107
-rw-r--r--lib/plugins/config/lang/it/lang.php1
-rw-r--r--lib/plugins/config/lang/ko/intro.txt4
-rw-r--r--lib/plugins/config/lang/ko/lang.php39
-rw-r--r--lib/plugins/config/lang/lv/lang.php94
-rw-r--r--lib/plugins/config/lang/ru/lang.php4
-rw-r--r--lib/plugins/config/lang/tr/lang.php47
-rw-r--r--lib/plugins/config/lang/zh-tw/intro.txt6
-rw-r--r--lib/plugins/config/lang/zh-tw/lang.php56
-rw-r--r--lib/plugins/config/settings/config.class.php270
-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/plugin.info.txt2
-rw-r--r--lib/plugins/info/syntax.php23
-rw-r--r--lib/plugins/plugin/admin.php25
-rw-r--r--lib/plugins/plugin/classes/ap_download.class.php29
-rw-r--r--lib/plugins/plugin/classes/ap_manage.class.php6
-rw-r--r--lib/plugins/plugin/classes/ap_update.class.php2
-rw-r--r--lib/plugins/plugin/lang/ar/lang.php2
-rw-r--r--lib/plugins/plugin/lang/ca/lang.php2
-rw-r--r--lib/plugins/plugin/lang/cs/lang.php1
-rw-r--r--lib/plugins/plugin/lang/de/lang.php2
-rw-r--r--lib/plugins/plugin/lang/el/lang.php1
-rw-r--r--lib/plugins/plugin/lang/es/lang.php5
-rw-r--r--lib/plugins/plugin/lang/fa/lang.php1
-rw-r--r--lib/plugins/plugin/lang/fr/admin_plugin.txt4
-rw-r--r--lib/plugins/plugin/lang/fr/lang.php45
-rw-r--r--lib/plugins/plugin/lang/gl/lang.php1
-rw-r--r--lib/plugins/plugin/lang/hi/lang.php1
-rw-r--r--lib/plugins/plugin/lang/lv/lang.php1
-rw-r--r--lib/plugins/plugin/lang/pl/lang.php2
-rw-r--r--lib/plugins/plugin/lang/tr/lang.php1
-rw-r--r--lib/plugins/plugin/lang/zh-tw/admin_plugin.txt4
-rw-r--r--lib/plugins/plugin/lang/zh-tw/lang.php55
-rw-r--r--lib/plugins/popularity/action.php8
-rw-r--r--lib/plugins/popularity/admin.php8
-rw-r--r--lib/plugins/popularity/helper.php10
-rw-r--r--lib/plugins/popularity/lang/ca/lang.php1
-rw-r--r--lib/plugins/popularity/lang/cs/lang.php1
-rw-r--r--lib/plugins/popularity/lang/el/lang.php1
-rw-r--r--lib/plugins/popularity/lang/es/lang.php1
-rw-r--r--lib/plugins/popularity/lang/fa/lang.php1
-rw-r--r--lib/plugins/popularity/lang/fr/intro.txt6
-rw-r--r--lib/plugins/popularity/lang/fr/lang.php9
-rw-r--r--lib/plugins/popularity/lang/fr/submitted.txt3
-rw-r--r--lib/plugins/popularity/lang/gl/lang.php1
-rw-r--r--lib/plugins/popularity/lang/ko/intro.txt2
-rw-r--r--lib/plugins/popularity/lang/tr/lang.php2
-rw-r--r--lib/plugins/popularity/lang/zh-tw/intro.txt9
-rw-r--r--lib/plugins/popularity/lang/zh-tw/lang.php9
-rw-r--r--lib/plugins/popularity/lang/zh-tw/submitted.txt2
-rw-r--r--lib/plugins/revert/admin.php15
-rw-r--r--lib/plugins/revert/lang/ca/lang.php1
-rw-r--r--lib/plugins/revert/lang/cs/lang.php1
-rw-r--r--lib/plugins/revert/lang/el/lang.php1
-rw-r--r--lib/plugins/revert/lang/es/lang.php1
-rw-r--r--lib/plugins/revert/lang/fa/lang.php1
-rw-r--r--lib/plugins/revert/lang/fr/intro.txt4
-rw-r--r--lib/plugins/revert/lang/fr/lang.php9
-rw-r--r--lib/plugins/revert/lang/gl/lang.php1
-rw-r--r--lib/plugins/revert/lang/tr/lang.php1
-rw-r--r--lib/plugins/revert/lang/zh-tw/intro.txt2
-rw-r--r--lib/plugins/revert/lang/zh-tw/lang.php5
-rw-r--r--lib/plugins/safefnrecode/action.php2
-rw-r--r--lib/plugins/syntax.php120
-rw-r--r--lib/plugins/testing/action.php3
-rw-r--r--lib/plugins/usermanager/admin.php30
-rw-r--r--lib/plugins/usermanager/lang/ca-valencia/lang.php2
-rw-r--r--lib/plugins/usermanager/lang/ca/lang.php1
-rw-r--r--lib/plugins/usermanager/lang/cs/lang.php1
-rw-r--r--lib/plugins/usermanager/lang/el/lang.php1
-rw-r--r--lib/plugins/usermanager/lang/es/lang.php1
-rw-r--r--lib/plugins/usermanager/lang/fa/lang.php1
-rw-r--r--lib/plugins/usermanager/lang/fr/edit.txt2
-rw-r--r--lib/plugins/usermanager/lang/fr/lang.php21
-rw-r--r--lib/plugins/usermanager/lang/gl/lang.php1
-rw-r--r--lib/plugins/usermanager/lang/kk/lang.php3
-rw-r--r--lib/plugins/usermanager/lang/ko/edit.txt2
-rw-r--r--lib/plugins/usermanager/lang/ko/lang.php8
-rw-r--r--lib/plugins/usermanager/lang/tr/lang.php1
-rw-r--r--lib/plugins/usermanager/lang/zh-tw/lang.php17
160 files changed, 8720 insertions, 866 deletions
diff --git a/lib/plugins/acl/admin.php b/lib/plugins/acl/admin.php
index 1197892f2..0d9cd742a 100644
--- a/lib/plugins/acl/admin.php
+++ b/lib/plugins/acl/admin.php
@@ -173,8 +173,6 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
* @author Andreas Gohr <andi@splitbrain.org>
*/
function html() {
- global $ID;
-
echo '<div id="acl_manager">'.NL;
echo '<h1>'.$this->getLang('admin_acl').'</h1>'.NL;
echo '<div class="level1">'.NL;
@@ -208,7 +206,6 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
* @author Andreas Gohr <andi@splitbrain.org>
*/
function _get_opts($addopts=null){
- global $ID;
$opts = array(
'do'=>'admin',
'page'=>'acl',
@@ -230,7 +227,6 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
global $ID;
global $lang;
- $dir = $conf['datadir'];
$ns = $this->ns;
if(empty($ns)){
$ns = dirname(str_replace(':','/',$ID));
@@ -326,7 +322,6 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
* @author Andreas Gohr <andi@splitbrain.org>
*/
function _html_detail(){
- global $conf;
global $ID;
echo '<form action="'.wl().'" method="post" accept-charset="utf-8"><div class="no">'.NL;
@@ -493,7 +488,6 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
* @author Andreas Gohr <andi@splitbrain.org>
*/
function _html_list_acl($item){
- global $ID;
$ret = '';
// what to display
if($item['label']){
@@ -764,7 +758,6 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
* @author Andreas Gohr <andi@splitbrain.org>
*/
function _html_select(){
- global $conf;
$inlist = false;
if($this->who &&
diff --git a/lib/plugins/acl/lang/ca/lang.php b/lib/plugins/acl/lang/ca/lang.php
index 10f656062..183db711b 100644
--- a/lib/plugins/acl/lang/ca/lang.php
+++ b/lib/plugins/acl/lang/ca/lang.php
@@ -7,6 +7,7 @@
* @author Carles Bellver <carles.bellver@gmail.com>
* @author carles.bellver@gmail.com
* @author carles.bellver@cent.uji.es
+ * @author daniel@6temes.cat
*/
$lang['admin_acl'] = 'Gestió de la Llista de Control d\'Accés';
$lang['acl_group'] = 'Grup';
diff --git a/lib/plugins/acl/lang/cs/lang.php b/lib/plugins/acl/lang/cs/lang.php
index a1dce0369..feb160a02 100644
--- a/lib/plugins/acl/lang/cs/lang.php
+++ b/lib/plugins/acl/lang/cs/lang.php
@@ -11,6 +11,7 @@
* @author Vojta Beran <xmamut@email.cz>
* @author zbynek.krivka@seznam.cz
* @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com>
+ * @author Jakub A. Těšínský (j@kub.cz)
*/
$lang['admin_acl'] = 'Správa přístupových práv';
$lang['acl_group'] = 'Skupina';
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/es/lang.php b/lib/plugins/acl/lang/es/lang.php
index 8aed3c504..b60033e0f 100644
--- a/lib/plugins/acl/lang/es/lang.php
+++ b/lib/plugins/acl/lang/es/lang.php
@@ -23,6 +23,7 @@
* @author Oscar Ciudad <oscar@jacho.net>
* @author Ruben Figols <ruben.figols@gmail.com>
* @author Gerardo Zamudio <gerardo@gerardozamudio.net>
+ * @author Mercè López mercelz@gmail.com
*/
$lang['admin_acl'] = 'Administración de lista de control de acceso';
$lang['acl_group'] = 'Grupo';
diff --git a/lib/plugins/acl/lang/fa/lang.php b/lib/plugins/acl/lang/fa/lang.php
index 8b7d72f51..7fe0f2c43 100644
--- a/lib/plugins/acl/lang/fa/lang.php
+++ b/lib/plugins/acl/lang/fa/lang.php
@@ -8,6 +8,7 @@
* @author Omid Mottaghi <omidmr@gmail.com>
* @author Mohammad Reza Shoaei <shoaei@gmail.com>
* @author Milad DZand <M.DastanZand@gmail.com>
+ * @author AmirH Hassaneini <mytechmix@gmail.com>
*/
$lang['admin_acl'] = 'مدیریت کنترل دسترسی‌ها';
$lang['acl_group'] = 'گروه';
diff --git a/lib/plugins/acl/lang/fr/help.txt b/lib/plugins/acl/lang/fr/help.txt
index 158ec92ed..081978488 100644
--- a/lib/plugins/acl/lang/fr/help.txt
+++ b/lib/plugins/acl/lang/fr/help.txt
@@ -1,9 +1,11 @@
=== Aide rapide ===
-Cette page vous permet d'ajouter ou de supprimer des permissions pour les catégories et les pages de votre wiki. Le panneau de gauche liste toutes les catégories et les pages disponibles.
+Cette page vous permet d'ajouter ou de supprimer des autorisations pour les catégories et les pages de votre wiki.
-Le formulaire ci-dessus permet d'afficher et de modifier les permissions d'un utilisateur ou d'un groupe sélectionné.
+Le panneau de gauche liste toutes les catégories et les pages disponibles.
-Dans le tableau ci-dessous, toutes les listes de contrôle d'accès actuelles sont affichées. Vous pouvez l'utiliser pour supprimer ou modifier rapidement plusieurs ACL.
+Le formulaire ci-dessus permet d'afficher et de modifier les autorisations d'un utilisateur ou d'un groupe sélectionné.
-La lecture de [[doku>fr:acl|la documentation officielle des ACL]] pourra vous permettre de bien comprendre le fonctionnement du contrôle d'accès dans DokuWiki.
+Dans le tableau ci-dessous, toutes les listes de contrôle d'accès (ACL) actuelles sont affichées. Vous pouvez l'utiliser pour supprimer ou modifier rapidement plusieurs contrôles d'accès.
+
+La lecture de [[doku>fr:acl|la documentation officielle des contrôles d'accès]] pourra vous permettre de mieux comprendre le fonctionnement du contrôle d'accès dans DokuWiki.
diff --git a/lib/plugins/acl/lang/fr/lang.php b/lib/plugins/acl/lang/fr/lang.php
index b1b3188be..e52bf51a0 100644
--- a/lib/plugins/acl/lang/fr/lang.php
+++ b/lib/plugins/acl/lang/fr/lang.php
@@ -24,32 +24,33 @@
* @author skimpax@gmail.com
* @author Yannick Aure <yannick.aure@gmail.com>
* @author Olivier DUVAL <zorky00@gmail.com>
+ * @author Anael Mobilia <contrib@anael.eu>
*/
$lang['admin_acl'] = 'Gestion de la liste des contrôles d\'accès (ACL)';
$lang['acl_group'] = 'Groupe';
$lang['acl_user'] = 'Utilisateur';
-$lang['acl_perms'] = 'Permission pour';
+$lang['acl_perms'] = 'Autorisations pour';
$lang['page'] = 'Page';
$lang['namespace'] = 'Catégorie';
$lang['btn_select'] = 'Sélectionner';
-$lang['p_user_id'] = 'Permissions actuelles de l\'utilisateur <strong class="acluser">%s</strong> sur la page <strong class="aclpage">%s</strong>: <em>%s</em>.';
-$lang['p_user_ns'] = 'Permissions actuelles de l\'utilisateur <strong class="acluser">%s</strong> sur la catégorie <strong class="aclns">%s</strong>: <em>%s</em>.';
-$lang['p_group_id'] = 'Permissions actuelles des membres du groupe <strong class="aclgroup">%s</strong> sur la page <strong class="aclpage">%s</strong>: <em>%s</em>.';
-$lang['p_group_ns'] = 'Permissions actuelles des membres du groupe <strong class="aclgroup">%s</strong> sur la catégorie <strong class="aclns">%s</strong>: <em>%s</em>.';
-$lang['p_choose_id'] = 'Saisissez un nom <strong>d\'utilisateur ou de groupe</strong> dans le formulaire ci-dessus pour afficher ou éditer les permissions relatives à la page <strong class="aclpage">%s</strong>.';
-$lang['p_choose_ns'] = 'Saisissez un nom <strong>d\'utilisateur ou de groupe</strong> dans le formulaire ci-dessous pour afficher ou éditer les permissions relatives à la catégorie <strong class="aclns">%s</strong>.';
-$lang['p_inherited'] = 'Note : Ces permissions n\'ont pas été explicitement fixées mais sont héritées d\'autres groupes ou catégories supérieures.';
-$lang['p_isadmin'] = 'Note : Le groupe ou l\'utilisateur sélectionné dispose de toutes les permissions car il est paramétré en tant que superutilisateur.';
-$lang['p_include'] = 'Les permissions les plus élevées induisent les plus faibles. Création, Télécharger et Effacer ne s\'appliquent qu\'aux catégories, pas aux pages.';
-$lang['current'] = 'ACL actuelles';
+$lang['p_user_id'] = 'Autorisations actuelles de l\'utilisateur <strong class="acluser">%s</strong> sur la page <strong class="aclpage">%s</strong> : <em>%s</em>.';
+$lang['p_user_ns'] = 'Autorisations actuelles de l\'utilisateur <strong class="acluser">%s</strong> sur la catégorie <strong class="aclns">%s</strong> : <em>%s</em>.';
+$lang['p_group_id'] = 'Autorisations actuelles des membres du groupe <strong class="aclgroup">%s</strong> sur la page <strong class="aclpage">%s</strong> : <em>%s</em>.';
+$lang['p_group_ns'] = 'Autorisations actuelles des membres du groupe <strong class="aclgroup">%s</strong> sur la catégorie <strong class="aclns">%s</strong> : <em>%s</em>.';
+$lang['p_choose_id'] = 'Saisissez un <strong>nom d\'utilisateur ou de groupe</strong> dans le formulaire ci-dessous pour afficher ou éditer les autorisations relatives à la page <strong class="aclpage">%s</strong>.';
+$lang['p_choose_ns'] = 'Saisissez un <strong>nom d\'utilisateur ou de groupe</strong> dans le formulaire ci-dessous pour afficher ou éditer les autorisations relatives à la catégorie <strong class="aclns">%s</strong>.';
+$lang['p_inherited'] = 'Note : ces autorisations n\'ont pas été explicitement définies mais sont héritées de groupes ou catégories supérieurs.';
+$lang['p_isadmin'] = 'Note : le groupe ou l\'utilisateur sélectionné dispose toujours de toutes les autorisations car il est paramétré en tant que super-utilisateur.';
+$lang['p_include'] = 'Les autorisations les plus élevées incluent les plus faibles. Création, Envoyer et Effacer ne s\'appliquent qu\'aux catégories, pas aux pages.';
+$lang['current'] = 'Contrôles d\'accès actuels';
$lang['where'] = 'Page/Catégorie';
$lang['who'] = 'Utilisateur/Groupe';
-$lang['perm'] = 'Permissions';
+$lang['perm'] = 'Autorisations';
$lang['acl_perm0'] = 'Aucune';
$lang['acl_perm1'] = 'Lecture';
$lang['acl_perm2'] = 'Écriture';
$lang['acl_perm4'] = 'Création';
-$lang['acl_perm8'] = 'Téléverser';
+$lang['acl_perm8'] = 'Envoyer';
$lang['acl_perm16'] = 'Effacer';
$lang['acl_new'] = 'Ajouter une nouvelle entrée';
$lang['acl_mod'] = 'Modifier l\'entrée';
diff --git a/lib/plugins/acl/lang/gl/lang.php b/lib/plugins/acl/lang/gl/lang.php
index db57598e6..3325bfd07 100644
--- a/lib/plugins/acl/lang/gl/lang.php
+++ b/lib/plugins/acl/lang/gl/lang.php
@@ -4,6 +4,7 @@
*
* @author Medúlio <medulio@ciberirmandade.org>
* @author Oscar M. Lage <r0sk10@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/kk/lang.php b/lib/plugins/acl/lang/kk/lang.php
index dde5b9577..f21b93132 100644
--- a/lib/plugins/acl/lang/kk/lang.php
+++ b/lib/plugins/acl/lang/kk/lang.php
@@ -4,3 +4,7 @@
*
* @author Nurgozha Kaliaskarov astana08@gmail.com
*/
+$lang['acl_group'] = 'Группа';
+$lang['acl_user'] = 'Пайдаланушы';
+$lang['page'] = 'Бет';
+$lang['acl_perm1'] = 'Оқу';
diff --git a/lib/plugins/acl/lang/ko/help.txt b/lib/plugins/acl/lang/ko/help.txt
index 377636682..6a15b7a2e 100644
--- a/lib/plugins/acl/lang/ko/help.txt
+++ b/lib/plugins/acl/lang/ko/help.txt
@@ -1,4 +1,4 @@
-=== 도움말: ===
+=== 빠른 도움말: ===
현재 문서에서 위키 이름공간과 문서에 대한 접근 권한을 추가하거나 삭제할 수 있습니다.
diff --git a/lib/plugins/acl/lang/ko/lang.php b/lib/plugins/acl/lang/ko/lang.php
index c8e1ce5cc..5d2662ef8 100644
--- a/lib/plugins/acl/lang/ko/lang.php
+++ b/lib/plugins/acl/lang/ko/lang.php
@@ -41,4 +41,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/tr/lang.php b/lib/plugins/acl/lang/tr/lang.php
index de96d2906..629ca546b 100644
--- a/lib/plugins/acl/lang/tr/lang.php
+++ b/lib/plugins/acl/lang/tr/lang.php
@@ -8,6 +8,7 @@
* @author Cihan Kahveci <kahvecicihan@gmail.com>
* @author Yavuz Selim <yavuzselim@gmail.com>
* @author Caleb Maclennan <caleb@alerque.com>
+ * @author farukerdemoncel@gmail.com
*/
$lang['admin_acl'] = 'Erişim Kontrol Listesi (ACL) Yönetimi';
$lang['acl_group'] = 'Grup';
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/lang/zh-tw/help.txt b/lib/plugins/acl/lang/zh-tw/help.txt
index d5d031059..2d1c84b7d 100644
--- a/lib/plugins/acl/lang/zh-tw/help.txt
+++ b/lib/plugins/acl/lang/zh-tw/help.txt
@@ -1,11 +1,11 @@
-=== 快速指南: ===
+=== 快速指南: ===
-你可以用這個頁面為維基中的分類空間或頁面增加或移除權限。
+你可以用這個頁面,為本 wiki 中的分類名稱或頁面增加或移除權限。
-左方面板顯示了所有分類空間和頁面。
+左方面板顯示了所有分類名稱和頁面。
上方表格允許你觀看及修改選取的使用者或群組的權限。
下方表格顯示了目前所有的存取控制表 (ACL),你可以用它快速刪除或更改多項規則。
-閱讀 [[doku>acl|official documentation on ACL]] 可以幫助你完整地了解 DokuWiki 存取控制的運作。
+閱讀 [[doku>acl|official documentation on ACL]] 可以幫助你完整地了解 DokuWiki 存取控制的運作。 \ No newline at end of file
diff --git a/lib/plugins/acl/lang/zh-tw/lang.php b/lib/plugins/acl/lang/zh-tw/lang.php
index ff115df18..ff2c6a184 100644
--- a/lib/plugins/acl/lang/zh-tw/lang.php
+++ b/lib/plugins/acl/lang/zh-tw/lang.php
@@ -12,25 +12,26 @@
* @author Danny Lin <danny0838@pchome.com.tw>
* @author Shuo-Ting Jian <shoting@gmail.com>
* @author syaoranhinata@gmail.com
+ * @author Ichirou Uchiki <syaoranhinata@gmail.com>
*/
$lang['admin_acl'] = '管理存取控制表 (ACL)';
$lang['acl_group'] = '群組';
$lang['acl_user'] = '使用者';
$lang['acl_perms'] = '設定權限於';
$lang['page'] = '頁面';
-$lang['namespace'] = '分類空間';
+$lang['namespace'] = '分類名稱';
$lang['btn_select'] = '選擇';
-$lang['p_user_id'] = '使用者 <b class="acluser">%s</b> 目前在頁面 <b class="aclpage">%s</b> 擁有以下權限:<i>%s</i>。';
-$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_user_id'] = '使用者 <b class="acluser">%s</b> 目前在頁面 <b class="aclpage">%s</b> 裏擁有以下權限:<i>%s</i>。';
+$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>輸入使用者或群組</b>以檢視或編輯頁面 <b class="aclpage">%s</b> 的權限設定。';
-$lang['p_choose_ns'] = '請在上方表格<b>輸入使用者或群組</b>以檢視或編輯分類空間 <b class=\"aclns\">%s</b> 的權限設定。';
-$lang['p_inherited'] = '注意:這些權限並未明確指定,而是從群組或上層的分類空間繼承而來。';
-$lang['p_isadmin'] = '注意:選取的群組或使用者擁有完整權限,因為它被設定為超級使用者。';
-$lang['p_include'] = '較高的權限亦包含了較低的權限。新增、上傳與刪除權限只能設定在分類空間,不能設定在頁面。';
+$lang['p_choose_ns'] = '請在上方表格<b>輸入使用者或群組</b>以檢視或編輯分類名稱 <b class=\"aclns\">%s</b> 的權限設定。';
+$lang['p_inherited'] = '注意:這些權限並未明確指定,它們是從群組或上層的分類名稱繼承而來。';
+$lang['p_isadmin'] = '注意:選取的群組或使用者擁有完整權限,因為他或他們已成為超級使用者。';
+$lang['p_include'] = '較高的權限亦包含了較低的權限。新增、上傳與刪除權限只能套用至分類名稱,不能套用至頁面。';
$lang['current'] = '目前的存取控制規則';
-$lang['where'] = '頁面/分類空間';
+$lang['where'] = '頁面/分類名稱';
$lang['who'] = '使用者/群組';
$lang['perm'] = '權限';
$lang['acl_perm0'] = '無';
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/action.php b/lib/plugins/action.php
index 885bd7c96..a2ad969d7 100644
--- a/lib/plugins/action.php
+++ b/lib/plugins/action.php
@@ -17,7 +17,7 @@ class DokuWiki_Action_Plugin extends DokuWiki_Plugin {
/**
* Registers a callback function for a given event
*/
- function register($controller) {
+ function register(Doku_Event_Handler $controller) {
trigger_error('register() not implemented in '.get_class($this), E_USER_WARNING);
}
}
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..6c49eafbb
--- /dev/null
+++ b/lib/plugins/authad/auth.php
@@ -0,0 +1,516 @@
+<?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']['ad_username'] = 'root';
+ * $conf['plugin']['authad']['ad_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;
+ }
+
+ /**
+ * 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);
+
+ //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']){
+ $timeleft = $adldap->user()->passwordExpiry($user); // returns unixtime
+ $timeleft = round($timeleft/(24*60*60));
+ $info['expiresin'] = $timeleft;
+
+ // if this is the current user, warn him (once per request only)
+ if(($_SERVER['REMOTE_USER'] == $user) &&
+ ($timeleft <= $this->conf['expirywarn']) &&
+ !$this->msgshown
+ ) {
+ $msg = sprintf($lang['authpwdexpire'], $timeleft);
+ 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']);
+
+ // 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;
+ }
+
+ if(isset($opts['ad_username']) && isset($opts['ad_password'])) {
+ $this->cando['getUsers'] = true;
+ } else {
+ $this->cando['getUsers'] = true;
+ }
+
+ 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..05d6c328e
--- /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['ad_username'] = '';
+$conf['ad_password'] = '';
+$conf['real_primarygroup'] = 0;
+$conf['use_ssl'] = 0;
+$conf['use_tls'] = 0;
+$conf['debug'] = 0;
+$conf['expirywarn'] = 0;
+$conf['additional'] = ''; \ No newline at end of file
diff --git a/lib/plugins/authad/conf/metadata.php b/lib/plugins/authad/conf/metadata.php
new file mode 100644
index 000000000..dc251a108
--- /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['ad_username'] = array('string');
+$meta['ad_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'); \ No newline at end of file
diff --git a/lib/plugins/authad/lang/en/settings.php b/lib/plugins/authad/lang/en/settings.php
new file mode 100644
index 000000000..41176847a
--- /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['ad_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['ad_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.'; \ No newline at end of file
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/zh/settings.php b/lib/plugins/authad/lang/zh/settings.php
new file mode 100644
index 000000000..9fd3c4e35
--- /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['ad_username'] = '一个活动目录的特权用户,可以查看其他所有用户的数据。可选,但对某些活动例如发送订阅邮件是必须的。';
+$lang['ad_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..f02b5118c
--- /dev/null
+++ b/lib/plugins/authad/plugin.info.txt
@@ -0,0 +1,7 @@
+base authad
+author Andreas Gohr
+email andi@splitbrain.org
+date 2012-11-09
+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..6e7bde1f0
--- /dev/null
+++ b/lib/plugins/authldap/auth.php
@@ -0,0 +1,534 @@
+<?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(!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);
+ }
+ $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, $timelimit = 0, $deref = LDAP_DEREF_NEVER) {
+ if(is_null($attributes)) $attributes = array();
+
+ if($scope == 'base') {
+ return @ldap_read(
+ $link_identifier, $base_dn, $filter, $attributes,
+ $attrsonly, $sizelimit, $timelimit, $deref
+ );
+ } elseif($scope == 'one') {
+ return @ldap_list(
+ $link_identifier, $base_dn, $filter, $attributes,
+ $attrsonly, $sizelimit, $timelimit, $deref
+ );
+ } else {
+ return @ldap_search(
+ $link_identifier, $base_dn, $filter, $attributes,
+ $attrsonly, $sizelimit, $timelimit, $deref
+ );
+ }
+ }
+
+ /**
+ * 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..d07f9c82e
--- /dev/null
+++ b/lib/plugins/authldap/conf/default.php
@@ -0,0 +1,19 @@
+<?php
+
+$conf['server'] = '';
+$conf['port'] = 389;
+$conf['usertree'] = '';
+$conf['grouptree'] = '';
+$conf['userfilter'] = '';
+$conf['groupfilter'] = '';
+$conf['version'] = 2;
+$conf['starttls'] = 0;
+$conf['referrals'] = 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'] = array('onoff'); \ 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..fc5b2e63c
--- /dev/null
+++ b/lib/plugins/authldap/conf/metadata.php
@@ -0,0 +1,18 @@
+<?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['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/en/settings.php b/lib/plugins/authldap/lang/en/settings.php
new file mode 100644
index 000000000..ddedf8ae3
--- /dev/null
+++ b/lib/plugins/authldap/lang/en/settings.php
@@ -0,0 +1,16 @@
+<?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['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 member ship 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';
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/zh/settings.php b/lib/plugins/authldap/lang/zh/settings.php
new file mode 100644
index 000000000..e84511b42
--- /dev/null
+++ b/lib/plugins/authldap/lang/zh/settings.php
@@ -0,0 +1,20 @@
+<?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 (如果匿名绑定不满足要求)。例如 Eg. <code>cn=admin, dc=my, dc=home</code>';
+$lang['bindpw'] = '上述用户的密码';
+$lang['userscope'] = '限制用户搜索的范围';
+$lang['groupscope'] = '限制组搜索的范围';
+$lang['debug'] = '有错误时显示额外的调试信息';
diff --git a/lib/plugins/authldap/plugin.info.txt b/lib/plugins/authldap/plugin.info.txt
new file mode 100644
index 000000000..2af8cf00a
--- /dev/null
+++ b/lib/plugins/authldap/plugin.info.txt
@@ -0,0 +1,7 @@
+base authldap
+author Andreas Gohr
+email andi@splitbrain.org
+date 2012-10-06
+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..7d303726b
--- /dev/null
+++ b/lib/plugins/authmysql/auth.php
@@ -0,0 +1,961 @@
+<?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);
+ }
+
+ /**
+ * 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->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['auth']['mysql']['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) {
+ if(is_array($this->getConf('TablesToLock'))) {
+ if($mode == "READ" || $mode == "WRITE") {
+ $sql = "LOCK TABLES ";
+ $cnt = 0;
+ foreach($this->getConf('TablesToLock') 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..647f3d96c
--- /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'] = '';
+$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/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/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/zh/settings.php b/lib/plugins/authmysql/lang/zh/settings.php
new file mode 100644
index 000000000..43cfbb3c0
--- /dev/null
+++ b/lib/plugins/authmysql/lang/zh/settings.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Chinese language file
+ *
+ * @author lainme <lainme993@gmail.com>
+ */
+$lang['server'] = '您的 MySQL 服务器';
+$lang['user'] = 'MySQL 用户名';
+$lang['password'] = '上述用户的密码';
+$lang['database'] = '使用的数据库';
+$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..c1e118427
--- /dev/null
+++ b/lib/plugins/authmysql/plugin.info.txt
@@ -0,0 +1,7 @@
+base authmysql
+author Andreas Gohr
+email andi@splitbrain.org
+date 2012-10-06
+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/en/settings.php b/lib/plugins/authpgsql/lang/en/settings.php
new file mode 100644
index 000000000..8c048fa0f
--- /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'] = 'PostreSQL 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/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/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..ad71771b4
--- /dev/null
+++ b/lib/plugins/authpgsql/plugin.info.txt
@@ -0,0 +1,7 @@
+base authpgsql
+author Andreas Gohr
+email andi@splitbrain.org
+date 2012-10-06
+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..3416ede89
--- /dev/null
+++ b/lib/plugins/authplain/auth.php
@@ -0,0 +1,358 @@
+<?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).'):/';
+
+ if(io_deleteFromFile($config_cascade['plainauth.users']['default'], $pattern, true)) {
+ foreach($deleted as $user) unset($this->users[$user]);
+ return count($deleted);
+ }
+
+ // problem deleting, 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..cde38eaac
--- /dev/null
+++ b/lib/plugins/authplain/plugin.info.txt
@@ -0,0 +1,7 @@
+base authplain
+author Andreas Gohr
+email andi@splitbrain.org
+date 2012-10-06
+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/ar/lang.php b/lib/plugins/config/lang/ar/lang.php
index 2e55446ec..76c155812 100644
--- a/lib/plugins/config/lang/ar/lang.php
+++ b/lib/plugins/config/lang/ar/lang.php
@@ -28,6 +28,7 @@ $lang['_anti_spam'] = 'اعدادات مضاد النفاية';
$lang['_editing'] = 'اعدادات التحرير';
$lang['_links'] = 'اعدادات الروابط';
$lang['_media'] = 'اعدادات الوسائط';
+$lang['_notifications'] = 'اعدادات التنبيه';
$lang['_advanced'] = 'اعدادات متقدمة';
$lang['_network'] = 'اعدادات الشبكة';
$lang['_plugin_sufix'] = 'اعدادات الملحقات';
@@ -35,29 +36,30 @@ $lang['_template_sufix'] = 'اعدادات القوالب';
$lang['_msg_setting_undefined'] = 'لا بيانات إعدادات.';
$lang['_msg_setting_no_class'] = 'لا صنف إعدادات.';
$lang['_msg_setting_no_default'] = 'لا قيمة افتراضية.';
-$lang['fmode'] = 'نمط انشاء الملفات';
-$lang['dmode'] = 'نمط انشاء المجلدات';
-$lang['lang'] = 'لغة الواجهة';
-$lang['basedir'] = 'مسار الخادوم (مثال. <code>/dokuwiki/</code>) اترك فارغا للاكتشاف التلقائي.';
-$lang['baseurl'] = 'عنوان الخادوم (مثال. <code>http://www.yourserver.com</code>). اترك فارغا للاكتشاف التلقائي.';
-$lang['savedir'] = 'دليل حفظ البيانات';
-$lang['cookiedir'] = 'مسار الكعكات. اترك فارغا لاستخدام baseurl.';
-$lang['start'] = 'اسم صفحة البداية';
$lang['title'] = 'عنوان الويكي';
+$lang['start'] = 'اسم صفحة البداية';
+$lang['lang'] = 'لغة الواجهة';
$lang['template'] = 'القالب';
$lang['tagline'] = 'Tagline (في حال دعم القالب له)
';
$lang['sidebar'] = 'اسم صفحة الشريط الجانبي (في حال دعم القالب له). تركه فارغا يعطل الشريط الجانبي.';
$lang['license'] = 'تحت أي رخصة تريد اصدار المحتوى؟';
-$lang['fullpath'] = 'اظهر المحتوى الكامل للصفحات في ';
+$lang['savedir'] = 'دليل حفظ البيانات';
+$lang['basedir'] = 'مسار الخادوم (مثال. <code>/dokuwiki/</code>) اترك فارغا للاكتشاف التلقائي.';
+$lang['baseurl'] = 'عنوان الخادوم (مثال. <code>http://www.yourserver.com</code>). اترك فارغا للاكتشاف التلقائي.';
+$lang['cookiedir'] = 'مسار الكعكات. اترك فارغا لاستخدام baseurl.';
+$lang['dmode'] = 'نمط انشاء المجلدات';
+$lang['fmode'] = 'نمط انشاء الملفات';
+$lang['allowdebug'] = 'مكّن التنقيح <b>عطّلها إن لم تكن بحاجلة لها!</b>';
$lang['recent'] = 'أحدث التغييرات';
+$lang['recent_days'] = 'مدة إبقاء أحدث التغييرات (ايام)';
$lang['breadcrumbs'] = 'عدد العناقيد للزيارات';
$lang['youarehere'] = 'عناقيد هرمية';
+$lang['fullpath'] = 'اظهر المحتوى الكامل للصفحات في ';
$lang['typography'] = 'اعمل استبدالات طبوغرافية';
-$lang['htmlok'] = 'مكّن تضمين HTML';
-$lang['phpok'] = 'مكّن تضمين PHP';
$lang['dformat'] = 'تنسيق التاريخ (انظر وظيفة PHP,s <a href="http://www.php.net/strftime">strftime</a>)';
$lang['signature'] = 'التوقيع';
+$lang['showuseras'] = 'الذي يعرض لاظهار المستخدم الذي قام بآخر تحرير لصفحة';
$lang['toptoclevel'] = 'المستوى الأعلى لمحتويات الجدول';
$lang['tocminheads'] = 'الحد الأدنى من الترويسات لبناء جدول المحتويات';
$lang['maxtoclevel'] = 'المستوى الأقصى لمحتويات الجدول';
@@ -65,16 +67,8 @@ $lang['maxseclevel'] = 'المستوى الأقصى لتحرير ال
$lang['camelcase'] = 'استخدم CamelCase للروابط';
$lang['deaccent'] = 'نظّف اسماء الصفحات';
$lang['useheading'] = 'استخدم اول ترويسة كأسم للصفحة';
-$lang['refcheck'] = 'التحقق من مرجع الوسائط';
-$lang['refshow'] = 'عدد مراجع الوسائط لتعرض';
-$lang['allowdebug'] = 'مكّن التنقيح <b>عطّلها إن لم تكن بحاجلة لها!</b>';
-$lang['mediarevisions'] = 'تفعيل إصدارات الوسائط؟';
-$lang['usewordblock'] = 'احجز الغثاء بناء على قائمة كلمات';
-$lang['indexdelay'] = 'التأخير قبل الفهرسة (ثوان)';
-$lang['relnofollow'] = 'استخدم rel="nofollow" للروابط الخارجية';
-$lang['mailguard'] = 'عناوين بريدية مبهمة';
-$lang['iexssprotect'] = 'تحقق الملفات المرفوعة من احتمال وجود أكواد جافاسكربت أو HTML ضارة';
-$lang['showuseras'] = 'الذي يعرض لاظهار المستخدم الذي قام بآخر تحرير لصفحة';
+$lang['sneaky_index'] = 'افتراضيا، ستعرض دوكو ويكي كل اسماء النطاقات في عرض الفهرس. تفعيل هذا الخيار سيخفي مالا يملك المستخدم صلاحية قراءته. قد يؤدي هذا إلى اخفاء نطاقات فرعية متاحة. وقد يؤدي لجعل صفحة الفهرس معطلة في بعض اعدادات ACL.';
+$lang['hidepages'] = 'أخف الصفحات المنطبق عليها (تعابير شرطية)';
$lang['useacl'] = 'استخدم قائمة التحم بالوصول';
$lang['autopasswd'] = 'ولد كلمات سر تلقائيا';
$lang['authtype'] = 'آلية المواثقة';
@@ -83,61 +77,68 @@ $lang['defaultgroup'] = 'المجموعة الافتراضية';
$lang['superuser'] = 'مجموعة المستخدم المتفوق أو مستخدم أو قائمة مفصولة بالفاصلة مستخدم1،@مجموعة، مستخدم2 صلاحيتهم الوصول الكامل لكل الصفحات و الوظائف بغض النظر عن اعدادات ACL';
$lang['manager'] = 'مجموعة المدراء أو مستخدم أو قائمة مفصولة بالفاصلة مستخدم1،@مجموعة، مستخدم2 صلاحيتهم بعض الوظائف الادارية';
$lang['profileconfirm'] = 'اكد تغيير اللاحة بكلمة المرور';
+$lang['rememberme'] = 'اسمح بكعكات الدخول الدائم (تذكرني)';
$lang['disableactions'] = 'عطّل اجراءات دوكو ويكي';
$lang['disableactions_check'] = 'تحقق';
$lang['disableactions_subscription'] = 'اشترك/الغ الاشتراك';
$lang['disableactions_wikicode'] = 'اعرض المصدر/صدّر صرفا';
$lang['disableactions_other'] = 'اجراءات أخرى (مفصولة بالفاصلة)';
-$lang['sneaky_index'] = 'افتراضيا، ستعرض دوكو ويكي كل اسماء النطاقات في عرض الفهرس. تفعيل هذا الخيار سيخفي مالا يملك المستخدم صلاحية قراءته. قد يؤدي هذا إلى اخفاء نطاقات فرعية متاحة. وقد يؤدي لجعل صفحة الفهرس معطلة في بعض اعدادات ACL.';
$lang['auth_security_timeout'] = 'زمن انتهاء أمان المواثقة (ثوان)';
$lang['securecookie'] = 'هل يفرض على كعكات التصفح المعدة عبر HTTPS ان ترسل فقط عبر HTTPS من قبل المتصفح؟ عطل هذا إن كان الولوج للويكي مؤمنا فقط عبر SSL لكن تصفح الويكي غير مؤمن.';
$lang['remote'] = 'مكّن نظام API البعيد. يسمح هذا لبرامج أخرى بالوصول للويكي عبر XML-RPC أو آليات أخرى.';
$lang['remoteuser'] = 'احصر الوصول البعيد ل API لمستخدمين ومجموعات يفصل بينها بالفاصلة هنا. اترك فارغا لتمكين الجميع.';
+$lang['usewordblock'] = 'احجز الغثاء بناء على قائمة كلمات';
+$lang['relnofollow'] = 'استخدم rel="nofollow" للروابط الخارجية';
+$lang['indexdelay'] = 'التأخير قبل الفهرسة (ثوان)';
+$lang['mailguard'] = 'عناوين بريدية مبهمة';
+$lang['iexssprotect'] = 'تحقق الملفات المرفوعة من احتمال وجود أكواد جافاسكربت أو HTML ضارة';
+$lang['usedraft'] = 'احفظ المسودة تلقائيا أثناء التحرير';
+$lang['htmlok'] = 'مكّن تضمين HTML';
+$lang['phpok'] = 'مكّن تضمين PHP';
+$lang['locktime'] = 'الحد الأعظمي لقفل الملف (ثوان)';
+$lang['cachetime'] = 'الحد الأعظم لعمر المخُبأ (ثوان)';
+$lang['target____wiki'] = 'النافذة الهدف للروابط الداخلية';
+$lang['target____interwiki'] = 'النافذة الهدف للروابط الممرة interwiki';
+$lang['target____extern'] = 'النافذة الهدف للروابط الخارجية';
+$lang['target____media'] = 'النافذة الهدف لروابط الوسائط';
+$lang['target____windows'] = 'النافذة الهدف لروابط النوافذ';
+$lang['mediarevisions'] = 'تفعيل إصدارات الوسائط؟';
+$lang['refcheck'] = 'التحقق من مرجع الوسائط';
+$lang['refshow'] = 'عدد مراجع الوسائط لتعرض';
+$lang['gdlib'] = 'اصدار مكتبة GD';
+$lang['im_convert'] = 'المسار إلى اداة تحويل ImageMagick';
+$lang['jpg_quality'] = 'دقة ضغط JPG (0-100)';
+$lang['fetchsize'] = 'الحجم الأعظمي (بايت) ل fetch.php لتنزيله من الخارج';
+$lang['subscribers'] = 'مكن دعم اشتراك الصفحة';
+$lang['subscribe_time'] = 'المهلة بعد ارسال قوائم الاشتراكات والملخصات (ثوان); هذا يجب أن يكون أقل من الوقت المخصص في أيام أحدث التغييرات.';
+$lang['notify'] = 'ارسل تنبيهات التغيير لهذا البريد';
+$lang['registernotify'] = 'ارسل بيانات عن المستخدمين المسجلين جديدا لهذا البريد';
+$lang['mailfrom'] = 'البريد الالكتروني ليستخدم للرسائل الآلية';
+$lang['mailprefix'] = 'بادئة موضوع البريد لتستخدم مع الرسائل الآلية';
+$lang['sitemap'] = 'ولد خرائط موقع جوجل (أيام)';
+$lang['rss_type'] = 'نوع تلقيمات XML';
+$lang['rss_linkto'] = 'تلقيمات XML توصل إلى';
+$lang['rss_content'] = 'مالذي يعرض في عناصر تلقيمات XML؟';
+$lang['rss_update'] = 'تحديث تلقيم XML (ثوان)';
+$lang['rss_show_summary'] = 'تلقيم XML يظهر ملخصا في العنوان';
+$lang['rss_media'] = 'مانوع التغييرات التي ستدرج في تغذية XML؟';
$lang['updatecheck'] = 'تحقق من التحديثات و تنبيهات الأمان؟ دوكو ويكي ستحتاج للاتصال ب update.dokuwiki.org لأجل ذلك';
$lang['userewrite'] = 'استعمل عناوين URLs جميلة';
$lang['useslash'] = 'استخدم الشرطة كفاصل النطاق في العناوين';
-$lang['usedraft'] = 'احفظ المسودة تلقائيا أثناء التحرير';
$lang['sepchar'] = 'فاصل كلمة اسم الصفحة';
$lang['canonical'] = 'استخدم العناوين الشائعة كاملة';
$lang['fnencode'] = 'نظام ترميز اسماء الملفات بغير الأسكي.';
$lang['autoplural'] = 'تحقق من صيغ الجمع في الروابط';
$lang['compression'] = 'طريقة الغضط لملفات attic';
-$lang['cachetime'] = 'الحد الأعظم لعمر المخُبأ (ثوان)';
-$lang['locktime'] = 'الحد الأعظمي لقفل الملف (ثوان)';
-$lang['fetchsize'] = 'الحجم الأعظمي (بايت) ل fetch.php لتنزيله من الخارج';
-$lang['notify'] = 'ارسل تنبيهات التغيير لهذا البريد';
-$lang['registernotify'] = 'ارسل بيانات عن المستخدمين المسجلين جديدا لهذا البريد';
-$lang['mailfrom'] = 'البريد الالكتروني ليستخدم للرسائل الآلية';
-$lang['mailprefix'] = 'بادئة موضوع البريد لتستخدم مع الرسائل الآلية';
$lang['gzip_output'] = 'استخدم ترميز-محتوى gzip ل xhtml';
-$lang['gdlib'] = 'اصدار مكتبة GD';
-$lang['im_convert'] = 'المسار إلى اداة تحويل ImageMagick';
-$lang['jpg_quality'] = 'دقة ضغط JPG (0-100)';
-$lang['subscribers'] = 'مكن دعم اشتراك الصفحة';
-$lang['subscribe_time'] = 'المهلة بعد ارسال قوائم الاشتراكات والملخصات (ثوان); هذا يجب أن يكون أقل من الوقت المخصص في أيام أحدث التغييرات.';
$lang['compress'] = 'رُص مخرجات CSS و جافا سكربت';
$lang['cssdatauri'] = 'الحجم بالبايتات للصور المذكورة في CSS التي ستُضمن في صفحة-التنسيق لخفض طلبات HTTP. لن تعمل هذه التقنية في IE 7 أو أقل! <code>400</code> إلى <code>600</code> بايت تعد قيمة جيدة. اضبط إلى <code>0</code> لتعطلها.';
-$lang['hidepages'] = 'أخف الصفحات المنطبق عليها (تعابير شرطية)';
$lang['send404'] = 'ارسل "HTTP 404/Page Not Found" للصفحات غير الموجودة';
-$lang['sitemap'] = 'ولد خرائط موقع جوجل (أيام)';
$lang['broken_iua'] = 'هل الوظيفة ignore_user_abort معطلة على جهازك؟ قد يؤدي ذلك لتعطيل فهرسة البحث. IIS+PHP/CGI تعرف بأنها لاتعمل. أنظر <a href="http://bugs.splitbrain.org/?do=details&amp;task_id=852">العلة 852</a> لمزيد من المعلومات.';
$lang['xsendfile'] = 'استخدم ترويسة X-Sendfile لتمكين خادم الوب من تقديم ملفات ثابتة؟ يجب أن يكون خادم الوب داعما له.';
$lang['renderer_xhtml'] = 'المحرك ليستخدم لمخرجات الويكي الأساسية وفق (xhtml).';
$lang['renderer__core'] = '%s (نواة دوكو ويكي)';
$lang['renderer__plugin'] = '%s (ملحق)';
-$lang['rememberme'] = 'اسمح بكعكات الدخول الدائم (تذكرني)';
-$lang['rss_type'] = 'نوع تلقيمات XML';
-$lang['rss_linkto'] = 'تلقيمات XML توصل إلى';
-$lang['rss_content'] = 'مالذي يعرض في عناصر تلقيمات XML؟';
-$lang['rss_update'] = 'تحديث تلقيم XML (ثوان)';
-$lang['recent_days'] = 'مدة إبقاء أحدث التغييرات (ايام)';
-$lang['rss_show_summary'] = 'تلقيم XML يظهر ملخصا في العنوان';
-$lang['rss_media'] = 'مانوع التغييرات التي ستدرج في تغذية XML؟';
-$lang['target____wiki'] = 'النافذة الهدف للروابط الداخلية';
-$lang['target____interwiki'] = 'النافذة الهدف للروابط الممرة interwiki';
-$lang['target____extern'] = 'النافذة الهدف للروابط الخارجية';
-$lang['target____media'] = 'النافذة الهدف لروابط الوسائط';
-$lang['target____windows'] = 'النافذة الهدف لروابط النوافذ';
$lang['proxy____host'] = 'اسم خادوم الوكيل';
$lang['proxy____port'] = 'منفذ الوكيل';
$lang['proxy____user'] = 'اسم مستخدم الوكيل';
diff --git a/lib/plugins/config/lang/ca/lang.php b/lib/plugins/config/lang/ca/lang.php
index 84680450a..205d7aa6b 100644
--- a/lib/plugins/config/lang/ca/lang.php
+++ b/lib/plugins/config/lang/ca/lang.php
@@ -6,6 +6,7 @@
* @author carles.bellver@gmail.com
* @author carles.bellver@cent.uji.es
* @author Carles Bellver <carles.bellver@cent.uji.es>
+ * @author daniel@6temes.cat
*/
$lang['menu'] = 'Paràmetres de configuració';
$lang['error'] = 'Els paràmetres no s\'han pogut actualitzar per causa d\'un valor incorrecte Reviseu els canvis i torneu a enviar-los.<br />Els valors incorrectes es ressaltaran amb un marc vermell.';
@@ -28,6 +29,8 @@ $lang['_anti_spam'] = 'Paràmetres anti-brossa';
$lang['_editing'] = 'Paràmetres d\'edició';
$lang['_links'] = 'Paràmetres d\'enllaços';
$lang['_media'] = 'Paràmetres de mitjans';
+$lang['_notifications'] = 'Paràmetres de notificació';
+$lang['_syndication'] = 'Paràmetres de sindicació';
$lang['_advanced'] = 'Paràmetres avançats';
$lang['_network'] = 'Paràmetres de xarxa';
$lang['_plugin_sufix'] = 'Paràmetres de connectors';
@@ -35,25 +38,29 @@ $lang['_template_sufix'] = 'Paràmetres de plantilla';
$lang['_msg_setting_undefined'] = 'Falten metadades de paràmetre.';
$lang['_msg_setting_no_class'] = 'Falta classe de paràmetre.';
$lang['_msg_setting_no_default'] = 'No hi ha valor per defecte.';
-$lang['fmode'] = 'Mode de creació de fitxers';
-$lang['dmode'] = 'Mode de creació de directoris';
-$lang['lang'] = 'Idioma';
-$lang['basedir'] = 'Directori base';
-$lang['baseurl'] = 'URL base';
-$lang['savedir'] = 'Directori per desar les dades';
-$lang['start'] = 'Nom de la pàgina d\'inici';
$lang['title'] = 'Títol del wiki';
+$lang['start'] = 'Nom de la pàgina d\'inici';
+$lang['lang'] = 'Idioma';
$lang['template'] = 'Plantilla';
+$lang['tagline'] = 'Lema (si la plantilla ho suporta)';
+$lang['sidebar'] = 'Nom de la barra lateral (si la plantilla ho suporta). Si ho deixeu buit, la barra lateral es deshabilitarà.';
$lang['license'] = 'Amb quina llicència voleu publicar el contingut?';
-$lang['fullpath'] = 'Mostra el camí complet de les pàgines al peu';
+$lang['savedir'] = 'Directori per desar les dades';
+$lang['basedir'] = 'Directori base';
+$lang['baseurl'] = 'URL base';
+$lang['cookiedir'] = 'Adreça per a les galetes. Si ho deixeu en blanc, es farà servir la URL base.';
+$lang['dmode'] = 'Mode de creació de directoris';
+$lang['fmode'] = 'Mode de creació de fitxers';
+$lang['allowdebug'] = 'Permet depuració <strong>inhabiliteu si no és necessari</strong>';
$lang['recent'] = 'Canvis recents';
+$lang['recent_days'] = 'Quantitat de canvis recents que es mantenen (dies)';
$lang['breadcrumbs'] = 'Nombre d\'engrunes';
$lang['youarehere'] = 'Camí d\'engrunes jeràrquic';
+$lang['fullpath'] = 'Mostra el camí complet de les pàgines al peu';
$lang['typography'] = 'Substitucions tipogràfiques';
-$lang['htmlok'] = 'Permet HTML incrustat';
-$lang['phpok'] = 'Permet PHP incrustat';
$lang['dformat'] = 'Format de data (vg. la funció PHP <a href="http://www.php.net/strftime">strftime</a>)';
$lang['signature'] = 'Signatura';
+$lang['showuseras'] = 'Què cal visualitzar quan es mostra el darrer usuari que ha editat la pàgina';
$lang['toptoclevel'] = 'Nivell superior per a la taula de continguts';
$lang['tocminheads'] = 'Quantitat mínima d\'encapçalaments que determina si es construeix o no la taula de continguts.';
$lang['maxtoclevel'] = 'Nivell màxim per a la taula de continguts';
@@ -61,15 +68,8 @@ $lang['maxseclevel'] = 'Nivell màxim d\'edició de seccions';
$lang['camelcase'] = 'Utilitza CamelCase per als enllaços';
$lang['deaccent'] = 'Noms de pàgina nets';
$lang['useheading'] = 'Utilitza el primer encapçalament per als noms de pàgina';
-$lang['refcheck'] = 'Comprova la referència en els fitxers de mitjans';
-$lang['refshow'] = 'Nombre de referències de mitjans per mostrar';
-$lang['allowdebug'] = 'Permet depuració <strong>inhabiliteu si no és necessari</strong>';
-$lang['usewordblock'] = 'Bloca brossa per llista de paraules';
-$lang['indexdelay'] = 'Retard abans d\'indexar (segons)';
-$lang['relnofollow'] = 'Utilitza rel="nofollow" en enllaços externs';
-$lang['mailguard'] = 'Ofusca les adreces de correu';
-$lang['iexssprotect'] = 'Comprova codi HTML o Javascript maligne en els fitxers penjats';
-$lang['showuseras'] = 'Què cal visualitzar quan es mostra el darrer usuari que ha editat la pàgina';
+$lang['sneaky_index'] = 'Per defecte, DokuWiki mostrarà tots els espai en la visualització d\'índex. Si activeu aquest paràmetre, s\'ocultaran aquells espais en els quals l\'usuari no té accés de lectura. Això pot fer que s\'ocultin subespais que sí que són accessibles. En algunes configuracions ACL pot fer que l\'índex resulti inutilitzable.';
+$lang['hidepages'] = 'Oculta pàgines coincidents (expressions regulars)';
$lang['useacl'] = 'Utilitza llistes de control d\'accés';
$lang['autopasswd'] = 'Generació automàtica de contrasenyes';
$lang['authtype'] = 'Rerefons d\'autenticació';
@@ -78,54 +78,60 @@ $lang['defaultgroup'] = 'Grup per defecte';
$lang['superuser'] = 'Superusuari: un grup o usuari amb accés complet a totes les pàgines i funcions independentment dels paràmetres ACL';
$lang['manager'] = 'Administrador: un grup o usuari amb accés a certes funcions d\'administració';
$lang['profileconfirm'] = 'Confirma amb contrasenya els canvis en el perfil';
+$lang['rememberme'] = 'Permet galetes de sessió permanents ("recorda\'m")';
$lang['disableactions'] = 'Inhabilita accions DokuWiki';
$lang['disableactions_check'] = 'Revisa';
$lang['disableactions_subscription'] = 'Subscripció/cancel·lació';
$lang['disableactions_wikicode'] = 'Mostra/exporta font';
$lang['disableactions_other'] = 'Altres accions (separades per comes)';
-$lang['sneaky_index'] = 'Per defecte, DokuWiki mostrarà tots els espai en la visualització d\'índex. Si activeu aquest paràmetre, s\'ocultaran aquells espais en els quals l\'usuari no té accés de lectura. Això pot fer que s\'ocultin subespais que sí que són accessibles. En algunes configuracions ACL pot fer que l\'índex resulti inutilitzable.';
$lang['auth_security_timeout'] = 'Temps d\'espera de seguretat en l\'autenticació (segons)';
$lang['securecookie'] = 'Les galetes que s\'han creat via HTTPS, només s\'han d\'enviar des del navegador per HTTPS? Inhabiliteu aquesta opció si només l\'inici de sessió del wiki es fa amb SSL i la navegació del wiki es fa sense seguretat.';
+$lang['usewordblock'] = 'Bloca brossa per llista de paraules';
+$lang['relnofollow'] = 'Utilitza rel="nofollow" en enllaços externs';
+$lang['indexdelay'] = 'Retard abans d\'indexar (segons)';
+$lang['mailguard'] = 'Ofusca les adreces de correu';
+$lang['iexssprotect'] = 'Comprova codi HTML o Javascript maligne en els fitxers penjats';
+$lang['usedraft'] = 'Desa automàticament un esborrany mentre s\'edita';
+$lang['htmlok'] = 'Permet HTML incrustat';
+$lang['phpok'] = 'Permet PHP incrustat';
+$lang['locktime'] = 'Durada màxima dels fitxers de bloqueig (segons)';
+$lang['cachetime'] = 'Durada màxima de la memòria cau (segons)';
+$lang['target____wiki'] = 'Finestra de destinació en enllaços interns';
+$lang['target____interwiki'] = 'Finestra de destinació en enllaços interwiki';
+$lang['target____extern'] = 'Finestra de destinació en enllaços externs';
+$lang['target____media'] = 'Finestra de destinació en enllaços de mitjans';
+$lang['target____windows'] = 'Finestra de destinació en enllaços de Windows';
+$lang['refcheck'] = 'Comprova la referència en els fitxers de mitjans';
+$lang['refshow'] = 'Nombre de referències de mitjans per mostrar';
+$lang['gdlib'] = 'Versió GD Lib';
+$lang['im_convert'] = 'Camí de la utilitat convert d\'ImageMagick';
+$lang['jpg_quality'] = 'Qualitat de compressió JPEG (0-100)';
+$lang['fetchsize'] = 'Mida màxima (bytes) que fetch.php pot baixar d\'un lloc extern';
+$lang['subscribers'] = 'Habilita la subscripció a pàgines';
+$lang['notify'] = 'Envia notificacions de canvis a aquesta adreça de correu';
+$lang['registernotify'] = 'Envia informació sobre nous usuaris registrats a aquesta adreça de correu';
+$lang['mailfrom'] = 'Adreça de correu remitent per a missatges automàtics';
+$lang['sitemap'] = 'Genera mapa del lloc en format Google (dies)';
+$lang['rss_type'] = 'Tipus de canal XML';
+$lang['rss_linkto'] = 'Destinació dels enllaços en el canal XML';
+$lang['rss_content'] = 'Què es mostrarà en els elements del canal XML?';
+$lang['rss_update'] = 'Interval d\'actualització del canal XML (segons)';
+$lang['rss_show_summary'] = 'Mostra resum en els títols del canal XML';
$lang['updatecheck'] = 'Comprova actualitzacions i avisos de seguretat. DokuWiki necessitarà contactar amb update.dokuwiki.org per utilitzar aquesta característica.';
$lang['userewrite'] = 'Utilitza URL nets';
$lang['useslash'] = 'Utilitza la barra / com a separador d\'espais en els URL';
-$lang['usedraft'] = 'Desa automàticament un esborrany mentre s\'edita';
$lang['sepchar'] = 'Separador de paraules en els noms de pàgina';
$lang['canonical'] = 'Utilitza URL canònics complets';
$lang['autoplural'] = 'Comprova formes plurals en els enllaços';
$lang['compression'] = 'Mètode de compressió per als fitxers de les golfes';
-$lang['cachetime'] = 'Durada màxima de la memòria cau (segons)';
-$lang['locktime'] = 'Durada màxima dels fitxers de bloqueig (segons)';
-$lang['fetchsize'] = 'Mida màxima (bytes) que fetch.php pot baixar d\'un lloc extern';
-$lang['notify'] = 'Envia notificacions de canvis a aquesta adreça de correu';
-$lang['registernotify'] = 'Envia informació sobre nous usuaris registrats a aquesta adreça de correu';
-$lang['mailfrom'] = 'Adreça de correu remitent per a missatges automàtics';
$lang['gzip_output'] = 'Codifica contingut xhtml com a gzip';
-$lang['gdlib'] = 'Versió GD Lib';
-$lang['im_convert'] = 'Camí de la utilitat convert d\'ImageMagick';
-$lang['jpg_quality'] = 'Qualitat de compressió JPEG (0-100)';
-$lang['subscribers'] = 'Habilita la subscripció a pàgines';
$lang['compress'] = 'Sortida CSS i Javascript compacta';
-$lang['hidepages'] = 'Oculta pàgines coincidents (expressions regulars)';
$lang['send404'] = 'Envia "HTTP 404/Page Not Found" per a les pàgines inexistents';
-$lang['sitemap'] = 'Genera mapa del lloc en format Google (dies)';
$lang['broken_iua'] = 'No funciona en el vostre sistema la funció ignore_user_abort? Això podria malmetre l\'índex de cerques. Amb IIS+PHP/CGI se sap que no funciona. Vg. <a href="http://bugs.splitbrain.org/?do=details&amp;task_id=852">Bug 852</a> per a més informació.';
$lang['xsendfile'] = 'Utilitza la capçalera X-Sendfile perquè el servidor web distribueixi fitxers estàtics. No funciona amb tots els servidors web.';
$lang['renderer_xhtml'] = 'Renderitzador que cal utilitzar per a la sortida principal (xhtml) del wiki';
$lang['renderer__core'] = '%s (ànima del dokuwiki)';
$lang['renderer__plugin'] = '%s (connector)';
-$lang['rememberme'] = 'Permet galetes de sessió permanents ("recorda\'m")';
-$lang['rss_type'] = 'Tipus de canal XML';
-$lang['rss_linkto'] = 'Destinació dels enllaços en el canal XML';
-$lang['rss_content'] = 'Què es mostrarà en els elements del canal XML?';
-$lang['rss_update'] = 'Interval d\'actualització del canal XML (segons)';
-$lang['recent_days'] = 'Quantitat de canvis recents que es mantenen (dies)';
-$lang['rss_show_summary'] = 'Mostra resum en els títols del canal XML';
-$lang['target____wiki'] = 'Finestra de destinació en enllaços interns';
-$lang['target____interwiki'] = 'Finestra de destinació en enllaços interwiki';
-$lang['target____extern'] = 'Finestra de destinació en enllaços externs';
-$lang['target____media'] = 'Finestra de destinació en enllaços de mitjans';
-$lang['target____windows'] = 'Finestra de destinació en enllaços de Windows';
$lang['proxy____host'] = 'Nom del servidor intermediari';
$lang['proxy____port'] = 'Port del servidor intermediari';
$lang['proxy____user'] = 'Nom d\'usuari del servidor intermediari';
diff --git a/lib/plugins/config/lang/cs/lang.php b/lib/plugins/config/lang/cs/lang.php
index d2ec5035a..383afebb4 100644
--- a/lib/plugins/config/lang/cs/lang.php
+++ b/lib/plugins/config/lang/cs/lang.php
@@ -11,6 +11,7 @@
* @author Vojta Beran <xmamut@email.cz>
* @author zbynek.krivka@seznam.cz
* @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com>
+ * @author Jakub A. Těšínský (j@kub.cz)
*/
$lang['menu'] = 'Správa nastavení';
$lang['error'] = 'Nastavení nebyla změněna kvůli alespoň jedné neplatné položce,
@@ -36,6 +37,8 @@ $lang['_anti_spam'] = 'Protispamová nastavení';
$lang['_editing'] = 'Nastavení editace';
$lang['_links'] = 'Nastavení odkazů';
$lang['_media'] = 'Nastavení médií';
+$lang['_notifications'] = 'Nastavení upozornění';
+$lang['_syndication'] = 'Nastavení syndikace';
$lang['_advanced'] = 'Pokročilá nastavení';
$lang['_network'] = 'Nastavení sítě';
$lang['_plugin_sufix'] = 'Nastavení pluginů ';
@@ -47,6 +50,8 @@ $lang['title'] = 'Název celé wiki';
$lang['start'] = 'Název úvodní stránky';
$lang['lang'] = 'Jazyk';
$lang['template'] = 'Šablona';
+$lang['tagline'] = 'Slogan (pokud ho šablona podporuje)';
+$lang['sidebar'] = 'Jméno stránky s obsahem postranní lišty (pokud ho šablona podporuje). Prázdné pole postranní lištu deaktivuje.';
$lang['license'] = 'Pod jakou licencí má být tento obsah publikován?';
$lang['savedir'] = 'Adresář pro ukládání dat';
$lang['basedir'] = 'Kořenový adresář (např. <code>/dokuwiki/</code>). Pro autodetekci nechte prázdné.';
@@ -55,8 +60,8 @@ $lang['cookiedir'] = 'Cesta pro cookie. Není-li vyplněno, použije
$lang['dmode'] = 'Přístupová práva pro vytváření adresářů';
$lang['fmode'] = 'Přístupová práva pro vytváření souborů';
$lang['allowdebug'] = 'Povolit debugování. <b>Vypněte, pokud to nepotřebujete!</b>';
-$lang['recent'] = 'Nedávné změny';
-$lang['recent_days'] = 'Jak staré nedávných změny uchovávat (ve dnech)';
+$lang['recent'] = 'Počet položek v nedávných změnách';
+$lang['recent_days'] = 'Jak staré nedávné změny zobrazovat (ve dnech)';
$lang['breadcrumbs'] = 'Počet odkazů na navštívené stránky';
$lang['youarehere'] = 'Hierarchická "drobečková" navigace';
$lang['fullpath'] = 'Ukazovat plnou cestu ke stránkám v patičce';
@@ -94,6 +99,8 @@ $lang['disableactions_wikicode'] = 'Prohlížet zdrojové kódy/Export wiki text
$lang['disableactions_other'] = 'Další akce (oddělené čárkou)';
$lang['auth_security_timeout'] = 'Časový limit pro autentikaci (v sekundách)';
$lang['securecookie'] = 'Má prohlížeč posílat cookies nastavené přes HTTPS opět jen přes HTTPS? Vypněte tuto volbu, pokud chcete, aby bylo pomocí SSL zabezpečeno pouze přihlašování do wiki, ale obsah budete prohlížet nezabezpečeně.';
+$lang['remote'] = 'Zapne API systému, umožňující jiným aplikacím vzdálený přístup k wiki pomoci XML-RPC nebo jiných mechanizmů.';
+$lang['remoteuser'] = 'Omezit přístup k API na tyto uživatelské skupiny či uživatele (seznam oddělený čárkami). Prázdné pole povolí přístup všem.';
$lang['usewordblock'] = 'Blokovat spam za použití seznamu známých spamových slov';
$lang['relnofollow'] = 'Používat rel="nofollow" na externí odkazy';
$lang['indexdelay'] = 'Časová prodleva před indexací (v sekundách)';
@@ -109,6 +116,7 @@ $lang['target____interwiki'] = 'Cílové okno pro interwiki odkazy';
$lang['target____extern'] = 'Cílové okno pro externí odkazy';
$lang['target____media'] = 'Cílové okno pro odkazy na média';
$lang['target____windows'] = 'Cílové okno pro odkazy na windows sdílení';
+$lang['mediarevisions'] = 'Aktivovat revize souborů';
$lang['refcheck'] = 'Kontrolovat odkazy na média (před vymazáním)';
$lang['refshow'] = 'Počet zobrazených odkazů na média';
$lang['gdlib'] = 'Verze GD knihovny';
@@ -121,12 +129,14 @@ $lang['notify'] = 'Posílat oznámení o změnách na následují
$lang['registernotify'] = 'Posílat informace o nově registrovaných uživatelích na tuto mailovou adresu';
$lang['mailfrom'] = 'E-mailová adresa, která se bude používat pro automatické maily';
$lang['mailprefix'] = 'Předpona předmětu e-mailu, která se bude používat pro automatické maily';
+$lang['htmlmail'] = 'Posílat emaily v HTML (hezčí ale větší). Při vypnutí budou posílány jen textové emaily.';
$lang['sitemap'] = 'Generovat Google sitemap (interval ve dnech)';
$lang['rss_type'] = 'Typ XML kanálu';
$lang['rss_linkto'] = 'XML kanál odkazuje na';
$lang['rss_content'] = 'Co zobrazovat v položkách XML kanálu?';
$lang['rss_update'] = 'Interval aktualizace XML kanálu (v sekundách)';
$lang['rss_show_summary'] = 'XML kanál ukazuje souhrn v titulku';
+$lang['rss_media'] = 'Jaký typ změn má být uveden v kanálu XML';
$lang['updatecheck'] = 'Kontrolovat aktualizace a bezpečnostní varování? DokuWiki potřebuje pro tuto funkci přístup k update.dokuwiki.org';
$lang['userewrite'] = 'Používat "pěkná" URL';
$lang['useslash'] = 'Používat lomítko jako oddělovač jmenných prostorů v URL';
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/es/lang.php b/lib/plugins/config/lang/es/lang.php
index b940f13cd..5d03efb60 100644
--- a/lib/plugins/config/lang/es/lang.php
+++ b/lib/plugins/config/lang/es/lang.php
@@ -23,6 +23,7 @@
* @author Oscar Ciudad <oscar@jacho.net>
* @author Ruben Figols <ruben.figols@gmail.com>
* @author Gerardo Zamudio <gerardo@gerardozamudio.net>
+ * @author Mercè López mercelz@gmail.com
*/
$lang['menu'] = 'Parámetros de configuración';
$lang['error'] = 'Los parámetros no han sido actualizados a causa de un valor inválido, por favor revise los cambios y re-envíe el formulario. <br /> Los valores incorrectos se mostrarán con un marco rojo alrededor.';
diff --git a/lib/plugins/config/lang/fa/lang.php b/lib/plugins/config/lang/fa/lang.php
index ba00d5a2d..34c76780c 100644
--- a/lib/plugins/config/lang/fa/lang.php
+++ b/lib/plugins/config/lang/fa/lang.php
@@ -8,6 +8,7 @@
* @author Omid Mottaghi <omidmr@gmail.com>
* @author Mohammad Reza Shoaei <shoaei@gmail.com>
* @author Milad DZand <M.DastanZand@gmail.com>
+ * @author AmirH Hassaneini <mytechmix@gmail.com>
*/
$lang['menu'] = 'تنظیمات پیکر‌بندی';
$lang['error'] = 'به دلیل ایراد در مقادیر وارد شده، تنظیمات اعمال نشد، خواهشمندیم تغییرات را مجددن کنترل نمایید و دوباره ارسال کنید.<br/> مقادیر مشکل‌دار با کادر قرمز مشخص شده‌اند.';
diff --git a/lib/plugins/config/lang/fr/intro.txt b/lib/plugins/config/lang/fr/intro.txt
index 2a59b34d1..3d71f6184 100644
--- a/lib/plugins/config/lang/fr/intro.txt
+++ b/lib/plugins/config/lang/fr/intro.txt
@@ -1,9 +1,9 @@
====== Gestionnaire de configuration ======
-Utilisez cette page pour contrôler les paramètres de votre installation de DokuWiki. Pour de l'aide sur chaque paramètre, reportez vous à [[doku>fr:config]]. Pour d'autres détails concernant ce module, reportez vous à [[doku>fr:plugin:config]].
+Utilisez cette page pour contrôler les paramètres de votre installation de DokuWiki. Pour de l'aide sur chaque paramètre, reportez vous à [[doku>fr:config]]. Pour plus de détails concernant cette extension, reportez vous à [[doku>fr:plugin:config]].
-Les paramètres affichés sur un fond rouge sont protégés et ne peuvent être modifiés avec ce module. Les paramètres affichés sur un fond bleu sont les valeurs par défaut et les valeurs affectées à votre installation sont affichées sur un fond blanc. Les paramètres bleus et blancs peuvent être modifiés.
+Les paramètres affichés sur un fond rouge sont protégés et ne peuvent être modifiés avec cette extension. Les paramètres affichés sur un fond bleu sont les valeurs par défaut et les valeurs spécifiquement définies pour votre installation sont affichées sur un fond blanc. Seuls les paramètres sur fond bleu ou blanc peuvent être modifiés.
-N'oubliez pas d'utiliser le bouton **Enregistrer** avant de quitter cette page, sinon vos modifications seront perdues.
+N'oubliez pas d'utiliser le bouton **ENREGISTRER** avant de quitter cette page, sinon vos modifications ne seront pas prises en compte !
diff --git a/lib/plugins/config/lang/fr/lang.php b/lib/plugins/config/lang/fr/lang.php
index af2217af5..c4b521497 100644
--- a/lib/plugins/config/lang/fr/lang.php
+++ b/lib/plugins/config/lang/fr/lang.php
@@ -19,18 +19,19 @@
* @author skimpax@gmail.com
* @author Yannick Aure <yannick.aure@gmail.com>
* @author Olivier DUVAL <zorky00@gmail.com>
+ * @author Anael Mobilia <contrib@anael.eu>
*/
$lang['menu'] = 'Paramètres de configuration';
-$lang['error'] = 'Paramètres non modifiés en raison d\'une valeur non valide, vérifiez vos réglages et réessayez. <br />Les valeurs erronées sont entourées d\'une bordure rouge.';
+$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.';
$lang['updated'] = 'Paramètres mis à jour avec succès.';
$lang['nochoice'] = '(aucun autre choix possible)';
-$lang['locked'] = 'Le fichier des paramètres ne peut être modifié, si ceci n\'est pas intentionnel, <br /> vérifiez que le nom et les droits du fichier sont corrects.';
-$lang['danger'] = 'Danger : Modifier cette option pourrait rendre inaccessible votre wiki et son menu de configuration.';
-$lang['warning'] = 'Attention : Modifier cette option pourrait engendrer un comportement indésirable.';
-$lang['security'] = 'Avertissement de sécurité : Modifier cette option pourrait induire un risque de sécurité.';
+$lang['locked'] = 'Le fichier des paramètres ne peut être modifié, si ceci n\'est pas intentionnel, <br /> vérifiez que le nom et les autorisations du fichier sont correctes.';
+$lang['danger'] = 'Danger : modifier cette option pourrait rendre inaccessibles votre wiki et son menu de configuration.';
+$lang['warning'] = 'Attention : modifier cette option pourrait engendrer un comportement indésirable.';
+$lang['security'] = 'Avertissement de sécurité : modifier cette option pourrait induire un risque de sécurité.';
$lang['_configuration_manager'] = 'Gestionnaire de configuration';
$lang['_header_dokuwiki'] = 'Paramètres de DokuWiki';
-$lang['_header_plugin'] = 'Paramètres des modules externes';
+$lang['_header_plugin'] = 'Paramètres des extensions';
$lang['_header_template'] = 'Paramètres des modèles';
$lang['_header_undefined'] = 'Paramètres indéfinis';
$lang['_basic'] = 'Paramètres de base';
@@ -39,54 +40,56 @@ $lang['_authentication'] = 'Paramètres d\'authentification';
$lang['_anti_spam'] = 'Paramètres anti-spam';
$lang['_editing'] = 'Paramètres d\'édition';
$lang['_links'] = 'Paramètres des liens';
-$lang['_media'] = 'Paramètres média';
-$lang['_notifications'] = 'Paramètres de Notification';
-$lang['_syndication'] = 'Paramètres de Syndication';
+$lang['_media'] = 'Paramètres des médias';
+$lang['_notifications'] = 'Paramètres de notification';
+$lang['_syndication'] = 'Paramètres de syndication';
$lang['_advanced'] = 'Paramètres avancés';
$lang['_network'] = 'Paramètres réseaux';
-$lang['_plugin_sufix'] = 'Paramètres de module';
+$lang['_plugin_sufix'] = 'Paramètres d\'extension';
$lang['_template_sufix'] = 'Paramètres de modèle';
-$lang['_msg_setting_undefined'] = 'Pas de métadonnée de paramètres.';
-$lang['_msg_setting_no_class'] = 'Pas de classe de paramètres.';
+$lang['_msg_setting_undefined'] = 'Pas de définition de métadonnées';
+$lang['_msg_setting_no_class'] = 'Pas de définition de paramètres.';
$lang['_msg_setting_no_default'] = 'Pas de valeur par défaut.';
-$lang['title'] = 'Titre du wiki';
-$lang['start'] = 'Nom de la page d\'accueil';
-$lang['lang'] = 'Langue';
-$lang['template'] = 'Modèle';
-$lang['license'] = 'Sous quelle licence doit être placé le contenu ?';
-$lang['savedir'] = 'Répertoire de stockage';
-$lang['basedir'] = 'Répertoire de base (ex. : <code>/dokuwiki/</code>). Laisser vide pour une détection automatique.';
-$lang['baseurl'] = 'URL de base. Laisser vide pour une détection automatique.';
+$lang['title'] = 'Titre du wiki (nom du wiki)';
+$lang['start'] = 'Nom de la page d\'accueil à utiliser pour toutes les catégories';
+$lang['lang'] = 'Langue de l\'interface';
+$lang['template'] = 'Modèle (rendu visuel du wiki)';
+$lang['tagline'] = 'Descriptif du site (si le modèle supporte cette fonctionnalité)';
+$lang['sidebar'] = 'Nom du panneau latéral (si le modèle supporte cette fonctionnalité). Laisser le champ vide désactive le panneau latéral.';
+$lang['license'] = 'Sous quelle licence doit-être placé le contenu ?';
+$lang['savedir'] = 'Répertoire d\'enregistrement des données';
+$lang['basedir'] = 'Répertoire de base du serveur (par exemple : <code>/dokuwiki/</code>). Laisser vide pour une détection automatique.';
+$lang['baseurl'] = 'URL de base du site (par exemple <code>http://www.example.com</code>). Laisser vide pour une détection automatique.';
$lang['cookiedir'] = 'Chemin des cookies. Laissez vide pour utiliser l\'URL de base.';
$lang['dmode'] = 'Mode de création des répertoires';
$lang['fmode'] = 'Mode de création des fichiers';
$lang['allowdebug'] = 'Debug (<strong>Ne l\'activez que si vous en avez besoin !</strong>)';
-$lang['recent'] = 'Nombre de derniers changements à afficher';
+$lang['recent'] = 'Nombre de lignes à afficher - par page - pour les derniers changements';
$lang['recent_days'] = 'Signaler les pages modifiées depuis (en jours)';
-$lang['breadcrumbs'] = 'Nombre de traces à afficher';
-$lang['youarehere'] = 'Traces hiérarchiques';
-$lang['fullpath'] = 'Utiliser le chemin complet dans le pied de page';
+$lang['breadcrumbs'] = 'Nombre de traces à afficher. 0 désactive cette fonctionnalité.';
+$lang['youarehere'] = 'Utiliser des traces hiérarchiques (vous voulez probablement désactiver l\'option ci-dessus)';
+$lang['fullpath'] = 'Afficher le chemin complet des pages dans le pied de page';
$lang['typography'] = 'Effectuer des améliorations typographiques';
$lang['dformat'] = 'Format de date (cf. fonction <a href="http://fr.php.net/strftime">strftime</a> de PHP)';
-$lang['signature'] = 'Signature';
-$lang['showuseras'] = 'Qu\'afficher en montrant les utilisateurs qui ont récemment modifié la page';
+$lang['signature'] = 'Données à insérer lors de l\'utilisation du bouton « signature » dans l\'éditeur';
+$lang['showuseras'] = 'Données à afficher concernant le dernier utilisateur ayant modifié une page';
$lang['toptoclevel'] = 'Niveau le plus haut à afficher dans la table des matières';
-$lang['tocminheads'] = 'Nombre minimum de titres pour qu\'une table des matières soit construite';
+$lang['tocminheads'] = 'Nombre minimum de titres pour qu\'une table des matières soit affichée';
$lang['maxtoclevel'] = 'Niveau maximum pour figurer dans la table des matières';
$lang['maxseclevel'] = 'Niveau maximum pour modifier des sections';
-$lang['camelcase'] = 'Utiliser CamelCase pour les liens';
+$lang['camelcase'] = 'Utiliser l\'affichage «CamelCase » pour les liens';
$lang['deaccent'] = 'Retirer les accents dans les noms de pages';
-$lang['useheading'] = 'Utiliser le titre de premier niveau';
-$lang['sneaky_index'] = 'Par défaut, DokuWiki affichera toutes les catégories dans la vue par index. Activer cette option permet de cacher celles pour lesquelles l\'utilisateur n\'a pas la permission de lecture. Il peut en résulter le masquage de sous-catégories accessibles. Ceci peut rendre l\'index inutilisable avec certaines ACL.';
+$lang['useheading'] = 'Utiliser le titre de premier niveau pour le nom de la page';
+$lang['sneaky_index'] = 'Par défaut, DokuWiki affichera toutes les catégories dans la vue par index. Activer cette option permet de cacher les catégories pour lesquelles l\'utilisateur n\'a pas l\'autorisation de lecture. Il peut en résulter le masquage de sous-catégories accessibles. Ceci peut rendre l\'index inutilisable avec certains contrôles d\'accès.';
$lang['hidepages'] = 'Cacher les pages correspondant à (expression régulière)';
$lang['useacl'] = 'Utiliser les listes de contrôle d\'accès (ACL)';
$lang['autopasswd'] = 'Auto-générer les mots de passe';
$lang['authtype'] = 'Mécanisme d\'authentification';
$lang['passcrypt'] = 'Méthode de chiffrement des mots de passe';
-$lang['defaultgroup'] = 'Groupe par défaut';
-$lang['superuser'] = 'Superuser - groupe, utilisateur ou liste séparée par des virgules user1,@group1,user2 ayant un accès complet à toutes les pages quelque soit le paramétrage des ACL';
-$lang['manager'] = 'Manager - groupe, utilisateur ou liste séparée par des virgules user1,@group1,user2 ayant accès à certaines fonctions de gestion';
-$lang['profileconfirm'] = 'Confirmer par mot de passe les modifications de profil';
+$lang['defaultgroup'] = 'Groupe par défaut : tous les nouveaux utilisateurs y seront affectés';
+$lang['superuser'] = 'Super-utilisateur : groupe, utilisateur ou liste séparée par des virgules utilisateur1,@groupe1,utilisateur2 ayant un accès complet à toutes les pages quelque soit le paramétrage des contrôle d\'accès';
+$lang['manager'] = 'Manager:- groupe, utilisateur ou liste séparée par des virgules utilisateur1,@groupe1,utilisateur2 ayant accès à certaines fonctionnalités de gestion';
+$lang['profileconfirm'] = 'Confirmer les modifications de profil par la saisie du mot de passe ';
$lang['rememberme'] = 'Permettre de conserver de manière permanente les cookies de connexion (mémoriser)';
$lang['disableactions'] = 'Actions à désactiver dans DokuWiki';
$lang['disableactions_check'] = 'Vérifier';
@@ -94,74 +97,76 @@ $lang['disableactions_subscription'] = 'Abonnement aux pages';
$lang['disableactions_wikicode'] = 'Afficher le texte source';
$lang['disableactions_other'] = 'Autres actions (séparées par des virgules)';
$lang['auth_security_timeout'] = 'Délai d\'expiration de sécurité (secondes)';
-$lang['securecookie'] = 'Les cookies mis via HTTPS doivent-ils n\'être envoyé par le navigateur que via HTTPS ? Ne désactivez cette option que si la connexion à votre wiki est sécurisée avec SSL mais que la navigation sur le wiki n\'est pas sécurisée.';
-$lang['remote'] = 'Active l\'API système distante. Ceci autorise d\'autres applications à accéder au wiki via XML-RPC ou d\'autres mécanismes.';
-$lang['remoteuser'] = 'Restreindre l\'accès à l\'API par une liste de groupes ou d\'utilisateurs séparés par une virgule. Laisser vide pour donner l\'accès à n\'importe qui.';
+$lang['securecookie'] = 'Les cookies définis via HTTPS doivent-ils n\'être envoyé par le navigateur que via HTTPS ? Désactivez cette option lorsque seule la connexion à votre wiki est sécurisée avec SSL et que la navigation sur le wiki est effectuée de manière non sécurisée.';
+$lang['remote'] = 'Active l\'API système distante. Ceci permet à d\'autres applications d\'accéder au wiki via XML-RPC ou d\'autres mécanismes.';
+$lang['remoteuser'] = 'Restreindre l\'accès à l\'API à une liste de groupes ou d\'utilisateurs (séparés par une virgule). Laisser vide pour donner l\'accès tout le monde.';
$lang['usewordblock'] = 'Bloquer le spam selon les mots utilisés';
-$lang['relnofollow'] = 'Utiliser rel="nofollow" sur les liens extérieurs';
-$lang['indexdelay'] = 'Délai avant l\'indexation (en secondes)';
-$lang['mailguard'] = 'Brouiller les adresses de courriel';
-$lang['iexssprotect'] = 'Vérifier la présence de code JavaScript ou HTML malveillant dans les fichiers envoyés';
+$lang['relnofollow'] = 'Utiliser l\'attribut « rel="nofollow" » sur les liens extérieurs';
+$lang['indexdelay'] = 'Délai avant l\'indexation (secondes)';
+$lang['mailguard'] = 'Cacher les adresses de courriel';
+$lang['iexssprotect'] = 'Vérifier, dans les fichiers envoyés, la présence de code JavaScript ou HTML malveillant';
$lang['usedraft'] = 'Enregistrer automatiquement un brouillon pendant l\'édition';
-$lang['htmlok'] = 'Permettre HTML dans les pages';
-$lang['phpok'] = 'Permettre PHP dans les pages';
-$lang['locktime'] = 'Âge maximum des fichiers verrous (en secondes)';
-$lang['cachetime'] = 'Âge maximum d\'un fichier en cache (en secondes)';
+$lang['htmlok'] = 'Permettre l\'utilisation de code HTML dans les pages';
+$lang['phpok'] = 'Permettre l\'utilisation de code PHP dans les pages';
+$lang['locktime'] = 'Âge maximum des fichiers de blocage (secondes)';
+$lang['cachetime'] = 'Âge maximum d\'un fichier en cache (secondes)';
$lang['target____wiki'] = 'Cible pour liens internes';
$lang['target____interwiki'] = 'Cible pour liens interwiki';
$lang['target____extern'] = 'Cible pour liens externes';
$lang['target____media'] = 'Cible pour liens média';
$lang['target____windows'] = 'Cible pour liens vers partages Windows';
$lang['mediarevisions'] = 'Activer les révisions (gestion de versions) des médias';
-$lang['refcheck'] = 'Vérifier les références de média';
-$lang['refshow'] = 'Nombre de références de média à montrer';
-$lang['gdlib'] = 'Version de GD Lib';
-$lang['im_convert'] = 'Chemin vers l\'outil de conversion d\'ImageMagick';
+$lang['refcheck'] = 'Vérifier si un média est toujours utilisé avant de le supprimer';
+$lang['refshow'] = 'Nombre de références de média à montrer lorsque le paramètre précédent est actif';
+$lang['gdlib'] = 'Version de la librairie GD';
+$lang['im_convert'] = 'Chemin vers l\'outil de conversion ImageMagick';
$lang['jpg_quality'] = 'Qualité de la compression JPEG (0-100)';
-$lang['fetchsize'] = 'Taille maximale (en octets) du fichier que fetch.php peut télécharger';
+$lang['fetchsize'] = 'Taille maximale (en octets) que fetch.php peut télécharger depuis une URL tierce (par exemple pour conserver en cache et redimensionner une image tierce)';
$lang['subscribers'] = 'Activer l\'abonnement aux pages';
-$lang['subscribe_time'] = 'Délai après lequel les listes d\'abonnement et résumés sont envoyés (en secondes). Devrait être plus petit que le délai précisé dans recent_days.';
-$lang['notify'] = 'Notifier les modifications à cette adresse de courriel';
-$lang['registernotify'] = 'Envoyer un courriel annonçant les nouveaux utilisateurs enregistrés à cette adresse';
-$lang['mailfrom'] = 'Expéditeur des notifications par courriel du wiki';
-$lang['mailprefix'] = 'Préfixe à utiliser dans les objets des courriels automatiques';
-$lang['sitemap'] = 'Fréquence de génération une carte Google du site (en jours)';
-$lang['rss_type'] = 'Type de flux RSS';
-$lang['rss_linkto'] = 'Lien du flux RSS vers';
-$lang['rss_content'] = 'Quel contenu afficher dans le flux RSS ?';
-$lang['rss_update'] = 'Fréquence de mise à jour du flux RSS (en secondes)';
+$lang['subscribe_time'] = 'Délai après lequel les listes d\'abonnement et résumés sont expédiés (en secondes). Devrait être plus petit que le délai précisé dans recent_days.';
+$lang['notify'] = 'Notifier systématiquement les modifications à cette adresse de courriel';
+$lang['registernotify'] = 'Notifier systématiquement les nouveaux utilisateurs enregistrés à cette adresse de courriel';
+$lang['mailfrom'] = 'Adresse de courriel de l\'expéditeur des notifications par courriel du wiki';
+$lang['mailprefix'] = 'Préfixe à utiliser dans les objets des courriels automatiques. Laisser vide pour utiliser le titre du wiki';
+$lang['htmlmail'] = 'Envoyer des courriel HTML multipart (visuellement plus agréable, mais plus lourd). Désactiver pour utiliser uniquement des courriel plain text';
+$lang['sitemap'] = 'Fréquence de génération du sitemap Google (jours). 0 pour désactiver';
+$lang['rss_type'] = 'Type de flux XML (RSS)';
+$lang['rss_linkto'] = 'Lien du flux XML vers';
+$lang['rss_content'] = 'Quel contenu afficher dans le flux XML?';
+$lang['rss_update'] = 'Fréquence de mise à jour du flux XML (secondes)';
$lang['rss_show_summary'] = 'Le flux XML affiche le résumé dans le titre';
-$lang['rss_media'] = 'Quels types de changements devraient être listés dans le flux XML?';
-$lang['updatecheck'] = 'Vérifier les mises à jour ? DokuWiki doit pouvoir contacter update.dokuwiki.org.';
-$lang['userewrite'] = 'URL esthétiques';
-$lang['useslash'] = 'Utiliser « / » comme séparateur de catégorie dans les URL';
+$lang['rss_media'] = 'Quels types de changements doivent être listés dans le flux XML?';
+$lang['updatecheck'] = 'Vérifier les mises à jour et alertes de sécurité? DokuWiki doit pouvoir contacter update.dokuwiki.org';
+$lang['userewrite'] = 'Utiliser des URL esthétiques';
+$lang['useslash'] = 'Utiliser « / » comme séparateur de catégories dans les URL';
$lang['sepchar'] = 'Séparateur de mots dans les noms de page';
$lang['canonical'] = 'Utiliser des URL canoniques';
$lang['fnencode'] = 'Méthode pour l\'encodage des fichiers non-ASCII';
$lang['autoplural'] = 'Rechercher les formes plurielles dans les liens';
-$lang['compression'] = 'Méthode de compression pour les fichiers dans attic';
-$lang['gzip_output'] = 'Utiliser Content-Encoding gzip pour XHTML';
-$lang['compress'] = 'Compresser CSS et JavaScript';
-$lang['cssdatauri'] = 'Taille maximale en octets pour inclure dans les feuilles de styles CSS, les images qui y sont référencées. Cette technique minimise les requêtes HTTP. Pour IE, ceci ne fonctionne qu\'à partir de la version 8 ! Valeurs correctes entre <code>400</code> et <code>600</code>. <code>0</code> pour désactiver.';
-$lang['send404'] = 'Renvoyer "HTTP 404/Page Non Trouvée" pour les pages introuvables';
+$lang['compression'] = 'Méthode de compression pour les fichiers attic';
+$lang['gzip_output'] = 'Utiliser gzip pour le Content-Encoding du XHTML';
+$lang['compress'] = 'Compresser les flux CSS et JavaScript';
+$lang['cssdatauri'] = 'Taille maximale en octets pour inclure dans les feuilles de styles CSS les images qui y sont référencées. Cette technique réduit le nombre de requêtes HTTP. Cette fonctionnalité ne fonctionne qu\'à partir de la version 8 d\'Internet Explorer! Nous recommandons une valeur entre <code>400</code> et <code>600</code>. <code>0</code> pour désactiver.';
+$lang['send404'] = 'Renvoyer « HTTP 404/Page Not Found » pour les pages inexistantes';
$lang['broken_iua'] = 'La fonction ignore_user_abort est-elle opérationnelle sur votre système ? Ceci peut empêcher le fonctionnement de l\'index de recherche. IIS+PHP/
-CGI dysfonctionne. Voir le <a href="http://bugs.splitbrain.org/?do=details&amp;task_id=852">bug 852</a> pour plus d\'info.';
-$lang['xsendfile'] = 'Utiliser l\'en-tête X-Sendfile pour permettre au serveur Web de délivrer des fichiers statiques ? Votre serveur Web doit supporter cette fonctionnalité.';
+CGI dysfonctionne. Voir le <a href="http://bugs.splitbrain.org/?do=details&amp;task_id=852">bug 852</a> pour plus d\'informations.';
+$lang['xsendfile'] = 'Utiliser l\'en-tête X-Sendfile pour permettre au serveur web de délivrer les fichiers statiques ? Votre serveur web doit supporter cette fonctionnalité.';
$lang['renderer_xhtml'] = 'Moteur de rendu du format de sortie principal (XHTML)';
-$lang['renderer__core'] = '%s (cœur de dokuwiki)';
-$lang['renderer__plugin'] = '%s (module externe)';
-$lang['proxy____host'] = 'Proxy - Serveur hôte';
-$lang['proxy____port'] = 'Proxy - Numéro de port';
-$lang['proxy____user'] = 'Proxy - Identifiant';
-$lang['proxy____pass'] = 'Proxy - Mot de passe';
-$lang['proxy____ssl'] = 'Proxy - Utilisation de SSL';
-$lang['proxy____except'] = 'Expression régulière de test des URLs pour lesquelles le proxy ne devrait pas être utilisé.';
+$lang['renderer__core'] = '%s (cœur de DokuWiki)';
+$lang['renderer__plugin'] = '%s (extension)';
+$lang['dnslookups'] = 'DokuWiki effectuera une résolution du nom d\'hôte sur les adresses IP des utilisateurs modifiant des pages. Si vous ne possédez pas de serveur DNS, que ce dernier est lent ou que vous ne souhaitez pas utiliser cette fonctionnalité : désactivez-la.';
+$lang['proxy____host'] = 'Mandataire (proxy) - Hôte';
+$lang['proxy____port'] = 'Mandataire - Port';
+$lang['proxy____user'] = 'Mandataire - Identifiant';
+$lang['proxy____pass'] = 'Mandataire - Mot de passe';
+$lang['proxy____ssl'] = 'Mandataire - Utilisation de SSL';
+$lang['proxy____except'] = 'Mandataire - Expression régulière de test des URLs pour lesquelles le mandataire (proxy) ne doit pas être utilisé.';
$lang['safemodehack'] = 'Activer l\'option Mode sans échec';
-$lang['ftp____host'] = 'FTP - Serveur hôte pour Mode sans échec';
-$lang['ftp____port'] = 'FTP - Numéro de port pour Mode sans échec';
-$lang['ftp____user'] = 'FTP - Identifiant pour Mode sans échec';
-$lang['ftp____pass'] = 'FTP - Mot de passe pour Mode sans échec';
-$lang['ftp____root'] = 'FTP - Répertoire racine pour Mode sans échec';
+$lang['ftp____host'] = 'FTP / Mode sans échec - Serveur hôte';
+$lang['ftp____port'] = 'FTP / Mode sans échec - Port';
+$lang['ftp____user'] = 'FTP / Mode sans échec - Identifiant';
+$lang['ftp____pass'] = 'FTP / Mode sans échec - Mot de passe';
+$lang['ftp____root'] = 'FTP / Mode sans échec - Répertoire racine';
$lang['license_o_'] = 'Aucune choisie';
$lang['typography_o_0'] = 'aucun';
$lang['typography_o_1'] = 'guillemets uniquement';
@@ -171,7 +176,7 @@ $lang['userewrite_o_1'] = 'Fichier .htaccess';
$lang['userewrite_o_2'] = 'Interne à DokuWiki';
$lang['deaccent_o_0'] = 'off';
$lang['deaccent_o_1'] = 'supprimer les accents';
-$lang['deaccent_o_2'] = 'convertir en roman';
+$lang['deaccent_o_2'] = 'convertir en caractères latins';
$lang['gdlib_o_0'] = 'Librairie GD non disponible';
$lang['gdlib_o_1'] = 'version 1.x';
$lang['gdlib_o_2'] = 'auto-détectée';
diff --git a/lib/plugins/config/lang/gl/lang.php b/lib/plugins/config/lang/gl/lang.php
index 97b7ecdc8..21fe17452 100644
--- a/lib/plugins/config/lang/gl/lang.php
+++ b/lib/plugins/config/lang/gl/lang.php
@@ -4,6 +4,7 @@
*
* @author Medúlio <medulio@ciberirmandade.org>
* @author Oscar M. Lage <r0sk10@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.
@@ -27,6 +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'] = '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';
@@ -34,26 +37,29 @@ $lang['_template_sufix'] = 'Configuración de Sobreplanta';
$lang['_msg_setting_undefined'] = 'Non hai configuración de metadatos.';
$lang['_msg_setting_no_class'] = 'Non hai configuración de clase.';
$lang['_msg_setting_no_default'] = 'Non hai valor predeterminado.';
-$lang['fmode'] = 'Modo de creación de arquivos';
-$lang['dmode'] = 'Modo de creación de directorios';
+$lang['title'] = 'Título do Wiki';
+$lang['start'] = 'Nome da páxina inicial';
$lang['lang'] = 'Idioma';
+$lang['template'] = 'Sobreplanta';
+$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';
$lang['baseurl'] = 'URL base';
-$lang['savedir'] = 'Directorio no que se gardarán os datos';
$lang['cookiedir'] = 'Ruta das cookies. Deixar en blanco para usar a url de base.';
-$lang['start'] = 'Nome da páxina inicial';
-$lang['title'] = 'Título do Wiki';
-$lang['template'] = 'Sobreplanta';
-$lang['license'] = 'Baixo de que licenza será ceibado o teu contido?';
-$lang['fullpath'] = 'Amosar a ruta completa das páxinas no pé das mesmas';
+$lang['dmode'] = 'Modo de creación de directorios';
+$lang['fmode'] = 'Modo de creación de arquivos';
+$lang['allowdebug'] = 'Permitir o depurado <b>desactívao se non o precisas!</b>';
$lang['recent'] = 'Trocos recentes';
+$lang['recent_days'] = 'Número de trocos recentes a manter (días)';
$lang['breadcrumbs'] = 'Número de niveis da estrutura de navegación';
$lang['youarehere'] = 'Niveis xerárquicos da estrutura de navegación';
+$lang['fullpath'] = 'Amosar a ruta completa das páxinas no pé das mesmas';
$lang['typography'] = 'Facer substitucións tipográficas';
-$lang['htmlok'] = 'Permitir a inserción de HTML';
-$lang['phpok'] = 'Permitir a inserción de PHP';
$lang['dformat'] = 'Formato de Data (bótalle un ollo á función <a href="http://www.php.net/strftime">strftime</a> do PHP)';
$lang['signature'] = 'Sinatura';
+$lang['showuseras'] = 'Que amosar cando se informe do usuario que fixo a última modificación dunha páxina';
$lang['toptoclevel'] = 'Nivel superior para a táboa de contidos';
$lang['tocminheads'] = 'Cantidade mínima de liñas de cabeceira que determinará se a TDC vai ser xerada';
$lang['maxtoclevel'] = 'Nivel máximo para a táboa de contidos';
@@ -61,16 +67,8 @@ $lang['maxseclevel'] = 'Nivel máximo de edición da sección';
$lang['camelcase'] = 'Utilizar CamelCase para as ligazóns';
$lang['deaccent'] = 'Limpar nomes de páxina';
$lang['useheading'] = 'Utilizar a primeira cabeceira para os nomes de páxina';
-$lang['refcheck'] = 'Comprobar a referencia media';
-$lang['refshow'] = 'Número de referencias media a amosar';
-$lang['allowdebug'] = 'Permitir o depurado <b>desactívao se non o precisas!</b>';
-$lang['mediarevisions'] = 'Habilitar revisións dos arquivos-media?';
-$lang['usewordblock'] = 'Bloquear correo-lixo segundo unha lista de verbas';
-$lang['indexdelay'] = 'Retardo denantes de indexar (seg)';
-$lang['relnofollow'] = 'Utilizar rel="nofollow" nas ligazóns externas';
-$lang['mailguard'] = 'Ofuscar enderezos de correo-e';
-$lang['iexssprotect'] = 'Comprobar arquivos subidos na procura de posíbel código JavaScript ou HTML malicioso';
-$lang['showuseras'] = 'Que amosar cando se informe do usuario que fixo a última modificación dunha páxina';
+$lang['sneaky_index'] = 'O DokuWiki amosará por defecto todos os nomes de espazo na vista de índice. Se activas isto agocharanse aqueles onde o usuario non teña permisos de lectura.';
+$lang['hidepages'] = 'Agochar páxinas que coincidan (expresións regulares)';
$lang['useacl'] = 'Utilizar lista de control de acceso';
$lang['autopasswd'] = 'Xerar contrasinais automaticamente';
$lang['authtype'] = 'Backend de autenticación';
@@ -79,57 +77,70 @@ $lang['defaultgroup'] = 'Grupo por defecto';
$lang['superuser'] = 'Super-usuario - un grupo ou usuario con acceso completo a todas as páxinas e funcións independentemente da configuración da ACL';
$lang['manager'] = 'Xestor - un grupo ou usuario con acceso a certas funcións de xestión';
$lang['profileconfirm'] = 'Confirmar trocos de perfil mediante contrasinal';
+$lang['rememberme'] = 'Permitir cookies permanentes de inicio de sesión (lembrarme)';
$lang['disableactions'] = 'Desactivar accións do DokuWiki';
$lang['disableactions_check'] = 'Comprobar';
$lang['disableactions_subscription'] = 'Subscribir/Desubscribir';
$lang['disableactions_wikicode'] = 'Ver fonte/Exportar Datos Raw';
$lang['disableactions_other'] = 'Outras accións (separadas por comas)';
-$lang['sneaky_index'] = 'O DokuWiki amosará por defecto todos os nomes de espazo na vista de índice. Se activas isto agocharanse aqueles onde o usuario non teña permisos de lectura.';
$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'] = '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)';
+$lang['mailguard'] = 'Ofuscar enderezos de correo-e';
+$lang['iexssprotect'] = 'Comprobar arquivos subidos na procura de posíbel código JavaScript ou HTML malicioso';
+$lang['usedraft'] = 'Gardar un borrador automaticamente no tempo da edición';
+$lang['htmlok'] = 'Permitir a inserción de HTML';
+$lang['phpok'] = 'Permitir a inserción de PHP';
+$lang['locktime'] = 'Tempo máximo para o bloqueo de arquivos (seg.)';
+$lang['cachetime'] = 'Tempo máximo para a caché (seg.)';
+$lang['target____wiki'] = 'Fiestra de destino para as ligazóns internas';
+$lang['target____interwiki'] = 'Fiestra de destino para as ligazóns interwiki';
+$lang['target____extern'] = 'Fiestra de destino para as ligazóns externas';
+$lang['target____media'] = 'Fiestra de destino para as ligazóns de media';
+$lang['target____windows'] = 'Fiestra de destino para as ligazóns de fiestras';
+$lang['mediarevisions'] = 'Habilitar revisións dos arquivos-media?';
+$lang['refcheck'] = 'Comprobar a referencia media';
+$lang['refshow'] = 'Número de referencias media a amosar';
+$lang['gdlib'] = 'Versión da Libraría GD';
+$lang['im_convert'] = 'Ruta deica a ferramenta de conversión ImageMagick';
+$lang['jpg_quality'] = 'Calidade de compresión dos JPG (0-100)';
+$lang['fetchsize'] = 'Tamaño máximo (en bytes) que pode descargar fetch.php dende fontes externas';
+$lang['subscribers'] = 'Activar posibilidade de subscrición á páxina';
+$lang['subscribe_time'] = 'Tempo despois do cal se enviarán os resumos e listas de subscrición (seg.): isto debe ser inferior ao tempo especificado en recent_days.';
+$lang['notify'] = 'Enviar notificacións de trocos a este enderezo de correo-e';
+$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 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'] = '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';
-$lang['usedraft'] = 'Gardar un borrador automaticamente no tempo da edición';
$lang['sepchar'] = 'Verba separadora do nome de páxina';
$lang['canonical'] = 'Utilizar URLs completamente canónicos';
$lang['fnencode'] = 'Método para codificar os nomes de arquivo non-ASCII.';
$lang['autoplural'] = 'Comprobar formas plurais nas ligazóns';
$lang['compression'] = 'Método de compresión para arquivos attic';
-$lang['cachetime'] = 'Tempo máximo para a caché (seg.)';
-$lang['locktime'] = 'Tempo máximo para o bloqueo de arquivos (seg.)';
-$lang['fetchsize'] = 'Tamaño máximo (en bytes) que pode descargar fetch.php dende fontes externas';
-$lang['notify'] = 'Enviar notificacións de trocos a este enderezo de correo-e';
-$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['gzip_output'] = 'Utilizar Contido-Codificación gzip para o xhtml';
-$lang['gdlib'] = 'Versión da Libraría GD';
-$lang['im_convert'] = 'Ruta deica a ferramenta de conversión ImageMagick';
-$lang['jpg_quality'] = 'Calidade de compresión dos JPG (0-100)';
-$lang['subscribers'] = 'Activar posibilidade de subscrición á páxina';
-$lang['subscribe_time'] = 'Tempo despois do cal se enviarán os resumos e listas de subscrición (seg.): isto debe ser inferior ao tempo especificado en recent_days.';
$lang['compress'] = 'Saída compacta de CSS e Javascript';
-$lang['hidepages'] = 'Agochar páxinas que coincidan (expresións regulares)';
+$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['sitemap'] = 'Xerar mapa do sitio co Google (días)';
$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['rememberme'] = 'Permitir cookies permanentes de inicio de sesión (lembrarme)';
-$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['recent_days'] = 'Número de trocos recentes a manter (días)';
-$lang['rss_show_summary'] = 'Amosar sumario no título da corrente XML';
-$lang['target____wiki'] = 'Fiestra de destino para as ligazóns internas';
-$lang['target____interwiki'] = 'Fiestra de destino para as ligazóns interwiki';
-$lang['target____extern'] = 'Fiestra de destino para as ligazóns externas';
-$lang['target____media'] = 'Fiestra de destino para as ligazóns de media';
-$lang['target____windows'] = 'Fiestra de destino para as ligazóns de fiestras';
+$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/ko/intro.txt b/lib/plugins/config/lang/ko/intro.txt
index f6b76ecfc..5ef34df64 100644
--- a/lib/plugins/config/lang/ko/intro.txt
+++ b/lib/plugins/config/lang/ko/intro.txt
@@ -1,7 +1,7 @@
====== 환경 설정 관리 ======
-DokuWiki 설치할 때 설정을 변경하기 위해 사용하는 페이지입니다. 각 설정에 대한 자세한 도움말이 필요하다면 [[doku>ko:config|설정 문서 (한국어)]]와 [[doku>config|설정 문서 (영어)]]를 참고하세요.
+DokuWiki 설치할 때 설정을 바꾸기 위해 사용하는 페이지입니다. 각 설정에 대한 자세한 도움말이 필요하다면 [[doku>ko:config|설정 문서 (한국어)]]와 [[doku>config|설정 문서 (영어)]]를 참고하세요.
-플러그인에 대한 자세한 정보가 필요하다면 [[doku>plugin:config|플러그인 설정]] 문서를 참고하세요. 빨간 배경색으로 보이는 설정은 이 플러그인에서 변경하지 못하도록 되어있습니다. 파란 배경색으로 보이는 설정은 기본 설정값을 가지고 있습니다. 하얀 배경색으로 보이는 설정은 특별한 설치를 위해 설정되어 있습니다. 파란색과 하얀색 배경으로 된 설정은 수정이 가능합니다.
+플러그인에 대한 자세한 정보가 필요하다면 [[doku>plugin:config|플러그인 설정]] 문서를 참고하세요. 빨간 배경색으로 보이는 설정은 이 플러그인에서 바꾸지 못하도록 되어있습니다. 파란 배경색으로 보이는 설정은 기본 설정값을 가지고 있습니다. 하얀 배경색으로 보이는 설정은 특별한 설치를 위해 설정되어 있습니다. 파란색과 하얀색 배경으로 된 설정은 수정이 가능합니다.
이 페이지를 끝내기 전에 **저장** 버튼을 누르지 않으면 설정값은 적용되지 않습니다.
diff --git a/lib/plugins/config/lang/ko/lang.php b/lib/plugins/config/lang/ko/lang.php
index 5f90044e4..cd2cc6d6c 100644
--- a/lib/plugins/config/lang/ko/lang.php
+++ b/lib/plugins/config/lang/ko/lang.php
@@ -12,9 +12,9 @@
* @author Myeongjin <aranet100@gmail.com>
*/
$lang['menu'] = '환경 설정';
-$lang['error'] = '잘못된 값 때문에 설정을 변경할 수 없습니다. 수정한 값을 검토하고 확인을 누르세요.
+$lang['error'] = '잘못된 값 때문에 설정을 바꿀 수 없습니다. 수정한 값을 검토하고 확인을 누르세요.
<br />잘못된 값은 빨간 선으로 둘러싸여 있습니다.';
-$lang['updated'] = '설정이 성공적으로 변경되었습니다.';
+$lang['updated'] = '설정이 성공적으로 바뀌었습니다.';
$lang['nochoice'] = '(다른 선택이 불가능합니다.)';
$lang['locked'] = '환경 설정 파일을 수정할 수 없습니다. 의도한 행동이 아니라면,<br />
파일 이름과 권한이 맞는지 확인하기 바랍니다. ';
@@ -39,9 +39,9 @@ $lang['_advanced'] = '고급 설정';
$lang['_network'] = '네트워크 설정';
$lang['_plugin_sufix'] = '플러그인 설정';
$lang['_template_sufix'] = '템플릿 설정';
-$lang['_msg_setting_undefined'] = '설정되지 않은 메타데이터.';
-$lang['_msg_setting_no_class'] = '설정되지 않은 클래스.';
-$lang['_msg_setting_no_default'] = '기본값 없음.';
+$lang['_msg_setting_undefined'] = '설정된 메타데이터가 없습니다.';
+$lang['_msg_setting_no_class'] = '설정된 클래스가 없습니다.';
+$lang['_msg_setting_no_default'] = '기본값이 없습니다.';
$lang['title'] = '위키 제목 (위키 이름)';
$lang['start'] = '각 이름공간에서 사용할 시작 문서 이름';
$lang['lang'] = '인터페이스 언어';
@@ -53,12 +53,12 @@ $lang['savedir'] = '데이타 저장 디렉토리';
$lang['basedir'] = '서버 경로 (예를 들어 <code>/dokuwiki/</code>). 자동 감지를 하려면 비우세요.';
$lang['baseurl'] = '서버 URL (예를 들어 <code>http://www.yourserver.com</code>). 자동 감지를 하려면 비우세요.';
$lang['cookiedir'] = '쿠키 위치. 비워두면 기본 URL 위치로 지정됩니다.';
-$lang['dmode'] = '디렉토리 생성 모드';
-$lang['fmode'] = '파일 생성 모드';
+$lang['dmode'] = '디렉토리 만들기 모드';
+$lang['fmode'] = '파일 만들기 모드';
$lang['allowdebug'] = '디버그 허용 <b>필요하지 않으면 금지!</b>';
$lang['recent'] = '최근 바뀐 문서당 항목 수';
$lang['recent_days'] = '최근 바뀐 문서 기준 시간 (날짜)';
-$lang['breadcrumbs'] = '위치 "추적" 수. 0으로 설정하면 비활성화함.';
+$lang['breadcrumbs'] = '위치 "추적" 수. 0으로 설정하면 비활성화합니다.';
$lang['youarehere'] = '계층형 위치 추적 (다음 위의 옵션을 비활성화하고 싶습니다)';
$lang['fullpath'] = '문서 하단에 전체 경로 보여주기';
$lang['typography'] = '기호 대체';
@@ -80,21 +80,21 @@ $lang['autopasswd'] = '자동으로 만들어진 비밀번호';
$lang['authtype'] = '인증 백-엔드';
$lang['passcrypt'] = '비밀번호 암호화 방법';
$lang['defaultgroup'] = '기본 그룹, 모든 새 사용자는 이 그룹에 속합니다';
-$lang['superuser'] = '슈퍼 유저 - ACL 설정과 상관없이 모든 문서와 기능에 대한 전체 접근 권한을 가진 그룹이나 사용자. 사용자1,@그룹1,사용자2 쉼표로 구분한 목록';
-$lang['manager'] = '관리자 - 관리 기능을 사용할 수 있는 그룹이나 사용자. 사용자1,@그룹1,사용자2 쉼표로 구분한 목록';
+$lang['superuser'] = '슈퍼 유저 - ACL 설정과 상관없이 모든 문서와 기능에 대한 전체 접근 권한을 가진 그룹이나 사용자 또는 사용자1,@그룹1,사용자2 쉼표로 구분한 목록';
+$lang['manager'] = '관리자 - 관리 기능을 사용할 수 있는 그룹이나 사용자 또는 사용자1,@그룹1,사용자2 쉼표로 구분한 목록';
$lang['profileconfirm'] = '개인 정보를 바꿀 때 비밀번호 다시 확인';
$lang['rememberme'] = '항상 로그인 정보 저장 허용 (기억하기)';
$lang['disableactions'] = 'DokuWiki 활동 비활성화';
$lang['disableactions_check'] = '검사';
$lang['disableactions_subscription'] = '구독 신청/해지';
-$lang['disableactions_wikicode'] = '내용 보기/원시 내보대기';
+$lang['disableactions_wikicode'] = '내용 보기/원본 내보대기';
$lang['disableactions_other'] = '다른 활동 (쉼표로 구분)';
$lang['auth_security_timeout'] = '인증 보안 초과 시간 (초)';
$lang['securecookie'] = 'HTTPS로 보내진 쿠키는 HTTPS에만 적용 할까요? 위키의 로그인 페이지만 SSL로 암호화하고 위키 문서는 그렇지 않은 경우 비활성화 합니다.';
-$lang['remote'] = '원격 API를 활성화 합니다. 이 항목을 허용하면 XML-RPC 및 기타 메카니즘을 통해 다른 어플리케이션으로 접근가능합니다.';
+$lang['remote'] = '원격 API를 활성화 합니다. 이 항목을 허용하면 XML-RPC 및 기타 메카니즘을 통해 다른 어플리케이션으로 접근 가능합니다.';
$lang['remoteuser'] = '이 항목에 입력된 쉼표로 나눠진 그룹이나 사용자에게 원격 API 접근을 제한합니다. 빈칸으로 두면 모두에게 허용합니다.';
$lang['usewordblock'] = '금지 단어를 사용해 스팸 막기';
-$lang['relnofollow'] = '외부 링크에 rel="nofollow" 사용';
+$lang['relnofollow'] = '바깥 링크에 rel="nofollow" 사용';
$lang['indexdelay'] = '색인 연기 시간 (초)';
$lang['mailguard'] = '이메일 주소를 알아볼 수 없게 하기';
$lang['iexssprotect'] = '올린 파일의 악성 자바스크립트, HTML 코드 가능성 여부를 검사';
@@ -105,7 +105,7 @@ $lang['locktime'] = '최대 파일 잠금 시간(초)';
$lang['cachetime'] = '최대 캐시 생존 시간 (초)';
$lang['target____wiki'] = '내부 링크에 대한 타겟 창';
$lang['target____interwiki'] = '인터위키 링크에 대한 타겟 창';
-$lang['target____extern'] = '외부 링크에 대한 타겟 창';
+$lang['target____extern'] = '바깥 링크에 대한 타겟 창';
$lang['target____media'] = '미디어 링크에 대한 타겟 창';
$lang['target____windows'] = '창 링크에 대한 타겟 창';
$lang['mediarevisions'] = '미디어 버전 관리를 사용하겠습니까?';
@@ -114,9 +114,9 @@ $lang['refshow'] = '위의 설정이 활성화되었을 때 보여
$lang['gdlib'] = 'GD 라이브러리 버전';
$lang['im_convert'] = 'ImageMagick 변환 도구 위치';
$lang['jpg_quality'] = 'JPG 압축 품질 (0-100)';
-$lang['fetchsize'] = 'fetch.php가 외부에서 다운로드할 수도 있는 최대 크기 (바이트)';
+$lang['fetchsize'] = 'fetch.php가 바깥에서 다운로드할 수도 있는 최대 크기 (바이트)';
$lang['subscribers'] = '사용자가 이메일로 문서 바뀜에 구독하도록 허용';
-$lang['subscribe_time'] = '구독 목록과 요약이 보내질 경과 시간 (초); 이 것은 recent_days에서 설정된 시간보다 작아야 합니다.';
+$lang['subscribe_time'] = '구독 목록과 요약이 보내질 경과 시간 (초); recent_days에서 설정된 시간보다 작아야 합니다.';
$lang['notify'] = '항상 이 이메일 주소로 바뀜 알림을 보냄';
$lang['registernotify'] = '항상 새 사용자한테 이 이메일 주소로 정보를 보냄';
$lang['mailfrom'] = '자동으로 보내지는 메일 발신자';
@@ -127,7 +127,7 @@ $lang['rss_type'] = 'XML 피드 타입';
$lang['rss_linkto'] = 'XML 피드 링크 정보';
$lang['rss_content'] = 'XML 피드 항목에 표시되는 내용은?';
$lang['rss_update'] = 'XML 피드 업데이트 주기 (초)';
-$lang['rss_show_summary'] = 'XML 피드 제목에서 요약정보 보여주기';
+$lang['rss_show_summary'] = 'XML 피드 제목에서 요약 보여주기';
$lang['rss_media'] = '어떤 규격으로 XML 피드를 받아보시겠습니까?';
$lang['updatecheck'] = '업데이트와 보안 문제를 검사할까요? 이 기능을 사용하려면 DokuWiki를 update.dokuwiki.org에 연결해야 합니다.';
$lang['userewrite'] = '멋진 URL 사용';
@@ -141,9 +141,8 @@ $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.splitbrain.org/?do=details&amp;task_id=852">Bug 852</a>를 참고하기 바랍니다.';
-$lang['xsendfile'] = '웹 서버 static 파일 전송 지원을 위해 X-Sendfile 헤더를 사용한다면 이 옵션을 사용합니다.
-웹 서버가 이 기능을 지원해야 합니다.';
+$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__plugin'] = '%s (플러그인)';
diff --git a/lib/plugins/config/lang/lv/lang.php b/lib/plugins/config/lang/lv/lang.php
index f95697c46..50031d5e5 100644
--- a/lib/plugins/config/lang/lv/lang.php
+++ b/lib/plugins/config/lang/lv/lang.php
@@ -33,25 +33,26 @@ $lang['_template_sufix'] = 'šablona iestatījumi';
$lang['_msg_setting_undefined'] = 'Nav atrodami iestatījumu metadati';
$lang['_msg_setting_no_class'] = 'Nav iestatījumu klases';
$lang['_msg_setting_no_default'] = 'Nav noklusētās vērtības';
-$lang['fmode'] = 'Tiesības izveidotajiem failiem';
-$lang['dmode'] = 'Tiesības izveidotajām direktorijām';
-$lang['lang'] = 'Valoda';
-$lang['basedir'] = 'Saknes direktorija';
-$lang['baseurl'] = 'Saknes adrese (URL)';
-$lang['savedir'] = 'Direktorija datu glabāšanai';
-$lang['start'] = 'Sākumlapas vārds';
$lang['title'] = 'Wiki virsraksts';
+$lang['start'] = 'Sākumlapas vārds';
+$lang['lang'] = 'Valoda';
$lang['template'] = 'Šablons';
$lang['license'] = 'Ar kādu licenci saturs tiks publicēts?';
-$lang['fullpath'] = 'Norādīt kājenē pilnu lapas ceļu';
+$lang['savedir'] = 'Direktorija datu glabāšanai';
+$lang['basedir'] = 'Saknes direktorija';
+$lang['baseurl'] = 'Saknes adrese (URL)';
+$lang['dmode'] = 'Tiesības izveidotajām direktorijām';
+$lang['fmode'] = 'Tiesības izveidotajiem failiem';
+$lang['allowdebug'] = 'Ieslēgt atkļūdošanu. <b>Izslēdz!</b>';
$lang['recent'] = 'Jaunākie grozījumi';
+$lang['recent_days'] = 'Cik dienas glabāt jaunākās izmaiņas';
$lang['breadcrumbs'] = 'Apmeklējumu vēstures garums';
$lang['youarehere'] = 'Rādīt "tu atrodies šeit"';
+$lang['fullpath'] = 'Norādīt kājenē pilnu lapas ceļu';
$lang['typography'] = 'Veikt tipogrāfijas aizvietošanu';
-$lang['htmlok'] = 'Atļaut iekļautu HTTP';
-$lang['phpok'] = 'Atļaut iekļautu PHP';
$lang['dformat'] = 'Datuma formāts (sk. PHP <a href="http://www.php.net/strftime">strftime</a> funkciju)';
$lang['signature'] = 'Paraksts';
+$lang['showuseras'] = 'Kā rādīt pēdējo lietotāju, ka labojis lapu';
$lang['toptoclevel'] = 'Satura rādītāja pirmais līmenis';
$lang['tocminheads'] = 'Mazākais virsrakstu skaits, no kuriem jāveido satura rādītājs.';
$lang['maxtoclevel'] = 'Satura rādītāja dziļākais līmenis';
@@ -59,15 +60,8 @@ $lang['maxseclevel'] = 'Dziļākais sekciju labošanas līmenis';
$lang['camelcase'] = 'Lietot saitēm CamelCase';
$lang['deaccent'] = 'Lapu nosaukumu transliterācija';
$lang['useheading'] = 'Izmantot pirmo virsrakstu lapu nosaukumiem';
-$lang['refcheck'] = 'Pārbaudīt saites uz mēdiju failiem';
-$lang['refshow'] = 'Cik saites uz mēdiju failiem rādīt';
-$lang['allowdebug'] = 'Ieslēgt atkļūdošanu. <b>Izslēdz!</b>';
-$lang['usewordblock'] = 'Bloķēt spamu pēc slikto vārdu saraksta.';
-$lang['indexdelay'] = 'Laika aizture pirms indeksācijas (sekundēs)';
-$lang['relnofollow'] = 'rel="nofollow" ārējām saitēm';
-$lang['mailguard'] = 'Slēpt epasta adreses';
-$lang['iexssprotect'] = 'Pārbaudīt, vai augšupielādētajā failā nav nav potenciāli bīstamā JavaScript vai HTML koda.';
-$lang['showuseras'] = 'Kā rādīt pēdējo lietotāju, ka labojis lapu';
+$lang['sneaky_index'] = 'Pēc noklusētā DokuWiki lapu sarakstā parāda visu nodaļu lapas. Ieslēdzot šo parametru, noslēps tās nodaļas, kuras apmeklētājam nav tiesības lasīt. Bet tad tiks arī paslēptas dziļākas, bet atļautas nodaļas. Atsevišķos pieejas tiesību konfigurācijas gadījumos lapu saraksts var nedarboties.';
+$lang['hidepages'] = 'Slēpt lapas (regulāras izteiksmes)';
$lang['useacl'] = 'Izmantot piekļuves tiesības';
$lang['autopasswd'] = 'Automātiski ģenerēt paroles';
$lang['authtype'] = 'Autentifikācijas mehānisms';
@@ -76,57 +70,63 @@ $lang['defaultgroup'] = 'Noklusētā grupa';
$lang['superuser'] = 'Administrators - grupa, lietotājs vai to saraksts ( piem.: user1,@group1,user2), kam ir pilnas tiesības.';
$lang['manager'] = 'Pārziņi - grupa, lietotājs vai to saraksts ( piem.: user1,@group1,user2), kam ir pieeja pie dažām administrēšanas funkcijām.';
$lang['profileconfirm'] = 'Profila labošanai vajag paroli';
+$lang['rememberme'] = 'Atļaut pastāvīgas ielogošanās sīkdatnes ("atceries mani")';
$lang['disableactions'] = 'Bloķēt Dokuwiki darbības';
$lang['disableactions_check'] = 'atzīmēt';
$lang['disableactions_subscription'] = 'abonēt/atteikties';
$lang['disableactions_wikicode'] = 'skatīt/eksportēt izejtekstu';
$lang['disableactions_other'] = 'citas darbības (atdalīt ar komatiem)';
-$lang['sneaky_index'] = 'Pēc noklusētā DokuWiki lapu sarakstā parāda visu nodaļu lapas. Ieslēdzot šo parametru, noslēps tās nodaļas, kuras apmeklētājam nav tiesības lasīt. Bet tad tiks arī paslēptas dziļākas, bet atļautas nodaļas. Atsevišķos pieejas tiesību konfigurācijas gadījumos lapu saraksts var nedarboties.';
$lang['auth_security_timeout'] = 'Autorizācijas drošības intervāls (sekundēs)';
$lang['securecookie'] = 'Vai pa HTTPS sūtāmās sīkdatnes sūtīt tikai pa HTTPS? Atslēdz šo iespēju, kad tikai pieteikšanās wiki sistēmā notiek pa SSL šifrētu savienojumu, bet skatīšana - pa nešifrētu.';
+$lang['usewordblock'] = 'Bloķēt spamu pēc slikto vārdu saraksta.';
+$lang['relnofollow'] = 'rel="nofollow" ārējām saitēm';
+$lang['indexdelay'] = 'Laika aizture pirms indeksācijas (sekundēs)';
+$lang['mailguard'] = 'Slēpt epasta adreses';
+$lang['iexssprotect'] = 'Pārbaudīt, vai augšupielādētajā failā nav nav potenciāli bīstamā JavaScript vai HTML koda.';
+$lang['usedraft'] = 'Labojot automātiski saglabāt melnrakstu';
+$lang['htmlok'] = 'Atļaut iekļautu HTTP';
+$lang['phpok'] = 'Atļaut iekļautu PHP';
+$lang['locktime'] = 'Bloķēšanas failu maksimālais vecums';
+$lang['cachetime'] = 'Bufera maksimālais vecums (sek)';
+$lang['target____wiki'] = 'Kur atvērt iekšējās saites';
+$lang['target____interwiki'] = 'Kur atvērt saites strap wiki';
+$lang['target____extern'] = 'Kur atvērt ārējās saites';
+$lang['target____media'] = 'Kur atvērt mēdiju saites';
+$lang['target____windows'] = 'Kur atvērt saites uz tīkla mapēm';
+$lang['refcheck'] = 'Pārbaudīt saites uz mēdiju failiem';
+$lang['refshow'] = 'Cik saites uz mēdiju failiem rādīt';
+$lang['gdlib'] = 'GD Lib versija';
+$lang['im_convert'] = 'Ceļš uz ImageMagick convert rīku';
+$lang['jpg_quality'] = 'JPG saspiešanas kvalitāte';
+$lang['fetchsize'] = 'Maksimālais faila apjoms baitos, ko fetch.php var ielādēt no interneta.';
+$lang['subscribers'] = 'Atļaut abonēt izmaiņas';
+$lang['subscribe_time'] = 'Pēc cik ilga laika izsūtīt abonētos sarakstus un kopsavilkumus (sekundes); jābūt mazākam par laiku, kas norādīts "recent_days".';
+$lang['notify'] = 'Nosūtīt izmaiņu paziņojumu uz epasta adresi';
+$lang['registernotify'] = 'Nosūtīt paziņojumu par jauniem lietotājiem uz epasta adresi';
+$lang['mailfrom'] = 'Epasta adrese automātiskajiem paziņojumiem';
+$lang['mailprefix'] = 'E-pasta temata prefikss automātiskajiem paziņojumiem';
+$lang['sitemap'] = 'Lapas karte priekš Google (dienas)';
+$lang['rss_type'] = 'XML barotnes veids';
+$lang['rss_linkto'] = 'XML barotnes uz ';
+$lang['rss_content'] = 'Ko attēlot XML barotnē?';
+$lang['rss_update'] = 'XML barotnes atjaunošanas intervāls (sec)';
+$lang['rss_show_summary'] = 'Rādīt visrakstos XML barotnes kopsavilkumu ';
$lang['updatecheck'] = 'Pārbaudīt, vai pieejami atjauninājumi un drošības brīdinājumi? Dokuwiki sazināsies ar update.dokuwiki.org';
$lang['userewrite'] = 'Ērti lasāmas adreses (URL)';
$lang['useslash'] = 'Lietot slīpiņu par URL atdalītāju';
-$lang['usedraft'] = 'Labojot automātiski saglabāt melnrakstu';
$lang['sepchar'] = 'Lapas nosaukuma vārdu atdalītājs';
$lang['canonical'] = 'Lietot kanoniskus URL';
$lang['fnencode'] = 'Ne ASCII failvārdu kodēšanas metode:';
$lang['autoplural'] = 'Automātisks daudzskaitlis';
$lang['compression'] = 'Saspiešanas metode vecajiem failiem';
-$lang['cachetime'] = 'Bufera maksimālais vecums (sek)';
-$lang['locktime'] = 'Bloķēšanas failu maksimālais vecums';
-$lang['fetchsize'] = 'Maksimālais faila apjoms baitos, ko fetch.php var ielādēt no interneta.';
-$lang['notify'] = 'Nosūtīt izmaiņu paziņojumu uz epasta adresi';
-$lang['registernotify'] = 'Nosūtīt paziņojumu par jauniem lietotājiem uz epasta adresi';
-$lang['mailfrom'] = 'Epasta adrese automātiskajiem paziņojumiem';
-$lang['mailprefix'] = 'E-pasta temata prefikss automātiskajiem paziņojumiem';
$lang['gzip_output'] = 'Lietot gzip Content-Encoding priekš xhtml';
-$lang['gdlib'] = 'GD Lib versija';
-$lang['im_convert'] = 'Ceļš uz ImageMagick convert rīku';
-$lang['jpg_quality'] = 'JPG saspiešanas kvalitāte';
-$lang['subscribers'] = 'Atļaut abonēt izmaiņas';
-$lang['subscribe_time'] = 'Pēc cik ilga laika izsūtīt abonētos sarakstus un kopsavilkumus (sekundes); jābūt mazākam par laiku, kas norādīts "recent_days".';
$lang['compress'] = 'Saspiest CSS un javascript failus';
-$lang['hidepages'] = 'Slēpt lapas (regulāras izteiksmes)';
$lang['send404'] = 'Par neesošām lapām atbildēt "HTTP 404/Page Not Found" ';
-$lang['sitemap'] = 'Lapas karte priekš Google (dienas)';
$lang['broken_iua'] = 'Varbūt tavā serverī nedarbojas funkcija ignore_user_abort? Tā dēļ var nestādāt meklēšanas indeksācija. Šī problēma sastopama, piemēram, IIS ar PHP/CGI. Papildus informāciju skatīt <a href="http://bugs.splitbrain.org/?do=details&amp;task_id=852">Kļūdā Nr.852</a>.';
$lang['xsendfile'] = 'Lietot X-Sendfile virsrakstu, augšupielādējot failu serverī? ';
$lang['renderer_xhtml'] = 'Galveno (xhtml) wiki saturu renderēt ar ';
$lang['renderer__core'] = '%s (dokuwiki kodols)';
$lang['renderer__plugin'] = '%s (modulis)';
-$lang['rememberme'] = 'Atļaut pastāvīgas ielogošanās sīkdatnes ("atceries mani")';
-$lang['rss_type'] = 'XML barotnes veids';
-$lang['rss_linkto'] = 'XML barotnes uz ';
-$lang['rss_content'] = 'Ko attēlot XML barotnē?';
-$lang['rss_update'] = 'XML barotnes atjaunošanas intervāls (sec)';
-$lang['recent_days'] = 'Cik dienas glabāt jaunākās izmaiņas';
-$lang['rss_show_summary'] = 'Rādīt visrakstos XML barotnes kopsavilkumu ';
-$lang['target____wiki'] = 'Kur atvērt iekšējās saites';
-$lang['target____interwiki'] = 'Kur atvērt saites strap wiki';
-$lang['target____extern'] = 'Kur atvērt ārējās saites';
-$lang['target____media'] = 'Kur atvērt mēdiju saites';
-$lang['target____windows'] = 'Kur atvērt saites uz tīkla mapēm';
$lang['proxy____host'] = 'Proxy servera vārds';
$lang['proxy____port'] = 'Proxy ports';
$lang['proxy____user'] = 'Proxy lietotāja vārds';
diff --git a/lib/plugins/config/lang/ru/lang.php b/lib/plugins/config/lang/ru/lang.php
index 84dce4a67..36e04686d 100644
--- a/lib/plugins/config/lang/ru/lang.php
+++ b/lib/plugins/config/lang/ru/lang.php
@@ -39,6 +39,7 @@ $lang['_editing'] = 'Параметры правки';
$lang['_links'] = 'Параметры ссылок';
$lang['_media'] = 'Параметры медиафайлов';
$lang['_notifications'] = 'Параметры уведомлений';
+$lang['_syndication'] = 'Настройки синдикаций';
$lang['_advanced'] = 'Тонкая настройка';
$lang['_network'] = 'Параметры сети';
$lang['_plugin_sufix'] = 'Параметры плагина';
@@ -95,6 +96,7 @@ $lang['disableactions_other'] = 'Другие операции (через за
$lang['auth_security_timeout'] = 'Интервал для безопасности авторизации (сек.)';
$lang['securecookie'] = 'Должны ли куки (cookies), выставленные через HTTPS, отправляться браузером только через HTTPS. Отключите эту опцию в случае, когда только логин вашей вики передаётся через SSL, а обычный просмотр осуществляется в небезопасном режиме.';
$lang['remote'] = 'Включить систему API для подключений. Это позволит другим приложениям получить доступ к вики через XML-RPC или другие механизмы.';
+$lang['remoteuser'] = 'Дать права для удаленного API доступа пользователям указанным тут (разделять запятыми). Оставьте это поле пустым что бы открыть доступ всем.';
$lang['usewordblock'] = 'Блокировать спам по ключевым словам';
$lang['relnofollow'] = 'rel="nofollow" для внешних ссылок';
$lang['indexdelay'] = 'Задержка перед индексированием';
@@ -129,6 +131,7 @@ $lang['rss_linkto'] = 'Ссылки в RSS';
$lang['rss_content'] = 'Что отображать в строках XML-ленты?';
$lang['rss_update'] = 'Интервал обновления XML-ленты (сек.)';
$lang['rss_show_summary'] = 'Показывать краткую выдержку в заголовках XML-ленты';
+$lang['rss_media'] = 'Какие изменения должны быть отображены в XML?';
$lang['updatecheck'] = 'Проверять наличие обновлений и предупреждений о безопасности? Для этого «ДокуВики» потребуется связываться с сайтом <a href="http://www.splitbrain.org/">splitbrain.org</a>.';
$lang['userewrite'] = 'Удобочитаемые адреса (URL)';
$lang['useslash'] = 'Использовать слэш';
@@ -146,6 +149,7 @@ $lang['xsendfile'] = 'Используете заголовок X-Se
$lang['renderer_xhtml'] = 'Обработчик основного (xhtml) вывода вики';
$lang['renderer__core'] = '%s (ядро dokuwiki)';
$lang['renderer__plugin'] = '%s (плагин)';
+$lang['dnslookups'] = 'DokuWiki ищет DNS имена пользователей редактирующих страницы. Если у вас нет DNS сервера или он работает медленно, рекомендуем отключить эту опцию.';
$lang['proxy____host'] = 'proxy-адрес';
$lang['proxy____port'] = 'proxy-порт';
$lang['proxy____user'] = 'proxy-имя пользователя';
diff --git a/lib/plugins/config/lang/tr/lang.php b/lib/plugins/config/lang/tr/lang.php
index 6d7d7cc2e..5bc4f3fc1 100644
--- a/lib/plugins/config/lang/tr/lang.php
+++ b/lib/plugins/config/lang/tr/lang.php
@@ -6,6 +6,7 @@
* @author Cihan Kahveci <kahvecicihan@gmail.com>
* @author Yavuz Selim <yavuzselim@gmail.com>
* @author Caleb Maclennan <caleb@alerque.com>
+ * @author farukerdemoncel@gmail.com
*/
$lang['menu'] = 'Site Ayarları';
$lang['error'] = 'Ayarlar yanlış bir değer girildiği için güncellenemedi. Lütfen değişikliklerinizi gözden geçirin ve tekrar gönderin.
@@ -36,25 +37,25 @@ $lang['_template_sufix'] = 'Şablon (Template) Ayarları';
$lang['_msg_setting_undefined'] = 'Ayar üstverisi yok.';
$lang['_msg_setting_no_class'] = 'Ayar sınıfı yok.';
$lang['_msg_setting_no_default'] = 'Varsayılan değer yok.';
-$lang['fmode'] = 'Dosya oluşturma yetkisi';
-$lang['dmode'] = 'Klasör oluşturma yetkisi';
-$lang['lang'] = 'Dil';
-$lang['basedir'] = 'Kök dizin';
-$lang['baseurl'] = 'Kök URL';
-$lang['savedir'] = 'Verileri kaydetmek için kullanılacak klasör';
-$lang['start'] = 'Ana sayfa adı';
$lang['title'] = 'Wiki başlığı';
+$lang['start'] = 'Ana sayfa adı';
+$lang['lang'] = 'Dil';
$lang['template'] = 'Şablon (Template)';
$lang['license'] = 'İçeriğinizi hangi lisans altında yayınlansın?';
-$lang['fullpath'] = 'sayfaların tüm patikasını (full path) göster';
+$lang['savedir'] = 'Verileri kaydetmek için kullanılacak klasör';
+$lang['basedir'] = 'Kök dizin';
+$lang['baseurl'] = 'Kök URL';
+$lang['dmode'] = 'Klasör oluşturma yetkisi';
+$lang['fmode'] = 'Dosya oluşturma yetkisi';
+$lang['allowdebug'] = 'Yanlış ayıklamasına izin ver <b>lazım değilse etkisiz kıl!</b>';
$lang['recent'] = 'En son değiştirilenler';
$lang['breadcrumbs'] = 'Ekmek kırıntıların sayısı';
$lang['youarehere'] = 'hiyerarşik ekmek kırıntıları';
+$lang['fullpath'] = 'sayfaların tüm patikasını (full path) göster';
$lang['typography'] = 'Tipografik değiştirmeleri yap';
-$lang['htmlok'] = 'Gömülü HTML koduna izin ver';
-$lang['phpok'] = 'Gömülü PHP koduna izin ver';
$lang['dformat'] = 'Tarih biçimi (PHP\'nin <a href="http://www.php.net/strftime">strftime</a> fonksiyonuna bakın)';
$lang['signature'] = 'İmza';
+$lang['showuseras'] = 'Bir sayfayı en son düzenleyen kullanıcıya ne gösterilsin';
$lang['toptoclevel'] = 'İçindekiler için en üst seviye';
$lang['tocminheads'] = 'İçindekilerin oluşturulması için gereken (en az) başlık sayısı';
$lang['maxtoclevel'] = 'İçindekiler için en fazla seviye';
@@ -62,15 +63,6 @@ $lang['maxseclevel'] = 'Bölümün azami düzenleme düzeyi';
$lang['camelcase'] = 'Linkler için CamelCase kullan';
$lang['deaccent'] = 'Sayfa adlarınız temizle';
$lang['useheading'] = 'Sayfa isimleri için ilk başlığı kullan';
-$lang['refcheck'] = 'Araç kaynak denetimi';
-$lang['refshow'] = 'Gösterilecek araç kaynağı sayısı';
-$lang['allowdebug'] = 'Yanlış ayıklamasına izin ver <b>lazım değilse etkisiz kıl!</b>';
-$lang['usewordblock'] = 'Wordlistesine göre spam engelle';
-$lang['indexdelay'] = 'Indekslemeden evvel zaman gecikmesi (saniye)';
-$lang['relnofollow'] = 'Dışsal linkler rel="nofollow" kullan';
-$lang['mailguard'] = 'Email adreslerini karart';
-$lang['iexssprotect'] = 'Yüklenmiş dosyaları muhtemel kötu niyetli JavaScript veya HTML koduna kontrol et';
-$lang['showuseras'] = 'Bir sayfayı en son düzenleyen kullanıcıya ne gösterilsin';
$lang['useacl'] = 'Erişim kontrol listesini kullan';
$lang['autopasswd'] = 'Parolaları otamatikmen üret';
$lang['authtype'] = 'Kimlik denetleme arka uç';
@@ -79,16 +71,25 @@ $lang['defaultgroup'] = 'Varsayılan grup';
$lang['disableactions'] = 'DokuWiki eylemlerini etkisiz kıl';
$lang['disableactions_check'] = 'Kontrol et';
$lang['disableactions_subscription'] = 'Abone ol/Abonelikten vazgeç';
-$lang['canonical'] = 'Tamolarak kurallara uygun URL\'leri kullan';
-$lang['mailfrom'] = 'Otomatik e-postalar için kullanılacak e-posta adresi';
+$lang['usewordblock'] = 'Wordlistesine göre spam engelle';
+$lang['relnofollow'] = 'Dışsal linkler rel="nofollow" kullan';
+$lang['indexdelay'] = 'Indekslemeden evvel zaman gecikmesi (saniye)';
+$lang['mailguard'] = 'Email adreslerini karart';
+$lang['iexssprotect'] = 'Yüklenmiş dosyaları muhtemel kötu niyetli JavaScript veya HTML koduna kontrol et';
+$lang['htmlok'] = 'Gömülü HTML koduna izin ver';
+$lang['phpok'] = 'Gömülü PHP koduna izin ver';
+$lang['refcheck'] = 'Araç kaynak denetimi';
+$lang['refshow'] = 'Gösterilecek araç kaynağı sayısı';
$lang['gdlib'] = 'GD Lib sürümü';
$lang['jpg_quality'] = 'JPG sıkıştırma kalitesi [0-100]';
+$lang['mailfrom'] = 'Otomatik e-postalar için kullanılacak e-posta adresi';
$lang['sitemap'] = 'Google site haritası oluştur (gün)';
-$lang['renderer__core'] = '%s (dokuwiki çekirdeği)';
-$lang['renderer__plugin'] = '%s (eklenti)';
$lang['rss_content'] = 'XML beslemesinde ne gösterilsin?';
$lang['rss_update'] = 'XML beslemesini güncelleme aralığı';
$lang['rss_show_summary'] = 'XML beslemesinde özeti başlıkta göster';
+$lang['canonical'] = 'Tamolarak kurallara uygun URL\'leri kullan';
+$lang['renderer__core'] = '%s (dokuwiki çekirdeği)';
+$lang['renderer__plugin'] = '%s (eklenti)';
$lang['proxy____host'] = 'Proxy sunucu adı';
$lang['proxy____user'] = 'Proxy kullanıcı adı';
$lang['proxy____pass'] = 'Proxy şifresi';
diff --git a/lib/plugins/config/lang/zh-tw/intro.txt b/lib/plugins/config/lang/zh-tw/intro.txt
index 4cacfc43f..228c12e0a 100644
--- a/lib/plugins/config/lang/zh-tw/intro.txt
+++ b/lib/plugins/config/lang/zh-tw/intro.txt
@@ -1,7 +1,7 @@
====== 設定管理器 ======
-使用本頁控制您的 Dokuwiki 設定。每個獨立設定的相關訊息可參閱 [[doku>config]]。設定管理器的更多訊息請參閱 [[doku>plugin:config]]。
+使用本頁控制您的 Dokuwiki 設定。您可以參閱 [[doku>config]],查看每個獨立設定的相關訊息。要知道更多設定管理器的資訊,請瀏覽 [[doku>plugin:config]]。
-淡紅色背景的項目是被保護的,不能通過這個管理器更改。藍色背景的項目是系統的預設值,白色背景的項目是您更改過的。藍色和白色的設定項目都可以更改。
+淡紅色背景的項目是受到保護的,不能通過這管理器更改。藍色背景的項目是系統的預設值,白色背景的項目是您更改過的。藍色和白色的設定項目都可以更改。
-離開本頁之前不要忘記點擊最下面的 **儲存** 按鈕,否則您的修改將不會生效。 \ No newline at end of file
+離開本頁之前,不要忘記點擊最下面的 **儲存** 按鈕,否則您的修改不會生效。 \ No newline at end of file
diff --git a/lib/plugins/config/lang/zh-tw/lang.php b/lib/plugins/config/lang/zh-tw/lang.php
index 204b2b229..8f5b16220 100644
--- a/lib/plugins/config/lang/zh-tw/lang.php
+++ b/lib/plugins/config/lang/zh-tw/lang.php
@@ -10,19 +10,20 @@
* @author Danny Lin
* @author Shuo-Ting Jian <shoting@gmail.com>
* @author syaoranhinata@gmail.com
+ * @author Ichirou Uchiki <syaoranhinata@gmail.com>
*/
$lang['menu'] = '系統設定';
-$lang['error'] = '設定因為不合法的值而未更新,請檢查您的更改並重新送出。
-<br />不正確的值會被紅色方框包住。';
-$lang['updated'] = '成功地更新設定。';
+$lang['error'] = '因為含有不合規格的設定值,故未能更新設定。請檢查您的更改並重新送出。
+<br />不正確的設定值,會以紅色方框包住。';
+$lang['updated'] = '設定已更新。';
$lang['nochoice'] = '(無其他可用選項)';
$lang['locked'] = '設定檔無法更新,若非故意,請確認本地檔名及權限正確。';
-$lang['danger'] = '危險:改變此選項可能使您無法存取維基及設定選單。';
+$lang['danger'] = '危險:改變此選項,可能使您無法存取本 wiki 及設定選單。';
$lang['warning'] = '警告:改變此選項可能導致不可預期的行為。';
$lang['security'] = '安全性警告:改變此選項可能造成安全風險。';
$lang['_configuration_manager'] = '設定管理器';
$lang['_header_dokuwiki'] = 'DokuWiki 設定';
-$lang['_header_plugin'] = '插件設定';
+$lang['_header_plugin'] = '附加元件設定';
$lang['_header_template'] = '樣板設定';
$lang['_header_undefined'] = '未定義設定';
$lang['_basic'] = '基本設定';
@@ -32,17 +33,21 @@ $lang['_anti_spam'] = '反垃圾設定';
$lang['_editing'] = '編輯設定';
$lang['_links'] = '連結設定';
$lang['_media'] = '媒體設定';
+$lang['_notifications'] = '提醒設定';
+$lang['_syndication'] = '聚合設定';
$lang['_advanced'] = '進階設定';
$lang['_network'] = '網路設定';
-$lang['_plugin_sufix'] = '插件設定';
+$lang['_plugin_sufix'] = '附加元件設定';
$lang['_template_sufix'] = '樣板設定';
$lang['_msg_setting_undefined'] = '設定的後設數據不存在。';
$lang['_msg_setting_no_class'] = '設定的分類不存在。';
$lang['_msg_setting_no_default'] = '無預設值';
-$lang['title'] = '維基標題';
+$lang['title'] = '本 wiki 的標題';
$lang['start'] = '開始頁面的名稱';
$lang['lang'] = '語系';
$lang['template'] = '樣板';
+$lang['tagline'] = '副標題 (若模板支援此功能)';
+$lang['sidebar'] = '側欄的頁面名稱 (若模板支援此功能) 。若把它留空,則會停用側欄';
$lang['license'] = '您希望您的內容為何種授權方式?';
$lang['savedir'] = '儲存資料的目錄';
$lang['basedir'] = '根目錄';
@@ -67,15 +72,15 @@ $lang['maxseclevel'] = '可編輯段落的最大層級';
$lang['camelcase'] = '對連結使用 CamelCase';
$lang['deaccent'] = '清理頁面名稱';
$lang['useheading'] = '使用第一個標題作為頁面名稱';
-$lang['sneaky_index'] = '預設情況下,DokuWiki 會在索引頁會顯示所有分類空間。啟用此選項會隱藏用戶沒有閱讀權限的頁面,但也可能將能閱讀的子頁面一併隱藏。在特定 ACL 設定下,這可能導致索引無法使用。';
+$lang['sneaky_index'] = '預設情況下,DokuWiki 會在索引頁會顯示所有分類名稱。啟用此選項,會隱藏使用者沒有閱讀權限的頁面,但也可能將他可以閱讀的子頁面一併隱藏。在特定 ACL 設定下,這可能導致索引無法使用。';
$lang['hidepages'] = '隱藏匹配的界面 (正規式)';
$lang['useacl'] = '使用存取控制名單';
$lang['autopasswd'] = '自動產生密碼';
$lang['authtype'] = '認證後台管理方式';
$lang['passcrypt'] = '密碼加密方式';
$lang['defaultgroup'] = '預設群組';
-$lang['superuser'] = '超級用戶 - 不論 ACL 如何設定,都能訪問所有頁面與功能的用戶組/用戶';
-$lang['manager'] = '管理員 - 能訪問相應管理功能的用戶组/用戶';
+$lang['superuser'] = '超級使用者 —— 不論 ACL 如何設定,都能訪問所有頁面與功能的群組或使用者';
+$lang['manager'] = '管理員 —— 能訪問相應管理功能的群組或使用者';
$lang['profileconfirm'] = '修改個人資料時需要確認密碼';
$lang['rememberme'] = '允許自動登入 (記住我)';
$lang['disableactions'] = '停用的 DokuWiki 動作';
@@ -84,11 +89,13 @@ $lang['disableactions_subscription'] = '訂閱/取消訂閱';
$lang['disableactions_wikicode'] = '檢視原始碼/匯出原始檔';
$lang['disableactions_other'] = '其他功能 (逗號分隔)';
$lang['auth_security_timeout'] = '安全認證的計時 (秒)';
-$lang['securecookie'] = 'HTTPS 頁面設定的 cookie 是否只能由瀏覽器經 HTTPS 傳送?取消此選項後,只有登入維基會被 SSL 保護而瀏覽時不會。';
+$lang['securecookie'] = 'HTTPS 頁面設定的 cookie 是否只能由瀏覽器經 HTTPS 傳送?取消此選項後,只有登入本 wiki 才會受 SSL 保護,瀏覽時則不受保護。';
+$lang['remote'] = '啟用遠程 API 系统。這允許其他程式經 XML-RPC 或其他機制來訪問本 wiki 。';
+$lang['remoteuser'] = '將遠程 API 的訪問權限,限制在指定的群組或使用者中。以逗號分隔群組或使用者。留空表示允許任何人訪問。';
$lang['usewordblock'] = '根據字詞表阻擋垃圾訊息';
$lang['relnofollow'] = '外部連結使用 rel="nofollow"';
$lang['indexdelay'] = '建立索引前的延遲時間 (秒)';
-$lang['mailguard'] = '混淆 E-mail 位址';
+$lang['mailguard'] = '自動弄亂使用者的電郵地址,以作保護';
$lang['iexssprotect'] = '檢查上傳的檔案中是否隱含惡意的 JavaScript 或 HTML 碼';
$lang['usedraft'] = '編輯時自動儲存草稿';
$lang['htmlok'] = '允許嵌入式 HTML';
@@ -96,10 +103,11 @@ $lang['phpok'] = '允許嵌入式 PHP';
$lang['locktime'] = '檔案的最大鎖定時間 (秒)';
$lang['cachetime'] = '緩存的最大存在時間 (秒)';
$lang['target____wiki'] = '內部連結的目標視窗';
-$lang['target____interwiki'] = '跨維基連結的目標視窗';
+$lang['target____interwiki'] = 'Wiki間互連的目標視窗';
$lang['target____extern'] = '外部連結的目標視窗';
$lang['target____media'] = '媒體連結的目標視窗';
$lang['target____windows'] = 'Windows 連結的目標視窗';
+$lang['mediarevisions'] = '啟用媒體修訂歷史嗎?';
$lang['refcheck'] = '媒體連結檢查';
$lang['refshow'] = '媒體連結的顯示數量';
$lang['gdlib'] = 'GD Lib 版本';
@@ -108,11 +116,12 @@ $lang['jpg_quality'] = 'JPG 壓縮品質(0-100)';
$lang['fetchsize'] = 'fetch.php 可以從外部下載的最大檔案尺寸 (bytes)';
$lang['subscribers'] = '啟用頁面訂閱';
$lang['subscribe_time'] = '訂閱列表和摘要發送的時間間隔 (秒);這個值應該小於指定的最近更改保留時間 (recent_days)。';
-$lang['notify'] = '寄送變更通知信到這個 E-mail 位址';
-$lang['registernotify'] = '寄送新使用者註冊資訊到這個 E-mail 位址';
+$lang['notify'] = '寄送變更通知信到這個電郵地址';
+$lang['registernotify'] = '寄送新使用者註冊資訊到這個電郵地址';
$lang['mailfrom'] = '自動發送郵件時使用的郵件地址';
$lang['mailprefix'] = '自動發送郵件時使用的標題前綴';
-$lang['sitemap'] = '產生 Google 站台地圖 (天)';
+$lang['htmlmail'] = '發送更加美觀,但體積會更大的 HTML 多部份電郵。若停用它,表示只發送純文字電郵。';
+$lang['sitemap'] = '產生 Google 站台地圖 (以多少天計算) 。輸入0表示停用';
$lang['rss_type'] = 'XML feed 類型';
$lang['rss_linkto'] = 'XML feed 連結到';
$lang['rss_content'] = 'XML feed 項目中顯示什麼呢?';
@@ -121,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 文件名稱的編輯方法。';
@@ -129,13 +138,14 @@ $lang['autoplural'] = '檢查複數形式的連結 (英文)';
$lang['compression'] = 'attic 文件的壓縮方式';
$lang['gzip_output'] = '對 xhtml 使用 gzip 內容編碼';
$lang['compress'] = '壓縮 CSS 與 JavaScript 的輸出';
-$lang['cssdatauri'] = 'CSS 中所引用的圖片假如小於該數字大小(bytes),將會被直接嵌入 CSS 中來減少 HTTP Request 的發送。此功能在 IE 7 及之下版本不支援。推薦使用 <code>400</code> 到 <code>600</code> 之間。設定為<code>0</code> 則停用。';
+$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'] = '主要維基輸出 (xhtml) 的的渲染器';
+$lang['renderer_xhtml'] = '主要wiki輸出 (xhtml) 的渲染器';
$lang['renderer__core'] = '%s (dokuwiki 核心)';
-$lang['renderer__plugin'] = '%s (插件)';
+$lang['renderer__plugin'] = '%s (附加元件)';
+$lang['dnslookups'] = 'Dokuwiki 將查詢使用者編輯頁面的遠程 IP 位址主機名稱。若您的 DNS 服務器速度較慢、失效,或者您不想要此功能,请停用此選項';
$lang['proxy____host'] = 'Proxy 伺服器名稱';
$lang['proxy____port'] = 'Proxy 連接埠';
$lang['proxy____user'] = 'Proxy 使用者名稱';
@@ -183,10 +193,10 @@ $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'] = '使用者的 email 位址 (根據郵件監控設定混淆化)';
-$lang['showuseras_o_email_link'] = '使用者的 email 位址標示成 mailto: link';
+$lang['showuseras_o_email'] = '使用者的電郵地址 (根據郵件監控設定混淆化)';
+$lang['showuseras_o_email_link'] = '使用者的電郵地址標示成 mailto: 連結';
$lang['useheading_o_0'] = '永不';
$lang['useheading_o_navigation'] = '僅導覽';
-$lang['useheading_o_content'] = '僅維基內容';
+$lang['useheading_o_content'] = '僅本 wiki 內容';
$lang['useheading_o_1'] = '總是';
$lang['readdircache'] = 'readdir 緩存的最大存在時間 (秒)';
diff --git a/lib/plugins/config/settings/config.class.php b/lib/plugins/config/settings/config.class.php
index 8c48018d7..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 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,11 +454,9 @@ if (!class_exists('setting')) {
$out = '';
if ($fmt=='php') {
- // translation string needs to be improved FIXME
- $tr = array("\n"=>'\n', "\r"=>'\r', "\t"=>'\t', "\\" => '\\\\', "'" => '\\\'');
$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;
@@ -467,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) {
@@ -533,12 +664,13 @@ 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
* if value fails error check, save it
*
- * @return true if changed, false otherwise (incl. on error)
+ * @return boolean true if changed, false otherwise (incl. on error)
*/
function update($input) {
if (is_null($input)) return false;
@@ -546,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;
@@ -567,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 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 3607f56c6..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','bcrypt'));
+$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/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 9aedbf0aa..97b28076b 100644
--- a/lib/plugins/info/syntax.php
+++ b/lib/plugins/info/syntax.php
@@ -16,20 +16,6 @@ if(!defined('DOKU_INC')) die();
class syntax_plugin_info extends DokuWiki_Syntax_Plugin {
/**
- * return some info
- */
- function getInfo(){
- return array(
- 'author' => 'Andreas Gohr',
- 'email' => 'andi@splitbrain.org',
- 'date' => '2008-09-12',
- 'name' => 'Info Plugin',
- 'desc' => 'Displays information about various DokuWiki internals',
- 'url' => 'http://dokuwiki.org/plugin:info',
- );
- }
-
- /**
* What kind of syntax are we?
*/
function getType(){
@@ -74,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;
@@ -114,7 +97,7 @@ class syntax_plugin_info extends DokuWiki_Syntax_Plugin {
*
* uses some of the original renderer methods
*/
- function _plugins_xhtml($type, &$renderer){
+ function _plugins_xhtml($type, Doku_Renderer &$renderer){
global $lang;
$renderer->doc .= '<ul>';
@@ -152,7 +135,7 @@ class syntax_plugin_info extends DokuWiki_Syntax_Plugin {
*
* uses some of the original renderer methods
*/
- function _helpermethods_xhtml(&$renderer){
+ function _helpermethods_xhtml(Doku_Renderer &$renderer){
global $lang;
$plugins = plugin_list('helper');
@@ -237,7 +220,7 @@ class syntax_plugin_info extends DokuWiki_Syntax_Plugin {
/**
* Adds a TOC item
*/
- function _addToTOC($text, $level, &$renderer){
+ function _addToTOC($text, $level, Doku_Renderer_xhtml &$renderer){
global $conf;
if (($level >= $conf['toptoclevel']) && ($level <= $conf['maxtoclevel'])){
diff --git a/lib/plugins/plugin/admin.php b/lib/plugins/plugin/admin.php
index b2108f185..de4de6aef 100644
--- a/lib/plugins/plugin/admin.php
+++ b/lib/plugins/plugin/admin.php
@@ -33,6 +33,10 @@ class admin_plugin_plugin extends DokuWiki_Admin_Plugin {
var $disabled = 0;
var $plugin = '';
var $cmd = '';
+
+ /**
+ * @var ap_manage
+ */
var $handler = NULL;
var $functions = array('delete','update',/*'settings',*/'info'); // require a plugin name
@@ -43,28 +47,10 @@ class admin_plugin_plugin extends DokuWiki_Admin_Plugin {
var $error = '';
function admin_plugin_plugin() {
- global $conf;
$this->disabled = plugin_isdisabled('plugin');
}
/**
- * return some info
- */
- function getInfo(){
- $disabled = ($this->disabled) ? '(disabled)' : '';
-
- return array(
- 'author' => 'Christopher Smith',
- 'email' => 'chris@jalakai.co.uk',
- 'date' => '2009-11-11',
- 'name' => 'Plugin Manager',
- 'desc' => "Manage Plugins, including automated plugin installer $disabled",
- 'url' => 'http://www.dokuwiki.org/plugin:plugin',
- );
- }
-
-
- /**
* return sort order for position in admin menu
*/
function getMenuSort() {
@@ -75,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/classes/ap_download.class.php b/lib/plugins/plugin/classes/ap_download.class.php
index d1b518d9d..3cc455867 100644
--- a/lib/plugins/plugin/classes/ap_download.class.php
+++ b/lib/plugins/plugin/classes/ap_download.class.php
@@ -7,7 +7,6 @@ class ap_download extends ap_manage {
* Initiate the plugin download
*/
function process() {
- global $lang;
global $INPUT;
$plugin_url = $INPUT->str('url');
@@ -45,7 +44,6 @@ class ap_download extends ap_manage {
* Process the downloaded file
*/
function download($url, $overwrite=false) {
- global $lang;
// check the url
$matches = array();
if (!preg_match("/[^\/]*$/", $url, $matches) || !$matches[0]) {
@@ -200,31 +198,26 @@ class ap_download extends ap_manage {
if (in_array($ext, array('tar','bz','gz'))) {
switch($ext){
case 'bz':
- $compress_type = TarLib::COMPRESS_BZIP;
+ $compress_type = Tar::COMPRESS_BZIP;
break;
case 'gz':
- $compress_type = TarLib::COMPRESS_GZIP;
+ $compress_type = Tar::COMPRESS_GZIP;
break;
default:
- $compress_type = TarLib::COMPRESS_NONE;
+ $compress_type = Tar::COMPRESS_NONE;
}
- $tar = new TarLib($file, $compress_type);
- if($tar->_initerror < 0){
+ $tar = new Tar();
+ try {
+ $tar->open($file, $compress_type);
+ $tar->extract($target);
+ return true;
+ }catch(Exception $e){
if($conf['allowdebug']){
- msg('TarLib Error: '.$tar->TarErrorStr($tar->_initerror),-1);
+ msg('Tar Error: '.$e->getMessage().' ['.$e->getFile().':'.$e->getLine().']',-1);
}
return false;
}
- $ok = $tar->Extract(TarLib::FULL_ARCHIVE, $target, '', 0777);
-
- if($ok<1){
- if($conf['allowdebug']){
- msg('TarLib Error: '.$tar->TarErrorStr($ok),-1);
- }
- return false;
- }
- return true;
} else if ($ext == 'zip') {
$zip = new ZipLib();
@@ -246,7 +239,7 @@ class ap_download extends ap_manage {
* if neither bz, gz or zip are recognized, tar is assumed.
*
* @author Andreas Gohr <andi@splitbrain.org>
- * @returns false if the file can't be read, otherwise an "extension"
+ * @returns boolean|string false if the file can't be read, otherwise an "extension"
*/
function guess_archive($file){
$fh = fopen($file,'rb');
diff --git a/lib/plugins/plugin/classes/ap_manage.class.php b/lib/plugins/plugin/classes/ap_manage.class.php
index 28579cbe9..3ec740dae 100644
--- a/lib/plugins/plugin/classes/ap_manage.class.php
+++ b/lib/plugins/plugin/classes/ap_manage.class.php
@@ -69,7 +69,6 @@ class ap_manage {
}
function html_pluginlist() {
- global $ID;
global $plugin_protected;
foreach ($this->manager->plugin_list as $plugin) {
@@ -195,11 +194,8 @@ class ap_manage {
closedir($dh);
return @rmdir($path);
- } else {
- return @unlink($path);
}
-
- return false;
+ return @unlink($path);
}
diff --git a/lib/plugins/plugin/classes/ap_update.class.php b/lib/plugins/plugin/classes/ap_update.class.php
index c43429a1b..5d7f6cb08 100644
--- a/lib/plugins/plugin/classes/ap_update.class.php
+++ b/lib/plugins/plugin/classes/ap_update.class.php
@@ -5,8 +5,6 @@ class ap_update extends ap_download {
var $overwrite = true;
function process() {
- global $lang;
-
$plugin_url = $this->plugin_readlog($this->plugin, 'url');
$this->download($plugin_url, $this->overwrite);
return '';
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/ca/lang.php b/lib/plugins/plugin/lang/ca/lang.php
index 0e3ef05df..5c7933666 100644
--- a/lib/plugins/plugin/lang/ca/lang.php
+++ b/lib/plugins/plugin/lang/ca/lang.php
@@ -6,6 +6,7 @@
* @author carles.bellver@gmail.com
* @author carles.bellver@cent.uji.es
* @author Carles Bellver <carles.bellver@cent.uji.es>
+ * @author daniel@6temes.cat
*/
$lang['menu'] = 'Gestió de connectors';
$lang['download'] = 'Baixa i instal·la un nou connector';
@@ -51,3 +52,4 @@ $lang['enabled'] = 'S\'ha habilitat el connector %s.';
$lang['notenabled'] = 'No s\'ha pogut habilitar el connector %s. Comproveu els permisos dels fitxers.';
$lang['disabled'] = 'S\'ha inhabilitat el connector %s.';
$lang['notdisabled'] = 'No s\'ha pogut inhabilitar el connector %s. Comproveu els permisos dels fitxers.';
+$lang['packageinstalled'] = 'El paquet del connector (%d plugins(s): %s) s\'ha instal·lat correctament.';
diff --git a/lib/plugins/plugin/lang/cs/lang.php b/lib/plugins/plugin/lang/cs/lang.php
index 1fd360dca..20a015cd4 100644
--- a/lib/plugins/plugin/lang/cs/lang.php
+++ b/lib/plugins/plugin/lang/cs/lang.php
@@ -12,6 +12,7 @@
* @author Vojta Beran <xmamut@email.cz>
* @author zbynek.krivka@seznam.cz
* @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com>
+ * @author Jakub A. Těšínský (j@kub.cz)
*/
$lang['menu'] = 'Správa pluginů';
$lang['download'] = 'Stáhnout a instalovat plugin';
diff --git a/lib/plugins/plugin/lang/de/lang.php b/lib/plugins/plugin/lang/de/lang.php
index 8708d7836..9f26a2933 100644
--- a/lib/plugins/plugin/lang/de/lang.php
+++ b/lib/plugins/plugin/lang/de/lang.php
@@ -53,7 +53,7 @@ $lang['desc'] = 'Beschreibung:';
$lang['author'] = 'Entwickler:';
$lang['www'] = 'Web:';
$lang['error'] = 'Ein unbekannter Fehler ist aufgetreten.';
-$lang['error_download'] = 'Konnte das Plugin %s nicht installieren';
+$lang['error_download'] = 'Konnte das Plugin %s nicht herunterladen';
$lang['error_badurl'] = 'Wahrscheinlich ungültige URL, konnte keinen Dateinamen ausfindig machen';
$lang['error_dircreate'] = 'Konnte keinen temporären Ordner für die Downloads erstellen';
$lang['error_decompress'] = 'Der Plugin Manager konnte das Plugin-Archiv nicht entpacken. Entweder ist der Download fehlerhaft oder das Komprimierungsverfahren wird nicht unterstützt. Bitte versuchen Sie es erneut oder downloaden und installieren Sie das Plugin manuell.';
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/es/lang.php b/lib/plugins/plugin/lang/es/lang.php
index db91b73c6..ded7d7369 100644
--- a/lib/plugins/plugin/lang/es/lang.php
+++ b/lib/plugins/plugin/lang/es/lang.php
@@ -23,6 +23,7 @@
* @author Oscar Ciudad <oscar@jacho.net>
* @author Ruben Figols <ruben.figols@gmail.com>
* @author Gerardo Zamudio <gerardo@gerardozamudio.net>
+ * @author Mercè López mercelz@gmail.com
*/
$lang['menu'] = 'Administración de Plugins';
$lang['download'] = 'Descargar e instalar un nuevo plugin';
@@ -66,6 +67,6 @@ $lang['error_copy'] = 'Hubo un error al copiar el fichero mientras se
$lang['error_delete'] = 'Hubo un error al intentar eliminar el plugin <em>%s</em>. La causa más probable es que no se cuente con los permisos necesarios en el fichero o en el directorio';
$lang['enabled'] = 'Plugin %s habilitado.';
$lang['notenabled'] = 'Plugin %s no puede ser habilitado, verifica los permisos del archivo.';
-$lang['disabled'] = 'Plugin %s desabilitado.';
-$lang['notdisabled'] = 'Plugin %s no puede ser desabilitado, verifica los permisos de archivo.';
+$lang['disabled'] = 'Plugin %s deshabilitado.';
+$lang['notdisabled'] = 'Plugin %s no puede ser deshabilitado, verifica los permisos de archivo.';
$lang['packageinstalled'] = 'Plugin (%d plugin(s): %s) instalado exitosamente.';
diff --git a/lib/plugins/plugin/lang/fa/lang.php b/lib/plugins/plugin/lang/fa/lang.php
index dbfe9ef9a..bc43ee3ef 100644
--- a/lib/plugins/plugin/lang/fa/lang.php
+++ b/lib/plugins/plugin/lang/fa/lang.php
@@ -8,6 +8,7 @@
* @author Omid Mottaghi <omidmr@gmail.com>
* @author Mohammad Reza Shoaei <shoaei@gmail.com>
* @author Milad DZand <M.DastanZand@gmail.com>
+ * @author AmirH Hassaneini <mytechmix@gmail.com>
*/
$lang['menu'] = 'مدیریت افزونه‌ها';
$lang['download'] = 'دریافت و نصب افزونه';
diff --git a/lib/plugins/plugin/lang/fr/admin_plugin.txt b/lib/plugins/plugin/lang/fr/admin_plugin.txt
index f90b627f3..b7beba25a 100644
--- a/lib/plugins/plugin/lang/fr/admin_plugin.txt
+++ b/lib/plugins/plugin/lang/fr/admin_plugin.txt
@@ -1,4 +1,4 @@
-====== Gestion des modules externes ======
+====== Gestion des extensions ======
-Cette page vous permet de gérer tout ce qui a trait aux [[doku>fr:plugins|modules externes]] de DokuWiki. Pour télécharger et installer un module, le répertoire « ''plugin'' » doit être accessible en écriture pour le serveur Web.
+Cette page vous permet de gérer tout ce qui a trait aux [[doku>fr:plugins|extensions]] de DokuWiki. Pour pouvoir télécharger et installer un module, le répertoire « ''plugin'' » doit être accessible en écriture pour le serveur web.
diff --git a/lib/plugins/plugin/lang/fr/lang.php b/lib/plugins/plugin/lang/fr/lang.php
index 31d524cc6..06cd1ab8d 100644
--- a/lib/plugins/plugin/lang/fr/lang.php
+++ b/lib/plugins/plugin/lang/fr/lang.php
@@ -19,10 +19,11 @@
* @author skimpax@gmail.com
* @author Yannick Aure <yannick.aure@gmail.com>
* @author Olivier DUVAL <zorky00@gmail.com>
+ * @author Anael Mobilia <contrib@anael.eu>
*/
-$lang['menu'] = 'Gestion des modules externes';
-$lang['download'] = 'Télécharger et installer un nouveau module';
-$lang['manage'] = 'Modules installés';
+$lang['menu'] = 'Gestion des extensions';
+$lang['download'] = 'Télécharger et installer une nouvelle extension';
+$lang['manage'] = 'Extensions installées';
$lang['btn_info'] = 'Info';
$lang['btn_update'] = 'Mettre à jour';
$lang['btn_delete'] = 'Supprimer';
@@ -35,18 +36,18 @@ $lang['lastupdate'] = 'Dernière mise à jour :';
$lang['source'] = 'Source :';
$lang['unknown'] = 'inconnu';
$lang['updating'] = 'Mise à jour…';
-$lang['updated'] = 'Modules %s mis à jour avec succès';
-$lang['updates'] = 'Les modules suivants ont été mis à jour avec succès';
+$lang['updated'] = 'Extension %s mise à jour avec succès';
+$lang['updates'] = 'Les extensions suivantes ont été mises à jour avec succès';
$lang['update_none'] = 'Aucune mise à jour n\'a été trouvée.';
$lang['deleting'] = 'Suppression…';
-$lang['deleted'] = 'Module %s supprimé.';
+$lang['deleted'] = 'Extension %s supprimée.';
$lang['downloading'] = 'Téléchargement…';
-$lang['downloaded'] = 'Module %s installé avec succès';
-$lang['downloads'] = 'Les modules suivants ont été installés avec succès :';
-$lang['download_none'] = 'Aucun module n\'était trouvé, ou un problème inconnu est survenu durant le téléchargement et l\'installation.';
-$lang['plugin'] = 'Module :';
+$lang['downloaded'] = 'Extension %s installée avec succès';
+$lang['downloads'] = 'Les extensions suivantes ont été installées avec succès :';
+$lang['download_none'] = 'Aucune extension n\'a été trouvée, ou un problème inconnu est survenu durant le téléchargement et l\'installation.';
+$lang['plugin'] = 'Extension :';
$lang['components'] = 'Composants';
-$lang['noinfo'] = 'Ce module externe n\'a transmis aucune information, il pourrait être invalide.';
+$lang['noinfo'] = 'Cette extension n\'a transmis aucune information, elle pourrait être invalide.';
$lang['name'] = 'Nom :';
$lang['date'] = 'Date :';
$lang['type'] = 'Type :';
@@ -54,14 +55,14 @@ $lang['desc'] = 'Description :';
$lang['author'] = 'Auteur :';
$lang['www'] = 'Site web :';
$lang['error'] = 'Une erreur inconnue est survenue.';
-$lang['error_download'] = 'Impossible de télécharger le fichier du module : %s';
-$lang['error_badurl'] = 'URL suspecte. Impossible de déterminer le nom du fichier à partir de l\'URL';
-$lang['error_dircreate'] = 'Impossible de créer le répertoire temporaire pour réceptionner le téléchargement';
-$lang['error_decompress'] = 'Le gestionnaire de modules externes a été incapable de décompresser le fichier téléchargé. Ceci peut être le résultat d\'un mauvais téléchargement, auquel cas vous devriez réessayer ; ou bien le format de compression est inconnu, auquel cas vous devez télécharger et installer le module manuellement.';
-$lang['error_copy'] = 'Une erreur de copie est survenue lors de l\'installation des fichiers du module <em>%s</em> : votre disque est peut-être plein ou les droits d\'accès au fichier sont incorrects. Il a pu en résulter une installation partielle du module rendant votre installation du wiki instable.';
-$lang['error_delete'] = 'Une erreur est survenue à la suppression du module <em>%s</em>. La raison la plus probable est l\'insuffisance des droits sur les fichiers ou le répertoire.';
-$lang['enabled'] = 'Module %s activé.';
-$lang['notenabled'] = 'Le module %s n\'a pas pu être activé, vérifiez le fichier des permissions.';
-$lang['disabled'] = 'Module %s désactivé.';
-$lang['notdisabled'] = 'Le module %s n\'a pas pu être désactivé, vérifiez le fichier des permissions.';
-$lang['packageinstalled'] = 'Ensemble de modules (%d module(s): %s) installé avec succès.';
+$lang['error_download'] = 'Impossible de télécharger le fichier de l\'extension : %s';
+$lang['error_badurl'] = 'URL suspecte : impossible de déterminer le nom du fichier à partir de l\'URL';
+$lang['error_dircreate'] = 'Impossible de créer le répertoire temporaire pour effectuer le téléchargement';
+$lang['error_decompress'] = 'Le gestionnaire d\'extensions a été incapable de décompresser le fichier téléchargé. Ceci peut être le résultat d\'un mauvais téléchargement, auquel cas vous devriez réessayer ; ou bien le format de compression est inconnu, auquel cas vous devez télécharger et installer l\'extension manuellement.';
+$lang['error_copy'] = 'Une erreur de copie est survenue lors de l\'installation des fichiers de l\'extension <em>%s</em> : le disque est peut-être plein ou les autorisations d\'accès sont incorrects. Il a pu en résulter une installation partielle de l\'extension et laisser votre installation du wiki instable.';
+$lang['error_delete'] = 'Une erreur est survenue lors de la suppression de l\'extension <em>%s</em>. La raison la plus probable est l\'insuffisance des autorisations sur les fichiers ou les répertoires.';
+$lang['enabled'] = 'Extension %s activée.';
+$lang['notenabled'] = 'L\'extension %s n\'a pas pu être activée, vérifiez les autorisations des fichiers.';
+$lang['disabled'] = 'Extension %s désactivée.';
+$lang['notdisabled'] = 'L\'extension %s n\'a pas pu être désactivée, vérifiez les autorisations des fichiers.';
+$lang['packageinstalled'] = 'Ensemble d\'extensions (%d extension(s): %s) installé avec succès.';
diff --git a/lib/plugins/plugin/lang/gl/lang.php b/lib/plugins/plugin/lang/gl/lang.php
index a314b71b9..b3da44096 100644
--- a/lib/plugins/plugin/lang/gl/lang.php
+++ b/lib/plugins/plugin/lang/gl/lang.php
@@ -4,6 +4,7 @@
*
* @author Medúlio <medulio@ciberirmandade.org>
* @author Oscar M. Lage <r0sk10@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/lv/lang.php b/lib/plugins/plugin/lang/lv/lang.php
index 0f6103899..9a8727875 100644
--- a/lib/plugins/plugin/lang/lv/lang.php
+++ b/lib/plugins/plugin/lang/lv/lang.php
@@ -48,3 +48,4 @@ $lang['enabled'] = 'Modulis %s pieslēgts.';
$lang['notenabled'] = 'Moduli %s nevar pieslēgt, pārbaudi failu tiesības.';
$lang['disabled'] = 'Modulis %s atslēgts.';
$lang['notdisabled'] = 'Moduli %s nevar atslēgt, pārbaudi failu tiesības.';
+$lang['packageinstalled'] = 'Moduļu paka (pavisam kopā %d: %s) veiksmīgi uzstādīti.';
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/tr/lang.php b/lib/plugins/plugin/lang/tr/lang.php
index 9a655e400..9598ade7d 100644
--- a/lib/plugins/plugin/lang/tr/lang.php
+++ b/lib/plugins/plugin/lang/tr/lang.php
@@ -6,6 +6,7 @@
* @author Cihan Kahveci <kahvecicihan@gmail.com>
* @author Yavuz Selim <yavuzselim@gmail.com>
* @author Caleb Maclennan <caleb@alerque.com>
+ * @author farukerdemoncel@gmail.com
*/
$lang['menu'] = 'Eklenti Yönetimi';
$lang['download'] = 'Yeni bir eklenti indirip kur';
diff --git a/lib/plugins/plugin/lang/zh-tw/admin_plugin.txt b/lib/plugins/plugin/lang/zh-tw/admin_plugin.txt
index 84d095f51..54fe7a59e 100644
--- a/lib/plugins/plugin/lang/zh-tw/admin_plugin.txt
+++ b/lib/plugins/plugin/lang/zh-tw/admin_plugin.txt
@@ -1,3 +1,3 @@
-====== 插件管理器 ======
+====== 附加元件管理器 ======
-您可以用本頁管理與 Dokuwiki [[doku>plugins|插件]] 相關的選項。若要正常下載及安裝插件,插件所在的資料夾必須允許網頁伺服器寫入。
+您可以用本頁管理與 Dokuwiki [[doku>plugins|附加元件]] 相關的選項。若要正常下載及安裝附加元件,附加元件所在的資料夾必須允許網頁伺服器寫入。 \ No newline at end of file
diff --git a/lib/plugins/plugin/lang/zh-tw/lang.php b/lib/plugins/plugin/lang/zh-tw/lang.php
index 8fa3efb0a..56149e79e 100644
--- a/lib/plugins/plugin/lang/zh-tw/lang.php
+++ b/lib/plugins/plugin/lang/zh-tw/lang.php
@@ -10,10 +10,11 @@
* @author Danny Lin
* @author Shuo-Ting Jian <shoting@gmail.com>
* @author syaoranhinata@gmail.com
+ * @author Ichirou Uchiki <syaoranhinata@gmail.com>
*/
-$lang['menu'] = '管理插件 (Plugins)';
-$lang['download'] = '下載與安裝插件';
-$lang['manage'] = '已安裝的插件';
+$lang['menu'] = '管理附加元件';
+$lang['download'] = '下載與安裝附加元件';
+$lang['manage'] = '已安裝的附加元件';
$lang['btn_info'] = '資訊';
$lang['btn_update'] = '更新';
$lang['btn_delete'] = '刪除';
@@ -25,34 +26,34 @@ $lang['installed'] = '安裝:';
$lang['lastupdate'] = '上次更新:';
$lang['source'] = '來源:';
$lang['unknown'] = '未知';
-$lang['updating'] = '更新中 ...';
-$lang['updated'] = '插件 %s 成功地更新';
-$lang['updates'] = '以下的插件已經成功地更新';
-$lang['update_none'] = '找不到更新';
-$lang['deleting'] = '刪除中 ...';
-$lang['deleted'] = '插件 %s 已刪除。';
-$lang['downloading'] = '下載中 ...';
-$lang['downloaded'] = '插件 %s 已成功地安裝';
-$lang['downloads'] = '以下的插件已成功地安裝:';
-$lang['download_none'] = '找不到插件,或在下載與安裝時發生了未知的問題';
-$lang['plugin'] = '插件:';
+$lang['updating'] = '更新中……';
+$lang['updated'] = '已更新附加元件 %s ';
+$lang['updates'] = '已更新下列附加元件';
+$lang['update_none'] = '找不到更新。';
+$lang['deleting'] = '刪除中……';
+$lang['deleted'] = '已刪除附加元件 %s 。';
+$lang['downloading'] = '下載中……';
+$lang['downloaded'] = '已安裝附加元件 %s ';
+$lang['downloads'] = '已安裝下列附加元件:';
+$lang['download_none'] = '找不到附加元件,或者在下載與安裝時發生了未知的問題。';
+$lang['plugin'] = '附加元件:';
$lang['components'] = '元件';
-$lang['noinfo'] = '此插件沒有回傳任何資訊,可能是無效的';
+$lang['noinfo'] = '此附加元件沒有回傳任何資訊,它可能已失效。';
$lang['name'] = '名稱:';
$lang['date'] = '日期:';
$lang['type'] = '類型:';
$lang['desc'] = '描述:';
$lang['author'] = '作者:';
-$lang['www'] = '網頁:';
-$lang['error'] = '一個未知的錯誤發生。';
-$lang['error_download'] = '無法下載插件檔案: %s';
-$lang['error_badurl'] = 'URL 可能有問題 - 從 URL 中無法得知文件名';
+$lang['www'] = '網頁:';
+$lang['error'] = '發生了未知的錯誤。';
+$lang['error_download'] = '無法下載附加元件檔案: %s';
+$lang['error_badurl'] = 'URL 可能有問題 —— 從 URL 中無法得知文件名';
$lang['error_dircreate'] = '無法建立暫存目錄來接收下載的內容';
-$lang['error_decompress'] = '插件管理器無法解壓下載的文件。這可能是由於下載出現錯誤,遇到這種情況,請您再次嘗試;或者是壓縮格式無法識別,遇到這種情況,您需要手動下載並安裝該插件。';
-$lang['error_copy'] = '嘗試安裝插件 <em>%s</em> 的相關文件時發生複製錯誤:可能是磁碟空間不足或檔案存取權限錯誤。這可能是由於未安裝完全的插件使維基系統不穩定導致。';
-$lang['error_delete'] = '嘗試刪除插件 <em>%s</em> 時發生錯誤。最可能原因是檔案或目錄存取權限不足';
-$lang['enabled'] = '插件 %s 已啟用。';
-$lang['notenabled'] = '插件 %s 無法啟用,請檢查檔案權限。';
-$lang['disabled'] = '插件 %s 已停用。';
-$lang['notdisabled'] = '插件 %s 無法停用,請檢查檔案權限。';
-$lang['packageinstalled'] = '插件 (%d 插件%s: %s) 已成功地安裝。';
+$lang['error_decompress'] = '附加元件管理器無法把下載的文件解壓,這可能是由於下載出現錯誤。遇到這種情況,請您再次嘗試。此外,無法識別壓縮格式也可能導致無法解壓。若是如此,您需要手動下載並安裝該附加元件。';
+$lang['error_copy'] = '嘗試安裝附加元件 <em>%s</em> 的相關文件時,發生複製錯誤。這可能是磁碟空間不足,或檔案存取權限錯誤。未安裝好的附加元件,也許會令wiki系統不穩定。';
+$lang['error_delete'] = '嘗試刪除附加元件 <em>%s</em> 時發生錯誤。最有可能原因是檔案或目錄存取權限不足';
+$lang['enabled'] = '附加元件 %s 已啟用。';
+$lang['notenabled'] = '附加元件 %s 無法啟用,請檢查檔案權限。';
+$lang['disabled'] = '附加元件 %s 已停用。';
+$lang['notdisabled'] = '附加元件 %s 無法停用,請檢查檔案權限。';
+$lang['packageinstalled'] = '附加元件 (%d 附加元件: %s) 已安裝好。';
diff --git a/lib/plugins/popularity/action.php b/lib/plugins/popularity/action.php
index bf11efba6..f0cbb771b 100644
--- a/lib/plugins/popularity/action.php
+++ b/lib/plugins/popularity/action.php
@@ -9,6 +9,10 @@ require_once(DOKU_PLUGIN.'action.php');
require_once(DOKU_PLUGIN.'popularity/admin.php');
class action_plugin_popularity extends Dokuwiki_Action_Plugin {
+
+ /**
+ * @var helper_plugin_popularity
+ */
var $helper;
function action_plugin_popularity(){
@@ -18,11 +22,11 @@ class action_plugin_popularity extends Dokuwiki_Action_Plugin {
/**
* Register its handlers with the dokuwiki's event controller
*/
- function register(&$controller) {
+ function register(Doku_Event_Handler $controller) {
$controller->register_hook('INDEXER_TASKS_RUN', 'AFTER', $this, '_autosubmit', array());
}
- function _autosubmit(&$event, $param){
+ function _autosubmit(Doku_Event &$event, $param){
//Do we have to send the data now
if ( !$this->helper->isAutosubmitEnabled() || $this->_isTooEarlyToSubmit() ){
return;
diff --git a/lib/plugins/popularity/admin.php b/lib/plugins/popularity/admin.php
index 474a09ef9..deb8048f4 100644
--- a/lib/plugins/popularity/admin.php
+++ b/lib/plugins/popularity/admin.php
@@ -14,6 +14,10 @@ if(!defined('DOKU_INC')) die();
*/
class admin_plugin_popularity extends DokuWiki_Admin_Plugin {
var $version;
+
+ /**
+ * @var helper_plugin_popularity
+ */
var $helper;
var $sentStatus = null;
@@ -118,9 +122,9 @@ class admin_plugin_popularity extends DokuWiki_Admin_Plugin {
/**
* Build the form which presents the data to be sent
- * @param string $submit How is the data supposed to be sent? (may be: 'browser' or 'server')
+ * @param string $submissionMode How is the data supposed to be sent? (may be: 'browser' or 'server')
* @param string $data The popularity data, if it has already been computed. NULL otherwise.
- * @return The form, as an html string
+ * @return string The form, as an html string
*/
function buildForm($submissionMode, $data = null){
$url = ($submissionMode === 'browser' ? $this->helper->submitUrl : script());
diff --git a/lib/plugins/popularity/helper.php b/lib/plugins/popularity/helper.php
index 34521021d..5bbeddba0 100644
--- a/lib/plugins/popularity/helper.php
+++ b/lib/plugins/popularity/helper.php
@@ -29,6 +29,8 @@ class helper_plugin_popularity extends Dokuwiki_Plugin {
*/
var $popularityLastSubmitFile;
+ var $version;
+
function helper_plugin_popularity(){
global $conf;
@@ -69,7 +71,7 @@ class helper_plugin_popularity extends Dokuwiki_Plugin {
/**
* Check if autosubmit is enabled
- * @return TRUE if we should send data once a month, FALSE otherwise
+ * @return boolean TRUE if we should send data once a month, FALSE otherwise
*/
function isAutoSubmitEnabled(){
return @file_exists($this->autosubmitFile);
@@ -78,7 +80,7 @@ class helper_plugin_popularity extends Dokuwiki_Plugin {
/**
* Send the data, to the submit url
* @param string $data The popularity data
- * @return An empty string if everything worked fine, a string describing the error otherwise
+ * @return string An empty string if everything worked fine, a string describing the error otherwise
*/
function sendData($data){
$error = '';
@@ -102,7 +104,7 @@ class helper_plugin_popularity extends Dokuwiki_Plugin {
/**
* Gather all information
- * @return The popularity data as a string
+ * @return string The popularity data as a string
*/
function gatherAsString(){
$data = $this->_gather();
@@ -119,7 +121,7 @@ class helper_plugin_popularity extends Dokuwiki_Plugin {
/**
* Gather all information
- * @return The popularity data as an array
+ * @return array The popularity data as an array
*/
function _gather(){
global $conf;
diff --git a/lib/plugins/popularity/lang/ca/lang.php b/lib/plugins/popularity/lang/ca/lang.php
index e6fdcd533..b30846118 100644
--- a/lib/plugins/popularity/lang/ca/lang.php
+++ b/lib/plugins/popularity/lang/ca/lang.php
@@ -5,6 +5,7 @@
* @author Carles Bellver <carles.bellver@cent.uji.es>
* @author Carles Bellver <carles.bellver@gmail.com>
* @author carles.bellver@cent.uji.es
+ * @author daniel@6temes.cat
*/
$lang['name'] = 'Retroacció sobre popularitat (pot trigar una mica a carregar)';
$lang['submit'] = 'Envia dades';
diff --git a/lib/plugins/popularity/lang/cs/lang.php b/lib/plugins/popularity/lang/cs/lang.php
index d7c58af2e..0b0dbae7f 100644
--- a/lib/plugins/popularity/lang/cs/lang.php
+++ b/lib/plugins/popularity/lang/cs/lang.php
@@ -9,6 +9,7 @@
* @author Vojta Beran <xmamut@email.cz>
* @author zbynek.krivka@seznam.cz
* @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com>
+ * @author Jakub A. Těšínský (j@kub.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/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/es/lang.php b/lib/plugins/popularity/lang/es/lang.php
index 2be2d4a04..e46735782 100644
--- a/lib/plugins/popularity/lang/es/lang.php
+++ b/lib/plugins/popularity/lang/es/lang.php
@@ -20,6 +20,7 @@
* @author Oscar Ciudad <oscar@jacho.net>
* @author Ruben Figols <ruben.figols@gmail.com>
* @author Gerardo Zamudio <gerardo@gerardozamudio.net>
+ * @author Mercè López mercelz@gmail.com
*/
$lang['name'] = 'Retroinformación (Feedback) plugin Popularity';
$lang['submit'] = 'Enviar datos';
diff --git a/lib/plugins/popularity/lang/fa/lang.php b/lib/plugins/popularity/lang/fa/lang.php
index 600e68077..6a0529891 100644
--- a/lib/plugins/popularity/lang/fa/lang.php
+++ b/lib/plugins/popularity/lang/fa/lang.php
@@ -8,6 +8,7 @@
* @author Omid Mottaghi <omidmr@gmail.com>
* @author Mohammad Reza Shoaei <shoaei@gmail.com>
* @author Milad DZand <M.DastanZand@gmail.com>
+ * @author AmirH Hassaneini <mytechmix@gmail.com>
*/
$lang['name'] = 'بازخورد محبوبیت (ممکن است اندکی زمان ببرد)';
$lang['submit'] = 'ارسال اطلاعات';
diff --git a/lib/plugins/popularity/lang/fr/intro.txt b/lib/plugins/popularity/lang/fr/intro.txt
index 041e65d69..598523492 100644
--- a/lib/plugins/popularity/lang/fr/intro.txt
+++ b/lib/plugins/popularity/lang/fr/intro.txt
@@ -1,10 +1,10 @@
====== Enquête de popularité ======
-Cet [[doku>popularity|outil]] collecte des données anonymes concernant votre wiki et vous permet de les expédier aux développeurs de DokuWiki. Ceci leur permet de mieux comprendre comment DokuWiki est employé par ses utilisateurs et d'orienter les décisions sur les développements futurs en tenant compte des statistiques d'usage réel.
+Cet [[doku>popularity|outil]] collecte des données anonymes concernant votre wiki et vous permet de les expédier aux développeurs de DokuWiki. Ceci leur permet de mieux comprendre comment DokuWiki est utilisé par ses utilisateurs et d'orienter les décisions sur les développements futurs en tenant compte des statistiques d'usage réel.
-Vous êtes encouragé à répéter l'opération de collecte et d'envoi des données anonymes de temps en temps afin d'informer les développeurs de la croissance de votre wiki.
+Vous êtes encouragé à répéter cette opération de temps à autres afin de tenir informés les développeurs de l'évolution de votre wiki. L'ensemble de vos contributions seront recensées via un identifiant anonyme.
-Les données collectées contiennent des informations telle que votre version de DokuWiki, le nombre et la taille de vos pages et fichiers, les modules installés ainsi que des informations sur la version de PHP installée.
+Les données collectées contiennent des informations telles votre version de DokuWiki, le nombre et la taille de vos pages et fichiers, les extensions installées ainsi que des informations sur la version de PHP installée.
Les données brutes qui sont envoyées sont affichées ci dessous. Merci d'utiliser le bouton « Envoyer les données » pour expédier l'information.
diff --git a/lib/plugins/popularity/lang/fr/lang.php b/lib/plugins/popularity/lang/fr/lang.php
index 904987079..d5bc92081 100644
--- a/lib/plugins/popularity/lang/fr/lang.php
+++ b/lib/plugins/popularity/lang/fr/lang.php
@@ -16,11 +16,12 @@
* @author skimpax@gmail.com
* @author Yannick Aure <yannick.aure@gmail.com>
* @author Olivier DUVAL <zorky00@gmail.com>
+ * @author Anael Mobilia <contrib@anael.eu>
*/
$lang['name'] = 'Enquête de popularité (peut nécessiter un certain temps pour être chargée)';
$lang['submit'] = 'Envoyer les données';
-$lang['autosubmit'] = 'Envoyer les données automatiquement chaque mois';
-$lang['submissionFailed'] = 'Les données ne peuvent pas être envoyées à cause des erreurs suivantes :';
-$lang['submitDirectly'] = 'Vous pouvez envoyer le données manuellement en soumettant ce formulaire.';
+$lang['autosubmit'] = 'Envoyer les données automatiquement une fois par mois';
+$lang['submissionFailed'] = 'Les données ne peuvent pas être expédiées à cause des erreurs suivantes :';
+$lang['submitDirectly'] = 'Vous pouvez envoyer les données manuellement en soumettant ce formulaire.';
$lang['autosubmitError'] = 'La dernière soumission automatique a échoué pour les raisons suivantes :';
-$lang['lastSent'] = 'Les données ont été envoyées ';
+$lang['lastSent'] = 'Les données ont été expédiées';
diff --git a/lib/plugins/popularity/lang/fr/submitted.txt b/lib/plugins/popularity/lang/fr/submitted.txt
index 0bc4cfe71..edb5e21f6 100644
--- a/lib/plugins/popularity/lang/fr/submitted.txt
+++ b/lib/plugins/popularity/lang/fr/submitted.txt
@@ -1,2 +1,3 @@
====== Enquête de popularité ======
-Les données ont été envoyées avec succès. \ No newline at end of file
+
+Les données ont été expédiées avec succès. \ No newline at end of file
diff --git a/lib/plugins/popularity/lang/gl/lang.php b/lib/plugins/popularity/lang/gl/lang.php
index 34bd3935f..86cd34db6 100644
--- a/lib/plugins/popularity/lang/gl/lang.php
+++ b/lib/plugins/popularity/lang/gl/lang.php
@@ -4,6 +4,7 @@
*
* @author Medúlio <medulio@ciberirmandade.org>
* @author Oscar M. Lage <r0sk10@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/ko/intro.txt b/lib/plugins/popularity/lang/ko/intro.txt
index 0af7ee2cc..b9e66094e 100644
--- a/lib/plugins/popularity/lang/ko/intro.txt
+++ b/lib/plugins/popularity/lang/ko/intro.txt
@@ -1,6 +1,6 @@
====== 인기도 조사 ======
-설치된 위키의 익명 정보를 DokuWiki 개발자에게 보냅니다. 이 [[doku>popularity|기능]]은 DokuWiki가 실제 사용자에게 어떻게 사용되는지 DokuWiki 개발자에게 알려줌으로써 이 후 개발 시 참고가 됩니다.
+설치된 위키의 익명 정보를 DokuWiki 개발자에게 보냅니다. 이 [[doku>popularity|도구]]는 DokuWiki가 실제 사용자에게 어떻게 사용되는지 DokuWiki 개발자에게 알려줌으로써 이 후 개발 시 참고가 됩니다.
설치된 위키가 커짐에 따라서 이 과정을 반복할 필요가 있습니다. 반복된 데이타는 익명 ID로 구별되어집니다.
diff --git a/lib/plugins/popularity/lang/tr/lang.php b/lib/plugins/popularity/lang/tr/lang.php
index fe87d1548..5339176bc 100644
--- a/lib/plugins/popularity/lang/tr/lang.php
+++ b/lib/plugins/popularity/lang/tr/lang.php
@@ -6,6 +6,8 @@
* @author Cihan Kahveci <kahvecicihan@gmail.com>
* @author Yavuz Selim <yavuzselim@gmail.com>
* @author Caleb Maclennan <caleb@alerque.com>
+ * @author farukerdemoncel@gmail.com
*/
$lang['name'] = 'Popülerlik Geribeslemesi (yüklemesi uzun sürebilir)';
$lang['submit'] = 'Verileri Gönder';
+$lang['lastSent'] = 'Bilgiler gönderildi';
diff --git a/lib/plugins/popularity/lang/zh-tw/intro.txt b/lib/plugins/popularity/lang/zh-tw/intro.txt
index 37c63dced..2a6337237 100644
--- a/lib/plugins/popularity/lang/zh-tw/intro.txt
+++ b/lib/plugins/popularity/lang/zh-tw/intro.txt
@@ -1,10 +1,9 @@
====== 人氣回饋 ======
-本工具會從您的維基站台收集訊息,並以匿名的方式發送給 DokuWiki 的開發者。這有助於他們了解使用者們如何使用 DokuWiki ,並能基於實際統計資料對未來開發做出更準確的決策。
+本工具會從您的 wiki 站台收集訊息,並以匿名的方式發送給 DokuWiki 的開發者。這有助於他們了解使用者們如何使用 DokuWiki ,並能基於實際統計資料對未來開發做出更準確的決策。
-我們鼓勵您經常重複這個步驟,讓開發者了解您的維基站台的成長情形。您的資料集將會被標識為一個匿名的識別碼 (ID)。
+我們鼓勵您經常重複這個步驟,讓開發者了解您的 wiki 站台的成長情形。您的資料集將會被標識為一個匿名的識別碼 (ID) 。
-收集的資料包括 DokuWiki 版本、頁面數量、檔案大小、安裝的插件、伺服器的 PHP 資訊。
-
-將被發送的原始資料顯示如下。請點擊「發送資料」按鈕進行傳輸。
+收集的資料包括 DokuWiki 版本、頁面數量、檔案大小、安裝的附加元件,以及伺服器的 PHP 資訊。
+將送出的原始資料顯示如下。請點擊「發送資料」按鈕進行傳輸。 \ No newline at end of file
diff --git a/lib/plugins/popularity/lang/zh-tw/lang.php b/lib/plugins/popularity/lang/zh-tw/lang.php
index 3d19ce53a..890c23bfa 100644
--- a/lib/plugins/popularity/lang/zh-tw/lang.php
+++ b/lib/plugins/popularity/lang/zh-tw/lang.php
@@ -10,11 +10,12 @@
* @author Danny Lin
* @author Shuo-Ting Jian <shoting@gmail.com>
* @author syaoranhinata@gmail.com
+ * @author Ichirou Uchiki <syaoranhinata@gmail.com>
*/
-$lang['name'] = '人氣回饋(載入可能需要一些時間)';
+$lang['name'] = '人氣回饋(可能需要一些時間載入)';
$lang['submit'] = '發送資料';
$lang['autosubmit'] = '每月自動發送';
-$lang['submissionFailed'] = '由於以下原因,資料無法發送:';
-$lang['submitDirectly'] = '你可以利用以下的表單來發手動發送資料.';
-$lang['autosubmitError'] = '由於以下原因,上次自動發送失敗:';
+$lang['submissionFailed'] = '由於以下原因,資料無法發送:';
+$lang['submitDirectly'] = '你可以利用以下的表單來發手動發送資料。';
+$lang['autosubmitError'] = '由於以下原因,上次自動發送無法進行:';
$lang['lastSent'] = '資料已發送';
diff --git a/lib/plugins/popularity/lang/zh-tw/submitted.txt b/lib/plugins/popularity/lang/zh-tw/submitted.txt
index 6febcd5b8..430a8a47a 100644
--- a/lib/plugins/popularity/lang/zh-tw/submitted.txt
+++ b/lib/plugins/popularity/lang/zh-tw/submitted.txt
@@ -1,3 +1,3 @@
====== 人氣回饋 ======
-資料已發送成功 \ No newline at end of file
+資料已發送。 \ No newline at end of file
diff --git a/lib/plugins/revert/admin.php b/lib/plugins/revert/admin.php
index 958cf5acf..847e38876 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');
$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 />';
@@ -73,8 +74,6 @@ class admin_plugin_revert extends DokuWiki_Admin_Plugin {
* Start the reversion process
*/
function _revert($revert,$filter){
- global $conf;
-
echo '<hr /><br />';
echo '<p>'.$this->getLang('revstart').'</p>';
diff --git a/lib/plugins/revert/lang/ca/lang.php b/lib/plugins/revert/lang/ca/lang.php
index b8800911f..4f4d518ea 100644
--- a/lib/plugins/revert/lang/ca/lang.php
+++ b/lib/plugins/revert/lang/ca/lang.php
@@ -6,6 +6,7 @@
* @author carles.bellver@gmail.com
* @author carles.bellver@cent.uji.es
* @author Carles Bellver <carles.bellver@cent.uji.es>
+ * @author daniel@6temes.cat
*/
$lang['menu'] = 'Gestió de reversions';
$lang['filter'] = 'Cerca pàgines brossa';
diff --git a/lib/plugins/revert/lang/cs/lang.php b/lib/plugins/revert/lang/cs/lang.php
index 5414ea1e5..dd8d7845c 100644
--- a/lib/plugins/revert/lang/cs/lang.php
+++ b/lib/plugins/revert/lang/cs/lang.php
@@ -12,6 +12,7 @@
* @author Vojta Beran <xmamut@email.cz>
* @author zbynek.krivka@seznam.cz
* @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com>
+ * @author Jakub A. Těšínský (j@kub.cz)
*/
$lang['menu'] = 'Obnova zaspamovaných stránek';
$lang['filter'] = 'Hledat zaspamované stránky';
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/es/lang.php b/lib/plugins/revert/lang/es/lang.php
index 3fb02be8e..129d71574 100644
--- a/lib/plugins/revert/lang/es/lang.php
+++ b/lib/plugins/revert/lang/es/lang.php
@@ -21,6 +21,7 @@
* @author Oscar Ciudad <oscar@jacho.net>
* @author Ruben Figols <ruben.figols@gmail.com>
* @author Gerardo Zamudio <gerardo@gerardozamudio.net>
+ * @author Mercè López mercelz@gmail.com
*/
$lang['menu'] = 'Restaurador';
$lang['filter'] = 'Buscar páginas con spam';
diff --git a/lib/plugins/revert/lang/fa/lang.php b/lib/plugins/revert/lang/fa/lang.php
index 34a5c430e..ba20313a3 100644
--- a/lib/plugins/revert/lang/fa/lang.php
+++ b/lib/plugins/revert/lang/fa/lang.php
@@ -8,6 +8,7 @@
* @author Omid Mottaghi <omidmr@gmail.com>
* @author Mohammad Reza Shoaei <shoaei@gmail.com>
* @author Milad DZand <M.DastanZand@gmail.com>
+ * @author AmirH Hassaneini <mytechmix@gmail.com>
*/
$lang['menu'] = 'مدیریت برگشت‌ها';
$lang['filter'] = 'جستجوی صفحات اسپم شده';
diff --git a/lib/plugins/revert/lang/fr/intro.txt b/lib/plugins/revert/lang/fr/intro.txt
index 6dcbe74b9..30e6d8a51 100644
--- a/lib/plugins/revert/lang/fr/intro.txt
+++ b/lib/plugins/revert/lang/fr/intro.txt
@@ -1,3 +1,3 @@
-====== Gestionnaire de réversions ======
+====== Gestionnaire des réversions ======
-Cette page peut vous aider à restaurer des pages après une attaque de spam. Pour trouver la liste des pages vandalisées, entrez un motif de recherche (p. ex. une URL de spam), puis confirmez que les pages trouvées contiennent du spam et annulez leurs éditions.
+Cette page vous aide à restaurer des pages après une attaque de spam. Pour trouver la liste des pages vandalisées, entrez un motif de recherche (par exemple : une URL de spam), puis confirmez que les pages trouvées contiennent du spam et annulez leur modifications.
diff --git a/lib/plugins/revert/lang/fr/lang.php b/lib/plugins/revert/lang/fr/lang.php
index 253e0c96e..07b012e38 100644
--- a/lib/plugins/revert/lang/fr/lang.php
+++ b/lib/plugins/revert/lang/fr/lang.php
@@ -17,13 +17,14 @@
* @author skimpax@gmail.com
* @author Yannick Aure <yannick.aure@gmail.com>
* @author Olivier DUVAL <zorky00@gmail.com>
+ * @author Anael Mobilia <contrib@anael.eu>
*/
-$lang['menu'] = 'Gestionnaire de réversions';
+$lang['menu'] = 'Gestionnaire des réversions';
$lang['filter'] = 'Trouver les pages spammées ';
$lang['revert'] = 'Annuler les modifications sélectionnées';
$lang['reverted'] = '%s restauré à la révision %s';
$lang['removed'] = '%s supprimé';
-$lang['revstart'] = 'Processus de réversion démarré. Ceci peut prendre longtemps. Si le script dépasse le délai avant de terminer, vous devrez restaurer de plus petits groupes de pages.';
+$lang['revstart'] = 'Processus de réversion démarré. Ceci peut durer longtemps. Si le script dépasse le délai d\'exécution avant de finir, vous devrez restaurer de plus petits groupes de pages.';
$lang['revstop'] = 'Processus de réversion terminé avec succès.';
-$lang['note1'] = 'Note : cette recherche est insensible à la casse';
-$lang['note2'] = 'Note : cette page sera révisée à la version précédente ne contenant pas le terme spammeur <em>%s</em>.';
+$lang['note1'] = 'Note : cette recherche est sensible à la casse';
+$lang['note2'] = 'Note : cette page sera restaurée à la dernière version ne contenant pas le terme « spam » <em>%s</em>.';
diff --git a/lib/plugins/revert/lang/gl/lang.php b/lib/plugins/revert/lang/gl/lang.php
index a0c5a9785..0e376d9a7 100644
--- a/lib/plugins/revert/lang/gl/lang.php
+++ b/lib/plugins/revert/lang/gl/lang.php
@@ -4,6 +4,7 @@
*
* @author Medúlio <medulio@ciberirmandade.org>
* @author Oscar M. Lage <r0sk10@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/tr/lang.php b/lib/plugins/revert/lang/tr/lang.php
index aa1458a95..9030c31e3 100644
--- a/lib/plugins/revert/lang/tr/lang.php
+++ b/lib/plugins/revert/lang/tr/lang.php
@@ -6,6 +6,7 @@
* @author Cihan Kahveci <kahvecicihan@gmail.com>
* @author Yavuz Selim <yavuzselim@gmail.com>
* @author Caleb Maclennan <caleb@alerque.com>
+ * @author farukerdemoncel@gmail.com
*/
$lang['menu'] = 'Eskiye Döndürme';
$lang['filter'] = 'Spam bulunan sayfaları ara';
diff --git a/lib/plugins/revert/lang/zh-tw/intro.txt b/lib/plugins/revert/lang/zh-tw/intro.txt
index 17632b1dd..b6da47e58 100644
--- a/lib/plugins/revert/lang/zh-tw/intro.txt
+++ b/lib/plugins/revert/lang/zh-tw/intro.txt
@@ -1,3 +1,3 @@
====== 還原管理器 ======
-本頁面能幫助您自動還原被垃圾訊息攻擊的頁面過來。先輸入關鍵字詞搜尋包含垃圾訊息的頁面(如垃圾訊息的 URL),確認找到的頁面確實包含垃圾訊息,再將它們還原。
+本頁面能幫助您自動還原遭垃圾訊息攻擊的頁面。先輸入關鍵字詞,搜尋包含垃圾訊息的頁面(例如垃圾訊息的 URL),確認找到的頁面確實包含垃圾訊息,再將它們還原。 \ No newline at end of file
diff --git a/lib/plugins/revert/lang/zh-tw/lang.php b/lib/plugins/revert/lang/zh-tw/lang.php
index 64da648cd..afd858455 100644
--- a/lib/plugins/revert/lang/zh-tw/lang.php
+++ b/lib/plugins/revert/lang/zh-tw/lang.php
@@ -10,6 +10,7 @@
* @author Danny Lin <danny0838@pchome.com.tw>
* @author Shuo-Ting Jian <shoting@gmail.com>
* @author syaoranhinata@gmail.com
+ * @author Ichirou Uchiki <syaoranhinata@gmail.com>
*/
$lang['menu'] = '還原管理';
$lang['filter'] = '搜索包含垃圾訊息的頁面';
@@ -17,6 +18,6 @@ $lang['revert'] = '還原選取的頁面';
$lang['reverted'] = '%s 已還原為版本 %s';
$lang['removed'] = '%s 已移除';
$lang['revstart'] = '已開始還原操作。有可能需要很長時間。如果程式執行逾時,請嘗試分次還原少量內容。';
-$lang['revstop'] = '還原程序已成功完成。';
+$lang['revstop'] = '還原程序已完成。';
$lang['note1'] = '注意:搜尋區分大小寫';
-$lang['note2'] = '注意:此頁面將被還原為最後一個不含垃圾訊息 <i>%s</i> 的版本。';
+$lang['note2'] = '注意:我們將把此頁面還原作最後一個不含垃圾訊息 <i>%s</i> 的版本。';
diff --git a/lib/plugins/safefnrecode/action.php b/lib/plugins/safefnrecode/action.php
index 5d3eaae3a..aae11c437 100644
--- a/lib/plugins/safefnrecode/action.php
+++ b/lib/plugins/safefnrecode/action.php
@@ -13,7 +13,7 @@ require_once DOKU_PLUGIN.'action.php';
class action_plugin_safefnrecode extends DokuWiki_Action_Plugin {
- public function register(Doku_Event_Handler &$controller) {
+ public function register(Doku_Event_Handler $controller) {
$controller->register_hook('INDEXER_TASKS_RUN', 'BEFORE', $this, 'handle_indexer_tasks_run');
diff --git a/lib/plugins/syntax.php b/lib/plugins/syntax.php
index 8b94493e4..b7839b2b2 100644
--- a/lib/plugins/syntax.php
+++ b/lib/plugins/syntax.php
@@ -84,13 +84,13 @@ class DokuWiki_Syntax_Plugin extends Doku_Parser_Mode {
*
* Usually you should only need the $match param.
*
- * @param $match string The text matched by the patterns
- * @param $state int The lexer state for the match
- * @param $pos int The character position of the matched text
- * @param $handler Doku_Handler Reference to the Doku_Handler object
- * @return array Return an array with all data you want to use in render
+ * @param string $match The text matched by the patterns
+ * @param int $state The lexer state for the match
+ * @param int $pos The character position of the matched text
+ * @param Doku_Handler $handler Reference to the Doku_Handler object
+ * @return array Return an array with all data you want to use in render
*/
- function handle($match, $state, $pos, &$handler){
+ function handle($match, $state, $pos, Doku_Handler &$handler){
trigger_error('handle() not implemented in '.get_class($this), E_USER_WARNING);
}
@@ -117,7 +117,7 @@ class DokuWiki_Syntax_Plugin extends Doku_Parser_Mode {
* @param $data array data created by handler()
* @return boolean rendered correctly?
*/
- function render($format, &$renderer, $data) {
+ function render($format, Doku_Renderer &$renderer, $data) {
trigger_error('render() not implemented in '.get_class($this), E_USER_WARNING);
}
@@ -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/action.php b/lib/plugins/testing/action.php
index e829847b6..a242ab0b7 100644
--- a/lib/plugins/testing/action.php
+++ b/lib/plugins/testing/action.php
@@ -7,7 +7,8 @@
* @author Tobias Sarnowski <tobias@trustedco.de>
*/
class action_plugin_testing extends DokuWiki_Action_Plugin {
- function register(&$controller) {
+
+ function register(Doku_Event_Handler $controller) {
$controller->register_hook('DOKUWIKI_STARTED', 'AFTER', $this, 'dokuwikiStarted');
}
diff --git a/lib/plugins/usermanager/admin.php b/lib/plugins/usermanager/admin.php
index 30b65debb..01f4a4cdb 100644
--- a/lib/plugins/usermanager/admin.php
+++ b/lib/plugins/usermanager/admin.php
@@ -73,13 +73,12 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
* handle user request
*/
function handle() {
- global $ID;
-
+ 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);
@@ -90,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();
}
@@ -308,7 +306,6 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
function _htmlInputField($id, $name, $label, $value, $cando, $indent=0) {
$class = $cando ? '' : ' class="disabled"';
- $disabled = $cando ? '' : ' disabled="disabled"';
echo str_pad('',$indent);
if($name == 'userpass'){
@@ -348,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;
@@ -356,7 +354,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
if ($this->_auth->canDo('modPass')){
if (empty($pass)){
- if(!empty($_REQUEST['usernotify'])){
+ if($INPUT->has('usernotify')){
$pass = auth_pwgen();
} else {
msg($this->lang['add_fail'], -1);
@@ -396,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 {
@@ -410,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)) {
@@ -466,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
@@ -497,7 +495,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
}
// generate password if left empty and notification is on
- if(!empty($_REQUEST['usernotify']) && empty($newpass)){
+ if($INPUT->has('usernotify') && empty($newpass)){
$newpass = auth_pwgen();
}
@@ -513,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);
}
@@ -549,7 +547,7 @@ class admin_plugin_usermanager extends DokuWiki_Admin_Plugin {
/**
* retrieve & clean user data from the form
*
- * @return array(user, password, full name, email, array(groups))
+ * @return array (user, password, full name, email, array(groups))
*/
function _retrieveUser($clean=true) {
global $auth;
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/ca/lang.php b/lib/plugins/usermanager/lang/ca/lang.php
index 445556973..6debd73ca 100644
--- a/lib/plugins/usermanager/lang/ca/lang.php
+++ b/lib/plugins/usermanager/lang/ca/lang.php
@@ -6,6 +6,7 @@
* @author carles.bellver@gmail.com
* @author carles.bellver@cent.uji.es
* @author Carles Bellver <carles.bellver@cent.uji.es>
+ * @author daniel@6temes.cat
*/
$lang['menu'] = 'Gestió d\'usuaris';
$lang['noauth'] = '(l\'autenticació d\'usuaris no està disponible)';
diff --git a/lib/plugins/usermanager/lang/cs/lang.php b/lib/plugins/usermanager/lang/cs/lang.php
index 8351c190b..6de408e14 100644
--- a/lib/plugins/usermanager/lang/cs/lang.php
+++ b/lib/plugins/usermanager/lang/cs/lang.php
@@ -11,6 +11,7 @@
* @author Vojta Beran <xmamut@email.cz>
* @author zbynek.krivka@seznam.cz
* @author Bohumir Zamecnik <bohumir.zamecnik@gmail.com>
+ * @author Jakub A. Těšínský (j@kub.cz)
*/
$lang['menu'] = 'Správa uživatelů';
$lang['noauth'] = '(autentizace uživatelů není k dispozici)';
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/es/lang.php b/lib/plugins/usermanager/lang/es/lang.php
index b616857a2..521191701 100644
--- a/lib/plugins/usermanager/lang/es/lang.php
+++ b/lib/plugins/usermanager/lang/es/lang.php
@@ -22,6 +22,7 @@
* @author Oscar Ciudad <oscar@jacho.net>
* @author Ruben Figols <ruben.figols@gmail.com>
* @author Gerardo Zamudio <gerardo@gerardozamudio.net>
+ * @author Mercè López mercelz@gmail.com
*/
$lang['menu'] = 'Administración de usuarios';
$lang['noauth'] = '(la autenticación de usuarios no está disponible)';
diff --git a/lib/plugins/usermanager/lang/fa/lang.php b/lib/plugins/usermanager/lang/fa/lang.php
index 674013474..8176b776b 100644
--- a/lib/plugins/usermanager/lang/fa/lang.php
+++ b/lib/plugins/usermanager/lang/fa/lang.php
@@ -8,6 +8,7 @@
* @author Omid Mottaghi <omidmr@gmail.com>
* @author Mohammad Reza Shoaei <shoaei@gmail.com>
* @author Milad DZand <M.DastanZand@gmail.com>
+ * @author AmirH Hassaneini <mytechmix@gmail.com>
*/
$lang['menu'] = 'مدیریت کاربر';
$lang['noauth'] = '(معتبرسازی کاربر ممکن نیست)';
diff --git a/lib/plugins/usermanager/lang/fr/edit.txt b/lib/plugins/usermanager/lang/fr/edit.txt
index ec193eb5a..e667989b4 100644
--- a/lib/plugins/usermanager/lang/fr/edit.txt
+++ b/lib/plugins/usermanager/lang/fr/edit.txt
@@ -1 +1 @@
-===== Modifier les informations d'un utilisateur =====
+===== Modifier l'utilisateur =====
diff --git a/lib/plugins/usermanager/lang/fr/lang.php b/lib/plugins/usermanager/lang/fr/lang.php
index d84ff65c3..7e602d0ce 100644
--- a/lib/plugins/usermanager/lang/fr/lang.php
+++ b/lib/plugins/usermanager/lang/fr/lang.php
@@ -18,10 +18,11 @@
* @author skimpax@gmail.com
* @author Yannick Aure <yannick.aure@gmail.com>
* @author Olivier DUVAL <zorky00@gmail.com>
+ * @author Anael Mobilia <contrib@anael.eu>
*/
$lang['menu'] = 'Gestion des utilisateurs';
-$lang['noauth'] = '(authentification utilisateur non disponible)';
-$lang['nosupport'] = '(gestion utilisateur non supportée)';
+$lang['noauth'] = '(authentification de l\'utilisateur non disponible)';
+$lang['nosupport'] = '(gestion de l\'utilisateur non supportée)';
$lang['badauth'] = 'mécanisme d\'authentification invalide';
$lang['user_id'] = 'Identifiant ';
$lang['user_pass'] = 'Mot de passe ';
@@ -40,20 +41,20 @@ $lang['search'] = 'Rechercher';
$lang['search_prompt'] = 'Effectuer la recherche';
$lang['clear'] = 'Réinitialiser la recherche';
$lang['filter'] = 'Filtre';
-$lang['summary'] = 'Affichage des utilisateurs %1$d-%2$d parmi %3$d trouvé(s). %4$d utilisateur(s) au total.';
-$lang['nonefound'] = 'Aucun utilisateur trouvé. %d utilisateur(s) au total.';
+$lang['summary'] = 'Affichage des utilisateurs %1$d-%2$d parmi %3$d trouvés. %4$d utilisateurs au total.';
+$lang['nonefound'] = 'Aucun utilisateur trouvé. %d utilisateurs au total.';
$lang['delete_ok'] = '%d utilisateurs effacés';
-$lang['delete_fail'] = '%d effacement échoué.';
+$lang['delete_fail'] = '%d effacements échoués.';
$lang['update_ok'] = 'Utilisateur mis à jour avec succès';
-$lang['update_fail'] = 'Échec de la mise à jour utilisateur';
-$lang['update_exists'] = 'Échec du changement de nom d\'utilisateur, le nom spécifié (%s) existe déjà (toutes les autres modifications seront effectuées).';
-$lang['start'] = 'Démarrage';
+$lang['update_fail'] = 'Échec lors de la mise à jour de l\'utilisateur';
+$lang['update_exists'] = 'Échec lors du changement du nom d\'utilisateur : le nom spécifié (%s) existe déjà (toutes les autres modifications seront effectuées).';
+$lang['start'] = 'Début';
$lang['prev'] = 'Précédent';
$lang['next'] = 'Suivant';
-$lang['last'] = 'Dernier';
+$lang['last'] = 'Fin';
$lang['edit_usermissing'] = 'Utilisateur sélectionné non trouvé, cet utilisateur a peut-être été supprimé ou modifié ailleurs.';
$lang['user_notify'] = 'Notifier l\'utilisateur ';
-$lang['note_notify'] = 'Envoi de notification par courriel uniquement lorsqu\'un nouveau mot de passe est attribué à l\'utilisateur.';
+$lang['note_notify'] = 'Expédition de notification par courriel uniquement lorsque l\'utilisateur fourni un nouveau mot de passe.';
$lang['note_group'] = 'Les nouveaux utilisateurs seront ajoutés au groupe par défaut (%s) si aucun groupe n\'est spécifié.';
$lang['note_pass'] = 'Le mot de passe sera généré automatiquement si le champ est laissé vide et si la notification de l\'utilisateur est activée.';
$lang['add_ok'] = 'Utilisateur ajouté avec succès';
diff --git a/lib/plugins/usermanager/lang/gl/lang.php b/lib/plugins/usermanager/lang/gl/lang.php
index c9c633b39..f3a7ef281 100644
--- a/lib/plugins/usermanager/lang/gl/lang.php
+++ b/lib/plugins/usermanager/lang/gl/lang.php
@@ -4,6 +4,7 @@
*
* @author Medúlio <medulio@ciberirmandade.org>
* @author Oscar M. Lage <r0sk10@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/kk/lang.php b/lib/plugins/usermanager/lang/kk/lang.php
index dde5b9577..b1bbd39ec 100644
--- a/lib/plugins/usermanager/lang/kk/lang.php
+++ b/lib/plugins/usermanager/lang/kk/lang.php
@@ -4,3 +4,6 @@
*
* @author Nurgozha Kaliaskarov astana08@gmail.com
*/
+$lang['user_id'] = 'Пайдаланушы';
+$lang['user_pass'] = 'Шартты белгi';
+$lang['user_mail'] = 'E-mail';
diff --git a/lib/plugins/usermanager/lang/ko/edit.txt b/lib/plugins/usermanager/lang/ko/edit.txt
index b8b13c5c8..ebb5bb002 100644
--- a/lib/plugins/usermanager/lang/ko/edit.txt
+++ b/lib/plugins/usermanager/lang/ko/edit.txt
@@ -1 +1 @@
-===== 사용자 정보 수정 =====
+===== 사용자 정보 편집 =====
diff --git a/lib/plugins/usermanager/lang/ko/lang.php b/lib/plugins/usermanager/lang/ko/lang.php
index 3754fea90..58f9bf14a 100644
--- a/lib/plugins/usermanager/lang/ko/lang.php
+++ b/lib/plugins/usermanager/lang/ko/lang.php
@@ -35,14 +35,14 @@ $lang['summary'] = '찾은 사용자 %3$d 중 %1$d-%2$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'] = '다음';
$lang['last'] = '마지막';
-$lang['edit_usermissing'] = '선택된 사용자를 찾을 수 없습니다. 사용자 이름이 삭제되거나 변경됐을 수도 있습니다.';
+$lang['edit_usermissing'] = '선택된 사용자를 찾을 수 없습니다. 사용자 이름이 삭제되거나 바뀌었을 수도 있습니다.';
$lang['user_notify'] = '사용자에게 알림';
$lang['note_notify'] = '사용자에게 새로운 비밀번호를 준 경우에만 알림 이메일이 보내집니다.';
$lang['note_group'] = '새로운 사용자는 어떤 그룹도 설정하지 않은 경우에 기본 그룹(%s)에 추가됩니다.';
diff --git a/lib/plugins/usermanager/lang/tr/lang.php b/lib/plugins/usermanager/lang/tr/lang.php
index b9c9cfc52..7ddb7dd5d 100644
--- a/lib/plugins/usermanager/lang/tr/lang.php
+++ b/lib/plugins/usermanager/lang/tr/lang.php
@@ -6,6 +6,7 @@
* @author Cihan Kahveci <kahvecicihan@gmail.com>
* @author Yavuz Selim <yavuzselim@gmail.com>
* @author Caleb Maclennan <caleb@alerque.com>
+ * @author farukerdemoncel@gmail.com
*/
$lang['menu'] = 'Kullanıcı Yönetimi';
$lang['noauth'] = '(kullanıcı onaylaması yoktur)';
diff --git a/lib/plugins/usermanager/lang/zh-tw/lang.php b/lib/plugins/usermanager/lang/zh-tw/lang.php
index 23b4fdac6..1db35cc82 100644
--- a/lib/plugins/usermanager/lang/zh-tw/lang.php
+++ b/lib/plugins/usermanager/lang/zh-tw/lang.php
@@ -11,6 +11,7 @@
* @author Danny Lin <danny0838@pchome.com.tw>
* @author Shuo-Ting Jian <shoting@gmail.com>
* @author syaoranhinata@gmail.com
+ * @author Ichirou Uchiki <syaoranhinata@gmail.com>
*/
$lang['menu'] = '帳號管理器';
$lang['noauth'] = '(帳號認證尚未開放)';
@@ -18,8 +19,8 @@ $lang['nosupport'] = '(尚不支援帳號管理)';
$lang['badauth'] = '錯誤的認證機制';
$lang['user_id'] = '帳號';
$lang['user_pass'] = '密碼';
-$lang['user_name'] = '真實姓名';
-$lang['user_mail'] = 'E-mail';
+$lang['user_name'] = '名稱';
+$lang['user_mail'] = '電郵';
$lang['user_groups'] = '群組';
$lang['field'] = '欄位';
$lang['value'] = '設定值';
@@ -36,10 +37,10 @@ $lang['filter'] = '篩選條件(Filter)';
$lang['summary'] = '顯示帳號 %1$d-%2$d,共 %3$d 筆符合。共有 %4$d 個帳號。';
$lang['nonefound'] = '找不到帳號。共有 %d 個帳號。';
$lang['delete_ok'] = '已刪除 %d 個帳號';
-$lang['delete_fail'] = '%d 個帳號刪除失敗。';
+$lang['delete_fail'] = '%d 個帳號無法刪除。';
$lang['update_ok'] = '已更新該帳號';
-$lang['update_fail'] = '更新該帳號時失敗';
-$lang['update_exists'] = '變更帳號名稱 (%s) 失敗,因為有同名帳號存在(其他修改已套用)。';
+$lang['update_fail'] = '無法更新該帳號';
+$lang['update_exists'] = '無法變更帳號名稱 (%s) ,因為有同名帳號存在。其他修改則已套用。';
$lang['start'] = '開始';
$lang['prev'] = '上一頁';
$lang['next'] = '下一頁';
@@ -47,9 +48,9 @@ $lang['last'] = '最後一頁';
$lang['edit_usermissing'] = '找不到選取的帳號,可能已被刪除或改為其他名稱。';
$lang['user_notify'] = '通知使用者';
$lang['note_notify'] = '通知信只會在指定使用者新密碼時寄送。';
-$lang['note_group'] = '如果沒有指定群組,新使用者將會被加入到預設群組(%s)當中。';
+$lang['note_group'] = '如果沒有指定群組,新使用者將會列入至預設群組(%s)當中。';
$lang['note_pass'] = '如果沒有輸入這個欄位而且有勾選通知使用者,則會自動產生一組密碼。';
-$lang['add_ok'] = '新增使用者成功';
-$lang['add_fail'] = '新增使用者失敗';
+$lang['add_ok'] = '已新增使用者';
+$lang['add_fail'] = '無法新增使用者';
$lang['notify_ok'] = '通知信已寄出';
$lang['notify_fail'] = '通知信無法寄出';