includes/pageutils.php~
changeset 3 2b2084ca1e60
parent 2 0931d60f5bdb
child 4 0b3a0aedfd53
equal deleted inserted replaced
2:0931d60f5bdb 3:2b2084ca1e60
     1 <?php
       
     2 /*
       
     3  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
       
     4  * Version 1.0 (Banshee)
       
     5  * Copyright (C) 2006-2007 Dan Fuhry
       
     6  * pageutils.php - a class that handles raw page manipulations, used mostly by AJAX requests or their old-fashioned form-based counterparts
       
     7  *
       
     8  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
       
     9  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
       
    10  *
       
    11  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
       
    12  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
       
    13  */
       
    14  
       
    15 class PageUtils {
       
    16   
       
    17   /**
       
    18    * List possible username completions
       
    19    * @param $name the name to check for
       
    20    * @return array
       
    21    */
       
    22   
       
    23   function checkusername($name)
       
    24   {
       
    25     global $db, $session, $paths, $template, $plugins; // Common objects
       
    26     $q = $db->sql_query('SELECT username FROM '.table_prefix.'users WHERE username=\''.$db->escape(rawurldecode($name)).'\'');
       
    27     if(!$q) die(mysql_error());
       
    28     if($db->numrows() < 1) { $db->free_result(); return('good'); }
       
    29     else { $db->free_result(); return('bad'); }
       
    30   }
       
    31   
       
    32   /**
       
    33    * Get the wiki formatting source for a page
       
    34    * @param $page the full page id (Namespace:Pagename)
       
    35    * @return string
       
    36    * @todo (DONE) Make it require a password (just for security purposes)
       
    37    */
       
    38    
       
    39   function getsource($page, $password = false)
       
    40   {
       
    41     global $db, $session, $paths, $template, $plugins; // Common objects
       
    42     if(!isset($paths->pages[$page]))
       
    43     {
       
    44       return '';
       
    45     }
       
    46     
       
    47     if(strlen($paths->pages[$page]['password']) == 40)
       
    48     {
       
    49       if(!$password || ( $password != $paths->pages[$page]['password']))
       
    50       {
       
    51         return 'invalid_password';
       
    52       }
       
    53     }
       
    54     
       
    55     if(!$session->get_permissions('view_source')) // Dependencies handle this for us - this also checks for read privileges
       
    56       return 'access_denied';
       
    57     $pid = RenderMan::strToPageID($page);
       
    58     if($pid[1] == 'Special' || $pid[1] == 'Admin')
       
    59     {
       
    60       die('This type of page ('.$paths->nslist[$pid[1]].') cannot be edited because the page source code is not stored in the database.');
       
    61     }
       
    62     
       
    63     $e = $db->sql_query('SELECT page_text,char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$pid[0].'\' AND namespace=\''.$pid[1].'\'');
       
    64     if ( !$e )
       
    65     {
       
    66       $db->_die('The page text could not be selected.');
       
    67     }
       
    68     if( $db->numrows() < 1 )
       
    69     {
       
    70       return ''; //$db->_die('There were no rows in the text table that matched the page text query.');
       
    71     }
       
    72     
       
    73     $r = $db->fetchrow();
       
    74     $db->free_result();
       
    75     $message = $r['page_text'];
       
    76     
       
    77     return htmlspecialchars($message);
       
    78   }
       
    79   
       
    80   /**
       
    81    * Basically a frontend to RenderMan::getPage(), with the ability to send valid data for nonexistent pages
       
    82    * @param $page the full page id (Namespace:Pagename)
       
    83    * @param $send_headers true if the theme headers should be sent (still dependent on current page settings), false otherwise
       
    84    * @return string
       
    85    */
       
    86   
       
    87   function getpage($page, $send_headers = false, $hist_id = false)
       
    88   {
       
    89     global $db, $session, $paths, $template, $plugins; // Common objects
       
    90     ob_start();
       
    91     $pid = RenderMan::strToPageID($page);
       
    92     //die('<pre>'.print_r($pid, true).'</pre>');
       
    93     if(isset($paths->pages[$page]['password']) && strlen($paths->pages[$page]['password']) == 40)
       
    94     {
       
    95       password_prompt($page);
       
    96     }
       
    97     if(isset($paths->pages[$page]))
       
    98     {
       
    99       doStats($pid[0], $pid[1]);
       
   100     }
       
   101     if($paths->custom_page || $pid[1] == 'Special')
       
   102     {
       
   103       // If we don't have access to the page, get out and quick!
       
   104       if(!$session->get_permissions('read') && $pid[0] != 'Login' && $pid[0] != 'Register')
       
   105       {
       
   106         $template->tpl_strings['PAGE_NAME'] = 'Access denied';
       
   107         
       
   108         if ( $send_headers )
       
   109         {
       
   110           $template->header();
       
   111         }
       
   112         
       
   113         echo '<div class="error-box"><b>Access to this page is denied.</b><br />This may be because you are not logged in or you have not met certain criteria for viewing this page.</div>';
       
   114         
       
   115         if ( $send_headers )
       
   116         {
       
   117           $template->footer();
       
   118         }
       
   119         
       
   120         $r = ob_get_contents();
       
   121         ob_end_clean();
       
   122         return $r;
       
   123       }
       
   124       
       
   125       $fname = 'page_'.$pid[1].'_'.$paths->pages[$page]['urlname_nons'];
       
   126       @call_user_func($fname);
       
   127       
       
   128     }
       
   129     else if ( $pid[1] == 'Admin' )
       
   130     {
       
   131       // If we don't have access to the page, get out and quick!
       
   132       if(!$session->get_permissions('read'))
       
   133       {
       
   134         $template->tpl_strings['PAGE_NAME'] = 'Access denied';
       
   135         if ( $send_headers )
       
   136         {
       
   137           $template->header();
       
   138         }
       
   139         echo '<div class="error-box"><b>Access to this page is denied.</b><br />This may be because you are not logged in or you have not met certain criteria for viewing this page.</div>';
       
   140         if ( $send_headers )
       
   141         {
       
   142           $template->footer();
       
   143         }
       
   144         $r = ob_get_contents();
       
   145         ob_end_clean();
       
   146         return $r;
       
   147       }
       
   148       
       
   149       $fname = 'page_'.$pid[1].'_'.$pid[0];
       
   150       if ( !function_exists($fname) )
       
   151       {
       
   152         $title = 'Page backend not found';
       
   153         $message = "The administration page you are looking for was properly registered using the page API, but the backend function
       
   154                     (<tt>$fname</tt>) was not found. If this is a plugin page, then this is almost certainly a bug with the plugin.";
       
   155         if ( $send_headers )
       
   156         {
       
   157           die_friendly($title, "<p>$message</p>");
       
   158         }
       
   159         else
       
   160         {
       
   161           echo "<h2>$title</h2>\n<p>$message</p>";
       
   162         }
       
   163       }
       
   164       @call_user_func($fname);
       
   165     }
       
   166     else if ( !isset( $paths->pages[$page] ) )
       
   167     {
       
   168       ob_start();
       
   169       $code = $plugins->setHook('page_not_found');
       
   170       foreach ( $code as $cmd )
       
   171       {
       
   172         eval($cmd);
       
   173       }
       
   174       $text = ob_get_contents();
       
   175       if ( $text != '' )
       
   176       {
       
   177         ob_end_clean();
       
   178         return $text;
       
   179       }
       
   180       $template->header();
       
   181       if($m = $paths->sysmsg('Page_not_found'))
       
   182       {
       
   183         eval('?>'.RenderMan::render($m));
       
   184       }
       
   185       else
       
   186       {
       
   187         header('HTTP/1.1 404 Not Found');
       
   188         echo '<h3>There is no page with this title yet.</h3>
       
   189                <p>You have requested a page that doesn\'t exist yet.';
       
   190         if($session->get_permissions('create_page')) echo ' You can <a href="'.makeUrl($paths->page, 'do=edit', true).'" onclick="ajaxEditor(); return false;">create this page</a>, or return to the <a href="'.makeUrl(getConfig('main_page')).'">homepage</a>.';
       
   191         else echo ' Return to the <a href="'.makeUrl(getConfig('main_page')).'">homepage</a>.</p>';
       
   192         if($session->get_permissions('history_rollback')) {
       
   193           $e = $db->sql_query('SELECT * FROM '.table_prefix.'logs WHERE action=\'delete\' AND page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$pid[1].'\' ORDER BY time_id DESC;');
       
   194           if(!$e) $db->_die('The deletion log could not be selected.');
       
   195           if($db->numrows() > 0) {
       
   196             $r = $db->fetchrow();
       
   197             echo '<p>This page also appears to have some log entries in the database - it seems that it was deleted on '.$r['date_string'].'. You can probably <a href="'.makeUrl($paths->page, 'do=rollback&amp;id='.$r['time_id']).'" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">roll back</a> the deletion.</p>';
       
   198           }
       
   199           $db->free_result();
       
   200         }
       
   201         echo '<p>
       
   202                 HTTP Error: 404 Not Found
       
   203               </p>';
       
   204       }
       
   205       $template->footer();
       
   206     }
       
   207     else
       
   208     {
       
   209       
       
   210       // If we don't have access to the page, get out and quick!
       
   211       if(!$session->get_permissions('read'))
       
   212       {
       
   213         $template->tpl_strings['PAGE_NAME'] = 'Access denied';
       
   214         if($send_headers) $template->header();
       
   215         echo '<div class="error-box"><b>Access to this page is denied.</b><br />This may be because you are not logged in or you have not met certain criteria for viewing this page.</div>';
       
   216         if($send_headers) $template->footer();
       
   217         $r = ob_get_contents();
       
   218         ob_end_clean();
       
   219         return $r;
       
   220       }
       
   221       
       
   222       ob_start();
       
   223       $code = $plugins->setHook('page_custom_handler');
       
   224       foreach ( $code as $cmd )
       
   225       {
       
   226         eval($cmd);
       
   227       }
       
   228       $text = ob_get_contents();
       
   229       if ( $text != '' )
       
   230       {
       
   231         ob_end_clean();
       
   232         return $text;
       
   233       }
       
   234       
       
   235       if($hist_id) {
       
   236         $e = $db->sql_query('SELECT page_text,date_string,char_tag FROM '.table_prefix.'logs WHERE page_id=\''.$paths->pages[$page]['urlname_nons'].'\' AND namespace=\''.$pid[1].'\' AND log_type=\'page\' AND action=\'edit\' AND time_id='.$db->escape($hist_id).'');
       
   237         if($db->numrows() < 1)
       
   238         {
       
   239           $db->_die('There were no rows in the text table that matched the page text query.');
       
   240         }
       
   241         $r = $db->fetchrow();
       
   242         $db->free_result();
       
   243         $message = '<div class="info-box" style="margin-left: 0; margin-top: 5px;"><b>Notice:</b><br />The page you are viewing was archived on '.$r['date_string'].'.<br /><a href="'.makeUrl($page).'" onclick="ajaxReset(); return false;">View current version</a>  |  <a href="'.makeUrl($page, 'do=rollback&amp;id='.$hist_id).'" onclick="ajaxRollback(\''.$hist_id.'\')">Restore this version</a></div><br />'.RenderMan::render($r['page_text']);
       
   244         
       
   245         if( !$paths->pages[$page]['special'] )
       
   246         {
       
   247           if($send_headers)
       
   248           {
       
   249             $template->header(); 
       
   250           }
       
   251           display_page_headers();
       
   252         }
       
   253         
       
   254         eval('?>'.$message);
       
   255         
       
   256         if( !$paths->pages[$page]['special'] )
       
   257         {
       
   258           display_page_footers();
       
   259           if($send_headers)
       
   260           {
       
   261             $template->footer();
       
   262           }
       
   263         }
       
   264         
       
   265       } else {
       
   266         if(!$paths->pages[$page]['special'])
       
   267         {
       
   268           $message = RenderMan::getPage($paths->pages[$page]['urlname_nons'], $pid[1]);
       
   269         }
       
   270         else
       
   271         {
       
   272           $message = RenderMan::getPage($paths->pages[$page]['urlname_nons'], $pid[1], 0, false, false, false, false);
       
   273         }
       
   274         // This line is used to debug wikiformatted code
       
   275         // die('<pre>'.htmlspecialchars($message).'</pre>');
       
   276         
       
   277         if( !$paths->pages[$page]['special'] )
       
   278         {
       
   279           if($send_headers)
       
   280           {
       
   281             $template->header(); 
       
   282           }
       
   283           display_page_headers();
       
   284         }
       
   285 
       
   286         // This is it, this is what all of Enano has been working up to...
       
   287         
       
   288         eval('?>'.$message);
       
   289         
       
   290         if( !$paths->pages[$page]['special'] )
       
   291         {
       
   292           display_page_footers();
       
   293           if($send_headers)
       
   294           {
       
   295             $template->footer();
       
   296           }
       
   297         }
       
   298       }
       
   299     }
       
   300     $ret = ob_get_contents();
       
   301     ob_end_clean();
       
   302     return $ret;
       
   303   }
       
   304   
       
   305   /**
       
   306    * Writes page data to the database, after verifying permissions and running the XSS filter
       
   307    * @param $page_id the page ID
       
   308    * @param $namespace the namespace
       
   309    * @param $message the text to save
       
   310    * @return string
       
   311    */
       
   312    
       
   313   function savepage($page_id, $namespace, $message, $summary = 'No edit summary given', $minor = false)
       
   314   {
       
   315     global $db, $session, $paths, $template, $plugins; // Common objects
       
   316     $uid = sha1(microtime());
       
   317     $pname = $paths->nslist[$namespace] . $page_id;
       
   318     
       
   319     if(!$session->get_permissions('edit_page'))
       
   320       return 'Access to edit pages is denied.';
       
   321     
       
   322     if(!isset($paths->pages[$pname]))
       
   323     {
       
   324       if(!PageUtils::createPage($page_id, $namespace))
       
   325         return 'The page did not exist, and I was not able to create it. Permissions problem?';
       
   326     }
       
   327     
       
   328     $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false;
       
   329     $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false;
       
   330     if(($prot || !$wiki) && $session->user_level < USER_LEVEL_ADMIN ) return('You are not authorized to edit this page.');
       
   331     
       
   332     // Strip potentially harmful tags and PHP from the message, if we are in wiki mode and the user is not an administrator
       
   333     $message = RenderMan::preprocess_text($message, false, false);
       
   334     
       
   335     $msg=$db->escape($message);
       
   336     
       
   337     $minor = $minor ? 'true' : 'false';
       
   338     $q='INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,page_id,namespace,page_text,char_tag,author,edit_summary,minor_edit) VALUES(\'page\', \'edit\', '.time().', \''.date('d M Y h:i a').'\', \''.$paths->cpage['urlname_nons'].'\', \''.$paths->namespace.'\', \''.$msg.'\', \''.$uid.'\', \''.$session->username.'\', \''.$db->escape(htmlspecialchars($summary)).'\', '.$minor.');';
       
   339     if(!$db->sql_query($q)) $db->_die('The history (log) entry could not be inserted into the logs table.');
       
   340     
       
   341     $q = 'UPDATE '.table_prefix.'page_text SET page_text=\''.$msg.'\',char_tag=\''.$uid.'\' WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';';
       
   342     $e = $db->sql_query($q);
       
   343     if(!$e) $db->_die('Enano was unable to save the page contents. Your changes have been lost <tt>:\'(</tt>.');
       
   344       
       
   345     $paths->rebuild_page_index($page_id, $namespace);
       
   346       
       
   347     return 'good';
       
   348   }
       
   349   
       
   350   /**
       
   351    * Creates a page, both in memory and in the database.
       
   352    * @param string $page_id
       
   353    * @param string $namespace
       
   354    * @return bool true on success, false on failure
       
   355    */
       
   356   
       
   357   function createPage($page_id, $namespace, $name = false, $visible = 1)
       
   358   {
       
   359     global $db, $session, $paths, $template, $plugins; // Common objects
       
   360     if(in_array($namespace, Array('Special', 'Admin')))
       
   361     {
       
   362       // echo '<b>Notice:</b> PageUtils::createPage: You can\'t create a special page in the database<br />';
       
   363       return false; // Can't create a special page
       
   364     }
       
   365     
       
   366     if(!isset($paths->nslist[$namespace]))
       
   367     {
       
   368       // echo '<b>Notice:</b> PageUtils::createPage: Couldn\'t look up the namespace<br />';
       
   369       return false; // Couldn't look up namespace
       
   370     }
       
   371     
       
   372     $pname = $paths->nslist[$namespace] . $page_id;
       
   373     if(isset($paths->pages[$pname]))
       
   374     {
       
   375       // echo '<b>Notice:</b> PageUtils::createPage: Page already exists<br />';
       
   376       return false; // Page already exists
       
   377     }
       
   378     
       
   379     if(!$session->get_permissions('create_page'))
       
   380     {
       
   381       // echo '<b>Notice:</b> PageUtils::createPage: Not authorized to create pages<br />';
       
   382       return false; // Access denied
       
   383     }
       
   384     
       
   385     if($session->user_level < USER_LEVEL_ADMIN && $namespace == 'System')
       
   386     {
       
   387       // echo '<b>Notice:</b> PageUtils::createPage: Not authorized to create system messages<br />';
       
   388       return false; // Not authorized to create system messages
       
   389     }
       
   390     
       
   391     if ( !$name )
       
   392       $name = str_replace('_', ' ', $page_id);
       
   393     $page = str_replace(' ', '_', $page_id);
       
   394     $regex = '#^([A-z0-9 _\-\.\/\!\@\(\)]*)$#is';
       
   395     if(!preg_match($regex, $page))
       
   396     {
       
   397       //echo '<b>Notice:</b> PageUtils::createPage: Name contains invalid characters<br />';
       
   398       return false; // Name contains invalid characters
       
   399     }
       
   400     
       
   401     $prot = ( $namespace == 'System' ) ? 1 : 0;
       
   402     
       
   403     $paths->add_page(Array(
       
   404       'name'=>$name,
       
   405       'urlname'=>$page,
       
   406       'namespace'=>$namespace,
       
   407       'special'=>0,'visible'=>1,'comments_on'=>0,'protected'=>$prot,'delvotes'=>0,'delvote_ips'=>'','wiki_mode'=>2,
       
   408     ));
       
   409     
       
   410     $qa = $db->sql_query('INSERT INTO '.table_prefix.'pages(name,urlname,namespace,visible,protected) VALUES(\''.$db->escape($name).'\', \''.$db->escape($page).'\', \''.$namespace.'\', '. ( $visible ? '1' : '0' ) .', '.$prot.');');
       
   411     $qb = $db->sql_query('INSERT INTO '.table_prefix.'page_text(page_id,namespace) VALUES(\''.$db->escape($page).'\', \''.$namespace.'\');');
       
   412     $qc = $db->sql_query('INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'create\', \''.$session->username.'\', \''.$db->escape($page).'\', \''.$namespace.'\');');
       
   413     
       
   414     if($qa && $qb && $qc)
       
   415       return true;
       
   416     else
       
   417     {
       
   418       echo $db->get_error();
       
   419       return false;
       
   420     }
       
   421   }
       
   422   
       
   423   /**
       
   424    * Sets the protection level on a page.
       
   425    * @param $page_id string the page ID
       
   426    * @param $namespace string the namespace
       
   427    * @param $level int level of protection - 0 is off, 1 is full, 2 is semi
       
   428    * @param $reason string why the page is being (un)protected
       
   429    * @return string - "good" on success, in all other cases, an error string (on query failure, calls $db->_die() )
       
   430    */
       
   431   function protect($page_id, $namespace, $level, $reason)
       
   432   {
       
   433     global $db, $session, $paths, $template, $plugins; // Common objects
       
   434     
       
   435     $pname = $paths->nslist[$namespace] . $page_id;
       
   436     $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false;
       
   437     $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false;
       
   438     
       
   439     if(!$session->get_permissions('protect')) return('Insufficient access rights');
       
   440     if(!$wiki) return('Page protection only has an effect when Wiki Mode is enabled.');
       
   441     if(!preg_match('#^([0-9]+){1}$#', (string)$level)) return('Invalid $level parameter.');
       
   442     
       
   443     if($reason!='NO_REASON') {
       
   444       switch($level)
       
   445       {
       
   446         case 0:
       
   447           $q = 'INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'unprot\', \''.$session->username.'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape(htmlspecialchars($reason)).'\');';
       
   448           break;
       
   449         case 1:
       
   450           $q = 'INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'prot\', \''.$session->username.'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape(htmlspecialchars($reason)).'\');';
       
   451           break;
       
   452         case 2:
       
   453           $q = 'INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'semiprot\', \''.$session->username.'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape(htmlspecialchars($reason)).'\');';
       
   454           break;
       
   455         default:
       
   456           return 'PageUtils::protect(): Invalid value for $level';
       
   457           break;
       
   458       }
       
   459       if(!$db->sql_query($q)) $db->_die('The log entry for the page protection could not be inserted.');
       
   460     }
       
   461     
       
   462     $q = $db->sql_query('UPDATE '.table_prefix.'pages SET protected='.$_POST['level'].' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
       
   463     if(!$q) $db->_die('The pages table was not updated.');
       
   464     
       
   465     return('good');
       
   466   }
       
   467   
       
   468   /**
       
   469    * Generates an HTML table with history information in it.
       
   470    * @param $page_id the page ID
       
   471    * @param $namespace the namespace
       
   472    * @return string
       
   473    */
       
   474   
       
   475   function histlist($page_id, $namespace)
       
   476   {
       
   477     global $db, $session, $paths, $template, $plugins; // Common objects
       
   478     
       
   479     if(!$session->get_permissions('history_view'))
       
   480       return 'Access denied';
       
   481     
       
   482     ob_start();
       
   483     
       
   484     $pname = $paths->nslist[$namespace] . $page_id;
       
   485     $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false;
       
   486     $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false;
       
   487     
       
   488     $q = 'SELECT time_id,date_string,page_id,namespace,author,edit_summary,minor_edit FROM '.table_prefix.'logs WHERE log_type=\'page\' AND action=\'edit\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' ORDER BY time_id DESC;';
       
   489     if(!$db->sql_query($q)) $db->_die('The history data for the page "'.$paths->cpage['name'].'" could not be selected.');
       
   490     echo 'History of edits and actions<h3>Edits:</h3>';
       
   491     $numrows = $db->numrows();
       
   492     if($numrows < 1) echo 'No history entries in this category.';
       
   493     else
       
   494     {
       
   495       
       
   496       echo '<form action="'.makeUrlNS($namespace, $page_id, 'do=diff').'" onsubmit="ajaxHistDiff(); return false;" method="get">
       
   497             <input type="submit" value="Compare selected revisions" />
       
   498             <br /><span>&nbsp;</span>
       
   499             <div class="tblholder">
       
   500             <table border="0" width="100%" cellspacing="1" cellpadding="4">
       
   501             <tr>
       
   502               <th colspan="2">Diff</th>
       
   503               <th>Date/time</th>
       
   504               <th>User</th>
       
   505               <th>Edit summary</th>
       
   506               <th>Minor</th>
       
   507               <th colspan="3">Actions</th>
       
   508             </tr>'."\n"."\n";
       
   509       $cls = 'row2';
       
   510       $ticker = 0;
       
   511       
       
   512       while($r = $db->fetchrow()) {
       
   513         
       
   514         $ticker++;
       
   515         
       
   516         if($cls == 'row2') $cls = 'row1';
       
   517         else $cls = 'row2';
       
   518         
       
   519         echo '<tr>'."\n";
       
   520         
       
   521         // Diff selection
       
   522         if($ticker == 1)
       
   523         {
       
   524           $s1 = '';
       
   525           $s2 = 'checked="checked" ';
       
   526         }
       
   527         elseif($ticker == 2)
       
   528         {
       
   529           $s1 = 'checked="checked" ';
       
   530           $s2 = '';
       
   531         }
       
   532         else
       
   533         {
       
   534           $s1 = '';
       
   535           $s2 = '';
       
   536         }
       
   537         if($ticker > 1)        echo '<td class="'.$cls.'" style="padding: 0;"><input '.$s1.'name="diff1" type="radio" value="'.$r['time_id'].'" id="diff1_'.$r['time_id'].'" class="clsDiff1Radio" onclick="selectDiff1Button(this);" /></td>'."\n"; else echo '<td class="'.$cls.'"></td>';
       
   538         if($ticker < $numrows) echo '<td class="'.$cls.'" style="padding: 0;"><input '.$s2.'name="diff2" type="radio" value="'.$r['time_id'].'" id="diff2_'.$r['time_id'].'" class="clsDiff2Radio" onclick="selectDiff2Button(this);" /></td>'."\n"; else echo '<td class="'.$cls.'"></td>';
       
   539         
       
   540         // Date and time
       
   541         echo '<td class="'.$cls.'">'.$r['date_string'].'</td class="'.$cls.'">'."\n";
       
   542         
       
   543         // User
       
   544         if($session->get_permissions('mod_misc') && preg_match('#^([0-9]*){1,3}\.([0-9]*){1,3}\.([0-9]*){1,3}\.([0-9]*){1,3}$#', $r['author'])) $rc = ' style="cursor: pointer;" title="Click cell background for reverse DNS info" onclick="ajaxReverseDNS(this, \''.$r['author'].'\');"';
       
   545         else $rc = '';
       
   546         echo '<td class="'.$cls.'"'.$rc.'><a href="'.makeUrlNS('User', $r['author']).'" ';
       
   547         if(!isPage($paths->nslist['User'] . $r['author'])) echo 'class="wikilink-nonexistent"';
       
   548         echo '>'.$r['author'].'</a></td class="'.$cls.'">'."\n";
       
   549         
       
   550         // Edit summary
       
   551         echo '<td class="'.$cls.'">'.$r['edit_summary'].'</td>'."\n";
       
   552         
       
   553         // Minor edit
       
   554         echo '<td class="'.$cls.'" style="text-align: center;">'. (( $r['minor_edit'] ) ? 'M' : '' ) .'</td>'."\n";
       
   555         
       
   556         // Actions!
       
   557         echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrlNS($namespace, $page_id, 'oldid='.$r['time_id']).'" onclick="ajaxHistView(\''.$r['time_id'].'\'); return false;">View revision</a></td>'."\n";
       
   558         echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrl($paths->nslist['Special'].'Contributions/'.$r['author']).'">View user contribs</a></td>'."\n";
       
   559         echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrlNS($namespace, $page_id, 'do=rollback&amp;id='.$r['time_id']).'" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">Revert to this revision</a></td>'."\n";
       
   560         
       
   561         echo '</tr>'."\n"."\n";
       
   562         
       
   563       }
       
   564       echo '</table>
       
   565             </div>
       
   566             <br />
       
   567             <input type="hidden" name="do" value="diff" />
       
   568             <input type="submit" value="Compare selected revisions" />
       
   569             </form>
       
   570             <script type="text/javascript">buildDiffList();</script>';
       
   571     }
       
   572     $db->free_result();
       
   573     echo '<h3>Other changes:</h3>';
       
   574     $q = 'SELECT time_id,action,date_string,page_id,namespace,author,edit_summary,minor_edit FROM '.table_prefix.'logs WHERE log_type=\'page\' AND action!=\'edit\' AND page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$paths->namespace.'\' ORDER BY time_id DESC;';
       
   575     if(!$db->sql_query($q)) $db->_die('The history data for the page "'.$paths->cpage['name'].'" could not be selected.');
       
   576     if($db->numrows() < 1) echo 'No history entries in this category.';
       
   577     else {
       
   578       
       
   579       echo '<div class="tblholder"><table border="0" width="100%" cellspacing="1" cellpadding="4"><tr><th>Date/time</th><th>User</th><th>Minor</th><th>Action taken</th><th>Extra info</th><th colspan="2"></th></tr>';
       
   580       $cls = 'row2';
       
   581       while($r = $db->fetchrow()) {
       
   582         
       
   583         if($cls == 'row2') $cls = 'row1';
       
   584         else $cls = 'row2';
       
   585         
       
   586         echo '<tr>';
       
   587         
       
   588         // Date and time
       
   589         echo '<td class="'.$cls.'">'.$r['date_string'].'</td class="'.$cls.'">';
       
   590         
       
   591         // User
       
   592         echo '<td class="'.$cls.'"><a href="'.makeUrlNS('User', $r['author']).'" ';
       
   593         if(!isPage($paths->nslist['User'] . $r['author'])) echo 'class="wikilink-nonexistent"';
       
   594         echo '>'.$r['author'].'</a></td class="'.$cls.'">';
       
   595         
       
   596         
       
   597         // Minor edit
       
   598         echo '<td class="'.$cls.'" style="text-align: center;">'. (( $r['minor_edit'] ) ? 'M' : '' ) .'</td>';
       
   599         
       
   600         // Action taken
       
   601         echo '<td class="'.$cls.'">';
       
   602         if    ($r['action']=='prot')     echo 'Protected page</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
       
   603         elseif($r['action']=='unprot')   echo 'Unprotected page</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
       
   604         elseif($r['action']=='semiprot') echo 'Semi-protected page</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
       
   605         elseif($r['action']=='rename')   echo 'Renamed page</td><td class="'.$cls.'">Old title: '.$r['edit_summary'];
       
   606         elseif($r['action']=='create')   echo 'Created page</td><td class="'.$cls.'">';
       
   607         elseif($r['action']=='delete')   echo 'Deleted page</td><td class="'.$cls.'">';
       
   608         elseif($r['action']=='reupload') echo 'Uploaded new file version</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
       
   609         echo '</td>';
       
   610         
       
   611         // Actions!
       
   612         echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrl($paths->nslist['Special'].'Contributions/'.$r['author']).'">View user contribs</a></td>';
       
   613         echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrlNS($namespace, $page_id, 'do=rollback&amp;id='.$r['time_id']).'" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">Revert action</a></td>';
       
   614         
       
   615         //echo '(<a href="#" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">rollback</a>) <i>'.$r['date_string'].'</i> '.$r['author'].' (<a href="'.makeUrl($paths->nslist['User'].$r['author']).'">Userpage</a>, <a href="'.makeUrl($paths->nslist['Special'].'Contributions/'.$r['author']).'">Contrib</a>): ';
       
   616         
       
   617         if($r['minor_edit']) echo '<b> - minor edit</b>';
       
   618         echo '<br />';
       
   619         
       
   620         echo '</tr>';
       
   621       }
       
   622       echo '</table></div>';
       
   623     }
       
   624     $db->free_result();
       
   625     $ret = ob_get_contents();
       
   626     ob_end_clean();
       
   627     return $ret;
       
   628   }
       
   629   
       
   630   /**
       
   631    * Rolls back a logged action
       
   632    * @param $id the time ID, a.k.a. the primary key in the logs table
       
   633    * @return string
       
   634    */
       
   635    
       
   636   function rollback($id)
       
   637   {
       
   638     global $db, $session, $paths, $template, $plugins; // Common objects
       
   639     if(!$session->get_permissions('history_rollback')) return('You are not authorized to perform rollbacks.');
       
   640     if(!preg_match('#^([0-9]+)$#', (string)$id)) return('The value "id" on the query string must be an integer.');
       
   641     $e = $db->sql_query('SELECT log_type,action,date_string,page_id,namespace,page_text,char_tag,author,edit_summary FROM '.table_prefix.'logs WHERE time_id='.$id.';');
       
   642     if(!$e) $db->_die('The rollback data could not be selected.');
       
   643     $rb = $db->fetchrow();
       
   644     $db->free_result();
       
   645     switch($rb['log_type']) {
       
   646       case "page":
       
   647         switch($rb['action']) {
       
   648           case "edit":
       
   649             $t = $db->escape($rb['page_text']);
       
   650             $e = $db->sql_query('UPDATE '.table_prefix.'page_text SET page_text=\''.$t.'\',char_tag=\''.$rb['char_tag'].'\' WHERE page_id=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
       
   651             if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
       
   652             else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been rolled back to the state it was in on '.$rb['date_string'].'.');
       
   653             break;
       
   654           case "rename":
       
   655             $t = $db->escape($rb['edit_summary']);
       
   656             $e = $db->sql_query('UPDATE '.table_prefix.'pages SET name=\''.$t.'\' WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
       
   657             if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
       
   658             else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been rolled back to the name it had ("'.$rb['edit_summary'].'") before '.$rb['date_string'].'.');
       
   659             break;
       
   660           case "prot":
       
   661             $e = $db->sql_query('UPDATE '.table_prefix.'pages SET protected=0 WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
       
   662             if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
       
   663             else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been unprotected according to the log created at '.$rb['date_string'].'.');
       
   664             break;
       
   665           case "semiprot":
       
   666             $e = $db->sql_query('UPDATE '.table_prefix.'pages SET protected=0 WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
       
   667             if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
       
   668             else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been unprotected according to the log created at '.$rb['date_string'].'.');
       
   669             break;
       
   670           case "unprot":
       
   671             $e = $db->sql_query('UPDATE '.table_prefix.'pages SET protected=1 WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
       
   672             if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
       
   673             else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been protected according to the log created at '.$rb['date_string'].'.');
       
   674             break;
       
   675           case "delete":
       
   676             if(!$session->get_permissions('history_rollback_extra')) return('Administrative privileges are required for page undeletion.');
       
   677             if(isset($paths->pages[$paths->cpage['urlname']])) return('You cannot raise a dead page that is alive.');
       
   678             $name = str_replace('_', ' ', $rb['page_id']);
       
   679             $e = $db->sql_query('INSERT INTO '.table_prefix.'pages(name,urlname,namespace) VALUES( \''.$name.'\', \''.$rb['page_id'].'\',\''.$rb['namespace'].'\' )');if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
       
   680             $e = $db->sql_query('SELECT page_text,char_tag FROM '.table_prefix.'logs WHERE page_id=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\' AND log_type=\'page\' AND action=\'edit\' ORDER BY time_id DESC;'); if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
       
   681             $r = $db->fetchrow();
       
   682             $e = $db->sql_query('INSERT INTO '.table_prefix.'page_text(page_id,namespace,page_text,char_tag) VALUES(\''.$rb['page_id'].'\',\''.$rb['namespace'].'\',\''.$db->escape($r['page_text']).'\',\''.$r['char_tag'].'\')'); if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
       
   683             return('The page "'.$name.'" has been undeleted according to the log created at '.$rb['date_string'].'.');
       
   684             break;
       
   685           case "reupload":
       
   686             if(!$session->get_permissions('history_rollbacks_extra')) return('Administrative privileges are required for file rollbacks.');
       
   687             $newtime = time();
       
   688             $newdate = date('d M Y h:i a');
       
   689             if(!$db->sql_query('UPDATE '.table_prefix.'logs SET time_id='.$newtime.',date_string=\''.$newdate.'\' WHERE time_id='.$id)) return('Error during query: '.mysql_error());
       
   690             if(!$db->sql_query('UPDATE '.table_prefix.'files SET time_id='.$newtime.' WHERE time_id='.$id)) return('Error during query: '.mysql_error());
       
   691             return('The file has been rolled back to the version uploaded on '.date('d M Y h:i a', (int)$id).'.');
       
   692             break;
       
   693           default:
       
   694             return('Rollback of the action "'.$rb['action'].'" is not yet supported.');
       
   695             break;
       
   696         }
       
   697         break;
       
   698       case "security":
       
   699       case "login":
       
   700         return('A '.$rb['log_type'].'-related log entry cannot be rolled back.');
       
   701         break;
       
   702       default:
       
   703         return('Unknown log entry type: "'.$rb['log_type'].'"');
       
   704     }
       
   705   }
       
   706   
       
   707   /**
       
   708    * Posts a comment.
       
   709    * @param $page_id the page ID
       
   710    * @param $namespace the namespace
       
   711    * @param $name the name of the person posting, defaults to current username/IP
       
   712    * @param $subject the subject line of the comment
       
   713    * @param $text the comment text
       
   714    * @return string javascript code
       
   715    */
       
   716    
       
   717   function addcomment($page_id, $namespace, $name, $subject, $text, $captcha_code = false, $captcha_id = false)
       
   718   {
       
   719     global $db, $session, $paths, $template, $plugins; // Common objects
       
   720     $_ob = '';
       
   721     if(!$session->get_permissions('post_comments'))
       
   722       return 'Access denied';
       
   723     if(getConfig('comments_need_login') == '2' && !$session->user_logged_in) _die('Access denied to post comments: you need to be logged in first.');
       
   724     if(getConfig('comments_need_login') == '1' && !$session->user_logged_in)
       
   725     {
       
   726       if(!$captcha_code || !$captcha_id) _die('BUG: PageUtils::addcomment: no CAPTCHA data passed to method');
       
   727       $result = $session->get_captcha($captcha_id);
       
   728       if($captcha_code != $result) _die('The confirmation code you entered was incorrect.');
       
   729     }
       
   730     $text = RenderMan::preprocess_text($text);
       
   731     $name = $session->user_logged_in ? RenderMan::preprocess_text($session->username) : RenderMan::preprocess_text($name);
       
   732     $subj = RenderMan::preprocess_text($subject);
       
   733     if(getConfig('approve_comments')=='1') $appr = '0'; else $appr = '1';
       
   734     $q = 'INSERT INTO '.table_prefix.'comments(page_id,namespace,subject,comment_data,name,user_id,approved,time) VALUES(\''.$page_id.'\',\''.$namespace.'\',\''.$subj.'\',\''.$text.'\',\''.$name.'\','.$session->user_id.','.$appr.','.time().')';
       
   735     $e = $db->sql_query($q);
       
   736     if(!$e) die('alert(unescape(\''.rawurlencode('Error inserting comment data: '.mysql_error().'\n\nQuery:\n'.$q).'\'))');
       
   737     else $_ob .= '<div class="info-box">Your comment has been posted.</div>';
       
   738     return PageUtils::comments($page_id, $namespace, false, Array(), $_ob);
       
   739   }
       
   740   
       
   741   /**
       
   742    * Generates partly-compiled HTML/Javascript code to be eval'ed by the user's browser to display comments
       
   743    * @param $page_id the page ID
       
   744    * @param $namespace the namespace
       
   745    * @param $action administrative action to perform, default is false
       
   746    * @param $flags additional info for $action, shouldn't be used except when deleting/approving comments, etc.
       
   747    * @param $_ob text to prepend to output, used by PageUtils::addcomment
       
   748    * @return array
       
   749    * @access private
       
   750    */
       
   751    
       
   752   function comments_raw($page_id, $namespace, $action = false, $flags = Array(), $_ob = '')
       
   753   {
       
   754     global $db, $session, $paths, $template, $plugins; // Common objects
       
   755     
       
   756     $pname = $paths->nslist[$namespace] . $page_id;
       
   757     
       
   758     ob_start();
       
   759     
       
   760     if($action && $session->get_permissions('mod_comments')) // Nip hacking attempts in the bud
       
   761     {
       
   762       switch($action) {
       
   763       case "delete":
       
   764         if(isset($flags['id']))
       
   765         {
       
   766           $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND comment_id='.intval($flags['id']).' LIMIT 1;';
       
   767         } else {
       
   768           $n = $db->escape($flags['name']);
       
   769           $s = $db->escape($flags['subj']);
       
   770           $t = $db->escape($flags['text']);
       
   771           $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND name=\''.$n.'\' AND subject=\''.$s.'\' AND comment_data=\''.$t.'\' LIMIT 1;';
       
   772         }
       
   773         $e=$db->sql_query($q);
       
   774         if(!$e) die('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
       
   775         break;
       
   776       case "approve":
       
   777         if(isset($flags['id']))
       
   778         {
       
   779           $where = 'comment_id='.intval($flags['id']);
       
   780         } else {
       
   781           $n = $db->escape($flags['name']);
       
   782           $s = $db->escape($flags['subj']);
       
   783           $t = $db->escape($flags['text']);
       
   784           $where = 'name=\''.$n.'\' AND subject=\''.$s.'\' AND comment_data=\''.$t.'\'';
       
   785         }
       
   786         $q = 'SELECT approved FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND '.$where.' LIMIT 1;';
       
   787         $e = $db->sql_query($q);
       
   788         if(!$e) die('alert(unesape(\''.rawurlencode('Error selecting approval status: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
       
   789         $r = $db->fetchrow();
       
   790         $db->free_result();
       
   791         $a = ( $r['approved'] ) ? '0' : '1';
       
   792         $q = 'UPDATE '.table_prefix.'comments SET approved='.$a.' WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND '.$where.';';
       
   793         $e=$db->sql_query($q);
       
   794         if(!$e) die('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
       
   795         if($a=='1') $v = 'Unapprove';
       
   796         else $v = 'Approve';
       
   797         echo 'document.getElementById("mdgApproveLink'.$_GET['id'].'").innerHTML="'.$v.'";';
       
   798         break;
       
   799       }
       
   800     }
       
   801     
       
   802     if(!defined('ENANO_TEMPLATE_LOADED'))
       
   803     {
       
   804       $template->load_theme($session->theme, $session->style);
       
   805     }
       
   806     
       
   807     $tpl = $template->makeParser('comment.tpl');
       
   808     
       
   809     $e = $db->sql_query('SELECT * FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND approved=0;');
       
   810     if(!$e) $db->_die('The comment text data could not be selected.');
       
   811     $num_unapp = $db->numrows();
       
   812     $db->free_result();
       
   813     $e = $db->sql_query('SELECT * FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND approved=1;');
       
   814     if(!$e) $db->_die('The comment text data could not be selected.');
       
   815     $num_app = $db->numrows();
       
   816     $db->free_result();
       
   817     $lq = $db->sql_query('SELECT c.comment_id,c.subject,c.name,c.comment_data,c.approved,c.time,c.user_id,u.user_level,u.signature
       
   818                   FROM '.table_prefix.'comments AS c
       
   819                   LEFT JOIN '.table_prefix.'users AS u
       
   820                     ON c.user_id=u.user_id
       
   821                   WHERE page_id=\''.$page_id.'\'
       
   822                   AND namespace=\''.$namespace.'\' ORDER BY c.time ASC;');
       
   823     if(!$lq) _die('The comment text data could not be selected. '.mysql_error());
       
   824     $_ob .= '<h3>Article Comments</h3>';
       
   825     $n = ( $session->get_permissions('mod_comments')) ? $db->numrows() : $num_app;
       
   826     if($n==1) $s = 'is '.$n.' comment'; else $s = 'are '.$n.' comments';
       
   827     if($n < 1)
       
   828     {
       
   829       $_ob .= '<p>There are currently no comments on this '.strtolower($namespace).'';
       
   830       if($namespace != 'Article') $_ob .= ' page';
       
   831       $_ob .= '.</p>';
       
   832     } else $_ob .= '<p>There '.$s.' on this article.</p>';
       
   833     if($session->get_permissions('mod_comments') && $num_unapp > 0) $_ob .= ' <span style="color: #D84308">'.$num_unapp.' of those are unapproved.</span>';
       
   834     elseif(!$session->get_permissions('mod_comments') && $num_unapp > 0) { $u = ($num_unapp == 1) ? "is $num_unapp comment" : "are $num_unapp comments"; $_ob .= ' However, there ' . $u . ' awating approval.'; }
       
   835     $list = 'list = { ';
       
   836     // _die(htmlspecialchars($ttext));
       
   837     $i = -1;
       
   838     while($row = $db->fetchrow($lq))
       
   839     {
       
   840       $i++;
       
   841       $strings = Array();
       
   842       $bool = Array();
       
   843       if($session->get_permissions('mod_comments') || $row['approved']) {
       
   844         $list .= $i . ' : { \'comment\' : unescape(\''.rawurlencode($row['comment_data']).'\'), \'name\' : unescape(\''.rawurlencode($row['name']).'\'), \'subject\' : unescape(\''.rawurlencode($row['subject']).'\'), }, ';
       
   845         
       
   846         // Comment ID (used in the Javascript apps)
       
   847         $strings['ID'] = (string)$i;
       
   848         
       
   849         // Determine the name, and whether to link to the user page or not
       
   850         $name = '';
       
   851         if($row['user_id'] > 0) $name .= '<a href="'.makeUrlNS('User', str_replace(' ', '_', $row['name'])).'">';
       
   852         $name .= $row['name'];
       
   853         if($row['user_id'] > 0) $name .= '</a>';
       
   854         $strings['NAME'] = $name; unset($name);
       
   855         
       
   856         // Subject
       
   857         $s = $row['subject'];
       
   858         if(!$row['approved']) $s .= ' <span style="color: #D84308">(Unapproved)</span>';
       
   859         $strings['SUBJECT'] = $s;
       
   860         
       
   861         // Date and time
       
   862         $strings['DATETIME'] = date('F d, Y h:i a', $row['time']);
       
   863         
       
   864         // User level
       
   865         switch($row['user_level'])
       
   866         {
       
   867           default:
       
   868           case USER_LEVEL_GUEST:
       
   869             $l = 'Guest';
       
   870             break;
       
   871           case USER_LEVEL_MEMBER:
       
   872             $l = 'Member';
       
   873             break;
       
   874           case USER_LEVEL_MOD:
       
   875             $l = 'Moderator';
       
   876             break;
       
   877           case USER_LEVEL_ADMIN:
       
   878             $l = 'Administrator';
       
   879             break;
       
   880         }
       
   881         $strings['USER_LEVEL'] = $l; unset($l);
       
   882         
       
   883         // The actual comment data
       
   884         $strings['DATA'] = RenderMan::render($row['comment_data']);
       
   885         
       
   886         if($session->get_permissions('edit_comments'))
       
   887         {
       
   888           // Edit link
       
   889           $strings['EDIT_LINK'] = '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=editcomment&amp;id='.$row['comment_id']).'" onclick="editComment(\''.$i.'\'); return false;" id="editbtn_'.$i.'">edit</a>';
       
   890         
       
   891           // Delete link
       
   892           $strings['DELETE_LINK'] = '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=deletecomment&amp;id='.$row['comment_id']).'" onclick="ajaxDeleteComment(\''.$i.'\'); return false;">delete</a>';
       
   893         }
       
   894         else
       
   895         {
       
   896           // Edit link
       
   897           $strings['EDIT_LINK'] = '';
       
   898         
       
   899           // Delete link
       
   900           $strings['DELETE_LINK'] = '';
       
   901         }
       
   902         
       
   903         // Send PM link
       
   904         $strings['SEND_PM_LINK'] = ( $session->user_logged_in && $row['user_id'] > 0 ) ? '<a href="'.makeUrlNS('Special', 'PrivateMessages/Compose/To/'.$row['name']).'">Send private message</a><br />' : '';
       
   905         
       
   906         // Add Buddy link
       
   907         $strings['ADD_BUDDY_LINK'] = ( $session->user_logged_in && $row['user_id'] > 0 ) ? '<a href="'.makeUrlNS('Special', 'PrivateMessages/FriendList/Add/'.$row['name']).'">Add to buddy list</a>' : '';
       
   908         
       
   909         // Mod links
       
   910         $applink = '';
       
   911         $applink .= '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=admin&amp;action=approve&amp;id='.$row['comment_id']).'" onclick="ajaxCommentAdmin(\'approve\', \''.$i.'\'); return false;" id="mdgApproveLink'.$i.'">';
       
   912         if($row['approved']) $applink .= 'Unapprove';
       
   913         else $applink .= 'Approve';
       
   914         $applink .= '</a>';
       
   915         $strings['MOD_APPROVE_LINK'] = $applink; unset($applink);
       
   916         $strings['MOD_DELETE_LINK'] = '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=admin&amp;action=delete&amp;id='.$row['comment_id']).'" onclick="ajaxCommentAdmin(\'delete\', \''.$i.'\'); return false;">Delete</a>';
       
   917         
       
   918         // Signature
       
   919         $strings['SIGNATURE'] = '';
       
   920         if($row['signature'] != '') $strings['SIGNATURE'] = RenderMan::render($row['signature']);
       
   921         
       
   922         $bool['auth_mod'] = ($session->get_permissions('mod_comments')) ? true : false;
       
   923         $bool['can_edit'] = ( ( $session->user_logged_in && $row['name'] == $session->username && $session->get_permissions('edit_comments') ) || $session->get_permissions('mod_comments') ) ? true : false;
       
   924         $bool['signature'] = ( $strings['SIGNATURE'] == '' ) ? false : true;
       
   925         
       
   926         // Done processing and compiling, now let's cook it into HTML
       
   927         $tpl->assign_vars($strings);
       
   928         $tpl->assign_bool($bool);
       
   929         $_ob .= $tpl->run();
       
   930       }
       
   931     }
       
   932     if(getConfig('comments_need_login') != '2' || $session->user_logged_in)
       
   933     {
       
   934       if(!$session->get_permissions('post_comments'))
       
   935       {
       
   936         $_ob .= '<h3>Got something to say?</h3><p>Access to post comments on this page is denied.</p>';
       
   937       }
       
   938       else
       
   939       {
       
   940         $_ob .= '<h3>Got something to say?</h3>If you have comments or suggestions on this article, you can shout it out here.';
       
   941         if(getConfig('approve_comments')=='1') $_ob .= '  Before your comment will be visible to the public, a moderator will have to approve it.';
       
   942         if(getConfig('comments_need_login') == '1' && !$session->user_logged_in) $_ob .= ' Because you are not logged in, you will need to enter a visual confirmation before your comment will be posted.';
       
   943         $sn = $session->user_logged_in ? $session->username . '<input name="name" id="mdgScreenName" type="hidden" value="'.$session->username.'" />' : '<input name="name" id="mdgScreenName" type="text" size="35" />';
       
   944         $_ob .= '  <a href="#" id="mdgCommentFormLink" style="display: none;" onclick="document.getElementById(\'mdgCommentForm\').style.display=\'block\';this.style.display=\'none\';return false;">Leave a comment...</a>
       
   945         <div id="mdgCommentForm">
       
   946         <h3>Comment form</h3>
       
   947         <form action="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=postcomment').'" method="post" style="margin-left: 1em">
       
   948         <table border="0">
       
   949         <tr><td>Your name or screen name:</td><td>'.$sn.'</td></tr>
       
   950         <tr><td>Comment subject:</td><td><input name="subj" id="mdgSubject" type="text" size="35" /></td></tr>';
       
   951         if(getConfig('comments_need_login') == '1' && !$session->user_logged_in)
       
   952         {
       
   953           $session->kill_captcha();
       
   954           $captcha = $session->make_captcha();
       
   955           $_ob .= '<tr><td>Visual confirmation:<br /><small>Please enter the code you see on the right.</small></td><td><img src="'.makeUrlNS('Special', 'Captcha/'.$captcha).'" alt="Visual confirmation" style="cursor: pointer;" onclick="this.src = \''.makeUrlNS("Special", "Captcha/".$captcha).'/\'+Math.floor(Math.random() * 100000);" /><input name="captcha_id" id="mdgCaptchaID" type="hidden" value="'.$captcha.'" /><br />Code: <input name="captcha_input" id="mdgCaptchaInput" type="text" size="10" /><br /><small><script type="text/javascript">document.write("If you can\'t read the code, click on the image to generate a new one.");</script><noscript>If you can\'t read the code, please refresh this page to generate a new one.</noscript></small></td></tr>';
       
   956         }
       
   957         $_ob .= '
       
   958         <tr><td valign="top">Comment text:<br />(most HTML will be stripped)</td><td><textarea name="text" id="mdgCommentArea" rows="10" cols="40"></textarea></td></tr>
       
   959         <tr><td colspan="2" style="text-align: center;"><input type="submit" value="Submit Comment" /></td></tr>
       
   960         </table>
       
   961         </form>
       
   962         </div>';
       
   963       }
       
   964     } else {
       
   965       $_ob .= '<h3>Got something to say?</h3><p>You need to be logged in to post comments. <a href="'.makeUrlNS('Special', 'Login/'.$pname.'%2523comments').'">Log in</a></p>';
       
   966     }
       
   967     $list .= '};';
       
   968     echo 'document.getElementById(\'ajaxEditContainer\').innerHTML = unescape(\''. rawurlencode($_ob) .'\');
       
   969     ' . $list;
       
   970     echo 'Fat.fade_all(); document.getElementById(\'mdgCommentForm\').style.display = \'none\'; document.getElementById(\'mdgCommentFormLink\').style.display="inline";';
       
   971     
       
   972     $ret = ob_get_contents();
       
   973     ob_end_clean();
       
   974     return Array($ret, $_ob);
       
   975     
       
   976   }
       
   977   
       
   978   /**
       
   979    * Generates ready-to-execute Javascript code to be eval'ed by the user's browser to display comments
       
   980    * @param $page_id the page ID
       
   981    * @param $namespace the namespace
       
   982    * @param $action administrative action to perform, default is false
       
   983    * @param $flags additional info for $action, shouldn't be used except when deleting/approving comments, etc.
       
   984    * @param $_ob text to prepend to output, used by PageUtils::addcomment
       
   985    * @return string
       
   986    */
       
   987    
       
   988   function comments($page_id, $namespace, $action = false, $id = -1, $_ob = '')
       
   989   {
       
   990     global $db, $session, $paths, $template, $plugins; // Common objects
       
   991     $r = PageUtils::comments_raw($page_id, $namespace, $action, $id, $_ob);
       
   992     return $r[0];
       
   993   }
       
   994   
       
   995   /**
       
   996    * Generates HTML code for comments - used in browser compatibility mode
       
   997    * @param $page_id the page ID
       
   998    * @param $namespace the namespace
       
   999    * @param $action administrative action to perform, default is false
       
  1000    * @param $flags additional info for $action, shouldn't be used except when deleting/approving comments, etc.
       
  1001    * @param $_ob text to prepend to output, used by PageUtils::addcomment
       
  1002    * @return string
       
  1003    */
       
  1004   
       
  1005   function comments_html($page_id, $namespace, $action = false, $id = -1, $_ob = '')
       
  1006   {
       
  1007     global $db, $session, $paths, $template, $plugins; // Common objects
       
  1008     $r = PageUtils::comments_raw($page_id, $namespace, $action, $id, $_ob);
       
  1009     return $r[1];
       
  1010   }
       
  1011   
       
  1012   /**
       
  1013    * Updates comment data.
       
  1014    * @param $page_id the page ID
       
  1015    * @param $namespace the namespace
       
  1016    * @param $subject new subject
       
  1017    * @param $text new text
       
  1018    * @param $old_subject the old subject, unprocessed and identical to the value in the DB
       
  1019    * @param $old_text the old text, unprocessed and identical to the value in the DB
       
  1020    * @param $id the javascript list ID, used internally by the client-side app
       
  1021    * @return string
       
  1022    */
       
  1023   
       
  1024   function savecomment($page_id, $namespace, $subject, $text, $old_subject, $old_text, $id = -1)
       
  1025   {
       
  1026     global $db, $session, $paths, $template, $plugins; // Common objects
       
  1027     if(!$session->get_permissions('edit_comments'))
       
  1028       return 'result="BAD";error="Access denied"';
       
  1029     // Avoid SQL injection
       
  1030     $old_text    = $db->escape($old_text);
       
  1031     $old_subject = $db->escape($old_subject);
       
  1032     // Safety check - username/login
       
  1033     if(!$session->get_permissions('mod_comments')) // allow mods to edit comments
       
  1034     {
       
  1035       if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
       
  1036       $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_data=\''.$old_text.'\' AND subject=\''.$old_subject.'\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
       
  1037       $s = $db->sql_query($q);
       
  1038       if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
       
  1039       $r = $db->fetchrow($s);
       
  1040       $db->free_result();
       
  1041       if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.');
       
  1042     }
       
  1043     $s = RenderMan::preprocess_text($subject);
       
  1044     $t = RenderMan::preprocess_text($text);
       
  1045     $sql  = 'UPDATE '.table_prefix.'comments SET subject=\''.$s.'\',comment_data=\''.$t.'\' WHERE comment_data=\''.$old_text.'\' AND subject=\''.$old_subject.'\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
       
  1046     $result = $db->sql_query($sql);
       
  1047     if($result)
       
  1048     {
       
  1049       return 'result="GOOD";
       
  1050                       list['.$id.'][\'subject\'] = unescape(\''.str_replace('%5Cn', '%0A', rawurlencode(str_replace('{{EnAnO:Newline}}', '\\n', stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $s))))).'\');
       
  1051                       list['.$id.'][\'comment\'] = unescape(\''.str_replace('%5Cn', '%0A', rawurlencode(str_replace('{{EnAnO:Newline}}', '\\n', stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $t))))).'\'); id = '.$id.';
       
  1052       s = unescape(\''.rawurlencode($s).'\');
       
  1053       t = unescape(\''.str_replace('%5Cn', '<br \\/>', rawurlencode(RenderMan::render(str_replace('{{EnAnO:Newline}}', "\n", stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $t)))))).'\');';
       
  1054     }
       
  1055     else
       
  1056     {
       
  1057       return 'result="BAD"; error=unescape("'.rawurlencode('Enano encountered a problem whilst saving the comment.
       
  1058       Performed SQL:
       
  1059       '.$sql.'
       
  1060     
       
  1061       Error returned by MySQL: '.mysql_error()).'");';
       
  1062     }
       
  1063   }
       
  1064   
       
  1065   /**
       
  1066    * Updates comment data using the comment_id column instead of the old, messy way
       
  1067    * @param $page_id the page ID
       
  1068    * @param $namespace the namespace
       
  1069    * @param $subject new subject
       
  1070    * @param $text new text
       
  1071    * @param $id the comment ID (primary key in enano_comments table)
       
  1072    * @return string
       
  1073    */
       
  1074   
       
  1075   function savecomment_neater($page_id, $namespace, $subject, $text, $id)
       
  1076   {
       
  1077     global $db, $session, $paths, $template, $plugins; // Common objects
       
  1078     if(!is_int($id)) die('PageUtils::savecomment: $id is not an integer, aborting for safety');
       
  1079     if(!$session->get_permissions('edit_comments'))
       
  1080       return 'Access denied';
       
  1081     // Safety check - username/login
       
  1082     if(!$session->get_permissions('mod_comments')) // allow mods to edit comments
       
  1083     {
       
  1084       if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
       
  1085       $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_id='.$id.' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
       
  1086       $s = $db->sql_query($q);
       
  1087       if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
       
  1088       $r = $db->fetchrow($s);
       
  1089       if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.');
       
  1090       $db->free_result();
       
  1091     }
       
  1092     $s = RenderMan::preprocess_text($subject);
       
  1093     $t = RenderMan::preprocess_text($text);
       
  1094     $sql  = 'UPDATE '.table_prefix.'comments SET subject=\''.$s.'\',comment_data=\''.$t.'\' WHERE comment_id='.$id.' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
       
  1095     $result = $db->sql_query($sql);
       
  1096     if($result)
       
  1097     return 'good';
       
  1098     else return 'Enano encountered a problem whilst saving the comment.
       
  1099     Performed SQL:
       
  1100     '.$sql.'
       
  1101     
       
  1102     Error returned by MySQL: '.mysql_error();
       
  1103   }
       
  1104   
       
  1105   /**
       
  1106    * Deletes a comment.
       
  1107    * @param $page_id the page ID
       
  1108    * @param $namespace the namespace
       
  1109    * @param $name the name the user posted under
       
  1110    * @param $subj the subject of the comment to be deleted
       
  1111    * @param $text the text of the comment to be deleted
       
  1112    * @param $id the javascript list ID, used internally by the client-side app
       
  1113    * @return string
       
  1114    */
       
  1115   
       
  1116   function deletecomment($page_id, $namespace, $name, $subj, $text, $id)
       
  1117   {
       
  1118     global $db, $session, $paths, $template, $plugins; // Common objects
       
  1119     
       
  1120     if(!$session->get_permissions('edit_comments'))
       
  1121       return 'alert("Access to delete/edit comments is denied");';
       
  1122     
       
  1123     if(!preg_match('#^([0-9]+)$#', (string)$id)) die('$_GET[id] is improperly formed.');
       
  1124     $n = $db->escape($name);
       
  1125     $s = $db->escape($subj);
       
  1126     $t = $db->escape($text);
       
  1127     
       
  1128     // Safety check - username/login
       
  1129     if(!$session->get_permissions('mod_comments')) // allows mods to delete comments
       
  1130     {
       
  1131       if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
       
  1132       $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_data=\''.$t.'\' AND subject=\''.$s.'\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
       
  1133       $s = $db->sql_query($q);
       
  1134       if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
       
  1135       $r = $db->fetchrow($s);
       
  1136       if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.');
       
  1137       $db->free_result();
       
  1138     }
       
  1139     $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND name=\''.$n.'\' AND subject=\''.$s.'\' AND comment_data=\''.$t.'\' LIMIT 1;';
       
  1140     $e=$db->sql_query($q);
       
  1141     if(!$e) return('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
       
  1142     return('good');
       
  1143   }
       
  1144   
       
  1145   /**
       
  1146    * Deletes a comment in a cleaner fashion.
       
  1147    * @param $page_id the page ID
       
  1148    * @param $namespace the namespace
       
  1149    * @param $id the comment ID (primary key)
       
  1150    * @return string
       
  1151    */
       
  1152   
       
  1153   function deletecomment_neater($page_id, $namespace, $id)
       
  1154   {
       
  1155     global $db, $session, $paths, $template, $plugins; // Common objects
       
  1156     
       
  1157     if(!preg_match('#^([0-9]+)$#', (string)$id)) die('$_GET[id] is improperly formed.');
       
  1158     
       
  1159     if(!$session->get_permissions('edit_comments'))
       
  1160       return 'alert("Access to delete/edit comments is denied");';
       
  1161     
       
  1162     // Safety check - username/login
       
  1163     if(!$session->get_permissions('mod_comments')) // allows mods to delete comments
       
  1164     {
       
  1165       if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
       
  1166       $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_id='.$id.' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
       
  1167       $s = $db->sql_query($q);
       
  1168       if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
       
  1169       $r = $db->fetchrow($s);
       
  1170       if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.');
       
  1171       $db->free_result();
       
  1172     }
       
  1173     $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND comment_id='.$id.' LIMIT 1;';
       
  1174     $e=$db->sql_query($q);
       
  1175     if(!$e) return('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
       
  1176     return('good');
       
  1177   }
       
  1178   
       
  1179   /**
       
  1180    * Renames a page.
       
  1181    * @param $page_id the page ID
       
  1182    * @param $namespace the namespace
       
  1183    * @param $name the new name for the page
       
  1184    * @return string error string or success message
       
  1185    */
       
  1186    
       
  1187   function rename($page_id, $namespace, $name)
       
  1188   {
       
  1189     global $db, $session, $paths, $template, $plugins; // Common objects
       
  1190     
       
  1191     $pname = $paths->nslist[$namespace] . $page_id;
       
  1192     
       
  1193     $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false;
       
  1194     $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false;
       
  1195     
       
  1196     if( empty($name)) die('Name is too short');
       
  1197     if( ( $session->get_permissions('rename') && ( ( $prot && $session->get_permissions('even_when_protected') ) || !$prot ) ) && ( $paths->namespace != 'Special' && $paths->namespace != 'Admin' )) {
       
  1198       $e = $db->sql_query('INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,page_id,namespace,author,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'rename\', \''.$paths->cpage['urlname_nons'].'\', \''.$paths->namespace.'\', \''.$session->username.'\', \''.$paths->cpage['name'].'\')');
       
  1199       if(!$e) $db->_die('The page title could not be updated.');
       
  1200       $e = $db->sql_query('UPDATE '.table_prefix.'pages SET name=\''.$db->escape($name).'\' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
       
  1201       if(!$e) $db->_die('The page title could not be updated.');
       
  1202       else return('The page "'.$paths->pages[$pname]['name'].'" has been renamed to "'.$name.'". You are encouraged to leave a comment explaining your action.
       
  1203 
       
  1204 You will see the change take effect the next time you reload this page.');
       
  1205     } else {
       
  1206       return('Access is denied.');
       
  1207     }
       
  1208   }
       
  1209   
       
  1210   /**
       
  1211    * Flushes (clears) the action logs for a given page
       
  1212    * @param $page_id the page ID
       
  1213    * @param $namespace the namespace
       
  1214    * @return string error/success string
       
  1215    */
       
  1216    
       
  1217   function flushlogs($page_id, $namespace)
       
  1218   {
       
  1219     global $db, $session, $paths, $template, $plugins; // Common objects
       
  1220     if(!$session->get_permissions('clear_logs')) die('Administrative privileges are required to flush logs, you loser.');
       
  1221     $e = $db->sql_query('DELETE FROM '.table_prefix.'logs WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
       
  1222     if(!$e) $db->_die('The log entries could not be deleted.');
       
  1223     $e = $db->sql_query('SELECT page_text,char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
       
  1224     if(!$e) $db->_die('The current page text could not be selected; as a result, creating the backup of the page failed. Please make a backup copy of the page by clicking Edit this page and then clicking Save Changes.');
       
  1225     $row = $db->fetchrow();
       
  1226     $db->free_result();
       
  1227     $q='INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,page_id,namespace,page_text,char_tag,author,edit_summary,minor_edit) VALUES(\'page\', \'edit\', '.time().', \''.date('d M Y h:i a').'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape($row['page_text']).'\', \''.$row['char_tag'].'\', \''.$session->username.'\', \''."Automatic backup created when logs were purged".'\', '.'false'.');';
       
  1228     if(!$db->sql_query($q)) $db->_die('The history (log) entry could not be inserted into the logs table.');
       
  1229     return('The logs for this page have been cleared. A backup of this page has been added to the logs table so that this page can be restored in case of vandalism or spam later.');
       
  1230   }
       
  1231   
       
  1232   /**
       
  1233    * Deletes a page.
       
  1234    * @param $page_id the condemned page ID
       
  1235    * @param $namespace the condemned namespace
       
  1236    * @return string
       
  1237    */
       
  1238    
       
  1239   function deletepage($page_id, $namespace)
       
  1240   {
       
  1241     global $db, $session, $paths, $template, $plugins; // Common objects
       
  1242     $perms = $session->fetch_page_acl($page_id, $namespace);
       
  1243     if(!$perms->get_permissions('delete_page')) die('Administrative privileges are required to delete pages, you loser.');
       
  1244     $e = $db->sql_query('INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,page_id,namespace,author) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'delete\', \''.$page_id.'\', \''.$namespace.'\', \''.$session->username.'\')');
       
  1245     if(!$e) $db->_die('The page log entry could not be inserted.');
       
  1246     $e = $db->sql_query('DELETE FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
       
  1247     if(!$e) $db->_die('The page categorization entries could not be deleted.');
       
  1248     $e = $db->sql_query('DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
       
  1249     if(!$e) $db->_die('The page comments could not be deleted.');
       
  1250     $e = $db->sql_query('DELETE FROM '.table_prefix.'page_text WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
       
  1251     if(!$e) $db->_die('The page text entry could not be deleted.');
       
  1252     $e = $db->sql_query('DELETE FROM '.table_prefix.'pages WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
       
  1253     if(!$e) $db->_die('The page entry could not be deleted.');
       
  1254     $e = $db->sql_query('DELETE FROM '.table_prefix.'files WHERE page_id=\''.$page_id.'\'');
       
  1255     if(!$e) $db->_die('The file entry could not be deleted.');
       
  1256     return('This page has been deleted. Note that there is still a log of edits and actions in the database, and anyone with admin rights can raise this page from the dead unless the log is cleared. If the deleted file is an image, there may still be cached thumbnails of it in the cache/ directory, which is inaccessible to users.');
       
  1257   }
       
  1258   
       
  1259   /**
       
  1260    * Increments the deletion votes for a page by 1, and adds the current username/IP to the list of users that have voted for the page to prevent dual-voting
       
  1261    * @param $page_id the page ID
       
  1262    * @param $namespace the namespace
       
  1263    * @return string
       
  1264    */
       
  1265    
       
  1266   function delvote($page_id, $namespace)
       
  1267   {
       
  1268     global $db, $session, $paths, $template, $plugins; // Common objects
       
  1269     if(!$session->get_permissions('vote_delete'))
       
  1270       return 'Access denied';
       
  1271     $pname = $paths->nslist[$namespace] . $page_id;
       
  1272     $cv = $paths->pages[$pname]['delvotes'];
       
  1273     $ips = $paths->pages[$pname]['delvote_ips'];
       
  1274     $ips = explode('|', $ips);
       
  1275     if(in_array($_SERVER['REMOTE_ADDR'], $ips)) return('It appears that you have already voted to have this page deleted.');
       
  1276     if($session->user_logged_in)
       
  1277       if(in_array($session->username, $ips))
       
  1278         return('It appears that you have already voted to have this page deleted.');
       
  1279     $ips[] = $_SERVER['REMOTE_ADDR'];
       
  1280     if($session->user_logged_in) $ips[] = $session->username;
       
  1281     $ips = implode('|', $ips);
       
  1282     $ips = substr($ips, 1, strlen($ips));
       
  1283     $cv++;
       
  1284     $q = 'UPDATE '.table_prefix.'pages SET delvotes='.$cv.',delvote_ips=\''.$ips.'\' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
       
  1285     $w = $db->sql_query($q);
       
  1286     if(!$w) return("Error updating pages table: ".mysql_error()."\n\nAttemped SQL:\n".$q);
       
  1287     return('Your vote to have this page deleted has been cast.'."\nYou are encouraged to leave a comment explaining the reason for your vote.");
       
  1288   }
       
  1289   
       
  1290   /**
       
  1291    * Resets the number of votes against a page to 0.
       
  1292    * @param $page_id the page ID
       
  1293    * @param $namespace the namespace
       
  1294    * @return string
       
  1295    */
       
  1296   
       
  1297   function resetdelvotes($page_id, $namespace)
       
  1298   {
       
  1299     global $db, $session, $paths, $template, $plugins; // Common objects
       
  1300     if(!$session->get_permissions('vote_reset')) die('You need moderator rights in order to do this, stinkin\' hacker.');
       
  1301     $q = 'UPDATE '.table_prefix.'pages SET delvotes=0,delvote_ips=\'\' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
       
  1302     $e = $db->sql_query($q);
       
  1303     if(!$e) $db->_die('The number of delete votes was not reset.');
       
  1304     else return('The number of votes for having this page deleted has been reset to zero.');
       
  1305   }
       
  1306   
       
  1307   /**
       
  1308    * Gets a list of styles for a given theme name.
       
  1309    * @param $id the name of the directory for the theme
       
  1310    * @return string Javascript code
       
  1311    */
       
  1312    
       
  1313   function getstyles()
       
  1314   {
       
  1315     $dir = './themes/'.$_GET['id'].'/css/';
       
  1316     $list = Array();
       
  1317     // Open a known directory, and proceed to read its contents
       
  1318     if (is_dir($dir)) {
       
  1319       if ($dh = opendir($dir)) {
       
  1320         while (($file = readdir($dh)) !== false) {
       
  1321           if(preg_match('#^(.*?)\.css$#is', $file) && $file != '_printable.css') { // _printable.css should be included with every theme
       
  1322                                                                                     // it should be a copy of the original style, but
       
  1323                                                                                     // mostly black and white
       
  1324                                                                                     // Note to self: document this
       
  1325             $list[] = substr($file, 0, strlen($file)-4);
       
  1326           }
       
  1327         }
       
  1328         closedir($dh);
       
  1329       }
       
  1330     } else return($dir.' is not a dir');
       
  1331     $l = 'var list = new Array();';
       
  1332     $i = -1;
       
  1333     foreach($list as $li) {
       
  1334       $i++;
       
  1335       $l .= "list[$i] = '$li';";
       
  1336     }
       
  1337     return $l;
       
  1338   }
       
  1339   
       
  1340   /**
       
  1341    * Assembles a Javascript app with category information
       
  1342    * @param $page_id the page ID
       
  1343    * @param $namespace the namespace
       
  1344    * @return string Javascript code
       
  1345    */
       
  1346    
       
  1347   function catedit($page_id, $namespace)
       
  1348   {
       
  1349     $d = PageUtils::catedit_raw($page_id, $namespace);
       
  1350     return $d[0] . ' /* BEGIN CONTENT */ document.getElementById("ajaxEditContainer").innerHTML = unescape(\''.rawurlencode($d[1]).'\');';
       
  1351   }
       
  1352   
       
  1353   /**
       
  1354    * Does the actual HTML/javascript generation for cat editing, but returns an array
       
  1355    * @access private
       
  1356    */
       
  1357    
       
  1358   function catedit_raw($page_id, $namespace)
       
  1359   {
       
  1360     global $db, $session, $paths, $template, $plugins; // Common objects
       
  1361     ob_start();
       
  1362     $_ob = '';
       
  1363     $e = $db->sql_query('SELECT category_id FROM '.table_prefix.'categories WHERE page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$paths->namespace.'\'');
       
  1364     if(!$e) jsdie('Error selecting category information for current page: '.mysql_error());
       
  1365     $cat_current = Array();
       
  1366     while($r = $db->fetchrow())
       
  1367     {
       
  1368       $cat_current[] = $r;
       
  1369     }
       
  1370     $db->free_result();
       
  1371     $cat_all = Array();
       
  1372     for($i=0;$i<sizeof($paths->pages)/2;$i++)
       
  1373     {
       
  1374       if($paths->pages[$i]['namespace']=='Category') $cat_all[] = $paths->pages[$i];
       
  1375     }
       
  1376     
       
  1377     // Make $cat_all an associative array, like $paths->pages
       
  1378     $sz = sizeof($cat_all);
       
  1379     for($i=0;$i<$sz;$i++)
       
  1380     {
       
  1381       $cat_all[$cat_all[$i]['urlname_nons']] = $cat_all[$i];
       
  1382     }
       
  1383     // Now, the "zipper" function - join the list of categories with the list of cats that this page is a part of
       
  1384     $cat_info = $cat_all;
       
  1385     for($i=0;$i<sizeof($cat_current);$i++)
       
  1386     {
       
  1387       $un = $cat_current[$i]['category_id'];
       
  1388       $cat_info[$un]['member'] = true;
       
  1389     }
       
  1390     // Now copy the information we just set into the numerically named keys
       
  1391     for($i=0;$i<sizeof($cat_info)/2;$i++)
       
  1392     {
       
  1393       $un = $cat_info[$i]['urlname_nons'];
       
  1394       $cat_info[$i] = $cat_info[$un];
       
  1395     }
       
  1396     
       
  1397     echo 'catlist = new Array();'; // Initialize the client-side category list
       
  1398     $_ob .= '<h3>Select which categories this page should be included in.</h3>
       
  1399              <form name="mdgCatForm" action="'.makeUrlNS($namespace, $page_id, 'do=catedit').'" method="post">';
       
  1400     if ( sizeof($cat_info) < 1 )
       
  1401     {
       
  1402       $_ob .= '<p>There are no categories on this site yet.</p>';
       
  1403     }
       
  1404     for ( $i = 0; $i < sizeof($cat_info) / 2; $i++ )
       
  1405     {
       
  1406       // Protection code added 1/3/07
       
  1407       // Updated 3/4/07
       
  1408       $is_prot = false;
       
  1409       $perms = $session->fetch_page_acl($cat_info[$i]['urlname_nons'], 'Category');
       
  1410       if ( !$session->get_permissions('edit_cat') || !$perms->get_permissions('edit_cat') ||
       
  1411          ( $cat_info[$i]['really_protected'] && !$perms->get_permissions('even_when_protected') ) )
       
  1412          $is_prot = true;
       
  1413       $prot = ( $is_prot ) ? ' disabled="disabled" ' : '';
       
  1414       $prottext = ( $is_prot ) ? ' <img alt="(protected)" width="16" height="16" src="'.scriptPath.'/images/lock16.png" />' : '';
       
  1415       echo 'catlist['.$i.'] = \''.$cat_info[$i]['urlname_nons'].'\';';
       
  1416       $_ob .= '<span class="catCheck"><input '.$prot.' name="'.$cat_info[$i]['urlname_nons'].'" id="mdgCat_'.$cat_info[$i]['urlname_nons'].'" type="checkbox"';
       
  1417       if(isset($cat_info[$i]['member'])) $_ob .= ' checked="checked"';
       
  1418       $_ob .= '/>  <label for="mdgCat_'.$cat_info[$i]['urlname_nons'].'">'.$cat_info[$i]['name'].$prottext.'</label></span><br />';
       
  1419     }
       
  1420     
       
  1421     $disabled = ( sizeof($cat_info) < 1 ) ? 'disabled="disabled"' : '';
       
  1422       
       
  1423     $_ob .= '<div style="border-top: 1px solid #CCC; padding-top: 5px; margin-top: 10px;"><input name="__enanoSaveButton" ' . $disabled . ' style="font-weight: bold;" type="submit" onclick="ajaxCatSave(); return false;" value="Save changes" /> <input name="__enanoCatCancel" type="submit" onclick="ajaxReset(); return false;" value="Cancel" /></div></form>';
       
  1424     
       
  1425     $cont = ob_get_contents();
       
  1426     ob_end_clean();
       
  1427     return Array($cont, $_ob);
       
  1428   }
       
  1429   
       
  1430   /**
       
  1431    * Saves category information
       
  1432    * WARNING: If $which_cats is empty, all the category information for the selected page will be nuked!
       
  1433    * @param $page_id string the page ID
       
  1434    * @param $namespace string the namespace
       
  1435    * @param $which_cats array associative array of categories to put the page in
       
  1436    * @return string "GOOD" on success, error string on failure
       
  1437    */
       
  1438   
       
  1439   function catsave($page_id, $namespace, $which_cats)
       
  1440   {
       
  1441     global $db, $session, $paths, $template, $plugins; // Common objects
       
  1442     if(!$session->get_permissions('edit_cat')) return('Insufficient privileges to change category information');
       
  1443     
       
  1444     $page_perms = $session->fetch_page_acl($page_id, $namespace);
       
  1445     $page_data =& $paths->pages[$paths->nslist[$namespace].$page_id];
       
  1446     
       
  1447     $cat_all = Array();
       
  1448     for($i=0;$i<sizeof($paths->pages)/2;$i++)
       
  1449     {
       
  1450       if($paths->pages[$i]['namespace']=='Category') $cat_all[] = $paths->pages[$i];
       
  1451     }
       
  1452     
       
  1453     // Make $cat_all an associative array, like $paths->pages
       
  1454     $sz = sizeof($cat_all);
       
  1455     for($i=0;$i<$sz;$i++)
       
  1456     {
       
  1457       $cat_all[$cat_all[$i]['urlname_nons']] = $cat_all[$i];
       
  1458     }
       
  1459     
       
  1460     $rowlist = Array();
       
  1461     
       
  1462     for($i=0;$i<sizeof($cat_all)/2;$i++)
       
  1463     {
       
  1464       $auth = true;
       
  1465       $perms = $session->fetch_page_acl($cat_all[$i]['urlname_nons'], 'Category');
       
  1466       if ( !$session->get_permissions('edit_cat') || !$perms->get_permissions('edit_cat') ||
       
  1467          ( $cat_all[$i]['really_protected'] && !$perms->get_permissions('even_when_protected') ) ||
       
  1468          ( !$page_perms->get_permissions('even_when_protected') && $page_data['protected'] == '1' ) )
       
  1469          $auth = false;
       
  1470       if(!$auth)
       
  1471       {
       
  1472         // Find out if the page is currently in the category
       
  1473         $q = $db->sql_query('SELECT * FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
       
  1474         if(!$q)
       
  1475           return 'MySQL error: '.$db->get_error();
       
  1476         if($db->numrows() > 0)
       
  1477         {
       
  1478           $auth = true;
       
  1479           $which_cats[$cat_all[$i]['urlname_nons']] = true; // Force the category to stay in its current state
       
  1480         }
       
  1481         $db->free_result();
       
  1482       }
       
  1483       if(isset($which_cats[$cat_all[$i]['urlname_nons']]) && $which_cats[$cat_all[$i]['urlname_nons']] == true /* for clarity ;-) */ && $auth ) $rowlist[] = '(\''.$page_id.'\', \''.$namespace.'\', \''.$cat_all[$i]['urlname_nons'].'\')';
       
  1484     }
       
  1485     if(sizeof($rowlist) > 0)
       
  1486     {
       
  1487       $val = implode(',', $rowlist);
       
  1488       $q = 'INSERT INTO '.table_prefix.'categories(page_id,namespace,category_id) VALUES' . $val . ';';
       
  1489       $e = $db->sql_query('DELETE FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
       
  1490       if(!$e) $db->_die('The old category data could not be deleted.');
       
  1491       $e = $db->sql_query($q);
       
  1492       if(!$e) $db->_die('The new category data could not be inserted.');
       
  1493       return('GOOD');
       
  1494     }
       
  1495     else
       
  1496     {
       
  1497       $e = $db->sql_query('DELETE FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
       
  1498       if(!$e) $db->_die('The old category data could not be deleted.');
       
  1499       return('GOOD');
       
  1500     }
       
  1501   }
       
  1502   
       
  1503   /**
       
  1504    * Sets the wiki mode level for a page.
       
  1505    * @param $page_id string the page ID
       
  1506    * @param $namespace string the namespace
       
  1507    * @param $level int 0 for off, 1 for on, 2 for use global setting
       
  1508    * @return string "GOOD" on success, error string on failure
       
  1509    */
       
  1510   
       
  1511   function setwikimode($page_id, $namespace, $level)
       
  1512   {
       
  1513     global $db, $session, $paths, $template, $plugins; // Common objects
       
  1514     if(!$session->get_permissions('set_wiki_mode')) return('Insufficient access rights');
       
  1515     if(!isset($level) || (isset($level) && !preg_match('#^([0-2]){1}$#', (string)$level))) return('Invalid mode string');
       
  1516     $q = $db->sql_query('UPDATE '.table_prefix.'pages SET wiki_mode='.$level.' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
       
  1517     if(!$q) return('Error during update query: '.mysql_error()."\n\nSQL Backtrace:\n".$db->sql_backtrace());
       
  1518     return('GOOD');
       
  1519   }
       
  1520   
       
  1521   /**
       
  1522    * Sets the access password for a page.
       
  1523    * @param $page_id string the page ID
       
  1524    * @param $namespace string the namespace
       
  1525    * @param $pass string the SHA1 hash of the password - if the password doesn't match the regex ^([0-9a-f]*){40,40}$ it will be sha1'ed
       
  1526    * @return string
       
  1527    */
       
  1528   
       
  1529   function setpass($page_id, $namespace, $pass)
       
  1530   {
       
  1531     global $db, $session, $paths, $template, $plugins; // Common objects
       
  1532     // Determine permissions
       
  1533     if($paths->pages[$paths->nslist[$namespace].$page_id]['password'] != '')
       
  1534       $a = $session->get_permissions('password_reset');
       
  1535     else
       
  1536       $a = $session->get_permissions('password_set');
       
  1537     if(!$a)
       
  1538       return 'Access is denied';
       
  1539     if(!isset($pass)) return('Password was not set on URL');
       
  1540     $p = $pass;
       
  1541     if(!preg_match('#([0-9a-f]){40,40}#', $p)) $p = sha1($p);
       
  1542     if($p=='da39a3ee5e6b4b0d3255bfef95601890afd80709') $p = '';
       
  1543     $e = $db->sql_query('UPDATE '.table_prefix.'pages SET password=\''.$p.'\' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
       
  1544     if(!$e) die('PageUtils::setpass(): Error during update query: '.mysql_error()."\n\nSQL Backtrace:\n".$db->sql_backtrace());
       
  1545     if($p=='') return('The password for this page has been disabled.');
       
  1546     else return('The password for this page has been set.');
       
  1547   }
       
  1548   
       
  1549   /**
       
  1550    * Generates some preview HTML
       
  1551    * @param $text string the wikitext to use
       
  1552    * @return string
       
  1553    */
       
  1554    
       
  1555   function genPreview($text)
       
  1556   {
       
  1557     return '<div class="info-box"><b>Reminder:</b> This is only a preview - your changes to this page have not yet been saved.</div><div style="background-color: #F8F8F8; padding: 10px; border: 1px dashed #406080; max-height: 250px; overflow: auto; margin: 1em 0 1em 1em;">'.RenderMan::render(RenderMan::preprocess_text($text, false, false)).'</div>';
       
  1558   }
       
  1559   
       
  1560   /**
       
  1561    * Makes a scrollable box
       
  1562    * @param string $text the inner HTML
       
  1563    * @param int $height Optional - the maximum height. Defaults to 250.
       
  1564    * @return string
       
  1565    */
       
  1566    
       
  1567   function scrollBox($text, $height = 250)
       
  1568   {
       
  1569     return '<div style="background-color: #F8F8F8; padding: 10px; border: 1px dashed #406080; max-height: '.(string)intval($height).'px; overflow: auto; margin: 1em 0 1em 1em;">'.$text.'</div>';
       
  1570   }
       
  1571   
       
  1572   /**
       
  1573    * Generates a diff summary between two page revisions.
       
  1574    * @param $page_id the page ID
       
  1575    * @param $namespace the namespace
       
  1576    * @param $id1 the time ID of the first revision
       
  1577    * @param $id2 the time ID of the second revision
       
  1578    * @return string XHTML-formatted diff
       
  1579    */
       
  1580    
       
  1581   function pagediff($page_id, $namespace, $id1, $id2)
       
  1582   {
       
  1583     global $db, $session, $paths, $template, $plugins; // Common objects
       
  1584     if(!$session->get_permissions('history_view'))
       
  1585       return 'Access denied';
       
  1586     if(!preg_match('#^([0-9]+)$#', (string)$id1) ||
       
  1587        !preg_match('#^([0-9]+)$#', (string)$id2  )) return 'SQL injection attempt';
       
  1588     // OK we made it through security
       
  1589     // Safest way to make sure we don't end up with the revisions in wrong columns is to make 2 queries
       
  1590     if(!$q1 = $db->sql_query('SELECT page_text,char_tag,author,edit_summary FROM '.table_prefix.'logs WHERE time_id='.$id1.' AND log_type=\'page\' AND action=\'edit\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';')) return 'MySQL error: '.mysql_error();
       
  1591     if(!$q2 = $db->sql_query('SELECT page_text,char_tag,author,edit_summary FROM '.table_prefix.'logs WHERE time_id='.$id2.' AND log_type=\'page\' AND action=\'edit\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';')) return 'MySQL error: '.mysql_error();
       
  1592     $row1 = $db->fetchrow($q1);
       
  1593     $db->free_result($q1);
       
  1594     $row2 = $db->fetchrow($q2);
       
  1595     $db->free_result($q2);
       
  1596     if(sizeof($row1) < 1 || sizeof($row2) < 2) return 'Couldn\'t find any rows that matched the query. The time ID probably doesn\'t exist in the logs table.';
       
  1597     $text1 = $row1['page_text'];
       
  1598     $text2 = $row2['page_text'];
       
  1599     $time1 = date('F d, Y h:i a', $id1);
       
  1600     $time2 = date('F d, Y h:i a', $id2);
       
  1601     $_ob = "
       
  1602     <p>Comparing revisions: {$time1} &rarr; {$time2}</p>
       
  1603     ";
       
  1604     // Free some memory
       
  1605     unset($row1, $row2, $q1, $q2);
       
  1606     
       
  1607     $_ob .= RenderMan::diff($text1, $text2);
       
  1608     return $_ob;
       
  1609   }
       
  1610   
       
  1611   /**
       
  1612    * Gets ACL information about the selected page for target type X and target ID Y.
       
  1613    * @param string $page_id The page ID
       
  1614    * @param string $namespace The namespace
       
  1615    * @param array $parms What to select. This is an array purely for JSON compatibility. It should be an associative array with keys target_type and target_id.
       
  1616    * @return array
       
  1617    */
       
  1618    
       
  1619   function acl_editor($parms = Array())
       
  1620   {
       
  1621     global $db, $session, $paths, $template, $plugins; // Common objects
       
  1622     if(!$session->get_permissions('edit_acl') && $session->user_level < USER_LEVEL_ADMIN)
       
  1623       return 'Access is denied.';
       
  1624     $parms['page_id'] = ( isset($parms['page_id']) ) ? $parms['page_id'] : false;
       
  1625     $parms['namespace'] = ( isset($parms['namespace']) ) ? $parms['namespace'] : false;
       
  1626     $page_id =& $parms['page_id'];
       
  1627     $namespace =& $parms['namespace'];
       
  1628     $page_where_clause      = ( empty($page_id) || empty($namespace) ) ? 'AND a.page_id IS NULL AND a.namespace IS NULL' : 'AND a.page_id=\''.$db->escape($page_id).'\' AND a.namespace=\''.$db->escape($namespace).'\'';
       
  1629     $page_where_clause_lite = ( empty($page_id) || empty($namespace) ) ? 'AND page_id IS NULL AND namespace IS NULL' : 'AND page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\'';
       
  1630     //die(print_r($page_id,true));
       
  1631     $template->load_theme();
       
  1632     // $perms_obj = $session->fetch_page_acl($page_id, $namespace);
       
  1633     $perms_obj =& $session;
       
  1634     $return = Array();
       
  1635     if ( !file_exists(ENANO_ROOT . '/themes/' . $session->theme . '/acledit.tpl') )
       
  1636     {
       
  1637       return Array(
       
  1638         'mode' => 'error',
       
  1639         'error' => 'It seems that (a) the file acledit.tpl is missing from these theme, and (b) the JSON response is working.',
       
  1640       );
       
  1641     }
       
  1642     $return['template'] = $template->extract_vars('acledit.tpl');
       
  1643     $return['page_id'] = $page_id;
       
  1644     $return['namespace'] = $namespace;
       
  1645     if(isset($parms['mode']))
       
  1646     {
       
  1647       switch($parms['mode'])
       
  1648       {
       
  1649         case 'listgroups':
       
  1650           $return['groups'] = Array();
       
  1651           $q = $db->sql_query('SELECT group_id,group_name FROM '.table_prefix.'groups ORDER BY group_name ASC;');
       
  1652           while($row = $db->fetchrow())
       
  1653           {
       
  1654             $return['groups'][] = Array(
       
  1655               'id' => $row['group_id'],
       
  1656               'name' => $row['group_name'],
       
  1657               );
       
  1658           }
       
  1659           $db->free_result();
       
  1660           break;
       
  1661         case 'seltarget':
       
  1662           $return['mode'] = 'seltarget';
       
  1663           $return['acl_types'] = $perms_obj->acl_types;
       
  1664           $return['acl_deps'] = $perms_obj->acl_deps;
       
  1665           $return['acl_descs'] = $perms_obj->acl_descs;
       
  1666           $return['target_type'] = $parms['target_type'];
       
  1667           $return['target_id'] = $parms['target_id'];
       
  1668           switch($parms['target_type'])
       
  1669           {
       
  1670             case ACL_TYPE_USER:
       
  1671               $q = $db->sql_query('SELECT a.rules,u.user_id FROM '.table_prefix.'users AS u
       
  1672                   LEFT JOIN '.table_prefix.'acl AS a
       
  1673                     ON a.target_id=u.user_id
       
  1674                   WHERE a.target_type='.ACL_TYPE_USER.'
       
  1675                     AND u.username=\''.$db->escape($parms['target_id']).'\'
       
  1676                     '.$page_where_clause.';');
       
  1677               if(!$q)
       
  1678                 return(Array('mode'=>'error','error'=>mysql_error()));
       
  1679               if($db->numrows() < 1)
       
  1680               {
       
  1681                 $return['type'] = 'new';
       
  1682                 $q = $db->sql_query('SELECT user_id FROM '.table_prefix.'users WHERE username=\''.$db->escape($parms['target_id']).'\';');
       
  1683                 if(!$q)
       
  1684                   return(Array('mode'=>'error','error'=>mysql_error()));
       
  1685                 if($db->numrows() < 1)
       
  1686                   return Array('mode'=>'error','error'=>'The username you entered was not found.');
       
  1687                 $row = $db->fetchrow();
       
  1688                 $return['target_name'] = $return['target_id'];
       
  1689                 $return['target_id'] = intval($row['user_id']);
       
  1690                 $return['current_perms'] = $session->acl_types;
       
  1691               }
       
  1692               else
       
  1693               {
       
  1694                 $return['type'] = 'edit';
       
  1695                 $row = $db->fetchrow();
       
  1696                 $return['target_name'] = $return['target_id'];
       
  1697                 $return['target_id'] = intval($row['user_id']);
       
  1698                 $return['current_perms'] = $session->acl_merge($perms_obj->acl_types, $session->string_to_perm($row['rules']));
       
  1699               }
       
  1700               $db->free_result();
       
  1701               // Eliminate types that don't apply to this namespace
       
  1702               if ( $namespace )
       
  1703               {
       
  1704                 foreach ( $return['current_perms'] AS $i => $perm )
       
  1705                 {
       
  1706                   if ( ( $page_id != null && $namespace != null ) && ( !in_array ( $namespace, $session->acl_scope[$i] ) && !in_array('All', $session->acl_scope[$i]) ) )
       
  1707                   {
       
  1708                     // echo "// SCOPE CONTROL: eliminating: $i\n";
       
  1709                     unset($return['current_perms'][$i]);
       
  1710                     unset($return['acl_types'][$i]);
       
  1711                     unset($return['acl_descs'][$i]);
       
  1712                     unset($return['acl_deps'][$i]);
       
  1713                   }
       
  1714                 }
       
  1715               }
       
  1716               break;
       
  1717             case ACL_TYPE_GROUP:
       
  1718               $q = $db->sql_query('SELECT a.rules,g.group_name,g.group_id FROM '.table_prefix.'groups AS g
       
  1719                   LEFT JOIN '.table_prefix.'acl AS a
       
  1720                     ON a.target_id=g.group_id
       
  1721                   WHERE a.target_type='.ACL_TYPE_GROUP.'
       
  1722                     AND g.group_id=\''.intval($parms['target_id']).'\'
       
  1723                     '.$page_where_clause.';');
       
  1724               if(!$q)
       
  1725                 return(Array('mode'=>'error','error'=>mysql_error()));
       
  1726               if($db->numrows() < 1)
       
  1727               {
       
  1728                 $return['type'] = 'new';
       
  1729                 $q = $db->sql_query('SELECT group_id,group_name FROM '.table_prefix.'groups WHERE group_id=\''.intval($parms['target_id']).'\';');
       
  1730                 if(!$q)
       
  1731                   return(Array('mode'=>'error','error'=>mysql_error()));
       
  1732                 if($db->numrows() < 1)
       
  1733                   return Array('mode'=>'error','error'=>'The group ID you submitted is not valid.');
       
  1734                 $row = $db->fetchrow();
       
  1735                 $return['target_name'] = $row['group_name'];
       
  1736                 $return['target_id'] = intval($row['group_id']);
       
  1737                 $return['current_perms'] = $session->acl_types;
       
  1738               }
       
  1739               else
       
  1740               {
       
  1741                 $return['type'] = 'edit';
       
  1742                 $row = $db->fetchrow();
       
  1743                 $return['target_name'] = $row['group_name'];
       
  1744                 $return['target_id'] = intval($row['group_id']);
       
  1745                 $return['current_perms'] = $session->acl_merge($session->acl_types, $session->string_to_perm($row['rules']));
       
  1746               }
       
  1747               $db->free_result();
       
  1748               // Eliminate types that don't apply to this namespace
       
  1749               if ( $namespace )
       
  1750               {
       
  1751                 foreach ( $return['current_perms'] AS $i => $perm )
       
  1752                 {
       
  1753                   if ( ( $page_id != false && $namespace != false ) && ( !in_array ( $namespace, $session->acl_scope[$i] ) && !in_array('All', $session->acl_scope[$i]) ) )
       
  1754                   {
       
  1755                     // echo "// SCOPE CONTROL: eliminating: $i\n"; //; ".print_r($namespace,true).":".print_r($page_id,true)."\n";
       
  1756                     unset($return['current_perms'][$i]);
       
  1757                     unset($return['acl_types'][$i]);
       
  1758                     unset($return['acl_descs'][$i]);
       
  1759                     unset($return['acl_deps'][$i]);
       
  1760                   }
       
  1761                 }
       
  1762               }
       
  1763               //return Array('mode'=>'debug','text'=>print_r($return, true));
       
  1764               break;
       
  1765             default:
       
  1766               return Array('mode'=>'error','error','Invalid ACL type ID');
       
  1767               break;
       
  1768           }
       
  1769           return $return;
       
  1770           break;
       
  1771         case 'save_new':
       
  1772         case 'save_edit':
       
  1773           $q = $db->sql_query('DELETE FROM '.table_prefix.'acl WHERE target_type='.intval($parms['target_type']).' AND target_id='.intval($parms['target_id']).'
       
  1774             '.$page_where_clause_lite.';');
       
  1775           if(!$q)
       
  1776             return Array('mode'=>'error','error'=>mysql_error());
       
  1777           $rules = $session->perm_to_string($parms['perms']);
       
  1778           if ( sizeof ( $rules ) < 1 )
       
  1779           {
       
  1780             return array(
       
  1781                 'mode' => 'error', 
       
  1782                 'error' => 'Supplied rule list has a length of zero'
       
  1783               );
       
  1784           }
       
  1785           $q = ($page_id && $namespace) ? 'INSERT INTO '.table_prefix.'acl ( target_type, target_id, page_id, namespace, rules )
       
  1786                                              VALUES( '.intval($parms['target_type']).', '.intval($parms['target_id']).', \''.$db->escape($page_id).'\', \''.$db->escape($namespace).'\', \''.$db->escape($rules).'\' )' :
       
  1787                                           'INSERT INTO '.table_prefix.'acl ( target_type, target_id, rules )
       
  1788                                              VALUES( '.intval($parms['target_type']).', '.intval($parms['target_id']).', \''.$db->escape($rules).'\' )';
       
  1789           if(!$db->sql_query($q)) return Array('mode'=>'error','error'=>mysql_error());
       
  1790           return Array(
       
  1791               'mode' => 'success',
       
  1792               'target_type' => $parms['target_type'],
       
  1793               'target_id' => $parms['target_id'],
       
  1794               'target_name' => $parms['target_name'],
       
  1795               'page_id' => $page_id,
       
  1796               'namespace' => $namespace,
       
  1797             );
       
  1798           break;
       
  1799         case 'delete':
       
  1800           $q = $db->sql_query('DELETE FROM '.table_prefix.'acl WHERE target_type='.intval($parms['target_type']).' AND target_id='.intval($parms['target_id']).'
       
  1801             '.$page_where_clause_lite.';');
       
  1802           if(!$q)
       
  1803             return Array('mode'=>'error','error'=>mysql_error());
       
  1804           return Array(
       
  1805               'mode' => 'delete',
       
  1806               'target_type' => $parms['target_type'],
       
  1807               'target_id' => $parms['target_id'],
       
  1808               'target_name' => $parms['target_name'],
       
  1809               'page_id' => $page_id,
       
  1810               'namespace' => $namespace,
       
  1811             );
       
  1812           break;
       
  1813         default:
       
  1814           return Array('mode'=>'error','error'=>'Hacking attempt');
       
  1815           break;
       
  1816       }
       
  1817     }
       
  1818     return $return;
       
  1819   }
       
  1820   
       
  1821   /**
       
  1822    * Same as PageUtils::acl_editor(), but the parms are a JSON string instead of an array. This also returns a JSON string.
       
  1823    * @param string $parms Same as PageUtils::acl_editor/$parms, but should be a valid JSON string.
       
  1824    * @return string
       
  1825    */
       
  1826    
       
  1827   function acl_json($parms = '{ }')
       
  1828   {
       
  1829     global $db, $session, $paths, $template, $plugins; // Common objects
       
  1830     $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
       
  1831     $parms = $json->decode($parms);
       
  1832     $ret = PageUtils::acl_editor($parms);
       
  1833     $ret = $json->encode($ret);
       
  1834     return $ret;
       
  1835   }
       
  1836   
       
  1837   /**
       
  1838    * A non-Javascript frontend for the ACL API.
       
  1839    * @param array The request data, if any, this should be in the format required by PageUtils::acl_editor()
       
  1840    */
       
  1841    
       
  1842   function aclmanager($parms)
       
  1843   {
       
  1844     global $db, $session, $paths, $template, $plugins; // Common objects
       
  1845     ob_start();
       
  1846     // Convenience
       
  1847     $formstart = '<form 
       
  1848                     action="' . makeUrl($paths->page, 'do=aclmanager', true) . '"
       
  1849                     method="post" enctype="multipart/form-data"
       
  1850                     onsubmit="if(!submitAuthorized) return false;"
       
  1851                     >';
       
  1852     $formend   = '</form>';
       
  1853     $parms    = PageUtils::acl_preprocess($parms);
       
  1854     $response = PageUtils::acl_editor($parms);
       
  1855     $response = PageUtils::acl_postprocess($response);
       
  1856     
       
  1857     //die('<pre>' . htmlspecialchars(print_r($response, true)) . '</pre>');
       
  1858     
       
  1859     switch($response['mode'])
       
  1860     {
       
  1861       case 'debug':
       
  1862         echo '<pre>' . htmlspecialchars($response['text']) . '</pre>';
       
  1863         break;
       
  1864       case 'stage1':
       
  1865         echo '<h3>Manage page access</h3>
       
  1866               <p>Please select who should be affected by this access rule.</p>';
       
  1867         echo $formstart;
       
  1868         echo '<p><label><input type="radio" name="data[target_type]" value="' . ACL_TYPE_GROUP . '" checked="checked" /> A usergroup</label></p>
       
  1869               <p><select name="data[target_id_grp]">';
       
  1870         foreach ( $response['groups'] as $group )
       
  1871         {
       
  1872           echo '<option value="' . $group['id'] . '">' . $group['name'] . '</option>';
       
  1873         }
       
  1874         echo '</select></p>
       
  1875               <p><label><input type="radio" name="data[target_type]" value="' . ACL_TYPE_USER . '" /> A specific user</label></p>
       
  1876               <p>' . $template->username_field('data[target_id_user]') . '</p>
       
  1877               <p>What should this access rule control?</p>
       
  1878               <p><label><input name="data[scope]" value="only_this" type="radio" checked="checked" /> Only this page</p>
       
  1879               <p><label><input name="data[scope]" value="entire_site" type="radio" /> The entire site</p>
       
  1880               <div style="margin: 0 auto 0 0; text-align: right;">
       
  1881                 <input name="data[mode]" value="seltarget" type="hidden" />
       
  1882                 <input type="hidden" name="data[page_id]" value="' . $paths->cpage['urlname_nons'] . '" />
       
  1883                 <input type="hidden" name="data[namespace]" value="' . $paths->namespace . '" />
       
  1884                 <input type="submit" value="Next &gt;" />
       
  1885               </div>';
       
  1886         echo $formend;
       
  1887         break;
       
  1888       case 'success':
       
  1889         echo '<div class="info-box">
       
  1890                 <b>Permissions updated</b><br />
       
  1891                 The permissions for ' . $response['target_name'] . ' on this page have been updated successfully.<br />
       
  1892                 ' . $formstart . '
       
  1893                 <input type="hidden" name="data[mode]" value="seltarget" />
       
  1894                 <input type="hidden" name="data[target_type]" value="' . $response['target_type'] . '" />
       
  1895                 <input type="hidden" name="data[target_id_user]" value="' . ( ( intval($response['target_type']) == ACL_TYPE_USER ) ? $response['target_name'] : $response['target_id'] ) .'" />
       
  1896                 <input type="hidden" name="data[target_id_grp]"  value="' . ( ( intval($response['target_type']) == ACL_TYPE_USER ) ? $response['target_name'] : $response['target_id'] ) .'" />
       
  1897                 <input type="hidden" name="data[scope]" value="' . ( ( $response['page_id'] ) ? 'only_this' : 'entire_site' ) . '" />
       
  1898                 <input type="hidden" name="data[page_id]" value="' . ( ( $response['page_id'] ) ? $response['page_id'] : 'false' ) . '" />
       
  1899                 <input type="hidden" name="data[namespace]" value="' . ( ( $response['namespace'] ) ? $response['namespace'] : 'false' ) . '" />
       
  1900                 <input type="submit" value="Return to ACL editor" /> <input type="submit" name="data[act_go_stage1]" value="Return to user/scope selection" />
       
  1901                 ' . $formend . '
       
  1902               </div>';
       
  1903         break;
       
  1904       case 'delete':
       
  1905         echo '<div class="info-box">
       
  1906                 <b>Rule deleted</b><br />
       
  1907                 The selected access rule has been successfully deleted.<br />
       
  1908                 ' . $formstart . '
       
  1909                 <input type="hidden" name="data[mode]" value="seltarget" />
       
  1910                 <input type="hidden" name="data[target_type]" value="' . $response['target_type'] . '" />
       
  1911                 <input type="hidden" name="data[target_id_user]" value="' . ( ( intval($response['target_type']) == ACL_TYPE_USER ) ? $response['target_name'] : $response['target_id'] ) .'" />
       
  1912                 <input type="hidden" name="data[target_id_grp]"  value="' . ( ( intval($response['target_type']) == ACL_TYPE_USER ) ? $response['target_name'] : $response['target_id'] ) .'" />
       
  1913                 <input type="hidden" name="data[scope]" value="' . ( ( $response['page_id'] ) ? 'only_this' : 'entire_site' ) . '" />
       
  1914                 <input type="hidden" name="data[page_id]" value="' . ( ( $response['page_id'] ) ? $response['page_id'] : 'false' ) . '" />
       
  1915                 <input type="hidden" name="data[namespace]" value="' . ( ( $response['namespace'] ) ? $response['namespace'] : 'false' ) . '" />
       
  1916                 <input type="submit" value="Return to ACL editor" /> <input type="submit" name="data[act_go_stage1]" value="Return to user/scope selection" />
       
  1917                 ' . $formend . '
       
  1918               </div>';
       
  1919         break;
       
  1920       case 'seltarget':
       
  1921         if ( $response['type'] == 'edit' )
       
  1922         {
       
  1923           echo '<h3>Editing permissions</h3>';
       
  1924         }
       
  1925         else
       
  1926         {
       
  1927           echo '<h3>Create new rule</h3>';
       
  1928         }
       
  1929         $type  = ( $response['target_type'] == ACL_TYPE_GROUP ) ? 'group' : 'user';
       
  1930         $scope = ( $response['page_id'] ) ? 'this page' : 'this entire site';
       
  1931         echo 'This panel allows you to edit what the '.$type.' "'.$response['target_name'].'" can do on <b>'.$scope.'</b>. Unless you set a permission to "Deny", these permissions may be overridden by other rules.';
       
  1932         echo $formstart;
       
  1933         $parser = $template->makeParserText( $response['template']['acl_field_begin'] );
       
  1934         echo $parser->run();
       
  1935         $parser = $template->makeParserText( $response['template']['acl_field_item'] );
       
  1936         $cls = 'row2';
       
  1937         foreach ( $response['acl_types'] as $acl_type => $value )
       
  1938         {
       
  1939           $vars = Array(
       
  1940               'FIELD_DENY_CHECKED' => '',
       
  1941               'FIELD_DISALLOW_CHECKED' => '',
       
  1942               'FIELD_WIKIMODE_CHECKED' => '',
       
  1943               'FIELD_ALLOW_CHECKED' => '',
       
  1944             );
       
  1945           $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
       
  1946           $vars['ROW_CLASS'] = $cls;
       
  1947           
       
  1948           switch ( $response['current_perms'][$acl_type] )
       
  1949           {
       
  1950             case AUTH_ALLOW:
       
  1951               $vars['FIELD_ALLOW_CHECKED'] = 'checked="checked"';
       
  1952               break;
       
  1953             case AUTH_WIKIMODE:
       
  1954               $vars['FIELD_WIKIMODE_CHECKED'] = 'checked="checked"';
       
  1955               break;
       
  1956             case AUTH_DISALLOW:
       
  1957             default:
       
  1958               $vars['FIELD_DISALLOW_CHECKED'] = 'checked="checked"';
       
  1959               break;
       
  1960              case AUTH_DENY:
       
  1961               $vars['FIELD_DENY_CHECKED'] = 'checked="checked"';
       
  1962               break;
       
  1963           }
       
  1964           $vars['FIELD_NAME'] = 'data[perms][' . $acl_type . ']';
       
  1965           $vars['FIELD_DESC'] = $response['acl_descs'][$acl_type];
       
  1966           $parser->assign_vars($vars);
       
  1967           echo $parser->run();
       
  1968         }
       
  1969         $parser = $template->makeParserText( $response['template']['acl_field_end'] );
       
  1970         echo $parser->run();
       
  1971         echo '<div style="margin: 10px auto 0 0; text-align: right;">
       
  1972                 <input name="data[mode]" value="save_' . $response['type'] . '" type="hidden" />
       
  1973                 <input type="hidden" name="data[page_id]" value="'   . (( $response['page_id']   ) ? $response['page_id']   : 'false') . '" />
       
  1974                 <input type="hidden" name="data[namespace]" value="' . (( $response['namespace'] ) ? $response['namespace'] : 'false') . '" />
       
  1975                 <input type="hidden" name="data[target_type]" value="' . $response['target_type'] . '" />
       
  1976                 <input type="hidden" name="data[target_id]" value="' . $response['target_id'] . '" />
       
  1977                 <input type="hidden" name="data[target_name]" value="' . $response['target_name'] . '" />
       
  1978                 <input type="submit" value="Save changes" />&nbsp;&nbsp;<input type="submit" name="data[act_delete_rule]" value="Delete rule" style="color: #AA0000;" onclick="return confirm(\'Do you really want to delete this ACL rule?\');" />
       
  1979               </div>';
       
  1980         echo $formend;
       
  1981         break;
       
  1982       case 'error':
       
  1983         ob_end_clean();
       
  1984         die_friendly('Error occurred', '<p>Error returned by permissions API:</p><pre>' . htmlspecialchars($response['error']) . '</pre>');
       
  1985         break;
       
  1986     }
       
  1987     $ret = ob_get_contents();
       
  1988     ob_end_clean();
       
  1989     echo
       
  1990       $template->getHeader() .
       
  1991       $ret .
       
  1992       $template->getFooter();
       
  1993   }
       
  1994   
       
  1995   /**
       
  1996    * Preprocessor to turn the form-submitted data from the ACL editor into something the backend can handle
       
  1997    * @param array The posted data
       
  1998    * @return array
       
  1999    * @access private
       
  2000    */
       
  2001    
       
  2002   function acl_preprocess($parms)
       
  2003   {
       
  2004     if ( !isset($parms['mode']) )
       
  2005       // Nothing to do
       
  2006       return $parms;
       
  2007     switch ( $parms['mode'] )
       
  2008     {
       
  2009       case 'seltarget':
       
  2010         
       
  2011         // Who's affected?
       
  2012         $parms['target_type'] = intval( $parms['target_type'] );
       
  2013         $parms['target_id'] = ( $parms['target_type'] == ACL_TYPE_GROUP ) ? $parms['target_id_grp'] : $parms['target_id_user'];
       
  2014         
       
  2015       case 'save_edit':
       
  2016       case 'save_new':
       
  2017         if ( isset($parms['act_delete_rule']) )
       
  2018         {
       
  2019           $parms['mode'] = 'delete';
       
  2020         }
       
  2021         
       
  2022         // Scope (just this page or entire site?)
       
  2023         if ( $parms['scope'] == 'entire_site' || ( $parms['page_id'] == 'false' && $parms['namespace'] == 'false' ) )
       
  2024         {
       
  2025           $parms['page_id']   = false;
       
  2026           $parms['namespace'] = false;
       
  2027         }
       
  2028         
       
  2029         break;
       
  2030     }
       
  2031     
       
  2032     if ( isset($parms['act_go_stage1']) )
       
  2033     {
       
  2034       $parms = array(
       
  2035           'mode' => 'listgroups'
       
  2036         );
       
  2037     }
       
  2038     
       
  2039     return $parms;
       
  2040   }
       
  2041   
       
  2042   function acl_postprocess($response)
       
  2043   {
       
  2044     if(!isset($response['mode']))
       
  2045     {
       
  2046       if ( isset($response['groups']) )
       
  2047         $response['mode'] = 'stage1';
       
  2048       else
       
  2049         $response = Array(
       
  2050             'mode' => 'error',
       
  2051             'error' => 'Invalid action passed by API backend.',
       
  2052           );
       
  2053     }
       
  2054     return $response;
       
  2055   }
       
  2056    
       
  2057 }
       
  2058 
       
  2059 ?>