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