Index: /extensions/CryptograPHP/admin.php
===================================================================
--- /extensions/CryptograPHP/admin.php	(revision 12616)
+++ /extensions/CryptograPHP/admin.php	(revision 12617)
@@ -2,26 +2,85 @@
 if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
 
+$conf['cryptographp'] = unserialize($conf['cryptographp']);
 load_language('plugin.lang', CRYPTO_PATH);
-$conf['cryptographp_theme'] = explode(',', $conf['cryptographp_theme']);
 
 if ( isset($_POST['submit']))
 {
-  $conf['cryptographp_theme'] = array(
-    $_POST['cryptographp_theme'],
-    $_POST['comments_action'],
+  $conf['cryptographp'] = array(
+    'comments_action' => $_POST['comments_action'],
+    'theme'           => $_POST['theme'],
+    'captcha_type'    => $_POST['captcha_type'],
+    'case_sensitive'  => $conf['cryptographp']['case_sensitive'], //not used, problem with some fonts
+    'width'           => (int)$_POST['width'], 
+    'height'          => (int)$_POST['height'],
+    'perturbation'    => (float)$_POST['perturbation'],
+    'image_bg_color'  => $_POST['image_bg_color'],
+    'code_length'     => (int)$_POST['code_length'],
+    'text_color'      => $_POST['text_color'],
+    'num_lines'       => (float)$_POST['num_lines'],
+    'line_color'      => $_POST['line_color'],
+    'noise_level'     => (float)$_POST['noise_level'],
+    'noise_color'     => $_POST['noise_color'],
+    'ttf_file'        => $_POST['ttf_file'],
     );
-  conf_update_param('cryptographp_theme', implode(',', $conf['cryptographp_theme']));
+  
+  conf_update_param('cryptographp', serialize($conf['cryptographp']));
   array_push($page['infos'], l10n('Information data registered in database'));
 }
 
-$template->set_filename('plugin_admin_content', dirname(__FILE__).'/admin.tpl');
+$presets = array(
+  'bluenoise' => array('perturbation'=>0.25, 'image_bg_color'=>'ffffff', 'text_color'=>'0000ff', 'num_lines'=>2, 'line_color'=>'0000ff', 'noise_level'=>2, 'noise_color'=>'0000ff', 'ttf_file'=>'AlteHassGroteskB'),
+  'gray' => array('perturbation'=>1, 'image_bg_color'=>'ffffff', 'text_color'=>'8a8a8a', 'num_lines'=>2, 'line_color'=>'8a8a8a', 'noise_level'=>0.1, 'noise_color'=>'8a8a8a', 'ttf_file'=>'TopSecret'),
+  'xcolor' => array('perturbation'=>0.5, 'image_bg_color'=>'ffffff', 'text_color'=>'random', 'num_lines'=>1, 'line_color'=>'ffffff', 'noise_level'=>2, 'noise_color'=>'ffffff', 'ttf_file'=>'Dread'),
+  'pencil' => array('perturbation'=>0.8, 'image_bg_color'=>'9e9e9e', 'text_color'=>'363636', 'num_lines'=>0, 'line_color'=>'ffffff', 'noise_level'=>0, 'noise_color'=>'ffffff', 'ttf_file'=>'AllStar'),
+  );
+  
+function list_fonts($dir)
+{
+  $dir = rtrim($dir, '/');
+  $dh = opendir($dir);
+  $fonts = array();
+  
+  while (($file = readdir($dh)) !== false )
+  {
+    if ($file !== '.' && $file !== '..') $fonts[] = str_replace('.ttf', null, $file);
+  }
+  
+  closedir($dh);
+  return $fonts;
+}
+
+function presets_to_js($presets)
+{
+  $out = null;
+  
+  foreach ($presets as $name => $param)
+  {
+    $out.= '
+function apply_'.$name.'() {
+  $("input[name=perturbation]").val("'.$param['perturbation'].'");
+  $("input[name=image_bg_color]").val("'.$param['image_bg_color'].'");
+  $("input[name=text_color]").val("'.$param['text_color'].'");
+  $("input[name=num_lines]").val("'.$param['num_lines'].'");
+  $("input[name=line_color]").val("'.$param['line_color'].'");
+  $("input[name=noise_level]").val("'.$param['noise_level'].'");
+  $("input[name=noise_color]").val("'.$param['noise_color'].'");
+  $("input[name=ttf_file]").val(["'.$param['ttf_file'].'"]);
+
+}';
+  }
+   
+  return $out;
+}
+
+$template->set_filename('plugin_admin_content', dirname(__FILE__).'/template/admin.tpl');
 
 $template->assign(array(
-  'cryptographp_theme' => $conf['cryptographp_theme'][0],
-  'comments_action' => $conf['cryptographp_theme'][1],
-  'available_themes' => array('cryptographp', 'bluenoise', 'gray', 'pencil', 'xcolor'),
+  'crypto' => $conf['cryptographp'],
+  'fonts' => list_fonts(CRYPTO_PATH.'securimage/fonts'),
+  'presets' => array_keys($presets),
+  'PRESETS_FUNC' => presets_to_js($presets),
   'CRYPTO_PATH' => CRYPTO_PATH,
-  )
-);
+  ));
 
 $template->assign_var_from_handle('ADMIN_CONTENT', 'plugin_admin_content');
Index: tensions/CryptograPHP/admin.tpl
===================================================================
--- /extensions/CryptograPHP/admin.tpl	(revision 12616)
+++ 	(revision )
@@ -1,32 +1,0 @@
-<div class="titrePage">
-  <h2>CryptograPHP</h2>
-</div>
-
-<form method="post" class="properties">
-<fieldset>
-  <legend>{'Configuration'|@translate}</legend>
-  
-  <ul>			
-    <li style="text-align:center;">
-      <b>{'Captcha theme'|@translate}</b><br/>
-      {foreach from=$available_themes item=theme}
-      <div style="display:inline-block;margin-top:5px;">
-       <label for="{$theme}-example"><img src="{$CRYPTO_PATH}cryptographp/images/{$theme}.png" alt="{$theme}"/></label> <br/>
-        <input type="radio" name="cryptographp_theme" id="{$theme}-example" value="{$theme}" {if $theme == $cryptographp_theme}checked="checked"{/if}/>
-      </div>
-      {/foreach}
-    </li>
-
-    <li>
-      <span class="property">{'Comments action'|@translate}</span>
-      <label><input type="radio" name="comments_action" value="inactive" {if $comments_action == 'inactive'}checked="checked"{/if}/> {'No captcha'|@translate}</label>
-      <label><input type="radio" name="comments_action" value="reject" {if $comments_action == 'reject'}checked="checked"{/if}/> {'Reject'|@translate}</label>
-      <label><input type="radio" name="comments_action" value="moderate" {if $comments_action == 'moderate'}checked="checked"{/if}/> {'Moderate'|@translate}</label>
-    </li>
-  </ul>
-  
-  <p class="bottomButtons">
-    <input class="submit" type="submit" value="{'Submit'|@translate}" name="submit"/>
-  </p>
-</fieldset>
-</form>
Index: /extensions/CryptograPHP/include/category.inc.php
===================================================================
--- /extensions/CryptograPHP/include/category.inc.php	(revision 12616)
+++ /extensions/CryptograPHP/include/category.inc.php	(revision 12617)
@@ -1,8 +1,4 @@
 <?php
-
 if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
-
-$cryptinstall = CRYPTO_PATH.'cryptographp/cryptographp.fct.php';
-include($cryptinstall);
 
 add_event_handler('loc_begin_index', 'add_crypto');
