1<?php
2/**
3 * Userhomepage plugin main file
4 * Previous authors: James GuanFeng Lin, Mikhail I. Izmestev, Daniel Stonier
5 * @author   Simon DELAGE <sdelage@gmail.com>
6 * @license: CC Attribution-Share Alike 3.0 Unported <http://creativecommons.org/licenses/by-sa/3.0/>
7 */
8
9// must be run within Dokuwiki
10if (!defined('DOKU_INC')) die();
11if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/');
12
13require_once (DOKU_PLUGIN . 'action.php');
14require_once (DOKU_PLUGIN . '/acl/admin.php');
15
16class action_plugin_userhomepage extends DokuWiki_Action_Plugin{
17
18    function register(Doku_Event_Handler $controller) {
19        $controller->register_hook('DOKUWIKI_STARTED', 'AFTER', $this, 'init',array());
20        $controller->register_hook('DETAIL_STARTED', 'AFTER', $this, 'init',array());
21        $controller->register_hook('ACTION_ACT_PREPROCESS', 'AFTER', $this, 'redirect',array());
22        $controller->register_hook('ACTION_ACT_PREPROCESS', 'AFTER', $this, 'acl',array());
23        $controller->register_hook('COMMON_USER_LINK', 'AFTER', $this, 'replaceUserLink',array());
24    }
25
26    function init(&$event, $param) {
27        global $conf;
28        global $INFO;
29
30        // If there's no conflict between private and public space
31        if ($this->multiNsOk(true)) {
32            $this->helper = plugin_load('helper','userhomepage');
33            // If templates_path option starts with 'data/pages' it can automatically be adapted but should be changed
34            if (substr($this->getConf('templates_path'),0,10) == 'data/pages') {
35                $dest = str_replace("data/pages", "./pages", $this->getConf('templates_path'));
36                msg("Userhomepage option [<code>templates_path</code>] should be changed to a path relative to data folder (as set by Dokuwiki's [<code>savedir</code>] setting). Current value is based on former default (i.e. <code>data/pages/...</code>) and will still work but this message will keep appearing until the value is corrected, check <a href='https://www.dokuwiki.org/plugin:userhomepage'>this page</a> for details.",2);
37            } else {
38                $dest = $this->getConf('templates_path');
39            }
40            if (!plugin_isdisabled('avatar')) {
41                $avatarHelper = plugin_load('helper','avatar');
42                $avatarsFolder = $avatarHelper->getConf('namespace');
43                if (($avatarsFolder == "user") && ($avatarsFolder == $this->getConf('users_namespace')) && (isadmin)) {
44                    msg($this->getLang('avatarsconflict'), -1);
45                }
46            }
47            //if ($event == "DETAIL_STARTED") { return false; }
48            $this->dataDir = $conf['savedir'];
49            // CREATE PRIVATE NAMESPACE START PAGE TEMPLATES IF NEEDED (is required by options, doesn't exist yet and a known user is logged in and not showing image details page)
50            if (($this->getConf('create_private_ns')) && (!is_file($this->dataDir.'/'.$this->getConf('templates_path').'/userhomepage_private.txt')) && ($this->userOk()) && ($event != "DETAIL_STARTED")) {
51                // If a template exists in path as builded before 2015/05/14 version, use it as source to create userhomepage_private.txt in new templates_path
52                if ((is_file(DOKU_CONF.'../'.$this->getConf('templates_path').'/userhomepage_private.txt')) && ($this->getConf('templatepath') != null)) {
53                    $source = DOKU_CONF.'../'.$this->getConf('templates_path').'/userhomepage_private.txt';
54                // If a template from version 3.0.4 exists, use it as source to create userhomepage_private.txt in templates_path
55                } elseif ((is_file(DOKU_INC.$this->getConf('templatepath'))) && ($this->getConf('templatepath') != null)) {
56                    $source = $this->getConf('templatepath');
57                // Otherwise, we're on a fresh install
58                } else {
59					if (is_file('lib/plugins/userhomepage/lang/'.$conf['lang'].'/userhomepage_private.default')) {
60						$source = 'lib/plugins/userhomepage/lang/'.$conf['lang'].'/userhomepage_private.default';
61					} else {
62						$source = 'lib/plugins/userhomepage/lang/en/userhomepage_private.default';
63					}
64                }
65                $this->copyFile($source, $dest, 'userhomepage_private.txt');
66            }
67            // CREATE PUBLIC PAGE TEMPLATES IF NEEDED (is required by options, doesn't exist yet and a known user is logged in and not showing image details page)
68            if (($this->getConf('create_public_page')) and (!is_file($this->dataDir.'/'.$this->getConf('templates_path').'/userhomepage_public.txt')) and ($this->userOk()) && ($event != "DETAIL_STARTED")) {
69                // If a template exists in path as builded before 2015/05/14 version, use it as source to create userhomepage_private.txt in new templates_path
70                if ((is_file(DOKU_CONF.'../'.$this->getConf('templates_path').'/userhomepage_public.txt')) && ($this->getConf('templatepath') != null)) {
71                    $source = DOKU_CONF.'../'.$this->getConf('templates_path').'/userhomepage_public.txt';
72                } else {
73					if (is_file('lib/plugins/userhomepage/lang/'.$conf['lang'].'/userhomepage_public.default')) {
74						$source = 'lib/plugins/userhomepage/lang/'.$conf['lang'].'/userhomepage_public.default';
75					} else {
76						$source = 'lib/plugins/userhomepage/lang/en/userhomepage_public.default';
77					}
78                }
79                $this->copyFile($source, $dest, 'userhomepage_public.txt');
80            }
81            // CREATE PUBLIC NAMESPACE START PAGE TEMPLATES IF NEEDED (is required by options, doesn't exist yet and a known user is logged in and not showing image details page)
82            if (($this->getConf('create_public_page')) and (strpos($this->getConf('public_pages_ns'),':%NAME%:%START%') !== false) and (!is_file($this->dataDir.'/'.$this->getConf('templates_path').'/userhomepage_publicspace.txt')) and ($this->userOk()) && ($event != "DETAIL_STARTED")) {
83                // If a template exists in path as builded before 2015/05/14 version, use it as source to create userhomepage_private.txt in new templates_path
84                if ((is_file(DOKU_CONF.'../'.$this->getConf('templates_path').'/userhomepage_publicspace.txt')) && ($this->getConf('templatepath') != null)) {
85                    $source = DOKU_CONF.'../'.$this->getConf('templates_path').'/userhomepage_publicspace.txt';
86                } else {
87                    $source = 'lib/plugins/userhomepage/lang/'.$conf['lang'].'/userhomepage_publicspace.default';
88                }
89                $this->copyFile($source, $dest, 'userhomepage_publicspace.txt');
90            }
91            // TARGETS
92            // ...:start.txt or ...:simon_delage.txt
93            $this->private_page = $this->helper->getPrivateID();
94            // user:simon.txt
95            $this->public_page = $this->helper->getPublicID();
96            // If a user is logged in, store timestamp (if it wasn't stored yet)
97            if (($_SERVER['REMOTE_USER'] != null) && (!isset($_SESSION['uhptimestamp']))) {
98                $_SESSION['uhptimestamp'] = time();
99            // If no user is logged in and a timestamp exists, set timestamp to null (ensures that redirection will work if user just logged out and comes back before closing browser)
100            } elseif (($_SERVER['REMOTE_USER'] == null) && (isset($_SESSION['uhptimestamp']))) {
101                $_SESSION['uhptimestamp'] = null;
102            }
103        } else {
104            return false;
105        }
106    }
107
108    function redirect(&$event, $param) {
109        global $conf;
110        global $lang;
111        global $ID;
112
113        // If there's no conflict between private and public space and if user did not request an action page
114//        if ($this->multiNsOk()) {
115        if (($this->multiNsOk()) and ($_GET['do'] == null)) {
116//        if (($this->multiNsOk()) and ($_GET['do'] != 'admin')) {
117            $created = array();
118            // If a user is logged in and not allready requesting his private namespace start page
119            if (($this->userOk())&&($_REQUEST['id']!=$this->private_page)) {
120                // if private page doesn't exists, create it (from template)
121                if ($this->getConf('create_private_ns') && is_file($this->dataDir.'/'.$this->getConf('templates_path').'/userhomepage_private.txt') && !page_exists($this->private_page) && !checklock($this->private_page) && !checkwordblock() && ($this->userOk('private'))) {
122                    // Target private start page template
123                    $this->private_page_template = $this->dataDir.'/'.$this->getConf('templates_path').'/userhomepage_private.txt';
124                    // Create private page
125                    lock($this->private_page);
126                    saveWikiText($this->private_page,$this->applyTemplate('private'),$this->getLang('uhpcreated'));
127                    unlock($this->private_page);
128                    // Announce private namespace was created
129                    msg($this->getLang('createdprivatens').' ('.$this->private_page.')', 1);
130                    // Note that we created private page
131                    $created['private'] = page_exists($this->private_page);
132                }
133                // If private ns is managed by plugin, check for any template from skeleton that doesn't exist yet
134                if ($this->getConf('create_private_ns') && (is_dir($this->dataDir.'/'.$this->getConf('templates_path').'/uhp_private_skeleton')) && ($this->userOk('private'))) {
135                    //$files = scandir($this->dataDir.'/'.$this->getConf('templates_path').'/uhp_private_skeleton/');
136                    $path = realpath($this->dataDir.'/'.$this->getConf('templates_path').'/uhp_private_skeleton/');
137                    $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);
138                    if ($this->getConf('group_by_name')) {
139                        // private:s:simon or private:s:simon_delage
140                        $this->private_ns = cleanID($this->getConf('users_namespace').':'.substr($this->privateNamespace(), 0, 1).':'. $this->privateNamespace());
141                    } else {
142                        // private:simon or private:simon_delage
143                        $this->private_ns = cleanID($this->getConf('users_namespace').':'. $this->privateNamespace());
144                    }
145                    foreach($objects as $objectName => $object){
146                        $file = str_replace($path, '', $objectName);
147                        if ((is_file($this->dataDir.'/'.$this->getConf('templates_path').'/uhp_private_skeleton'.$file)) and (strpos($file, '.txt') !== false)) {
148                            $custom_page_id = cleanID(str_replace('.txt', '', str_replace('/', ':', str_replace('\\', ':', $file))));
149                            $this->custom_target = $this->private_ns.':'.$custom_page_id;
150                            if (!page_exists($this->custom_target)) {
151                                $this->custom_page_template = $this->dataDir.'/'.$this->getConf('templates_path').'/uhp_private_skeleton'.$file;
152                                lock($this->custom_target);
153                                saveWikiText($this->custom_target,$this->applyTemplate($this->custom_page_template),$this->getLang('uhpcreated'));
154                                msg($this->getLang('fromskeleton').' '.$this->custom_target,0);
155                                unlock($this->custom_target);
156                            }
157                        }
158                    }
159                }
160                // Public page?
161                // If public page doesn't exists, create it (from template)
162                if ($this->getConf('create_public_page') && is_file($this->dataDir.'/'.$this->getConf('templates_path').'/userhomepage_public.txt') && !page_exists($this->public_page) && !checklock($this->public_page) && !checkwordblock() && ($this->userOk('public'))) {
163                    // Target public page template or public namespace start page template
164                    if (strpos($this->getConf('public_pages_ns'),':%NAME%:%START%') !== false) {
165                        $this->public_page_template = $this->dataDir.'/'.$this->getConf('templates_path').'/userhomepage_publicspace.txt';
166                    } else {
167                        $this->public_page_template = $this->dataDir.'/'.$this->getConf('templates_path').'/userhomepage_public.txt';
168                    }
169                    // Create public page
170                    lock($this->public_page);
171                    saveWikiText($this->public_page,$this->applyTemplate('public'),$this->getLang('uhpcreated'));
172                    unlock($this->public_page);
173                    // Announce plubic page was created
174                    msg($this->getLang('createdpublicpage').' ('.$this->public_page.')', 1);
175                    // Note that we created public page
176                    $created['public'] = page_exists($this->public_page);
177                }
178                // If public page is in fact a public namespace and is managed by plugin, check for any template from skeleton that doesn't exist yet
179                if ($this->getConf('create_public_page') && (is_dir($this->dataDir.'/'.$this->getConf('templates_path').'/uhp_public_skeleton')) && ($this->userOk('public'))) {
180                    $path = realpath($this->dataDir.'/'.$this->getConf('templates_path').'/uhp_public_skeleton/');
181                    $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);
182                    $this->public_ns = cleanID(getNS($this->public_page));
183                    foreach($objects as $objectName => $object){
184                        $file = str_replace($path, '', $objectName);
185                        if ((is_file($this->dataDir.'/'.$this->getConf('templates_path').'/uhp_public_skeleton'.$file)) and (strpos($file, '.txt') !== false)) {
186                            $custom_page_id = cleanID(str_replace('.txt', '', str_replace('/', ':', str_replace('\\', ':', $file))));
187                            $this->custom_target = $this->public_ns.':'.$custom_page_id;
188                            if (!page_exists($this->custom_target)) {
189                                $this->custom_page_template = $this->dataDir.'/'.$this->getConf('templates_path').'/uhp_public_skeleton'.$file;
190                                lock($this->custom_target);
191                                saveWikiText($this->custom_target,$this->applyTemplate($this->custom_page_template),$this->getLang('uhpcreated'));
192                                msg($this->getLang('fromskeleton').' '.$this->custom_target,0);
193                                unlock($this->custom_target);
194                            }
195                        }
196                    }
197                }
198                // List IDs that can match wiki start
199                $wikistart = array($conf['start'], ':'.$conf['start']);
200                // If Translation plugin is active, wiki start page can also be '??:start'
201                if (!plugin_isdisabled('translation')) {
202                    // For each language in Translation settings
203                    foreach (explode(' ',$conf['plugin']['translation']['translations']) as $language){
204                        array_push($wikistart, $language.':'.$conf['start'], ':'.$language.':'.$conf['start']);
205                    }
206                }
207                // If user isn't on public or private page yet, check for redirection conditions
208                if (($ID != $this->public_page) && ($ID != $this->private_page)) {
209                    // If Public page was just created, redirect to it and edit (or show)
210                    if (($created['public']) && (page_exists($this->public_page))) {
211                        send_redirect(wl($this->public_page, array('do='.$this->getConf('action')), true));
212//msg('Public page creation redirection: id '.$_GET['id'].'; do '.$_GET['do'], 1);
213                    // Else if private start page was just created and edit option is set, redirect to it and edit
214                    } elseif (($created['private']) && (page_exists($this->private_page)) && ($this->getConf('edit_before_create'))) {
215                        send_redirect(wl($this->private_page, array('do='.$this->getConf('action')), true));
216//msg('Private page creation redirection: id '.$_GET['id'].'; do '.$_GET['do'], 1);
217                    // Else if redirection is enabled and user's private page exists AND [(user isn't requesting a specific page OR he's requesting wiki start page) AND logged in 2sec ago max]
218                    } elseif (($this->getConf('redirection')) && (page_exists($this->private_page)) && (((!isset($_GET['id'])) or (in_array($_GET['id'], $wikistart))) && (time()-$_SESSION["uhptimestamp"] <= 2))) {
219//msg('Default redirection: id '.$_GET['id'].'; do '.$_GET['do'], 1);
220                        send_redirect(wl($this->private_page, '', true));
221                    }
222                }
223            }
224        } else {
225            return false;
226        }
227    }
228
229    function acl(&$event, $param) {
230        global $conf;
231
232        // If there's no conflict between private and public space
233        if ($this->multiNsOk()) {
234            if ((!$this->getConf('no_acl')) && ($conf['useacl']) && ($this->userOk())) {
235                global $config_cascade;
236                $existingLines = file($config_cascade['acl']['default']);
237                $newLines = array();
238                // ACL
239                $acl = new admin_plugin_acl();
240                // On private namespace
241                if ($this->getConf('create_private_ns')) {
242                    // For known users
243                    // If use_name_string or group_by_name is enabled, we can't use ACL wildcards so let's create ACL for current user on his private ns
244                    if (($this->getConf('use_name_string')) or ($this->getConf('group_by_name'))) {
245                        $where = $this->private_ns.':*';
246                        $who = strtolower($_SERVER['REMOTE_USER']);
247                    // Otherwise we can set ACL for all known users at once
248                    } else {
249                        $where = cleanID($this->getConf('users_namespace')).':%USER%:*';
250                        $who = '%USER%';
251                    }
252                    $perm = AUTH_DELETE;
253                    if (!in_array("$where\t$who\t$perm\n", $existingLines)) { $newLines[] = array('where' => $where, 'who' => $who, 'perm' => $perm); }
254                    // For @ALL
255                    if ($this->getConf('acl_all_private') != 'noacl') {
256                        $where = cleanID($this->getConf('users_namespace')).':*';
257                        $who = '@ALL';
258                        $perm = (int)$this->getConf('acl_all_private');
259                        if (!in_array("$where\t$who\t$perm\n", $existingLines)) { $newLines[] = array('where' => $where, 'who' => $who, 'perm' => $perm); }
260                    }
261                    // For @user
262                    if (($this->getConf('acl_user_private') != 'noacl') && ($this->getConf('acl_user_private') !== $this->getConf('acl_all_private'))) {
263                        $where = cleanID($this->getConf('users_namespace')).':*';
264                        $who = '@user';
265                        $perm = (int)$this->getConf('acl_user_private');
266                        if (!in_array("$where\t$who\t$perm\n", $existingLines)) { $newLines[] = array('where' => $where, 'who' => $who, 'perm' => $perm); }
267                    }
268                } // end of private namespaces acl
269                // On public user pages
270                if ($this->getConf('create_public_page')) {
271                    // For known users
272                    if (strpos($this->getConf('public_pages_ns'),':%NAME%:%START%') !== false) {
273                        $where = str_replace('%NAME%:%START%', '%USER%', $this->getConf('public_pages_ns')).':*';
274                        $perm = AUTH_DELETE;
275                    } else {
276                        $where = cleanID($this->getConf('public_pages_ns')).':%USER%';
277                        $perm = AUTH_EDIT;
278                    }
279                    $who = '%USER%';
280                    if (!in_array("$where\t$who\t$perm\n", $existingLines)) { $newLines[] = array('where' => $where, 'who' => $who, 'perm' => $perm); }
281                    // For others
282                    if ($this->getConf('acl_all_public') != 'noacl') {
283                        // If both private and public namespaces are identical, we need to force rights for @ALL and/or @user on each public page
284                        if ($this->getConf('users_namespace') == $this->getConf('public_pages_ns')) {
285                            $files = scandir($this->dataDir.'/pages/'.$this->getConf('public_pages_ns'));
286                            foreach($files as $file) {
287                                if (is_file($this->dataDir.'/pages/'.$this->getConf('public_pages_ns').'/'.$file)) {
288                                    // ACL on templates will be managed another way
289                                    if (strpos($file, 'userhomepage_p') !== 0) {
290                                        // @ALL
291                                        if ($this->getConf('acl_all_public') != 'noacl') {
292                                            $where = $this->getConf('public_pages_ns').':'.substr($file, 0, -4);
293                                            $who = '@ALL';
294                                            $perm = $this->getConf('acl_all_public');
295                                            if (!in_array("$where\t$who\t$perm\n", $existingLines)) { $newLines[] = array('where' => $where, 'who' => $who, 'perm' => $perm); }
296                                        }
297                                        // @user
298                                        if ($this->getConf('acl_user_public') != 'noacl') {
299                                            $where = $this->getConf('public_pages_ns').':'.substr($file, 0, -4);
300                                            $who = '@user';
301                                            $perm = $this->getConf('acl_user_public');
302                                            if (!in_array("$where\t$who\t$perm\n", $existingLines)) { $newLines[] = array('where' => $where, 'who' => $who, 'perm' => $perm); }
303                                        }
304                                    }
305                                }
306                            }
307                        // Otherwise we just need to give the right permission to each group on public pages namespace
308                        } else {
309                            // @ALL
310                            if ($this->getConf('acl_all_public') != 'noacl') {
311                                $where = cleanID(str_replace(':%NAME%:%START%', '', $this->getConf('public_pages_ns'))).':*';
312                                $who = '@ALL';
313                                $perm = $this->getConf('acl_all_public');
314                                if (!in_array("$where\t$who\t$perm\n", $existingLines)) { $newLines[] = array('where' => $where, 'who' => $who, 'perm' => $perm); }
315                            }
316                            // @user
317                            if ($this->getConf('acl_user_public') != 'noacl') {
318                                $where = cleanID(str_replace(':%NAME%:%START%', '', $this->getConf('public_pages_ns'))).':*';
319                                $who = '@user';
320                                $perm = $this->getConf('acl_user_public');
321                                if (!in_array("$where\t$who\t$perm\n", $existingLines)) { $newLines[] = array('where' => $where, 'who' => $who, 'perm' => $perm); }
322                            }
323                        }
324                    }
325                } // end for public pages acl
326                // On templates if they're in data/pages
327                if (strpos($this->getConf('templates_path'),'/pages') !== false) {
328                    // For @ALL
329                    if (($this->getConf('acl_all_templates') != 'noacl') && (($this->getConf('create_private_ns')) or ($this->getConf('create_public_page')))) {
330                        $where = end(explode('/',$this->getConf('templates_path'))).':userhomepage_private';
331                        $who = '@ALL';
332                        $perm = (int)$this->getConf('acl_all_templates');
333                        if (!in_array("$where\t$who\t$perm\n", $existingLines)) { $newLines[] = array('where' => $where, 'who' => $who, 'perm' => $perm); }
334                        $where = end(explode('/',$this->getConf('templates_path'))).':userhomepage_public';
335                        $who = '@ALL';
336                        $perm = (int)$this->getConf('acl_all_templates');
337                        if (!in_array("$where\t$who\t$perm\n", $existingLines)) { $newLines[] = array('where' => $where, 'who' => $who, 'perm' => $perm); }
338                    }
339                    // For @user
340                    if (($this->getConf('acl_user_templates') != 'noacl') && ($this->getConf('acl_user_templates') !== $this->getConf('acl_all_templates')) && (($this->getConf('create_private_ns')) or ($this->getConf('create_public_page')))) {
341                        $where = end(explode('/',$this->getConf('templates_path'))).':userhomepage_private';
342                        $who = '@user';
343                        $perm = (int)$this->getConf('acl_user_templates');
344                        if (!in_array("$where\t$who\t$perm\n", $existingLines)) { $newLines[] = array('where' => $where, 'who' => $who, 'perm' => $perm); }
345                        $where = end(explode('/',$this->getConf('templates_path'))).':userhomepage_public';
346                        $who = '@user';
347                        $perm = (int)$this->getConf('acl_user_templates');
348                        if (!in_array("$where\t$who\t$perm\n", $existingLines)) { $newLines[] = array('where' => $where, 'who' => $who, 'perm' => $perm); }
349                    }
350                } // end of templates acl
351                $i = count($newLines);
352                if ($i > 0) {
353                    msg($this->getLang('aclupdate').' '.$i, 1);
354                    foreach($newLines as $line) {
355                        if (($line['where'] != null) && ($line['who'] != null)) {
356                            // delete potential ACL rule with same scope (aka 'where') and same user (aka 'who')
357                            $acl->deleteACL($line['where'], $line['who']);
358                            $acl->addOrUpdateACL($line['where'], $line['who'], $line['perm']);
359                        }
360                    }
361                }
362            }
363        } else {
364            return false;
365        }
366    }
367
368    function copyFile($source = null, $target_dir = null, $target_file = null) {
369        if (!is_file($this->dataDir.DIRECTORY_SEPARATOR.$target_dir.DIRECTORY_SEPARATOR.$target_file)) {
370            if(!is_dir($this->dataDir.DIRECTORY_SEPARATOR.$target_dir)){
371                io_mkdir_p($this->dataDir.DIRECTORY_SEPARATOR.$target_dir) || msg($this->getLang('mkdirfailure').' '.$target_dir,-1);
372            }
373            $source = str_replace('/', DIRECTORY_SEPARATOR, $source);
374            copy($source, $this->dataDir.DIRECTORY_SEPARATOR.$target_dir.DIRECTORY_SEPARATOR.$target_file);
375            if (is_file($this->dataDir.DIRECTORY_SEPARATOR.$target_dir.DIRECTORY_SEPARATOR.$target_file)) {
376                msg($this->getLang('copysuccess').' ('.$source.' > '.$this->dataDir.DIRECTORY_SEPARATOR.$target_dir.DIRECTORY_SEPARATOR.$target_file.')', 1);
377            } else {
378                msg($this->getLang('copyerror').' ('.$source.' > '.$this->dataDir.DIRECTORY_SEPARATOR.$target_dir.DIRECTORY_SEPARATOR.$target_file.')', -1);
379            }
380        } else {
381            msg($this->getLang('copynotneeded').' ('.$source.' > '.$this->dataDir.DIRECTORY_SEPARATOR.$target_dir.DIRECTORY_SEPARATOR.$target_file.')', 0);
382        }
383    }
384
385    function privateNamespace() {
386        if ( $this->getConf('use_name_string')) {
387            global $INFO;
388            $raw_string = cleanID($INFO['userinfo']['name']);
389            // simon_delage
390            return $raw_string;
391        } else {
392            // simon
393            return strtolower($_SERVER['REMOTE_USER']);
394        }
395    }
396
397    function privateStart() {
398        if ($this->getConf('use_start_page')) {
399            global $conf;
400            return cleanID($conf['start']);
401        } else {
402            return $this->privateNamespace();
403        }
404    }
405
406    function applyTemplate($type) {
407        global $conf;
408        if ($type == 'private') {
409            $content = io_readFile($this->private_page_template, false);
410        } elseif ($type == 'public') {
411            $content = io_readFile($this->public_page_template, false);
412        } else {
413            $content = io_readFile($type, false);
414        }
415        // If template is absolutely empty (ie. is NULL), target file will not be created but plugin will pretend it did and will keep trying over next page load
416        if ($content == NULL) {
417            // fill empty template with a simple space to work around the problem
418            $content = " ";
419        }
420
421        $content = str_replace('@TARGETPRIVATEPAGE@', $this->helper->getPrivateID(), $content);
422        $content = str_replace('@TARGETPRIVATENS@', cleanID(str_replace(':'.$conf['start'], '', $this->helper->getPrivateID())), $content);
423        $content = str_replace('@TARGETPUBLICPAGE@', $this->helper->getPublicID(), $content);
424        $content = str_replace('@TARGETPUBLICNS@', cleanID(str_replace(':'.$conf['start'], '', $this->helper->getPublicID())), $content);
425        // Improved template process to use standard replacement patterns from https://www.dokuwiki.org/namespace_templates based on code proposed by Christian Nancy
426        // Build a fake data structure for the parser
427        $data = array('tpl' => $content, 'id' => $this->private_page);
428        // Use the built-in parser
429        $content = parsePageTemplate($data);
430        return $content;
431    }
432
433    function replaceUserLink(&$event, $param) {
434        global $INFO;
435        global $conf;
436
437        // If there's no conflict between private and public space
438        if ($this->multiNsOk()) {
439            if (($conf['showuseras'] == "username_link") and ($this->getConf('userlink_replace'))) {
440                $classes = $this->getConf('userlink_classes');
441                $classes = str_replace(',', ' ', $classes);
442                //if ($this->getConf('userlink_fa')) {
443                //    $classes = str_replace('interwiki', '', $classes);
444                //}
445                $this->username = $event->data['username'];
446                $this->name = $event->data['name'];
447                $this->link = $event->data['link'];
448                $this->userlink = $event->data['userlink'];
449                $this->textonly = $event->data['textonly'];
450                // Logged in as...
451                if (strpos($this->name, '<bdi>') !== false) {
452                    $privateId = $this->helper->getPrivateID();
453                    $publicId = $this->helper->getPublicID();
454                    if ((page_exists($privateId)) && (page_exists($publicId))) {
455                        if ($this->getConf('userlink_fa')) {
456                            $return = '<a href="'.wl($privateId).'" class="'.$classes.' uhp_fa" rel="nofollow" title="'.$this->getLang('privatenamespace').' ('.$privateId.')'.'"><bdi><i class="fa fa-user-secret"></i>'.$INFO['userinfo']['name'].'</bdi></a> (<a href="'.wl($publicId).'" class="'.$classes.' uhp_fa" rel="nofollow" title="'.$this->getLang('publicpage').' ('.$publicId.')'.'"><bdi><i class="fa fa-user"></i>'.$_SERVER['REMOTE_USER'].'</bdi></a>)';
457                        } else {
458                            $return = '<a href="'.wl($privateId).'" class="'.$classes.' uhp_private_'.$this->getConf('userlink_icons').'" rel="nofollow" title="'.$this->getLang('privatenamespace').' ('.$privateId.')'.'"><bdi>'.$INFO['userinfo']['name'].'</bdi></a> (<a href="'.wl($publicId).'" class="'.$classes.' uhp_public_'.$this->getConf('userlink_icons').'" rel="nofollow" title="'.$this->getLang('publicpage').' ('.$publicId.')'.'"><bdi>'.$_SERVER['REMOTE_USER'].'</bdi></a>)';
459                        }
460                    } elseif (page_exists($publicId)) {
461                        if ($this->getConf('userlink_fa')) {
462                            $return = '</a> (<a href="'.wl($publicId).'" class="'.$classes.' uhp_fa" rel="nofollow" title="'.$this->getLang('publicpage').'('.$publicId.')'.'"><bdi><i class="fa fa-user"></i>'.$_SERVER['REMOTE_USER'].'</bdi></a>)';
463                        } else {
464                            $return = '<bdi>'.$INFO['userinfo']['name'].'</bdi> (<a href="'.wl($publicId).'" class="'.$classes.' uhp_public_'.$this->getConf('userlink_icons').'" rel="nofollow" title="'.$this->getLang('publicpage').' ('.$publicId.')'.'"><bdi>'.$_SERVER['REMOTE_USER'].'</bdi></a>)';
465                        }
466                    } elseif (page_exists($privateId)) {
467                        if ($this->getConf('userlink_fa')) {
468                            $return = '<a href="'.wl($privateId).'" class="'.$classes.' uhp_fa" rel="nofollow" title="'.$this->getLang('privatenamespace').' ('.$privateId.')'.'"><bdi><i class="fa fa-user-secret"></i>'.$INFO['userinfo']['name'].'</bdi></a>';
469                        } else {
470                            $return = '<a href="'.wl($privateId).'" class="'.$classes.' uhp_private_'.$this->getConf('userlink_icons').'" rel="nofollow" title="'.$this->getLang('privatenamespace').' ('.$privateId.')'.'"><bdi>'.$INFO['userinfo']['name'].'</bdi></a> (<bdi>'.$_SERVER['REMOTE_USER'].'</bdi>)';
471                        }
472                    } else {
473                        $return = null;
474                    }
475                // ... or Last modified...
476                } else {
477                    // No change for this right now
478                    $return = null;
479                }
480                if ($return != null) {
481                    $event->data = array(
482                        'username' => $this->username,
483                        'name' => $this->name,
484                        'link' => $this->link,
485                        'userlink' => $return,
486                        'textonly' => $this->textonly
487                    );
488                }
489            }
490        } else {
491            return false;
492        }
493    }
494
495    function multiNsOk($msg=false) {
496        // Error: Public page switched to namespace and is in conflict with Private namespace
497        if (strpos($this->getConf('public_pages_ns'),':%NAME%:%START%') !== false) {
498            $PublicNS = str_replace(':%NAME%:%START%', '', $this->getConf('public_pages_ns'));
499            $PublicNS = str_replace(':', '', $PublicNS);
500            $PrivateNS = str_replace(':', '', $this->getConf('users_namespace'));
501            if ($PublicNS == $PrivateNS) {
502                if ($msg) {
503                    msg($this->getLang('settingsconflict'), -1);
504                }
505                return false;
506            } else {
507                return true;
508            }
509        } else {
510            return true;
511        }
512    }
513
514    function userOk($check = null) {
515        global $INFO;
516
517        // Proceed only if named user is connected...
518        if ($_SERVER['REMOTE_USER'] != null) {
519            // Check if user is member of a group in 'groups_private' or 'groups_public' (depending on $check)
520            if (($check == 'private') or ($check == 'public')) {
521                // Stop if 'groups_private' is set and and user is not member of at least one of said groups
522                $groups = $this->getConf('groups_'.$check);
523                $groups = str_replace(' ','', $groups);
524                $groups = explode(',', $groups);
525                $userGroups = $INFO['userinfo']['grps'];
526                // If UHP is set to check user's group(s)
527                if (($groups != null) and ($groups[0] != null) and ($userGroups != null)) {
528                    $test = array_intersect($groups, $userGroups);
529                    // Proceed if user is member of at least one group set UHP's corresponding setting
530                    if (count($test) > 0) {
531                        return true;
532                    } else {
533                        return false;
534                    }
535                // If UHP isn't set to ckeck user's group(s) we can proceed
536                } else {
537                    return true;
538                }
539            // If $check is null, we only need to know that a named user is connected (wich we allready know if we went that far)
540            } else {
541                return true;
542            }
543        // ... else stop
544        } else {
545            return false;
546        }
547    }
548
549}
550