Index: /extensions/grum_plugins_classes-2/ajax.class.inc.php
===================================================================
--- /extensions/grum_plugins_classes-2/ajax.class.inc.php	(revision 3395)
+++ /extensions/grum_plugins_classes-2/ajax.class.inc.php	(revision 3395)
@@ -0,0 +1,56 @@
+<?php
+
+/* -----------------------------------------------------------------------------
+  class name: ajax
+  class version: 2.0
+  date: 2008-07-20
+  ------------------------------------------------------------------------------
+  author: grum at grum.dnsalias.com
+  << May the Little SpaceFrog be with you >>
+  ------------------------------------------------------------------------------
+
+   this classes provides base functions to add ajax.js file into html page ;
+   just instanciate an ajax object, and call return_result
+    $ajax_content_to_be_returned = "...............";
+    $ajax = new ajax();
+    $ajax->return_result($ajax_content_to_be_returned);
+
+    - constructor ajax()
+    - function return_result($str)
+   ---------------------------------------------------------------------- */
+
+
+
+class ajax
+{
+  function ajax()
+  {
+    add_event_handler('loc_end_page_header', array(&$this, 'load_JS'));
+  }
+
+  function load_JS()
+  {
+    global $template;
+
+    $name='plugins/'.basename(dirname(__FILE__)).'/ajax.js';
+
+    $template->append('head_elements', '<script src="'.$name.'" type="text/javascript"></script>');
+  }
+
+  function return_result($str)
+  {
+    //$chars=get_html_translation_table(HTML_ENTITIES, ENT_NOQUOTES);
+    $chars['<']='<';
+    $chars['>']='>';
+    $chars['&']='&';
+    exit(strtr($str, $chars));
+  }
+} //class
+
+/*
+ it's better to make $ajax instance into the plugin object, otherwise an object
+ made here cannot be acceeded..
+*/
+//$ajax=new ajax();
+
+?>
Index: /extensions/grum_plugins_classes-2/ajax.js
===================================================================
--- /extensions/grum_plugins_classes-2/ajax.js	(revision 3395)
+++ /extensions/grum_plugins_classes-2/ajax.js	(revision 3395)
@@ -0,0 +1,104 @@
+/* -----------------------------------------------------------------------------
+  file: ajax.js
+  file version: 1.1.0
+  date: 2008-05-25
+  ------------------------------------------------------------------------------
+  author: grum at grum.dnsalias.com
+  << May the Little SpaceFrog be with you >>
+  ------------------------------------------------------------------------------
+
+   this classes provides base functions to add ajax into html page
+
+    + create_httpobject provide a simple function to create an HTML request to a
+      server ; return an XMLHttpRequest object (or compatible object for IE)
+
+    + tHttpObject is a class providing :
+        - an XMLHttpRequest object
+        - 
+
+  ------------------------------------------------------------------------------
+  HISTORY VERSION
+  v1.0.1  + [create_httpobject] overrideMimeType unknown by IE 7.0 ;
+  v1.1.0  + add create_httpobject2 with mimetype parameter
+              
+   -------------------------------------------------------------------------- */
+
+
+  function create_httpobject(requesttype, charset, ajaxurl, async)
+  {
+    return(create_httpobject2(requesttype, charset, ajaxurl, async, ''));
+  }
+
+  function create_httpobject2(requesttype, charset, ajaxurl, async, mimetype)
+  {
+    if (window.XMLHttpRequest)
+    {
+      // IE7 & FF method
+      http_request = new XMLHttpRequest();
+    }
+    else
+    {
+      //Other IE method.....
+      if (window.ActiveXObject)
+      {
+        try
+        {
+          http_request = new ActiveXObject("Msxml2.XMLHTTP");
+        }
+        catch (e)
+        {
+          try
+          {
+            http_request = new ActiveXObject("Microsoft.XMLHTTP");
+          }
+          catch (e)
+          {
+            window.alert("Your browser is unable to use XMLHTTPRequest");
+          } // try-catch
+        } // try-catch
+      }
+    } // if-else
+
+    if(charset=='') { charset='utf-8'; }
+
+    http_request.onreadystatechange = function() {  };
+    http_request.open(requesttype.toUpperCase(), ajaxurl, async);
+
+    if(mimetype=='')
+    {
+      mimetype='text/html';
+    }
+
+    try
+    {
+      http_request.overrideMimeType(mimetype+'; charset='+charset);
+    }
+    catch(e)
+    {
+    }
+
+    if(requesttype.toUpperCase()=='POST')
+    {
+      http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+    }
+
+    //method to restitute an XML object ; needed for compatibility between FF&IE
+    http_request.XML = httpobject_responseXML;
+
+    return(http_request);
+  }
+
+
+  function httpobject_responseXML()
+  {
+    if (document.implementation && document.implementation.createDocument)
+    {
+      //ff method
+      return(this.responseXML);
+    }
+    else
+    {
+      //ie method
+      return(xmlCreateFromString(this.responseText));
+    }
+  }
Index: /extensions/grum_plugins_classes-2/common_plugin.class.inc.php
===================================================================
--- /extensions/grum_plugins_classes-2/common_plugin.class.inc.php	(revision 3395)
+++ /extensions/grum_plugins_classes-2/common_plugin.class.inc.php	(revision 3395)
@@ -0,0 +1,224 @@
+<?php
+/* -----------------------------------------------------------------------------
+  class name: common_plugin
+  class version: 2.0
+  date: 2008-07-13
+
+  ------------------------------------------------------------------------------
+  Author     : Grum
+    email    : grum@grum.dnsalias.com
+    website  : http://photos.grum.dnsalias.com
+    PWG user : http://forum.phpwebgallery.net/profile.php?id=3706
+
+    << May the Little SpaceFrog be with you ! >>
+  ------------------------------------------------------------------------------
+
+  this class provides base functions to manage a plugin
+  public
+    ADMINISTRATION RELATED
+    - manage()
+    - plugin_admin_menu($menu)
+    INITIALIZATION RELATED
+    - init_events()
+    CONFIG RELATED
+    - get_filelocation()
+    - get_admin_link()
+    - init_config()
+    - load_config()
+    - save_config()
+    - delete_config()
+
+  protected
+    INITIALIZATION RELATED
+    - set_tables_list($list)
+  ------------------------------------------------------------------------------
+  :: HISTORY
+
+  2.0.0     - 2008-07-13
+              migrate to piwigo 2.0 ; use of PHP5 classes possibilities
+
+  --------------------------------------------------------------------------- */
+
+class common_plugin
+{
+  protected $prefixeTable;  // prefixe for tables names
+  protected $page_link; //link to admin page
+  protected $filelocation; //files plugin location on server
+  protected $display_result_ok;
+  protected $display_result_ko;
+  protected $plugin_name;   // used for interface display
+  protected $plugin_name_files;   // used for files
+  protected $plugin_admin_file = "plugin_admin";
+  protected $tables;   // list of all tables names used by plugin
+  private $debug_file; 
+  public $my_config;     // array of config parameters
+
+  /* constructor allows to initialize $prefixeTable value */
+  public function common_plugin($prefixeTable, $filelocation)
+  {
+    $this->debug_file="debug.txt";
+
+    $this->filelocation=$filelocation;
+    $this->prefixeTable=$prefixeTable;
+    $this->page_link="admin.php?page=plugin&section=".basename(dirname($this->filelocation))."/admin/".$this->plugin_admin_file.".php";
+    //$this->page_link=get_admin_plugin_menu_link($filelocation);
+    $this->init_config();
+    $this->display_result_ok="OK";
+    $this->display_result_ko="KO";
+  }
+
+  public function get_filelocation()
+  {
+    return($this->filelocation);
+  }
+
+  public function get_admin_link()
+  {
+    return($this->page_link);
+  }
+
+
+  /* ---------------------------------------------------------------------------
+     CONFIGURATION RELATED FUNCTIONS 
+  --------------------------------------------------------------------------- */
+
+  /* this function initialize var $my_config with default values */
+  public function init_config()
+  {
+    $this->my_config=array();
+  }
+
+  /* load config from CONFIG_TABLE into var $my_config */
+  public function load_config()
+  {
+    $this->init_config();
+    $sql="SELECT value FROM ".CONFIG_TABLE."
+          WHERE param = '".$this->plugin_name_files."_config'";
+    $result=pwg_query($sql);
+    if($result)
+    {
+      $row=mysql_fetch_row($result);
+      if(is_string($row[0])) 
+      {
+        $config = unserialize($row[0]);
+        reset($config);
+        while (list($key, $val) = each($config)) 
+        { $this->my_config[$key] =$val; }
+      }
+    }
+  }
+
+  /* save var $my_config into CONFIG_TABLE */
+  public function save_config()
+  {
+    $sql="REPLACE INTO ".CONFIG_TABLE." 
+           VALUES('".$this->plugin_name_files."_config', '"
+           .serialize($this->my_config)."', '')"; 
+    $result=pwg_query($sql);
+    if($result) 
+    { return true; } 
+    else 
+    { return false; }
+  }
+
+  /* delete config from CONFIG_TABLE */
+  public function delete_config()
+  {
+    $sql="DELETE FROM ".CONFIG_TABLE." 
+          WHERE param='".$this->plugin_name_files."_config'"; 
+    $result=pwg_query($sql);
+    if($result) 
+    { return true; } 
+    else 
+    { return false; }
+  }
+
+  /* ---------------------------------------------------------------------------
+     PLUGIN INITIALIZATION RELATED FUNCTIONS
+  --------------------------------------------------------------------------- */
+
+  /*
+      initialize tables list used by the plugin
+        $list = array('table1', 'table2')
+        $this->tables_list['table1'] = $prefixeTable.$plugin_name.'_table1'
+  */
+  protected function set_tables_list($list)
+  {
+    for($i=0;$i<count($list);$i++)
+    {
+      $this->tables[$list[$i]]=$this->prefixeTable.$this->plugin_name_files.'_'.$list[$i];
+    }
+  }
+
+  /* ---------------------------------------------------------------------------
+     ADMINISTRATOR CONSOLE RELATED FUNCTIONS 
+  --------------------------------------------------------------------------- */
+
+  /* add plugin into administration menu */
+  public function plugin_admin_menu($menu)
+  {
+    array_push($menu,
+               array(
+                  'NAME' => $this->plugin_name,
+                  'URL' => get_admin_plugin_menu_link(dirname($this->filelocation).
+                                '/admin/'.$this->plugin_admin_file.'.php')
+                   ));
+    return $menu;
+  }
+
+  /*
+    manage plugin integration into piwigo's admin interface
+
+    to be surcharged by child's classes
+  */
+  public function manage()
+  {
+  }
+
+  /*
+    intialize plugin's events
+    to be surcharged by child's classes
+  */
+  public function init_events()
+  {
+  }
+
+  protected function debug($text, $rewrite=false)
+  {
+    if($rewrite)
+    {
+      $fhandle=fopen($this->debug_file, "w");
+    }
+    else
+    {
+      $fhandle=fopen($this->debug_file, "a");
+    }
+    
+    if($fhandle)
+    {
+      fwrite($fhandle, date("Y-m-d h:i:s")." [".$this->plugin_name."] : ".print_r($text,true).chr(10));
+      fclose($fhandle);
+    }
+  }
+
+  /*
+    manage infos & errors display
+  */
+  protected function display_result($action_msg, $result)
+  {
+    global $page;
+
+    if($result)
+    {
+      array_push($page['infos'], $action_msg);
+      array_push($page['infos'], $this->display_result_ok);
+    }
+    else
+    {
+      array_push($page['errors'], $action_msg);
+      array_push($page['errors'], $this->display_result_ko);
+    }
+  }
+} //class common_plugin
+
+?>
Index: /extensions/grum_plugins_classes-2/css.class.inc.php
===================================================================
--- /extensions/grum_plugins_classes-2/css.class.inc.php	(revision 3395)
+++ /extensions/grum_plugins_classes-2/css.class.inc.php	(revision 3395)
@@ -0,0 +1,76 @@
+<?php
+
+/* -----------------------------------------------------------------------------
+  class name: css
+  class version: 2.0
+  date: 2008-07-13
+
+  ------------------------------------------------------------------------------
+  Author     : Grum
+    email    : grum@grum.dnsalias.com
+    website  : http://photos.grum.dnsalias.com
+    PWG user : http://forum.phpwebgallery.net/profile.php?id=3706
+
+    << May the Little SpaceFrog be with you ! >>
+  ------------------------------------------------------------------------------
+
+   this classes provides base functions to manage css
+    classe consider that $filename is under plugins/ directory
+
+
+    - constructor css($filename)
+    - (public) function css_file_exists()
+    - (public) function make_CSS($css)
+    - (public) function apply_CSS()
+   ---------------------------------------------------------------------- */
+class css
+{
+  private $filename;
+
+  public function css($filename)
+  {
+    $this->filename=$filename;
+  }
+
+  /*
+    make the css file
+  */
+  public function make_CSS($css)
+  {
+    if($css!="")
+    {
+      $handle=fopen($this->filename, "w");
+      if($handle)
+      {
+        fwrite($handle, $css);
+        fclose($handle);
+      }
+    }
+  }
+
+  /*
+    return true if css file exists
+  */
+  public function css_file_exists()
+  {
+    return(file_exists($this->filename));
+  }
+
+  /*
+    put a link in the template to load the css file
+    this function have to be called in a 'loc_end_page_header' trigger
+
+    if $text="", insert link to css file, otherwise insert directly a <style> markup
+  */
+  public function apply_CSS()
+  {
+    global $template;
+
+    if($this->css_file_exists())
+    {
+      $template->append('head_elements', '<link rel="stylesheet" type="text/css" href="plugins/'.basename(dirname($this->filename))."/".basename($this->filename).'">');
+    }
+  }
+} //class
+
+?>
Index: /extensions/grum_plugins_classes-2/genericjs.class.inc.php
===================================================================
--- /extensions/grum_plugins_classes-2/genericjs.class.inc.php	(revision 3395)
+++ /extensions/grum_plugins_classes-2/genericjs.class.inc.php	(revision 3395)
@@ -0,0 +1,41 @@
+<?php
+
+/* -----------------------------------------------------------------------------
+  class name: genericjs
+  class version: 2.0
+  date: 2008-07-20
+  ------------------------------------------------------------------------------
+  author: grum at grum.dnsalias.com
+  << May the Little SpaceFrog be with you >>
+  ------------------------------------------------------------------------------
+
+   this classes provides base functions to add genericjs.js file into html page
+
+   > see genericjs.js file to know javascript functions added 
+
+    - constructor genericjs()
+   ---------------------------------------------------------------------- */
+
+
+class genericjs
+{
+  function genericjs()
+  {
+    add_event_handler('loc_end_page_header', array(&$this, 'load_JS'));
+  }
+
+  function load_JS()
+  {
+    global $template;
+
+    $name='plugins/'.basename(dirname(__FILE__)).'/genericjs.js';
+
+    $template->append('head_elements', '<script src="'.$name.'" type="text/javascript"></script>');
+
+  }
+
+} //class
+
+$genericjs=new genericjs();
+
+?>
Index: /extensions/grum_plugins_classes-2/genericjs.js
===================================================================
--- /extensions/grum_plugins_classes-2/genericjs.js	(revision 3395)
+++ /extensions/grum_plugins_classes-2/genericjs.js	(revision 3395)
@@ -0,0 +1,49 @@
+/* -----------------------------------------------------------------------------
+  file: genricjs.js
+  file version: 1.0
+  date: 2008-01-02
+  ------------------------------------------------------------------------------
+  author: grum at grum.dnsalias.com
+  << May the Little SpaceFrog be with you >>
+  ------------------------------------------------------------------------------
+
+  this classes provides base functions to make easiest a compliant code with
+  FF2.0 & IE7.0
+  
+
+  ------------------------------------------------------------------------------
+  HISTORY VERSION
+              
+   -------------------------------------------------------------------------- */
+
+
+
+/*
+  this is an implementation of the function <indexOf> to the Array class, as
+  defined in the ECMA-262 standard
+  for more information, see at http://developer.mozilla.org/fr/docs/R%C3%A9f%C3%A9rence_de_JavaScript_1.5_Core:Objets_globaux:Array:indexOf
+
+  not implemented in IE 7.0
+*/
+if (!Array.prototype.indexOf)
+{
+  Array.prototype.indexOf = function(elt /*, from*/)
+  {
+    var len = this.length;
+
+    var from = Number(arguments[1]) || 0;
+    from = (from < 0)
+         ? Math.ceil(from)
+         : Math.floor(from);
+    if (from < 0)
+      from += len;
+
+    for (; from < len; from++)
+    {
+      if (from in this &&
+          this[from] === elt)
+        return from;
+    }
+    return -1;
+  };
+}
Index: /extensions/grum_plugins_classes-2/google_translate.js
===================================================================
--- /extensions/grum_plugins_classes-2/google_translate.js	(revision 3395)
+++ /extensions/grum_plugins_classes-2/google_translate.js	(revision 3395)
@@ -0,0 +1,47 @@
+/* -----------------------------------------------------------------------------
+  file: google_translate.js
+  file version: 2.0.0
+  date: 2008-05-25
+  ------------------------------------------------------------------------------
+  author: grum at grum.dnsalias.com
+  << May the Little SpaceFrog be with you >>
+  ------------------------------------------------------------------------------
+
+   this classes provides base functions to use Google Translate AJAX API
+    >>  http://code.google.com/apis/ajaxlanguage/
+
+  ------------------------------------------------------------------------------
+  HISTORY VERSION
+  v2.0.0  + 
+              
+   -------------------------------------------------------------------------- */
+
+  google.load("language", "1");
+
+
+  var global_google_translate_plugin_objdest;
+  var global_google_translate_plugin_objproperty;
+
+
+  function google_translate(text, pfrom, pto, objdest, objproperty)
+  {
+    global_google_translate_plugin_objdest = objdest;
+    global_google_translate_plugin_objproperty = objproperty;
+    google.language.translate(text, pfrom, pto, google_translate_do);
+  }
+
+  function google_translate_do(result)
+  {
+    if (!result.error)
+    {
+      if(global_google_translate_plugin_objproperty=='value')
+      {
+        global_google_translate_plugin_objdest.value = result.translation;
+      }
+      else if(global_google_translate_plugin_objproperty=='innerHTML')
+      {
+        global_google_translate_plugin_objdest.innerHTML = result.translation;
+      }
+    }    
+  }
+
Index: /extensions/grum_plugins_classes-2/index.php
===================================================================
--- /extensions/grum_plugins_classes-2/index.php	(revision 3395)
+++ /extensions/grum_plugins_classes-2/index.php	(revision 3395)
@@ -0,0 +1,33 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | file          : $Id: index.php 1912 2007-03-16 06:30:07Z rub $
+// | last update   : $Date: 2007-03-16 07:30:07 +0100 (ven, 16 mar 2007) $
+// | last modifier : $Author: rub $
+// | revision      : $Revision: 1912 $
+// +-----------------------------------------------------------------------+
+// | 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/grum_plugins_classes-2/main.inc.php
===================================================================
--- /extensions/grum_plugins_classes-2/main.inc.php	(revision 3395)
+++ /extensions/grum_plugins_classes-2/main.inc.php	(revision 3395)
@@ -0,0 +1,69 @@
+<?php
+/*
+Plugin Name: Grum Plugins Classes.2
+Version: 2.0.2
+Description: Collection de classes partagées entre mes plugins (existants, ou à venir) / Partaged classes between my plugins (actuals or futures)
+Plugin URI: http://phpwebgallery.net/ext/extension_view.php?eid=199
+Author: grum@piwigo.org
+Author URI: http://photos.grum.fr/
+*/
+
+/*
+--------------------------------------------------------------------------------
+  Author     : Grum
+    email    : grum@grum.dnsalias.com
+    website  : http://photos.grum.dnsalias.com
+    PWG user : http://forum.phpwebgallery.net/profile.php?id=3706
+
+    << May the Little SpaceFrog be with you ! >>
+--------------------------------------------------------------------------------
+
+:: HISTORY
+  2.0.0       - 2008/07/20  +convert classes for piwigo 2.0
+  2.0.1       - 2008/12/28  +convert classe tables.class.inc to php5 
+  2.0.2       - 2009/04/26  +add set_options/get_options for pages_navigation class
+                            +add option to set first/prev/next/last textes 
+
+:: TO DO
+
+:: WHAT ? WHY ?
+This plugin doesn't do anything itself. It just provide classes for others plugins.
+
+Classes version for this package
+    ajax.class.php -v2.0 + ajax.js -v1.0.1
+    common_plugin.class.php -v2.0
+    css.class.php -v2.0
+    pages_navigation.class.php -v1.0
+    public_integration.class.php -v1.0
+    tables.class.php -v1.4
+    tabsheets.class.inc.php -v1.1
+    translate.class.inc.php -v2.0.0 + google_translate.js -v2.0.0
+    users_groups.class.inc.php -v1.0
+    genericjs.class.inc.php -v1.0 + genericjs.js -v1.0
+
+See each file to know more about them
+--------------------------------------------------------------------------------
+*/
+
+if(!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+
+define('GPC_DIR' , basename(dirname(__FILE__)));
+define('GPC_PATH' , PHPWG_PLUGINS_PATH . GPC_DIR . '/');
+
+define('GPC_VERSION' , '2.0.2');
+
+/*
+  this function return true if class release if greater than needed by the plugin
+*/
+function checkGPCRelease($major, $minor, $minor2)
+{
+  $release = explode(".", GPC_VERSION);
+  if(($release[0]>=$major)&&($release[1]>=$minor)&&($release[2]>=$minor2))
+  {
+    return(true);
+  }
+  return(false);
+}
+
+
+?>
Index: /extensions/grum_plugins_classes-2/maintain.inc.php
===================================================================
--- /extensions/grum_plugins_classes-2/maintain.inc.php	(revision 3395)
+++ /extensions/grum_plugins_classes-2/maintain.inc.php	(revision 3395)
@@ -0,0 +1,26 @@
+<?php
+
+if (!defined('PHPWG_ROOT_PATH')) { die('Hacking attempt!'); }
+
+// ini_set('error_reporting', E_ALL);
+// ini_set('display_errors', true);
+
+
+function plugin_install($plugin_id, $plugin_version, &$errors)
+{
+}
+
+function plugin_activate($plugin_id, $plugin_version, &$errors)
+{
+}
+
+function plugin_deactivate($plugin_id)
+{
+}
+
+function plugin_uninstall($plugin_id)
+{
+}
+
+
+?>
Index: /extensions/grum_plugins_classes-2/pages_navigation.class.inc.php
===================================================================
--- /extensions/grum_plugins_classes-2/pages_navigation.class.inc.php	(revision 3395)
+++ /extensions/grum_plugins_classes-2/pages_navigation.class.inc.php	(revision 3395)
@@ -0,0 +1,323 @@
+<?php
+
+/* -----------------------------------------------------------------------------
+  class name: pages_navigation
+  class version: 1.1
+  date: 2009-04-26
+  ------------------------------------------------------------------------------
+  author: grum at grum.dnsalias.com
+  << May the Little SpaceFrog be with you >>
+  ------------------------------------------------------------------------------
+
+   this classes provides base functions to manage pages navigation
+
+    - constructor pages_navigation($url)
+    - (public) function set_nb_items($nbitems)
+    - (public) function get_nb_items()
+    - (public) function set_nb_items_per_page($nbitems)
+    - (public) function get_nb_items_per_page()
+    - (public) function get_nb_pages()
+    - (public) function set_current_page($page)
+    - (public) function get_current_page()
+    - (public) function set_base_url($url)
+    - (public) function get_base_url()
+    - (public) function set_options($var)
+    - (public) function get_options()
+    - (public) function make_navigation()
+    - (public) function make_navigation_function()
+    - (private) function calc_nb_pages()
+   ---------------------------------------------------------------------- */
+class pages_navigation
+{
+  protected $nbitems;
+  protected $nbitemsperpages;
+  protected $nbpages;
+  protected $currentpage;
+  protected $baseurl;
+  protected $pagevarurl;
+  protected $options;
+
+  public function pages_navigation()
+  {
+    $this->nbitems=0;
+    $this->nbitemsperpages=0;
+    $this->nbpages=0;
+    $this->currentpage=0;
+    $this->baseurl='';
+    $this->pagevarurl='';
+    $this->options=array(
+      'prev_next' => true,
+      'first_last' => true,
+      'display_all' => true,
+      'number_displayed' => 2, //number of page displayed before and after current page
+      'text_prev' => "&lt;",
+      'text_first' => "&lt;&lt;",
+      'text_next' => "&gt;",
+      'text_last' => "&gt;&gt;",
+    );
+  }
+
+  /*
+    define value for total number of items
+  */
+  public function set_nb_items($nbitems)
+  {
+    if($nbitems!=$this->nbitems)
+    {
+      $this->nbitems=$nbitems;
+      $this->calc_nb_pages();
+    }
+    return($nbitems);
+  }
+
+  public function get_nb_items()
+  {
+    return($nbitems);
+  }
+
+  /*
+    define value for number of items displayed per pages
+  */
+  public function set_nb_items_per_page($nbitems)
+  {
+    if(($nbitems!=$this->nbitemsperpages)&&($nbitems>0))
+    {
+      $this->nbitemsperpages=$nbitems;
+      $this->calc_nb_pages();
+    }
+    return($this->nbitemsperpages);
+  }
+
+  public function get_nb_items_per_page()
+  {
+    return($this->nbitemsperpages);
+  }
+
+  /*
+    return numbers of pages
+  */
+  public function get_nb_pages()
+  {
+    return($this->nbpages);
+  }
+
+  /*
+    define the current page number
+  */
+  public function set_current_page($page)
+  {
+    if(($page!=$this->currentpage)&&($page<=$this->nbpages)&&($page>0))
+    {
+      $this->currentpage=$page;
+    }
+    return($this->currentpage);
+  }
+
+  /*
+    returns the current page number
+  */
+  public function get_current_page()
+  {
+    return($this->currentpage);
+  }
+
+  /*
+    define the value for url
+    ex: "http://mysite.com/admin.php?var1=xxx&var2=xxx"
+  */
+  public function set_base_url($url)
+  {
+    if($url!=$this->baseurl)
+    {
+      $this->baseurl=$url;
+    }
+    return($this->baseurl);
+  }
+
+  public function get_base_url()
+  {
+    return($this->baseurl);
+  }
+
+  /*
+    define the value for variables's name
+    ex: url = "http://mysite.com/admin.php?var1=xxx&var2=xxx"
+        pagevar = "pagenumber"
+    url made is "http://mysite.com/admin.php?var1=xxx&var2=xxx&pagenumber=xxx"
+  */
+  public function set_pagevar_url($var)
+  {
+    if($var!=$this->pagevarurl)
+    {
+      $this->pagevarurl=$var;
+    }
+    return($this->pagevarurl);
+  }
+
+  public function get_pagevar_url()
+  {
+    return($this->pagevarurl);
+  }
+
+  /*
+    define the navigation bar options
+  */
+  public function set_options($var)
+  {
+    if(is_array($var))
+    {
+      foreach($this->options as $key=>$val)
+      {
+        if(isset($var[$key]))
+        {
+          $this->options[$key]=$var[$key];
+        }
+      }
+    }
+    return($this->options);
+  }
+
+  public function get_options()
+  {
+    return($this->options);
+  }
+
+
+  /*
+    returns an html formatted string
+  */
+  public function make_navigation($functionname='')
+  {
+    $text='';
+    if(($this->options['display_all'])||($this->options['number_displayed']>=$this->nbpages))
+    {
+      for($i=1;$i<=$this->nbpages;$i++)
+      {
+        if($i!=$this->currentpage)
+        {
+          if($functionname=='')
+          {
+            $text.='<a href="'.$this->baseurl.'&'.$this->pagevarurl.'='.$i.'">'.$i.'</a>&nbsp;';
+          }
+          else
+          {
+            $text.='<a style="cursor:pointer;" onclick="'.$functionname.'('.$i.');">'.$i.'</a>&nbsp;';
+          }
+        }
+        else
+        {
+          $text.=$i.'&nbsp;';
+        }
+      }
+    }
+    else
+    {
+      for($i=$this->currentpage-$this->options['number_displayed'];$i<=$this->currentpage+$this->options['number_displayed'];$i++)
+      {
+        if(($i>0)&&($i<=$this->nbpages))
+        {
+          if($i!=$this->currentpage)
+          {
+            if($functionname=='')
+            {
+              $text.='<a href="'.$this->baseurl.'&'.$this->pagevarurl.'='.$i.'">'.$i.'</a>&nbsp;';
+            }
+            else
+            {
+              $text.='<a style="cursor:pointer;" onclick="'.$functionname.'('.$i.');">'.$i.'</a>&nbsp;';
+            }
+          }
+          else
+          {
+            $text.=$i.'&nbsp;';
+          }
+        }
+      }
+      if($this->currentpage-$this->options['number_displayed']>0)
+      {
+        $text='&nbsp;...&nbsp;'.$text;
+      }
+      if($this->currentpage+$this->options['number_displayed']<$this->nbpages)
+      {
+        $text.='&nbsp;...&nbsp;';
+      }
+    }
+
+    if($this->options['prev_next'])
+    {
+      $prevp='';
+      $nextp='';
+      if($this->currentpage>1)
+      {
+        if($functionname=='')
+        {
+          $prevp='<a href="'.$this->baseurl.'&'.$this->pagevarurl.'='.($this->currentpage-1).'">&nbsp;'.$this->options['text_prev'].'&nbsp;</a>';
+        }
+        else
+        {
+          $prevp='<a style="cursor:pointer;" onclick="'.$functionname.'('.($this->currentpage-1).');">&nbsp;'.$this->options['text_prev'].'&nbsp;</a>';
+        }
+      }
+      if($this->currentpage<$this->nbpages)
+      {
+        if($functionname=='')
+        {
+          $nextp='<a href="'.$this->baseurl.'&'.$this->pagevarurl.'='.($this->currentpage+1).'">&nbsp;'.$this->options['text_next'].'&nbsp;</a>';
+        }
+        else
+        {
+          $nextp='<a style="cursor:pointer;" onclick="'.$functionname.'('.($this->currentpage+1).');">&nbsp;'.$this->options['text_next'].'&nbsp;</a>';
+        }
+      }
+
+      $text=$prevp.$text.$nextp;
+    }
+
+    if($this->options['first_last'])
+    {
+      $firstp='';
+      $lastp='';
+      if($this->currentpage>1)
+      {
+        if($functionname=='')
+        {
+          $firstp='<a href="'.$this->baseurl.'&'.$this->pagevarurl.'=1">&nbsp;'.$this->options['text_first'].'&nbsp;</a>';
+        }
+        else
+        {
+          $firstp='<a style="cursor:pointer;" onclick="'.$functionname.'(1);">&nbsp;'.$this->options['text_first'].'&nbsp;</a>';
+        }
+      }
+      if($this->currentpage<$this->nbpages)
+      {
+        if($functionname=='')
+        {
+          $lastp='<a href="'.$this->baseurl.'&'.$this->pagevarurl.'='.$this->nbpages.'">&nbsp;'.$this->options['text_last'].'&nbsp;</a>';
+        }
+        else
+        {
+          $lastp='<a style="cursor:pointer;" onclick="'.$functionname.'('.$this->nbpages.');">&nbsp;'.$this->options['text_last'].'&nbsp;</a>';
+        }
+      }
+
+      $text=$firstp.$text.$lastp;
+    }
+
+    return($text);
+  }
+
+
+  /*
+    calculate the number of pages...
+  */
+  public function calc_nb_pages()
+  {
+    if($this->nbitemsperpages>0)
+    {
+      $this->nbpages=ceil($this->nbitems/$this->nbitemsperpages);
+    }
+  }
+
+} //class
+
+?>
Index: /extensions/grum_plugins_classes-2/public_integration.class.inc.php
===================================================================
--- /extensions/grum_plugins_classes-2/public_integration.class.inc.php	(revision 3395)
+++ /extensions/grum_plugins_classes-2/public_integration.class.inc.php	(revision 3395)
@@ -0,0 +1,78 @@
+<?php 
+
+/* -----------------------------------------------------------------------------
+  class name: public_integration
+  class version: 1.0
+  date: 2007-10-31
+  ------------------------------------------------------------------------------
+  author: grum at grum.dnsalias.com
+  << May the Little SpaceFrog be with you >>
+  ------------------------------------------------------------------------------
+  
+  this class provides base functions to manage an integration into main index
+  page
+  the class use plugin MenuBarManager function if installed
+
+  - constructor public_integration($section)
+  - (public) function init_events()
+  - (public) function set_callback_page_function($value)
+  - (private) function init_section()
+  - (private) function call_page()
+
+  use init_events() function to initialize needed triggers for updating menubar
+
+  the "callback_page_function" is called everytime a specific page is displayed
+
+----------------------------------------------------------------------------- */
+
+class public_integration
+{
+  var $section;         //section applied to the page viewed
+  var $callback_page_function;        //called function to display page
+
+  function public_integration($section)
+  {
+    $this->section=$section;
+    $this->callback_page_function='';
+  }
+
+  //initialize events to manage menu & page integration
+  function init_events()
+  {
+    add_event_handler('loc_end_section_init', array(&$this, 'init_section'));
+    add_event_handler('loc_end_index', array(&$this, 'call_page'));
+  }
+  
+  function set_callback_page_function($value)
+  {
+    $this->callback_page_function=$value;
+  }
+
+  /*
+    init section
+  */
+  function init_section()
+  {
+    global $tokens, $page;
+    
+    if ($tokens[0] == $this->section)
+    { $page['section'] = $this->section; }
+  }
+
+  /*
+    loads a page
+  */
+  function call_page()
+  {
+    global $page, $user;
+
+    if($page['section'] == $this->section)
+    {
+      @call_user_func($this->callback_page_function);
+    }
+  }
+
+} //class public_integration
+
+
+?>
Index: /extensions/grum_plugins_classes-2/tables.class.inc.php
===================================================================
--- /extensions/grum_plugins_classes-2/tables.class.inc.php	(revision 3395)
+++ /extensions/grum_plugins_classes-2/tables.class.inc.php	(revision 3395)
@@ -0,0 +1,454 @@
+<?php 
+
+/* -----------------------------------------------------------------------------
+  class name: manage_tables
+  class version: 1.4
+  date: 2008-12-28
+  ------------------------------------------------------------------------------
+  author: grum at grum.dnsalias.com
+  << May the Little SpaceFrog be with you >>
+  ------------------------------------------------------------------------------
+  
+  this class provides base functions to manage tables while plugin installation
+    - constructor manage_tables($tables)
+    - (public) function create_tables($tables_def)
+    - (public) function update_tables_fields($tables_alteration)
+    - (public) function drop_tables()
+    - (public) function rename_tables($list)  -v1.1
+    - (public) function tables_exists()  -v1.1
+    - (public) function export($filename, $options, $tables, $infos)  -v1.3
+    - (public) function multi_queries($queries)  -v1.3
+    - (public) function import($filename)  -v1.3
+
+  ------------------------------------------------------------------------------
+  v1.1              + add rename_tables($list) function
+                    + add tables_exists() function
+  v1.2              + add export($filename, $options, $tables) function
+  v1.3              + modify export($filename, $options, $tables, $infos, $resultboolean) function
+                        + new parameters '$infos' allows to add some information on the
+                          exported file
+                        + add 'delete' and 'colnames' options
+                        + $resultbooelan option for return
+                    + add multi_queries($queries) function
+                    + add import($filename) function 
+  v1.4 - 2009-03-01 + PHP5 migration (use of public/protected/private)
+                    + export => DROP TABLE IF EXISTS
+                    + import => if DROP TABLE without IF EXISTS, add IF EXISTS
+
+   -------------------------------------------------------------------------- */
+class manage_tables
+{
+  public $tables;    //array of tables names
+  public $version = "1.4";
+
+  public function manage_tables($tables)
+  {
+    $this->tables = $tables;
+  }
+  
+  /* 
+      create tables
+      $tables_def is an array of SQL CREATE queries
+
+      return true if everything is ok, otherwise tablename 
+  */
+  public function create_tables($tables_def)
+  {
+    //deleting tables if exists
+    $this->drop_tables();
+
+    for($i=0;$i<count($tables_def);$i++)
+    {
+      $result=pwg_query($tables_def[$i]);
+      if(!$result)
+      {
+        //if an error occurs, deleting created tables
+        $this->drop_tables();
+        return(false);
+      }
+    }
+    return(true);
+  }
+
+  /* update tables definition 
+     $tables_alteration : array of arrays
+      example :
+      $tables_alteration['table1']=array(
+        "attribute1" => " ADD COLUMN `attribute1` text null default ''",
+        "attribute2" => " ADD COLUMN `attribute2` text null default ''"));
+      $tables_alteration['table2']=array(
+        "attribute1" => " ADD COLUMN `attribute1` text null default ''",
+        "attribute2" => " ADD COLUMN `attribute2` text null default ''"));
+
+      return true if no error, otherwise return table.fields of error 
+  */
+  public function update_tables_fields($tables_alteration)
+  {
+    if(!is_array($tables_alteration))
+    {
+      return('');
+    }
+
+    reset($tables_alteration);
+    while (list($key, $val) = each($tables_alteration))
+    {
+      $sql="SHOW COLUMNS FROM $key";
+      $result=pwg_query($sql);
+      if($result)
+      {
+        $columns=array();
+        while($row=mysql_fetch_assoc($result))
+        { 
+          array_push($columns, $row['Field']); 
+        }
+
+        reset($val);
+        while (list($attname, $sql) = each($val))
+        {
+          if(!in_array($attname, $columns))
+          {
+            $result=pwg_query("ALTER TABLE `$key` ".$sql);
+            if(!$result)
+            {
+              return($key.".".$attname);
+            }
+          }
+        }
+      }
+    }
+    return(true);
+  }
+
+
+  /* 
+      delete tables listed in $this->tables_list
+  */
+  public function drop_tables()
+  {
+    foreach($this->tables as $key => $table_name)
+    {
+      $sql="DROP TABLE IF EXISTS ".$table_name;
+      $result=pwg_query($sql);
+    }
+  }
+
+  /*
+      rename tables name of list
+        $list is an array('old_name' => 'new_name')
+      return true if ok, else old table name
+  */
+  public function rename_tables($list)
+  {
+    $tmplist=array_flip($this->tables);
+    foreach($list as $key => $val)
+    {
+      if(isset($tmplist[$key]))
+      {
+        $this->tables[$tmplist[$key]] = $val;
+        $sql="ALTER TABLE `$key` RENAME TO `$val`";
+        if(!pwg_query($sql))
+        {
+          return($key);
+        }
+      }
+      else
+      {
+        return($key);
+      }
+    }
+    return(true);
+  }
+
+  /*
+    return true if all listed tables exists
+  */
+  public function tables_exists()
+  {
+    $list=array_flip($this->tables);
+    $sql="SHOW TABLES";
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=mysql_fetch_row($result))
+      {
+        if(isset($list[$row[0]]))
+        {
+          array_splice($list, $row[0],1);
+        }
+      }
+    }
+    if(count($list)>0)
+    {
+      return(false);
+    }
+    else
+    {
+      return(true);
+    }
+  }
+
+  /*
+    export all tables as SQL in a text file
+
+    each query end with a " -- EOQ" ; it's just a method to increase parsing for
+    import function
+
+      $filename : name of the file
+      $options : array of options like
+                    array(
+                      'drop' => true/false,  //add DROP TABLE statements
+                      'create' => true/false,  //add CREATE TABLE statements
+                      'insert' => true/false,  //add INSERT statements
+                      'delete' => true/false, //add delete statements
+                      'colnames' => true/false, //add columns names for inserts statements
+                    )
+      $tables : array of tables names to export
+                    array('tablename1', 'tablenamen', 'tablename3', ...)
+                  if empty, assume that all tables have to be exported
+      $infos : additional info written in exported file (as comment)
+      $resultboolean : if true, result is true/false ; 
+                       if false, if result, return a string with nfo about export
+  */
+  public function export($filename, $options=array(), $tables=array(), $infos="", $resultboolean=true)
+  {
+    $defaultopt=array(
+      'drop' => true,
+      'create' => true,
+      'insert' => true,
+      'delete' => false,
+      'colnames' => false
+    );
+
+    if(!isset($options['drop']))
+    {
+      $options['drop']=$defaultopt['drop'];
+    }
+    if(!isset($options['create']))
+    {
+      $options['create']=$defaultopt['create'];
+    }
+    if(!isset($options['insert']))
+    {
+      $options['insert']=$defaultopt['insert'];
+    }
+    if(!isset($options['delete']))
+    {
+      $options['delete']=$defaultopt['delete'];
+    }
+    if(!isset($options['colnames']))
+    {
+      $options['colnames']=$defaultopt['colnames'];
+    }
+    if(count($tables)==0)
+    {
+      $tables=$this->tables;
+    }
+
+    $resultnfo='';
+
+    $returned=true;
+    $text='
+-- ***************************************************************              -- EOQ
+-- * SQL export made with Grum Plugins Classes (Export tool r'.$this->version.')         -- EOQ
+-- * Export date    :'.date('Y-m-d H:i:s').'                                    -- EOQ
+-- * Export options :';
+if($options['drop']){$text.=' [drop]';}
+if($options['delete']){$text.=' [delete]';}
+if($options['create']){$text.=' [create]';}
+if($options['insert']){$text.=' [insert]';}
+if($options['colnames']){$text.=' [colnames]';}
+$text.="                            -- EOQ";
+if($infos!="")
+{
+  $text.='
+-- * '.$infos." -- EOQ";
+}
+$text.='
+-- ***************************************************************              -- EOQ
+
+';
+    foreach($tables as $key => $val)
+    {
+      $countelems=0;
+
+      $text.="
+
+-- ***************************************************************              -- EOQ
+-- * Statements for ".$this->tables[$key]." table                               -- EOQ
+-- ***************************************************************              -- EOQ
+";
+
+      if($options['drop'])
+      {
+        $text.=sprintf("DROP TABLE IF EXISTS `%s`; -- EOQ\n", $this->tables[$key]);
+      }
+
+      if($options['delete'])
+      {
+        $text.=sprintf("DELETE FROM `%s`; -- EOQ\n", $this->tables[$key]);
+      }
+
+      if($options['create'])
+      {
+        $sql='SHOW CREATE TABLE '.$this->tables[$key];
+        $result=pwg_query($sql);
+        if($result)
+        {
+          while($row=mysql_fetch_row($result))
+          {
+            $text.=sprintf("%s; -- EOQ\n", $row[1]);
+          }
+        }
+        else
+        {
+          $returned=false;
+        }
+      }
+
+      if($options['insert'])
+      {
+        $colnames="";
+        if($options['colnames'])
+        {
+          $sql='SHOW COLUMNS FROM `'.$this->tables[$key].'`';
+          $result=pwg_query($sql);
+          if($result)
+          {
+            $tmp=array();
+            while($row=mysql_fetch_row($result))
+            {
+              $tmp[]=$row[0];
+            }
+          }
+          $colnames='('.implode(',', $tmp).')';
+        }
+    
+        $sql='SELECT * FROM '.$this->tables[$key];
+        $result=pwg_query($sql);
+        if($result)
+        {
+          while($row=mysql_fetch_row($result))
+          {
+            foreach($row as $key2 => $val2)
+            {
+              $row[$key2]="'".addslashes($val2)."'";
+            }
+            $text.=sprintf("INSERT INTO `%s` %s VALUES(%s); -- EOQ\n", $this->tables[$key], $colnames, implode(', ', $row));
+            $countelems++;
+          }
+        }
+        else
+        {
+          $returned=false;
+        }
+        $resultnfo.=$key.':'.$countelems.'@';
+      }
+    }
+    $fhandle=fopen($filename, 'wb');
+    if($fhandle)
+    {
+      fwrite($fhandle, $text);
+      fclose($fhandle);
+    }
+    else
+    {
+      $returned=false;
+    }
+    if(($resultboolean==false)&&($returned))
+    {
+      $returned=$resultnfo;
+    }
+    return($returned);
+  }
+
+  /*
+    import an .sql file
+      $filename : name of the file
+      'errors' : -1 file don't exists
+                 -2 can't open file
+  */
+  public function import($filename)
+  {
+    $return = array(
+      'numinsert'=>0,
+      'numdelete'=>0,
+      'numdrop'=>0,
+      'numcreate'=>0,
+      'errors'=>array(),
+      'total_ok'=>0
+    );
+
+    if(file_exists($filename))
+    {
+      $fhandle=fopen($filename, 'r');
+      if($fhandle)
+      {
+        $queries=fread($fhandle, filesize($filename));
+        fclose($fhandle);
+        $return=$this->multi_queries($queries);
+      }
+      else
+      {
+        $return['errors']=-2;
+      }
+    }
+    else
+    {
+      $return['errors']=-1;
+    }
+    return($return);
+  }
+
+  /*
+    execute multiple query
+      each query have to be separated by a "-- EOQ\n"
+      
+      $queries : sql queries
+  */
+  public function multi_queries($queries)
+  {
+    $queries_list=preg_split(
+      '/\s*;?\s*--\s+EOQ[\r\n]{1}/i', $queries, -1, PREG_SPLIT_NO_EMPTY);
+
+    $return = array(
+      'numinsert'=>0,
+      'numdelete'=>0,
+      'numdrop'=>0,
+      'numcreate'=>0,
+      'errors'=>array(),
+      'total_ok'=>0
+    );
+
+    $i=0;
+    foreach($queries_list as $key => $sql)
+    {
+      $i++;
+
+      // replace " DROP TABLE `xxxx`; " by " DROP TABLE IF EXISTS `xxxx`; "
+      $sql=preg_replace("/(.*DROP TABLE)\s*(`.*)/i", "$1 IF EXISTS $2", $sql);
+
+      @$result=pwg_query($sql);
+      if($result)
+      {
+        $return['total_ok']++;
+        if(preg_match('/\b[\s]*insert[\s]+/i', $sql)>0)
+        {$return['numinsert']++;}
+        elseif(preg_match('/\b[\s]*drop[\s]+/i', $sql)>0)
+        {$return['numdrop']++;}
+        elseif(preg_match('/\b[\s]*delete[\s]+/i', $sql)>0)
+        {$return['numdelete']++;}
+        elseif(preg_match('/\b[\s]*create[\s]+/i',$sql)>0)
+        {$return['numcreate']++;}
+      }
+      else
+      {
+        array_push($return['errors'], '['.$i.'] '.$sql);
+      }
+    }
+    return($return);
+  }
+
+} //class
+
+
+?>
Index: /extensions/grum_plugins_classes-2/translate.class.inc.php
===================================================================
--- /extensions/grum_plugins_classes-2/translate.class.inc.php	(revision 3395)
+++ /extensions/grum_plugins_classes-2/translate.class.inc.php	(revision 3395)
@@ -0,0 +1,192 @@
+<?php
+
+/* -----------------------------------------------------------------------------
+  class name: translate
+  class version: 2.0.1
+  date: 2008-05-25
+  ------------------------------------------------------------------------------
+  author: grum at grum.dnsalias.com
+  << May the Little SpaceFrog be with you >>
+  ------------------------------------------------------------------------------
+
+   this classes provides base functions to manage call to "translate.google.com"
+
+   release 2.x use durect call to Google Translate AJAX API, so all functions
+    from PHP class are removed (except for "can_translate")
+   class call API in HTML header, and provide a .js file manage API call
+
+    - constructor translate()
+    - (public) function can_translate($from, $to)   //v1.1
+
+  version 1.1.1
+    - google have changed HTML code for translation page ; change search string of translation result
+    - bug corrected : if language given with uppercase, force them to lowercase
+  version 2.0.0
+    - use of Google Translate javascript API
+        >>  http://code.google.com/apis/ajaxlanguage/
+
+   ---------------------------------------------------------------------- */
+class translate
+{
+  protected $language_list;
+
+  public function translate()
+  {
+    //alloweds from->to transations languages
+    $this->language_list=array_flip(
+      array(
+        'ar', //arabic
+        'bg', //Bulgarian
+        'zh', //Chinese (simplified)
+        'hr', //Croatian
+        'cs', //Czech
+        'da', //Danish
+        "nl", //Dutch
+        'en', //English
+        'fi', //Finnish
+        "fr", //French
+        "de", //German
+        "el", //Greek
+        'hi', //Hindi
+        "it", //Italian
+        "ja", //Japanese
+        "ko", //Korean
+        'no', //Norwegian
+        'pl', //Polish
+        "pt", //Portuguese
+        'ro', //Romanian
+        "ru", //Russian
+        "es", //Spanish
+        'sv' //Swedish
+      )
+    );
+    add_event_handler('loc_end_page_header', array(&$this, 'load_JS'));
+  }
+
+  public function load_JS()
+  {
+    global $template;
+
+    $googleload='
+<script type="text/javascript" src="http://www.google.com/jsapi"></script>
+<script type="text/javascript" src="plugins/'.basename(dirname(__FILE__)).'/google_translate.js"></script>';
+
+    $template->append('head_elements', $googleload);
+
+
+  }
+
+  public function can_translate($from, $to)
+  {
+    if(isset($this->language_list[strtolower($from)])&&isset($this->language_list[strtolower($to)]))
+    {
+      return(true);
+    }
+    else
+    {
+      return(false);
+    }
+  }
+  
+
+/*
+  theses methods are removed for direct use of the Google AJAX API (better choice for
+  performance)
+
+  how to :
+    create one instance of this classe
+    classe can be used by server to know authorized language to be translated
+    all translations have to be made with javascript functions
+
+  =8<===========================================================================
+
+  function set_languages($lang)
+  {
+    $pair=explode('|', strtolower($lang));
+
+    if(isset($this->language_list[$pair[0]])&&isset($this->language_list[$pair[1]]))
+    {
+      $this->from_to_lang=strtolower($lang);
+    }
+    return($this->from_to_lang);
+  }
+
+  function get_languages()
+  {
+    return($this->from_to_lang);
+  }
+
+  function set_input_charset($charset)
+  {
+    $this->input_charset=$charset;
+  }
+
+  function get_input_charset($charset)
+  {
+    return($this->input_charset);
+  }
+
+  function set_output_charset($charset)
+  {
+    $this->output_charset=$charset;
+  }
+
+  function get_output_charset($charset)
+  {
+    return($this->output_charset);
+  }
+
+  function do_translation($text)
+  {
+    if(ini_get('allow_url_fopen')!="1")
+    {
+      return("");
+    }
+
+    $req="http://translate.google.com/translate_t?text=".urlencode($text).
+         "&langpair=".strtolower($this->from_to_lang);
+    if($this->input_charset!="")
+    {
+      $req.="&ie=".$this->input_charset;
+    }
+    if($this->output_charset!="")
+    {
+      $req.="&oe=".$this->output_charset;
+    }
+
+    $handle=fopen($req, "r");
+    if($handle)
+    {
+      $contents="";
+      while (!feof($handle))
+      {
+        $contents .= fread($handle, 4196);
+      }
+      fclose($handle);
+
+      $search="<div id=result_box dir=\"ltr\">";
+      $p = strpos($contents, $search);
+      if($p>0)
+      {
+        $contents=substr($contents, $p+strlen($search));
+        $search="</div>";
+        $p = strpos($contents, $search);
+        $contents=substr($contents, 0, $p);
+      }
+      else
+      {
+        $contents="";
+      }
+
+      return($contents);
+    }
+    else
+    {
+      return("");
+    }
+  }
+*/
+
+} //class
+
+?>
Index: /extensions/grum_plugins_classes-2/users_groups.class.inc.php
===================================================================
--- /extensions/grum_plugins_classes-2/users_groups.class.inc.php	(revision 3395)
+++ /extensions/grum_plugins_classes-2/users_groups.class.inc.php	(revision 3395)
@@ -0,0 +1,290 @@
+<?php
+
+/* -----------------------------------------------------------------------------
+  class name: allowed_access, groups, users
+  class version: 1.0
+  date: 2007-10-31
+  ------------------------------------------------------------------------------
+  author: grum at grum.dnsalias.com
+  << May the Little SpaceFrog be with you >>
+  ------------------------------------------------------------------------------
+
+   this classes provides base functions to manage users/groups access
+  groups and users classes extends allowed_access classes
+
+    - constructor allowed_access($alloweds="")
+    - constructor groups($alloweds="")
+    - constructor users($alloweds="")
+    - (public) function get_list()
+    - (public) function set_allowed($id, $allowed)
+    - (public) function set_alloweds()
+    - (public) function get_alloweds($return_type)
+    - (public) function is_allowed($id)
+    - (public) function html_view($sep=", ", $empty="")
+    - (public) function html_form($basename)
+    - (private) function init_list()
+   ---------------------------------------------------------------------- */
+class allowed_access
+{
+  var $access_list;
+
+  /*
+    constructor initialize the groups_list
+  */
+  function allowed_access($alloweds = "")
+  {
+    $this->init_list();
+    $this->set_alloweds($alloweds);
+  }
+
+  /*
+    initialize the groups list
+  */
+  function init_list()
+  {
+    $this->access_list=array();
+  }
+
+  /*
+    returns list (as an array)
+  */
+  function get_list()
+  {
+    return($this->access_list);
+  }
+
+  /*
+    set element an allowed state
+  */
+  function set_allowed($id, $allowed)
+  {
+    if(isset($this->access_list[$id]))
+    {
+      $this->access_list[$id]['allowed']=$allowed;
+    }
+  }
+
+  /*
+    set a group enabled/disabled state
+  */
+  function set_state($id, $enabled)
+  {
+    if(isset($this->access_list[$id]))
+    {
+      $this->access_list[$id]['enabled']=$enabled;
+    }
+  }
+
+  /*
+    set alloweds list
+    $list is string of id, separated with "/"
+  */
+  function set_alloweds($list)
+  {
+    $alloweds=explode("/", $list);
+    $alloweds=array_flip($alloweds);
+    foreach($this->access_list as $key => $val)
+    {
+      if(isset($alloweds[$key]))
+      {
+        $this->access_list[$key]['allowed']=true;
+      }
+      else
+      {
+        $this->access_list[$key]['allowed']=false;
+      }
+    }
+  }
+
+  /*
+    get alloweds list
+    return a string of groups, separated with "/"
+  */
+  function get_alloweds($return_type = 'name')
+  {
+    $returned="";
+    foreach($this->access_list as $key => $val)
+    {
+      if($val['allowed'])
+      { $returned.=$val[$return_type]."/"; }
+    }
+    return($returned);
+  }
+
+
+  /*
+    returns true if is allowed
+  */
+  function is_allowed($id)
+  {
+    if(isset($this->access_list[$id]))
+    { return($this->access_list[$id]['allowed']); }
+    else
+    { return(false); }
+  }
+
+  /*
+    returns true if all or one is allowed
+      ids is an array
+  */
+  function are_allowed($ids, $all=false)
+  {
+    foreach($ids as $val)
+    {
+      if($all)
+      {
+        if(!$this->is_allowed($val))
+        {
+          return(false);
+        }
+      }
+      else
+      {
+        if($this->is_allowed($val))
+        {
+          return(true);
+        }        
+      }
+    }
+    return(false);
+  }
+
+  /*
+    returns an HTML list with label rather than id
+  */
+  function html_view($sep=", ", $empty="")
+  {
+    $returned="";
+    foreach($this->access_list as $key => $val)
+    {
+      if($val['allowed'])
+      {
+        if($returned!="")
+        {
+          $returned.=$sep;
+        }
+        $returned.=$val['name'];
+      }
+    }
+    if($returned=="")
+    {
+      $returned=$empty;
+    }
+    return($returned);
+  }
+  /*
+    returns a generic HTML form to manage the groups access
+  */
+  function html_form($basename)
+  {
+    /*
+    <!-- BEGIN allowed_group_row -->
+    <label><input type="checkbox" name="fmypolls_att_allowed_groups_{allowed_group_row.ID}" {allowed_group_row.CHECKED}/>&nbsp;{allowed_group_row.NAME}</label>
+    <!-- END allowed_group_row -->
+    */
+    $text='';
+    foreach($this->access_list as $key => $val)
+    {
+      if($val['allowed'])
+      {
+        $checked=' checked';
+      }
+      else
+      {
+        $checked='';
+      }
+
+      if($val['enabled'])
+      {
+        $enabled='';
+      }
+      else
+      {
+        $enabled=' disabled';
+      }
+
+      $text.='<label><input type="checkbox" name="'.$basename.$val['id'].'" '.$checked.$enabled.'/>
+          &nbsp;'.$val['name'].'</label>&nbsp;';
+    }
+    return($text);
+  }
+} //allowed_access
+
+
+
+
+
+
+
+
+/* ----------------------------------------------------------------------
+   this class provides base functions to manage groups access
+    init_list redefined to initialize access_list from database GROUPS
+   ---------------------------------------------------------------------- */
+class groups extends allowed_access
+{
+  /*
+    initialize the groups list
+  */
+  function init_list()
+  {
+    $this->access_list=array();
+    $sql="SELECT id, name FROM ".GROUPS_TABLE." ORDER BY name";
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=mysql_fetch_assoc($result))
+      {
+        $this->access_list[$row['id']] =
+                   array('id' => $row['id'],
+                         'name' => $row['name'],
+                         'allowed' => false,
+                         'enabled' => true);
+      }
+    }
+  }
+}
+
+
+
+
+
+
+
+
+/* -----------------------------------------------------------------------------
+   this class provides base functions to manage users access
+----------------------------------------------------------------------------- */
+class users extends allowed_access
+{
+  /*
+    constructor
+  */
+  function users($alloweds = "")
+  {
+    parent::allowed_access($alloweds);
+    $this->set_state('admin', false);
+    $this->set_allowed('admin', true);
+  }
+
+  /*
+    initialize the groups list
+  */
+  function init_list()
+  {
+    $users_list = array('guest', 'generic', 'normal', 'admin');
+    $this->access_list=array();
+    foreach($users_list as $val)
+    {
+      $this->access_list[$val] =
+                  array('id' => $val,
+                        'name' => l10n('user_status_'.$val),
+                        'allowed' => false,
+                        'enabled' => true);
+    }
+  }
+} //class users
+
+
+
+?>