@@ -11,19 +7,25 @@
 function add_crypto()
 {
-  global $template, $conf;
+  global $template;
   
   if (!is_a_guest()) return;
   
   $template->set_prefilter('comments_on_albums', 'prefilter_crypto');
-  $template->assign('CAPTCHA', dsp_crypt($conf['cryptographp_theme'][0].'.cfg.php',1));
 }
 
 function prefilter_crypto($content, $smarty)
 {
-  load_language('plugin.lang', CRYPTO_PATH);
+  global $conf;
   
   $search = '<input type="hidden" name="key" value="{$comment_add.KEY}">';
   $replace = $search.'
-  <label>{$CAPTCHA}<input type="text" name="code"></label>';
+  <label>
+    <img id="captcha" src="'.CRYPTO_PATH.'securimage/securimage_show.php" alt="CAPTCHA Image">
+    <a href="#" onclick="document.getElementById(\'captcha\').src = \''.CRYPTO_PATH.'securimage/securimage_show.php?\' + Math.random(); return false">
+      <img src="'.CRYPTO_PATH.'template/refresh.png"></a>
+    <br>{\''.($conf['cryptographp']['captcha_type']=='string'?'Enter code':'Solve equation').'\'|@translate} :
+    <input type="text" name="captcha_code" size="'.($conf['cryptographp']['code_length']+1).'" maxlength="'.$conf['cryptographp']['code_length'].'" />
+    
+  </label>';
 
   return str_replace($search, $replace, $content);
@@ -32,21 +34,20 @@
 function check_crypto($action, $comment)
 {
-  global $conf, $user;
+  global $conf;
   
-  $my_action = ($conf['cryptographp_theme'][1] == 'reject') ? 'reject':'moderate';
+  include_once(CRYPTO_PATH.'securimage/securimage.php');
+  $securimage = new Securimage();
 
-  if ($action == 'reject' OR $action == $my_action OR !is_a_guest())
+  if ( $action == 'reject' or $action == $conf['cryptographp']['comments_action'] or !is_a_guest() )
   {
     return $action;
   }
 
-  if (!chk_crypt($_POST['code']))
+  if ($securimage->check($_POST['captcha_code']) == false)
   {
-    return $my_action;
+    return $conf['cryptographp']['comments_action'];
   }
-  else
-  {
-    return $action;
-  }
+
+  return $action;
 }
 
Index: /extensions/CryptograPHP/include/contactform.inc.php
===================================================================
--- /extensions/CryptograPHP/include/contactform.inc.php	(revision 12616)
+++ /extensions/CryptograPHP/include/contactform.inc.php	(revision 12617)
@@ -1,8 +1,4 @@
 <?php
-
 if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
-
-$cryptinstall = CRYPTO_PATH.'cryptographp/cryptographp.fct.php';
-include($cryptinstall);
 
 add_event_handler('display_contactform', 'add_crypto');
@@ -11,14 +7,15 @@
 function add_crypto()
 {
-  global $template, $conf;
+  global $template;
 
   if (!is_a_guest()) return;
 
   $template->set_prefilter('cf_form', 'prefilter_crypto');
-  $template->assign('CAPTCHA', dsp_crypt($conf['cryptographp_theme'][0].'.cfg.php',1));
 }
 
 function prefilter_crypto($content, $smarty)
 {
+  global $conf;
+  
   $search = '
       <tr>
@@ -26,8 +23,14 @@
         <td class="contact-form-right"><input class="submit" type="submit" value="{\'cf_submit\'|@translate}"></td>
       </tr>';
-  $replace = '
+  $replace = '     
     <tr>
-      <td class="contact-form-left" style="vertical-align:top;">{\'Antibot test\'|@translate}</td>
-      <td class="contact-form-right"><input type="text" name="code"> <span style="vertical-align:top;">{$CAPTCHA}</span></td>
+      <td class="contact-form-left" style="vertical-align:top;">
+        {\''.($conf['cryptographp']['captcha_type']=='string'?'Enter code':'Solve equation').'\'|@translate}
+        <img id="captcha" src="'.CRYPTO_PATH.'securimage/securimage_show.php" alt="CAPTCHA Image">
+      </td>
+      <td class="contact-form-right"><input type="text" name="captcha_code" size="'.($conf['cryptographp']['code_length']+1).'" maxlength="'.$conf['cryptographp']['code_length'].'" />
+        <a href="#" onclick="document.getElementById(\'captcha\').src = \''.CRYPTO_PATH.'securimage/securimage_show.php?\' + Math.random(); return false">
+          <img src="'.CRYPTO_PATH.'template/refresh.png"></a>
+      </td>
     </tr>'
   ."\n".$search;
@@ -39,8 +42,10 @@
 {
   if (!is_a_guest()) return $infos;
-
-  if (!chk_crypt($_POST['code']))
+  
+  include_once(CRYPTO_PATH.'securimage/securimage.php');
+  $securimage = new Securimage();
+  
+  if ($securimage->check($_POST['captcha_code']) == false)
   {
-    load_language('plugin.lang', CRYPTO_PATH);
     array_push($infos['errors'], l10n('Invalid Captcha'));
   }
Index: /extensions/CryptograPHP/include/picture.inc.php
===================================================================
--- /extensions/CryptograPHP/include/picture.inc.php	(revision 12616)
+++ /extensions/CryptograPHP/include/picture.inc.php	(revision 12617)
@@ -1,29 +1,31 @@
 <?php
-
 if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
 
-$cryptinstall = CRYPTO_PATH.'cryptographp/cryptographp.fct.php';
-include($cryptinstall);
-
-add_event_handler('loc_begin_picture', 'add_crypto');
+add_event_handler('loc_end_picture', 'add_crypto');
 add_event_handler('user_comment_check', 'check_crypto', EVENT_HANDLER_PRIORITY_NEUTRAL, 2);
 
 function add_crypto()
 {
-  global $template, $conf;
+  global $template;
   
   if (!is_a_guest()) return;
   
   $template->set_prefilter('picture', 'prefilter_crypto');
-  $template->assign('CAPTCHA', dsp_crypt($conf['cryptographp_theme'][0].'.cfg.php',1));
 }
 
 function prefilter_crypto($content, $smarty)
 {
-  load_language('plugin.lang', CRYPTO_PATH);
+  global $conf;
   
   $search = '<input type="hidden" name="key" value="{$comment_add.KEY}">';
   $replace = $search.'
-  <label>{$CAPTCHA}<input type="text" name="code"></label>';
+  <label>
+    <img id="captcha" src="'.CRYPTO_PATH.'securimage/securimage_show.php" alt="CAPTCHA Image">
+    <a href="#" onclick="document.getElementById(\'captcha\').src = \''.CRYPTO_PATH.'securimage/securimage_show.php?\' + Math.random(); return false">
+      <img src="'.CRYPTO_PATH.'template/refresh.png"></a>
+    <br>{\''.($conf['cryptographp']['captcha_type']=='string'?'Enter code':'Solve equation').'\'|@translate} :
+    <input type="text" name="captcha_code" size="'.($conf['cryptographp']['code_length']+1).'" maxlength="'.$conf['cryptographp']['code_length'].'" />
+    
+  </label>';
 
   return str_replace($search, $replace, $content);
@@ -32,21 +34,20 @@
 function check_crypto($action, $comment)
 {
-  global $conf, $user;
+  global $conf;
   
-  $my_action = ($conf['cryptographp_theme'][1] == 'reject') ? 'reject':'moderate';
+  include_once(CRYPTO_PATH.'securimage/securimage.php');
+  $securimage = new Securimage();
 
-  if ($action == 'reject' OR $action == $my_action OR !is_a_guest())
+  if ( $action == 'reject' or $action == $conf['cryptographp']['comments_action'] or !is_a_guest() )
   {
     return $action;
   }
 
-  if (!chk_crypt($_POST['code']))
+  if ($securimage->check($_POST['captcha_code']) == false)
   {
-    return $my_action;
+    return $conf['cryptographp']['comments_action'];
   }
-  else
-  {
-    return $action;
-  }
+
+  return $action;
 }
 
Index: /extensions/CryptograPHP/include/register.inc.php
===================================================================
--- /extensions/CryptograPHP/include/register.inc.php	(revision 12616)
+++ /extensions/CryptograPHP/include/register.inc.php	(revision 12617)
@@ -1,8 +1,4 @@
 <?php
-
 if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
-
-$cryptinstall = CRYPTO_PATH.'cryptographp/cryptographp.fct.php';
-include($cryptinstall);
 
 add_event_handler('loc_end_page_header', 'add_crypto');
@@ -11,37 +7,40 @@
 function add_crypto()
 {
-  global $template, $conf;
+  global $template;
 
   $template->set_prefilter('register', 'prefilter_crypto');
-  $template->assign('CAPTCHA', dsp_crypt($conf['cryptographp_theme'][0].'.cfg.php',1));
 }
 
 function prefilter_crypto($content, $smarty)
 {
-  load_language('plugin.lang', CRYPTO_PATH);
+  global $conf;
   
-  $search = '<p class="bottomButtons">';
+  $search = '#\<\/ul\>(.{0,10})\<\/fieldset\>(.{0,10})\<p class\=\"bottomButtons\"\>#is';
   $replace = '
-  <fieldset>
-    <legend>{\'Antibot test\'|@translate}</legend>
-    <ul>
       <li>
         <span class="property">
-          <label>{$CAPTCHA}</label>
+          <label><img id="captcha" src="'.CRYPTO_PATH.'securimage/securimage_show.php" alt="CAPTCHA Image"></label>
         </span>
-        <input type="text" name="code">
+        <b>{\''.($conf['cryptographp']['captcha_type']=='string'?'Enter code':'Solve equation').'\'|@translate} :</b><br>
+        <input type="text" name="captcha_code" size="'.($conf['cryptographp']['code_length']+1).'" maxlength="'.$conf['cryptographp']['code_length'].'" />
+        <a href="#" onclick="document.getElementById(\'captcha\').src = \''.CRYPTO_PATH.'securimage/securimage_show.php?\' + Math.random(); return false">
+          <img src="'.CRYPTO_PATH.'template/refresh.png"></a>
       </li>
-    </ul>
-  </fieldset>'
-."\n".$search;
+  </ul>
 
-  return str_replace($search, $replace, $content);
+  </fieldset>
+
+  <p class="bottomButtons">';
+
+  return preg_replace($search, $replace, $content);
 }
 
 function check_crypto($errors)
 {
-  if (!chk_crypt($_POST['code']))
+  include_once(CRYPTO_PATH.'securimage/securimage.php');
+  $securimage = new Securimage();
+  
+  if ($securimage->check($_POST['captcha_code']) == false)
   {
-    load_language('plugin.lang', CRYPTO_PATH);
     array_push($errors, l10n('Invalid Captcha'));
   }
Index: /extensions/CryptograPHP/language/cs_CZ/description.txt
===================================================================
--- /extensions/CryptograPHP/language/cs_CZ/description.txt	(revision 12616)
+++ /extensions/CryptograPHP/language/cs_CZ/description.txt	(revision 12617)
@@ -1,1 +1,1 @@
-Vloží CryptograPHP captcha ověření pro registrační stránku a kontaktní formulář (thanks to P@t)
+Vloží captcha ověření pro registrační stránku a kontaktní formulář (thanks to P@t)
Index: /extensions/CryptograPHP/language/cs_CZ/plugin.lang.php
===================================================================
--- /extensions/CryptograPHP/language/cs_CZ/plugin.lang.php	(revision 12616)
+++ /extensions/CryptograPHP/language/cs_CZ/plugin.lang.php	(revision 12617)
@@ -6,5 +6,4 @@
 $lang['Moderate'] = 'Moderovat';
 $lang['No captcha'] = 'Bez captcha kódu';
-$lang['Antibot test'] = 'Antirobot test';
 
 ?>
Index: /extensions/CryptograPHP/language/el_GR/description.txt
===================================================================
--- /extensions/CryptograPHP/language/el_GR/description.txt	(revision 12616)
+++ /extensions/CryptograPHP/language/el_GR/description.txt	(revision 12617)
@@ -1,1 +1,1 @@
-Πρόσθεσε ένα CryptograPHP captcha για εγγραφή, σχόλιο και  φόρμα επικοινωνίας
+Πρόσθεσε ένα captcha για εγγραφή, σχόλιο και  φόρμα επικοινωνίας
Index: /extensions/CryptograPHP/language/el_GR/plugin.lang.php
===================================================================
--- /extensions/CryptograPHP/language/el_GR/plugin.lang.php	(revision 12616)
+++ /extensions/CryptograPHP/language/el_GR/plugin.lang.php	(revision 12617)
@@ -3,5 +3,4 @@
 $lang['Invalid Captcha'] = 'Άκυρο Captcha';
 $lang['Captcha theme'] = 'Θέμα Captcha';
-$lang['Antibot test'] = 'Δοκιμή Antibot';
 $lang['Comments action'] = 'Ενέργεια σχολίου';
 $lang['Moderate'] = 'Μέτριο';
Index: /extensions/CryptograPHP/language/en_UK/description.txt
===================================================================
--- /extensions/CryptograPHP/language/en_UK/description.txt	(revision 12616)
+++ /extensions/CryptograPHP/language/en_UK/description.txt	(revision 12617)
@@ -1,1 +1,1 @@
-Add a CryptograPHP captcha to register, comment and ContactForm pages (thanks to P@t)
+Add a captcha to register, comment and ContactForm pages (thanks to P@t)
Index: /extensions/CryptograPHP/language/en_UK/plugin.lang.php
===================================================================
--- /extensions/CryptograPHP/language/en_UK/plugin.lang.php	(revision 12616)
+++ /extensions/CryptograPHP/language/en_UK/plugin.lang.php	(revision 12617)
@@ -2,9 +2,29 @@
 
 $lang['Invalid Captcha'] = 'Invalid Captcha';
-$lang['Captcha theme'] = 'Captcha theme';
-$lang['Antibot test'] = 'Antibot test';
+$lang['Enter code'] = 'Enter code';
+$lang['Solve equation'] = 'Solve equation';
+
 $lang['Comments action'] = 'Comments action';
 $lang['Moderate'] = 'Moderate';
 $lang['No captcha'] = 'No captcha';
+$lang['Captcha type'] = 'Captcha type';
+$lang['Random string'] = 'Random string';
+$lang['Simple equation'] = 'Simple equation';
+$lang['Case sensitive'] = 'Case sensitive';
+$lang['Code lenght'] = 'Code lenght';
+$lang['good value:'] = 'good value:';
+$lang['Captcha theme'] = 'Captcha theme';
+
+$lang['Perturbation'] = 'Perturbation';
+$lang['range:'] = 'range:';
+$lang['Background color'] = 'Background color';
+$lang['Text color'] = 'Text color';
+$lang['Lines density'] = 'Lines density';
+$lang['Lines color'] = 'Lines color';
+$lang['Noise level'] = 'Noise level';
+$lang['Noise color'] = 'Noise color';
+$lang['Font'] = 'Font';
+$lang['Preview'] = 'Preview';
+$lang['Tip: type "random" on a color field to have a random color'] = 'Tip: type "random" on a color field to have a random color';
 
 ?>
Index: /extensions/CryptograPHP/language/es_ES/description.txt
===================================================================
--- /extensions/CryptograPHP/language/es_ES/description.txt	(revision 12616)
+++ /extensions/CryptograPHP/language/es_ES/description.txt	(revision 12617)
@@ -1,1 +1,1 @@
-Añade un captcha CryptograPHP a la página de registro y en la página de ContactForm (gracias a P@t)
+Añade un captcha a la página de registro y en la página de ContactForm (gracias a P@t)
Index: /extensions/CryptograPHP/language/es_ES/plugin.lang.php
===================================================================
--- /extensions/CryptograPHP/language/es_ES/plugin.lang.php	(revision 12616)
+++ /extensions/CryptograPHP/language/es_ES/plugin.lang.php	(revision 12617)
@@ -3,5 +3,4 @@
 $lang['Invalid Captcha'] = 'Captcha no valido';
 $lang['Captcha theme'] = 'Tema del captcha';
-$lang['Antibot test'] = 'Test anti-bots';
 $lang['Comments action'] = 'Acción para los Comentario';
 $lang['Moderate'] = 'Moderar';
Index: /extensions/CryptograPHP/language/fr_FR/description.txt
===================================================================
--- /extensions/CryptograPHP/language/fr_FR/description.txt	(revision 12616)
+++ /extensions/CryptograPHP/language/fr_FR/description.txt	(revision 12617)
@@ -1,1 +1,1 @@
-Ajoute un captcha CryptograPHP à la page d'enregistrement, au formulaire de commentaire et sur la page de ContactForm (merci à P@t)
+Ajoute un captcha à la page d'enregistrement, au formulaire de commentaire et sur la page de ContactForm (merci à P@t)
Index: /extensions/CryptograPHP/language/fr_FR/plugin.lang.php
===================================================================
--- /extensions/CryptograPHP/language/fr_FR/plugin.lang.php	(revision 12616)
+++ /extensions/CryptograPHP/language/fr_FR/plugin.lang.php	(revision 12617)
@@ -2,9 +2,29 @@
 
 $lang['Invalid Captcha'] = 'Captcha non valide';
-$lang['Captcha theme'] = 'Thème du captcha';
-$lang['Antibot test'] = 'Test anti-bots';
+$lang['Enter code'] = 'Entrez le code';
+$lang['Solve equation'] = 'Resolvez l\'équation';
+
 $lang['Comments action'] = 'Action pour les commentaires';
 $lang['Moderate'] = 'Modérer';
 $lang['No captcha'] = 'Pas de captcha';
+$lang['Captcha type'] = 'Type de captcha';
+$lang['Random string'] = 'Code aléatoire';
+$lang['Simple equation'] = 'Equation simple';
+$lang['Case sensitive'] = 'Sensibilité à la case';
+$lang['Code lenght'] = 'Longueur du code';
+$lang['good value:'] = 'conseillé:';
+$lang['Captcha theme'] = 'Thème du captcha';
+
+$lang['Perturbation'] = 'Perturbation';
+$lang['range:'] = 'plage:';
+$lang['Background color'] = 'Couleur de fond';
+$lang['Text color'] = 'Couleur du texte';
+$lang['Lines density'] = 'Nombre de lignes';
+$lang['Lines color'] = 'Couleur des lignes';
+$lang['Noise level'] = 'Quantité de bruit';
+$lang['Noise color'] = 'Couleur du bruit';
+$lang['Font'] = 'Police';
+$lang['Preview'] = 'Prévisualisation';
+$lang['Tip: type "random" on a color field to have a random color'] = 'Astuce: inscrivez "random" dans un champs de couleur pour avoir une couleur aléatoire';
 
 ?>
Index: /extensions/CryptograPHP/language/hu_HU/description.txt
===================================================================
--- /extensions/CryptograPHP/language/hu_HU/description.txt	(revision 12616)
+++ /extensions/CryptograPHP/language/hu_HU/description.txt	(revision 12617)
@@ -1,1 +1,1 @@
-CryptograPHP captcha hozzáadása a regisztrációs, komment és KapcsolatŰrlap oldalakhoz.
+Captcha hozzáadása a regisztrációs, komment és KapcsolatŰrlap oldalakhoz.
Index: /extensions/CryptograPHP/language/hu_HU/plugin.lang.php
===================================================================
--- /extensions/CryptograPHP/language/hu_HU/plugin.lang.php	(revision 12616)
+++ /extensions/CryptograPHP/language/hu_HU/plugin.lang.php	(revision 12617)
@@ -3,5 +3,4 @@
 $lang['Invalid Captcha'] = 'Érvénytelen Captcha';
 $lang['Captcha theme'] = 'Captcha téma';
-$lang['Antibot test'] = 'Antibot teszt';
 $lang['Comments action'] = 'Hozzászólás műveletek';
 $lang['Moderate'] = 'Moderálás';
Index: /extensions/CryptograPHP/language/it_IT/description.txt
===================================================================
--- /extensions/CryptograPHP/language/it_IT/description.txt	(revision 12616)
+++ /extensions/CryptograPHP/language/it_IT/description.txt	(revision 12617)
@@ -1,1 +1,1 @@
-Aggiunge un captcha CryptograPHP sulla pagina di iscrizione, sul modulo dei commenti e sulla pagina di ContactForm (grazie a P@t)
+Aggiunge un captcha sulla pagina di iscrizione, sul modulo dei commenti e sulla pagina di ContactForm (grazie a P@t)
Index: /extensions/CryptograPHP/language/it_IT/plugin.lang.php
===================================================================
--- /extensions/CryptograPHP/language/it_IT/plugin.lang.php	(revision 12616)
+++ /extensions/CryptograPHP/language/it_IT/plugin.lang.php	(revision 12617)
@@ -3,5 +3,4 @@
 $lang['Invalid Captcha'] = 'Captcha non valido';
 $lang['Captcha theme'] = 'Tema del captcha';
-$lang['Antibot test'] = 'Test Antibot';
 $lang['Comments action'] = 'Azione per i commenti';
 $lang['Moderate'] = 'Moderare';
Index: tensions/CryptograPHP/language/lv_LV/description.txt
===================================================================
--- /extensions/CryptograPHP/language/lv_LV/description.txt	(revision 12616)
+++ 	(revision )
@@ -1,1 +1,0 @@
-Pievieno CryptograPHP captcha reģistram un KontaktFormas lapām
Index: /extensions/CryptograPHP/language/pl_PL/index.php
===================================================================
--- /extensions/CryptograPHP/language/pl_PL/index.php	(revision 12617)
+++ /extensions/CryptograPHP/language/pl_PL/index.php	(revision 12617)
@@ -0,0 +1,30 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based picture gallery                                  |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2010 Piwigo Team                  http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/CryptograPHP/language/pl_PL/plugin.lang.php
===================================================================
--- /extensions/CryptograPHP/language/pl_PL/plugin.lang.php	(revision 12616)
+++ /extensions/CryptograPHP/language/pl_PL/plugin.lang.php	(revision 12617)
@@ -1,25 +1,4 @@
 <?php
-// +-----------------------------------------------------------------------+
-// | Piwigo - a PHP based photo gallery                                    |
-// +-----------------------------------------------------------------------+
-// | Copyright(C) 2008-2009 Piwigo Team                  http://piwigo.org |
-// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
-// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
-// +-----------------------------------------------------------------------+
-// | This program is free software; you can redistribute it and/or modify  |
-// | it under the terms of the GNU General Public License as published by  |
-// | the Free Software Foundation                                          |
-// |                                                                       |
-// | This program is distributed in the hope that it will be useful, but   |
-// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
-// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
-// | General Public License for more details.                              |
-// |                                                                       |
-// | You should have received a copy of the GNU General Public License     |
-// | along with this program; if not, write to the Free Software           |
-// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
-// | USA.                                                                  |
-// +-----------------------------------------------------------------------+
-$lang['Antibot test'] = 'Test antybotowy';
+
 $lang['Captcha theme'] = 'Wygląd captcha';
 $lang['Comments action'] = 'Akcja wykonywana dla komentarzy';
@@ -27,3 +6,4 @@
 $lang['Moderate'] = 'Średni';
 $lang['No captcha'] = 'Brak captcha';
+
 ?>
Index: /extensions/CryptograPHP/main.inc.php
===================================================================
--- /extensions/CryptograPHP/main.inc.php	(revision 12616)
+++ /extensions/CryptograPHP/main.inc.php	(revision 12617)
@@ -3,8 +3,17 @@
 Plugin Name: Crypto Captcha
 Version: auto
-Description: Add a CryptograPHP captcha to register, comment and ContactForm pages (thanks to P@t)
+Description: Add a captcha to register, comment and ContactForm pages (thanks to P@t)
 Plugin URI: http://piwigo.org/ext/extension_view.php?eid=535
 Author: Mistic
 Author URI: http://www.strangeplanet.fr
+*/
+
+## TODO : add customization of background image
+
+/*
+Author note :
+Le plugin était appellé à l'origine CryptograPHP et utilisait la librairie CryptograPHP
+Puis il a été renommé Crypto Captcha pour plus de clareté
+La version actuelle s'appelle toujours Crypto Captcha mais utilise la librairie Securimage
 */
 
@@ -17,5 +26,7 @@
 {
   global $conf, $pwg_loaded_plugins, $page;
-  $conf['cryptographp_theme'] = explode(',', $conf['cryptographp_theme']);
+  
+  $conf['cryptographp'] = unserialize($conf['cryptographp']);
+  load_language('plugin.lang', CRYPTO_PATH);
   
   if (script_basename() == 'register')
@@ -23,18 +34,19 @@
     include(CRYPTO_PATH.'include/register.inc.php');
   }
-  else if (script_basename() == 'picture' AND $conf['cryptographp_theme'][1] != 'inactive')
+  else if (script_basename() == 'picture' and $conf['cryptographp']['comments_action'] != 'inactive')
   {
     include(CRYPTO_PATH.'include/picture.inc.php');
-  }
-  else if (
-    script_basename() == 'index' AND $conf['cryptographp_theme'][1] != 'inactive' AND 
-    isset($pwg_loaded_plugins['Comments_on_Albums']) AND 
-    $page['section'] == 'categories' AND isset($page['category'])
-  ) {
-    include(CRYPTO_PATH.'include/category.inc.php');
   }
   else if (isset($_GET['/contact'])) 
   {
     include(CRYPTO_PATH.'include/contactform.inc.php');
+  }
+  else if (
+    script_basename() == 'index' and $conf['cryptographp']['comments_action'] != 'inactive' and 
+    isset($pwg_loaded_plugins['Comments_on_Albums']) and isset($page['section']) and 
+    $page['section'] == 'categories' and isset($page['category'])
+    ) 
+  {
+    include(CRYPTO_PATH.'include/category.inc.php');
   }
 }
@@ -46,13 +58,8 @@
   function crypto_plugin_admin_menu($menu)
   {
-    global $page,$conf;
-
-    array_push(
-      $menu,
-      array(
-        'NAME' => 'CryptograPHP',
-        'URL' => get_root_url().'admin.php?page=plugin-'.basename(dirname(__FILE__))
-        )
-      );
+    array_push($menu, array(
+      'NAME' => 'Crypto Captcha',
+      'URL' => get_root_url().'admin.php?page=plugin-'.basename(dirname(__FILE__))
+      ));
     return $menu;
   }
Index: /extensions/CryptograPHP/maintain.inc.php
===================================================================
--- /extensions/CryptograPHP/maintain.inc.php	(revision 12616)
+++ /extensions/CryptograPHP/maintain.inc.php	(revision 12617)
@@ -1,10 +1,28 @@
 <?php
+define('default_config', serialize(array(
+  'comments_action' => 'reject',
+  'theme'           => 'gray',
+  'captcha_type'    => 'string',
+  'case_sensitive'  => 'false',
+  'code_length'     => 6,
+  'width'           => 120, 
+  'height'          => 40,
+  'perturbation'    => 1, 
+  'image_bg_color'  => 'ffffff', 
+  'text_color'      => '8a8a8a', 
+  'num_lines'       => 2, 
+  'line_color'      => '8a8a8a', 
+  'noise_level'     => 0.1, 
+  'noise_color'     => '8a8a8a', 
+  'ttf_file'        => 'TopSecret',
+)));
+
 function plugin_install()
 {
   global $conf;
   
-  if (!isset($conf['cryptographp_theme']))
+  if (!isset($conf['cryptographp']))
   {
-    pwg_query('INSERT INTO '.CONFIG_TABLE.' (param,value,comment) VALUES ("cryptographp_theme","cryptographp,reject","CryptograPHP config");');
+    pwg_query('INSERT INTO '.CONFIG_TABLE.' (param,value,comment) VALUES ("cryptographp",\''.default_config.'\',"CryptograPHP config");');
   }
 }
@@ -13,14 +31,18 @@
 {
   global $conf;
-  $conf['cryptographp_theme'] = explode(',', $conf['cryptographp_theme']);
   
-  if(count($conf['cryptographp_theme']) == 1)
+  if (isset($conf['cryptograph_theme']))
   {
-    pwg_query('UPDATE '.CONFIG_TABLE.' SET value = "'.$conf['cryptographp_theme'][0].',reject" WHERE param = "cryptographp_theme";');
+    pwg_query('DELETE FROM '.CONFIG_TABLE.' WHERE param="cryptographp_theme" LIMIT 1');
+  }
+  
+  if (!isset($conf['cryptograph']))
+  {
+    pwg_query('INSERT INTO '.CONFIG_TABLE.' (param,value,comment) VALUES ("cryptographp",\''.default_config.'\',"CryptograPHP config");');
   }
 }
 function plugin_uninstall()
 {
-  pwg_query('DELETE FROM '.CONFIG_TABLE.' WHERE param="cryptographp_theme" LIMIT 1');
+  pwg_query('DELETE FROM '.CONFIG_TABLE.' WHERE param="cryptographp" LIMIT 1');
 }
 
Index: /extensions/CryptograPHP/securimage/LICENSE.txt
===================================================================
--- /extensions/CryptograPHP/securimage/LICENSE.txt	(revision 12617)
+++ /extensions/CryptograPHP/securimage/LICENSE.txt	(revision 12617)
@@ -0,0 +1,25 @@
+COPYRIGHT:
+    Copyright (c) 2011 Drew Phillips
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+
+    - Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    - Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+    POSSIBILITY OF SUCH DAMAGE.
+
Index: /extensions/CryptograPHP/securimage/README.txt
===================================================================
--- /extensions/CryptograPHP/securimage/README.txt	(revision 12617)
+++ /extensions/CryptograPHP/securimage/README.txt	(revision 12617)
@@ -0,0 +1,108 @@
+NAME:
+
+    Securimage - A PHP class for creating captcha images and audio with many options.
+
+VERSION: 3.0
+
+AUTHOR:
+
+    Drew Phillips <drew@drew-phillips.com>
+
+DOWNLOAD:
+
+    The latest version can always be
+    found at http://www.phpcaptcha.org
+
+DOCUMENTATION:
+
+    Online documentation of the class, methods, and variables can
+    be found at http://www.phpcaptcha.org/Securimage_Docs/
+
+REQUIREMENTS:
+    PHP 5.2 or greater
+    GD  2.0
+    FreeType (Required, for TTF fonts)
+
+SYNOPSIS:
+
+    require_once 'securimage.php';
+
+    $image = new Securimage();
+
+    $image->show();
+
+    // Code Validation
+
+    $image = new Securimage();
+    if ($image->check($_POST['code']) == true) {
+      echo "Correct!";
+    } else {
+      echo "Sorry, wrong code.";
+    }
+
+DESCRIPTION:
+
+    What is Securimage?
+
+    Securimage is a PHP class that is used to generate and validate CAPTCHA images.
+    The classes uses an existing PHP session or creates its own if none is found to store the
+    CAPTCHA code.  Variables within the class are used to control the style and display of the image.
+    The class supports TTF fonts and effects for strengthening the security of the image.
+    An audible code can also be streamed to the browser for visually impared users.
+
+
+COPYRIGHT:
+    Copyright (c) 2011 Drew Phillips
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+
+    - Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    - Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+    POSSIBILITY OF SUCH DAMAGE.
+
+    -----------------------------------------------------------------------------
+    Flash code created for Securimage by Mario Romero (animario@hotmail.com)
+    Many thanks for releasing this to the project!
+
+    ------------------------------------------------------------------------------
+    Portions of Securimage contain code from Han-Kwang Nienhuys' PHP captcha
+        
+    Han-Kwang Nienhuys' PHP captcha
+    Copyright June 2007
+    
+    This copyright message and attribution must be preserved upon
+    modification. Redistribution under other licenses is expressly allowed.
+    Other licenses include GPL 2 or higher, BSD, and non-free licenses.
+    The original, unrestricted version can be obtained from
+    http://www.lagom.nl/linux/hkcaptcha/
+    
+    -------------------------------------------------------------------------------
+    AHGBold.ttf (AlteHaasGroteskBold.ttf) font was created by Yann Le Coroller and is distributed as freeware
+    
+    Alte Haas Grotesk is a typeface that look like an helvetica printed in an old Muller-Brockmann Book.
+    
+    These fonts are freeware and can be distributed as long as they are
+    together with this text file. 
+    
+    I would appreciate very much to see what you have done with it anyway.
+    
+    yann le coroller 
+    www.yannlecoroller.com
+    yann@lecoroller.com
+
Index: /extensions/CryptograPHP/securimage/index.php
===================================================================
--- /extensions/CryptograPHP/securimage/index.php	(revision 12617)
+++ /extensions/CryptograPHP/securimage/index.php	(revision 12617)
@@ -0,0 +1,30 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery                                    |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2011 Piwigo Team                  http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/CryptograPHP/securimage/securimage.php
===================================================================
--- /extensions/CryptograPHP/securimage/securimage.php	(revision 12617)
+++ /extensions/CryptograPHP/securimage/securimage.php	(revision 12617)
@@ -0,0 +1,1437 @@
+<?php
+/**
+ * Project:     Securimage: A PHP class for creating and managing form CAPTCHA images
+ * File:        securimage.php
+ *
+ * Copyright (c) 2011, Drew Phillips
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 
+ *  - Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Any modifications to the library should be indicated clearly in the source code
+ * to inform users that the changes are not a part of the original software.
+ *
+ * If you found this script useful, please take a quick moment to rate it.
+ * http://www.hotscripts.com/rate/49400.html  Thanks.
+ *
+ * @link http://www.phpcaptcha.org Securimage PHP CAPTCHA
+ * @link http://www.phpcaptcha.org/latest.zip Download Latest Version
+ * @link http://www.phpcaptcha.org/Securimage_Docs/ Online Documentation
+ * @copyright 2011 Drew Phillips
+ * @author Drew Phillips <drew@drew-phillips.com>
+ * @version 3.0 (October 2011)
+ * @package Securimage
+ *
+ */
+
+/**
+ ChangeLog
+ 
+ 3.0
+ - Rewrite class using PHP5 OOP
+ - Remove support for GD fonts, require FreeType
+ - Remove support for multi-color codes
+ - Add option to make codes case-sensitive
+ - Add namespaces to support multiple captchas on a single page or page specific captchas
+ - Add option to show simple math problems instead of codes
+ - Remove support for mp3 files due to vulnerability in decoding mp3 audio files
+ - Create new flash file to stream wav files instead of mp3
+ - Changed to BSD license
+
+ 2.0.2
+ - Fix pathing to make integration into libraries easier (Nathan Phillip Brink ohnobinki@ohnopublishing.net)
+
+ 2.0.1
+ - Add support for browsers with cookies disabled (requires php5, sqlite) maps users to md5 hashed ip addresses and md5 hashed codes for security
+ - Add fallback to gd fonts if ttf support is not enabled or font file not found (Mike Challis http://www.642weather.com/weather/scripts.php)
+ - Check for previous definition of image type constants (Mike Challis)
+ - Fix mime type settings for audio output
+ - Fixed color allocation issues with multiple colors and background images, consolidate allocation to one function
+ - Ability to let codes expire after a given length of time
+ - Allow HTML color codes to be passed to Securimage_Color (suggested by Mike Challis)
+
+ 2.0.0
+ - Add mathematical distortion to characters (using code from HKCaptcha)
+ - Improved session support
+ - Added Securimage_Color class for easier color definitions
+ - Add distortion to audio output to prevent binary comparison attack (proposed by Sven "SavageTiger" Hagemann [insecurity.nl])
+ - Flash button to stream mp3 audio (Douglas Walsh www.douglaswalsh.net)
+ - Audio output is mp3 format by default
+ - Change font to AlteHaasGrotesk by yann le coroller
+ - Some code cleanup 
+
+ 1.0.4 (unreleased)
+ - Ability to output audible codes in mp3 format to stream from flash
+
+ 1.0.3.1
+ - Error reading from wordlist in some cases caused words to be cut off 1 letter short
+
+ 1.0.3
+ - Removed shadow_text from code which could cause an undefined property error due to removal from previous version
+
+ 1.0.2
+ - Audible CAPTCHA Code wav files
+ - Create codes from a word list instead of random strings
+
+ 1.0
+ - Added the ability to use a selected character set, rather than a-z0-9 only.
+ - Added the multi-color text option to use different colors for each letter.
+ - Switched to automatic session handling instead of using files for code storage
+ - Added GD Font support if ttf support is not available.  Can use internal GD fonts or load new ones.
+ - Added the ability to set line thickness
+ - Added option for drawing arced lines over letters
+ - Added ability to choose image type for output
+
+ */
+
+
+/**
+ * Securimage CAPTCHA Class.
+ *
+ * @version    3.0
+ * @package    Securimage
+ * @subpackage classes
+ * @author     Drew Phillips <drew@drew-phillips.com>
+ *
+ */
+class Securimage
+{
+	// All of the public variables below are securimage options
+	// They can be passed as an array to the Securimage constructor, set below,
+	// or set from securimage_show.php and securimage_play.php
+	
+    /**
+     * Renders captcha as a JPEG image
+     * @var int
+     */
+    const SI_IMAGE_JPEG = 1;
+    /**
+     * Renders captcha as a PNG image (default)
+     * @var int
+     */
+    const SI_IMAGE_PNG  = 2;
+    /**
+     * Renders captcha as a GIF image
+     * @var int
+     */
+    const SI_IMAGE_GIF  = 3;
+    
+    /**
+     * Create a normal alphanumeric captcha
+     * @var int
+     */
+    const SI_CAPTCHA_STRING     = 0;
+    /**
+     * Create a captcha consisting of a simple math problem
+     * @var int
+     */
+    const SI_CAPTCHA_MATHEMATIC = 1;
+    
+    /**
+     * The width of the captcha image
+     * @var int
+     */
+    public $image_width = 215;
+    /**
+     * The height of the captcha image
+     * @var int
+     */
+    public $image_height = 80;
+    /**
+     * The type of the image, default = png
+     * @var int
+     */
+    public $image_type   = self::SI_IMAGE_PNG;
+
+    /**
+     * The background color of the captcha
+     * @var Securimage_Color
+     */
+    public $image_bg_color = '#ffffff';
+    /**
+     * The color of the captcha text
+     * @var Securimage_Color
+     */
+    public $text_color     = '#707070';
+    /**
+     * The color of the lines over the captcha
+     * @var Securimage_Color
+     */
+    public $line_color     = '#707070';
+    /**
+     * The color of the noise that is drawn
+     * @var Securimage_Color 
+     */
+    public $noise_color    = '#707070';
+    
+    /**
+     * How transparent to make the text 0 = completely opaque, 100 = invisible
+     * @var int
+     */
+    public $text_transparency_percentage = 50;
+    /**
+     * Whether or not to draw the text transparently, true = use transparency, false = no transparency
+     * @var bool
+     */
+    public $use_transparent_text         = false;
+    
+    /**
+     * The length of the captcha code
+     * @var int
+     */
+    public $code_length    = 6;
+    /**
+     * Whether the captcha should be case sensitive (not recommended, use only for maximum protection)
+     * @var bool
+     */
+    public $case_sensitive = false;
+    /**
+     * The character set to use for generating the captcha code
+     * @var string
+     */
+    public $charset        = 'ABCDEFGHKLMNPRSTUVWYZabcdefghklmnprstuvwyz23456789';
+    /**
+     * How long in seconds a captcha remains valid, after this time it will not be accepted
+     * @var unknown_type
+     */
+    public $expiry_time    = 900;
+    
+    /**
+     * The session name securimage should use, only set this if your application uses a custom session name
+     * It is recommended to set this value below so it is used by all securimage scripts
+     * @var string
+     */
+    public $session_name   = null;
+    
+    /**
+     * true to use the wordlist file, false to generate random captcha codes
+     * @var bool
+     */
+    public $use_wordlist   = false;
+
+    /**
+     * The level of distortion, 0.75 = normal, 1.0 = very high distortion
+     * @var double
+     */
+    public $perturbation = 0.75;
+    /**
+     * How many lines to draw over the captcha code to increase security
+     * @var int
+     */
+    public $num_lines    = 8;
+    /**
+     * The level of noise (random dots) to place on the image, 0-10
+     * @var int
+     */
+    public $noise_level  = 0;
+    
+    /**
+     * The signature text to draw on the bottom corner of the image
+     * @var string
+     */
+    public $image_signature = '';
+    /**
+     * The color of the signature text
+     * @var Securimage_Color
+     */
+    public $signature_color = '#707070';
+    /**
+     * The path to the ttf font file to use for the signature text, defaults to $ttf_file (AHGBold.ttf)
+     * @var string
+     */
+    public $signature_font;
+    
+    /**
+     * Use an SQLite database to store data (for users that do not support cookies)
+     * @var bool
+     */
+    public $use_sqlite_db = false;
+    
+    /**
+     * The type of captcha to create, either alphanumeric, or a math problem<br />
+     * Securimage::SI_CAPTCHA_STRING or Securimage::SI_CAPTCHA_MATHEMATIC
+     * @var int
+     */
+    public $captcha_type  = self::SI_CAPTCHA_STRING;
+    
+    /**
+     * The captcha namespace, use this if you have multiple forms on a single page, blank if you do not use multiple forms on one page
+     * @var string
+     * <code>
+     * <?php
+     * // in securimage_show.php (create one show script for each form)
+     * $img->namespace = 'contact_form';
+     * 
+     * // in form validator
+     * $img->namespace = 'contact_form';
+     * if ($img->check($code) == true) {
+     *     echo "Valid!";
+     *  }
+     * </code>
+     */
+    public $namespace;
+    
+    /**
+     * The font file to use to draw the captcha code, leave blank for default font AHGBold.ttf
+     * @var string
+     */
+    public $ttf_file;
+    /**
+     * The path to the wordlist file to use, leave blank for default words/words.txt
+     * @var string
+     */
+    public $wordlist_file;
+    /**
+     * The directory to scan for background images, if set a random background will be chosen from this folder
+     * @var string
+     */
+    public $background_directory;
+    /**
+     * The path to the SQLite database file to use, if $use_sqlite_database = true, should be chmod 666
+     * @var string
+     */
+    public $sqlite_database;
+    /**
+     * The path to the securimage audio directory, can be set in securimage_play.php
+     * @var string
+     * <code>
+     * $img->audio_path = '/home/yoursite/public_html/securimage/audio/';
+     * </code>
+     */
+    public $audio_path;
+
+    
+    
+    protected $im;
+    protected $tmpimg;
+    protected $bgimg;
+    protected $iscale = 5;
+    
+    protected $securimage_path = null;
+    
+    protected $code;
+    protected $code_display;
+    
+    protected $captcha_code;
+    protected $sqlite_handle;
+    
+    protected $gdbgcolor;
+    protected $gdtextcolor;
+    protected $gdlinecolor;
+    protected $gdsignaturecolor;
+    
+    /**
+     * Create a new securimage object, pass options to set in the constructor.<br />
+     * This can be used to display a captcha, play an audible captcha, or validate an entry
+     * @param array $options
+     * <code>
+     * $options = array(
+     *     'text_color' => new Securimage_Color('#013020'),
+     *     'code_length' => 5,
+     *     'num_lines' => 5,
+     *     'noise_level' => 3,
+     *     'font_file' => Securimage::getPath() . '/custom.ttf'
+     * );
+     * 
+     * $img = new Securimage($options);
+     * </code>
+     */
+    public function __construct($options = array())
+    {
+        $this->securimage_path = dirname(__FILE__);
+        
+        if (is_array($options) && sizeof($options) > 0) {
+            foreach($options as $prop => $val) {
+                $this->$prop = $val;
+            }
+        }
+
+        $this->image_bg_color  = $this->initColor($this->image_bg_color,  '#ffffff');
+        $this->text_color      = $this->initColor($this->text_color,      '#616161');
+        $this->line_color      = $this->initColor($this->line_color,      '#616161');
+        $this->noise_color     = $this->initColor($this->noise_color,     '#616161');
+        $this->signature_color = $this->initColor($this->signature_color, '#616161');
+
+        if ($this->ttf_file == null) {
+            $this->ttf_file = $this->securimage_path . '/AHGBold.ttf';
+        }
+        
+        $this->signature_font = $this->ttf_file;
+        
+        if ($this->wordlist_file == null) {
+            $this->wordlist_file = $this->securimage_path . '/words/words.txt';
+        }
+        
+        if ($this->sqlite_database == null) {
+            $this->sqlite_database = $this->securimage_path . '/database/securimage.sqlite';
+        }
+        
+        if ($this->audio_path == null) {
+            $this->audio_path = $this->securimage_path . '/audio/';
+        }
+        
+        if ($this->code_length == null || $this->code_length < 1) {
+            $this->code_length = 6;
+        }
+        
+        if ($this->perturbation == null || !is_numeric($this->perturbation)) {
+            $this->perturbation = 0.75;
+        }
+        
+        if ($this->namespace == null || !is_string($this->namespace)) {
+            $this->namespace = 'default';
+        }
+
+        // Initialize session or attach to existing
+        if ( session_id() == '' ) { // no session has been started yet, which is needed for validation
+            if ($this->session_name != null && trim($this->session_name) != '') {
+                session_name(trim($this->session_name)); // set session name if provided
+            }
+            session_start();
+        }
+    }
+    
+    /**
+     * Return the absolute path to the Securimage directory
+     * @return string The path to the securimage base directory
+     */
+    public static function getPath()
+    {
+        return dirname(__FILE__);
+    }
+    
+    /**
+     * Used to serve a captcha image to the browser
+     * @param string $background_image The path to the background image to use
+     * <code> 
+     * $img = new Securimage();
+     * $img->code_length = 6;
+     * $img->num_lines   = 5;
+     * $img->noise_level = 5;
+     * 
+     * $img->show(); // sends the image to browser
+     * exit;
+     * </code>
+     */
+    public function show($background_image = '')
+    {
+        if($background_image != '' && is_readable($background_image)) {
+            $this->bgimg = $background_image;
+        }
+
+        $this->doImage();
+    }
+    
+    /**
+     * Check a submitted code against the stored value
+     * @param string $code  The captcha code to check
+     * <code>
+     * $code = $_POST['code'];
+     * $img  = new Securimage();
+     * if ($img->check($code) == true) {
+     *     $captcha_valid = true;
+     * } else {
+     *     $captcha_valid = false;
+     * }
+     * </code>
+     */
+    public function check($code)
+    {
+        $this->code_entered = $code;
+        $this->validate();
+        return $this->correct_code;
+    }
+    
+    /**
+     * Output a wav file of the captcha code to the browser
+     * 
+     * <code>
+     * $img = new Securimage();
+     * $img->outputAudioFile(); // outputs a wav file to the browser
+     * exit;
+     * </code>
+     */
+    public function outputAudioFile()
+    {
+        $ext = 'wav'; // force wav - mp3 is insecure
+        
+        header("Content-Disposition: attachment; filename=\"securimage_audio.{$ext}\"");
+        header('Cache-Control: no-store, no-cache, must-revalidate');
+        header('Expires: Sun, 1 Jan 2000 12:00:00 GMT');
+        header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT');
+        header('Content-type: audio/x-wav');
+        
+        $audio = $this->getAudibleCode($ext);
+
+        header('Content-Length: ' . strlen($audio));
+
+        echo $audio;
+        exit;
+    }
+    
+    /**
+     * The main image drawing routing, responsible for constructing the entire image and serving it
+     */
+    protected function doImage()
+    {
+        if( ($this->use_transparent_text == true || $this->bgimg != '') && function_exists('imagecreatetruecolor')) {
+            $imagecreate = 'imagecreatetruecolor';
+        } else {
+            $imagecreate = 'imagecreate';
+        }
+        
+        $this->im     = $imagecreate($this->image_width, $this->image_height);
+        $this->tmpimg = $imagecreate($this->image_width * $this->iscale, $this->image_height * $this->iscale);
+        
+        $this->allocateColors();
+        imagepalettecopy($this->tmpimg, $this->im);
+
+        $this->setBackground();
+
+        $this->createCode();
+        
+        $this->drawWord();
+
+        if ($this->noise_level > 0) {
+            $this->drawNoise();
+        }
+        
+        if ($this->perturbation > 0 && is_readable($this->ttf_file)) {
+            $this->distortedCopy();
+        }
+
+        if ($this->num_lines > 0) {
+            $this->drawLines();
+        }
+
+        if (trim($this->image_signature) != '') {
+            $this->addSignature();
+        }
+
+        $this->output();
+    }
+    
+    /**
+     * Allocate the colors to be used for the image
+     */
+    protected function allocateColors()
+    {
+        // allocate bg color first for imagecreate
+        $this->gdbgcolor = imagecolorallocate($this->im,
+                                              $this->image_bg_color->r,
+                                              $this->image_bg_color->g,
+                                              $this->image_bg_color->b);
+        
+        $alpha = intval($this->text_transparency_percentage / 100 * 127);
+        
+        if ($this->use_transparent_text == true) {
+            $this->gdtextcolor = imagecolorallocatealpha($this->im,
+                                                         $this->text_color->r,
+                                                         $this->text_color->g,
+                                                         $this->text_color->b,
+                                                         $alpha);
+            $this->gdlinecolor = imagecolorallocatealpha($this->im,
+                                                         $this->line_color->r,
+                                                         $this->line_color->g,
+                                                         $this->line_color->b,
+                                                         $alpha);
+            $this->gdnoisecolor = imagecolorallocatealpha($this->im,
+                                                          $this->noise_color->r,
+                                                          $this->noise_color->g,
+                                                          $this->noise_color->b,
+                                                          $alpha);
+        } else {
+            $this->gdtextcolor = imagecolorallocate($this->im,
+                                                    $this->text_color->r,
+                                                    $this->text_color->g,
+                                                    $this->text_color->b);
+            $this->gdlinecolor = imagecolorallocate($this->im,
+                                                    $this->line_color->r,
+                                                    $this->line_color->g,
+                                                    $this->line_color->b);
+            $this->gdnoisecolor = imagecolorallocate($this->im,
+                                                          $this->noise_color->r,
+                                                          $this->noise_color->g,
+                                                          $this->noise_color->b);
+        }
+    
+        $this->gdsignaturecolor = imagecolorallocate($this->im,
+                                                     $this->signature_color->r,
+                                                     $this->signature_color->g,
+                                                     $this->signature_color->b);
+
+    }
+    
+    /**
+     * The the background color, or background image to be used
+     */
+    protected function setBackground()
+    {
+        // set background color of image by drawing a rectangle since imagecreatetruecolor doesn't set a bg color
+        imagefilledrectangle($this->im, 0, 0,
+                             $this->image_width, $this->image_height,
+                             $this->gdbgcolor);
+        imagefilledrectangle($this->tmpimg, 0, 0,
+                             $this->image_width * $this->iscale, $this->image_height * $this->iscale,
+                             $this->gdbgcolor);
+    
+        if ($this->bgimg == '') {
+            if ($this->background_directory != null && 
+                is_dir($this->background_directory) &&
+                is_readable($this->background_directory))
+            {
+                $img = $this->getBackgroundFromDirectory();
+                if ($img != false) {
+                    $this->bgimg = $img;
+                }
+            }
+        }
+        
+        if ($this->bgimg == '') {
+            return;
+        }
+
+        $dat = @getimagesize($this->bgimg);
+        if($dat == false) { 
+            return;
+        }
+
+        switch($dat[2]) {
+            case 1:  $newim = @imagecreatefromgif($this->bgimg); break;
+            case 2:  $newim = @imagecreatefromjpeg($this->bgimg); break;
+            case 3:  $newim = @imagecreatefrompng($this->bgimg); break;
+            default: return;
+        }
+
+        if(!$newim) return;
+
+        imagecopyresized($this->im, $newim, 0, 0, 0, 0,
+                         $this->image_width, $this->image_height,
+                         imagesx($newim), imagesy($newim));
+    }
+    
+    /**
+     * Scan the directory for a background image to use
+     */
+    protected function getBackgroundFromDirectory()
+    {
+        $images = array();
+
+        if ( ($dh = opendir($this->background_directory)) !== false) {
+            while (($file = readdir($dh)) !== false) {
+                if (preg_match('/(jpg|gif|png)$/i', $file)) $images[] = $file;
+            }
+
+            closedir($dh);
+
+            if (sizeof($images) > 0) {
+                return rtrim($this->background_directory, '/') . '/' . $images[rand(0, sizeof($images)-1)];
+            }
+        }
+
+        return false;
+    }
+    
+    /**
+     * Generates the code or math problem and saves the value to the session
+     */
+    protected function createCode()
+    {
+        $this->code = false;
+
+        switch($this->captcha_type) {
+            case self::SI_CAPTCHA_MATHEMATIC:
+            {
+                $signs = array('+', '-', 'x');
+                $left  = rand(1, 10);
+                $right = rand(1, 5);
+                $sign  = $signs[rand(0, 2)];
+                
+                switch($sign) {
+                    case 'x': $c = $left * $right; break;
+                    case '-': $c = $left - $right; break;
+                    default:  $c = $left + $right; break;
+                }
+                
+                $this->code         = $c;
+                $this->code_display = "$left $sign $right";
+                break;
+            }
+            
+            default:
+            {
+                if ($this->use_wordlist && is_readable($this->wordlist_file)) {
+                    $this->code = $this->readCodeFromFile();
+                }
+
+                if ($this->code == false) {
+                    $this->code = $this->generateCode($this->code_length);
+                }
+                
+                $this->code_display = $this->code;
+                $this->code         = ($this->case_sensitive) ? $this->code : strtolower($this->code);
+            } // default
+        }
+        
+        $this->saveData();
+    }
+    
+    /**
+     * Draws the captcha code on the image
+     */
+    protected function drawWord()
+    {
+        $width2  = $this->image_width * $this->iscale;
+        $height2 = $this->image_height * $this->iscale;
+         
+        if (!is_readable($this->ttf_file)) {
+            imagestring($this->im, 4, 10, ($this->image_height / 2) - 5, 'Failed to load TTF font file!', $this->gdtextcolor);
+        } else {
+            if ($this->perturbation > 0) {
+                $font_size = $height2 * .4;
+                $bb = imageftbbox($font_size, 0, $this->ttf_file, $this->code_display);
+                $tx = $bb[4] - $bb[0];
+                $ty = $bb[5] - $bb[1];
+                $x  = floor($width2 / 2 - $tx / 2 - $bb[0]);
+                $y  = round($height2 / 2 - $ty / 2 - $bb[1]);
+
+                imagettftext($this->tmpimg, $font_size, 0, $x, $y, $this->gdtextcolor, $this->ttf_file, $this->code_display);
+            } else {
+                $font_size = $this->image_height * .4;
+                $bb = imageftbbox($font_size, 0, $this->ttf_file, $this->code_display);
+                $tx = $bb[4] - $bb[0];
+                $ty = $bb[5] - $bb[1];
+                $x  = floor($this->image_width / 2 - $tx / 2 - $bb[0]);
+                $y  = round($this->image_height / 2 - $ty / 2 - $bb[1]);
+
+                imagettftext($this->im, $font_size, 0, $x, $y, $this->gdtextcolor, $this->ttf_file, $this->code_display);
+            }
+        }
+        
+        // DEBUG
+        //$this->im = $this->tmpimg;
+        //$this->output();
+        
+    }
+    
+    /**
+     * Copies the captcha image to the final image with distortion applied
+     */
+    protected function distortedCopy()
+    {
+        $numpoles = 3; // distortion factor
+        // make array of poles AKA attractor points
+        for ($i = 0; $i < $numpoles; ++ $i) {
+            $px[$i]  = rand($this->image_width  * 0.2, $this->image_width  * 0.8);
+            $py[$i]  = rand($this->image_height * 0.2, $this->image_height * 0.8);
+            $rad[$i] = rand($this->image_height * 0.2, $this->image_height * 0.8);
+            $tmp     = ((- $this->frand()) * 0.15) - .15;
+            $amp[$i] = $this->perturbation * $tmp;
+        }
+        
+        $bgCol = imagecolorat($this->tmpimg, 0, 0);
+        $width2 = $this->iscale * $this->image_width;
+        $height2 = $this->iscale * $this->image_height;
+        imagepalettecopy($this->im, $this->tmpimg); // copy palette to final image so text colors come across
+        // loop over $img pixels, take pixels from $tmpimg with distortion field
+        for ($ix = 0; $ix < $this->image_width; ++ $ix) {
+            for ($iy = 0; $iy < $this->image_height; ++ $iy) {
+                $x = $ix;
+                $y = $iy;
+                for ($i = 0; $i < $numpoles; ++ $i) {
+                    $dx = $ix - $px[$i];
+                    $dy = $iy - $py[$i];
+                    if ($dx == 0 && $dy == 0) {
+                        continue;
+                    }
+                    $r = sqrt($dx * $dx + $dy * $dy);
+                    if ($r > $rad[$i]) {
+                        continue;
+                    }
+                    $rscale = $amp[$i] * sin(3.14 * $r / $rad[$i]);
+                    $x += $dx * $rscale;
+                    $y += $dy * $rscale;
+                }
+                $c = $bgCol;
+                $x *= $this->iscale;
+                $y *= $this->iscale;
+                if ($x >= 0 && $x < $width2 && $y >= 0 && $y < $height2) {
+                    $c = imagecolorat($this->tmpimg, $x, $y);
+                }
+                if ($c != $bgCol) { // only copy pixels of letters to preserve any background image
+                    imagesetpixel($this->im, $ix, $iy, $c);
+                }
+            }
+        }
+    }
+    
+    /**
+     * Draws distorted lines on the image
+     */
+    protected function drawLines()
+    {
+        for ($line = 0; $line < $this->num_lines; ++ $line) {
+            $x = $this->image_width * (1 + $line) / ($this->num_lines + 1);
+            $x += (0.5 - $this->frand()) * $this->image_width / $this->num_lines;
+            $y = rand($this->image_height * 0.1, $this->image_height * 0.9);
+            
+            $theta = ($this->frand() - 0.5) * M_PI * 0.7;
+            $w = $this->image_width;
+            $len = rand($w * 0.4, $w * 0.7);
+            $lwid = rand(0, 2);
+            
+            $k = $this->frand() * 0.6 + 0.2;
+            $k = $k * $k * 0.5;
+            $phi = $this->frand() * 6.28;
+            $step = 0.5;
+            $dx = $step * cos($theta);
+            $dy = $step * sin($theta);
+            $n = $len / $step;
+            $amp = 1.5 * $this->frand() / ($k + 5.0 / $len);
+            $x0 = $x - 0.5 * $len * cos($theta);
+            $y0 = $y - 0.5 * $len * sin($theta);
+            
+            $ldx = round(- $dy * $lwid);
+            $ldy = round($dx * $lwid);
+            
+            for ($i = 0; $i < $n; ++ $i) {
+                $x = $x0 + $i * $dx + $amp * $dy * sin($k * $i * $step + $phi);
+                $y = $y0 + $i * $dy - $amp * $dx * sin($k * $i * $step + $phi);
+                imagefilledrectangle($this->im, $x, $y, $x + $lwid, $y + $lwid, $this->gdlinecolor);
+            }
+        }
+    }
+    
+    /**
+     * Draws random noise on the image
+     */
+    protected function drawNoise()
+    {
+        if ($this->noise_level > 10) {
+            $noise_level = 10;
+        } else {
+            $noise_level = $this->noise_level;
+        }
+
+        $t0 = microtime(true);
+        
+        $noise_level *= 125; // an arbitrary number that works well on a 1-10 scale
+        
+        $points = $this->image_width * $this->image_height * $this->iscale;
+        $height = $this->image_height * $this->iscale;
+        $width  = $this->image_width * $this->iscale;
+        for ($i = 0; $i < $noise_level; ++$i) {
+            $x = rand(10, $width);
+            $y = rand(10, $height);
+            $size = rand(7, 10);
+            if ($x - $size <= 0 && $y - $size <= 0) continue; // dont cover 0,0 since it is used by imagedistortedcopy
+            imagefilledarc($this->tmpimg, $x, $y, $size, $size, 0, 360, $this->gdnoisecolor, IMG_ARC_PIE);
+        }
+        
+        $t1 = microtime(true);
+        
+        $t = $t1 - $t0;
+        
+        /*
+        // DEBUG
+        imagestring($this->tmpimg, 5, 25, 30, "$t", $this->gdnoisecolor);
+        header('content-type: image/png');
+        imagepng($this->tmpimg);
+        exit;
+        */
+    }
+    
+	/**
+	* Print signature text on image
+	*/
+    protected function addSignature()
+    {
+        if ($this->use_gd_font) {
+            imagestring($this->im, 5, $this->image_width - (strlen($this->image_signature) * 10), $this->image_height - 20, $this->image_signature, $this->gdsignaturecolor);
+        } else {
+             
+            $bbox = imagettfbbox(10, 0, $this->signature_font, $this->image_signature);
+            $textlen = $bbox[2] - $bbox[0];
+            $x = $this->image_width - $textlen - 5;
+            $y = $this->image_height - 3;
+             
+            imagettftext($this->im, 10, 0, $x, $y, $this->gdsignaturecolor, $this->signature_font, $this->image_signature);
+        }
+    }
+    
+    /**
+     * Sends the appropriate image and cache headers and outputs image to the browser
+     */
+    protected function output()
+    {
+        header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
+        header("Last-Modified: " . gmdate("D, d M Y H:i:s") . "GMT");
+        header("Cache-Control: no-store, no-cache, must-revalidate");
+        header("Cache-Control: post-check=0, pre-check=0", false);
+        header("Pragma: no-cache");
+        
+        switch ($this->image_type) {
+            case self::SI_IMAGE_JPEG:
+                header("Content-Type: image/jpeg");
+                imagejpeg($this->im, null, 90);
+                break;
+            case self::SI_IMAGE_GIF:
+                header("Content-Type: image/gif");
+                imagegif($this->im);
+                break;
+            default:
+                header("Content-Type: image/png");
+                imagepng($this->im);
+                break;
+        }
+        
+        imagedestroy($this->im);
+        exit();
+    }
+    
+    /**
+     * Gets the code and returns the binary audio file for the stored captcha code
+     * @param string $format WAV only
+     */
+    protected function getAudibleCode($format = 'wav')
+    {
+        // override any format other than wav for now
+        // this is due to security issues with MP3 files
+        $format  = 'wav';
+        
+        $letters = array();
+        $code    = $this->getCode();
+
+        if ($code == '') {
+            $this->createCode();
+            $code = $this->getCode();
+        }
+
+        for($i = 0; $i < strlen($code); ++$i) {
+            $letters[] = $code{$i};
+        }
+        
+        if ($format == 'mp3') {
+            return $this->generateMP3($letters);
+        } else {
+            return $this->generateWAV($letters);
+        }
+    }
+
+    /**
+     * Gets a captcha code from a wordlist
+     */
+    protected function readCodeFromFile()
+    {
+        $fp = @fopen($this->wordlist_file, 'rb');
+        if (!$fp) return false;
+
+        $fsize = filesize($this->wordlist_file);
+        if ($fsize < 128) return false; // too small of a list to be effective
+
+        fseek($fp, rand(0, $fsize - 64), SEEK_SET); // seek to a random position of file from 0 to filesize-64
+        $data = fread($fp, 64); // read a chunk from our random position
+        fclose($fp);
+        $data = preg_replace("/\r?\n/", "\n", $data);
+
+        $start = @strpos($data, "\n", rand(0, 56)) + 1; // random start position
+        $end   = @strpos($data, "\n", $start);          // find end of word
+        
+        if ($start === false) {
+            return false;
+        } else if ($end === false) {
+            $end = strlen($data);
+        }
+
+        return strtolower(substr($data, $start, $end - $start)); // return a line of the file
+    }
+    
+    /**
+     * Generates a random captcha code from the set character set
+     */
+    protected function generateCode()
+    {
+        $code = '';
+
+        for($i = 1, $cslen = strlen($this->charset); $i <= $this->code_length; ++$i) {
+            $code .= $this->charset{rand(0, $cslen - 1)};
+        }
+        
+        //return 'testing';  // debug, set the code to given string
+        
+        return $code;
+    }
+    
+    /**
+     * Checks the entered code against the value stored in the session or sqlite database, handles case sensitivity
+     * Also clears the stored codes if the code was entered correctly to prevent re-use
+     */
+    protected function validate()
+    {
+        $code = $this->getCode();
+        // returns stored code, or an empty string if no stored code was found
+        // checks the session and sqlite database if enabled
+        
+        if ($this->case_sensitive == false && preg_match('/[A-Z]/', $code)) {
+            // case sensitive was set from securimage_show.php but not in class
+            // the code saved in the session has capitals so set case sensitive to true
+            $this->case_sensitive = true;
+        }
+        
+        $code_entered = trim( (($this->case_sensitive) ? $this->code_entered
+                                                       : strtolower($this->code_entered))
+                        );
+        $this->correct_code = false;
+        
+        if ($code != '') {
+            if ($code == $code_entered) {
+                $this->correct_code = true;
+                $_SESSION['securimage_code_value'][$this->namespace] = '';
+                $_SESSION['securimage_code_ctime'][$this->namespace] = '';
+                $this->clearCodeFromDatabase();
+            }
+        }
+    }
+    
+    /**
+     * Return the code from the session or sqlite database if used.  If none exists yet, an empty string is returned
+     */
+    protected function getCode()
+    {
+        $code = '';
+        
+        if (isset($_SESSION['securimage_code_value'][$this->namespace]) &&
+         trim($_SESSION['securimage_code_value'][$this->namespace]) != '') {
+            if ($this->isCodeExpired(
+            $_SESSION['securimage_code_ctime'][$this->namespace]) == false) {
+                $code = $_SESSION['securimage_code_value'][$this->namespace];
+            }
+        } else if ($this->use_sqlite_db == true && function_exists('sqlite_open')) {
+            // no code in session - may mean user has cookies turned off
+            $this->openDatabase();
+            $code = $this->getCodeFromDatabase();
+        } else { /* no code stored in session or sqlite database, validation will fail */ }
+        
+        return $code;
+    }
+    
+    /**
+     * Save data to session namespace and database if used
+     */
+    protected function saveData()
+    {
+        $_SESSION['securimage_code_value'][$this->namespace] = $this->code;
+        $_SESSION['securimage_code_ctime'][$this->namespace] = time();
+        
+        $this->saveCodeToDatabase();
+    }
+    
+    /**
+     * Saves the code to the sqlite database
+     */
+    protected function saveCodeToDatabase()
+    {
+        $success = false;
+        
+        $this->openDatabase();
+        
+        if ($this->use_sqlite_db && $this->sqlite_handle !== false) {
+            $ip      = $_SERVER['REMOTE_ADDR'];
+            $time    = time();
+            $code    = $_SESSION['securimage_code_value'][$this->namespace]; // if cookies are disabled the session still exists at this point
+            $success = sqlite_query($this->sqlite_handle,
+                                    "INSERT OR REPLACE INTO codes(ip, code, namespace, created)
+                                    VALUES('$ip', '$code', '{$this->namespace}', $time)");
+        }
+        
+        return $success !== false;
+    }
+    
+    /**
+     * Open sqlite database
+     */
+    protected function openDatabase()
+    {
+        $this->sqlite_handle = false;
+        
+        if ($this->use_sqlite_db && function_exists('sqlite_open')) {
+            $this->sqlite_handle = sqlite_open($this->sqlite_database, 0666, $error);
+            
+            if ($this->sqlite_handle !== false) {
+                $res = sqlite_query($this->sqlite_handle, "PRAGMA table_info(codes)");
+                if (sqlite_num_rows($res) == 0) {
+                    sqlite_query($this->sqlite_handle, "CREATE TABLE codes (ip VARCHAR(32) PRIMARY KEY, code VARCHAR(32) NOT NULL, namespace VARCHAR(32) NOT NULL, created INTEGER)");
+                }
+            }
+            
+            return $this->sqlite_handle != false;
+        }
+        
+        return $this->sqlite_handle;
+    }
+    
+    /**
+     * Get a code from the sqlite database for ip address
+     */
+    protected function getCodeFromDatabase()
+    {
+        $code = '';
+
+        if ($this->use_sqlite_db && $this->sqlite_handle !== false) {
+            $ip = $_SERVER['REMOTE_ADDR'];
+            $ns = sqlite_escape_string($this->namespace);
+
+            $res = sqlite_query($this->sqlite_handle, "SELECT * FROM codes WHERE ip = '$ip' AND namespace = '$ns'");
+            if ($res && sqlite_num_rows($res) > 0) {
+                $res = sqlite_fetch_array($res);
+
+                if ($this->isCodeExpired($res['created']) == false) {
+                    $code = $res['code'];
+                }
+            }
+        }
+        return $code;
+    }
+    
+    /**
+     * Remove an entered code from the database
+     */
+    protected function clearCodeFromDatabase()
+    {
+        if (is_resource($this->sqlite_handle)) {
+            $ip = $_SERVER['REMOTE_ADDR'];
+            $ns = sqlite_escape_string($this->namespace);
+            
+            sqlite_query($this->sqlite_handle, "DELETE FROM codes WHERE ip = '$ip' AND namespace = '$ns'");
+        }
+    }
+    
+    /**
+     * Deletes old codes from sqlite database
+     */
+    protected function purgeOldCodesFromDatabase()
+    {
+        if ($this->use_sqlite_db && $this->sqlite_handle !== false) {
+            $now   = time();
+            $limit = (!is_numeric($this->expiry_time) || $this->expiry_time < 1) ? 86400 : $this->expiry_time;
+            
+            sqlite_query($this->sqlite_handle, "DELETE FROM codes WHERE $now - created > $limit");
+        }
+    }
+    
+    /**
+     * Checks to see if the captcha code has expired and cannot be used
+     * @param unknown_type $creation_time
+     */
+    protected function isCodeExpired($creation_time)
+    {
+        $expired = true;
+        
+        if (!is_numeric($this->expiry_time) || $this->expiry_time < 1) {
+            $expired = false;
+        } else if (time() - $creation_time < $this->expiry_time) {
+            $expired = false;
+        }
+        
+        return $expired;
+    }
+    
+    /**
+     * 
+     * Generate an MP3 audio file of the captcha image
+     * 
+     * @deprecated 3.0
+     */
+    protected function generateMP3()
+    {
+        return false;
+    }
+    
+    /**
+     * Generate a wav file given the $letters in the code
+     * @todo Add ability to merge 2 sound files together to have random background sounds
+     * @param array $letters
+     * @return string The binary contents of the wav file
+     */
+    protected function generateWAV($letters)
+    {
+        $data_len       = 0;
+        $files          = array();
+        $out_data       = '';
+        $out_channels   = 0;
+        $out_samplert   = 0;
+        $out_bpersample = 0;
+        $numSamples     = 0;
+        $removeChunks   = array('LIST', 'DISP', 'NOTE');
+
+        for ($i = 0; $i < sizeof($letters); ++$i) {
+            $letter   = $letters[$i];
+            $filename = $this->audio_path . strtoupper($letter) . '.wav';
+            $file     = array();
+            $data     = @file_get_contents($filename);
+            
+            if ($data === false) {
+                // echo "Failed to read $filename";
+                return $this->audioError();
+            }
+
+            $header = substr($data, 0, 36);
+            $info   = unpack('NChunkID/VChunkSize/NFormat/NSubChunk1ID/'
+                            .'VSubChunk1Size/vAudioFormat/vNumChannels/'
+                            .'VSampleRate/VByteRate/vBlockAlign/vBitsPerSample',
+                             $header);
+            
+            $dataPos        = strpos($data, 'data');
+            $out_channels   = $info['NumChannels'];
+            $out_samplert   = $info['SampleRate'];
+            $out_bpersample = $info['BitsPerSample'];
+            
+            if ($dataPos === false) {
+                // wav file with no data?
+                // echo "Failed to find DATA segment in $filename";
+                return $this->audioError();
+            }
+            
+            if ($info['AudioFormat'] != 1) {
+                // only work with PCM audio
+                // echo "$filename was not PCM audio, only PCM is supported";
+                return $this->audioError();
+            }
+            
+            if ($info['SubChunk1Size'] != 16 && $info['SubChunk1Size'] != 18) {
+                // probably unsupported extension
+                // echo "Bad SubChunk1Size in $filename - Size was {$info['SubChunk1Size']}";
+                return $this->audioError();
+            }
+            
+            if ($info['SubChunk1Size'] > 16) {
+                $header .= substr($data, 36, $info['SubChunk1Size'] - 16);
+            }
+            
+            if ($i == 0) {
+                // create the final file's header, size will be adjusted later
+                $out_data = $header . 'data';
+            }
+            
+            $removed = 0;
+            
+            foreach($removeChunks as $chunk) {
+                $chunkPos = strpos($data, $chunk);
+                if ($chunkPos !== false) {
+                    $listSize = unpack('VSize', substr($data, $chunkPos + 4, 4));
+                    
+                    $data = substr($data, 0, $chunkPos) .
+                            substr($data, $chunkPos + 8 + $listSize['Size']);
+                            
+                    $removed += $listSize['Size'] + 8;
+                }
+            }
+            
+            $dataSize    = unpack('VSubchunk2Size', substr($data, $dataPos + 4, 4));
+            $dataSize['Subchunk2Size'] -= $removed;
+            $out_data   .= substr($data, $dataPos + 8, $dataSize['Subchunk2Size'] * ($out_bpersample / 8));
+            $numSamples += $dataSize['Subchunk2Size'];
+        }
+
+        $filesize  = strlen($out_data);
+        $chunkSize = $filesize - 8;
+        $dataCSize = $numSamples;
+        
+        $out_data = substr_replace($out_data, pack('V', $chunkSize), 4, 4);
+        $out_data = substr_replace($out_data, pack('V', $numSamples), 40 + ($info['SubChunk1Size'] - 16), 4);
+
+        $this->scrambleAudioData($out_data, 'wav');
+        
+        return $out_data;
+    }
+    
+    /**
+     * Randomizes the audio data to add noise and prevent binary recognition
+     * @param string $data  The binary audio file data
+     * @param string $format The format of the sound file (wav only)
+     */
+    protected function scrambleAudioData(&$data, $format)
+    {
+        $start = strpos($data, 'data') + 4; // look for "data" indicator
+        if ($start === false) $start = 44;  // if not found assume 44 byte header
+         
+        $start  += rand(1, 4); // randomize starting offset
+        $datalen = strlen($data) - $start;
+        $step    = 1;
+        
+        for ($i = $start; $i < $datalen; $i += $step) {
+            $ch = ord($data{$i});
+            if ($ch == 0 || $ch == 255) continue;
+            
+            if ($ch < 16 || $ch > 239) {
+                $ch += rand(-6, 6);
+            } else {
+                $ch += rand(-12, 12);
+            }
+            
+            if ($ch < 0) $ch = 0; else if ($ch > 255) $ch = 255;
+
+            $data{$i} = chr($ch);
+            
+            $step = rand(1,4);
+        }
+
+        return $data;
+    }
+    
+    /**
+     * Return a wav file saying there was an error generating file
+     * 
+     * @return string The binary audio contents
+     */
+    protected function audioError()
+    {
+        return @file_get_contents(dirname(__FILE__) . '/audio/error.wav');
+    }
+    
+    function frand()
+    {
+        return 0.0001 * rand(0,9999);
+    }
+    
+    /**
+     * Convert an html color code to a Securimage_Color
+     * @param string $color
+     * @param Securimage_Color $default The defalt color to use if $color is invalid
+     */
+    protected function initColor($color, $default)
+    {
+        if ($color == null) {
+            return new Securimage_Color($default);
+        } else if (is_string($color)) {
+            try {
+                return new Securimage_Color($color);
+            } catch(Exception $e) {
+                return new Securimage_Color($default);
+            }
+        } else if (is_array($color) && sizeof($color) == 3) {
+            return new Securimage_Color($color[0], $color[1], $color[2]);
+        } else {
+            return new Securimage_Color($default);
+        }
+    }
+}
+
+
+/**
+ * Color object for Securimage CAPTCHA
+ *
+ * @version 3.0
+ * @since 2.0
+ * @package Securimage
+ * @subpackage classes
+ *
+ */
+class Securimage_Color
+{
+    public $r;
+    public $g;
+    public $b;
+
+    /**
+     * Create a new Securimage_Color object.<br />
+     * Constructor expects 1 or 3 arguments.<br />
+     * When passing a single argument, specify the color using HTML hex format,<br />
+     * when passing 3 arguments, specify each RGB component (from 0-255) individually.<br />
+     * $color = new Securimage_Color('#0080FF') or <br />
+     * $color = new Securimage_Color(0, 128, 255)
+     * 
+     * @param string $color
+     * @throws Exception
+     */
+    public function __construct($color = '#ffffff')
+    {
+        $args = func_get_args();
+        
+        if (sizeof($args) == 0) {
+            $this->r = 255;
+            $this->g = 255;
+            $this->b = 255;
+        } else if (sizeof($args) == 1) {
+            // set based on html code
+            if (substr($color, 0, 1) == '#') {
+                $color = substr($color, 1);
+            }
+            
+            if (strlen($color) != 3 && strlen($color) != 6) {
+                throw new InvalidArgumentException(
+                  'Invalid HTML color code passed to Securimage_Color'
+                );
+            }
+            
+            $this->constructHTML($color);
+        } else if (sizeof($args) == 3) {
+            $this->constructRGB($args[0], $args[1], $args[2]);
+        } else {
+            throw new InvalidArgumentException(
+              'Securimage_Color constructor expects 0, 1 or 3 arguments; ' . sizeof($args) . ' given'
+            );
+        }
+    }
+    
+    /**
+     * Construct from an rgb triplet
+     * @param int $red The red component, 0-255
+     * @param int $green The green component, 0-255
+     * @param int $blue The blue component, 0-255
+     */
+    protected function constructRGB($red, $green, $blue)
+    {
+        if ($red < 0)     $red   = 0;
+        if ($red > 255)   $red   = 255;
+        if ($green < 0)   $green = 0;
+        if ($green > 255) $green = 255;
+        if ($blue < 0)    $blue  = 0;
+        if ($blue > 255)  $blue  = 255;
+        
+        $this->r = $red;
+        $this->g = $green;
+        $this->b = $blue;
+    }
+    
+    /**
+     * Construct from an html hex color code
+     * @param string $color
+     */
+    protected function constructHTML($color)
+    {
+        if (strlen($color) == 3) {
+            $red   = str_repeat(substr($color, 0, 1), 2);
+            $green = str_repeat(substr($color, 1, 1), 2);
+            $blue  = str_repeat(substr($color, 2, 1), 2);
+        } else {
+            $red   = substr($color, 0, 2);
+            $green = substr($color, 2, 2);
+            $blue  = substr($color, 4, 2); 
+        }
+        
+        $this->r = hexdec($red);
+        $this->g = hexdec($green);
+        $this->b = hexdec($blue);
+    }
+}
+?>
Index: /extensions/CryptograPHP/securimage/securimage_show.php
===================================================================
--- /extensions/CryptograPHP/securimage/securimage_show.php	(revision 12617)
+++ /extensions/CryptograPHP/securimage/securimage_show.php	(revision 12617)
@@ -0,0 +1,89 @@
+<?php
+/**
+ * Project:     Securimage: A PHP class for creating and managing form CAPTCHA images
+ * File:        securimage_show.php
+ *
+ * Copyright (c) 2011, Drew Phillips
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 
+ *  - Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Any modifications to the library should be indicated clearly in the source code
+ * to inform users that the changes are not a part of the original software.
+ *
+ * If you found this script useful, please take a quick moment to rate it.
+ * http://www.hotscripts.com/rate/49400.html  Thanks.
+ *
+ * @link http://www.phpcaptcha.org Securimage PHP CAPTCHA
+ * @link http://www.phpcaptcha.org/latest.zip Download Latest Version
+ * @link http://www.phpcaptcha.org/Securimage_Docs/ Online Documentation
+ * @copyright 2011 Drew Phillips
+ * @author Drew Phillips <drew@drew-phillips.com>
+ * @version 3.0 (October 2011)
+ * @package Securimage
+ *
+ */
+
+// error_reporting(E_ALL); ini_set('display_errors', 1); // uncomment this line for debugging
+
+define('PHPWG_ROOT_PATH','../../../');
+include_once(PHPWG_ROOT_PATH.'include/common.inc.php');
+
+$conf['cryptographp'] = unserialize($conf['cryptographp']);
+
+// randomize colors
+function randomColor()
+{
+  mt_srand((double)microtime()*1000000);
+  $c = null;
+  while(strlen($c)<6)
+  {
+      $c .= sprintf("%02X", mt_rand(0, 255));
+  }
+  return $c;
+}
+
+foreach (array('image_bg_color','text_color','line_color','noise_color') as $color)
+{
+  if ($conf['cryptographp'][$color] == 'random') $conf['cryptographp'][$color] = randomColor();
+}
+
+require_once dirname(__FILE__) . '/securimage.php';
+$img = new securimage();
+
+$img->ttf_file        = './fonts/'.$conf['cryptographp']['ttf_file'].'.ttf';
+$img->captcha_type    = ($conf['cryptographp']['captcha_type'] == 'string') ? Securimage::SI_CAPTCHA_STRING : Securimage::SI_CAPTCHA_MATHEMATIC;
+// $img->case_sensitive  = get_boolean($conf['cryptographp']['case_sensitive']);
+$img->image_width     = $conf['cryptographp']['width']; 
+$img->image_height    = $conf['cryptographp']['height'];
+$img->perturbation    = $conf['cryptographp']['perturbation'];
+$img->image_bg_color  = new Securimage_Color('#'.$conf['cryptographp']['image_bg_color']);
+$img->text_color      = new Securimage_Color('#'.$conf['cryptographp']['text_color']); 
+$img->num_lines       = $conf['cryptographp']['num_lines'];
+$img->line_color      = new Securimage_Color('#'.$conf['cryptographp']['line_color']);
+$img->noise_level     = $conf['cryptographp']['noise_level'];
+$img->noise_color     = new Securimage_Color('#'.$conf['cryptographp']['noise_color']);
+$img->code_length     = $conf['cryptographp']['code_length'];
+
+$img->show();
+
+?>
Index: /extensions/CryptograPHP/template/admin.tpl
===================================================================
--- /extensions/CryptograPHP/template/admin.tpl	(revision 12617)
+++ /extensions/CryptograPHP/template/admin.tpl	(revision 12617)
@@ -0,0 +1,188 @@
+{combine_css path=$CRYPTO_PATH|@cat:"template/colorpicker/colorpicker.css"}
+{combine_script id="jquery.colorpicker" require="jquery" path=$CRYPTO_PATH|@cat:"template/colorpicker/colorpicker.js"}
+
+{footer_script require='jquery.colorpicker'}{literal}
+jQuery(document).ready(function() {
+  $('.colorpicker-input')
+  .ColorPicker({
+    onSubmit: function(hsb, hex, rgb, el) { 
+      $(el).val(hex); 
+      $(el).ColorPickerHide(); 
+    },
+    onChange: function(hsb, hex, rgb, el) { 
+      $(el).val(hex); 
+      changeColor(el, hex); 
+      $('.preset').removeClass('selected'); 
+      $('input[name=theme]').val('custom');
+    },
+    onBeforeShow: function () { 
+      $(this).ColorPickerSetColor(this.value); 
+    }
+  })
+  .bind('keyup', function(){ 
+    $(this).ColorPickerSetColor(this.value);
+    changeColor(this, $(this).val());
+  })
+  .each(function() {
+    changeColor(this, $(this).val());
+  });
+  
+  $('.preset').click(function() {
+    $('.preset').removeClass('selected');
+    $(this).addClass('selected');
+    eval('apply_'+ $(this).attr('title') +'();');
+    $('.colorpicker-input').each(function() { changeColor(this, $(this).val()); });
+    $('input[name=theme]').val($(this).attr('title'));
+  });
+  
+  $('.customize').click(function() {
+    $('#theming').fadeToggle();
+  });
+  
+  $('input.istheme').change(function() {
+    $('.preset').removeClass('selected');
+    $('input[name=theme]').val('custom');
+  });
+});
+
+function changeColor(target, color) {
+  if (color == 'random') color = '808080';
+  if (parseInt(color, 16) > 16777215/2) {
+    $(target).css('color', '#222');
+  } else {
+    $(target).css('color', '#ddd');
+  }
+  $(target).css('background', '#'+color)
+}
+{/literal}
+
+{$PRESETS_FUNC}
+{/footer_script}
+
+{html_head}
+<style type="text/css">
+{foreach from=$fonts item=font}
+@font-face {ldelim}  
+  font-family: {$font} ;  
+  src: url({$CRYPTO_PATH}securimage/fonts/{$font}.ttf) format("truetype");  
+}
+{/foreach}
+.preset img {ldelim}
+  margin:1px;
+  padding:3px;
+  border:1px solid #999;
+}
+.preset.selected img {ldelim}
+  border-color:#f70;
+}
+</style>
+{/html_head}
+
+<div class="titrePage">
+  <h2>Crypto Captcha</h2>
+</div>
+
+<form method="post" class="properties">
+<fieldset>
+  <legend>{'Configuration'|@translate}</legend>
+  
+  <ul>			
+    <li>
+      <span class="property">{'Comments action'|@translate}</span>
+      <label><input type="radio" name="comments_action" value="inactive" {if $crypto.comments_action == 'inactive'}checked="checked"{/if}> {'No captcha'|@translate}</label>
+      <label><input type="radio" name="comments_action" value="reject" {if $crypto.comments_action == 'reject'}checked="checked"{/if}> {'Reject'|@translate}</label>
+      <label><input type="radio" name="comments_action" value="moderate" {if $crypto.comments_action == 'moderate'}checked="checked"{/if}> {'Moderate'|@translate}</label>
+    </li>
+    <li>
+      <span class="property">{'Captcha type'|@translate}</span>
+      <label><input type="radio" name="captcha_type" value="string" {if $crypto.captcha_type == 'string'}checked="checked"{/if}> {'Random string'|@translate}</label>
+      <label><input type="radio" name="captcha_type" value="math" {if $crypto.captcha_type == 'math'}checked="checked"{/if}> {'Simple equation'|@translate}</label>
+    </li>
+    <!--<li>
+      <span class="property">{'Case sensitive'|@translate}</span>
+      <label><input type="radio" name="case_sensitive" value="false" {if $crypto.case_sensitive == 'false'}checked="checked"{/if}> {'No'|@translate}</label>
+      <label><input type="radio" name="case_sensitive" value="true" {if $crypto.case_sensitive == 'true'}checked="checked"{/if}> {'Yes'|@translate}</label>
+    </li>-->
+    <li>
+      <span class="property">{'Code lenght'|@translate}</span>
+      <label><input type="text" name="code_length" value="{$crypto.code_length}" size="6" maxlength="2"></label>
+    </li>
+    <li>
+      <span class="property">{'Width'|@translate}</span>
+      <label><input type="text" name="width" value="{$crypto.width}" size="6" maxlength="3"> {'good value:'|@translate} lenght*20</label>
+    </li>
+    <li>
+      <span class="property">{'Height'|@translate}</span>
+      <label><input type="text" name="height" value="{$crypto.height}" size="6" maxlength="3"> {'good value:'|@translate} width/4</label>
+    </li>
+    <li>
+      <span class="property">{'Captcha theme'|@translate}</span>
+      <div style="display:relative;margin-left:51%;">
+        {foreach from=$presets item=preset}
+        <a class="preset {if $crypto.theme == $preset}selected{/if}" title="{$preset}"><img src="{$CRYPTO_PATH}template/presets/{$preset}.png" alt="{$preset}"></a>
+        {/foreach}
+        <br><a class="customize">{'Customize'|@translate}</a><input type="hidden" name="theme" value="{$crypto.theme}">
+      </div>
+    </li>
+  </ul>
+  
+  <fieldset {if $crypto.theme != 'custom'}style="display:none;"{/if} id="theming">
+    <legend>{'Customize'|@translate}</legend>
+    
+    <ul>
+      <li>
+        <span class="property">{'Perturbation'|@translate}</span>
+        <label><input type="text" name="perturbation" value="{$crypto.perturbation}" class="istheme" size="6" maxlength="4"> {'range:'|@translate} 0 to 1</label>
+      </li>
+      <li>
+        <span class="property">{'Background color'|@translate}</span>
+        <label><input type="text" name="image_bg_color" value="{$crypto.image_bg_color}" class="colorpicker-input istheme" size="6" maxlength="6"></label>
+      </li>
+      <li>
+        <span class="property">{'Text color'|@translate}</span>
+        <label><input type="text" name="text_color" value="{$crypto.text_color}" class="colorpicker-input istheme" size="6" maxlength="6"></label>
+      </li>
+      <li>
+        <span class="property">{'Lines density'|@translate}</span>
+        <label><input type="text" name="num_lines" value="{$crypto.num_lines}" class="istheme" size="6" maxlength="4"> {'range:'|@translate} 0 to 10</label>
+      </li>
+      <li>
+        <span class="property">{'Lines color'|@translate}</span>
+        <label><input type="text" name="line_color" value="{$crypto.line_color}" class="colorpicker-input istheme" size="6" maxlength="6"></label>
+      </li>
+      <li>
+        <span class="property">{'Noise level'|@translate}</span>
+        <label><input type="text" name="noise_level" value="{$crypto.noise_level}" class="istheme" size="6" maxlength="4"> {'range:'|@translate} 0 to 10</label>
+      </li>
+      <li>
+        <span class="property">{'Noise color'|@translate}</span>
+        <label><input type="text" name="noise_color" value="{$crypto.noise_color}" class="colorpicker-input istheme" size="6" maxlength="6"></label>
+      </li>
+      <li>
+        <span class="property">{'Font'|@translate}</span>
+        <div style="display:relative;margin-left:51%;">
+          {foreach from=$fonts item=font}
+          <label style="font-family:{$font};" title="{$font}"><input type="radio" name="ttf_file" value="{$font}" {if $crypto.ttf_file == $font}checked="checked"{/if} class="istheme"> {$font}</label>
+          {/foreach}
+        </div>
+      </li>
+      
+      <li>
+        <span class="property">{'Preview'|@translate}</span>
+        <label><img id="captcha" src="{$CRYPTO_PATH}securimage/securimage_show.php" alt="CAPTCHA Image"></label>
+      </li>
+    </ul>
+    
+    {'Tip: type "random" on a color field to have a random color'|@translate}
+  </fieldset>
+  
+  <p class="bottomButtons">
+    <input class="submit" type="submit" value="{'Submit'|@translate}" name="submit">
+  </p>
+</fieldset>
+</form>
+
+<div style="text-align:right;">
+  All free fonts from <a href="http://www.dafont.com" target="_blank">dafont.com</a> | 
+  Powered by : <a href="http://www.phpcaptcha.org/" target="_blank"><img src="{$CRYPTO_PATH}template/logo.png" alt="Secureimage"></a>
+</div>
Index: /extensions/CryptograPHP/template/colorpicker/colorpicker.css
===================================================================
--- /extensions/CryptograPHP/template/colorpicker/colorpicker.css	(revision 12617)
+++ /extensions/CryptograPHP/template/colorpicker/colorpicker.css	(revision 12617)
@@ -0,0 +1,143 @@
+.colorpicker {
+  width: 286px;
+  height: 176px;
+  overflow: hidden;
+  position: absolute;
+  background: url(colorpicker_background.png);
+  font-family: Arial, Helvetica, sans-serif;
+  display: none;
+}
+.colorpicker_color {
+  width: 150px;
+  height: 150px;
+  left: 14px;
+  top: 13px;
+  position: absolute;
+  background: #f00;
+  overflow: hidden;
+  cursor: crosshair;
+}
+.colorpicker_color div {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 150px;
+  height: 150px;
+  background: url(colorpicker_overlay.png);
+}
+.colorpicker_color div div {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 11px;
+  height: 11px;
+  overflow: hidden;
+  background: url(colorpicker_select.gif);
+  margin: -5px 0 0 -5px;
+}
+.colorpicker_hue {
+  position: absolute;
+  top: 13px;
+  left: 171px;
+  width: 35px;
+  height: 150px;
+  cursor: n-resize;
+}
+.colorpicker_hue div {
+  position: absolute;
+  width: 35px;
+  height: 9px;
+  overflow: hidden;
+  background: url(colorpicker_indic.gif) left top;
+  margin: -4px 0 0 0;
+  left: 0px;
+}
+.colorpicker_new_color {
+  position: absolute;
+  width: 60px;
+  height: 30px;
+  left: 213px;
+  top: 13px;
+  background: #f00;
+}
+.colorpicker_current_color {
+  display:none;
+}
+.colorpicker input {
+  background-color: transparent;
+  border: 1px solid transparent;
+  position: absolute;
+  font-size: 10px;
+  font-family: Arial, Helvetica, sans-serif;
+  color: #898989;
+  top: 4px;
+  right: 11px;
+  text-align: right;
+  margin: 0;
+  padding: 0;
+  height: 11px;
+}
+/* annulation des styles généraux */
+.colorpicker input:hover, .colorpicker input:focus {
+  border:none;
+  background:none;
+  -moz-box-shadow:none;
+  -webkit-box-shadow:none;
+}
+.colorpicker_hex {
+  display:none;
+}
+.colorpicker_field {
+  height: 22px;
+  width: 62px;
+  background-position: top;
+  position: absolute;
+}
+.colorpicker_field span {
+  position: absolute;
+  width: 12px;
+  height: 22px;
+  overflow: hidden;
+  top: 0;
+  right: 0;
+  cursor: n-resize;
+}
+.colorpicker_rgb_r {
+  background-image: url(colorpicker_rgb_r.png);
+  top: 52px;
+  left: 212px;
+}
+.colorpicker_rgb_g {
+  background-image: url(colorpicker_rgb_g.png);
+  top: 82px;
+  left: 212px;
+}
+.colorpicker_rgb_b {
+  background-image: url(colorpicker_rgb_b.png);
+  top: 112px;
+  left: 212px;
+}
+.colorpicker_hsb_h, .colorpicker_hsb_s, .colorpicker_hsb_b {
+  display:none;
+}
+.colorpicker_submit {
+  position: absolute;
+  width: 22px;
+  height: 22px;
+  background: url(colorpicker_submit.png) top;
+  right: 6px;
+  bottom: 6px;
+  overflow: hidden;
+}
+.colorpicker_focus {
+  background-position: center;
+}
+.colorpicker_hex.colorpicker_focus {
+  background-position: bottom;
+}
+.colorpicker_submit.colorpicker_focus {
+  background-position: bottom;
+}
+.colorpicker_slider {
+  background-position: bottom;
+}
Index: /extensions/CryptograPHP/template/colorpicker/colorpicker.js
===================================================================
--- /extensions/CryptograPHP/template/colorpicker/colorpicker.js	(revision 12617)
+++ /extensions/CryptograPHP/template/colorpicker/colorpicker.js	(revision 12617)
@@ -0,0 +1,484 @@
+/**
+ *
+ * Color picker
+ * Author: Stefan Petre www.eyecon.ro
+ * 
+ * Dual licensed under the MIT and GPL licenses
+ * 
+ */
+(function ($) {
+	var ColorPicker = function () {
+		var
+			ids = {},
+			inAction,
+			charMin = 65,
+			visible,
+			tpl = '<div class="colorpicker"><div class="colorpicker_color"><div><div></div></div></div><div class="colorpicker_hue"><div></div></div><div class="colorpicker_new_color"></div><div class="colorpicker_current_color"></div><div class="colorpicker_hex"><input type="text" maxlength="6" size="6" /></div><div class="colorpicker_rgb_r colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_rgb_g colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_rgb_b colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_h colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_s colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_b colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_submit"></div></div>',
+			defaults = {
+				eventName: 'click',
+				onShow: function () {},
+				onBeforeShow: function(){},
+				onHide: function () {},
+				onChange: function () {},
+				onSubmit: function () {},
+				color: 'ff0000',
+				livePreview: true,
+				flat: false
+			},
+			fillRGBFields = function  (hsb, cal) {
+				var rgb = HSBToRGB(hsb);
+				$(cal).data('colorpicker').fields
+					.eq(1).val(rgb.r).end()
+					.eq(2).val(rgb.g).end()
+					.eq(3).val(rgb.b).end();
+			},
+			fillHSBFields = function  (hsb, cal) {
+				$(cal).data('colorpicker').fields
+					.eq(4).val(hsb.h).end()
+					.eq(5).val(hsb.s).end()
+					.eq(6).val(hsb.b).end();
+			},
+			fillHexFields = function (hsb, cal) {
+				$(cal).data('colorpicker').fields
+					.eq(0).val(HSBToHex(hsb)).end();
+			},
+			setSelector = function (hsb, cal) {
+				$(cal).data('colorpicker').selector.css('backgroundColor', '#' + HSBToHex({h: hsb.h, s: 100, b: 100}));
+				$(cal).data('colorpicker').selectorIndic.css({
+					left: parseInt(150 * hsb.s/100, 10),
+					top: parseInt(150 * (100-hsb.b)/100, 10)
+				});
+			},
+			setHue = function (hsb, cal) {
+				$(cal).data('colorpicker').hue.css('top', parseInt(150 - 150 * hsb.h/360, 10));
+			},
+			setCurrentColor = function (hsb, cal) {
+				$(cal).data('colorpicker').currentColor.css('backgroundColor', '#' + HSBToHex(hsb));
+			},
+			setNewColor = function (hsb, cal) {
+				$(cal).data('colorpicker').newColor.css('backgroundColor', '#' + HSBToHex(hsb));
+			},
+			keyDown = function (ev) {
+				var pressedKey = ev.charCode || ev.keyCode || -1;
+				if ((pressedKey > charMin && pressedKey <= 90) || pressedKey == 32) {
+					return false;
+				}
+				var cal = $(this).parent().parent();
+				if (cal.data('colorpicker').livePreview === true) {
+					change.apply(this);
+				}
+			},
+			change = function (ev) {
+				var cal = $(this).parent().parent(), col;
+				if (this.parentNode.className.indexOf('_hex') > 0) {
+					cal.data('colorpicker').color = col = HexToHSB(fixHex(this.value));
+				} else if (this.parentNode.className.indexOf('_hsb') > 0) {
+					cal.data('colorpicker').color = col = fixHSB({
+						h: parseInt(cal.data('colorpicker').fields.eq(4).val(), 10),
+						s: parseInt(cal.data('colorpicker').fields.eq(5).val(), 10),
+						b: parseInt(cal.data('colorpicker').fields.eq(6).val(), 10)
+					});
+				} else {
+					cal.data('colorpicker').color = col = RGBToHSB(fixRGB({
+						r: parseInt(cal.data('colorpicker').fields.eq(1).val(), 10),
+						g: parseInt(cal.data('colorpicker').fields.eq(2).val(), 10),
+						b: parseInt(cal.data('colorpicker').fields.eq(3).val(), 10)
+					}));
+				}
+				if (ev) {
+					fillRGBFields(col, cal.get(0));
+					fillHexFields(col, cal.get(0));
+					fillHSBFields(col, cal.get(0));
+				}
+				setSelector(col, cal.get(0));
+				setHue(col, cal.get(0));
+				setNewColor(col, cal.get(0));
+				cal.data('colorpicker').onChange(col, HSBToHex(col), HSBToRGB(col), cal.data('colorpicker').el);
+			},
+			blur = function (ev) {
+				var cal = $(this).parent().parent();
+				cal.data('colorpicker').fields.parent().removeClass('colorpicker_focus');
+			},
+			focus = function () {
+				charMin = this.parentNode.className.indexOf('_hex') > 0 ? 70 : 65;
+				$(this).parent().parent().data('colorpicker').fields.parent().removeClass('colorpicker_focus');
+				$(this).parent().addClass('colorpicker_focus');
+			},
+			downIncrement = function (ev) {
+				var field = $(this).parent().find('input').focus();
+				var current = {
+					el: $(this).parent().addClass('colorpicker_slider'),
+					max: this.parentNode.className.indexOf('_hsb_h') > 0 ? 360 : (this.parentNode.className.indexOf('_hsb') > 0 ? 100 : 255),
+					y: ev.pageY,
+					field: field,
+					val: parseInt(field.val(), 10),
+					preview: $(this).parent().parent().data('colorpicker').livePreview					
+				};
+				$(document).bind('mouseup', current, upIncrement);
+				$(document).bind('mousemove', current, moveIncrement);
+			},
+			moveIncrement = function (ev) {
+				ev.data.field.val(Math.max(0, Math.min(ev.data.max, parseInt(ev.data.val + ev.pageY - ev.data.y, 10))));
+				if (ev.data.preview) {
+					change.apply(ev.data.field.get(0), [true]);
+				}
+				return false;
+			},
+			upIncrement = function (ev) {
+				change.apply(ev.data.field.get(0), [true]);
+				ev.data.el.removeClass('colorpicker_slider').find('input').focus();
+				$(document).unbind('mouseup', upIncrement);
+				$(document).unbind('mousemove', moveIncrement);
+				return false;
+			},
+			downHue = function (ev) {
+				var current = {
+					cal: $(this).parent(),
+					y: $(this).offset().top
+				};
+				current.preview = current.cal.data('colorpicker').livePreview;
+				$(document).bind('mouseup', current, upHue);
+				$(document).bind('mousemove', current, moveHue);
+			},
+			moveHue = function (ev) {
+				change.apply(
+					ev.data.cal.data('colorpicker')
+						.fields
+						.eq(4)
+						.val(parseInt(360*(150 - Math.max(0,Math.min(150,(ev.pageY - ev.data.y))))/150, 10))
+						.get(0),
+					[ev.data.preview]
+				);
+				return false;
+			},
+			upHue = function (ev) {
+				fillRGBFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
+				fillHexFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
+				$(document).unbind('mouseup', upHue);
+				$(document).unbind('mousemove', moveHue);
+				return false;
+			},
+			downSelector = function (ev) {
+				var current = {
+					cal: $(this).parent(),
+					pos: $(this).offset()
+				};
+				current.preview = current.cal.data('colorpicker').livePreview;
+				$(document).bind('mouseup', current, upSelector);
+				$(document).bind('mousemove', current, moveSelector);
+			},
+			moveSelector = function (ev) {
+				change.apply(
+					ev.data.cal.data('colorpicker')
+						.fields
+						.eq(6)
+						.val(parseInt(100*(150 - Math.max(0,Math.min(150,(ev.pageY - ev.data.pos.top))))/150, 10))
+						.end()
+						.eq(5)
+						.val(parseInt(100*(Math.max(0,Math.min(150,(ev.pageX - ev.data.pos.left))))/150, 10))
+						.get(0),
+					[ev.data.preview]
+				);
+				return false;
+			},
+			upSelector = function (ev) {
+				fillRGBFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
+				fillHexFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
+				$(document).unbind('mouseup', upSelector);
+				$(document).unbind('mousemove', moveSelector);
+				return false;
+			},
+			enterSubmit = function (ev) {
+				$(this).addClass('colorpicker_focus');
+			},
+			leaveSubmit = function (ev) {
+				$(this).removeClass('colorpicker_focus');
+			},
+			clickSubmit = function (ev) {
+				var cal = $(this).parent();
+				var col = cal.data('colorpicker').color;
+				cal.data('colorpicker').origColor = col;
+				setCurrentColor(col, cal.get(0));
+				cal.data('colorpicker').onSubmit(col, HSBToHex(col), HSBToRGB(col), cal.data('colorpicker').el);
+			},
+			show = function (ev) {
+				var cal = $('#' + $(this).data('colorpickerId'));
+				cal.data('colorpicker').onBeforeShow.apply(this, [cal.get(0)]);
+				var pos = $(this).offset();
+				var viewPort = getViewport();
+				var top = pos.top + this.offsetHeight;
+				var left = pos.left;
+				if (top + 176 > viewPort.t + viewPort.h) {
+					top -= this.offsetHeight + 176;
+				}
+				if (left + 356 > viewPort.l + viewPort.w) {
+					left -= 356;
+				}
+				cal.css({left: left + 'px', top: top + 'px'});
+				if (cal.data('colorpicker').onShow.apply(this, [cal.get(0)]) != false) {
+					cal.show();
+				}
+				$(document).bind('mousedown', {cal: cal}, hide);
+				return false;
+			},
+			hide = function (ev) {
+				if (!isChildOf(ev.data.cal.get(0), ev.target, ev.data.cal.get(0))) {
+					if (ev.data.cal.data('colorpicker').onHide.apply(this, [ev.data.cal.get(0)]) != false) {
+						ev.data.cal.hide();
+					}
+					$(document).unbind('mousedown', hide);
+				}
+			},
+			isChildOf = function(parentEl, el, container) {
+				if (parentEl == el) {
+					return true;
+				}
+				if (parentEl.contains) {
+					return parentEl.contains(el);
+				}
+				if ( parentEl.compareDocumentPosition ) {
+					return !!(parentEl.compareDocumentPosition(el) & 16);
+				}
+				var prEl = el.parentNode;
+				while(prEl && prEl != container) {
+					if (prEl == parentEl)
+						return true;
+					prEl = prEl.parentNode;
+				}
+				return false;
+			},
+			getViewport = function () {
+				var m = document.compatMode == 'CSS1Compat';
+				return {
+					l : window.pageXOffset || (m ? document.documentElement.scrollLeft : document.body.scrollLeft),
+					t : window.pageYOffset || (m ? document.documentElement.scrollTop : document.body.scrollTop),
+					w : window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth),
+					h : window.innerHeight || (m ? document.documentElement.clientHeight : document.body.clientHeight)
+				};
+			},
+			fixHSB = function (hsb) {
+				return {
+					h: Math.min(360, Math.max(0, hsb.h)),
+					s: Math.min(100, Math.max(0, hsb.s)),
+					b: Math.min(100, Math.max(0, hsb.b))
+				};
+			}, 
+			fixRGB = function (rgb) {
+				return {
+					r: Math.min(255, Math.max(0, rgb.r)),
+					g: Math.min(255, Math.max(0, rgb.g)),
+					b: Math.min(255, Math.max(0, rgb.b))
+				};
+			},
+			fixHex = function (hex) {
+				var len = 6 - hex.length;
+				if (len > 0) {
+					var o = [];
+					for (var i=0; i<len; i++) {
+						o.push('0');
+					}
+					o.push(hex);
+					hex = o.join('');
+				}
+				return hex;
+			}, 
+			HexToRGB = function (hex) {
+				var hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16);
+				return {r: hex >> 16, g: (hex & 0x00FF00) >> 8, b: (hex & 0x0000FF)};
+			},
+			HexToHSB = function (hex) {
+				return RGBToHSB(HexToRGB(hex));
+			},
+			RGBToHSB = function (rgb) {
+				var hsb = {
+					h: 0,
+					s: 0,
+					b: 0
+				};
+				var min = Math.min(rgb.r, rgb.g, rgb.b);
+				var max = Math.max(rgb.r, rgb.g, rgb.b);
+				var delta = max - min;
+				hsb.b = max;
+				if (max != 0) {
+					
+				}
+				hsb.s = max != 0 ? 255 * delta / max : 0;
+				if (hsb.s != 0) {
+					if (rgb.r == max) {
+						hsb.h = (rgb.g - rgb.b) / delta;
+					} else if (rgb.g == max) {
+						hsb.h = 2 + (rgb.b - rgb.r) / delta;
+					} else {
+						hsb.h = 4 + (rgb.r - rgb.g) / delta;
+					}
+				} else {
+					hsb.h = -1;
+				}
+				hsb.h *= 60;
+				if (hsb.h < 0) {
+					hsb.h += 360;
+				}
+				hsb.s *= 100/255;
+				hsb.b *= 100/255;
+				return hsb;
+			},
+			HSBToRGB = function (hsb) {
+				var rgb = {};
+				var h = Math.round(hsb.h);
+				var s = Math.round(hsb.s*255/100);
+				var v = Math.round(hsb.b*255/100);
+				if(s == 0) {
+					rgb.r = rgb.g = rgb.b = v;
+				} else {
+					var t1 = v;
+					var t2 = (255-s)*v/255;
+					var t3 = (t1-t2)*(h%60)/60;
+					if(h==360) h = 0;
+					if(h<60) {rgb.r=t1;	rgb.b=t2; rgb.g=t2+t3}
+					else if(h<120) {rgb.g=t1; rgb.b=t2;	rgb.r=t1-t3}
+					else if(h<180) {rgb.g=t1; rgb.r=t2;	rgb.b=t2+t3}
+					else if(h<240) {rgb.b=t1; rgb.r=t2;	rgb.g=t1-t3}
+					else if(h<300) {rgb.b=t1; rgb.g=t2;	rgb.r=t2+t3}
+					else if(h<360) {rgb.r=t1; rgb.g=t2;	rgb.b=t1-t3}
+					else {rgb.r=0; rgb.g=0;	rgb.b=0}
+				}
+				return {r:Math.round(rgb.r), g:Math.round(rgb.g), b:Math.round(rgb.b)};
+			},
+			RGBToHex = function (rgb) {
+				var hex = [
+					rgb.r.toString(16),
+					rgb.g.toString(16),
+					rgb.b.toString(16)
+				];
+				$.each(hex, function (nr, val) {
+					if (val.length == 1) {
+						hex[nr] = '0' + val;
+					}
+				});
+				return hex.join('');
+			},
+			HSBToHex = function (hsb) {
+				return RGBToHex(HSBToRGB(hsb));
+			},
+			restoreOriginal = function () {
+				var cal = $(this).parent();
+				var col = cal.data('colorpicker').origColor;
+				cal.data('colorpicker').color = col;
+				fillRGBFields(col, cal.get(0));
+				fillHexFields(col, cal.get(0));
+				fillHSBFields(col, cal.get(0));
+				setSelector(col, cal.get(0));
+				setHue(col, cal.get(0));
+				setNewColor(col, cal.get(0));
+			};
+		return {
+			init: function (opt) {
+				opt = $.extend({}, defaults, opt||{});
+				if (typeof opt.color == 'string') {
+					opt.color = HexToHSB(opt.color);
+				} else if (opt.color.r != undefined && opt.color.g != undefined && opt.color.b != undefined) {
+					opt.color = RGBToHSB(opt.color);
+				} else if (opt.color.h != undefined && opt.color.s != undefined && opt.color.b != undefined) {
+					opt.color = fixHSB(opt.color);
+				} else {
+					return this;
+				}
+				return this.each(function () {
+					if (!$(this).data('colorpickerId')) {
+						var options = $.extend({}, opt);
+						options.origColor = opt.color;
+						var id = 'collorpicker_' + parseInt(Math.random() * 1000);
+						$(this).data('colorpickerId', id);
+						var cal = $(tpl).attr('id', id);
+						if (options.flat) {
+							cal.appendTo(this).show();
+						} else {
+							cal.appendTo(document.body);
+						}
+						options.fields = cal
+											.find('input')
+												.bind('keyup', keyDown)
+												.bind('change', change)
+												.bind('blur', blur)
+												.bind('focus', focus);
+						cal
+							.find('span').bind('mousedown', downIncrement).end()
+							.find('>div.colorpicker_current_color').bind('click', restoreOriginal);
+						options.selector = cal.find('div.colorpicker_color').bind('mousedown', downSelector);
+						options.selectorIndic = options.selector.find('div div');
+						options.el = this;
+						options.hue = cal.find('div.colorpicker_hue div');
+						cal.find('div.colorpicker_hue').bind('mousedown', downHue);
+						options.newColor = cal.find('div.colorpicker_new_color');
+						options.currentColor = cal.find('div.colorpicker_current_color');
+						cal.data('colorpicker', options);
+						cal.find('div.colorpicker_submit')
+							.bind('mouseenter', enterSubmit)
+							.bind('mouseleave', leaveSubmit)
+							.bind('click', clickSubmit);
+						fillRGBFields(options.color, cal.get(0));
+						fillHSBFields(options.color, cal.get(0));
+						fillHexFields(options.color, cal.get(0));
+						setHue(options.color, cal.get(0));
+						setSelector(options.color, cal.get(0));
+						setCurrentColor(options.color, cal.get(0));
+						setNewColor(options.color, cal.get(0));
+						if (options.flat) {
+							cal.css({
+								position: 'relative',
+								display: 'block'
+							});
+						} else {
+							$(this).bind(options.eventName, show);
+						}
+					}
+				});
+			},
+			showPicker: function() {
+				return this.each( function () {
+					if ($(this).data('colorpickerId')) {
+						show.apply(this);
+					}
+				});
+			},
+			hidePicker: function() {
+				return this.each( function () {
+					if ($(this).data('colorpickerId')) {
+						$('#' + $(this).data('colorpickerId')).hide();
+					}
+				});
+			},
+			setColor: function(col) {
+				if (typeof col == 'string') {
+					col = HexToHSB(col);
+				} else if (col.r != undefined && col.g != undefined && col.b != undefined) {
+					col = RGBToHSB(col);
+				} else if (col.h != undefined && col.s != undefined && col.b != undefined) {
+					col = fixHSB(col);
+				} else {
+					return this;
+				}
+				return this.each(function(){
+					if ($(this).data('colorpickerId')) {
+						var cal = $('#' + $(this).data('colorpickerId'));
+						cal.data('colorpicker').color = col;
+						cal.data('colorpicker').origColor = col;
+						fillRGBFields(col, cal.get(0));
+						fillHSBFields(col, cal.get(0));
+						fillHexFields(col, cal.get(0));
+						setHue(col, cal.get(0));
+						setSelector(col, cal.get(0));
+						setCurrentColor(col, cal.get(0));
+						setNewColor(col, cal.get(0));
+					}
+				});
+			}
+		};
+	}();
+	$.fn.extend({
+		ColorPicker: ColorPicker.init,
+		ColorPickerHide: ColorPicker.hidePicker,
+		ColorPickerShow: ColorPicker.showPicker,
+		ColorPickerSetColor: ColorPicker.setColor
+	});
+})(jQuery)
Index: /extensions/CryptograPHP/template/colorpicker/index.php
===================================================================
--- /extensions/CryptograPHP/template/colorpicker/index.php	(revision 12617)
+++ /extensions/CryptograPHP/template/colorpicker/index.php	(revision 12617)
@@ -0,0 +1,30 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery                                    |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2011 Piwigo Team                  http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/CryptograPHP/template/index.php
===================================================================
--- /extensions/CryptograPHP/template/index.php	(revision 12617)
+++ /extensions/CryptograPHP/template/index.php	(revision 12617)
@@ -0,0 +1,30 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery                                    |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2011 Piwigo Team                  http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/CryptograPHP/template/presets/index.php
===================================================================
--- /extensions/CryptograPHP/template/presets/index.php	(revision 12617)
+++ /extensions/CryptograPHP/template/presets/index.php	(revision 12617)
@@ -0,0 +1,30 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery                                    |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2011 Piwigo Team                  http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
