/**
  * Select all SD pages (not only saved SDs as incorrect SDs may be not saved).
  */
 public function getSDPages($types, $name, $not_name, $offset, $limit, &$total)
 {
     global $haclgContLang;
     $dbr = wfGetDB(DB_SLAVE);
     $t = $types ? array_flip(IACLStorage::explode($types)) : NULL;
     $n = str_replace(' ', '_', $name);
     $not_n = $not_name ? str_replace(' ', '_', $not_name) : NULL;
     $where = array();
     foreach ($haclgContLang->getPetAliases() as $k => $v) {
         if (!$t || array_key_exists($k, $t)) {
             $where[] = 'CAST(page_title AS CHAR CHARACTER SET utf8) COLLATE utf8_unicode_ci LIKE ' . $dbr->addQuotes($k . '/' . $n . '%');
         }
     }
     if (!$where) {
         return array();
     }
     $where = 'page_namespace=' . HACL_NS_ACL . ' AND (' . implode(' OR ', $where) . ')';
     if ($not_n) {
         $where .= ' AND CAST(page_title AS CHAR CHARACTER SET utf8) COLLATE utf8_unicode_ci NOT LIKE ' . $dbr->addQuotes('%' . $not_n . '%');
     }
     // Select SDs
     $res = $dbr->select('page', '*', $where, __METHOD__, array('SQL_CALC_FOUND_ROWS', 'ORDER BY' => 'page_title', 'OFFSET' => $offset, 'LIMIT' => $limit));
     $rows = array();
     foreach ($res as $row) {
         $t = Title::newFromRow($row);
         $rows["{$t}"] = $t;
     }
     return $rows;
 }
 /**
  * Get HTML code for linked content protection toolbar.
  * Used by ACL editor and IntraACL toolbar.
  * Handled by IACLToolbar::articleSaveComplete_SaveEmbedded.
  *
  * FIXME: Linked content protection is not exactly usable, because it does not replicate
  * namespace and category rights applied to the source page. I don't yet know how to deal
  * with it...
  *
  * @param required int $peID - page ID to retrieve linked content from
  * @param optional int $sdType
  * @param optional int $sdID - page SD ID to check if SDs of linked content are already
  *     single inclusions of this SD.
  * @return html code for embedded content protection toolbar
  *     it containts checkboxes with names "sd_emb_$pageID" and values
  *     "$sdType-$sdID-$revid". $sdID here is the passed $sdID and $revid is the ID
  *     of embedded element's SD last revision, if it exists.
  *     Value may be even just "-" when the toolbar was queried for article without SD,
  *     and when the embedded element did not have any SD.
  */
 public static function getEmbeddedHtml($peID, $sdType, $sdID)
 {
     global $haclgContLang, $wgRequest;
     if (!$sdID) {
         $sdID = '';
     }
     // Retrieve the list of templates used on the page with id=$peID
     $templatelinks = IACLStorage::get('SD')->getEmbedded($peID, $sdType, $sdID, 'templatelinks');
     // Retrieve the list of images used on the page
     $imagelinks = IACLStorage::get('SD')->getEmbedded($peID, $sdType, $sdID, 'imagelinks');
     // Build HTML code for embedded content toolbar
     $links = array_merge($templatelinks, $imagelinks);
     $html = array();
     $all = array();
     foreach ($links as $link) {
         $id = $link['title']->getArticleId();
         $href = $link['title']->getLocalUrl();
         $t = $link['title']->getPrefixedText();
         // Latest revision ID is checked to detect editing conflicts
         $revid = $link['sd_revid'];
         if ($prev = $wgRequest->getVal("sd_emb_{$id}")) {
             list($unused, $revid) = explode($prev, '/', 2);
         }
         if ($link['sd_title']) {
             if ($link['sd_single']) {
                 // Already protected by page SD
                 $customprot = wfMsgForContent('hacl_toolbar_emb_already_prot');
             } else {
                 // Custom SD defined
                 $customprot = wfMsgForContent('hacl_toolbar_emb_custom_prot', $link['sd_title']->getLocalUrl());
             }
         } else {
             $customprot = '';
         }
         if ($link['used_on_pages'] > 1) {
             $usedon = Title::newFromText("Special:WhatLinksHere/{$t}")->getLocalUrl(array('hidelinks' => 1));
             $usedon = wfMsgForContent('hacl_toolbar_used_on', $link['used_on_pages'], $usedon);
         } else {
             $usedon = '';
         }
         $P = $customprot || $usedon ? " — " : "";
         $S = $customprot && $usedon ? "; " : "";
         // [x] Title — custom SD defined; used on Y pages
         $h = '<input type="checkbox" id="sd_emb_' . $id . '" name="sd_emb_' . $id . '"' . ($link['sd_single'] ? ' value="" checked="checked" disabled="disabled"' : " value=\"{$sdType}-{$sdID}-{$revid}\" onchange=\"hacle_noall(this)\" onclick=\"hacle_noall(this)\"" . ($prev ? ' checked="checked"' : '')) . ' />' . ' <label for="sd_emb_' . $id . '"><a target="_blank" href="' . htmlspecialchars($href) . '">' . htmlspecialchars($t) . '</a></label>' . $P . $customprot . $S . $usedon;
         $h = '<div class="hacl_embed' . ($link['sd_single'] ? '_disabled' : '') . '">' . $h . '</div>';
         $html[] = $h;
         if (!$link['sd_single']) {
             $all[] = $id;
         }
     }
     if ($all) {
         $html[] = '<div class="hacl_embed"><input type="checkbox" id="hacl_emb_all" onchange="hacle_checkall(this, [' . implode(',', $all) . '])" onclick="hacle_checkall(this, [' . implode(',', $all) . '])" /> ' . wfMsg('hacl_toolbar_emb_all') . '</div>';
     } elseif ($html) {
         $html[] = '<div class="hacl_embed_disabled"><input type="checkbox" disabled="disabled" checked="checked" /> ' . wfMsg('hacl_toolbar_emb_all_already') . '</div>';
     }
     if ($html) {
         array_unshift($html, '<div class="hacl_emb_text">' . wfMsgForContent('hacl_toolbar_protect_embedded') . '</div>');
     }
     $html = implode("\n", $html);
     return $html;
 }
