]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/PagePerm.php
Remove FPDF
[SourceForge/phpwiki.git] / lib / PagePerm.php
1 <?php
2
3 /*
4  * Copyright 2004,2007 $ThePhpWikiProgrammingTeam
5  * Copyright 2009-2010 Marc-Etienne Vargenau, Alcatel-Lucent
6  *
7  * This file is part of PhpWiki.
8  *
9  * PhpWiki is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * PhpWiki is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 /**
25  * Permissions per page and action based on current user,
26  * ownership and group membership implemented with ACL's (Access Control Lists),
27  * opposed to the simplier unix-like ugo:rwx system.
28  * The previous system was only based on action and current user. (lib/main.php)
29  *
30  * Permissions may be inherited from its parent pages, a optional the
31  * optional master page ("."), and predefined default permissions, if "."
32  * is not defined.
33  * Pagenames starting with "." have special default permissions.
34  * For Authentication see WikiUser.php, WikiGroup.php and main.php
35  * Page Permissions are in PhpWiki since v1.3.9 and enabled since v1.4.0
36  *
37  * This file might replace the following functions from main.php:
38  *   Request::_notAuthorized($require_level)
39  *     display the denied message and optionally a login form
40  *     to gain higher privileges
41  *   Request::getActionDescription($action)
42  *     helper to localize the _notAuthorized message per action,
43  *     when login is tried.
44  *   Request::getDisallowedActionDescription($action)
45  *     helper to localize the _notAuthorized message per action,
46  *     when it aborts
47  *   Request::requiredAuthority($action)
48  *     returns the needed user level
49  *     has a hook for plugins on POST
50  *   Request::requiredAuthorityForAction($action)
51  *     just returns the level per action, will be replaced with the
52  *     action + page pair
53  *
54  *   The defined main.php actions map to simplier access types:
55  *     browse => view
56  *     edit   => edit
57  *     create => edit or create
58  *     remove => remove
59  *     rename => change
60  *     store prefs => change
61  *     list in PageList => list
62  */
63
64 /* Symbolic special ACL groups. Untranslated to be stored in page metadata*/
65 define('ACL_EVERY', '_EVERY');
66 define('ACL_ANONYMOUS', '_ANONYMOUS');
67 define('ACL_BOGOUSER', '_BOGOUSER');
68 define('ACL_HASHOMEPAGE', '_HASHOMEPAGE');
69 define('ACL_SIGNED', '_SIGNED');
70 define('ACL_AUTHENTICATED', '_AUTHENTICATED');
71 define('ACL_ADMIN', '_ADMIN');
72 define('ACL_OWNER', '_OWNER');
73 define('ACL_CREATOR', '_CREATOR');
74
75 // Return an page permissions array for this page.
76 // To provide ui helpers to view and change page permissions:
77 //   <tr><th>Group</th><th>Access</th><th>Allow or Forbid</th></tr>
78 //   <tr><td>$group</td><td>_($access)</td><td> [ ] </td></tr>
79 function pagePermissions($pagename)
80 {
81     global $request;
82     $page = $request->getPage($pagename);
83     // Page not found (new page); returned inherited permissions, to be displayed in gray
84     if (!$page->exists()) {
85         if ($pagename == '.') // stop recursion
86             return array('default', new PagePermission());
87         else {
88             return array('inherited', pagePermissions(getParentPage($pagename)));
89         }
90     } elseif ($perm = getPagePermissions($page)) {
91         return array('page', $perm);
92         // or no permissions defined; returned inherited permissions, to be displayed in gray
93     } elseif ($pagename == '.') { // stop recursion in pathological case.
94         // "." defined, without any acl
95         return array('default', new PagePermission());
96     } else {
97         return array('inherited', pagePermissions(getParentPage($pagename)));
98     }
99 }
100
101 function pagePermissionsSimpleFormat($perm_tree, $owner, $group = false)
102 {
103     list($type, $perm) = pagePermissionsAcl($perm_tree[0], $perm_tree);
104     /*
105     $type = $perm_tree[0];
106     $perm = pagePermissionsAcl($perm_tree);
107     if (is_object($perm_tree[1]))
108         $perm = $perm_tree[1];
109     elseif (is_array($perm_tree[1])) {
110         $perm_tree = pagePermissionsSimpleFormat($perm_tree[1],$owner,$group);
111     if (is_a($perm_tree[1],'pagepermission'))
112         $perm = $perm_tree[1];
113     elseif (is_a($perm_tree,'htmlelement'))
114             return $perm_tree;
115     }
116     */
117     if ($type == 'page')
118         return HTML::samp(HTML::strong($perm->asRwxString($owner, $group)));
119     elseif ($type == 'default')
120         return HTML::samp($perm->asRwxString($owner, $group)); elseif ($type == 'inherited') {
121         return HTML::samp(array('class' => 'inherited', 'style' => 'color:#aaa;'),
122             $perm->asRwxString($owner, $group));
123     }
124 }
125
126 function pagePermissionsAcl($type, $perm_tree)
127 {
128     $perm = $perm_tree[1];
129     while (!is_object($perm)) {
130         $perm_tree = pagePermissionsAcl($type, $perm);
131         $perm = $perm_tree[1];
132     }
133     return array($type, $perm);
134 }
135
136 // view => who
137 // edit => who
138 function pagePermissionsAclFormat($perm_tree, $editable = false)
139 {
140     list($type, $perm) = pagePermissionsAcl($perm_tree[0], $perm_tree);
141     if ($editable)
142         return $perm->asEditableTable($type);
143     else
144         return $perm->asTable($type);
145 }
146
147 /**
148  * Check the permissions for the current action.
149  * Walk down the inheritance tree. Collect all permissions until
150  * the minimum required level is gained, which is not
151  * overruled by more specific forbid rules.
152  * Todo: cache result per access and page in session?
153  */
154 function requiredAuthorityForPage($action)
155 {
156     global $request;
157     $auth = _requiredAuthorityForPagename(action2access($action),
158         $request->getArg('pagename'));
159     assert($auth !== -1);
160     if ($auth)
161         return $request->_user->_level;
162     else
163         return WIKIAUTH_UNOBTAINABLE;
164 }
165
166 // Translate action or plugin to the simplier access types:
167 function action2access($action)
168 {
169     global $request;
170     switch ($action) {
171         case 'browse':
172         case 'viewsource':
173         case 'diff':
174         case 'select':
175         case 'search':
176         case 'pdf':
177         case 'captcha':
178             return 'view';
179
180         // performance and security relevant
181         case 'xmlrpc':
182         case 'soap':
183         case 'zip':
184         case 'ziphtml':
185         case 'dumphtml':
186         case 'dumpserial':
187             return 'dump';
188
189         // invent a new access-perm massedit? or switch back to change, or keep it at edit?
190         case _("PhpWikiAdministration") . "/" . _("Rename"):
191         case _("PhpWikiAdministration") . "/" . _("SearchReplace"):
192         case 'replace':
193         case 'rename':
194         case 'revert':
195         case 'edit':
196             return 'edit';
197         case 'create':
198             $page = $request->getPage();
199             if (!$page->exists())
200                 return 'create';
201             else
202                 return 'view';
203             break;
204         case 'upload':
205         case 'loadfile':
206             // probably create/edit but we cannot check all page permissions, can we?
207         case 'remove':
208         case 'purge':
209         case 'lock':
210         case 'unlock':
211         case 'upgrade':
212         case 'chown':
213         case 'setacl':
214         case 'deleteacl':
215             return 'change';
216         default:
217             //Todo: Plugins should be able to override its access type
218             if (isWikiWord($action))
219                 return 'view';
220             else
221                 return 'change';
222             break;
223     }
224 }
225
226 // Recursive helper to do the real work.
227 // Using a simple perm cache for page-access pairs.
228 // Maybe page-(current+edit+change?)action pairs will help
229 function _requiredAuthorityForPagename($access, $pagename)
230 {
231     static $permcache = array();
232
233     if (array_key_exists($pagename, $permcache)
234         and array_key_exists($access, $permcache[$pagename])
235     )
236         return $permcache[$pagename][$access];
237
238     global $request;
239     $page = $request->getPage($pagename);
240
241     // Exceptions:
242     if (defined('FUSIONFORGE') and FUSIONFORGE) {
243         if ($pagename != '.' && isset($request->_user->_is_external) && $request->_user->_is_external && !$page->get('external')) {
244             $permcache[$pagename][$access] = 0;
245             return 0;
246         }
247     }
248     if ((READONLY or $request->_dbi->readonly)
249         and in_array($access, array('edit', 'create', 'change'))
250     ) {
251         return 0;
252     }
253
254     // Page not found; check against default permissions
255     if (!$page->exists()) {
256         $perm = new PagePermission();
257         $result = ($perm->isAuthorized($access, $request->_user) === true);
258         $permcache[$pagename][$access] = $result;
259         return $result;
260     }
261     // no ACL defined; check for special dotfile or walk down
262     if (!($perm = getPagePermissions($page))) {
263         if ($pagename == '.') {
264             $perm = new PagePermission();
265             if ($perm->isAuthorized('change', $request->_user)) {
266                 // warn the user to set ACL of ".", if he has permissions to do so.
267                 trigger_error(". (dotpage == rootpage for inheriting pageperm ACLs) exists without any ACL!\n" .
268                     "Please do ?action=setacl&pagename=.", E_USER_WARNING);
269             }
270             $result = ($perm->isAuthorized($access, $request->_user) === true);
271             $permcache[$pagename][$access] = $result;
272             return $result;
273         } elseif ($pagename[0] == '.') {
274             $perm = new PagePermission(PagePermission::dotPerms());
275             $result = ($perm->isAuthorized($access, $request->_user) === true);
276             $permcache[$pagename][$access] = $result;
277             return $result;
278         }
279         return _requiredAuthorityForPagename($access, getParentPage($pagename));
280     }
281     // ACL defined; check if isAuthorized returns true or false or undecided
282     $authorized = $perm->isAuthorized($access, $request->_user);
283     if ($authorized !== -1) { // interestingly true is also -1
284         $permcache[$pagename][$access] = $authorized;
285         return $authorized;
286     } elseif ($pagename == '.') {
287         return false;
288     } else {
289         return _requiredAuthorityForPagename($access, getParentPage($pagename));
290     }
291 }
292
293 /**
294  * @param  string $pagename   page from which the parent page is searched.
295  * @return string parent      pagename or the (possibly pseudo) dot-pagename.
296  */
297 function getParentPage($pagename)
298 {
299     if (isSubPage($pagename)) {
300         return subPageSlice($pagename, 0);
301     } else {
302         return '.';
303     }
304 }
305
306 // Read the ACL from the page
307 // Done: Not existing pages should NOT be queried.
308 // Check the parent page instead and don't take the default ACL's
309 function getPagePermissions($page)
310 {
311     if ($hash = $page->get('perm')) // hash => object
312         return new PagePermission(unserialize($hash));
313     else
314         return false;
315 }
316
317 // Store the ACL in the page
318 function setPagePermissions($page, $perm)
319 {
320     $perm->store($page);
321 }
322
323 function getAccessDescription($access)
324 {
325     static $accessDescriptions;
326     if (!$accessDescriptions) {
327         $accessDescriptions = array(
328             'list' => _("List this page and all subpages"),
329             'view' => _("View this page and all subpages"),
330             'edit' => _("Edit this page and all subpages"),
331             'create' => _("Create a new (sub)page"),
332             'dump' => _("Download page contents"),
333             'change' => _("Change page attributes"),
334             'remove' => _("Remove this page"),
335             'purge' => _("Purge this page"),
336         );
337     }
338     if (in_array($access, array_keys($accessDescriptions)))
339         return $accessDescriptions[$access];
340     else
341         return $access;
342 }
343
344 /**
345  * The ACL object per page. It is stored in a page, but can also
346  * be merged with ACL's from other pages or taken from the master (pseudo) dot-file.
347  *
348  * A hash of "access" => "requires" pairs.
349  *   "access"   is a shortcut for common actions, which map to main.php actions
350  *   "requires" required username or groupname or any special group => true or false
351  *
352  * Define any special rules here, like don't list dot-pages.
353  */
354 class PagePermission
355 {
356     public $perm;
357
358     function PagePermission($hash = array())
359     {
360         $this->_group = &$GLOBALS['request']->getGroup();
361         if (is_array($hash) and !empty($hash)) {
362             $accessTypes = $this->accessTypes();
363             foreach ($hash as $access => $requires) {
364                 if (in_array($access, $accessTypes))
365                     $this->perm[$access] = $requires;
366                 else
367                     trigger_error(sprintf(_("Unsupported ACL access type %s ignored."), $access),
368                         E_USER_WARNING);
369             }
370         } else {
371             // set default permissions, the so called dot-file acl's
372             $this->perm = $this->defaultPerms();
373         }
374         return $this;
375     }
376
377     /**
378      * The workhorse to check the user against the current ACL pairs.
379      * Must translate the various special groups to the actual users settings
380      * (userid, group membership).
381      */
382     function isAuthorized($access, $user)
383     {
384         // Admin can see all pages, regardless of access rights
385         if ($user->isAdmin()) {
386             return true;
387         }
388         $allow = -1;
389         if (!empty($this->perm{$access})) {
390             foreach ($this->perm[$access] as $group => $bool) {
391                 if ($this->isMember($user, $group)) {
392                     return $bool;
393                 } elseif ($allow == -1) { // not a member and undecided: check other groups
394                     $allow = !$bool;
395                 }
396             }
397         }
398         return $allow; // undecided
399     }
400
401     /**
402      * Translate the various special groups to the actual users settings
403      * (userid, group membership).
404      */
405     function isMember($user, $group)
406     {
407         global $request;
408         if ($group === ACL_EVERY) return true;
409         if (!isset($this->_group)) $member =& $request->getGroup();
410         else $member =& $this->_group;
411         //$user = & $request->_user;
412         if ($group === ACL_ADMIN) // WIKI_ADMIN or member of _("Administrators")
413             return $user->isAdmin() or
414                 ($user->isAuthenticated() and
415                     $member->isMember(GROUP_ADMIN));
416         if ($group === ACL_ANONYMOUS)
417             return !$user->isSignedIn();
418         if ($group === ACL_BOGOUSER)
419             return is_a($user, '_BogoUser') or
420                     (isWikiWord($user->_userid) and $user->_level >= WIKIAUTH_BOGO);
421         if ($group === ACL_HASHOMEPAGE)
422             return $user->hasHomePage();
423         if ($group === ACL_SIGNED)
424             return $user->isSignedIn();
425         if ($group === ACL_AUTHENTICATED)
426             return $user->isAuthenticated();
427         if ($group === ACL_OWNER) {
428             if (!$user->isAuthenticated()) return false;
429             $page = $request->getPage();
430             $owner = $page->getOwner();
431             return ($owner === $user->UserName()
432                 or $member->isMember($owner));
433         }
434         if ($group === ACL_CREATOR) {
435             if (!$user->isAuthenticated()) return false;
436             $page = $request->getPage();
437             $creator = $page->getCreator();
438             return ($creator === $user->UserName()
439                 or $member->isMember($creator));
440         }
441         /* Or named groups or usernames.
442            Note: We don't separate groups and users here.
443            Users overrides groups with the same name.
444         */
445         return $user->UserName() === $group or
446             $member->isMember($group);
447     }
448
449     /**
450      * returns hash of default permissions.
451      * check if the page '.' exists and returns this instead.
452      */
453     function defaultPerms()
454     {
455         //Todo: check for the existance of '.' and take this instead.
456         //Todo: honor more config.ini auth settings here
457         $perm = array('view' => array(ACL_EVERY => true),
458             'edit' => array(ACL_EVERY => true),
459             'create' => array(ACL_EVERY => true),
460             'list' => array(ACL_EVERY => true),
461             'remove' => array(ACL_ADMIN => true,
462                 ACL_OWNER => true),
463             'purge' => array(ACL_ADMIN => true,
464                 ACL_OWNER => true),
465             'dump' => array(ACL_ADMIN => true,
466                 ACL_OWNER => true),
467             'change' => array(ACL_ADMIN => true,
468                 ACL_OWNER => true));
469         if (ZIPDUMP_AUTH)
470             $perm['dump'] = array(ACL_ADMIN => true,
471                 ACL_OWNER => true);
472         elseif (INSECURE_ACTIONS_LOCALHOST_ONLY) {
473             if (is_localhost())
474                 $perm['dump'] = array(ACL_EVERY => true);
475             else
476                 $perm['dump'] = array(ACL_ADMIN => true);
477         } else
478             $perm['dump'] = array(ACL_EVERY => true);
479         if (defined('REQUIRE_SIGNIN_BEFORE_EDIT') && REQUIRE_SIGNIN_BEFORE_EDIT)
480             $perm['edit'] = array(ACL_SIGNED => true);
481         // view:
482         if (!ALLOW_ANON_USER) {
483             if (!ALLOW_USER_PASSWORDS)
484                 $perm['view'] = array(ACL_SIGNED => true);
485             else
486                 $perm['view'] = array(ACL_AUTHENTICATED => true);
487             $perm['view'][ACL_BOGOUSER] = ALLOW_BOGO_LOGIN ? true : false;
488         }
489         // edit:
490         if (!ALLOW_ANON_EDIT) {
491             if (!ALLOW_USER_PASSWORDS)
492                 $perm['edit'] = array(ACL_SIGNED => true);
493             else
494                 $perm['edit'] = array(ACL_AUTHENTICATED => true);
495             $perm['edit'][ACL_BOGOUSER] = ALLOW_BOGO_LOGIN ? true : false;
496             $perm['create'] = $perm['edit'];
497         }
498         return $perm;
499     }
500
501     /**
502      * FIXME: check valid groups and access
503      */
504     function sanify()
505     {
506         foreach ($this->perm as $access => $groups) {
507             foreach ($groups as $group => $bool) {
508                 $this->perm[$access][$group] = (boolean)$bool;
509             }
510         }
511     }
512
513     /**
514      * do a recursive comparison
515      */
516     function equal($otherperm)
517     {
518         // The equal function seems to be unable to detect removed perm.
519         // Use case is when a rule is removed.
520         return (print_r($this->perm, true) === print_r($otherperm, true));
521     }
522
523     /**
524      * returns list of all supported access types.
525      */
526     function accessTypes()
527     {
528         return array_keys(PagePermission::defaultPerms());
529     }
530
531     /**
532      * special permissions for dot-files, beginning with '.'
533      * maybe also for '_' files?
534      */
535     function dotPerms()
536     {
537         $def = array(ACL_ADMIN => true,
538             ACL_OWNER => true);
539         $perm = array();
540         foreach (PagePermission::accessTypes() as $access) {
541             $perm[$access] = $def;
542         }
543         return $perm;
544     }
545
546     /**
547      *  dead code. not needed inside the object. see getPagePermissions($page)
548      */
549     function retrieve($page)
550     {
551         $hash = $page->get('perm');
552         if ($hash) // hash => object
553             $perm = new PagePermission(unserialize($hash));
554         else
555             $perm = new PagePermission();
556         $perm->sanify();
557         return $perm;
558     }
559
560     function store($page)
561     {
562         // object => hash
563         $this->sanify();
564         return $page->set('perm', serialize($this->perm));
565     }
566
567     function groupName($group)
568     {
569         if ($group[0] == '_') return constant("GROUP" . $group);
570         else return $group;
571     }
572
573     /* type: page, default, inherited */
574     function asTable($type)
575     {
576         $table = HTML::table();
577         foreach ($this->perm as $access => $perms) {
578             $td = HTML::table(array('class' => 'cal'));
579             foreach ($perms as $group => $bool) {
580                 $td->pushContent(HTML::tr(HTML::td(array('align' => 'right'), $group),
581                     HTML::td($bool ? '[X]' : '[ ]')));
582             }
583             $table->pushContent(HTML::tr(array('class' => 'top'),
584                 HTML::td($access), HTML::td($td)));
585         }
586         if ($type == 'default')
587             $table->setAttr('style', 'border: dotted thin black; background-color:#eee;');
588         elseif ($type == 'inherited')
589             $table->setAttr('style', 'border: dotted thin black; background-color:#ddd;'); elseif ($type == 'page')
590             $table->setAttr('style', 'border: solid thin black; font-weight: bold;');
591         return $table;
592     }
593
594     /* type: page, default, inherited */
595     function asEditableTable($type)
596     {
597         global $WikiTheme;
598         if (!isset($this->_group)) {
599             $this->_group =& $GLOBALS['request']->getGroup();
600         }
601         $table = HTML::table();
602         $table->pushContent(HTML::tr(
603             HTML::th(array('align' => 'left'),
604                 _("Access")),
605             HTML::th(array('align' => 'right'),
606                 _("Group/User")),
607             HTML::th(_("Grant")),
608             HTML::th(_("Del/+")),
609             HTML::th(_("Description"))));
610
611         $allGroups = $this->_group->_specialGroups();
612         foreach ($this->_group->getAllGroupsIn() as $group) {
613             if (!in_array($group, $this->_group->specialGroups()))
614                 $allGroups[] = $group;
615         }
616         //array_unique(array_merge($this->_group->getAllGroupsIn(),
617         $deletesrc = $WikiTheme->_findData('images/delete.png');
618         $addsrc = $WikiTheme->_findData('images/add.png');
619         $nbsp = HTML::raw('&nbsp;');
620         foreach ($this->perm as $access => $groups) {
621             //$permlist = HTML::table(array('class' => 'cal'));
622             $first_only = true;
623             $newperm = HTML::input(array('type' => 'checkbox',
624                 'name' => "acl[_new_perm][$access]",
625                 'value' => 1));
626             $addbutton = HTML::input(array('type' => 'checkbox',
627                 'name' => "acl[_add_group][$access]",
628                 //'src'  => $addsrc,
629                 //'alt'   => "Add",
630                 'title' => _("Add this ACL"),
631                 'value' => 1));
632             $newgroup = HTML::select(array('name' => "acl[_new_group][$access]",
633                 'style' => 'text-align: right;',
634                 'size' => 1));
635             foreach ($allGroups as $groupname) {
636                 if (!isset($groups[$groupname]))
637                     $newgroup->pushContent(HTML::option(array('value' => $groupname),
638                         $this->groupName($groupname)));
639             }
640             if (empty($groups)) {
641                 $addbutton->setAttr('checked', 'checked');
642                 $newperm->setAttr('checked', 'checked');
643                 $table->pushContent(
644                     HTML::tr(array('class' => 'top'),
645                         HTML::td(HTML::strong($access . ":")),
646                         HTML::td($newgroup),
647                         HTML::td($nbsp, $newperm),
648                         HTML::td($nbsp, $addbutton),
649                         HTML::td(HTML::em(getAccessDescription($access)))));
650             }
651             foreach ($groups as $group => $bool) {
652                 $checkbox = HTML::input(array('type' => 'checkbox',
653                     'name' => "acl[$access][$group]",
654                     'title' => _("Allow / Deny"),
655                     'value' => 1));
656                 if ($bool) $checkbox->setAttr('checked', 'checked');
657                 $checkbox = HTML(HTML::input(array('type' => 'hidden',
658                         'name' => "acl[$access][$group]",
659                         'value' => 0)),
660                     $checkbox);
661                 $deletebutton = HTML::input(array('type' => 'checkbox',
662                     'name' => "acl[_del_group][$access][$group]",
663                     'style' => 'background: #aaa url(' . $deletesrc . ')',
664                     //'src'  => $deletesrc,
665                     //'alt'   => "Del",
666                     'title' => _("Delete this ACL"),
667                     'value' => 1));
668                 if ($first_only) {
669                     $table->pushContent(
670                         HTML::tr(
671                             HTML::td(HTML::strong($access . ":")),
672                             HTML::td(array('class' => 'cal-today', 'align' => 'right'),
673                                 HTML::strong($this->groupName($group))),
674                             HTML::td(array('align' => 'center'), $nbsp, $checkbox),
675                             HTML::td(array('align' => 'right', 'style' => 'background: #aaa url(' . $deletesrc . ') no-repeat'), $deletebutton),
676                             HTML::td(HTML::em(getAccessDescription($access)))));
677                     $first_only = false;
678                 } else {
679                     $table->pushContent(
680                         HTML::tr(
681                             HTML::td(),
682                             HTML::td(array('class' => 'cal-today', 'align' => 'right'),
683                                 HTML::strong($this->groupName($group))),
684                             HTML::td(array('align' => 'center'), $nbsp, $checkbox),
685                             HTML::td(array('align' => 'right', 'style' => 'background: #aaa url(' . $deletesrc . ') no-repeat'), $deletebutton),
686                             HTML::td()));
687                 }
688             }
689             if (!empty($groups))
690                 $table->pushContent(
691                     HTML::tr(array('class' => 'top'),
692                         HTML::td(array('align' => 'right'), _("add ")),
693                         HTML::td($newgroup),
694                         HTML::td(array('align' => 'center'), $nbsp, $newperm),
695                         HTML::td(array('align' => 'right', 'style' => 'background: #ccc url(' . $addsrc . ') no-repeat'), $addbutton),
696                         HTML::td(HTML::small(_("Check to add this ACL")))));
697         }
698         if ($type == 'default')
699             $table->setAttr('style', 'border: dotted thin black; background-color:#eee;');
700         elseif ($type == 'inherited')
701             $table->setAttr('style', 'border: dotted thin black; background-color:#ddd;'); elseif ($type == 'page')
702             $table->setAttr('style', 'border: solid thin black; font-weight: bold;');
703         return $table;
704     }
705
706     // Print ACL as lines of [+-]user[,group,...]:access[,access...]
707     // Seperate acl's by "; " or whitespace
708     // See http://opag.ca/wiki/HelpOnAccessControlLists
709     // As used by WikiAdminSetAclSimple
710     function asAclLines()
711     {
712         $s = '';
713         $line = '';
714         $this->sanify();
715         foreach ($this->perm as $access => $groups) {
716             // unify groups for same access+bool
717             //    view:CREATOR,-OWNER,
718             $line = $access . ':';
719             foreach ($groups as $group => $bool) {
720                 $line .= ($bool ? '' : '-') . $group . ",";
721             }
722             if (substr($line, -1) == ',')
723                 $s .= substr($line, 0, -1) . "; ";
724         }
725         if (substr($s, -2) == '; ')
726             $s = substr($s, 0, -2);
727         return $s;
728     }
729
730     // This is just a bad hack for testing.
731     // Simplify the ACL to a unix-like "rwx------+" string
732     // See getfacl(8)
733     function asRwxString($owner, $group = false)
734     {
735         global $request;
736         // simplify object => rwxrw---x+ string as in cygwin (+ denotes additional ACLs)
737         $perm =& $this->perm;
738         // get effective user and group
739         $s = '---------+';
740         if (isset($perm['view'][$owner]) or
741             (isset($perm['view'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated())
742         )
743             $s[0] = 'r';
744         if (isset($perm['edit'][$owner]) or
745             (isset($perm['edit'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated())
746         )
747             $s[1] = 'w';
748         if (isset($perm['change'][$owner]) or
749             (isset($perm['change'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated())
750         )
751             $s[2] = 'x';
752         if (!empty($group)) {
753             if (isset($perm['view'][$group]) or
754                 (isset($perm['view'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated())
755             )
756                 $s[3] = 'r';
757             if (isset($perm['edit'][$group]) or
758                 (isset($perm['edit'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated())
759             )
760                 $s[4] = 'w';
761             if (isset($perm['change'][$group]) or
762                 (isset($perm['change'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated())
763             )
764                 $s[5] = 'x';
765         }
766         if (isset($perm['view'][ACL_EVERY]) or
767             (isset($perm['view'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated())
768         )
769             $s[6] = 'r';
770         if (isset($perm['edit'][ACL_EVERY]) or
771             (isset($perm['edit'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated())
772         )
773             $s[7] = 'w';
774         if (isset($perm['change'][ACL_EVERY]) or
775             (isset($perm['change'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated())
776         )
777             $s[8] = 'x';
778         return $s;
779     }
780 }
781
782 // Local Variables:
783 // mode: php
784 // tab-width: 8
785 // c-basic-offset: 4
786 // c-hanging-comment-ender-p: nil
787 // indent-tabs-mode: nil
788 // End: