]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/PagePerm.php
Normalize header
[SourceForge/phpwiki.git] / lib / PagePerm.php
1 <?php // -*-php-*-
2 rcs_id('$Id$');
3 /*
4  * Copyright 2004,2007 $ThePhpWikiProgrammingTeam
5  * Copyright 2009 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
20  * along with PhpWiki; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 WikiUserNew.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     global $request;
81     $page = $request->getPage($pagename);
82     // Page not found (new page); returned inherited permissions, to be displayed in gray
83     if (! $page->exists() ) {
84         if ($pagename == '.') // stop recursion
85             return array('default', new PagePermission());
86         else {
87             return array('inherited', pagePermissions(getParentPage($pagename)));
88         }
89     } elseif ($perm = getPagePermissions($page)) {
90         return array('page', $perm);
91     // or no permissions defined; returned inherited permissions, to be displayed in gray
92     } elseif ($pagename == '.') { // stop recursion in pathological case. 
93         // "." defined, without any acl
94         return array('default', new PagePermission());
95     } else {
96         return array('inherited', pagePermissions(getParentPage($pagename)));
97     }
98 }
99
100 function pagePermissionsSimpleFormat($perm_tree, $owner, $group=false) {
101     list($type,$perm) = pagePermissionsAcl($perm_tree[0], $perm_tree);
102     /*
103     $type = $perm_tree[0];
104     $perm = pagePermissionsAcl($perm_tree);
105     if (is_object($perm_tree[1]))
106         $perm = $perm_tree[1];
107     elseif (is_array($perm_tree[1])) {
108         $perm_tree = pagePermissionsSimpleFormat($perm_tree[1],$owner,$group);
109         if (isa($perm_tree[1],'pagepermission'))
110             $perm = $perm_tree[1];
111         elseif (isa($perm_tree,'htmlelement'))
112             return $perm_tree;
113     }
114     */
115     if ($type == 'page')
116         return HTML::tt(HTML::strong($perm->asRwxString($owner, $group)));
117     elseif ($type == 'default')
118         return HTML::tt($perm->asRwxString($owner, $group));
119     elseif ($type == 'inherited') {
120         return HTML::tt(array('class'=>'inherited', 'style'=>'color:#aaa;'),
121                         $perm->asRwxString($owner, $group));
122     }
123 }
124
125 function pagePermissionsAcl($type,$perm_tree) {
126     $perm = $perm_tree[1];
127     while (!is_object($perm)) {
128         $perm_tree = pagePermissionsAcl($type, $perm);
129         $perm = $perm_tree[1];
130     }
131     return array($type,$perm);
132 }
133
134 // view => who
135 // edit => who
136 function pagePermissionsAclFormat($perm_tree, $editable=false) {
137     list($type,$perm) = pagePermissionsAcl($perm_tree[0], $perm_tree);
138     if ($editable)
139         return $perm->asEditableTable($type);
140     else
141         return $perm->asTable($type);
142 }
143
144 /** 
145  * Check the permissions for the current action.
146  * Walk down the inheritance tree. Collect all permissions until 
147  * the minimum required level is gained, which is not 
148  * overruled by more specific forbid rules.
149  * Todo: cache result per access and page in session?
150  */
151 function requiredAuthorityForPage ($action) {
152     global $request;
153     $auth = _requiredAuthorityForPagename(action2access($action),
154                                           $request->getArg('pagename'));
155     assert($auth !== -1);
156     if ($auth)
157         return $request->_user->_level;
158     else
159         return WIKIAUTH_UNOBTAINABLE;
160 }
161
162 // Translate action or plugin to the simplier access types:
163 function action2access ($action) {
164     global $request;
165     switch ($action) {
166     case 'browse':
167     case 'viewsource':
168     case 'diff':
169     case 'select':
170     case 'search':
171     case 'pdf':
172     case 'captcha':
173     case 'zip':
174         return 'view';
175
176     case 'dumpserial':
177         if (INSECURE_ACTIONS_LOCALHOST_ONLY and is_localhost())
178             return 'dump';
179         else
180             return 'view';
181
182     // performance and security relevant
183     case 'xmlrpc':
184     case 'soap':
185     case 'ziphtml':
186     case 'dumphtml':
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")."/"._("Replace"):
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         return 'change';
215     default:
216         //Todo: Plugins should be able to override its access type
217         if (isWikiWord($action))
218             return 'view';
219         else
220             return 'change';
221         break;
222     }
223 }
224
225 // Recursive helper to do the real work.
226 // Using a simple perm cache for page-access pairs.
227 // Maybe page-(current+edit+change?)action pairs will help
228 function _requiredAuthorityForPagename($access, $pagename) {
229     static $permcache = array();
230     
231     if (array_key_exists($pagename, $permcache)
232         and array_key_exists($access, $permcache[$pagename]))
233         return $permcache[$pagename][$access];
234         
235     global $request;
236     $page = $request->getPage($pagename);
237
238     // Exceptions:
239     if (defined('GFORGE') and GFORGE) {
240         if ($pagename != '.' && isset($request->_user->_is_external) && $request->_user->_is_external && ! $page->get('external')) {
241                 $permcache[$pagename][$access] = 0;
242                 return 0;
243         }
244     }
245     if ((READONLY or $request->_dbi->readonly)
246         and in_array($access, array('edit','create','change')))
247     {
248         return 0;
249     }
250
251     // Page not found; check against default permissions
252     if (! $page->exists() ) {
253         $perm = new PagePermission();
254         $result = ($perm->isAuthorized($access, $request->_user) === true);
255         $permcache[$pagename][$access] = $result;
256         return $result;
257     }
258     // no ACL defined; check for special dotfile or walk down
259     if (! ($perm = getPagePermissions($page))) { 
260         if ($pagename == '.') {
261             $perm = new PagePermission();
262             if ($perm->isAuthorized('change', $request->_user)) {
263                 // warn the user to set ACL of ".", if he has permissions to do so.
264                 trigger_error(". (dotpage == rootpage for inheriting pageperm ACLs) exists without any ACL!\n".
265                               "Please do ?action=setacl&pagename=.", E_USER_WARNING);
266             }
267             $result = ($perm->isAuthorized($access, $request->_user) === true);
268             $permcache[$pagename][$access] = $result;
269             return $result;
270         } elseif ($pagename[0] == '.') {
271             $perm = new PagePermission(PagePermission::dotPerms());
272             $result = ($perm->isAuthorized($access, $request->_user) === true);
273             $permcache[$pagename][$access] = $result;
274             return $result;
275         }
276         return _requiredAuthorityForPagename($access, getParentPage($pagename));
277     }
278     // ACL defined; check if isAuthorized returns true or false or undecided
279     $authorized = $perm->isAuthorized($access, $request->_user);
280     if ($authorized !== -1) { // interestingly true is also -1
281         $permcache[$pagename][$access] = $authorized;
282         return $authorized;
283     } elseif ($pagename == '.') {
284         return false;
285     } else {    
286         return _requiredAuthorityForPagename($access, getParentPage($pagename));
287     }
288 }
289
290 /**
291  * @param  string $pagename   page from which the parent page is searched.
292  * @return string parent      pagename or the (possibly pseudo) dot-pagename.
293  */
294 function getParentPage($pagename) {
295     if (isSubPage($pagename)) {
296         return subPageSlice($pagename, 0);
297     } else {
298         return '.';
299     }
300 }
301
302 // Read the ACL from the page
303 // Done: Not existing pages should NOT be queried. 
304 // Check the parent page instead and don't take the default ACL's
305 function getPagePermissions ($page) {
306     if ($hash = $page->get('perm'))  // hash => object
307         return new PagePermission(unserialize($hash));
308     else 
309         return false;
310 }
311
312 // Store the ACL in the page
313 function setPagePermissions ($page,$perm) {
314     $perm->store($page);
315 }
316
317 function getAccessDescription($access) {
318     static $accessDescriptions;
319     if (! $accessDescriptions) {
320         $accessDescriptions = array(
321                                     'list'     => _("List this page and all subpages"),
322                                     'view'     => _("View this page and all subpages"),
323                                     'edit'     => _("Edit this page and all subpages"),
324                                     'create'   => _("Create a new (sub)page"),
325                                     'dump'     => _("Download page contents"),
326                                     'change'   => _("Change page attributes"),
327                                     'remove'   => _("Remove this page"),
328                                     'purge'    => _("Purge this page"),
329                                     );
330     }
331     if (in_array($access, array_keys($accessDescriptions)))
332         return $accessDescriptions[$access];
333     else
334         return $access;
335 }
336
337 // from php.net docs
338 function array_diff_assoc_recursive($array1, $array2) {
339     foreach ($array1 as $key => $value) {
340          if (is_array($value)) {
341              if (!is_array($array2[$key])) {
342                  $difference[$key] = $value;
343              } else {
344                  $new_diff = array_diff_assoc_recursive($value, $array2[$key]);
345                  if ($new_diff != false) {
346                      $difference[$key] = $new_diff;
347                  } 
348              }
349          } elseif(!isset($array2[$key]) || $array2[$key] != $value) {
350              $difference[$key] = $value;
351          }
352     }
353     return !isset($difference) ? 0 : $difference;
354 }
355
356 /**
357  * The ACL object per page. It is stored in a page, but can also 
358  * be merged with ACL's from other pages or taken from the master (pseudo) dot-file.
359  *
360  * A hash of "access" => "requires" pairs.
361  *   "access"   is a shortcut for common actions, which map to main.php actions
362  *   "requires" required username or groupname or any special group => true or false
363  *
364  * Define any special rules here, like don't list dot-pages.
365  */ 
366 class PagePermission {
367     var $perm;
368
369     function PagePermission($hash = array()) {
370         $this->_group = &$GLOBALS['request']->getGroup();
371         if (is_array($hash) and !empty($hash)) {
372             $accessTypes = $this->accessTypes();
373             foreach ($hash as $access => $requires) {
374                 if (in_array($access, $accessTypes))
375                     $this->perm[$access] = $requires;
376                 else
377                     trigger_error(sprintf(_("Unsupported ACL access type %s ignored."), $access),
378                                   E_USER_WARNING);
379             }
380         } else {
381             // set default permissions, the so called dot-file acl's
382             $this->perm = $this->defaultPerms();
383         }
384         return $this;
385     }
386
387     /**
388      * The workhorse to check the user against the current ACL pairs.
389      * Must translate the various special groups to the actual users settings 
390      * (userid, group membership).
391      */
392     function isAuthorized($access, $user) {
393         $allow = -1;
394         if (!empty($this->perm{$access})) {
395             foreach ($this->perm[$access] as $group => $bool) {
396                 if ($this->isMember($user, $group)) {
397                     return $bool;
398                 } elseif ($allow == -1) { // not a member and undecided: check other groups
399                     $allow = !$bool;
400                 }
401             }
402         }
403         return $allow; // undecided
404     }
405
406     /**
407      * Translate the various special groups to the actual users settings 
408      * (userid, group membership).
409      */
410     function isMember($user, $group) {
411         global $request;
412         if ($group === ACL_EVERY) return true;
413         if (!isset($this->_group)) $member =& $request->getGroup();
414         else $member =& $this->_group;
415         //$user = & $request->_user;
416         if ($group === ACL_ADMIN)   // WIKI_ADMIN or member of _("Administrators")
417             return $user->isAdmin() or 
418                    ($user->isAuthenticated() and 
419                    $member->isMember(GROUP_ADMIN));
420         if ($group === ACL_ANONYMOUS) 
421             return ! $user->isSignedIn();
422         if ($group === ACL_BOGOUSER)
423             if (ENABLE_USER_NEW)
424                 return isa($user,'_BogoUser') or 
425                       (isWikiWord($user->_userid) and $user->_level >= WIKIAUTH_BOGO);
426             else return isWikiWord($user->UserName());
427         if ($group === ACL_HASHOMEPAGE)
428             return $user->hasHomePage();
429         if ($group === ACL_SIGNED)
430             return $user->isSignedIn();
431         if ($group === ACL_AUTHENTICATED)
432             return $user->isAuthenticated();
433         if ($group === ACL_OWNER) {
434             if (!$user->isAuthenticated()) return false;
435             $page = $request->getPage();
436             $owner = $page->getOwner();
437             return ($owner === $user->UserName() 
438                     or $member->isMember($owner));
439         }
440         if ($group === ACL_CREATOR) {
441             if (!$user->isAuthenticated()) return false;
442             $page = $request->getPage();
443             $creator = $page->getCreator();
444             return ($creator === $user->UserName() 
445                     or $member->isMember($creator));
446         }
447         /* Or named groups or usernames.
448            Note: We don't seperate groups and users here. 
449            Users overrides groups with the same name. 
450         */
451         return $user->UserName() === $group or
452                $member->isMember($group);
453     }
454
455     /**
456      * returns hash of default permissions.
457      * check if the page '.' exists and returns this instead.
458      */
459     function defaultPerms() {
460         //Todo: check for the existance of '.' and take this instead.
461         //Todo: honor more config.ini auth settings here
462         $perm = array('view'   => array(ACL_EVERY => true),
463                       'edit'   => array(ACL_EVERY => true),
464                       'create' => array(ACL_EVERY => true),
465                       'list'   => array(ACL_EVERY => true),
466                       'remove' => array(ACL_ADMIN => true,
467                                         ACL_OWNER => true),
468                       'purge'  => array(ACL_ADMIN => true,
469                                         ACL_OWNER => true),
470                       'dump'   => array(ACL_ADMIN => true,
471                                         ACL_OWNER => true),
472                       'change' => array(ACL_ADMIN => true,
473                                         ACL_OWNER => true));
474         if (ZIPDUMP_AUTH)
475             $perm['dump'] = array(ACL_ADMIN => true,
476                                   ACL_OWNER => true);
477         elseif (INSECURE_ACTIONS_LOCALHOST_ONLY) {
478             if (is_localhost())
479                 $perm['dump'] = array(ACL_EVERY => true);
480             else
481                 $perm['dump'] = array(ACL_ADMIN => true);
482         }
483         else
484             $perm['dump'] = array(ACL_EVERY => true);
485         if (defined('REQUIRE_SIGNIN_BEFORE_EDIT') && REQUIRE_SIGNIN_BEFORE_EDIT)
486             $perm['edit'] = array(ACL_SIGNED => true);
487         // view:
488         if (!ALLOW_ANON_USER) {
489             if (!ALLOW_USER_PASSWORDS) 
490                 $perm['view'] = array(ACL_SIGNED => true);
491             else                
492                 $perm['view'] = array(ACL_AUTHENTICATED => true);
493             $perm['view'][ACL_BOGOUSER] = ALLOW_BOGO_LOGIN ? true : false;
494         }
495         // edit:
496         if (!ALLOW_ANON_EDIT) {
497             if (!ALLOW_USER_PASSWORDS) 
498                 $perm['edit'] = array(ACL_SIGNED => true);
499             else                
500                 $perm['edit'] = array(ACL_AUTHENTICATED => true);
501             $perm['edit'][ACL_BOGOUSER] = ALLOW_BOGO_LOGIN ? true : false;
502             $perm['create'] = $perm['edit'];
503         }
504         return $perm;
505     }
506
507     /**
508      * FIXME: check valid groups and access
509      */
510     function sanify() {
511         foreach ($this->perm as $access => $groups) {
512             foreach ($groups as $group => $bool) {
513                 $this->perm[$access][$group] = (boolean) $bool;
514             }
515         }
516     }
517
518     /**
519      * do a recursive comparison
520      */
521     function equal($otherperm) {
522         // The equal function seems to be unable to detect removed perm.
523         // Use case is when a rule is removed.
524         return (print_r($this->perm, true) === print_r($otherperm, true));
525
526 //      $diff = array_diff_assoc_recursive($this->perm, $otherperm);
527 //        return empty($diff);
528     }
529     
530     /**
531      * returns list of all supported access types.
532      */
533     function accessTypes() {
534         return array_keys(PagePermission::defaultPerms());
535     }
536
537     /**
538      * special permissions for dot-files, beginning with '.'
539      * maybe also for '_' files?
540      */
541     function dotPerms() {
542         $def = array(ACL_ADMIN => true,
543                      ACL_OWNER => true);
544         $perm = array();
545         foreach (PagePermission::accessTypes() as $access) {
546             $perm[$access] = $def;
547         }
548         return $perm;
549     }
550
551     /**
552      *  dead code. not needed inside the object. see getPagePermissions($page)
553      */
554     function retrieve($page) {
555         $hash = $page->get('perm');
556         if ($hash)  // hash => object
557             $perm = new PagePermission(unserialize($hash));
558         else 
559             $perm = new PagePermission();
560         $perm->sanify();
561         return $perm;
562     }
563
564     function store($page) {
565         // object => hash
566         $this->sanify();
567         return $page->set('perm',serialize($this->perm));
568     }
569
570     function groupName ($group) {
571         if ($group[0] == '_') return constant("GROUP".$group);
572         else return $group;
573     }
574     
575     /* type: page, default, inherited */
576     function asTable($type) {
577         $table = HTML::table();
578         foreach ($this->perm as $access => $perms) {
579             $td = HTML::table(array('class' => 'cal'));
580             foreach ($perms as $group => $bool) {
581                 $td->pushContent(HTML::tr(HTML::td(array('align'=>'right'),$group),
582                                                    HTML::td($bool ? '[X]' : '[ ]')));
583             }
584             $table->pushContent(HTML::tr(array('valign' => 'top'),
585                                          HTML::td($access),HTML::td($td)));
586         }
587         if ($type == 'default')
588             $table->setAttr('style','border: dotted thin black; background-color:#eee;');
589         elseif ($type == 'inherited')
590             $table->setAttr('style','border: dotted thin black; background-color:#ddd;');
591         elseif ($type == 'page')
592             $table->setAttr('style','border: solid thin black; font-weight: bold;');
593         return $table;
594     }
595     
596     /* type: page, default, inherited */
597     function asEditableTable($type) {
598         global $WikiTheme;
599         if (!isset($this->_group)) { 
600             $this->_group =& $GLOBALS['request']->getGroup();
601         }
602         $table = HTML::table();
603         $table->pushContent(HTML::tr(
604                                      HTML::th(array('align' => 'left'),
605                                               _("Access")),
606                                      HTML::th(array('align'=>'right'),
607                                               _("Group/User")),
608                                      HTML::th(_("Grant")),
609                                      HTML::th(_("Del/+")),
610                                      HTML::th(_("Description"))));
611         
612         $allGroups = $this->_group->_specialGroups();
613         foreach ($this->_group->getAllGroupsIn() as $group) {
614             if (!in_array($group,$this->_group->specialGroups()))
615                 $allGroups[] = $group;
616         }
617         //array_unique(array_merge($this->_group->getAllGroupsIn(),
618         $deletesrc = $WikiTheme->_findData('images/delete.png');
619         $addsrc = $WikiTheme->_findData('images/add.png');
620         $nbsp = HTML::raw('&nbsp;');
621         foreach ($this->perm as $access => $groups) {
622             //$permlist = HTML::table(array('class' => 'cal'));
623             $first_only = true;
624             $newperm = HTML::input(array('type' => 'checkbox',
625                                          'name' => "acl[_new_perm][$access]",
626                                          'value' => 1));
627             $addbutton = HTML::input(array('type' => 'checkbox',
628                                            'name' => "acl[_add_group][$access]",
629                                            //'src'  => $addsrc,
630                                            //'alt'   => "Add",
631                                            'title' => _("Add this ACL"),
632                                            'value' => 1));
633             $newgroup = HTML::select(array('name' => "acl[_new_group][$access]",
634                                            'style'=> 'text-align: right;',
635                                            'size' => 1));
636             foreach ($allGroups as $groupname) {
637                 if (!isset($groups[$groupname]))
638                     $newgroup->pushContent(HTML::option(array('value' => $groupname),
639                                                         $this->groupName($groupname)));
640             }
641             if (empty($groups)) {
642                 $addbutton->setAttr('checked','checked');
643                 $newperm->setAttr('checked','checked');
644                 $table->pushContent(
645                     HTML::tr(array('valign' => 'top'),
646                              HTML::td(HTML::strong($access.":")),
647                              HTML::td($newgroup),
648                              HTML::td($nbsp,$newperm),
649                              HTML::td($nbsp,$addbutton),
650                              HTML::td(HTML::em(getAccessDescription($access)))));
651             }
652             foreach ($groups as $group => $bool) {
653                 $checkbox = HTML::input(array('type' => 'checkbox',
654                                               'name' => "acl[$access][$group]",
655                                               'title' => _("Allow / Deny"),
656                                               'value' => 1));
657                 if ($bool) $checkbox->setAttr('checked','checked');
658                 $checkbox = HTML(HTML::input(array('type' => 'hidden',
659                                                    'name' => "acl[$access][$group]",
660                                                    'value' => 0)),
661                                  $checkbox);
662                 $deletebutton = HTML::input(array('type' => 'checkbox',
663                                                   'name' => "acl[_del_group][$access][$group]",
664                                                   'style' => 'background: #aaa url('.$deletesrc.')',
665                                                   //'src'  => $deletesrc,
666                                                   //'alt'   => "Del",
667                                                   'title' => _("Delete this ACL"),
668                                                   'value' => 1));
669                 if ($first_only) {
670                     $table->pushContent(
671                         HTML::tr(
672                                  HTML::td(HTML::strong($access.":")),
673                                  HTML::td(array('class' => 'cal-today','align'=>'right'),
674                                           HTML::strong($this->groupName($group))),
675                                  HTML::td(array('align'=>'center'),$nbsp,$checkbox),
676                                  HTML::td(array('align'=>'right','style' => 'background: #aaa url('.$deletesrc.') no-repeat'),$deletebutton),
677                                  HTML::td(HTML::em(getAccessDescription($access)))));
678                     $first_only = false;
679                 } else {
680                     $table->pushContent(
681                         HTML::tr(
682                                  HTML::td(),
683                                  HTML::td(array('class' => 'cal-today','align'=>'right'),
684                                           HTML::strong($this->groupName($group))),
685                                  HTML::td(array('align'=>'center'),$nbsp,$checkbox),
686                                  HTML::td(array('align'=>'right','style' => 'background: #aaa url('.$deletesrc.') no-repeat'),$deletebutton),
687                                  HTML::td()));
688                 }
689             }
690             if (!empty($groups))
691                 $table->pushContent(
692                     HTML::tr(array('valign' => 'top'),
693                              HTML::td(array('align'=>'right'),_("add ")),
694                              HTML::td($newgroup),
695                              HTML::td(array('align'=>'center'),$nbsp,$newperm),
696                              HTML::td(array('align'=>'right','style' => 'background: #ccc url('.$addsrc.') no-repeat'),$addbutton),
697                              HTML::td(HTML::small(_("Check to add this ACL")))));
698         }
699         if ($type == 'default')
700             $table->setAttr('style','border: dotted thin black; background-color:#eee;');
701         elseif ($type == 'inherited')
702             $table->setAttr('style','border: dotted thin black; background-color:#ddd;');
703         elseif ($type == 'page')
704             $table->setAttr('style','border: solid thin black; font-weight: bold;');
705         return $table;
706     }
707
708     // Print ACL as lines of [+-]user[,group,...]:access[,access...]
709     // Seperate acl's by "; " or whitespace
710     // See http://opag.ca/wiki/HelpOnAccessControlLists
711     // As used by WikiAdminSetAclSimple
712     function asAclLines() {
713         $s = ''; $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     // Print ACL as group followed by actions allowed for the group
731     function asAclGroupLines() {
732
733         $s = '';
734         $perm =& $this->perm;
735         $actions = array("view", "edit", "create", "list", "remove", "purge", "dump", "change");
736         $groups = array(ACL_EVERY, ACL_ANONYMOUS, ACL_BOGOUSER, ACL_HASHOMEPAGE, ACL_SIGNED, ACL_AUTHENTICATED, ACL_ADMIN, ACL_OWNER, ACL_CREATOR);
737
738         foreach ($groups as $group) {
739             $none = true;
740             foreach ($actions as $action) {
741                 if (isset($perm[$action][$group])) {
742                     if ($none) {
743                         $none = false;
744                         $s .= "$group:";
745                     }
746                     $s .= (($perm[$action][$group] ? " " : " -") . $action);
747                 }
748             }
749             if (!($none)) {
750                 $s .= "; ";
751             }
752         }
753         return $s;
754     }
755
756     // This is just a bad hack for testing.
757     // Simplify the ACL to a unix-like "rwx------+" string
758     // See getfacl(8)
759     function asRwxString($owner,$group=false) {
760         global $request;
761         // simplify object => rwxrw---x+ string as in cygwin (+ denotes additional ACLs)
762         $perm =& $this->perm;
763         // get effective user and group
764         $s = '---------+';
765         if (isset($perm['view'][$owner]) or 
766             (isset($perm['view'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
767             $s[0] = 'r';
768         if (isset($perm['edit'][$owner]) or 
769             (isset($perm['edit'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
770             $s[1] = 'w';
771         if (isset($perm['change'][$owner]) or 
772             (isset($perm['change'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
773             $s[2] = 'x';
774         if (!empty($group)) {
775             if (isset($perm['view'][$group]) or 
776                 (isset($perm['view'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
777                 $s[3] = 'r';
778             if (isset($perm['edit'][$group]) or 
779                 (isset($perm['edit'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
780                 $s[4] = 'w';
781             if (isset($perm['change'][$group]) or 
782                 (isset($perm['change'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
783                 $s[5] = 'x';
784         }
785         if (isset($perm['view'][ACL_EVERY]) or 
786             (isset($perm['view'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
787             $s[6] = 'r';
788         if (isset($perm['edit'][ACL_EVERY]) or 
789             (isset($perm['edit'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
790             $s[7] = 'w';
791         if (isset($perm['change'][ACL_EVERY]) or 
792             (isset($perm['change'][ACL_AUTHENTICATED]) and $request->_user->isAuthenticated()))
793             $s[8] = 'x';
794         return $s;
795     }
796 }
797
798 // Local Variables:
799 // mode: php
800 // tab-width: 8
801 // c-basic-offset: 4
802 // c-hanging-comment-ender-p: nil
803 // indent-tabs-mode: nil
804 // End:
805 ?>