/**
 * Returns the article ID for a given article name. This function has a special
 * handling for Special pages, which do not have an article ID. IntraACL stores
 * special IDs for these pages. Their IDs are always negative while the IDs of
 * normal pages are positive.
 *
 * @param string $articleName   Name of the article
 * @param int $defaultNS        The default namespace if no namespace is given in the name
 * @param boolean $force        True to force the namespace to be $defaultNS
 *
 * @return int
 *         ID of the article:
 *         >0: ID of an article in a normal namespace
 *         =0: Name of the article is invalid
 *         <0: ID of a Special Page
 *
 */
function haclfArticleID($articleName, $defaultNS = NS_MAIN, $force = false)
{
    $t = $articleName;
    if (!is_object($t)) {
        $etc = haclfDisableTitlePatch();
        $t = $force ? Title::makeTitleSafe($defaultNS, $articleName) : Title::newFromText($articleName, $defaultNS);
        haclfRestoreTitlePatch($etc);
    }
    if (!$t || $t->getInterwiki()) {
        return 0;
    }
    if ($t->getNamespace() == NS_SPECIAL) {
        // Canonicalize special page titles
        list($base, $par) = SpecialPageFactory::resolveAlias($t->getText());
        if (!$base) {
            // No such special page exists, just take the base text
            $base = $t->getBaseText();
        }
        return -IACLStorage::get('SpecialPage')->idForSpecial($base);
    }
    $id = $t->getArticleID();
    if ($id === 0) {
        $id = $t->getArticleID(Title::GAID_FOR_UPDATE);
    }
    return $id;
}
 function save()
 {
     return IACLStorage::get('QuickACL')->saveQuickacl($this->userid, $this->pe_ids, $this->default_pe_id);
 }
 /**
  * Saves this definition into database
  */
 public function save(&$preventLoop = array())
 {
     // Load ID and parents before saving, as the definition may be deleted next
     $parents = $this['parents'];
     $peType = $this['pe_type'];
     $peID = $this['pe_id'];
     $key = $peType . '-' . $peID;
     $st = IACLStorage::get('SD');
     if (!$this->data['rules']) {
         // Delete definition
         $clean = $this->clean();
         $delRules = $clean['rules'] ? $clean['rules'] : array();
         $addRules = array();
         $st->deleteRules(array(array('pe_type' => $peType, 'pe_id' => $peID)));
     } else {
         // Update definition
         list($delRules, $addRules) = $this->diffRulesAssoc();
         if ($delRules) {
             $st->deleteRules(self::expandRuleArray($delRules));
         }
         if ($addRules) {
             $st->addRules(self::expandRuleArray($addRules));
         }
     }
     // Invalidate userCan() cache (FIXME - in fact our parents don't need to do it...)
     if (isset($delRules[IACL::PE_ALL_USERS]) || isset($delRules[IACL::PE_REG_USERS]) || isset($addRules[IACL::PE_ALL_USERS]) || isset($addRules[IACL::PE_REG_USERS])) {
         self::$userCache = array();
         self::$userCacheLoaded = array();
     } else {
         if (isset($delRules[IACL::PE_USER])) {
             foreach ($delRules[IACL::PE_USER] as $userID => $rule) {
                 unset(self::$userCache[$userID]);
                 unset(self::$userCacheLoaded[$userID]);
             }
         }
         if (isset($addRules[IACL::PE_USER])) {
             foreach ($addRules[IACL::PE_USER] as $userID => $rule) {
                 unset(self::$userCache[$userID]);
                 unset(self::$userCacheLoaded[$userID]);
             }
         }
     }
     // Invalidate 'parents' field for children
     foreach ($delRules as $peType => $ids) {
         foreach ($ids as $peID => $rules) {
             if (!empty(self::$clean["{$peType}-{$peID}"])) {
                 unset(self::$clean["{$peType}-{$peID}"]->data['parents']);
             }
         }
     }
     foreach ($addRules as $peType => $ids) {
         foreach ($ids as $peID => $rules) {
             if (!empty(self::$clean["{$peType}-{$peID}"])) {
                 unset(self::$clean["{$peType}-{$peID}"]->data['parents']);
             }
         }
     }
     // Commit new state into the object cache (FIXME - is the object cache needed at all?)
     unset(self::$dirty[$key]);
     $this->rw = false;
     if ($this->data['rules']) {
         self::$clean[$key] = $this;
     } else {
         self::$clean[$key] = false;
     }
     // Invalidate parents - they will do the same recursively for their parents and so on
     $preventLoop[$key] = true;
     foreach ($parents as $p) {
         if (!isset($preventLoop[$p['key']])) {
             $p->save($preventLoop);
         }
     }
 }
