ajim/ajim.php
changeset 0 2f9b67edc9b1
child 1 7785b3e99977
equal deleted inserted replaced
-1:000000000000 0:2f9b67edc9b1
       
     1 <?php
       
     2 
       
     3 /**
       
     4  * AjIM - the Asynchronous Javascript Instant Messenger
       
     5  * A shoutbox/chatbox framework that uses PHP, AJAX, MySQL, and Javascript
       
     6  * Version: 1.0 RC 1
       
     7  * Copyright (C) 2006-2007 Dan Fuhry
       
     8  *
       
     9  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
       
    10  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
       
    11  *
       
    12  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
       
    13  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. 
       
    14  */
       
    15 
       
    16 error_reporting(E_ALL);
       
    17 class ajim {
       
    18   var $table_prefix, $conn, $id, $admin, $iface, $prune, $formatfunc, $config, $bad_words;
       
    19   /**
       
    20    * Die and be friendly about it.
       
    21    * @param string $text - should be the text to show to the user, include mysql_error() value if applicable
       
    22    */
       
    23   function kill($text) {
       
    24     die('AjIM: Database error<br />'.$text);
       
    25   }
       
    26   /**
       
    27    * Make a SQL query. This function contains some error correction that performs automatic database upgrades if needed.
       
    28    * @param string $q - The query text to send to MySQL.
       
    29    * @return resource - or, kills the connection and bails out if the query failed
       
    30    */
       
    31   function sql($q) {
       
    32     $r = mysql_query($q, $this->conn);
       
    33     if(!$r)
       
    34     {
       
    35       if(strstr(mysql_error(), 'Unknown column \'time_id\''))
       
    36       {
       
    37         $this->sql('ALTER TABLE '.$this->table_prefix.'ajim ADD COLUMN time_id int(11) NOT NULL DEFAULT 0;');
       
    38         $r = mysql_query($q, $this->conn);
       
    39       }
       
    40       elseif(strstr(mysql_error(), 'Unknown column \'sid\''))
       
    41       {
       
    42         $this->sql('ALTER TABLE '.$this->table_prefix.'ajim ADD COLUMN sid varchar(40) NOT NULL DEFAULT \'\';');
       
    43         $r = mysql_query($q, $this->conn);
       
    44       }
       
    45       elseif(strstr(mysql_error(), 'Unknown column \'ip_addr\''))
       
    46       {
       
    47         $this->sql('ALTER TABLE '.$this->table_prefix.'ajim ADD COLUMN ip_addr varchar(15) NOT NULL DEFAULT \'\';');
       
    48         $r = mysql_query($q, $this->conn);
       
    49       }
       
    50       $this->kill('Error during query:<br /><pre>'.htmlspecialchars($q).'</pre><br />MySQL said: '.mysql_error().'<br /><br />Depending on the error, AjIM may be able to automatically repair it. Just hang tight for about ten seconds. Whatever you do, don\'t close this browser window!');
       
    51     }
       
    52     return $r;
       
    53   }
       
    54   /**
       
    55    * Get the user's SID (unique ID used for editing authorization) or generate a new one.
       
    56    * @return string
       
    57    */
       
    58   function get_sid()
       
    59   {
       
    60     // Tag the user with a unique ID that can be used to edit posts
       
    61     // This is used to essentially track users, but only for the purpose of letting them edit posts
       
    62     if(!isset($_COOKIE['ajim_sid']))
       
    63     {
       
    64       $hash = sha1(microtime());
       
    65       setcookie('ajim_sid', $hash, time()+60*60*24*365); // Cookies last for one year
       
    66     }
       
    67     else
       
    68       $hash = $_COOKIE['ajim_sid'];
       
    69       
       
    70     return $hash;
       
    71   }
       
    72   /**
       
    73    * Set the default value for a configuration field.
       
    74    * @param string $key - name of the configuration key
       
    75    * @param string $value - the default value
       
    76    * @param array $confarray - needs to be the array passed as the first param on the constructor
       
    77    */
       
    78   function config_default($key, $value, &$confarray)
       
    79   {
       
    80     if(!isset($confarray[$key]))
       
    81       $confarray[$key] = $value;
       
    82   }
       
    83   /**
       
    84    * Set up some basic vars and a database connection
       
    85    * @param array $config - a configuration array, with either the key db_connection_handle (a valid MySQL connection resource) or the keys dbhost, dbname, dbuser, and dbpass
       
    86    * @param string $table_prefix - the text prepended to the "ajim" table, should match ^([A-z0-9_]+)$
       
    87    * @param string $handler - URL to the backend script, for example in Enano this would be the plugin file plugins/ajim.php
       
    88    * @param string $admin - string containing the MD5 hash of the user's password, IF AND ONLY IF the user should be allowed to use the moderation function. In all other cases this should be false.
       
    89    * @param string $id - used to carry over the randomly generated instance ID between requests. Should be false if the class is being initialized for displaying the inital HTML, in all other cases should be the value of the class variable AjIM::$id
       
    90    * @param bool $can_post - true if the user is allowed to post, false otherwise. Defaults to true.
       
    91    * @param mixed $formatfunc - a string containing the name of a function that can be called to format text before posts are sent to the user. If you need to call a class method, this should be an array with key 0 being the class name and key 1 being the method name.
       
    92    */
       
    93   function __construct($config, $table_prefix, $handler, $admin = false, $id = false, $can_post = true, $formatfunc = false) {
       
    94     // CONFIGURATION
       
    95     // $this->prune: a limit on the number of posts in the chat box. Usually this should be set to 40 or 50. Default is 40.
       
    96     // Set to -1 to disable pruning.
       
    97     $this->prune = -1;
       
    98     
       
    99     $this->get_sid();
       
   100     
       
   101     if(!is_array($config))
       
   102       $this->kill('$config passed to the AjIM constructor should be an associative array with either the keys dbhost, dbname, dbuser, and dbpass, or the key db_connection_handle.');
       
   103     if(isset($config['db_connection_handle']))
       
   104     {
       
   105       if(!is_resource($config['db_connection_handle'])) $this->kill('$config[\'db_connection_handle\'] is not a valid resource');
       
   106       $this->conn = $config['db_connection_handle'];
       
   107       if(!$this->conn) $this->kill('Error verifying database connection: '.mysql_error());
       
   108     } elseif(isset($config['dbhost']) && isset($config['dbname']) && isset($config['dbuser']) && isset($config['dbpass'])) {
       
   109       $this->conn = mysql_connect($config['dbhost'], $config['dbuser'], $config['dbpass']);
       
   110       if(!$this->conn) $this->kill('Error connecting to the database: '.mysql_error());
       
   111       $this->sql('USE '.$config['dbname']);
       
   112     }
       
   113     
       
   114     $this->bad_words = Array('viagra', 'phentermine', 'pharma', 'rolex', 'genital', 'penis', 'ranitidine', 'prozac', 'acetaminophen', 'acyclovir', 'ionamin', 'denavir', 'nizoral', 'zoloft', 'estradiol', 'didrex', 'aciphex', 'seasonale', 'allegra', 'lexapro', 'famvir', 'propecia', 'nasacort');
       
   115     if(isset($config['bad_words']) && is_array($config['bad_words']))
       
   116     {
       
   117       $this->bad_words = array_values(array_merge($this->bad_words, $config['bad_words']));
       
   118     }
       
   119     
       
   120     // Don't change these values here - change them by passing values to the config array in this constructor's params!
       
   121     $this->config_default('sb_color_background', '#FFFFFF', $config);
       
   122     $this->config_default('sb_color_foreground', '#000000', $config);
       
   123     $this->config_default('sb_color_editlink',   '#00C000', $config);
       
   124     $this->config_default('sb_color_deletelink', '#FF0000', $config);
       
   125     $this->config_default('sb_color_userlink',   '#0000FF', $config);
       
   126     
       
   127     $this->config = $config;
       
   128     
       
   129     if($id) $this->id = $id;
       
   130     else    $this->id = 'ajim_'.time();
       
   131     $this->admin = $admin;
       
   132     $this->formatfunc = $formatfunc;
       
   133     $this->can_post = $can_post;
       
   134     $this->table_prefix = $table_prefix;
       
   135     $this->sql('CREATE TABLE IF NOT EXISTS '.$this->table_prefix.'ajim(
       
   136         post_id mediumint(8) NOT NULL auto_increment,
       
   137         name text,
       
   138         website text,
       
   139         post text,
       
   140         time_id int(11) NOT NULL DEFAULT 0,
       
   141         PRIMARY KEY ( post_id )
       
   142       );');
       
   143     $this->iface = $handler;
       
   144     if(isset($_GET['ajimmode'])) $this->handler();
       
   145   }
       
   146   /**
       
   147    * A dummy function used for PHP4 compatibility.
       
   148    * @see AjIM::__construct()
       
   149    */
       
   150   function ajim($config, $table_prefix, $handler, $admin = false, $id = false, $can_post = true, $formatfunc = false) {
       
   151     $this->__construct($config, $table_prefix, $handler, $admin, $id, $can_post, $formatfunc);
       
   152   }
       
   153   /**
       
   154    * Generates the initial HTML UI to be sent to the user, used internally.
       
   155    * @access private
       
   156    * @param string $ajimPath - path to the AjIM connector (not this file), relative to document root, with initial slash.
       
   157    */
       
   158   function html($ajimPath) {
       
   159     
       
   160     $enstr = $this->can_post ? '' : ' disabled="disabled"';
       
   161     $html = '';
       
   162     $html .= '<script type="text/javascript" src="'.$ajimPath.'/ajim.php?js&amp;id='.$this->id.'&amp;path='.urlencode($this->iface).'&amp;pfx='.$this->table_prefix.'"></script>';
       
   163     if($this->admin) {
       
   164     $html.= '<script type="text/javascript" src="'.$ajimPath.'/ajim.php?jsadmin&amp;id='.$this->id.'&amp;path='.urlencode($this->iface).'&amp;pfx='.$this->table_prefix.'"></script>';
       
   165     }
       
   166     $html .= '<div id="'.$this->id.'_master" style="padding: 5%; width: 90%;">
       
   167              <div id="'.$this->id.'_c" style="text-align: center; color: '.$this->config['sb_color_foreground'].';
       
   168              font-family: arial, sans-serif; font-size: 7pt; background-color: '.$this->config['sb_color_background'].';
       
   169              text-align: left; border: 1px solid #000000; border-bottom: none; margin-bottom: 0; padding: 5%; width: 90%;
       
   170              height: 200px; clip: rect(0px,auto,200px,0px); overflow: auto;"><noscript><p>You need to have JavaScript support to use this shoutbox.</p></noscript></div>';
       
   171       // This is the post form div
       
   172     if($this->can_post)
       
   173     {
       
   174     $html .= '<div style="font-family: arial; font-size: 7pt; margin-top: 0; border: 1px solid #000000; border-top-width: 0; width: 100%;">
       
   175             <form action="#" onsubmit="'.$this->id.'_form(); return false;" method="get">
       
   176              <table border="0" style="margin: 0; padding: 0; width: 90%;">
       
   177               <tr><td><span style="font-family: arial; font-size: 7pt; ">Name:</span></td>   <td><input style="font-family: arial; font-size: 7pt; border: 1px solid #000; height: 15px; width: 65px; padding: 1px;" id="'.$this->id.'_name" name="name"'.$enstr.' /></td></tr>
       
   178               <tr><td><span style="font-family: arial; font-size: 7pt; ">Website:</span></td><td><input style="font-family: arial; font-size: 7pt; border: 1px solid #000; height: 15px; width: 65px; padding: 1px;" id="'.$this->id.'_website" name="website"'.$enstr.' /></td></tr>
       
   179               <tr><td colspan="2"><span style="font-family: arial; font-size: 7pt; ">Message:</span></td></tr>
       
   180               <tr><td colspan="2"><textarea'.$enstr.' rows="2" cols="16" style="width: auto; margin: 0 auto;" id="'.$this->id.'_post" name="post" onkeyup="'.$this->id.'_keyhandler();"></textarea></td></tr>
       
   181               <tr><td colspan="2" align="center"><input'.$enstr.' type="submit" value="Submit post" /><br />
       
   182               <span style="font-family: arial; font-size: 6pt; color: #000000;">AjIM powered</span></td></tr>
       
   183               ';
       
   184     $html .= '</table>
       
   185             </form>';
       
   186     if($this->admin) {
       
   187       $html .= '<table border="0" style="margin: 0; padding: 0; width: 90%;" align="center"><tr><td colspan="2" align="center"><span id="'.$this->id.'_admin"><a href="#" onclick="'.$this->id.'_prompt(); return false;">Administration</a></span></td></tr></table>';
       
   188     }
       
   189     $html.='</div></div>';
       
   190     } else {
       
   191       $html .= '<div style="font-family: arial; font-size: 7pt; margin: 5px; margin-top: 0; border: 1px solid #000000; border-top: none;">';
       
   192       if(isset($this->config['cant_post_notice'])) {
       
   193         $html .= '<div style="margin: 0; padding: 5px;">'.$this->config['cant_post_notice'].'</div>';
       
   194       }
       
   195       $html .= '</div></div>';
       
   196     }
       
   197     $html.='<script type="text/javascript">
       
   198     document.getElementById(\''.$this->id.'_c\').innerHTML = unescape(\'%3Cdiv align="center" style="width:95%;"%3EInitializing...%3C\/div%3E\');';
       
   199     if($this->can_post) $html .= 'if('.$this->id.'readCookie("ajim_password") && ( typeof "'.$this->id.'_login_bin" == "string" || typeof "'.$this->id.'_login_bin" == "function" )) {
       
   200       '.$this->id.'_login_bin('.$this->id.'readCookie("ajim_password"));
       
   201     }
       
   202     if('.$this->id.'readCookie("ajim_name")) document.getElementById("'.$this->id.'_name").value = '.$this->id.'readCookie("ajim_name");
       
   203     if('.$this->id.'readCookie("ajim_website")) document.getElementById("'.$this->id.'_website").value = '.$this->id.'readCookie("ajim_website");';
       
   204     $html .= ''.$this->id.'_refresh();
       
   205     </script>';
       
   206     
       
   207     return $html;
       
   208   }
       
   209   /**
       
   210    * Kills the database connection
       
   211    */
       
   212   function destroy() {
       
   213     mysql_close($this->conn);
       
   214   }
       
   215   /**
       
   216    * Strips all traces of HTML, XML, and PHP from text, and prepares it for being inserted into a MySQL database.
       
   217    * @access private
       
   218    * @param string $text - the text to sanitize
       
   219    * @return string
       
   220    */
       
   221   function sanitize($text) {
       
   222     $text = rawurldecode($text);
       
   223     $text = preg_replace('#<(.*?)>#is', '&lt;\\1&gt;', $text);
       
   224     $text = str_replace("\n", '<br />', $text);
       
   225     $text = mysql_real_escape_string($text);
       
   226     return $text;
       
   227   }
       
   228   /**
       
   229    * Scrutinizes a string $text for any traces of the word $word, returns true if the text is clean.
       
   230    * For example, if $word is "viagra" and the text contains "\/|@6r/\" this returns false, else you would get true.
       
   231    * @access private
       
   232    * @param string $text - the text to check
       
   233    * @param string $word - word to look for.
       
   234    * @return bool
       
   235    */
       
   236   function spamcheck($text, $word)
       
   237   {
       
   238     // build an array, with each key containing one letter (equiv. to str_split() in PHP 5)
       
   239     $chars = Array();
       
   240     for($i=0;$i<strlen($word);$i++)
       
   241     {
       
   242       $chars[] = substr($word, $i, 1);
       
   243     }
       
   244     // This is our rule list - all the known substitutions for a given letter (e.g. "\/" in place of "V", etc.), needs to be escaped for regex use
       
   245     $subs = Array(
       
   246       'a'=>'a|\/\\\\|@',
       
   247       'b'=>'b|\|o',
       
   248       'c'=>'c|\(|',
       
   249       'd'=>'d|o\|',
       
   250       'e'=>'e|3',
       
   251       'f'=>'f',
       
   252       'g'=>'g|6|9',
       
   253       'h'=>'h|\|n',
       
   254       'i'=>'i|\!|1|\|',
       
   255       'j'=>'j|\!|1|\|',
       
   256       'k'=>'k|\|<|\|&lt;',
       
   257       'l'=>'l|\!|1|\|',
       
   258       'm'=>'m|nn|rn',
       
   259       'n'=>'n|h|u\\|\\\\\|',
       
   260       'o'=>'o|\(\)|0|@',
       
   261       'p'=>'p',
       
   262       'q'=>'q',
       
   263       'r'=>'r|\|\^',
       
   264       's'=>'s',
       
   265       't'=>'t|\+',
       
   266       'u'=>'u|n',
       
   267       'v'=>'v|\\\\\/', // "\/"
       
   268       'w'=>'w|vv|\\\\\/\\\\\/', // allows for "\/\/"
       
   269       'x'=>'x|><|&gt;<|>&lt;|&gt;&lt;',
       
   270       'y'=>'y',
       
   271       'z'=>'z|\|\\\\\|' // |\|
       
   272       );
       
   273     $regex = '#([\s]){0,1}';
       
   274     foreach($chars as $c)
       
   275     {
       
   276       $lc = strtolower($c);
       
   277       if(isset($subs[$lc]))
       
   278       {
       
   279         $regex .= '('.$subs[$lc].')';
       
   280       } else {
       
   281         die('0 $subs['.$lc.'] is not set');
       
   282         $regex .= preg_quote($c);
       
   283       }
       
   284       $regex .= '(.|)';
       
   285     }
       
   286     $regex .= '([\s]){0,1}#is';
       
   287     //echo($word.': '.$regex.'<br />');
       
   288     if(preg_match($regex, $text)) return false;
       
   289     return true;
       
   290   }
       
   291   /**
       
   292    * Processes AJAX requests. Usually called if $_GET['ajimmode'] is set.
       
   293    * @access private
       
   294    */
       
   295   function handler() {
       
   296     if(isset($_GET['ajimmode'])) {
       
   297       switch($_GET['ajimmode']) {
       
   298       default:
       
   299         die('');
       
   300         break;
       
   301       case 'getsource':
       
   302       case 'getpost':
       
   303         if(!preg_match('#^([0-9]+)$#', $_GET['p'])) die('SQL injection attempt');
       
   304         $q = $this->sql('SELECT post,sid,ip_addr FROM '.$this->table_prefix.'ajim WHERE post_id='.$_GET['p']);
       
   305         $r = mysql_fetch_assoc($q);
       
   306         if( ( ( isset($_GET['ajim_auth']) && (!$this->admin || ($this->admin != $_GET['ajim_auth']) ) ) || !isset($_GET['ajim_auth']) ) && ( $this->get_sid() != $r['sid'] || $_SERVER['REMOTE_ADDR'] != $r['ip_addr'] ) ) die('Hacking attempt');
       
   307         if($_GET['ajimmode']=='getpost')
       
   308           if($this->formatfunc)
       
   309           {
       
   310             $p = @call_user_func($this->formatfunc, $r['post']);
       
   311             if($p) $r['post'] = $p;
       
   312             unset($p); // Free some memory
       
   313           }
       
   314         echo $r['post'];
       
   315         break;
       
   316       case "savepost":
       
   317         if(!preg_match('#^([0-9]+)$#', $_POST['p'])) die('SQL injection attempt');
       
   318         $q = $this->sql('SELECT sid,ip_addr FROM '.$this->table_prefix.'ajim WHERE post_id='.$_POST['p']);
       
   319         $r = mysql_fetch_assoc($q);
       
   320         if( ( ( isset($_POST['ajim_auth']) && (!$this->admin || ($this->admin != $_POST['ajim_auth']) ) ) || !isset($_POST['ajim_auth']) ) && ( $this->get_sid() != $r['sid'] || $_SERVER['REMOTE_ADDR'] != $r['ip_addr'] ) ) die('Hacking attempt');
       
   321         $post = $this->sanitize($_POST['post']);
       
   322         $post = $this->make_clickable($post);
       
   323         $post = preg_replace('#_(.*?)_#is', '<i>\\1</i>', $post);
       
   324         $post = preg_replace('#\*(.*?)\*#is', '<b>\\1</b>', $post);
       
   325         $bad_words = Array('viagra', 'phentermine', 'pharma');
       
   326         foreach($bad_words as $w)
       
   327         {
       
   328           die('0000 checking');
       
   329           if(!$this->spamcheck($post, $w)) die('34567 <span style="color: red">The word "'.$w.'" has been detected in your message and as a result your post has been blocked.</span> Don\'t argue, that will only get you banned.');
       
   330         }
       
   331         if(!$this->can_post) die('Access to posting messages has been denied because the administrator has set that you must be logged into this website in order to post.');
       
   332         
       
   333         $this->sql('UPDATE '.$this->table_prefix.'ajim SET post=\''.$post.'\' WHERE post_id='.$_POST['p'].';');
       
   334         
       
   335         if($this->formatfunc)
       
   336         {
       
   337           $p = @call_user_func($this->formatfunc, $post);
       
   338           if($p) $post = $p;
       
   339           unset($p); // Free some memory
       
   340         }    
       
   341         die($post);
       
   342         break;
       
   343       case 'delete':
       
   344         if(!preg_match('#^([0-9]+)$#', $_POST['p'])) die('SQL injection attempt');
       
   345         $q = $this->sql('SELECT sid,ip_addr FROM '.$this->table_prefix.'ajim WHERE post_id='.$_POST['p']);
       
   346         $r = mysql_fetch_assoc($q);
       
   347         if( ( ( isset($_POST['ajim_auth']) && (!$this->admin || ($this->admin != $_POST['ajim_auth']) ) ) || !isset($_POST['ajim_auth']) ) && ( $this->get_sid() != $r['sid'] || $_SERVER['REMOTE_ADDR'] != $r['ip_addr'] ) ) die('Hacking attempt'); 
       
   348         $this->sql('DELETE FROM '.$this->table_prefix.'ajim WHERE post_id='.$_POST['p']);
       
   349         die('good');
       
   350         break;
       
   351       case 'post':
       
   352         if(!preg_match('#(^|[\n ])([\w]+?://[\w\#$%&~/.\-;:=,?@\[\]+]*)$#is', $_POST['website'])) $_POST['website']='';
       
   353         // Now for a clever anti-spam trick: blacklist the words "viagra" and "phentermine" using one wicked regex:
       
   354         // #([\s]){1}(v|\\\\\/)(.*){1}(i|\||l|1)(.*){1}(a|@|\/\\\\)(.*){1}(g|6)(.*){1}r(.*){1}(a|@|\/\\\\)(\s){1}#is
       
   355         $name    = $this->sanitize($_POST['name']);
       
   356         $website = $this->sanitize($_POST['website']);
       
   357         $post    = $this->sanitize($_POST['post']);
       
   358         foreach($this->bad_words as $w)
       
   359         {
       
   360           if(!$this->spamcheck($post, $w)) die('<span style="color: red">The word "'.$w.'" has been detected in your message and as a result your post has been blocked.</span> Don\'t argue, that will only get you banned.');
       
   361         }
       
   362         $post = $this->make_clickable($post);
       
   363         $post = preg_replace('#_(.*?)_#is', '<i>\\1</i>', $post);
       
   364         $post = preg_replace('#\*(.*?)\*#is', '<b>\\1</b>', $post);
       
   365         if(!$this->can_post) die('Access to posting messages has been denied because the administrator has set that you must be logged into this website in order to post.');
       
   366         $this->sql('INSERT INTO '.$this->table_prefix.'ajim ( name, website, post, time_id, sid, ip_addr ) VALUES(\''.$name.'\', \''.$website.'\', \''.$post.'\', '.time().', \''.mysql_real_escape_string($this->get_sid()).'\', \''.mysql_real_escape_string($_SERVER['REMOTE_ADDR']).'\');');
       
   367       case 'view':
       
   368         // if(isset($_GET['ajim_auth']))
       
   369         //   die('Auth: '.$_GET['ajim_auth']); // .'<br />Pw:   '.$this->admin);
       
   370         if(isset($_GET['latest']) && ( isset($this->config['allow_looping']) && $this->config['allow_looping'] == true ))
       
   371         {
       
   372           // Determine max execution time
       
   373           $max_exec = intval(@ini_get('max_execution_time'));
       
   374           if(!$max_exec) $max_exec = 30;
       
   375           $time_left = $max_exec - 1;
       
   376         }
       
   377         $q = $this->sql('SELECT name, website, post, post_id, time_id, sid, ip_addr FROM '.$this->table_prefix.'ajim ORDER BY post_id;');
       
   378         if(mysql_num_rows($q) < 1) echo '0 <span style="color: #666666">No posts.</span>';
       
   379         else {
       
   380           // Prune the table
       
   381           if($this->prune > 0) {
       
   382             $nr = mysql_num_rows($q);
       
   383             $nr = $nr - $this->prune;
       
   384             if($nr > 0) $this->sql('DELETE FROM '.$this->table_prefix.'ajim LIMIT '.$nr.';');
       
   385           }
       
   386           // Alright, what we want to do here is grab the entire table, load it into an array, and then display the posts in reverse order.
       
   387           for($i = 1; $i<=mysql_num_rows($q); $i++) {
       
   388             $t[$i] = mysql_fetch_object($q);
       
   389           }
       
   390           
       
   391           $s = sizeof($t);
       
   392           
       
   393           if(isset($_GET['latest']) && ( isset($this->config['allow_looping']) && $this->config['allow_looping'] == true ))
       
   394           {
       
   395             // When I was coding this, I immediately thought "use labels and goto!" Here's hoping, PHP6 :-)
       
   396             $latest_from_user = intval($_GET['latest']);
       
   397             $latest_from_db   = intval($t[$s]->time_id);
       
   398             while(true)
       
   399             {
       
   400               if($latest_from_user == $latest_from_db && $time_left > 5)
       
   401               {
       
   402                 $time_left = $time_left - 5;
       
   403                 sleep(5);
       
   404                 mysql_free_result($q);
       
   405                 $q = $this->sql('SELECT name, website, post, post_id, time_id, sid, ip_addr FROM '.$this->table_prefix.'ajim ORDER BY post_id;');
       
   406                 $t = Array();
       
   407                 for($i = 1; $i<=mysql_num_rows($q); $i++) {
       
   408                   $t[$i] = mysql_fetch_object($q);
       
   409                 }
       
   410                 $s = sizeof($t);
       
   411                 $latest_from_user = intval($_GET['latest']);
       
   412                 $latest_from_db   = intval($t[$s]->time_id);
       
   413                 //echo (string)$latest_from_db.'<br />';
       
   414                 //flush();
       
   415                 //exit;
       
   416                 if($latest_from_user != $latest_from_db)
       
   417                   break;
       
   418                 continue;
       
   419               }
       
   420               elseif($latest_from_user == $latest_from_db && $time_left < 5)
       
   421               {
       
   422                 die('[E] No new posts');
       
   423               }
       
   424               break;
       
   425             }
       
   426           }
       
   427           
       
   428           echo $t[$s]->time_id . ' ';
       
   429           
       
   430           // This is my favorite array trick - it baffles everyone who looks at it :-D
       
   431           // What it does is the same as for($i=0;$i<sizeof($t);$i++), but it processes the
       
   432           // array in reverse order.
       
   433           
       
   434           for($i = $s; $i > 0; $i--) {
       
   435             if($this->formatfunc)
       
   436             {
       
   437               $p = @call_user_func($this->formatfunc, $t[$i]->post);
       
   438               if($p) $t[$i]->post = $p;
       
   439               unset($p); // Free some memory
       
   440               $good_tags = Array('b', 'i', 'u', 'br');
       
   441               $gt = implode('|', $good_tags);
       
   442               
       
   443               // Override any modifications that may have been made to the HTML
       
   444               $t[$i]->post = preg_replace('#&lt;('.$gt.')&gt;([^.]+)&lt;/\\1&gt;#is', '<\\1>\\2</\\1>', $t[$i]->post);
       
   445               $t[$i]->post = preg_replace('#&lt;('.$gt.')([ ]*?)/&gt;#is', '<\\1 />', $t[$i]->post);
       
   446               $t[$i]->post = preg_replace('#&lt;('.$gt.')&gt;#is', '<\\1 />', $t[$i]->post);
       
   447             }
       
   448             echo '<div style="border-bottom: 1px solid #BBB; width: 98%;"><table border="0" cellspacing="0" cellpadding="0" width="100%"><tr><td><span style="font-weight: bold">';
       
   449             if($t[$i]->website != '') echo '<a href="'.$t[$i]->website.'" style="color: #0000FF">'.$t[$i]->name.'</a>';
       
   450             else echo ''.$t[$i]->name.'';
       
   451             echo '</span> ';
       
   452             if( $this->can_post && ($t[$i]->sid == $this->get_sid() && $t[$i]->ip_addr == $_SERVER['REMOTE_ADDR'] ) || ( isset($_GET['ajim_auth']) && $_GET['ajim_auth']==$this->admin ) )
       
   453             echo '</td><td style="text-align: right"><a href="#" onclick="void('.$this->id.'_delete_post(\''.$t[$i]->post_id.'\')); return false;" style="color: '.$this->config['sb_color_deletelink'].'">Delete</a> <a href="javascript:void('.$this->id.'_edit_post(\''.$t[$i]->post_id.'\'));" id="'.$this->id.'_editbtn_'.$t[$i]->post_id.'" style="color: '.$this->config['sb_color_editlink'].'">Edit</a>';
       
   454             echo '</td></tr></table><span style="color: #CCC; font-style: italic;">Posted on '.date('n/j, g:ia', $t[$i]->time_id).'</span></div>';
       
   455             echo '<div style="border-bottom: 1px solid #CCC; width: 98%;" id="'.$this->id.'_post_'.$t[$i]->post_id.'">'.$t[$i]->post.'</div>';
       
   456             echo '<br />';
       
   457           }
       
   458         }
       
   459         break;
       
   460       case 'auth':
       
   461         if($_POST['ajim_auth']==$this->admin) echo 'good';
       
   462         else echo 'The password you entered is invalid.';
       
   463         break;
       
   464       }
       
   465     }
       
   466   }
       
   467   
       
   468   /**
       
   469    * Replace URLs within a block of text with anchors
       
   470    * Written by Nathan Codding, copyright (C) phpBB Group
       
   471    * @param string $text - the text to process
       
   472    * @return string
       
   473    */
       
   474   function make_clickable($text)
       
   475   {
       
   476     $text = preg_replace('#(script|about|applet|activex|chrome):#is', "\\1&#058;", $text);
       
   477     $ret = ' ' . $text;
       
   478     $ret = preg_replace('#(^|[\n ])([\w]+?://[\w\#$%&~/.\-;:=,?@\[\]+]*)#is', '\\1<a href="\\2" target="_blank">\\2</a>', $ret);
       
   479     $ret = preg_replace("#(^|[\ n ])((www|ftp)\.[\w\#$%&~/.\-;:=,?@\[\]+]*)#is", '\\1<a href="http://\\2" target="_blank">\\2</a>', $ret);
       
   480     $ret = preg_replace("#(^|[\n ])([a-z0-9&\-_.]+?)@([\w\-]+\.([\w\-\.]+\.)*[\w]+)#i", '\\1<a href="mailto:\\2@\\3">\\2@\\3</a>', $ret);
       
   481     $ret = substr($ret, 1);
       
   482     return($ret);
       
   483   }
       
   484 }
       
   485 
       
   486 // The client-side javascript and CSS code
       
   487 
       
   488 if(isset($_GET['js']) && isset($_GET['id']) && isset($_GET['path']) && isset($_GET['pfx'])) {
       
   489   header('Content-type: text/javascript');
       
   490   ?>
       
   491   // <script>
       
   492   var <?php echo $_GET['id']; ?>id='<?php echo $_GET['id']; ?>';
       
   493   var path='<?php echo $_GET['path']; ?>';
       
   494   var pfx='<?php echo $_GET['pfx']; ?>';
       
   495   var authed = false; // Don't even try to hack this var; it contains the MD5 of the password that *you* enter, setting it to true will just botch up all the requests
       
   496                       // authed is always set to false unless your password has been verified by the server, and it is sent to the server with every request.
       
   497   var shift;
       
   498   var <?php echo $_GET['id']; ?>editlist = new Array();
       
   499   var <?php echo $_GET['id']; ?>_latestpost = 0;
       
   500   var <?php echo $_GET['id']; ?>_allowrequest = true;
       
   501   
       
   502   var <?php echo $_GET['id']; ?>_refcount = 0;
       
   503   var <?php echo $_GET['id']; ?>_refcount_current = 0;
       
   504   
       
   505   var <?php echo $_GET['id']; ?>interval = setInterval('<?php echo $_GET['id']; ?>_refresh();', 5000);
       
   506   var ajim_editlevels = 0;
       
   507                       
       
   508   // Add the AjIM stylesheet to the HTML header
       
   509   var link = document.createElement('link');
       
   510   link.href = path+'?title=null&css&id='+<?php echo $_GET['id']; ?>id+'&path='+path+'&pfx='+pfx+'&ajimmode=';
       
   511   link.rel  = 'stylesheet';
       
   512   link.type = 'text/css';
       
   513   var head = document.getElementsByTagName('head');
       
   514   head = head[0];
       
   515   head.appendChild(link);
       
   516   
       
   517   if(typeof window.onload == 'function')
       
   518     var __ajim_oltemp = window.onload;
       
   519   else
       
   520     var __ajim_oltemp = function(e) { };
       
   521   window.onload = function(e)
       
   522   {
       
   523     if(document.getElementById('<?php echo $_GET['id']; ?>_post'))
       
   524     {
       
   525       document.getElementById('<?php echo $_GET['id']; ?>_post').onkeyup = function(e) { <?php echo $_GET['id']; ?>_keyhandler(e); };
       
   526     }
       
   527     __ajim_oltemp(e);
       
   528   }
       
   529   
       
   530   function <?php echo $_GET['id']; ?>readCookie(name) {var nameEQ = name + "=";var ca = document.cookie.split(';');for(var i=0;i < ca.length;i++){var c = ca[i];while (c.charAt(0)==' ') c = c.substring(1,c.length);if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);}return null;}
       
   531   function <?php echo $_GET['id']; ?>setCookie(name,value,days){if (days){var date = new Date();date.setTime(date.getTime()+(days*24*60*60*1000));var expires = "; expires="+date.toGMTString();}else var expires = "";document.cookie = name+"="+value+expires+"; path=/";}
       
   532   function <?php echo $_GET['id']; ?>eraseCookie(name) {createCookie(name,"",-1);}
       
   533   
       
   534   function strpos(haystack, needle)
       
   535   {
       
   536     if(typeof(haystack) != 'string') return false;
       
   537     if(typeof(needle) != 'string')   return false;
       
   538     len = needle.length;
       
   539     for(i=0;i<haystack.length;i++)
       
   540     {
       
   541       if ( haystack.substr(i, len) == needle )
       
   542         return i;
       
   543     }
       
   544     return 0;
       
   545   }
       
   546                       
       
   547   function <?php echo $_GET['id']; ?>_newReq(what2call) {
       
   548     if (window.XMLHttpRequest) {
       
   549       request = new XMLHttpRequest();
       
   550     } else {
       
   551       if (window.ActiveXObject) {           
       
   552         request = new ActiveXObject("Microsoft.XMLHTTP");
       
   553       } else {
       
   554         alert('Your browser does not support AJAX. Get Firefox 2.0!');
       
   555         return false;
       
   556       }
       
   557     }
       
   558     request.onreadystatechange = what2call;
       
   559     return request;
       
   560   }
       
   561   
       
   562   function <?php echo $_GET['id']; ?>_refresh(force) {
       
   563     <?php echo $_GET['id']; ?>_refcount++;
       
   564     <?php echo $_GET['id']; ?>_refcount_current = <?php echo $_GET['id']; ?>_refcount;
       
   565     if(!<?php echo $_GET['id']; ?>_allowrequest && !force)
       
   566       return false;
       
   567     <?php echo $_GET['id']; ?>_allowrequest = false;
       
   568     var r = <?php echo $_GET['id']; ?>_newReq(function() {
       
   569        if(r.readyState == 4)
       
   570        {
       
   571          // Prevent an old request from taking over a more recent one
       
   572          if(<?php echo $_GET['id']; ?>_refcount > <?php echo $_GET['id']; ?>_refcount_current)
       
   573            return;
       
   574          if(r.responseText != '[E] No new posts')
       
   575          {
       
   576            time = r.responseText.substr(0, strpos(r.responseText, ' '));
       
   577            <?php echo $_GET['id']; ?>_latestpost = parseInt(time);
       
   578            text = r.responseText.substr(strpos(r.responseText, ' ')+1, r.responseText.length);
       
   579            document.getElementById('<?php echo $_GET['id']; ?>_c').innerHTML = text;
       
   580          }
       
   581          <?php echo $_GET['id']; ?>_allowrequest = true;
       
   582        }
       
   583     });
       
   584     if(force)
       
   585       latest = '';
       
   586     else
       
   587       latest = '&latest='+<?php echo $_GET['id']; ?>_latestpost;
       
   588     if(authed) r.open('GET', path+'?title=null&ajimmode=view&id='+<?php echo $_GET['id']; ?>id+'&pfx='+pfx+latest+'&ajim_auth='+authed, true);
       
   589     else       r.open('GET', path+'?title=null&ajimmode=view&id='+<?php echo $_GET['id']; ?>id+'&pfx='+pfx+latest, true);
       
   590     r.send(null);
       
   591   }
       
   592   
       
   593   function <?php echo $_GET['id']; ?>_submit(name, website, post) {
       
   594     var r = <?php echo $_GET['id']; ?>_newReq(function() {
       
   595        if(r.readyState == 4)
       
   596        {
       
   597          if(r.responseText != '[E] No new posts')
       
   598          {
       
   599            if(parseInt(r.responseText.substr(0,1)) != 0)
       
   600            {
       
   601              time = r.responseText.substr(0, strpos(r.responseText, ' '));
       
   602              <?php echo $_GET['id']; ?>_latestpost = parseInt(time);
       
   603              text = r.responseText.substr(strpos(r.responseText, ' ')+1, r.responseText.length);
       
   604            }
       
   605            else
       
   606            {
       
   607              text = r.responseText;
       
   608            }
       
   609            document.getElementById('<?php echo $_GET['id']; ?>_c').innerHTML = text;
       
   610          }
       
   611        }
       
   612     })
       
   613     if(authed) var parms = 'name='+name+'&website='+website+'&post='+post+'&ajim_auth='+authed;
       
   614     else       var parms = 'name='+name+'&website='+website+'&post='+post;
       
   615     r.open('POST', path+'?title=null&ajimmode=post&id='+<?php echo $_GET['id']; ?>id+'', true);
       
   616     r.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
       
   617     r.setRequestHeader("Content-length", parms.length);
       
   618     r.setRequestHeader("Connection", "close");
       
   619     r.send(parms);
       
   620   }
       
   621   
       
   622   function <?php echo $_GET['id']; ?>_form() {
       
   623     var name = document.getElementById(<?php echo $_GET['id']; ?>id+'_name').value;
       
   624     var website = document.getElementById(<?php echo $_GET['id']; ?>id+'_website').value;
       
   625     var post = document.getElementById(<?php echo $_GET['id']; ?>id+'_post').value;
       
   626     if(name.length < 1) { alert('Please enter your name.'); return; }
       
   627     if(post.length < 1) { alert('Please enter a post.'); return; }
       
   628     <?php echo $_GET['id']; ?>setCookie('ajim_name', name, 60*60*24*365*10);
       
   629     <?php echo $_GET['id']; ?>setCookie('ajim_website', website, 60*60*24*365*10);
       
   630     <?php echo $_GET['id']; ?>_submit(name, website, post);
       
   631     document.getElementById(<?php echo $_GET['id']; ?>id+'_post').value = '';
       
   632   }
       
   633   
       
   634   
       
   635   function <?php echo $_GET['id']; ?>_keyhandler(e)
       
   636   {
       
   637     if(!e) e = window.event;
       
   638     if(e.keyCode == 13)
       
   639     {
       
   640       val = document.getElementById(<?php echo $_GET['id']; ?>id+'_post').value;
       
   641       if(!shift)
       
   642       {
       
   643         document.getElementById(<?php echo $_GET['id']; ?>id+'_post').value = val.substr(0, val.length - 1);
       
   644         <?php echo $_GET['id']; ?>_form();
       
   645       }
       
   646     }
       
   647   }
       
   648   
       
   649   function <?php echo $_GET['id']; ?>keysensor(event)
       
   650   {
       
   651     if (event.shiftKey==1)
       
   652     {
       
   653       shift = true;
       
   654     }
       
   655     else
       
   656     {
       
   657       shift = false;
       
   658     }
       
   659   }
       
   660   
       
   661   if(window.onkeydown)
       
   662   {
       
   663     var kttemp = window.onkeydown;
       
   664     window.onkeydown = function(e) { kttemp(e); <?php echo $_GET['id']; ?>keysensor(e); }
       
   665   } else {
       
   666     window.onkeydown = function(e) { <?php echo $_GET['id']; ?>keysensor(e); }
       
   667   }
       
   668   
       
   669   if(window.onkeyup)
       
   670   {
       
   671     var kttemp = window.onkeyup;
       
   672     window.onkeyup = function(e) { kttemp(e); <?php echo $_GET['id']; ?>keysensor(e); }
       
   673   } else {
       
   674     window.onkeyup = function(e) { <?php echo $_GET['id']; ?>keysensor(e); }
       
   675   }
       
   676   
       
   677   function <?php echo $_GET['id']; ?>_edit_post(pid)
       
   678   {
       
   679     if(<?php echo $_GET['id']; ?>editlist[pid])
       
   680     {
       
   681       var r = <?php echo $_GET['id']; ?>_newReq(function() {
       
   682         if(r.readyState == 4) {
       
   683            document.getElementById('<?php echo $_GET['id']; ?>_post_'+pid).innerHTML = r.responseText;
       
   684            document.getElementById('<?php echo $_GET['id']; ?>_editbtn_'+pid).innerHTML = 'Edit';
       
   685            ajim_editlevels--;
       
   686            <?php echo $_GET['id']; ?>editlist[pid] = false;
       
   687            if(ajim_editlevels < 1)
       
   688             {
       
   689               <?php echo $_GET['id']; ?>interval = setInterval('<?php echo $_GET['id']; ?>_refresh();', 5000);
       
   690             }
       
   691         }
       
   692       });
       
   693       if(authed) r.open('GET', path+'?title=null&ajimmode=getpost&id='+<?php echo $_GET['id']; ?>id+'&pfx='+pfx+'&p='+pid+'&ajim_auth='+authed, true);
       
   694       else       r.open('GET', path+'?title=null&ajimmode=getpost&id='+<?php echo $_GET['id']; ?>id+'&pfx='+pfx+'&p='+pid, true);
       
   695       r.send(null);
       
   696     } else {
       
   697       clearInterval(<?php echo $_GET['id']; ?>interval);
       
   698       var r = <?php echo $_GET['id']; ?>_newReq(function() {
       
   699         if(r.readyState == 4) {
       
   700            document.getElementById('<?php echo $_GET['id']; ?>_post_'+pid).innerHTML = '<textarea rows="4" cols="17" id="<?php echo $_GET['id']; ?>_editor_'+pid+'">'+r.responseText+'</textarea><br /><a href="#" onclick="<?php echo $_GET['id']; ?>_save_post(\''+pid+'\'); return false;" style="font-size: 7pt; color: #00C000;">save</a>';
       
   701            document.getElementById('<?php echo $_GET['id']; ?>_editbtn_'+pid).innerHTML = 'Cancel';
       
   702            ajim_editlevels++;
       
   703            <?php echo $_GET['id']; ?>editlist[pid] = true;
       
   704         }
       
   705       });
       
   706       if(authed) r.open('GET', path+'?title=null&ajimmode=getsource&id='+<?php echo $_GET['id']; ?>id+'&pfx='+pfx+'&p='+pid+'&ajim_auth='+authed, true);
       
   707       else       r.open('GET', path+'?title=null&ajimmode=getsource&id='+<?php echo $_GET['id']; ?>id+'&pfx='+pfx+'&p='+pid, true);
       
   708       r.send(null);
       
   709     }
       
   710   }
       
   711   
       
   712   var ajim_global_pid;
       
   713   function <?php echo $_GET['id']; ?>_save_post(pid) {
       
   714     ajim_global_pid = pid;
       
   715     if(!document.getElementById('<?php echo $_GET['id']; ?>_editor_'+pid))
       
   716     {
       
   717       alert('AjIM internal error: bad post ID '+pid+': editor is not open');
       
   718       return false;
       
   719     }
       
   720     var r = <?php echo $_GET['id']; ?>_newReq(function() {
       
   721       if(r.readyState == 4)
       
   722       {
       
   723         ajim_editlevels--;
       
   724         <?php echo $_GET['id']; ?>editlist[pid] = false;
       
   725         document.getElementById('<?php echo $_GET['id']; ?>_editbtn_'+ajim_global_pid).innerHTML = 'Edit';
       
   726         document.getElementById('<?php echo $_GET['id']; ?>_post_'+ajim_global_pid).innerHTML = r.responseText;
       
   727         if(ajim_editlevels < 1)
       
   728         {
       
   729           <?php echo $_GET['id']; ?>_refresh(true);
       
   730           <?php echo $_GET['id']; ?>interval = setInterval('<?php echo $_GET['id']; ?>_refresh();', 5000);
       
   731         }
       
   732       }
       
   733     });
       
   734     var parms = 'post='+escape(document.getElementById('<?php echo $_GET['id']; ?>_editor_'+pid).value.replace('+', '%2B'))+'&ajim_auth='+authed+'&p='+pid;
       
   735     r.open('POST', path+'?title=null&ajimmode=savepost&id='+<?php echo $_GET['id']; ?>id+'', true);
       
   736     r.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
       
   737     r.setRequestHeader("Content-length", parms.length);
       
   738     r.setRequestHeader("Connection", "close");
       
   739     r.send(parms);
       
   740     return null;
       
   741   }
       
   742   
       
   743   function <?php echo $_GET['id']; ?>_delete_post(pid) {
       
   744     //document.getElementById(<?php echo $_GET['id']; ?>id+'_admin').innerHTML = '<span style="font-family: arial; font-size: 7pt; ">Loading...</span>';
       
   745     var r = <?php echo $_GET['id']; ?>_newReq(function() {
       
   746        if(r.readyState == 4)
       
   747          if(r.responseText=="good") {
       
   748            <?php echo $_GET['id']; ?>_refresh(true);
       
   749          } else alert(r.responseText);
       
   750     });
       
   751     var parms = 'ajim_auth='+authed+'&p='+pid;
       
   752     r.open('POST', path+'?title=null&ajimmode=delete&id='+<?php echo $_GET['id']; ?>id+'', true);
       
   753     r.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
       
   754     r.setRequestHeader("Content-length", parms.length);
       
   755     r.setRequestHeader("Connection", "close");
       
   756     r.send(parms);
       
   757     return null;
       
   758   }
       
   759   
       
   760   <?php
       
   761 } elseif(isset($_GET['jsadmin']) && isset($_GET['id']) && isset($_GET['path'])) {
       
   762   header('Content-type: text/javascript');
       
   763   ?>
       
   764   
       
   765   var abuffer;
       
   766   function <?php echo $_GET['id']; ?>_prompt() {
       
   767     abuffer = document.getElementById(<?php echo $_GET['id']; ?>id+'_admin').innerHTML;
       
   768     document.getElementById(<?php echo $_GET['id']; ?>id+'_admin').innerHTML = '<form action="javascript:void(0)" onsubmit="'+<?php echo $_GET['id']; ?>id+'_login()" method="get"><span style="font-family: arial; font-size: 7pt; ">Password:</span>  <input style="font-family: arial; font-size: 7pt; border: 1px solid #000; height: 15px; width: 65px" id="'+<?php echo $_GET['id']; ?>id+'_passfield" name="pass" type="password" /> <input style="font-family: arial; font-size: 7pt; border: 1px solid #000; height: 15px; width: 65px" type="submit" value="OK" /></form>';
       
   769   }
       
   770   
       
   771   function <?php echo $_GET['id']; ?>_login() {
       
   772     pass = document.getElementById(<?php echo $_GET['id']; ?>id+'_passfield').value;
       
   773     pass = hex_md5(pass);
       
   774     <?php echo $_GET['id']; ?>_login_bin(pass);
       
   775   }
       
   776   function <?php echo $_GET['id']; ?>_login_bin(pass) {
       
   777     document.getElementById(<?php echo $_GET['id']; ?>id+'_admin').innerHTML = '<span style="font-family: arial; font-size: 7pt; ">Loading...</span>';
       
   778     var r = <?php echo $_GET['id']; ?>_newReq(function() {
       
   779        if(r.readyState == 4)
       
   780        {
       
   781          if(r.responseText=="good") {
       
   782            authed = pass;
       
   783            <?php echo $_GET['id']; ?>setCookie('ajim_password', authed, 60*60*24*365*10);
       
   784            <?php echo $_GET['id']; ?>_latestpost = 0;
       
   785            <?php echo $_GET['id']; ?>_refresh(true);
       
   786            document.getElementById(<?php echo $_GET['id']; ?>id+'_admin').innerHTML = '';
       
   787          }
       
   788          else
       
   789          {
       
   790            alert(r.responseText); 
       
   791            document.getElementById(<?php echo $_GET['id']; ?>id+'_admin').innerHTML = '<span style="font-family: arial; font-size: 7pt; color: #ff0000">Invalid password!</span><br />'+abuffer;
       
   792          }
       
   793        }
       
   794     })
       
   795     var parms = 'ajim_auth='+pass;
       
   796     r.open('POST', path+'?title=null&ajimmode=auth&id='+<?php echo $_GET['id']; ?>id+'', true);
       
   797     r.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
       
   798     r.setRequestHeader("Content-length", parms.length);
       
   799     r.setRequestHeader("Connection", "close");
       
   800     r.send(parms);
       
   801   }
       
   802   
       
   803   var hexcase = 0; var b64pad  = ""; var chrsz   = 8; function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}; function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}; function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}; function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }; function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }; function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }; function md5_vm_test() { return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72"; }; function core_md5(x, len) { x[len >> 5] |= 0x80 << ((len) % 32); x[(((len + 64) >>> 9) << 4) + 14] = len; var a =  1732584193; var b = -271733879; var c = -1732584194; var d =  271733878; for(var i = 0; i < x.length; i += 16) { var olda = a; var oldb = b; var oldc = c; var oldd = d; a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);c = md5_ff(c, d, a, b, x[i+10], 17, -42063);b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); a = safe_add(a, olda); b = safe_add(b, oldb); c = safe_add(c, oldc); d = safe_add(d, oldd); } return Array(a, b, c, d); }; function md5_cmn(q, a, b, x, s, t) { return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); }; function md5_ff(a, b, c, d, x, s, t) { return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); }; function md5_gg(a, b, c, d, x, s, t) { return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); }; function md5_hh(a, b, c, d, x, s, t) { return md5_cmn(b ^ c ^ d, a, b, x, s, t); }; function md5_ii(a, b, c, d, x, s, t) { return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); }; function core_hmac_md5(key, data) { var bkey = str2binl(key); if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz); var ipad = Array(16), opad = Array(16); for(var i = 0; i < 16; i++) { ipad[i] = bkey[i] ^ 0x36363636; opad[i] = bkey[i] ^ 0x5C5C5C5C; } var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz); return core_md5(opad.concat(hash), 512 + 128); }; function safe_add(x, y) {var lsw = (x & 0xFFFF) + (y & 0xFFFF);var msw = (x >> 16) + (y >> 16) + (lsw >> 16);return (msw << 16) | (lsw & 0xFFFF); }; function bit_rol(num, cnt) { return (num << cnt) | (num >>> (32 - cnt)); }; function str2binl(str) { var bin = Array(); var mask = (1 << chrsz) - 1; for(var i = 0; i < str.length * chrsz; i += chrsz) bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32); return bin; }; function binl2str(bin) { var str = ""; var mask = (1 << chrsz) - 1; for(var i = 0; i < bin.length * 32; i += chrsz) str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask); return str; }; function binl2hex(binarray) { var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; var str = ""; for(var i = 0; i < binarray.length * 4; i++) { str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) + hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF); } return str; }; function binl2b64(binarray) { var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; var str = ""; for(var i = 0; i < binarray.length * 4; i += 3) { var triplet = (((binarray[i >> 2] >> 8 * ( i   %4)) & 0xFF) << 16) | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 ) |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF); for(var j = 0; j < 4; j++) { if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); } } return str; };
       
   804   
       
   805   <?php
       
   806 } elseif(isset($_GET['css']) && isset($_GET['id']) && isset($_GET['path'])) {
       
   807   header('Content-type: text/css');
       
   808   ?>
       
   809   div#<?php echo $_GET['id']; ?>_master {
       
   810     margin: 0;
       
   811     padding: 0;
       
   812     /* background-color: #DDD; */
       
   813   }
       
   814   div#<?php echo $_GET['id']; ?>_master a {
       
   815     display: inline;
       
   816     color: #0000FF;
       
   817   }
       
   818   div#<?php echo $_GET['id']; ?>_master textarea {
       
   819     font-family: arial;
       
   820     font-size: 7pt;
       
   821     border: 1px solid #000;
       
   822     padding: 0;
       
   823   }
       
   824   <?php
       
   825 }
       
   826 ?>