/**
 * Return group members for each group of $groups='group1,group2,...',
 * + returns rights for each predefined right of $predefined='sd1[sd2,...'
 * predefined right names are joined by [ as it is forbidden by MediaWiki in titles
 *
 * TODO: Rewrite it to just getRights($titles) returning json array(array(
 *     'pe_type' => $pe_type,
 *     'pe_id' => $pe_id,
 *     'child_type' => $child_type,
 *     'child_id' => $child_id,
 *     'actions' => $actions,
 * ))
 */
function haclGroupClosure($groups, $rights)
{
    global $haclgContLang;
    $pe = array();
    $grp = $haclgContLang->getPetPrefix(IACL::PE_GROUP) . '/';
    foreach (explode(',', $groups) as $k) {
        if (substr($k, 0, strlen($grp)) !== $grp) {
            $k = $grp . $k;
        }
        $pe[] = $k;
    }
    foreach (explode('[', $rights) as $k) {
        $pe[] = $k;
    }
    $pe = IACLDefinition::newFromTitles($pe);
    // Transform all user and group IDs into names
    $users = $groups = array();
    foreach ($pe as $name => $def) {
        if (isset($def['rules'][IACL::PE_USER])) {
            $users += $def['rules'][IACL::PE_USER];
        }
        if (isset($def['rules'][IACL::PE_GROUP])) {
            $groups += $def['rules'][IACL::PE_GROUP];
        }
    }
    $users = IACLStorage::get('Util')->getUsers(array_keys($users));
    if ($groups) {
        $res = wfGetDB(DB_SLAVE)->select('page', '*', array('page_id' => array_keys($groups)));
        $groups = array();
        foreach ($res as $row) {
            $groups[$row->page_id] = $row;
        }
    }
    // Then form the result
    $memberAction = IACL::ACTION_GROUP_MEMBER | IACL::ACTION_GROUP_MEMBER << IACL::INDIRECT_OFFSET;
    $members = array();
    $rules = array();
    foreach ($pe as $name => $def) {
        if ($def['pe_type'] != IACL::PE_GROUP) {
            // Select all user and group rules for SDs
            $cur = array();
            if (isset($def['rules'][IACL::PE_ALL_USERS])) {
                foreach ($def['rules'][IACL::PE_ALL_USERS] as $uid => $rule) {
                    $cur[] = array('*', $rule['actions']);
                }
            }
            if (isset($def['rules'][IACL::PE_REG_USERS])) {
                foreach ($def['rules'][IACL::PE_REG_USERS] as $uid => $rule) {
                    $cur[] = array('#', $rule['actions']);
                }
            }
            if (isset($def['rules'][IACL::PE_USER])) {
                foreach ($def['rules'][IACL::PE_USER] as $uid => $rule) {
                    if (!isset($users[$uid])) {
                        continue;
                    }
                    $cur[] = array('User:'******'actions']);
                }
            }
            if (isset($def['rules'][IACL::PE_GROUP])) {
                foreach ($def['rules'][IACL::PE_GROUP] as $gid => $rule) {
                    if (!isset($groups[$gid])) {
                        continue;
                    }
                    $cur[] = array(str_replace('_', ' ', $groups[$gid]->page_title), $rule['actions']);
                }
            }
            foreach ($cur as $child) {
                foreach (IACL::$actionToName as $i => $a) {
                    if ($child[1] & ($i | $i << IACL::INDIRECT_OFFSET)) {
                        $rules[$name][$child[0]][$a] = true;
                    }
                }
            }
        } else {
            // Select user and group members for groups
            if (isset($def['rules'][IACL::PE_ALL_USERS])) {
                $rule = $def['rules'][IACL::PE_ALL_USERS];
                $rule = reset($rule);
                if ($rule['actions'] & $memberAction) {
                    $members[$name][] = '*';
                }
            }
            if (isset($def['rules'][IACL::PE_REG_USERS])) {
                $rule = reset($def['rules'][IACL::PE_REG_USERS]);
                if ($rule['actions'] & $memberAction) {
                    $members[$name][] = '#';
                }
            }
            if (isset($def['rules'][IACL::PE_USER])) {
                foreach ($def['rules'][IACL::PE_USER] as $uid => $rule) {
                    if ($rule['actions'] & $memberAction) {
                        if (!isset($users[$uid])) {
                            continue;
                        }
                        $members[$name][] = 'User:'******'rules'][IACL::PE_GROUP])) {
                foreach ($g['rules'][IACL::PE_GROUP] as $gid => $right) {
                    if ($right['actions'] & $memberAction) {
                        $members[$name][] = str_replace('_', ' ', $groups[$gid]->page_title);
                    }
                }
                sort($members[$name]);
            }
        }
    }
    return json_encode(array('groups' => $members, 'rights' => $rules));
}
 /**
  * "Real" group list, loaded using AJAX
  */
 static function haclGrouplist($n, $not_n = NULL)
 {
     global $wgScript, $haclgHaloScriptPath, $haclgContLang;
     haclCheckScriptPath();
     /* Load data */
     $total = 0;
     $titles = IACLStorage::get('SD')->getSDPages('group', $n, $not_n, NULL, NULL, $total);
     $groups = array();
     $l = strlen($haclgContLang->getPetPrefix(IACL::PE_GROUP)) + 1;
     foreach ($titles as $t) {
         $groups[] = array('name' => $t->getText(), 'real' => substr($t->getText(), $l), 'editlink' => $wgScript . '?title=Special:IntraACL&action=group&group=' . urlencode($t->getText()), 'viewlink' => $t->getLocalUrl());
     }
     $max = false;
     /* Run template */
     ob_start();
     require dirname(__FILE__) . '/../templates/HACL_GroupListContents.tpl.php';
     $html = ob_get_contents();
     ob_end_clean();
     return $html;
 }
 protected static function checkProtectPageRight($pageID, $userID)
 {
     $etc = haclfDisableTitlePatch();
     $title = Title::newFromId($pageID);
     haclfRestoreTitlePatch($etc);
     return IACLDefinition::userCan($userID, IACL::PE_NAMESPACE, $title->getNamespace(), IACL::ACTION_PROTECT_PAGES) > 0 || IACLDefinition::userCan($userID, IACL::PE_CATEGORY, IACLStorage::get('Util')->getParentCategoryIDs($pageID), IACL::ACTION_PROTECT_PAGES) > 0;
 }