Index: /branches/1.4/about.php
===================================================================
--- /branches/1.4/about.php	(revision 3249)
+++ /branches/1.4/about.php	(revision 3249)
@@ -0,0 +1,50 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+//----------------------------------------------------------- include
+define('PHPWG_ROOT_PATH','./');
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+//----------------------------------------------------- template initialization
+//
+// Start output of page
+//
+$title= $lang['about_page_title'];
+include(PHPWG_ROOT_PATH.'include/page_header.php');
+
+$template->set_filenames(array('about'=>'about.tpl'));
+$template->assign_vars(array(
+	'PAGE_TITLE' => $title,
+	'L_ABOUT' => $lang['about_message'],
+	'L_RETURN' =>  $lang['home'],
+	'L_RETURN_HINT' =>  $lang['home_hint'],  
+	'U_RETURN' => add_session_id(PHPWG_ROOT_PATH.'category.php?'.$_SERVER['QUERY_STRING'])
+	)
+	);
+
+$template->parse('about');
+include(PHPWG_ROOT_PATH.'include/page_tail.php');
+?>
Index: /branches/1.4/admin.php
===================================================================
--- /branches/1.4/admin.php	(revision 3249)
+++ /branches/1.4/admin.php	(revision 3249)
@@ -0,0 +1,269 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+//----------------------------------------------------------- include
+define('PHPWG_ROOT_PATH','./');
+define('IN_ADMIN', true);
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+include_once( PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php' );
+//--------------------------------------- validating page and creation of title
+$page_valide = false;
+$title = '';
+$username='';
+if (isset($_POST['username']))
+{
+  $username = $_POST['username'];
+}
+else if (isset($_POST['userid']))
+{
+  $username = get_username($_POST['userid']);
+}
+else if (isset($_GET['user_id']))
+{
+  $username = get_username($_GET['user_id']);
+}
+
+if (isset( $_GET['page'] ))
+switch ( $_GET['page'] )
+{
+ case 'user_list':
+   $title = $lang['title_liste_users'];   $page_valide = true; break;
+ case 'profile':
+   $title = $lang['title_user_modify'];
+	 $page_valide = true; 
+	 break;
+ case 'user_perm':
+   $title = $lang['title_user_perm'].' '.$username;
+   $page_valide = true; break;
+ case 'group_list' :
+   $title = $lang['title_groups'];        $page_valide = true; break;
+ case 'group_perm' :
+   /*if ( !is_numeric( $_GET['group_id'] ) ) $_GET['group_id'] = -1;
+   $query = 'SELECT name FROM '.GROUPS_TABLE;
+   $query.= ' WHERE id = '.$_GET['group_id'];
+   $query.= ';';
+   $result = pwg_query( $query );
+   if ( mysql_num_rows( $result ) > 0 )
+   {
+     $row = mysql_fetch_array( $result );*/
+     $title = $lang['title_group_perm'];//.' "'.$row['name'].'"';
+     $page_valide = true;
+   /*}
+   else
+   {
+     $page_valide = false;
+   }*/
+   break;
+ case 'stats':
+   $title = $lang['title_history'];       $page_valide = true; break;
+ case 'update':
+   $title = $lang['title_update'];        $page_valide = true; break;
+ case 'configuration':
+   $title = $lang['title_configuration']; $page_valide = true; break;
+ case 'admin_phpinfo':
+   $title = $lang['phpinfos']; $page_valide = true; break;
+ case 'help':
+   $title = $lang['title_instructions'];  $page_valide = true; break;
+ case 'cat_perm':
+   $title = $lang['title_cat_perm'];
+   if ( isset( $_GET['cat_id'] ) )
+   {
+     check_cat_id( $_GET['cat_id'] );
+     if ( isset( $page['cat'] ) and is_numeric( $page['cat'] ) )
+     {
+       $result = get_cat_info( $page['cat'] );
+       $name = get_cat_display_name($result['name'], '');
+       $title.= ' "'.$name.'"';
+     }
+   }
+   $page_valide = true;
+   break;
+ case 'cat_list':
+   $title = $lang['title_categories'];    $page_valide = true; break;
+ case 'cat_modify':
+   $title = $lang['title_edit_cat'];      $page_valide = true; break;
+ case 'infos_images':
+   $title = $lang['title_info_images'];   $page_valide = true; break;
+ case 'waiting':
+   $title = $lang['title_waiting'];       $page_valide = true; break;
+ case 'thumbnail':
+   $title = $lang['title_thumbnails'];
+   if ( isset( $_GET['dir'] ) )
+   {
+     $title.= ' '.$lang['title_thumbnails_2'].' <span class="titreImg">';
+     // $_GET['dir'] contains :
+     // ./galleries/vieux_lyon ou
+     // ./galleries/vieux_lyon/visite ou
+     // ./galleries/vieux_lyon/visite/truc ...
+     $dir = explode( "/", $_GET['dir'] );
+     $title.= $dir[2];
+     for ( $i = 2; $i < sizeof( $dir ) - 1; $i++ )
+     {
+       $title.= ' &gt; '.$dir[$i+1];
+     }
+     $title.= "</span>";
+   }
+   $page_valide = true;
+   break;
+ case 'comments' :
+   $title = $lang['title_comments'];
+   $page_valide = true;
+   break;
+ case 'picture_modify' :
+   $title = $lang['title_picmod'];
+   $page_valide = true;
+   break;
+ case 'remote_site' :
+ {
+   $title = $lang['remote_sites'];
+   $page_valide = true;
+   break;
+ }
+ case 'cat_options' :
+ {
+   $title = $lang['title_cat_options'];
+   $page_valide = true;
+   break;
+ }
+ default:
+   $title = $lang['title_default']; break;
+}
+if ( $title == '' ) $title = $lang['title_default'];
+
+// waiting
+$query = 'SELECT id FROM '.WAITING_TABLE;
+$query.= " WHERE validated='false'";
+$query.= ';';
+$result = pwg_query( $query );
+$nb_waiting = '';
+if ( mysql_num_rows( $result ) > 0 )
+{
+  $nb_waiting =  ' [ '.mysql_num_rows( $result ).' ]';
+}
+// comments
+$query = 'SELECT id FROM '.COMMENTS_TABLE;
+$query.= " WHERE validated='false'";
+$query.= ';';
+$result = pwg_query( $query );
+$nb_comments = '';
+if ( mysql_num_rows( $result ) > 0 )
+{
+  $nb_comments =  ' [ '.mysql_num_rows( $result ).' ]';
+}
+
+$link_start = PHPWG_ROOT_PATH.'admin.php?page=';
+$conf_link = $link_start.'configuration&amp;section=';
+$opt_link = $link_start.'cat_options&amp;section=';
+//----------------------------------------------------- template initialization
+include(PHPWG_ROOT_PATH.'include/page_header.php');
+$template->set_filenames( array('admin'=>'admin.tpl') );
+
+$template->assign_vars(array(
+  'L_TITLE'=>$lang['admin_panel'],
+  'L_LINKS'=>$lang['links'],
+  'L_GALLERY_INDEX'=>$lang['home'],
+  'L_GENERAL'=>$lang['general'],
+  'L_DEFAULT'=>$lang['gallery_default'],
+  'L_PHPINFO'=>$lang['phpinfos'],
+  'L_HISTORY'=>$lang['history'],
+  'L_FAQ'=>$lang['instructions'],
+  'L_CONFIGURATION'=>$lang['config'],
+  'L_CONFIG_GENERAL'=>$lang['general'],
+  'L_CONFIG_COMMENTS'=>$lang['comments'],
+  'L_CONFIG_DISPLAY'=>$lang['conf_default'],
+  'L_CONFIG_UPLOAD'=>$lang['upload'],
+  'L_CONFIG_SESSION'=>$lang['conf_cookie'],
+  'L_CONFIG_METADATA'=>$lang['metadata'],
+  'L_SITES'=>$lang['remote_sites'],
+  'L_CATEGORIES'=>$lang['categories'],
+  'L_MANAGE'=>$lang['manage'],
+  'L_IMAGES'=>$lang['pictures'],
+  'L_WAITING'=>$lang['waiting'].$nb_waiting,
+  'L_COMMENTS'=>$lang['comments'].$nb_comments,
+  'L_THUMBNAILS'=>$lang['thumbnails'],
+  'L_IDENTIFY'=>$lang['identification'],
+  'L_USERS'=>$lang['users'],
+  'L_GROUPS'=>$lang['groups'],
+  'L_AUTH'=>$lang['permissions'],
+  'L_UPDATE'=>$lang['update'],
+  'L_CAT_UPLOAD'=>$lang['upload'],
+  'L_CAT_COMMENTS'=>$lang['comments'],
+  'L_CAT_VISIBLE'=>$lang['lock'],
+  'L_CAT_STATUS'=>$lang['cat_security'],
+
+  'U_HISTORY'=>add_session_id($link_start.'stats' ),
+  'U_FAQ'=>add_session_id($link_start.'help' ),
+  'U_SITES'=>add_session_id($link_start.'remote_site'),
+  'U_PHPINFO'=>add_session_id($link_start.'admin_phpinfo' ),
+  'U_CONFIG_GENERAL'=>add_session_id($conf_link.'general' ),
+  'U_CONFIG_COMMENTS'=>add_session_id($conf_link.'comments' ),
+  'U_CONFIG_DISPLAY'=>add_session_id($conf_link.'default' ),
+  'U_CONFIG_UPLOAD'=>add_session_id($conf_link.'upload' ),
+  'U_CONFIG_SESSION'=>add_session_id($conf_link.'session' ),
+  'U_CONFIG_METADATA'=>add_session_id($conf_link.'metadata' ),
+  'U_CATEGORIES'=>add_session_id($link_start.'cat_list' ),
+  'U_CAT_UPLOAD'=>add_session_id($opt_link.'upload'),
+  'U_CAT_COMMENTS'=>add_session_id($opt_link.'comments'),
+  'U_CAT_VISIBLE'=>add_session_id($opt_link.'visible'),
+  'U_CAT_STATUS'=>add_session_id($opt_link.'status'),
+  'U_CAT_OPTIONS'=>add_session_id($link_start.'cat_options'),
+  'U_CAT_UPDATE'=>add_session_id($link_start.'update'),
+  'U_WAITING'=>add_session_id($link_start.'waiting' ),
+  'U_COMMENTS'=>add_session_id($link_start.'comments' ),
+  'U_THUMBNAILS'=>add_session_id($link_start.'thumbnail' ),
+  'U_USERS'=>add_session_id($link_start.'profile' ),
+  'U_GROUPS'=>add_session_id($link_start.'group_list' ),
+  'U_USERS_AUTH'=>add_session_id($link_start.'user_perm' ),
+  'U_GROUPS_AUTH'=>add_session_id($link_start.'group_perm'),
+  'U_CAT_AUTH'=>add_session_id($link_start.'cat_perm' ),
+  'U_RETURN'=>add_session_id(PHPWG_ROOT_PATH.'category.php')
+  ));
+
+//--------------------------------------------------------------------- summary
+$link_start = PHPWG_ROOT_PATH.'admin.php?page=';
+//------------------------------------------------------------- content display
+if ( $page_valide )
+{
+  if ($_GET['page']=='comments') include ( PHPWG_ROOT_PATH.'comments.php');
+	elseif ($_GET['page']=='profile') include ( PHPWG_ROOT_PATH.'profile.php');
+  else include ( PHPWG_ROOT_PATH.'admin/'.$_GET['page'].'.php' );
+}
+else
+{
+  $template->assign_vars(array ('ADMIN_CONTENT'=> '<div style="text-align:center">'.$lang['default_message'].'</div>') );
+}
+$template->parse('admin');
+include(PHPWG_ROOT_PATH.'include/page_tail.php');
+// +-----------------------------------------------------------------------+
+// |                     order permission refreshment                      |
+// +-----------------------------------------------------------------------+
+$query = '
+UPDATE '.USER_FORBIDDEN_TABLE.'
+  SET need_update = \'true\'
+;';
+pwg_query($query);
+?>
Index: /branches/1.4/admin/admin_phpinfo.php
===================================================================
--- /branches/1.4/admin/admin_phpinfo.php	(revision 3249)
+++ /branches/1.4/admin/admin_phpinfo.php	(revision 3249)
@@ -0,0 +1,82 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if( !defined("PHPWG_ROOT_PATH") )
+{
+	die ("Hacking attempt!");
+}
+
+include_once( PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php' );
+
+ob_start(); 
+phpinfo(INFO_GENERAL | INFO_CONFIGURATION | INFO_MODULES | INFO_VARIABLES); 
+$phpinfo = ob_get_contents(); 
+ob_end_clean(); 
+
+// Get used layout
+$layout = (preg_match('#bgcolor#i', $phpinfo)) ? 'old' : 'new';
+$output='';
+// Here we play around a little with the PHP Info HTML to try and stylise
+// it along phpBB's lines ... hopefully without breaking anything. The idea
+// for this was nabbed from the PHP annotated manual
+preg_match_all('#<body[^>]*>(.*)</body>#siU', $phpinfo, $output); 
+
+switch ($layout)
+{
+  case 'old':
+    $output = preg_replace('#<table#', '<table class="table2"', $output[1][0]);
+    $output = preg_replace('# bgcolor="\#(\w){6}"#', '', $output);
+    $output = preg_replace('#(\w),(\w)#', '\1, \2', $output);
+    $output = preg_replace('#border="0" cellpadding="3" cellspacing="1" width="600"#', 'border="0" cellspacing="1" cellpadding="4" width="95%"', $output);
+    $output = preg_replace('#<tr valign="top"><td align="left">(.*?<a .*?</a>)(.*?)</td></tr>#s', '<tr class="row1"><td style="{background-color: #9999cc;}"><table width="100%" cellspacing="0" cellpadding="0" border="0"><tr><td style="{background-color: #9999cc;}">\2</td><td style="{background-color: #9999cc;}">\1</td></tr></table></td></tr>', $output);
+    $output = preg_replace('#<tr valign="baseline"><td[ ]{0,1}><b>(.*?)</b>#', '<tr><td class="row1" nowrap="nowrap">\1', $output);
+    $output = preg_replace('#<td align="(center|left)">#', '<td class="row2">', $output);
+    $output = preg_replace('#<td>#', '<td class="row2">', $output);
+    $output = preg_replace('#valign="middle"#', '', $output);
+    $output = preg_replace('#<tr >#', '<tr>', $output);
+    $output = preg_replace('#<hr(.*?)>#', '', $output);
+    $output = preg_replace('#<h1 align="center">#i', '<h1>', $output);
+    $output = preg_replace('#<h2 align="center">#i', '<h2>', $output);
+    break;
+  case 'new':
+    $output = preg_replace('#<table#', '<table class="table2"', $output[1][0]);
+    $output = preg_replace('#(\w),(\w)#', '\1, \2', $output);
+    $output = preg_replace('#border="0" cellpadding="3" width="600"#', 'border="0" cellspacing="1" cellpadding="2" width="95%"', $output);
+    $output = preg_replace('#<tr class="v"><td>(.*?<a .*?</a>)(.*?)</td></tr>#s', '<tr class="throw"><td><table width="100%" cellspacing="0" cellpadding="0" border="0"><tr><td>\2</td><td>\1</td></tr></table></td></tr>', $output);
+    $output = preg_replace('#<td>#', '<td style="background-color: #444444;text-align:center;">', $output);
+	$output = preg_replace('#<th>#', '<th class="throw">', $output);
+    $output = preg_replace('#class="e"#', 'class="row1"', $output);
+    $output = preg_replace('#class="v"#', 'class="row2"', $output);
+    $output = preg_replace('# class="h"#', '', $output);
+    $output = preg_replace('#<hr />#', '', $output);
+    preg_match_all('#<div class="center">(.*)</div>#siU', $output, $output); 
+    $output = $output[1][0];
+    break;
+}
+$template->assign_var('ADMIN_CONTENT',$output);
+
+?>
Index: /branches/1.4/admin/cat_list.php
===================================================================
--- /branches/1.4/admin/cat_list.php	(revision 3249)
+++ /branches/1.4/admin/cat_list.php	(revision 3249)
@@ -0,0 +1,479 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if (!defined('PHPWG_ROOT_PATH'))
+{
+  die('Hacking attempt!');
+}
+include_once(PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php');
+// +-----------------------------------------------------------------------+
+// |                            initialization                             |
+// +-----------------------------------------------------------------------+
+$errors = array();
+$infos = array();
+$categories = array();
+$navigation = $lang['home'];
+// +-----------------------------------------------------------------------+
+// |                    virtual categories management                      |
+// +-----------------------------------------------------------------------+
+// request to delete a virtual category
+if (isset($_GET['delete']) and is_numeric($_GET['delete']))
+{
+  delete_categories(array($_GET['delete']));
+  array_push($infos, $lang['cat_virtual_deleted']);
+  ordering();
+  update_global_rank();
+}
+// request to add a virtual category
+else if (isset($_POST['submit']))
+{
+  // is the given category name only containing blank spaces ?
+  if (preg_match('/^\s*$/', $_POST['virtual_name']))
+  {
+    array_push($errors, $lang['cat_error_name']);
+  }
+	
+  if (!count($errors))
+  {
+    $parent_id = !empty($_GET['parent_id'])?$_GET['parent_id']:'NULL';
+    
+    if ($parent_id != 'NULL')
+    {
+      $query = '
+SELECT id,uppercats,global_rank,visible,status
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id = '.$parent_id.'
+;';
+      $row = mysql_fetch_array(pwg_query($query));
+      $parent = array('id' => $row['id'],
+                      'uppercats' => $row['uppercats'],
+                      'visible' => $row['visible'],
+                      'status' => $row['status'],
+                      'global_rank' => $row['global_rank']);
+    }
+
+    // what will be the inserted id ?
+    $query = '
+SELECT IF(MAX(id)+1 IS NULL, 1, MAX(id)+1)
+  FROM '.CATEGORIES_TABLE.'
+;';
+    list($next_id) = mysql_fetch_array(pwg_query($query));
+    
+    $insert = array();
+    $insert{'id'} = $next_id++;
+    $insert{'name'} = $_POST['virtual_name'];
+    $insert{'rank'} = $_POST['rank'];
+    $insert{'commentable'} = $conf['newcat_default_commentable'];
+
+    // a virtual category can't be uploadable
+    $insert{'uploadable'} = 'false';
+    
+    if (isset($parent))
+    {
+      $insert{'id_uppercat'} = $parent{'id'};
+      $insert{'uppercats'}   = $parent{'uppercats'}.','.$insert{'id'};
+      $insert{'global_rank'} = $parent{'global_rank'}.'.'.$insert{'rank'};
+      // at creation, must a category be visible or not ? Warning : if
+      // the parent category is invisible, the category is automatically
+      // create invisible. (invisible = locked)
+      if ('false' == $parent['visible'])
+      {
+        $insert{'visible'} = 'false';
+      }
+      else
+      {
+        $insert{'visible'} = $conf['newcat_default_visible'];
+      }
+      // at creation, must a category be public or private ? Warning :
+      // if the parent category is private, the category is
+      // automatically create private.
+      if ('private' == $parent['status'])
+      {
+        $insert{'status'} = 'private';
+      }
+      else
+      {
+        $insert{'status'} = $conf['newcat_default_status'];
+      }
+    }
+    else
+    {
+      $insert{'visible'} = $conf['newcat_default_visible'];
+      $insert{'status'} = $conf['newcat_default_status'];
+      $insert{'uppercats'} = $insert{'id'};
+      $insert{'global_rank'} = $insert{'rank'};
+    }
+
+    $inserts = array($insert);
+    
+    // we have then to add the virtual category
+    $dbfields = array('id','site_id','name','id_uppercat','rank',
+                      'commentable','uploadable','visible','status',
+                      'uppercats','global_rank');
+    mass_inserts(CATEGORIES_TABLE, $dbfields, $inserts);
+
+    array_push($infos, $lang['cat_virtual_added']);
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                           Cache management                            |
+// +-----------------------------------------------------------------------+
+$query = '
+SELECT *
+  FROM '.CATEGORIES_TABLE;
+if (!isset($_GET['parent_id']))
+{
+  $query.= '
+  WHERE id_uppercat IS NULL';
+}
+else
+{
+  $query.= '
+  WHERE id_uppercat = '.$_GET['parent_id'];
+}
+$query.= '
+  ORDER BY rank ASC
+;';
+$result = pwg_query($query);
+while ($row = mysql_fetch_assoc($result))
+{
+  $categories[$row['rank']] = $row;
+  $categories[$row['rank']]['nb_subcats'] = 0;
+}
+// +-----------------------------------------------------------------------+
+// |                            Navigation path                            |
+// +-----------------------------------------------------------------------+
+if (isset($_GET['parent_id']))
+{
+  $base_url = PHPWG_ROOT_PATH.'admin.php?page=cat_list';
+  
+  $navigation = '<a class="" href="'.add_session_id($base_url).'">';
+  $navigation.= $lang['home'];
+  $navigation.= '</a>';
+  $navigation.= $conf['level_separator'];
+
+  $current_category = get_cat_info($_GET['parent_id']);
+  $navigation.= get_cat_display_name($current_category['name'],
+                                     $base_url.'&amp;parent_id=',
+                                     false);
+}
+// +-----------------------------------------------------------------------+
+// |                               rank updates                            |
+// +-----------------------------------------------------------------------+
+$current_rank = 0;
+if (isset($_GET['up']) and is_numeric($_GET['up']))
+{
+  // 1. searching the id of the category just above at the same level
+  while (list ($id,$current) = each($categories))
+  {
+    if ($current['id'] == $_GET['up'])
+    {
+      $current_rank = $current['rank'];
+      break;
+    }
+  }
+  if ($current_rank > 1)
+  {
+    // 2. Exchanging ranks between the two categories
+    $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET rank = '.($current_rank-1).'
+  WHERE id = '.$_GET['up'].'
+;';
+    pwg_query($query);
+    $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET rank = '.$current_rank.'
+  WHERE id = '.$categories[($current_rank-1)]['id'].'
+;';
+    pwg_query($query);
+    // 3. Updating the cache array
+    $categories[$current_rank] = $categories[($current_rank-1)];
+    $categories[($current_rank-1)] = $current;
+  }
+  else
+  {
+    // 2. Updating the rank of our category to be after the previous max rank
+    $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET rank = '.(count($categories) + 1).'
+  WHERE id = '.$_GET['up'].'
+;';
+    pwg_query($query);
+    $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET rank = rank-1
+  WHERE id_uppercat ';
+    if (empty($_GET['parent_id']))
+    {
+      $query.= 'IS NULL';
+    }
+    else
+    {
+      $query.= '= '.$_GET['parent_id'];
+    }
+    $query.= '
+;';
+    pwg_query($query);
+    // 3. Updating the cache array
+    array_push($categories, $current);
+    array_shift($categories);
+  }
+  update_global_rank(@$_GET['parent_id']);
+}
+else if (isset($_GET['down']) and is_numeric($_GET['down']))
+{
+  // 1. searching the id of the category just above at the same level
+  while (list ($id,$current) = each($categories))
+  {
+    if ($current['id'] == $_GET['down'])
+    {
+      $current_rank = $current['rank'];
+      break;
+    }
+  }
+  if ($current_rank < count($categories))
+  {
+    // 2. Exchanging ranks between the two categories
+    $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET rank = '.($current_rank+1).'
+  WHERE id = '.$_GET['down'].'
+;';
+    pwg_query($query);
+    $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET rank = '.$current_rank.'
+  WHERE id = '.$categories[($current_rank+1)]['id'].'
+;';
+    pwg_query($query);
+    // 3. Updating the cache array
+    $categories[$current_rank]=$categories[($current_rank+1)];
+    $categories[($current_rank+1)] = $current;
+  }
+  else 
+  {
+    // 2. updating the rank of our category to be the first one
+    $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET rank = 0
+  WHERE id = '.$_GET['down'].'
+;';
+    pwg_query($query);
+    $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET rank = rank+1
+  WHERE id_uppercat ';
+    if (empty($_GET['parent_id']))
+    {
+      $query.= 'IS NULL';
+    }
+    else
+    {
+      $query.= '= '.$_GET['parent_id'];
+    }
+    $query.= '
+;';
+    pwg_query($query);
+    // 3. Updating the cache array
+    array_unshift($categories, $current);
+    array_pop($categories);
+  }
+  update_global_rank(@$_GET['parent_id']);
+}
+reset($categories);
+// +-----------------------------------------------------------------------+
+// |                       template initialization                         |
+// +-----------------------------------------------------------------------+
+$template->set_filenames(array('categories'=>'admin/cat_list.tpl'));
+
+$form_action = PHPWG_ROOT_PATH.'admin.php?page=cat_list';
+if (isset($_GET['parent_id']))
+{
+  $form_action.= '&amp;parent_id='.$_GET['parent_id'];
+}
+
+if (count($categories) > 0)
+{
+  $next_rank = max(array_keys($categories)) + 1;
+}
+else
+{
+  $next_rank = 1;
+}
+
+$template->assign_vars(array(
+  'CATEGORIES_NAV'=>$navigation,
+  'NEXT_RANK'=>$next_rank,
+  'F_ACTION'=>add_session_id($form_action),
+  
+  'L_ADD_VIRTUAL'=>$lang['cat_add'],
+  'L_SUBMIT'=>$lang['submit'],
+  'L_STORAGE'=>$lang['storage'],
+  'L_NB_IMG'=>$lang['pictures'],
+  'L_MOVE_UP'=>$lang['up'],
+  'L_MOVE_DOWN'=>$lang['down'],
+  'L_EDIT'=>$lang['edit'],
+  'L_INFO_IMG'=>$lang['cat_image_info'],
+  'L_DELETE'=>$lang['delete'],
+ ));
+  
+$tpl = array('cat_first','cat_last');
+// +-----------------------------------------------------------------------+
+// |                            errors & infos                             |
+// +-----------------------------------------------------------------------+
+if (count($errors) != 0)
+{
+  $template->assign_block_vars('errors',array());
+  foreach ($errors as $error)
+  {
+    $template->assign_block_vars('errors.error',array('ERROR'=>$error));
+  }
+}
+if (count($infos) != 0)
+{
+  $template->assign_block_vars('infos',array());
+  foreach ($infos as $info)
+  {
+    $template->assign_block_vars('infos.info',array('INFO'=>$info));
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                          Categories display                           |
+// +-----------------------------------------------------------------------+
+$ranks = array();
+
+if (count($categories) > 0)
+{
+  foreach ($categories as $category)
+  {
+    $ranks[$category['id']] = $category['rank'];
+  }
+
+  $query = '
+SELECT id_uppercat, COUNT(*) AS nb_subcats
+  FROM '. CATEGORIES_TABLE.'
+  WHERE id_uppercat IN ('.implode(',', array_keys($ranks)).')
+  GROUP BY id_uppercat
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    $categories[$ranks[$row['id_uppercat']]]['nb_subcats']
+      = $row['nb_subcats'];
+  }
+}
+
+foreach ($categories as $category)
+{
+  $images_folder = PHPWG_ROOT_PATH.'template/';
+  $images_folder.= $user['template'].'/admin/images';
+  
+  if ($category['visible'] == 'false')
+  {
+    $image_src = $images_folder.'/icon_folder_lock.gif';
+    $image_alt = $lang['cat_private'];
+    $image_title = $lang['cat_private'];
+  }
+  else if (empty($category['dir']))
+  {
+    $image_src = $images_folder.'/icon_folder_link.gif';
+    $image_alt = $lang['cat_virtual'];
+    $image_title = $lang['cat_virtual'];
+  }
+  else
+  {
+    if ($category['nb_subcats'] > 0)
+    {
+      $image_src = $images_folder.'/icon_subfolder.gif';
+    }
+    else
+    {
+      $image_src = $images_folder.'/icon_folder.gif';
+    }
+    $image_alt = '';
+    $image_title = '';
+  }
+
+  $base_url = PHPWG_ROOT_PATH.'admin.php?page=';
+  $cat_list_url = $base_url.'cat_list';
+  
+  $self_url = $cat_list_url;
+  if (isset($_GET['parent_id']))
+  {
+    $self_url.= '&amp;parent_id='.$_GET['parent_id'];
+  }
+
+  $template->assign_block_vars(
+    'category',
+    array(
+      'CATEGORY_IMG_SRC'=>$image_src,
+      'CATEGORY_IMG_ALT'=>$image_alt,
+      'CATEGORY_IMG_TITLE'=>$image_title,
+      'CATEGORY_NAME'=>$category['name'],
+      'CATEGORY_DIR'=>@$category['dir'],
+      'CATEGORY_NB_IMG'=>$category['nb_images'],
+      
+      'U_CATEGORY'=>
+      add_session_id($cat_list_url.'&amp;parent_id='.$category['id']),
+      
+      'U_MOVE_UP'=>add_session_id($self_url.'&amp;up='.$category['id']),
+      
+      'U_MOVE_DOWN'=>add_session_id($self_url.'&amp;down='.$category['id']),
+      
+      'U_CAT_EDIT'=>
+      add_session_id($base_url.'cat_modify&amp;cat_id='.$category['id']),
+      
+      'U_CAT_DELETE'=>add_session_id($self_url.'&amp;delete='.$category['id']),
+      
+      'U_INFO_IMG'
+      => add_session_id($base_url.'infos_images&amp;cat_id='.$category['id'])
+      ));
+  
+  if (!empty($category['dir']))
+  {
+    $template->assign_block_vars('category.storage' ,array());
+  }
+  else
+  {
+    $template->assign_block_vars('category.virtual' ,array());
+  }
+  
+  if ($category['nb_images'] > 0)
+  {
+    $template->assign_block_vars('category.image_info' ,array());
+  }
+  else
+  {
+    $template->assign_block_vars('category.no_image_info' ,array()); 
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                          sending html code                            |
+// +-----------------------------------------------------------------------+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'categories');
+?>
Index: /branches/1.4/admin/cat_modify.php
===================================================================
--- /branches/1.4/admin/cat_modify.php	(revision 3249)
+++ /branches/1.4/admin/cat_modify.php	(revision 3249)
@@ -0,0 +1,210 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if (!defined('PHPWG_ROOT_PATH'))
+{
+  die('Hacking attempt!');
+}
+include_once(PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php');
+//---------------------------------------------------------------- verification
+if ( !isset( $_GET['cat_id'] ) || !is_numeric( $_GET['cat_id'] ) )
+{
+  $_GET['cat_id'] = '-1';
+}
+
+$template->set_filenames( array('categories'=>'admin/cat_modify.tpl') );
+
+//--------------------------------------------------------- form criteria check
+if ( isset( $_POST['submit'] ) )
+{
+  $query = 'SELECT status';
+  $query.= ' FROM '.CATEGORIES_TABLE;
+  $query.= ' WHERE id = '.$_GET['cat_id'];
+  $query.= ';';
+  $row = mysql_fetch_array( pwg_query( $query ) );
+  
+  $query = 'UPDATE '.CATEGORIES_TABLE;
+  $query.= ' SET name = ';
+  if ( empty($_POST['name']))
+    $query.= 'NULL';
+  else
+    $query.= "'".htmlentities( $_POST['name'], ENT_QUOTES)."'";
+
+  $query.= ', comment = ';
+  if ( empty($_POST['comment']))
+    $query.= 'NULL';
+  else
+    $query.= "'".htmlentities( $_POST['comment'], ENT_QUOTES )."'";
+
+  if ( isset( $_POST['uploadable'] ) )
+    $query.= ", uploadable = '".$_POST['uploadable']."'";
+
+  if ( isset( $_POST['commentable'] ) )
+    $query.= ", commentable = '".$_POST['commentable']."'";
+
+  if ( isset( $_POST['associate'] ) )
+  {
+    $query.= ', id_uppercat = ';
+    if ( $_POST['associate'] == -1 or $_POST['associate'] == '' )
+      $query.= 'NULL';
+    else
+      $query.= $_POST['associate'];
+  }
+  $query.= ' WHERE id = '.$_GET['cat_id'];
+  $query.= ';';
+  pwg_query( $query );
+
+  set_cat_visible(array($_GET['cat_id']), $_POST['visible']);
+  set_cat_status(array($_GET['cat_id']), $_POST['status']);
+
+  $template->assign_block_vars('confirmation' ,array());
+}
+else if (isset($_POST['set_random_representant']))
+{
+  set_random_representant(array($_GET['cat_id']));
+}
+
+$query = '
+SELECT *
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id = '.$_GET['cat_id'].'
+;';
+$category = mysql_fetch_array( pwg_query( $query ) );
+// nullable fields
+foreach (array('comment','dir','site_id') as $nullable)
+{
+  if (!isset($category[$nullable]))
+  {
+    $category[$nullable] = '';
+  }
+}
+
+// Navigation path
+$url = PHPWG_ROOT_PATH.'admin.php?page=cat_list&amp;parent_id=';
+$navigation = '<a class="" href="'.add_session_id(PHPWG_ROOT_PATH.'admin.php?page=cat_list').'">';
+$navigation.= $lang['home'].'</a>'.$conf['level_separator'];
+
+$navigation.= get_cat_display_name_cache(
+  $category['uppercats'],
+  $url);
+
+$form_action = PHPWG_ROOT_PATH.'admin.php?page=cat_modify&amp;cat_id='.$_GET['cat_id'];
+$status = ($category['status']=='public')?'STATUS_PUBLIC':'STATUS_PRIVATE'; 
+$lock = ($category['visible']=='true')?'UNLOCKED':'LOCKED';
+
+if ($category['commentable'] == 'true')
+{
+  $commentable = 'COMMENTABLE_TRUE';
+}
+else
+{
+  $commentable = 'COMMENTABLE_FALSE';
+}
+if ($category['uploadable'] == 'true')
+{
+  $uploadable = 'UPLOADABLE_TRUE';
+}
+else
+{
+  $uploadable = 'UPLOADABLE_FALSE';
+}
+
+//----------------------------------------------------- template initialization
+$template->assign_vars(array( 
+  'CATEGORIES_NAV'=>$navigation,
+  'CAT_NAME'=>$category['name'],
+  'CAT_COMMENT'=>$category['comment'],
+  
+  $status=>'checked="checked"',
+  $lock=>'checked="checked"',
+  $commentable=>'checked="checked"',
+  $uploadable=>'checked="checked"',
+  
+  'L_EDIT_CONFIRM'=>$lang['editcat_confirm'],
+  'L_EDIT_NAME'=>$lang['name'],
+  'L_STORAGE'=>$lang['storage'],
+  'L_REMOTE_SITE'=>$lang['remote_site'],
+  'L_EDIT_COMMENT'=>$lang['description'],
+  'L_EDIT_CAT_OPTIONS'=>$lang['cat_options'],
+  'L_EDIT_STATUS'=>$lang['conf_access'],
+  'L_EDIT_STATUS_INFO'=>$lang['cat_access_info'],
+  'L_STATUS_PUBLIC'=>$lang['public'],
+  'L_STATUS_PRIVATE'=>$lang['private'],
+  'L_EDIT_LOCK'=>$lang['lock'],
+  'L_EDIT_LOCK_INFO'=>$lang['editcat_lock_info'],
+  'L_EDIT_UPLOADABLE'=>$lang['editcat_uploadable'],
+  'L_EDIT_UPLOADABLE_INFO'=>$lang['editcat_uploadable_info'],
+  'L_EDIT_COMMENTABLE'=>$lang['comments'],
+  'L_EDIT_COMMENTABLE_INFO'=>$lang['editcat_commentable_info'],
+  'L_YES'=>$lang['yes'],
+  'L_NO'=>$lang['no'],
+  'L_SUBMIT'=>$lang['submit'],
+  'L_SET_RANDOM_REPRESENTANT'=>$lang['cat_representant'],
+   
+  'F_ACTION'=>add_session_id($form_action)
+  ));
+
+if ($category['nb_images'] > 0)
+{
+  $query = '
+SELECT tn_ext,path
+  FROM '.IMAGES_TABLE.'
+  WHERE id = '.$category['representative_picture_id'].'
+;';
+  $row = mysql_fetch_array(pwg_query($query));
+  $src = get_thumbnail_src($row['path'], @$row['tn_ext']);
+  $url = PHPWG_ROOT_PATH.'admin.php?page=picture_modify';
+  $url.= '&amp;image_id='.$category['representative_picture_id'];
+  $template->assign_block_vars('representant',
+                               array('SRC' => $src,
+                                     'URL' => $url));
+}
+
+if (!empty($category['dir']))
+{
+  $template->assign_block_vars(
+    'storage',
+    array('CATEGORY_DIR'=>preg_replace('/\/$/',
+                                       '',
+                                       get_complete_dir($category['id']))));
+  $template->assign_block_vars('upload' ,array());
+}
+
+if (is_numeric($category['site_id']) and $category['site_id'] != 1)
+{
+  $query = '
+SELECT galleries_url
+  FROM '.SITES_TABLE.'
+  WHERE id = '.$category['site_id'].'
+;';
+  list($galleries_url) = mysql_fetch_array(pwg_query($query));
+  $template->assign_block_vars('server', array('SITE_URL' => $galleries_url));
+}
+
+//----------------------------------------------------------- sending html code
+$template->assign_var_from_handle('ADMIN_CONTENT', 'categories');
+?>
Index: /branches/1.4/admin/cat_options.php
===================================================================
--- /branches/1.4/admin/cat_options.php	(revision 3249)
+++ /branches/1.4/admin/cat_options.php	(revision 3249)
@@ -0,0 +1,260 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if (!defined('PHPWG_ROOT_PATH'))
+{
+  die ("Hacking attempt!");
+}
+include_once(PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php');
+// +-----------------------------------------------------------------------+
+// |                       modification registration                       |
+// +-----------------------------------------------------------------------+
+// print '<pre>';
+// print_r($_POST);
+// print '</pre>';
+if (isset($_POST['falsify'])
+    and isset($_POST['cat_true'])
+    and count($_POST['cat_true']) > 0)
+{
+  switch ($_GET['section'])
+  {
+    case 'upload' :
+    {
+      $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET uploadable = \'false\'
+  WHERE id IN ('.implode(',', $_POST['cat_true']).')
+;';
+      pwg_query($query);
+      break;
+    }
+    case 'comments' :
+    {
+      $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET commentable = \'false\'
+  WHERE id IN ('.implode(',', $_POST['cat_true']).')
+;';
+      pwg_query($query);
+      break;
+    }
+    case 'visible' :
+    {
+      set_cat_visible($_POST['cat_true'], 'false');
+      break;
+    }
+    case 'status' :
+    {
+      set_cat_status($_POST['cat_true'], 'private');
+      break;
+    }
+  }
+}
+else if (isset($_POST['trueify'])
+         and isset($_POST['cat_false'])
+         and count($_POST['cat_false']) > 0)
+{
+  switch ($_GET['section'])
+  {
+    case 'upload' :
+    {
+      $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET uploadable = \'true\'
+  WHERE id IN ('.implode(',', $_POST['cat_false']).')
+;';
+      pwg_query($query);
+      break;
+    }
+    case 'comments' :
+    {
+      $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET commentable = \'true\'
+  WHERE id IN ('.implode(',', $_POST['cat_false']).')
+;';
+      pwg_query($query);
+      break;
+    }
+    case 'visible' :
+    {
+      set_cat_visible($_POST['cat_false'], 'true');
+      break;
+    }
+    case 'status' :
+    {
+      set_cat_status($_POST['cat_false'], 'public');
+      break;
+    }
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                             template init                             |
+// +-----------------------------------------------------------------------+
+$template->set_filenames(array('cat_options'=>'admin/cat_options.tpl'));
+
+if (!isset($_GET['section']))
+{
+  $page['section'] = 'upload';
+}
+else
+{
+  $page['section'] = $_GET['section'];
+}
+
+$base_url = PHPWG_ROOT_PATH.'admin.php?page=cat_options&amp;section=';
+$template->assign_vars(
+  array(
+    'L_SUBMIT'=>$lang['submit'],
+    'L_RESET'=>$lang['reset'],
+    
+    'F_ACTION'=>add_session_id($base_url.$page['section'])
+   )
+ );
+
+$template->assign_vars(array(strtoupper($page['section']).'_CLASS'=>'opened'));
+// +-----------------------------------------------------------------------+
+// |                              form display                             |
+// +-----------------------------------------------------------------------+
+
+// for each section, categories in the multiselect field can be :
+//
+// - true : uploadable for upload section
+// - false : un-uploadable for upload section
+// - NA : (not applicable) for virtual categories
+//
+// for true and false status, we associates an array of category ids,
+// function display_select_categories will use the given CSS class for each
+// option
+$cats_true = array();
+$cats_false = array();
+switch ($page['section'])
+{
+  case 'upload' :
+  {
+    $query_true = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE uploadable = \'true\'
+    AND dir IS NOT NULL
+    AND site_id = 1
+;';
+    $query_false = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE uploadable = \'false\'
+    AND dir IS NOT NULL
+    AND site_id = 1
+;';
+    $template->assign_vars(
+      array(
+        'L_CAT_TITLE' => $lang['cat_upload_title'],
+        'L_CAT_OPTIONS_TRUE' => $lang['authorized'],
+        'L_CAT_OPTIONS_FALSE' => $lang['forbidden'],
+        'L_CAT_OPTIONS_INFO' => $lang['cat_upload_info'],
+        )
+      );
+    $template->assign_block_vars('upload', array());
+    break;
+  }
+  case 'comments' :
+  {
+    $query_true = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE commentable = \'true\'
+;';
+    $query_false = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE commentable = \'false\'
+;';
+    $template->assign_vars(
+      array(
+        'L_CAT_TITLE' => $lang['cat_comments_title'],
+        'L_CAT_OPTIONS_TRUE' => $lang['authorized'],
+        'L_CAT_OPTIONS_FALSE' => $lang['forbidden'],
+        'L_CAT_OPTIONS_INFO' => $lang['cat_comments_info'],
+        )
+      );
+    $template->assign_block_vars('comments', array());
+    break;
+  }
+  case 'visible' :
+  {
+    $query_true = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE visible = \'true\'
+;';
+    $query_false = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE visible = \'false\'
+;';
+    $template->assign_vars(
+      array(
+        'L_CAT_TITLE' => $lang['cat_lock_title'],
+        'L_CAT_OPTIONS_TRUE' => $lang['unlocked'],
+        'L_CAT_OPTIONS_FALSE' => $lang['locked'],
+        'L_CAT_OPTIONS_INFO' => $lang['cat_lock_info'],
+        )
+      );
+    $template->assign_block_vars('visible', array());
+    break;
+  }
+  case 'status' :
+  {
+    $query_true = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE status = \'public\'
+;';
+    $query_false = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE status = \'private\'
+;';
+    $template->assign_vars(
+      array(
+        'L_CAT_TITLE' => $lang['cat_status_title'],
+        'L_CAT_OPTIONS_TRUE' => $lang['cat_public'],
+        'L_CAT_OPTIONS_FALSE' => $lang['cat_private'],
+        'L_CAT_OPTIONS_INFO' => $lang['cat_status_info'],
+        )
+      );
+    $template->assign_block_vars('status', array());
+    break;
+  }
+}
+display_select_cat_wrapper($query_true,array(),'category_option_true');
+display_select_cat_wrapper($query_false,array(),'category_option_false');
+// +-----------------------------------------------------------------------+
+// |                           sending html code                           |
+// +-----------------------------------------------------------------------+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'cat_options');
+?>
Index: /branches/1.4/admin/cat_perm.php
===================================================================
--- /branches/1.4/admin/cat_perm.php	(revision 3249)
+++ /branches/1.4/admin/cat_perm.php	(revision 3249)
@@ -0,0 +1,228 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+include_once( './admin/include/isadmin.inc.php' );
+//----------------------------------------------------- template initialization
+$sub = $vtp->Open( './template/'.$user['template'].'/admin/cat_perm.vtp' );
+$error = array();
+$tpl = array( 'permuser_authorized','permuser_forbidden','menu_groups',
+              'submit','menu_users','permuser_parent_forbidden' );
+templatize_array( $tpl, 'lang', $sub );
+$vtp->setGlobalVar( $sub, 'user_template', $user['template'] );
+//-------------------------------------------------------------- category infos
+if ( isset( $_GET['cat_id'] ) )
+{
+  check_cat_id( $_GET['cat_id'] );
+  if ( isset( $page['cat'] ) and is_numeric( $page['cat'] ) )
+  {
+    $result = get_cat_info( $page['cat'] );
+    $page['cat_name']    = $result['name'];
+    $page['id_uppercat'] = $result['id_uppercat'];
+  }
+}
+//---------------------------------------------------------- permission updates
+if ( isset( $_POST['submit'] ) )
+{
+  // groups access update
+  $query = 'DELETE';
+  $query.= ' FROM '.PREFIX_TABLE.'group_access';
+  $query.= ' WHERE cat_id = '.$page['cat'];
+  $query.= ';';
+  pwg_query( $query );
+  $query = 'SELECT id';
+  $query.= ' FROM '.PREFIX_TABLE.'groups';
+  $query.= ';';
+  $result = pwg_query( $query );
+  while ( $row = mysql_fetch_array( $result ) )
+  {
+    $radioname = 'groupaccess-'.$row['id'];
+    if ( $_POST[$radioname] == 0 )
+    {
+      $query = 'INSERT INTO '.PREFIX_TABLE.'group_access';
+      $query.= ' (cat_id,group_id) VALUES';
+      $query.= ' ('.$page['cat'].','.$row['id'].')';
+      $query.= ';';
+      pwg_query( $query );
+    }
+  }
+  // users access update
+  $query = 'DELETE';
+  $query.= ' FROM '.PREFIX_TABLE.'user_access';
+  $query.= ' WHERE cat_id = '.$page['cat'];
+  $query.= ';';
+  pwg_query( $query );
+  $query = 'SELECT id';
+  $query.= ' FROM '.USERS_TABLE;
+  $query.= ';';
+  $result = pwg_query( $query );
+  while ( $row = mysql_fetch_array( $result ) )
+  {
+    $radioname = 'useraccess-'.$row['id'];
+    if ( $_POST[$radioname] == 0 )
+    {
+      $query = 'INSERT INTO '.PREFIX_TABLE.'user_access';
+      $query.= ' (cat_id,user_id) VALUES';
+      $query.= ' ('.$page['cat'].','.$row['id'].')';
+      $query.= ';';
+      pwg_query( $query );
+    }
+    check_favorites( $row['id'] );
+  }
+  // resynchronize all users
+  synchronize_all_users();
+}
+//---------------------------------------------------------------------- groups
+$query = 'SELECT id,name';
+$query.= ' FROM '.PREFIX_TABLE.'groups';
+$query. ';';
+$result = pwg_query( $query );
+if ( mysql_num_rows( $result ) > 0 )
+{
+  $vtp->addSession( $sub, 'groups' );
+  // creating an array with all authorized groups for this category
+  $query = 'SELECT group_id';
+  $query.= ' FROM '.PREFIX_TABLE.'group_access';
+  $query.= ' WHERE cat_id = '.$_GET['cat_id'];
+  $query.= ';';
+  $subresult = pwg_query( $query );
+  $authorized_groups = array();
+  while ( $subrow = mysql_fetch_array( $subresult ) )
+  {
+    array_push( $authorized_groups, $subrow['group_id'] );
+  }
+  // displaying each group
+  while( $row = mysql_fetch_array( $result ) )
+  {
+    $vtp->addSession( $sub, 'group' );
+    if ( in_array( $row['id'], $authorized_groups ) )
+    {
+      $vtp->setVar( $sub, 'group.color', 'green' );
+      $vtp->setVar( $sub, 'group.authorized_checked', ' checked="checked"' );
+    }
+    else
+    {
+      $vtp->setVar( $sub, 'group.color', 'red' );
+      $vtp->setVar( $sub, 'group.forbidden_checked', ' checked="checked"' );
+    }
+    $vtp->setVar( $sub, 'group.groupname', $row['name'] );
+    $vtp->setVar( $sub, 'group.id', $row['id'] );
+    $url = './admin.php?page=group_perm&amp;group_id='.$row['id'];
+    $vtp->setVar( $sub, 'group.group_perm_link', add_session_id( $url ) );
+    $vtp->closeSession( $sub, 'group' );
+  }
+  $vtp->closeSession( $sub, 'groups' );
+}
+//----------------------------------------------------------------------- users
+$query = 'SELECT id,username,status';
+$query.= ' FROM '.USERS_TABLE;
+// only the webmaster can modify webmaster's permissions
+if ( $user['username'] != $conf['webmaster'] )
+{
+  $query.= " WHERE username != '".$conf['webmaster']."'";
+}
+$query.= ';';
+$result = pwg_query( $query );
+while ( $row = mysql_fetch_array( $result ) )
+{
+  $vtp->addSession( $sub, 'user' );
+  $vtp->setVar( $sub, 'user.id', $row['id'] );
+  $url = add_session_id( './admin.php?page=user_perm&amp;user_id='.$row['id']);
+  $vtp->setVar( $sub, 'user.user_perm_link', $url);
+  if ( $row['username'] == 'guest' )
+  {
+    $row['username'] = $lang['guest'];
+  }
+  $vtp->setVar( $sub, 'user.username', $row['username'] );
+
+  // for color of user : (red means access forbidden, green authorized) we
+  // ask all forbidden categories, including the groups rights
+  $restrictions = get_user_restrictions( $row['id'], $row['status'], false );
+  $is_user_allowed = is_user_allowed( $page['cat'], $restrictions );
+  if ( $is_user_allowed == 0 )
+  {
+    $vtp->setVar( $sub, 'user.color', 'green' );
+  }
+  else
+  {
+    $vtp->setVar( $sub, 'user.color', 'red' );
+  }
+  // for permission update button, we only ask forbidden categories for the
+  // user, not taking into account the groups the user belongs to
+  $restrictions = get_user_restrictions($row['id'],$row['status'],false,false);
+  $is_user_allowed = is_user_allowed( $page['cat'], $restrictions );
+  if ( $is_user_allowed == 2 )
+  {
+    $vtp->addSession( $sub, 'parent_forbidden' );
+    $url = './admin.php?page=cat_perm&amp;cat_id='.$page['id_uppercat'];
+    $vtp->setVar( $sub, 'parent_forbidden.url', add_session_id( $url ) );
+    $vtp->closeSession( $sub, 'parent_forbidden' );
+  }
+  if ( $is_user_allowed == 0 )
+  {
+    $vtp->setVar( $sub, 'user.authorized_checked', ' checked="checked"' );
+  }
+  else
+  {
+    $vtp->setVar( $sub, 'user.forbidden_checked', ' checked="checked"' );
+  }
+  // user's group(s)
+  $query = 'SELECT g.name as groupname, g.id as groupid';
+  $query.= ' FROM '.PREFIX_TABLE.'groups as g';
+  $query.= ', '.PREFIX_TABLE.'user_group as ug';
+  $query.= ' WHERE ug.group_id = g.id';
+  $query.= ' AND ug.user_id = '.$row['id'];
+  $query.= ';';
+  $subresult = pwg_query( $query );
+  if ( mysql_num_rows( $subresult ) > 0 )
+  {
+    $vtp->addSession( $sub, 'usergroups' );
+    $i = 0;
+    while( $subrow = mysql_fetch_array( $subresult ) )
+    {
+      $vtp->addSession( $sub, 'usergroup' );
+      if ( in_array( $subrow['groupid'], $authorized_groups ) )
+      {
+        $vtp->setVar( $sub, 'usergroup.color', 'green' );
+      }
+      else
+      {
+        $vtp->setVar( $sub, 'usergroup.color', 'red' );
+      }
+      $vtp->setVar( $sub, 'usergroup.name', $subrow['groupname'] );
+      if ( $i < mysql_num_rows( $subresult ) - 1 )
+      {
+        $vtp->setVar( $sub, 'usergroup.separation', ',' );
+      }
+      $vtp->closeSession( $sub, 'usergroup' );
+      $i++;
+    }
+    $vtp->closeSession( $sub, 'usergroups' );
+  }
+  $vtp->closeSession( $sub, 'user' );
+}
+//----------------------------------------------------------- sending html code
+$vtp->Parse( $handle , 'sub', $sub );
+?>
Index: /branches/1.4/admin/configuration.php
===================================================================
--- /branches/1.4/admin/configuration.php	(revision 3249)
+++ /branches/1.4/admin/configuration.php	(revision 3249)
@@ -0,0 +1,375 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if( !defined("PHPWG_ROOT_PATH") )
+{
+	die ("Hacking attempt!");
+}
+
+include_once( PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php' );
+//-------------------------------------------------------- sections definitions
+if (!isset($_GET['section']))
+{
+  $page['section'] = 'general';
+}
+else
+{
+  $page['section'] = $_GET['section'];
+}
+//------------------------------------------------------ $conf reinitialization
+$result = pwg_query('SELECT param,value FROM '.CONFIG_TABLE);
+while ($row = mysql_fetch_array($result))
+{
+  $conf[$row['param']] = $row['value'];
+  // if the parameter is present in $_POST array (if a form is submited), we
+  // override it with the submited value
+  if (isset($_POST[$row['param']]))
+  {
+    $conf[$row['param']] = $_POST[$row['param']];
+  }
+}					   
+//------------------------------ verification and registration of modifications
+$errors = array();
+if (isset($_POST['submit']))
+{
+  $int_pattern = '/^\d+$/';
+  switch ($page['section'])
+  {
+    case 'general' :
+    {
+      // thumbnail prefix must only contain simple ASCII characters
+      if (!preg_match('/^[\w-]*$/', $_POST['prefix_thumbnail']))
+      {
+        array_push($errors, $lang['conf_prefix_thumbnail_error']);
+      }
+      // as webmaster mail address shown on the website, it can be obfuscated
+      // and no comply with normal mail address pattern
+      break;
+    }
+    case 'comments' :
+    {
+      // the number of comments per page must be an integer between 5 and 50
+      // included
+      if (!preg_match($int_pattern, $_POST['nb_comment_page'])
+           or $_POST['nb_comment_page'] < 5
+           or $_POST['nb_comment_page'] > 50)
+      {
+        array_push($errors, $lang['conf_nb_comment_page_error']);
+      }
+      break;
+    }
+    case 'default' :
+    {
+      // periods must be integer values, they represents number of days
+      if (!preg_match($int_pattern, $_POST['recent_period'])
+          or $_POST['recent_period'] <= 0)
+      {
+        array_push($errors, $lang['periods_error']);
+      }
+      // maxwidth
+      if (isset($_POST['default_maxwidth'])
+          and !empty($_POST['default_maxwidth'])
+          and (!preg_match($int_pattern, $_POST['default_maxwidth'])
+               or $_POST['default_maxwidth'] < 50))
+      {
+        array_push($errors, $lang['maxwidth_error']);
+      }
+      // maxheight
+      if (isset($_POST['default_maxheight'])
+          and !empty($_POST['default_maxheight'])
+          and (!preg_match($int_pattern, $_POST['default_maxheight'])
+               or $_POST['default_maxheight'] < 50))
+      {
+        array_push($errors, $lang['maxheight_error']);
+      }
+      break;
+    }
+    case 'upload' :
+    {
+      // the maximum upload filesize must be an integer between 10 and 1000
+      if (!preg_match($int_pattern, $_POST['upload_maxfilesize'])
+          or $_POST['upload_maxfilesize'] < 10
+          or $_POST['upload_maxfilesize'] > 1000)
+      {
+        array_push($errors, $lang['conf_upload_maxfilesize_error']);
+      }
+      
+      foreach (array('upload_maxwidth',
+                     'upload_maxheight',
+                     'upload_maxwidth_thumbnail',
+                     'upload_maxheight_thumbnail')
+               as $field)
+      {
+        if (!preg_match($int_pattern, $_POST[$field])
+          or $_POST[$field] < 10)
+        {
+          array_push($errors, $lang['conf_'.$field.'_error']);
+        }
+      }
+      break;
+    }
+  }
+  
+  // updating configuration if no error found
+  if (count($errors) == 0)
+  {
+    $result = pwg_query('SELECT * FROM '.CONFIG_TABLE);
+    while ($row = mysql_fetch_array($result))
+    {
+      if (isset($_POST[$row['param']]))
+      {
+        $query = '
+UPDATE '.CONFIG_TABLE.'
+  SET value = \''. str_replace("\'", "''", $_POST[$row['param']]).'\'
+  WHERE param = \''.$row['param'].'\'
+;';
+        pwg_query($query);
+      }
+    }
+  }
+}
+
+//----------------------------------------------------- template initialization
+$template->set_filenames( array('config'=>'admin/configuration.tpl') );
+
+$action = PHPWG_ROOT_PATH.'admin.php?page=configuration';
+$action.= '&amp;section='.$page['section'];
+
+$template->assign_vars(
+  array(
+    'L_CONFIRM'=>$lang['conf_confirmation'],
+    'L_YES'=>$lang['yes'],
+    'L_NO'=>$lang['no'],
+    'L_SUBMIT'=>$lang['submit'],
+    'L_RESET'=>$lang['reset'],
+    
+    'F_ACTION'=>add_session_id($action)
+    ));
+
+switch ($page['section'])
+{
+  case 'general' :
+  {
+    $history_yes = ($conf['log']=='true')?'checked="checked"':'';
+    $history_no  = ($conf['log']=='false')?'checked="checked"':'';
+    $notif_yes = ($conf['mail_notification']=='true')?'checked="checked"':'';
+    $notif_no = ($conf['mail_notification']=='false')?'checked="checked"':'';
+    $lock_yes = ($conf['gallery_locked']=='true')?'checked="checked"':'';
+    $lock_no = ($conf['gallery_locked']=='false')?'checked="checked"':'';
+    
+    $template->assign_block_vars(
+      'general',
+      array(
+        'L_CONF_TITLE'=>$lang['conf_general_title'],
+        'L_CONF_MAIL'=>$lang['conf_mail_webmaster'],
+        'L_CONF_MAIL_INFO'=>$lang['conf_mail_webmaster_info'],
+        'L_CONF_TN_PREFIX'=>$lang['conf_prefix'],
+        'L_CONF_TN_PREFIX_INFO'=>$lang['conf_prefix_info'],
+        'L_CONF_HISTORY'=>$lang['history'],
+        'L_CONF_HISTORY_INFO'=>$lang['conf_log_info'],
+        'L_CONF_NOTIFICATION'=>$lang['conf_notification'],
+        'L_CONF_NOTIFICATION_INFO'=>$lang['conf_notification_info'],
+        'L_CONF_GALLERY_LOCKED'=>$lang['conf_gallery_locked'],
+        'L_CONF_GALLERY_LOCKED_INFO'=>$lang['conf_gallery_locked_info'],
+          
+        'ADMIN_MAIL'=>$conf['mail_webmaster'],
+        'THUMBNAIL_PREFIX'=>$conf['prefix_thumbnail'],
+        'HISTORY_YES'=>$history_yes,
+        'HISTORY_NO'=>$history_no,
+        'NOTIFICATION_YES'=>$notif_yes,
+        'NOTIFICATION_NO'=>$notif_no,
+        'GALLERY_LOCKED_YES'=>$lock_yes,
+        'GALLERY_LOCKED_NO'=>$lock_no,
+        ));
+    break;
+  }
+  case 'comments' :
+  {
+    $all_yes = ($conf['comments_forall']=='true')?'checked="checked"':'';
+    $all_no  = ($conf['comments_forall']=='false')?'checked="checked"':'';
+    $validate_yes = ($conf['comments_validation']=='true')?'checked="checked"':'';
+    $validate_no = ($conf['comments_validation']=='false')?'checked="checked"':'';
+      
+    $template->assign_block_vars(
+      'comments',
+      array(
+        'L_CONF_TITLE'=>$lang['conf_comments_title'],
+        'L_CONF_COMMENTS_ALL'=>$lang['conf_comments_forall'],
+        'L_CONF_COMMENTS_ALL_INFO'=>$lang['conf_comments_forall_info'],
+        'L_CONF_NB_COMMENTS_PAGE'=>$lang['conf_nb_comment_page'],
+        'L_CONF_NB_COMMENTS_PAGE_INFO'=>$lang['conf_nb_comment_page'],
+        'L_CONF_VALIDATE'=>$lang['conf_comments_validation'],
+        'L_CONF_VALIDATE_INFO'=>$lang['conf_comments_validation_info'],
+          
+        'NB_COMMENTS_PAGE'=>$conf['nb_comment_page'],
+        'COMMENTS_ALL_YES'=>$all_yes,
+        'COMMENTS_ALL_NO'=>$all_no,
+        'VALIDATE_YES'=>$validate_yes,
+        'VALIDATE_NO'=>$validate_no
+        ));
+    break;
+  }
+  case 'default' :
+  {
+    $show_yes = ($conf['show_nb_comments']=='true')?'checked="checked"':'';
+    $show_no = ($conf['show_nb_comments']=='false')?'checked="checked"':'';
+    $expand_yes = ($conf['auto_expand']=='true')?'checked="checked"':'';
+    $expand_no  = ($conf['auto_expand']=='false')?'checked="checked"':'';
+      
+    $template->assign_block_vars(
+      'default',
+      array(
+        'L_CONF_TITLE'=>$lang['conf_default_title'],
+        'L_CONF_LANG'=>$lang['language'],
+        'L_CONF_LANG_INFO'=>$lang['conf_default_language_info'],
+        'L_NB_IMAGE_LINE'=>$lang['nb_image_per_row'],
+        'L_NB_IMAGE_LINE_INFO'=>$lang['conf_nb_image_line_info'],
+        'L_NB_ROW_PAGE'=>$lang['nb_row_per_page'],
+        'L_NB_ROW_PAGE_INFO'=>$lang['conf_nb_line_page_info'],
+        'L_CONF_STYLE'=>$lang['theme'],
+        'L_CONF_STYLE_INFO'=>$lang['conf_default_theme_info'],
+        'L_CONF_RECENT'=>$lang['recent_period'],
+        'L_CONF_RECENT_INFO'=>$lang['conf_recent_period_info'],
+        'L_CONF_EXPAND'=>$lang['auto_expand'],
+        'L_CONF_EXPAND_INFO'=>$lang['conf_default_expand_info'],
+        'L_NB_COMMENTS'=>$lang['show_nb_comments'],
+        'L_NB_COMMENTS_INFO'=>$lang['conf_show_nb_comments_info'],
+        'L_MAXWIDTH'=>$lang['maxwidth'],
+        'L_MAXHEIGHT'=>$lang['maxheight'],
+  
+        'CONF_LANG_SELECT'=>language_select($conf['default_language'], 'default_language'),
+        'NB_IMAGE_LINE'=>$conf['nb_image_line'],
+        'NB_ROW_PAGE'=>$conf['nb_line_page'],
+        'CONF_STYLE_SELECT'=>style_select($conf['default_template'], 'default_template'),
+        'CONF_RECENT'=>$conf['recent_period'],
+        'NB_COMMENTS_PAGE'=>$conf['nb_comment_page'],
+        'MAXWIDTH'=>$conf['default_maxwidth'],
+        'MAXHEIGHT'=>$conf['default_maxheight'],
+        'EXPAND_YES'=>$expand_yes,
+        'EXPAND_NO'=>$expand_no,
+        'SHOW_COMMENTS_YES'=>$show_yes,
+        'SHOW_COMMENTS_NO'=>$show_no
+        ));
+    break;
+  }
+  case 'upload' :
+  {
+    $template->assign_block_vars(
+      'upload',
+      array(
+        'L_CONF_TITLE'=>$lang['conf_upload_title'],
+        'L_CONF_MAXSIZE'=>$lang['conf_upload_maxfilesize'],
+        'L_CONF_MAXSIZE_INFO'=>$lang['conf_upload_maxfilesize_info'],
+        'L_CONF_MAXWIDTH'=>$lang['conf_upload_maxwidth'],
+        'L_CONF_MAXWIDTH_INFO'=>$lang['conf_upload_maxwidth_info'],
+        'L_CONF_MAXHEIGHT'=>$lang['conf_upload_maxheight'],
+        'L_CONF_MAXHEIGHT_INFO'=>$lang['conf_upload_maxheight_info'],
+        'L_CONF_TN_MAXWIDTH'=>$lang['conf_upload_tn_maxwidth'],
+        'L_CONF_TN_MAXWIDTH_INFO'=>$lang['conf_upload_tn_maxwidth_info'],
+        'L_CONF_TN_MAXHEIGHT'=>$lang['conf_upload_tn_maxheight'],
+        'L_CONF_TN_MAXHEIGHT_INFO'=>$lang['conf_upload_tn_maxheight_info'],
+          
+        'UPLOAD_MAXSIZE'=>$conf['upload_maxfilesize'],
+        'UPLOAD_MAXWIDTH'=>$conf['upload_maxwidth'],
+        'UPLOAD_MAXHEIGHT'=>$conf['upload_maxheight'],
+        'TN_UPLOAD_MAXWIDTH'=>$conf['upload_maxwidth_thumbnail'],
+        'TN_UPLOAD_MAXHEIGHT'=>$conf['upload_maxheight_thumbnail'],
+        ));
+    break;
+  }
+  case 'session' :
+  {
+    $authorize_remembering_yes =
+      ($conf['authorize_remembering']=='true')?'checked="checked"':'';
+    $authorize_remembering_no =
+      ($conf['authorize_remembering']=='false')?'checked="checked"':'';
+      
+    $template->assign_block_vars(
+      'session',
+      array(
+        'L_CONF_TITLE'=>$lang['conf_session_title'],
+        'L_CONF_AUTHORIZE_REMEMBERING'=>$lang['conf_authorize_remembering'],
+        'L_CONF_AUTHORIZE_REMEMBERING_INFO' =>
+        $lang['conf_authorize_remembering_info'],
+
+        'AUTHORIZE_REMEMBERING_YES'=>$authorize_remembering_yes,
+        'AUTHORIZE_REMEMBERING_NO'=>$authorize_remembering_no
+        ));
+    break;
+  }
+  case 'metadata' :
+  {
+    $exif_yes = ($conf['use_exif']=='true')?'checked="checked"':'';
+    $exif_no = ($conf['use_exif']=='false')?'checked="checked"':'';
+    $iptc_yes = ($conf['use_iptc']=='true')?'checked="checked"':'';
+    $iptc_no = ($conf['use_iptc']=='false')?'checked="checked"':'';
+    $show_exif_yes = ($conf['show_exif']=='true')?'checked="checked"':'';
+    $show_exif_no = ($conf['show_exif']=='false')?'checked="checked"':'';
+    $show_iptc_yes = ($conf['show_iptc']=='true')?'checked="checked"':'';
+    $show_iptc_no = ($conf['show_iptc']=='false')?'checked="checked"':'';
+      
+    $template->assign_block_vars(
+      'metadata',
+      array(
+        'L_CONF_TITLE'=>$lang['conf_metadata_title'],
+        'L_CONF_EXIF'=>$lang['conf_use_exif'],
+        'L_CONF_EXIF_INFO'=>$lang['conf_use_exif_info'],
+        'L_CONF_IPTC'=>$lang['conf_use_iptc'],
+        'L_CONF_IPTC_INFO'=>$lang['conf_use_iptc_info'],
+        'L_CONF_SHOW_EXIF'=>$lang['conf_show_exif'],
+        'L_CONF_SHOW_EXIF_INFO'=>$lang['conf_show_exif_info'],
+        'L_CONF_SHOW_IPTC'=>$lang['conf_show_iptc'],
+        'L_CONF_SHOW_IPTC_INFO'=>$lang['conf_show_iptc_info'],
+          
+        'USE_EXIF_YES'=>$exif_yes,
+        'USE_EXIF_NO'=>$exif_no,
+        'USE_IPTC_YES'=>$iptc_yes,
+        'USE_IPTC_NO'=>$iptc_no,
+        'SHOW_EXIF_YES'=>$show_exif_yes,
+        'SHOW_EXIF_NO'=>$show_exif_no,
+        'SHOW_IPTC_YES'=>$show_iptc_yes,
+        'SHOW_IPTC_NO'=>$show_iptc_no
+        ));
+    break;
+  }
+}
+//-------------------------------------------------------------- errors display
+if ( sizeof( $errors ) != 0 )
+{
+  $template->assign_block_vars('errors',array());
+  for ( $i = 0; $i < sizeof( $errors ); $i++ )
+  {
+    $template->assign_block_vars('errors.error',array('ERROR'=>$errors[$i]));
+  }
+}
+elseif ( isset( $_POST['submit'] ) )
+{
+  $template->assign_block_vars('confirmation' ,array());
+}
+//----------------------------------------------------------- sending html code
+$template->assign_var_from_handle('ADMIN_CONTENT', 'config');
+?>
Index: /branches/1.4/admin/group_list.php
===================================================================
--- /branches/1.4/admin/group_list.php	(revision 3249)
+++ /branches/1.4/admin/group_list.php	(revision 3249)
@@ -0,0 +1,204 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+if( !defined("PHPWG_ROOT_PATH") )
+{
+	die ("Hacking attempt!");
+}
+include_once( PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php' );
+
+//-------------------------------------------------------------- delete a group
+$error = array();
+if ( isset( $_POST['delete'] ) && isset( $_POST['confirm_delete'] )  )
+{
+  // destruction of the access linked to the group
+  $query = 'DELETE FROM '.GROUP_ACCESS_TABLE;
+  $query.= ' WHERE group_id = '.$_POST['group_id'];
+  $query.= ';';
+  pwg_query( $query );
+	
+	// destruction of the users links for this group
+  $query = 'DELETE FROM ' . USER_GROUP_TABLE; 
+  $query.= ' WHERE group_id = '.$_POST['group_id'];
+	pwg_query( $query );
+	
+	// destruction of the group
+	$query = 'DELETE FROM ' . GROUPS_TABLE; 
+  $query.= ' WHERE id = '.$_POST['group_id'];
+	$query.= ';';
+	pwg_query( $query );
+}
+//----------------------------------------------------------------- add a group
+elseif ( isset( $_POST['new'] ) )
+{
+  if ( empty($_POST['newgroup']) || preg_match( "/'/", $_POST['newgroup'] )
+       or preg_match( '/"/', $_POST['newgroup'] ) )
+  {
+    array_push( $error, $lang['group_add_error1'] );
+  }
+  if ( count( $error ) == 0 )
+  {
+    // is the group not already existing ?
+    $query = 'SELECT id FROM '.GROUPS_TABLE;
+    $query.= " WHERE name = '".$_POST['newgroup']."'";
+    $query.= ';';
+    $result = pwg_query( $query );
+    if ( mysql_num_rows( $result ) > 0 )
+    {
+      array_push( $error, $lang['group_add_error2'] );
+    }
+  }
+  if ( count( $error ) == 0 )
+  {
+    // creating the group
+    $query = ' INSERT INTO '.GROUPS_TABLE;
+    $query.= " (name) VALUES ('".$_POST['newgroup']."')";
+    $query.= ';';
+    pwg_query( $query );
+  }
+}
+//--------------------------------------------------------------- user management
+elseif ( isset( $_POST['add'] ) )
+{
+  $userdata = getuserdata($_POST['username']);
+  if (!$userdata)
+  {
+    array_push($error, $lang['user_err_unknown']);
+  }
+  else
+  {
+    // create a new association between the user and a group
+    $query = '
+INSERT INTO '.USER_GROUP_TABLE.'
+  (user_id,group_id)
+  VALUES
+  ('.$userdata['id'].','.$_POST['edit_group_id'].')
+;';
+    pwg_query($query);
+  }
+}
+elseif (isset( $_POST['deny_user'] ))
+{
+  $sql_in = '';
+	$members = $_POST['members'];
+	for($i = 0; $i < count($members); $i++)
+  {
+    $sql_in .= ( ( $sql_in != '' ) ? ', ' : '' ) . intval($members[$i]);
+  }
+  $query = 'DELETE FROM ' . USER_GROUP_TABLE; 
+  $query.= ' WHERE user_id IN ('.$sql_in;
+	$query.= ') AND group_id = '.$_POST['edit_group_id'];
+	pwg_query( $query );
+}
+//-------------------------------------------------------------- errors display
+if ( sizeof( $error ) != 0 )
+{
+  $template->assign_block_vars('errors',array());
+  for ( $i = 0; $i < sizeof( $error ); $i++ )
+  {
+    $template->assign_block_vars('errors.error',array('ERROR'=>$error[$i]));
+  }
+}
+//----------------------------------------------------------------- groups list
+
+$query = 'SELECT id,name FROM '.GROUPS_TABLE;
+$query.= ' ORDER BY id ASC;';
+$result = pwg_query( $query );
+$groups_display = '<select name="group_id">';
+$groups_nb=0;
+while ( $row = mysql_fetch_array( $result ) )
+{
+  $groups_nb++;
+	$selected = '';
+	if (isset($_POST['group_id']) && $_POST['group_id']==$row['id'])
+		$selected = 'selected';
+  $groups_display .= '<option value="' . $row['id'] . '" '.$selected.'>' . $row['name']  . '</option>';
+}
+$groups_display .= '</select>';
+
+$action = PHPWG_ROOT_PATH.'admin.php?page=group_list';
+//----------------------------------------------------- template initialization
+$template->set_filenames( array('groups'=>'admin/group_list.tpl') );
+$template->assign_vars(array(
+  'S_GROUP_SELECT'=>$groups_display,
+	
+  'L_GROUP_SELECT'=>$lang['group_list_title'],
+  'L_GROUP_CONFIRM'=>$lang['group_confirm_delete'],
+  'L_LOOK_UP'=>$lang['edit'],
+  'L_GROUP_DELETE'=>$lang['delete'],
+  'L_CREATE_NEW_GROUP'=>$lang['group_add'],
+  'L_GROUP_EDIT'=>$lang['group_edit'],
+  'L_USER_NAME'=>$lang['login'],
+  'L_USER_EMAIL'=>$lang['mail_address'],
+  'L_USER_SELECT'=>$lang['Select'],
+  'L_DENY_SELECTED'=>$lang['group_deny_user'],
+  'L_ADD_MEMBER'=>$lang['group_add_user'],
+  'L_FIND_USERNAME'=>$lang['Find_username'],
+	
+  'S_GROUP_ACTION'=>add_session_id($action),
+  'U_SEARCH_USER' => add_session_id(PHPWG_ROOT_PATH.'admin/search.php')
+  ));
+
+if ($groups_nb) 
+{
+  $template->assign_block_vars('select_box',array());
+}
+
+//----------------------------------------------------------------- add a group
+if ( isset( $_POST['edit']) || isset( $_POST['add']) || isset( $_POST['deny_user'] ))
+{
+  // Retrieving the group name
+  $query = 'SELECT id, name FROM '.GROUPS_TABLE;
+  $query.= " WHERE id = '".$_POST['group_id']."'";
+  $query.= ';';
+  $result = mysql_fetch_array(pwg_query( $query ));
+  $template->assign_block_vars('edit_group',array(
+	  'GROUP_NAME'=>$result['name'],
+	  'GROUP_ID'=>$result['id']
+		));
+		
+  // Retrieving all the users
+  $query = 'SELECT id, username, mail_address';
+  $query.= ' FROM ('.USERS_TABLE.' as u';
+  $query.= ' LEFT JOIN '.USER_GROUP_TABLE.' as ug ON ug.user_id=u.id)';
+  $query.= " WHERE ug.group_id = '".$_POST['group_id']."';";
+  $result = pwg_query( $query );
+  $i=0;
+  while ( $row = mysql_fetch_array( $result ) )
+  {
+    $class = ($i % 2)? 'row1':'row2'; $i++;
+	$template->assign_block_vars('edit_group.user',array(
+		'ID'=>$row['id'],
+		'NAME'=>$row['username'],
+		'EMAIL'=>$row['mail_address'],
+		'T_CLASS'=>$class
+	));
+  }
+}
+
+//----------------------------------------------------------- sending html code
+$template->assign_var_from_handle('ADMIN_CONTENT', 'groups');
+?>
Index: /branches/1.4/admin/group_perm.php
===================================================================
--- /branches/1.4/admin/group_perm.php	(revision 3249)
+++ /branches/1.4/admin/group_perm.php	(revision 3249)
@@ -0,0 +1,167 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+if( !defined("PHPWG_ROOT_PATH") )
+{
+	die ("Hacking attempt!");
+}
+
+include_once( PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php' );
+//--------------------------------------------------------------------- updates
+if (isset($_POST['falsify'])
+         and isset($_POST['cat_true'])
+         and count($_POST['cat_true']) > 0)
+{
+  // if you forbid access to a category, all sub-categories become
+  // automatically forbidden
+  $subcats = get_subcat_ids($_POST['cat_true']);
+  $query = 'DELETE FROM '.GROUP_ACCESS_TABLE.'
+    WHERE group_id = '.$_POST['group_id'].'
+    AND cat_id IN ('.implode(',', $subcats).');';
+  pwg_query($query);
+}
+else if (isset($_POST['trueify'])
+         and isset($_POST['cat_false'])
+         and count($_POST['cat_false']) > 0)
+{
+  $uppercats = get_uppercat_ids($_POST['cat_false']);
+  $private_uppercats = array();
+
+  $query = 'SELECT id
+    FROM '.CATEGORIES_TABLE.'
+    WHERE id IN ('.implode(',', $uppercats).')
+    AND status = \'private\';';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($private_uppercats, $row['id']);
+  }
+
+  // retrying to authorize a category which is already authorized may cause
+  // an error (in SQL statement), so we need to know which categories are
+  // accesible
+  $authorized_ids = array();
+    
+  $query = 'SELECT cat_id
+  FROM '.GROUP_ACCESS_TABLE.'
+  WHERE group_id = '.$_POST['group_id'].';';
+  $result = pwg_query($query);
+  
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($authorized_ids, $row['cat_id']);
+  }
+  
+  $inserts = array();
+  $to_autorize_ids = array_diff($private_uppercats, $authorized_ids);
+  foreach ($to_autorize_ids as $to_autorize_id)
+  {
+    array_push($inserts, array('group_id' => $_POST['group_id'],
+                               'cat_id' => $to_autorize_id));
+  }
+
+  mass_inserts(GROUP_ACCESS_TABLE, array('group_id','cat_id'), $inserts);
+}
+
+//----------------------------------------------------- template initialization
+$query = 'SELECT id,name FROM '.GROUPS_TABLE;
+$query.= ' ORDER BY id ASC;';
+$result = pwg_query( $query );
+$groups_display = '<select name="group_id">';
+$groups_nb=0;
+while ( $row = mysql_fetch_array( $result ) )
+{
+  $groups_nb++;
+  $selected = '';
+  if (isset($_POST['group_id']) && $_POST['group_id']==$row['id'])
+		$selected = 'selected';
+  $groups_display .= '<option value="' . $row['id'] . '" '.$selected.'>' . $row['name']  . '</option>';
+}
+$groups_display .= '</select>';
+
+$action = PHPWG_ROOT_PATH.'admin.php?page=group_perm';
+$template->set_filenames( array('groups'=>'admin/group_perm.tpl') );
+$template->assign_vars(array(
+  'S_GROUP_SELECT'=>$groups_display,
+  'L_GROUP_SELECT'=>$lang['group_list_title'],
+  'L_LOOK_UP'=>$lang['edit'],
+  'S_GROUP_ACTION'=>add_session_id($action)
+  ));
+  
+if ($groups_nb) 
+{
+  $template->assign_block_vars('select_box',array());
+}
+
+if ( isset( $_POST['edit']) || isset($_POST['falsify']) || isset($_POST['trueify']))
+{
+  $template->set_filenames(array('groups_auth'=>'admin/cat_options.tpl'));
+  $template->assign_vars(array(
+      'L_RESET'=>$lang['reset'],
+      'L_CAT_OPTIONS_TRUE'=>$lang['authorized'],
+      'L_CAT_OPTIONS_FALSE'=>$lang['forbidden'],
+      'L_CAT_OPTIONS_INFO'=>$lang['permuser_info'],
+      
+      'HIDDEN_NAME'=> 'group_id',
+      'HIDDEN_VALUE'=>$_POST['group_id'],
+      'F_ACTION' => add_session_id(PHPWG_ROOT_PATH.'admin.php?page=group_perm'),
+  ));
+  
+  // only private categories are listed
+  $query_true = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.' INNER JOIN '.GROUP_ACCESS_TABLE.' ON cat_id = id
+  WHERE status = \'private\'
+    AND group_id = '.$_POST['group_id'].'
+;';
+  display_select_cat_wrapper($query_true,array(),'category_option_true');
+  
+  $result = pwg_query($query_true);
+  $authorized_ids = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($authorized_ids, $row['id']);
+  }
+  
+  $query_false = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE status = \'private\'';
+  if (count($authorized_ids) > 0)
+  {
+    $query_false.= '
+    AND id NOT IN ('.implode(',', $authorized_ids).')';
+  }
+  $query_false.= '
+;';
+  display_select_cat_wrapper($query_false,array(),'category_option_false');
+  
+  $template->assign_var_from_handle('ADMIN_CONTENT_2', 'groups_auth');
+}
+//----------------------------------------------------------- sending html code
+$template->assign_var_from_handle('ADMIN_CONTENT', 'groups');
+
+?>
Index: /branches/1.4/admin/help.php
===================================================================
--- /branches/1.4/admin/help.php	(revision 3249)
+++ /branches/1.4/admin/help.php	(revision 3249)
@@ -0,0 +1,46 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+include_once( PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php' );
+//----------------------------------------------------- template initialization
+$template->set_filenames( array('help'=>'admin/help.tpl') );
+
+//----------------------------------------------------- help categories display
+$categories = array('images','thumbnails','database','access','groups',
+                    'remote','upload','virtual','infos');
+foreach ($categories as $category)
+{
+  $template->assign_block_vars(
+    'cat',
+    array('NAME'=>$lang['help_'.$category.'_title']));
+  
+  foreach ($lang['help_'.$category] as $item)
+  {
+    $template->assign_block_vars('cat.item', array('CONTENT'=>$item));
+  }
+}
+$template->assign_var_from_handle('ADMIN_CONTENT', 'help');
+?>
Index: /branches/1.4/admin/images/global_stats.img.php
===================================================================
--- /branches/1.4/admin/images/global_stats.img.php	(revision 3249)
+++ /branches/1.4/admin/images/global_stats.img.php	(revision 3249)
@@ -0,0 +1,121 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+//----------------------------------------------------------- include
+define('PHPWG_ROOT_PATH','../../');
+define('IN_ADMIN', true);
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+include_once( PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php' );
+include_once( 'phpBarGraph.php' );
+
+//------------------------------------------------ variable definition
+$outputFormat = "png";
+$legend = $lang['stats_global_graph_title'];
+$imageHeight = 256;
+$imageWidth = 320;
+$sql = "SELECT DISTINCT COUNT(*), MONTH(date) 
+  FROM ".HISTORY_TABLE." 
+  WHERE (date > DATE_SUB(CURRENT_DATE(), INTERVAL 12 MONTH)) 
+  GROUP BY DATE_FORMAT(date,'%Y-%m') DESC;";
+
+//------------------------------------------------ Image definition
+$image = ImageCreate($imageWidth, $imageHeight);
+//$image = ImageCreateTrueColor($imageWidth, $imageHeight);
+// Fill it with your favorite background color..
+$backgroundColor = ImageColorAllocate($image, 184, 184, 184);
+ImageFill($image, 0, 0, $backgroundColor);
+$white = ImageColorAllocate($image, 0, 0, 0);
+
+// Interlace the image..
+Imageinterlace($image, 1);
+
+// Create a new BarGraph..
+$myBarGraph = new PhpBarGraph;
+$myBarGraph->SetX(10);              // Set the starting x position
+$myBarGraph->SetY(10);              // Set the starting y position
+$myBarGraph->SetWidth($imageWidth-20);    // Set how wide the bargraph will be
+$myBarGraph->SetHeight($imageHeight-20);  // Set how tall the bargraph will be
+$myBarGraph->SetNumOfValueTicks(3); // Set this to zero if you don't want to show any. These are the vertical bars to help see the values.
+
+
+// You can try uncommenting these lines below for different looks.
+
+// $myBarGraph->SetShowLabels(false);  // The default is true. Setting this to false will cause phpBarGraph to not print the labels of each bar.
+ $myBarGraph->SetShowValues(false);  // The default is true. Setting this to false will cause phpBarGraph to not print the values of each bar.
+// $myBarGraph->SetBarBorder(false);   // The default is true. Setting this to false will cause phpBarGraph to not print the border of each bar.
+// $myBarGraph->SetShowFade(false);    // The default is true. Setting this to false will cause phpBarGraph to not print each bar as a gradient.
+// $myBarGraph->SetShowOuterBox(false);   // The default is true. Setting this to false will cause phpBarGraph to not print the outside box.
+$myBarGraph->SetBarSpacing(5);     // The default is 10. This changes the space inbetween each bar.
+
+
+// Add Values to the bargraph..
+$result = pwg_query($sql)
+or die(mysql_errno().": ".mysql_error()."<BR>".$sql);
+
+//$monthes =array_fill(1,12,0);
+$monthes =array();
+$date = getdate();
+$current_month = $date['mon'];
+for ($i=0;$i<12;$i++)
+{
+  $monthes[(($current_month-$i+11)%12)+1]=0;
+}
+
+while ($r = mysql_fetch_row($result))
+{ 
+  if (!$monthes[$r[1]]) $monthes[$r[1]]= $r[0];
+}
+$monthes = array_reverse($monthes,true);
+while (list ($key,$value) = each($monthes))
+{
+  $nls_key = substr($lang['month'][$key],0,3);
+  $myBarGraph->AddValue($nls_key, $value);
+}
+
+//$myBarGraph->SetDebug(true);
+// Set the colors of the bargraph..
+$myBarGraph->SetStartBarColor("6666ff");  // This is the color on the top of every bar.
+$myBarGraph->SetEndBarColor("2222aa");    // This is the color on the bottom of every bar. This is not used when SetShowFade() is set to false.
+$myBarGraph->SetLineColor("000000");      // This is the color all the lines and text are printed out with.
+
+// Print the BarGraph to the image..
+$myBarGraph->DrawBarGraph($image);
+Imagestring($image, 2, 2, $imageHeight-14, $legend, $white);
+   
+//------------------------------------------------ Image output
+if ($outputFormat == "png")
+{
+  header("Content-type: image/png");
+  ImagePNG($image);
+}
+else if ($outputFormat == "jpg")
+{
+  header("Content-type: image/jpeg");
+  Imagejpeg($image);
+}
+// Destroy the image.
+Imagedestroy($image);
+?> 
Index: /branches/1.4/admin/images/index.htm
===================================================================
--- /branches/1.4/admin/images/index.htm	(revision 3249)
+++ /branches/1.4/admin/images/index.htm	(revision 3249)
@@ -0,0 +1,8 @@
+<html>
+    <head>
+        <title>PhpWebGallery</title>
+    </head>
+    <body>
+        No access authorized
+    </body>
+</html>
Index: /branches/1.4/admin/images/phpBarGraph.php
===================================================================
--- /branches/1.4/admin/images/phpBarGraph.php	(revision 3249)
+++ /branches/1.4/admin/images/phpBarGraph.php	(revision 3249)
@@ -0,0 +1,391 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Original PhpBarGraph Version 2.3 
+// Written By TJ Hunter (tjhunter@ruistech.com)
+// http://www.ruistech.com/phpBarGraph
+// This class has been adapted to fill phpWG requirements
+
+class PhpBarGraph
+{
+   /* -------------------------------- */
+   /* Preference Variables             */
+   /* -------------------------------- */
+   var $_debug;
+   var $_image;            // The image to print the bargraph too.
+   var $_x;                // The starting column of the bargraph
+   var $_y;                // The starting row of the bargraph
+   var $_width;            // The width of the bargraph
+   var $_height;           // The height of the bargraph
+   var $_startBarColorHex; // The top color of the bargraph
+   var $_endBarColorHex;   // The bottom color of the bargraph
+   var $_lineColorHex;     // The color of the lines and text
+   var $_barSpacing;       // The spacing width in between each bar
+   var $_numOfValueTicks;  // The number of horizontal rule ticks
+   var $_values;           // An array of arrays of the values of each bargraph and it's label
+   var $_showLabels;       // If true, print the labels to the image
+   var $_showValues;       // If true, print the values to the image
+   var $_showBarBorder;    // If true, draws a box of around each bar
+   var $_showFade;         // If true, draws each bar with a gradient
+   var $_showOuterBox;     // If true, draws the box on the outside of the bargraph
+
+   /* -------------------------------- */
+   /* Private Variables                */
+   /* -------------------------------- */
+   var $_topMargin;
+   var $_bottomMargin;
+   var $_leftMargin;
+   var $_rightMargin;
+   var $_barWidth;
+   var $_minBarHeight;
+   var $_maxBarHeight;
+   var $_realMinBarHeight;
+   var $_realMaxBarHeight;
+   var $_buffer;
+
+   function PhpBarGraph()
+   {
+      $this->_debug = false;
+      $this->_values = array();
+      $this->_startBarColorHex = "0000ff";
+      $this->_endBarColorHex = "ffffff";
+      $this->_lineColorHex = "000000";
+      $this->_barSpacing = 10;
+      $this->_numOfValueTicks = 4;
+      $this->_buffer = .5;
+      $this->_showLabels = true;
+      $this->_showValues = true;
+      $this->_showBarBorder = true;
+      $this->_showFade = true;
+      $this->_showOuterBox = true;
+   }
+
+   function AddValue($labelName, $theValue)
+   {
+      array_push($this->_values, array("label" => $labelName, "value" => $theValue));
+   }
+
+   function SetDebug($debug)
+   {
+      $this->_debug = $debug;
+   }
+
+   function SetX($x)
+   {
+      $this->_x = $x;
+   }
+
+   function SetY($y)
+   {
+      $this->_y = $y;
+   }
+
+   function SetWidth($width)
+   {
+      $this->_width = $width;
+   }
+
+   function SetHeight($height)
+   {
+      $this->_height = $height;
+   }
+
+   function SetStartBarColor($color)
+   {
+      $this->_startBarColorHex = $color;
+   }
+
+   function SetEndBarColor($color)
+   {
+      $this->_endBarColorHex = $color;
+   }
+
+   function SetLineColor($color)
+   {
+      $this->_lineColorHex = $color;
+   }
+
+   function SetBarSpacing($barSpacing)
+   {
+      $this->_barSpacing = $barSpacing;
+   }
+
+   function SetNumOfValueTicks($ticks)
+   {
+      $this->_numOfValueTicks = $ticks;
+   }
+
+   function SetShowLabels($labels)
+   {
+      $this->_showLabels = $labels;
+   }
+
+   function SetShowValues($values)
+   {
+      $this->_showValues = $values;
+   }
+
+   function SetBarBorder($border)
+   {
+      $this->_showBarBorder = $border;
+   }
+
+   function SetShowFade($fade)
+   {
+      $this->_showFade = $fade;
+   }
+
+   function SetShowOuterBox($box)
+   {
+      $this->_showOuterBox = $box;
+   }
+
+
+   function RGBColor($hexColor) // Returns an array of decimal values from a hex color
+   {
+      $r = hexdec(substr($hexColor, 0, 2));
+      $g = hexdec(substr($hexColor, 2, 2));
+      $b = hexdec(substr($hexColor, 4, 2));
+
+      $RGBColors = array("red" => $r, "green" => $g, "blue" => $b);
+
+      return $RGBColors;
+   }
+
+   function DebugPrint() // Prints a bunch of debug information.
+   {
+      foreach($this->_values as $value)
+      {
+         echo $value["label"] . "=" . $value["value"] . "<br>\n";
+      }
+
+      $startColor = $this->RGBColor($this->_startBarColorHex);
+      echo "StartColor: " . $startColor["red"] . ", " . $startColor["green"] . ", " . $startColor["blue"] . "<br>\n";
+
+      $endColor = $this->RGBColor($this->_endBarColorHex);
+      echo "EndColor: " . $endColor["red"] . ", " . $endColor["green"] . ", " . $endColor["blue"] . "<br>\n";
+
+      $lineColor = $this->RGBColor($this->_lineColorHex);
+      echo "LineColor: " . $lineColor["red"] . ", " . $lineColor["green"] . ", " . $lineColor["blue"] . "<br>\n";
+
+      echo "x=" . $this->_x . "<br>\n";
+      echo "y=" . $this->_y . "<br>\n";
+      echo "width=" . $this->_width . "<br>\n";
+      echo "height=" . $this->_height . "<br>\n";
+      echo "startBarColorHex=" . $this->_startBarColorHex . "<br>\n";
+      echo "endBarColorHex=" . $this->_endBarColorHex . "<br>\n";
+      echo "lineColorHex=" . $this->_lineColorHex . "<br>\n";
+      echo "barSpacing=" . $this->_barSpacing . "<br>\n";
+      echo "numOfValueTicks=" . $this->_numOfValueTicks . "<br>\n";
+
+   }
+
+   function dif ($start,$end)
+   {
+	   if ($start >= $end)
+		   $dif = $start - $end;
+   	else
+	   	$dif = $end - $start;
+		
+	   return $dif;
+   }
+
+   function draw($start,$end,$pos,$step_width)
+   {
+   	if ($start > $end)	
+   		$color = $start - $step_width * $pos;
+   	else
+   		$color = $start + $step_width * $pos;
+   		
+   	return $color;
+   }	
+
+   function fadeBar($image, $x1, $y1, $x2, $y2, $colorsStart, $colorsEnd, $height, $width) // Draws a rectangle with a gradient
+   {
+      $startColor = $this->RGBColor($colorsStart);
+      $red_start = $startColor["red"];
+      $green_start = $startColor["green"];
+      $blue_start = $startColor["blue"];
+
+      $endColor = $this->RGBColor($colorsEnd);
+      $red_end = $endColor["red"];
+      $green_end = $endColor["green"];
+      $blue_end = $endColor["blue"];
+      
+      // difference between start and end
+      $dif_red = $this->dif($red_start,$red_end);
+      $dif_green = $this->dif($green_start,$green_end);
+      $dif_blue = $this->dif($blue_start,$blue_end);
+      
+      $height = $height + 1;
+
+      // width of one color step
+      $step_red = $dif_red / $height;
+      $step_green = $dif_green / $height;
+      $step_blue = $dif_blue / $height;
+      $width = $width - 1;
+      
+      
+      for ($pos=0; $pos<=$height; $pos++)
+      {
+         $color = imagecolorexact ($image, $this->draw($red_start,$red_end,$pos,$step_red),
+      						   			$this->draw($green_start,$green_end,$pos,$step_green),
+      						   			$this->draw($blue_start,$blue_end,$pos,$step_blue));
+         if ($color == -1) // If this color is already allocatated, don't allocate it again.
+         {
+         	$color = ImageColorAllocate($image,$this->draw($red_start,$red_end,$pos,$step_red),
+         						   			$this->draw($green_start,$green_end,$pos,$step_green),
+         						   			$this->draw($blue_start,$blue_end,$pos,$step_blue));	
+         }      	
+      	imageline($image,$x1,$pos+$y1,$x1+$width,$pos+$y1,$color);
+      	
+      }
+      
+   }
+
+   function DrawBarGraph($image)
+   {
+      if ($this->_debug)
+         $this->DebugPrint();
+
+      // Setup the margins
+      $this->_topMargin = 0;
+      $this->_bottomMargin = 30;
+      $this->_leftMargin = 20;
+      $this->_rightMargin = $this->_barSpacing + 1 + 10;
+
+      // setup the color for the lines
+      $tempLineColor = $this->RGBColor($this->_lineColorHex);
+      $lineColor = ImageColorAllocate($image, $tempLineColor["red"], $tempLineColor["green"], $tempLineColor["blue"]);
+
+      $tempStartColor = $this->RGBColor($this->_startBarColorHex);
+      $startColor = ImageColorAllocate($image, $tempStartColor["red"], $tempStartColor["green"], $tempStartColor["blue"]);
+
+      // Figure out how wide each bar is going to be.
+      $this->_barWidth = ($this->_width - ($this->_leftMargin + $this->_rightMargin + 1) - (count($this->_values) * $this->_barSpacing)) / count($this->_values);
+
+      // Find out what the smallest and largest amount is.
+      $this->_minBarHeight = $this->_values[0]["value"];
+      $this->_maxBarHeight = $this->_values[0]["value"];
+      for ($i=1; $i < count($this->_values); $i++)
+      {
+         if ($this->_minBarHeight > $this->_values[$i]["value"])
+         {
+            $this->_minBarHeight = $this->_values[$i]["value"];
+         }
+         if ($this->_maxBarHeight < $this->_values[$i]["value"])
+         {
+            $this->_maxBarHeight = $this->_values[$i]["value"];
+         }
+      }
+      
+      if ($this->_minBarHeight == 0 && $this->_maxBarHeight > 0) // Having the min value as 0 looks funny
+      {
+         $this->_minBarHeight = 1;
+      }
+      $buff = 1;
+      // Figure out how tall the tallest and smallest bar are going to be.
+      $this->_realMinBarHeight = $this->_minBarHeight - ($this->_minBarHeight * $buff + 1);
+      $this->_realMaxBarHeight = $this->_maxBarHeight * ($this->_buffer + 1);
+      $workArea = $this->_height - $this->_bottomMargin - $this->_topMargin - 1;
+
+      // Print out all the ticks
+      if ($this->_numOfValueTicks > $this->_maxBarHeight)
+      {
+         $this->_numOfValueTicks = $this->_maxBarHeight;
+      }
+      
+      for ($i=1; $i<=$this->_numOfValueTicks; $i++)
+      {
+         $thisBarValue = floor((($this->_maxBarHeight - $this->_minBarHeight) / $this->_numOfValueTicks) * $i) + $this->_minBarHeight;
+         $myTickheight = ($workArea / ($this->_maxBarHeight - $this->_realMinBarHeight) * ($thisBarValue - $this->_realMinBarHeight));
+
+         // Figure out where we're going to put this tick..
+         $y1 = $this->_height - $this->_bottomMargin - 1 - ($myTickheight);
+
+         if ($thisBarValue >= $this->_minBarHeight)
+         {
+            imageline($image, $this->_leftMargin - 5 + $this->_x, $y1 + $this->_y,  $this->_width - $this->_rightMargin + $this->_barSpacing + $this->_x, $y1 + $this->_y, $lineColor);
+            Imagestring($image, 1, $this->_leftMargin + $this->_x - 15, $y1 + $this->_y + 2, $thisBarValue, $lineColor);
+         }
+      }
+      
+      // Print out all the bars
+      for ($i=1; $i<=count($this->_values); $i++)
+      {
+         // Get the bar height for this bar.
+         $myBarheight = ($workArea / ($this->_maxBarHeight - $this->_realMinBarHeight) * ($this->_values[$i-1]["value"] - $this->_realMinBarHeight));
+         
+         // Figure out where we're going to put this bar..
+         $x1 = $this->_leftMargin + 1 + (($i-1) * $this->_barWidth) + ($i * $this->_barSpacing);
+         $y1 = $this->_height - $this->_bottomMargin - 1 - ($myBarheight);
+         $x2 = $this->_leftMargin + (($i-1) * $this->_barWidth) + ($i * $this->_barSpacing) + $this->_barWidth;
+         $y2 = $this->_height - $this->_bottomMargin - 1;
+   
+         if ($this->_values[$i-1]["value"] != 0) // Don't print a bar if the value is 0
+         {
+            // Print the bar
+            if ($this->_showFade)
+            {
+               $this->fadeBar($image, $x1 + $this->_x, $y1 + $this->_y, $x2 + $this->_x, $y2 + $this->_y, $this->_startBarColorHex, $this->_endBarColorHex, $myBarheight, $this->_barWidth);
+            }
+            else
+            {
+               ImageFilledRectangle($image, $x1 + $this->_x, $y1 + $this->_y, $x2 + $this->_x, $y2 + $this->_y, $startColor);
+            }
+   
+            if ($this->_showBarBorder)
+            {
+               ImageRectangle($image, $x1 + $this->_x, $y1 + $this->_y, $x2 + $this->_x, $y2 + $this->_y + 1, $lineColor);
+            }
+         }   
+         // Print the amount of the bar
+         if ($this->_showValues)
+         {
+            Imagestring($image, 2, $x1 + $this->_x, $this->_height-($this->_bottomMargin/2)-10 + $this->_y, $this->_values[$i-1]["value"], $lineColor); 
+         }
+
+         // Print out the label of the bar.
+         if ($this->_showLabels)
+         {
+            Imagestring($image, 2, $x1 + $this->_x, $this->_height-($this->_bottomMargin/2) + $this->_y, $this->_values[$i-1]["label"], $lineColor); 
+         }
+      }
+
+      // draw the border box
+      if ($this->_showOuterBox)
+      {
+         ImageRectangle($image, $this->_leftMargin + $this->_x, $this->_topMargin + $this->_y, $this->_width - $this->_rightMargin + $this->_barSpacing + $this->_x, $this->_height - $this->_bottomMargin + $this->_y, $lineColor);
+      }
+
+
+       
+   }
+}
+
+
+?>
Index: /branches/1.4/admin/include/functions.php
===================================================================
--- /branches/1.4/admin/include/functions.php	(revision 3249)
+++ /branches/1.4/admin/include/functions.php	(revision 3249)
@@ -0,0 +1,1329 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+include(PHPWG_ROOT_PATH.'admin/include/functions_metadata.php');
+
+$tab_ext_create_TN = array ( 'jpg', 'png', 'JPG', 'PNG' );
+
+// is_image returns true if the given $filename (including the path) is a
+// picture according to its format and its extension.
+// As GD library can only generate pictures from jpeg and png files, if you
+// ask if the filename is an image for thumbnail creation (second parameter
+// set to true), the only authorized formats are jpeg and png.
+function is_image( $filename, $create_thumbnail = false )
+{
+  global $conf, $tab_ext_create_TN;
+
+  if (is_file($filename)
+      and in_array(get_extension($filename), $conf['picture_ext']))
+  {
+    $size = getimagesize( $filename );
+    // $size[2] == 1 means GIF
+    // $size[2] == 2 means JPG
+    // $size[2] == 3 means PNG
+    if ( !$create_thumbnail )
+    {
+      if ( in_array( get_extension( $filename ), $conf['picture_ext'] )
+           and ( $size[2] == 1 or $size[2] == 2 or $size[2] == 3 ) )
+      {
+        return true;
+      }
+    }
+    else
+    {
+      if ( in_array( get_extension( $filename ), $tab_ext_create_TN )
+           and ( $size[2] == 2 or $size[2] == 3 ) )
+      {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+/**
+ * returns an array with all picture files according to $conf['file_ext']
+ *
+ * @param string $dir
+ * @return array
+ */
+function get_pwg_files($dir)
+{
+  global $conf;
+
+  $pictures = array();
+  if ($opendir = opendir($dir))
+  {
+    while ($file = readdir($opendir))
+    {
+      if (in_array(get_extension($file), $conf['file_ext']))
+      {
+        array_push($pictures, $file);
+      }
+    }
+  }
+  return $pictures;
+}
+
+/**
+ * returns an array with all thumbnails according to $conf['picture_ext']
+ * and $conf['prefix_thumbnail']
+ *
+ * @param string $dir
+ * @return array
+ */
+function get_thumb_files($dir)
+{
+  global $conf;
+
+  $prefix_length = strlen($conf['prefix_thumbnail']);
+  
+  $thumbnails = array();
+  if ($opendir = @opendir($dir.'/thumbnail'))
+  {
+    while ($file = readdir($opendir))
+    {
+      if (in_array(get_extension($file), $conf['picture_ext'])
+          and substr($file, 0, $prefix_length) == $conf['prefix_thumbnail'])
+      {
+        array_push($thumbnails, $file);
+      }
+    }
+  }
+  return $thumbnails;
+}
+
+/**
+ * returns an array with representative picture files of a directory
+ * according to $conf['picture_ext']
+ *
+ * @param string $dir
+ * @return array
+ */
+function get_representative_files($dir)
+{
+  global $conf;
+
+  $pictures = array();
+  if ($opendir = @opendir($dir.'/pwg_representative'))
+  {
+    while ($file = readdir($opendir))
+    {
+      if (in_array(get_extension($file), $conf['picture_ext']))
+      {
+        array_push($pictures, $file);
+      }
+    }
+  }
+  return $pictures;
+}
+
+function TN_exists( $dir, $file )
+{
+  global $conf;
+
+  $filename = get_filename_wo_extension( $file );
+  foreach ( $conf['picture_ext'] as $ext ) {
+    $test = $dir.'/thumbnail/'.$conf['prefix_thumbnail'].$filename.'.'.$ext;
+    if ( is_file ( $test ) )
+    {
+      return $ext;
+    }
+  }
+  return false;
+}
+	
+
+// The function delete_site deletes a site and call the function
+// delete_categories for each primary category of the site
+function delete_site( $id )
+{
+  // destruction of the categories of the site
+  $query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE site_id = '.$id.'
+;';
+  $result = pwg_query($query);
+  $category_ids = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($category_ids, $row['id']);
+  }
+  delete_categories($category_ids);
+		
+  // destruction of the site
+  $query = '
+DELETE FROM '.SITES_TABLE.'
+  WHERE id = '.$id.'
+;';
+  pwg_query($query);
+}
+	
+
+// The function delete_categories deletes the categories identified by the
+// (numeric) key of the array $ids. It also deletes (in the database) :
+//    - all the elements of the category (delete_elements, see further)
+//    - all the links between elements and this category
+//    - all the restrictions linked to the category
+// The function works recursively.
+function delete_categories($ids)
+{
+  global $counts;
+
+  if (count($ids) == 0)
+  {
+    return;
+  }
+
+  // add sub-category ids to the given ids : if a category is deleted, all
+  // sub-categories must be so
+  $ids = get_subcat_ids($ids);
+  
+  // destruction of all the related elements
+  $query = '
+SELECT id
+  FROM '.IMAGES_TABLE.'
+  WHERE storage_category_id IN (
+'.wordwrap(implode(', ', $ids), 80, "\n").')
+;';
+  $result = pwg_query($query);
+  $element_ids = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($element_ids, $row['id']);
+  }
+  delete_elements($element_ids);
+
+  // destruction of the links between images and this category
+  $query = '
+DELETE FROM '.IMAGE_CATEGORY_TABLE.'
+  WHERE category_id IN (
+'.wordwrap(implode(', ', $ids), 80, "\n").')
+;';
+  pwg_query($query);
+
+  // destruction of the access linked to the category
+  $query = '
+DELETE FROM '.USER_ACCESS_TABLE.'
+  WHERE cat_id IN (
+'.wordwrap(implode(', ', $ids), 80, "\n").')
+;';
+  pwg_query($query);
+  $query = '
+DELETE FROM '.GROUP_ACCESS_TABLE.'
+  WHERE cat_id IN (
+'.wordwrap(implode(', ', $ids), 80, "\n").')
+;';
+  pwg_query($query);
+
+  // destruction of the category
+  $query = '
+DELETE FROM '.CATEGORIES_TABLE.'
+  WHERE id IN (
+'.wordwrap(implode(', ', $ids), 80, "\n").')
+;';
+  pwg_query($query);
+
+  if (isset($counts['del_categories']))
+  {
+    $counts['del_categories']+= count($ids);
+  }
+}
+
+// The function delete_elements deletes the elements identified by the
+// (numeric) values of the array $ids. It also deletes (in the database) :
+//    - all the comments related to elements
+//    - all the links between categories and elements
+//    - all the favorites associated to elements
+function delete_elements($ids)
+{
+  global $counts;
+
+  if (count($ids) == 0)
+  {
+    return;
+  }
+  
+  // destruction of the comments on the image
+  $query = '
+DELETE FROM '.COMMENTS_TABLE.'
+  WHERE image_id IN (
+'.wordwrap(implode(', ', $ids), 80, "\n").')
+;';
+  pwg_query($query);
+
+  // destruction of the links between images and this category
+  $query = '
+DELETE FROM '.IMAGE_CATEGORY_TABLE.'
+  WHERE image_id IN (
+'.wordwrap(implode(', ', $ids), 80, "\n").')
+;';
+  pwg_query($query);
+
+  // destruction of the favorites associated with the picture
+  $query = '
+DELETE FROM '.FAVORITES_TABLE.'
+  WHERE image_id IN (
+'.wordwrap(implode(', ', $ids), 80, "\n").')
+;';
+  pwg_query($query);
+
+  // destruction of the rates associated to this element
+  $query = '
+DELETE FROM '.RATE_TABLE.'
+  WHERE element_id IN (
+'.wordwrap(implode(', ', $ids), 80, "\n").')
+;';
+  pwg_query($query);
+		
+  // destruction of the image
+  $query = '
+DELETE FROM '.IMAGES_TABLE.'
+  WHERE id IN (
+'.wordwrap(implode(', ', $ids), 80, "\n").')
+;';
+  pwg_query($query);
+
+  if (isset($counts['del_elements']))
+  {
+    $counts['del_elements']+= count($ids);
+  }
+}
+
+// The delete_user function delete a user identified by the $user_id
+// It also deletes :
+//     - all the access linked to this user
+//     - all the links to any group
+//     - all the favorites linked to this user
+//     - all sessions linked to this user
+//     - calculated permissions linked to the user
+function delete_user($user_id)
+{
+  // destruction of the access linked to the user
+  $query = '
+DELETE FROM '.USER_ACCESS_TABLE.'
+  WHERE user_id = '.$user_id.'
+;';
+  pwg_query($query);
+
+  // destruction of the group links for this user
+  $query = '
+DELETE FROM '.USER_GROUP_TABLE.'
+  WHERE user_id = '.$user_id.'
+;';
+  pwg_query($query);
+
+  // destruction of the favorites associated with the user
+  $query = '
+DELETE FROM '.FAVORITES_TABLE.'
+  WHERE user_id = '.$user_id.'
+;';
+  pwg_query($query);
+
+  // destruction of the sessions linked with the user
+  $query = '
+DELETE FROM '.SESSIONS_TABLE.'
+  WHERE user_id = '.$user_id.'
+;';
+  pwg_query($query);
+
+  // deletion of calculated permissions linked to the user
+  $query = '
+DELETE FROM '.USER_FORBIDDEN_TABLE.'
+  WHERE user_id = '.$user_id.'
+;';
+  pwg_query($query);
+
+  // destruction of the user
+  $query = '
+DELETE FROM '.USERS_TABLE.'
+  WHERE id = '.$user_id.'
+;';
+  pwg_query($query);
+}
+
+/**
+ * updates calculated informations about a set of categories : date_last and
+ * nb_images. It also verifies that the representative picture is really
+ * linked to the category. Optionnaly recursive.
+ *
+ * @param mixed category id
+ * @param boolean recursive
+ * @returns void
+ */
+function update_category($ids = 'all', $recursive = false)
+{
+  // retrieving all categories to update
+  $cat_ids = array();
+  
+  $query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE;
+  if (is_array($ids))
+  {
+    if ($recursive)
+    {
+      foreach ($ids as $num => $id)
+      {
+        if ($num == 0)
+        {
+          $query.= '
+  WHERE ';
+        }
+        else
+        {
+          $query.= '
+  OR    ';
+        }
+        $query.= 'uppercats REGEXP \'(^|,)'.$id.'(,|$)\'';
+      }
+    }
+    else
+    {
+      $query.= '
+  WHERE id IN ('.wordwrap(implode(', ', $ids), 80, "\n").')';
+    }
+  }
+  $query.= '
+;';
+  $result = pwg_query( $query );
+  while ( $row = mysql_fetch_array( $result ) )
+  {
+    array_push($cat_ids, $row['id']);
+  }
+  $cat_ids = array_unique($cat_ids);
+
+  if (count($cat_ids) == 0)
+  {
+    return false;
+  }
+  
+  // calculate informations about categories retrieved
+  $query = '
+SELECT category_id,
+       COUNT(image_id) AS nb_images,
+       MAX(date_available) AS date_last
+  FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id = image_id
+  WHERE category_id IN ('.wordwrap(implode(', ', $cat_ids), 80, "\n").')
+  GROUP BY category_id
+;';
+  $result = pwg_query($query);
+  $datas = array();
+  $query_ids = array();
+  while ( $row = mysql_fetch_array( $result ) )
+  {
+    array_push($query_ids, $row['category_id']);
+    array_push($datas, array('id' => $row['category_id'],
+                             'date_last' => $row['date_last'],
+                             'nb_images' => $row['nb_images']));
+  }
+  // if all links between a category and elements have disappeared, no line
+  // is returned but the update must be done !
+  foreach (array_diff($cat_ids, $query_ids) as $id)
+  {
+    array_push($datas, array('id' => $id, 'nb_images' => 0));
+  }
+  
+  $fields = array('primary' => array('id'),
+                  'update'  => array('date_last', 'nb_images'));
+  mass_updates(CATEGORIES_TABLE, $fields, $datas);
+
+  $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET representative_picture_id = NULL
+  WHERE nb_images = 0
+;';
+  pwg_query($query);
+  
+  if (count($cat_ids) > 0)
+  {
+    $categories = array();
+    // find all categories where the setted representative is not possible
+    $query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.' LEFT JOIN '.IMAGE_CATEGORY_TABLE.'
+    ON id = category_id AND representative_picture_id = image_id
+  WHERE representative_picture_id IS NOT NULL
+    AND id IN ('.wordwrap(implode(', ', $cat_ids), 80, "\n").')
+    AND category_id IS NULL
+;';
+    $result = pwg_query($query);
+    while ($row = mysql_fetch_array($result))
+    {
+      array_push($categories, $row['id']);
+    }
+    // find categories with elements and with no representant
+    $query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE representative_picture_id IS NULL
+    AND nb_images != 0
+;';
+    $result = pwg_query($query);
+    while ($row = mysql_fetch_array($result))
+    {
+      array_push($categories, $row['id']);
+    }
+
+    $categories = array_unique($categories);
+    set_random_representant($categories);
+  }
+}
+
+function check_date_format( $date )
+{
+  // date arrives at this format : DD/MM/YYYY
+  @list($day,$month,$year) = explode( '/', $date );
+  return @checkdate( $month, $day, $year );
+}
+
+function date_convert( $date )
+{
+  // date arrives at this format : DD/MM/YYYY
+  // It must be transformed in YYYY-MM-DD
+  list($day,$month,$year) = explode( '/', $date );
+  return $year.'-'.$month.'-'.$day;
+}
+
+function date_convert_back( $date )
+{
+  // date arrives at this format : YYYY-MM-DD
+  // It must be transformed in DD/MM/YYYY
+  if ( $date != '' )
+  {
+    list($year,$month,$day) = explode( '-', $date );
+    return $day.'/'.$month.'/'.$year;
+  }
+  else
+  {
+    return '';
+  }
+}
+
+// get_keywords returns an array with relevant keywords found in the string
+// given in argument. Keywords must be separated by comma in this string.
+// keywords must :
+//   - be longer or equal to 3 characters
+//   - not contain ', " or blank characters
+//   - unique in the string ("test,test" -> "test")
+function get_keywords( $keywords_string )
+{
+  $keywords = array();
+
+  $candidates = explode( ',', $keywords_string );
+  foreach ( $candidates as $candidate ) {
+    if ( strlen($candidate) >= 3 and !preg_match( '/(\'|"|\s)/', $candidate ) )
+      array_push( $keywords, $candidate );
+  }
+
+  return array_unique( $keywords );
+}
+
+/**
+ * returns an array with the ids of the restricted categories for the user
+ *
+ * Returns an array with the ids of the restricted categories for the
+ * user. If the $check_invisible parameter is set to true, invisible
+ * categorie are added to the restricted one in the array.
+ *
+ * @param int $user_id
+ * @param string $user_status
+ * @param bool $check_invisible
+ * @param bool $use_groups
+ * @return array
+ */
+function get_user_restrictions( $user_id, $user_status,
+                                $check_invisible, $use_groups = true )
+{
+  // 1. retrieving ids of private categories
+  $query = 'SELECT id FROM '.CATEGORIES_TABLE;
+  $query.= " WHERE status = 'private'";
+  $query.= ';';
+  $result = pwg_query( $query );
+  $privates = array();
+  while ( $row = mysql_fetch_array( $result ) )
+  {
+    array_push( $privates, $row['id'] );
+  }
+  // 2. retrieving all authorized categories for the user
+  $authorized = array();
+  // 2.1. retrieving authorized categories thanks to personnal user
+  //      authorization
+  $query = 'SELECT cat_id FROM '.USER_ACCESS_TABLE;
+  $query.= ' WHERE user_id = '.$user_id;
+  $query.= ';';
+  $result = pwg_query( $query );
+  while ( $row = mysql_fetch_array( $result ) )
+  {
+    array_push( $authorized, $row['cat_id'] );
+  }
+  // 2.2. retrieving authorized categories thanks to group authorization to
+  //      which the user is a member
+  if ( $use_groups )
+  {
+    $query = 'SELECT ga.cat_id';
+    $query.= ' FROM '.USER_GROUP_TABLE.' as ug';
+    $query.= ', '.GROUP_ACCESS_TABLE.' as ga';
+    $query.= ' WHERE ug.group_id = ga.group_id';
+    $query.= ' AND ug.user_id = '.$user_id;
+    $query.= ';';
+    $result = pwg_query( $query );
+    while ( $row = mysql_fetch_array( $result ) )
+    {
+      array_push( $authorized, $row['cat_id'] );
+    }
+    $authorized = array_unique( $authorized );
+  }
+
+  $forbidden = array();
+  foreach ( $privates as $private ) {
+    if ( !in_array( $private, $authorized ) )
+    {
+      array_push( $forbidden, $private );
+    }
+  }
+
+  if ( $check_invisible )
+  {
+    // 3. adding to the restricted categories, the invisible ones
+    if ( $user_status != 'admin' )
+    {
+      $query = 'SELECT id FROM '.CATEGORIES_TABLE;
+      $query.= " WHERE visible = 'false';";
+      $result = pwg_query( $query );
+      while ( $row = mysql_fetch_array( $result ) )
+      {
+        array_push( $forbidden, $row['id'] );
+      }
+    }
+  }
+  return array_unique( $forbidden );
+}
+
+/**
+ * updates the calculated data users.forbidden_categories, it includes
+ * sub-categories of the direct forbidden categories
+ *
+ * @param nt $user_id
+ * @return array
+ */
+function update_user_restrictions( $user_id )
+{
+  $restrictions = get_user_all_restrictions( $user_id );
+
+  // update the users.forbidden_categories in database
+  $query = 'UPDATE '.USERS_TABLE;
+  $query.= ' SET forbidden_categories = ';
+  if ( count( $restrictions ) > 0 )
+    $query.= "'".implode( ',', $restrictions )."'";
+  else
+    $query.= 'NULL';
+  $query .= ' WHERE id = '.$user_id;
+  $query.= ';';
+  pwg_query( $query );
+
+  return $restrictions;
+}
+
+/**
+ * returns all the restricted categories ids including sub-categories
+ *
+ * @param int $user_id
+ * @return array
+ */
+function get_user_all_restrictions( $user_id )
+{
+  global $page;
+  
+  $query = 'SELECT status';
+  $query.= ' FROM '.USERS_TABLE;
+  $query.= ' WHERE id = '.$user_id;
+  $query.= ';';
+  $row = mysql_fetch_array( pwg_query( $query ) );
+  
+  $base_restrictions=get_user_restrictions($user_id,$row['status'],true,true);
+
+  $restrictions = $base_restrictions;
+  foreach ( $base_restrictions as $category_id ) {
+    echo $category_id.' is forbidden to user '.$user_id.'<br />';
+    $restrictions =
+      array_merge( $restrictions,
+                   $page['plain_structure'][$category_id]['all_subcats_ids'] );
+  }
+
+  return array_unique( $restrictions );
+}
+
+// The function is_user_allowed returns :
+//      - 0 : if the category is allowed with this $restrictions array
+//      - 1 : if this category is not allowed
+//      - 2 : if an uppercat category is not allowed
+// Note : the restrictions array must represent ONLY direct forbidden
+// categories, not all forbidden categories
+function is_user_allowed( $category_id, $restrictions )
+{
+  if ( in_array( $category_id, $restrictions ) ) return 1;
+
+  $query = 'SELECT uppercats';
+  $query.= ' FROM '.CATEGORIES_TABLE;
+  $query.= ' WHERE id = '.$category_id;
+  $query.= ';';
+  $row = mysql_fetch_array( pwg_query( $query ) );
+  $uppercats = explode( ',', $row['uppercats'] );
+  foreach ( $uppercats as $category_id ) {
+    if ( in_array( $category_id, $restrictions ) ) return 2;
+  }
+
+  // no restriction found : the user is allowed to access this category
+  return 0;
+}
+
+/**
+ * returns an array containing sub-directories which can be a category
+ *
+ * directories nammed "thumbnail", "pwg_high" or "pwg_representative" are
+ * omitted
+ *
+ * @param string $basedir
+ * @return array
+ */
+function get_category_directories( $basedir )
+{
+  $sub_dirs = array();
+  
+  if ( $opendir = opendir( $basedir ) )
+  {
+    while ( $file = readdir( $opendir ) )
+    {
+      if ($file != '.'
+          and $file != '..'
+          and $file != 'thumbnail'
+          and $file != 'pwg_high'
+          and $file != 'pwg_representative'
+          and is_dir($basedir.'/'.$file))
+      {
+        array_push( $sub_dirs, $file );
+      }
+    }
+  }
+  return $sub_dirs;
+}
+
+/**
+ * returns an array containing sub-directories which can be a category,
+ * recursive by default
+ *
+ * directories nammed "thumbnail", "pwg_high" or "pwg_representative" are
+ * omitted
+ *
+ * @param string $basedir
+ * @return array
+ */
+function get_fs_directories($path, $recursive = true)
+{
+  $dirs = array();
+  
+  if (is_dir($path))
+  {
+    if ($contents = opendir($path))
+    {
+      while (($node = readdir($contents)) !== false)
+      {
+        if (is_dir($path.'/'.$node)
+            and $node != '.'
+            and $node != '..'
+            and $node != 'thumbnail'
+            and $node != 'pwg_high'
+            and $node != 'pwg_representative')
+        {
+          array_push($dirs, $path.'/'.$node);
+          if ($recursive)
+          {
+            $dirs = array_merge($dirs, get_fs_directories($path.'/'.$node));
+          }
+        }
+      }
+    }
+  }
+
+  return $dirs;
+}
+
+/**
+ * inserts multiple lines in a table
+ *
+ * @param string table_name
+ * @param array dbfields
+ * @param array inserts
+ * @return void
+ */
+function mass_inserts($table_name, $dbfields, $datas)
+{
+  // inserts all found categories
+  $query = '
+INSERT INTO '.$table_name.'
+  ('.implode(',', $dbfields).')
+   VALUES';
+  foreach ($datas as $insert_id => $insert)
+  {
+    $query.= '
+  ';
+    if ($insert_id > 0)
+    {
+      $query.= ',';
+    }
+    $query.= '(';
+    foreach ($dbfields as $field_id => $dbfield)
+    {
+      if ($field_id > 0)
+      {
+        $query.= ',';
+      }
+      
+      if (!isset($insert[$dbfield]) or $insert[$dbfield] == '')
+      {
+        $query.= 'NULL';
+      }
+      else
+      {
+        $query.= "'".$insert[$dbfield]."'";
+      }
+    }
+    $query.=')';
+  }
+  $query.= '
+;';
+  pwg_query($query);
+}
+
+/**
+ * updates multiple lines in a table
+ *
+ * @param string table_name
+ * @param array dbfields
+ * @param array datas
+ * @return void
+ */
+function mass_updates($tablename, $dbfields, $datas)
+{
+  // depending on the MySQL version, we use the multi table update or N
+  // update queries
+  $query = 'SELECT VERSION() AS version;';
+  $row = mysql_fetch_array(pwg_query($query));
+  if (count($datas) < 10 or version_compare($row['version'],'4.0.4') < 0)
+  {
+    // MySQL is prior to version 4.0.4, multi table update feature is not
+    // available
+    foreach ($datas as $data)
+    {
+      $query = '
+UPDATE '.$tablename.'
+  SET ';
+      foreach ($dbfields['update'] as $num => $key)
+      {
+        if ($num >= 1)
+        {
+          $query.= ",\n      ";
+        }
+        $query.= $key.' = ';
+        if (isset($data[$key]))
+        {
+          $query.= '\''.$data[$key].'\'';
+        }
+        else
+        {
+          $query.= 'NULL';
+        }
+      }
+      $query.= '
+  WHERE ';
+      foreach ($dbfields['primary'] as $num => $key)
+      {
+        if ($num > 1)
+        {
+          $query.= ' AND ';
+        }
+        $query.= $key.' = \''.$data[$key].'\'';
+      }
+      $query.= '
+;';
+      pwg_query($query);
+    }
+  }
+  else
+  {
+    // creation of the temporary table
+    $query = '
+DESCRIBE '.$tablename.'
+;';
+    $result = pwg_query($query);
+    $columns = array();
+    $all_fields = array_merge($dbfields['primary'], $dbfields['update']);
+    while ($row = mysql_fetch_array($result))
+    {
+      if (in_array($row['Field'], $all_fields))
+      {
+        $column = $row['Field'];
+        $column.= ' '.$row['Type'];
+        if (!isset($row['Null']) or $row['Null'] == '')
+        {
+          $column.= ' NOT NULL';
+        }
+        if (isset($row['Default']))
+        {
+          $column.= " default '".$row['Default']."'";
+        }
+        array_push($columns, $column);
+      }
+    }
+    
+    $temporary_tablename = $tablename.'_'.micro_seconds();
+    
+    $query = '
+CREATE TABLE '.$temporary_tablename.'
+(
+'.implode(",\n", $columns).',
+PRIMARY KEY (id)
+)
+;';
+    pwg_query($query);
+    mass_inserts($temporary_tablename, $all_fields, $datas);
+    // update of images table by joining with temporary table
+    $query = '
+UPDATE '.$tablename.' AS t1, '.$temporary_tablename.' AS t2
+  SET '.implode("\n    , ",
+                array_map(
+                  create_function('$s', 'return "t1.$s = t2.$s";')
+                  , $dbfields['update'])).'
+  WHERE '.implode("\n    AND ",
+                array_map(
+                  create_function('$s', 'return "t1.$s = t2.$s";')
+                  , $dbfields['primary'])).'
+;';
+    pwg_query($query);
+    $query = '
+DROP TABLE '.$temporary_tablename.'
+;';
+    pwg_query($query);
+  }
+}
+
+/**
+ * updates the global_rank of categories under the given id_uppercat
+ *
+ * @param int id_uppercat
+ * @return void
+ */
+function update_global_rank($id_uppercat = 'all')
+{
+  $query = '
+SELECT id,rank
+  FROM '.CATEGORIES_TABLE.'
+;';
+  $result = pwg_query($query);
+  $ranks_array = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    $ranks_array[$row['id']] = $row['rank'];
+  }
+
+  // which categories to update ?
+  $uppercats_array = array();
+
+  $query = '
+SELECT id,uppercats
+  FROM '.CATEGORIES_TABLE;
+  if (is_numeric($id_uppercat))
+  {
+    $query.= '
+  WHERE uppercats REGEXP \'(^|,)'.$id_uppercat.'(,|$)\'
+    AND id != '.$id_uppercat.'
+';
+  }
+  $query.= '
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    $uppercats_array[$row['id']] =  $row['uppercats'];
+  }
+  
+  $datas = array();
+  foreach ($uppercats_array as $id => $uppercats)
+  {
+    $data = array();
+    $data['id'] = $id;
+    $global_rank = preg_replace('/(\d+)/e',
+                                "\$ranks_array['$1']",
+                                str_replace(',', '.', $uppercats));
+    $data['global_rank'] = $global_rank;
+    array_push($datas, $data);
+  }
+
+  $fields = array('primary' => array('id'), 'update' => array('global_rank'));
+  mass_updates(CATEGORIES_TABLE, $fields, $datas);
+}
+
+/**
+ * change the visible property on a set of categories
+ *
+ * @param array categories
+ * @param string value
+ * @return void
+ */
+function set_cat_visible($categories, $value)
+{
+  if (!in_array($value, array('true', 'false')))
+  {
+    return false;
+  }
+
+  // unlocking a category => all its parent categories become unlocked
+  if ($value == 'true')
+  {
+    $uppercats = get_uppercat_ids($categories);
+    $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET visible = \'true\'
+  WHERE id IN ('.implode(',', $uppercats).')
+;';
+    pwg_query($query);
+  }
+  // locking a category   => all its child categories become locked
+  if ($value == 'false')
+  {
+    $subcats = get_subcat_ids($categories);
+    $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET visible = \'false\'
+  WHERE id IN ('.implode(',', $subcats).')
+;';
+    pwg_query($query);
+  }
+}
+
+/**
+ * change the status property on a set of categories : private or public
+ *
+ * @param array categories
+ * @param string value
+ * @return void
+ */
+function set_cat_status($categories, $value)
+{
+  if (!in_array($value, array('public', 'private')))
+  {
+    return false;
+  }
+
+  // make public a category => all its parent categories become public
+  if ($value == 'public')
+  {
+    $uppercats = get_uppercat_ids($categories);
+    $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET status = \'public\'
+  WHERE id IN ('.implode(',', $uppercats).')
+;';
+    pwg_query($query);
+  }
+  // make a category private => all its child categories become private
+  if ($value == 'private')
+  {
+    $subcats = get_subcat_ids($categories);
+    $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET status = \'private\'
+  WHERE id IN ('.implode(',', $subcats).')
+;';
+    pwg_query($query);
+  }
+}
+
+/**
+ * returns all uppercats category ids of the given category ids
+ *
+ * @param array cat_ids
+ * @return array
+ */
+function get_uppercat_ids($cat_ids)
+{
+  if (!is_array($cat_ids) or count($cat_ids) < 1)
+  {
+    return array();
+  }
+  
+  $uppercats = array();
+
+  $query = '
+SELECT uppercats
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id IN ('.implode(',', $cat_ids).')
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    $uppercats = array_merge($uppercats,
+                             explode(',', $row['uppercats']));
+  }
+  $uppercats = array_unique($uppercats);
+
+  return $uppercats;
+}
+
+/**
+ * set a new random representant to the categories
+ *
+ * @param array categories
+ */
+function set_random_representant($categories)
+{
+  $datas = array();
+  foreach ($categories as $category_id)
+  {
+    $query = '
+SELECT image_id
+  FROM '.IMAGE_CATEGORY_TABLE.'
+  WHERE category_id = '.$category_id.'
+  ORDER BY RAND()
+  LIMIT 0,1
+;';
+    list($representative) = mysql_fetch_array(pwg_query($query));
+    $data = array('id' => $category_id,
+                  'representative_picture_id' => $representative);
+    array_push($datas, $data);
+  }
+
+  $fields = array('primary' => array('id'),
+                  'update' => array('representative_picture_id'));
+  mass_updates(CATEGORIES_TABLE, $fields, $datas);
+}
+
+/**
+ * order categories (update categories.rank and global_rank database fields)
+ *
+ * the purpose of this function is to give a rank for all categories
+ * (insides its sub-category), even the newer that have none at te
+ * beginning. For this, ordering function selects all categories ordered by
+ * rank ASC then name ASC for each uppercat.
+ *
+ * @returns void
+ */
+function ordering()
+{
+  $current_rank = 0;
+  $current_uppercat = '';
+		
+  $query = '
+SELECT id, if(id_uppercat is null,\'\',id_uppercat) AS id_uppercat
+  FROM '.CATEGORIES_TABLE.'
+  ORDER BY id_uppercat,rank,name
+;';
+  $result = pwg_query($query);
+  $datas = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    if ($row['id_uppercat'] != $current_uppercat)
+    {
+      $current_rank = 0;
+      $current_uppercat = $row['id_uppercat'];
+    }
+    $data = array('id' => $row['id'], 'rank' => ++$current_rank);
+    array_push($datas, $data);
+  }
+
+  $fields = array('primary' => array('id'), 'update' => array('rank'));
+  mass_updates(CATEGORIES_TABLE, $fields, $datas);
+}
+
+/**
+ * returns the fulldir for each given category id
+ *
+ * @param array cat_ids
+ * @return array
+ */
+function get_fulldirs($cat_ids)
+{
+  if (count($cat_ids) == 0)
+  {
+    return array();
+  }
+  
+  // caching directories of existing categories
+  $query = '
+SELECT id, dir
+  FROM '.CATEGORIES_TABLE.'
+  WHERE dir IS NOT NULL
+;';
+  $result = pwg_query($query);
+  $cat_dirs = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    $cat_dirs[$row['id']] = $row['dir'];
+  }
+
+  // caching galleries_url
+  $query = '
+SELECT id, galleries_url
+  FROM '.SITES_TABLE.'
+;';
+  $result = pwg_query($query);
+  $galleries_url = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    $galleries_url[$row['id']] = $row['galleries_url'];
+  }
+
+  // categories : id, site_id, uppercats
+  $categories = array();
+  
+  $query = '
+SELECT id, uppercats, site_id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id IN (
+'.wordwrap(implode(', ', $cat_ids), 80, "\n").')
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($categories, $row);
+  }
+  
+  // filling $cat_fulldirs
+  $cat_fulldirs = array();
+  foreach ($categories as $category)
+  {
+    $uppercats = str_replace(',', '/', $category['uppercats']);
+    $cat_fulldirs[$category['id']] = $galleries_url[$category['site_id']];
+    $cat_fulldirs[$category['id']].= preg_replace('/(\d+)/e',
+                                                  "\$cat_dirs['$1']",
+                                                  $uppercats);
+  }
+
+  return $cat_fulldirs;
+}
+
+/**
+ * returns an array with all file system files according to
+ * $conf['file_ext']
+ *
+ * @param string $path
+ * @param bool recursive
+ * @return array
+ */
+function get_fs($path, $recursive = true)
+{
+  global $conf;
+
+  // because isset is faster than in_array...
+  if (!isset($conf['flip_picture_ext']))
+  {
+    $conf['flip_picture_ext'] = array_flip($conf['picture_ext']);
+  }
+  if (!isset($conf['flip_file_ext']))
+  {
+    $conf['flip_file_ext'] = array_flip($conf['file_ext']);
+  }
+
+  $fs['elements'] = array();
+  $fs['thumbnails'] = array();
+  $fs['representatives'] = array();
+  $subdirs = array();
+
+  if (is_dir($path))
+  {
+    if ($contents = opendir($path))
+    {
+      while (($node = readdir($contents)) !== false)
+      {
+        if (is_file($path.'/'.$node))
+        {
+          $extension = get_extension($node);
+          
+//          if (in_array($extension, $conf['picture_ext']))
+          if (isset($conf['flip_picture_ext'][$extension]))
+          {
+            if (basename($path) == 'thumbnail')
+            {
+              array_push($fs['thumbnails'], $path.'/'.$node);
+            }
+            else if (basename($path) == 'pwg_representative')
+            {
+              array_push($fs['representatives'], $path.'/'.$node);
+            }
+            else
+            {
+              array_push($fs['elements'], $path.'/'.$node);
+            }
+          }
+//          else if (in_array($extension, $conf['file_ext']))
+          else if (isset($conf['flip_file_ext'][$extension]))
+          {
+            array_push($fs['elements'], $path.'/'.$node);
+          }
+        }
+        else if (is_dir($path.'/'.$node)
+                 and $node != '.'
+                 and $node != '..'
+                 and $node != 'pwg_high'
+                 and $recursive)
+        {
+          array_push($subdirs, $node);
+        }
+      }
+    }
+    closedir($contents);
+
+    foreach ($subdirs as $subdir)
+    {
+      $tmp_fs = get_fs($path.'/'.$subdir);
+
+      $fs['elements']        = array_merge($fs['elements'],
+                                           $tmp_fs['elements']);
+      
+      $fs['thumbnails']      = array_merge($fs['thumbnails'],
+                                           $tmp_fs['thumbnails']);
+      
+      $fs['representatives'] = array_merge($fs['representatives'],
+                                           $tmp_fs['representatives']);
+    }
+  }
+  return $fs;
+}
+
+/**
+ * stupidly returns the current microsecond since Unix epoch
+ */
+function micro_seconds()
+{
+  $t1 = explode(' ', microtime());
+  $t2 = explode('.', $t1[0]);
+  $t2 = $t1[1].substr($t2[1], 0, 6);
+  return $t2;
+}
+?>
Index: /branches/1.4/admin/include/functions_metadata.php
===================================================================
--- /branches/1.4/admin/include/functions_metadata.php	(revision 3249)
+++ /branches/1.4/admin/include/functions_metadata.php	(revision 3249)
@@ -0,0 +1,207 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+include_once(PHPWG_ROOT_PATH.'/include/functions_metadata.inc.php');
+
+function get_sync_iptc_data($file)
+{
+  global $conf;
+  
+  $map = $conf['use_iptc_mapping'];
+  $datefields = array('date_creation', 'date_available');
+  
+  $iptc = get_iptc_data($file, $map);
+
+  foreach ($iptc as $pwg_key => $value)
+  {
+    if (in_array($pwg_key, $datefields))
+    {
+      if (preg_match('/(\d{4})(\d{2})(\d{2})/', $value, $matches))
+      {
+        $iptc[$pwg_key] = $matches[1].'-'.$matches[2].'-'.$matches[3];
+      }
+    }
+  }
+
+  if (isset($iptc['keywords']))
+  {
+    // keywords separator is the comma, nothing else. Allowed characters in
+    // keywords : [A-Za-z0-9], "-" and "_". All other characters will be
+    // considered as separators
+    $iptc['keywords'] = preg_replace('/[^\w-]+/', ',', $iptc['keywords']);
+    $iptc['keywords'] = preg_replace('/^,+|,+$/', '', $iptc['keywords']);
+  }
+
+  return $iptc;
+}
+
+function update_metadata($files)
+{
+  global $conf;
+
+  if (!defined('CURRENT_DATE'))
+  {
+    define('CURRENT_DATE', date('Y-m-d'));
+  }
+
+  $datas = array();
+
+  foreach ($files as $id => $file)
+  {
+    $data = array();
+    $data['id'] = $id;
+    $data['filesize'] = floor(filesize($file)/1024);
+  
+    if ($image_size = @getimagesize($file))
+    {
+      $data['width'] = $image_size[0];
+      $data['height'] = $image_size[1];
+    }
+  
+    if ($conf['use_exif'])
+    {
+      if (!function_exists('read_exif_data'))
+      {
+        die('Exif extension not available, admin should disable exif use');
+      }
+      
+      if ($exif = @read_exif_data($file))
+      {
+        if (isset($exif['DateTime']))
+        {
+          preg_match('/^(\d{4}).(\d{2}).(\d{2})/',$exif['DateTime'],$matches);
+          $data['date_creation'] = $matches[1].'-'.$matches[2].'-'.$matches[3];
+        }
+      }
+    }
+
+    if ($conf['use_iptc'])
+    {
+      $iptc = get_sync_iptc_data($file);
+      if (count($iptc) > 0)
+      {
+        foreach (array_keys($iptc) as $key)
+        {
+          $data[$key] = addslashes($iptc[$key]);
+        }
+      }
+    }
+
+    $data['date_metadata_update'] = CURRENT_DATE;
+
+    array_push($datas, $data);
+  }
+  
+  if (count($datas) > 0)
+  {
+    $update_fields = array('filesize','width','height','date_metadata_update');
+    if ($conf['use_exif'])
+    {
+      array_push($update_fields, 'date_creation');
+    }
+    if ($conf['use_iptc'])
+    {
+      $update_fields = array_merge($update_fields,
+                                   array_keys($conf['use_iptc_mapping']));
+    }
+    
+    $fields = array('primary' => array('id'),
+                    'update'  => array_unique($update_fields));
+    mass_updates(IMAGES_TABLE, $fields, $datas);
+  }
+}
+
+/**
+ * returns an array associating element id (images.id) with its complete
+ * path in the filesystem
+ *
+ * @param int id_uppercat
+ * @param boolean recursive ?
+ * @param boolean only newly added files ?
+ * @return array
+ */
+function get_filelist($category_id = '', $recursive = false, $only_new = false)
+{
+  // filling $cat_ids : all categories required
+  $cat_ids = array();
+  
+  $query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE site_id = 1
+    AND dir IS NOT NULL';
+  if (is_numeric($category_id))
+  {
+    if ($recursive)
+    {
+      $query.= '
+    AND uppercats REGEXP \'(^|,)'.$category_id.'(,|$)\'
+';
+    }
+    else
+    {
+      $query.= '
+    AND id = '.$category_id.'
+';
+    }
+  }
+  $query.= '
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($cat_ids, $row['id']);
+  }
+
+  if (count($cat_ids) == 0)
+  {
+    return array();
+  }
+
+  $files = array();
+
+  $query = '
+SELECT id, path
+  FROM '.IMAGES_TABLE.'
+  WHERE storage_category_id IN ('.implode(',', $cat_ids).')';
+  if ($only_new)
+  {
+    $query.= '
+    AND date_metadata_update IS NULL
+';
+  }
+  $query.= '
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    $files[$row['id']] = $row['path'];
+  }
+  
+  return $files;
+}
+?>
Index: /branches/1.4/admin/include/index.htm
===================================================================
--- /branches/1.4/admin/include/index.htm	(revision 3249)
+++ /branches/1.4/admin/include/index.htm	(revision 3249)
@@ -0,0 +1,8 @@
+<html>
+    <head>
+        <title>PhpWebGallery</title>
+    </head>
+    <body>
+        No access authorized
+    </body>
+</html>
Index: /branches/1.4/admin/include/isadmin.inc.php
===================================================================
--- /branches/1.4/admin/include/isadmin.inc.php	(revision 3249)
+++ /branches/1.4/admin/include/isadmin.inc.php	(revision 3249)
@@ -0,0 +1,36 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+include( PHPWG_ROOT_PATH.'admin/include/functions.php' );
+
+if ($user['status'] != 'admin')
+{
+  echo '<div style="text-align:center;">'.$lang['access_forbiden'].'<br />';
+  echo '<a href="'.PHPWG_ROOT_PATH.'identification.php">'.$lang['identification'].'</a></div>';
+  exit();
+}
+?>
Index: /branches/1.4/admin/index.htm
===================================================================
--- /branches/1.4/admin/index.htm	(revision 3249)
+++ /branches/1.4/admin/index.htm	(revision 3249)
@@ -0,0 +1,8 @@
+<html>
+    <head>
+        <title>PhpWebGallery</title>
+    </head>
+    <body>
+        No access authorized
+    </body>
+</html>
Index: /branches/1.4/admin/infos_images.php
===================================================================
--- /branches/1.4/admin/infos_images.php	(revision 3249)
+++ /branches/1.4/admin/infos_images.php	(revision 3249)
@@ -0,0 +1,351 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if(!defined("PHPWG_ROOT_PATH"))
+{
+  die ("Hacking attempt!");
+}
+include_once(PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php');
+// +-----------------------------------------------------------------------+
+// |                             initialization                            |
+// +-----------------------------------------------------------------------+
+check_cat_id($_GET['cat_id']);
+$errors = array();
+
+if (isset($page['cat']))
+{
+// +-----------------------------------------------------------------------+
+// |                       update individual options                       |
+// +-----------------------------------------------------------------------+
+  if (isset($_POST['submit']))
+  {
+    if (isset($_POST['associate']) and $_POST['associate'] != '')
+    {
+      // does the uppercat id exists in the database ?
+      if (!is_numeric($_POST['associate']))
+      {
+        array_push($errors, $lang['cat_unknown_id']);
+      }
+      else
+      {
+        $query = 'SELECT id FROM '.CATEGORIES_TABLE;
+        $query.= ' WHERE id = '.$_POST['associate'];
+        $query.= ';';
+        if (mysql_num_rows(pwg_query($query)) == 0)
+          array_push($errors, $lang['cat_unknown_id']);
+      }
+    }
+
+    $query = 'SELECT id,file FROM '.IMAGES_TABLE;
+    $query.= ' INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id = image_id';
+    $query.= ' WHERE category_id = '.$page['cat'];
+    $query.= ';';
+    $result = pwg_query($query);
+    while ($row = mysql_fetch_array($result))
+    {
+      $name          = 'name-'.$row['id'];
+      $author        = 'author-'.$row['id'];
+      $comment       = 'comment-'.$row['id'];
+      $date_creation = 'date_creation-'.$row['id'];
+      $keywords      = 'keywords-'.$row['id'];
+      if (isset($_POST[$name]))
+      {
+        $query = 'UPDATE '.IMAGES_TABLE.' SET name = ';
+        if ($_POST[$name] == '')
+          $query.= 'NULL';
+        else
+          $query.= "'".htmlentities($_POST[$name], ENT_QUOTES)."'";
+
+        $query.= ', author = ';
+        if ($_POST[$author] == '')
+          $query.= 'NULL';
+        else
+          $query.= "'".htmlentities($_POST[$author],ENT_QUOTES)."'";
+
+        $query.= ', comment = ';
+        if ($_POST[$comment] == '')
+          $query.= 'NULL';
+        else
+          $query.= "'".htmlentities($_POST[$comment],ENT_QUOTES)."'";
+
+        $query.= ', date_creation = ';
+        if (check_date_format($_POST[$date_creation]))
+          $query.= "'".date_convert($_POST[$date_creation])."'";
+        else if ($_POST[$date_creation] == '')
+          $query.= 'NULL';
+
+        $query.= ', keywords = ';
+
+        $keywords_array = get_keywords($_POST[$keywords]);
+        if (count($keywords_array) == 0) $query.= 'NULL';
+        else $query.= "'".implode(',', $keywords_array)."'";
+
+        $query.= ' WHERE id = '.$row['id'];
+        $query.= ';';
+        pwg_query($query);
+      }
+      // add link to another category
+      if (isset($_POST['check-'.$row['id']])
+          and isset($_POST['associate'])
+          and $_POST['associate'] != '')
+      {
+        $query = 'INSERT INTO '.IMAGE_CATEGORY_TABLE;
+        $query.= ' (image_id,category_id) VALUES';
+        $query.= ' ('.$row['id'].','.$_POST['associate'].')';
+        $query.= ';';
+        pwg_query($query);
+      }
+    }
+    if (isset($_POST['associate']) and $_POST['associate'] != '')
+    {
+      update_category(array($_POST['associate']));
+    }
+// +-----------------------------------------------------------------------+
+// |                        update general options                         |
+// +-----------------------------------------------------------------------+
+    if (isset($_POST['use_common_author']))
+    {
+      $query = 'SELECT image_id FROM '.IMAGE_CATEGORY_TABLE;
+      $query.= ' WHERE category_id = '.$page['cat'];
+      $result = pwg_query($query);
+      while ($row = mysql_fetch_array($result))
+      {
+        $query = 'UPDATE '.IMAGES_TABLE;
+        if ($_POST['author_cat'] == '')
+        {
+          $query.= ' SET author = NULL';
+        }
+        else
+        {
+          $query.= ' SET author = ';
+          $query.= "'".htmlentities($_POST['author_cat'], ENT_QUOTES)."'";
+        }
+        $query.= ' WHERE id = '.$row['image_id'];
+        $query.= ';';
+        pwg_query($query);
+      }
+    }
+    if (isset($_POST['use_common_date_creation']))
+    {
+      if (check_date_format($_POST['date_creation_cat']))
+      {
+        $date = date_convert($_POST['date_creation_cat']);
+        $query = 'SELECT image_id FROM '.IMAGE_CATEGORY_TABLE;
+        $query.= ' WHERE category_id = '.$page['cat'];
+        $result = pwg_query($query);
+        while ($row = mysql_fetch_array($result))
+        {
+          $query = 'UPDATE '.IMAGES_TABLE;
+          if ($_POST['date_creation_cat'] == '')
+          {
+            $query.= ' SET date_creation = NULL';
+          }
+          else
+          {
+            $query.= " SET date_creation = '".$date."'";
+          }
+          $query.= ' WHERE id = '.$row['image_id'];
+          $query.= ';';
+          pwg_query($query);
+        }
+      }
+      else
+      {
+        array_push($errors, $lang['err_date']);
+      }
+    }
+    if (isset($_POST['common_keywords']) and $_POST['keywords_cat'] != '')
+    {
+      $query = 'SELECT id,keywords FROM '.IMAGES_TABLE;
+      $query.= ' INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id = image_id';
+      $query.= ' WHERE category_id = '.$page['cat'];
+      $query.= ';';
+      $result = pwg_query($query);
+      while ($row = mysql_fetch_array($result))
+      {
+        if (!isset($row['keywords'])) $specific_keywords = array();
+        else $specific_keywords = explode(',', $row['keywords']);
+        
+        $common_keywords   = get_keywords($_POST['keywords_cat']);
+        // first possiblity : adding the given keywords to all the pictures
+        if ($_POST['common_keywords'] == 'add')
+        {
+          $keywords = array_merge($specific_keywords, $common_keywords);
+          $keywords = array_unique($keywords);
+        }
+        // second possiblity : removing the given keywords from all pictures
+        // (without deleting the other specific keywords
+        if ($_POST['common_keywords'] == 'remove')
+        {
+          $keywords = array_diff($specific_keywords, $common_keywords);
+        }
+        // cleaning the keywords array, sometimes, an empty value still remain
+        $keywords = array_remove($keywords, '');
+        // updating the picture with new keywords array
+        $query = 'UPDATE '.IMAGES_TABLE.' SET keywords = ';
+        if (count($keywords) == 0)
+        {
+          $query.= 'NULL';
+        }
+        else
+        {
+          $query.= '"';
+          $i = 0;
+          foreach ($keywords as $keyword) {
+            if ($i++ > 0) $query.= ',';
+            $query.= $keyword;
+          }
+          $query.= '"';
+        }
+        $query.= ' WHERE id = '.$row['id'];
+        $query.= ';';
+        pwg_query($query);
+      }
+    }
+  }
+// +-----------------------------------------------------------------------+
+// |                           form initialization                         |
+// +-----------------------------------------------------------------------+
+  if (!isset($_GET['start'])
+      or !is_numeric($_GET['start'])
+      or (is_numeric($_GET['start']) and $_GET['start'] < 0))
+  {
+    $page['start'] = 0;
+  }
+  else
+  {
+    $page['start'] = $_GET['start'];
+  }
+
+  if (isset($_GET['num']) and is_numeric($_GET['num']) and $_GET['num'] >= 0)
+  {
+    $max = $conf['info_nb_elements_page'];
+    $page['start'] = floor($_GET['num'] / $max) * $max;
+  }
+  // Navigation path
+  $current_category = get_cat_info($_GET['cat_id']);
+  $url = PHPWG_ROOT_PATH.'admin.php?page=infos_images&amp;cat_id=';
+  $category_path = get_cat_display_name($current_category['name'], $url);
+  
+  $form_action = PHPWG_ROOT_PATH.'admin.php';
+  $form_action.= '?page=infos_images&amp;cat_id='.$_GET['cat_id'];
+  if($page['start'])
+  {
+    $form_action.= '&amp;start='.$_GET['start'];
+  }
+  
+  $nav_bar = create_navigation_bar($form_action,
+                                   $current_category['nb_images'],
+                                   $page['start'],
+                                   $conf['info_nb_elements_page'],
+                                   '');
+// +-----------------------------------------------------------------------+
+// |                         template initialization                       |
+// +-----------------------------------------------------------------------+
+  $template->set_filenames(array('infos_images'=>'admin/infos_images.tpl'));
+  $template->assign_vars(
+    array(
+      'CATEGORY'=>$category_path,
+      'NAV_BAR'=>$nav_bar,
+      
+      'L_INFOS_TITLE'=>$lang['infoimage_general'],
+      'L_AUTHOR'=>$lang['author'],
+      'L_INFOS_OVERALL_USE'=>$lang['infoimage_useforall'],
+      'L_INFOS_CREATION_DATE'=>$lang['infoimage_creation_date'],
+      'L_KEYWORD'=>$lang['keywords'],
+      'L_KEYWORD_SEPARATION'=>$lang['infoimage_keyword_separation'],
+      'L_INFOS_ADDTOALL'=>$lang['infoimage_addtoall'],
+      'L_INFOS_REMOVEFROMALL'=>$lang['infoimage_removefromall'],
+      'L_INFOS_DETAIL'=>$lang['infoimage_detailed'],
+      'L_THUMBNAIL'=>$lang['thumbnail'],
+      'L_INFOS_IMG'=>$lang['infoimage_title'],
+      'L_INFOS_COMMENT'=>$lang['description'],
+      'L_INFOS_ASSOCIATE'=>$lang['infoimage_associate'],
+      'L_SUBMIT'=>$lang['submit'],
+      
+      'F_ACTION'=>add_session_id($form_action)
+      ));
+// +-----------------------------------------------------------------------+
+// |                            errors display                             |
+// +-----------------------------------------------------------------------+
+  if (count($errors) != 0)
+  {
+    $template->assign_block_vars('errors',array());
+    foreach ($errors as $error)
+    {
+      $template->assign_block_vars('errors.error',array('ERROR'=>$error));
+    }
+  }
+// +-----------------------------------------------------------------------+
+// |                                 form                                  |
+// +-----------------------------------------------------------------------+
+  $array_cat_directories = array();
+
+  $pic_mod_base_url = PHPWG_ROOT_PATH.'admin.php';
+  $pic_mod_base_url = '?page=picture_modify&amp;image_id=';
+  
+  $query = '
+SELECT *
+  FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id = image_id
+  WHERE category_id = '.$page['cat'].'
+  '.$conf['order_by'].'
+  LIMIT '.$page['start'].','.$conf['info_nb_elements_page'].'
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    $thumbnail_url = get_thumbnail_src($row['path'], @$row['tn_ext']);
+
+    $template->assign_block_vars(
+      'picture',
+      array(
+        'ID_IMG'=>$row['id'],
+        'URL_IMG'=>add_session_id($pic_mod_base_url.$row['id']),
+        'TN_URL_IMG'=>$thumbnail_url,
+        'FILENAME_IMG'=>$row['file'],
+        'DEFAULTNAME_IMG'=>get_filename_wo_extension($row['file']),
+        'NAME_IMG'=>@$row['name'],
+        'DATE_IMG'=>date_convert_back(@$row['date_creation']),
+        'AUTHOR_IMG'=>@$row['author'],
+        'KEYWORDS_IMG'=>@$row['keywords'],
+        'COMMENT_IMG'=>@$row['comment']
+       ));
+  }
+  
+  // Virtualy associate a picture to a category
+  $query = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+;';
+  display_select_cat_wrapper($query,
+                             array(),
+                             'associate_option',
+                             true);
+}
+//----------------------------------------------------------- sending html code
+$template->assign_var_from_handle('ADMIN_CONTENT', 'infos_images');
+?>
Index: /branches/1.4/admin/picture_modify.php
===================================================================
--- /branches/1.4/admin/picture_modify.php	(revision 3249)
+++ /branches/1.4/admin/picture_modify.php	(revision 3249)
@@ -0,0 +1,290 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if(!defined("PHPWG_ROOT_PATH"))
+{
+  die ("Hacking attempt!");
+}
+include_once(PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php');
+//--------------------------------------------------------- update informations
+$errors = array();
+// first, we verify whether there is a mistake on the given creation date
+if (isset($_POST['date_creation']) and !empty($_POST['date_creation']))
+{
+  if (!check_date_format($_POST['date_creation']))
+  {
+    array_push($errors, $lang['err_date']);
+  }
+}
+if (isset($_POST['submit']) and count($errors) == 0)
+{
+  $query = 'UPDATE '.IMAGES_TABLE.' SET name = ';
+  if ($_POST['name'] == '')
+    $query.= 'NULL';
+  else
+    $query.= "'".htmlentities($_POST['name'], ENT_QUOTES)."'";
+  
+  $query.= ', author = ';
+  if ($_POST['author'] == '')
+    $query.= 'NULL';
+  else
+    $query.= "'".htmlentities($_POST['author'],ENT_QUOTES)."'";
+
+  $query.= ', comment = ';
+  if ($_POST['comment'] == '')
+    $query.= 'NULL';
+  else
+    $query.= "'".htmlentities($_POST['comment'],ENT_QUOTES)."'";
+
+  $query.= ', date_creation = ';
+  if (!empty($_POST['date_creation']))
+    $query.= "'".date_convert($_POST['date_creation'])."'";
+  else if ($_POST['date_creation'] == '')
+    $query.= 'NULL';
+
+  $query.= ', keywords = ';
+  $keywords_array = get_keywords($_POST['keywords']);
+  if (count($keywords_array) == 0)
+    $query.= 'NULL';
+  else
+  {
+    $query.= "'";
+    foreach ($keywords_array as $i => $keyword) {
+      if ($i > 0) $query.= ',';
+      $query.= $keyword;
+    }
+    $query.= "'";
+  }
+
+  $query.= ' WHERE id = '.$_GET['image_id'];
+  $query.= ';';
+  pwg_query($query);
+}
+// associate the element to other categories than its storage category
+if (isset($_POST['associate'])
+    and isset($_POST['cat_dissociated'])
+    and count($_POST['cat_dissociated']) > 0)
+{
+  $datas = array();
+  foreach ($_POST['cat_dissociated'] as $category_id)
+  {
+    array_push($datas, array('image_id' => $_GET['image_id'],
+                             'category_id' => $category_id));
+  }
+  mass_inserts(IMAGE_CATEGORY_TABLE, array('image_id', 'category_id'), $datas);
+
+  update_category($_POST['cat_dissociated']);
+}
+// dissociate the element from categories (but not from its storage category)
+if (isset($_POST['dissociate'])
+    and isset($_POST['cat_associated'])
+    and count($_POST['cat_associated']) > 0)
+{
+  $query = '
+DELETE FROM '.IMAGE_CATEGORY_TABLE.'
+  WHERE image_id = '.$_GET['image_id'].'
+    AND category_id IN ('.implode(',',$_POST['cat_associated'] ).')
+';
+  pwg_query($query);
+  update_category($_POST['cat_associated']);
+}
+// elect the element to represent the given categories
+if (isset($_POST['elect'])
+    and isset($_POST['cat_dismissed'])
+    and count($_POST['cat_dismissed']) > 0)
+{
+  $datas = array();
+  foreach ($_POST['cat_dismissed'] as $category_id)
+  {
+    array_push($datas,
+               array('id' => $category_id,
+                     'representative_picture_id' => $_GET['image_id']));
+  }
+  $fields = array('primary' => array('id'),
+                  'update' => array('representative_picture_id'));
+  mass_updates(CATEGORIES_TABLE, $fields, $datas);
+}
+// dismiss the element as representant of the given categories
+if (isset($_POST['dismiss'])
+    and isset($_POST['cat_elected'])
+    and count($_POST['cat_elected']) > 0)
+{
+  set_random_representant($_POST['cat_elected']);
+}
+
+// retrieving direct information about picture
+$query = '
+SELECT i.*, c.uppercats
+  FROM '.IMAGES_TABLE.' AS i
+   INNER JOIN '.CATEGORIES_TABLE.' AS c ON i.storage_category_id = c.id
+  WHERE i.id = '.$_GET['image_id'].'
+;';
+$row = mysql_fetch_array(pwg_query($query));
+
+$storage_category_id = $row['storage_category_id'];
+
+if (empty($row['name']))
+{
+  $title = str_replace('_', ' ',get_filename_wo_extension($row['file']));
+}
+else
+{
+  $title = $row['name'];
+}
+// Navigation path
+$thumbnail_url = get_thumbnail_src($row['path'], @$row['tn_ext']);
+
+$url_img = PHPWG_ROOT_PATH.'picture.php?image_id='.$_GET['image_id'];
+
+$query = '
+SELECT category_id
+  FROM '.IMAGE_CATEGORY_TABLE.'
+  WHERE image_id = '.$_GET['image_id'];
+
+if (isset($user['forbidden_categories'])
+    and !empty($user['forbidden_categories']))
+{
+  $query.= '
+    AND category_id NOT IN ('.$user['forbidden_categories'].')';
+}
+$query.= '
+  ORDER BY RAND()
+;';
+$result = pwg_query($query);
+
+if (mysql_num_rows($result) > 0)
+{
+  list($category_id) = mysql_fetch_array($result);
+  $url_img .= '&amp;cat='.$category_id;
+}
+else
+{
+  $url_img .= '&amp;cat='.$row['storage_category_id'];
+}
+
+$date = isset($_POST['date_creation']) && empty($errors)
+?$_POST['date_creation']:date_convert_back(@$row['date_creation']);
+
+$url = PHPWG_ROOT_PATH.'admin.php?page=cat_modify&amp;cat_id=';
+$storage_category = get_cat_display_name_cache($row['uppercats'],
+                                               $url,
+                                               false);
+//----------------------------------------------------- template initialization
+$template->set_filenames(array('picture_modify'=>'admin/picture_modify.tpl'));
+$template->assign_vars(array(
+  'TITLE_IMG'=>$title,
+  'STORAGE_CATEGORY_IMG'=>$storage_category,
+  'PATH_IMG'=>$row['path'],
+  'FILE_IMG'=>$row['file'],
+  'TN_URL_IMG'=>$thumbnail_url,
+  'URL_IMG'=>add_session_id($url_img),
+  'DEFAULT_NAME_IMG'=>str_replace('_',' ',get_filename_wo_extension($row['file'])),
+  'FILE_IMG'=>$row['file'],
+  'NAME_IMG'=>isset($_POST['name'])?$_POST['name']:@$row['name'],
+  'SIZE_IMG'=>@$row['width'].' * '.@$row['height'],
+  'FILESIZE_IMG'=>@$row['filesize'].' KB',
+  'REGISTRATION_DATE_IMG'=> format_date($row['date_available']),
+  'AUTHOR_IMG'=>isset($_POST['author'])?$_POST['author']:@$row['author'],
+  'CREATION_DATE_IMG'=>$date,
+  'KEYWORDS_IMG'=>isset($_POST['keywords'])?$_POST['keywords']:@$row['keywords'],
+  'COMMENT_IMG'=>isset($_POST['comment'])?$_POST['comment']:@$row['comment'],
+  
+  'L_UPLOAD_NAME'=>$lang['upload_name'],
+  'L_DEFAULT'=>$lang['default'],
+  'L_FILE'=>$lang['file'],
+  'L_SIZE'=>$lang['size'],
+  'L_FILESIZE'=>$lang['filesize'],
+  'L_REGISTRATION_DATE'=>$lang['registration_date'],
+  'L_AUTHOR'=>$lang['author'],
+  'L_CREATION_DATE'=>$lang['creation_date'],
+  'L_KEYWORDS'=>$lang['keywords'],
+  'L_COMMENT'=>$lang['description'],
+  'L_CATEGORIES'=>$lang['categories'],
+  'L_DISSOCIATE'=>$lang['dissociate'],
+  'L_INFOIMAGE_ASSOCIATE'=>$lang['infoimage_associate'],
+  'L_SUBMIT'=>$lang['submit'],
+  'L_RESET'=>$lang['reset'],
+  'L_CAT_ASSOCIATED'=>$lang['infoimage_associated'],
+  'L_CAT_DISSOCIATED'=>$lang['infoimage_dissociated'],
+  'L_PATH'=>$lang['path'],
+  'L_STORAGE_CATEGORY'=>$lang['storage_category'],
+  'L_REPRESENTS'=>$lang['represents'],
+  'L_DOESNT_REPRESENT'=>$lang['doesnt_represent'],
+  
+  'F_ACTION'=>add_session_id(PHPWG_ROOT_PATH.'admin.php?'.$_SERVER['QUERY_STRING'])
+ ));
+  
+//-------------------------------------------------------------- errors display
+if (count($errors) != 0)
+{
+  $template->assign_block_vars('errors',array());
+  foreach ($errors as $error)
+  {
+    $template->assign_block_vars('errors.error',array('ERROR'=>$error));
+  }
+}
+
+// associate to another category ?
+$query = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+    INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id = category_id
+  WHERE image_id = '.$_GET['image_id'].'
+    AND id != '.$storage_category_id.'
+;';
+display_select_cat_wrapper($query,array(),'associated_option');
+
+$result = pwg_query($query);
+$associateds = array($storage_category_id);
+while ($row = mysql_fetch_array($result))
+{
+  array_push($associateds, $row['id']);
+}
+$query = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id NOT IN ('.implode(',', $associateds).')
+;';
+display_select_cat_wrapper($query,array(),'dissociated_option');
+// representing
+$query = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE representative_picture_id = '.$_GET['image_id'].'
+;';
+display_select_cat_wrapper($query,array(),'elected_option');
+
+$query = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id IN ('.implode(',', $associateds).')
+    AND representative_picture_id != '.$_GET['image_id'].'
+;';
+display_select_cat_wrapper($query,array(),'dismissed_option');
+//----------------------------------------------------------- sending html code
+$template->assign_var_from_handle('ADMIN_CONTENT', 'picture_modify');
+?>
Index: /branches/1.4/admin/remote_site.php
===================================================================
--- /branches/1.4/admin/remote_site.php	(revision 3249)
+++ /branches/1.4/admin/remote_site.php	(revision 3249)
@@ -0,0 +1,755 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if (!defined('PHPWG_ROOT_PATH'))
+{
+  die ("Hacking attempt!");
+}
+include_once(PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php');
+
+define('CURRENT_DATE', date('Y-m-d'));
+// +-----------------------------------------------------------------------+
+// |                               functions                               |
+// +-----------------------------------------------------------------------+
+
+/**
+ * requests the given $url (a remote create_listing_file.php) and fills a
+ * list of lines corresponding to request output
+ *
+ * @param string $url
+ * @return void
+ */
+function remote_output($url)
+{
+  global $template, $errors, $lang;
+  
+  if($lines = @file($url))
+  {
+    $template->assign_block_vars('remote_output', array());
+    // cleaning lines from HTML tags
+    foreach ($lines as $line)
+    {
+      $line = trim(strip_tags($line));
+      if (preg_match('/^PWG-([A-Z]+)-/', $line, $matches))
+      {
+        $template->assign_block_vars(
+          'remote_output.remote_line',
+          array(
+            'CLASS' => 'remote'.ucfirst(strtolower($matches[1])),
+            'CONTENT' => $line
+           )
+         );
+      }
+    }
+  }
+  else
+  {
+    array_push($errors, $lang['remote_site_file_not_found']);
+  }
+}
+
+/**
+ * returns an array where are linked the sub-categories id and there
+ * directories corresponding to the given uppercat id
+ *
+ * @param int site_id
+ * @param mixed id_uppercat
+ * @return array
+ */
+function database_subdirs($site_id, $id_uppercat)
+{
+  $database_dirs = array();
+  
+  $query = '
+SELECT id,dir
+  FROM '.CATEGORIES_TABLE.'
+  WHERE site_id = '.$site_id;
+  if (!is_numeric($id_uppercat))
+  {
+    $query.= '
+    AND id_uppercat IS NULL';
+  }
+  else
+  {
+    $query.= '
+    AND id_uppercat = '.$id_uppercat;
+  }
+  // virtual categories not taken
+  $query.= '
+    AND dir IS NOT NULL
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    $database_dirs[$row['id']] = $row['dir'];
+  }
+
+  return $database_dirs;
+}
+
+/**
+ * read $listing_file and update a remote site according to its id
+ *
+ * @param string listing_file
+ * @param int site_id
+ * @return void
+ */
+function update_remote_site($listing_file, $site_id)
+{
+  global $lang, $counts, $template, $removes, $errors;
+  
+  if (@fopen($listing_file, 'r'))
+  {
+    $counts = array(
+      'new_elements' => 0,
+      'new_categories' => 0,
+      'del_elements' => 0,
+      'del_categories' => 0
+      );
+    $removes = array();
+        
+    $xml_content = getXmlCode($listing_file);
+    insert_remote_category($xml_content, $site_id, 'NULL', 0);
+    update_category();
+    ordering();
+    update_global_rank();
+        
+    $template->assign_block_vars(
+      'update',
+      array(
+        'NB_NEW_CATEGORIES'=>$counts['new_categories'],
+        'NB_DEL_CATEGORIES'=>$counts['del_categories'],
+        'NB_NEW_ELEMENTS'=>$counts['new_elements'],
+        'NB_DEL_ELEMENTS'=>$counts['del_elements']
+        ));
+        
+    if (count($removes) > 0)
+    {
+      $template->assign_block_vars('update.removes', array());
+    }
+    foreach ($removes as $remove)
+    {
+      $template->assign_block_vars('update.removes.remote_remove',
+                                   array('NAME'=>$remove));
+    }
+  }
+  else
+  {
+    array_push($errors, $lang['remote_site_listing_not_found']);
+  }
+}
+
+/**
+ * searchs the "dir" node of the xml_dir given and insert the contained
+ * categories if the are not in the database yet. The function also deletes
+ * the categories that are in the database and not in the xml_file.
+ *
+ * @param string xml_content
+ * @param int site_id
+ * @param mixed id_uppercat
+ * @param int level
+ * @return void
+ */
+function insert_remote_category($xml_content, $site_id, $id_uppercat, $level)
+{
+  global $counts, $removes, $conf;
+  
+  $uppercats = '';
+  // 0. retrieving informations on the category to display
+		
+  if (is_numeric($id_uppercat))
+  {
+    $query = '
+SELECT id,name,uppercats,dir,status,visible
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id = '.$id_uppercat.'
+;';
+    $row = mysql_fetch_array(pwg_query($query));
+    $parent = array('id' => $row['id'],
+                    'name' => $row['name'],
+                    'dir' => $row['dir'],
+                    'uppercats' => $row['uppercats'],
+                    'visible' => $row['visible'],
+                    'status' => $row['status']);
+    
+    insert_remote_element($xml_content, $id_uppercat);
+  }
+
+  // $xml_dirs contains dir names contained in the xml file for this
+  // id_uppercat
+  $xml_dirs = array();
+  $temp_dirs = getChildren($xml_content, 'dir'.$level);
+  foreach ($temp_dirs as $temp_dir)
+  {
+    array_push($xml_dirs, getAttribute($temp_dir, 'name'));
+  }
+
+  // $database_dirs contains dir names contained in the database for this
+  // id_uppercat and site_id
+  $database_dirs = database_subdirs($site_id, $id_uppercat);
+  
+  // 3. we have to remove the categories of the database not present anymore
+  $to_delete = array();
+  foreach ($database_dirs as $id => $dir)
+  {
+    if (!in_array($dir, $xml_dirs))
+    {
+      array_push($to_delete, $id);
+      array_push($removes, get_complete_dir($id));
+    }
+  }
+  delete_categories($to_delete);
+
+  // array of new categories to insert
+  $inserts = array();
+  
+  // calculate default value at category creation
+  $create_values = array();
+  if (isset($parent))
+  {
+    // at creation, must a category be visible or not ? Warning : if
+    // the parent category is invisible, the category is automatically
+    // create invisible. (invisible = locked)
+    if ('false' == $parent['visible'])
+    {
+      $create_values{'visible'} = 'false';
+    }
+    else
+    {
+      $create_values{'visible'} = $conf['newcat_default_visible'];
+    }
+    // at creation, must a category be public or private ? Warning :
+    // if the parent category is private, the category is
+    // automatically create private.
+    if ('private' == $parent['status'])
+    {
+      $create_values{'status'} = 'private';
+    }
+    else
+    {
+      $create_values{'status'} = $conf['newcat_default_status'];
+    }
+  }
+  else
+  {
+    $create_values{'visible'} = $conf['newcat_default_visible'];
+    $create_values{'status'} = $conf['newcat_default_status'];
+  }
+
+  foreach ($xml_dirs as $xml_dir)
+  {
+    // 5. Is the category already existing ? we create a subcat if not
+    //    existing
+    $category_id = array_search($xml_dir, $database_dirs);
+    if (!is_numeric($category_id))
+    {
+      $name = str_replace('_', ' ', $xml_dir);
+
+      $insert = array();
+
+      $insert{'dir'} = $xml_dir;
+      $insert{'name'} = $name;
+      $insert{'site_id'} = $site_id;
+      $insert{'uppercats'} = 'undef';
+      $insert{'commentable'} = $conf['newcat_default_commentable'];
+      $insert{'uploadable'} = 'false';
+      $insert{'status'} = $create_values{'status'};
+      $insert{'visible'} = $create_values{'visible'};
+      if (isset($parent))
+      {
+        $insert{'id_uppercat'} = $parent['id'];
+      }
+      array_push($inserts, $insert);
+    }
+  }
+
+  // we have to create the category
+  if (count($inserts) > 0)
+  {
+    // inserts all found categories
+    $dbfields = array('dir','name','site_id','uppercats','id_uppercat',
+                      'commentable','uploadable','status','visible');
+    mass_inserts(CATEGORIES_TABLE, $dbfields, $inserts);
+    $counts{'new_categories'}+= count($inserts);
+    
+    // updating uppercats field
+    $query = '
+UPDATE '.CATEGORIES_TABLE;
+    if (isset($parent))
+    {
+      $query.= "
+  SET uppercats = CONCAT('".$parent['uppercats']."',',',id)
+  WHERE id_uppercat = ".$id_uppercat;
+    }
+    else
+    {
+      $query.= '
+  SET uppercats = id
+  WHERE id_uppercat IS NULL';
+    }
+    $query.= '
+;';
+    pwg_query($query);
+  }
+
+  // Recursive call on the sub-categories (not virtual ones)
+  $database_dirs = database_subdirs($site_id, $id_uppercat);
+  
+  foreach ($temp_dirs as $temp_dir)
+  {
+    $dir = getAttribute($temp_dir, 'name');
+    $id_uppercat = array_search($dir, $database_dirs);
+    insert_remote_category($temp_dir, $site_id, $id_uppercat, $level+1);
+  }
+}
+
+/**
+ * searchs the "root" node of $xml_dir (xml string), inserts elements in the
+ * database if new
+ *
+ * @param string xml_dir
+ * @param int category_id
+ * @return void
+ */
+function insert_remote_element($xml_dir, $category_id)
+{
+  global $counts, $lang, $removes;
+
+  $output = '';
+  $root = getChild($xml_dir, 'root');
+
+  $xml_files = array();
+  $xml_elements = getChildren($root, 'element');
+  foreach ($xml_elements as $xml_element)
+  {
+    array_push($xml_files, getAttribute($xml_element,'file'));
+  }
+  
+  // we have to delete all the images from the database that are not in the
+  // directory anymore (not in the XML anymore)
+  $query = '
+SELECT id,file
+  FROM '.IMAGES_TABLE.'
+  WHERE storage_category_id = '.$category_id.'
+;';
+  $result = pwg_query($query);
+  $to_delete = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    if (!in_array($row['file'], $xml_files))
+    {
+      // local_dir is cached
+      if (!isset($local_dir))
+      {
+        $local_dir = get_local_dir($category_id);
+      }
+      array_push($removes, $local_dir.$row['file']);
+      array_push($to_delete, $row['id']);
+    }
+  }
+  delete_elements($to_delete);
+
+  $database_elements = array();
+  $query = '
+SELECT file
+  FROM '.IMAGES_TABLE.'
+  WHERE storage_category_id = '.$category_id.'
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($database_elements, $row['file']);
+  }
+
+  $inserts = array();
+  foreach ($xml_elements as $xml_element)
+  {
+    // minimal tag : <element file="albatros.jpg"/>
+    $file = getAttribute($xml_element, 'file');
+
+    // is the picture already existing in the database ?
+    if (!in_array($file, $database_elements))
+    {
+      $insert = array();
+      $insert{'file'} = $file;
+      $insert{'storage_category_id'} = $category_id;
+      $insert{'date_available'} = CURRENT_DATE;
+      $optional_atts = array('tn_ext',
+                             'representative_ext',
+                             'filesize',
+                             'width',
+                             'height',
+                             'date_creation',
+                             'author',
+                             'keywords',
+                             'name',
+                             'comment',
+                             'path');
+      foreach ($optional_atts as $att)
+      {
+        if (getAttribute($xml_element, $att) != '')
+        {
+          $insert{$att} = getAttribute($xml_element, $att);
+        }
+      }
+      array_push($inserts, $insert);
+    }
+  }
+
+  if (count($inserts) > 0)
+  {
+    $dbfields = array('file','storage_category_id','date_available','tn_ext',
+                      'filesize','width','height','date_creation','author',
+                      'keywords','name','comment','path');
+    mass_inserts(IMAGES_TABLE, $dbfields, $inserts);
+    $counts{'new_elements'}+= count($inserts);
+
+    // what are the ids of the pictures in the $category_id ?
+    $ids = array();
+
+    $query = '
+SELECT id
+  FROM '.IMAGES_TABLE.'
+  WHERE storage_category_id = '.$category_id.'
+;';
+    $result = pwg_query($query);
+    while ($row = mysql_fetch_array($result))
+    {
+      array_push($ids, $row['id']);
+    }
+
+    // recreation of the links between this storage category pictures and
+    // its storage category
+    $query = '
+DELETE FROM '.IMAGE_CATEGORY_TABLE.'
+  WHERE category_id = '.$category_id.'
+    AND image_id IN ('.implode(',', $ids).')
+;';
+    pwg_query($query);
+
+    $query = '
+INSERT INTO '.IMAGE_CATEGORY_TABLE.'
+  (category_id,image_id)
+  VALUES';
+    foreach ($ids as $num => $image_id)
+    {
+      $query.= '
+  ';
+      if ($num > 0)
+      {
+        $query.= ',';
+      }
+      $query.= '('.$category_id.','.$image_id.')';
+    }
+    $query.= '
+;';
+    pwg_query($query);
+    // set a new representative element for this category
+    $query = '
+SELECT image_id
+  FROM '.IMAGE_CATEGORY_TABLE.'
+  WHERE category_id = '.$category_id.'
+  ORDER BY RAND()
+  LIMIT 0,1
+;';
+    list($representative) = mysql_fetch_array(pwg_query($query));
+    $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET representative_picture_id = '.$representative.'
+  WHERE id = '.$category_id.'
+;';
+    pwg_query($query);
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                             template init                             |
+// +-----------------------------------------------------------------------+
+$template->set_filenames(array('remote_site'=>'admin/remote_site.tpl'));
+
+$template->assign_vars(
+  array(
+    'L_SUBMIT'=>$lang['submit'],
+    'L_REMOTE_SITE_CREATE'=>$lang['remote_site_create'],
+    'L_REMOTE_SITE_GENERATE'=>$lang['remote_site_generate'],
+    'L_REMOTE_SITE_GENERATE_HINT'=>$lang['remote_site_generate_hint'],
+    'L_REMOTE_SITE_UPDATE'=>$lang['remote_site_update'],
+    'L_REMOTE_SITE_UPDATE_HINT'=>$lang['remote_site_update_hint'],
+    'L_REMOTE_SITE_CLEAN'=>$lang['remote_site_clean'],
+    'L_REMOTE_SITE_CLEAN_HINT'=>$lang['remote_site_clean_hint'],
+    'L_REMOTE_SITE_DELETE'=>$lang['remote_site_delete'],
+    'L_REMOTE_SITE_DELETE_HINT'=>$lang['remote_site_delete_hint'],
+    'L_NB_NEW_ELEMENTS'=>$lang['update_nb_new_elements'],
+    'L_NB_NEW_CATEGORIES'=>$lang['update_nb_new_categories'],
+    'L_NB_DEL_ELEMENTS'=>$lang['update_nb_del_elements'],
+    'L_NB_DEL_CATEGORIES'=>$lang['update_nb_del_categories'],
+    'L_REMOTE_SITE_REMOVED_TITLE'=>$lang['remote_site_removed_title'],
+    'L_REMOTE_SITE_REMOVED'=>$lang['remote_site_removed'],
+    'L_REMOTE_SITE_LOCAL_FOUND'=>$lang['remote_site_local_found'],
+    'L_REMOTE_SITE_LOCAL_NEW'=>$lang['remote_site_local_new'],
+    'L_REMOTE_SITE_LOCAL_UPDATE'=>$lang['remote_site_local_update'],
+    
+    'F_ACTION'=>add_session_id(PHPWG_ROOT_PATH.'admin.php?page=remote_site')
+   )
+ );
+// +-----------------------------------------------------------------------+
+// |                        new site creation form                         |
+// +-----------------------------------------------------------------------+
+$errors = array();
+
+if (isset($_POST['submit']))
+{
+  // site must start by http:// or https://
+  if (!preg_match('/^https?:\/\/[~\/\.\w-]+$/', $_POST['galleries_url']))
+  {
+    array_push($errors, $lang['remote_site_uncorrect_url']);
+  }
+  else
+  {
+    $page['galleries_url'] = preg_replace('/[\/]*$/',
+                                          '',
+                                          $_POST['galleries_url']);
+    $page['galleries_url'].= '/';
+    // site must not exists
+    $query = '
+SELECT COUNT(id) AS count
+  FROM '.SITES_TABLE.'
+  WHERE galleries_url = \''.$page['galleries_url'].'\'
+;';
+    $row = mysql_fetch_array(pwg_query($query));
+    if ($row['count'] > 0)
+    {
+      array_push($errors, $lang['remote_site_already_exists']);
+    }
+  }
+
+  if (count($errors) == 0)
+  {
+    $url = $page['galleries_url'].'create_listing_file.php';
+    $url.= '?action=test';
+    $url.= '&version='.PHPWG_VERSION;
+    if ($lines = @file($url))
+    {
+      $first_line = strip_tags($lines[0]);
+      if (!preg_match('/^PWG-INFO-2:/', $first_line))
+      {
+        array_push($errors, $lang['remote_site_error'].' : '.$first_line);
+      }
+    }
+    else
+    {
+      array_push($errors, $lang['remote_site_file_not_found']);
+    }
+  }
+  
+  if (count($errors) == 0)
+  {
+    $query = '
+INSERT INTO '.SITES_TABLE.'
+  (galleries_url)
+  VALUES
+  (\''.$page['galleries_url'].'\')
+;';
+    pwg_query($query);
+
+    $template->assign_block_vars(
+      'confirmation',
+      array(
+        'CONTENT'=>$page['galleries_url'].' '.$lang['remote_site_created']
+        ));
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                            actions on site                            |
+// +-----------------------------------------------------------------------+
+if (isset($_GET['site']) and is_numeric($_GET['site']))
+{
+  $page['site'] = $_GET['site'];
+}
+
+if (isset($_GET['action']))
+{
+  if (isset($page['site']))
+  {
+    $query = '
+SELECT galleries_url
+  FROM '.SITES_TABLE.'
+  WHERE id = '.$page['site'].'
+;';
+    list($galleries_url) = mysql_fetch_array(pwg_query($query));
+  }
+
+  switch($_GET['action'])
+  {
+    case 'delete' :
+    {
+      delete_site($page['site']);
+
+      $template->assign_block_vars(
+        'confirmation',
+        array(
+          'CONTENT'=>$galleries_url.' '.$lang['remote_site_deleted']
+          ));
+      
+      break;
+    }
+    case 'generate' :
+    {
+      $title = $galleries_url.' : '.$lang['remote_site_generate'];
+      $template->assign_vars(array('REMOTE_SITE_TITLE'=>$title));
+      remote_output($galleries_url.'create_listing_file.php?action=generate');
+      break;
+    }
+    case 'update' :
+    {
+      $title = $galleries_url.' : '.$lang['remote_site_update'];
+      $template->assign_vars(array('REMOTE_SITE_TITLE'=>$title));
+      update_remote_site($galleries_url.'listing.xml', $page['site']);
+      break;
+    }
+    case 'clean' :
+    {
+      $title = $galleries_url.' : '.$lang['remote_site_clean'];
+      $template->assign_vars(array('REMOTE_SITE_TITLE'=>$title));
+      remote_output($galleries_url.'create_listing_file.php?action=clean');
+      break;
+    }
+    case 'local_update' :
+    {
+      $local_listing = PHPWG_ROOT_PATH.'listing.xml';
+      $xml_content = getXmlCode($local_listing);
+      $url = getAttribute(getChild($xml_content, 'informations'), 'url');
+
+      // is the site already existing ?
+      $query = '
+SELECT id
+  FROM '.SITES_TABLE.'
+  WHERE galleries_url = \''.addslashes($url).'\'
+;';
+      $result = pwg_query($query);
+      if (mysql_num_rows($result) == 0)
+      {
+        // we have to register this site in the database
+        $query = '
+INSERT INTO '.SITES_TABLE.'
+  (galleries_url)
+  VALUES
+  (\''.$url.'\')
+;';
+        pwg_query($query);
+        $site_id = mysql_insert_id();
+      }
+      else
+      {
+        // we get the already registered id
+        $row = mysql_fetch_array($result);
+        $site_id = $row['id'];
+      }
+      
+      $title = $url.' : '.$lang['remote_site_local_update'];
+      $template->assign_vars(array('REMOTE_SITE_TITLE'=>$title));
+      update_remote_site($local_listing, $site_id);
+      break;
+    }
+  }
+}
+else
+{
+  // we search a "local" listing.xml file
+  $local_listing = PHPWG_ROOT_PATH.'listing.xml';
+  if (is_file($local_listing))
+  {
+    $xml_content = getXmlCode($local_listing);
+    $url = getAttribute(getChild($xml_content, 'informations'), 'url');
+
+    $base_url = PHPWG_ROOT_PATH.'admin.php?page=remote_site&amp;action=';
+    
+    $template->assign_block_vars(
+      'local',
+      array(
+        'URL' => $url,
+        'U_UPDATE' => add_session_id($base_url.'local_update')
+        )
+      );
+
+    // is the site already existing ?
+    $query = '
+SELECT COUNT(*)
+  FROM '.SITES_TABLE.'
+  WHERE galleries_url = \''.addslashes($url).'\'
+;';
+    list($count) = mysql_fetch_array(pwg_query($query));
+    if ($count == 0)
+    {
+      $template->assign_block_vars('local.new_site', array());
+    }
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                           remote sites list                           |
+// +-----------------------------------------------------------------------+
+
+// site 1 is the local site, should not be taken into account
+$query = '
+SELECT id, galleries_url
+  FROM '.SITES_TABLE.'
+  WHERE id != 1
+;';
+$result = pwg_query($query);
+while ($row = mysql_fetch_array($result))
+{
+  $base_url = PHPWG_ROOT_PATH.'admin.php';
+  $base_url.= '?page=remote_site';
+  $base_url.= '&amp;site='.$row['id'];
+  $base_url.= '&amp;action=';
+  
+  $template->assign_block_vars(
+    'site',
+    array(
+      'NAME' => $row['galleries_url'],
+      'U_GENERATE' => add_session_id($base_url.'generate'),
+      'U_UPDATE' => add_session_id($base_url.'update'),
+      'U_CLEAN' => add_session_id($base_url.'clean'),
+      'U_DELETE' => add_session_id($base_url.'delete')
+     )
+   );
+}
+// +-----------------------------------------------------------------------+
+// |                             errors display                            |
+// +-----------------------------------------------------------------------+
+if (count($errors) != 0)
+{
+  $template->assign_block_vars('errors',array());
+  foreach ($errors as $error)
+  {
+    $template->assign_block_vars('errors.error',array('ERROR'=>$error));
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                           sending html code                           |
+// +-----------------------------------------------------------------------+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'remote_site');
+?>
Index: /branches/1.4/admin/search.php
===================================================================
--- /branches/1.4/admin/search.php	(revision 3249)
+++ /branches/1.4/admin/search.php	(revision 3249)
@@ -0,0 +1,108 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+define('PHPWG_ROOT_PATH','../');
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+include_once( PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php' );
+
+//----------------------------------------------------- template initialization
+$title = $lang['Find_username'];
+include(PHPWG_ROOT_PATH.'include/page_header.php');
+
+$template->set_filenames( array('search'=>'admin/search_username.tpl') );
+$template->assign_vars(array(
+  'USERNAME'=>( !empty($search_match) ) ? strip_tags($search_match) : '',
+  
+  'L_SEARCH_USERNAME'=>$lang['Find_username'],
+  'L_SEARCH'=>$lang['search'],
+  'L_SEARCH_EXPLAIN'=>$lang['search_explain'],
+  'L_SELECT'=>$lang['Select'],
+  'L_UPDATE_USERNAME'=>$lang['Look_up_user'],
+  'L_CLOSE_WINDOW'=>$lang['Close'],
+
+  'F_SEARCH_ACTION' => add_session_id($_SERVER['PHP_SELF']),
+  ));
+
+//----------------------------------------------------------------- form action
+//
+// Define initial vars
+//
+if ( isset($_POST['mode']) || isset($_GET['mode']) )
+{
+  $mode = ( isset($_POST['mode']) ) ? $_POST['mode'] : $_GET['mode'];
+}
+else
+{
+  $mode = '';
+}
+$search_match = ''; 
+if ( isset($_POST['search_username']) )
+{
+  $search_match = $_POST['search_username'];
+}
+  
+$username_list = '';
+if ( !empty($search_match) )
+{
+  $username_search = preg_replace('/\*/', '%', trim(strip_tags($search_match)));
+  
+  $sql = "SELECT username 
+    FROM " . USERS_TABLE . " 
+    WHERE username LIKE '" . str_replace("\'", "''", $username_search) . "' 
+    AND id <> ".ANONYMOUS."
+		ORDER BY username";
+  if ( !($result = pwg_query($sql)) )
+  {
+    die('Could not obtain search results');
+  }
+  
+  if ( $row = mysql_fetch_array($result) )
+  {
+    do
+    {
+    $username_list .= '<option value="' . $row['username'] . '">' . $row['username'] . '</option>';
+    }
+    while ( $row = mysql_fetch_array($result) );
+  }
+  else
+  {
+    $username_list .= '<option>' . $lang['No_match']. '</option>';
+  }
+  mysql_free_result($result);
+}
+  
+//------------------------------------------------------------------ users list
+if ( !empty($username_list))
+{
+  $template->assign_block_vars('switch_select_name', array(
+    'F_USERNAME_OPTIONS'=>$username_list
+    ));
+}
+
+$template->parse('search');
+include(PHPWG_ROOT_PATH.'include/page_tail.php');
+?>
Index: /branches/1.4/admin/stats.php
===================================================================
--- /branches/1.4/admin/stats.php	(revision 3249)
+++ /branches/1.4/admin/stats.php	(revision 3249)
@@ -0,0 +1,110 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+if( !defined("PHPWG_ROOT_PATH") )
+{
+	die ("Hacking attempt!");
+}
+include_once( PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php' );
+
+$url_img_global_report = PHPWG_ROOT_PATH.'admin/images/global_stats.img.php';
+//----------------------------------------------------- template initialization
+$template->set_filenames( array('stats'=>'admin/stats.tpl') );
+
+$template->assign_vars(array(
+  'L_MONTH'=>$lang['w_month'],
+  'L_PAGES_SEEN'=>$lang['stats_pages_seen'],
+  'L_VISITORS'=>$lang['visitors'],
+  'L_PICTURES'=>$lang['pictures'],
+  'L_STAT_TITLE'=>$lang['stats_title'],
+  'L_STAT_MONTH_TITLE'=>$lang['stats_month_title'],
+  'L_STAT_MONTHLY_ALT'=>$lang['stats_global_graph_title'],
+  
+  'IMG_MONTHLY_REPORT'=>add_session_id($url_img_global_report)
+  ));
+
+//---------------------------------------------------------------- log  history
+$query = '
+SELECT DISTINCT COUNT(*) as p,
+       MONTH(date) as m,
+       YEAR(date) as y
+  FROM '.HISTORY_TABLE.' 
+  GROUP BY DATE_FORMAT(date,\'%Y-%m\') DESC
+;';
+$result = pwg_query( $query );
+$i=0;
+while ( $row = mysql_fetch_array( $result ) )
+{
+  $current_month = $row['y']."-";
+  if ($row['m'] <10) {$current_month.='0';}
+  $current_month .= $row['m'];
+  // Number of pictures seen
+  $query = '
+SELECT COUNT(*) as p,
+       FILE as f
+  FROM '.HISTORY_TABLE.' 
+  WHERE DATE_FORMAT(date,\'%Y-%m\') = \''.$current_month.'\'
+    AND FILE = \'picture\'
+  GROUP BY FILE
+;';
+  $pictures = mysql_fetch_array(pwg_query( $query ));
+  
+  // Number of different visitors
+  $query = '
+SELECT COUNT(*) as p, login
+  FROM '.HISTORY_TABLE.' 
+  WHERE DATE_FORMAT(date,\'%Y-%m\') = \''.$current_month.'\'
+  GROUP BY login, IP
+;';
+  $user_results = pwg_query( $query );
+  $nb_visitors = 0;
+  $auth_users = array();
+  while ( $user_array = mysql_fetch_array( $user_results ) )
+  {
+    if ($user_array['login'] == 'guest') 
+	  $nb_visitors += 1;
+	else
+	  array_push($auth_users, $user_array['login']);
+  }
+  $nb_visitors +=count(array_unique($auth_users));
+  $class = ($i % 2)? 'row1':'row2'; $i++;
+  
+  $template->assign_block_vars('month',array(
+    'MONTH'=>$lang['month'][$row['m']].' '.$row['y'],
+	'PAGES'=>$row['p'],
+	'VISITORS'=>$nb_visitors,
+	'IMAGES'=>$pictures['p'],
+	
+	'T_CLASS'=>$class
+    ));
+}
+$nb_visitors = mysql_num_rows( $result );
+$days = array();
+$max_nb_visitors = 0;
+$max_pages_seen = 0;
+//----------------------------------------------------------- sending html code
+$template->assign_var_from_handle('ADMIN_CONTENT', 'stats');
+?>
Index: /branches/1.4/admin/thumbnail.php
===================================================================
--- /branches/1.4/admin/thumbnail.php	(revision 3249)
+++ /branches/1.4/admin/thumbnail.php	(revision 3249)
@@ -0,0 +1,418 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+include_once( PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php' );
+//------------------------------------------------------------------- functions
+// RatioResizeImg creates a new picture (a thumbnail since it is supposed to
+// be smaller than original picture !) in the sub directory named
+// "thumbnail".
+function RatioResizeImg($path, $newWidth, $newHeight, $tn_ext)
+{
+  global $conf, $lang, $errors;
+
+  $filename = basename($path);
+  $dirname = dirname($path);
+  
+  // extension of the picture filename
+  $extension = get_extension($filename);
+
+  if ($extension == 'jpg' or $extension == 'JPG')
+  {
+    $srcImage = @imagecreatefromjpeg($path);
+  }
+  else if ($extension == 'png' or $extension == 'PNG')
+  {
+    $srcImage = @imagecreatefrompng($path);
+  }
+  else
+  {
+    unset($extension);
+  }
+		
+  if ( isset( $srcImage ) )
+  {
+    // width/height
+    $srcWidth    = imagesx( $srcImage ); 
+    $srcHeight   = imagesy( $srcImage ); 
+    $ratioWidth  = $srcWidth/$newWidth;
+    $ratioHeight = $srcHeight/$newHeight;
+
+    // maximal size exceeded ?
+    if ( ( $ratioWidth > 1 ) or ( $ratioHeight > 1 ) )
+    {
+      if ( $ratioWidth < $ratioHeight)
+      { 
+        $destWidth = $srcWidth/$ratioHeight;
+        $destHeight = $newHeight; 
+      }
+      else
+      { 
+        $destWidth = $newWidth; 
+        $destHeight = $srcHeight/$ratioWidth;
+      }
+    }
+    else
+    {
+      $destWidth = $srcWidth;
+      $destHeight = $srcHeight;
+    }
+    // according to the GD version installed on the server
+    if ( $_POST['gd'] == 2 )
+    {
+      // GD 2.0 or more recent -> good results (but slower)
+      $destImage = imagecreatetruecolor( $destWidth, $destHeight); 
+      imagecopyresampled( $destImage, $srcImage, 0, 0, 0, 0,
+                          $destWidth,$destHeight,$srcWidth,$srcHeight );
+    }
+    else
+    {
+      // GD prior to version  2 -> pretty bad results :-/ (but fast)
+      $destImage = imagecreate( $destWidth, $destHeight);
+      imagecopyresized( $destImage, $srcImage, 0, 0, 0, 0,
+                        $destWidth,$destHeight,$srcWidth,$srcHeight );
+    }
+    
+    $tndir = $dirname.'/thumbnail';
+    if (!is_dir($tndir))
+    {
+      if (!is_writable($dirname))
+      {
+        array_push($errors, '['.$dirname.'] : '.$lang['no_write_access']);
+        return false;
+      }
+      umask(0000);
+      mkdir($tndir, 0777);
+    }
+    
+    $dest_file = $tndir.'/'.$conf['prefix_thumbnail'];
+    $dest_file.= get_filename_wo_extension($filename);
+    $dest_file.= '.'.$tn_ext;
+    
+    // creation and backup of final picture
+    if (!is_writable($tndir))
+    {
+      array_push($errors, '['.$tndir.'] : '.$lang['no_write_access']);
+      return false;
+    }
+    imagejpeg($destImage, $dest_file);
+    // freeing memory ressources
+    imagedestroy( $srcImage );
+    imagedestroy( $destImage );
+    
+    list($tn_width, $tn_height) = getimagesize($dest_file);
+    $tn_size = floor(filesize($dest_file) / 1024).' KB';
+    
+    $info = array( 'path'      => $path,
+                   'tn_file'   => $dest_file,
+                   'tn_width'  => $tn_width,
+                   'tn_height' => $tn_height,
+                   'tn_size'   => $tn_size );
+    return $info;
+  }
+  // error
+  else
+  {
+    echo $lang['tn_no_support']." ";
+    if ( isset( $extenstion ) )
+    {
+      echo $lang['tn_format'].' '.$extension;
+    }
+    else
+    {
+      echo $lang['tn_thisformat'];
+    }
+    exit();
+  }
+}
+
+$errors = array();
+$pictures = array();
+$stats = array();
+// +-----------------------------------------------------------------------+
+// |                       template initialization                         |
+// +-----------------------------------------------------------------------+
+$template->set_filenames( array('thumbnail'=>'admin/thumbnail.tpl') );
+
+$template->assign_vars(array(
+  'L_THUMBNAIL_TITLE'=>$lang['tn_dirs_title'],
+  'L_UNLINK'=>$lang['tn_no_missing'],
+  'L_MISSING_THUMBNAILS'=>$lang['tn_dirs_alone'],
+  'L_RESULTS'=>$lang['tn_results_title'],
+  'L_PATH'=>$lang['path'],
+  'L_FILESIZE'=>$lang['filesize'],
+  'L_WIDTH'=>$lang['tn_width'],
+  'L_HEIGHT'=>$lang['tn_height'],
+  'L_GENERATED'=>$lang['tn_results_gen_time'],
+  'L_THUMBNAIL'=>$lang['thumbnail'],
+  'L_PARAMS'=>$lang['tn_params_title'],
+  'L_GD'=>$lang['tn_params_GD'],
+  'L_GD_INFO'=>$lang['tn_params_GD_info'],
+  'L_WIDTH_INFO'=>$lang['tn_params_width_info'],
+  'L_HEIGHT_INFO'=>$lang['tn_params_height_info'],
+  'L_CREATE'=>$lang['tn_params_create'],
+  'L_CREATE_INFO'=>$lang['tn_params_create_info'],
+  'L_FORMAT'=>$lang['tn_params_format'],
+  'L_FORMAT_INFO'=>$lang['tn_params_format_info'],
+  'L_SUBMIT'=>$lang['submit'],
+  'L_REMAINING'=>$lang['tn_alone_title'],
+  'L_TN_STATS'=>$lang['tn_stats'],
+  'L_TN_NB_STATS'=>$lang['tn_stats_nb'],
+  'L_TN_TOTAL'=>$lang['tn_stats_total'],
+  'L_TN_MAX'=>$lang['tn_stats_max'],
+  'L_TN_MIN'=>$lang['tn_stats_min'],
+  'L_TN_AVERAGE'=>$lang['tn_stats_mean'],
+  'L_ALL'=>$lang['tn_all'],
+  
+  'T_STYLE'=>$user['template']
+  ));
+// +-----------------------------------------------------------------------+
+// |                   search pictures without thumbnails                  |
+// +-----------------------------------------------------------------------+
+$wo_thumbnails = array();
+$thumbnalized = array();
+
+// what is the directory to search in ?
+$query = '
+SELECT galleries_url
+  FROM '.SITES_TABLE.'
+  WHERE id = 1
+;';
+list($galleries_url) = mysql_fetch_array(pwg_query($query));
+$basedir = preg_replace('#/*$#', '', $galleries_url);
+
+$fs = get_fs($basedir);
+// because isset is one hundred time faster than in_array
+$fs['thumbnails'] = array_flip($fs['thumbnails']);
+
+foreach ($fs['elements'] as $path)
+{
+  // only pictures need thumbnails
+  if (in_array(get_extension($path), $conf['picture_ext']))
+  {
+    $dirname = dirname($path);
+    $filename = basename($path);
+
+    // only files matching the authorized filename pattern can be considered
+    // as "without thumbnail"
+    if (!preg_match('/^[a-zA-Z0-9-_.]+$/', $filename))
+    {
+      continue;
+    }
+    
+    // searching the element
+    $filename_wo_ext = get_filename_wo_extension($filename);
+    $tn_ext = '';
+    $base_test = $dirname.'/thumbnail/';
+    $base_test.= $conf['prefix_thumbnail'].$filename_wo_ext.'.';
+    foreach ($conf['picture_ext'] as $ext)
+    {
+      if (isset($fs['thumbnails'][$base_test.$ext]))
+      {
+        $tn_ext = $ext;
+        break;
+      }
+    }
+    
+    if (empty($tn_ext))
+    {
+      array_push($wo_thumbnails, $path);
+    }
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                         thumbnails creation                           |
+// +-----------------------------------------------------------------------+
+if (isset($_POST['submit']))
+{
+  $errors = array();
+  $times = array();
+  $infos = array();
+  
+  // checking criteria
+  if (!ereg('^[0-9]{2,3}$', $_POST['width']) or $_POST['width'] < 10)
+  {
+    array_push($errors, $lang['tn_err_width'].' 10');
+  }
+  if (!ereg('^[0-9]{2,3}$', $_POST['height']) or $_POST['height'] < 10)
+  {
+    array_push($errors, $lang['tn_err_height'].' 10');
+  }
+  
+  // picture miniaturization
+  if (count($errors) == 0)
+  {
+    $num = 1;
+    foreach ($wo_thumbnails as $path)
+    {
+      if (is_numeric($_POST['n']) and $num > $_POST['n'])
+      {
+        break;
+      }
+      
+      $starttime = get_moment();
+      if ($info = RatioResizeImg($path,$_POST['width'],$_POST['height'],'jpg'))
+      {
+        $endtime = get_moment();
+        $info['time'] = ($endtime - $starttime) * 1000;
+        array_push($infos, $info);
+        array_push($times, $info['time']);
+        array_push($thumbnalized, $path);
+        $num++;
+      }
+      else
+      {
+        break;
+      }
+    }
+
+    if (count($infos) > 0)
+    {
+      $sum = array_sum($times);
+      $average = $sum / count($times);
+      sort($times, SORT_NUMERIC);
+      $max = array_pop($times);
+      if (count($thumbnalized) == 1)
+      {
+        $min = $max;
+      }
+      else
+      {
+        $min = array_shift($times);
+      }
+      
+      $template->assign_block_vars(
+        'results',
+        array(
+          'TN_NB'=>count($infos),
+          'TN_TOTAL'=>number_format($sum, 2, '.', ' ').' ms',
+          'TN_MAX'=>number_format($max, 2, '.', ' ').' ms',
+          'TN_MIN'=>number_format($min, 2, '.', ' ').' ms',
+          'TN_AVERAGE'=>number_format($average, 2, '.', ' ').' ms'
+          ));
+      
+      foreach ($infos as $i => $info)
+      {
+        if ($info['time'] == $max)
+        {
+          $class = 'worst_gen_time';
+        }
+        else if ($info['time'] == $min)
+        {
+          $class = 'best_gen_time';
+        }
+        else
+        {
+          $class = '';
+        }
+        
+        $template->assign_block_vars(
+          'results.picture',
+          array(
+            'PATH'=>$info['path'],
+            'TN_FILE_IMG'=>$info['tn_file'],
+            'TN_FILESIZE_IMG'=>$info['tn_size'],
+            'TN_WIDTH_IMG'=>$info['tn_width'],
+            'TN_HEIGHT_IMG'=>$info['tn_height'],
+            'GEN_TIME'=>number_format($info['time'], 2, '.', ' ').' ms',
+            
+            'T_CLASS'=>$class
+            ));
+      }
+    }
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                            errors display                             |
+// +-----------------------------------------------------------------------+
+if (count($errors) != 0)
+{
+  $template->assign_block_vars('errors',array());
+  foreach ($errors as $error)
+  {
+    $template->assign_block_vars('errors.error',array('ERROR'=>$error));
+  }
+}
+// +-----------------------------------------------------------------------+
+// |             form & pictures without thumbnails display                |
+// +-----------------------------------------------------------------------+
+$remainings = array_diff($wo_thumbnails, $thumbnalized);
+
+if (count($remainings) > 0)
+{
+  $form_url = PHPWG_ROOT_PATH.'admin.php?page=thumbnail';
+  $gd = !empty($_POST['gd']) ? $_POST['gd'] : 2;
+  $width = !empty($_POST['width']) ? $_POST['width'] : $conf['tn_width'];
+  $height = !empty($_POST['height']) ? $_POST['height'] : $conf['tn_height'];
+  $n = !empty($_POST['n']) ? $_POST['n'] : 5;
+  
+  $gdlabel = 'GD'.$gd.'_CHECKED';
+  $nlabel = 'n_'.$n.'_CHECKED';
+  
+  $template->assign_block_vars(
+    'params',
+    array(
+      'F_ACTION'=>add_session_id($form_url),
+      $gdlabel=>'checked="checked"',
+      $nlabel=>'checked="checked"',
+      'WIDTH_TN'=>$width,
+      'HEIGHT_TN'=>$height
+      ));
+
+  $template->assign_block_vars(
+    'remainings',
+    array('TOTAL_IMG'=>count($remainings)));
+
+  $num = 1;
+  foreach ($remainings as $path)
+  {
+    $class = ($num % 2) ? 'row1' : 'row2';
+    list($width, $height) = getimagesize($path);
+    $size = floor(filesize($path) / 1024).' KB';
+
+    $template->assign_block_vars(
+      'remainings.remaining',
+      array(
+        'NB_IMG'=>($num),
+        'PATH'=>$path,
+        'FILESIZE_IMG'=>$size,
+        'WIDTH_IMG'=>$width,
+        'HEIGHT_IMG'=>$height,
+        
+        'T_CLASS'=>$class
+        ));
+
+    $num++;
+  }
+}
+else
+{
+  $template->assign_block_vars('warning', array());
+}
+// +-----------------------------------------------------------------------+
+// |                           return to admin                             |
+// +-----------------------------------------------------------------------+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'thumbnail');
+?>
Index: /branches/1.4/admin/update.php
===================================================================
--- /branches/1.4/admin/update.php	(revision 3249)
+++ /branches/1.4/admin/update.php	(revision 3249)
@@ -0,0 +1,750 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if (!defined('PHPWG_ROOT_PATH'))
+{
+  die ('Hacking attempt!');
+}
+include_once( PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php');
+
+define('CURRENT_DATE', date('Y-m-d'));
+$error_labels = array('PWG-UPDATE-1' => $lang['update_wrong_dirname_short'],
+                      'PWG-UPDATE-2' => $lang['update_missing_tn_short']);
+$errors = array();
+$infos = array();
+// +-----------------------------------------------------------------------+
+// |                      directories / categories                         |
+// +-----------------------------------------------------------------------+
+if (isset($_POST['submit'])
+    and ($_POST['sync'] == 'dirs' or $_POST['sync'] == 'files'))
+{
+  $counts['new_categories'] = 0;
+  $counts['del_categories'] = 0;
+  $counts['del_elements'] = 0;
+  $counts['new_elements'] = 0;
+
+  // shall we simulate only
+  if (isset($_POST['simulate']) and $_POST['simulate'] == 1)
+  {
+    $simulate = true;
+  }
+  else
+  {
+    $simulate = false;
+  }
+  
+  $start = get_moment();
+  // which categories to update ?
+  $cat_ids = array();
+
+  $query = '
+SELECT id, uppercats, global_rank, status, visible
+  FROM '.CATEGORIES_TABLE.'
+  WHERE dir IS NOT NULL
+    AND site_id = 1';
+  if (isset($_POST['cat']) and is_numeric($_POST['cat']))
+  {
+    if (isset($_POST['subcats-included']) and $_POST['subcats-included'] == 1)
+    {
+      $query.= '
+    AND uppercats REGEXP \'(^|,)'.$_POST['cat'].'(,|$)\'
+';
+    }
+    else
+    {
+      $query.= '
+    AND id = '.$_POST['cat'].'
+';
+    }
+  }
+  $query.= '
+;';
+  $result = pwg_query($query);
+
+  $db_categories = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    $db_categories[$row['id']] = $row;
+  }
+
+  // get categort full directories in an array for comparison with file
+  // system directory tree
+  $db_fulldirs = get_fulldirs(array_keys($db_categories));
+  
+  // what is the base directory to search file system sub-directories ?
+  if (isset($_POST['cat']) and is_numeric($_POST['cat']))
+  {
+    $basedir = $db_fulldirs[$_POST['cat']];
+  }
+  else
+  {
+    $query = '
+SELECT galleries_url
+  FROM '.SITES_TABLE.'
+  WHERE id = 1
+;';
+    list($galleries_url) = mysql_fetch_array(pwg_query($query));
+    $basedir = preg_replace('#/*$#', '', $galleries_url);
+  }
+
+  // we need to have fulldirs as keys to make efficient comparison
+  $db_fulldirs = array_flip($db_fulldirs);
+
+  // finding next rank for each id_uppercat
+  $next_rank['NULL'] = 1;
+  
+  $query = '
+SELECT id_uppercat, MAX(rank)+1 AS next_rank
+  FROM '.CATEGORIES_TABLE.'
+  GROUP BY id_uppercat
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    // for the id_uppercat NULL, we write 'NULL' and not the empty string
+    if (!isset($row['id_uppercat']) or $row['id_uppercat'] == '')
+    {
+      $row['id_uppercat'] = 'NULL';
+    }
+    $next_rank[$row['id_uppercat']] = $row['next_rank'];
+  }
+  
+  // next category id available
+  $query = '
+SELECT IF(MAX(id)+1 IS NULL, 1, MAX(id)+1) AS next_id
+  FROM '.CATEGORIES_TABLE.'
+;';
+  list($next_id) = mysql_fetch_array(pwg_query($query));
+
+  // retrieve file system sub-directories fulldirs
+  $fs_fulldirs = get_fs_directories($basedir);
+  // get_fs_directories doesn't include the base directory, so if it's a
+  // category directory, we need to include it in our array
+  if (isset($_POST['cat']))
+  {
+    array_push($fs_fulldirs, $basedir);
+  }
+  
+  $inserts = array();
+  // new categories are the directories not present yet in the database
+  foreach (array_diff($fs_fulldirs, array_keys($db_fulldirs)) as $fulldir)
+  {
+    $dir = basename($fulldir);
+    if (preg_match('/^[a-zA-Z0-9-_.]+$/', $dir))
+    {
+      $insert = array();
+      
+      $insert{'id'} = $next_id++;
+      $insert{'dir'} = $dir;
+      $insert{'name'} = str_replace('_', ' ', $dir);
+      $insert{'site_id'} = 1;
+      $insert{'commentable'} = $conf['newcat_default_commentable'];
+      $insert{'uploadable'} = $conf['newcat_default_uploadable'];
+      $insert{'status'} = $conf{'newcat_default_status'};
+      $insert{'visible'} = $conf{'newcat_default_visible'};
+
+      if (isset($db_fulldirs[dirname($fulldir)]))
+      {
+        $parent = $db_fulldirs[dirname($fulldir)];
+
+        $insert{'id_uppercat'} = $parent;
+        $insert{'uppercats'} =
+          $db_categories[$parent]['uppercats'].','.$insert{'id'};
+        $insert{'rank'} = $next_rank[$parent]++;
+        $insert{'global_rank'} =
+          $db_categories[$parent]['global_rank'].'.'.$insert{'rank'};
+        if ('private' == $db_categories[$parent]['status'])
+        {
+          $insert{'status'} = 'private';
+        }
+        if ('false' == $db_categories[$parent]['visible'])
+        {
+          $insert{'visible'} = 'false';
+        }
+      }
+      else
+      {
+        $insert{'uppercats'} = $insert{'id'};
+        $insert{'rank'} = $next_rank['NULL']++;
+        $insert{'global_rank'} = $insert{'rank'};
+      }
+
+      array_push($inserts, $insert);
+      array_push($infos, array('path' => $fulldir,
+                               'info' => $lang['update_research_added']));
+
+      // add the new category to $db_categories and $db_fulldirs array
+      $db_categories[$insert{'id'}] =
+        array(
+          'id' => $insert{'id'},
+          'status' => $insert{'status'},
+          'visible' => $insert{'visible'},
+          'uppercats' => $insert{'uppercats'},
+          'global_rank' => $insert{'global_rank'}
+          );
+      $db_fulldirs[$fulldir] = $insert{'id'};
+      $next_rank[$insert{'id'}] = 1;
+    }
+    else
+    {
+      array_push($errors, array('path' => $fulldir, 'type' => 'PWG-UPDATE-1'));
+    }
+  }
+
+  if (count($inserts) > 0)
+  {
+    if (!$simulate)
+    {
+      $dbfields = array(
+        'id','dir','name','site_id','id_uppercat','uppercats','commentable',
+        'uploadable','visible','status','rank','global_rank'
+        );
+      mass_inserts(CATEGORIES_TABLE, $dbfields, $inserts);
+    }
+    
+    $counts['new_categories'] = count($inserts);
+  }
+
+  // to delete categories
+  $to_delete = array();
+  foreach (array_diff(array_keys($db_fulldirs), $fs_fulldirs) as $fulldir)
+  {
+    array_push($to_delete, $db_fulldirs[$fulldir]);
+    unset($db_fulldirs[$fulldir]);
+    array_push($infos, array('path' => $fulldir,
+                             'info' => $lang['update_research_deleted']));
+  }
+  if (count($to_delete) > 0)
+  {
+    if (!$simulate)
+    {
+      delete_categories($to_delete);
+    }
+    $counts['del_categories'] = count($to_delete);
+  }
+  
+  echo '<!-- scanning dirs : ';
+  echo get_elapsed_time($start, get_moment());
+  echo ' -->'."\n";
+}
+// +-----------------------------------------------------------------------+
+// |                           files / elements                            |
+// +-----------------------------------------------------------------------+
+if (isset($_POST['submit']) and $_POST['sync'] == 'files')
+{  
+  $start_files = get_moment();
+  $start= $start_files;
+
+  $fs = get_fs($basedir);
+  
+  echo '<!-- get_fs : '.get_elapsed_time($start, get_moment()).' -->'."\n";
+  
+  $cat_ids = array_diff(array_keys($db_categories), $to_delete);
+
+  $db_elements = array();
+  $db_unvalidated = array();
+  
+  if (count($cat_ids) > 0)
+  {
+    $query = '
+SELECT id, path
+  FROM '.IMAGES_TABLE.'
+  WHERE storage_category_id IN (
+'.wordwrap(implode(', ', $cat_ids), 80, "\n").')
+;';
+    $result = pwg_query($query);
+    while ($row = mysql_fetch_array($result))
+    {
+      $db_elements[$row['id']] = $row['path'];
+    }
+
+    // searching the unvalidated waiting elements (they must not be taken into
+    // account)
+    $query = '
+SELECT file,storage_category_id
+  FROM '.WAITING_TABLE.'
+  WHERE storage_category_id IN (
+'.wordwrap(implode(', ', $cat_ids), 80, "\n").')
+    AND validated = \'false\'
+;';
+    $result = pwg_query($query);
+    while ($row = mysql_fetch_array($result))
+    {
+      array_push(
+        $db_unvalidated,
+        array_search($row['storage_category_id'],
+                     $db_fulldirs).'/'.$row['file']
+        );
+    }
+  }
+
+  // next element id available
+  $query = '
+SELECT IF(MAX(id)+1 IS NULL, 1, MAX(id)+1) AS next_element_id
+  FROM '.IMAGES_TABLE.'
+;';
+  list($next_element_id) = mysql_fetch_array(pwg_query($query));
+
+  $start = get_moment();
+
+  // because isset is one hundred time faster than in_array
+  $fs['thumbnails'] = array_flip($fs['thumbnails']);
+  $fs['representatives'] = array_flip($fs['representatives']);
+  
+  $inserts = array();
+  $insert_links = array();
+  
+  foreach (array_diff($fs['elements'], $db_elements, $db_unvalidated) as $path)
+  {
+    $insert = array();
+    // storage category must exist
+    $dirname = dirname($path);
+    if (!isset($db_fulldirs[$dirname]))
+    {
+      continue;
+    }
+    $filename = basename($path);
+    if (!preg_match('/^[a-zA-Z0-9-_.]+$/', $filename))
+    {
+      array_push($errors, array('path' => $path, 'type' => 'PWG-UPDATE-1'));
+      continue;
+    }
+
+    // searching the thumbnail
+    $filename_wo_ext = get_filename_wo_extension($filename);
+    $tn_ext = '';
+    $base_test = $dirname.'/thumbnail/';
+    $base_test.= $conf['prefix_thumbnail'].$filename_wo_ext.'.';
+    foreach ($conf['picture_ext'] as $ext)
+    {
+      $test = $base_test.$ext;
+      if (isset($fs['thumbnails'][$test]))
+      {
+        $tn_ext = $ext;
+        break;
+      }
+    }
+
+    // 2 cases : the element is a picture or not. Indeed, for a picture
+    // thumbnail is mandatory and for non picture element, thumbnail and
+    // representative are optionnal
+    if (in_array(get_extension($filename), $conf['picture_ext']))
+    {
+      // if we found a thumnbnail corresponding to our picture...
+      if ($tn_ext != '')
+      {
+        $insert{'id'} = $next_element_id++;
+        $insert{'file'} = $filename;
+        $insert{'storage_category_id'} = $db_fulldirs[$dirname];
+        $insert{'date_available'} = CURRENT_DATE;
+        $insert{'tn_ext'} = $tn_ext;
+        $insert{'path'} = $path;
+
+        array_push($inserts, $insert);
+        array_push($insert_links,
+                   array('image_id' => $insert{'id'},
+                         'category_id' => $insert{'storage_category_id'}));
+        array_push($infos, array('path' => $insert{'path'},
+                                 'info' => $lang['update_research_added']));
+      }
+      else
+      {
+        array_push($errors, array('path' => $path, 'type' => 'PWG-UPDATE-2'));
+      }
+    }
+    else
+    {
+      // searching a representative
+      $representative_ext = '';
+      $base_test = $dirname.'/pwg_representative/'.$filename_wo_ext.'.';
+      foreach ($conf['picture_ext'] as $ext)
+      {
+        $test = $base_test.$ext;
+        if (isset($fs['representatives'][$test]))
+        {
+          $representative_ext = $ext;
+          break;
+        }
+      }
+
+      $insert{'id'} = $next_element_id++;
+      $insert{'file'} = $filename;
+      $insert{'storage_category_id'} = $db_fulldirs[$dirname];
+      $insert{'date_available'} = CURRENT_DATE;
+      $insert{'path'} = $path;
+        
+      if ($tn_ext != '')
+      {
+        $insert{'tn_ext'} = $tn_ext;
+      }
+      if ($representative_ext != '')
+      {
+        $insert{'representative_ext'} = $representative_ext;
+      }
+      
+      array_push($inserts, $insert);
+      array_push($insert_links,
+                 array('image_id' => $insert{'id'},
+                       'category_id' => $insert{'storage_category_id'}));
+      array_push($infos, array('path' => $insert{'path'},
+                               'info' => $lang['update_research_added']));
+    }
+  }
+
+  if (count($inserts) > 0)
+  {
+    if (!$simulate)
+    {
+      // inserts all new elements
+      $dbfields = array(
+        'id','file','storage_category_id','date_available','tn_ext'
+        ,'representative_ext','path'
+        );
+      mass_inserts(IMAGES_TABLE, $dbfields, $inserts);
+
+      // insert all links between new elements and their storage category
+      $dbfields = array('image_id','category_id');
+      mass_inserts(IMAGE_CATEGORY_TABLE, $dbfields, $insert_links);
+    }
+    $counts['new_elements'] = count($inserts);
+  }
+
+  // delete elements that are in database but not in the filesystem
+  $to_delete_elements = array();
+  foreach (array_diff($db_elements, $fs['elements']) as $path)
+  {
+    array_push($to_delete_elements, array_search($path, $db_elements));
+    array_push($infos, array('path' => $path,
+                             'info' => $lang['update_research_deleted']));
+  }
+  if (count($to_delete_elements) > 0)
+  {
+    if (!$simulate)
+    {
+      delete_elements($to_delete_elements);
+    }
+    $counts['del_elements'] = count($to_delete_elements);
+  }
+  
+  echo '<!-- scanning files : ';
+  echo get_elapsed_time($start_files, get_moment());
+  echo ' -->'."\n";
+
+  // retrieving informations given by uploaders
+  if (!$simulate)
+  {
+    $query = '
+SELECT id,file,storage_category_id,infos
+  FROM '.WAITING_TABLE.'
+  WHERE storage_category_id IN (
+'.wordwrap(implode(', ', $cat_ids), 80, "\n").')
+    AND validated = \'true\'
+;';
+    $result = pwg_query($query);
+  
+    $datas = array();
+    $fields =
+      array(
+        'primary' => array('id'),
+        'update'  => array('date_creation', 'author', 'name', 'comment')
+        );
+
+    $waiting_to_delete = array();
+    
+    while ($row = mysql_fetch_array($result))
+    {
+      $data = array();
+      
+      $query = '
+SELECT id
+  FROM '.IMAGES_TABLE.'
+  WHERE storage_category_id = \''.$row['storage_category_id'].'\'
+    AND file = \''.$row['file'].'\'
+;';
+      list($data['id']) = mysql_fetch_array(pwg_query($query));
+
+      foreach ($fields['update'] as $field)
+      {
+        $data[$field] = getAttribute($row['infos'], $field);
+      }
+      
+      array_push($datas, $data);
+      array_push($waiting_to_delete, $row['id']);
+    }
+
+    if (count($datas) > 0)
+    {
+      mass_updates(IMAGES_TABLE, $fields, $datas);
+
+      // delete now useless waiting elements
+      $query = '
+DELETE
+  FROM '.WAITING_TABLE.'
+  WHERE id IN ('.implode(',', $waiting_to_delete).')
+;';
+      pwg_query($query);
+    }
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                        template initialization                        |
+// +-----------------------------------------------------------------------+
+$template->set_filenames(array('update'=>'admin/update.tpl'));
+
+$result_title = '';
+if (isset($simulate) and $simulate)
+{
+  $result_title.= $lang['update_simulation_title'].' ';
+}
+$result_title.= $lang['update_part_research'];
+
+// used_metadata string is displayed to inform admin which metadata will be
+// used from files for synchronization
+$used_metadata = $lang['metadata_basic'].' (filesize, width, height)';
+
+if ($conf['use_exif'])
+{
+  $used_metadata.= ', '.$lang['metadata_exif'].' (date_creation)';
+}
+
+if ($conf['use_iptc'])
+{
+  $used_metadata.= ', '.$lang['metadata_iptc'];
+  $used_metadata.= '(';
+  $used_metadata.= implode(', ', array_keys($conf['use_iptc_mapping']));
+  $used_metadata.= ')';
+}
+
+$template->assign_vars(
+  array(
+    'L_SUBMIT'=>$lang['submit'],
+    'L_RESET'=>$lang['reset'],
+    'L_UPDATE_TITLE'=>$lang['update_default_title'],
+    'L_UPDATE_SYNC_FILES'=>$lang['update_sync_files'],
+    'L_UPDATE_SYNC_DIRS'=>$lang['update_sync_dirs'],
+    'L_UPDATE_SYNC_ALL'=>$lang['update_sync_all'],
+    'L_UPDATE_SYNC_METADATA'=>$lang['update_sync_metadata'],
+    'L_UPDATE_SYNC_METADATA_NEW'=>$lang['update_sync_metadata_new'],
+    'L_UPDATE_SYNC_METADATA_ALL'=>$lang['update_sync_metadata_all'],
+    'L_UPDATE_CATS_SUBSET'=>$lang['update_cats_subset'],
+    'L_RESULT_UPDATE'=>$result_title,
+    'L_NB_NEW_ELEMENTS'=>$lang['update_nb_new_elements'],
+    'L_NB_NEW_CATEGORIES'=>$lang['update_nb_new_categories'],
+    'L_NB_DEL_ELEMENTS'=>$lang['update_nb_del_elements'],
+    'L_NB_DEL_CATEGORIES'=>$lang['update_nb_del_categories'],
+    'L_UPDATE_NB_ERRORS'=>$lang['update_nb_errors'],
+    'L_SEARCH_SUBCATS_INCLUDED'=>$lang['search_subcats_included'],
+    'L_UPDATE_WRONG_DIRNAME_INFO'=>$lang['update_wrong_dirname_info'],
+    'L_UPDATE_MISSING_TN_INFO'=>$lang['update_missing_tn_info'],
+    'PICTURE_EXT_LIST'=>implode(',', $conf['picture_ext']),
+    'L_UPDATE_ERROR_LIST_TITLE'=>$lang['update_error_list_title'],
+    'L_UPDATE_ERRORS_CAPTION'=>$lang['update_errors_caption'],
+    'L_UPDATE_DISPLAY_INFO'=>$lang['update_display_info'],
+    'L_UPDATE_SIMULATE'=>$lang['update_simulate'],
+    'L_UPDATE_INFOS_TITLE'=>$lang['update_infos_title'],
+    'L_RESULT_METADATA'=>$lang['update_result_metadata'],
+    'L_ELEMENTS_METADATA_SYNC'=>$lang['update_elements_metadata_sync'],
+    'L_USED_METADATA'=>$lang['update_used_metadata'],
+    'METADATA_LIST' => $used_metadata
+    ));
+// +-----------------------------------------------------------------------+
+// |                        introduction : choices                         |
+// +-----------------------------------------------------------------------+
+if (!isset($_POST['submit']) or (isset($simulate) and $simulate))
+{
+  $template->assign_block_vars('introduction', array());
+
+  if (isset($simulate) and $simulate)
+  {
+    switch ($_POST['sync'])
+    {
+      case 'dirs' :
+      {
+        $template->assign_vars(
+          array('SYNC_DIRS_CHECKED'=>'checked="checked"'));
+        break;
+      }
+      case 'files' :
+      {
+        $template->assign_vars(
+          array('SYNC_ALL_CHECKED'=>'checked="checked"'));
+        break;
+      }
+    }
+
+    if (isset($_POST['display_info']) and $_POST['display_info'] == 1)
+    {
+      $template->assign_vars(
+        array('DISPLAY_INFO_CHECKED'=>'checked="checked"'));
+    }
+
+    if (isset($_POST['subcats-included']) and $_POST['subcats-included'] == 1)
+    {
+      $template->assign_vars(
+        array('SUBCATS_INCLUDED_CHECKED'=>'checked="checked"'));
+    }
+
+    if (isset($_POST['cat']) and is_numeric($_POST['cat']))
+    {
+      $cat_selected = array($_POST['cat']);
+    }
+    else
+    {
+      $cat_selected = array();
+    }
+  }
+  else
+  {
+    $template->assign_vars(
+      array('SYNC_DIRS_CHECKED' => 'checked="checked"',
+            'SUBCATS_INCLUDED_CHECKED'=>'checked="checked"'));
+
+    $cat_selected = array();
+  }
+
+  $query = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE site_id = 1
+;';
+  display_select_cat_wrapper($query,
+                             $cat_selected,
+                             'introduction.category_option',
+                             false);
+}
+// +-----------------------------------------------------------------------+
+// |                          synchronize files                            |
+// +-----------------------------------------------------------------------+
+if (isset($_POST['submit'])
+    and ($_POST['sync'] == 'dirs' or $_POST['sync'] == 'files'))
+{
+  $template->assign_block_vars(
+    'update',
+    array(
+      'NB_NEW_CATEGORIES'=>$counts['new_categories'],
+      'NB_DEL_CATEGORIES'=>$counts['del_categories'],
+      'NB_NEW_ELEMENTS'=>$counts['new_elements'],
+      'NB_DEL_ELEMENTS'=>$counts['del_elements'],
+      'NB_ERRORS'=>count($errors),
+      ));
+  
+  if (count($errors) > 0)
+  {
+    $template->assign_block_vars('update.errors', array());
+    foreach ($errors as $error)
+    {
+      $template->assign_block_vars(
+        'update.errors.error',
+        array(
+          'ELEMENT' => $error['path'],
+          'LABEL' => $error['type'].' ('.$error_labels[$error['type']].')'
+          ));
+    }
+  }
+  if (count($infos) > 0
+      and isset($_POST['display_info'])
+      and $_POST['display_info'] == 1)
+  {
+    $template->assign_block_vars('update.infos', array());
+    foreach ($infos as $info)
+    {
+      $template->assign_block_vars(
+        'update.infos.info',
+        array(
+          'ELEMENT' => $info['path'],
+          'LABEL' => $info['info']
+          ));
+    }
+  }
+
+  if (!$simulate)
+  {
+    $start = get_moment();
+    update_category('all');
+    echo '<!-- update_category(all) : ';
+    echo get_elapsed_time($start,get_moment());
+    echo ' -->'."\n";
+    $start = get_moment();
+    ordering();
+    update_global_rank();
+    echo '<!-- ordering categories : ';
+    echo get_elapsed_time($start, get_moment());
+    echo ' -->'."\n";
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                          synchronize metadata                         |
+// +-----------------------------------------------------------------------+
+else if (isset($_POST['submit']) and preg_match('/^metadata/', $_POST['sync']))
+{
+  // sync only never synchronized files ?
+  if ($_POST['sync'] == 'metadata_new')
+  {
+    $opts['only_new'] = true;
+  }
+  else
+  {
+    $opts['only_new'] = false;
+  }
+  $opts['category_id'] = '';
+  $opts['recursive'] = true;
+  
+  if (isset($_POST['cat']))
+  {
+    $opts['category_id'] = $_POST['cat'];
+    // recursive ?
+    if (!isset($_POST['subcats-included']) or $_POST['subcats-included'] != 1)
+    {
+      $opts['recursive'] = false;
+    }
+  }
+  $start = get_moment();
+  $files = get_filelist($opts['category_id'],
+                        $opts['recursive'],
+                        $opts['only_new']);
+  
+  echo '<!-- get_filelist : ';
+  echo get_elapsed_time($start, get_moment());
+  echo ' -->'."\n";
+  
+  $start = get_moment();
+  update_metadata($files);
+  echo '<!-- metadata update : ';
+  echo get_elapsed_time($start, get_moment());
+  echo ' -->'."\n";
+  
+  $template->assign_block_vars(
+    'metadata_result',
+    array(
+      'NB_ELEMENTS' => count($files),
+      ));
+}
+// +-----------------------------------------------------------------------+
+// |                          sending html code                            |
+// +-----------------------------------------------------------------------+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'update');
+?>
Index: /branches/1.4/admin/user_perm.php
===================================================================
--- /branches/1.4/admin/user_perm.php	(revision 3249)
+++ /branches/1.4/admin/user_perm.php	(revision 3249)
@@ -0,0 +1,170 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if (!defined('IN_ADMIN'))
+{
+  die('Hacking attempt!');
+}
+include_once(PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php');
+
+$userdata = array();
+if (isset($_POST['submituser']))
+{
+  $userdata = getuserdata($_POST['username']);
+}
+else if (isset($_GET['user_id']))
+{
+  $userdata = getuserdata(intval($_GET['user_id']));
+}
+else if (isset($_POST['falsify'])
+         and isset($_POST['cat_true'])
+         and count($_POST['cat_true']) > 0)
+{
+  $userdata = getuserdata(intval($_POST['userid']));
+  // if you forbid access to a category, all sub-categories become
+  // automatically forbidden
+  $subcats = get_subcat_ids($_POST['cat_true']);
+  $query = '
+DELETE FROM '.USER_ACCESS_TABLE.'
+  WHERE user_id = '.$userdata['id'].'
+    AND cat_id IN ('.implode(',', $subcats).')
+;';
+  pwg_query($query);
+}
+else if (isset($_POST['trueify'])
+         and isset($_POST['cat_false'])
+         and count($_POST['cat_false']) > 0)
+{
+  $userdata = getuserdata(intval($_POST['userid']));
+    
+  $uppercats = get_uppercat_ids($_POST['cat_false']);
+  $private_uppercats = array();
+
+  $query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id IN ('.implode(',', $uppercats).')
+    AND status = \'private\'
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($private_uppercats, $row['id']);
+  }
+
+  // retrying to authorize a category which is already authorized may cause
+  // an error (in SQL statement), so we need to know which categories are
+  // accesible
+  $authorized_ids = array();
+    
+  $query = '
+SELECT cat_id
+  FROM '.USER_ACCESS_TABLE.'
+  WHERE user_id = '.$userdata['id'].'
+;';
+  $result = pwg_query($query);
+  
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($authorized_ids, $row['cat_id']);
+  }
+  
+  $inserts = array();
+  $to_autorize_ids = array_diff($private_uppercats, $authorized_ids);
+  foreach ($to_autorize_ids as $to_autorize_id)
+  {
+    array_push($inserts, array('user_id' => $userdata['id'],
+                               'cat_id' => $to_autorize_id));
+  }
+
+  mass_inserts(USER_ACCESS_TABLE, array('user_id','cat_id'), $inserts);
+}
+//----------------------------------------------------- template initialization
+if (empty($userdata))
+{
+  $template->set_filenames(array('user' => 'admin/user_perm.tpl'));
+
+  $base_url = PHPWG_ROOT_PATH.'admin.php?page=';
+  
+  $template->assign_vars(array(
+    'L_SELECT_USERNAME'=>$lang['Select_username'],
+    'L_LOOKUP_USER'=>$lang['Look_up_user'],
+    'L_FIND_USERNAME'=>$lang['Find_username'],
+    'L_AUTH_USER'=>$lang['permuser_only_private'],
+    'L_SUBMIT'=>$lang['submit'],
+
+    'F_SEARCH_USER_ACTION' => add_session_id($base_url.'user_perm'),
+    'U_SEARCH_USER' => add_session_id(PHPWG_ROOT_PATH.'admin/search.php')
+    ));
+}
+else
+{
+  $template->set_filenames(array('user'=>'admin/cat_options.tpl'));
+  $template->assign_vars(
+    array(
+      'L_RESET'=>$lang['reset'],
+      'L_CAT_OPTIONS_TRUE'=>$lang['authorized'],
+      'L_CAT_OPTIONS_FALSE'=>$lang['forbidden'],
+      'L_CAT_OPTIONS_INFO'=>$lang['permuser_info'],
+      
+      'HIDDEN_NAME'=> 'userid',
+      'HIDDEN_VALUE'=>$userdata['id'],
+      'F_ACTION' => add_session_id(PHPWG_ROOT_PATH.'admin.php?page=user_perm'),
+      ));
+
+  // only private categories are listed
+  $query_true = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.' INNER JOIN '.USER_ACCESS_TABLE.' ON cat_id = id
+  WHERE status = \'private\'
+    AND user_id = '.$userdata['id'].'
+;';
+  display_select_cat_wrapper($query_true,array(),'category_option_true');
+  
+  $result = pwg_query($query_true);
+  $authorized_ids = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($authorized_ids, $row['id']);
+  }
+  
+  $query_false = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE status = \'private\'';
+  if (count($authorized_ids) > 0)
+  {
+    $query_false.= '
+    AND id NOT IN ('.implode(',', $authorized_ids).')';
+  }
+  $query_false.= '
+;';
+  display_select_cat_wrapper($query_false,array(),'category_option_false');
+}
+//----------------------------------------------------------- sending html code
+$template->assign_var_from_handle('ADMIN_CONTENT', 'user');
+?>
Index: /branches/1.4/admin/waiting.php
===================================================================
--- /branches/1.4/admin/waiting.php	(revision 3249)
+++ /branches/1.4/admin/waiting.php	(revision 3249)
@@ -0,0 +1,149 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+if( !defined("PHPWG_ROOT_PATH") )
+{
+  die ("Hacking attempt!");
+}
+include_once( PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php');
+//--------------------------------------------------------------------- updates
+if ( isset( $_POST['submit'] ) )
+{
+  $query = 'SELECT * FROM '.WAITING_TABLE;
+  $query.= " WHERE validated = 'false';";
+  $result = pwg_query( $query );
+  while ( $row = mysql_fetch_array( $result ) )
+  {
+    $key = 'validate-'.$row['id'];
+    if ( isset( $_POST[$key] ) )
+    {
+      if ( $_POST[$key] == 'true' )
+      {
+        // The uploaded element was validated, we have to set the
+        // "validated" field to "true"
+        $query = 'UPDATE '.WAITING_TABLE;
+        $query.= " SET validated = 'true'";
+        $query.= ' WHERE id = '.$row['id'];
+        $query.= ';';
+        pwg_query( $query );
+      }
+      else
+      {
+        // The uploaded element was refused, we have to delete its reference
+        // in the database and to delete the element as well.
+        $query = 'DELETE FROM '.WAITING_TABLE;
+        $query.= ' WHERE id = '.$row['id'];
+        $query.= ';';
+        pwg_query( $query );
+        // deletion of the associated files
+        $dir = get_complete_dir( $row['storage_category_id'] );
+        unlink( $dir.$row['file'] );
+        if (isset($row['tn_ext']) and $row['tn_ext'] != '' )
+        {
+          $thumbnail = $conf['prefix_thumbnail'];
+          $thumbnail.= get_filename_wo_extension( $row['file'] );
+          $thumbnail.= '.'.$row['tn_ext'];
+          $url = $dir.'thumbnail/'.$thumbnail;
+          unlink( $url );
+        }
+      }
+    }
+  }
+}
+
+//----------------------------------------------------- template initialization
+$template->set_filenames(array('waiting'=>'admin/waiting.tpl'));
+$template->assign_vars(array(
+  'L_WAITING_CONFIRMATION'=>$lang['waiting_update'],
+  'L_AUTHOR'=>$lang['author'],
+  'L_THUMBNAIL'=>$lang['thumbnail'],
+  'L_DATE'=>$lang['date'],
+  'L_FILE'=>$lang['file'],
+  'L_CATEGORY'=>$lang['category'],
+  'L_SUBMIT'=>$lang['submit'],
+  'L_RESET'=>$lang['reset'],
+  'L_DELETE'=>$lang['delete'],
+  
+  'F_ACTION'=>add_session_id(str_replace( '&', '&amp;', $_SERVER['REQUEST_URI'] ))
+  ));
+  
+//-------------------------------------------------------- confirmation message
+if (isset($_POST['submit']))
+{
+  $template->assign_block_vars('confirmation' ,array());
+}
+//---------------------------------------------------------------- form display
+$cat_names = array();
+$query = 'SELECT * FROM '.WAITING_TABLE;
+$query.= " WHERE validated = 'false'";
+$query.= ' ORDER BY storage_category_id';
+$query.= ';';
+$result = pwg_query( $query );
+$i = 0;
+while ( $row = mysql_fetch_array( $result ) )
+{
+  if ( !isset( $cat_names[$row['storage_category_id']] ) )
+  {
+    $cat = get_cat_info( $row['storage_category_id'] );
+    $cat_names[$row['storage_category_id']] = array();
+    $cat_names[$row['storage_category_id']]['dir'] =
+      PHPWG_ROOT_PATH.get_complete_dir( $row['storage_category_id'] );
+    $cat_names[$row['storage_category_id']]['display_name'] =
+      get_cat_display_name($cat['name']);
+  }
+  $preview_url = PHPWG_ROOT_PATH.$cat_names[$row['storage_category_id']]['dir'].$row['file'];
+  $class='row1';
+  if ( $i++ % 2== 0 ) $class='row2';
+  
+  $template->assign_block_vars('picture' ,array(
+    'WAITING_CLASS'=>$class,
+    'CATEGORY_IMG'=>$cat_names[$row['storage_category_id']]['display_name'],
+    'ID_IMG'=>$row['id'],
+	'DATE_IMG'=>format_date( $row['date'], 'unix', true ),
+	'FILE_IMG'=>$row['file'],
+	'PREVIEW_URL_IMG'=>$preview_url, 
+	'UPLOAD_EMAIL'=>$row['mail_address'],
+	'UPLOAD_USERNAME'=>$row['username']
+	));
+
+  // is there an existing associated thumnail ?
+  if ( !empty( $row['tn_ext'] ))
+  {
+    $thumbnail = $conf['prefix_thumbnail'];
+    $thumbnail.= get_filename_wo_extension( $row['file'] );
+    $thumbnail.= '.'.$row['tn_ext'];
+	$url = $cat_names[$row['storage_category_id']]['dir'];
+    $url.= 'thumbnail/'.$thumbnail;
+	
+    $template->assign_block_vars('picture.thumbnail' ,array(
+	  'PREVIEW_URL_TN_IMG'=>$url,
+	  'FILE_TN_IMG'=>$thumbnail
+	  ));
+  }
+}
+//----------------------------------------------------------- sending html code
+$template->assign_var_from_handle('ADMIN_CONTENT', 'waiting');
+?>
Index: /branches/1.4/category.php
===================================================================
--- /branches/1.4/category.php	(revision 3249)
+++ /branches/1.4/category.php	(revision 3249)
@@ -0,0 +1,340 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+//--------------------------------------------------------------------- include
+define('PHPWG_ROOT_PATH','./');
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+//---------------------------------------------------------------------- logout
+if ( isset( $_GET['act'] )
+     and $_GET['act'] == 'logout'
+     and isset( $_COOKIE['id'] ) )
+{
+  // cookie deletion if exists
+  setcookie( 'id', '', 0, cookie_path() );
+  $url = 'category.php';
+  redirect( $url );
+}
+//-------------------------------------------------- access authorization check
+if (isset($_GET['cat']))
+{
+  check_cat_id($_GET['cat']);
+}
+check_login_authorization();
+if (isset($page['cat']) and is_numeric($page['cat']))
+{
+  check_restrictions($page['cat']);
+}
+//-------------------------------------------------------------- initialization
+// detection of the start picture to display
+if ( !isset( $_GET['start'] )
+     or !is_numeric( $_GET['start'] )
+     or ( is_numeric( $_GET['start'] ) and $_GET['start'] < 0 ) )
+{
+  $page['start'] = 0;
+}
+else
+{
+  $page['start'] = $_GET['start'];
+}
+
+// Sometimes, a "num" is provided in the URL. It is the number
+// of the picture to show. This picture must be in the thumbnails page.
+// We have to find the right $page['start'] that show the num picture
+// in this category
+if ( isset( $_GET['num'] )
+     and is_numeric( $_GET['num'] )
+     and $_GET['num'] >= 0 )
+{
+  $page['start'] = floor( $_GET['num'] / $user['nb_image_page'] );
+  $page['start']*= $user['nb_image_page'];
+}
+
+initialize_category();
+
+// creation of the array containing the cat ids to expand in the menu
+// $page['tab_expand'] contains an array with the category ids
+// $page['expand'] contains the string to display in URL with comma
+$page['tab_expand'] = array();
+if ( isset( $page['cat'] ) and is_numeric( $page['cat'] ) )
+{
+  // the category displayed (in the URL cat=23) must be seen in the menu ->
+  // parent categories must be expanded
+  $uppercats = explode( ',', $page['uppercats'] );
+  foreach ( $uppercats as $uppercat ) {
+    array_push( $page['tab_expand'], $uppercat );
+  }
+}
+// in case of expanding all authorized cats $page['tab_expand'] is empty
+if ( $user['expand'] )
+{
+  $page['tab_expand'] = array();
+}
+//----------------------------------------------------- template initialization
+//
+// Start output of page
+//
+$title = $page['title'];
+include(PHPWG_ROOT_PATH.'include/page_header.php');
+
+$template->set_filenames( array('category'=>'category.tpl') );
+//-------------------------------------------------------------- category title
+if (isset($page['cat']) and is_numeric($page['cat']))
+{
+  $template_title = get_cat_display_name($page['cat_name'],
+                                         'category.php?cat=',
+                                         false);
+}
+else
+{
+  $template_title = $page['title'];
+}
+
+if ( isset( $page['cat_nb_images'] ) and $page['cat_nb_images'] > 0 )
+{
+  $template_title.= ' ['.$page['cat_nb_images'].']';
+}
+
+$icon_recent = get_icon(date('Y-m-d'));
+
+$template->assign_vars(array(
+  'NB_PICTURE' => count_user_total_images(),
+  'TITLE' => $template_title,
+  'USERNAME' => $user['username'],
+  'TOP_NUMBER'=>$conf['top_number'],
+  'MENU_CATEGORIES_CONTENT'=>get_categories_menu(),
+
+  'L_CATEGORIES' => $lang['categories'],
+  'L_HINT_CATEGORY' => $lang['hint_category'],
+  'L_SUBCAT' => $lang['sub-cat'],
+  'L_IMG_AVAILABLE' => $lang['images_available'],
+  'L_TOTAL' => $lang['total'],
+  'L_SPECIAL_CATEGORIES' => $lang['special_categories'],
+  'L_SUMMARY' => $lang['title_menu'],
+  'L_UPLOAD' => $lang['upload_picture'],
+  'L_COMMENT' => $lang['comments'],
+  'L_IDENTIFY' => $lang['identification'],
+  'L_SUBMIT' => $lang['menu_login'],
+  'L_USERNAME' => $lang['login'],
+  'L_PASSWORD' => $lang['password'],
+  'L_HELLO' => $lang['hello'],
+  'L_REGISTER' => $lang['ident_register'],
+  'L_LOGIN' => $lang['menu_login'],
+  'L_LOGOUT' => $lang['logout'],
+  'L_ADMIN' => $lang['admin'],
+  'L_ADMIN_HINT' => $lang['hint_admin'],
+  'L_PROFILE' => $lang['customize'],
+  'L_PROFILE_HINT' => $lang['hint_customize'],
+  'L_REMEMBER_ME' => $lang['remember_me'],
+  
+  'F_IDENTIFY' => add_session_id( PHPWG_ROOT_PATH.'identification.php' ),
+  'T_RECENT' => $icon_recent,
+
+  'U_HOME' => add_session_id( PHPWG_ROOT_PATH.'category.php' ),
+  'U_REGISTER' => add_session_id( PHPWG_ROOT_PATH.'register.php' ),
+  'U_LOGOUT' => PHPWG_ROOT_PATH.'category.php?act=logout',
+  'U_ADMIN'=>add_session_id( PHPWG_ROOT_PATH.'admin.php' ),
+  'U_PROFILE'=>add_session_id(PHPWG_ROOT_PATH.'profile.php?'.str_replace( '&', '&amp;', $_SERVER['QUERY_STRING'] ))
+  )
+);
+//---------------------------------------------------------- special categories
+// favorites categories
+if ( !$user['is_the_guest'] )
+{
+  $template->assign_block_vars('username', array());
+
+  $template->assign_block_vars(
+    'special_cat',
+    array(
+      'URL' => add_session_id(PHPWG_ROOT_PATH.'category.php?cat=fav'),
+      'TITLE' => $lang['favorite_cat_hint'],
+      'NAME' => $lang['favorite_cat']
+      ));
+}
+// most visited
+$template->assign_block_vars(
+  'special_cat',
+  array(
+    'URL' => add_session_id(PHPWG_ROOT_PATH.'category.php?cat=most_visited'),
+    'TITLE' => $lang['most_visited_cat_hint'],
+    'NAME' => $lang['most_visited_cat']
+    ));
+// best rated
+if ($conf['rate'])
+{
+  $template->assign_block_vars(
+    'special_cat',
+    array(
+      'URL' => add_session_id(PHPWG_ROOT_PATH.'category.php?cat=best_rated'),
+      'TITLE' => $lang['best_rated_cat_hint'],
+      'NAME' => $lang['best_rated_cat']
+      ));
+}
+// random
+$template->assign_block_vars(
+  'special_cat',
+  array(
+    'URL' => add_session_id(PHPWG_ROOT_PATH.'random.php'),
+    'TITLE' => $lang['random_cat_hint'],
+    'NAME' => $lang['random_cat']
+    ));
+// recent pics
+$template->assign_block_vars(
+  'special_cat',
+  array(
+    'URL' => add_session_id(PHPWG_ROOT_PATH.'category.php?cat=recent_pics'),
+    'TITLE' => $lang['recent_pics_cat_hint'],
+    'NAME' => $lang['recent_pics_cat']
+    ));
+// recent cats
+$template->assign_block_vars(
+  'special_cat',
+  array(
+    'URL' => add_session_id(PHPWG_ROOT_PATH.'category.php?cat=recent_cats'),
+    'TITLE' => $lang['recent_cats_cat_hint'],
+    'NAME' => $lang['recent_cats_cat']
+    ));
+// calendar
+$template->assign_block_vars(
+  'special_cat',
+  array(
+    'URL' => add_session_id(PHPWG_ROOT_PATH.'category.php?cat=calendar'),
+    'TITLE' => $lang['calendar_hint'],
+    'NAME' => $lang['calendar']
+    ));
+//--------------------------------------------------------------------- summary
+
+if ( !$user['is_the_guest'] )
+{
+  $template->assign_block_vars('logout',array());
+  // administration link
+  if ( $user['status'] == 'admin' )
+  {
+    $template->assign_block_vars('logout.admin', array());
+  }
+}
+else
+{
+  $template->assign_block_vars('login',array());
+  if ($conf['authorize_remembering'])
+  {
+    $template->assign_block_vars('login.remember_me',array());
+  }
+}
+
+// search link
+$template->assign_block_vars('summary', array(
+'TITLE'=>$lang['hint_search'],
+'NAME'=>$lang['search'],
+'U_SUMMARY'=>add_session_id( 'search.php' ),
+));
+
+// comments link
+$template->assign_block_vars('summary', array(
+'TITLE'=>$lang['hint_comments'],
+'NAME'=>$lang['comments'],
+'U_SUMMARY'=>add_session_id( 'comments.php' ),
+));
+
+// about link
+$template->assign_block_vars('summary', array(
+'TITLE'=>$lang['hint_about'],
+'NAME'=>$lang['about'],
+'U_SUMMARY'=>add_session_id( 'about.php?'.str_replace( '&', '&amp;', $_SERVER['QUERY_STRING'] ) )
+));
+
+//------------------------------------------------------ main part : thumbnails
+if (isset($page['cat'])
+    and ((is_numeric($page['cat']) and $page['cat_nb_images'] != 0)
+         or in_array($page['cat'],
+                     array('search'
+                           ,'most_visited'
+                           ,'recent_pics'
+                           ,'best_rated'
+                           ,'list'
+                           ,'fav'
+                       ))))
+{
+  include(PHPWG_ROOT_PATH.'include/category_default.inc.php');
+}
+elseif (isset($page['cat']) and $page['cat'] == 'calendar')
+{
+  include(PHPWG_ROOT_PATH.'include/category_calendar.inc.php');
+}
+elseif (isset($page['cat']) and $page['cat'] == 'recent_cats')
+{
+  include(PHPWG_ROOT_PATH.'include/category_recent_cats.inc.php');
+}
+else
+{
+  include(PHPWG_ROOT_PATH.'include/category_subcats.inc.php');
+}
+//------------------------------------------------------- category informations
+if ( isset ( $page['cat'] ) )
+{
+  // upload a picture in the category
+  if (is_numeric($page['cat'])
+      and $page['cat_site_id'] == 1
+      and $page['cat_dir'] != ''
+      and $page['cat_uploadable'])
+  {
+    $url = PHPWG_ROOT_PATH.'upload.php?cat='.$page['cat'];
+    $template->assign_block_vars(
+      'upload',
+      array('U_UPLOAD'=>add_session_id( $url ))
+      );
+  }
+
+  if ( $page['navigation_bar'] != ''
+       or ( isset( $page['comment'] ) and $page['comment'] != '' ) )
+  {
+    $template->assign_block_vars('cat_infos',array());
+  }
+  
+  // navigation bar
+  if ( $page['navigation_bar'] != '' )
+  { 
+    $template->assign_block_vars(
+      'cat_infos.navigation',
+      array('NAV_BAR' => $page['navigation_bar'])
+      );
+  }
+  // category comment
+  if ( isset( $page['comment'] ) and $page['comment'] != '' )
+  {
+    $template->assign_block_vars(
+      'cat_infos.comment',
+      array('COMMENTS' => $page['comment'])
+      );
+  }
+}
+//------------------------------------------------------------ log informations
+pwg_log( 'category', $page['title'] );
+mysql_close();
+
+$template->parse('category');
+include(PHPWG_ROOT_PATH.'include/page_tail.php');
+?>
Index: /branches/1.4/comments.php
===================================================================
--- /branches/1.4/comments.php	(revision 3249)
+++ /branches/1.4/comments.php	(revision 3249)
@@ -0,0 +1,235 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// +-----------------------------------------------------------------------+
+// |                           initialization                              |
+// +-----------------------------------------------------------------------+
+if (!defined('IN_ADMIN'))
+{
+  define('PHPWG_ROOT_PATH','./');
+  include_once(PHPWG_ROOT_PATH.'include/common.inc.php');
+}
+
+if (isset($_GET['last_days']))
+{
+  define('MAX_DAYS', $_GET['last_days']);
+}
+else
+{
+  define('MAX_DAYS', 0);
+}
+$array_cat_names = array();
+// +-----------------------------------------------------------------------+
+// |                         comments management                           |
+// +-----------------------------------------------------------------------+
+// comments deletion
+if (isset($_POST['delete']) and count($_POST['comment_id']) > 0)
+{
+  $query = '
+DELETE FROM '.COMMENTS_TABLE.'
+  WHERE id IN ('.implode(',', $_POST['comment_id']).')
+;';
+  pwg_query($query);
+}
+// comments validation
+if (isset($_POST['validate']) and count($_POST['comment_id']) > 0)
+{
+  $query = '
+UPDATE '.COMMENTS_TABLE.'
+  SET validated = \'true\'
+  WHERE id IN ('.implode(',', $_POST['comment_id']).')
+;';
+  pwg_query($query);
+}
+// +-----------------------------------------------------------------------+
+// |                       page header and options                         |
+// +-----------------------------------------------------------------------+
+if (!defined('IN_ADMIN'))
+{
+  $title= $lang['title_comments'];
+  include(PHPWG_ROOT_PATH.'include/page_header.php');
+}
+
+$template->set_filenames(array('comments'=>'comments.tpl'));
+$template->assign_vars(
+  array(
+    'L_COMMENT_TITLE' => $title,
+    'L_COMMENT_STATS' => $lang['stats_last_days'],
+    'L_COMMENT_RETURN' => $lang['home'],
+	'L_COMMENT_RETURN_HINT' => $lang['home_hint'],
+    'L_DELETE' =>$lang['delete'],
+    'L_VALIDATE'=>$lang['submit'],
+    
+    'U_HOME' => add_session_id(PHPWG_ROOT_PATH.'category.php')
+    )
+  );
+
+foreach ($conf['last_days'] as $option)
+{
+  $url = $_SERVER['PHP_SELF'].'?last_days='.($option - 1);
+  if (defined('IN_ADMIN'))
+  {
+    $url.= '&amp;page=comments';
+  }
+  $template->assign_block_vars(
+    'last_day_option',
+    array(
+      'OPTION'=>$option,
+      'T_STYLE'=>(($option == MAX_DAYS + 1)?'text-decoration:underline;':''),
+      'U_OPTION'=>add_session_id($url)
+      )
+    );
+}
+// +-----------------------------------------------------------------------+
+// |                        last comments display                          |
+// +-----------------------------------------------------------------------+
+// 1. retrieving picture ids which have comments recently added
+$maxdate = date('Y-m-d', strtotime('-'.MAX_DAYS.' day'));
+
+$query = '
+SELECT DISTINCT(ic.image_id) AS image_id,ic.category_id, uppercats
+  FROM '.COMMENTS_TABLE.' AS c, '.IMAGE_CATEGORY_TABLE.' AS ic
+    , '.CATEGORIES_TABLE.' AS cat
+  WHERE c.image_id = ic.image_id
+    AND ic.category_id = cat.id
+    AND date >= \''.$maxdate.'\'';
+if ($user['status'] != 'admin')
+{
+  $query.= "
+    AND validated = 'true'";
+  // we must not show pictures of a forbidden category
+  if ($user['forbidden_categories'] != '')
+  {
+    $query.= '
+    AND category_id NOT IN ('.$user['forbidden_categories'].')';
+  }
+}
+$query.= '
+  GROUP BY ic.image_id
+  ORDER BY ic.image_id DESC
+;';
+$result = pwg_query($query);
+if ($user['status'] == 'admin')
+{
+  $template->assign_block_vars('validation', array());
+}
+while ($row = mysql_fetch_array($result))
+{
+  $category_id = $row['category_id'];
+  
+  // for each picture, getting informations for displaying thumbnail and
+  // link to the full size picture
+  $query = '
+SELECT name,file,storage_category_id as cat_id,tn_ext,path
+  FROM '.IMAGES_TABLE.'
+  WHERE id = '.$row['image_id'].'
+;';
+  $subresult = pwg_query($query);
+  $subrow = mysql_fetch_array($subresult);
+
+  // name of the picture
+  $name = get_cat_display_name_cache($row['uppercats'], '', false);
+  $name.= $conf['level_separator'];
+  if (!empty($subrow['name']))
+  {
+    $name.= $subrow['name'];
+  }
+  else
+  {
+    $name.= str_replace('_',' ',get_filename_wo_extension($subrow['file']));
+  }
+
+  // source of the thumbnail picture
+  $thumbnail_src = get_thumbnail_src($subrow['path'], @$subrow['tn_ext']);
+  // link to the full size picture
+  $url = PHPWG_ROOT_PATH.'picture.php?cat='.$category_id;
+  $url.= '&amp;image_id='.$row['image_id'];
+    
+  $template->assign_block_vars(
+    'picture',
+    array(
+      'TITLE_IMG'=>$name,
+      'I_THUMB'=>$thumbnail_src,
+      'U_THUMB'=>add_session_id($url)
+      ));
+    
+  // for each picture, retrieving all comments
+  $query = '
+SELECT *
+  FROM '.COMMENTS_TABLE.'
+  WHERE image_id = '.$row['image_id'].'
+    AND date >= \''.$maxdate.'\'';
+  if ($user['status'] != 'admin')
+  {
+    $query.= '
+    AND validated = \'true\'';
+  }
+  $query.= '
+  ORDER BY date DESC
+;';
+  $handleresult = pwg_query($query);
+  while ($subrow = mysql_fetch_array($handleresult))
+  {
+    $author = $subrow['author'];
+    if (empty($subrow['author']))
+    {
+      $author = $lang['guest'];
+    }
+
+    $template->assign_block_vars(
+      'picture.comment',
+      array(
+        'COMMENT_AUTHOR'=>$author,
+        'COMMENT_DATE'=>format_date($subrow['date'],'mysql_datetime',true),
+        'COMMENT'=>parse_comment_content($subrow['content']),
+        ));
+    
+    if ($user['status'] == 'admin')
+    {
+      $template->assign_block_vars(
+        'picture.comment.validation',
+        array(
+          'ID'=> $subrow['id'],
+          'CHECKED'=>($subrow['validated']=='false')?'checked="checked"': ''
+          ));
+    }
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                           html code display                           |
+// +-----------------------------------------------------------------------+
+if (defined('IN_ADMIN'))
+{
+  $template->assign_var_from_handle('ADMIN_CONTENT', 'comments');
+}
+else
+{
+  $template->assign_block_vars('title',array());
+  $template->parse('comments');
+  include(PHPWG_ROOT_PATH.'include/page_tail.php');
+}
+?>
Index: /branches/1.4/doc/COPYING
===================================================================
--- /branches/1.4/doc/COPYING	(revision 3249)
+++ /branches/1.4/doc/COPYING	(revision 3249)
@@ -0,0 +1,345 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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; either version 2 of the License, or
+    (at your option) any later version.
+
+    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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
Index: /branches/1.4/doc/README_en.txt
===================================================================
--- /branches/1.4/doc/README_en.txt	(revision 3249)
+++ /branches/1.4/doc/README_en.txt	(revision 3249)
@@ -0,0 +1,91 @@
+                               PhpWebGallery
+
+official website   : http://phpwebgallery.net
+documentation      : http://doc.phpwebgallery.net
+forum              : http://forum.phpwebgallery.net
+
++-----------------------------------------------------------------------------+
+|                        Installation instructions                            |
++-----------------------------------------------------------------------------+
+
+1. extract files from the downloaded file (using tar or unzip command, or
+   softwares like 7-zip or winzip)
+
+2. place de source files on your website in the directory of your choice
+   ("gallery" for example)
+
+3. go to the URL http://your.domain/gallery/install.php and follow the
+   instructions of installation
+
++-----------------------------------------------------------------------------+
+|                           Upgrade instructions                              |
++-----------------------------------------------------------------------------+
+
+1. elements to save :
+
+ - file "include/mysql.inc.php"
+ - directory "galleries"
+ - your database (create a dump, using PhpMyAdmin for instance)
+
+2. delete all files and directories of your previous installation (but not
+   the previous listed elements)
+
+3. extract files from the downloaded file (using tar or unzip command, or
+   softwares like 7-zip or winzip)
+
+4. upload all the new version files to your website but the previous listed
+   elements. The only elements coming from the previous installed version
+   are the elements listed above.
+
+5. go to the URL http://your.domain/gallery/upgrade.php and follow the
+   instructions
+
++-----------------------------------------------------------------------------+
+|                              How to start                                   |
++-----------------------------------------------------------------------------+
+
+Once installed or upgraded, your gallery is ready to run. Start by
+displaying the installation directory in your browser :
+
+http://your.domain/gallery
+
+Then identify as an administrator. A new link in Identification menu of main
+page will appear : Administration. Enter the administration panel.
+
+In the administration panel, take all your time for reading instructions
+explaining how to use your gallery.
+
++-----------------------------------------------------------------------------+
+|                               Newsletter                                    |
++-----------------------------------------------------------------------------+
+
+It is *highly* recommended to subscribe to PhpWebGallery newsletter. This is
+extremely low-traffic, but will provide you with announcements of new
+PhpWebGallery releases and serious bug notification. You will find available
+mailing lists at this URL :
+
+                 https://gna.org/mail/?group=phpwebgallery
+
+Be sure that the mail address you are going to give for newsletter is
+completely unreadable by someone else than PhpWebGallery team and not
+present on any web page (a web search engine won't find it).
+
+PhpWebGallery also assure you that your mail address will NEVER be used for
+something else than PhpWebGallery informations.
+
++-----------------------------------------------------------------------------+
+|                             Discussion forum                                |
++-----------------------------------------------------------------------------+
+
+A forum is available and recommended for any question (installation, bug
+reports, new feature requests) :
+
+                     http://forum.phpwebgallery.net
+
+Before asking any question on the forum, do not hesitate to search for
+related topics... other users may have found same bugs, had same requests.
+
+PhpWebGallery forum is a place open to every one. Please be always
+respectful in this place. Consider also that clear messages (with simple and
+direct subjects) are always prefered. It is forbidden (and useless) to say
+that your question is "urgent", you won't be answered in priority.
Index: /branches/1.4/doc/README_fr.txt
===================================================================
--- /branches/1.4/doc/README_fr.txt	(revision 3249)
+++ /branches/1.4/doc/README_fr.txt	(revision 3249)
@@ -0,0 +1,97 @@
+                               PhpWebGallery
+
+site officel   : http://phpwebgallery.net
+documentation  : http://doc.phpwebgallery.net
+forum          : http://forum.phpwebgallery.net
+
++-----------------------------------------------------------------------------+
+|                              installation                                   |
++-----------------------------------------------------------------------------+
+
+1. décompresser à l'aide de winzip par exemple (winrar, winace et beaucoup
+   d'autres le permettent également) le fichier téléchargé.
+
+2. placer les fichiers décompressés sur votre serveur web dans le répertoire
+   de votre choix ("galerie" par exemple)
+
+3. se rendre à l'URL http://votre.domaine/galerie/install.php et suivre les
+   instructions
+
++-----------------------------------------------------------------------------+
+|                               mise à jour                                   |
++-----------------------------------------------------------------------------+
+
+1. éléments à sauvegarder :
+
+ - fichier "include/mysql.inc.php"
+ - répertoire "galleries"
+ - votre base de données (en créant un dump, avec PhpMyAdmin par exemple)
+
+2. supprimer tous les fichiers et répertoires de la précédente installation
+   (sauf les éléments listés ci-dessus)
+
+3. décompresser à l'aide de winzip par exemple (winrar, winace et beaucoup
+   d'autres le permettent également) le fichier téléchargé.
+
+4. placer tous les fichiers de la nouvelle version sur votre site web sauf
+   pour les élements listés ci-dessus. Les seuls éléments venant de la
+   précédente installation sont ceux listés ci-dessus.
+
+5. se rendre à l'URL http://votre.domaine/galerie/upgrade.php et suivre les
+   instructions
+
++-----------------------------------------------------------------------------+
+|                             Comment commencer                               |
++-----------------------------------------------------------------------------+
+
+Une fois installée ou mise à jour, votre galerie est prête à
+fonctionner. Commencez par vous rendre sur le répertoire d'installation dans
+votre navigateur : 
+
+http://votre.domaine/galerie
+
+Ensuite, identifiez-vous en tant qu'un administrateur. Un nouveau lien dans
+le menu d'identification de la page principale va apparaître :
+Administration. Suivre ce lien :-)
+
+Dans la zone d'administration, prenez tout le temps nécessaire pour
+consulter les instructions, expliquant comment utiliser votre galerie.
+
++-----------------------------------------------------------------------------+
+|                               newsletter                                    |
++-----------------------------------------------------------------------------+
+
+Il est *fortement* recommandé de souscrire à la newsletter de
+PhpWebGallery. Très peu de mails sont envoyés, mais les informations sont
+importantes : nouvelles versions de l'application, notification de bugs
+importants (relatifs à la sécurité). Vous trouverez les listes de
+discussions disponibles sur la page suivante :
+
+         https://gna.org/mail/?group=phpwebgallery
+
+Etant moi-même très dérangé par le spam (courrier non solicité), je peux
+vous assurer que le mail que vous allez donner à l'équipe de PhpWebGallery
+est absolument illisible autrement que par nous sur une page avec accès
+sécurisé dont l'URL n'est en lien nul part sur le web (donc introuvable par
+un moteur de recherche).
+
+L'équipe de PhpWebGallery vous assure également que JAMAIS l'adresse qui
+nous a été confiée ne sera utilisée dans un autre cadre que la newsletter de
+PhpWebGallery.
+
++-----------------------------------------------------------------------------+
+|                            forum de discussion                              |
++-----------------------------------------------------------------------------+
+
+Un forum est disponible et recommandé pour toutes vos questions
+(installation, rapport de bugs, demandes de nouvelles fonctionnalités) :
+
+                     http://forum.phpwebgallery.net
+
+Avant le poser une question, assurez-vous qu'elle n'a pas déjà sa réponse en
+effectuant une recherche.
+
+Le forum est ouvert à tous. Merci d'y faire preuve de respect. Rappelez-vous
+que les messages clairs (avec un sujet direct et un énoncé du problème
+précis) sont toujours préférés. Il est interdit (et surtout inutile) de dire
+que votre question est "urgente", on ne vous répondra pas en priorité.
Index: /branches/1.4/galleries/.cvsignore
===================================================================
--- /branches/1.4/galleries/.cvsignore	(revision 3249)
+++ /branches/1.4/galleries/.cvsignore	(revision 3249)
@@ -0,0 +1,1 @@
+*
Index: /branches/1.4/galleries/index.htm
===================================================================
--- /branches/1.4/galleries/index.htm	(revision 3249)
+++ /branches/1.4/galleries/index.htm	(revision 3249)
@@ -0,0 +1,8 @@
+<html>
+    <head>
+        <title>PhpWebGallery</title>
+    </head>
+    <body>
+        No access authorized
+    </body>
+</html>
Index: /branches/1.4/identification.php
===================================================================
--- /branches/1.4/identification.php	(revision 3249)
+++ /branches/1.4/identification.php	(revision 3249)
@@ -0,0 +1,103 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+//--------------------------------------------------------------------- include
+define('PHPWG_ROOT_PATH','./');
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+
+//-------------------------------------------------------------- identification
+$errors = array();
+if (isset($_POST['login']))
+{
+  // retrieving the encrypted password of the login submitted
+  $query = '
+SELECT id, password
+  FROM '.USERS_TABLE.'
+  WHERE username = \''.$_POST['username'].'\'
+;';
+  $row = mysql_fetch_array(pwg_query($query));
+  if ($row['password'] == md5($_POST['password']))
+  {
+    $session_length = $conf['session_length'];
+    if ($conf['authorize_remembering']
+        and isset($_POST['remember_me'])
+        and $_POST['remember_me'] == 1)
+    {
+      $session_length = $conf['remember_me_length'];
+    }
+    $session_id = session_create($row['id'], $session_length);
+    redirect('category.php?id='.$session_id);
+  }
+  else
+  {
+    array_push( $errors, $lang['invalid_pwd'] );
+  }
+}
+//----------------------------------------------------- template initialization
+//
+// Start output of page
+//
+$title = $lang['identification'];
+include(PHPWG_ROOT_PATH.'include/page_header.php');
+
+$template->set_filenames( array('identification'=>'identification.tpl') );
+
+$template->assign_vars(
+  array(
+    'MAIL_ADMIN' => $conf['mail_webmaster'],
+    
+    'L_TITLE' => $lang['identification'],
+    'L_USERNAME' => $lang['login'],
+    'L_PASSWORD' => $lang['password'],
+    'L_LOGIN' => $lang['submit'],
+    'L_GUEST' => $lang['ident_guest_visit'],
+    'L_REGISTER' => $lang['ident_register'],
+    'L_FORGET' => $lang['ident_forgotten_password'],
+    'L_REMEMBER_ME'=>$lang['remember_me'],
+    
+    'F_LOGIN_ACTION' => add_session_id('identification.php')
+    ));
+
+if ($conf['authorize_remembering'])
+{
+  $template->assign_block_vars('remember_me',array());
+}
+//-------------------------------------------------------------- errors display
+if ( sizeof( $errors ) != 0 )
+{
+  $template->assign_block_vars('errors',array());
+  for ( $i = 0; $i < sizeof( $errors ); $i++ )
+  {
+    $template->assign_block_vars('errors.error',array('ERROR'=>$errors[$i]));
+  }
+}
+//-------------------------------------------------------------- visit as guest
+$template->assign_block_vars('free_access',array());
+//----------------------------------------------------------- html code display
+$template->parse('identification');
+include(PHPWG_ROOT_PATH.'include/page_tail.php');
+?>
Index: /branches/1.4/include/.cvsignore
===================================================================
--- /branches/1.4/include/.cvsignore	(revision 3249)
+++ /branches/1.4/include/.cvsignore	(revision 3249)
@@ -0,0 +1,1 @@
+mysql.inc.php
Index: /branches/1.4/include/category_calendar.inc.php
===================================================================
--- /branches/1.4/include/category_calendar.inc.php	(revision 3249)
+++ /branches/1.4/include/category_calendar.inc.php	(revision 3249)
@@ -0,0 +1,434 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+/**
+ * This file is included by category.php to show thumbnails for the category
+ * calendar
+ * 
+ */
+
+// years of image availability
+$query = '
+SELECT YEAR('.$conf['calendar_datefield'].') AS year, COUNT(id) AS count
+  FROM '.IMAGES_TABLE.', '.IMAGE_CATEGORY_TABLE.'
+  '.$page['where'].'
+    AND id = image_id
+  GROUP BY year
+;';
+$result = pwg_query($query);
+$calendar_years = array();
+while ($row = mysql_fetch_array($result))
+{
+  $calendar_years[$row['year']] = $row['count'];
+}
+
+// if the year requested is not among the available years, we unset the
+// variable
+if (isset($page['calendar_year'])
+    and !isset($calendar_years[$page['calendar_year']]))
+{
+  unset($page['calendar_year']);
+}
+
+// years navigation bar creation
+$years_nav_bar = '';
+foreach ($calendar_years as $calendar_year => $nb_picture_year)
+{
+  if (isset($page['calendar_year'])
+      and $calendar_year == $page['calendar_year'])
+  {
+    $years_nav_bar.= ' <span class="dateSelected">'.$calendar_year.'</span>';
+  }
+  else
+  {
+    $url = PHPWG_ROOT_PATH.'category.php?cat=calendar';
+    $url.= '&amp;year='.$calendar_year;
+    $url = add_session_id($url);
+    $years_nav_bar.= ' <a href="'.$url.'">'.$calendar_year.'</a>';
+  }
+}
+
+$template->assign_block_vars(
+  'calendar',
+  array('YEARS_NAV_BAR' => $years_nav_bar)
+  );
+
+// months are calculated (to know which months are available, and how many
+// pictures per month we can find) only if a year is requested.
+if (isset($page['calendar_year']))
+{
+  // creation of hash associating the number of the month in the year with
+  // the number of picture for this month : $calendar_months
+  $query = '
+SELECT DISTINCT(MONTH('.$conf['calendar_datefield'].')) AS month
+     , COUNT(id) AS count
+  FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id = image_id
+  '.$page['where'].'
+    AND '.$conf['calendar_datefield'].'
+      BETWEEN \''.$page['calendar_year'].'-1-1\'
+      AND \''.$page['calendar_year'].'-12-31\'
+  GROUP BY MONTH('.$conf['calendar_datefield'].')
+;';
+  $result = pwg_query($query);
+  $calendar_months = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    $calendar_months[$row['month']] = $row['count'];
+  }
+
+  // if a month is requested and is not among the available months, we unset
+  // the requested month
+  if (isset($page['calendar_month'])
+      and !isset($calendar_months[$page['calendar_month']]))
+  {
+    unset($page['calendar_month']);
+  }
+
+  // months navigation bar creation
+  $months_nav_bar = '';
+  foreach ($calendar_months as $calendar_month => $nb_picture_month)
+  {
+    if (isset($page['calendar_month'])
+        and $calendar_month == $page['calendar_month'])
+    {
+      $months_nav_bar.= ' <span class="dateSelected">';
+      $months_nav_bar.= $lang['month'][(int)$calendar_month];
+      $months_nav_bar.= '</span>';
+    }
+    else
+    {
+      $url = PHPWG_ROOT_PATH.'category.php?cat=calendar&amp;month=';
+      $url.= $page['calendar_year'].'.'.sprintf('%02s', $calendar_month);
+      $months_nav_bar.= ' ';
+      $months_nav_bar.= '<a href="'.add_session_id($url).'">';
+      $months_nav_bar.= $lang['month'][(int)$calendar_month];
+      $months_nav_bar.= '</a>';
+    }
+  }
+  $template->assign_block_vars(
+    'calendar',
+    array('MONTHS_NAV_BAR' => $months_nav_bar));
+}
+
+/**
+ * 4 sub-cases are possibles for the calendar category :
+ *
+ *  1. show years if no year is requested
+ *  2. show months of the requested year if no month is requested
+ *  3. show days of the {year,month} requested if no day requested
+ *  4. show categories of the requested day (+ a special category gathering
+ *     all categories)
+ */
+
+if (!isset($page['calendar_year']))
+{
+  $nb_pics = count($calendar_years);
+}
+elseif (!isset($page['calendar_month']))
+{
+  $nb_pics = count($calendar_months);
+}
+elseif (!isset($page['calendar_day']))
+{
+  // creation of hash associating the number of the day in the month with
+  // the number of picture for this day : $calendar_days
+  $query = '
+SELECT DISTINCT('.$conf['calendar_datefield'].') AS day, COUNT(id) AS count
+  FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id = image_id
+  '.$page['where'].'
+    AND '.$conf['calendar_datefield'].'
+      BETWEEN \''.$page['calendar_year'].'-'.$page['calendar_month'].'-1\'
+      AND \''.$page['calendar_year'].'-'.$page['calendar_month'].'-31\'
+  GROUP BY day
+;';
+  $result = pwg_query($query);
+  $calendar_days = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    $calendar_days[$row['day']] = $row['count'];
+  }
+  $nb_pics = count($calendar_days);
+}
+elseif (isset($page['calendar_day']))
+{
+  // $page['calendar_date'] is the concatenation of year-month-day. simplier
+  // to use in SQ queries
+  $page['calendar_date'] = $page['calendar_year'];
+  $page['calendar_date'].= '-'.$page['calendar_month'];
+  $page['calendar_date'].= '-'.$page['calendar_day'];
+  
+  $query = '
+SELECT category_id AS category, COUNT(id) AS count
+  FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id = image_id
+  '.$page['where'].'
+    AND '.$conf['calendar_datefield'].' = \''.$page['calendar_date'].'\'
+  GROUP BY category_id
+;';
+  $result = pwg_query($query);
+  $calendar_categories = array();
+  // special category 0 : gathering all available categories (0 cannot be a
+  // oregular category identifier)
+  $calendar_categories[0] = 0;
+  while ($row = mysql_fetch_array($result))
+  {
+    $calendar_categories[$row['category']] = $row['count'];
+  }
+  // update the total number of pictures for this day
+  $calendar_categories[0] = array_sum($calendar_categories);
+  
+  $nb_pics = count($calendar_categories);
+}
+
+// template thumbnail initialization
+if ($nb_pics > 0)
+{
+  $template->assign_block_vars('thumbnails', array());
+  // first line
+  $template->assign_block_vars('thumbnails.line', array());
+  // current row displayed
+  $row_number = 0;
+}
+
+if (!isset($page['calendar_year']))
+{
+  // for each month of this year, display a random picture
+  foreach ($calendar_years as $calendar_year => $nb_pics)
+  {
+    $query = '
+SELECT file,tn_ext,'.$conf['calendar_datefield'].',path
+  FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id = image_id
+  '.$page['where'].'
+    AND '.$conf['calendar_datefield'].'
+      BETWEEN \''.$calendar_year.'-1-1\'
+      AND \''.$calendar_year.'-12-31\'
+  ORDER BY RAND()
+  LIMIT 0,1
+;';
+    $row = mysql_fetch_array(pwg_query($query));
+    
+    $thumbnail_src = get_thumbnail_src($row['path'], @$row['tn_ext']);
+    
+    $name = $calendar_year.' ('.$nb_pics.')';
+
+    $thumbnail_title = $lang['calendar_picture_hint'].$name;
+      
+    $url_link = PHPWG_ROOT_PATH.'category.php?cat=calendar';
+    $url_link.= '&amp;year='.$calendar_year;
+    
+    $template->assign_block_vars(
+      'thumbnails.line.thumbnail',
+      array(
+        'IMAGE'=>$thumbnail_src,
+        'IMAGE_ALT'=>$row['file'],
+        'IMAGE_TITLE'=>$thumbnail_title,
+        'IMAGE_NAME'=>$name,
+          
+        'U_IMG_LINK'=>add_session_id($url_link)
+       )
+     );
+
+    // create a new line ?
+    if (++$row_number == $user['nb_image_line'])
+    {
+      $template->assign_block_vars('thumbnails.line', array());
+      $row_number = 0;
+    }
+  }
+}
+elseif (!isset($page['calendar_month']))
+{
+  // for each month of this year, display a random picture
+  foreach ($calendar_months as $calendar_month => $nb_pics)
+  {
+    $query = '
+SELECT file,tn_ext,'.$conf['calendar_datefield'].',path
+  FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id = image_id
+  '.$page['where'].'
+    AND '.$conf['calendar_datefield'].'
+      BETWEEN \''.$page['calendar_year'].'-'.$calendar_month.'-1\'
+      AND \''.$page['calendar_year'].'-'.$calendar_month.'-31\'
+  ORDER BY RAND()
+  LIMIT 0,1
+;';
+    $row = mysql_fetch_array(pwg_query($query));
+    
+    $thumbnail_src = get_thumbnail_src($row['path'], @$row['tn_ext']);
+    
+    $name = $lang['month'][$calendar_month];
+    $name.= ' '.$page['calendar_year'];
+    $name.= ' ('.$nb_pics.')';
+
+    $thumbnail_title = $lang['calendar_picture_hint'].$name;
+      
+    $url_link = PHPWG_ROOT_PATH.'category.php?cat=calendar';
+    $url_link.= '&amp;month='.$page['calendar_year'].'.';
+    if ($calendar_month < 10)
+    {
+      // adding leading zero
+      $url_link.= '0';
+    }
+    $url_link.= $calendar_month;
+    
+    $template->assign_block_vars(
+      'thumbnails.line.thumbnail',
+      array(
+        'IMAGE'=>$thumbnail_src,
+        'IMAGE_ALT'=>$row['file'],
+        'IMAGE_TITLE'=>$thumbnail_title,
+        'IMAGE_NAME'=>$name,
+          
+        'U_IMG_LINK'=>add_session_id($url_link)
+       )
+     );
+
+    // create a new line ?
+    if (++$row_number == $user['nb_image_line'])
+    {
+      $template->assign_block_vars('thumbnails.line', array());
+      $row_number = 0;
+    }
+  }
+}
+elseif (!isset($page['calendar_day']))
+{
+  // for each day of the requested month, display a random picture
+  foreach ($calendar_days as $calendar_day => $nb_pics)
+  {
+    $query = '
+SELECT file,tn_ext,'.$conf['calendar_datefield'].',path
+       , DAYOFWEEK(\''.$calendar_day.'\') AS dow
+  FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id = image_id
+  '.$page['where'].'
+    AND '.$conf['calendar_datefield'].' = \''.$calendar_day.'\'
+  ORDER BY RAND()
+  LIMIT 0,1
+;';
+    $row = mysql_fetch_array(pwg_query($query));
+    
+    $thumbnail_src = get_thumbnail_src($row['path'], @$row['tn_ext']);
+
+    list($year,$month,$day) = explode('-', $calendar_day);
+    $name = $lang['day'][$row['dow']-1];
+    $name.= ' '.$day;
+    $name.= ' ('.$nb_pics.')';
+      
+    $thumbnail_title = $lang['calendar_picture_hint'].$name;
+
+    $url_link = PHPWG_ROOT_PATH.'category.php';
+    $url_link.= '?cat=calendar&amp;day='.str_replace('-', '.', $calendar_day);
+    
+    $template->assign_block_vars(
+      'thumbnails.line.thumbnail',
+      array(
+        'IMAGE'=>$thumbnail_src,
+        'IMAGE_ALT'=>$row['file'],
+        'IMAGE_TITLE'=>$thumbnail_title,
+        'IMAGE_NAME'=>$name,
+          
+        'U_IMG_LINK'=>add_session_id($url_link)
+         )
+       );
+
+    // create a new line ?
+    if (++$row_number == $user['nb_image_line'])
+    {
+      $template->assign_block_vars('thumbnails.line', array());
+      $row_number = 0;
+    }
+  }
+}
+elseif (isset($page['calendar_day']))
+{
+  $old_level_separator = $conf['level_separator'];
+  $conf['level_separator'] = '<br />';
+  // for each category of this day, display a random picture
+  foreach ($calendar_categories as $calendar_category => $nb_pics)
+  {
+    if ($calendar_category == 0)
+    {
+      $name = '['.$lang['all_categories'].']';
+    }
+    else
+    {
+      $cat_infos = get_cat_info( $calendar_category );
+      
+      $name = get_cat_display_name($cat_infos['name'],'',false);
+      $name = '['.$name.']';
+    }
+    $name.= ' ('.$nb_pics.')';
+    
+    $query = '
+SELECT file,tn_ext,'.$conf['calendar_datefield'].',path
+  FROM '.IMAGES_TABLE.', '.IMAGE_CATEGORY_TABLE.'
+  '.$page['where'].'
+    AND '.$conf['calendar_datefield'].' = \''.$page['calendar_date'].'\'';
+    if ($calendar_category != 0)
+    {
+      $query.= '
+    AND category_id = '.$calendar_category;
+    }
+    $query.= '
+    AND id = image_id
+  ORDER BY RAND()
+  LIMIT 0,1
+;';
+    $row = mysql_fetch_array(pwg_query($query));
+    
+    $thumbnail_src = get_thumbnail_src($row['path'], @$row['tn_ext']);
+    
+    $thumbnail_title = $lang['calendar_picture_hint'].$name;
+
+    $url_link = PHPWG_ROOT_PATH.'category.php?cat=search';
+    $url_link.= '&amp;search='.$conf['calendar_datefield'].':'.$_GET['day'];
+    if ($calendar_category != 0)
+    {
+      $url_link.= '--cat:'.$calendar_category.'|AND';
+    }
+    
+    $template->assign_block_vars(
+      'thumbnails.line.thumbnail',
+      array(
+        'IMAGE'=>$thumbnail_src,
+        'IMAGE_ALT'=>$row['file'],
+        'IMAGE_TITLE'=>$thumbnail_title,
+        'IMAGE_NAME'=>$name,
+          
+        'U_IMG_LINK'=>add_session_id($url_link)
+         )
+       );
+    $template->assign_block_vars('thumbnails.line.thumbnail.bullet',array());
+    
+    // create a new line ?
+    if (++$row_number == $user['nb_image_line'])
+    {
+      $template->assign_block_vars('thumbnails.line', array());
+      $row_number = 0;
+    }
+  }
+  $conf['level_separator'] = $old_level_separator;
+}
+?>
Index: /branches/1.4/include/category_default.inc.php
===================================================================
--- /branches/1.4/include/category_default.inc.php	(revision 3249)
+++ /branches/1.4/include/category_default.inc.php	(revision 3249)
@@ -0,0 +1,140 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+/**
+ * This file is included by category.php to show thumbnails for the default
+ * case
+ * 
+ */
+
+/**
+ * $array_cat_directories is a cache hash associating category id with their
+ * complete directory
+ */
+$array_cat_directories = array();
+  
+$query = '
+SELECT DISTINCT(id),path,file,date_available
+       ,tn_ext,name,filesize,storage_category_id,average_rate
+  FROM '.IMAGES_TABLE.' AS i
+    INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id=ic.image_id
+  '.$page['where'].'
+  '.$conf['order_by'].'
+  LIMIT '.$page['start'].','.$page['nb_image_page'].'
+;';
+//echo '<pre>'.$query.'</pre>';
+$result = pwg_query($query);
+
+// template thumbnail initialization
+if ( mysql_num_rows($result) > 0 )
+{
+  $template->assign_block_vars('thumbnails', array());
+  // first line
+  $template->assign_block_vars('thumbnails.line', array());
+  // current row displayed
+  $row_number = 0;
+}
+
+while ($row = mysql_fetch_array($result))
+{
+  // name of the picture
+  if (isset($row['name']) and $row['name'] != '')
+  {
+    $name = $row['name'];
+  }
+  else
+  {
+    $name = str_replace('_', ' ', get_filename_wo_extension($row['file']));
+  }
+  if ($page['cat'] == 'best_rated')
+  {
+    $name = '('.$row['average_rate'].') '.$name;
+  }
+
+  if ($page['cat'] == 'search')
+  {
+    $name = replace_search($name, $_GET['search']);
+  }
+  
+  $thumbnail_url = get_thumbnail_src($row['path'], @$row['tn_ext']);
+  
+  // message in title for the thumbnail
+  $thumbnail_title = $row['file'];
+  if (isset($row['filesize']))
+  {
+    $thumbnail_title .= ' : '.$row['filesize'].' KB';
+  }
+  // url link on picture.php page
+  $url_link = PHPWG_ROOT_PATH.'picture.php?cat='.$page['cat'];
+  $url_link.= '&amp;image_id='.$row['id'];
+  if ($page['cat'] == 'search')
+  {
+    $url_link.= '&amp;search='.$_GET['search'];
+  }
+  else if ($page['cat'] == 'list')
+  {
+    $url_link.= '&amp;list='.$_GET['list'];
+  }
+    
+  $template->assign_block_vars(
+    'thumbnails.line.thumbnail',
+    array(
+      'IMAGE'              => $thumbnail_url,
+      'IMAGE_ALT'          => $row['file'],
+      'IMAGE_TITLE'        => $thumbnail_title,
+      'IMAGE_NAME'         => $name,
+      'IMAGE_TS'           => get_icon($row['date_available']),
+      'IMAGE_STYLE'        => 'thumb_picture',
+      
+      'U_IMG_LINK'         => add_session_id($url_link)
+      )
+    );
+    
+  if ($user['show_nb_comments']
+      and is_numeric($page['cat'])
+      and $page['cat_commentable'])
+  {
+    $query = '
+SELECT COUNT(*) AS nb_comments
+  FROM '.COMMENTS_TABLE.'
+  WHERE image_id = '.$row['id'].'
+    AND validated = \'true\'
+;';
+    $row = mysql_fetch_array(pwg_query($query));
+    $template->assign_block_vars(
+      'thumbnails.line.thumbnail.nb_comments',
+      array('NB_COMMENTS'=>$row['nb_comments']));
+  }
+
+  // create a new line ?
+  if (++$row_number == $user['nb_image_line'])
+  {
+    $template->assign_block_vars('thumbnails.line', array());
+    $row_number = 0;
+  }
+}
+?>
Index: /branches/1.4/include/category_recent_cats.inc.php
===================================================================
--- /branches/1.4/include/category_recent_cats.inc.php	(revision 3249)
+++ /branches/1.4/include/category_recent_cats.inc.php	(revision 3249)
@@ -0,0 +1,96 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+/**
+ * This file is included by category.php to show thumbnails for recent_cats
+ * category
+ * 
+ */
+
+// retrieving categories recently update, ie containing pictures added
+// recently. The calculated table field categories.date_last will be
+// easier to use
+$query = '
+SELECT c.id AS category_id,uppercats,representative_picture_id,path,file,tn_ext
+  FROM '.CATEGORIES_TABLE.' AS c INNER JOIN '.IMAGES_TABLE.' AS i
+    ON i.id = c.representative_picture_id
+  WHERE date_last > SUBDATE(CURRENT_DATE
+                            ,INTERVAL '.$user['recent_period'].' DAY)';
+if ( $user['forbidden_categories'] != '' )
+{
+  $query.= '
+    AND c.id NOT IN ('.$user['forbidden_categories'].')';
+}
+$query.= '
+;';
+$result = pwg_query( $query );
+
+// template thumbnail initialization
+if (mysql_num_rows($result) > 0)
+{
+  $template->assign_block_vars('thumbnails', array());
+  // first line
+  $template->assign_block_vars('thumbnails.line', array());
+  // current row displayed
+  $row_number = 0;
+}
+
+$old_level_separator = $conf['level_separator'];
+$conf['level_separator'] = '<br />';
+// for each category, we have to search a recent picture to display and
+// the name to display
+while ( $row = mysql_fetch_array( $result ) )
+{
+  $name = get_cat_display_name_cache($row['uppercats'], '', false);
+
+  $thumbnail_src = get_thumbnail_src($row['path'], @$row['tn_ext']);
+  
+  $url_link = PHPWG_ROOT_PATH.'category.php?cat='.$row['category_id'];
+  
+  $template->assign_block_vars(
+    'thumbnails.line.thumbnail',
+    array(
+      'IMAGE'                   => $thumbnail_src,
+      'IMAGE_ALT'               => $row['file'],
+      'IMAGE_TITLE'             => $lang['hint_category'],
+      'IMAGE_NAME'              => '['.$name.']',
+      'IMAGE_STYLE'             => 'thumb_category',
+        
+      'U_IMG_LINK'              => add_session_id($url_link)
+      )
+    );
+  $template->assign_block_vars('thumbnails.line.thumbnail.bullet',array());
+
+  // create a new line ?
+  if (++$row_number == $user['nb_image_line'])
+  {
+    $template->assign_block_vars('thumbnails.line', array());
+    $row_number = 0;
+  }
+}
+$conf['level_separator'] = $old_level_separator;
+?>
Index: /branches/1.4/include/category_subcats.inc.php
===================================================================
--- /branches/1.4/include/category_subcats.inc.php	(revision 3249)
+++ /branches/1.4/include/category_subcats.inc.php	(revision 3249)
@@ -0,0 +1,119 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+/**
+ * This file is included by category.php to show thumbnails for a category
+ * that have only subcategories
+ * 
+ */
+
+$query = '
+SELECT id, name, date_last
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id_uppercat ';
+if (!isset($page['cat']) or !is_numeric($page['cat']))
+{
+  $query.= 'is NULL';
+}
+else
+{
+  $query.= '= '.$page['cat'];
+}
+// we must not show pictures of a forbidden category
+if ($user['forbidden_categories'] != '')
+{
+  $query.= ' AND id NOT IN ('.$user['forbidden_categories'].')';
+}
+$query.= '
+  ORDER BY rank
+;';
+$result = pwg_query($query);
+
+// template thumbnail initialization
+if (mysql_num_rows($result) > 0)
+{
+  $template->assign_block_vars('thumbnails', array());
+  // first line
+  $template->assign_block_vars('thumbnails.line', array());
+  // current row displayed
+  $row_number = 0;
+}
+
+while ($row = mysql_fetch_array($result))
+{
+  $query = '
+SELECT path, tn_ext
+  FROM '.CATEGORIES_TABLE.' AS c INNER JOIN '.IMAGES_TABLE.' AS i
+    ON i.id = c.representative_picture_id
+  WHERE uppercats REGEXP \'(^|,)'.$row['id'].'(,|$)\'';
+  // we must not show pictures of a forbidden category
+  if ($user['forbidden_categories'] != '')
+  {
+    $query.= '
+    AND c.id NOT IN ('.$user['forbidden_categories'].')';
+  }
+  $query.= '
+  ORDER BY RAND()
+  LIMIT 0,1
+;';
+  $element_result = pwg_query($query);
+  if (mysql_num_rows($element_result) == 0)
+  {
+    continue;
+  }
+  $element_row = mysql_fetch_array($element_result);
+
+  $thumbnail_link = get_thumbnail_src($element_row['path'],
+                                      @$element_row['tn_ext']);
+
+  $thumbnail_title = $lang['hint_category'];
+
+  $url_link = PHPWG_ROOT_PATH.'category.php?cat='.$row['id'];
+
+  $template->assign_block_vars(
+    'thumbnails.line.thumbnail',
+    array(
+      'IMAGE'                 => $thumbnail_link,
+      'IMAGE_ALT'             => $row['name'],
+      'IMAGE_TITLE'           => $thumbnail_title,
+      'IMAGE_NAME'            => '['.$row['name'].']',
+      'IMAGE_TS'              => get_icon(@$row['date_last']),
+      'IMAGE_STYLE'           => 'thumb_category',
+        
+      'U_IMG_LINK'            => add_session_id($url_link)
+     )
+   );
+  $template->assign_block_vars('thumbnails.line.thumbnail.bullet',array());
+
+  // create a new line ?
+  if (++$row_number == $user['nb_image_line'])
+  {
+    $template->assign_block_vars('thumbnails.line', array());
+    $row_number = 0;
+  }
+}
+?>
Index: /branches/1.4/include/common.inc.php
===================================================================
--- /branches/1.4/include/common.inc.php	(revision 3249)
+++ /branches/1.4/include/common.inc.php	(revision 3249)
@@ -0,0 +1,166 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if (!defined('PHPWG_ROOT_PATH'))
+{
+  die('Hacking attempt!');
+}
+// determine the initial instant to indicate the generation time of this page
+$t1 = explode( ' ', microtime() );
+$t2 = explode( '.', $t1[0] );
+$t2 = $t1[1].'.'.$t2[1];
+
+set_magic_quotes_runtime(0); // Disable magic_quotes_runtime
+
+//
+// addslashes to vars if magic_quotes_gpc is off this is a security
+// precaution to prevent someone trying to break out of a SQL statement.
+//
+if( !get_magic_quotes_gpc() )
+{
+  if( is_array( $_GET ) )
+  {
+    while( list($k, $v) = each($_GET) )
+    {
+      if( is_array($_GET[$k]) )
+      {
+        while( list($k2, $v2) = each($_GET[$k]) )
+        {
+          $_GET[$k][$k2] = addslashes($v2);
+        }
+        @reset($_GET[$k]);
+      }
+      else
+      {
+        $_GET[$k] = addslashes($v);
+      }
+    }
+    @reset($_GET);
+  }
+  
+  if( is_array($_POST) )
+  {
+    while( list($k, $v) = each($_POST) )
+    {
+      if( is_array($_POST[$k]) )
+      {
+        while( list($k2, $v2) = each($_POST[$k]) )
+        {
+          $_POST[$k][$k2] = addslashes($v2);
+        }
+        @reset($_POST[$k]);
+      }
+      else
+      {
+        $_POST[$k] = addslashes($v);
+      }
+    }
+    @reset($_POST);
+  }
+
+  if( is_array($_COOKIE) )
+  {
+    while( list($k, $v) = each($_COOKIE) )
+    {
+      if( is_array($_COOKIE[$k]) )
+      {
+        while( list($k2, $v2) = each($_COOKIE[$k]) )
+        {
+          $_COOKIE[$k][$k2] = addslashes($v2);
+        }
+        @reset($_COOKIE[$k]);
+      }
+      else
+      {
+        $_COOKIE[$k] = addslashes($v);
+      }
+    }
+    @reset($_COOKIE);
+  }
+}
+
+//
+// Define some basic configuration arrays this also prevents malicious
+// rewriting of language and otherarray values via URI params
+//
+$conf = array();
+$page = array();
+$user = array();
+$lang = array();
+
+
+include(PHPWG_ROOT_PATH .'include/mysql.inc.php');
+if (!defined('PHPWG_INSTALLED'))
+{
+  header('Location: install.php');
+  exit;
+}
+
+include(PHPWG_ROOT_PATH . 'include/constants.php');
+include(PHPWG_ROOT_PATH . 'include/config.inc.php');
+include(PHPWG_ROOT_PATH . 'include/functions.inc.php');
+include(PHPWG_ROOT_PATH . 'include/template.php');
+
+// Database connection
+mysql_connect( $cfgHote, $cfgUser, $cfgPassword )
+or die ( "Could not connect to database server" );
+mysql_select_db( $cfgBase )
+or die ( "Could not connect to database" );
+	
+//
+// Setup gallery wide options, if this fails then we output a CRITICAL_ERROR
+// since basic gallery information is not available
+//
+$query = '
+SELECT param,value
+ FROM '.CONFIG_TABLE.'
+;';
+if (!($result = pwg_query($query)))
+{
+  die("Could not query config information");
+}
+
+while ( $row =mysql_fetch_array( $result ) )
+{
+  if ( isset( $row['value'] ) )
+  {
+    $conf[$row['param']] = $row['value'];
+  }
+  else
+  {
+    $conf[$row['param']] = '';
+  }
+  // If the field is true or false, the variable is transformed into a
+  // boolean value.
+  if ( $conf[$row['param']] == 'true' or $conf[$row['param']] == 'false' )
+  {
+    $conf[$row['param']] = get_boolean( $conf[$row['param']] );
+  }
+}
+
+include(PHPWG_ROOT_PATH.'include/user.inc.php');
+?>
Index: /branches/1.4/include/config.inc.php
===================================================================
--- /branches/1.4/include/config.inc.php	(revision 3249)
+++ /branches/1.4/include/config.inc.php	(revision 3249)
@@ -0,0 +1,198 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+/**
+ *                           configuration page
+ *
+ * Set configuration parameters that are not in the table config. In the
+ * application, configuration parameters are considered in the same way
+ * coming from config table or config.inc.php.
+ *
+ * Why having some parameters in config table and others in config.inc.php ?
+ * Modifying config.inc.php is a "hard" task for low skilled users, they
+ * need a GUI for this : admin/configuration. But only parameters that might
+ * be modified by low skilled users are in config table, other parameters
+ * are in config.inc.php
+ */
+
+// order_by : how to change the order of display for images in a category ?
+//
+// There are several fields that can order the display :
+//
+//  - date_available : the date of the adding to the gallery
+//  - file : the name of the file
+//  - id : element identifier
+//  - date_creation : date of element creation
+//
+// Once you've chosen which field(s) to use for ordering, you must chose the
+// ascending or descending order for each field.  examples :
+//
+// 1. $conf['order_by'] = " order by date_available desc, file asc";
+//    will order pictures by date_available descending & by filename ascending
+//
+// 2. $conf['order_by'] = " order by file asc";
+//    will only order pictures by file ascending without taking into account
+//    the date_available
+$conf['order_by'] = ' ORDER BY date_available DESC, file ASC, id ASC';
+
+// slideshow_period : waiting time in seconds before loading a new page
+// during automated slideshow
+$conf['slideshow_period'] = 4;
+
+// last_days : options for X last days to displays for comments
+$conf['last_days'] = array(1,2,3,10,30,365);
+
+// file_ext : file extensions (case sensitive) authorized
+$conf['file_ext'] = array('jpg','JPG','png','PNG','gif','GIF','mpg','zip',
+                          'avi','mp3','ogg');
+
+// picture_ext : file extensions for picture file, must be a subset of
+// file_ext
+$conf['picture_ext'] = array('jpg','JPG','png','PNG','gif','GIF');
+
+// top_number : number of element to display for "best rated" and "most
+// visited" categories
+$conf['top_number'] = 15;
+
+// anti-flood_time : number of seconds between 2 comments : 0 to disable
+$conf['anti-flood_time'] = 60;
+
+// show_iptc_mapping : is used for showing IPTC metadata on picture.php
+// page. For each key of the array, you need to have the same key in the
+// $lang array. For example, if my first key is 'iptc_keywords' (associated
+// to '2#025') then you need to have $lang['iptc_keywords'] set in
+// language/$user['language']/common.lang.php. If you don't have the lang
+// var set, the key will be simply displayed
+//
+// To know how to associated iptc_field with their meaning, use
+// tools/metadata.php
+$conf['show_iptc_mapping'] = array(
+  'iptc_keywords'        => '2#025',
+  'iptc_caption_writer'  => '2#122',
+  'iptc_byline_title'    => '2#085',
+  'iptc_caption'         => '2#120'
+  );
+
+// use_iptc_mapping : in which IPTC fields will PhpWebGallery find image
+// information ? This setting is used during metadata synchronisation. It
+// associates a phpwebgallery_images column name to a IPTC key
+$conf['use_iptc_mapping'] = array(
+  'keywords'        => '2#025',
+  'date_creation'   => '2#055',
+  'author'          => '2#122',
+  'name'            => '2#005',
+  'comment'         => '2#120'
+  );
+
+// show_exif_fields : in EXIF fields, you can choose to display fields in
+// sub-arrays, for example ['COMPUTED']['ApertureFNumber']. for this, add
+// 'COMPUTED;ApertureFNumber' in $conf['show_exif_fields']
+//
+// The key displayed in picture.php will be $lang['exif_field_Make'] for
+// example and if it exists. For compound fields, only take into account the
+// last part : for key 'COMPUTED;ApertureFNumber', you need
+// $lang['exif_field_ApertureFNumber']
+//
+// for PHP version newer than 4.1.2 :
+// $conf['show_exif_fields'] = array('CameraMake','CameraModel','DateTime');
+// 
+$conf['show_exif_fields'] = array('Make',
+                                  'Model',
+                                  'DateTime',
+                                  'COMPUTED;ApertureFNumber');
+
+// calendar_datefield : date field of table "images" used for calendar
+// catgory
+$conf['calendar_datefield'] = 'date_creation';
+
+// rate : enable feature for rating elements
+$conf['rate'] = true;
+
+// remember_me_length : time of validity for "remember me" cookies, in
+// seconds.
+$conf['remember_me_length'] = 31536000;
+
+// session_length : time of validity for normal session, in seconds.
+$conf['session_length'] = 3600;
+
+// session_id_size : a session identifier is compound of alphanumeric
+// characters and is case sensitive. Each character is among 62
+// possibilities. The number of possible sessions is
+// 62^$conf['session_id_size'].
+//
+// 62^5  =             916,132,832
+// 62^10 = 839,299,365,868,340,224
+//
+$conf['session_id_size'] = 10;
+
+// info_nb_elements_page : number of elements to display per page on
+// admin/infos_images
+$conf['info_nb_elements_page'] = 5;
+
+// show_queries : for debug purpose, show queries and execution times
+$conf['show_queries'] = false;
+
+// show_gt : display generation time at the bottom of each page
+$conf['show_gt'] = true;
+
+// newcat_default_commentable : at creation, must a category be commentable
+// or not ?
+$conf['newcat_default_commentable'] = 'true';
+
+// newcat_default_uploadable : at creation, must a category be uploadable or
+// not ?
+$conf['newcat_default_uploadable'] = 'false';
+
+// newcat_default_visible : at creation, must a category be visible or not ?
+// Warning : if the parent category is invisible, the category is
+// automatically create invisible. (invisible = locked)
+$conf['newcat_default_visible'] = 'true';
+
+// newcat_default_status : at creation, must a category be public or private
+// ? Warning : if the parent category is private, the category is
+// automatically create private.
+$conf['newcat_default_status'] = 'public';
+
+// level_separator : character string used for separating a category level
+// to the sub level. Suggestions : ' / ', ' &raquo; ', ' &rarr; ', ' - ',
+// ' &gt;'
+$conf['level_separator'] = ' / ';
+
+// paginate_pages_around : on paginate navigation bar, how many pages
+// display before and after the current page ?
+$conf['paginate_pages_around'] = 2;
+
+// tn_width : default width for thumbnails creation
+$conf['tn_width'] = 128;
+
+// tn_height : default height for thumbnails creation
+$conf['tn_height'] = 96;
+
+// show_version : shall the version of PhpWebGallery be displayed at the
+// bottom of each page ?
+$conf['show_version'] = false;
+?>
Index: /branches/1.4/include/constants.php
===================================================================
--- /branches/1.4/include/constants.php	(revision 3249)
+++ /branches/1.4/include/constants.php	(revision 3249)
@@ -0,0 +1,61 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Default settings
+define('PHPWG_VERSION', '1.4.1');
+define('PHPWG_URL', 'http://www.phpwebgallery.net');
+define('PHPWG_FORUM_URL', 'http://forum.phpwebgallery.net');
+
+// User level
+define('ANONYMOUS', 2);
+ 
+// Error codes
+define('GENERAL_MESSAGE', 200);
+define('GENERAL_ERROR', 202);
+define('CRITICAL_MESSAGE', 203);
+define('CRITICAL_ERROR', 204); 
+
+// Table names
+define('CATEGORIES_TABLE', $prefixeTable.'categories');
+define('COMMENTS_TABLE', $prefixeTable.'comments');
+define('CONFIG_TABLE', $prefixeTable.'config');
+define('FAVORITES_TABLE', $prefixeTable.'favorites');
+define('GROUP_ACCESS_TABLE', $prefixeTable.'group_access');
+define('GROUPS_TABLE', $prefixeTable.'groups');
+define('HISTORY_TABLE', $prefixeTable.'history');
+define('IMAGE_CATEGORY_TABLE', $prefixeTable.'image_category');
+define('IMAGES_TABLE', $prefixeTable.'images');
+define('SESSIONS_TABLE', $prefixeTable.'sessions');
+define('SITES_TABLE', $prefixeTable.'sites');
+define('USER_ACCESS_TABLE', $prefixeTable.'user_access');
+define('USER_GROUP_TABLE', $prefixeTable.'user_group');
+define('USERS_TABLE', $prefixeTable.'users');
+define('WAITING_TABLE', $prefixeTable.'waiting');
+define('IMAGE_METADATA_TABLE', $prefixeTable.'image_metadata');
+define('RATE_TABLE', $prefixeTable.'rate');
+define('USER_FORBIDDEN_TABLE', $prefixeTable.'user_forbidden');
+?>
Index: /branches/1.4/include/functions.inc.php
===================================================================
--- /branches/1.4/include/functions.inc.php	(revision 3249)
+++ /branches/1.4/include/functions.inc.php	(revision 3249)
@@ -0,0 +1,621 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+include_once( PHPWG_ROOT_PATH .'include/functions_user.inc.php' );
+include_once( PHPWG_ROOT_PATH .'include/functions_session.inc.php' );
+include_once( PHPWG_ROOT_PATH .'include/functions_category.inc.php' );
+include_once( PHPWG_ROOT_PATH .'include/functions_xml.inc.php' );
+include_once( PHPWG_ROOT_PATH .'include/functions_group.inc.php' );
+include_once( PHPWG_ROOT_PATH .'include/functions_html.inc.php' );
+
+//----------------------------------------------------------- generic functions
+
+// get_boolean transforms a string to a boolean value. If the string is
+// "false" (case insensitive), then the boolean value false is returned. In
+// any other case, true is returned.
+function get_boolean( $string )
+{
+  $boolean = true;
+  if ( preg_match( '/^false$/i', $string ) )
+  {
+    $boolean = false;
+  }
+  return $boolean;
+}
+
+/**
+ * returns boolean string 'true' or 'false' if the given var is boolean
+ *
+ * @param mixed $var
+ * @return mixed
+ */
+function boolean_to_string($var)
+{
+  if (is_bool($var))
+  {
+    if ($var)
+    {
+      return 'true';
+    }
+    else
+    {
+      return 'false';
+    }
+  }
+  else
+  {
+    return $var;
+  }
+}
+
+// array_remove removes a value from the given array if the value existed in
+// this array.
+function array_remove( $array, $value )
+{
+  $output = array();
+  foreach ( $array as $v ) {
+    if ( $v != $value ) array_push( $output, $v );
+  }
+  return $output;
+}
+
+// The function get_moment returns a float value coresponding to the number
+// of seconds since the unix epoch (1st January 1970) and the microseconds
+// are precised : e.g. 1052343429.89276600
+function get_moment()
+{
+  $t1 = explode( ' ', microtime() );
+  $t2 = explode( '.', $t1[0] );
+  $t2 = $t1[1].'.'.$t2[1];
+  return $t2;
+}
+
+// The function get_elapsed_time returns the number of seconds (with 3
+// decimals precision) between the start time and the end time given.
+function get_elapsed_time( $start, $end )
+{
+  return number_format( $end - $start, 3, '.', ' ').' s';
+}
+
+// - The replace_space function replaces space and '-' characters
+//   by their HTML equivalent  &nbsb; and &minus;
+// - The function does not replace characters in HTML tags
+// - This function was created because IE5 does not respect the
+//   CSS "white-space: nowrap;" property unless space and minus
+//   characters are replaced like this function does.
+// - Example :
+//                 <div class="foo">My friend</div>
+//               ( 01234567891111111111222222222233 )
+//               (           0123456789012345678901 )
+// becomes :
+//             <div class="foo">My&nbsp;friend</div>
+function replace_space( $string )
+{
+  //return $string;
+  $return_string = '';
+  // $remaining is the rest of the string where to replace spaces characters
+  $remaining = $string;
+  // $start represents the position of the next '<' character
+  // $end   represents the position of the next '>' character
+  $start = 0;
+  $end = 0;
+  $start = strpos ( $remaining, '<' ); // -> 0
+  $end   = strpos ( $remaining, '>' ); // -> 16
+  // as long as a '<' and his friend '>' are found, we loop
+  while ( is_numeric( $start ) and is_numeric( $end ) )
+  {
+    // $treatment is the part of the string to treat
+    // In the first loop of our example, this variable is empty, but in the
+    // second loop, it equals 'My friend'
+    $treatment = substr ( $remaining, 0, $start );
+    // Replacement of ' ' by his equivalent '&nbsp;'
+    $treatment = str_replace( ' ', '&nbsp;', $treatment );
+    $treatment = str_replace( '-', '&minus;', $treatment );
+    // composing the string to return by adding the treated string and the
+    // following HTML tag -> 'My&nbsp;friend</div>'
+    $return_string.= $treatment.substr( $remaining, $start, $end-$start+1 );
+    // the remaining string is deplaced to the part after the '>' of this
+    // loop
+    $remaining = substr ( $remaining, $end + 1, strlen( $remaining ) );
+    $start = strpos ( $remaining, '<' );
+    $end   = strpos ( $remaining, '>' );
+  }
+  $treatment = str_replace( ' ', '&nbsp;', $remaining );
+  $treatment = str_replace( '-', '&minus;', $treatment );
+  $return_string.= $treatment;
+
+  return $return_string;
+}
+
+// get_extension returns the part of the string after the last "."
+function get_extension( $filename )
+{
+  return substr( strrchr( $filename, '.' ), 1, strlen ( $filename ) );
+}
+
+// get_filename_wo_extension returns the part of the string before the last
+// ".".
+// get_filename_wo_extension( 'test.tar.gz' ) -> 'test.tar'
+function get_filename_wo_extension( $filename )
+{
+  return substr( $filename, 0, strrpos( $filename, '.' ) );
+}
+
+/**
+ * returns an array contening sub-directories, excluding "CVS"
+ *
+ * @param string $dir
+ * @return array
+ */
+function get_dirs($directory)
+{
+  $sub_dirs = array();
+
+  if ($opendir = opendir($directory))
+  {
+    while ($file = readdir($opendir))
+    {
+      if ($file != '.'
+          and $file != '..'
+          and is_dir($directory.'/'.$file)
+          and $file != 'CVS')
+      {
+        array_push($sub_dirs, $file);
+      }
+    }
+  }
+  return $sub_dirs;
+}
+
+// The get_picture_size function return an array containing :
+//      - $picture_size[0] : final width
+//      - $picture_size[1] : final height
+// The final dimensions are calculated thanks to the original dimensions and
+// the maximum dimensions given in parameters.  get_picture_size respects
+// the width/height ratio
+function get_picture_size( $original_width, $original_height,
+                           $max_width, $max_height )
+{
+  $width = $original_width;
+  $height = $original_height;
+  $is_original_size = true;
+                
+  if ( $max_width != "" )
+  {
+    if ( $original_width > $max_width )
+    {
+      $width = $max_width;
+      $height = floor( ( $width * $original_height ) / $original_width );
+    }
+  }
+  if ( $max_height != "" )
+  {
+    if ( $original_height > $max_height )
+    {
+      $height = $max_height;
+      $width = floor( ( $height * $original_width ) / $original_height );
+      $is_original_size = false;
+    }
+  }
+  if ( is_numeric( $max_width ) and is_numeric( $max_height )
+       and $max_width != 0 and $max_height != 0 )
+  {
+    $ratioWidth = $original_width / $max_width;
+    $ratioHeight = $original_height / $max_height;
+    if ( ( $ratioWidth > 1 ) or ( $ratioHeight > 1 ) )
+    {
+      if ( $ratioWidth < $ratioHeight )
+      { 
+        $width = floor( $original_width / $ratioHeight );
+        $height = $max_height;
+      }
+      else
+      { 
+        $width = $max_width; 
+        $height = floor( $original_height / $ratioWidth );
+      }
+      $is_original_size = false;
+    }
+  }
+  $picture_size = array();
+  $picture_size[0] = $width;
+  $picture_size[1] = $height;
+  return $picture_size;
+}
+//-------------------------------------------- PhpWebGallery specific functions
+
+/**
+ * returns an array with a list of {language_code => language_name}
+ *
+ * @returns array
+ */
+function get_languages()
+{
+  $dir = opendir(PHPWG_ROOT_PATH.'language');
+  $languages = array();
+
+  while ($file = readdir($dir))
+  {
+    $path = PHPWG_ROOT_PATH.'language/'.$file;
+    if (is_dir($path) and !is_link($path) and file_exists($path.'/iso.txt'))
+    {
+      list($language_name) = @file($path.'/iso.txt');
+      $languages[$file] = $language_name;
+    }
+  }
+  closedir($dir);
+  @asort($languages);
+  @reset($languages);
+
+  return $languages;
+}
+
+/**
+ * replaces the $search into <span style="$style">$search</span> in the
+ * given $string.
+ *
+ * case insensitive replacements, does not replace characters in HTML tags
+ *
+ * @param string $string
+ * @param string $search
+ * @param string $style
+ * @return string
+ */
+function add_style( $string, $search, $style )
+{
+  //return $string;
+  $return_string = '';
+  $remaining = $string;
+
+  $start = 0;
+  $end = 0;
+  $start = strpos ( $remaining, '<' );
+  $end   = strpos ( $remaining, '>' );
+  while ( is_numeric( $start ) and is_numeric( $end ) )
+  {
+    $treatment = substr ( $remaining, 0, $start );
+    $treatment = preg_replace( '/('.$search.')/i',
+                               '<span style="'.$style.'">\\0</span>',
+                               $treatment );
+    $return_string.= $treatment.substr( $remaining, $start, $end-$start+1 );
+    $remaining = substr ( $remaining, $end + 1, strlen( $remaining ) );
+    $start = strpos ( $remaining, '<' );
+    $end   = strpos ( $remaining, '>' );
+  }
+  $treatment = preg_replace( '/('.$search.')/i',
+                             '<span style="'.$style.'">\\0</span>',
+                             $remaining );
+  $return_string.= $treatment;
+                
+  return $return_string;
+}
+
+// replace_search replaces a searched words array string by the search in
+// another style for the given $string.
+function replace_search( $string, $search )
+{
+  // FIXME : with new advanced search, this function needs a rewrite
+  return $string;
+  
+  $words = explode( ',', $search );
+  $style = 'background-color:white;color:red;';
+  foreach ( $words as $word ) {
+    $string = add_style( $string, $word, $style );
+  }
+  return $string;
+}
+
+function pwg_log( $file, $category, $picture = '' )
+{
+  global $conf, $user;
+
+  if ($conf['log'])
+  {
+    $query = '
+INSERT INTO '.HISTORY_TABLE.'
+  (date,login,IP,file,category,picture)
+  VALUES
+  (NOW(),
+  \''.(($user['id'] == 2) ? 'guest' : addslashes($user['username'])).'\',
+  \''.$_SERVER['REMOTE_ADDR'].'\',
+  \''.addslashes($file).'\',
+  \''.addslashes($category).'\',
+  \''.addslashes($picture).'\')
+;';
+    pwg_query($query);
+  }
+}
+
+// format_date returns a formatted date for display. The date given in
+// argument can be a unixdate (number of seconds since the 01.01.1970) or an
+// american format (2003-09-15). By option, you can show the time. The
+// output is internationalized.
+//
+// format_date( "2003-09-15", 'us', true ) -> "Monday 15 September 2003 21:52"
+function format_date($date, $type = 'us', $show_time = false)
+{
+  global $lang;
+
+  list($year,$month,$day,$hour,$minute,$second) = array(0,0,0,0,0,0);
+  
+  switch ( $type )
+  {
+    case 'us' :
+    {
+      list($year,$month,$day) = explode('-', $date);
+      break;
+    }
+    case 'unix' :
+    {
+      list($year,$month,$day,$hour,$minute) =
+        explode('.', date('Y.n.j.G.i', $date));
+      break;
+    }
+    case 'mysql_datetime' :
+    {
+      preg_match('/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/',
+                 $date, $out);
+      list($year,$month,$day,$hour,$minute,$second) =
+        array($out[1],$out[2],$out[3],$out[4],$out[5],$out[6]);
+      break;
+    }
+  }
+  $formated_date = '';
+  // before 1970, Microsoft Windows can't mktime
+  if ($year >= 1970)
+  {
+    // we ask midday because Windows think it's prior to midnight with a
+    // zero and refuse to work
+    $formated_date.= $lang['day'][date('w', mktime(12,0,0,$month,$day,$year))];
+  }
+  $formated_date.= ' '.$day;
+  $formated_date.= ' '.$lang['month'][(int)$month];
+  $formated_date.= ' '.$year;
+  if ($show_time)
+  {
+    $formated_date.= ' '.$hour.':'.$minute;
+  }
+
+  return $formated_date;
+}
+
+// notify sends a email to every admin of the gallery
+function notify( $type, $infos = '' )
+{
+  global $conf;
+
+  $headers = 'From: <'.$conf['mail_webmaster'].'>'."\n";
+  $headers.= 'Reply-To: '.$conf['mail_webmaster']."\n";
+  $headers.= 'X-Mailer: PhpWebGallery, PHP '.phpversion();
+
+  $options = '-f '.$conf['mail_webmaster'];
+  // retrieving all administrators
+  $query = 'SELECT username,mail_address,language';
+  $query.= ' FROM '.USERS_TABLE;
+  $query.= " WHERE status = 'admin'";
+  $query.= ' AND mail_address IS NOT NULL';
+  $query.= ';';
+  $result = pwg_query( $query );
+  while ( $row = mysql_fetch_array( $result ) )
+  {
+    $to = $row['mail_address'];
+    include( PHPWG_ROOT_PATH.'language/'.$row['language'].'/common.lang.php' );
+    $content = $lang['mail_hello']."\n\n";
+    switch ( $type )
+    {
+    case 'upload' :
+      $subject = $lang['mail_new_upload_subject'];
+      $content.= $lang['mail_new_upload_content'];
+      break;
+    case 'comment' :
+      $subject = $lang['mail_new_comment_subject'];
+      $content.= $lang['mail_new_comment_content'];
+      break;
+    }
+    $infos = str_replace( '&nbsp;',  ' ', $infos );
+    $infos = str_replace( '&minus;', '-', $infos );
+    $content.= "\n\n".$infos;
+    $content.= "\n\n-- \nPhpWebGallery ".PHPWG_VERSION;
+    $content = wordwrap( $content, 72 );
+    @mail( $to, $subject, $content, $headers, $options );
+  }
+}
+
+function pwg_write_debug()
+{
+  global $debug;
+  
+  $fp = @fopen( './log/debug.log', 'a+' );
+  fwrite( $fp, "\n\n" );
+  fwrite( $fp, $debug );
+  fclose( $fp );
+}
+
+function pwg_query($query)
+{
+  global $conf,$page;
+  
+  $start = get_moment();
+  $result = mysql_query($query) or my_error($query."\n");
+  
+  $time = get_moment() - $start;
+
+  if (!isset($page['count_queries']))
+  {
+    $page['count_queries'] = 0;
+    $page['queries_time'] = 0;
+  }
+  
+  $page['count_queries']++;
+  $page['queries_time']+= $time;
+  
+  if ($conf['show_queries'])
+  {
+    $output = '';
+    $output.= '<pre>['.$page['count_queries'].'] ';
+    $output.= "\n".$query;
+    $output.= "\n".'(this query time : ';
+    $output.= number_format($time, 3, '.', ' ').' s)</b>';
+    $output.= "\n".'(total SQL time  : ';
+    $output.= number_format($page['queries_time'], 3, '.', ' ').' s)';
+    $output.= '</pre>';
+    
+    echo $output;
+  }
+  
+  return $result;
+}
+
+function pwg_debug( $string )
+{
+  global $debug,$t2,$count_queries;
+
+  $now = explode( ' ', microtime() );
+  $now2 = explode( '.', $now[0] );
+  $now2 = $now[1].'.'.$now2[1];
+  $time = number_format( $now2 - $t2, 3, '.', ' ').' s';
+  $debug.= '['.$time.', ';
+  $debug.= $count_queries.' queries] : '.$string;
+  $debug.= "\n";
+}
+
+/**
+ * Redirects to the given URL
+ *
+ * Note : once this function called, the execution doesn't go further
+ * (presence of an exit() instruction.
+ *
+ * @param string $url
+ * @return void
+ */
+function redirect( $url )
+{
+  global $user, $template, $lang_info, $conf, $lang, $t2, $page;
+
+  // $refresh, $url_link and $title are required for creating an automated
+  // refresh page in header.tpl
+  $refresh = 0;
+  $url_link = $url;
+  $title = 'redirection';
+
+  include( PHPWG_ROOT_PATH.'include/page_header.php' );
+  
+  $template->set_filenames( array( 'redirect' => 'redirect.tpl' ) );
+  $template->parse('redirect');
+  
+  include( PHPWG_ROOT_PATH.'include/page_tail.php' );
+
+  exit();
+}
+
+/**
+ * returns $_SERVER['QUERY_STRING'] whitout keys given in parameters
+ *
+ * @param array $rejects
+ * @returns string
+ */
+function get_query_string_diff($rejects = array())
+{
+  $query_string = '';
+  
+  $str = $_SERVER['QUERY_STRING'];
+  parse_str($str, $vars);
+  
+  $is_first = true;
+  foreach ($vars as $key => $value)
+  {
+    if (!in_array($key, $rejects))
+    {
+      if ($is_first)
+      {
+        $query_string.= '?';
+        $is_first = false;
+      }
+      else
+      {
+        $query_string.= '&amp;';
+      }
+      $query_string.= $key.'='.$value;
+    }
+  }
+
+  return $query_string;
+}
+
+/**
+ * returns available templates
+ */
+function get_templates()
+{
+  return get_dirs(PHPWG_ROOT_PATH.'template');
+}
+
+/**
+ * returns thumbnail filepath (or distant URL if thumbnail is remote) for a
+ * given element
+ *
+ * the returned string can represente the filepath of the thumbnail or the
+ * filepath to the corresponding icon for non picture elements
+ *
+ * @param string path
+ * @param string tn_ext
+ * @return string
+ */
+function get_thumbnail_src($path, $tn_ext = '')
+{
+  global $conf, $user;
+
+  if ($tn_ext != '')
+  {
+    $src = substr_replace(get_filename_wo_extension($path),
+                          '/thumbnail/'.$conf['prefix_thumbnail'],
+                          strrpos($path,'/'),
+                          1);
+    $src.= '.'.$tn_ext;
+  }
+  else
+  {
+    $src = PHPWG_ROOT_PATH;
+    $src.= 'template/'.$user['template'].'/mimetypes/';
+    $src.= strtolower(get_extension($path)).'.png';
+  }
+  
+  return $src;
+}
+
+// my_error returns (or send to standard output) the message concerning the
+// error occured for the last mysql query.
+function my_error($header)
+{
+  $error = '<pre>';
+  $error.= $header;
+  $error.= '[mysql error '.mysql_errno().'] ';
+  $error.= mysql_error();
+  $error.= '</pre>';
+  die ($error);
+}
+?>
Index: /branches/1.4/include/functions_category.inc.php
===================================================================
--- /branches/1.4/include/functions_category.inc.php	(revision 3249)
+++ /branches/1.4/include/functions_category.inc.php	(revision 3249)
@@ -0,0 +1,850 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+/**
+ * Provides functions to handle categories.
+ *
+ * 
+ */
+
+/**
+ * Is the category accessible to the connected user ?
+ *
+ * Note : if the user is not authorized to see this category, page creation
+ * ends (exit command in this function)
+ *
+ * @param int category id to verify
+ * @return void
+ */
+function check_restrictions( $category_id )
+{
+  global $user,$lang;
+
+  if ( in_array( $category_id, $user['restrictions'] ) )
+  {
+    echo '<div style="text-align:center;">'.$lang['access_forbiden'].'<br />';
+    echo '<a href="'.add_session_id( './category.php' ).'">';
+    echo $lang['thumbnails'].'</a></div>';
+    exit();
+  }
+}
+
+/**
+ * Checks whether the argument is a right parameter category id
+ *
+ * The argument is a right parameter if corresponds to one of these :
+ *
+ *  - is numeric and corresponds to a category in the database
+ *  - equals 'fav' (for favorites)
+ *  - equals 'search' (when the result of a search is displayed)
+ *  - equals 'most_visited'
+ *  - equals 'best_rated'
+ *  - equals 'recent_pics'
+ *  - equals 'recent_cats'
+ *  - equals 'calendar'
+ *  - equals 'list'
+ *
+ * The function fills the global var $page['cat'] and returns nothing
+ *
+ * @param mixed category id or special category name
+ * @return void
+ */
+function check_cat_id( $cat )
+{
+  global $page;
+
+  unset( $page['cat'] );
+  if ( isset( $cat ) )
+  {
+    if ( isset( $page['plain_structure'][$cat] ) )
+    {
+      $page['cat'] = $cat;
+    }
+    else if ( is_numeric( $cat ) )
+    {
+      $query = 'SELECT id';
+      $query.= ' FROM '.CATEGORIES_TABLE.' WHERE id = '.$cat.';';
+      $result = pwg_query( $query );
+      if ( mysql_num_rows( $result ) != 0 )
+      {
+        $page['cat'] = $cat;
+      }
+    }
+    if ( $cat == 'fav'
+         or $cat == 'most_visited'
+         or $cat == 'best_rated'
+         or $cat == 'recent_pics'
+         or $cat == 'recent_cats'
+         or $cat == 'calendar' )
+    {
+      $page['cat'] = $cat;
+    }
+    if ($cat == 'search' and isset($_GET['search']))
+    {
+      $page['cat'] = $cat;
+    }
+    if ($cat == 'list'
+        and isset($_GET['list'])
+        and preg_match('/^\d+(,\d+)*$/', $_GET['list']))
+    {
+      $page['cat'] = 'list';
+    }
+  }
+}
+
+function get_categories_menu()
+{
+  global $page,$user;
+  
+  $infos = array('');
+  
+  $query = '
+SELECT name,id,date_last,nb_images,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE 1 = 1'; // stupid but permit using AND after it !
+  if (!$user['expand'])
+  {
+    $query.= '
+    AND (id_uppercat is NULL';
+    if (isset ($page['tab_expand']) and count($page['tab_expand']) > 0)
+    {
+      $query.= ' OR id_uppercat IN ('.implode(',',$page['tab_expand']).')';
+    }
+    $query.= ')';
+  }
+  if ($user['forbidden_categories'] != '')
+  {
+    $query.= '
+    AND id NOT IN ('.$user['forbidden_categories'].')';
+  }
+  $query.= '
+;';
+
+  $result = pwg_query($query);
+  $cats = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($cats, $row);
+  }
+  usort($cats, 'global_rank_compare');
+
+  return get_html_menu_category($cats);
+}
+
+/**
+ * returns the total number of elements viewable in the gallery by the
+ * connected user
+ *
+ * @return int
+ */
+function count_user_total_images()
+{
+  global $user;
+
+  $query = '
+SELECT COUNT(DISTINCT(image_id)) as total
+  FROM '.IMAGE_CATEGORY_TABLE;
+  if (count($user['restrictions']) > 0)
+  {
+    $query.= '
+  WHERE category_id NOT IN ('.$user['forbidden_categories'].')';
+  }
+  $query.= '
+;';
+ 
+  $row = mysql_fetch_array(pwg_query($query));
+
+  return isset($row['total']) ? $row['total'] : 0;
+}
+
+/**
+ * Retrieve informations about a category in the database
+ *
+ * Returns an array with following keys :
+ *
+ *  - comment
+ *  - dir : directory, might be empty for virtual categories
+ *  - name : an array with indexes from 0 (lowest cat name) to n (most
+ *           uppercat name findable)
+ *  - nb_images
+ *  - id_uppercat
+ *  - site_id
+ *  - 
+ *
+ * @param int category id
+ * @return array
+ */
+function get_cat_info( $id )
+{
+  $infos = array('nb_images','id_uppercat','comment','site_id'
+                 ,'dir','date_last','uploadable','status','visible'
+                 ,'representative_picture_id','uppercats','commentable');
+  
+  $query = '
+SELECT '.implode(',', $infos).'
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id = '.$id.'
+;';
+  $row = mysql_fetch_array(pwg_query($query));
+
+  $cat = array();
+  foreach ($infos as $info)
+  {
+    if (isset($row[$info]))
+    {
+      $cat[$info] = $row[$info];
+    }
+    else
+    {
+      $cat[$info] = '';
+    }
+    // If the field is true or false, the variable is transformed into a
+    // boolean value.
+    if ($cat[$info] == 'true' or $cat[$info] == 'false')
+    {
+      $cat[$info] = get_boolean( $cat[$info] );
+    }
+  }
+  $cat['comment'] = nl2br($cat['comment']);
+
+  $names = array();
+  $query = '
+SELECT name,id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id IN ('.$cat['uppercats'].')
+;';
+  $result = pwg_query($query);
+  while($row = mysql_fetch_array($result))
+  {
+    $names[$row['id']] = $row['name'];
+  }
+
+  // category names must be in the same order than uppercats list
+  $cat['name'] = array();
+  foreach (explode(',', $cat['uppercats']) as $cat_id)
+  {
+    $cat['name'][$cat_id] = $names[$cat_id];
+  }
+  
+  return $cat;
+}
+
+// get_complete_dir returns the concatenation of get_site_url and
+// get_local_dir
+// Example : "pets > rex > 1_year_old" is on the the same site as the
+// PhpWebGallery files and this category has 22 for identifier
+// get_complete_dir(22) returns "./galleries/pets/rex/1_year_old/"
+function get_complete_dir( $category_id )
+{
+  return get_site_url($category_id).get_local_dir($category_id);
+}
+
+// get_local_dir returns an array with complete path without the site url
+// Example : "pets > rex > 1_year_old" is on the the same site as the
+// PhpWebGallery files and this category has 22 for identifier
+// get_local_dir(22) returns "pets/rex/1_year_old/"
+function get_local_dir( $category_id )
+{
+  global $page;
+
+  $uppercats = '';
+  $local_dir = '';
+
+  if ( isset( $page['plain_structure'][$category_id]['uppercats'] ) )
+  {
+    $uppercats = $page['plain_structure'][$category_id]['uppercats'];
+  }
+  else
+  {
+    $query = 'SELECT uppercats';
+    $query.= ' FROM '.CATEGORIES_TABLE.' WHERE id = '.$category_id;
+    $query.= ';';
+    $row = mysql_fetch_array( pwg_query( $query ) );
+    $uppercats = $row['uppercats'];
+  }
+
+  $upper_array = explode( ',', $uppercats );
+
+  $database_dirs = array();
+  $query = 'SELECT id,dir';
+  $query.= ' FROM '.CATEGORIES_TABLE.' WHERE id IN ('.$uppercats.')';
+  $query.= ';';
+  $result = pwg_query( $query );
+  while( $row = mysql_fetch_array( $result ) )
+  {
+    $database_dirs[$row['id']] = $row['dir'];
+  }
+  foreach ($upper_array as $id)
+  {
+    $local_dir.= $database_dirs[$id].'/';
+  }
+
+  return $local_dir;
+}
+
+// retrieving the site url : "http://domain.com/gallery/" or
+// simply "./galleries/"
+function get_site_url($category_id)
+{
+  global $page;
+
+  $query = '
+SELECT galleries_url
+  FROM '.SITES_TABLE.' AS s,'.CATEGORIES_TABLE.' AS c
+  WHERE s.id = c.site_id
+    AND c.id = '.$category_id.'
+;';
+  $row = mysql_fetch_array(pwg_query($query));
+  return $row['galleries_url'];
+}
+
+// initialize_category initializes ;-) the variables in relation
+// with category :
+// 1. calculation of the number of pictures in the category
+// 2. determination of the SQL query part to ask to find the right category
+//    $page['where'] is not the same if we are in
+//       - simple category
+//       - search result
+//       - favorites displaying
+//       - most visited pictures
+//       - best rated pictures
+//       - recent pictures
+//       - defined list (used for random)
+// 3. determination of the title of the page
+// 4. creation of the navigation bar
+function initialize_category( $calling_page = 'category' )
+{
+  pwg_debug( 'start initialize_category' );
+  global $page,$lang,$user,$conf;
+
+  if ( isset( $page['cat'] ) )
+  {
+    // $page['nb_image_page'] is the number of picture to display on this page
+    // By default, it is the same as the $user['nb_image_page']
+    $page['nb_image_page'] = $user['nb_image_page'];
+    // $url is used to create the navigation bar
+    $url = PHPWG_ROOT_PATH.'category.php?cat='.$page['cat'];
+    if ( isset($page['expand']) ) $url.= '&amp;expand='.$page['expand'];
+    // simple category
+    if ( is_numeric( $page['cat'] ) )
+    {
+      $result = get_cat_info( $page['cat'] );
+      $page['comment']        = $result['comment'];
+      $page['cat_dir']        = $result['dir'];
+      $page['cat_name']       = $result['name'];
+      $page['cat_nb_images']  = $result['nb_images'];
+      $page['cat_site_id']    = $result['site_id'];
+      $page['cat_uploadable'] = $result['uploadable'];
+      $page['cat_commentable'] = $result['commentable'];
+      $page['uppercats']      = $result['uppercats'];
+      $page['title'] =
+        get_cat_display_name($page['cat_name'],
+                             '',
+                             false);
+      $page['where'] = ' WHERE category_id = '.$page['cat'];
+    }
+    else
+    {
+      if ($page['cat'] == 'search'
+          or $page['cat'] == 'most_visited'
+          or $page['cat'] == 'recent_pics'
+          or $page['cat'] == 'recent_cats'
+          or $page['cat'] == 'best_rated'
+          or $page['cat'] == 'calendar'
+          or $page['cat'] == 'list')
+      {
+        // we must not show pictures of a forbidden category
+        if ( $user['forbidden_categories'] != '' )
+        {
+          $forbidden = ' category_id NOT IN ';
+          $forbidden.= '('.$user['forbidden_categories'].')';
+        }
+      }
+      // search result
+      if ( $page['cat'] == 'search' )
+      {
+        // analyze search string given in URL (created in search.php)
+        $tokens = explode('|', $_GET['search']);
+
+        if (isset($tokens[1]) and $tokens[1] == 'AND')
+        {
+          $search['mode'] = 'AND';
+        }
+        else
+        {
+          $search['mode'] = 'OR';
+        }
+
+        $search_tokens = explode('--', $tokens[0]);
+        foreach ($search_tokens as $search_token)
+        {
+          $tokens = explode(':', $search_token);
+          $field_name = $tokens[0];
+          $field_content = $tokens[1];
+
+          $tokens = explode('~', $tokens[1]);
+          if (isset($tokens[1]))
+          {
+            $search['fields'][$field_name]['mode'] = $tokens[1];
+          }
+          else
+          {
+            $search['fields'][$field_name]['mode'] = '';
+          }
+
+          $search['fields'][$field_name]['words'] = array();
+          $tokens = explode(',', $tokens[0]);
+          foreach ($tokens as $token)
+          {
+            array_push($search['fields'][$field_name]['words'],
+                       htmlentities($token));
+          }
+        }
+        
+        $page['title'] = $lang['search_result'];
+        if ( $calling_page == 'picture' )
+        {
+          $page['title'].= ' : <span style="font-style:italic;">';
+          $page['title'].= $_GET['search']."</span>";
+        }
+
+        // SQL where clauses are stored in $clauses array during query
+        // construction
+        $clauses = array();
+        
+        $textfields = array('file', 'name', 'comment', 'keywords', 'author');
+        foreach ($textfields as $textfield)
+        {
+          if (isset($search['fields'][$textfield]))
+          {
+            $local_clauses = array();
+            foreach ($search['fields'][$textfield]['words'] as $word)
+            {
+              array_push($local_clauses, $textfield." LIKE '%".$word."%'");
+            }
+            // adds brackets around where clauses
+            array_walk($local_clauses,create_function('&$s','$s="(".$s.")";'));
+            array_push($clauses,
+                       implode(' '.$search['fields'][$textfield]['mode'].' ',
+                               $local_clauses));
+          }
+        }
+
+        if (isset($search['fields']['allwords']))
+        {
+          $fields = array('file', 'name', 'comment', 'keywords', 'author');
+          // in the OR mode, request bust be :
+          // ((field1 LIKE '%word1%' OR field2 LIKE '%word1%')
+          // OR (field1 LIKE '%word2%' OR field2 LIKE '%word2%'))
+          //
+          // in the AND mode :
+          // ((field1 LIKE '%word1%' OR field2 LIKE '%word1%')
+          // AND (field1 LIKE '%word2%' OR field2 LIKE '%word2%'))
+          $word_clauses = array();
+          foreach ($search['fields']['allwords']['words'] as $word)
+          {
+            $field_clauses = array();
+            foreach ($fields as $field)
+            {
+              array_push($field_clauses, $field." LIKE '%".$word."%'");
+            }
+            // adds brackets around where clauses
+            array_push($word_clauses, implode(' OR ', $field_clauses));
+          }
+          array_walk($word_clauses, create_function('&$s','$s="(".$s.")";'));
+          array_push($clauses,
+                     implode(' '.$search['fields']['allwords']['mode'].' ',
+                               $word_clauses));
+        }
+
+        $datefields = array('date_available', 'date_creation');
+        foreach ($datefields as $datefield)
+        {
+          $key = $datefield;
+          if (isset($search['fields'][$key]))
+          {
+            $local_clause = $datefield." = '";
+            $local_clause.= str_replace('.', '-',
+                                        $search['fields'][$key]['words'][0]);
+            $local_clause.= "'";
+            array_push($clauses, $local_clause);
+          }
+
+          foreach (array('after','before') as $suffix)
+          {
+            $key = $datefield.'-'.$suffix;
+            if (isset($search['fields'][$key]))
+            {
+              $local_clause = $datefield;
+              if ($suffix == 'after')
+              {
+                $local_clause.= ' >';
+              }
+              else
+              {
+                $local_clause.= ' <';
+              }
+              if (isset($search['fields'][$key]['mode'])
+                  and $search['fields'][$key]['mode'] == 'inc')
+              {
+                $local_clause.= '=';
+              }
+              $local_clause.= " '";
+              $local_clause.= str_replace('.', '-',
+                                          $search['fields'][$key]['words'][0]);
+              $local_clause.= "'";
+              array_push($clauses, $local_clause);
+            }
+          }
+        }
+
+        if (isset($search['fields']['cat']))
+        {
+          if ($search['fields']['cat']['mode'] == 'sub_inc')
+          {
+            // searching all the categories id of sub-categories
+            $cat_ids = get_subcat_ids($search['fields']['cat']['words']);
+          }
+          else
+          {
+            $cat_ids = $search['fields']['cat']['words'];
+          }
+          
+          $local_clause = 'category_id IN ('.implode(',', $cat_ids).')';
+          array_push($clauses, $local_clause);
+        }
+
+        // adds brackets around where clauses
+        array_walk($clauses, create_function('&$s', '$s = "(".$s.")";'));
+        $page['where'] = 'WHERE '.implode(' '.$search['mode'].' ', $clauses);
+        if ( isset( $forbidden ) ) $page['where'].= ' AND '.$forbidden;
+
+        $query = '
+SELECT COUNT(DISTINCT(id)) AS nb_total_images
+  FROM '.IMAGES_TABLE.'
+    INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id
+  '.$page['where'].'
+;';
+        $url.= '&amp;search='.$_GET['search'];
+      }
+      // favorites displaying
+      else if ( $page['cat'] == 'fav' )
+      {
+        check_user_favorites();
+        
+        $page['title'] = $lang['favorites'];
+
+        $page['where'] = ', '.FAVORITES_TABLE.' AS fav';
+        $page['where'].= ' WHERE user_id = '.$user['id'];
+        $page['where'].= ' AND fav.image_id = id';
+      
+        $query = 'SELECT COUNT(*) AS nb_total_images';
+        $query.= ' FROM '.FAVORITES_TABLE;
+        $query.= ' WHERE user_id = '.$user['id'];
+        $query.= ';';
+      }
+      // pictures within the short period
+      else if ( $page['cat'] == 'recent_pics' )
+      {
+        $page['title'] = $lang['recent_pics_cat'];
+        // We must find the date corresponding to :
+        // today - $conf['periode_courte']
+        $date = time() - 60*60*24*$user['recent_period'];
+        $page['where'] = " WHERE date_available > '";
+        $page['where'].= date( 'Y-m-d', $date )."'";
+        if ( isset( $forbidden ) ) $page['where'].= ' AND '.$forbidden;
+
+        $query = '
+SELECT COUNT(DISTINCT(id)) AS nb_total_images
+  FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic
+    ON id = ic.image_id
+  '.$page['where'].'
+;';
+      }
+      // categories containing recent pictures
+      else if ( $page['cat'] == 'recent_cats' )
+      {
+        $page['title'] = $lang['recent_cats_cat'];
+        $page['cat_nb_images'] = 0;
+      }
+      // most visited pictures
+      else if ( $page['cat'] == 'most_visited' )
+      {
+        $page['title'] = $conf['top_number'].' '.$lang['most_visited_cat'];
+
+        $page['where'] = 'WHERE hit > 0';
+        if (isset($forbidden))
+        {
+          $page['where'] = "\n".'    AND '.$forbidden;
+        }
+
+        $conf['order_by'] = ' ORDER BY hit DESC, file ASC';
+
+        // $page['cat_nb_images'] equals $conf['top_number'] unless there
+        // are less visited items
+        $query ='
+SELECT COUNT(DISTINCT(id)) AS count
+  FROM '.IMAGES_TABLE.'
+    INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id
+  '.$page['where'].'
+;';
+        $row = mysql_fetch_array(pwg_query($query));
+        if ($row['count'] < $conf['top_number'])
+        {
+          $page['cat_nb_images'] = $row['count'];
+        }
+        else
+        {
+          $page['cat_nb_images'] = $conf['top_number'];
+        }
+        unset($query);
+        
+        if ( isset( $page['start'] )
+             and ($page['start']+$user['nb_image_page']>=$conf['top_number']))
+        {
+          $page['nb_image_page'] = $conf['top_number'] - $page['start'];
+        }
+      }
+      else if ( $page['cat'] == 'calendar' )
+      {
+        $page['cat_nb_images'] = 0;
+        $page['title'] = $lang['calendar'];
+        if (isset($_GET['year'])
+            and preg_match('/^\d+$/', $_GET['year']))
+        {
+          $page['calendar_year'] = (int)$_GET['year'];
+        }
+        if (isset($_GET['month'])
+            and preg_match('/^(\d+)\.(\d{2})$/', $_GET['month'], $matches))
+        {
+          $page['calendar_year'] = (int)$matches[1];
+          $page['calendar_month'] = (int)$matches[2];
+        }
+        if (isset($_GET['day'])
+            and preg_match('/^(\d+)\.(\d{2})\.(\d{2})$/',
+                           $_GET['day'],
+                           $matches))
+        {
+          $page['calendar_year'] = (int)$matches[1];
+          $page['calendar_month'] = (int)$matches[2];
+          $page['calendar_day'] = (int)$matches[3];
+        }
+        if (isset($page['calendar_year']))
+        {
+          $page['title'] .= ' (';
+          if (isset($page['calendar_day']))
+          {
+            if ($page['calendar_year'] >= 1970)
+            {
+              $unixdate = mktime(0,0,0,
+                                 $page['calendar_month'],
+                                 $page['calendar_day'],
+                                 $page['calendar_year']);
+              $page['title'].= $lang['day'][date("w", $unixdate)];
+            }
+            $page['title'].= ' '.$page['calendar_day'].', ';
+          }
+          if (isset($page['calendar_month']))
+          {
+            $page['title'] .= $lang['month'][$page['calendar_month']].' ';
+          }
+          $page['title'] .= $page['calendar_year'];
+          $page['title'] .= ')';
+        }
+        
+        $page['where'] = 'WHERE '.$conf['calendar_datefield'].' IS NOT NULL';
+        if (isset($forbidden))
+        {
+          $page['where'].= ' AND '.$forbidden;
+        }
+      }
+      else if ($page['cat'] == 'best_rated')
+      {
+        $page['title'] = $conf['top_number'].' '.$lang['best_rated_cat'];
+
+        $page['where'] = ' WHERE average_rate IS NOT NULL';
+        
+        if (isset($forbidden))
+        {
+          $page['where'].= ' AND '.$forbidden;
+        }
+
+        $conf['order_by'] = ' ORDER BY average_rate DESC, id ASC';
+
+        // $page['cat_nb_images'] equals $conf['top_number'] unless there
+        // are less rated items
+        $query ='
+SELECT COUNT(DISTINCT(id)) AS count
+  FROM '.IMAGES_TABLE.'
+    INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id
+  '.$page['where'].'
+;';
+        $row = mysql_fetch_array(pwg_query($query));
+        if ($row['count'] < $conf['top_number'])
+        {
+          $page['cat_nb_images'] = $row['count'];
+        }
+        else
+        {
+          $page['cat_nb_images'] = $conf['top_number'];
+        }
+        unset($query);
+          
+
+        if (isset($page['start'])
+            and ($page['start']+$user['nb_image_page']>=$conf['top_number']))
+        {
+          $page['nb_image_page'] = $conf['top_number'] - $page['start'];
+        }
+      }
+      else if ($page['cat'] == 'list')
+      {
+        $page['title'] = $lang['random_cat'];
+          
+        $page['where'] = 'WHERE 1=1';
+        if (isset($forbidden))
+        {
+          $page['where'].= ' AND '.$forbidden;
+        }
+        $page['where'].= ' AND image_id IN ('.$_GET['list'].')';
+        $page['cat_nb_images'] = count(explode(',', $_GET['list']));
+
+        $url.= '&amp;list='.$_GET['list'];
+      }
+
+      if (isset($query))
+      {
+        $result = pwg_query( $query );
+        $row = mysql_fetch_array( $result );
+        $page['cat_nb_images'] = $row['nb_total_images'];
+      }
+    }
+    if ( $calling_page == 'category' )
+    {
+      $page['navigation_bar'] =
+        create_navigation_bar( $url, $page['cat_nb_images'], $page['start'],
+                               $user['nb_image_page'], 'back' );
+    }
+  }
+  else
+  {
+    $page['title'] = $lang['no_category'];
+  }
+  pwg_debug( 'end initialize_category' );
+}
+
+function display_select_categories($categories,
+                                   $selecteds,
+                                   $blockname,
+                                   $fullname = true)
+{
+  global $template;
+
+  foreach ($categories as $category)
+  {
+    $selected = '';
+    if (in_array($category['id'], $selecteds))
+    {
+      $selected = ' selected="selected"';
+    }
+
+    if ($fullname)
+    {
+      $option = get_cat_display_name_cache($category['uppercats'],
+                                           '',
+                                           false);
+    }
+    else
+    {
+      $option = str_repeat('&nbsp;',
+                           (3 * substr_count($category['global_rank'], '.')));
+      $option.= '- '.$category['name'];
+    }
+    
+    $template->assign_block_vars(
+      $blockname,
+      array('SELECTED'=>$selected,
+            'VALUE'=>$category['id'],
+            'OPTION'=>$option
+        ));
+  }
+}
+
+function display_select_cat_wrapper($query, $selecteds, $blockname,
+                                    $fullname = true)
+{
+  $result = pwg_query($query);
+  $categories = array();
+  if (!empty($result))
+  {
+    while ($row = mysql_fetch_array($result))
+    {
+      array_push($categories, $row);
+    }
+  }
+  usort($categories, 'global_rank_compare');
+  display_select_categories($categories, $selecteds, $blockname, $fullname);
+}
+
+/**
+ * returns all subcategory identifiers of given category ids
+ *
+ * @param array ids
+ * @return array
+ */
+function get_subcat_ids($ids)
+{
+  $query = '
+SELECT DISTINCT(id)
+  FROM '.CATEGORIES_TABLE.'
+  WHERE ';
+  foreach ($ids as $num => $category_id)
+  {
+    if ($num > 0)
+    {
+      $query.= '
+    OR ';
+    }
+    $query.= 'uppercats REGEXP \'(^|,)'.$category_id.'(,|$)\'';
+  }
+  $query.= '
+;';
+  $result = pwg_query($query);
+
+  $subcats = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($subcats, $row['id']);
+  }
+  return $subcats;
+}
+
+function global_rank_compare($a, $b)
+{
+  return strnatcasecmp($a['global_rank'], $b['global_rank']);
+}
+?>
Index: /branches/1.4/include/functions_group.inc.php
===================================================================
--- /branches/1.4/include/functions_group.inc.php	(revision 3249)
+++ /branches/1.4/include/functions_group.inc.php	(revision 3249)
@@ -0,0 +1,109 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// get_group_restrictions returns an array containing all unaccessible
+// category ids.
+function get_group_restrictions( $group_id )
+{
+  // 1. retrieving ids of private categories
+  $query = 'SELECT id FROM '.CATEGORIES_TABLE;
+  $query.= " WHERE status = 'private'";
+  $query.= ';';
+  $result = pwg_query( $query );
+  $privates = array();
+  while ( $row = mysql_fetch_array( $result ) )
+  {
+    array_push( $privates, $row['id'] );
+  }
+  // 2. retrieving all authorized categories for the group
+  $authorized = array();
+  $query = 'SELECT cat_id FROM '.GROUP_ACCESS_TABLE;
+  $query.= ' WHERE group_id = '.$group_id;
+  $query.= ';';
+  $result = pwg_query( $query );
+  while ( $row = mysql_fetch_array( $result ) )
+  {
+    array_push( $authorized, $row['cat_id'] );
+  }
+
+  $forbidden = array();
+  foreach ( $privates as $private ) {
+    if ( !in_array( $private, $authorized ) )
+    {
+      array_push( $forbidden, $private );
+    }
+  }
+
+  return $forbidden;
+}
+
+// get_all_group_restrictions returns an array with ALL unaccessible
+// category ids, including sub-categories
+function get_all_group_restrictions( $group_id )
+{
+  $restricted_cats = get_group_restrictions( $group_id );
+  foreach ( $restricted_cats as $restricted_cat ) {
+    $sub_restricted_cats = get_subcats_id( $restricted_cat );
+    foreach ( $sub_restricted_cats as $sub_restricted_cat ) {
+      array_push( $restricted_cats, $sub_restricted_cat );
+    }
+  }
+  return $restricted_cats;
+}
+
+// The function is_group_allowed returns :
+//      - 0 : if the category is allowed with this $restrictions array
+//      - 1 : if this category is not allowed
+//      - 2 : if an uppercat category is not allowed
+function is_group_allowed( $category_id, $restrictions )
+{
+  $lowest_category_id = $category_id;
+                
+  $is_root = false;
+  while ( !$is_root and !in_array( $category_id, $restrictions ) )
+  {
+    $query = 'SELECT id_uppercat FROM '.CATEGORIES_TABLE;
+    $query.= ' WHERE id = '.$category_id;
+    $query.= ';';
+    $row = mysql_fetch_array( pwg_query( $query ) );
+    if ( !isset( $row['id_uppercat'] ) ) $row['id_uppercat'] = '';
+    if ( $row['id_uppercat'] == '' ) $is_root = true;
+    $category_id = $row['id_uppercat'];
+  }
+                
+  if ( in_array( $lowest_category_id, $restrictions ) )
+  {
+    return 1;
+  }
+  if ( in_array( $category_id, $restrictions ) )
+  {
+    return 2;
+  }
+  // this group is allowed to go in this category
+  return 0;
+}
+?>
Index: /branches/1.4/include/functions_html.inc.php
===================================================================
--- /branches/1.4/include/functions_html.inc.php	(revision 3249)
+++ /branches/1.4/include/functions_html.inc.php	(revision 3249)
@@ -0,0 +1,451 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+function get_icon( $date )
+{
+  global $user, $conf, $lang;
+
+  if (!preg_match('/\d{4}-\d{2}-\d{2}/', $date))
+  {
+    return '';
+  }
+
+  list( $year,$month,$day ) = explode( '-', $date );
+  $unixtime = mktime( 0, 0, 0, $month, $day, $year );
+  
+  $diff = time() - $unixtime;
+  $day_in_seconds = 24*60*60;
+  $output = '';
+  $title = $lang['recent_image'].'&nbsp;';
+  if ( $diff < $user['recent_period'] * $day_in_seconds )
+  {
+    $icon_url = './template/'.$user['template'].'/theme/';
+    $icon_url.= 'recent.gif';
+    $title .= $user['recent_period'];
+    $title .=  '&nbsp;'.$lang['days'];
+    $size = getimagesize( $icon_url );
+    $output = '<img title="'.$title.'" src="'.$icon_url.'" style="border:0;';
+    $output.= 'height:'.$size[1].'px;width:'.$size[0].'px" alt="" />';
+  }
+  return $output;
+}
+
+function create_navigation_bar($url, $nb_element, $start,
+                               $nb_element_page, $link_class)
+{
+  global $lang, $conf;
+
+  $pages_around = $conf['paginate_pages_around'];
+  
+  $navbar = '';
+  
+  // current page detection
+  if (!isset($start)
+      or !is_numeric($start)
+      or (is_numeric($start) and $start < 0))
+  {
+    $start = 0;
+  }
+  
+  // navigation bar useful only if more than one page to display !
+  if ($nb_element > $nb_element_page)
+  {
+    // current page and last page
+    $cur_page = ceil($start / $nb_element_page) + 1;
+    $maximum = ceil($nb_element / $nb_element_page);
+
+    // link to first page ?
+    if ($cur_page != 1)
+    {
+      $navbar.= '<a href="';
+      $navbar.= add_session_id($url.'&amp;start=0');
+      $navbar.= '" class="'.$link_class.'">'.$lang['first_page'];
+      $navbar.= '</a>';
+    }
+    else
+    {
+      $navbar.= $lang['first_page'];
+    }
+    $navbar.= ' | ';
+    // link on previous page ?
+    if ( $start != 0 )
+    {
+      $previous = $start - $nb_element_page;
+      $navbar.= '<a href="';
+      $navbar.= add_session_id( $url.'&amp;start='.$previous );
+      $navbar.= '" class="'.$link_class.'">'.$lang['previous_page'];
+      $navbar.= '</a>';
+    }
+    else
+    {
+      $navbar.= $lang['previous_page'];
+    }
+    $navbar.= ' | ';
+
+    if ($cur_page > $pages_around + 1)
+    {
+      $navbar.= '&nbsp;<a href="';
+      $navbar.= add_session_id($url.'&amp;start=0');
+      $navbar.= '" class="'.$link_class.'">1</a>';
+      if ($cur_page > $pages_around + 2)
+      {
+        $navbar.= ' ...';
+      }
+    }
+    
+    // inspired from punbb source code
+    for ($i = $cur_page - $pages_around, $stop = $cur_page + $pages_around + 1;
+         $i < $stop;
+         $i++)
+    {
+      if ($i < 1 or $i > $maximum)
+      {
+        continue;
+      }
+      else if ($i != $cur_page)
+      {
+        $temp_start = ($i - 1) * $nb_element_page;
+        $navbar.= '&nbsp;<a href="';
+        $navbar.= add_session_id($url.'&amp;start='.$temp_start);
+        $navbar.= '" class="'.$link_class.'">'.$i.'</a>';
+      }
+      else
+      {
+        $navbar.= '&nbsp;<span class="pageNumberSelected">';
+        $navbar.= $i.'</span>';
+      }
+    }
+
+    if ($cur_page < ($maximum - $pages_around))
+    {
+      $temp_start = ($maximum - 1) * $nb_element_page;
+      if ($cur_page < ($maximum - $pages_around - 1))
+      {
+        $navbar.= ' ...';
+      }
+      $navbar.= ' <a href="';
+      $navbar.= add_session_id($url.'&amp;start='.$temp_start);
+      $navbar.= '" class="'.$link_class.'">'.$maximum.'</a>';
+    }
+    
+    $navbar.= ' | ';
+    // link on next page ?
+    if ( $nb_element > $nb_element_page
+         && $start + $nb_element_page < $nb_element )
+    {
+      $next = $start + $nb_element_page;
+      $navbar.= '<a href="';
+      $navbar.= add_session_id( $url.'&amp;start='.$next );
+      $navbar.= '" class="'.$link_class.'">'.$lang['next_page'].'</a>';
+    }
+    else
+    {
+      $navbar.= $lang['next_page'];
+    }
+    
+    $navbar.= ' | ';
+    // link to last page ?
+    if ($cur_page != $maximum)
+    {
+      $temp_start = ($maximum - 1) * $nb_element_page;
+      $navbar.= '<a href="';
+      $navbar.= add_session_id($url.'&amp;start='.$temp_start);
+      $navbar.= '" class="'.$link_class.'">'.$lang['last_page'];
+      $navbar.= '</a>';
+    }
+    else
+    {
+      $navbar.= $lang['last_page'];
+    }
+  }
+  return $navbar;
+}
+
+//
+// Pick a language, any language ...
+//
+function language_select($default, $select_name = "language")
+{
+  $available_lang = get_languages();
+
+  $lang_select = '<select name="' . $select_name . '" onchange="this.form.submit()">';
+  foreach ($available_lang as $code => $displayname)
+  {
+    $selected = ( strtolower($default) == strtolower($code) ) ? ' selected="selected"' : '';
+    $lang_select .= '<option value="' . $code . '"' . $selected . '>' . ucwords($displayname) . '</option>';
+  }
+  $lang_select .= '</select>';
+
+  return $lang_select;
+}
+
+//
+// Pick a template/theme combo, 
+//
+function style_select($default_style, $select_name = "style")
+{
+  $templates = get_templates();
+
+  $style_selected = '<select name="' . $select_name . '" >';
+  foreach ($templates as $template)
+  {
+    $selected = ( $template == $default_style ) ? ' selected="selected"' : '';
+    $style_selected.= '<option value="'.$template.'"'.$selected.'>';
+    $style_selected.= $template.'</option>';
+  }
+  $style_selected .= '</select>';
+  return $style_selected;
+}
+
+/**
+ * returns the list of categories as a HTML string
+ *
+ * categories string returned contains categories as given in the input
+ * array $cat_informations. $cat_informations array must be an association
+ * of {category_id => category_name}. If url input parameter is empty,
+ * returns only the categories name without links.
+ *
+ * @param array cat_informations
+ * @param string url
+ * @param boolean replace_space
+ * @return string
+ */
+function get_cat_display_name($cat_informations,
+                              $url = 'category.php?cat=',
+                              $replace_space = true)
+{
+  global $conf;
+  
+  $output = '';
+  $is_first = true;
+  foreach ($cat_informations as $id => $name)
+  {
+    if ($is_first)
+    {
+      $is_first = false;
+    }
+    else
+    {
+      $output.= $conf['level_separator'];
+    }
+
+    if ($url == '')
+    {
+      $output.= $name;
+    }
+    else
+    {
+      $output.= '
+<a class="" href="'.add_session_id(PHPWG_ROOT_PATH.$url.$id).'">'.$name.'</a>';
+    }
+  }
+  if ($replace_space)
+  {
+    return replace_space($output);
+  }
+  else
+  {
+    return $output;
+  }
+}
+
+/**
+ * returns the list of categories as a HTML string, with cache of names
+ *
+ * categories string returned contains categories as given in the input
+ * array $cat_informations. $uppercats is the list of category ids to
+ * display in the right order. If url input parameter is empty, returns only
+ * the categories name without links.
+ *
+ * @param string uppercats
+ * @param string url
+ * @param boolean replace_space
+ * @return string
+ */
+function get_cat_display_name_cache($uppercats,
+                                    $url = 'category.php?cat=',
+                                    $replace_space = true)
+{
+  global $cat_names, $conf;
+
+  if (!isset($cat_names))
+  {
+    $query = '
+SELECT id,name
+  FROM '.CATEGORIES_TABLE.'
+;';
+    $result = pwg_query($query);
+    while ($row = mysql_fetch_array($result))
+    {
+      $cat_names[$row['id']] = $row['name'];
+    }
+  }
+  
+  $output = '';
+  $is_first = true;
+  foreach (explode(',', $uppercats) as $category_id)
+  {
+    $name = $cat_names[$category_id];
+    
+    if ($is_first)
+    {
+      $is_first = false;
+    }
+    else
+    {
+      $output.= $conf['level_separator'];
+    }
+
+    if ($url == '')
+    {
+      $output.= $name;
+    }
+    else
+    {
+      $output.= '
+<a class=""
+   href="'.add_session_id(PHPWG_ROOT_PATH.$url.$category_id).'">'.$name.'</a>';
+    }
+  }
+  if ($replace_space)
+  {
+    return replace_space($output);
+  }
+  else
+  {
+    return $output;
+  }
+}
+
+/**
+ * returns the HTML code for a category item in the menu (for category.php)
+ *
+ * HTML code generated uses logical list tags ul and each category is an
+ * item li. The paramter given is the category informations as an array,
+ * used keys are : id, name, nb_images, date_last
+ *
+ * @param array categories
+ * @return string
+ */
+function get_html_menu_category($categories)
+{
+  global $page, $lang;
+
+  $ref_level = 0;
+  $menu = '
+             <ul class="menu">';
+  
+  foreach ($categories as $category)
+  {
+    $level = substr_count($category['global_rank'], '.');
+    if ($level > $ref_level)
+    {
+      $menu.= '
+             <ul class="menu">';
+    }
+    else if ($level < $ref_level)
+    {
+      // we may have to close more than one level at the same time...
+      $menu.= str_repeat("\n</ul>",($ref_level-$level));
+    }
+    $ref_level = $level;
+    
+    $menu.= '
+
+           <li>';
+  
+    $url = add_session_id(PHPWG_ROOT_PATH.'category.php?cat='.$category['id']);
+
+    $class = '';
+    if (isset($page['cat'])
+        and is_numeric($page['cat'])
+        and $category['id'] == $page['cat'])
+    {
+      $class = 'menuCategorySelected';
+    }
+    else
+    {
+      $class = 'menuCategoryNotSelected';
+    }
+
+    $menu.= '
+           <a href="'.$url.'"
+              title="'.$lang['hint_category'].'"
+              class="'.$class.'">
+             '.$category['name'].'
+           </a>';
+
+    if ($category['nb_images'] > 0)
+    {
+      $menu.= '
+             <span class="menuInfoCat"
+                   title="'.$category['nb_images'].' '.$lang['images_available'].'">
+             ['.$category['nb_images'].']
+             </span>
+             '.get_icon($category['date_last']);
+    }
+
+    $menu.= '</li>';
+  }
+  
+  $menu.= '
+             </ul>';
+  
+  return $menu;
+}
+
+/**
+ * returns HTMLized comment contents retrieved from database
+ *
+ * newlines becomes br tags, _word_ becomes underline, /word/ becomes
+ * italic, *word* becomes bolded
+ *
+ * @param string content
+ * @return string
+ */
+function parse_comment_content($content)
+{
+  $content = nl2br($content);
+  
+  // replace _word_ by an underlined word
+  $pattern = '/_([^\s]*)_/';
+  $replacement = '<span style="text-decoration:underline;">\1</span>';
+  $content = preg_replace($pattern, $replacement, $content);
+  
+  // replace *word* by a bolded word
+  $pattern = '/\*([^\s]*)\*/';
+  $replacement = '<span style="font-weight:bold;">\1</span>';
+  $content = preg_replace($pattern, $replacement, $content);
+  
+  // replace /word/ by an italic word
+  $pattern = '/\/([^\s]*)\//';
+  $replacement = '<span style="font-style:italic;">\1</span>';
+  $content = preg_replace($pattern, $replacement, $content);
+
+  return $content;
+}
+?>
Index: /branches/1.4/include/functions_metadata.inc.php
===================================================================
--- /branches/1.4/include/functions_metadata.inc.php	(revision 3249)
+++ /branches/1.4/include/functions_metadata.inc.php	(revision 3249)
@@ -0,0 +1,94 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+/**
+ * returns informations from IPTC metadata, mapping is done at the beginning
+ * of the function
+ *
+ * @param string $filename
+ * @return array
+ */
+function get_iptc_data($filename, $map)
+{
+  $result = array();
+  
+  // Read IPTC data
+  $iptc = array();
+  
+  $imginfo = array();
+  getimagesize($filename, $imginfo);
+  
+  if (isset($imginfo['APP13']))
+  {
+    $iptc = iptcparse($imginfo['APP13']);
+    if (is_array($iptc))
+    {
+      $rmap = array_flip($map);
+      foreach (array_keys($rmap) as $iptc_key)
+      {
+        if (isset($iptc[$iptc_key][0]))
+        {
+          if ($iptc_key == '2#025')
+          {
+            $value = implode(',',
+                             array_map('clean_iptc_value',$iptc[$iptc_key]));
+          }
+          else
+          {
+            $value = clean_iptc_value($iptc[$iptc_key][0]);
+          }
+
+          foreach (array_keys($map, $iptc_key) as $pwg_key)
+          {
+            $result[$pwg_key] = $value;
+          }
+        }
+      }
+    }
+  }
+  return $result;
+}
+
+/**
+ * return a cleaned IPTC value
+ *
+ * @param string value
+ * @return string
+ */
+function clean_iptc_value($value)
+{
+  // strip leading zeros (weird Kodak Scanner software)
+  while ($value[0] == chr(0))
+  {
+    $value = substr($value, 1);
+  }
+  // remove binary nulls
+  $value = str_replace(chr(0x00), ' ', $value);
+  
+  return $value;
+}
+?>
Index: /branches/1.4/include/functions_session.inc.php
===================================================================
--- /branches/1.4/include/functions_session.inc.php	(revision 3249)
+++ /branches/1.4/include/functions_session.inc.php	(revision 3249)
@@ -0,0 +1,144 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// The function generate_key creates a string with pseudo random characters.
+// the size of the string depends on the $conf['session_id_size'].
+// Characters used are a-z A-Z and numerical values. Examples :
+//                    "Er4Tgh6", "Rrp08P", "54gj"
+// input  : none (using global variable)
+// output : $key
+function generate_key($size)
+{
+  global $conf;
+
+  $md5 = md5(substr(microtime(), 2, 6));
+  $init = '';
+  for ( $i = 0; $i < strlen( $md5 ); $i++ )
+  {
+    if ( is_numeric( $md5[$i] ) ) $init.= $md5[$i];
+  }
+  $init = substr( $init, 0, 8 );
+  mt_srand( $init );
+  $key = '';
+  for ( $i = 0; $i < $size; $i++ )
+  {
+    $c = mt_rand( 0, 2 );
+    if ( $c == 0 )      $key .= chr( mt_rand( 65, 90 ) );
+    else if ( $c == 1 ) $key .= chr( mt_rand( 97, 122 ) );
+    else                $key .= mt_rand( 0, 9 );
+  }
+  return $key;
+}
+
+/**
+ * create a new session and returns the session identifier
+ *
+ * - find a non-already-used session key
+ * - create a session in database
+ * - return session identifier
+ *
+ * @param int userid
+ * @param int session_lentgh : in seconds
+ * @return string
+ */
+function session_create($userid, $session_length)
+{
+  global $conf;
+
+  // 1. searching an unused session key
+  $id_found = false;
+  while (!$id_found)
+  {
+    $generated_id = generate_key($conf['session_id_size']);
+    $query = '
+SELECT id
+  FROM '.SESSIONS_TABLE.'
+  WHERE id = \''.$generated_id.'\'
+;';
+    $result = pwg_query($query);
+    if (mysql_num_rows($result) == 0)
+    {
+      $id_found = true;
+    }
+  }
+  // 3. inserting session in database
+  $query = '
+INSERT INTO '.SESSIONS_TABLE.'
+  (id,user_id,expiration)
+  VALUES
+  (\''.$generated_id.'\','.$userid.',
+   ADDDATE(NOW(), INTERVAL '.$session_length.' SECOND))
+;';
+  pwg_query($query);
+
+  $expiration = $session_length + time();
+  setcookie('id', $generated_id, $expiration, cookie_path());
+                
+  return $generated_id;
+}
+
+// add_session_id adds the id of the session to the string given in
+// parameter as $url. If the session id is the first parameter to the url,
+// it is preceded by a '?', else it is preceded by a '&amp;'. If the
+// parameter $redirect is set to true, '&' is used instead of '&'.
+function add_session_id( $url, $redirect = false )
+{
+  global $page, $user;
+
+  if ( $user['has_cookie'] ) return $url;
+
+  $amp = '&amp;';
+  if ( $redirect )
+  {
+    $amp = '&';
+  }
+  if ( !$user['is_the_guest'] )
+  {
+    if ( preg_match( '/\.php\?/',$url ) )
+    {
+      return $url.$amp.'id='.$page['session_id'];
+    }
+    else
+    {
+      return $url.'?id='.$page['session_id'];
+    }
+  }
+  else
+  {
+    return $url;
+  }
+}
+
+// cookie_path returns the path to use for the PhpWebGallery cookie.
+// If PhpWebGallery is installed on :
+// http://domain.org/meeting/gallery/category.php
+// cookie_path will return : "/meeting/gallery"
+function cookie_path()
+{
+  return substr($_SERVER['PHP_SELF'],0,strrpos( $_SERVER['PHP_SELF'],'/'));
+}
+?>
Index: /branches/1.4/include/functions_user.inc.php
===================================================================
--- /branches/1.4/include/functions_user.inc.php	(revision 3249)
+++ /branches/1.4/include/functions_user.inc.php	(revision 3249)
@@ -0,0 +1,398 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// validate_mail_address verifies whether the given mail address has the
+// right format. ie someone@domain.com "someone" can contain ".", "-" or
+// even "_". Exactly as "domain". The extension doesn't have to be
+// "com". The mail address can also be empty.
+// If the mail address doesn't correspond, an error message is returned.
+function validate_mail_address( $mail_address )
+{
+  global $lang;
+
+  if ( $mail_address == '' )
+  {
+    return '';
+  }
+  $regex = '/^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)*\.[a-z]+$/';
+  if ( !preg_match( $regex, $mail_address ) )
+  {
+    return $lang['reg_err_mail_address'];
+  }
+}
+
+function register_user($login, $password, $password_conf,
+                       $mail_address, $status = 'guest')
+{
+  global $lang, $conf;
+
+  $errors = array();
+  // login must not
+  //      1. be empty
+  //      2. start ou end with space character
+  //      3. include ' or " characters
+  //      4. be already used
+  if ($login == '')
+  {
+    array_push($errors, $lang['reg_err_login1']);
+  }
+  if (ereg("^.* $", $login))
+  {
+    array_push($errors, $lang['reg_err_login2']);
+  }
+  if (ereg("^ .*$", $login))
+  {
+    array_push($errors, $lang['reg_err_login3']);
+  }
+
+  if (ereg("'", $login) or ereg("\"", $login))
+  {
+    array_push($errors, $lang['reg_err_login4']);
+  }
+  else
+  {
+    $query = '
+SELECT id
+  FROM '.USERS_TABLE.'
+  WHERE username = \''.$login.'\'
+;';
+    $result = pwg_query($query);
+    if (mysql_num_rows($result) > 0)
+    {
+      array_push($errors, $lang['reg_err_login5']);
+    }
+  }
+  // given password must be the same as the confirmation
+  if ($password != $password_conf)
+  {
+    array_push($errors, $lang['reg_err_pass']);
+  }
+
+  $error_mail_address = validate_mail_address($mail_address);
+  if ($error_mail_address != '')
+  {
+    array_push($errors, $error_mail_address);
+  }
+
+  // if no error until here, registration of the user
+  if (count($errors) == 0)
+  {
+    $insert = array();
+    $insert['username'] = $login;
+    $insert['password'] = md5($password);
+    $insert['status'] = $status;
+    $insert['template'] = $conf['default_template'];
+    $insert['nb_image_line'] = $conf['nb_image_line'];
+    $insert['nb_line_page'] = $conf['nb_line_page'];
+    $insert['language'] = $conf['default_language'];
+    $insert['recent_period'] = $conf['recent_period'];
+    $insert['expand'] = boolean_to_string($conf['auto_expand']);
+    $insert['show_nb_comments'] = boolean_to_string($conf['show_nb_comments']);
+    if ( $mail_address != '' )
+    {
+      $insert['mail_address'] = $mail_address;
+    }
+    if ($conf['default_maxwidth'] != '')
+    {
+      $insert['maxwidth'] = $conf['default_maxwidth'];
+    }
+    if ($conf['default_maxheight'] != '')
+    {
+      $insert['maxheight'] = $conf['default_maxheight'];
+    }
+
+    $query = '
+INSERT INTO '.USERS_TABLE.'
+  ('.implode(',', array_keys($insert)).')
+  VALUES
+  (';
+    $is_first = true;
+    foreach (array_keys($insert) as $field)
+    {
+      if (!$is_first)
+      {
+        $query.= ',';
+      }
+      $query.= "'".$insert[$field]."'";
+      $is_first = false;
+    }
+    $query.= ')
+;';
+    pwg_query($query);
+  }
+  return $errors;
+}
+
+function update_user( $user_id, $mail_address, $status,
+                      $use_new_password = false, $password = '' )
+{
+  $error = array();
+  $i = 0;
+  
+  $error_mail_address = validate_mail_address( $mail_address );
+  if ( $error_mail_address != '' )
+  {
+    $error[$i++] = $error_mail_address;
+  }
+
+  if ( sizeof( $error ) == 0 )
+  {
+    $query = 'UPDATE '.USERS_TABLE;
+    $query.= " SET status = '".$status."'";
+    if ( $use_new_password )
+    {
+      $query.= ", password = '".md5( $password )."'";
+    }
+    $query.= ', mail_address = ';
+    if ( $mail_address != '' )
+    {
+      $query.= "'".$mail_address."'";
+    }
+    else
+    {
+      $query.= 'NULL';
+    }
+    $query.= ' WHERE id = '.$user_id;
+    $query.= ';';
+    pwg_query( $query );
+  }
+  return $error;
+}
+
+function check_login_authorization($guest_allowed = true)
+{
+  global $user,$lang,$conf,$template;
+
+  if ($user['is_the_guest'] and !$guest_allowed)
+  {
+    echo '<div style="text-align:center;">'.$lang['only_members'].'<br />';
+    echo '<a href="./identification.php">'.$lang['ident_title'].'</a></div>';
+    exit();
+  }
+
+  if ($conf['gallery_locked'])
+  {
+    echo '<div style="text-align:center;">';
+    echo $lang['gallery_locked_message'];
+    echo '</div>';
+    if ($user['status'] != 'admin')
+    {
+      exit();
+    }
+  }
+}
+
+function setup_style($style)
+{
+  return new Template(PHPWG_ROOT_PATH.'template/'.$style);
+}
+
+function getuserdata($user)
+{
+  $sql = "SELECT * FROM " . USERS_TABLE;
+  $sql.= " WHERE ";
+  $sql .= ( ( is_integer($user) ) ? "id = $user" : "username = '" .  str_replace("\'", "''", $user) . "'" ) . " AND id <> " . ANONYMOUS;
+  $result = pwg_query($sql);
+  return ( $row = mysql_fetch_array($result) ) ? $row : false;
+}
+
+/*
+ * deletes favorites of the current user if he's not allowed to see them
+ *
+ * @return void
+ */
+function check_user_favorites()
+{
+  global $user;
+
+  if ($user['forbidden_categories'] == '')
+  {
+    return;
+  }
+
+  // retrieving images allowed : belonging to at least one authorized
+  // category
+  $query = '
+SELECT DISTINCT f.image_id
+  FROM '.FAVORITES_TABLE.' AS f INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic
+    ON f.image_id = ic.image_id
+  WHERE f.user_id = '.$user['id'].'
+    AND ic.category_id NOT IN ('.$user['forbidden_categories'].')
+;';
+  $result = pwg_query($query);
+  $authorizeds = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($authorizeds, $row['image_id']);
+  }
+
+  $query = '
+SELECT image_id
+  FROM '.FAVORITES_TABLE.'
+  WHERE user_id = '.$user['id'].'
+;';
+  $result = pwg_query($query);
+  $favorites = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($favorites, $row['image_id']);
+  }
+
+  $to_deletes = array_diff($favorites, $authorizeds);
+
+  if (count($to_deletes) > 0)
+  {
+    $query = '
+DELETE FROM '.FAVORITES_TABLE.'
+  WHERE image_id IN ('.implode(',', $to_deletes).')
+    AND user_id = '.$user['id'].'
+;';
+    pwg_query($query);
+  }
+}
+
+/**
+ * update table user_forbidden for the given user
+ *
+ * table user_forbidden contains calculated data. Calculation is based on
+ * private categories minus categories authorized to the groups the user
+ * belongs to minus the categories directly authorized to the user
+ *
+ * @param int user_id
+ * @param string user_status
+ * @return string forbidden_categories
+ */
+function calculate_permissions($user_id, $user_status)
+{
+  $private_array = array();
+  $authorized_array = array();
+
+  $query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE status = \'private\'
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($private_array, $row['id']);
+  }
+
+  // if user is not an admin, locked categories can be considered as private$
+  if ($user_status != 'admin')
+  {
+    $query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE visible = \'false\'
+;';
+    $result = pwg_query($query);
+    while ($row = mysql_fetch_array($result))
+    {
+      array_push($private_array, $row['id']);
+    }
+
+    $private_array = array_unique($private_array);
+  }
+  
+  // retrieve category ids directly authorized to the user
+  $query = '
+SELECT cat_id
+  FROM '.USER_ACCESS_TABLE.'
+  WHERE user_id = '.$user_id.'
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($authorized_array, $row['cat_id']);
+  }
+
+  // retrieve category ids authorized to the groups the user belongs to
+  $query = '
+SELECT cat_id
+  FROM '.USER_GROUP_TABLE.' AS ug INNER JOIN '.GROUP_ACCESS_TABLE.' AS ga
+    ON ug.group_id = ga.group_id
+  WHERE ug.user_id = '.$user_id.'
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($authorized_array, $row['cat_id']);
+  }
+
+  // uniquify ids : some private categories might be authorized for the
+  // groups and for the user
+  $authorized_array = array_unique($authorized_array);
+
+  // only unauthorized private categories are forbidden
+  $forbidden_array = array_diff($private_array, $authorized_array);
+
+  $query = '
+DELETE FROM '.USER_FORBIDDEN_TABLE.'
+  WHERE user_id = '.$user_id.'
+;';
+  pwg_query($query);
+
+  $forbidden_categories = implode(',', $forbidden_array);
+  
+  $query = '
+INSERT INTO '.USER_FORBIDDEN_TABLE.'
+  (user_id,need_update,forbidden_categories)
+  VALUES
+  ('.$user_id.',\'false\',\''.$forbidden_categories.'\')
+;';
+  pwg_query($query);
+  
+  return $forbidden_categories;
+}
+
+/**
+ * returns the username corresponding to the given user identifier if exists
+ *
+ * @param int user_id
+ * @return mixed
+ */
+function get_username($user_id)
+{
+  $query = '
+SELECT username
+  FROM '.USERS_TABLE.'
+  WHERE id = '.intval($user_id).'
+;';
+  $result = pwg_query($query);
+  if (mysql_num_rows($result) > 0)
+  {
+    list($username) = mysql_fetch_row($result);
+  }
+  else
+  {
+    return false;
+  }
+  
+  return $username;
+}
+?>
Index: /branches/1.4/include/functions_xml.inc.php
===================================================================
--- /branches/1.4/include/functions_xml.inc.php	(revision 3249)
+++ /branches/1.4/include/functions_xml.inc.php	(revision 3249)
@@ -0,0 +1,130 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+define( 'ATT_REG', '\w+' );
+define( 'VAL_REG', '[^"]*' );
+
+//------------------------------------------------------------------- functions
+// getContent returns the content of a tag
+//
+// example : getContent( "<name>Joe</name>" ) returns "Joe"
+//
+// It also works with strings containing themself sub-tags :
+// <perso><name>Jean</name><firstname>Billie</fisrtname></perso> ->
+// <name>Jean</name><firstname>Billie</firstname>
+function getContent( $element )
+{
+  // deleting start of the tag
+  $content = preg_replace( '/^<[^>]+>/', '', $element );
+  // deleting end of the tag
+  $content = preg_replace( '/<\/[^>]+>$/', '', $content );
+  // replacing multiple instance of space character
+  $content = preg_replace( '/\s+/', ' ', $content );
+
+  return $content;
+}
+
+// The function get Attribute returns the value corresponding to the
+// attribute $attribute for the tag $element.
+function getAttribute( $element, $attribute )
+{
+//  echo htmlentities($element).'<br /><br />';
+  $regex = '/^<\w+[^>]*'.$attribute.'\s*=\s*"('.VAL_REG.')"/i';
+  if ( preg_match( $regex, $element, $out ) ) return $out[1];
+  else return '';
+}
+
+function deprecated_getAttribute( $element, $attribute )
+{
+  // Retrieving string with tag name and all attributes
+  $regex = '/^<\w+( '.ATT_REG.'="'.VAL_REG.'")*/';
+  preg_match( $regex, $element, $out );
+
+  // Splitting string for retrieving separately attributes
+  // and corresponding values
+  $regex = '/('.ATT_REG.')="('.VAL_REG.')"/';
+  preg_match_all( $regex, $out[0], $out );
+
+  // Searching and returning the value of the requested attribute
+  for ( $i = 0; $i < sizeof( $out[0] ); $i++ )
+  {
+    if ( $out[1][$i] == $attribute )
+    {
+      return $out[2][$i];
+    }
+  }
+  return '';
+}
+	
+// The function getChild returns the first child
+// exemple : getChild( "<table><tr>XXX</tr><tr>YYY</tr></table>", "tr" )
+//           returns "<tr>XXX</tr>"
+function getChild( $document, $node )
+{
+  $regex = '/<'.$node.'(\s+'.ATT_REG.'="'.VAL_REG.'")*';
+  $regex.= '(\s*\/>|>.*<\/'.$node.'>)/U';
+
+  preg_match( $regex, $document, $out );
+  return $out[0];
+}
+
+// getChildren returns a list of the children identified by the $node
+// example : 
+//     getChild( "<table><tr>XXX</tr><tr>YYY</tr></table>", "tr" )
+//     returns an array with :
+//          $array[0] equals "<tr>XXX</tr>"
+//          $array[1] equals "<tr>YYY</tr>"
+function getChildren( $document, $node )
+{
+  $regex = '/<'.$node.'(\s+'.ATT_REG.'="'.VAL_REG.'")*';
+  $regex.= '(\s*\/>|>.*<\/'.$node.'>)/U';
+
+  preg_match_all( $regex, $document, $out );
+  return $out[0];
+}
+	
+// get_CodeXML places the content of a text file in a PHP variable and
+// return it. If the file can't be opened, returns false.
+function getXmlCode( $filename )
+{
+  $file = fopen( $filename, 'r' );
+  if ( !$file )
+  {
+    return false;
+  }
+
+  $xml_content = '';
+  while ( !feof( $file ) )
+  {
+    $xml_content .= fgets( $file, 1024 );
+  }
+  fclose( $file );
+  $xml_content = str_replace( "\n", '', $xml_content );
+  $xml_content = str_replace( "\t", '', $xml_content );
+
+  return $xml_content;
+}
+?>
Index: /branches/1.4/include/index.php
===================================================================
--- /branches/1.4/include/index.php	(revision 3249)
+++ /branches/1.4/include/index.php	(revision 3249)
@@ -0,0 +1,32 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+$url = '../category.php';
+header( 'Request-URI: '.$url );  
+header( 'Content-Location: '.$url );  
+header( 'Location: '.$url );
+exit();
+?>
Index: /branches/1.4/include/page_header.php
===================================================================
--- /branches/1.4/include/page_header.php	(revision 3249)
+++ /branches/1.4/include/page_header.php	(revision 3249)
@@ -0,0 +1,58 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+ 
+//
+// Start output of page
+//
+$template->set_filenames(array('header'=>'header.tpl'));
+
+$css = PHPWG_ROOT_PATH.'template/'.$user['template'];
+$css.= '/'.$user['template'].'.css';
+
+$template->assign_vars(
+  array(
+    'CONTENT_ENCODING' => $lang_info['charset'],
+    'PAGE_TITLE' => $title,
+    'LANG'=>$lang_info['code'],
+    'DIR'=>$lang_info['direction'],
+    
+    'T_STYLE' => $css
+    ));
+
+// refresh
+if ( isset( $refresh ) and intval($refresh) >= 0 and isset( $url_link ) )
+{
+  $template->assign_vars(
+    array(
+      'REFRESH_TIME' => $refresh,
+      'U_REFRESH' => add_session_id( $url_link )
+      ));
+  $template->assign_block_vars('refresh', array());
+}
+
+$template->parse('header');
+?>
Index: /branches/1.4/include/page_tail.php
===================================================================
--- /branches/1.4/include/page_tail.php	(revision 3249)
+++ /branches/1.4/include/page_tail.php	(revision 3249)
@@ -0,0 +1,66 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+$template->set_filenames(array('tail'=>'footer.tpl'));
+
+$template->assign_vars(
+  array(
+    'VERSION' => $conf['show_version'] ? PHPWG_VERSION : '',
+    'MAIL'=>$conf['mail_webmaster'],
+    
+    'L_GEN_TIME' => $lang['generation_time'],
+    'L_SQL_QUERIES_IN' => $lang['sql_queries_in'],
+    'L_SEND_MAIL' => $lang['send_mail'],
+    'L_TITLE_MAIL' => $lang['title_send_mail'],
+    'L_WEBMASTER'=>$lang['webmaster'],
+    'L_POWERED_BY'=>$lang['powered_by']
+    ));
+//------------------------------------------------------------- generation time
+if ($conf['show_gt'])
+{
+  $time = get_elapsed_time($t2, get_moment());
+
+  if (!isset($page['count_queries']))
+  {
+    $page['count_queries'] = 0;
+    $page['queries_time'] = 0;
+  }
+  
+  $template->assign_block_vars(
+    'debug',
+    array('TIME' => $time,
+          'NB_QUERIES' => $page['count_queries'],
+          'SQL_TIME' => number_format($page['queries_time'],3,'.',' ').' s'));
+}
+
+//
+// Generate the page
+//
+
+$template->parse('tail');
+
+$template->p();
+?>
Index: /branches/1.4/include/scripts.js
===================================================================
--- /branches/1.4/include/scripts.js	(revision 3249)
+++ /branches/1.4/include/scripts.js	(revision 3249)
@@ -0,0 +1,32 @@
+function SelectAll( formulaire )
+{
+len = formulaire.elements.length;
+var i=0;
+for( i = 0; i < len; i++)
+{
+  if ( formulaire.elements[i].type=='checkbox'
+	   && formulaire.elements[i].name != 'copie')
+  {
+	formulaire.elements[i].checked = true;
+  }
+}
+}
+
+function Inverser( formulaire )
+{
+len = formulaire.elements.length;
+var i=0;
+for( i=0; i<len; i++)
+{
+  if ( formulaire.elements[i].type=='checkbox'
+	   && formulaire.elements[i].name != 'copie')
+  {
+	formulaire.elements[i].checked = !formulaire.elements[i].checked;
+  }
+}
+}
+
+function phpWGOpenWindow(theURL,winName,features) 
+{
+  window.open(theURL,winName,features);
+}
Index: /branches/1.4/include/template.php
===================================================================
--- /branches/1.4/include/template.php	(revision 3249)
+++ /branches/1.4/include/template.php	(revision 3249)
@@ -0,0 +1,523 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+/**
+ * Template class. By Nathan Codding of the phpBB group. The interface was
+ * originally inspired by PHPLib templates, and the template file formats
+ * are quite similar.
+ */
+
+class Template {
+
+  var $classname = "Template";
+  
+  // variable that holds all the data we'll be substituting into
+  // the compiled templates.
+  // ...
+  // This will end up being a multi-dimensional array like this :
+  // $this->_tpldata[block.][iteration#][child.][iteration#][child2.][iteration#][variablename] == value
+  // if it's a root-level variable, it'll be like this:
+  // $this->_tpldata[.][0][varname] == value
+  var $_tpldata = array();
+  
+  // Hash of filenames for each template handle.
+  var $files = array();
+  
+  // Root template directory.
+  var $root = "";
+
+  // this will hash handle names to the compiled code for that handle.
+  var $compiled_code = array();
+  
+  // This will hold the uncompiled code for that handle.
+  var $uncompiled_code = array();
+
+  // output
+  var $output = '';
+  
+  /**
+   * Constructor. Simply sets the root dir.
+   *
+   */
+  function Template($root = ".")
+    {
+      $this->set_rootdir($root);
+    }
+  
+  /**
+   * Destroys this template object. Should be called when you're done with
+   * it, in order to clear out the template data so you can load/parse a new
+   * template set.
+   */
+  function destroy()
+    {
+      $this->_tpldata = array();
+    }
+
+  /**
+   * Sets the template root directory for this Template object.
+   */
+  function set_rootdir($dir)
+    {
+      if (!is_dir($dir))
+      {
+        return false;
+      }
+      
+      $this->root = $dir;
+      return true;
+    }
+  
+  /**
+   * Sets the template filenames for handles. $filename_array should be a
+   * hash of handle => filename pairs.
+   */
+  function set_filenames($filename_array)
+    {
+      if (!is_array($filename_array))
+      {
+        return false;
+      }
+      
+      reset($filename_array);
+      while(list($handle, $filename) = each($filename_array))
+      {
+        $this->files[$handle] = $this->make_filename($filename);
+      }
+      
+      return true;
+    }
+  
+  
+  /**
+   * Load the file for the handle, compile the file, and run the compiled
+   * code. This will print out the results of executing the template.
+   */
+  function pparse($handle)
+    {
+      if (!$this->loadfile($handle))
+      {
+        die("Template->pparse(): Couldn't load template file for handle $handle");
+      }
+      
+      // actually compile the template now.
+      if (!isset($this->compiled_code[$handle]) || empty($this->compiled_code[$handle]))
+      {
+        // Actually compile the code now.
+        $this->compiled_code[$handle] = $this->compile($this->uncompiled_code[$handle]);
+      }
+
+      // Run the compiled code.
+      //echo ("<!-- ".$this->compiled_code[$handle]." -->");
+      eval($this->compiled_code[$handle]);
+      return true;
+    }
+
+  /**
+   * fills $output template var
+   */
+  function parse($handle)
+    {
+      if (!$this->loadfile($handle))
+      {
+        die("Template->pparse(): Couldn't load template file for handle $handle");
+      }
+      
+      // actually compile the template now.
+      if (!isset($this->compiled_code[$handle]) || empty($this->compiled_code[$handle]))
+      {
+        // Actually compile the code now.
+        $this->compiled_code[$handle] = $this->compile($this->uncompiled_code[$handle], true, '_str');
+      }
+
+      // Run the compiled code.
+      $_str = '';
+      eval($this->compiled_code[$handle]);
+      $this->output.= $_str;
+
+      return true;
+    }
+
+  /**
+   * prints $output template var
+   */
+  function p()
+    {
+      echo $this->output;
+    }
+  
+  /**
+   * Inserts the uncompiled code for $handle as the value of $varname in the
+   * root-level. This can be used to effectively include a template in the
+   * middle of another template.
+   *
+   * Note that all desired assignments to the variables in $handle should be
+   * done BEFORE calling this function.
+   */
+  function assign_var_from_handle($varname, $handle)
+    {
+      if (!$this->loadfile($handle))
+      {
+        die("Template->assign_var_from_handle(): Couldn't load template file for handle $handle");
+      }
+      
+      // Compile it, with the "no echo statements" option on.
+      $_str = "";
+      $code = $this->compile($this->uncompiled_code[$handle], true, '_str');
+      
+      // evaluate the variable assignment.
+      eval($code);
+      // assign the value of the generated variable to the given varname.
+      $this->assign_var($varname, $_str);
+      
+      return true;
+    }
+  
+  /**
+   * Block-level variable assignment. Adds a new block iteration with the
+   * given variable assignments. Note that this should only be called once
+   * per block iteration.
+   */
+  function assign_block_vars($blockname, $vararray)
+    {
+      if (strstr($blockname, '.'))
+      {
+        // Nested block.
+        $blocks = explode('.', $blockname);
+        $blockcount = sizeof($blocks) - 1;
+        $str = '$this->_tpldata';
+        for ($i = 0; $i < $blockcount; $i++)
+        {
+          $str .= '[\'' . $blocks[$i] . '.\']';
+          eval('$lastiteration = sizeof(' . $str . ') - 1;');
+          $str .= '[' . $lastiteration . ']';
+        }
+        // Now we add the block that we're actually assigning to.
+        // We're adding a new iteration to this block with the given
+        // variable assignments.
+        $str .= '[\'' . $blocks[$blockcount] . '.\'][] = $vararray;';
+        
+        // Now we evaluate this assignment we've built up.
+        eval($str);
+      }
+      else
+      {
+        // Top-level block. Add a new iteration to this block with the
+        // variable assignments we were given.
+        $this->_tpldata[$blockname . '.'][] = $vararray;
+      }
+      
+      return true;
+    }
+  
+  /**
+   * Root-level variable assignment. Adds to current assignments, overriding
+   * any existing variable assignment with the same name.
+   */
+  function assign_vars($vararray)
+    {
+      reset ($vararray);
+      while (list($key, $val) = each($vararray))
+      {
+        $this->_tpldata['.'][0][$key] = $val;
+      }
+      
+      return true;
+    }
+  
+  /**
+   * Root-level variable assignment. Adds to current assignments, overriding
+   * any existing variable assignment with the same name.
+   */
+  function assign_var($varname, $varval)
+    {
+      $this->_tpldata['.'][0][$varname] = $varval;
+      
+      return true;
+    }
+  
+  
+  /**
+   * Generates a full path+filename for the given filename, which can either
+   * be an absolute name, or a name relative to the rootdir for this
+   * Template object.
+   */
+  function make_filename($filename)
+    {
+      // Check if it's an absolute or relative path.
+      if (substr($filename, 0, 1) != '/')
+      {
+        $filename = $this->root.'/'.$filename;
+      }
+      
+      if (!file_exists($filename))
+      {
+        die("Template->make_filename(): Error - file $filename does not exist");
+      }
+
+      return $filename;
+    }
+  
+  
+  /**
+   * If not already done, load the file for the given handle and populate
+   * the uncompiled_code[] hash with its code. Do not compile.
+   */
+  function loadfile($handle)
+    {
+      // If the file for this handle is already loaded and compiled, do
+      // nothing.
+      if (isset($this->uncompiled_code[$handle])
+          and !empty($this->uncompiled_code[$handle]))
+      {
+        return true;
+      }
+      
+      // If we don't have a file assigned to this handle, die.
+      if (!isset($this->files[$handle]))
+      {
+        die("Template->loadfile(): No file specified for handle $handle");
+      }
+      
+      $filename = $this->files[$handle];
+      
+      $str = implode("", @file($filename));
+      if (empty($str))
+      {
+        die("Template->loadfile(): File $filename for handle $handle is empty");
+      }
+      
+      $this->uncompiled_code[$handle] = $str;
+      
+      return true;
+    }
+  
+  
+  
+  /**
+   * Compiles the given string of code, and returns the result in a string.
+   *
+   * If "do_not_echo" is true, the returned code will not be directly
+   * executable, but can be used as part of a variable assignment for use in
+   * assign_code_from_handle().
+   */
+  function compile($code, $do_not_echo = false, $retvar = '')
+    {
+      // replace \ with \\ and then ' with \'.
+      $code = str_replace('\\', '\\\\', $code);
+      $code = str_replace('\'', '\\\'', $code);
+      
+      // change template varrefs into PHP varrefs
+      
+      // This one will handle varrefs WITH namespaces
+      $varrefs = array();
+      preg_match_all('#\{(([a-z0-9\-_]+?\.)+?)([a-z0-9\-_]+?)\}#is', $code, $varrefs);
+      $varcount = sizeof($varrefs[1]);
+      for ($i = 0; $i < $varcount; $i++)
+      {
+        $namespace = $varrefs[1][$i];
+        $varname = $varrefs[3][$i];
+        $new = $this->generate_block_varref($namespace, $varname);
+        
+        $code = str_replace($varrefs[0][$i], $new, $code);
+      }
+      
+      // This will handle the remaining root-level varrefs
+      $code = preg_replace('#\{([a-z0-9\-_]*?)\}#is', '\' . ( ( isset($this->_tpldata[\'.\'][0][\'\1\']) ) ? $this->_tpldata[\'.\'][0][\'\1\'] : \'\' ) . \'', $code);
+      
+      // Break it up into lines.
+      $code_lines = explode("\n", $code);
+      
+      $block_nesting_level = 0;
+      $block_names = array();
+      $block_names[0] = ".";
+      
+      // Second: prepend echo ', append ' . "\n"; to each line.
+      $line_count = sizeof($code_lines);
+      for ($i = 0; $i < $line_count; $i++)
+      {
+        $code_lines[$i] = chop($code_lines[$i]);
+        if (preg_match('#<!-- BEGIN (.*?) -->#', $code_lines[$i], $m))
+        {
+          $n[0] = $m[0];
+          $n[1] = $m[1];
+          
+          // Added: dougk_ff7-Keeps templates from bombing if begin is on
+          // the same line as end.. I think. :)
+          if ( preg_match('#<!-- END (.*?) -->#', $code_lines[$i], $n) )
+          {
+            $block_nesting_level++;
+            $block_names[$block_nesting_level] = $m[1];
+            if ($block_nesting_level < 2)
+            {
+              // Block is not nested.
+              $code_lines[$i] = '$_' . $n[1] . '_count = ( isset($this->_tpldata[\'' . $n[1] . '.\']) ) ?  sizeof($this->_tpldata[\'' . $n[1] . '.\']) : 0;';
+              $code_lines[$i] .= "\n" . 'for ($_' . $n[1] . '_i = 0; $_' . $n[1] . '_i < $_' . $n[1] . '_count; $_' . $n[1] . '_i++)';
+              $code_lines[$i] .= "\n" . '{';
+            }
+            else
+            {
+              // This block is nested.
+              
+              // Generate a namespace string for this block.
+              $namespace = implode('.', $block_names);
+              // strip leading period from root level..
+              $namespace = substr($namespace, 2);
+              // Get a reference to the data array for this block that depends on the
+              // current indices of all parent blocks.
+              $varref = $this->generate_block_data_ref($namespace, false);
+              // Create the for loop code to iterate over this block.
+              $code_lines[$i] = '$_' . $n[1] . '_count = ( isset(' . $varref . ') ) ? sizeof(' . $varref . ') : 0;';
+              $code_lines[$i] .= "\n" . 'for ($_' . $n[1] . '_i = 0; $_' . $n[1] . '_i < $_' . $n[1] . '_count; $_' . $n[1] . '_i++)';
+              $code_lines[$i] .= "\n" . '{';
+            }
+            
+            // We have the end of a block.
+            unset($block_names[$block_nesting_level]);
+            $block_nesting_level--;
+            $code_lines[$i] .= '} // END ' . $n[1];
+            $m[0] = $n[0];
+            $m[1] = $n[1];
+          }
+          else
+          {
+            // We have the start of a block.
+            $block_nesting_level++;
+            $block_names[$block_nesting_level] = $m[1];
+            if ($block_nesting_level < 2)
+            {
+              // Block is not nested.
+              $code_lines[$i] = '$_' . $m[1] . '_count = ( isset($this->_tpldata[\'' . $m[1] . '.\']) ) ? sizeof($this->_tpldata[\'' . $m[1] . '.\']) : 0;';
+              $code_lines[$i] .= "\n" . 'for ($_' . $m[1] . '_i = 0; $_' . $m[1] . '_i < $_' . $m[1] . '_count; $_' . $m[1] . '_i++)';
+              $code_lines[$i] .= "\n" . '{';
+            }
+            else
+            {
+              // This block is nested.
+              
+              // Generate a namespace string for this block.
+              $namespace = implode('.', $block_names);
+              // strip leading period from root level..
+              $namespace = substr($namespace, 2);
+              // Get a reference to the data array for this block that
+              // depends on the current indices of all parent blocks.
+              $varref = $this->generate_block_data_ref($namespace, false);
+              // Create the for loop code to iterate over this block.
+              $code_lines[$i] = '$_' . $m[1] . '_count = ( isset(' . $varref . ') ) ? sizeof(' . $varref . ') : 0;';
+              $code_lines[$i] .= "\n" . 'for ($_' . $m[1] . '_i = 0; $_' . $m[1] . '_i < $_' . $m[1] . '_count; $_' . $m[1] . '_i++)';
+              $code_lines[$i] .= "\n" . '{';
+            }
+          }
+        }
+        else if (preg_match('#<!-- END (.*?) -->#', $code_lines[$i], $m))
+        {
+          // We have the end of a block.
+          unset($block_names[$block_nesting_level]);
+          $block_nesting_level--;
+          $code_lines[$i] = '} // END ' . $m[1];
+        }
+        else
+        {
+          // We have an ordinary line of code.
+          if (!$do_not_echo)
+          {
+            $code_lines[$i] = 'echo \'' . $code_lines[$i] . '\' . "\\n";';
+          }
+          else
+          {
+            $code_lines[$i] = '$' . $retvar . '.= \'' . $code_lines[$i] . '\' . "\\n";'; 
+          }
+        }
+      }
+      
+      // Bring it back into a single string of lines of code.
+      $code = implode("\n", $code_lines);
+      return $code	;
+      
+    }
+  
+  
+  /**
+   * Generates a reference to the given variable inside the given (possibly
+   * nested) block namespace. This is a string of the form: '
+   * . $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname']
+   * . ' It's ready to be inserted into an "echo" line in one of the
+   * templates.  NOTE: expects a trailing "." on the namespace.
+   */
+  function generate_block_varref($namespace, $varname)
+    {
+      // Strip the trailing period.
+      $namespace = substr($namespace, 0, strlen($namespace) - 1);
+      
+      // Get a reference to the data block for this namespace.
+      $varref = $this->generate_block_data_ref($namespace, true);
+      // Prepend the necessary code to stick this in an echo line.
+      
+      // Append the variable reference.
+      $varref .= '[\'' . $varname . '\']';
+      
+      $varref = '\' . ( ( isset(' . $varref . ') ) ? ' . $varref . ' : \'\' ) . \'';
+      
+      return $varref;
+      
+    }
+  
+  
+  /**
+   * Generates a reference to the array of data values for the given
+   * (possibly nested) block namespace. This is a string of the form:
+   * $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN']
+   *
+   * If $include_last_iterator is true, then [$_childN_i] will be appended
+   * to the form shown above.  NOTE: does not expect a trailing "." on the
+   * blockname.
+   */
+  function generate_block_data_ref($blockname, $include_last_iterator)
+    {
+      // Get an array of the blocks involved.
+      $blocks = explode(".", $blockname);
+      $blockcount = sizeof($blocks) - 1;
+      $varref = '$this->_tpldata';
+      // Build up the string with everything but the last child.
+      for ($i = 0; $i < $blockcount; $i++)
+      {
+        $varref .= '[\'' . $blocks[$i] . '.\'][$_' . $blocks[$i] . '_i]';
+      }
+      // Add the block reference for the last child.
+      $varref .= '[\'' . $blocks[$blockcount] . '.\']';
+      // Add the iterator for the last child if requried.
+      if ($include_last_iterator)
+      {
+              $varref .= '[$_' . $blocks[$blockcount] . '_i]';
+      }
+      
+      return $varref;
+    }
+  
+}
+
+?>
Index: /branches/1.4/include/user.inc.php
===================================================================
--- /branches/1.4/include/user.inc.php	(revision 3249)
+++ /branches/1.4/include/user.inc.php	(revision 3249)
@@ -0,0 +1,184 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// retrieving connected user informations
+
+if (isset($_COOKIE['id']))
+{
+  $session_id = $_COOKIE['id'];
+  $user['has_cookie'] = true;
+}
+else if (isset($_GET['id']))
+{
+  $session_id = $_GET['id'];
+  $user['has_cookie'] = false;
+}
+else
+{
+  $user['has_cookie'] = false;
+}
+
+if (isset($session_id)
+    and ereg("^[0-9a-zA-Z]{".$conf['session_id_size']."}$", $session_id))
+{
+  $page['session_id'] = $session_id;
+  $query = '
+SELECT user_id,expiration,NOW() AS now
+  FROM '.SESSIONS_TABLE.'
+  WHERE id = \''.$page['session_id'].'\'
+;';
+  $result = pwg_query($query);
+  if (mysql_num_rows($result) > 0)
+  {
+    $row = mysql_fetch_array($result);
+    if (strnatcmp($row['expiration'], $row['now']) < 0)
+    {
+      // deletion of the session from the database, because it is
+      // out-of-date
+      $delete_query = '
+DELETE FROM '.SESSIONS_TABLE.'
+  WHERE id = \''.$page['session_id'].'\'
+;';
+      pwg_query($delete_query);
+    }
+    else
+    {
+      $user['id'] = $row['user_id'];
+      $user['is_the_guest'] = false;
+    }
+  }
+}
+if (!isset($user['id']))
+{
+  $user['id'] = 2;
+  $user['is_the_guest'] = true;
+}
+
+$query = '
+SELECT u.*, uf.*
+  FROM '.USERS_TABLE.' AS u LEFT JOIN '.USER_FORBIDDEN_TABLE.' AS uf
+    ON id = user_id
+  WHERE u.id = '.$user['id'].'
+;';
+$row = mysql_fetch_array(pwg_query($query));
+
+// affectation of each value retrieved in the users table into a variable of
+// the array $user.
+foreach ($row as $key => $value)
+{
+  if (!is_numeric($key))
+  {
+    // If the field is true or false, the variable is transformed into a
+    // boolean value.
+    if ($value == 'true' or $value == 'false')
+    {
+      $user[$key] = get_boolean($value);
+    }
+    else
+    {
+      $user[$key] = $value;
+    }
+  }
+}
+
+// properties of user guest are found in the configuration
+if ($user['is_the_guest'])
+{
+  $user['template'] = $conf['default_template'];
+  $user['nb_image_line'] = $conf['nb_image_line'];
+  $user['nb_line_page'] = $conf['nb_line_page'];
+  $user['language'] = $conf['default_language'];
+  $user['maxwidth'] = $conf['default_maxwidth'];
+  $user['maxheight'] = $conf['default_maxheight'];
+  $user['recent_period'] = $conf['recent_period'];
+  $user['expand'] = $conf['auto_expand'];
+  $user['show_nb_comments'] = $conf['show_nb_comments'];
+}
+
+// if no information were found about user in user_forbidden table OR the
+// forbidden categories must be updated : only if current user is in public
+// part
+if (!defined('IN_ADMIN') or !IN_ADMIN)
+{
+  if (!isset($user['need_update'])
+      or !is_bool($user['need_update'])
+      or $user['need_update'] == true)
+  {
+    $user['forbidden_categories'] = calculate_permissions($user['id'],
+                                                          $user['status']);
+  }
+}
+
+// forbidden_categories is a must be empty, at least
+if (!isset($user['forbidden_categories']))
+{
+  $user['forbidden_categories'] = '';
+}
+
+// special for $user['restrictions'] array
+$user['restrictions'] = explode(',', $user['forbidden_categories']);
+if ($user['restrictions'][0] == '')
+{
+  $user['restrictions'] = array();
+}
+
+// calculation of the number of picture to display per page
+$user['nb_image_page'] = $user['nb_image_line'] * $user['nb_line_page'];
+
+if (empty($user['language'])
+    or !file_exists(PHPWG_ROOT_PATH.'language/'.
+                    $user['language'].'/common.lang.php'))
+{
+  $user['language'] = $conf['default_language'];
+}
+include_once(PHPWG_ROOT_PATH.'language/'.$user['language'].'/common.lang.php');
+
+// displaying the username in the language of the connected user, instead of
+// "guest" as you can find in the database
+if ($user['is_the_guest'])
+{
+  $user['username'] = $lang['guest'];
+}
+
+// only if we are in the administration section
+if (defined('IN_ADMIN') and IN_ADMIN)
+{
+  $langdir = PHPWG_ROOT_PATH.'language/'.$user['language'];
+  if (!file_exists($langdir.'/admin.lang.php'))
+  {
+    $langdir = PHPWG_ROOT_PATH.'language/'.$conf['default_language'];
+  }
+  include_once($langdir.'/admin.lang.php');
+  include_once($langdir.'/faq.lang.php');
+}
+
+if (empty($user['template']))
+{
+  $user['template'] = $conf['default_template'];
+}
+$template = setup_style($user['template']);
+?>
Index: /branches/1.4/index.php
===================================================================
--- /branches/1.4/index.php	(revision 3249)
+++ /branches/1.4/index.php	(revision 3249)
@@ -0,0 +1,31 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+define('PHPWG_ROOT_PATH','./');
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+redirect('category.php');
+?>
Index: /branches/1.4/install.php
===================================================================
--- /branches/1.4/install.php	(revision 3249)
+++ /branches/1.4/install.php	(revision 3249)
@@ -0,0 +1,393 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+//----------------------------------------------------------- include
+define('PHPWG_ROOT_PATH','./');
+
+// Guess an initial language ... 
+function guess_lang()
+{
+  return 'en_UK.iso-8859-1';
+
+//   $languages = array();
+//   $i = 0;
+//   if ($opendir = opendir(PHPWG_ROOT_PATH.'language/'))
+//   {
+//     while ( $file = readdir ( $opendir ) )
+//     {
+//       if ( is_dir ( PHPWG_ROOT_PATH.'language/'.$file )&& !substr_count($file,'.'))
+//       {
+//         $languages[$i++] =$file;
+//       }
+//     }
+//   }
+
+//   if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
+//   {
+//     $accept_lang_ary = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
+//     for ($i = 0; $i < sizeof($accept_lang_ary); $i++)
+//     {
+//       for ($j=0; $j<sizeof($languages); $j++)
+//       {
+//         if (preg_match('#' . substr($languages[$j],0,2) . '#i', substr(trim($accept_lang_ary[$i]),0,2)))
+//         {
+//           if (file_exists(PHPWG_ROOT_PATH . 'language/' . $languages[$j].'/install.lang.php'))
+// 		  {
+//                     return $languages[$j];
+// 		  }
+//         }
+//       }
+//     }
+//   }
+//   return 'en_EN';
+}
+
+/**
+ * loads an sql file and executes all queries
+ *
+ * Before executing a query, $replaced is... replaced by $replacing. This is
+ * useful when the SQL file contains generic words. Drop table queries are
+ * not executed.
+ *
+ * @param string filepath
+ * @param string replaced
+ * @param string replacing
+ * @return void
+ */
+function execute_sqlfile($filepath, $replaced, $replacing)
+{
+  $sql_lines = file($filepath);
+  $query = '';
+  foreach ($sql_lines as $sql_line)
+  {
+    $sql_line = trim($sql_line);
+    if (preg_match('/(^--|^$)/', $sql_line))
+    {
+      continue;
+    }
+    $query.= ' '.$sql_line;
+    // if we reached the end of query, we execute it and reinitialize the
+    // variable "query"
+    if (preg_match('/;$/', $sql_line))
+    {
+      $query = trim($query);
+      $query = str_replace($replaced, $replacing, $query);
+      // we don't execute "DROP TABLE" queries
+      if (!preg_match('/^DROP TABLE/i', $query))
+      {
+        mysql_query($query);
+      }
+      $query = '';
+    }
+  }
+}
+
+set_magic_quotes_runtime(0); // Disable magic_quotes_runtime
+//
+// addslashes to vars if magic_quotes_gpc is off this is a security
+// precaution to prevent someone trying to break out of a SQL statement.
+//
+if( !get_magic_quotes_gpc() )
+{
+  if( is_array($_POST) )
+  {
+    while( list($k, $v) = each($_POST) )
+    {
+      if( is_array($_POST[$k]) )
+      {
+        while( list($k2, $v2) = each($_POST[$k]) )
+        {
+          $_POST[$k][$k2] = addslashes($v2);
+        }
+        @reset($_POST[$k]);
+      }
+      else
+      {
+        $_POST[$k] = addslashes($v);
+      }
+    }
+    @reset($_POST);
+  }
+
+  if( is_array($_COOKIE) )
+  {
+    while( list($k, $v) = each($_COOKIE) )
+    {
+      if( is_array($_COOKIE[$k]) )
+      {
+        while( list($k2, $v2) = each($_COOKIE[$k]) )
+        {
+          $_COOKIE[$k][$k2] = addslashes($v2);
+        }
+        @reset($_COOKIE[$k]);
+      }
+      else
+      {
+        $_COOKIE[$k] = addslashes($v);
+      }
+    }
+    @reset($_COOKIE);
+  }
+}
+
+//----------------------------------------------------- variable initialization
+$install_style = 'default';
+
+// Obtain various vars
+$dbhost = (!empty($_POST['dbhost'])) ? $_POST['dbhost'] : 'localhost';
+$dbuser = (!empty($_POST['dbuser'])) ? $_POST['dbuser'] : '';
+$dbpasswd = (!empty($_POST['dbpasswd'])) ? $_POST['dbpasswd'] : '';
+$dbname = (!empty($_POST['dbname'])) ? $_POST['dbname'] : '';
+
+$table_prefix = (!empty($_POST['prefix'])) ? $_POST['prefix'] : 'phpwebgallery_';
+
+$admin_name = (!empty($_POST['admin_name'])) ? $_POST['admin_name'] : '';
+$admin_pass1 = (!empty($_POST['admin_pass1'])) ? $_POST['admin_pass1'] : '';
+$admin_pass2 = (!empty($_POST['admin_pass2'])) ? $_POST['admin_pass2'] : '';
+$admin_mail = (!empty($_POST['admin_mail'])) ? $_POST['admin_mail'] : '';
+
+$infos = array();
+$errors = array();
+
+// Open config.php ... if it exists
+$config_file = PHPWG_ROOT_PATH.'include/mysql.inc.php';
+if (@file_exists($config_file))
+{
+  include($config_file);
+  // Is PhpWebGallery already installed ?
+  if (defined("PHPWG_INSTALLED"))
+  {
+    die('PhpWebGallery is already installed');
+  }
+}
+
+$prefixeTable = $table_prefix;
+include(PHPWG_ROOT_PATH . 'include/constants.php');
+include(PHPWG_ROOT_PATH . 'include/functions.inc.php');
+include(PHPWG_ROOT_PATH . 'include/template.php');
+
+if ( isset( $_POST['language'] ))
+{
+  $language = strip_tags($_POST['language']);
+}
+else 
+{
+  $language = guess_lang();
+}
+
+if (!file_exists(PHPWG_ROOT_PATH.'language/'.$language.'/install.lang.php'))
+{
+  $language = 'en_UK.iso-8859-1';
+}
+
+include( './language/'.$language.'/common.lang.php' );
+include( './language/'.$language.'/admin.lang.php' );
+include( './language/'.$language.'/install.lang.php' );
+//----------------------------------------------------- template initialization
+$template=setup_style($install_style);
+$template->set_filenames( array('install'=>'install.tpl') );
+$step = 1;
+//---------------------------------------------------------------- form analyze
+if ( isset( $_POST['install'] ))
+{
+  if ( @mysql_connect( $_POST['dbhost'],
+                       $_POST['dbuser'],
+                       $_POST['dbpasswd'] ) )
+  {
+    if ( @mysql_select_db($_POST['dbname'] ) )
+    {
+      array_push( $infos, $lang['step1_confirmation'] );
+    }
+    else
+    {
+      array_push( $errors, $lang['step1_err_db'] );
+    }
+  }
+  else
+  {
+    array_push( $errors, $lang['step1_err_server'] );
+  }
+  
+  $webmaster = trim(preg_replace( '/\s{2,}/', ' ', $admin_name ));
+  if ( empty($webmaster))
+    array_push( $errors, $lang['step2_err_login1'] );
+  else if ( preg_match( '/[\'"]/', $webmaster ) )
+    array_push( $errors, $lang['step2_err_login3'] );
+  if ( $admin_pass1 != $admin_pass2 || empty($admin_pass1) )
+    array_push( $errors, $lang['step2_err_pass'] );
+  if ( empty($admin_mail))
+    array_push( $errors, $lang['reg_err_mail_address'] );
+  else 
+  {
+    $error_mail_address = validate_mail_address($admin_mail);
+    if (!empty($error_mail_address))
+      array_push( $errors, $error_mail_address );
+  }
+  
+  if ( count( $errors ) == 0 )
+  {
+    $step = 2;
+    $file_content = "<?php";
+    $file_content.= "\n\$cfgBase = '".     $dbname."';";
+    $file_content.= "\n\$cfgUser = '".     $dbuser."';";
+    $file_content.= "\n\$cfgPassword = '". $dbpasswd."';";
+    $file_content.= "\n\$cfgHote = '".     $dbhost."';";
+    $file_content.= "\n";
+    $file_content.= "\n\$prefixeTable = '".$table_prefix."';";
+    $file_content.= "\n";
+    $file_content.= "\ndefine('PHPWG_INSTALLED', true);";
+    $file_content.= "\n?".">";
+    
+    @umask(0111);
+    // writing the configuration file
+    if ( !($fp = @fopen( $config_file, 'w' )))
+    {
+      $html_content = htmlentities( $file_content, ENT_QUOTES );
+      $html_content = nl2br( $html_content );
+      $template->assign_block_vars('error_copy',
+                                   array('FILE_CONTENT'=>$html_content));
+    }
+    @fputs($fp, $file_content, strlen($file_content));
+    @fclose($fp);
+    
+    // tables creation, based on phpwebgallery_structure.sql
+    execute_sqlfile( PHPWG_ROOT_PATH.'install/phpwebgallery_structure.sql'
+                     , 'phpwebgallery_'
+                     , $table_prefix );
+    // We fill the tables with basic informations
+    execute_sqlfile( PHPWG_ROOT_PATH.'install/config.sql'
+                     , 'phpwebgallery_'
+                     , $table_prefix );
+
+    $query = 'UPDATE '.CONFIG_TABLE;
+    $query.= " SET value = '".$admin_mail."'";
+    $query.= " WHERE param = 'mail_webmaster'";
+    $query.= ';';
+    mysql_query( $query );
+	
+    $query = 'UPDATE '.CONFIG_TABLE;
+    $query.= " SET value = '".$language."'";
+    $query.= " WHERE param = 'default_language'";
+    $query.= ';';
+    mysql_query( $query );
+    
+    $query = 'INSERT INTO '.SITES_TABLE;
+    $query.= " (id,galleries_url) VALUES (1, '".PHPWG_ROOT_PATH."galleries/');";
+    mysql_query( $query );
+    
+    // webmaster admin user
+    $query = 'INSERT INTO '.USERS_TABLE;
+    $query.= ' (id,username,password,status,language,mail_address) VALUES ';
+    $query.= "(1,'".$admin_name."','".md5( $admin_pass1 )."'";
+    $query.= ",'admin','".$language."'";
+    $query.= ",'".$admin_mail."');";
+    mysql_query($query);
+    
+    // guest user
+    $query = 'INSERT INTO '.USERS_TABLE;
+    $query.= '(id,username,password,status,language) VALUES ';
+    $query.= "(2,'guest','','guest','".$language."')";
+    $query.= ';';
+    mysql_query( $query );
+  }
+}
+
+$template->assign_vars(
+  array(
+    'RELEASE'=>PHPWG_VERSION,
+  
+    'L_BASE_TITLE'=>$lang['Initial_config'],
+    'L_LANG_TITLE'=>$lang['Default_lang'],
+    'L_DB_TITLE'=>$lang['step1_title'],
+    'L_DB_HOST'=>$lang['step1_host'],
+    'L_DB_HOST_INFO'=>$lang['step1_host_info'],
+    'L_DB_USER'=>$lang['step1_user'],
+    'L_DB_USER_INFO'=>$lang['step1_user_info'],
+    'L_DB_PASS'=>$lang['step1_pass'],
+    'L_DB_PASS_INFO'=>$lang['step1_pass_info'],
+    'L_DB_NAME'=>$lang['step1_database'],
+    'L_DB_NAME_INFO'=>$lang['step1_database_info'],
+    'L_DB_PREFIX'=>$lang['step1_prefix'],
+    'L_DB_PREFIX_INFO'=>$lang['step1_prefix_info'],
+    'L_ADMIN_TITLE'=>$lang['step2_title'],
+    'L_ADMIN'=>$lang['install_webmaster'],
+    'L_ADMIN_INFO'=>$lang['install_webmaster_info'],
+    'L_ADMIN_PASSWORD'=>$lang['step2_pwd'],
+    'L_ADMIN_PASSWORD_INFO'=>$lang['step2_pwd_info'],
+    'L_ADMIN_CONFIRM_PASSWORD'=>$lang['step2_pwd_conf'],
+    'L_ADMIN_CONFIRM_PASSWORD_INFO'=>$lang['step2_pwd_conf_info'],
+    'L_ADMIN_EMAIL'=>$lang['conf_mail_webmaster'],
+    'L_ADMIN_EMAIL_INFO'=>$lang['conf_mail_webmaster_info'],
+    'L_SUBMIT'=>$lang['Start_Install'],
+    'L_HELP'=>$lang['install_help'],
+    'L_ERR_COPY'=>$lang['step1_err_copy'],
+    'L_END_TITLE'=>$lang['install_end_title'],
+    'L_END_MESSAGE'=>$lang['install_end_message'],
+    
+    'F_ACTION'=>add_session_id( 'install.php' ),
+    'F_DB_HOST'=>$dbhost,
+    'F_DB_USER'=>$dbuser,
+    'F_DB_NAME'=>$dbname,
+    'F_DB_PREFIX'=>$table_prefix,
+    'F_ADMIN'=>$admin_name,
+    'F_ADMIN_EMAIL'=>$admin_mail,
+    'F_LANG_SELECT'=>language_select($language),
+    
+    'T_CONTENT_ENCODING' => $lang_info['charset']
+    ));
+
+//------------------------------------------------------ errors & infos display
+if ( sizeof( $errors ) != 0 )
+{
+  $template->assign_block_vars('errors',array());
+  for ( $i = 0; $i < sizeof( $errors ); $i++ )
+  {
+    $template->assign_block_vars('errors.error',array('ERROR'=>$errors[$i]));
+  }
+}
+
+if ( sizeof( $infos ) != 0 )
+{
+  $template->assign_block_vars('infos',array());
+  for ( $i = 0; $i < sizeof( $infos ); $i++ )
+  {
+    $template->assign_block_vars('infos.info',array('INFO'=>$infos[$i]));
+  }
+}
+
+if ($step ==1)
+{
+  $template->assign_block_vars('install',array());
+}
+else
+{
+  $template->assign_block_vars('install_end',array());
+}
+
+//----------------------------------------------------------- html code display
+$template->pparse('install');
+?>
Index: /branches/1.4/install/config.sql
===================================================================
--- /branches/1.4/install/config.sql	(revision 3249)
+++ /branches/1.4/install/config.sql	(revision 3249)
@@ -0,0 +1,29 @@
+-- initial configuration for PhpWebGallery
+
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('prefix_thumbnail','TN-','thumbnails filename prefix');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('mail_webmaster','','webmaster mail');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('default_language','en_UK.iso-8859-1','Default gallery language');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('default_template','default','Default gallery style');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('default_maxwidth','','maximum width authorized for displaying images');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('default_maxheight','','maximum height authorized for the displaying images');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('nb_comment_page','10','number of comments to display on each page');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('upload_maxfilesize','150','maximum filesize for the uploaded pictures');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('upload_maxwidth','800','maximum width authorized for the uploaded images');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('upload_maxheight','600','maximum height authorized for the uploaded images');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('upload_maxwidth_thumbnail','150','maximum width authorized for the uploaded thumbnails');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('upload_maxheight_thumbnail','100','maximum height authorized for the uploaded thumbnails');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('log','false','keep an history of visits on your website');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('comments_validation','false','administrators validate users comments before becoming visible');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('comments_forall','false','even guest not registered can post comments');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('mail_notification','false','automated mail notification for adminsitrators');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('nb_image_line','5','Number of images displayed per row');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('nb_line_page','3','Number of rows displayed per page');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('recent_period','7','Period within which pictures are displayed as new (in days)');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('auto_expand','false','Auto expand of the category tree');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('show_nb_comments','false','Show the number of comments under the thumbnails');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('use_iptc','false','Use IPTC data during database synchronization with files metadata');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('use_exif','false','Use EXIF data during database synchronization with files metadata');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('show_iptc','false','Show IPTC metadata on picture.php if asked by user');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('show_exif','true','Show EXIF metadata on picture.php if asked by user');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('authorize_remembering','true','Authorize users to be remembered, see $conf{remember_me_length}');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('gallery_locked','false','Lock your gallery temporary for non admin users');
Index: /branches/1.4/install/dbscheme.txt
===================================================================
--- /branches/1.4/install/dbscheme.txt	(revision 3249)
+++ /branches/1.4/install/dbscheme.txt	(revision 3249)
@@ -0,0 +1,149 @@
+
+table:categories
+table:comments
+table:config
+table:favorites
+table:group_access
+table:groups
+table:history
+table:image_category
+table:images
+table:rate
+table:sessions
+table:sites
+table:user_access
+table:user_forbidden
+table:user_group
+table:users
+table:waiting
+
+column:id                        table:categories     type:smallint                 nullable:N length:5   signed:N
+column:date_last                 table:categories     type:date                     nullable:Y
+column:nb_images                 table:categories     type:mediumint                nullable:N length:8   signed:N
+column:name                      table:categories     type:varchar                  nullable:N length:255 binary:N
+column:id_uppercat               table:categories     type:smallint                 nullable:Y length:5   signed:N
+column:comment                   table:categories     type:text                     nullable:Y
+column:dir                       table:categories     type:varchar                  nullable:Y length:255 binary:N
+column:rank                      table:categories     type:tinyint                  nullable:Y length:3   signed:N
+column:status                    table:categories     type:enum('public','private') nullable:N
+column:site_id                   table:categories     type:tinyint                  nullable:Y length:4   signed:N
+column:visible                   table:categories     type:enum('true','false')     nullable:N
+column:uploadable                table:categories     type:enum('true','false')     nullable:N
+column:representative_picture_id table:categories     type:mediumint                nullable:Y length:8   signed:N
+column:uppercats                 table:categories     type:varchar                  nullable:N length:255 binary:N
+column:commentable               table:categories     type:enum('true','false')     nullable:N
+column:global_rank               table:categories     type:varchar                  nullable:Y length:255 binary:N
+column:id                        table:comments       type:int                      nullable:N length:11  signed:N
+column:image_id                  table:comments       type:mediumint                nullable:N length:8   signed:N
+column:date                      table:comments       type:datetime                 nullable:N
+column:author                    table:comments       type:varchar                  nullable:Y length:255 binary:N
+column:content                   table:comments       type:longtext                 nullable:Y
+column:validated                 table:comments       type:enum('true','false')     nullable:N
+column:param                     table:config         type:varchar                  nullable:N length:40  binary:N
+column:value                     table:config         type:varchar                  nullable:Y length:255 binary:N
+column:comment                   table:config         type:varchar                  nullable:Y length:255 binary:N
+column:user_id                   table:favorites      type:smallint                 nullable:N length:5   signed:N
+column:image_id                  table:favorites      type:mediumint                nullable:N length:8   signed:N
+column:group_id                  table:group_access   type:smallint                 nullable:N length:5   signed:N
+column:cat_id                    table:group_access   type:smallint                 nullable:N length:5   signed:N
+column:id                        table:groups         type:smallint                 nullable:N length:5   signed:N
+column:name                      table:groups         type:varchar                  nullable:N length:255 binary:N
+column:date                      table:history        type:datetime                 nullable:N
+column:login                     table:history        type:varchar                  nullable:Y length:15  binary:N
+column:IP                        table:history        type:varchar                  nullable:N length:50  binary:N
+column:category                  table:history        type:varchar                  nullable:Y length:150 binary:N
+column:file                      table:history        type:varchar                  nullable:Y length:50  binary:N
+column:picture                   table:history        type:varchar                  nullable:Y length:150 binary:N
+column:image_id                  table:image_category type:mediumint                nullable:N length:8   signed:N
+column:category_id               table:image_category type:smallint                 nullable:N length:5   signed:N
+column:id                        table:images         type:mediumint                nullable:N length:8   signed:N
+column:file                      table:images         type:varchar                  nullable:N length:255 binary:N
+column:date_available            table:images         type:date                     nullable:N
+column:date_creation             table:images         type:date                     nullable:Y
+column:tn_ext                    table:images         type:varchar                  nullable:Y length:4   binary:N
+column:name                      table:images         type:varchar                  nullable:Y length:255 binary:N
+column:comment                   table:images         type:text                     nullable:Y
+column:author                    table:images         type:varchar                  nullable:Y length:255 binary:N
+column:hit                       table:images         type:int                      nullable:N length:10  signed:N
+column:filesize                  table:images         type:mediumint                nullable:Y length:9   signed:N
+column:width                     table:images         type:smallint                 nullable:Y length:9   signed:N
+column:height                    table:images         type:smallint                 nullable:Y length:9   signed:N
+column:keywords                  table:images         type:varchar                  nullable:Y length:255 binary:N
+column:storage_category_id       table:images         type:smallint                 nullable:Y length:5   signed:N
+column:representative_ext        table:images         type:varchar                  nullable:Y length:4   binary:N
+column:date_metadata_update      table:images         type:date                     nullable:Y
+column:average_rate              table:images         type:float                    nullable:Y length:5,2 signed:N
+column:path                      table:images         type:varchar                  nullable:N length:255 binary:N
+column:user_id                   table:rate           type:smallint                 nullable:N length:5   signed:N
+column:element_id                table:rate           type:mediumint                nullable:N length:8   signed:N
+column:rate                      table:rate           type:tinyint                  nullable:N length:2   signed:N
+column:id                        table:sessions       type:varchar                  nullable:N length:255 binary:Y
+column:user_id                   table:sessions       type:smallint                 nullable:N length:5   signed:N
+column:expiration                table:sessions       type:datetime                 nullable:N
+column:id                        table:sites          type:tinyint                  nullable:N length:4   signed:Y
+column:galleries_url             table:sites          type:varchar                  nullable:N length:255 binary:N
+column:user_id                   table:user_access    type:smallint                 nullable:N length:5   signed:N
+column:cat_id                    table:user_access    type:smallint                 nullable:N length:5   signed:N
+column:user_id                   table:user_forbidden type:smallint                 nullable:N length:5   signed:N
+column:need_update               table:user_forbidden type:enum('true','false')     nullable:N
+column:forbidden_categories      table:user_forbidden type:text                     nullable:Y
+column:user_id                   table:user_group     type:smallint                 nullable:N length:5   signed:N
+column:group_id                  table:user_group     type:smallint                 nullable:N length:5   signed:N
+column:id                        table:users          type:smallint                 nullable:N length:5   signed:N
+column:username                  table:users          type:varchar                  nullable:N length:20  binary:Y
+column:password                  table:users          type:varchar                  nullable:N length:255 binary:N
+column:mail_address              table:users          type:varchar                  nullable:Y length:255 binary:N
+column:nb_image_line             table:users          type:tinyint                  nullable:N length:1   signed:N
+column:nb_line_page              table:users          type:tinyint                  nullable:N length:3   signed:N
+column:status                    table:users          type:enum('admin','guest')    nullable:N
+column:language                  table:users          type:varchar                  nullable:N length:50  binary:N
+column:maxwidth                  table:users          type:smallint                 nullable:Y length:6   signed:Y
+column:maxheight                 table:users          type:smallint                 nullable:Y length:6   signed:Y
+column:expand                    table:users          type:enum('true','false')     nullable:N
+column:show_nb_comments          table:users          type:enum('true','false')     nullable:N
+column:recent_period             table:users          type:tinyint                  nullable:N length:3   signed:N
+column:template                  table:users          type:varchar                  nullable:N length:255 binary:N
+column:id                        table:waiting        type:int                      nullable:N length:10  signed:N
+column:storage_category_id       table:waiting        type:smallint                 nullable:N length:5   signed:N
+column:file                      table:waiting        type:varchar                  nullable:N length:255 binary:N
+column:username                  table:waiting        type:varchar                  nullable:N length:255 binary:N
+column:mail_address              table:waiting        type:varchar                  nullable:N length:255 binary:N
+column:date                      table:waiting        type:int                      nullable:N length:10  signed:N
+column:tn_ext                    table:waiting        type:char                     nullable:Y length:3   binary:N
+column:validated                 table:waiting        type:enum('true','false')     nullable:N
+column:infos                     table:waiting        type:text                     nullable:Y
+
+PK:categories_pk     table:categories     column:id
+PK:comments_pk       table:comments       column:id
+PK:config_pk         table:config         column:param
+PK:favorites_pk      table:favorites      column:user_id
+PK:favorites_pk      table:favorites      column:image_id
+PK:group_access_pk   table:group_access   column:group_id
+PK:group_access_pk   table:group_access   column:cat_id
+PK:groups_pk         table:groups         column:id
+PK:image_category_pk table:image_category column:image_id
+PK:image_category_pk table:image_category column:category_id
+PK:images_pk         table:images         column:id
+PK:rate_pk           table:rate           column:user_id
+PK:rate_pk           table:rate           column:element_id
+PK:sessions_pk       table:sessions       column:id
+PK:sites_pk          table:sites          column:id
+PK:user_access_pk    table:user_access    column:user_id
+PK:user_access_pk    table:user_access    column:cat_id
+PK:user_forbidden_pk table:user_forbidden column:user_id
+PK:user_group_pk     table:user_group     column:group_id
+PK:user_group_pk     table:user_group     column:user_id
+PK:users_pk          table:users          column:id
+PK:waiting_pk        table:waiting        column:id
+
+index:categories_i2     table:categories     column:id_uppercat
+index:history_i1        table:history        column:date
+index:image_category_i1 table:image_category column:image_id
+index:image_category_i2 table:image_category column:category_id
+index:images_i2         table:images         column:date_available
+index:images_i1         table:images         column:storage_category_id
+index:images_i3         table:images         column:average_rate
+index:images_i4         table:images         column:hit
+index:images_i5         table:images         column:date_creation
+index:sites_ui1         table:sites          column:galleries_url
+index:users_ui1         table:users          column:username
Index: /branches/1.4/install/phpwebgallery_structure.sql
===================================================================
--- /branches/1.4/install/phpwebgallery_structure.sql	(revision 3249)
+++ /branches/1.4/install/phpwebgallery_structure.sql	(revision 3249)
@@ -0,0 +1,264 @@
+-- MySQL dump 8.21
+--
+-- Host: localhost    Database: pwg-bsf
+---------------------------------------------------------
+-- Server version	3.23.49-log
+
+--
+-- Table structure for table 'phpwebgallery_categories'
+--
+
+DROP TABLE IF EXISTS phpwebgallery_categories;
+CREATE TABLE phpwebgallery_categories (
+  id smallint(5) unsigned NOT NULL auto_increment,
+  date_last date default NULL,
+  nb_images mediumint(8) unsigned NOT NULL default '0',
+  name varchar(255) NOT NULL default '',
+  id_uppercat smallint(5) unsigned default NULL,
+  comment text,
+  dir varchar(255) default NULL,
+  rank tinyint(3) unsigned default NULL,
+  status enum('public','private') NOT NULL default 'public',
+  site_id tinyint(4) unsigned default '1',
+  visible enum('true','false') NOT NULL default 'true',
+  uploadable enum('true','false') NOT NULL default 'false',
+  representative_picture_id mediumint(8) unsigned default NULL,
+  uppercats varchar(255) NOT NULL default '',
+  commentable enum('true','false') NOT NULL default 'true',
+  global_rank varchar(255) default NULL,
+  PRIMARY KEY  (id),
+  KEY categories_i2 (id_uppercat)
+) TYPE=MyISAM;
+
+--
+-- Table structure for table 'phpwebgallery_comments'
+--
+
+DROP TABLE IF EXISTS phpwebgallery_comments;
+CREATE TABLE phpwebgallery_comments (
+  id int(11) unsigned NOT NULL auto_increment,
+  image_id mediumint(8) unsigned NOT NULL default '0',
+  date datetime NOT NULL default '0000-00-00 00:00:00',
+  author varchar(255) default NULL,
+  content longtext,
+  validated enum('true','false') NOT NULL default 'false',
+  PRIMARY KEY  (id)
+) TYPE=MyISAM;
+
+--
+-- Table structure for table 'phpwebgallery_config'
+--
+
+DROP TABLE IF EXISTS phpwebgallery_config;
+CREATE TABLE phpwebgallery_config (
+  param varchar(40) NOT NULL default '',
+  value varchar(255) default NULL,
+  comment varchar(255) default NULL,
+  PRIMARY KEY  (param)
+) TYPE=MyISAM COMMENT='configuration table';
+
+--
+-- Table structure for table 'phpwebgallery_favorites'
+--
+
+DROP TABLE IF EXISTS phpwebgallery_favorites;
+CREATE TABLE phpwebgallery_favorites (
+  user_id smallint(5) unsigned NOT NULL default '0',
+  image_id mediumint(8) unsigned NOT NULL default '0',
+  PRIMARY KEY  (user_id,image_id)
+) TYPE=MyISAM;
+
+--
+-- Table structure for table 'phpwebgallery_group_access'
+--
+
+DROP TABLE IF EXISTS phpwebgallery_group_access;
+CREATE TABLE phpwebgallery_group_access (
+  group_id smallint(5) unsigned NOT NULL default '0',
+  cat_id smallint(5) unsigned NOT NULL default '0',
+  PRIMARY KEY  (group_id,cat_id)
+) TYPE=MyISAM;
+
+--
+-- Table structure for table 'phpwebgallery_groups'
+--
+
+DROP TABLE IF EXISTS phpwebgallery_groups;
+CREATE TABLE phpwebgallery_groups (
+  id smallint(5) unsigned NOT NULL auto_increment,
+  name varchar(255) NOT NULL default '',
+  PRIMARY KEY  (id)
+) TYPE=MyISAM;
+
+--
+-- Table structure for table 'phpwebgallery_history'
+--
+
+DROP TABLE IF EXISTS phpwebgallery_history;
+CREATE TABLE phpwebgallery_history (
+  date datetime NOT NULL default '0000-00-00 00:00:00',
+  login varchar(15) default NULL,
+  IP varchar(50) NOT NULL default '',
+  category varchar(150) default NULL,
+  file varchar(50) default NULL,
+  picture varchar(150) default NULL,
+  KEY history_i1 (date)
+) TYPE=MyISAM;
+
+--
+-- Table structure for table 'phpwebgallery_image_category'
+--
+
+DROP TABLE IF EXISTS phpwebgallery_image_category;
+CREATE TABLE phpwebgallery_image_category (
+  image_id mediumint(8) unsigned NOT NULL default '0',
+  category_id smallint(5) unsigned NOT NULL default '0',
+  PRIMARY KEY  (image_id,category_id),
+  KEY image_category_i1 (image_id),
+  KEY image_category_i2 (category_id)
+) TYPE=MyISAM;
+
+--
+-- Table structure for table 'phpwebgallery_images'
+--
+
+DROP TABLE IF EXISTS phpwebgallery_images;
+CREATE TABLE phpwebgallery_images (
+  id mediumint(8) unsigned NOT NULL auto_increment,
+  file varchar(255) NOT NULL default '',
+  date_available date NOT NULL default '0000-00-00',
+  date_creation date default NULL,
+  tn_ext varchar(4) default '',
+  name varchar(255) default NULL,
+  comment text,
+  author varchar(255) default NULL,
+  hit int(10) unsigned NOT NULL default '0',
+  filesize mediumint(9) unsigned default NULL,
+  width smallint(9) unsigned default NULL,
+  height smallint(9) unsigned default NULL,
+  keywords varchar(255) default NULL,
+  storage_category_id smallint(5) unsigned default NULL,
+  representative_ext varchar(4) default NULL,
+  date_metadata_update date default NULL,
+  average_rate float(5,2) unsigned default NULL,
+  path varchar(255) NOT NULL default '',
+  PRIMARY KEY  (id),
+  KEY images_i2 (date_available),
+  KEY images_i1 (storage_category_id),
+  KEY images_i3 (average_rate),
+  KEY images_i4 (hit),
+  KEY images_i5 (date_creation)
+) TYPE=MyISAM;
+
+--
+-- Table structure for table 'phpwebgallery_rate'
+--
+
+DROP TABLE IF EXISTS phpwebgallery_rate;
+CREATE TABLE phpwebgallery_rate (
+  user_id smallint(5) unsigned NOT NULL default '0',
+  element_id mediumint(8) unsigned NOT NULL default '0',
+  rate tinyint(2) unsigned NOT NULL default '0',
+  PRIMARY KEY  (user_id,element_id)
+) TYPE=MyISAM;
+
+--
+-- Table structure for table 'phpwebgallery_sessions'
+--
+
+DROP TABLE IF EXISTS phpwebgallery_sessions;
+CREATE TABLE phpwebgallery_sessions (
+  id varchar(255) binary NOT NULL default '',
+  user_id smallint(5) unsigned NOT NULL default '0',
+  expiration datetime NOT NULL default '0000-00-00 00:00:00',
+  PRIMARY KEY  (id)
+) TYPE=MyISAM;
+
+--
+-- Table structure for table 'phpwebgallery_sites'
+--
+
+DROP TABLE IF EXISTS phpwebgallery_sites;
+CREATE TABLE phpwebgallery_sites (
+  id tinyint(4) NOT NULL auto_increment,
+  galleries_url varchar(255) NOT NULL default '',
+  PRIMARY KEY  (id),
+  UNIQUE KEY sites_ui1 (galleries_url)
+) TYPE=MyISAM;
+
+--
+-- Table structure for table 'phpwebgallery_user_access'
+--
+
+DROP TABLE IF EXISTS phpwebgallery_user_access;
+CREATE TABLE phpwebgallery_user_access (
+  user_id smallint(5) unsigned NOT NULL default '0',
+  cat_id smallint(5) unsigned NOT NULL default '0',
+  PRIMARY KEY  (user_id,cat_id)
+) TYPE=MyISAM;
+
+--
+-- Table structure for table 'phpwebgallery_user_forbidden'
+--
+
+DROP TABLE IF EXISTS phpwebgallery_user_forbidden;
+CREATE TABLE phpwebgallery_user_forbidden (
+  user_id smallint(5) unsigned NOT NULL default '0',
+  need_update enum('true','false') NOT NULL default 'true',
+  forbidden_categories text,
+  PRIMARY KEY  (user_id)
+) TYPE=MyISAM;
+
+--
+-- Table structure for table 'phpwebgallery_user_group'
+--
+
+DROP TABLE IF EXISTS phpwebgallery_user_group;
+CREATE TABLE phpwebgallery_user_group (
+  user_id smallint(5) unsigned NOT NULL default '0',
+  group_id smallint(5) unsigned NOT NULL default '0',
+  PRIMARY KEY  (group_id,user_id)
+) TYPE=MyISAM;
+
+--
+-- Table structure for table 'phpwebgallery_users'
+--
+
+DROP TABLE IF EXISTS phpwebgallery_users;
+CREATE TABLE phpwebgallery_users (
+  id smallint(5) unsigned NOT NULL auto_increment,
+  username varchar(20) binary NOT NULL default '',
+  password varchar(255) NOT NULL default '',
+  mail_address varchar(255) default NULL,
+  nb_image_line tinyint(1) unsigned NOT NULL default '5',
+  nb_line_page tinyint(3) unsigned NOT NULL default '3',
+  status enum('admin','guest') NOT NULL default 'guest',
+  language varchar(50) NOT NULL default 'english',
+  maxwidth smallint(6) default NULL,
+  maxheight smallint(6) default NULL,
+  expand enum('true','false') NOT NULL default 'false',
+  show_nb_comments enum('true','false') NOT NULL default 'false',
+  recent_period tinyint(3) unsigned NOT NULL default '7',
+  template varchar(255) NOT NULL default 'default',
+  PRIMARY KEY  (id),
+  UNIQUE KEY users_ui1 (username)
+) TYPE=MyISAM;
+
+--
+-- Table structure for table 'phpwebgallery_waiting'
+--
+
+DROP TABLE IF EXISTS phpwebgallery_waiting;
+CREATE TABLE phpwebgallery_waiting (
+  id int(10) unsigned NOT NULL auto_increment,
+  storage_category_id smallint(5) unsigned NOT NULL default '0',
+  file varchar(255) NOT NULL default '',
+  username varchar(255) NOT NULL default '',
+  mail_address varchar(255) NOT NULL default '',
+  date int(10) unsigned NOT NULL default '0',
+  tn_ext char(3) default NULL,
+  validated enum('true','false') NOT NULL default 'false',
+  infos text,
+  PRIMARY KEY  (id)
+) TYPE=MyISAM;
+
Index: /branches/1.4/install/upgrade_1.3.0.php
===================================================================
--- /branches/1.4/install/upgrade_1.3.0.php	(revision 3249)
+++ /branches/1.4/install/upgrade_1.3.0.php	(revision 3249)
@@ -0,0 +1,401 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if (!defined('IN_UPGRADE') or !IN_UPGRADE)
+{
+  die('Hacking attempt!');
+}
+
+$last_time = get_moment();
+
+// save data before deletion
+$query = '
+SELECT prefix_thumbnail, mail_webmaster
+  FROM '.PREFIX_TABLE.'config
+;';
+$save = mysql_fetch_array(mysql_query($query));
+
+$queries = array(
+  "
+DROP TABLE phpwebgallery_config
+;",
+
+  "
+CREATE TABLE phpwebgallery_config (
+  param varchar(40) NOT NULL default '',
+  value varchar(255) default NULL,
+  comment varchar(255) default NULL,
+  PRIMARY KEY  (param)
+) TYPE=MyISAM COMMENT='configuration table'
+;",
+
+  "
+ALTER TABLE phpwebgallery_categories
+  CHANGE COLUMN site_id site_id tinyint(4) unsigned default '1',
+  ADD COLUMN commentable enum('true','false') NOT NULL default 'true',
+  ADD COLUMN uppercats varchar(255) NOT NULL default '',
+  ADD COLUMN global_rank varchar(255) default NULL,
+  ADD INDEX categories_i2 (id_uppercat)
+;",
+
+  "
+ALTER TABLE phpwebgallery_comments
+  ADD COLUMN date_temp int(11) unsigned
+;",
+
+  "
+UPDATE phpwebgallery_comments
+  SET date_temp = date
+;",
+  
+  "
+ALTER TABLE phpwebgallery_comments
+  CHANGE COLUMN date date datetime NOT NULL default '0000-00-00 00:00:00'
+;",
+
+  "
+UPDATE phpwebgallery_comments
+  SET date = FROM_UNIXTIME(date_temp)
+;",
+
+  "
+ALTER TABLE phpwebgallery_comments
+  DROP COLUMN date_temp
+;",
+
+  "
+ALTER TABLE phpwebgallery_favorites
+  DROP INDEX user_id,
+  ADD PRIMARY KEY (user_id,image_id)
+;",
+
+  "
+ALTER TABLE phpwebgallery_history
+  ADD COLUMN date_temp int(11) unsigned
+;",
+
+  "
+UPDATE phpwebgallery_history
+  SET date_temp = date
+;",
+  
+  "
+ALTER TABLE phpwebgallery_history
+  CHANGE COLUMN date date datetime NOT NULL default '0000-00-00 00:00:00'
+;",
+
+  "
+UPDATE phpwebgallery_history
+  SET date = FROM_UNIXTIME(date_temp)
+;",
+
+  "
+ALTER TABLE phpwebgallery_history
+  DROP COLUMN date_temp
+;",
+
+  "
+ALTER TABLE phpwebgallery_history
+  ADD INDEX history_i1 (date)
+;",
+
+  "
+ALTER TABLE phpwebgallery_image_category
+  ADD INDEX image_category_i1 (image_id),
+  ADD INDEX image_category_i2 (category_id)
+;",
+
+  "
+ALTER TABLE phpwebgallery_images
+  CHANGE COLUMN tn_ext tn_ext varchar(4) default '',
+  ADD COLUMN path varchar(255) NOT NULL default '',
+  ADD COLUMN date_metadata_update date default NULL,
+  ADD COLUMN average_rate float(5,2) unsigned default NULL,
+  ADD COLUMN representative_ext varchar(4) default NULL,
+  DROP INDEX storage_category_id,
+  ADD INDEX images_i1 (storage_category_id),
+  ADD INDEX images_i2 (date_available),
+  ADD INDEX images_i3 (average_rate),
+  ADD INDEX images_i4 (hit),
+  ADD INDEX images_i5 (date_creation)
+;",
+  
+  "
+ALTER TABLE phpwebgallery_sessions
+  DROP COLUMN ip
+;",
+
+    "
+ALTER TABLE phpwebgallery_sessions
+  ADD COLUMN expiration_temp int(11) unsigned
+;",
+
+  "
+UPDATE phpwebgallery_sessions
+  SET expiration_temp = expiration
+;",
+  
+  "
+ALTER TABLE phpwebgallery_sessions
+  CHANGE COLUMN expiration expiration datetime NOT NULL default '0000-00-00 00:00:00'
+;",
+
+  "
+UPDATE phpwebgallery_sessions
+  SET expiration = FROM_UNIXTIME(expiration_temp)
+;",
+
+  "
+ALTER TABLE phpwebgallery_sessions
+  DROP COLUMN expiration_temp
+;",
+  
+  "
+ALTER TABLE phpwebgallery_sites
+  DROP INDEX galleries_url,
+  ADD UNIQUE sites_ui1 (galleries_url)
+;",
+  
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN long_period,
+  DROP COLUMN short_period,
+  ADD COLUMN recent_period tinyint(3) unsigned NOT NULL default '7',
+  DROP INDEX username,
+  ADD UNIQUE users_ui1 (username)
+;",
+  
+  "
+CREATE TABLE phpwebgallery_rate (
+  user_id smallint(5) unsigned NOT NULL default '0',
+  element_id mediumint(8) unsigned NOT NULL default '0',
+  rate tinyint(2) unsigned NOT NULL default '0',
+  PRIMARY KEY  (user_id,element_id)
+) TYPE=MyISAM
+;",
+
+  "
+CREATE TABLE phpwebgallery_user_forbidden (
+  user_id smallint(5) unsigned NOT NULL default '0',
+  need_update enum('true','false') NOT NULL default 'true',
+  forbidden_categories text,
+  PRIMARY KEY  (user_id)
+) TYPE=MyISAM
+;",
+
+  "
+UPDATE phpwebgallery_users
+  SET language = 'en_UK.iso-8859-1'
+    , template = 'default'
+;",
+
+  "
+DELETE FROM phpwebgallery_user_access
+;",
+
+  "
+DELETE FROM phpwebgallery_group_access
+;"
+
+  );
+
+foreach ($queries as $query)
+{
+  $query = str_replace('phpwebgallery_', PREFIX_TABLE, $query);
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' Basic database structure upgrade done</pre>';
+flush();
+$last_time = $new_time;
+
+execute_sqlfile(PHPWG_ROOT_PATH.'install/config.sql',
+                'phpwebgallery_',
+                PREFIX_TABLE);
+
+$queries = array(
+  "
+UPDATE phpwebgallery_config
+  SET value = '".$save['prefix_thumbnail']."'
+  WHERE param = 'prefix_thumbnail'
+;",
+
+  "
+UPDATE phpwebgallery_config
+  SET value = '".$save['mail_webmaster']."'
+  WHERE param = 'mail_webmaster'
+;"
+  );
+
+foreach ($queries as $query)
+{
+  $query = str_replace('phpwebgallery_', PREFIX_TABLE, $query);
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' Saved configuration information restored</pre>';
+flush();
+$last_time = $new_time;
+
+// filling the new column categories.uppercats
+$id_uppercats = array();
+
+$query = '
+SELECT id, id_uppercat
+  FROM '.CATEGORIES_TABLE.'
+;';
+$result = pwg_query($query);
+while ($row = mysql_fetch_array($result))
+{
+  if (!isset($row['id_uppercat']) or $row['id_uppercat'] == '')
+  {
+    $row['id_uppercat'] = 'NULL';
+  }
+  $id_uppercats[$row['id']] = $row['id_uppercat'];
+}
+
+$datas = array();
+
+foreach (array_keys($id_uppercats) as $id)
+{
+  $data = array();
+  $data['id'] = $id;
+  $uppercats = array();
+  
+  array_push($uppercats, $id);
+  while (isset($id_uppercats[$id]) and $id_uppercats[$id] != 'NULL')
+  {
+    array_push($uppercats, $id_uppercats[$id]);
+    $id = $id_uppercats[$id];
+  }
+  $data['uppercats'] = implode(',', array_reverse($uppercats));
+
+  array_push($datas, $data);
+}
+
+$fields = array('primary' => array('id'), 'update' => array('uppercats'));
+mass_updates(CATEGORIES_TABLE, $fields, $datas);
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' filling the new column categories.uppercats</pre>';
+flush();
+$last_time = $new_time;
+
+// refresh calculated datas
+ordering();
+update_global_rank();
+update_category();
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' Calculated data updated (categories.rank, categories.global_rank,
+categories.date_last, categories.representative_picture_id,
+categories.nb_images)</pre>';
+flush();
+$last_time = $new_time;
+
+// update calculated field "images.path"
+$cat_ids = array();
+
+$query = '
+SELECT DISTINCT(storage_category_id) AS unique_storage_category_id
+  FROM '.IMAGES_TABLE.'
+;';
+$result = pwg_query($query);
+while ($row = mysql_fetch_array($result))
+{
+  array_push($cat_ids, $row['unique_storage_category_id']);
+}
+$fulldirs = get_fulldirs($cat_ids);
+
+foreach ($cat_ids as $cat_id)
+{
+  $query = '
+UPDATE '.IMAGES_TABLE.'
+  SET path = CONCAT(\''.$fulldirs[$cat_id].'\',\'/\',file)
+  WHERE storage_category_id = '.$cat_id.'
+;';
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' new column images.path filled</pre>';
+flush();
+$last_time = $new_time;
+
+// all sub-categories of private categories become private
+$cat_ids = array();
+
+$query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE status = \'private\'
+;';
+$result = pwg_query($query);
+while ($row = mysql_fetch_array($result))
+{
+  array_push($cat_ids, $row['id']);
+}
+
+if (count($cat_ids) > 0)
+{
+  $privates = get_subcat_ids($cat_ids);
+
+  $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET status = \'private\'
+  WHERE id IN ('.implode(',', $privates).')
+;';
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' all sub-categories of private categories become private</pre>';
+flush();
+$last_time = $new_time;
+
+$infos = array(
+  'user permissions and group permissions have been erased',
+
+  'only thumbnails prefix and webmaster mail address have been saved from
+previous configuration',
+
+  'in include/mysql.inc.php, before
+<pre style="background-color:lightgray">?&gt;</pre>
+insert
+<pre style="background-color:lightgray">define(\'PHPWG_INSTALLED\', true);<pre>'
+  
+  );
+
+?>
Index: /branches/1.4/install/upgrade_1.3.1.php
===================================================================
--- /branches/1.4/install/upgrade_1.3.1.php	(revision 3249)
+++ /branches/1.4/install/upgrade_1.3.1.php	(revision 3249)
@@ -0,0 +1,363 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if (!defined('IN_UPGRADE') or !IN_UPGRADE)
+{
+  die('Hacking attempt!');
+}
+
+$last_time = get_moment();
+
+// save data before deletion
+$query = '
+SELECT prefix_thumbnail, mail_webmaster
+  FROM '.PREFIX_TABLE.'config
+;';
+$save = mysql_fetch_array(mysql_query($query));
+
+$queries = array(
+  "
+DROP TABLE phpwebgallery_config
+;",
+
+  "
+CREATE TABLE phpwebgallery_config (
+  param varchar(40) NOT NULL default '',
+  value varchar(255) default NULL,
+  comment varchar(255) default NULL,
+  PRIMARY KEY  (param)
+) TYPE=MyISAM COMMENT='configuration table'
+;",
+
+  "
+ALTER TABLE phpwebgallery_categories
+  CHANGE COLUMN site_id site_id tinyint(4) unsigned default '1',
+  ADD COLUMN commentable enum('true','false') NOT NULL default 'true',
+  ADD COLUMN global_rank varchar(255) default NULL,
+  DROP INDEX id,
+  DROP INDEX id_uppercat,
+  ADD INDEX categories_i2 (id_uppercat)
+;",
+
+  "
+ALTER TABLE phpwebgallery_comments
+  ADD COLUMN date_temp int(11) unsigned
+;",
+
+  "
+UPDATE phpwebgallery_comments
+  SET date_temp = date
+;",
+  
+  "
+ALTER TABLE phpwebgallery_comments
+  CHANGE COLUMN date date datetime NOT NULL default '0000-00-00 00:00:00'
+;",
+
+  "
+UPDATE phpwebgallery_comments
+  SET date = FROM_UNIXTIME(date_temp)
+;",
+
+  "
+ALTER TABLE phpwebgallery_comments
+  DROP COLUMN date_temp
+;",
+
+  "
+ALTER TABLE phpwebgallery_favorites
+  DROP INDEX user_id,
+  ADD PRIMARY KEY (user_id,image_id)
+;",
+
+  "
+ALTER TABLE phpwebgallery_history
+  ADD COLUMN date_temp int(11) unsigned
+;",
+
+  "
+UPDATE phpwebgallery_history
+  SET date_temp = date
+;",
+  
+  "
+ALTER TABLE phpwebgallery_history
+  CHANGE COLUMN date date datetime NOT NULL default '0000-00-00 00:00:00'
+;",
+
+  "
+UPDATE phpwebgallery_history
+  SET date = FROM_UNIXTIME(date_temp)
+;",
+
+  "
+ALTER TABLE phpwebgallery_history
+  DROP COLUMN date_temp
+;",
+
+  "
+ALTER TABLE phpwebgallery_history
+  ADD INDEX history_i1 (date)
+;",
+
+  "
+ALTER TABLE phpwebgallery_image_category
+  DROP INDEX image_id,
+  DROP INDEX category_id,
+  ADD INDEX image_category_i1 (image_id),
+  ADD INDEX image_category_i2 (category_id)
+;",
+
+  "
+ALTER TABLE phpwebgallery_images
+  CHANGE COLUMN tn_ext tn_ext varchar(4) default '',
+  ADD COLUMN path varchar(255) NOT NULL default '',
+  ADD COLUMN date_metadata_update date default NULL,
+  ADD COLUMN average_rate float(5,2) unsigned default NULL,
+  ADD COLUMN representative_ext varchar(4) default NULL,
+  DROP INDEX storage_category_id,
+  ADD INDEX images_i1 (storage_category_id),
+  ADD INDEX images_i2 (date_available),
+  ADD INDEX images_i3 (average_rate),
+  ADD INDEX images_i4 (hit),
+  ADD INDEX images_i5 (date_creation)
+;",
+  
+  "
+ALTER TABLE phpwebgallery_sessions
+  DROP COLUMN ip
+;",
+
+    "
+ALTER TABLE phpwebgallery_sessions
+  ADD COLUMN expiration_temp int(11) unsigned
+;",
+
+  "
+UPDATE phpwebgallery_sessions
+  SET expiration_temp = expiration
+;",
+  
+  "
+ALTER TABLE phpwebgallery_sessions
+  CHANGE COLUMN expiration expiration datetime NOT NULL default '0000-00-00 00:00:00'
+;",
+
+  "
+UPDATE phpwebgallery_sessions
+  SET expiration = FROM_UNIXTIME(expiration_temp)
+;",
+
+  "
+ALTER TABLE phpwebgallery_sessions
+  DROP COLUMN expiration_temp
+;",
+  
+  "
+ALTER TABLE phpwebgallery_sites
+  DROP INDEX galleries_url,
+  ADD UNIQUE sites_ui1 (galleries_url)
+;",
+  
+  "
+DROP TABLE phpwebgallery_user_category
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN long_period,
+  DROP COLUMN short_period,
+  DROP COLUMN forbidden_categories,
+  ADD COLUMN recent_period tinyint(3) unsigned NOT NULL default '7',
+  DROP INDEX username,
+  ADD UNIQUE users_ui1 (username)
+;",
+  
+  "
+CREATE TABLE phpwebgallery_rate (
+  user_id smallint(5) unsigned NOT NULL default '0',
+  element_id mediumint(8) unsigned NOT NULL default '0',
+  rate tinyint(2) unsigned NOT NULL default '0',
+  PRIMARY KEY  (user_id,element_id)
+) TYPE=MyISAM
+;",
+
+  "
+CREATE TABLE phpwebgallery_user_forbidden (
+  user_id smallint(5) unsigned NOT NULL default '0',
+  need_update enum('true','false') NOT NULL default 'true',
+  forbidden_categories text,
+  PRIMARY KEY  (user_id)
+) TYPE=MyISAM
+;",
+
+  "
+UPDATE phpwebgallery_users
+  SET language = 'en_UK.iso-8859-1'
+    , template = 'default'
+;",
+
+  "
+DELETE FROM phpwebgallery_user_access
+;",
+
+  "
+DELETE FROM phpwebgallery_group_access
+;"
+
+  );
+
+foreach ($queries as $query)
+{
+  $query = str_replace('phpwebgallery_', PREFIX_TABLE, $query);
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' Basic database structure upgrade done</pre>';
+flush();
+$last_time = $new_time;
+
+execute_sqlfile(PHPWG_ROOT_PATH.'install/config.sql',
+                'phpwebgallery_',
+                PREFIX_TABLE);
+
+$queries = array(
+  "
+UPDATE phpwebgallery_config
+  SET value = '".$save['prefix_thumbnail']."'
+  WHERE param = 'prefix_thumbnail'
+;",
+
+  "
+UPDATE phpwebgallery_config
+  SET value = '".$save['mail_webmaster']."'
+  WHERE param = 'mail_webmaster'
+;"
+  );
+
+foreach ($queries as $query)
+{
+  $query = str_replace('phpwebgallery_', PREFIX_TABLE, $query);
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' Saved configuration information restored</pre>';
+flush();
+$last_time = $new_time;
+
+ordering();
+update_global_rank();
+update_category();
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' Calculated data updated (categories.rank, categories.global_rank,
+categories.date_last, categories.representative_picture_id,
+categories.nb_images)</pre>';
+flush();
+$last_time = $new_time;
+
+// update calculated field "images.path"
+$cat_ids = array();
+
+$query = '
+SELECT DISTINCT(storage_category_id) AS unique_storage_category_id
+  FROM '.IMAGES_TABLE.'
+;';
+$result = pwg_query($query);
+while ($row = mysql_fetch_array($result))
+{
+  array_push($cat_ids, $row['unique_storage_category_id']);
+}
+$fulldirs = get_fulldirs($cat_ids);
+
+foreach ($cat_ids as $cat_id)
+{
+  $query = '
+UPDATE '.IMAGES_TABLE.'
+  SET path = CONCAT(\''.$fulldirs[$cat_id].'\',\'/\',file)
+  WHERE storage_category_id = '.$cat_id.'
+;';
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' new column images.path filled</pre>';
+flush();
+$last_time = $new_time;
+
+// all sub-categories of private categories become private
+$cat_ids = array();
+
+$query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE status = \'private\'
+;';
+$result = pwg_query($query);
+while ($row = mysql_fetch_array($result))
+{
+  array_push($cat_ids, $row['id']);
+}
+
+if (count($cat_ids) > 0)
+{
+  $privates = get_subcat_ids($cat_ids);
+
+  $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET status = \'private\'
+  WHERE id IN ('.implode(',', $privates).')
+;';
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' all sub-categories of private categories become private</pre>';
+flush();
+$last_time = $new_time;
+
+$infos = array(
+  'user permissions and group permissions have been erased',
+
+  'only thumbnails prefix and webmaster mail address have been saved from
+previous configuration',
+
+  'in include/mysql.inc.php, before
+<pre style="background-color:lightgray">?&gt;</pre>
+insert
+<pre style="background-color:lightgray">define(\'PHPWG_INSTALLED\', true);<pre>'
+  
+  );
+
+?>
Index: /branches/1.4/install/upgrade_1.3.2.php
===================================================================
--- /branches/1.4/install/upgrade_1.3.2.php	(revision 3249)
+++ /branches/1.4/install/upgrade_1.3.2.php	(revision 3249)
@@ -0,0 +1,362 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if (!defined('IN_UPGRADE') or !IN_UPGRADE)
+{
+  die('Hacking attempt!');
+}
+
+$last_time = get_moment();
+
+// save data before deletion
+$query = '
+SELECT prefix_thumbnail, mail_webmaster
+  FROM '.PREFIX_TABLE.'config
+;';
+$save = mysql_fetch_array(mysql_query($query));
+
+$queries = array(
+  "
+DROP TABLE phpwebgallery_config
+;",
+
+  "
+CREATE TABLE phpwebgallery_config (
+  param varchar(40) NOT NULL default '',
+  value varchar(255) default NULL,
+  comment varchar(255) default NULL,
+  PRIMARY KEY  (param)
+) TYPE=MyISAM COMMENT='configuration table'
+;",
+
+  "
+ALTER TABLE phpwebgallery_categories
+  CHANGE COLUMN site_id site_id tinyint(4) unsigned default '1',
+  ADD COLUMN commentable enum('true','false') NOT NULL default 'true',
+  ADD COLUMN global_rank varchar(255) default NULL,
+  DROP INDEX id_uppercat,
+  ADD INDEX categories_i2 (id_uppercat)
+;",
+
+  "
+ALTER TABLE phpwebgallery_comments
+  ADD COLUMN date_temp int(11) unsigned
+;",
+
+  "
+UPDATE phpwebgallery_comments
+  SET date_temp = date
+;",
+  
+  "
+ALTER TABLE phpwebgallery_comments
+  CHANGE COLUMN date date datetime NOT NULL default '0000-00-00 00:00:00'
+;",
+
+  "
+UPDATE phpwebgallery_comments
+  SET date = FROM_UNIXTIME(date_temp)
+;",
+
+  "
+ALTER TABLE phpwebgallery_comments
+  DROP COLUMN date_temp
+;",
+
+  "
+ALTER TABLE phpwebgallery_favorites
+  DROP INDEX user_id,
+  ADD PRIMARY KEY (user_id,image_id)
+;",
+
+  "
+ALTER TABLE phpwebgallery_history
+  ADD COLUMN date_temp int(11) unsigned
+;",
+
+  "
+UPDATE phpwebgallery_history
+  SET date_temp = date
+;",
+  
+  "
+ALTER TABLE phpwebgallery_history
+  CHANGE COLUMN date date datetime NOT NULL default '0000-00-00 00:00:00'
+;",
+
+  "
+UPDATE phpwebgallery_history
+  SET date = FROM_UNIXTIME(date_temp)
+;",
+
+  "
+ALTER TABLE phpwebgallery_history
+  DROP COLUMN date_temp
+;",
+
+  "
+ALTER TABLE phpwebgallery_history
+  ADD INDEX history_i1 (date)
+;",
+
+  "
+ALTER TABLE phpwebgallery_image_category
+  DROP INDEX image_id,
+  DROP INDEX category_id,
+  ADD INDEX image_category_i1 (image_id),
+  ADD INDEX image_category_i2 (category_id)
+;",
+
+  "
+ALTER TABLE phpwebgallery_images
+  CHANGE COLUMN tn_ext tn_ext varchar(4) default '',
+  ADD COLUMN path varchar(255) NOT NULL default '',
+  ADD COLUMN date_metadata_update date default NULL,
+  ADD COLUMN average_rate float(5,2) unsigned default NULL,
+  ADD COLUMN representative_ext varchar(4) default NULL,
+  DROP INDEX storage_category_id,
+  ADD INDEX images_i1 (storage_category_id),
+  ADD INDEX images_i2 (date_available),
+  ADD INDEX images_i3 (average_rate),
+  ADD INDEX images_i4 (hit),
+  ADD INDEX images_i5 (date_creation)
+;",
+  
+  "
+ALTER TABLE phpwebgallery_sessions
+  DROP COLUMN ip
+;",
+
+    "
+ALTER TABLE phpwebgallery_sessions
+  ADD COLUMN expiration_temp int(11) unsigned
+;",
+
+  "
+UPDATE phpwebgallery_sessions
+  SET expiration_temp = expiration
+;",
+  
+  "
+ALTER TABLE phpwebgallery_sessions
+  CHANGE COLUMN expiration expiration datetime NOT NULL default '0000-00-00 00:00:00'
+;",
+
+  "
+UPDATE phpwebgallery_sessions
+  SET expiration = FROM_UNIXTIME(expiration_temp)
+;",
+
+  "
+ALTER TABLE phpwebgallery_sessions
+  DROP COLUMN expiration_temp
+;",
+  
+  "
+ALTER TABLE phpwebgallery_sites
+  DROP INDEX galleries_url,
+  ADD UNIQUE sites_ui1 (galleries_url)
+;",
+  
+  "
+DROP TABLE phpwebgallery_user_category
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN long_period,
+  DROP COLUMN short_period,
+  DROP COLUMN forbidden_categories,
+  ADD COLUMN recent_period tinyint(3) unsigned NOT NULL default '7',
+  DROP INDEX username,
+  ADD UNIQUE users_ui1 (username)
+;",
+  
+  "
+CREATE TABLE phpwebgallery_rate (
+  user_id smallint(5) unsigned NOT NULL default '0',
+  element_id mediumint(8) unsigned NOT NULL default '0',
+  rate tinyint(2) unsigned NOT NULL default '0',
+  PRIMARY KEY  (user_id,element_id)
+) TYPE=MyISAM
+;",
+
+  "
+CREATE TABLE phpwebgallery_user_forbidden (
+  user_id smallint(5) unsigned NOT NULL default '0',
+  need_update enum('true','false') NOT NULL default 'true',
+  forbidden_categories text,
+  PRIMARY KEY  (user_id)
+) TYPE=MyISAM
+;",
+
+  "
+UPDATE phpwebgallery_users
+  SET language = 'en_UK.iso-8859-1'
+    , template = 'default'
+;",
+
+  "
+DELETE FROM phpwebgallery_user_access
+;",
+
+  "
+DELETE FROM phpwebgallery_group_access
+;"
+
+  );
+
+foreach ($queries as $query)
+{
+  $query = str_replace('phpwebgallery_', PREFIX_TABLE, $query);
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' Basic database structure upgrade done</pre>';
+flush();
+$last_time = $new_time;
+
+execute_sqlfile(PHPWG_ROOT_PATH.'install/config.sql',
+                'phpwebgallery_',
+                PREFIX_TABLE);
+
+$queries = array(
+  "
+UPDATE phpwebgallery_config
+  SET value = '".$save['prefix_thumbnail']."'
+  WHERE param = 'prefix_thumbnail'
+;",
+
+  "
+UPDATE phpwebgallery_config
+  SET value = '".$save['mail_webmaster']."'
+  WHERE param = 'mail_webmaster'
+;"
+  );
+
+foreach ($queries as $query)
+{
+  $query = str_replace('phpwebgallery_', PREFIX_TABLE, $query);
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' Saved configuration information restored</pre>';
+flush();
+$last_time = $new_time;
+
+ordering();
+update_global_rank();
+update_category();
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' Calculated data updated (categories.rank, categories.global_rank,
+categories.date_last, categories.representative_picture_id,
+categories.nb_images)</pre>';
+flush();
+$last_time = $new_time;
+
+// update calculated field "images.path"
+$cat_ids = array();
+
+$query = '
+SELECT DISTINCT(storage_category_id) AS unique_storage_category_id
+  FROM '.IMAGES_TABLE.'
+;';
+$result = pwg_query($query);
+while ($row = mysql_fetch_array($result))
+{
+  array_push($cat_ids, $row['unique_storage_category_id']);
+}
+$fulldirs = get_fulldirs($cat_ids);
+
+foreach ($cat_ids as $cat_id)
+{
+  $query = '
+UPDATE '.IMAGES_TABLE.'
+  SET path = CONCAT(\''.$fulldirs[$cat_id].'\',\'/\',file)
+  WHERE storage_category_id = '.$cat_id.'
+;';
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' new column images.path filled</pre>';
+flush();
+$last_time = $new_time;
+
+// all sub-categories of private categories become private
+$cat_ids = array();
+
+$query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE status = \'private\'
+;';
+$result = pwg_query($query);
+while ($row = mysql_fetch_array($result))
+{
+  array_push($cat_ids, $row['id']);
+}
+
+if (count($cat_ids) > 0)
+{
+  $privates = get_subcat_ids($cat_ids);
+
+  $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET status = \'private\'
+  WHERE id IN ('.implode(',', $privates).')
+;';
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' all sub-categories of private categories become private</pre>';
+flush();
+$last_time = $new_time;
+
+$infos = array(
+  'user permissions and group permissions have been erased',
+
+  'only thumbnails prefix and webmaster mail address have been saved from
+previous configuration',
+
+  'in include/mysql.inc.php, before
+<pre style="background-color:lightgray">?&gt;</pre>
+insert
+<pre style="background-color:lightgray">define(\'PHPWG_INSTALLED\', true);<pre>'
+  
+  );
+
+?>
Index: /branches/1.4/install/upgrade_1.3.3.php
===================================================================
--- /branches/1.4/install/upgrade_1.3.3.php	(revision 3249)
+++ /branches/1.4/install/upgrade_1.3.3.php	(revision 3249)
@@ -0,0 +1,362 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if (!defined('IN_UPGRADE') or !IN_UPGRADE)
+{
+  die('Hacking attempt!');
+}
+
+$last_time = get_moment();
+
+// save data before deletion
+$query = '
+SELECT prefix_thumbnail, mail_webmaster
+  FROM '.PREFIX_TABLE.'config
+;';
+$save = mysql_fetch_array(mysql_query($query));
+
+$queries = array(
+  "
+DROP TABLE phpwebgallery_config
+;",
+
+  "
+CREATE TABLE phpwebgallery_config (
+  param varchar(40) NOT NULL default '',
+  value varchar(255) default NULL,
+  comment varchar(255) default NULL,
+  PRIMARY KEY  (param)
+) TYPE=MyISAM COMMENT='configuration table'
+;",
+
+  "
+ALTER TABLE phpwebgallery_categories
+  CHANGE COLUMN site_id site_id tinyint(4) unsigned default '1',
+  ADD COLUMN commentable enum('true','false') NOT NULL default 'true',
+  ADD COLUMN global_rank varchar(255) default NULL,
+  DROP INDEX id_uppercat,
+  ADD INDEX categories_i2 (id_uppercat)
+;",
+
+  "
+ALTER TABLE phpwebgallery_comments
+  ADD COLUMN date_temp int(11) unsigned
+;",
+
+  "
+UPDATE phpwebgallery_comments
+  SET date_temp = date
+;",
+  
+  "
+ALTER TABLE phpwebgallery_comments
+  CHANGE COLUMN date date datetime NOT NULL default '0000-00-00 00:00:00'
+;",
+
+  "
+UPDATE phpwebgallery_comments
+  SET date = FROM_UNIXTIME(date_temp)
+;",
+
+  "
+ALTER TABLE phpwebgallery_comments
+  DROP COLUMN date_temp
+;",
+
+  "
+ALTER TABLE phpwebgallery_favorites
+  DROP INDEX user_id,
+  ADD PRIMARY KEY (user_id,image_id)
+;",
+
+  "
+ALTER TABLE phpwebgallery_history
+  ADD COLUMN date_temp int(11) unsigned
+;",
+
+  "
+UPDATE phpwebgallery_history
+  SET date_temp = date
+;",
+  
+  "
+ALTER TABLE phpwebgallery_history
+  CHANGE COLUMN date date datetime NOT NULL default '0000-00-00 00:00:00'
+;",
+
+  "
+UPDATE phpwebgallery_history
+  SET date = FROM_UNIXTIME(date_temp)
+;",
+
+  "
+ALTER TABLE phpwebgallery_history
+  DROP COLUMN date_temp
+;",
+
+  "
+ALTER TABLE phpwebgallery_history
+  ADD INDEX history_i1 (date)
+;",
+
+  "
+ALTER TABLE phpwebgallery_image_category
+  DROP INDEX image_id,
+  DROP INDEX category_id,
+  ADD INDEX image_category_i1 (image_id),
+  ADD INDEX image_category_i2 (category_id)
+;",
+
+  "
+ALTER TABLE phpwebgallery_images
+  CHANGE COLUMN tn_ext tn_ext varchar(4) default '',
+  ADD COLUMN path varchar(255) NOT NULL default '',
+  ADD COLUMN date_metadata_update date default NULL,
+  ADD COLUMN average_rate float(5,2) unsigned default NULL,
+  ADD COLUMN representative_ext varchar(4) default NULL,
+  DROP INDEX storage_category_id,
+  ADD INDEX images_i1 (storage_category_id),
+  ADD INDEX images_i2 (date_available),
+  ADD INDEX images_i3 (average_rate),
+  ADD INDEX images_i4 (hit),
+  ADD INDEX images_i5 (date_creation)
+;",
+  
+  "
+ALTER TABLE phpwebgallery_sessions
+  DROP COLUMN ip
+;",
+
+    "
+ALTER TABLE phpwebgallery_sessions
+  ADD COLUMN expiration_temp int(11) unsigned
+;",
+
+  "
+UPDATE phpwebgallery_sessions
+  SET expiration_temp = expiration
+;",
+  
+  "
+ALTER TABLE phpwebgallery_sessions
+  CHANGE COLUMN expiration expiration datetime NOT NULL default '0000-00-00 00:00:00'
+;",
+
+  "
+UPDATE phpwebgallery_sessions
+  SET expiration = FROM_UNIXTIME(expiration_temp)
+;",
+
+  "
+ALTER TABLE phpwebgallery_sessions
+  DROP COLUMN expiration_temp
+;",
+  
+  "
+ALTER TABLE phpwebgallery_sites
+  DROP INDEX galleries_url,
+  ADD UNIQUE sites_ui1 (galleries_url)
+;",
+  
+  "
+DROP TABLE phpwebgallery_user_category
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN long_period,
+  DROP COLUMN short_period,
+  DROP COLUMN forbidden_categories,
+  ADD COLUMN recent_period tinyint(3) unsigned NOT NULL default '7',
+  DROP INDEX username,
+  ADD UNIQUE users_ui1 (username)
+;",
+  
+  "
+CREATE TABLE phpwebgallery_rate (
+  user_id smallint(5) unsigned NOT NULL default '0',
+  element_id mediumint(8) unsigned NOT NULL default '0',
+  rate tinyint(2) unsigned NOT NULL default '0',
+  PRIMARY KEY  (user_id,element_id)
+) TYPE=MyISAM
+;",
+
+  "
+CREATE TABLE phpwebgallery_user_forbidden (
+  user_id smallint(5) unsigned NOT NULL default '0',
+  need_update enum('true','false') NOT NULL default 'true',
+  forbidden_categories text,
+  PRIMARY KEY  (user_id)
+) TYPE=MyISAM
+;",
+
+  "
+UPDATE phpwebgallery_users
+  SET language = 'en_UK.iso-8859-1'
+    , template = 'default'
+;",
+
+  "
+DELETE FROM phpwebgallery_user_access
+;",
+
+  "
+DELETE FROM phpwebgallery_group_access
+;"
+
+  );
+
+foreach ($queries as $query)
+{
+  $query = str_replace('phpwebgallery_', PREFIX_TABLE, $query);
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' Basic database structure upgrade done</pre>';
+flush();
+$last_time = $new_time;
+
+execute_sqlfile(PHPWG_ROOT_PATH.'install/config.sql',
+                'phpwebgallery_',
+                PREFIX_TABLE);
+
+$queries = array(
+  "
+UPDATE phpwebgallery_config
+  SET value = '".$save['prefix_thumbnail']."'
+  WHERE param = 'prefix_thumbnail'
+;",
+
+  "
+UPDATE phpwebgallery_config
+  SET value = '".$save['mail_webmaster']."'
+  WHERE param = 'mail_webmaster'
+;"
+  );
+
+foreach ($queries as $query)
+{
+  $query = str_replace('phpwebgallery_', PREFIX_TABLE, $query);
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' Saved configuration information restored</pre>';
+flush();
+$last_time = $new_time;
+
+ordering();
+update_global_rank();
+update_category();
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' Calculated data updated (categories.rank, categories.global_rank,
+categories.date_last, categories.representative_picture_id,
+categories.nb_images)</pre>';
+flush();
+$last_time = $new_time;
+
+// update calculated field "images.path"
+$cat_ids = array();
+
+$query = '
+SELECT DISTINCT(storage_category_id) AS unique_storage_category_id
+  FROM '.IMAGES_TABLE.'
+;';
+$result = pwg_query($query);
+while ($row = mysql_fetch_array($result))
+{
+  array_push($cat_ids, $row['unique_storage_category_id']);
+}
+$fulldirs = get_fulldirs($cat_ids);
+
+foreach ($cat_ids as $cat_id)
+{
+  $query = '
+UPDATE '.IMAGES_TABLE.'
+  SET path = CONCAT(\''.$fulldirs[$cat_id].'\',\'/\',file)
+  WHERE storage_category_id = '.$cat_id.'
+;';
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' new column images.path filled</pre>';
+flush();
+$last_time = $new_time;
+
+// all sub-categories of private categories become private
+$cat_ids = array();
+
+$query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE status = \'private\'
+;';
+$result = pwg_query($query);
+while ($row = mysql_fetch_array($result))
+{
+  array_push($cat_ids, $row['id']);
+}
+
+if (count($cat_ids) > 0)
+{
+  $privates = get_subcat_ids($cat_ids);
+
+  $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET status = \'private\'
+  WHERE id IN ('.implode(',', $privates).')
+;';
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' all sub-categories of private categories become private</pre>';
+flush();
+$last_time = $new_time;
+
+$infos = array(
+  'user permissions and group permissions have been erased',
+
+  'only thumbnails prefix and webmaster mail address have been saved from
+previous configuration',
+
+  'in include/mysql.inc.php, before
+<pre style="background-color:lightgray">?&gt;</pre>
+insert
+<pre style="background-color:lightgray">define(\'PHPWG_INSTALLED\', true);<pre>'
+  
+  );
+
+?>
Index: /branches/1.4/install/upgrade_1.3.4.php
===================================================================
--- /branches/1.4/install/upgrade_1.3.4.php	(revision 3249)
+++ /branches/1.4/install/upgrade_1.3.4.php	(revision 3249)
@@ -0,0 +1,362 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if (!defined('IN_UPGRADE') or !IN_UPGRADE)
+{
+  die('Hacking attempt!');
+}
+
+$last_time = get_moment();
+
+// save data before deletion
+$query = '
+SELECT prefix_thumbnail, mail_webmaster
+  FROM '.PREFIX_TABLE.'config
+;';
+$save = mysql_fetch_array(mysql_query($query));
+
+$queries = array(
+  "
+DROP TABLE phpwebgallery_config
+;",
+
+  "
+CREATE TABLE phpwebgallery_config (
+  param varchar(40) NOT NULL default '',
+  value varchar(255) default NULL,
+  comment varchar(255) default NULL,
+  PRIMARY KEY  (param)
+) TYPE=MyISAM COMMENT='configuration table'
+;",
+
+  "
+ALTER TABLE phpwebgallery_categories
+  CHANGE COLUMN site_id site_id tinyint(4) unsigned default '1',
+  ADD COLUMN commentable enum('true','false') NOT NULL default 'true',
+  ADD COLUMN global_rank varchar(255) default NULL,
+  DROP INDEX id_uppercat,
+  ADD INDEX categories_i2 (id_uppercat)
+;",
+
+  "
+ALTER TABLE phpwebgallery_comments
+  ADD COLUMN date_temp int(11) unsigned
+;",
+
+  "
+UPDATE phpwebgallery_comments
+  SET date_temp = date
+;",
+  
+  "
+ALTER TABLE phpwebgallery_comments
+  CHANGE COLUMN date date datetime NOT NULL default '0000-00-00 00:00:00'
+;",
+
+  "
+UPDATE phpwebgallery_comments
+  SET date = FROM_UNIXTIME(date_temp)
+;",
+
+  "
+ALTER TABLE phpwebgallery_comments
+  DROP COLUMN date_temp
+;",
+
+  "
+ALTER TABLE phpwebgallery_favorites
+  DROP INDEX user_id,
+  ADD PRIMARY KEY (user_id,image_id)
+;",
+
+  "
+ALTER TABLE phpwebgallery_history
+  ADD COLUMN date_temp int(11) unsigned
+;",
+
+  "
+UPDATE phpwebgallery_history
+  SET date_temp = date
+;",
+  
+  "
+ALTER TABLE phpwebgallery_history
+  CHANGE COLUMN date date datetime NOT NULL default '0000-00-00 00:00:00'
+;",
+
+  "
+UPDATE phpwebgallery_history
+  SET date = FROM_UNIXTIME(date_temp)
+;",
+
+  "
+ALTER TABLE phpwebgallery_history
+  DROP COLUMN date_temp
+;",
+
+  "
+ALTER TABLE phpwebgallery_history
+  ADD INDEX history_i1 (date)
+;",
+
+  "
+ALTER TABLE phpwebgallery_image_category
+  DROP INDEX image_id,
+  DROP INDEX category_id,
+  ADD INDEX image_category_i1 (image_id),
+  ADD INDEX image_category_i2 (category_id)
+;",
+
+  "
+ALTER TABLE phpwebgallery_images
+  CHANGE COLUMN tn_ext tn_ext varchar(4) default '',
+  ADD COLUMN path varchar(255) NOT NULL default '',
+  ADD COLUMN date_metadata_update date default NULL,
+  ADD COLUMN average_rate float(5,2) unsigned default NULL,
+  ADD COLUMN representative_ext varchar(4) default NULL,
+  DROP INDEX storage_category_id,
+  ADD INDEX images_i1 (storage_category_id),
+  ADD INDEX images_i2 (date_available),
+  ADD INDEX images_i3 (average_rate),
+  ADD INDEX images_i4 (hit),
+  ADD INDEX images_i5 (date_creation)
+;",
+  
+  "
+ALTER TABLE phpwebgallery_sessions
+  DROP COLUMN ip
+;",
+
+    "
+ALTER TABLE phpwebgallery_sessions
+  ADD COLUMN expiration_temp int(11) unsigned
+;",
+
+  "
+UPDATE phpwebgallery_sessions
+  SET expiration_temp = expiration
+;",
+  
+  "
+ALTER TABLE phpwebgallery_sessions
+  CHANGE COLUMN expiration expiration datetime NOT NULL default '0000-00-00 00:00:00'
+;",
+
+  "
+UPDATE phpwebgallery_sessions
+  SET expiration = FROM_UNIXTIME(expiration_temp)
+;",
+
+  "
+ALTER TABLE phpwebgallery_sessions
+  DROP COLUMN expiration_temp
+;",
+  
+  "
+ALTER TABLE phpwebgallery_sites
+  DROP INDEX galleries_url,
+  ADD UNIQUE sites_ui1 (galleries_url)
+;",
+  
+  "
+DROP TABLE phpwebgallery_user_category
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN long_period,
+  DROP COLUMN short_period,
+  DROP COLUMN forbidden_categories,
+  ADD COLUMN recent_period tinyint(3) unsigned NOT NULL default '7',
+  DROP INDEX username,
+  ADD UNIQUE users_ui1 (username)
+;",
+  
+  "
+CREATE TABLE phpwebgallery_rate (
+  user_id smallint(5) unsigned NOT NULL default '0',
+  element_id mediumint(8) unsigned NOT NULL default '0',
+  rate tinyint(2) unsigned NOT NULL default '0',
+  PRIMARY KEY  (user_id,element_id)
+) TYPE=MyISAM
+;",
+
+  "
+CREATE TABLE phpwebgallery_user_forbidden (
+  user_id smallint(5) unsigned NOT NULL default '0',
+  need_update enum('true','false') NOT NULL default 'true',
+  forbidden_categories text,
+  PRIMARY KEY  (user_id)
+) TYPE=MyISAM
+;",
+
+  "
+UPDATE phpwebgallery_users
+  SET language = 'en_UK.iso-8859-1'
+    , template = 'default'
+;",
+
+  "
+DELETE FROM phpwebgallery_user_access
+;",
+
+  "
+DELETE FROM phpwebgallery_group_access
+;"
+
+  );
+
+foreach ($queries as $query)
+{
+  $query = str_replace('phpwebgallery_', PREFIX_TABLE, $query);
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' Basic database structure upgrade done</pre>';
+flush();
+$last_time = $new_time;
+
+execute_sqlfile(PHPWG_ROOT_PATH.'install/config.sql',
+                'phpwebgallery_',
+                PREFIX_TABLE);
+
+$queries = array(
+  "
+UPDATE phpwebgallery_config
+  SET value = '".$save['prefix_thumbnail']."'
+  WHERE param = 'prefix_thumbnail'
+;",
+
+  "
+UPDATE phpwebgallery_config
+  SET value = '".$save['mail_webmaster']."'
+  WHERE param = 'mail_webmaster'
+;"
+  );
+
+foreach ($queries as $query)
+{
+  $query = str_replace('phpwebgallery_', PREFIX_TABLE, $query);
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' Saved configuration information restored</pre>';
+flush();
+$last_time = $new_time;
+
+ordering();
+update_global_rank();
+update_category();
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' Calculated data updated (categories.rank, categories.global_rank,
+categories.date_last, categories.representative_picture_id,
+categories.nb_images)</pre>';
+flush();
+$last_time = $new_time;
+
+// update calculated field "images.path"
+$cat_ids = array();
+
+$query = '
+SELECT DISTINCT(storage_category_id) AS unique_storage_category_id
+  FROM '.IMAGES_TABLE.'
+;';
+$result = pwg_query($query);
+while ($row = mysql_fetch_array($result))
+{
+  array_push($cat_ids, $row['unique_storage_category_id']);
+}
+$fulldirs = get_fulldirs($cat_ids);
+
+foreach ($cat_ids as $cat_id)
+{
+  $query = '
+UPDATE '.IMAGES_TABLE.'
+  SET path = CONCAT(\''.$fulldirs[$cat_id].'\',\'/\',file)
+  WHERE storage_category_id = '.$cat_id.'
+;';
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' new column images.path filled</pre>';
+flush();
+$last_time = $new_time;
+
+// all sub-categories of private categories become private
+$cat_ids = array();
+
+$query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE status = \'private\'
+;';
+$result = pwg_query($query);
+while ($row = mysql_fetch_array($result))
+{
+  array_push($cat_ids, $row['id']);
+}
+
+if (count($cat_ids) > 0)
+{
+  $privates = get_subcat_ids($cat_ids);
+
+  $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET status = \'private\'
+  WHERE id IN ('.implode(',', $privates).')
+;';
+  pwg_query($query);
+}
+
+$new_time = get_moment();
+echo '<pre>['.get_elapsed_time($last_time, $new_time).']';
+echo ' all sub-categories of private categories become private</pre>';
+flush();
+$last_time = $new_time;
+
+$infos = array(
+  'user permissions and group permissions have been erased',
+
+  'only thumbnails prefix and webmaster mail address have been saved from
+previous configuration',
+
+  'in include/mysql.inc.php, before
+<pre style="background-color:lightgray">?&gt;</pre>
+insert
+<pre style="background-color:lightgray">define(\'PHPWG_INSTALLED\', true);<pre>'
+  
+  );
+
+?>
Index: /branches/1.4/language/en_UK.iso-8859-1/admin.lang.php
===================================================================
--- /branches/1.4/language/en_UK.iso-8859-1/admin.lang.php	(revision 3249)
+++ /branches/1.4/language/en_UK.iso-8859-1/admin.lang.php	(revision 3249)
@@ -0,0 +1,349 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Main words
+$lang['links'] = 'Links';
+$lang['general'] = 'General';
+$lang['config'] = 'Configuration';
+$lang['users'] = 'Users';
+$lang['instructions'] = 'Instructions';
+$lang['history'] = 'History';
+$lang['manage'] = 'Manage';
+$lang['waiting'] = 'Waiting';
+$lang['groups'] = 'Groups';
+$lang['permissions'] = 'Permissions';
+$lang['update'] = 'Synchronize';
+$lang['storage'] = 'Directory';
+$lang['edit'] = 'Edit';
+$lang['authorized'] = 'Authorized';
+$lang['forbidden'] = 'Forbidden';
+$lang['public'] = 'public';
+$lang['private'] = 'private';
+$lang['metadata']='Metadata';
+$lang['visitors'] = 'Visitors';
+$lang['locked'] = 'Locked';
+$lang['unlocked'] = 'Unlocked';
+$lang['lock'] = 'Lock';
+$lang['unlock'] = 'Unlock';
+$lang['up'] = 'Move up';
+$lang['down'] = 'Move down';
+$lang['path'] = 'path';
+$lang['no_write_access'] = 'no write access';
+
+// Specific words
+$lang['phpinfos'] = 'PHP Information';
+$lang['remote_site'] = 'Remote site';
+$lang['remote_sites'] = 'Remote sites';
+$lang['gallery_default'] = 'Gallery Default';
+$lang['upload'] = 'Upload';
+
+// Remote sites management
+$lang['remote_site_create'] = 'Create a new site : (give its URL to generate_file_listing.php)';
+$lang['remote_site_uncorrect_url'] = 'Remote site url must start by http or https and must only contain characters among "/", "a-zA-Z0-9", "-" or "_"';
+$lang['remote_site_already_exists'] = 'This site already exists';
+$lang['remote_site_generate'] = 'generate listing';
+$lang['remote_site_generate_hint'] = 'generate file listing.xml on remote site';
+$lang['remote_site_update'] = 'update';
+$lang['remote_site_update_hint'] = 'read remote listing.xml and updates database';
+$lang['remote_site_clean'] = 'clean';
+$lang['remote_site_clean_hint'] = 'remove remote listing.xml file';
+$lang['remote_site_delete'] = 'delete';
+$lang['remote_site_delete_hint'] = 'delete this site and all its attached elements';
+$lang['remote_site_file_not_found'] = 'file create_listing_file.php on remote site was not found';
+$lang['remote_site_error'] = 'an error happened';
+$lang['remote_site_listing_not_found'] = 'listing.xml file was not found';
+$lang['remote_site_removed'] = 'was removed on remote site';
+$lang['remote_site_removed_title'] = 'Removed elements';
+$lang['remote_site_created'] = 'created';
+$lang['remote_site_deleted'] = 'deleted';
+$lang['remote_site_local_found'] = 'A local listing.xml file has been found for ';
+$lang['remote_site_local_new'] = '(new site)';
+$lang['remote_site_local_update'] = 'read local listing.xml and update';
+
+// Categories
+$lang['cat_security'] = 'Public / Private';
+$lang['cat_options'] = 'Category options';
+$lang['cat_add'] = 'Add a virtual category';
+$lang['cat_virtual'] = 'Virtual category';
+$lang['cat_public'] = 'Public category';
+$lang['cat_private'] = 'Private category';
+$lang['cat_image_info'] = 'Images info';
+$lang['editcat_status'] = 'Status';
+$lang['editcat_confirm'] = 'Category informations updated successfully.';
+$lang['editcat_perm'] = 'To set permissions for this category, click';
+$lang['editcat_lock_info'] = 'The category and its sub-categories will temporary been disabled for maintenance.';
+$lang['editcat_uploadable'] = 'Authorize upload';
+$lang['editcat_uploadable_info'] = 'Authorize users to upload files';
+$lang['editcat_commentable_info'] = 'Authorize users to comment elements of this category';
+$lang['cat_access_info'] = 'Permission management. If you make a category private, all its child categories becomes private. If you make a category public, all its parent categories becomes public';
+$lang['cat_virtual_added'] = 'Virtual category added';
+$lang['cat_virtual_deleted'] = 'Virtual category deleted';
+$lang['cat_upload_title'] = 'Select uploadable categories';
+$lang['cat_upload_info'] = 'Only non virtual and non remote categories are shown.';
+$lang['cat_lock_title'] = 'Lock categories';
+$lang['cat_lock_info'] = 'Selected categories will temporary been disabled for maintenance.
+<br />If you lock a category, all its child categories become locked.
+<br />If you unlock a category, all its parent categories become unlocked.';
+$lang['cat_comments_title'] = 'Authorize users to add comments on selected categories';
+$lang['cat_comments_info'] = 'By inheritance, an element is commentable if it belongs at least to one commentable category.';
+$lang['cat_status_title'] = 'Manage authorizations for selected categories';
+$lang['cat_status_info'] = 'Selected categories are private : you will need to authorize users and/or groups to access to them.
+<br />If you make a category private, all its child categories becomes private.
+<br />If you make a category public, all its parent categories becomes public';
+$lang['cat_representant'] = 'Find a new representant by random';
+
+// Titles
+$lang['admin_panel'] = 'Administration Panel';
+$lang['default_message'] = 'PhpWebGallery Administration Control Panel';
+$lang['title_liste_users'] = 'Users list';
+$lang['title_history'] = 'History';
+$lang['title_update'] = 'Database synchronization with files';
+$lang['title_configuration'] = 'PhpWebGallery configuration';
+$lang['title_instructions'] = 'Instructions';
+$lang['title_categories'] = 'Categories management';
+$lang['title_edit_cat'] = 'Edit a category';
+$lang['title_info_images'] = 'Modify category\'s image information';
+$lang['title_thumbnails'] = 'Thumbnail creation';
+$lang['title_thumbnails_2'] = 'for';
+$lang['title_default'] = 'PhpWebGallery administration';
+$lang['title_waiting'] = 'Pictures waiting for validation';
+$lang['title_cat_options'] = 'Categories options';
+$lang['title_groups'] = 'Groups management';
+$lang['title_cat_perm'] = 'Modify permissions for category';
+
+//Error messages
+$lang['cat_error_name'] = 'The name of a category should not be empty';
+
+//Configuration
+$lang['conf_confirmation'] = 'Information data registered in database';
+$lang['conf_default'] = 'Default display';
+$lang['conf_cookie'] = 'Session & Cookie';
+
+// Configuration -> general
+$lang['conf_general_title'] = 'Main configuration';
+$lang['conf_mail_webmaster'] = 'Webmaster mail adress';
+$lang['conf_mail_webmaster_info'] = 'Visitors will be able to contact site administrator with this mail';
+$lang['conf_mail_webmaster_error'] = 'e-mail address refused, it must be like name@domain.com';
+$lang['conf_prefix'] = 'Thumbnail prefix';
+$lang['conf_prefix_info'] = 'Thumbnails use this prefix. Do not fill if your not sure.';
+$lang['conf_prefix_error'] = 'Thumbnail\'s prefix must only contain characters among : a to z (case insensitive), "-" or "_"';
+$lang['conf_access'] = 'Access type';
+$lang['conf_log_info'] = 'Keep an history of visits on your website ? Visits will be shown in the history section of the administration panel';
+$lang['conf_notification'] = 'Mail notification';
+$lang['conf_notification_info'] = 'Automated mail notification for adminsitrators (and only for them) when a user add a comment or upload a picture.';
+$lang['conf_gallery_locked'] = 'Lock gallery';
+$lang['conf_gallery_locked_info'] = 'Lock the entire gallery for maintenance. Only administrator users will be able to reach the gallery';
+
+// Configuration -> comments
+$lang['conf_comments_title'] = 'Users comments';
+$lang['conf_comments_forall'] = 'Comments for all ?';
+$lang['conf_comments_forall_info'] = 'Even guest not registered can post comments';
+$lang['conf_nb_comment_page'] = 'Number of comments per page';
+$lang['conf_nb_comment_page_info'] = 'number of comments to display on each page. This number is unlimited for a picture. Enter a number between 5 and 50.';
+$lang['conf_nb_comment_page_error'] = 'The number of comments a page must be between 5 and 50 included.';
+$lang['conf_comments_validation'] = 'Validation';
+$lang['conf_comments_validation_info'] = 'An administrator validate users posted comments before the becom visible on the site';
+
+// Configuration -> default
+$lang['conf_default_title'] = 'Default display';
+$lang['conf_default_language_info'] = 'Default language';
+$lang['conf_default_theme_info'] = 'Default theme';
+$lang['conf_nb_image_line_info'] = 'Number of pictures for each row by default';
+$lang['conf_nb_line_page_info'] = 'Number of rows by page by default';
+$lang['conf_recent_period_info'] = 'By days. Period within a picture is shown as new. Must be superior to 1 day.';
+$lang['conf_default_expand_info'] = 'Expand all categories by default in the menu ?';
+$lang['conf_show_nb_comments_info'] = 'show the number of comments for each picture on the thumbnails page';
+
+// Configuration -> upload
+$lang['conf_upload_title'] = 'Users upload';
+$lang['conf_upload_maxfilesize'] = 'Maximum filesize';
+$lang['conf_upload_maxfilesize_info'] = 'Maximum filesize for the uploaded pictures. Must be a number between 10 and 1000 KB.';
+$lang['conf_upload_maxfilesize_error'] = 'Maximum filesize for the uploaded pictures must be a number between 10 and 1000 KB.';
+$lang['conf_upload_maxwidth'] = 'Maximum width';
+$lang['conf_upload_maxwidth_info'] = 'Maximum width authorized for the uploaded images. Must be a number superior to 10 pixels';
+$lang['conf_upload_maxwidth_error'] = 'maximum width authorized for the uploaded images must be a number superior to 10 pixels.';
+$lang['conf_upload_maxheight'] = 'Maximum height';
+$lang['conf_upload_maxheight_info'] = 'Maximum height authorized for the uploaded images. Must be a number superior to 10 pixels';
+$lang['conf_upload_maxheight_error'] = 'maximum height authorized for the uploaded images must be a number superior to 10 pixels.';
+$lang['conf_upload_tn_maxwidth'] = 'thumbnails maximum width';
+$lang['conf_upload_tn_maxwidth_info'] = 'Maximum width authorized for the uploaded thumbnails. Must be a number superior to 10 pixels';
+$lang['conf_upload_maxwidth_thumbnail_error'] = 'Maximum width authorized for the uploaded thumbnails must be a number superior to 10 pixels.';
+$lang['conf_upload_tn_maxheight'] = 'Thumbnails maximum height';
+$lang['conf_upload_tn_maxheight_info'] = 'Maximum height authorized for the uploaded thumbnails. Must be a number superior to 10 pixels';
+$lang['conf_upload_maxheight_thumbnail_error'] = 'Maximum height authorized for the uploaded thumbnails must be a number superior to 10 pixels.';
+
+// Configuration -> session
+$lang['conf_session_title'] = 'Sessions';
+$lang['conf_authorize_remembering'] = 'Authorize remembering';
+$lang['conf_authorize_remembering_info'] = 'Permits user to log for a long time. It creates a cookie on client side, with duration set in include/config.inc.php (1 year per default)';
+
+// Configuration -> metadata
+$lang['conf_metadata_title'] = 'Metadata';
+$lang['conf_use_exif'] = 'Use EXIF';
+$lang['conf_use_exif_info'] = 'Use EXIF data during metadata synchronization into PhpWebGallery database';
+$lang['conf_use_iptc'] = 'Use IPTC';
+$lang['conf_use_iptc_info'] = 'Use IPTC data during metadata synchronization into PhpWebGallery database';
+$lang['conf_show_exif'] = 'Show EXIF';
+$lang['conf_show_exif_info'] = 'Give the possibility to show EXIF metadata on visualisation page. See include/config.inc.php for available EXIF fields';
+$lang['conf_show_iptc'] = 'Show IPTC';
+$lang['conf_show_iptc_info'] = 'Give the possibility to show IPTC metadata on visualisation page. See include/config.inc.php for available IPTC fields';
+
+// Configuration -> remote
+$lang['conf_remote_site_delete_info'] = 'Deleting a remote server will delete all the image and the categories in relation with this server.';
+
+// Image informations
+$lang['title_picmod'] = 'Modify informations about a picture';
+$lang['infoimage_general'] = 'General options for the category';
+$lang['infoimage_useforall'] = 'use for all pictures ?';
+$lang['infoimage_creation_date'] = 'Creation date';
+$lang['infoimage_detailed'] = 'Option for each picture';
+$lang['infoimage_title'] = 'Title';
+$lang['infoimage_keyword_separation'] = '(separate with coma ",")';
+$lang['infoimage_addtoall'] = 'add to all';
+$lang['infoimage_removefromall'] = 'remove from all';
+$lang['infoimage_associate'] = 'Associate to the category';
+$lang['infoimage_associated'] = 'virtually associated to';
+$lang['infoimage_dissociated'] = 'dissociated from';
+$lang['storage_category'] = 'storage category';
+$lang['represents'] = 'represents';
+$lang['doesnt_represent'] = 'doesn\'t represent';
+$lang['cat_unknown_id'] = 'This category is unknown in the database';
+$lang['dissociate'] = 'dissociate';
+
+// Thumbnails
+$lang['tn_width'] = 'width';
+$lang['tn_height'] = 'height';
+$lang['tn_no_support'] = 'Picture unreachable or no support';
+$lang['tn_format'] = 'for the file format';
+$lang['tn_thisformat'] = 'for this file format';
+$lang['tn_err_width'] = 'width must be a number superior to';
+$lang['tn_err_height'] = 'height must be a number superior to';
+$lang['tn_results_title'] = 'Results of miniaturization';
+$lang['tn_picture'] = 'picture';
+$lang['tn_results_gen_time'] = 'generated in';
+$lang['tn_stats'] = 'General statistics';
+$lang['tn_stats_nb'] = 'number of miniaturized pictures';
+$lang['tn_stats_total'] = 'total time';
+$lang['tn_stats_max'] = 'max time';
+$lang['tn_stats_min'] = 'min time';
+$lang['tn_stats_mean'] = 'average time';
+$lang['tn_err'] = 'You made mistakes';
+$lang['tn_params_title'] = 'Miniaturization parameters';
+$lang['tn_params_GD'] = 'GD version';
+$lang['tn_params_GD_info'] = '- GD is the picture manipulating library for PHP<br />-choose the version installed on your server. If you choose the wrong, you\'ll just have errors messages, come back with your browser and choose the other version. If no version works, it means your server doesn\'t support GD.';
+$lang['tn_params_width_info'] = 'maximum width that thumbnails can take';
+$lang['tn_params_height_info'] = 'maximum height that thumbnails can take';
+$lang['tn_params_create'] = 'create';
+$lang['tn_params_create_info'] = 'Do not try to miniaturize too many pictures in the same time.<br />Indeed, miniaturization uses a lot of CPU. If you installed PhpWebGallery on a free provider, a too high CPU load can sometime lead to the deletion of your website.';
+$lang['tn_params_format'] = 'file format';
+$lang['tn_params_format_info'] = 'only jpeg file format is supported for thumbnail creation';
+$lang['tn_alone_title'] = 'pictures without thumbnail (jpeg and png only)';
+$lang['tn_dirs_title'] = 'Directories list';
+$lang['tn_dirs_alone'] = 'pictures without thumbnail';
+$lang['tn_no_missing'] = 'No missing thumbnail';
+$lang['tn_all'] = 'all';
+
+// Waiting files 
+$lang['waiting_update'] = 'Validated pictures will be displayed only once pictures database updated';
+
+// Update
+$lang['update_missing_tn'] = 'the thumbnail is missing for';
+$lang['update_missing_tn_short'] = 'missing thumbnail';
+$lang['update_missing_tn_info'] = 'a picture filetype requires a thumbnail. The thumbnail must be present in the sub-directory "thumbnail" of the category directory. The thumbnail filename must start with the configured thumbnail prefix and the extension must be among the following list :';
+$lang['update_disappeared_tn'] = 'the thumbnail disapeared';
+$lang['update_disappeared'] = 'doesn\'t exist';
+$lang['update_part_deletion'] = 'Deletion of images that have no thumbnail or that doesn\'t exist';
+$lang['update_part_research'] = 'Search for new images in the directories';
+$lang['update_research_added'] = 'added';
+$lang['update_research_deleted'] = 'deleted';
+$lang['update_research_tn_ext'] = 'thumbnail in';
+$lang['update_nb_new_elements'] = 'elements added in the database';
+$lang['update_nb_del_elements'] = 'elements deleted in the database';
+$lang['update_nb_new_categories'] = 'categories added in the database';
+$lang['update_nb_del_categories'] = 'categories deleted in the database';
+$lang['update_default_title'] = 'Choose an option';
+$lang['update_sync_files'] = 'synchronize files structure with database';
+$lang['update_sync_dirs'] = 'only directories';
+$lang['update_sync_all'] = 'directories + files';
+$lang['update_sync_metadata'] = 'synchronize files metadata with database elements informations';
+$lang['update_sync_metadata_new'] = 'only never synchronized elements';
+$lang['update_sync_metadata_all'] = 'even already synchronized elements';
+$lang['update_cats_subset'] = 'reduce to single existing categories';
+$lang['update_nb_errors'] = 'errors during synchronization';
+$lang['update_error_list_title'] = 'Error list';
+$lang['update_errors_caption'] = 'Errors caption';
+$lang['update_display_info'] = 'display maximum informations (added categories and elements, deleted categories and elements)';
+$lang['update_simulate'] = 'only perform a simulation (no change in database will be made)';
+$lang['update_infos_title'] = 'Detailed informations';
+$lang['update_simulation_title'] = '[Simulation]';
+$lang['update_wrong_dirname'] = 'The name of directories and files must be composed of letters, figures, "-", "_" or "."';
+$lang['update_wrong_dirname_short'] = 'wrong filename';
+$lang['update_wrong_dirname_info'] = 'The name of directories and files must be composed of letters, figures, "-", "_" or "."';
+$lang['update_result_metadata'] = 'Metadata synchronization results';
+$lang['update_elements_metadata_sync'] = 'elements informations synchronized with files metadata';
+$lang['update_used_metadata'] = 'Used metadata';
+$lang['metadata_basic'] = 'basic';
+$lang['metadata_exif'] = 'EXIF';
+$lang['metadata_iptc'] = 'IPTC';
+
+// History
+$lang['stats_title'] = 'Last year statistics';
+$lang['stats_month_title'] = 'Monthly statistics';
+$lang['stats_pages_seen'] = 'Pages seen';
+$lang['stats_global_graph_title'] = 'Pages seen by month';
+$lang['stats_visitors_graph_title'] = 'Nombre de visiteurs par jour';
+
+// Users
+$lang['title_user_modify'] = 'Modify a user';
+$lang['title_user_perm'] = 'Modify permission for user';
+$lang['user_err_modify'] = 'This user can\'t be modified or deleted';
+$lang['user_err_unknown'] = 'This user doesn\'t exist in the database';
+$lang['user_management'] = 'Special field for administrators';
+$lang['user_status'] = 'User status';
+$lang['user_status_admin'] = 'Administrator';
+$lang['user_status_guest'] = 'User';
+$lang['user_delete'] = 'Delete user';
+$lang['user_delete_hint'] = 'Click here to delete this user. Warning! This operation cannot be undone!';
+$lang['permuser_only_private'] = 'Only private categories are shown';
+$lang['permuser_info'] = 'Only private categories are listed. Private/Public category status can be set in screen "Categories &gt; Public / Private"';
+$lang['order_by'] = 'order by';
+$lang['registration_date'] = 'registration date';
+$lang['ascending'] = 'ascending';
+$lang['descending'] = 'descending';
+$lang['actions'] = 'actions';
+
+// Groups
+$lang['group_confirm_delete']= 'Confirm group deletion';
+$lang['group_add'] = 'Add a group';
+$lang['group_add_error1'] = 'The name of a group must not contain " or \' or be empty.';
+$lang['group_add_error2'] = 'This name is already used by another group.';
+$lang['group_list_title'] = 'List of existing groups';
+$lang['group_edit'] = 'Manage users of the group';
+$lang['group_deny_user'] = 'Deny selected';
+$lang['group_add_user']= 'Add user';
+$lang['title_group_perm'] = 'Modify permissions for group';
+?>
Index: /branches/1.4/language/en_UK.iso-8859-1/common.lang.php
===================================================================
--- /branches/1.4/language/en_UK.iso-8859-1/common.lang.php	(revision 3249)
+++ /branches/1.4/language/en_UK.iso-8859-1/common.lang.php	(revision 3249)
@@ -0,0 +1,308 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Langage informations
+$lang_info['language_name'] = 'English';
+$lang_info['country'] = 'Great Britain';
+$lang_info['charset'] = 'iso-8859-1';
+$lang_info['direction'] = 'ltr';
+$lang_info['code'] = 'en';
+
+// Main words 
+$lang['no_category'] = 'Home';
+$lang['category'] = 'Category';
+$lang['categories'] = 'Categories';
+$lang['thumbnail'] = 'Thumbnail';
+$lang['thumbnails'] = 'Thumbnails';
+$lang['search'] = 'Search';
+$lang['comment'] = 'Comment';
+$lang['comments'] = 'Comments';
+$lang['picture'] = 'Picture';
+$lang['pictures'] = 'Pictures';
+$lang['name'] = 'Name';
+$lang['no'] = 'No';
+$lang['yes'] = 'Yes';
+$lang['date'] = 'Date';
+$lang['description'] = 'Description';
+$lang['author'] = 'Author';
+$lang['size'] = 'Size';
+$lang['filesize'] = 'Filesize';
+$lang['file'] = 'File';
+$lang['keywords'] = 'Keywords';
+$lang['default'] = 'Default';
+$lang['send_mail'] = 'Contact';
+$lang['webmaster'] = 'Webmaster';
+$lang['language']='Language';
+$lang['powered_by'] = 'Powered by';
+$lang['all_categories'] = 'all categories';
+
+//Properties
+$lang['registration_date'] = 'Registered on';
+$lang['creation_date'] = 'Created on';
+
+// Form words 
+$lang['submit'] = 'Submit';
+$lang['delete'] = 'Delete';
+$lang['reset'] = 'Reset';
+$lang['Close'] = 'Close the window';
+$lang['Select'] = 'Select';
+
+// Error management
+$lang['mandatory'] = 'obligatory';
+$lang['err_date'] = 'wrong date';
+
+// Navigation
+$lang['home'] = 'Home';
+$lang['title_menu'] = 'Menu';
+$lang['home_hint'] = 'Back to the home page';
+$lang['special_categories'] = 'Specials';
+$lang['favorite_cat'] = 'my favorites';
+$lang['favorite_cat_hint'] = 'display my favorites pictures';
+$lang['most_visited_cat'] = 'most visited';
+$lang['most_visited_cat_hint'] = 'displays most visited pictures';
+$lang['best_rated_cat'] = 'best rated';
+$lang['best_rated_cat_hint'] = 'displays best rated items';
+$lang['recent_image'] = 'Image within the';
+$lang['recent_pics_cat'] = 'Last pictures';
+$lang['recent_pics_cat_hint'] = 'Displays most recent pictures';
+$lang['recent_cats_cat'] = 'Last categories';
+$lang['recent_cats_cat_hint'] = 'Displays recently updated categories';
+$lang['about'] = 'about';
+$lang['hint_about'] = 'more informations on PhpWebGallery...';
+$lang['admin'] = 'Administration';
+$lang['hint_admin'] = 'available for administrators only';
+$lang['page_number'] = 'page number';
+$lang['previous_page'] = 'Previous';
+$lang['next_page'] = 'Next';
+$lang['first_page'] = 'First';
+$lang['last_page'] = 'Last';
+$lang['hint_category'] = 'shows images at the root of this categry';
+$lang['hint_customize'] = 'customize the appareance of the gallery';
+$lang['hint_search'] = 'search';
+$lang['upload_picture'] = 'Upload a picture';
+$lang['favorites'] = 'Favorites';
+$lang['random_cat'] = 'random pictures';
+$lang['random_cat_hint'] = 'Displays a set of random pictures';
+
+// Identification
+$lang['login'] = 'Login';
+$lang['logout'] = 'Logout';
+$lang['password'] = 'Password';
+$lang['customize'] = 'Customize';
+$lang['new'] = 'New';
+$lang['identification'] = 'Identification';
+$lang['remember_me'] = 'Auto login';
+$lang['only_members'] = 'Only members can access this page';
+$lang['invalid_pwd'] = 'Invalid password!';
+$lang['access_forbiden'] = 'You are not authorized to access this page';
+$lang['ident_register'] = 'Register';
+$lang['ident_forgotten_password'] = 'Forget your password ?';
+$lang['ident_guest_visit'] = 'Go through the gallery as a visitor';
+
+// Registration
+$lang['register_page_title'] = 'Registration';
+$lang['register_title'] = 'Registration';
+$lang['reg_err_login1'] = 'Please, enter a login';
+$lang['reg_err_login2'] = 'login mustn\'t end with a space character';
+$lang['reg_err_login3'] = 'login mustn\'t start with a space character';
+$lang['reg_err_login4'] = 'login mustn\'t contain characters " and \'';
+$lang['reg_err_login5'] = 'this login is already used';
+$lang['reg_err_pass'] = 'please enter your password again';
+$lang['reg_confirm'] = 'Confirm password';
+$lang['reg_err_mail_address'] = 'mail address must be like xxx@yyy.eee (example : jack@altern.org)';
+
+//Calendar
+$lang['calendar'] = 'calendar';
+$lang['calendar_hint'] = 'displays each day with pictures, month per month';
+$lang['calendar_picture_hint'] = 'displays pictures added on ';
+$lang['month'][1] = 'January';
+$lang['month'][2] = 'February';
+$lang['month'][3] = 'March';
+$lang['month'][4] = 'April';
+$lang['month'][5] = 'May';
+$lang['month'][6] = 'June';
+$lang['month'][7] = 'July';
+$lang['month'][8] = 'August';
+$lang['month'][9] = 'September';
+$lang['month'][10] = 'October';
+$lang['month'][11] = 'November';
+$lang['month'][12] = 'December';
+$lang['day'][0] = 'Sunday';
+$lang['day'][1] = 'Monday';
+$lang['day'][2] = 'Tuesday';
+$lang['day'][3] = 'Wednesday';
+$lang['day'][4] = 'Thursday';
+$lang['day'][5] = 'Friday';
+$lang['day'][6] = 'Saturday';
+$lang['w_month'] = 'Month';
+$lang['w_day'] = 'Day';
+$lang['days'] = 'days';
+$lang['today']='Today';
+
+// Customization
+$lang['customize_page_title'] = 'Your Gallery Customization ';
+$lang['customize_title'] = 'Customization';
+$lang['preferences'] = 'Preferences';
+$lang['mail_address'] = 'E-mail address';
+$lang['password_hint'] = 'You only have to give your password if you wish to change your e-mail';
+$lang['new_password'] = 'New password';
+$lang['new_password_hint'] = 'You only have to give a password if you wish to change it.';
+$lang['confirm_password_hint'] = 'You only have to confirm your new password if you wish to change it.';
+$lang['nb_image_per_row'] = 'Number of images per row';
+$lang['nb_row_per_page'] = 'Number of rows per page';
+$lang['maxwidth'] = 'Maximum width of the pictures';
+$lang['maxheight'] = 'Maximum height of the pictures';
+$lang['maxwidth_error'] = 'Maximum width must be a number superior to 50';
+$lang['maxheight_error'] = 'Maximum height must be a number superior to 50';
+$lang['theme'] = 'Interface theme';
+$lang['auto_expand'] = 'Expand all categories';
+$lang['show_nb_comments'] = 'Show number of comments';
+$lang['recent_period'] = 'Recent period';
+$lang['periods_error'] = 'Recent period must be a positive integer value';
+
+// search
+$lang['search_title'] = 'Search';
+$lang['search_options'] = 'Search Options';
+$lang['search_keywords'] = 'Search for words';
+$lang['search_keywords_hint'] = 'Search for entered words in all the attributes related to the pictures displayed in the gallery. Use * as a wildcard for partial matches';
+$lang['search_mode_or'] = 'Search for any terms';
+$lang['search_mode_and'] = 'Search for all terms ';
+$lang['search_author'] = 'Search for Author';
+$lang['search_categories'] = 'Search in Categories';
+$lang['search_subcats_included'] = 'Search in subcategroies';
+$lang['search_categories_hint'] = 'Select the category or categories you wish to search in. For speed all subcategories can be searched by selecting the parent and setting enable search subcategories below.';
+$lang['search_explain'] = 'Use * as a wildcard for partial matches';
+$lang['search_date'] = 'Search by Date';
+$lang['search_date_hint'] = 'Select a date and/or an ending date for your query.<br /> 
+Leave date empty if you want to make a "before" query.<br />
+The year must be entered in the last field in the following format : 0000 (i.e. 2004)';
+$lang['search_date_from'] = 'Date';
+$lang['search_date_to'] = 'End-Date';
+$lang['search_date_type'] = 'Kind of date';
+$lang['search_date_available'] = 'Availability';
+$lang['search_date_creation'] = 'Creation';
+$lang['search_sort'] = 'Sort results by';
+$lang['search_ascending'] = 'Ascending';
+$lang['search_descending'] = 'Descending';
+$lang['search_one_clause_at_least'] = 'Empty query. No criteria has been entered.';
+$lang['search_result'] = 'Search results';
+$lang['Look_up_user'] = 'Seek user';
+$lang['Find_username'] = 'Find a username';
+$lang['No_match'] = 'No match';
+$lang['Select_username'] = 'Select a username';
+
+// Category
+$lang['sub-cat'] = 'subcategories';
+$lang['images_available'] = 'images in this category';
+$lang['total'] = 'images';
+
+// About
+$lang['about_page_title'] = 'About PhpWebGallery';
+$lang['about_title'] = 'About...';
+$lang['about_message'] = '<div style="text-align:center;font-weigh:bold;">Information about PhpWebGallery</div>
+<ul>
+  <li>This website uses the version '.PHPWG_VERSION.' of <a href="htt://www.phpwebgallery.net" style="text-decoration:underline">PhpWebGallery</a>. PhpWebGallery is a web application giving you the possibility to create an online images gallery easily.</li>
+  <li>Technicaly, PhpWebGallery is fully developped with PHP (the elePHPant) with a MySQL database (the SQuirreL).</li>
+  <li>If you have any suggestions or comments, please visit <a href="http://www.phpwebgallery.net" style="text-decoration:underline">PhpWebGallery</a> official site, and its dedicated <a href="http://forum.phpwebgallery.net" style="text-decoration:underline">forum</a>.</li>
+</ul>';
+
+// Picture
+$lang['add_favorites_alt'] = 'Add to favorites';
+$lang['add_favorites_hint'] = 'Add this picture to your favorites';
+$lang['del_favorites_alt'] = 'Delete from favorites';
+$lang['del_favorites_hint'] = 'Delete this picture from your favorites';
+$lang['link_info_image'] = 'Modify information';
+$lang['true_size'] = 'Real size';
+$lang['comments_title'] = 'Comments from the users of the site';
+$lang['comments_del'] = 'delete this comment';
+$lang['comments_add'] = 'Add a comment';
+$lang['slideshow'] = 'slideshow';
+$lang['period_seconds'] = 'seconds per picture';
+$lang['slideshow_stop'] = 'stop the slideshow';
+$lang['download'] = 'download';
+$lang['download_hint'] = 'download this file';
+$lang['comment_added'] = 'Your comment has been registered';
+$lang['comment_to_validate'] = 'An administrator must authorize your comment before it is visible.';
+$lang['comment_anti-flood'] = 'Anti-flood system : please wait for a moment before trying to post another comment';
+$lang['comment_user_exists'] = 'This login is already used by another user';
+$lang['picture_show_metadata'] = 'Show file metadata';
+$lang['picture_hide_metadata'] = 'Hide file metadata';
+$lang['to_rate'] = 'Rate';
+$lang['update_rate'] = 'Update your rating';
+$lang['element_rate'] = 'rate';
+$lang['already_rated'] = 'You\'ve already rated this item';
+$lang['never_rated'] = 'You\'ve never rated this item';
+$lang['no_rate'] = 'no rate';
+$lang['rates'] = 'rates';
+$lang['standard_deviation'] = 'STD';
+$lang['picture_high'] = 'Click on the picture to see it in high definition';
+$lang['visited'] = 'visited';
+$lang['times'] = 'times';
+
+// Upload
+$lang['upload_forbidden'] = 'You can\'t upload pictures in this category';
+$lang['upload_file_exists'] = 'A picture\'s name already used';
+$lang['upload_filenotfound'] = 'You must choose a picture fileformat for the image';
+$lang['upload_cannot_upload'] = 'can\'t upload the picture on the server';
+$lang['upload_title'] = 'Upload a picture';
+$lang['upload_advise'] = 'Choose an image to place in the category : ';
+$lang['upload_advise_thumbnail'] = 'Optional, but recommended : choose a thumbnail to associate to ';
+$lang['upload_advise_filesize'] = 'the filesize of the picture must not exceed : ';
+$lang['upload_advise_width'] = 'the width of the picture must not exceed : ';
+$lang['upload_advise_height'] = 'the height of the picture must not exceed : ';
+$lang['upload_advise_filetype'] = 'the picture must be to the fileformat jpg, gif or png';
+$lang['upload_err_username'] = 'the username must be given';
+$lang['upload_username'] = 'Username';
+$lang['upload_successful'] = 'Picture uploaded with success, an administrator will validate it as soon as possible';
+$lang['upload_name'] = 'Name of the picture';
+$lang['upload_author'] = 'Author (eg "Pierrick LE GALL")';
+$lang['upload_creation_date'] = 'Creation date (DD/MM/YYYY)';
+
+// Admin messages
+$lang['gallery_locked_message'] = 'The gallery is locked for maintenance. Please, come back later or loggin as an administrator to enter the gallery : <a href="'.PHPWG_ROOT_PATH.'identification.php">Identification</a>';
+$lang['sql_queries_in'] = 'SQL queries in';
+$lang['title_send_mail'] = 'A comment on your site';
+$lang['generation_time'] = 'Page generated in';
+$lang['mail_hello'] = 'Hi,';
+$lang['mail_new_upload_subject'] = 'New picture on the website';
+$lang['mail_new_upload_content'] = 'A new picture has been uploaded on the gallery. It is waiting for your validation. Let\'s meet in the administration panel to authorize or refuse this picture.';
+$lang['mail_new_comment_subject'] = 'New comment on website';
+$lang['mail_new_comment_content'] = 'A new comment has been registered on the gallery. If you chose to validate each comment, you first have to validate this comment in the administration panel to make it visible in the gallery.'."\n\n".'You can see last comments in the administration panel';
+
+
+
+// NOT YET VALIDATED
+$lang['guest'] = 'guest';
+$lang['add'] = 'add';
+
+$lang['title_comments'] = 'Users comments';
+$lang['stats_last_days'] = 'last days';
+$lang['hint_comments'] = 'See last users comments';
+$lang['menu_login'] = 'login';
+$lang['hello'] = 'Hello';
+
+?>
Index: /branches/1.4/language/en_UK.iso-8859-1/faq.lang.php
===================================================================
--- /branches/1.4/language/en_UK.iso-8859-1/faq.lang.php	(revision 3249)
+++ /branches/1.4/language/en_UK.iso-8859-1/faq.lang.php	(revision 3249)
@@ -0,0 +1,274 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Admin FAQ
+$lang['help_images_title'] = 'Adding elements';
+$lang['help_images'] =
+array(
+  'Category directories are in the PhpWebGallery directory "galleries". Here
+follow the directory tree of a very small gallery (but using many features)
+: <br />
+<pre>
+.
+|-- admin
+|-- doc
+|-- galleries
+|   |-- category-1
+|   |   |-- category-1.1
+|   |   |   |-- category-1.1.1
+|   |   |   |   |-- category-1.1.1.1
+|   |   |   |   |   |-- pwg_high
+|   |   |   |   |   |   +-- wedding.jpg
+|   |   |   |   |   |-- thumbnail
+|   |   |   |   |   |   +-- TN-wedding.jpg
+|   |   |   |   |   +-- wedding.jpg
+|   |   |   |   +-- category-1.1.1.2
+|   |   |   +-- category-1.1.2
+|   |   |-- category-1.2
+|   |   |   |-- pookie.jpg
+|   |   |   +-- thumbnail
+|   |   |       +-- TN-pookie.jpg
+|   |   +-- category-1.3
+|   +-- category-2
+|       |-- piglet.gif
+|       |-- pwg_representative
+|       |   +-- video.jpg
+|       |-- thumbnail
+|       |   +-- TN-piglet.jpg
+|       +-- video.avi
+|-- include
+|-- install
+|-- language
+|-- template
++-- tool
+</pre>',
+  
+  'Basically, a category is represented by a directory at any level in
+PhpWebGallery directory "galleries". Each category can contain as many
+sub-level as you wish. In the example above, category-1.1.1.1 is at level 4
+of deepness.',
+  
+  'Basically, an element is represented by a file. A file can be a
+PhpWebGallery element if its extenstion is among $conf[\'file_ext\']
+possibilities (see include/config.inc.php file). A file can be a picture if
+its extension is among $conf[\'picture_ext\'] (see include/config.inc.php
+file).',
+  
+  'Picture elements must have an associated thumbnail (see section below about
+thumbnails)',
+
+  'Picture elements can have a high quality file associated. As for wedding.jpg
+in the example above. No prefix on the high quality picture is required.',
+
+  'Non picture elements (video, sounds, file texts, what you want...) are by
+default represented by an icon corresponding to the filename
+extension. Optionaly, you can associate a thumbnail and a representative
+file (see video.avi in the example above).',
+  
+  'Warning : the name of directories and files must be composed of letters,
+figures, "-", "_" or ".". No blank space, no accentuated characters',
+  
+  'Advise : a category can contain elements and sub-categories in the same
+time. Nerverthless, you are strongly advised for each category to choose
+between category containing elements OR category containing sub-categories.'
+  );
+
+$lang['help_thumbnails_title'] = 'Thumbnails';
+$lang['help_thumbnails'] =
+array(
+  'As said earlier, each element of picture type must be associated with a
+thumbnail.',
+
+  'Thumbnails are stored in the sub-directory "thumbnail" of the category
+directory. The thumbnail is a picture (same filename extensions possible
+than picture files) which filename is prefixed by the configured "Thumbnail
+prefix" (see admin panel, Configuration, General).',
+
+  'Thumbnails don\'t need to have the same extension as their associated
+picture (a picture with .jpg extension can have a thumbnail in .GIF
+extention for instance).',
+
+  'I advise you to use an external module for thumbnails creation (such as
+ThumbClic available on the presentation site of PhpWebGallery).',
+
+  'You can also use the thumbnail creation page integrated in PhpWebGallery,
+but I don\'t advise you so, because thumbnail quality may be poor and it
+uses a high CPU load which can be a problem if you use free web hosting.',
+
+  'If you choose to use your hosting provider to create thumbnails, you must
+give write rights on all category directories and sub-directories
+"thumbnail" for ugo (user, group, other).'
+  
+  );
+
+$lang['help_database_title'] = 'Synchronize filesystem and database';
+$lang['help_database'] =
+array(
+  'Once files, thumbnails and representatives are correctly placed in the
+directories, go to : administration panel, General, Synchronize',
+
+  'There are 2 synchronizations possible : directories/files and file
+metadata. directories/files is about synchronizing your directories tree
+with the category tree in the database. metadata is about updating elements
+informations such as filesize, dimensions in pixels, EXIF or IPTC
+informations.',
+
+  'The first synchronization must be the directories/files one.',
+
+  'Synchronization process may take long (depending on your server load and
+quantity of elements to manage) so it is possible to progress by step :
+category by category.'
+  
+  );
+
+$lang['help_access_title'] = 'Access authorization';
+$lang['help_access'] =
+array(
+  'You can forbid access to categories. Categories can be "public" or
+"private". Permissions (for groups and users) can be set only if the
+category is private.',
+
+  'You can set a category to private by editing a single category
+(administration panel, Categories, Manage, edit) or by setting options to
+your whole category tree (administration panel, Categories, Public/Private)',
+
+  'Once the category is private, you can manage permissions for groups and
+users (administration panel, Permissions).'
+  
+  );
+
+$lang['help_groups_title'] = 'Users Groups';
+$lang['help_groups'] =
+array(
+  
+  'PhpWebGallery is able to manage groups of users. It can be very useful to
+have common permission access for private categories.',
+
+  'You can create groups and add users to a group in administration panel,
+Identification, Groups.',
+
+  'A user can belong to several groups. The authorization is stronger than
+prohibition : if user "jack" belongs to groups "family" and "friends", and
+that only group "family" can see category "Christmas 2003", "jack" will be
+able to see "Christmas 2003".'
+  
+  );
+
+$lang['help_remote_title'] = 'Remote site';
+$lang['help_remote'] =
+array(
+
+  'PhpWebGallery offers the possibility to use several servers to store the
+images which will compose your gallery. It can be useful if your gallery is
+installed on one limited space and that you have a big quantity of images to
+be shown.',
+
+  '1. edit file tools/create_listing_file.php, by modifying parameters section
+such as $conf[\'prefix_thumbnail\'] or $conf[\'use_exif\'].',
+
+  '2. place file "tools/create_listing_file.php" modified on your distant
+website, in the same directory than your category directories (as the
+directory "galleries" of this website) by ftp. For the example, let\'s say
+that you can access http://example.com/galleries/create_listing_file.php.',
+
+  '3. go to administration panel, General, Remote sites. Ask to create a new
+site, for example http://example.com/galleries',
+
+  '4. a new remote site is registered. You can perform 4 actions :
+<ol>
+
+  <li>generate listing : launches a distant request to generate a distant
+  file listing</li>
+
+  <li>update : reads the distant listing.xml file and synchronizes with
+  database informations</li>
+
+  <li>clean : removes distant listing.xml file</li>
+
+  <li>delete : deletes the site (and all related categories and elements) in
+  the database</li>
+
+</ol>',
+
+  'You can do all this by hand by generating yourself the listing.xml file,
+moving it from your distant server to you local PhpWebGallery root
+directory and opening the remote site management screen : PhpWebGallery will
+propose you to use the found listing.xml file.'
+  
+  );
+
+$lang['help_upload_title'] = 'Files upload by users';
+$lang['help_upload'] =
+array(
+  'PhpWebGallery offers the possibility for users to upload images. in order to
+do it :',
+  
+  '1. authorize upload on any categories (administration panel, Categories,
+Manage, edit or administration panel, Categories, Upload)',
+
+  '2. give write rights on directories for ugo (user, group, other)',
+  
+  'Files uploaded by users are not directly visible on the website, they must
+be validated by an administrator. For that purpose, an administrator must go
+on administration panel, Pictures, Waiting in order to validate or to refuse
+the files proposed, then to synchronize filesystem with database.'
+  );
+
+$lang['help_virtual_title'] = 'Links between elements and categories, virtual categories';
+$lang['help_virtual'] =
+array(
+  'PhpWebGallery dissociates categories where elements are stored and
+categories where they are shown.',
+  
+  'By default, elements are shown only in their real categories : the ones
+corresponding to directories on the web server.',
+
+  'To link an element to a category, you just have to make the association on
+the page of element edition (link to this screen on picture.php logged as an
+administrator) or on the informations of all elements of a category.',
+  
+  'Using this principle, it is possible to create virtual categories : no
+directory coresponds to this category. You can create virtual categories in
+administration panel, Categories, Manage.'
+  );
+
+$lang['help_infos_title'] = 'Miscellanous informations';
+$lang['help_infos'] =
+array(
+  'As soon as you created your gallery, modify default display properties in
+administration panel, Configuration, Default. Indeed, every new registered
+user will have by default the same display properties.',
+  
+  'If you have any question, do not hesitate to take a look at the forum or ask
+a question there. The <a href="http://forum.phpwebgallery.net"
+style="text-decoration:underline">forum</a> (message board) is available on
+the presentation site of PhpWebGallery. Check the <a
+href="http://doc.phpwebgallery.net"
+style="text-decoration:underline">official PhpWebGallery documentation</a> for
+further reading.'
+  );
+?>
Index: /branches/1.4/language/en_UK.iso-8859-1/install.lang.php
===================================================================
--- /branches/1.4/language/en_UK.iso-8859-1/install.lang.php	(revision 3249)
+++ /branches/1.4/language/en_UK.iso-8859-1/install.lang.php	(revision 3249)
@@ -0,0 +1,75 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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['install_message'] = 'Message';
+$lang['Initial_config'] = 'Basic configuration';
+$lang['Default_lang'] = 'Default galerie language';
+$lang['step1_title'] = 'Database configuration';
+$lang['step2_title'] = 'Admin configuration';
+$lang['Start_Install'] = 'Start Install';
+$lang['reg_err_mail_address'] = 'mail address must be like xxx@yyy.eee (example : jack@altern.org)';
+$lang['mail_webmaster'] = 'Webmaster mail adress';
+$lang['mail_webmaster_info'] = 'Visitors will be able to contact site administrator with this mail';
+$lang['reg_err_mail_address'] = 'e-mail address refused, it must be like name@server.com';
+
+$lang['install_webmaster'] = 'webmaster login';
+$lang['install_webmaster_info'] = 'It will be shown to the visitors. It is necessary for website administration';
+
+$lang['step1_confirmation'] = 'Parameters are correct';
+$lang['step1_err_db'] = 'Connection to server succeed, but it was impossible to connect to database';
+$lang['step1_err_server'] = 'Can\'t connect to server';
+$lang['step1_err_copy_2'] = 'The next step of the installation is now possible';
+$lang['step1_err_copy_next'] = 'next step';
+$lang['step1_err_copy'] = 'Copy the text between hyphens and paste it into the file "include/mysql.inc.php"(Warning : mysql.inc.php must only contain what is in blue, no line return or space character)';
+
+$lang['step1_host'] = 'MySQL host';
+$lang['step1_host_info'] = 'localhost, sql.multimania.com, toto.freesurf.fr';
+$lang['step1_user'] = 'user';
+$lang['step1_user_info'] = 'user login given by your host provider';
+$lang['step1_pass'] = 'Password';
+$lang['step1_pass_info'] = 'user password given by your host provider';
+$lang['step1_database'] = 'Database name';
+$lang['step1_database_info'] = 'also given by your host provider';
+$lang['step1_prefix'] = 'Database table prefix';
+$lang['step1_prefix_info'] = 'database tables names will be prefixed with it (enables you to manage better your tables)';
+$lang['step2_err_login1'] = 'enter a login for webmaster';
+$lang['step2_err_login3'] = 'webmaster login can\'t contain characters \' or "';
+$lang['step2_err_pass'] = 'please enter your password again';
+$lang['install_end_title'] = 'Installation finished';
+$lang['step2_pwd'] = 'webmaster password';
+$lang['step2_pwd_info'] = 'Keep it confidential, it enables you to access administration panel';
+$lang['step2_pwd_conf'] = 'confirm password';
+$lang['step2_pwd_conf_info'] = 'verification';
+$lang['install_help'] = 'Need help ? Ask your question on <a href="http://forum.phpwebgallery.net">PhpWebGallery message board</a>.';
+$lang['install_end_message'] = 'The configuration of PhpWebGallery is finished, here is the next step<br /><br />
+For security reason, please delete file "install.php"<br />
+Once this file deleted , follow this instructions :
+<ul>
+<li>go to the identification page : [ <a href="identification.php">identification</a> ] and use the login/password given for webmaster</li>
+<li>this login will enable you to access to the administration panel and to the instructions in order to place pictures in your directories</li>
+</ul>';
+?>
Index: /branches/1.4/language/en_UK.iso-8859-1/iso.txt
===================================================================
--- /branches/1.4/language/en_UK.iso-8859-1/iso.txt	(revision 3249)
+++ /branches/1.4/language/en_UK.iso-8859-1/iso.txt	(revision 3249)
@@ -0,0 +1,1 @@
+English [UK]
Index: /branches/1.4/language/fr_FR.iso-8859-1/admin.lang.php
===================================================================
--- /branches/1.4/language/fr_FR.iso-8859-1/admin.lang.php	(revision 3249)
+++ /branches/1.4/language/fr_FR.iso-8859-1/admin.lang.php	(revision 3249)
@@ -0,0 +1,357 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Main words
+$lang['links'] = 'Liens';
+$lang['general'] = 'Général';
+$lang['config'] = 'Configuration';
+$lang['users'] = 'Utilisateurs';
+$lang['instructions'] = 'Instructions';
+$lang['history'] = 'Historique';
+$lang['manage'] = 'Gestion';
+$lang['waiting'] = 'En attente';
+$lang['access'] = 'Accès';
+$lang['groups'] = 'Groupes';
+$lang['permissions'] = 'Autorisations';
+$lang['update'] = 'Synchroniser';
+$lang['edit'] = 'Editer';
+$lang['authorized'] = 'Autorisé';
+$lang['forbidden'] = 'Interdit';
+$lang['public'] = 'Publique';
+$lang['private'] = 'Privée';
+$lang['metadata']='Métadonnées';
+$lang['visitors'] = 'Visiteurs';
+$lang['storage'] = 'Répertoire';
+$lang['locked'] = 'Verrouillée';
+$lang['unlocked'] = 'Déverrouillée';
+$lang['lock'] = 'Verrouiller';
+$lang['unlock'] = 'Déverrouiller';
+$lang['up'] = 'Monter';
+$lang['down'] = 'Descendre';
+$lang['path'] = 'Chemin d\'accès';
+$lang['no_write_access'] = 'pas d\'accès en écriture';
+
+// Specific words
+$lang['phpinfos'] = 'Informations PHP';
+$lang['remote_site'] = 'Site distant';
+$lang['remote_sites'] = 'Sites distant';
+$lang['gallery_default'] = 'Options par défaut';
+$lang['upload'] = 'Ajout d\'images';
+
+// Remote sites management
+$lang['remote_site_create'] = 'Créer un nouveau site distant : (donner l\'URL vers generate_file_listing.php)';
+$lang['remote_site_uncorrect_url'] = 'L\'URL d\'un site distant doit commencer par http ou https et ne doit être composé que de caractères parmi "/", "a-zA-Z0-9", "-" ou "_"';
+$lang['remote_site_already_exists'] = 'Ce site existe déjà';
+$lang['remote_site_generate'] = 'générer la liste';
+$lang['remote_site_generate_hint'] = 'générer fichier listing.xml sur le site distant';
+$lang['remote_site_update'] = 'mettre à jour';
+$lang['remote_site_update_hint'] = 'lire le fichier distant listing.xml et mettre à jour la base de données locale';
+$lang['remote_site_clean'] = 'nettoyer';
+$lang['remote_site_clean_hint'] = 'supprimer le fichier listing.xml distant';
+$lang['remote_site_delete'] = 'détruire';
+$lang['remote_site_delete_hint'] = 'détruire ce site et tous les éléments associés';
+$lang['remote_site_file_not_found'] = 'le fichier create_listing_file.php n\'a pas été trouvé sur le site distant';
+$lang['remote_site_error'] = 'Une erreur est intervenue';
+$lang['remote_site_listing_not_found'] = 'fichier distant de listing introuvable';
+$lang['remote_site_removed'] = 'a été supprimé du site distant';
+$lang['remote_site_removed_title'] = 'Eléments supprimés';
+$lang['remote_site_created'] = 'Créé';
+$lang['remote_site_deleted'] = 'Détruit';
+$lang['remote_site_local_found'] = 'Un fichier listing.xml local a été trouvé pour ';
+$lang['remote_site_local_new'] = '(nouveau site)';
+$lang['remote_site_local_update'] = 'lire fichier listing.xml local et mettre à jour la base';
+
+// Category words
+$lang['title_cat_perm'] = 'Modifier les permissions pour la catégorie';
+$lang['cat_security'] = 'Sécurité';
+$lang['cat_options'] = 'Options de la catégorie';
+$lang['cat_add'] = 'Ajouter une catégorie virtuelle';
+$lang['cat_virtual'] = 'Catégorie virtuelle';
+$lang['cat_public'] = 'Catégorie publique';
+$lang['cat_private'] = 'Catégorie privée';
+$lang['cat_image_info'] = 'Infos images';
+$lang['editcat_status'] = 'Statut';
+$lang['editcat_confirm'] = 'Les informations associées à cette catégorie ont été mises à jour.';
+$lang['editcat_perm'] = 'Pour accéder aux permissions associées, cliquez';
+$lang['editcat_lock_info'] = 'Verrouiller temporairement une catégorie (maintenance). Elle devient alors invisible pour les utilisateurs.';
+$lang['editcat_uploadable'] = 'Autoriser l\'ajout d\'images';
+$lang['editcat_uploadable_info'] = 'Les utilisateurs pourront ajouter des images.';
+$lang['editcat_commentable_info'] = 'Autoriser les utilisateurs à poster des commentaires.';
+$lang['cat_access_info'] = 'Permet de gérer l\'accès à cette catégorie.';
+$lang['cat_virtual_added'] = 'Catégorie virtuelle créée';
+$lang['cat_virtual_deleted'] = 'Catégorie virtuelle détruite';
+$lang['cat_upload_title'] = 'Sélectionner les catégories pour lesquelles l\'ajout d\'image est autorisé';
+$lang['cat_upload_info'] = 'Seules les catégories non virtuelles et non distantes sont repertoriées.';
+$lang['cat_lock_title'] = 'Verrouiller les catégories';
+$lang['cat_lock_info'] = 'Verrouiller temporairement une catégorie (maintenance). Elle devient alors invisible pour les utilisateurs.
+<br />Toutes les sous-catégories seront aussi verrouillées ou toutes les catégories mères seront déverouillées selon votre action.';
+$lang['cat_comments_title'] = 'Autoriser les utilisateurs à poster des commentaires';
+$lang['cat_comments_info'] = 'Par héritage, il est possible de poster des commentaires dans une sous-catégorie si cela est autorisé pour au moins une catégorie mère.';
+$lang['cat_status_title'] = 'Gestion des autorisations';
+$lang['cat_status_info'] = 'Les catégories sélectionnées sont privées : vous devrez permettre à vos utilisateurs et / ou groupes d\'y accéder.
+<br />Si une catégorie est déclarée privée, alors toutes ses sous catégories deviennent privées.
+<br />Si une catégorie est déclarée publique, alors toutes les catégories mères deviennent publiques.';
+$lang['cat_representant'] = 'Trouver un nouveau représentant au hasard';
+
+//Titles
+$lang['admin_panel'] = 'Panneau d\'administration';
+$lang['default_message'] = 'Zone d\'administration de PhpWebGallery';
+$lang['title_liste_users'] = 'Liste des utilisateurs';
+$lang['title_history'] = 'Historique';
+$lang['title_update'] = 'Synchronisation base de données avec fichiers';
+$lang['title_configuration'] = 'Configuration de PhpWebGallery';
+$lang['title_instructions'] = 'Instructions';
+$lang['title_categories'] = 'Gestion des catégories';
+$lang['title_edit_cat'] = 'Editer une catégorie';
+$lang['title_info_images'] = 'Modifier les informations sur les images d\'une catégorie';
+$lang['title_thumbnails'] = 'Création des miniatures';
+$lang['title_thumbnails_2'] = 'pour';
+$lang['title_default'] = 'Administration de PhpWebGallery';
+$lang['title_waiting'] = 'Images en attente de validation';
+$lang['title_upload'] = 'Sélectionner les catégories pour lesquelles l\'ajout d\'image est autorisé';
+$lang['title_cat_options'] = 'Options relatives aux catégories';
+$lang['title_groups'] = 'Gestion des groupes';
+
+//Error messages
+$lang['conf_confirmation'] = 'Informations enregistrées dans la base de données';
+$lang['cat_error_name'] = 'Le nom d\'une catégorie ne doit pas être nul';
+
+// Configuration
+$lang['conf_default'] = 'Affichage par défaut';
+$lang['conf_cookie'] = 'Session & Cookie';
+
+// Configuration -> general
+$lang['conf_general_title'] = 'Configuration générale';
+$lang['conf_mail_webmaster'] = 'Adresse e-mail de l\'Administrateur';
+$lang['conf_mail_webmaster_info'] = 'Les visiteurs pourront vous contacter par ce mail';
+$lang['conf_mail_webmaster_error'] = 'Adresse email non valide. Elle doit être de la forme : nom@domaine.com';
+$lang['conf_prefix'] = 'Préfixe miniature';
+$lang['conf_prefix_info'] = 'Les noms des fichiers miniatures en sont préfixé. Laissez vide en cas de doute.';
+$lang['conf_prefix_thumbnail_error'] = 'Le préfixe doit être uniquement composé des caractères suivant : a-z, "-" ou "_"';
+$lang['conf_access'] = 'Type d\'acces';
+$lang['conf_log_info'] = 'historiser les visites sur le site ? Les visites seront visibles dans l\'historique de l\'administration';
+$lang['conf_notification'] = 'Notification par mail';
+$lang['conf_notification_info'] = 'Notification automatique par mail des administrateurs (seuls les administrateurs) lors de l\'ajout d\'un commentaire, ou lors de l\'ajout d\'une image.';
+$lang['conf_gallery_locked'] = 'Verrouiller la galerie';
+$lang['conf_gallery_locked_info'] = 'Verrouiller toute la galerie pour maintenance. 
+Attention à ne pas vous déconnecter : seul l\'administrateur sera capable d\'y accéder.';
+
+// Configuration -> comments
+$lang['conf_comments_title'] = 'Configuration des commentaires';
+$lang['conf_comments_forall'] = 'Autoriser pour tous ?';
+$lang['conf_comments_forall_info'] = 'Même les invités non enregistrés peuvent déposer les messages';
+$lang['conf_nb_comment_page'] = 'Nombre de commentaires par page';
+$lang['conf_nb_comment_page_info'] = 'Nombre de commentaire à afficher sur chaque page. Le nombre de commentaires pour une image reste illimité. Entrer un nombre entre 5 et 50.';
+$lang['conf_nb_comment_page_error'] = 'Le nombre de commentaires par page doit être compris entre 5 et 50 inclus.';
+$lang['conf_comments_validation'] = 'Validation';
+$lang['conf_comments_validation_info'] = 'L\'administrateur valide les commentaires avant qu\'ils apparaissent sur le site';
+
+// Configuration -> default
+$lang['conf_default_title'] = 'Configuration de l\'affichage par défaut';
+$lang['conf_default_language_info'] = 'Langue par défaut';
+$lang['conf_default_theme_info'] = 'Thème par défaut';
+$lang['conf_nb_image_line_info'] = 'Nombre d\'images par ligne par défaut';
+$lang['conf_nb_line_page_info'] = 'Nombre de lignes par page par défaut';
+$lang['conf_recent_period_info'] = 'En nombre de jours. Période pendant laquelle l\'image est notée comme récente. La durée doit au moins être d\'un jour.';
+$lang['conf_default_expand_info'] = 'Développer toutes les catégories par défaut dans le menu ?';
+$lang['conf_show_nb_comments_info'] = 'Montrer le nombre de commentaires pour chaque image sur la page des miniatures';
+$lang['conf_default_maxwidth_info'] = 'Largeur maximum affichable pour les images : les images ne seront redimensionnées que pour l\'affichage, les fichiers images resteront intacts. 
+Laisser vide si vous ne souhaitez pas mettre de limite.';
+$lang['conf_default_maxheight_info'] = 'Idem mais pour la hauteur des images';
+
+// Configuration -> upload
+$lang['conf_upload_title'] = 'Configuration de l\'envoi d\'images par les utilisateurs';
+$lang['conf_upload_maxfilesize'] = 'Poids maximum';
+$lang['conf_upload_maxfilesize_info'] = 'Poids maximum autorisé pour les images uploadées. Celui-ci doit être un entier compris entre 10 et 1000, en Ko.';
+$lang['conf_upload_maxfilesize_error'] = 'Le poids maximum pour les images uploadés doit être un entier compris entre 10 et 1000.';
+$lang['conf_upload_maxwidth'] = 'Largeur maximum';
+$lang['conf_upload_maxwidth_info'] = 'Largeur maximum autorisée pour les images. Celle-ci doit être un entier supérieur à 10, en pixels.';
+$lang['conf_upload_maxwidth_error'] = 'la largeur maximum des images uploadées doit être un entier supérieur à 10.';
+$lang['conf_upload_maxheight'] = 'Hauteur maximum';
+$lang['conf_upload_maxheight_info'] = 'Hauteur maximum autorisée pour les images. Celle-ci doit être un entier supérieur à 10, en pixels.';
+$lang['conf_upload_maxheight_error'] = 'La hauteur maximum des images uploadées doit être un entier supérieur à 10.';
+$lang['conf_upload_tn_maxwidth'] = 'Largeur maximum miniatures.';
+$lang['conf_upload_tn_maxwidth_info'] = 'Largeur maximum autorisée pour les miniatures. Celle-ci doit être un entier supérieur à 10, en pixels.';
+$lang['conf_upload_maxwidth_thumbnail_error'] = 'La largeur maximum des miniatures uploadées doit être un entier supérieur à 10.';
+$lang['conf_upload_tn_maxheight'] = 'Hauteur maximum miniatures';
+$lang['conf_upload_tn_maxheight_info'] = 'Hauteur maximum autorisée pour les miniatures. Celle-ci doit être un entier supérieur à 10, en pixels.';
+$lang['conf_upload_maxheight_thumbnail_error'] = 'La hauteur maximum des miniatures uploadées doit être un entier supérieur à 10.';
+
+// Configuration -> session
+$lang['conf_session_title'] = 'Configuration des sessions';
+$lang['conf_authorize_remembering'] = 'Connexion automatique';
+$lang['conf_authorize_remembering_info'] = 'Les utilisateurs ne devront plus s\'identifier à chaque nouvelle visiste du site';
+
+// Configuration -> metadata
+$lang['conf_metadata_title'] = 'Configuration des métadonnées des images';
+$lang['conf_use_exif'] = 'Analyse des EXIF';
+$lang['conf_use_exif_info'] = 'Analyse les données EXIF durant la synchronisation des images';
+$lang['conf_use_iptc'] = 'Analyse des IPTC';
+$lang['conf_use_iptc_info'] = 'Analyse les données IPTC durant la synchronisation des images';
+$lang['conf_show_exif'] = 'Montrer les EXIF';
+$lang['conf_show_exif_info'] = 'Affiche les métadonnées EXIF';
+$lang['conf_show_iptc'] = 'Montrer les IPTC';
+$lang['conf_show_iptc_info'] = 'Affiche les métadonnées IPTC';
+
+// Image informations
+$lang['title_picmod'] = 'Modifier les informations d\'une image';
+$lang['infoimage_general'] = 'Options générale pour la catégorie';
+$lang['infoimage_useforall'] = 'utiliser pour toutes les images ?';
+$lang['infoimage_creation_date'] = 'Date de création';
+$lang['infoimage_detailed'] = 'Options pour chaque image / photo';
+$lang['infoimage_title'] = 'Titre';
+$lang['infoimage_keyword_separation'] = '(séparer avec des ",")';
+$lang['infoimage_addtoall'] = 'ajouter à tous';
+$lang['infoimage_removefromall'] = 'retirer à tous';
+$lang['infoimage_associate'] = 'Associer à la catégorie';
+$lang['infoimage_associated'] = 'Associé';
+$lang['infoimage_dissociated'] = 'Non associé';
+$lang['storage_category'] = 'Repertoire de stockage';
+$lang['represents'] = 'Représente';
+$lang['doesnt_represent'] = 'Autres catégories';
+$lang['cat_unknown_id'] = 'Cette catégorie n\'existe pas dans la base de données';
+$lang['dissociate'] = 'dissocier';
+
+// Thumbnails
+$lang['tn_width'] = 'largeur';
+$lang['tn_height'] = 'hauteur';
+$lang['tn_no_support'] = 'Image inexistante ou aucun support';
+$lang['tn_format'] = 'pour le format';
+$lang['tn_thisformat'] = 'pour ce format de fichier';
+$lang['tn_err_width'] = 'la largeur doit être un entier supérieur à';
+$lang['tn_err_height'] = 'la hauteur doit être un entier supérieur à';
+$lang['tn_results_title'] = 'Résultats de la miniaturisation';
+$lang['tn_picture'] = 'image';
+$lang['tn_results_gen_time'] = 'généré en';
+$lang['tn_stats'] = 'Statistiques générales';
+$lang['tn_stats_nb'] = 'nombre d\'images miniaturisées';
+$lang['tn_stats_total'] = 'temps total';
+$lang['tn_stats_max'] = 'temps max';
+$lang['tn_stats_min'] = 'temps min';
+$lang['tn_stats_mean'] = 'temps moyen';
+$lang['tn_err'] = 'Vous avez commis des erreurs';
+$lang['tn_params_title'] = 'Paramètres de miniaturisation';
+$lang['tn_params_GD'] = 'version de GD';
+$lang['tn_params_GD_info'] = '- GD est la bibliothèque de manipulation graphique pour PHP<br />
+- cochez la version de GD installée sur le serveur. Si vous choisissez l\'une et que vous obtenez ensuite des messages d\'erreur, choisissez l\'autre version. 
+Si aucune version ne marche, cela signifie que GD n\'est pas installé sur le serveur.';
+$lang['tn_params_width_info'] = 'largeur maximum que peut prendre les miniatures';
+$lang['tn_params_height_info'] = 'hauteur maximum que peut prendre les miniatures';
+$lang['tn_params_create'] = 'en créer';
+$lang['tn_params_create_info'] = 'N\'essayez pas de lancer directement un grand nombre de miniaturisation.<br />
+En effet la miniaturisation est coûteuse en ressources processeur pour le serveur. 
+Si vous êtes chez un hébergeur gratuit, une trop forte occupation processeur peut amener l\'hébergeur à supprimer votre compte.';
+$lang['tn_params_format'] = 'format';
+$lang['tn_params_format_info'] = 'seul le format jpeg est supporté pour la création des miniatures';
+$lang['tn_alone_title'] = 'images sans miniatures (format jpg et png uniquement)';
+$lang['tn_dirs_title'] = 'Liste des répertoires';
+$lang['tn_dirs_alone'] = 'images sans miniatures';
+$lang['tn_no_missing'] = 'Aucune miniature ne manque';
+$lang['tn_all'] = 'tout';
+
+// Waiting files 
+$lang['waiting_update'] = 'Les images validées ne seront visibles qu\'après mise à jour de la base d\'images.';
+
+// Update
+$lang['update_missing_tn'] = 'Il manque la miniature pour';
+$lang['update_missing_tn_short'] = 'Miniature manquante';
+$lang['update_missing_tn_info'] = 'Une image nécessite une miniature. 
+Celle ci doit être présente dans le répertoire "thumbnail" du repertoire de la catégorie.
+Le nom de la miniature doit commencer par le préfixe défini par la configuration de la galerie et doit être du type :';
+$lang['update_disappeared_tn'] = 'La miniature n\'existe pas';
+$lang['update_disappeared'] = 'n\'existe pas';
+$lang['update_part_deletion'] = 'Suppression des images de la base qui n\'ont pas de thumbnail ou qui n\'existent pas';
+$lang['update_part_research'] = 'Recherche des nouvelles images dans les répertoires';
+$lang['update_research_added'] = 'ajouté';
+$lang['update_research_deleted'] = 'détruit';
+$lang['update_research_tn_ext'] = 'miniature en';
+$lang['update_default_title'] = 'Type de synchronisation';
+$lang['update_nb_new_elements'] = 'élément(s) ajouté(s)';
+$lang['update_nb_del_elements'] = 'élément(s) effacé(s)';
+$lang['update_nb_new_categories'] = 'catégorie(s) ajoutée(s)';
+$lang['update_nb_del_categories'] = 'catégorie(s) effacée(s)';
+$lang['update_sync_files'] = 'Synchroniser la structure';
+$lang['update_sync_dirs'] = 'Seulement les catégories';
+$lang['update_sync_all'] = 'Catégories et fichiers';
+$lang['update_sync_metadata'] = 'Synchroniser les méta-donnnées';
+$lang['update_sync_metadata_new'] = 'Seulement sur les nouveaux éléments';
+$lang['update_sync_metadata_all'] = 'Sur tous les éléments';
+$lang['update_cats_subset'] = 'Limiter la synchronisation aux catégories suivantes';
+$lang['update_nb_errors'] = 'erreurs durant la synchronisation';
+$lang['update_error_list_title'] = 'Liste d\'erreurs';
+$lang['update_errors_caption'] = 'Explications';
+$lang['update_display_info'] = 'Afficher des informations détaillées';
+$lang['update_simulate'] = 'Simuler (aucune opération ne sera sauvegardée)';
+$lang['update_infos_title'] = 'Informations détaillées';
+$lang['update_simulation_title'] = '[Simulation]';
+$lang['update_wrong_dirname'] = 'Le nom du répertoire peut être composé de lettres et des signes "-", "_" or "."';
+$lang['update_wrong_dirname_short'] = 'Nom incorrect';
+$lang['update_wrong_dirname_info'] = 'Le nom du répertoire peut être composé de lettres et des signes "-", "_" or "."';
+$lang['update_result_metadata'] = 'Résultats de la synchronization avec les méta-données';
+$lang['update_elements_metadata_sync'] = 'éléments synchronisés avec les méta-données';
+$lang['update_used_metadata'] = 'Méta-données utilisées';
+$lang['metadata_basic'] = 'basique';
+$lang['metadata_exif'] = 'EXIF';
+$lang['metadata_iptc'] = 'IPTC';
+
+// History
+$lang['stats_title'] = 'Historique de l\'année écoulée';
+$lang['stats_month_title'] = 'Historique mois par mois';
+$lang['stats_pages_seen'] = 'Pages vues';
+$lang['stats_global_graph_title'] = 'Nombre de pages vues par mois';
+$lang['stats_visitors_graph_title'] = 'Nombre de visiteurs par jour';
+
+// Users
+$lang['title_user_modify'] = 'Modifier un utilisateur';
+$lang['title_user_perm'] = 'Modifier les permissions pour l\'utilisateur';
+$lang['user_err_modify'] = 'Cet utilisateur ne peut pas être modifé ou supprimé';
+$lang['user_err_unknown'] = 'Cet utilisateur n\'existe pas dans la base de données';
+$lang['user_management'] = 'Champs spéciaux pour l\'administrateur';
+$lang['user_status'] = 'Statut de l\'utilisateur';
+$lang['user_status_admin'] = 'Administrateur';
+$lang['user_status_guest'] = 'Utilisateur';
+$lang['user_delete'] = 'Supprimer l\'utilisateur';
+$lang['user_delete_hint'] = 'Cliquez ici pour supprimer définitivement l\'utilisateur. Attention cette opération ne pourra être rétablie.';
+$lang['permuser_info'] = 'Seules les catégories déclarées en privée sont affichées. Le status privé/public des catégories est configurable dans l\'écran "Catégories &gt; Sécurité" de l\'administration.';
+$lang['permuser_only_private'] = 'Seules les catégories privées sont représentées';
+$lang['order_by'] = 'classer par';
+$lang['registration_date'] = 'date d\'enregistrement';
+$lang['ascending'] = 'croissant';
+$lang['descending'] = 'décroissant';
+$lang['actions'] = 'actions';
+
+// Groups
+$lang['group_list_title'] = 'Liste des groupes existants';
+$lang['group_confirm_delete']= 'Confirmer la destruction du groupe';
+$lang['group_add'] = 'Ajouter un groupe';
+$lang['group_add_error1'] = 'Le nom du groupe ne doit pas comporter de " ou de \' et ne pas être vide.';
+$lang['group_add_error2'] = 'Ce nom de groupe est déjà utilisé.';
+$lang['group_edit'] = 'Edition des utilisateurs appartenant au groupe';
+$lang['group_deny_user'] = 'Supprimer la sélection';
+$lang['group_add_user']= 'Ajouter le membre';
+$lang['title_group_perm'] = 'Modifier les permissions pour le groupe';
+?>
Index: /branches/1.4/language/fr_FR.iso-8859-1/common.lang.php
===================================================================
--- /branches/1.4/language/fr_FR.iso-8859-1/common.lang.php	(revision 3249)
+++ /branches/1.4/language/fr_FR.iso-8859-1/common.lang.php	(revision 3249)
@@ -0,0 +1,311 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Langage informations
+$lang_info['language_name'] = 'Français';
+$lang_info['country'] = 'France';
+$lang_info['charset'] = 'iso-8859-1';
+$lang_info['direction'] = 'ltr';
+$lang_info['code'] = 'fr';
+
+// Main words 
+$lang['no_category'] = 'Accueil';
+$lang['category'] = 'Catégorie';
+$lang['categories'] = 'Catégories';
+$lang['thumbnail'] = 'Miniature';
+$lang['thumbnails'] = 'Miniatures';
+$lang['search'] = 'Rechercher';
+$lang['comment'] = 'Commentaire';
+$lang['comments'] = 'Commentaires';
+$lang['picture'] = 'Image';
+$lang['pictures'] = 'Images';
+$lang['name'] = 'Nom';
+$lang['no'] = 'Non';
+$lang['yes'] = 'Oui';
+$lang['date'] = 'Date';
+$lang['description'] = 'Description';
+$lang['author'] = 'Auteur';
+$lang['size'] = 'Dimensions';
+$lang['filesize'] = 'Poids';
+$lang['file'] = 'Fichier';
+$lang['keywords'] = 'Mots-clefs';
+$lang['default'] = 'Défaut';
+$lang['webmaster'] = 'Webmaster';
+$lang['language'] = 'Langue';
+$lang['send_mail'] = 'Contact';
+$lang['powered_by'] = 'Propulsé par';
+$lang['all_categories'] = 'toutes catégories';
+
+// Properties
+$lang['registration_date'] = 'Enregistré le';
+$lang['creation_date'] = 'Créé le';
+
+// Form words 
+$lang['submit'] = 'Valider';
+$lang['delete'] = 'Supprimer';
+$lang['reset'] = 'Rétablir';
+$lang['Close'] = 'Fermer la fenêtre';
+$lang['Select'] = 'Sélectionner';
+
+// Error management
+$lang['mandatory'] = 'obligatoire';
+$lang['err_date'] = 'date erronée';
+
+// Identification
+$lang['login'] = 'Nom d\'utilisateur';
+$lang['password'] = 'Mot de passe';
+$lang['logout'] = 'Se déconnecter';
+$lang['customize'] = 'Personnalisation';
+$lang['new'] = 'Nouveau';
+$lang['identification'] = 'Identification';
+$lang['remember_me'] = 'Connexion auto';
+$lang['only_members'] = 'Seuls les membres du site peuvent accéder à cette page';
+$lang['invalid_pwd'] = 'Le mot de passe rentré n\'est pas valide';
+$lang['access_forbiden'] = 'Vous n\'êtes pas autorisé à aller dans cette section';
+$lang['ident_register'] = 'S\'enregistrer';
+$lang['ident_forgotten_password'] = 'Mot de passe oublié ?';
+$lang['ident_guest_visit'] = 'Parcourir la galerie en tant que visiteur';
+
+// Register
+$lang['register_page_title'] = 'Enregistrement';
+$lang['register_title'] = 'Enregistrement';
+$lang['reg_err_login1'] = 'veuillez rentrer un pseudo';
+$lang['reg_err_login2'] = 'le pseudo ne doit pas se terminer par un espace';
+$lang['reg_err_login3'] = 'le pseudo ne doit pas commencer par un espace';
+$lang['reg_err_login4'] = 'le pseudo ne doit pas comporter les caractère " et \'';
+$lang['reg_err_login5'] = 'ce pseudo est déjà utilisé';
+$lang['reg_err_pass'] = 'veuillez retaper le mot de passe';
+$lang['reg_confirm'] = 'Confirmer le mot de passe';
+$lang['reg_err_mail_address'] = 'l\'adresse mail doit être de la forme xxx@yyy.eee (exemple : jack@altern.org)';
+
+// Navigation
+$lang['home'] = 'Accueil';
+$lang['title_menu'] = 'Sommaire';
+$lang['home_hint'] = 'Retour à la page des miniatures';
+$lang['special_categories'] = 'Spécial';
+$lang['favorite_cat'] = 'Favoris';
+$lang['favorite_cat_hint'] = 'Afficher vos favoris';
+$lang['most_visited_cat'] = 'plus vues';
+$lang['most_visited_cat_hint'] = 'affiche les images les plus visitées';
+$lang['best_rated_cat'] = 'mieux notées';
+$lang['best_rated_cat_hint'] = 'affiche les images les mieux notées';
+$lang['recent_pics_cat'] = 'Nouvelles images';
+$lang['recent_pics_cat_hint'] = 'Affiche les images les plus récentes';
+$lang['recent_cats_cat'] = 'Nouvelles catégories';
+$lang['recent_cats_cat_hint'] = 'Affiche les catégories les plus récentes';
+$lang['random_cat'] = 'Images au hasard';
+$lang['random_cat_hint'] = 'Affiche plusieurs images choisies au hasard';
+$lang['recent_image'] = 'Image datant de moins de';
+$lang['about'] = 'A propos';
+$lang['hint_about'] = 'Quelques informations sur PhpWebGallery...';
+$lang['admin'] = 'Administration';
+$lang['hint_admin'] = 'Partie accessible uniquement aux administrateurs';
+$lang['page_number'] = 'numéro de page';
+$lang['previous_page'] = 'Précédente';
+$lang['next_page'] = 'Suivante';
+$lang['first_page'] = '<<';
+$lang['last_page'] = '>>';
+$lang['hint_category'] = 'affiche les images à la racine de cette catégorie';
+$lang['hint_customize'] = 'personnaliser votre affichage';
+$lang['hint_search'] = 'lancer une recherche';
+$lang['upload_picture'] = 'Ajouter une image';
+$lang['favorites'] = 'Favoris';
+
+//Calendar
+$lang['calendar'] = 'Calendrier';
+$lang['calendar_hint'] = 'Affiche toutes les images triées par mois';
+$lang['calendar_picture_hint'] = 'Affiche les images ajoutées en ';
+$lang['month'][1] = 'Janvier';
+$lang['month'][2] = 'Février';
+$lang['month'][3] = 'Mars';
+$lang['month'][4] = 'Avril';
+$lang['month'][5] = 'Mai';
+$lang['month'][6] = 'Juin';
+$lang['month'][7] = 'Juillet';
+$lang['month'][8] = 'Août';
+$lang['month'][9] = 'Septembre';
+$lang['month'][10] = 'Octobre';
+$lang['month'][11] = 'Novembre';
+$lang['month'][12] = 'Décembre';
+$lang['day'][0] = 'Dimanche';
+$lang['day'][1] = 'Lundi';
+$lang['day'][2] = 'Mardi';
+$lang['day'][3] = 'Mercredi';
+$lang['day'][4] = 'Jeudi';
+$lang['day'][5] = 'Vendredi';
+$lang['day'][6] = 'Samedi';
+$lang['w_month']='Mois';
+$lang['w_day']='Jour';;
+$lang['days']='Jours';
+$lang['today']='Aujourd\'hui';
+
+// Customization
+$lang['customize_page_title'] = 'Personnalisation de votre galerie';
+$lang['customize_title'] = 'Personnalisation';
+$lang['preferences'] = 'Préférences';
+$lang['password_hint'] = 'Vous devez confirmer votre mot de passe si vous souhaitez modifier votre adresse e-mail';
+$lang['new_password'] = 'Nouveau mot de passe';
+$lang['new_password_hint'] = 'Vous avez seulement besoin de fournir un mot de passe si vous voulez le changer';
+$lang['confirm_password_hint'] = 'Vous avez seulement besoin de confirmer votre mot de passe si vous l\'avez changé ci-dessus';
+$lang['nb_image_per_row'] = 'Nombre d\'images par ligne';
+$lang['nb_row_per_page'] = 'Nombre de lignes par page';
+$lang['maxwidth'] = 'Largeur maximum des images';
+$lang['maxheight'] = 'Hauteur maximum des images';
+$lang['auto_expand'] = 'Développer toutes les catégories';
+$lang['show_nb_comments'] = 'Montrer le nombre de commentaires';
+$lang['recent_period'] = 'Durée de nouveauté';
+$lang['theme'] = 'Thème de l\'interface';
+$lang['mail_address'] = 'Adresse e-mail';
+$lang['periods_error'] = 'La période doit être entière.';
+$lang['maxwidth_error'] = 'La largeur maximum des images doit être un entier supérieur à 50';
+$lang['maxheight_error'] = 'La hauteur maximum des images doit être un entier supérieur à 50';
+
+// search
+$lang['search_title'] = 'Rechercher';
+$lang['search_options'] = 'Options de recherche';
+$lang['search_keywords'] = 'Recherche par mots';
+$lang['search_keywords_hint'] = 'Effectuez une recherche sur tous les champs des images présentes dans la galerie. Utilisez * comme un joker pour des recherches partielles';
+$lang['search_mode_or'] = 'Rechercher n\'importe quel de ces termes';
+$lang['search_mode_and'] = 'Rechercher tous les termes';
+$lang['search_author'] = 'Recherche par auteur';
+$lang['search_categories'] = 'Recherche dans les catégories';
+$lang['search_subcats_included'] = 'Rechercher dans les sous-catégories';
+$lang['search_categories_hint'] = 'Sélectionnez le ou les catégorie(s) pour lesquelles vous souhaitez faire votre rechercher.';
+$lang['search_explain'] = 'Utilisez * comme un joker pour des recherches partielles';
+$lang['search_date'] = 'Rechercher par date';
+$lang['search_date_hint'] = 'Sélectionnez une date et une date de fin pour vos recherches.<br />
+Ne remplissez que la date de fin pour faire une recherche de type "avant".<br />
+L\'année doit être rentrée dans le dernier champ sous la forme 0000 (par exemple 2004).';
+$lang['search_date_from'] = 'Date';
+$lang['search_date_to'] = 'Date de fin';
+$lang['search_date_type'] = 'Type de date';
+$lang['search_date_available'] = 'Mise à disposition';
+$lang['search_date_creation'] = 'Création';
+$lang['search_sort'] = 'Trier par';
+$lang['search_ascending'] = 'Croissant';
+$lang['search_descending'] = 'Décroissant';
+$lang['search_one_clause_at_least'] = 'Recherche vide. Aucun critère n\'a été renseigné.';
+$lang['search_result'] = 'Résultats de la recherche';
+$lang['invalid_search'] = 'Les mots recherchés doivent comporter plus de 3 caractères et ne doivent pas inclure de caractères de ponctuation';
+$lang['Look_up_user'] = 'Rechercher l\'utilisateur';
+$lang['Find_username'] = 'Trouver un nom d\'utilisateur';
+$lang['No_match'] = 'Aucun enregistrement trouvé.';
+$lang['Select_username'] = 'Sélectionner un Nom d\'utilisateur';
+
+// Category
+$lang['sub-cat'] = 'sous-catégories';
+$lang['images_available'] = 'images dans cette catégorie';
+$lang['total'] = 'images';
+
+// About
+$lang['about_page_title'] = 'A propos de PhpWebGallery';
+$lang['about_title'] = 'A propos...';
+$lang['about_message'] = '<div style="text-align:center;font-weigh:bold;">Informations sur le PhpWebGallery</div>
+<ul>
+<li>Ce site utilise la version '.PHPWG_VERSION.' de <a href="'.PHPWG_URL.'" style="text-decoration:underline">PhpWebGallery</a>. PhpWebGallery est une application web permettant de créer simplement une galerie d\'images en ligne.</li>
+<li>D\'un point de vue technique, PhpWebGallery est entièrement développé en PHP (l\'elePHPant) avec une base de données MySQL(le mySQreuiL).</li>
+<li>Si vous avez des suggestions ou des commentaires, n\'hésitez pas à visiter le site de <a href="'.PHPWG_URL.'" style="text-decoration:underline">PhpWebGallery</a> et son <a href="'.PHPWG_FORUM_URL.'" style="text-decoration:underline">forum</a>.</li>
+</ul>';
+
+// Picture
+$lang['add_favorites_alt'] = 'Ajouter aux favoris';
+$lang['add_favorites_hint'] = 'ajouter cette image à vos favoris';
+$lang['del_favorites_alt'] = 'Retirer des favoris';
+$lang['del_favorites_hint'] = 'supprimer cette image de vos favoris';
+$lang['link_info_image'] = 'Modifier les informations de cette image';
+$lang['true_size'] = 'Taille réelle';
+$lang['comments_title'] = 'Commentaires des visiteurs du site';
+$lang['comments_del'] = 'supprimer ce message';
+$lang['comments_add'] = 'Ajouter un commentaire';
+$lang['slideshow'] = 'diaporama';
+$lang['period_seconds'] = 'secondes par image';
+$lang['slideshow_stop'] = 'stopper le diaporama';
+$lang['download'] = 'Télécharger';
+$lang['download_hint'] = 'Télécharger ce fichier';
+$lang['comment_added'] = 'Votre commentaire a été enregistré';
+$lang['comment_to_validate'] = 'Un administrateur doit valider votre commentaire pour qu\'il soit visible';
+$lang['comment_anti-flood'] = 'Système anti-flood : attendez un moment avant de déposer un message';
+$lang['comment_user_exists'] = 'Ce pseudo appartient à un autre utilisateur';
+$lang['picture_show_metadata'] = 'Montrer les métadonnées';
+$lang['picture_hide_metadata'] = 'Cacher les métadonnées';
+$lang['to_rate'] = 'Note';
+$lang['update_rate'] = 'Mettre à jour votre note';
+$lang['element_rate'] = 'note';
+$lang['already_rated'] = 'Vous avez déja noté image';
+$lang['never_rated'] = 'Vous n\'avez jamais noté cette image';
+$lang['no_rate'] = 'Aucune note';
+$lang['rates'] = 'Notes';
+$lang['standard_deviation'] = 'STD';
+$lang['picture_high'] = 'Cliquez sur l\'image pour la voir en haute résolution';
+$lang['visited'] = 'visité';
+$lang['times'] = 'fois';
+
+// Upload
+$lang['upload_forbidden'] = 'On ne peut pas ajouter d\'image dans cette catégorie';
+$lang['upload_file_exists'] = 'Une image du même nom existe déjà';
+$lang['upload_filenotfound'] = 'vous devez choisir un fichier image pour la photo';
+$lang['upload_cannot_upload'] = 'impossible d\'uploader la photo sur le serveur';
+$lang['upload_title'] = 'Ajouter une image';
+$lang['upload_advise'] = 'Choisissez une image à placer dans la catégorie : ';
+$lang['upload_advise_thumbnail'] = 'Optionnel, mais recommandé : Choisissez la miniature à associer à ';
+$lang['upload_advise_filesize'] = 'le poids de l\'image ne doit pas dépasser : ';
+$lang['upload_advise_width'] = 'la largeur de l\'image ne doit pas dépasser : ';
+$lang['upload_advise_height'] = 'la hauteur de l\'image ne doit pas dépasser : ';
+$lang['upload_advise_filetype'] = 'l\'image doit être au format jpg, gif ou png';
+$lang['upload_err_username'] = 'le nom de l\'utilisateur doit être renseigné';
+$lang['upload_username'] = 'Nom d\'utilisateur';
+$lang['upload_successful'] = 'Image uploadée avec succès, un administrateur validera celle-ci dès que possible.';
+$lang['upload_name'] = 'Nom de l\'image';
+$lang['upload_author'] = 'Auteur (eg "Pierrick LE GALL")';
+$lang['upload_creation_date'] = 'Date de création (JJ/MM/AAAA)';
+
+// Admin messages
+$lang['gallery_locked_message'] = 'Cette galerie est actuellement inaccessible pour cause de maintenance.
+Revenez plus tard ou connectez vous en tant qu\'administrateur: <a href="'.PHPWG_ROOT_PATH.'identification.php">Identification</a>';
+$lang['sql_queries_in'] = 'requêtes SQL en';
+$lang['title_send_mail'] = '[phpwebgallery] une remarque sur ton site';
+$lang['generation_time'] = 'Page générée en';
+$lang['mail_hello'] = 'Bonjour,';
+$lang['mail_new_upload_subject'] = 'Nouvelle image sur le site';
+$lang['mail_new_upload_content'] = 'Une nouvelle image a été placée sur la galerie. Elle est en attente de validation. RDV dans la section d\'administration pour valider ou supprimer cette image.';
+$lang['mail_new_comment_subject'] = 'Nouveau commentaire sur le site';
+$lang['mail_new_comment_content'] = 'Un nouveau commentaire a été posté sur la galerie. Si vous avez activé la validation des commentaires, il faut d\'abord valider le commentaire dans la zone d\'administration pour le voir apparaître.'."\n\n".'Vous avez accès aux derniers commentaires dans la zone d\'administration.';
+
+
+// NOT YET VALIDATED
+
+$lang['guest'] = 'visiteur';
+$lang['add'] = 'ajouter';
+
+$lang['title_comments'] = 'Commentaires des visiteurs';
+$lang['stats_last_days'] = 'derniers jours';
+$lang['menu_login'] = 'Connexion';
+$lang['hint_comments'] = 'Voir les derniers commentaires des visiteurs';
+
+$lang['update_wrong_dirname'] = 'Le nom des fichiers et répertoires ne doivent être composé que de lettres, de chiffres et "-", "_" ou ".".';
+$lang['hello'] = 'Bonjour';
+?>
Index: /branches/1.4/language/fr_FR.iso-8859-1/faq.lang.php
===================================================================
--- /branches/1.4/language/fr_FR.iso-8859-1/faq.lang.php	(revision 3249)
+++ /branches/1.4/language/fr_FR.iso-8859-1/faq.lang.php	(revision 3249)
@@ -0,0 +1,288 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Admin FAQ
+$lang['help_images_title'] = 'Ajouts d\'éléments';
+$lang['help_images'] =
+array(
+  'Les répertoires représentant les catégories sont dans le répertoire
+"galleries". Ci-dessous l\'arbre des répertoires d\'une très petite galerie
+(mais utilisant de nombreuses fonctionnalités) : <br />
+<pre>
+.
+|-- admin
+|-- doc
+|-- galleries
+|   |-- categorie-1
+|   |   |-- categorie-1.1
+|   |   |   |-- categorie-1.1.1
+|   |   |   |   |-- categorie-1.1.1.1
+|   |   |   |   |   |-- pwg_high
+|   |   |   |   |   |   +-- mariage.jpg
+|   |   |   |   |   |-- thumbnail
+|   |   |   |   |   |   +-- TN-mariage.jpg
+|   |   |   |   |   +-- mariage.jpg
+|   |   |   |   +-- categorie-1.1.1.2
+|   |   |   +-- categorie-1.1.2
+|   |   |-- categorie-1.2
+|   |   |   |-- pookie.jpg
+|   |   |   +-- thumbnail
+|   |   |       +-- TN-pookie.jpg
+|   |   +-- categorie-1.3
+|   +-- categorie-2
+|       |-- porcinet.gif
+|       |-- pwg_representative
+|       |   +-- video.jpg
+|       |-- thumbnail
+|       |   +-- TN-porcinet.jpg
+|       +-- video.avi
+|-- include
+|-- install
+|-- language
+|-- template
++-- tool
+</pre>',
+
+  'Fondamentalement, une catégorie est représentée par un répertoire à
+n\'importe quel niveau sous le répertoire "galleries" de votre installation de
+PhpWebGallery. Chaque catégorie peut contenir autant de sous-niveaux que
+désiré. Dans l\'exemple ci-dessus, categorie-1.1.1.1 est à un niveau 4 de
+profondeur.',
+
+  'Fondamentalement, un élément est représenté par un fichier. Un fichier peut
+être un élément pour PhpWebGallery si l\'extension du nom du fichier est parmi
+la liste $conf[\'file_ext\'] (voir fichier include/config.inc.php). Un fichier
+peut être une image si son extension est parmi $conf[\'picture_ext\'] (voir
+fichier include/config.inc.php).',
+
+  'Les éléments de type image doivent avoir une miniature associée (voir la
+section suivante à propos des miniatures).',
+
+  'Les éléments de type image peuvent avoir un image en grand format associé.
+Comme pour le fichier mariage.jpg dans l\'exemple ci-dessus. Aucun préfix
+n\'est nécessaire sur le nom du fichier.',
+
+  'Les éléments non image (vidéos, sons, fichiers texte, tout ce que vous
+voulez...) sont par défaut représentés par un icône correspondant à
+l\'extension du nom du fichier. Optionnellement, une miniature et un
+représentant peuvent être associés (voir le fichier video.avi dans
+l\'exemple)',
+
+  'Attention : le nom d\'un répertoire ou d\'un fichier ne doit être composé
+que de lettres, de chiffres, de "-", "_" ou ".". Pas d\'espace ou de
+caractères accentués.',
+
+  'Conseil : une catégorie peut contenir des éléments et des sous-catégories à
+la fois. Néanmoins, il est fortement conseillé pour chaque catégorie de choisir
+entre contenir des éléments OU BIEN des sous-catégories.',
+  );
+
+$lang['help_thumbnails_title'] = 'Miniatures';
+$lang['help_thumbnails'] =
+array(
+  'Comme mentionné précédemment, chaque élément de type image doit être
+associé à une miniature.',
+
+  'Les miniatures sont stockées dans le sous-répertoire "thumbnail" de chaque
+répertoire représentant une catégorie. Une miniature est un fichier de type
+image (même extension du nom du fichier) dont le nom de fichier est préfixé par
+le paramètre "Préfixe miniature" (voir zone administration, Configuration,
+Général)',
+
+  'Les miniatures n\'ont pas besoin d\'avoir la même extension que leur image
+associée (une image avec ".jpg" comme extension peut avoir une miniature en
+".GIF" par exemple).',
+
+  'Il est conseillé d\'utiliser un outil externe pour la création des
+miniatures (comme ThumbClic ou PhpMyVignettes, voir le site de présentation
+de PhpWebGallery).',
+
+  'Vous pouvez également utiliser l\'outil de création de miniature intégré à
+PhpWebGallery mais cela est déconseillé car la qualité risque d\'être décevante
+et cela utilise inutilement les ressources du serveur (ce qui peut être un
+grave problème sur un serveur mutualisé).',
+
+  'Si vous choisissez d\'utiliser le serveur web pour générer les miniatures,
+vous devez donner les droits en écriture sur tous les répertoires représentant
+les catégories pour tous les utilisateurs (propriétaire, groupe, autre)'
+  );
+
+$lang['help_database_title'] =
+'Synchroniser le système de fichiers et la base';
+$lang['help_database'] =
+array(
+  'Une fois que les fichiers, miniatures, représentants ont été correctement
+placés dans les répertoires, se rendre sur : zone administration, Général,
+Synchroniser',
+
+  'Il existe 2 types de synchronisations : structure et meta-données.
+Synchroniser la structure revient à synchroniser votre arbre des répertoires
+et fichiers avec la représentation de la structure dans la base de données.
+Synchroniser les méta-données permet de mettre à jour les informations comme
+le poids du fichier, les dimensions, les données EXIF ou IPTC.',
+
+  'La première synchronisation à effectuer doit être celle sur la structure.',
+
+  'Le processus de synchronisation peut prendre du temps (en fonction de la
+charge du serveur et de la quantité de fichiers à gérer), il est donc
+possible d\'avancer pas à pas : catégorie par catégorie.'
+  
+  );
+
+$lang['help_access_title'] = 'Autorisations';
+$lang['help_access'] =
+array(
+  'Vous pouvez interdire l\'accès aux catégories. Les catégories peuvent être
+publiques ou privées. Les autorisations (valables pour les groupes et les
+utilisateurs) sont gérables uniquement pour les catégories privées.',
+  
+  'Vous pouvez rendre une catégorie privée en l\'éditant (zone administration,
+Catégories, Gestion, Editer) ou en gérant les options pour votre arbre complet
+des catégories (zone administration, Catégories, Sécurité)',
+
+  'Une fois que certaines catégories sont privées, vous pouvez gérer les
+autorisations pour les groupes et les utilisateurs (zone administration,
+Autorisations).'
+  );
+
+$lang['help_groups_title'] = 'Groupes d\'utilisateurs';
+$lang['help_groups'] =
+array(
+
+  'PhpWebGallery peut gérer des groupes d\'utilisateurs. Très pratique pour
+gérer des autorisations communes sur les catégories privées.',
+
+  'Vous pouvez créer des groupes et y ajouter des utilisateurs dans la zone
+administration, Identification, Groupes',
+
+  'Un utilisateur peut appartenir à plusieurs groupes. L\'autorisation est
+plus forte que l\'interdiction : si l\'utilisateur "pierre" appartient aux
+groupes "famille" et "amis", et que seul le groupe "famille" peut visiter la
+catégorie "Noël 2003", alors "pierre" peut visiter cette catégorie.'
+  
+  );
+
+$lang['help_remote_title'] = 'Sites distant';
+$lang['help_remote'] =
+array(
+
+  'PhpWebGallery offre la possibilité d\'utiliser plusieurs sites pour
+stocker les fichiers qui composeront votre galerie. Cela peut être utile si
+votre galerie est installée sur un espace de stockage limité et que vous avez
+de nombreux fichiers à montrer.',
+
+  '1. éditer le fichier tools/create_listing_file.php en modifiant la section
+des paramètres comme $conf[\'prefix_thumbnail\'] ou $conf[\'use_exif\'].',
+
+  '2. placer le fichier "tools/create_listing_file.php" modifié sur votre
+site distant, dans le même répertoire que les répertoires représentant vos
+catégories (comme le répertoire "galleries" de ce site) par FTP. Par exemple,
+disons que vous pouvez accéder à
+http://exemple.com/galleries/create_listing_file.php.',
+
+  '3. zone administration, Général, Sites distant. Demander à créer un nouveau
+site, par exemple http://exemple.com/galleries',
+
+  '4. un nouveau site distant est enregistré. 4 actions possibles :
+
+<ol>
+
+  <li>générer la liste : lance une requête distant pour générer le fichier
+  de listing distant</li>
+
+  <li>mettre à jour : lit le fichier distant listing.xml et synchronise avec
+  la base de données locale</li>
+
+  <li>nettoyer : supprime le fichier distant de listing</li>
+
+  <li>détruire : supprime le site (et tous les éléments qui y sont associés)
+  dans la base de données</li>
+
+</ol>',
+
+  'Vous pouvez également effectuer ces opérations manuellement en éditant le
+fichier listing.xml à la main et en le déplaçant vers votre répertoire
+racine. Se rendre sur zone administration, Général, Sites distant :
+PhpWebGallery détecte le fichier et propose de s\'en servir.'
+  
+  );
+
+$lang['help_upload_title'] = 'Ajout de fichiers par les utilisateurs';
+$lang['help_upload'] =
+array(
+  'Pour permettre aux utilisateurs d\'ajouter des fichiers :',
+
+  '1. autoriser l\'ajout d\'images sur n\'importe quelle catégorie (zone
+administation, Catégories, Gestion, Edit ou zone administration, Catégories,
+Ajout d\'images)',
+
+  '2. donner les droits en écriture (pour tous les utilisateurs) sur les
+répertoires correspondant aux catégories qui sont autorisées à l\'ajout',
+
+  'Les fichiers ajoutés par les utilisateurs ne sont pas directement visibles
+sur le site, ils doivent être validés par un administrateur. Pour cela, un
+administrateur doit se rendre dans zone administration, Images, En attente
+afin de valider ou rejeter les fichiers proposés. Il est ensuite nécessaire
+de synchroniser le système de fichier avec la base de données.'
+  );
+
+$lang['help_virtual_title'] = 'Liens entre les éléments et les catégories, catégories virtuelles';
+$lang['help_virtual'] =
+array(
+  'PhpWebGallery dissocie les catégories qui stockent les éléments et les
+catégories où les éléments sont montrés.',
+
+  'Par défaut, les élement ne sont montrés que dans leurs catégories réelles :
+celles qui correspondent à leurs répertoires sur le serveur.',
+
+  'Pour lier un élément à une catégorie, il suffit de faire une association sur
+la page d\'édition de l\'élément (un lien existe vers cette page lorsque
+vous êtes connecté en tant qu\'administrateur) ou sur la page regroupant les
+informations sur tous les éléments d\'une catégorie.',
+
+  'En partant de ce principe, il est possible de créer des catégories
+virtuelles : aucun répertoire ne correspond à ces catégories. Vous pouvez
+créer des catégories virtuelle sur zone administration, Catégorie, Gestion.'
+  );
+
+$lang['help_infos_title'] = 'Informations diverses';
+$lang['help_infos'] =
+array(
+  'Dès que vous aurez créer votre galerie, configurez l\'affichage par défaut
+tel que désiré dans zone administation, Configuration, Affichage par
+défaut. En effet, chaque nouvel utilisateur héritera de ces propriétés
+d\'affichage.',
+
+  'Pour tout question, n\'hésitez pas à visiter le forum ou à y poser une
+question si votre recherche est infructueuse. Le <a
+href="http://forum.phpwebgallery.net"
+style="text-decoration:underline">forum</a> est disponible sur le site de
+PhpWebGallery. Consulter également la <a href="http://doc.phpwebgallery.net"
+style="text-decoration:underline">documentation officielle de
+PhpWebGallery</a> pour obtenir plus de détails.'
+  );
+?>
Index: /branches/1.4/language/fr_FR.iso-8859-1/install.lang.php
===================================================================
--- /branches/1.4/language/fr_FR.iso-8859-1/install.lang.php	(revision 3249)
+++ /branches/1.4/language/fr_FR.iso-8859-1/install.lang.php	(revision 3249)
@@ -0,0 +1,70 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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['install_message'] = 'Message';
+$lang['Initial_config'] = 'Configuration de Base';
+$lang['Default_lang'] = 'Langue par défaut de la galerie';
+$lang['step1_title'] = 'Configuration de la Base de données';
+$lang['step2_title'] = 'Configuration du compte Administrateur';
+$lang['Start_Install'] = 'Démarrer l\'installation';
+$lang['reg_err_mail_address'] = 'L\'adresse mail doit être de la forme xxx@yyy.eee (exemple : jack@altern.org)';
+
+$lang['install_webmaster'] = 'Administrateur';
+$lang['install_webmaster_info'] = 'Cet identifiant apparaîtra à tous vos visiteurs. Il vous sert pour administrer le site';
+
+$lang['step1_confirmation'] = 'Les paramètres rentrés sont corrects';
+$lang['step1_err_db'] = 'La connexion au serveur est OK, mais impossible de se connecter à cette base de données';
+$lang['step1_err_server'] = 'Impossible de se connecter au serveur';
+
+$lang['step1_host'] = 'Hôte MySQL';
+$lang['step1_host_info'] = 'localhost, sql.multimania.com, toto.freesurf.fr';
+$lang['step1_user'] = 'Utilisateur';
+$lang['step1_user_info'] = 'nom d\'utilisateur pour votre hébergeur';
+$lang['step1_pass'] = 'Mot de passe';
+$lang['step1_pass_info'] = 'celui fourni par votre hébergeur';
+$lang['step1_database'] = 'Nom de la base';
+$lang['step1_database_info'] = 'celui fourni par votre hébergeur';
+$lang['step1_prefix'] = 'Préfixe des noms de table';
+$lang['step1_prefix_info'] = 'le nom des tables apparaîtra avec ce préfixe (permet de mieux gérer sa base de données)';
+$lang['step2_err_login1'] = 'veuillez rentrer un pseudo pour le webmaster';
+$lang['step2_err_login3'] = 'le pseudo du webmaster ne doit pas comporter les caractère " et \'';
+$lang['step2_err_pass'] = 'veuillez retaper votre mot de passe';
+$lang['install_end_title'] = 'Installation terminée';
+$lang['step2_pwd'] = 'Mot de passe';
+$lang['step2_pwd_info'] = 'Il doit rester confidentiel, il permet d\'accéder au panneau d\'administration.';
+$lang['step2_pwd_conf'] = 'Mot de passe [ Confirmer ]';
+$lang['step2_pwd_conf_info'] = 'Vérification';
+$lang['step1_err_copy'] = 'Copiez le texte en bleu entre les tirets et collez-le dans le fichier mysql.inc.php qui se trouve dans le répertoire "include" à la base de l\'endroit où vous avez installé PhpWebGallery (le fichier mysql.inc.php ne doit comporter QUE ce qui est en bleu entre les tirets, aucun retour à la ligne ou espace n\'est autorisé)';
+$lang['install_help'] = 'Besoin d\'aide ? Posez votre question sur le <a href="http://forum.phpwebgallery.net">forum de PhpWebGallery</a>.';
+$lang['install_end_message'] = 'La configuration de l\'application s\'est correctement déroulée, place à la prochaine étape<br /><br />
+Par mesure de sécurité, merci de supprimer le fichier "install.php"<br />
+Un fois ce fichier supprimé, veuillez suivre ces indications :
+<ul>
+<li>allez sur la page d\'identification : [ <a href="./identification.php">identification</a> ] et connectez-vous avec le pseudo donné pour le webmaster</li>
+<li>celui-ci vous permet d\'accéder à la partie administration et aux instructions pour placer les images dans les répertoires.</li>
+</ul>';
+?>
Index: /branches/1.4/language/fr_FR.iso-8859-1/iso.txt
===================================================================
--- /branches/1.4/language/fr_FR.iso-8859-1/iso.txt	(revision 3249)
+++ /branches/1.4/language/fr_FR.iso-8859-1/iso.txt	(revision 3249)
@@ -0,0 +1,1 @@
+Français [FR]
Index: /branches/1.4/language/index.htm
===================================================================
--- /branches/1.4/language/index.htm	(revision 3249)
+++ /branches/1.4/language/index.htm	(revision 3249)
@@ -0,0 +1,8 @@
+<html>
+    <head>
+        <title>PhpWebGallery</title>
+    </head>
+    <body>
+        No access authorized
+    </body>
+</html>
Index: /branches/1.4/picture.php
===================================================================
--- /branches/1.4/picture.php	(revision 3249)
+++ /branches/1.4/picture.php	(revision 3249)
@@ -0,0 +1,1048 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+$rate_items = array(0,1,2,3,4,5);
+//--------------------------------------------------------------------- include
+define('PHPWG_ROOT_PATH','./');
+include_once(PHPWG_ROOT_PATH.'include/common.inc.php');
+//-------------------------------------------------- access authorization check
+check_cat_id( $_GET['cat'] );
+
+if (!isset($page['cat']))
+{
+  die($lang['access_forbiden']);
+}
+
+check_login_authorization();
+if ( isset( $page['cat'] ) and is_numeric( $page['cat'] ) )
+{
+  check_restrictions( $page['cat'] );
+}
+//---------------------------------------- incrementation of the number of hits
+$query = '
+UPDATE '.IMAGES_TABLE.'
+  SET hit = hit+1
+  WHERE id = '.$_GET['image_id'].'
+;';
+@pwg_query( $query );
+//-------------------------------------------------------------- initialization
+initialize_category( 'picture' );
+// retrieving the number of the picture in its category (in order)
+$query = '
+SELECT DISTINCT(id)
+  FROM '.IMAGES_TABLE.'
+    INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id
+  '.$page['where'].'
+  '.$conf['order_by'].'
+;';
+$result = pwg_query( $query );
+$page['num'] = 0;
+$belongs = false;
+while ($row = mysql_fetch_array($result))
+{
+  if ($row['id'] == $_GET['image_id'])
+  {
+    $belongs = true;
+    break;
+  }
+  $page['num']++;
+}
+// if this image_id doesn't correspond to this category, an error message is
+// displayed, and execution is stopped
+if (!$belongs)
+{
+  echo '<div style="text-align:center;">'.$lang['access_forbiden'].'<br />';
+  echo '<a href="'.add_session_id( PHPWG_ROOT_PATH.'category.php' ).'">';
+  echo $lang['thumbnails'].'</a></div>';
+  exit();
+}
+//---------------------------------------------------------- related categories
+$query = '
+SELECT category_id,uppercats,commentable,global_rank
+  FROM '.IMAGE_CATEGORY_TABLE.'
+    INNER JOIN '.CATEGORIES_TABLE.' ON category_id = id
+  WHERE image_id = '.$_GET['image_id'];
+if ($user['forbidden_categories'] != '')
+{
+  $query.= '
+    AND category_id NOT IN ('.$user['forbidden_categories'].')';
+}
+$query.= '
+;';
+$result = pwg_query($query);
+$related_categories = array();
+while ($row = mysql_fetch_array($result))
+{
+  array_push($related_categories, $row);
+}
+usort($related_categories, 'global_rank_compare');
+//------------------------------------- prev, current & next picture management
+$picture = array();
+
+if ($page['num'] == 0)
+{
+  $has_prev = false;
+}
+else
+{
+  $has_prev = true;
+}
+
+if ($page['num'] == $page['cat_nb_images'] - 1)
+{
+  $has_next = false;
+}
+else
+{
+  $has_next = true;
+}
+
+$query = '
+SELECT DISTINCT(i.id), i.*
+  FROM '.IMAGES_TABLE.' AS i
+    INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON i.id = ic.image_id
+  '.$page['where'].'
+  '.$conf['order_by'].'
+  ';
+
+if ( !$has_prev )
+{
+  $query.= ' LIMIT 0,2';
+}
+else
+{
+  $query.= ' LIMIT '.($page['num'] - 1).',3';
+}
+$query.= ';';
+
+$result = pwg_query( $query );
+$indexes = array('prev', 'current', 'next');
+
+foreach (array('prev', 'current', 'next') as $i)
+{
+  if ($i == 'prev' and !$has_prev)
+  {
+    continue;
+  }
+  if ($i == 'next' and !$has_next)
+  {
+    break;
+  }
+
+  $row = mysql_fetch_array($result);
+  foreach (array_keys($row) as $key)
+  {
+    if (!is_numeric($key))
+    {
+      $picture[$i][$key] = $row[$key];
+    }
+  }
+
+  $picture[$i]['is_picture'] = false;
+  if (in_array(get_extension($row['file']), $conf['picture_ext']))
+  {
+    $picture[$i]['is_picture'] = true;
+  }
+  
+  $cat_directory = dirname($row['path']);
+  $file_wo_ext = get_filename_wo_extension($row['file']);
+
+  $icon = PHPWG_ROOT_PATH.'template/'.$user['template'].'/mimetypes/';
+  $icon.= strtolower(get_extension($row['file'])).'.png';
+
+  if (isset($row['representative_ext']) and $row['representative_ext'] != '')
+  {
+    $picture[$i]['src'] = $cat_directory.'/pwg_representative/';
+    $picture[$i]['src'].= $file_wo_ext.'.'.$row['representative_ext'];
+  }
+  else
+  {
+    $picture[$i]['src'] = $icon;
+  }
+  // special case for picture files
+  if ($picture[$i]['is_picture'])
+  {
+    $picture[$i]['src'] = $row['path'];
+    // if we are working on the "current" element, we search if there is a
+    // high quality picture
+    // FIXME : with remote pictures, this "remote fopen" takes long...
+    if ($i == 'current')
+    {
+      if (@fopen($cat_directory.'/pwg_high/'.$row['file'], 'r'))
+      {
+        $picture[$i]['high'] = $cat_directory.'/pwg_high/'.$row['file'];
+      }
+    }
+  }
+
+  // if picture is not a file, we need the download link
+  if (!$picture[$i]['is_picture'])
+  {
+    $picture[$i]['download'] = $row['path'];
+  }
+
+  $picture[$i]['thumbnail'] = get_thumbnail_src($row['path'], @$row['tn_ext']);
+  
+  if ( !empty( $row['name'] ) )
+  {
+    $picture[$i]['name'] = $row['name'];
+  }
+  else
+  {
+    $picture[$i]['name'] = str_replace('_', ' ', $file_wo_ext);
+  }
+
+  $picture[$i]['url'] = PHPWG_ROOT_PATH.'picture.php';
+  $picture[$i]['url'].= get_query_string_diff(array('image_id','add_fav',
+                                                    'slideshow','rate'));
+  $picture[$i]['url'].= '&amp;image_id='.$row['id'];
+}
+
+$url_up = PHPWG_ROOT_PATH.'category.php?cat='.$page['cat'].'&amp;';
+$url_up.= 'num='.$page['num']; 
+if ( $page['cat'] == 'search' )
+{
+  $url_up.= "&amp;search=".$_GET['search'];
+}
+if ( $page['cat'] == 'list' )
+{
+  $url_up.= "&amp;list=".$_GET['list'];
+}
+
+$url_admin = PHPWG_ROOT_PATH.'admin.php?page=picture_modify';
+$url_admin.= '&amp;cat_id='.$page['cat'];
+$url_admin.= '&amp;image_id='.$_GET['image_id'];
+
+$url_slide = $picture['current']['url'];
+$url_slide.= '&amp;slideshow='.$conf['slideshow_period'];
+//----------------------------------------------------------- rate registration
+if (isset($_GET['rate'])
+    and $conf['rate']
+    and !$user['is_the_guest']
+    and in_array($_GET['rate'], $rate_items))
+{
+  $query = '
+DELETE
+  FROM '.RATE_TABLE.'
+  WHERE user_id = '.$user['id'].'
+    AND element_id = '.$_GET['image_id'].'
+;';
+  pwg_query($query);
+  $query = '
+INSERT INTO '.RATE_TABLE.'
+  (user_id,element_id,rate)
+  VALUES
+  ('.$user['id'].','.$_GET['image_id'].','.$_GET['rate'].')
+;';
+  pwg_query($query);
+
+  // update of images.average_rate field
+  $query = '
+SELECT ROUND(AVG(rate),2) AS average_rate
+  FROM '.RATE_TABLE.'
+  WHERE element_id = '.$_GET['image_id'].'
+;';
+  $row = mysql_fetch_array(pwg_query($query));
+  $query = '
+UPDATE '.IMAGES_TABLE.'
+  SET average_rate = '.$row['average_rate'].'
+  WHERE id = '.$_GET['image_id'].'
+;';
+  pwg_query($query);
+}
+//--------------------------------------------------------- favorite management
+if ( isset( $_GET['add_fav'] ) )
+{
+  $query = 'DELETE FROM '.FAVORITES_TABLE;
+  $query.= ' WHERE user_id = '.$user['id'];
+  $query.= ' AND image_id = '.$picture['current']['id'];
+  $query.= ';';
+  $result = pwg_query( $query );
+  
+  if ( $_GET['add_fav'] == 1 )
+  {
+    $query = 'INSERT INTO '.FAVORITES_TABLE;
+    $query.= ' (image_id,user_id) VALUES';
+    $query.= ' ('.$picture['current']['id'].','.$user['id'].')';
+    $query.= ';';
+    $result = pwg_query( $query );
+  }
+  if ( !$_GET['add_fav'] and $page['cat'] == 'fav' )
+  {
+    if (!$has_prev and !$has_next)
+    {
+      // there is no favorite picture anymore we redirect the user to the
+      // category page
+      $url = add_session_id($url_up);
+      redirect($url);
+    }
+    else if (!$has_prev)
+    {
+      $url = str_replace( '&amp;', '&', $picture['next']['url'] );
+      $url = add_session_id( $url, true);
+    }
+    else
+    {
+      $url = str_replace('&amp;', '&', $picture['prev']['url'] );
+      $url = add_session_id( $url, true);
+    }
+    redirect( $url );
+  }
+}
+
+//------------------------------------------------------  comment registeration
+if ( isset( $_POST['content'] ) && !empty($_POST['content']) )
+{
+  $register_comment = true;
+  $author = !empty($_POST['author'])?$_POST['author']:$lang['guest'];
+  // if a guest try to use the name of an already existing user, he must be
+  // rejected
+  if ( $author != $user['username'] )
+  {
+    $query = 'SELECT COUNT(*) AS user_exists';
+    $query.= ' FROM '.USERS_TABLE;
+    $query.= " WHERE username = '".$author."'";
+    $query.= ';';
+    $row = mysql_fetch_array( pwg_query( $query ) );
+    if ( $row['user_exists'] == 1 )
+    {
+      $template->assign_block_vars(
+        'information',
+        array('INFORMATION'=>$lang['comment_user_exists']));
+      $register_comment = false;
+    }
+  }
+  
+  if ( $register_comment )
+  {
+    // anti-flood system
+    $reference_date = time() - $conf['anti-flood_time'];
+    $query = 'SELECT id FROM '.COMMENTS_TABLE;
+    $query.= ' WHERE date > FROM_UNIXTIME('.$reference_date.')';
+    $query.= " AND author = '".$author."'";
+    $query.= ';';
+    if ( mysql_num_rows( pwg_query( $query ) ) == 0
+         or $conf['anti-flood_time'] == 0 )
+    {
+      $query = 'INSERT INTO '.COMMENTS_TABLE;
+      $query.= ' (author,date,image_id,content,validated) VALUES (';
+      $query.= "'".$author."'";
+      $query.= ',NOW(),'.$_GET['image_id'];
+      $query.= ",'".htmlspecialchars( $_POST['content'], ENT_QUOTES)."'";
+      if ( !$conf['comments_validation'] or $user['status'] == 'admin' )
+      {        
+        $query.= ",'true'";
+      }
+      else
+      {
+        $query.= ",'false'";
+      }
+      $query.= ');';
+      pwg_query( $query );
+      // information message
+      $message = $lang['comment_added'];
+      if ( $conf['comments_validation'] and $user['status'] != 'admin' )
+      {
+        $message.= '<br />'.$lang['comment_to_validate'];
+      }
+      $template->assign_block_vars('information',
+                                   array('INFORMATION'=>$message));
+      // notification to the administrators
+      if ( $conf['mail_notification'] )
+      {
+        // find any related category (can be unreachable to this admin)
+        $category = $related_categories[0];
+        // locally, we change the $conf['level_separator']
+        $conf_separator = $conf['level_separator'];
+        $conf['level_separator'] = ' > ';
+        $cat_name = get_cat_display_name_cache($category['uppercats'],
+                                               '',
+                                               false);
+        $conf['level_separator'] = $conf_separator;
+        
+        $cat_name = strip_tags( $cat_name );
+        notify( 'comment', $cat_name.' > '.$picture['current']['name']);
+      }
+    }
+    else
+    {
+      // information message
+      $template->assign_block_vars(
+        'information',
+        array('INFORMATION'=>$lang['comment_anti-flood']));
+    }
+  }
+}
+// comment deletion
+if ( isset( $_GET['del'] )
+     and is_numeric( $_GET['del'] )
+     and $user['status'] == 'admin' )
+{
+  $query = 'DELETE FROM '.COMMENTS_TABLE;
+  $query.= ' WHERE id = '.$_GET['del'];
+  $query.= ';';
+  pwg_query( $query );
+}
+
+//
+// Start output of page
+//
+
+$title =  $picture['current']['name'];
+$refresh = 0;
+if ( isset( $_GET['slideshow'] ) and $has_next )
+{
+  $refresh= $_GET['slideshow'];
+  $url_link = $picture['next']['url'].'&amp;slideshow='.$refresh;
+}
+
+$title_img = $picture['current']['name'];
+$title_nb = '';
+if (is_numeric( $page['cat'] )) 
+{
+  $title_img = replace_space(get_cat_display_name($page['cat_name']));
+  $n = $page['num'] + 1;
+  $title_nb = $n.'/'.$page['cat_nb_images'];
+}
+else if ( $page['cat'] == 'search' )
+{
+  $title_img = replace_search( $title_img, $_GET['search'] );
+}
+
+// calculation of width and height
+if (empty($picture['current']['width']))
+{
+  $taille_image = @getimagesize($picture['current']['src']);
+  $original_width = $taille_image[0];
+  $original_height = $taille_image[1];
+}
+else
+{
+  $original_width = $picture['current']['width'];
+  $original_height = $picture['current']['height'];
+}
+
+$picture_size = get_picture_size($original_width, $original_height,
+                                 @$user['maxwidth'], @$user['maxheight']);
+
+// metadata
+if ($conf['show_exif'] or $conf['show_iptc'])
+{
+  $metadata_showable = true;
+}
+else
+{
+  $metadata_showable = false;
+}
+
+$url_metadata = PHPWG_ROOT_PATH.'picture.php';
+$url_metadata .=  get_query_string_diff(array('add_fav', 'slideshow', 'show_metadata'));
+if ($metadata_showable and !isset($_GET['show_metadata']))
+{
+  $url_metadata.= '&amp;show_metadata=1';
+}
+				  
+include(PHPWG_ROOT_PATH.'include/page_header.php');
+$template->set_filenames(array('picture'=>'picture.tpl'));
+
+$template->assign_vars(array(
+  'CATEGORY' => $title_img,
+  'PHOTO' => $title_nb,
+  'TITLE' => $picture['current']['name'],
+  'SRC_IMG' => $picture['current']['src'],
+  'ALT_IMG' => $picture['current']['file'],
+  'WIDTH_IMG' => $picture_size[0],
+  'HEIGHT_IMG' => $picture_size[1],
+
+  'LEVEL_SEPARATOR' => $conf['level_separator'],
+
+  'L_HOME' => $lang['home'],
+  'L_SLIDESHOW' => $lang['slideshow'],
+  'L_STOP_SLIDESHOW' => $lang['slideshow_stop'],
+  'L_PREV_IMG' =>$lang['previous_page'].' : ',
+  'L_NEXT_IMG' =>$lang['next_page'].' : ',
+  'L_ADMIN' =>$lang['link_info_image'],
+  'L_COMMENT_TITLE' =>$lang['comments_title'],
+  'L_ADD_COMMENT' =>$lang['comments_add'],
+  'L_DELETE_COMMENT' =>$lang['comments_del'],
+  'L_DELETE' =>$lang['delete'],
+  'L_SUBMIT' =>$lang['submit'],
+  'L_AUTHOR' =>$lang['author'],
+  'L_COMMENT' =>$lang['comment'],
+  'L_DOWNLOAD' => $lang['download'],
+  'L_DOWNLOAD_HINT' => $lang['download_hint'],
+  'L_PICTURE_METADATA' => $lang['picture_show_metadata'],
+  'L_PICTURE_HIGH' => $lang['picture_high'],
+  'L_UP_HINT' => $lang['home_hint'],
+  'L_UP_ALT' => $lang['home'],
+  
+  'U_HOME' => add_session_id(PHPWG_ROOT_PATH.'category.php'),
+  'U_UP' => add_session_id($url_up),
+  'U_METADATA' => add_session_id($url_metadata),
+  'U_ADMIN' => add_session_id($url_admin),
+  'U_SLIDESHOW'=> add_session_id($url_slide),
+  'U_ADD_COMMENT' => add_session_id(str_replace( '&', '&amp;', $_SERVER['REQUEST_URI'] ))
+  )
+);
+//------------------------------------------------------- upper menu management
+// download link if file is not a picture
+if (!$picture['current']['is_picture'])
+{
+  $template->assign_block_vars(
+    'download',
+    array('U_DOWNLOAD' => $picture['current']['download']));
+}
+else
+{
+  $template->assign_block_vars(
+    'ecard',
+    array('U_ECARD' => $picture['current']['url']));
+}
+// display a high quality link if present
+if (isset($picture['current']['high']))
+{
+  $full_size = @getimagesize($picture['current']['high']);
+  $full_width = $full_size[0];
+  $full_height = $full_size[1];
+  $uuid = uniqid(rand());
+  $template->assign_block_vars('high', array(
+    'U_HIGH' => $picture['current']['high'],
+	'UUID'=>$uuid,
+	'WIDTH_IMG'=>($full_width + 16),
+	'HEIGHT_IMG'=>($full_height + 16)
+	));
+}
+//------------------------------------------------------- favorite manipulation
+if ( !$user['is_the_guest'] )
+{
+  // verify if the picture is already in the favorite of the user
+  $query = 'SELECT COUNT(*) AS nb_fav';
+  $query.= ' FROM '.FAVORITES_TABLE.' WHERE image_id = '.$_GET['image_id'];
+  $query.= ' AND user_id = '.$user['id'].';';
+  $result = pwg_query( $query );
+  $row = mysql_fetch_array( $result );
+  if (!$row['nb_fav'])
+  {
+    $url = PHPWG_ROOT_PATH.'picture.php';
+    $url.= get_query_string_diff(array('rate','add_fav'));
+    $url.= '&amp;add_fav=1';
+
+    $template->assign_block_vars(
+      'favorite',
+      array(
+        'FAVORITE_IMG' => PHPWG_ROOT_PATH.'template/'.$user['template'].'/theme/favorite.gif',
+        'FAVORITE_HINT' =>$lang['add_favorites_hint'],
+        'FAVORITE_ALT' =>$lang['add_favorites_alt'],
+        'U_FAVORITE' => $url
+        ));
+  }
+  else
+  {
+    $url = PHPWG_ROOT_PATH.'picture.php';
+    $url.= get_query_string_diff(array('rate','add_fav'));
+    $url.= '&amp;add_fav=0';
+    
+    $template->assign_block_vars(
+      'favorite',
+      array(
+        'FAVORITE_IMG' => PHPWG_ROOT_PATH.'template/'.$user['template'].'/theme/del_favorite.gif',
+        'FAVORITE_HINT' =>$lang['del_favorites_hint'],
+        'FAVORITE_ALT' =>$lang['del_favorites_alt'],
+        'U_FAVORITE'=> $url
+        ));
+  }
+}
+//------------------------------------ admin link for information modifications
+if ( $user['status'] == 'admin' )
+{
+  $template->assign_block_vars('admin', array());
+}
+
+//-------------------------------------------------------- navigation management
+if ($has_prev)
+{
+  $template->assign_block_vars(
+    'previous',
+    array(
+      'TITLE_IMG' => $picture['prev']['name'],
+      'IMG' => $picture['prev']['thumbnail'],
+      'U_IMG' => add_session_id($picture['prev']['url'])
+      ));
+}
+
+if ($has_next)
+{
+  $template->assign_block_vars(
+    'next',
+    array(
+      'TITLE_IMG' => $picture['next']['name'],
+      'IMG' => $picture['next']['thumbnail'],
+      'U_IMG' => add_session_id($picture['next']['url'])
+      ));
+}
+
+//--------------------------------------------------------- picture information
+// legend
+if (isset($picture['current']['comment'])
+    and !empty($picture['current']['comment']))
+{
+  $template->assign_block_vars(
+    'legend',
+    array(
+      'COMMENT_IMG' => nl2br($picture['current']['comment'])
+      ));
+}
+
+// author
+if ( !empty($picture['current']['author']) )
+{
+  $search_url = PHPWG_ROOT_PATH.'category.php?cat=search';
+  $search_url.= '&amp;search=author:'.$picture['current']['author'];
+  
+  $value = '<a href="';
+  $value.= add_session_id($search_url);
+  $value.= '">'.$picture['current']['author'].'</a>';
+  
+  $template->assign_block_vars(
+    'info_line',
+    array(
+      'INFO'=>$lang['author'],
+      'VALUE'=>$value
+      ));
+}
+// creation date
+if ( !empty($picture['current']['date_creation']) )
+{
+  $search_url = PHPWG_ROOT_PATH.'category.php?cat=search';
+  $search_url.= '&amp;search=';
+  $search_url.= 'date_creation:'.$picture['current']['date_creation'];
+  
+  $value = '<a href="';
+  $value.= add_session_id($search_url);
+  $value.= '">'.format_date($picture['current']['date_creation']).'</a>';
+  
+  $template->assign_block_vars(
+    'info_line',
+    array(
+      'INFO'=>$lang['creation_date'],
+      'VALUE'=>$value
+      ));
+}
+// date of availability
+$search_url = PHPWG_ROOT_PATH.'category.php?cat=search';
+$search_url.= '&amp;search=';
+$search_url.= 'date_available:'.$picture['current']['date_available'];
+  
+$value = '<a href="';
+$value.= add_session_id($search_url);
+$value.= '">'.format_date($picture['current']['date_available']).'</a>';
+
+$template->assign_block_vars(
+  'info_line',
+  array(
+    'INFO'=>$lang['registration_date'],
+    'VALUE'=>$value
+    ));
+// size in pixels
+if ($picture['current']['is_picture'])
+{
+  if ($original_width != $picture_size[0]
+      or $original_height != $picture_size[1])
+  {
+    $content = '[ <a href="'.$picture['current']['src'].'" ';
+    $content.= ' title="'.$lang['true_size'].'">';
+    $content.= $original_width.'*'.$original_height.'</a> ]';
+  }
+  else
+  {
+    $content = $original_width.'*'.$original_height;
+  }
+  $template->assign_block_vars(
+    'info_line',
+    array(
+      'INFO'=>$lang['size'],
+      'VALUE'=>$content 
+      ));
+}
+// file
+$template->assign_block_vars('info_line', array(
+	  'INFO'=>$lang['file'],
+	  'VALUE'=>$picture['current']['file'] 
+	  ));
+// filesize
+if (empty($picture['current']['filesize']))
+{
+  if (!$picture['current']['is_picture'])
+  {
+    $filesize = floor(filesize($picture['current']['download'])/1024);
+  }
+  else
+  {
+    $filesize = floor(filesize($picture['current']['src'])/1024);
+  }
+}
+else
+{
+  $filesize = $picture['current']['filesize'];
+}
+
+$template->assign_block_vars('info_line', array(
+	  'INFO'=>$lang['filesize'],
+	  'VALUE'=>$filesize.' KB'
+	  ));
+// keywords
+if (!empty($picture['current']['keywords']))
+{
+  $keywords = explode(',', $picture['current']['keywords']);
+  $content = '';
+  $url = PHPWG_ROOT_PATH.'category.php?cat=search&amp;search=keywords:';
+  foreach ($keywords as $i => $keyword)
+  {
+    $local_url = add_session_id($url.$keyword);
+    if ($i > 0)
+    {
+      $content.= ',';
+    }
+    $content.= '<a href="'.$local_url.'">'.$keyword.'</a>';
+  }
+  $template->assign_block_vars(
+    'info_line',
+    array(
+      'INFO'=>$lang['keywords'],
+      'VALUE'=>$content
+      ));
+}
+// number of visits
+$template->assign_block_vars(
+  'info_line',
+  array(
+    'INFO'=>$lang['visited'],
+    'VALUE'=>$picture['current']['hit'].' '.$lang['times']
+    ));
+// rate results
+if ($conf['rate'])
+{
+  $query = '
+SELECT COUNT(rate) AS count
+     , ROUND(AVG(rate),2) AS average
+     , ROUND(STD(rate),2) AS STD
+  FROM '.RATE_TABLE.'
+  WHERE element_id = '.$picture['current']['id'].'
+;';
+  $row = mysql_fetch_array(pwg_query($query));
+  if ($row['count'] == 0)
+  {
+    $value = $lang['no_rate'];
+  }
+  else
+  {
+    $value = $row['average'];
+    $value.= ' (';
+    $value.= $row['count'].' '.$lang['rates'];
+    $value.= ', '.$lang['standard_deviation'].' : '.$row['STD'];
+    $value.= ')';
+  }
+  
+  $template->assign_block_vars(
+    'info_line',
+    array(
+      'INFO'  => $lang['element_rate'],
+      'VALUE' => $value
+      ));
+}
+// related categories
+$cat_output = '';
+$page['show_comments'] = false;
+foreach ($related_categories as $category)
+{
+  if ($cat_output != '')
+  {
+    $cat_output.= '<br />';
+  }
+  
+  if (count($related_categories) > 3)
+  {
+    $cat_output .= get_cat_display_name_cache($category['uppercats']);
+  }
+  else
+  {
+    $cat_info = get_cat_info($category['category_id']);
+    $cat_output .= get_cat_display_name($cat_info['name']);
+  }
+  // the picture is commentable if it belongs at least to one category which
+  // is commentable
+  if ($category['commentable'] == 'true')
+  {
+    $page['show_comments'] = true;
+  }
+}
+$template->assign_block_vars(
+  'info_line',
+  array(
+    'INFO'  => $lang['categories'],
+    'VALUE' => $cat_output
+    ));
+// metadata
+if ($metadata_showable and isset($_GET['show_metadata']))
+{
+  include_once(PHPWG_ROOT_PATH.'/include/functions_metadata.inc.php');
+  $template->assign_block_vars('metadata', array());
+  if ($conf['show_exif'])
+  {
+    if (!function_exists('read_exif_data'))
+    {
+      die('Exif extension not available, admin should disable exif display');
+    }
+    
+    if ($exif = @read_exif_data($picture['current']['src']))
+    {
+      $template->assign_block_vars(
+        'metadata.headline',
+        array('TITLE' => 'EXIF Metadata')
+        );
+
+      foreach ($conf['show_exif_fields'] as $field)
+      {
+        if (strpos($field, ';') === false)
+        {
+          if (isset($exif[$field]))
+          {
+            $key = $field;
+            if (isset($lang['exif_field_'.$field]))
+            {
+              $key = $lang['exif_field_'.$field];
+            }
+            
+            $template->assign_block_vars(
+              'metadata.line',
+              array(
+                'KEY' => $key,
+                'VALUE' => $exif[$field]
+                )
+              );
+          }
+        }
+        else
+        {
+          $tokens = explode(';', $field);
+          if (isset($exif[$tokens[0]][$tokens[1]]))
+          {
+            $key = $tokens[1];
+            if (isset($lang['exif_field_'.$tokens[1]]))
+            {
+              $key = $lang['exif_field_'.$tokens[1]];
+            }
+            
+            $template->assign_block_vars(
+              'metadata.line',
+              array(
+                'KEY' => $key,
+                'VALUE' => $exif[$tokens[0]][$tokens[1]]
+                )
+              );
+          }
+        }
+      }
+    }
+  }
+  if ($conf['show_iptc'])
+  {
+    $iptc = get_iptc_data($picture['current']['src'],
+                          $conf['show_iptc_mapping']);
+
+    if (count($iptc) > 0)
+    {
+      $template->assign_block_vars(
+        'metadata.headline',
+        array('TITLE' => 'IPTC Metadata')
+        );
+    }
+    
+    foreach ($iptc as $field => $value)
+    {
+      $key = $field;
+      if (isset($lang[$field]))
+      {
+        $key = $lang[$field];
+      }
+      
+      $template->assign_block_vars(
+        'metadata.line',
+        array(
+          'KEY' => $key,
+          'VALUE' => $value
+          )
+        );
+    }
+  }
+}
+//slideshow end
+if ( isset( $_GET['slideshow'] ) )
+{
+  if ( !is_numeric( $_GET['slideshow'] ) ) $_GET['slideshow'] = $conf['slideshow_period'];
+	
+  $template->assign_block_vars('stop_slideshow', array(
+  'U_SLIDESHOW'=>add_session_id( $picture['current']['url'] )
+  ));
+}
+
+//------------------------------------------------------------------- rate form
+if ($conf['rate'] and !$user['is_the_guest'])
+{
+  $query = '
+SELECT rate
+  FROM '.RATE_TABLE.'
+  WHERE user_id = '.$user['id'].'
+    AND element_id = '.$_GET['image_id'].'
+;';
+  $result = pwg_query($query);
+  if (mysql_num_rows($result) > 0)
+  {
+    $row = mysql_fetch_array($result);
+    $sentence = $lang['already_rated'];
+    $sentence.= ' ('.$row['rate'].'). ';
+    $sentence.= $lang['update_rate'];
+  }
+  else
+  {
+    $sentence = $lang['never_rated'].'. '.$lang['to_rate'];
+  }
+  $template->assign_block_vars(
+    'rate',
+    array('SENTENCE' => $sentence)
+    );
+  
+  
+  foreach ($rate_items as $num => $mark)
+  {
+    if ($num > 0)
+    {
+      $separator = '|';
+    }
+    else
+    {
+      $separator = '';
+    }
+
+    $url = PHPWG_ROOT_PATH.'picture.php';
+    $url.= get_query_string_diff(array('rate','add_fav'));
+    $url.= '&amp;rate='.$mark;
+    
+    $template->assign_block_vars(
+      'rate.rate_option',
+      array(
+        'OPTION' => $mark,
+        'URL' => $url,
+        'SEPARATOR' => $separator
+        ));
+  }
+}
+//---------------------------------------------------- users's comments display
+if ($page['show_comments'])
+{
+  // number of comment for this picture
+  $query = 'SELECT COUNT(*) AS nb_comments';
+  $query.= ' FROM '.COMMENTS_TABLE.' WHERE image_id = '.$_GET['image_id'];
+  $query.= " AND validated = 'true'";
+  $query.= ';';
+  $row = mysql_fetch_array( pwg_query( $query ) );
+  
+  // navigation bar creation
+  $url = PHPWG_ROOT_PATH.'picture.php';
+  $url.= get_query_string_diff(array('rate','add_fav'));
+
+  if (!isset( $_GET['start'] )
+      or !is_numeric( $_GET['start'] )
+      or ( is_numeric( $_GET['start'] ) and $_GET['start'] < 0 ) )
+  {
+    $page['start'] = 0;
+  }
+  else
+  {
+    $page['start'] = $_GET['start'];
+  }
+  $page['navigation_bar'] = create_navigation_bar( $url, $row['nb_comments'],
+                                                   $page['start'],
+                                                   $conf['nb_comment_page'],
+                                                   '' );
+  $template->assign_block_vars('comments', array(
+    'NB_COMMENT'=>$row['nb_comments'],
+    'NAV_BAR'=>$page['navigation_bar']));
+
+  $query = 'SELECT id,author,date,image_id,content';
+  $query.= ' FROM '.COMMENTS_TABLE.' WHERE image_id = '.$_GET['image_id'];
+  $query.= " AND validated = 'true'";
+  $query.= ' ORDER BY date ASC';
+  $query.= ' LIMIT '.$page['start'].', '.$conf['nb_comment_page'].';';
+  $result = pwg_query( $query );
+                
+  while ( $row = mysql_fetch_array( $result ) )
+  {
+    $template->assign_block_vars(
+      'comments.comment',
+      array(
+        'COMMENT_AUTHOR'=>empty($row['author'])?$lang['guest']:$row['author'],
+        'COMMENT_DATE'=>format_date($row['date'], 'mysql_datetime', true),
+	'COMMENT'=>parse_comment_content($row['content'])
+	));
+	
+    if ( $user['status'] == 'admin' )
+    {
+      $template->assign_block_vars(
+        'comments.comment.delete',
+        array('U_COMMENT_DELETE'=>add_session_id( $url.'&amp;del='.$row['id'])
+          ));
+    }
+  }
+
+  if (!$user['is_the_guest']
+      or ($user['is_the_guest'] and $conf['comments_forall']))
+  {
+    $template->assign_block_vars('comments.add_comment', array());
+    // display author field if the user is not logged in
+    if (!$user['is_the_guest'])
+    {
+      $template->assign_block_vars(
+        'comments.add_comment.author_known',
+        array('KNOWN_AUTHOR'=>$user['username'])
+        );
+    }
+    else
+    {
+      $template->assign_block_vars(
+        'comments.add_comment.author_field', array()
+        );
+    }
+  }
+}
+//------------------------------------------------------------ log informations
+pwg_log( 'picture', $title_img, $picture['current']['file'] );
+mysql_close();
+
+$template->parse('picture');
+include(PHPWG_ROOT_PATH.'include/page_tail.php');
+?>
Index: /branches/1.4/profile.php
===================================================================
--- /branches/1.4/profile.php	(revision 3249)
+++ /branches/1.4/profile.php	(revision 3249)
@@ -0,0 +1,489 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// customize appearance of the site for a user
+// +-----------------------------------------------------------------------+
+// |                           initialization                              |
+// +-----------------------------------------------------------------------+
+$userdata = array();
+if (defined('IN_ADMIN') and isset($_POST['submituser']))
+{
+  $userdata = getuserdata($_POST['username']);
+}
+else if (defined('IN_ADMIN') and IN_ADMIN and isset($_GET['user_id']))
+{
+  $userdata = getuserdata(intval($_GET['user_id']));
+}
+elseif (defined('IN_ADMIN') and isset($_POST['submit']))
+{
+  $userdata = getuserdata(intval($_POST['userid']));
+}
+elseif (!defined('IN_ADMIN') or !IN_ADMIN)
+{
+  define('PHPWG_ROOT_PATH','./');
+  include_once(PHPWG_ROOT_PATH.'include/common.inc.php');
+  check_login_authorization(false);
+  $userdata = $user;
+}
+//------------------------------------------------------ update & customization
+$infos = array('nb_image_line', 'nb_line_page', 'language',
+               'maxwidth', 'maxheight', 'expand', 'show_nb_comments',
+               'recent_period', 'template', 'mail_address');
+
+$errors = array();
+if (isset($_POST['submit']))
+{
+  $int_pattern = '/^\d+$/';
+  
+  if ($_POST['maxwidth'] != ''
+      and (!preg_match($int_pattern, $_POST['maxwidth'])
+           or $_POST['maxwidth'] < 50))
+  {
+    array_push($errors, $lang['maxwidth_error']);
+  }
+  if ($_POST['maxheight']
+       and (!preg_match($int_pattern, $_POST['maxheight'])
+             or $_POST['maxheight'] < 50))
+  {
+    array_push($errors, $lang['maxheight_error']);
+  }
+  // periods must be integer values, they represents number of days
+  if (!preg_match($int_pattern, $_POST['recent_period'])
+      or $_POST['recent_period'] <= 0)
+  {
+    array_push($errors, $lang['periods_error']);
+  }
+
+  // if mail_address has changed
+  if (!isset($userdata['mail_address']))
+  {
+    $userdata['mail_address'] = '';
+  }
+  
+  if ($_POST['mail_address'] != @$userdata['mail_address'])
+  {
+    if ($user['status'] == 'admin')
+    {
+      $mail_error = validate_mail_address($_POST['mail_address']);
+      if (!empty($mail_error))
+      {
+        array_push($errors, $mail_error);
+      }
+    }
+    else if (!empty($_POST['password']))
+    {
+      array_push($errors, $lang['reg_err_pass']);
+    }
+    else
+    {
+      // retrieving the encrypted password of the login submitted
+      $query = '
+SELECT password
+  FROM '.USERS_TABLE.'
+  WHERE id = \''.$userdata['id'].'\'
+;';
+      $row = mysql_fetch_array(pwg_query($query));
+      if ($row['password'] == md5($_POST['password']))
+      {
+        $mail_error = validate_mail_address($_POST['mail_address']);
+        if (!empty($mail_error))
+        {
+          array_push($errors, $mail_error);
+        }
+      }
+      else
+      {
+        array_push($errors, $lang['reg_err_pass']);
+      }
+    }
+  }
+  
+  // password must be the same as its confirmation
+  if (!empty($_POST['use_new_pwd'])
+      and $_POST['use_new_pwd'] != $_POST['passwordConf'])
+  {
+    array_push($errors, $lang['reg_err_pass']);
+  }
+  
+  // We check if we are in the admin level
+  if (isset($_POST['user_delete']))
+  {
+    if ($_POST['userid'] > 2) // gallery founder + guest
+    {
+      delete_user($_POST['userid']);
+    }
+    else
+    {
+      array_push($errors, $lang['user_err_modify']);
+    }
+  }
+	
+  // We check if we are in the admin level
+  if (isset($_POST['status']) and $_POST['status'] <> $userdata['status'])
+  {
+    if ($_POST['userid'] > 2) // gallery founder + guest
+    {
+      array_push($infos, 'status');
+    }
+    else
+    {
+      array_push($errors, $lang['user_err_modify']);
+    }
+  }
+  
+  if (count($errors) == 0)
+  {
+    $query = '
+UPDATE '.USERS_TABLE.'
+  SET ';
+    $is_first = true;
+    foreach ($infos as $i => $info)
+    {
+      if (!$is_first)
+      {
+        $query.= '
+    , ';
+      }
+      $is_first = false;
+      
+      $query.= $info;
+      $query.= ' = ';
+      if ($_POST[$info] == '')
+      {
+        $query.= 'NULL';
+      }
+      else
+      {
+        $query.= "'".$_POST[$info]."'";
+      }
+    }
+    $query.= '
+  WHERE id = '.$_POST['userid'].'
+;';
+    pwg_query($query);
+
+    if (!empty($_POST['use_new_pwd']))
+    {
+      $query = '
+UPDATE '.USERS_TABLE.'
+  SET password = \''.md5($_POST['use_new_pwd']).'\'
+  WHERE id = '.$_POST['userid'].'
+;';
+      pwg_query($query);
+    }
+    
+    // redirection
+    if (!defined('IN_ADMIN') or !IN_ADMIN)
+    {
+      $url = PHPWG_ROOT_PATH.'category.php?'.$_SERVER['QUERY_STRING'];
+      redirect(add_session_id($url));
+    }
+    else
+    {
+      redirect(add_session_id(PHPWG_ROOT_PATH.'admin.php?page=profile'));
+    }
+  }
+}
+else if (defined('IN_ADMIN') and IN_ADMIN and isset($_POST['submit_add']))
+{
+  $errors = register_user($_POST['login'], $_POST['password'],
+                          $_POST['password'], '');
+}
+// +-----------------------------------------------------------------------+
+// |                       page header and options                         |
+// +-----------------------------------------------------------------------+
+$url_action = PHPWG_ROOT_PATH;
+if (!defined('IN_ADMIN'))
+{
+  $title= $lang['customize_page_title'];
+  include(PHPWG_ROOT_PATH.'include/page_header.php');
+  $url_action .='profile.php';
+}
+else
+{
+  $url_action .='admin.php?page=profile';
+}
+//----------------------------------------------------- template initialization
+$template->set_filenames(array('profile_body'=>'profile.tpl'));
+
+if (defined('IN_ADMIN') and IN_ADMIN and empty($userdata))
+{
+  $admin_profile = add_session_id(PHPWG_ROOT_PATH.'admin.php?page=profile');
+  
+  $template->assign_block_vars('add_user', array('F_ACTION'=>$admin_profile));
+  $template->assign_block_vars('select_user',array());
+
+  $conf['users_page'] = 20;
+  $start = isset($_GET['start']) ? $_GET['start'] : 0;
+
+  $query = '
+SELECT COUNT(*) AS counter
+  FROM '.USERS_TABLE.'
+  WHERE id != 2
+;';
+  list($counter) = mysql_fetch_row(pwg_query($query));
+  $url = PHPWG_ROOT_PATH.'admin.php'.get_query_string_diff(array('start'));
+  $navbar = create_navigation_bar($url,
+                                  $counter,
+                                  $start,
+                                  $conf['users_page'],
+                                  '');
+  
+  $template->assign_vars(
+    array(
+      'L_SELECT_USERNAME'=>$lang['Select_username'],
+      'L_LOOKUP_USER'=>$lang['Look_up_user'],
+      'L_FIND_USERNAME'=>$lang['Find_username'],
+      'L_AUTH_USER'=>$lang['permuser_only_private'],
+      'L_GROUP_ADD_USER' => $lang['group_add_user'],
+      'L_SUBMIT'=>$lang['submit'],
+      'L_STATUS'=>$lang['user_status'],
+      'L_USERNAME' => $lang['login'],
+      'L_PASSWORD' => $lang['password'],
+      'L_EMAIL' => $lang['mail_address'],
+      'L_ORDER_BY' => $lang['order_by'],
+      'L_ACTIONS' => $lang['actions'],
+      'L_PERMISSIONS' => $lang['permissions'],
+      'L_USERS_LIST' => $lang['title_liste_users'],
+
+      'NAVBAR'=>$navbar,
+      'F_SEARCH_USER_ACTION' => $admin_profile,
+      'F_ORDER_ACTION' => $admin_profile,
+      'U_SEARCH_USER' => add_session_id(PHPWG_ROOT_PATH.'admin/search.php')
+      ));
+
+  $order_by_items = array('id' => $lang['registration_date'],
+                          'username' => $lang['login']);
+  foreach ($order_by_items as $item => $label)
+  {
+    $selected = (isset($_GET['order_by']) and $_GET['order_by'] == $item) ?
+      'selected="selected"' : '';
+    $template->assign_block_vars(
+      'select_user.order_by',
+      array(
+        'VALUE' => $item,
+        'CONTENT' => $label,
+        'SELECTED' => $selected
+        ));
+  }
+
+  $direction_items = array('asc' => $lang['ascending'],
+                           'desc' => $lang['descending']);
+  foreach ($direction_items as $item => $label)
+  {
+    $selected = (isset($_GET['direction']) and $_GET['direction'] == $item) ?
+      'selected="selected"' : '';
+    $template->assign_block_vars(
+      'select_user.direction',
+      array(
+        'VALUE' => $item,
+        'CONTENT' => $label,
+        'SELECTED' => $selected
+        ));
+  }
+
+  $profile_url = PHPWG_ROOT_PATH.'admin.php?page=profile&amp;user_id=';
+  $perm_url = PHPWG_ROOT_PATH.'admin.php?page=user_perm&amp;user_id=';
+
+  $users = array();
+  $user_ids = array();
+  $groups_content = array();
+
+  $order_by = 'id';
+  if (isset($_GET['order_by'])
+      and in_array($_GET['order_by'], array_keys($order_by_items)))
+  {
+    $order_by = $_GET['order_by'];
+  }
+
+  $direction = 'ASC';
+  if (isset($_GET['direction'])
+      and in_array($_GET['direction'], array_keys($direction_items)))
+  {
+    $direction = strtoupper($_GET['direction']);
+  }
+  
+  $query = '
+SELECT id, username, mail_address, status
+  FROM '.USERS_TABLE.'
+  WHERE id != 2
+  ORDER BY '.$order_by.' '.$direction.'
+  LIMIT '.$start.', '.$conf['users_page'].'
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($users, $row);
+    array_push($user_ids, $row['id']);
+    $user_groups[$row['id']] = array();
+  }
+
+  $query = '
+SELECT user_id, group_id, name
+  FROM '.USER_GROUP_TABLE.' INNER JOIN '.GROUPS_TABLE.' ON group_id = id
+  WHERE user_id IN ('.implode(',', $user_ids).')
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    $groups_content[$row['group_id']] = $row['name'];
+    array_push($user_groups[$row['user_id']], $row['group_id']);
+  }
+
+  foreach ($users as $item)
+  {
+    $groups = preg_replace('/(\d+)/e',
+                           "\$groups_content['$1']",
+                           implode(', ', $user_groups[$item['id']]));
+    
+    $template->assign_block_vars(
+      'select_user.user',
+      array(
+        'U_MOD'=>add_session_id($profile_url.$item['id']),
+        'U_PERM'=>add_session_id($perm_url.$item['id']),
+        'USERNAME'=>$item['username'],
+        'STATUS'=>$lang['user_status_'.$item['status']],
+        'EMAIL'=>isset($item['mail_address']) ? $item['mail_address'] : '',
+        'GROUPS'=>$groups
+        ));
+  }
+}
+else
+{
+  $expand =
+    ($userdata['expand']=='true')?
+    'EXPAND_TREE_YES':'EXPAND_TREE_NO';
+  
+  $nb_comments =
+    ($userdata['show_nb_comments']=='true')?
+    'NB_COMMENTS_YES':'NB_COMMENTS_NO';
+  
+  $template->assign_block_vars('modify',array());
+  $template->assign_vars(
+    array(
+      'USERNAME'=>$userdata['username'],
+      'USERID'=>$userdata['id'],
+      'EMAIL'=>@$userdata['mail_address'],
+      'LANG_SELECT'=>language_select($userdata['language'], 'language'),
+      'NB_IMAGE_LINE'=>$userdata['nb_image_line'],
+      'NB_ROW_PAGE'=>$userdata['nb_line_page'],
+      'STYLE_SELECT'=>style_select($userdata['template'], 'template'),
+      'RECENT_PERIOD'=>$userdata['recent_period'],
+      'MAXWIDTH'=>@$userdata['maxwidth'],
+      'MAXHEIGHT'=>@$userdata['maxheight'],
+  
+      $expand=>'checked="checked"',
+      $nb_comments=>'checked="checked"',
+      
+      'L_TITLE' => $lang['customize_title'],
+      'L_REGISTRATION_INFO' => $lang['register_title'],
+      'L_PREFERENCES' => $lang['preferences'],
+      'L_USERNAME' => $lang['login'],
+      'L_EMAIL' => $lang['mail_address'],
+      'L_CURRENT_PASSWORD' => $lang['password'],
+      'L_CURRENT_PASSWORD_HINT' => $lang['password_hint'],
+      'L_NEW_PASSWORD' =>  $lang['new_password'],
+      'L_NEW_PASSWORD_HINT' => $lang['new_password_hint'],
+      'L_CONFIRM_PASSWORD' =>  $lang['reg_confirm'],
+      'L_CONFIRM_PASSWORD_HINT' => $lang['confirm_password_hint'],
+      'L_LANG_SELECT'=>$lang['language'],
+      'L_NB_IMAGE_LINE'=>$lang['nb_image_per_row'],
+      'L_NB_ROW_PAGE'=>$lang['nb_row_per_page'],
+      'L_STYLE_SELECT'=>$lang['theme'],
+      'L_RECENT_PERIOD'=>$lang['recent_period'],
+      'L_EXPAND_TREE'=>$lang['auto_expand'],
+      'L_NB_COMMENTS'=>$lang['show_nb_comments'],
+      'L_MAXWIDTH'=>$lang['maxwidth'],
+      'L_MAXHEIGHT'=>$lang['maxheight'],
+      'L_YES'=>$lang['yes'],
+      'L_NO'=>$lang['no'],
+      'L_SUBMIT'=>$lang['submit'],
+      'L_RESET'=>$lang['reset'],
+      'L_RETURN' =>  $lang['home'],
+      'L_RETURN_HINT' =>  $lang['home_hint'],  
+      
+      'F_ACTION'=>add_session_id($url_action),
+      ));
+
+  if (!defined('IN_ADMIN') or !IN_ADMIN)
+  {
+    $url_return = PHPWG_ROOT_PATH.'category.php?'.$_SERVER['QUERY_STRING'];
+    $template->assign_vars(array('U_RETURN' => add_session_id($url_return)));
+  }
+//------------------------------------------------------------- user management
+  if (defined('IN_ADMIN') and IN_ADMIN)
+  {
+    $status_select = '<select name="status">';
+    $status_select .='<option value = "guest" ';
+    if ($userdata['status'] == 'guest')
+    {
+      $status_select .= 'selected="selected"';
+    }
+    $status_select .='>'.$lang['user_status_guest'] .'</option>';
+    $status_select .='<option value = "admin" ';
+    if ($userdata['status'] == 'admin')
+    {
+      $status_select .= 'selected="selected"';
+    }
+    $status_select .='>'.$lang['user_status_admin'] .'</option>';
+    $status_select .='</select>';
+    $template->assign_block_vars(
+      'modify.admin',
+      array(
+        'L_ADMIN_USER'=>$lang['user_management'],
+        'L_STATUS'=>$lang['user_status'],
+        'L_DELETE'=>$lang['user_delete'],
+        'L_DELETE_HINT'=>$lang['user_delete_hint'],
+        'STATUS'=>$status_select
+        ));
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                             errors display                            |
+// +-----------------------------------------------------------------------+
+if (count($errors) != 0)
+{
+  $template->assign_block_vars('errors',array());
+  foreach ($errors as $error)
+  {
+    $template->assign_block_vars('errors.error', array('ERROR'=>$error));
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                           html code display                           |
+// +-----------------------------------------------------------------------+
+if (defined('IN_ADMIN') and IN_ADMIN)
+{
+  $template->assign_var_from_handle('ADMIN_CONTENT', 'profile_body');
+}
+else
+{
+  $template->assign_block_vars('modify.profile',array());
+  $template->parse('profile_body');
+  include(PHPWG_ROOT_PATH.'include/page_tail.php');
+}
+?>
Index: /branches/1.4/random.php
===================================================================
--- /branches/1.4/random.php	(revision 3249)
+++ /branches/1.4/random.php	(revision 3249)
@@ -0,0 +1,63 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// +-----------------------------------------------------------------------+
+// |                          define and include                           |
+// +-----------------------------------------------------------------------+
+define('PHPWG_ROOT_PATH','./');
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+// +-----------------------------------------------------------------------+
+// |                     generate random element list                      |
+// +-----------------------------------------------------------------------+
+
+// we must not show pictures of a forbidden category
+$where = '';
+if ( $user['forbidden_categories'] != '' )
+{
+  $where = 'WHERE category_id NOT IN ('.$user['forbidden_categories'].')';
+}
+
+$query = '
+SELECT DISTINCT(id)
+  FROM '.IMAGES_TABLE.'
+    INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id
+  '.$where.'
+  ORDER BY RAND(NOW())
+  LIMIT 0, '.$conf['top_number'].'
+;';
+$result = pwg_query($query);
+$ids = array();
+while ($row = mysql_fetch_array($result))
+{
+  array_push($ids, $row['id']);
+}
+// +-----------------------------------------------------------------------+
+// |                                redirect                               |
+// +-----------------------------------------------------------------------+
+$url = PHPWG_ROOT_PATH.'category.php?cat=list&amp;list='.implode(',', $ids);
+redirect(add_session_id($url));
+?>
Index: /branches/1.4/register.php
===================================================================
--- /branches/1.4/register.php	(revision 3249)
+++ /branches/1.4/register.php	(revision 3249)
@@ -0,0 +1,88 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+//----------------------------------------------------------- include
+define('PHPWG_ROOT_PATH','./');
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+//----------------------------------------------------------- user registration
+$errors = array();
+if (isset($_POST['submit']))
+{
+  $errors = register_user($_POST['login'], $_POST['password'],
+                          $_POST['password_conf'], $_POST['mail_address']);
+  if (count($errors) == 0)
+  {
+    $query = '
+SELECT id
+  FROM '.USERS_TABLE.'
+  WHERE username = \''.$_POST['login'].'\'
+;';
+    list($user_id) = mysql_fetch_array(pwg_query($query));
+    $session_id = session_create($user_id, $conf['session_length']);
+    $url = 'category.php?id='.$session_id;
+    redirect($url);
+  }
+}
+
+$login = !empty($_POST['login'])?$_POST['login']:'';
+$email = !empty($_POST['mail_address'])?$_POST['mail_address']:'';
+
+//----------------------------------------------------- template initialization
+//
+// Start output of page
+//
+$title= $lang['register_page_title'];
+include(PHPWG_ROOT_PATH.'include/page_header.php');
+
+$template->set_filenames( array('register'=>'register.tpl') );
+$template->assign_vars(array(
+  'L_TITLE' => $lang['register_title'],
+  'L_GUEST' => $lang['ident_guest_visit'],
+  'L_SUBMIT' => $lang['submit'],
+  'L_USERNAME' => $lang['login'],
+  'L_PASSWORD' => $lang['password'],
+  'L_CONFIRM_PASSWORD' => $lang['reg_confirm'],
+  'L_EMAIL' => $lang['mail_address'],
+  
+  'F_ACTION' => add_session_id('register.php'),
+  'F_LOGIN' => $login,
+  'F_EMAIL' => $email
+  ));
+
+//-------------------------------------------------------------- errors display
+if ( sizeof( $errors ) != 0 )
+{
+  $template->assign_block_vars('errors',array());
+  for ( $i = 0; $i < sizeof( $errors ); $i++ )
+  {
+    $template->assign_block_vars('errors.error',array('ERROR'=>$errors[$i]));
+  }
+}
+
+$template->parse('register');
+include(PHPWG_ROOT_PATH.'include/page_tail.php');
+?>
Index: /branches/1.4/search.php
===================================================================
--- /branches/1.4/search.php	(revision 3249)
+++ /branches/1.4/search.php	(revision 3249)
@@ -0,0 +1,275 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+//--------------------------------------------------------------------- include
+define('PHPWG_ROOT_PATH','./');
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+//-------------------------------------------------- access authorization check
+check_login_authorization();
+//------------------------------------------------------------------ form check
+$errors = array();
+$search = array();
+if (isset($_POST['submit']))
+{
+  if (isset($_POST['search_allwords'])
+      and !preg_match('/^\s*$/', $_POST['search_allwords']))
+  {
+    $local_search = array();
+    $search_allwords = $_POST['search_allwords'];
+    $drop_char_match = array(
+      '-','^','$',';','#','&','(',')','<','>','`','\'','"','|',',','@','_',
+      '?','%','~','.','[',']','{','}',':','\\','/','=','\'','!','*');
+    $drop_char_replace = array(
+      ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','','',' ',' ',' ',' ','',' ',
+      ' ',' ',' ',' ',' ',' ',' ',' ','' ,' ',' ',' ',' ',' ');
+    $search_allwords = str_replace($drop_char_match,
+                                   $drop_char_replace,
+                                   $search_allwords);
+	
+    // Split words
+    $words = preg_split('/\s+/', $search_allwords);
+    $words = array_unique($words);
+    $search['fields']['allwords'] = array();
+    $search['fields']['allwords']['words'] = $words;
+    $search['fields']['allwords']['mode'] = $_POST['mode'];
+  }
+  
+  if ($_POST['search_author'])
+  {
+    $search['fields']['author'] = array();
+    $search['fields']['author']['words'] = array($_POST['search_author']);
+  }
+  
+  if (isset($_POST['cat']))
+  {
+    $search['fields']['cat'] = array();
+    $search['fields']['cat']['words'] = $_POST['cat'];
+    if ($_POST['subcats-included'] == 1)
+    {
+      $search['fields']['cat']['mode'] = 'sub_inc';
+    }
+  }
+
+  // dates
+  $type_date = $_POST['date_type'];
+  
+  if (!empty($_POST['start_year']))
+  {
+    $year = $_POST['start_year'];
+    $month = $_POST['start_month'] != 0 ? $_POST['start_month'] : '01';
+    $day = $_POST['start_day'] != 0 ? $_POST['start_day'] : '01';
+    $date = $year.'-'.$month.'-'.$day;
+    
+    $search['fields'][$type_date.'-after']['words'] = array($date);
+    $search['fields'][$type_date.'-after']['mode'] = 'inc';
+  }
+
+  if (!empty($_POST['end_year']))
+  {
+    $year = $_POST['end_year'];
+    $month = $_POST['end_month'] != 0 ? $_POST['end_month'] : '12';
+    $day = $_POST['end_day'] != 0 ? $_POST['end_day'] : '31';
+    $date = $year.'-'.$month.'-'.$day;
+    
+    $search['fields'][$type_date.'-before']['words'] = array($date);
+    $search['fields'][$type_date.'-before']['mode'] = 'inc';
+  }
+    
+  // search string (for URL) creation
+  $search_string = '';
+  $tokens = array();
+  if (!empty($search))
+  {
+    foreach (array_keys($search['fields']) as $field)
+    {
+      $token = $field.':';
+      $token.= implode(',', $search['fields'][$field]['words']);
+      if (isset($search['fields'][$field]['mode']))
+      {
+        $token.= '~'.$search['fields'][$field]['mode'];
+      }
+      array_push($tokens, $token);
+    }
+    $search_string.= implode('--', $tokens);
+    if (count($tokens) > 1)
+    {
+      $search_string.= '|AND';
+    }
+  }
+  else
+  {
+    array_push($errors, $lang['search_one_clause_at_least']);
+  }
+}
+//----------------------------------------------------------------- redirection
+if (isset($_POST['submit']) and count($errors) == 0)
+{
+  $url = 'category.php?cat=search&search='.$search_string;
+  $url = add_session_id($url, true);
+  redirect($url);
+}
+//----------------------------------------------------- template initialization
+/**
+ * instantiate number list for days in a template block
+ *
+ * @param string blockname
+ * @param string selection
+ */
+function get_day_list($blockname, $selection)
+{
+  global $template;
+  
+  $template->assign_block_vars(
+    $blockname, array('SELECTED' => '', 'VALUE' => 0, 'OPTION' => '--'));
+  
+  for ($i = 1; $i <= 31; $i++)
+  {
+    $selected = '';
+    if ($i == (int)$selection)
+    {
+      $selected = 'selected="selected"';
+    }
+    $template->assign_block_vars(
+      $blockname, array('SELECTED' => $selected,
+                        'VALUE' => $i,
+                        'OPTION' => str_pad($i, 2, '0', STR_PAD_LEFT)));
+  }
+}
+
+/**
+ * instantiate month list in a template block
+ *
+ * @param string blockname
+ * @param string selection
+ */
+function get_month_list($blockname, $selection)
+{
+  global $template, $lang;
+  
+  $template->assign_block_vars(
+    $blockname, array('SELECTED' => '',
+                      'VALUE' => 0,
+                      'OPTION' => '------------'));
+
+  for ($i = 1; $i <= 12; $i++)
+  {
+    $selected = '';
+    if ($i == (int)$selection)
+    {
+      $selected = 'selected="selected"';
+    }
+    $template->assign_block_vars(
+      $blockname, array('SELECTED' => $selected,
+                        'VALUE' => $i,
+                        'OPTION' => $lang['month'][$i]));
+  }
+}
+
+// start date
+get_day_list('start_day', @$_POST['start_day']);
+get_month_list('start_month', @$_POST['start_month']);
+// end date
+get_day_list('end_day', @$_POST['end_day']);
+get_month_list('end_month', @$_POST['end_month']);
+
+//
+// Start output of page
+//
+$title= $lang['search_title'];
+include(PHPWG_ROOT_PATH.'include/page_header.php');
+
+$template->set_filenames( array('search'=>'search.tpl') );
+$template->assign_vars(array(
+  'L_RETURN_HINT' => $lang['home_hint'],
+  'L_SEARCH_TITLE' => $lang['search_title'],
+  'L_SEARCH_OPTIONS' => $lang['search_options'],
+  'L_RETURN' => $lang['home'],
+  'L_SUBMIT' => $lang['submit'],
+  'L_RESET' => $lang['reset'],
+  'L_SEARCH_KEYWORDS'=>$lang['search_keywords'],
+  'L_SEARCH_KEYWORDS_HINT'=>$lang['search_keywords_hint'],
+  'L_SEARCH_ANY_TERMS'=>$lang['search_mode_or'],
+  'L_SEARCH_ALL_TERMS'=>$lang['search_mode_and'],
+  'L_SEARCH_AUTHOR'=>$lang['search_author'],
+  'L_SEARCH_AUTHOR_HINT'=>$lang['search_explain'],
+  'L_SEARCH_CATEGORIES'=>$lang['search_categories'],
+  'L_SEARCH_CATEGORIES_HINT'=>$lang['search_categories_hint'],
+  'L_SEARCH_SUBFORUMS'=>$lang['search_subcats_included'],
+  'L_YES' => $lang['yes'],
+  'L_NO' => $lang['no'],
+  'L_SEARCH_DATE' => $lang['search_date'],
+  'L_SEARCH_DATE_HINT' => $lang['search_date_hint'],
+  'L_TODAY' => $lang['today'],
+  'L_SEARCH_DATE_FROM'=>$lang['search_date_from'],
+  'L_SEARCH_DATE_TO'=>$lang['search_date_to'],
+  'L_DAYS'=>$lang['days'],
+  'L_MONTH'=>$lang['w_month'],
+  'L_SEARCH_DATE_TYPE'=>$lang['search_date_type'],
+  'L_SEARCH_CREATION'=>$lang['search_date_creation'],
+  'L_SEARCH_AVAILABILITY'=>$lang['search_date_available'],
+  'L_RESULT_SORT'=>$lang['search_sort'],
+  'L_SORT_ASCENDING'=>$lang['search_ascending'],
+  'L_SORT_DESCENDING'=>$lang['search_descending'],
+  
+  'TODAY_DAY' => date('d', time()),
+  'TODAY_MONTH' => date('m', time()),
+  'TODAY_YEAR' => date('Y', time()),
+  'S_SEARCH_ACTION' => add_session_id( 'search.php' ),   
+  'U_HOME' => add_session_id( 'category.php' )
+  )
+);
+
+//------------------------------------------------------------- categories form
+$query = '
+SELECT name,id,date_last,nb_images,global_rank,uppercats
+  FROM '.CATEGORIES_TABLE;
+if ($user['forbidden_categories'] != '')
+{
+  $query.= '
+  WHERE id NOT IN ('.$user['forbidden_categories'].')';
+}
+$query.= '
+;';
+
+$selecteds = array();
+display_select_cat_wrapper($query, $selecteds, 'category_option', false);
+
+//-------------------------------------------------------------- errors display
+if (sizeof($errors) != 0)
+{
+  $template->assign_block_vars('errors',array());
+  foreach ($errors as $error)
+  {
+    $template->assign_block_vars('errors.error',array('ERROR'=>$error));
+  }
+}
+//------------------------------------------------------------ log informations
+pwg_log( 'search', $title );
+mysql_close();
+$template->parse('search');
+include(PHPWG_ROOT_PATH.'include/page_tail.php');
+?>
Index: /branches/1.4/template/default/about.tpl
===================================================================
--- /branches/1.4/template/default/about.tpl	(revision 3249)
+++ /branches/1.4/template/default/about.tpl	(revision 3249)
@@ -0,0 +1,10 @@
+<div class="titrePage">{PAGE_TITLE}</div>
+<div class="menu" style="white-space:normal;margin:10px;">
+  {L_ABOUT}
+</div>
+<div style="text-align:center;margin:5px;">
+<a href="{U_RETURN}" title="{L_RETURN_HINT}">[{L_RETURN}]</a>
+</div>
+<div style="text-align:center;margin:5px;">
+<img src="./template/default/images/php_sqreuil_artistes.gif" alt="php logo" />
+</div>
Index: /branches/1.4/template/default/admin.tpl
===================================================================
--- /branches/1.4/template/default/admin.tpl	(revision 3249)
+++ /branches/1.4/template/default/admin.tpl	(revision 3249)
@@ -0,0 +1,77 @@
+<!-- BEGIN install_warning -->
+  <p class="install_warning">{L_INSTALL_WARNING}</div>
+<!-- END install_warning -->
+<table style="width:100%;">
+  <tr>
+	<td valign="top" style="padding:10px;width:1%;">
+	<div class="table1">
+
+<div class="titreMenu">{L_LINKS}</div>
+<div class="menu">
+<ul class="menu">
+  <li><a class="adminMenu" href="{U_RETURN}">{L_GALLERY_INDEX}</a></li>
+  </ul>
+</div>
+<div class="titreMenu">{L_GENERAL}</div>
+<div class="menu">
+<ul class="menu">
+  <li><a class="adminMenu" href="{U_FAQ}">{L_FAQ}</a></li>
+  <li><a class="adminMenu" href="{U_SITES}">{L_SITES}</a></li>
+  <li><a class="adminMenu" href="{U_PHPINFO}">{L_PHPINFO}</a></li>
+  <li><a class="adminMenu" href="{U_HISTORY}">{L_HISTORY}</a></li>
+  <li><a class="adminMenu" href="{U_CAT_UPDATE}">{L_UPDATE}</a></li>
+</ul>
+</div>
+<div class="titreMenu">{L_CONFIGURATION}</div>
+<div class="menu">
+<ul class="menu">
+  <li><a class="adminMenu" href="{U_CONFIG_GENERAL}">{L_CONFIG_GENERAL}</a></li>
+  <li><a class="adminMenu" href="{U_CONFIG_COMMENTS}">{L_CONFIG_COMMENTS}</a></li>
+  <li><a class="adminMenu" href="{U_CONFIG_DISPLAY}">{L_CONFIG_DISPLAY}</a></li>
+  <li><a class="adminMenu" href="{U_CONFIG_UPLOAD}">{L_CONFIG_UPLOAD}</a></li>
+  <li><a class="adminMenu" href="{U_CONFIG_SESSION}">{L_CONFIG_SESSION}</a></li>
+  <li><a class="adminMenu" href="{U_CONFIG_METADATA}">{L_CONFIG_METADATA}</a></li>
+</ul>
+</div>
+<div class="titreMenu">{L_CATEGORIES}</div>
+<div class="menu">
+<ul class="menu">
+  <li><a class="adminMenu" href="{U_CATEGORIES}">{L_MANAGE}</a></li>
+  <li><a class="adminMenu" href="{U_CAT_UPLOAD}">{L_CAT_UPLOAD}</a></li>
+  <li><a class="adminMenu" href="{U_CAT_COMMENTS}">{L_CAT_COMMENTS}</a></li>
+  <li><a class="adminMenu" href="{U_CAT_VISIBLE}">{L_CAT_VISIBLE}</a></li>
+  <li><a class="adminMenu" href="{U_CAT_STATUS}">{L_CAT_STATUS}</a></li>
+</ul>
+</div>
+<div class="titreMenu">{L_IMAGES}</div>
+<div class="menu">
+<ul class="menu">
+  <li><a class="adminMenu" href="{U_WAITING}">{L_WAITING}</a></li>
+  <li><a class="adminMenu" href="{U_THUMBNAILS}">{L_THUMBNAILS}</a></li>
+  <li><a class="adminMenu" href="{U_COMMENTS}">{L_COMMENTS}</a></li>
+</ul>
+</div>
+<div class="titreMenu">{L_IDENTIFY}</div>
+<div class="menu">
+<ul class="menu">
+  <li><a class="adminMenu" href="{U_USERS}">{L_USERS}</a></li>
+  <li><a class="adminMenu" href="{U_GROUPS}">{L_GROUPS}</a></li>
+</ul>
+</div>
+<div class="titreMenu">{L_AUTH}</div>
+<div class="menu">
+<ul class="menu">
+  <li><a class="adminMenu" href="{U_USERS_AUTH}">{L_USERS}</a></li>
+  <li><a class="adminMenu" href="{U_GROUPS_AUTH}">{L_GROUPS}</a></li>
+</ul>
+</div>
+      </div>
+	</td>
+	<td style="padding:10px;width:99%;" valign="top">
+<div class="home">
+  <div class="titrePage">{PAGE_TITLE}</div>
+  <div align="center">{ADMIN_CONTENT}{ADMIN_CONTENT_2}</div>
+</div>
+	</td>
+  </tr>
+</table>
Index: /branches/1.4/template/default/admin/cat_list.tpl
===================================================================
--- /branches/1.4/template/default/admin/cat_list.tpl	(revision 3249)
+++ /branches/1.4/template/default/admin/cat_list.tpl	(revision 3249)
@@ -0,0 +1,59 @@
+<!-- BEGIN errors -->
+<div class="errors">
+<ul>
+  <!-- BEGIN error -->
+  <li>{errors.error.ERROR}</li>
+  <!-- END error -->
+</ul>
+</div>
+<!-- END errors -->
+<!-- BEGIN infos -->
+<div class="info">
+  <!-- BEGIN info -->
+  <li>{infos.info.INFO}</li>
+  <!-- END info -->
+</div>
+<!-- END infos -->
+<div class="admin">{CATEGORIES_NAV}</div>
+<table style="width:100%;">
+<!-- BEGIN category -->
+<tr>
+  <td style="width:1px;padding:5px;"><img src="{category.CATEGORY_IMG_SRC}" alt="{category.CATEGORY_IMG_ALT}" title="{category.CATEGORY_IMG_TITLE}" /></td>
+  <td style="width:60%;text-align:left;"><a class="titreImg" href="{category.U_CATEGORY}">{category.CATEGORY_NAME}</a>
+    <br />
+	<!-- BEGIN storage -->
+    {L_STORAGE} : {category.CATEGORY_DIR} - 
+    <!-- END storage -->
+	{L_NB_IMG} : {category.CATEGORY_NB_IMG}
+  </td>
+  <td class="row1" style="width:10%;white-space:nowrap;text-align:center;">
+    <a href="{category.U_MOVE_UP}">{L_MOVE_UP}</a><br />
+	<a href="{category.U_MOVE_DOWN}">{L_MOVE_DOWN}</a>
+  </td>
+  <td class="row1" style="width:10%;white-space:nowrap;text-align:center;">
+    <a href="{category.U_CAT_EDIT}">{L_EDIT}</a>
+  </td>
+  <td class="row1" style="width:10%;white-space:nowrap;text-align:center;">
+    <!-- BEGIN image_info -->
+    <a href="{category.U_INFO_IMG}">{L_INFO_IMG}</a>
+    <!-- END image_info -->
+    <!-- BEGIN no_image_info -->
+    <span style="color:darkgray;">{L_INFO_IMG}</span>
+    <!-- END no_image_info -->
+  </td>
+  <td class="row1" style="width:10%;white-space:nowrap;text-align:center;">
+    <!-- BEGIN virtual -->
+    <a href="{category.U_CAT_DELETE}">{L_DELETE}</a>
+    <!-- END virtual -->
+    <!-- BEGIN storage -->
+    <span style="color:darkgray;">{L_DELETE}</span>
+    <!-- END storage -->
+  </td>
+<tr>
+<!-- END category -->
+</table>
+<form action="{F_ACTION}" method="post">
+  {L_ADD_VIRTUAL} : <input type="text" name="virtual_name" />
+  <input type="hidden" name="rank" value="{NEXT_RANK}"/>
+  <input type="submit" value="{L_SUBMIT}" class="bouton" name="submit" />
+</form>
Index: /branches/1.4/template/default/admin/cat_modify.tpl
===================================================================
--- /branches/1.4/template/default/admin/cat_modify.tpl	(revision 3249)
+++ /branches/1.4/template/default/admin/cat_modify.tpl	(revision 3249)
@@ -0,0 +1,86 @@
+<!-- BEGIN confirmation -->
+<div style="color:red;text-align:center;">
+  {L_EDIT_CONFIRM} <a href="{U_PERMISSIONS}">{L_HERE}</a></div>
+<!-- END confirmation -->
+<div class="admin">{CATEGORIES_NAV}</div>
+<form action="{F_ACTION}" method="POST">
+<table style="width:100%;">
+    <!-- BEGIN representant -->
+    <tr>
+      <td style="width:50%;" align="center">
+        <a href="{representant.URL}"><img src="{representant.SRC}" alt="" class="miniature" /></a>
+      </td>
+      <td class="row1"><input type="submit" name="set_random_representant" value="{L_SET_RANDOM_REPRESENTANT}" class="bouton" /></td>
+    </tr>
+    <!-- END representant -->
+  </table>
+</form>
+<form action="{F_ACTION}" method="POST">
+<table style="width:100%;">
+    <!-- BEGIN server -->
+    <tr>
+      <td style="width:50%;"><strong>{L_REMOTE_SITE}</strong></td>
+      <td class="row1">{server.SITE_URL}</td>
+    </tr>
+    <!-- END server -->
+    <tr>
+      <td style="width:50%;"><strong>{L_EDIT_NAME}</strong></td>
+      <td class="row1">
+        <input type="text" name="name" value="{CAT_NAME}" maxlength="60"/>
+      </td>
+    </tr>
+	<!-- BEGIN storage -->
+	<tr>
+      <td><strong>{L_STORAGE}</strong></td>
+      <td class="row1">{storage.CATEGORY_DIR}</td>
+    </tr>
+	<!-- END storage -->
+    <tr>
+      <td><strong>{L_EDIT_COMMENT}</strong></td>
+      <td class="row1">
+        <textarea name="comment" rows="3" cols="50" >{CAT_COMMENT}</textarea>
+      </td>
+    </tr>
+	<tr class="admin">
+	  <th colspan="2">{L_EDIT_CAT_OPTIONS}</th>
+	</tr>
+    <tr>
+      <td><strong>{L_EDIT_STATUS}&nbsp;:</strong><br /><span class="small">{L_EDIT_STATUS_INFO}</span></td>
+      <td class="row1">
+	  <input type="radio" class="radio" name="status" value="public" {STATUS_PUBLIC} />{L_STATUS_PUBLIC}&nbsp;&nbsp;
+	  <input type="radio" class="radio" name="status" value="private" {STATUS_PRIVATE} />{L_STATUS_PRIVATE}
+      </td>
+    </tr>
+    <tr>
+      <td><strong>{L_EDIT_LOCK}&nbsp;:</strong><br /><span class="small">{L_EDIT_LOCK_INFO}</span></td>
+      <td class="row1">
+	  <input type="radio" class="radio" name="visible" value="false" {LOCKED} />{L_YES}&nbsp;&nbsp;
+	  <input type="radio" class="radio" name="visible" value="true" {UNLOCKED} />{L_NO}
+      </td>
+    </tr>
+    <tr>
+      <td><strong>{L_EDIT_COMMENTABLE}&nbsp;:</strong><br /><span class="small">{L_EDIT_COMMENTABLE_INFO}</span></td>
+      <td class="row1">
+          <input type="radio" class="radio" name="commentable" value="true" {COMMENTABLE_TRUE} />{L_YES}&nbsp;&nbsp;
+          <input type="radio" class="radio" name="commentable" value="false" {COMMENTABLE_FALSE} />{L_NO}
+      </td>
+    </tr>
+    <!-- BEGIN upload -->
+    <tr>
+      <td><strong>{L_EDIT_UPLOADABLE}&nbsp;:</strong><br /><span class="small">{L_EDIT_UPLOADABLE_INFO}</span></td>
+      <td class="row1">
+          <input type="radio" class="radio" name="uploadable" value="true" {UPLOADABLE_TRUE} />{L_YES}&nbsp;&nbsp;
+          <input type="radio" class="radio" name="uploadable" value="false" {UPLOADABLE_FALSE} />{L_NO}
+      </td>
+    </tr>
+    <!-- END upload -->
+    <tr>
+      <td colspan="2">&nbsp;</td>
+    </tr>
+    <tr>
+      <td colspan="2" align="center">
+        <input type="submit" name="submit" value="{L_SUBMIT}" class="bouton" />
+      </td>
+    </tr>
+  </table>
+</form>
Index: /branches/1.4/template/default/admin/cat_options.tpl
===================================================================
--- /branches/1.4/template/default/admin/cat_options.tpl	(revision 3249)
+++ /branches/1.4/template/default/admin/cat_options.tpl	(revision 3249)
@@ -0,0 +1,31 @@
+<div class="admin">{L_CAT_TITLE}</div>
+<form name="form1" method="post" action="{F_ACTION}" style="text-align:center;width:800px;">
+<div style="clear:both;"></div>
+<div style="height:auto;">
+  <div style="float:left;padding:10px;width:300px;">
+  <span class="titreMenu">{L_CAT_OPTIONS_TRUE}</span><br />
+  <select style="height:auto;width:280px" name="cat_true[]" multiple="multiple" size="10">
+    <!-- BEGIN category_option_true -->
+    <option class="{category_option_true.CLASS}" {category_option_true.SELECTED} value="{category_option_true.VALUE}">{category_option_true.OPTION}</option>
+    <!-- END category_option_true -->
+  </select>
+  </div>
+  <div style="float:left;padding-top:80px;padding-bottom:80px;text-align:center;width:160px;" >
+    <input type="submit" value="&laquo;" name="trueify" style="font-size:15px;" class="bouton" /><br/>
+    <input type="submit" value="&raquo;" name="falsify" style="font-size:15px;" class="bouton" />
+  </div>
+  <div style="float:right;padding:10px;width:300px;">
+   <span class="titreMenu">{L_CAT_OPTIONS_FALSE}</span><br />
+  <select style="width:280px" name="cat_false[]" multiple="multiple" size="10">
+    <!-- BEGIN category_option_false -->
+    <option class="{category_option_false.CLASS}" {category_option_false.SELECTED} value="{category_option_false.VALUE}">{category_option_false.OPTION}</option>
+    <!-- END category_option_false -->
+  </select>
+  </div>
+</div>
+<div style="clear:both;"></div>
+<input type="hidden" name="{HIDDEN_NAME}" value="{HIDDEN_VALUE}" />
+<input type="reset" name="reset" value="{L_RESET}" class="bouton" />
+</form>
+<div class="information">{L_CAT_OPTIONS_INFO}</div>
+
Index: /branches/1.4/template/default/admin/cat_perm.vtp
===================================================================
--- /branches/1.4/template/default/admin/cat_perm.vtp	(revision 3249)
+++ /branches/1.4/template/default/admin/cat_perm.vtp	(revision 3249)
@@ -0,0 +1,48 @@
+<form action="{#action}" method="post">
+  <!--VTP_groups-->
+  <table style="width:100%;">
+    <tr>
+      <th colspan="2">{#menu_groups}</th>
+    </tr>
+    <!--VTP_group-->
+    <tr>
+      <td><img src="./template/{#user_template}/admin/images/puce.gif" alt="&gt;" /><a href="{#group_perm_link}"><span style="color:{#color}">{#groupname}</span></a></td>
+      <td style="text-align:right;">
+        <input type="radio" name="groupaccess-{#id}" value="0"{#authorized_checked}/>{#permuser_authorized}
+        <input type="radio" name="groupaccess-{#id}" value="1"{#forbidden_checked}/>{#permuser_forbidden}
+      </td>
+    </tr>
+    <!--/VTP_group-->
+  </table>
+  <!--/VTP_groups-->
+  <table style="width:100%;">
+    <tr>
+      <th colspan="2">{#menu_users}</th>
+    </tr>
+    <!--VTP_user-->
+    <tr>
+      <td>
+        <img src="./template/{#user_template}/admin/images/puce.gif" alt="&gt;" />
+        <a href="{#user_perm_link}"><span style="color:{#color}">{#username}</span></a>
+        <!--VTP_usergroups-->
+        [
+        <!--VTP_usergroup-->
+        <span style="color:{#color};">{#name}</span>{#separation}
+        <!--/VTP_usergroup-->
+        ]
+        <!--/VTP_usergroups-->
+      </td>
+      <td style="text-align:right;">
+        <!--VTP_parent_forbidden-->
+        <a href="{#url}">{#permuser_parent_forbidden}</a>
+        <!--/VTP_parent_forbidden-->
+        <input type="radio" name="useraccess-{#id}" value="0"{#authorized_checked}/>{#permuser_authorized}
+        <input type="radio" name="useraccess-{#id}" value="1"{#forbidden_checked}/>{#permuser_forbidden}
+      </td>
+    </tr>
+    <!--/VTP_user-->
+    <tr>
+      <td colspan="2" align="center"><input type="submit" name="submit" value="{#submit}"/></td>
+    </tr>
+  </table>
+</form>
Index: /branches/1.4/template/default/admin/configuration.tpl
===================================================================
--- /branches/1.4/template/default/admin/configuration.tpl	(revision 3249)
+++ /branches/1.4/template/default/admin/configuration.tpl	(revision 3249)
@@ -0,0 +1,212 @@
+<!-- BEGIN errors -->
+<div class="errors">
+<ul>
+  <!-- BEGIN error -->
+  <li>{errors.error.ERROR}</li>
+  <!-- END error -->
+</ul>
+</div>
+<!-- END errors -->
+<!-- BEGIN confirmation -->
+<div class="info">{L_CONFIRM}</div>
+<!-- END confirmation -->
+<form method="post" action="{F_ACTION}">
+<table width="100%" align="center">
+<!-- BEGIN general -->
+  <tr class="admin">
+    <th colspan="2">{general.L_CONF_TITLE}</th>
+  </tr>
+  <tr>
+    <td colspan="2">&nbsp;</td>
+  </tr>
+  <tr>
+    <td width="70%"><strong>{general.L_CONF_MAIL}&nbsp;:</strong><br /><span class="small">{general.L_CONF_MAIL_INFO}</span></td>
+	<td class="row1"><input type="text" size="25" maxlength="100" name="mail_webmaster" value="{general.ADMIN_MAIL}" /></td>
+  </tr>
+  <tr>
+    <td><strong>{general.L_CONF_TN_PREFIX}&nbsp;:</strong><br /><span class="small">{general.L_CONF_TN_PREFIX_INFO}</span></td>
+	<td class="row1"><input type="text" size="10" maxlength="10" name="prefix_thumbnail" value="{general.THUMBNAIL_PREFIX}" /></td>
+  </tr>
+  <tr>
+    <td><strong>{general.L_CONF_HISTORY}&nbsp;:</strong><br /><span class="small">{general.L_CONF_HISTORY_INFO}</span></td>
+	<td class="row1"><input type="radio" class="radio" name="log" value="true" {general.HISTORY_YES} />{L_YES}&nbsp;&nbsp;
+	<input type="radio" class="radio" name="log" value="false" {general.HISTORY_NO} />{L_NO}</td>
+  </tr>
+  <tr>
+    <td><strong>{general.L_CONF_NOTIFICATION}&nbsp;:</strong><br /><span class="small">{general.L_CONF_NOTIFICATION_INFO}</span></td>
+	<td class="row1"><input type="radio" class="radio" name="mail_notification" value="true" {general.NOTIFICATION_YES} />{L_YES}&nbsp;&nbsp;
+	<input type="radio" class="radio" name="mail_notification" value="false" {general.NOTIFICATION_NO} />{L_NO}</td>
+  </tr>
+  <tr>
+    <td><strong>{general.L_CONF_GALLERY_LOCKED}&nbsp;:</strong><br /><span class="small">{general.L_CONF_GALLERY_LOCKED_INFO}</span></td>
+        <td class="row1"><input type="radio" class="radio" name="gallery_locked" value="true" {general.GALLERY_LOCKED_YES} />{L_YES}&nbsp;&nbsp;
+        <input type="radio" class="radio" name="gallery_locked" value="false" {general.GALLERY_LOCKED_NO} />{L_NO}</td>
+  </tr>
+<!-- END general -->
+<!-- BEGIN comments -->
+  <tr class="admin">
+    <th colspan="2">{comments.L_CONF_TITLE}</th>
+  </tr>
+    <tr>
+    <td colspan="2">&nbsp;</td>
+  </tr>
+  <tr>
+    <td width="70%"><strong>{comments.L_CONF_COMMENTS_ALL}&nbsp;:</strong><br /><span class="small">{comments.L_CONF_COMMENTS_ALL_INFO}</span></td>
+	<td class="row1"><input type="radio" class="radio" name="comments_forall" value="true" {comments.COMMENTS_ALL_YES} />{L_YES}&nbsp;&nbsp;
+	<input type="radio" class="radio" name="comments_forall" value="false" {comments.COMMENTS_ALL_NO} />{L_NO}</td>
+  </tr>
+  <tr>
+    <td><strong>{comments.L_CONF_NB_COMMENTS_PAGE}&nbsp;:</strong><br /><span class="small">{comments.L_CONF_NB_COMMENTS_PAGE_INFO}</span></td>
+	<td class="row1"><input type="text" size="3" maxlength="4" name="nb_comment_page" value="{comments.NB_COMMENTS_PAGE}" /></td>
+  </tr>
+  <tr>
+    <td><strong>{comments.L_CONF_VALIDATE}&nbsp;:</strong><br /><span class="small">{comments.L_CONF_VALIDATE_INFO}</span></td>
+	<td class="row1"><input type="radio" class="radio" name="comments_validation" value="true" {comments.VALIDATE_YES} />{L_YES}&nbsp;&nbsp;
+	<input type="radio" class="radio" name="comments_validation" value="false" {comments.VALIDATE_NO} />{L_NO}</td>
+  </tr>
+<!-- END comments -->
+<!-- BEGIN default -->
+  <tr class="admin">
+    <th colspan="2">{default.L_CONF_TITLE}</th>
+  </tr>
+    <tr>
+    <td colspan="2">&nbsp;</td>
+  </tr>
+  <tr>
+    <td width="70%"><strong>{default.L_CONF_LANG}&nbsp;:</strong><br /><span class="small">{default.L_CONF_LANG_INFO}</span></td>
+	<td class="row1">{default.CONF_LANG_SELECT}</td>
+  </tr>
+  <tr>
+    <td><strong>{default.L_NB_IMAGE_LINE}&nbsp;:</strong><br /><span class="small">{default.L_NB_IMAGE_LINE_INFO}</span></td>
+	<td class="row1"><input type="text" size="3" maxlength="2" name="nb_image_line" value="{default.NB_IMAGE_LINE}" /></td>
+  </tr>
+  <tr>
+    <td><strong>{default.L_NB_ROW_PAGE}&nbsp;:</strong><br /><span class="small">{default.L_NB_ROW_PAGE_INFO}</span></td>
+	<td class="row1"><input type="text" size="3" maxlength="2" name="nb_line_page" value="{default.NB_ROW_PAGE}" /></td>
+  </tr>
+  <tr>
+    <td><strong>{default.L_CONF_STYLE}&nbsp;:</strong><br /><span class="small">{default.L_CONF_STYLE_INFO}</span></td>
+	<td class="row1">{default.CONF_STYLE_SELECT}</td>
+  </tr>
+  <tr>
+    <td><strong>{default.L_CONF_RECENT}&nbsp;:</strong><br /><span class="small">{default.L_CONF_RECENT_INFO}</span></td>
+	<td class="row1"><input type="text" size="3" maxlength="2" name="recent_period" value="{default.CONF_RECENT}" /></td>
+  </tr>
+  <tr>
+    <td><strong>{default.L_CONF_EXPAND}&nbsp;:</strong><br /><span class="small">{default.L_CONF_EXPAND_INFO}</span></td>
+	<td class="row1"><input type="radio" class="radio" name="auto_expand" value="true" {default.EXPAND_YES} />{L_YES}&nbsp;&nbsp;
+	<input type="radio" class="radio" name="auto_expand" value="false" {default.EXPAND_NO} />{L_NO}</td>
+  </tr>
+  <tr>
+    <td><strong>{default.L_NB_COMMENTS}&nbsp;:</strong><br /><span class="small">{default.L_NB_COMMENTS_INFO}</span></td>
+	<td class="row1"><input type="radio" class="radio" name="show_nb_comments" value="true" {default.SHOW_COMMENTS_YES} />{L_YES}&nbsp;&nbsp;
+	<input type="radio" class="radio" name="show_nb_comments" value="false" {default.SHOW_COMMENTS_NO} />{L_NO}</td>
+  </tr>
+  <tr>
+    <td><strong>{default.L_MAXWIDTH}&nbsp;:</strong></td>
+	<td><input type="text" size="4" maxlength="4" name="default_maxwidth" value="{default.MAXWIDTH}" />
+	</td>
+  </tr>
+	<tr>
+    <td><strong>{default.L_MAXHEIGHT}&nbsp;:</strong></td>
+	<td><input type="text" size="4" maxlength="4" name="default_maxheight" value="{default.MAXHEIGHT}" />
+	</td>
+  </tr>
+<!-- END default -->
+<!-- BEGIN upload -->
+  <tr class="admin">
+    <th colspan="2">{upload.L_CONF_TITLE}</th>
+  </tr>
+  <tr>
+    <td colspan="2">&nbsp;</td>
+  </tr>
+  <tr>
+    <td width="70%"><strong>{upload.L_CONF_MAXSIZE}&nbsp;:</strong><br /><span class="small">{upload.L_CONF_MAXSIZE_INFO}</span></td>
+	<td class="row1"><input type="text" size="4" maxlength="4" name="upload_maxfilesize" value="{upload.UPLOAD_MAXSIZE}" /></td>
+  </tr>
+  <tr>
+    <td><strong>{upload.L_CONF_MAXWIDTH}&nbsp;:</strong><br /><span class="small">{upload.L_CONF_MAXWIDTH_INFO}</span></td>
+	<td class="row1"><input type="text" size="4" maxlength="4" name="upload_maxwidth" value="{upload.UPLOAD_MAXWIDTH}" /></td>
+  </tr>
+  <tr>
+    <td><strong>{upload.L_CONF_MAXHEIGHT}&nbsp;:</strong><br /><span class="small">{upload.L_CONF_MAXHEIGHT_INFO}</span></td>
+	<td class="row1"><input type="text" size="4" maxlength="4" name="upload_maxheight" value="{upload.UPLOAD_MAXHEIGHT}" /></td>
+  </tr>
+    <tr>
+    <td><strong>{upload.L_CONF_TN_MAXWIDTH}&nbsp;:</strong><br /><span class="small">{upload.L_CONF_TN_MAXWIDTH_INFO}</span></td>
+	<td class="row1"><input type="text" size="4" maxlength="4" name="upload_maxwidth_thumbnail" value="{upload.TN_UPLOAD_MAXWIDTH}" /></td>
+  </tr>
+  <tr>
+    <td><strong>{upload.L_CONF_TN_MAXHEIGHT}&nbsp;:</strong><br /><span class="small">{upload.L_CONF_TN_MAXHEIGHT_INFO}</span></td>
+	<td class="row1"><input type="text" size="4" maxlength="4" name="upload_maxheight_thumbnail" value="{upload.TN_UPLOAD_MAXHEIGHT}" /></td>
+  </tr>
+<!-- END upload -->
+<!-- BEGIN session -->
+  <tr class="admin">
+    <th colspan="2">{session.L_CONF_TITLE}</th>
+  </tr>
+  <tr>
+    <td colspan="2">&nbsp;</td>
+  </tr>
+    <tr>
+    <td width="70%"><strong>{session.L_CONF_AUTHORIZE_REMEMBERING}&nbsp;:</strong><br /><span class="small">{session.L_CONF_AUTHORIZE_REMEMBERING_INFO}</span></td>
+        <td class="row1"><input type="radio" class="radio" name="authorize_remembering" value="true" {session.AUTHORIZE_REMEMBERING_YES} />{L_YES}&nbsp;&nbsp;
+        <input type="radio" class="radio" name="authorize_remembering" value="false" {session.AUTHORIZE_REMEMBERING_NO} />{L_NO}</td>
+  </tr>
+<!-- END session -->
+<!-- BEGIN metadata -->
+  <tr class="admin">
+    <th colspan="2">{metadata.L_CONF_TITLE}</th>
+  </tr>
+  <tr>
+    <td colspan="2">&nbsp;</td>
+  </tr>
+  <tr>
+    <td width="70%">
+      <strong>{metadata.L_CONF_EXIF}&nbsp;:</strong>
+      <br /><span class="small">{metadata.L_CONF_EXIF_INFO}</span>
+    </td>
+    <td class="row1">
+      <input type="radio" class="radio" name="use_exif" value="true" {metadata.USE_EXIF_YES} />{L_YES}&nbsp;&nbsp;
+      <input type="radio" class="radio" name="use_exif" value="false" {metadata.USE_EXIF_NO} />{L_NO}
+    </td>
+  </tr>
+  <tr>
+    <td>
+      <strong>{metadata.L_CONF_IPTC}&nbsp;:</strong>
+      <br /><span class="small">{metadata.L_CONF_IPTC_INFO}</span>
+    </td>
+    <td class="row1">
+      <input type="radio" class="radio" name="use_iptc" value="true" {metadata.USE_IPTC_YES} />{L_YES}&nbsp;&nbsp;
+      <input type="radio" class="radio" name="use_iptc" value="false" {metadata.USE_IPTC_NO} />{L_NO}
+    </td>
+  </tr>
+  <tr>
+    <td>
+      <strong>{metadata.L_CONF_SHOW_EXIF}&nbsp;:</strong>
+      <br /><span class="small">{metadata.L_CONF_SHOW_EXIF_INFO}</span>
+    </td>
+    <td class="row1">
+      <input type="radio" class="radio" name="show_exif" value="true" {metadata.SHOW_EXIF_YES} />{L_YES}&nbsp;&nbsp;
+      <input type="radio" class="radio" name="show_exif" value="false" {metadata.SHOW_EXIF_NO} />{L_NO}
+    </td>
+  </tr>
+  <tr>
+    <td>
+      <strong>{metadata.L_CONF_SHOW_IPTC}&nbsp;:</strong>
+      <br /><span class="small">{metadata.L_CONF_SHOW_IPTC_INFO}</span>
+    </td>
+    <td class="row1">
+      <input type="radio" class="radio" name="show_iptc" value="true" {metadata.SHOW_IPTC_YES} />{L_YES}&nbsp;&nbsp;
+      <input type="radio" class="radio" name="show_iptc" value="false" {metadata.SHOW_IPTC_NO} />{L_NO}
+    </td>
+  </tr>
+<!-- END metadata -->
+    <tr>
+      <td colspan="2" align="center">
+        <input type="submit" name="submit" class="bouton" value="{L_SUBMIT}">
+	<input type="reset" name="reset" class="bouton" value="{L_RESET}">
+      </td>
+    </tr>
+  </table>
+</form>
Index: /branches/1.4/template/default/admin/group_list.tpl
===================================================================
--- /branches/1.4/template/default/admin/group_list.tpl	(revision 3249)
+++ /branches/1.4/template/default/admin/group_list.tpl	(revision 3249)
@@ -0,0 +1,52 @@
+<!-- BEGIN errors -->
+<div class="errors">
+<ul>
+  <!-- BEGIN error -->
+  <li>{errors.error.ERROR}</li>
+  <!-- END error -->
+</ul>
+</div>
+<!-- END errors -->
+<form method="post" name="post" action="{S_GROUP_ACTION}">
+<div class="admin">{L_GROUP_SELECT}</div>
+<!-- BEGIN select_box -->
+{S_GROUP_SELECT}&nbsp;&nbsp;<input type="submit" name="edit" value="{L_LOOK_UP}" class="bouton" />
+<input type="submit" name="delete" value="{L_GROUP_DELETE}" class="bouton" />
+<div style="vertical-align:middle;">
+<input type="checkbox" name="confirm_delete" value="1">{L_GROUP_CONFIRM}
+</div>
+<!-- END select_box -->
+<input type="text" name="newgroup">
+<input type="submit" class="bouton" name="new" value="{L_CREATE_NEW_GROUP}" />
+<br />
+<br />
+<!-- BEGIN edit_group -->
+<div class="admin">{L_GROUP_EDIT} [{edit_group.GROUP_NAME}]</div>
+<table class="table2" width="60%" style="margin-left:20%;">
+<tr class="throw">
+    <th width="25%">{L_USER_NAME}</th>
+	  <th width="25%">{L_USER_EMAIL}</th>
+    <th width="10%">{L_USER_SELECT}</th>
+</tr>
+<!-- BEGIN user -->
+  <tr class="{edit_group.user.T_CLASS}">
+    <td>{edit_group.user.NAME}</td>
+    <td>{edit_group.user.EMAIL}</td>
+	  <td align="center"><input name="members[]" type="checkbox" value="{edit_group.user.ID}"></td>
+  </tr>
+<!-- END user -->
+<tr>
+  <td colspan="3" align="right" valign="middle">
+    <input type="submit" name="deny_user" value="{L_DENY_SELECTED}" class="bouton" />
+  </td>
+</tr>
+</table>
+<div align="left" style="margin-left:20%;">
+<input type="text" name="username" maxlength="50" size="20" />
+<input type="submit" name="add" value="{L_ADD_MEMBER}" class="bouton" />
+<input name="edit_group_id" type="hidden" value="{edit_group.GROUP_ID}">
+<input type="submit" name="usersubmit" value="{L_FIND_USERNAME}" class="bouton" onClick="window.open('{U_SEARCH_USER}', '_phpbbsearch', 'HEIGHT=250,resizable=yes,WIDTH=400');return false;" />
+</div>
+<br />
+<!-- END edit_group -->
+</form>
Index: /branches/1.4/template/default/admin/group_perm.tpl
===================================================================
--- /branches/1.4/template/default/admin/group_perm.tpl	(revision 3249)
+++ /branches/1.4/template/default/admin/group_perm.tpl	(revision 3249)
@@ -0,0 +1,7 @@
+<!-- BEGIN select_box -->
+<form method="post" name="post" action="{S_GROUP_ACTION}">
+  <div class="admin">{L_GROUP_SELECT}</div>
+  {S_GROUP_SELECT}&nbsp;&nbsp;
+  <input type="submit" name="edit" value="{L_LOOK_UP}" class="bouton" />
+</form>
+<!-- END select_box -->
Index: /branches/1.4/template/default/admin/help.tpl
===================================================================
--- /branches/1.4/template/default/admin/help.tpl	(revision 3249)
+++ /branches/1.4/template/default/admin/help.tpl	(revision 3249)
@@ -0,0 +1,26 @@
+<table style="width:100%;">
+  <!-- BEGIN cat -->
+  <tr class="admin">
+    <th >{cat.NAME}</th>
+  </tr>
+  <tr>
+    <td>&nbsp;</td>
+  </tr>
+  <tr>
+    <td>
+      <!-- BEGIN illustration -->
+      <div style="text-align:center;margin:auto;margin-bottom:10px;"><img src="{cat.illustration.SRC_IMG}" style="border:1px solid black;" alt=""/></div>
+      {cat.illustration.CAPTION}
+      <!-- END illustration -->
+      <ul style="text-align:left; margin-right:10px;">
+        <!-- BEGIN item -->
+        <li style="margin-bottom:5px;">{cat.item.CONTENT}</li>
+        <!-- END item -->
+      </ul>
+    </td>
+  </tr>
+  <tr>
+    <td>&nbsp;</td>
+  </tr>
+  <!-- END cat -->
+</table>
Index: /branches/1.4/template/default/admin/infos_images.tpl
===================================================================
--- /branches/1.4/template/default/admin/infos_images.tpl	(revision 3249)
+++ /branches/1.4/template/default/admin/infos_images.tpl	(revision 3249)
@@ -0,0 +1,96 @@
+<!-- BEGIN errors -->
+<div class="errors">
+<ul>
+  <!-- BEGIN error -->
+  <li>{errors.error.ERROR}</li>
+  <!-- END error -->
+</ul>
+</div>
+<!-- END errors -->
+
+<form action="{F_ACTION}" method="POST">
+<div class="admin">{L_INFOS_TITLE} &quot;{CATEGORY}&quot;</div>
+  <table width="100%">
+    <tr>
+      <td><div style="margin-left:50px;">{L_AUTHOR}</div></td>
+      <td style="row1">
+        <input type="text" name="author_cat" value="" maxlength="255" />
+      </td>
+      <td style="text-align:left;">
+        <input type="checkbox" name="use_common_author" value="1" />
+        {L_INFOS_OVERALL_USE}
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <div style="margin-left:50px;">{L_INFOS_CREATION_DATE} [DD/MM/YYYY]</div>
+      </td>
+      <td style="row1">
+        <input type="text" name="date_creation_cat" value="" size="12" maxlength="10"/>
+      </td>
+      <td style="text-align:left;">
+        <input type="checkbox" name="use_common_date_creation" value="1" />
+        {L_INFOS_OVERALL_USE}
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <div style="margin-left:50px;">{L_KEYWORD} {L_KEYWORD_SEPARATION}</div>
+      </td>
+      <td style="row1">
+        <input type="text" name="keywords_cat" value="" maxlength="255" />
+      </td>
+      <td style="text-align:left;">
+        <input type="radio" name="common_keywords" value="add" />
+        {L_INFOS_ADDTOALL}
+        <input type="radio" name="common_keywords" value="remove" />
+        {L_INFOS_REMOVEFROMALL}
+      </td>
+    </tr>
+  </table>
+  <br />
+  <div class="admin">{L_INFOS_DETAIL}</div>
+  <div class="navigationBar">{NAV_BAR}</div>
+  <table width="100%">
+    <tr>
+      <td style="width:0px;">&nbsp;</td>
+      <td class="row2" style="text-align:center;">{L_THUMBNAIL}</td>
+      <td class="row2" style="text-align:center;">{L_INFOS_IMG}</td>
+      <td class="row2" style="text-align:center;">{L_AUTHOR}</td>
+      <td class="row2" style="text-align:center;">{L_INFOS_COMMENT}</td>
+      <td class="row2" style="text-align:center;">{L_INFOS_CREATION_DATE}</td>
+      <td class="row2" style="text-align:center;">{L_KEYWORD}</td>
+    </tr>
+    <!-- BEGIN picture -->
+    <tr>
+      <td style="width:0px;">
+        <div style="margin-left:2px;margin-right:2px;">
+          <input type="checkbox" name="check-{picture.ID_IMG}" value="1" />
+        </div>
+      </td>
+      <td style="text-align:center;"><a name="{picture.DEFAULTNAME_IMG}" href="{picture.URL_IMG}"><img src="{picture.TN_URL_IMG}" alt="" class="miniature" title="{picture.FILENAME_IMG}" /></a></td>
+      <td style="text-align:center;">{picture.DEFAULTNAME_IMG}<br /><input type="text" name="name-{picture.ID_IMG}" value="{picture.NAME_IMG}" maxlength="255"/></td>
+      <td style="text-align:center;"><input type="text" name="author-{picture.ID_IMG}" value="{picture.AUTHOR_IMG}" maxlength="255" size="12" /></td>
+      <td style="text-align:center;"><textarea name="comment-{picture.ID_IMG}" rows="5" cols="30" style="overflow:auto">{picture.COMMENT_IMG}</textarea></td>
+      <td style="text-align:center;"><input type="text" name="date_creation-{picture.ID_IMG}" value="{picture.DATE_IMG}" maxlength="10" size="10" /></td>
+      <td style="text-align:center;"><input type="text" name="keywords-{picture.ID_IMG}" value="{picture.KEYWORDS_IMG}" length="255" /></td>
+    </tr>
+    <!-- END picture -->
+    <tr>
+      <td colspan="7">
+        <img src="./template/default/admin/images/arrow_select.gif" alt="&uarr;" />
+        {L_INFOS_ASSOCIATE}
+        <select style="width:400px" name="associate" size="1">
+          <!-- BEGIN associate_option -->
+          <option {associate_option.SELECTED} value="{associate_option.VALUE}">{associate_option.OPTION}</option>
+          <!-- END category_option -->
+        </select>
+      </td>
+    </tr>
+    <tr>
+      <td colspan="7" style="text-align:center;">
+        <input type="submit" value="{L_SUBMIT}" name="submit" class="bouton" />
+      </td>
+    </tr>
+  </table>
+</form>
Index: /branches/1.4/template/default/admin/picture_modify.tpl
===================================================================
--- /branches/1.4/template/default/admin/picture_modify.tpl	(revision 3249)
+++ /branches/1.4/template/default/admin/picture_modify.tpl	(revision 3249)
@@ -0,0 +1,144 @@
+<!-- BEGIN errors -->
+<div class="errors">
+<ul>
+  <!-- BEGIN error -->
+  <li>{errors.error.ERROR}</li>
+  <!-- END error -->
+</ul>
+</div>
+<!-- END errors -->
+<div class="admin">{TITLE_IMG}</div>
+<form action="{F_ACTION}" method="POST">
+  <table style="width:100%;">
+    <tr>
+      <td colspan="2" align="center"><a href="{URL_IMG}" class="thumbnail"><img src="{TN_URL_IMG}" alt="" class="miniature" /></a></td>
+    </tr>
+    <tr>
+      <td style="width:50%;"><strong>{L_UPLOAD_NAME}</strong></td>
+      <td class="row1"><input type="text" name="name" value="{NAME_IMG}" /> [ {L_DEFAULT} : {DEFAULT_NAME_IMG} ]</td>
+    </tr>
+    <tr>
+      <td style="width:50%;"><strong>{L_FILE}</strong></td>
+      <td class="row1">{FILE_IMG}</td>
+    </tr>
+    <tr>
+      <td style="width:50%;"><strong>{L_SIZE}</strong></td>
+      <td class="row1">{SIZE_IMG}</td>
+    </tr>
+    <tr>
+      <td style="width:50%;"><strong>{L_FILESIZE}</strong></td>
+      <td class="row1">{FILESIZE_IMG}</td>
+    </tr>
+    <tr>
+      <td style="width:50%;"><strong>{L_REGISTRATION_DATE}</strong></td>
+      <td class="row1">{REGISTRATION_DATE_IMG}</td>
+    </tr>
+    <tr>
+      <td style="width:50%;"><strong>{L_PATH}</strong></td>
+      <td class="row1">{PATH_IMG}</td>
+    </tr>
+    <tr>
+      <td style="width:50%;"><strong>{L_STORAGE_CATEGORY}</strong></td>
+      <td class="row1">{STORAGE_CATEGORY_IMG}</td>
+    </tr>
+    <tr>
+      <td style="width:50%;"><strong>{L_AUTHOR}</strong></td>
+      <td class="row1"><input type="text" name="author" value="{AUTHOR_IMG}" /></td>
+    </tr>
+    <tr>
+      <td style="width:50%;"><strong>{L_CREATION_DATE}</strong></td>
+      <td class="row1"><input type="text" name="date_creation" value="{CREATION_DATE_IMG}" /></td>
+    </tr>
+    <tr>
+      <td style="width:50%;"><strong>{L_KEYWORDS}</strong></td>
+      <td class="row1"><input type="text" name="keywords" value="{KEYWORDS_IMG}" size="50" /></td>
+    </tr>
+    <tr>
+      <td style="width:50%;"><strong>{L_COMMENT}</strong></td>
+      <td class="row1"><textarea name="comment" rows="5" cols="50" style="overflow:auto">{COMMENT_IMG}</textarea></td>
+    </tr>
+    <tr>
+      <td colspan="2"><div style="margin-bottom:0px">&nbsp;</div></td>
+    </tr>
+    <tr>
+      <td colspan="2" align="center">
+        <input type="submit" name="submit" value="{L_SUBMIT}" class="bouton" />
+        <input type="reset" name="reset" value="{L_RESET}" class="bouton" />
+      </td>
+    </tr>
+  </table>
+</form>
+
+<form name="form1" method="post" action="{F_ACTION}" style="text-align:center;width:800px;">
+
+  <div style="clear:both;"></div>
+
+  <div style="height:auto;">
+
+    <div style="float:left;padding:10px;width:300px;">
+      <span class="titreMenu">{L_CAT_ASSOCIATED}</span><br />
+      <select style="height:auto;width:280px" name="cat_associated[]" multiple="multiple" size="10">
+        <!-- BEGIN associated_option -->
+        <option class="{associated_option.CLASS}" {associated_option.SELECTED} value="{associated_option.VALUE}">{associated_option.OPTION}</option>
+        <!-- END associated_option -->
+      </select>
+    </div>
+
+    <div style="float:left;padding-top:80px;padding-bottom:80px;text-align:center;width:160px;" >
+      <input type="submit" value="&laquo;" name="associate" style="font-size:15px;" class="bouton" /><br/>
+      <input type="submit" value="&raquo;" name="dissociate" style="font-size:15px;" class="bouton" />
+    </div>
+
+    <div style="float:right;padding:10px;width:300px;">
+      <span class="titreMenu">{L_CAT_DISSOCIATED}</span><br />
+      <select style="width:280px" name="cat_dissociated[]" multiple="multiple" size="10">
+        <!-- BEGIN dissociated_option -->
+        <option class="{dissociated_option.CLASS}" {dissociated_option.SELECTED} value="{dissociated_option.VALUE}">{dissociated_option.OPTION}</option>
+        <!-- END dissociated_option -->
+      </select>
+    </div>
+
+  </div>
+
+  <div style="clear:both;"></div>
+
+  <input type="reset" name="reset" value="{L_RESET}" class="bouton" />
+
+</form>
+
+<form name="form2" method="post" action="{F_ACTION}" style="text-align:center;width:800px;">
+
+  <div style="clear:both;"></div>
+
+  <div style="height:auto;">
+
+    <div style="float:left;padding:10px;width:300px;">
+      <span class="titreMenu">{L_REPRESENTS}</span><br />
+      <select style="height:auto;width:280px" name="cat_elected[]" multiple="multiple" size="10">
+        <!-- BEGIN elected_option -->
+        <option class="{elected_option.CLASS}" {elected_option.SELECTED} value="{elected_option.VALUE}">{elected_option.OPTION}</option>
+        <!-- END elected_option -->
+      </select>
+    </div>
+
+    <div style="float:left;padding-top:80px;padding-bottom:80px;text-align:center;width:160px;" >
+      <input type="submit" value="&laquo;" name="elect" style="font-size:15px;" class="bouton" /><br/>
+      <input type="submit" value="&raquo;" name="dismiss" style="font-size:15px;" class="bouton" />
+    </div>
+
+    <div style="float:right;padding:10px;width:300px;">
+      <span class="titreMenu">{L_DOESNT_REPRESENT}</span><br />
+      <select style="width:280px" name="cat_dismissed[]" multiple="multiple" size="10">
+        <!-- BEGIN dismissed_option -->
+        <option class="{dismissed_option.CLASS}" {dismissed_option.SELECTED} value="{dismissed_option.VALUE}">{dismissed_option.OPTION}</option>
+        <!-- END dismissed_option -->
+      </select>
+    </div>
+
+  </div>
+
+  <div style="clear:both;"></div>
+
+  <input type="reset" name="reset" value="{L_RESET}" class="bouton" />
+
+</form>
Index: /branches/1.4/template/default/admin/remote_site.tpl
===================================================================
--- /branches/1.4/template/default/admin/remote_site.tpl	(revision 3249)
+++ /branches/1.4/template/default/admin/remote_site.tpl	(revision 3249)
@@ -0,0 +1,71 @@
+{REMOTE_SITE_TITLE}
+
+<!-- BEGIN errors -->
+<div class="errors">
+  <ul>
+    <!-- BEGIN error -->
+    <li>{errors.error.ERROR}</li>
+    <!-- END error -->
+  </ul>
+</div>
+<!-- END errors -->
+
+<!-- BEGIN confirmation -->
+<div class="info">{confirmation.CONTENT}</div>
+<!-- END confirmation -->
+
+<!-- BEGIN update -->
+<div class="admin">{L_RESULT_UPDATE}</div>
+<ul style="text-align:left;">
+  <li class="update_summary_new">{update.NB_NEW_CATEGORIES} {L_NB_NEW_CATEGORIES}</li>
+  <li class="update_summary_new">{update.NB_NEW_ELEMENTS} {L_NB_NEW_ELEMENTS}</li>
+  <li class="update_summary_del">{update.NB_DEL_CATEGORIES} {L_NB_DEL_CATEGORIES}</li>
+  <li class="update_summary_del">{update.NB_DEL_ELEMENTS} {L_NB_DEL_ELEMENTS}</li>
+</ul>
+<!-- BEGIN removes -->
+{L_REMOTE_SITE_REMOVED_TITLE}
+<ul style="text-align:left;">
+  <!-- BEGIN remote_remove -->
+  <li>{update.removes.remote_remove.NAME} {L_REMOTE_SITE_REMOVED}</li>
+  <!-- END remote_remove -->
+</ul>
+<!-- END removes -->
+<!-- END update -->
+
+<!-- BEGIN remote_output -->
+<div class="remoteOutput">
+  <ul>
+    <!-- BEGIN remote_line -->
+    <li class="{remote_output.remote_line.CLASS}">{remote_output.remote_line.CONTENT}</li>
+    <!-- END remote_line -->
+  </ul>
+</div>
+<!-- END remote_output -->
+
+<!-- BEGIN local -->
+<div class="remoteLocal">
+  {L_REMOTE_SITE_LOCAL_FOUND} {local.URL}
+  <!-- BEGIN new_site -->
+  {L_REMOTE_SITE_LOCAL_NEW}
+  <!-- END new_site -->
+  [<a href="{local.U_UPDATE}">{L_REMOTE_SITE_LOCAL_UPDATE}</a>]
+</div>
+<!-- END local -->
+
+<form action="{F_ACTION}" method="post">
+  {L_REMOTE_SITE_CREATE} 
+  <input type="text" name="galleries_url" value="{F_GALLERIES_URL}" />
+  <input class="bouton" type="submit" name="submit" value="{L_SUBMIT}" />
+</form>
+
+<table>
+  <!-- BEGIN site -->
+  <tr>
+    <td>{site.NAME}</td>
+    <td>[<a href="{site.U_GENERATE}" title="{L_REMOTE_SITE_GENERATE_HINT}">{L_REMOTE_SITE_GENERATE}</a>]</td>
+    <td>[<a href="{site.U_UPDATE}" title="{L_REMOTE_SITE_UPDATE_HINT}">{L_REMOTE_SITE_UPDATE}</a>]</td>
+    <td>[<a href="{site.U_CLEAN}" title="{L_REMOTE_SITE_CLEAN_HINT}">{L_REMOTE_SITE_CLEAN}</a>]</td>
+    <td>[<a href="{site.U_DELETE}" title="{L_REMOTE_SITE_DELETE_HINT}">{L_REMOTE_SITE_DELETE}</a>]</td>
+  </tr>
+  <!-- END site -->
+</table>
Index: /branches/1.4/template/default/admin/search_username.tpl
===================================================================
--- /branches/1.4/template/default/admin/search_username.tpl	(revision 3249)
+++ /branches/1.4/template/default/admin/search_username.tpl	(revision 3249)
@@ -0,0 +1,22 @@
+<script language="javascript" type="text/javascript">
+<!--
+function refresh_username(selected_username)
+{
+	opener.document.forms['post'].username.value = selected_username;
+	opener.focus();
+	window.close();
+}
+//-->
+</script>
+<div class="titrePage">{L_SEARCH_USERNAME}</div>
+<form method="post" name="search" action="{F_SEARCH_ACTION}">
+  <input type="text" name="search_username" value="{USERNAME}" class="post" />&nbsp; 
+  <input type="submit" name="search" value="{L_SEARCH}" class="bouton" /><br />
+  <span class="gensmall">{L_SEARCH_EXPLAIN}</span><br />
+  <!-- BEGIN switch_select_name -->
+  <span class="genmed">{L_UPDATE_USERNAME}<br />
+  <select name="username_list">{switch_select_name.F_USERNAME_OPTIONS}</select>&nbsp; 
+  <input type="submit" class="bouton" onClick="refresh_username(this.form.username_list.options[this.form.username_list.selectedIndex].value);return false;" name="use" value="{L_SELECT}" /></span><br />
+  <!-- END switch_select_name -->
+  <br /><a href="javascript:window.close();" class="adminMenu">{L_CLOSE_WINDOW}</a>
+</form>
Index: /branches/1.4/template/default/admin/stats.tpl
===================================================================
--- /branches/1.4/template/default/admin/stats.tpl	(revision 3249)
+++ /branches/1.4/template/default/admin/stats.tpl	(revision 3249)
@@ -0,0 +1,20 @@
+<div class="admin">{L_STAT_TITLE}</div>
+<img class="image" src="{IMG_MONTHLY_REPORT}" alt="{L_STAT_MONTHLY_ALT}" />
+<div class="admin">{L_STAT_MONTH_TITLE}</div>
+<table class="table2" width="60%">
+<tr class="throw">
+    <th>{L_MONTH}</th>
+	<th>{L_PAGES_SEEN}</th>
+    <th>{L_VISITORS}</th>
+    <th>{L_PICTURES}</th>
+</tr>
+<!-- BEGIN month -->
+  <tr class="{month.T_CLASS}">
+    <td>{month.MONTH}</td>
+    <td>{month.PAGES}</td>
+    <td>{month.VISITORS}</td>
+	<td>{month.IMAGES}</td>
+  </tr>
+<!-- END month -->
+</table>
+<br />
Index: /branches/1.4/template/default/admin/thumbnail.tpl
===================================================================
--- /branches/1.4/template/default/admin/thumbnail.tpl	(revision 3249)
+++ /branches/1.4/template/default/admin/thumbnail.tpl	(revision 3249)
@@ -0,0 +1,139 @@
+<!-- BEGIN errors -->
+<div class="errors">
+<ul>
+  <!-- BEGIN error -->
+  <li>{errors.error.ERROR}</li>
+  <!-- END error -->
+</ul>
+</div>
+<!-- END errors -->
+
+<!-- BEGIN results -->
+<div class="admin">{L_RESULTS}</div>
+<table style="width:100%;">
+  <tr class="throw">
+    <th>{L_PATH}</td>
+    <th>{L_THUMBNAIL}</td>
+    <th>{L_GENERATED}</th>
+    <th>{L_FILESIZE}</td>
+    <th>{L_WIDTH}</td>
+    <th>{L_HEIGHT}</td>
+  </tr>
+  <!-- BEGIN picture -->
+  <tr class="{results.picture.T_CLASS}">
+    <td>{results.picture.PATH}</td>
+    <td><img src="{results.picture.TN_FILE_IMG}" /></td>
+    <td style="text-align:right;" class="{results.picture.T_CLASS}">{results.picture.GEN_TIME}</td>
+    <td style="text-align:right;">{results.picture.TN_FILESIZE_IMG}</td>
+    <td style="text-align:right;">{results.picture.TN_WIDTH_IMG}</td>
+    <td style="text-align:right;">{results.picture.TN_HEIGHT_IMG}</td>
+  </tr>
+  <!-- END picture -->
+</table>
+
+<table class="table2">
+  <tr class="throw">
+    <th colspan="2">{L_TN_STATS}</td>
+  </tr>
+  <tr>
+    <td>{L_TN_NB_STATS}</td>
+    <td style="text-align:center;">{results.TN_NB}</td>
+  </tr>
+  <tr>
+    <td>{L_TN_TOTAL}</td>
+    <td style="text-align:right;">{results.TN_TOTAL}</td>
+  </tr>
+  <tr>
+    <td>{L_TN_MAX}</td>
+    <td style="text-align:right;" class="worst_gen_time">{results.TN_MAX}</td>
+  </tr>
+  <tr>
+    <td>{L_TN_MIN}</td>
+    <td style="text-align:right;" class="best_gen_time">{results.TN_MIN}</td>
+  </tr>
+  <tr>
+    <td>{L_TN_AVERAGE}</td>
+    <td style="text-align:right;">{results.TN_AVERAGE}</td>
+  </tr>
+</table>
+<br />
+<!-- END results -->
+
+<!-- BEGIN params -->
+<form method="post" action="{params.F_ACTION}">
+  <table style="width:100%;">
+    <tr>
+      <th class="admin" colspan="3">{L_PARAMS}</th>
+    </tr>
+    <tr><td colspan="3">&nbsp;</td></tr>
+    <tr>
+      <td><div class="key">{L_GD}</div></td>
+      <td class="choice">
+        <input type="radio" name="gd" value="2" {params.GD2_CHECKED} />2.x
+        <input type="radio" name="gd" value="1" {params.GD1_CHECKED} />1.x
+      </td>
+      <td style="width:50%;" class="row2">{L_GD_INFO}</td>
+    </tr>
+    <tr>
+      <td><div class="key">{L_WIDTH}</div></td>
+      <td class="choice">
+        <input type="text" name="width" value="{params.WIDTH_TN}"/>
+      </td>
+      <td>{L_WIDTH_INFO}</td>
+    </tr>
+    <tr>
+      <td><div class="key">{L_HEIGHT}</div></td>
+      <td class="choice">
+        <input type="text" name="height" value="{params.HEIGHT_TN}"/>
+      </td>
+      <td>{L_HEIGHT_INFO}</td>
+    </tr>
+    <tr>
+      <td><div class="key">{L_CREATE}</div></td>
+      <td class="choice">
+        <input type="radio" name="n" value="5"   {params.n_5_CHECKED} /> 5
+        <input type="radio" name="n" value="10"  {params.n_10_CHECKED} /> 10
+        <input type="radio" name="n" value="20"  {params.n_20_CHECKED} /> 20
+        <input type="radio" name="n" value="all" {params.n_all_CHECKED} /> {L_ALL}
+      </td>
+      <td>{L_CREATE_INFO}</td>
+    </tr>
+    <tr>
+      <td><div class="key">{L_FORMAT}</div></td>
+      <td class="choice"><span style="font-weight:bold;">jpeg</span></td>
+      <td>{L_FORMAT_INFO}</td>
+    </tr>
+    <tr>
+      <td colspan="3" style="text-align:center;">
+        <input type="submit" name="submit" class="bouton" value="{L_SUBMIT}"/>
+      </td>
+    </tr>
+  </table>
+</form>
+<!-- END params -->
+
+<!-- BEGIN warning -->
+<div style="text-align:center;font-weight:bold;margin:10px;"> [ {L_UNLINK} ]</div>
+<!-- END warning -->
+
+<!-- BEGIN remainings -->
+<div class="admin">{remainings.TOTAL_IMG} {L_REMAINING}</div>
+<table style="width:100%;">
+  <tr class="throw">
+    <th>&nbsp;</td>
+    <th style="width:60%;">{L_PATH}</td>
+    <th>{L_FILESIZE}</td>
+    <th>{L_WIDTH}</td>
+    <th>{L_HEIGHT}</td>
+  </tr>
+  <!-- BEGIN remaining -->
+  <tr class="{remainings.remaining.T_CLASS}">
+    <td>{remainings.remaining.NB_IMG}</td>
+    <td><div style="margin-left:10px;">{remainings.remaining.PATH}</div></td>
+    <td><div style="margin-left:10px;">{remainings.remaining.FILESIZE_IMG}</div></td>
+    <td><div style="margin-left:10px;">{remainings.remaining.WIDTH_IMG}</div></td>
+    <td><div style="margin-left:10px;">{remainings.remaining.HEIGHT_IMG}</div></td>
+  </tr>
+  <!-- END remaining -->
+</table>
+<!-- END remainings -->
Index: /branches/1.4/template/default/admin/update.tpl
===================================================================
--- /branches/1.4/template/default/admin/update.tpl	(revision 3249)
+++ /branches/1.4/template/default/admin/update.tpl	(revision 3249)
@@ -0,0 +1,76 @@
+<!-- BEGIN update -->
+<div class="admin">{L_RESULT_UPDATE}</div>
+<ul style="text-align:left;">
+  <li class="update_summary_new">{update.NB_NEW_CATEGORIES} {L_NB_NEW_CATEGORIES}</li>
+  <li class="update_summary_new">{update.NB_NEW_ELEMENTS} {L_NB_NEW_ELEMENTS}</li>
+  <li class="update_summary_del">{update.NB_DEL_CATEGORIES} {L_NB_DEL_CATEGORIES}</li>
+  <li class="update_summary_del">{update.NB_DEL_ELEMENTS} {L_NB_DEL_ELEMENTS}</li>
+  <li class="update_summary_err">{update.NB_ERRORS} {L_UPDATE_NB_ERRORS}</li>
+</ul>
+<!-- BEGIN errors -->
+<div class="admin">{L_UPDATE_ERROR_LIST_TITLE}</div>
+<ul style="text-align:left;">
+  <!-- BEGIN error -->
+  <li>[{update.errors.error.ELEMENT}] {update.errors.error.LABEL}</li>
+  <!-- END error -->
+</ul>
+<div class="admin">{L_UPDATE_ERRORS_CAPTION}</div>
+<ul style="text-align:left;">
+  <li><strong>PWG-UPDATE-1</strong> : {L_UPDATE_WRONG_DIRNAME_INFO}</li>
+  <li><strong>PWG-UPDATE-2</strong> : {L_UPDATE_MISSING_TN_INFO} {{PICTURE_EXT_LIST}}</li>
+</ul>
+<!-- END errors -->
+<!-- BEGIN infos -->
+<div class="admin">{L_UPDATE_INFOS_TITLE}</div>
+<ul style="text-align:left;">
+  <!-- BEGIN info -->
+  <li>[{update.infos.info.ELEMENT}] {update.infos.info.LABEL}</li>
+  <!-- END info -->
+</ul>
+<!-- END infos -->
+<!-- END update -->
+
+<!-- BEGIN metadata_result -->
+<div class="admin">{L_RESULT_METADATA}</div>
+<ul style="text-align:left;">
+  <li>{metadata_result.NB_ELEMENTS} {L_ELEMENTS_METADATA_SYNC}</li>
+  <li>{L_USED_METADATA} : {METADATA_LIST}</li>
+</ul>
+<!-- END metadata_result -->
+
+<!-- BEGIN introduction -->
+<div class="admin">{L_UPDATE_TITLE}</div>
+<form action="{F_ACTION}" method="post">
+  <ul class="menu">
+    <li>
+      {L_UPDATE_SYNC_FILES}
+      <ul class="menu">
+        <li><input type="radio" name="sync" value="dirs" {SYNC_DIRS_CHECKED} /> {L_UPDATE_SYNC_DIRS}</li>
+        <li><input type="radio" name="sync" value="files" {SYNC_ALL_CHECKED} /> {L_UPDATE_SYNC_ALL}</li>
+        <li><input type="checkbox" name="display_info" value="1" {DISPLAY_INFO_CHECKED} /> {L_UPDATE_DISPLAY_INFO}</li>
+        <li><input type="checkbox" name="simulate" value="1" checked="checked" /> {L_UPDATE_SIMULATE}</li>
+      </ul>
+    </li>
+    <li>
+      {L_UPDATE_SYNC_METADATA}. {L_USED_METADATA} : {METADATA_LIST}.
+      <ul class="menu">
+        <li><input type="radio" name="sync" value="metadata_new" /> {L_UPDATE_SYNC_METADATA_NEW}</li>
+        <li><input type="radio" name="sync" value="metadata_all" /> {L_UPDATE_SYNC_METADATA_ALL}</li>
+      </ul>
+    </li>
+    <li>
+      {L_UPDATE_CATS_SUBSET}<br />
+      <select style="width:500px" name="cat" size="10">
+        <!-- BEGIN category_option -->
+        <option {introduction.category_option.SELECTED} value="{introduction.category_option.VALUE}">{introduction.category_option.OPTION}</option>
+        <!-- END category_option -->
+      </select>
+      <input type="checkbox" name="subcats-included" value="1" {SUBCATS_INCLUDED_CHECKED} /> {L_SEARCH_SUBCATS_INCLUDED}
+    </li>
+  </ul>
+  <p style="text-align:center;">
+    <input type="submit" value="{L_SUBMIT}" name="submit" class="bouton" />
+    <input type="reset"  value="{L_RESET}"  name="reset"  class="bouton" />
+  </p>
+</form>
+<!-- END introduction -->
Index: /branches/1.4/template/default/admin/user_perm.tpl
===================================================================
--- /branches/1.4/template/default/admin/user_perm.tpl	(revision 3249)
+++ /branches/1.4/template/default/admin/user_perm.tpl	(revision 3249)
@@ -0,0 +1,6 @@
+<div class="admin">{L_SELECT_USERNAME}</div>
+<form method="post" name="post" action="{F_SEARCH_USER_ACTION}">
+  <input type="text" name="username" maxlength="50" size="20" />
+  <input type="submit" name="submituser" value="{L_LOOKUP_USER}" class="bouton" /> 
+  <input type="submit" name="usersubmit" value="{L_FIND_USERNAME}" class="bouton" onClick="window.open('{U_SEARCH_USER}', '_phpwgsearch', 'HEIGHT=250,resizable=yes,WIDTH=400');return false;" />
+</form>
Index: /branches/1.4/template/default/admin/waiting.tpl
===================================================================
--- /branches/1.4/template/default/admin/waiting.tpl	(revision 3249)
+++ /branches/1.4/template/default/admin/waiting.tpl	(revision 3249)
@@ -0,0 +1,42 @@
+<form action="{F_ACTION}" method="post">
+  <!-- BEGIN confirmation -->
+  <div class="info">{L_WAITING_CONFIRMATION}</div>
+  <!-- END confirmation -->
+  <table style="width:100%;" >
+    <tr class="throw">
+      <th style="width:20%;">{L_CATEGORY}</th>
+      <th style="width:20%;">{L_DATE}</th>
+      <th style="width:20%;">{L_FILE}</th>
+      <th style="width:20%;">{L_THUMBNAIL}</th>
+      <th style="width:20%;">{L_AUTHOR}</th>
+      <th style="width:1px;">&nbsp;</th>
+    </tr>
+    <!-- BEGIN picture -->
+    <tr>
+      <td class="{picture.WAITING_CLASS}" style="white-space:nowrap;">{picture.CATEGORY_IMG}</td>
+      <td class="{picture.WAITING_CLASS}" style="white-space:nowrap;">{picture.DATE_IMG}</td>
+      <td class="{picture.WAITING_CLASS}" style="white-space:nowrap;">
+        <a target="_blank" href="{picture.PREVIEW_URL_IMG}">{picture.FILE_IMG}</a>
+      </td>
+      <td class="{picture.WAITING_CLASS}" style="white-space:nowrap;">
+        <!-- BEGIN thumbnail -->
+        <a target="_blank" href="{picture.thumbnail.PREVIEW_URL_TN_IMG}">{picture.thumbnail.FILE_TN_IMG}</a>
+        <!-- END thumbnail -->
+      </td>
+      <td class="{picture.WAITING_CLASS}" style="white-space:nowrap;">
+        <a href="mailto:{picture.UPLOAD_EMAIL}">{picture.UPLOAD_USERNAME}</a>
+      </td>
+      <td class="{picture.WAITING_CLASS}" style="white-space:nowrap;">
+        <input type="radio" name="validate-{picture.ID_IMG}" value="true" />{L_SUBMIT}
+        <input type="radio" name="validate-{picture.ID_IMG}" value="false" />{L_DELETE}
+      </td>
+    </tr>
+    <!-- END picture -->
+    <tr>
+      <td colspan="6" align="center">
+	  <input type="submit" name="submit" value="{L_SUBMIT}" class="bouton" />
+          <input type="reset" name="reset" value="{L_RESET}" class="bouton" />
+	  </td>
+    </tr>
+  </table>
+</form>
Index: /branches/1.4/template/default/category.tpl
===================================================================
--- /branches/1.4/template/default/category.tpl	(revision 3249)
+++ /branches/1.4/template/default/category.tpl	(revision 3249)
@@ -0,0 +1,107 @@
+<div style="padding:3px;"><img src="template/default/images/logo.jpg"></div>
+<table style="width:100%;">
+  <tr>
+    <td valign="top" style="padding:0px 10px 0px 10px;width:1%;">
+      <div class="table1">
+        <div class="titreMenu">
+          <a href="{U_HOME}">{L_CATEGORIES}</a>
+        </div>
+        <div class="menu">
+            {MENU_CATEGORIES_CONTENT}
+        <div class="totalImages">[&nbsp;{NB_PICTURE}&nbsp;{L_TOTAL}&nbsp;]</div>
+		</div>
+		<div class="titreMenu">{L_SPECIAL_CATEGORIES}</div>
+		<div class="menu">
+		    <ul class="menu">
+                      <!-- BEGIN special_cat -->
+                      <li><a href="{special_cat.URL}" title="{special_cat.TITLE}">{special_cat.NAME}</a></li>
+                      <!-- END special_cat -->
+		    </ul>
+		</div>
+		<div class="titreMenu">{L_SUMMARY}</div>
+		<div class="menu">
+		<ul class="menu">
+		  <!-- BEGIN summary -->
+		  <li><a href="{summary.U_SUMMARY}" title="{summary.TITLE}">{summary.NAME}</a></li>
+		  <!-- END summary -->
+		  <!-- BEGIN upload -->
+		  <li><a href="{upload.U_UPLOAD}">{L_UPLOAD}</a></li>
+		  <!-- END upload -->
+		</ul>
+		</div>
+		<div class="titreMenu">{L_IDENTIFY}</div>
+		 <div class="menu">
+		 <!-- BEGIN login -->
+		<ul class="menu">
+		  <li><a href="{U_REGISTER}">{L_REGISTER}</a></li>
+			<li><a href="{F_IDENTIFY}">{L_LOGIN}</a></li>
+		</ul>
+		<hr />
+		<form method="post" action="{F_IDENTIFY}">
+		<input type="hidden" name="redirect" value="{U_REDIRECT}">
+		{L_USERNAME}<br />
+		<input type="text" name="username" size="15" value="" /><br />
+		{L_PASSWORD}<br />
+		<input type="password" name="password" size="15"><br />
+                <!-- BEGIN remember_me -->
+                <input type="checkbox" name="remember_me" value="1" /> {L_REMEMBER_ME}<br />
+                <!-- END remember_me -->
+		<input type="submit" name="login" value="{L_SUBMIT}" class="bouton" />
+		</form>
+		<!-- END login -->
+		<!-- BEGIN logout -->
+		<p>{L_HELLO}&nbsp;{USERNAME}&nbsp;!</p>
+		<ul class="menu">
+		  <li><a href="{U_LOGOUT}">{L_LOGOUT}</a></li>
+		  <li><a href="{U_PROFILE}" title="{L_PROFILE_HINT}">{L_PROFILE}</a></li>
+		<!-- BEGIN admin -->
+	      <li><a href="{U_ADMIN}" title="{L_ADMIN_HINT}">{L_ADMIN}</a></li>
+		<!-- END admin -->
+		</ul>
+		<!-- END logout -->
+		</div>
+      </div>
+	</td>
+	<td style="padding:0px 10px 0px 10px; width:99%;" valign="top">
+	  <div class="home">
+			<div class="titrePage">{TITLE}</div>
+			<!-- BEGIN calendar -->
+               <div class="navigationBar">{calendar.YEARS_NAV_BAR}</div>
+			  <div class="navigationBar">{calendar.MONTHS_NAV_BAR}</div>
+			<!-- END calendar -->
+			<!-- BEGIN thumbnails -->
+			<table valign="top" align="center" class="thumbnail">
+			  <!-- BEGIN line -->
+			  <tr>
+				<!-- BEGIN thumbnail -->
+				<td class="thumbnail">
+				  <a href="{thumbnails.line.thumbnail.U_IMG_LINK}">
+				  <img src="{thumbnails.line.thumbnail.IMAGE}"
+					   alt="{thumbnails.line.thumbnail.IMAGE_ALT}"
+					   title="{thumbnails.line.thumbnail.IMAGE_TITLE}"
+					   class="thumbLink" />
+				  <br />
+				  <span class="{thumbnails.line.thumbnail.IMAGE_STYLE}">{thumbnails.line.thumbnail.IMAGE_NAME}</span></a>
+				  {thumbnails.line.thumbnail.IMAGE_TS}
+				  <!-- BEGIN nb_comments -->
+				  <br />{thumbnails.line.thumbnail.nb_comments.NB_COMMENTS} {L_COMMENT}
+				  <!-- END nb_comments -->
+				</td>
+				<!-- END thumbnail -->
+			  </tr>
+			  <!-- END line -->
+			</table>
+			<!-- END thumbnails -->
+		<br />
+			<!-- BEGIN cat_infos -->
+			  <!-- BEGIN navigation -->
+			  <div class="navigationBar">{cat_infos.navigation.NAV_BAR}</div>
+			  <!-- END navigation -->
+			  <!-- BEGIN comment -->
+			  <div class="info">{cat_infos.comment.COMMENTS}</div>
+			  <!-- END comment -->
+			<!-- END cat_infos -->
+      </div>
+	</td>
+  </tr>
+</table>
Index: /branches/1.4/template/default/comments.tpl
===================================================================
--- /branches/1.4/template/default/comments.tpl	(revision 3249)
+++ /branches/1.4/template/default/comments.tpl	(revision 3249)
@@ -0,0 +1,57 @@
+<!-- BEGIN title -->
+<div class="titrePage">{L_COMMENT_TITLE}</div>
+<!-- END title -->
+<div class="admin">
+      [
+      <!-- BEGIN last_day_option -->
+      <a class="admin" href="{last_day_option.U_OPTION}" style="{last_day_option.T_STYLE}">{last_day_option.OPTION}</a>{T_SEPARATION}
+      <!-- END last_day_option -->
+      {L_COMMENT_STATS}
+      ]
+	  <!-- BEGIN title -->
+      [ <a class="admin" href="{U_HOME}" title="{L_COMMENT_RETURN_HINT}">{L_COMMENT_RETURN}</a> ]
+	  <!-- END title -->
+</div>
+<!-- BEGIN validation -->
+<form action="{F_ACTION}" method="post">
+<!-- END validation -->
+<table class="table2">
+<!-- BEGIN picture -->
+<tr class="row1">
+<td >
+<a href="{picture.U_THUMB}" title="{picture.TITLE_IMG}">
+<img src="{picture.I_THUMB}" class="thumbLink" alt="{picture.THUMB_ALT_IMG}"/>
+</a>
+</td>
+<td class="tablecompact">
+  <div class="commentTitle">{picture.TITLE_IMG}</div>
+  <div class="commentsNavigationBar">{picture.NAV_BAR}</div>
+  <table class="tablecompact">
+  <!-- BEGIN comment -->
+	<tr class="throw">
+	  <td class="throw">
+	  {picture.comment.COMMENT_AUTHOR}
+	  </td>
+	  <td class="commentDate">
+	  {picture.comment.COMMENT_DATE}
+	<!-- BEGIN validation -->
+	<input type="checkbox" name="comment_id[]" value="{picture.comment.validation.ID}" {picture.comment.validation.CHECKED} />
+	<!-- END validation -->
+	  </td>
+	</tr>
+	<tr class="row1">
+	  <td class="comment" colspan="2">{picture.comment.COMMENT}</td>
+	</tr>
+	<!-- END comment -->
+  </table>
+</td>
+</tr>
+<!-- END picture -->
+</table>
+<!-- BEGIN validation -->
+<div align="center">
+<input type="submit" name="validate" class="bouton" value="{L_VALIDATE}" />
+<input type="submit" name="delete" class="bouton" value="{L_DELETE}" />
+</div>
+</form>
+<!-- END validation -->
Index: /branches/1.4/template/default/default.css
===================================================================
--- /branches/1.4/template/default/default.css	(revision 3249)
+++ /branches/1.4/template/default/default.css	(revision 3249)
@@ -0,0 +1,379 @@
+/* BACKGROUND */
+
+body { background-color:#000000;} /*General background color*/
+.main, .throw, .admin {	background-color:#3F3F3F;} /*Main background color*/
+.row1,input,select,textarea, .table1, .home { background-color:#5F5F5F;} /* Tables & forms */
+.table2, .commentTitle { background-color: #797979;} /* Alternate table & comments  */
+.errors { background-color:red;} /* Errors display */
+.titreMenu,.titrePage,.imgMenu a:hover { background-image: url(theme/tableh1_bg.gif);} /* Titles background image  */
+.bouton, .imgMenu a, #imgBarMenu { background-image: url(theme/button_bg.gif);} /* Buttons background image */
+
+/* FONT COLORS */
+
+body { color:#E0E0E0;} /* General font color */
+input,select,textarea { color:#FFFFCC;} /* Forms font color */
+.titreMenu, .titreMenu a, .info, .admin{ color:#FFF48E;} /* Menu & sections titles */
+.titrePage, .titreMenu a:hover { color:#E0E0E0;} /* Page title */
+.comment{ color:#C6B78E;} /* Comments */
+.commentDate { color:#999999;} /* Comments date */
+.throw { color:#FFFFCC;} /* First line of tables */
+.bouton, .errors { color:#FFFFFF;} /* Buttons & errors */
+
+/* Update results (admin side only) */
+.update_summary_new, .best_gen_time
+{ color:#9cb4ce;}
+
+/* Update results (admin side only) */
+.update_summary_del,.worst_gen_time
+{ color:#ffe1e1;}
+
+/* ANCHORS */
+
+a { text-decoration:none; color:#FFFFFF;}
+a:hover { text-decoration:none; color:#FFF48E;}
+a.none:hover { text-decoration:none;}
+a.image:hover { text-decoration:none;}
+a.thumbLink:hover { text-decoration:none;}
+
+/* FONT STYLES */
+
+body /* Main font style */
+{
+  font-family: Verdana, Geneva, Arial, sans-serif;
+  font-size:12px;
+  margin:5px;
+}
+
+h1 /* H1 tag style (admin side only) */
+{
+	font-family: 'Trebuchet MS', Verdana, sans-serif;
+	text-decoration:none; 
+	line-height:	120%;
+	font-size:18px;
+	font-weight: bold;
+}
+
+h2 /* H2 tag style (admin side only) */
+{
+	font-family: Arial, Helvetica, sans-serif;
+	text-decoration:none; 
+	line-height:	120%; 
+	font-size:12px;
+	font-weight: bold;
+}
+
+.titreMenu /* Menu titles */
+{
+  font-size:12px;
+  font-weight:600;
+}
+
+.titrePage /* Page titles */
+{
+  font-family: 'Trebuchet MS', Verdana, sans-serif;
+  font-weight:600;
+  font-size:16px;
+}
+
+.commentTitle /* Comments title */
+{
+  font-family: Arial, Helvetica, sans-serif;
+  font-size:12px;
+  font-weight:bold;
+}
+
+.menu, .thumbnail, .totalImages { font-size:11px;}
+.small{ font-size:10px;}
+.menuCategorySelected, .throw, .admin, .errors { font-weight:bold;}
+.menuCategoryNotSelected, .dateSelected, .pageNumberSelected, .thumb_picture, .thumb_category  { font-weight:normal;}
+.commentDate, .bouton  { font-weight:lighter;}
+.commentImage { font-style:italic; font-size:16px;}
+.nameImage { font-size:20px;}
+.info { font-size:16px;}
+.copyright { font-size:10px; text-align:center; letter-spacing:-1px;}
+div.information {  font-size:14px; font-weight:bold;}
+
+/*----------------------------------------------*/
+/* Under this point, do not modify the values   */
+/* unless you are aware of what you are doing!  */
+/*----------------------------------------------*/
+
+/* POSITION */
+
+#gauche,#droite
+{
+  float:left;
+  width:30%;
+  text-align:left;
+  white-space:nowrap;
+}
+
+#centre
+{
+  float:left;
+  width:39%;
+  text-align:center;
+}
+
+#droite{text-align:right;}
+#left {float:left; }
+#right{float:right; }
+
+/* GENERAL LAYOUT STYLES */
+
+.main 
+{
+	border: 1px solid #E0E0E0; 
+	width:100%;
+	padding-bottom:30px;
+	text-align:center;
+	display:block;
+}
+
+.home
+{
+  border: 1px solid #000000;
+  display:block;
+  text-align:center;
+  width:100%;
+}
+
+.navigationBar 
+{
+  text-align:center;
+  margin-top:10px;
+  margin-bottom:10px;
+}
+
+.info 
+{
+  margin:5px 0px 5px 0px;
+  /* white-space:nowrap; */
+  text-align:center;
+}
+
+.errors 
+{
+  text-align:left;
+  margin-top:5px;
+  margin-bottom:5px;
+  border:1px solid black;
+}
+
+div.information {
+  text-align:left;
+  margin:10px;
+  padding:5px;
+}
+
+span.dateSelected, span.pageNumberSelected {
+  text-decoration:underline;
+}
+/* MENU LAYOUT STYLES */
+
+.titreMenu,.titrePage
+{
+  padding-right: 10px;
+  padding-left: 10px;
+  border-bottom: 1px solid #000000;
+  border-right: 1px solid #000000;
+  height: 25px;
+  line-height: 25px;
+  text-align:center;
+}
+.titrePage {text-align:left;}
+
+.menu 
+{
+  margin:10px 5px 10px 5px;
+  white-space:nowrap;
+  text-align:left;
+}
+
+ul.menu 
+{
+  text-align:left;
+  list-style-type: square ;
+  padding-left:15px;
+  margin:5px;
+}
+
+.totalImages {
+  text-align:center;
+  margin-top:5px;
+}
+
+ /* IMAGE LAYOUT STYLES */
+ 
+.image 
+{
+	border : 3px solid #FFFFFF;
+	margin : 10px 4px 10px 4px;
+}
+
+#imgBarMenu
+{
+  width:100%;
+  display:block;
+  height:25px;
+  border-bottom: 1px solid #000000;
+}
+  
+.imgMenu
+{
+  width:48px;
+  border:none;
+  float:left;
+}
+
+.imgMenu img
+{
+ border:none;
+ text-align:center;
+ margin-top:4px;
+}
+  
+.imgMenu a
+{
+  display:block;
+  height: 25px;
+  border-bottom: 1px solid #000000;
+  border-left: 1px solid #838383;
+  border-right: 1px solid #000000;
+}
+
+.imgMenu a:hover
+{
+  border-bottom: 1px solid #3F3F3F;
+  border-left: 1px solid #3F3F3F;
+  border-right: 1px solid #3F3F3F;
+}
+
+.commentImage {
+  text-align:justify;
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+
+/* TABLE LAYOUT STYLES */
+
+.table1
+{
+  border: 1px solid #000000;
+  display:block;
+}
+  
+.table2 {
+	border: 1px solid #000000; 
+	margin:	0px 10px 0px 0px;
+	padding:0px;
+}
+
+.tablecompact{
+  width:100%;
+  border-collapse:collapse;
+}
+
+.row1,.row2 {
+  text-align:left;
+  padding:5px 0px 5px 0px;
+  height:20px;
+} 
+
+.throw {
+  text-align:center;
+  border-top: 1px solid #000000; 
+  border-bottom: 1px solid #000000; 
+  height:20px;
+}
+
+td.throw{
+  text-align:left;
+  width:auto;
+}
+
+/* THUMBNAILS LAYOUT STYLES */
+
+.thumbnail {
+	text-align:center;
+	vertical-align: baseline;
+	white-space: nowrap;
+}
+
+table.thumbnail {
+  border-collapse:separate;
+  display:inline-table;
+}
+
+.thumbLink {
+	border-style: solid;
+	border-width:1px;
+	border-color: #A0A0A0;
+	margin: 2px;
+}
+
+/* COMMENTS LAYOUT STYLES */
+
+.commentTitle {  padding: 15px 5px 10px 5px; }
+.commentDate {
+  text-align:right;
+  border-top: 1px solid #000000; 
+  border-bottom: 1px solid #000000;
+}
+
+/* FORM LAYOUT STYLES */
+
+form
+{
+  text-align:left;
+  padding:10px;
+}
+
+.bouton
+{
+  border: 1px solid #404750;
+  padding-left: 3px;
+  padding-right: 3px;
+  background-position : bottom;
+  margin-top:10px;
+}
+
+input,select,textarea 
+{
+ text-indent:2px;
+ border: 1px solid #797979;
+ padding: 0;
+}
+
+.radio{  border:0;}
+
+/* ADMIN LAYOUT STYLES */
+
+.adminMenu 
+{
+  text-align:center;
+  font-size:12px;
+}
+
+div.adminMenu{ margin:10px 50px 10px 50px; }
+
+.admin 
+{
+margin:0px 0px 12px 0px;
+text-align: center;
+padding:0px;
+}
+
+div.remoteOutput, div.remoteLocal {
+  border:1px solid black;
+  margin:10px;
+  text-align:left;
+  padding:5px;
+}
+
+div.remoteLocal {
+  text-align:center;
+}
+
+/* for debugging purpose */
+pre { text-align:left; }
Index: /branches/1.4/template/default/footer.tpl
===================================================================
--- /branches/1.4/template/default/footer.tpl	(revision 3249)
+++ /branches/1.4/template/default/footer.tpl	(revision 3249)
@@ -0,0 +1,21 @@
+ <div class="copyright">
+ <!-- BEGIN debug -->
+ {L_GEN_TIME} {debug.TIME} ({debug.NB_QUERIES} {L_SQL_QUERIES_IN} {debug.SQL_TIME}) -
+ <!-- END debug -->
+
+ <!-- Please, do not remove this copyright. If you really want to,
+	  contact me pierrick@phpwebgallery.net to find a solution on how
+	  to show the origin of the script...-->
+
+  {L_POWERED_BY} <a href="http://www.phpwebgallery.net" class="back">PhpWebGallery</a>
+  {VERSION} - 
+
+  {L_SEND_MAIL}
+  <a href="mailto:{MAIL}?subject={L_TITLE_MAIL}">
+   <span style="font-weight:bold;">{L_WEBMASTER}</span>
+  </a>
+
+ </div>
+ </div>
+ </body>
+</html>
Index: /branches/1.4/template/default/header.tpl
===================================================================
--- /branches/1.4/template/default/header.tpl	(revision 3249)
+++ /branches/1.4/template/default/header.tpl	(revision 3249)
@@ -0,0 +1,16 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="{LANG}" lang="{LANG}" dir="{DIR}">
+
+ <head>
+  <meta http-equiv="Content-Type" content="text/html; charset={CONTENT_ENCODING}" />
+  <meta http-equiv="Content-Style-Type" content="text/css" />
+  <!-- BEGIN refresh -->
+  <meta http-equiv="refresh" content="{REFRESH_TIME};url={U_REFRESH}">
+  <!-- END refresh -->
+  <title>{PAGE_TITLE}</title>
+  <link rel="stylesheet" href="{T_STYLE}" type="text/css" />
+  <script type="text/javascript" src="include/scripts.js"></script>
+ </head>
+
+ <body>
+ <div class="main">
Index: /branches/1.4/template/default/identification.tpl
===================================================================
--- /branches/1.4/template/default/identification.tpl	(revision 3249)
+++ /branches/1.4/template/default/identification.tpl	(revision 3249)
@@ -0,0 +1,58 @@
+<div class="titrePage">{L_TITLE}</div>
+<div style="margin-top:15px;text-align:center;">
+<table width="60%" cellpadding="4" cellspacing="1" border="0" align="center">
+<form action="{F_LOGIN_ACTION}" method="post">
+<!-- BEGIN errors -->
+  <tr>
+	<td colspan="2">
+	  <div class="errors">
+		<ul>
+		  <!-- BEGIN error -->
+		  <li>{errors.error.ERROR}</li>
+		  <!-- END error -->
+		</ul>
+	  </div>
+	</td>
+  </tr>
+  <!-- END errors -->
+  <tr> 
+	<td colspan="2" align="center">&nbsp;</td>
+  </tr>
+  <tr> 
+	<td width="45%" align="right"><span class="gentbl">{L_USERNAME}:</span></td>
+	<td> 
+	  <input class="login" type="text" name="username" size="25" maxlength="40" value="{USERNAME}" />
+	</td>
+  </tr>
+  <tr> 
+	<td align="right"><span class="gentbl">{L_PASSWORD}:</span></td>
+	<td> 
+	  <input class="login" type="password" name="password" size="25" maxlength="25" />
+	</td>
+  </tr>
+  <!-- BEGIN remember_me -->
+  <tr>
+        <td align="right"><span class="gentbl">{L_REMEMBER_ME}:</span></td>
+        <td>
+          <input type="checkbox" name="remember_me" value="1" />
+        </td>
+  </tr>
+  <!-- END remember_me -->
+  <tr align="center"> 
+	<td colspan="2"><input type="submit" name="login" value="{L_LOGIN}" class="bouton" /></td>
+  </tr>
+</form>
+</table>
+
+<table style="width:80%;margin-left:auto;margin-right:auto;">
+<tr>
+  <td colspan="3" align="center">
+	<!-- BEGIN free_access -->
+	  <p><a href="./category.php">[ {L_GUEST} ]</a></p>
+	  <a href="register.php"><img src="template/default/theme/register.gif" style="border:0;" alt=""/>&nbsp;{L_REGISTER}</a>&nbsp;&nbsp;-&nbsp;&nbsp;
+	<!-- END free_access -->
+	  <a href="mailto:{MAIL_ADMIN}?subject=[PhpWebGallery] {L_FORGET}"><img src="template/default/theme/lost.gif" style="border:0;" alt=""/>&nbsp;{L_FORGET}</a>
+  </td>
+</tr>
+</table>
+</div>
Index: /branches/1.4/template/default/install.tpl
===================================================================
--- /branches/1.4/template/default/install.tpl	(revision 3249)
+++ /branches/1.4/template/default/install.tpl	(revision 3249)
@@ -0,0 +1,203 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset={T_CONTENT_ENCODING}"  />
+<meta http-equiv="Content-script-type" content="text/javascript" />
+<meta http-equiv="Content-Style-Type" content="text/css" />
+<title>PhpWebGallery {RELEASE}</title>
+<style type="text/css">
+a, a:hover {
+color:#006699;
+}
+
+body,table,input,form,select {
+font-family:arial,verdana,sans-serif;
+font-size:12px;
+color:#000000;
+text-align:left;
+}
+table 
+{
+border-collapse:separate;
+}
+body {
+background-color:#E5E5E5;
+margin:5px;
+}
+
+.contenucellule {
+background-color:#EEEEEE;
+border:2px solid #006699;
+}
+
+th {
+font-weight:bold;
+background-color:#D3DCE3;
+margin-bottom:10px;
+text-align: center;
+}
+td.row1 {
+background-color:#E6E4E4;
+}
+td.row2
+{
+background-color:#E8E8E8;
+}
+
+.info {
+color:darkblue;
+text-align:center;
+}
+.errors {
+  text-align:left;
+  margin:25px;
+  background-color:#ffe1e1;
+  border:1px solid red;
+  color:black;
+}
+.grostitre {
+  text-align : center;
+  font-size : 20px;
+   margin-bottom : 20px;
+}
+</style>
+</head>
+<body>
+    <table style="width:100%;height:100%">
+      <tr align="center" valign="middle">
+        <td>
+	  <div class="grostitre">PhpWebGallery {RELEASE}</div>
+          <table class="table1">
+		  <!-- BEGIN errors -->
+		  <tr>
+			<td class="contenucellule" colspan="3">
+			  <div class="errors">
+				<ul>
+				  <!-- BEGIN error -->
+				  <li>{errors.error.ERROR}</li>
+				  <!-- END error -->
+				</ul>
+			  </div>
+			</td>
+		  </tr>
+		  <!-- END errors -->
+		  <!-- BEGIN infos -->
+		  <tr>
+			<td class="contenucellule" colspan="3">
+			  <div class="infos">
+				<ul>
+				  <!-- BEGIN info -->
+				  <li>{infos.info.INFO}</li>
+				  <!-- END info -->
+				</ul>
+			  </div>
+			</td>
+		  </tr>
+		  <!-- END infos -->
+			 <tr>
+              <td class="contenucellule">
+
+<!-- BEGIN error_copy -->
+{L_ERR_COPY} :
+<br />-----------------------------------------------------<br />
+<div style="color:blue;">{error_copy.FILE_CONTENT}</div>
+-----------------------------------------------------<br />
+<!-- END error_copy -->
+<!-- BEGIN install -->
+<form method="POST" action="{F_ACTION}" name="install_form">
+  <table width="100%">
+  	<tr>
+      <th colspan="3">{L_BASE_TITLE}</th>
+    </tr>
+    <tr>
+  	  <td width="30%">{L_LANG_TITLE}</td>
+      <td colspan="2" align="left">
+	  {F_LANG_SELECT}
+      </td>
+    </tr>
+    <tr>
+      <th colspan="3">{L_DB_TITLE}</th>
+    </tr>
+    <tr>
+      <td colspan="3">&nbsp;</td>
+    </tr>
+    <tr>
+      <td>{L_DB_HOST}</td>
+      <td align=center><input type="text" name="dbhost" value="{F_DB_HOST}" /></td>
+      <td class="row2">{L_DB_HOST_INFO}</td>
+    </tr>
+    <tr>
+      <td>{L_DB_USER}</td>
+      <td align=center><input type="text" name="dbuser" value="{F_DB_USER}" /></td>
+      <td class="row2">{L_DB_USER_INFO}</td>
+    </tr>
+    <tr>
+      <td>{L_DB_PASS}</td>
+      <td align=center><input type="password" name="dbpasswd" value="" /></td>
+      <td class="row2">{L_DB_PASS_INFO}</td>
+    </tr>
+    <tr>
+      <td>{L_DB_NAME}</td>
+      <td align=center><input type="text" name="dbname" value="{F_DB_NAME}" /></td>
+      <td class="row2">{L_DB_NAME_INFO}</td>
+    </tr>
+    <tr>
+      <td>{L_DB_PREFIX}</td>
+      <td align=center><input type="text" name="prefix" value="{F_DB_PREFIX}" /></td>
+      <td class="row2">{L_DB_PREFIX_INFO}</td>
+    </tr>
+    <tr>
+     <td colspan="3">&nbsp;</td>
+    </tr>
+    <tr>
+      <th colspan="3">{L_ADMIN_TITLE}</th>
+    </tr>
+    <tr>
+      <td colspan="3">&nbsp;</td>
+    </tr>
+    <tr>
+      <td>{L_ADMIN}</td>
+      <td align="center"><input type="text" name="admin_name" value="{F_ADMIN}" /></td>
+      <td class="row2">{L_ADMIN_INFO}</td>
+    </tr>
+    <tr>
+      <td>{L_ADMIN_PASSWORD}</td>
+      <td align="center"><input type="password" name="admin_pass1" value="" /></td>
+      <td class="row2">{L_ADMIN_PASSWORD_INFO}</td>
+    </tr>
+    <tr>
+      <td>{L_ADMIN_CONFIRM_PASSWORD}</td>
+      <td align="center"><input type="password" name="admin_pass2" value="" /></td>
+      <td class="row2">{L_ADMIN_CONFIRM_PASSWORD_INFO}</td>
+    </tr>
+    <tr>
+      <td>{L_ADMIN_EMAIL}</td>
+      <td align="center"><input type="text" name="admin_mail" value="{F_ADMIN_EMAIL}" /></td>
+      <td class="row2">{L_ADMIN_EMAIL_INFO}</td>
+    </tr>
+    <tr>
+      <td colspan="3">&nbsp;</th>
+    </tr>
+    <tr>
+      <td colspan="3" align="center">
+        <input type="submit" name="install" value="{L_SUBMIT}" />
+      </td>
+    </tr>
+  </table>
+</form>
+<!-- END install -->
+
+<!-- BEGIN install_end -->
+<div class="infos_title">{L_END_TITLE}</div>
+<div style="padding:5px;">{L_END_MESSAGE}</div>
+<!-- END install_end -->
+
+              </td>
+            </tr>
+          </table>
+          <div style="text-align:center;margin:20px;">{L_INSTALL_HELP}</div>
+        </td>
+      </tr>
+    </table>
+  </body>
+</html>
Index: /branches/1.4/template/default/picture.tpl
===================================================================
--- /branches/1.4/template/default/picture.tpl	(revision 3249)
+++ /branches/1.4/template/default/picture.tpl	(revision 3249)
@@ -0,0 +1,176 @@
+<!-- BEGIN information -->
+<div class="information">{information.INFORMATION}</div>
+<!-- END information -->
+<div class="titrePage">
+  <div id="gauche"><a href="{U_HOME}">{L_HOME}</a>{LEVEL_SEPARATOR}{CATEGORY}</div>
+  <div id="centre" class="nameImage">{TITLE}</div>
+  <div id="droite">{PHOTO}</div>
+</div>
+
+<div id="imgBarMenu">
+<div class="imgMenu" id="left">
+  <a href="{U_UP}" title="{L_UP_HINT}">
+	<img src="template/default/theme/categories.gif" alt="{L_UP_ALT}" />
+  </a>
+</div>
+<div class="imgMenu" id="left">
+  <a href="{U_SLIDESHOW}" title="{L_SLIDESHOW}">
+	<img src="template/default/theme/slideshow.gif" alt="{L_SLIDESHOW}" />
+  </a>
+</div>
+<div class="imgMenu" id="left">
+  <a href="{U_METADATA}" title="{L_PICTURE_METADATA}">
+	<img src="template/default/theme/metadata.gif" alt="{L_PICTURE_METADATA}" />
+  </a>
+</div>
+<!-- BEGIN favorite -->
+<div class="imgMenu" id="right">
+  <a href="{favorite.U_FAVORITE}" title="{favorite.FAVORITE_HINT}">
+	<img src="{favorite.FAVORITE_IMG}" alt="{favorite.FAVORITE_ALT}" />
+  </a>
+</div>
+<!-- END favorite -->
+<!-- BEGIN download -->
+<div class="imgMenu" id="right">
+  <a href="{download.U_DOWNLOAD}" title="{L_DOWNLOAD}">
+	<img src="template/default/theme/download.gif" alt="{L_DOWNLOAD}" />
+  </a>
+</div>
+<!-- END download -->
+<!-- BEGIN admin -->
+<div class="imgMenu" id="right">
+  <a href="{U_ADMIN}" title="{L_ADMIN}">
+	<img src="template/default/theme/properties.gif" alt="{L_ADMIN}" />
+  </a>
+</div>
+<!-- END admin -->
+</div>
+<!-- BEGIN high -->
+<a href="javascript:phpWGOpenWindow('{high.U_HIGH}','{high.UUID}','scrollbars=yes,toolbar=yes,status=yes,resizable=yes,width={high.WIDTH_IMG},height={high.HEIGHT_IMG}')">
+<!-- END high -->
+  <img class="image" src="{SRC_IMG}" style="width:{WIDTH_IMG}px;height:{HEIGHT_IMG}px;" alt="{ALT_IMG}"/>
+<!-- BEGIN high -->
+</a>
+<div style="text-align:center;font-weight:bold;">{L_PICTURE_HIGH}</div>
+<!-- END high -->
+<!-- BEGIN legend -->
+<div class="commentImage">{legend.COMMENT_IMG}</div>
+<!-- END legend -->
+
+<!-- BEGIN stop_slideshow -->
+<div style="text-align:center;margin-bottom:5px;">
+  [ <a href="{stop_slideshow.U_SLIDESHOW}" class="back" style="font-weight:bold;">{L_STOP_SLIDESHOW}</a> ]
+</div>
+<!-- END stop_slideshow -->
+<div style="clear:both;"></div>
+<div style="white-space:nowrap;">
+<div id="gauche">
+&nbsp;
+  <!-- BEGIN previous -->
+	<a class="none" href="{previous.U_IMG}" title="{L_PREV_IMG}{previous.TITLE_IMG}">
+	<img style="border:none;" width="30" height="100" src="template/default/theme/left-arrow.gif" alt="" />
+	  <img src="{previous.IMG}" class="thumbLink" style="margin-right:10px;margin-left:5px;" alt="{previous.TITLE_IMG}"/>
+	  </a>
+  <!-- END previous -->
+</div>
+<div id="centre">
+  <table style="margin:auto;margin-top:5px;margin-bottom:5px;">
+	  <!-- BEGIN info_line -->
+	  <tr>
+		 <td class="menu" style="font-weight:bold;">{info_line.INFO} : </td>
+		 <td class="menu" style="text-align:right;">{info_line.VALUE}</td>
+	  </tr>
+	  <!-- END info_line -->
+  </table>
+</div>
+<div id="droite">
+  <!-- BEGIN next -->
+  <a  class="none" href="{next.U_IMG}" title="{L_NEXT_IMG}{next.TITLE_IMG}">
+	  <img class="thumbLink" src="{next.IMG}" style="margin-right:10px;margin-left:5px;" alt="{next.TITLE_IMG}"/>
+	  <img style="border:none;" class="thumbLink" width="30" height="100" src="template/default/theme/right-arrow.gif" alt="" />
+	  </a>
+  <!-- END next -->
+  &nbsp;
+</div>
+</div>
+<div style="clear:both;"></div>
+         <!-- BEGIN metadata -->
+          <table class="tablecompact">
+            <!-- BEGIN headline -->
+            <tr>
+              <th colspan="2">{metadata.headline.TITLE}</th>
+            </tr>
+            <!-- END headline -->
+            <!-- BEGIN line -->
+            <tr>
+              <td>{metadata.line.KEY}</td>
+              <td>{metadata.line.VALUE}</td>
+            </tr>
+            <!-- END line -->
+          </table>
+          <!-- END metadata -->
+
+          <!-- BEGIN rate -->
+          <div>
+            {rate.SENTENCE} :
+            <!-- BEGIN rate_option -->
+            {rate.rate_option.SEPARATOR} <a href="{rate.rate_option.URL}">{rate.rate_option.OPTION}</a>
+            <!-- END rate_option -->
+          </div>
+          <!-- END rate -->
+         
+<table class="tablecompact">
+      <!-- BEGIN comments -->
+      <tr align="center" valign="middle">
+        <td colspan="3" class="table2">
+                  <div class="commentTitle">
+                    [{comments.NB_COMMENT}] {L_COMMENT_TITLE}
+                  </div>
+                  <div class="commentsNavigationBar">{comments.NAV_BAR}</div>
+				  <table class="tablecompact">
+                  <!-- BEGIN comment -->
+				    <tr class="throw">
+					  <td class="throw">
+					  {comments.comment.COMMENT_AUTHOR}
+					  </td>
+					  <td colspan="2" class="commentDate">
+					  {comments.comment.COMMENT_DATE}
+					<!-- BEGIN delete -->
+					  <a href="{comments.comment.delete.U_COMMENT_DELETE}" title="{L_DELETE_COMMENT}"><img src="template/default/theme/delete.gif" style="border:none;vertical-align:middle; margin-left:5px;" alt="[{L_DELETE}]"/></a>
+					<!-- END delete -->
+					  </td>
+					</tr>
+					<tr class="row1">
+					  <td class="comment" colspan="3">{comments.comment.COMMENT}</td>
+					</tr>
+                  <!-- END comment -->
+            <!-- BEGIN add_comment -->
+			<tr class="throw">
+			  <td colspan="3">{L_ADD_COMMENT}</td>
+			</tr>
+			<form  method="post" action="{U_ADD_COMMENT}">
+  		    <tr class="row1">
+			  <td class="comment" >
+                    <!-- BEGIN author_field -->
+                    {L_AUTHOR}</td><td colspan="2"><input type="text" name="author" />
+					</td></tr>
+					<tr class="row1">
+					<td class="comment" >
+                    <!-- END author_field -->
+                    <!-- BEGIN author_known -->
+                    <input type="hidden" name="author"  value="{comments.add_comment.author_known.KNOWN_AUTHOR}" />
+                    <!-- END author_known -->
+                    {L_COMMENT}</td>
+					<td style="width:100%;">
+					<textarea name="content" rows="2" style="width:100%;"></textarea>
+					</td><td>
+					<input type="submit" value="{L_SUBMIT}" class="bouton" />
+			  </td>
+			 </tr>
+			 </form>
+           	</table>
+            <!-- END add_comment -->
+        </td>
+      </tr>
+      <!-- END comments -->
+    </table>
Index: /branches/1.4/template/default/profile.tpl
===================================================================
--- /branches/1.4/template/default/profile.tpl	(revision 3249)
+++ /branches/1.4/template/default/profile.tpl	(revision 3249)
@@ -0,0 +1,172 @@
+<!-- BEGIN errors -->
+<div class="errors">
+  <ul>
+    <!-- BEGIN error -->
+    <li>{errors.error.ERROR}</li>
+    <!-- END error -->
+  </ul>
+</div>
+<!-- END errors -->
+
+<!-- BEGIN add_user -->
+<div class="admin">{L_GROUP_ADD_USER}</div>
+<form method="post" name="post" action="{add_user.F_ACTION}">
+  {L_USERNAME} <input type="text" name="login" maxlength="50" size="20" />
+  {L_PASSWORD} <input type="text" name="password" />
+  <input type="submit" name="submit_add" value="{L_SUBMIT}" class="bouton" />
+</form>
+<!-- END add_user -->
+
+<!-- BEGIN select_user -->
+<div class="admin">{L_SELECT_USERNAME}</div>
+<form method="post" name="post" action="{F_SEARCH_USER_ACTION}">
+  <input type="text" name="username" maxlength="50" size="20" />
+  <input type="submit" name="submituser" value="{L_LOOKUP_USER}" class="bouton" /> 
+  <input type="submit" name="usersubmit" value="{L_FIND_USERNAME}" class="bouton" onClick="window.open('{U_SEARCH_USER}', '_phpwgsearch', 'HEIGHT=250,resizable=yes,WIDTH=400');return false;" />
+</form>
+
+<div class="admin">{L_USERS_LIST}</div>
+<form method="get" action="{F_ORDER_ACTION}">
+<input type="hidden" name="page" value="profile" />
+<div style="text-align:center">
+  {L_ORDER_BY}
+  <select name="order_by">
+    <!-- BEGIN order_by -->
+    <option value="{select_user.order_by.VALUE}" {select_user.order_by.SELECTED} >{select_user.order_by.CONTENT}</option>
+    <!-- END order_by -->
+  </select>
+  <select name="direction">
+    <!-- BEGIN direction -->
+    <option value="{select_user.direction.VALUE}" {select_user.direction.SELECTED} >{select_user.direction.CONTENT}</option>
+    <!-- END direction -->
+  </select>
+  <input type="submit" value="{L_SUBMIT}" class="bouton" />
+</div>
+</form>
+
+<table style="width:100%;" >
+  <tr class="throw">
+    <th style="width:20%;">{L_USERNAME}</th>
+    <th style="width:20%;">{L_STATUS}</th>
+    <th style="width:30%;">{L_EMAIL}</th>
+    <th style="width:30%;">{L_GROUPS}</th>
+    <th style="width:1%;">{L_ACTIONS}</th>
+  </tr>
+  <!-- BEGIN user -->
+  <tr>
+    <td><a href="{select_user.user.U_MOD}">{select_user.user.USERNAME}</a></td>
+    <td>{select_user.user.STATUS}</td>
+    <td>{select_user.user.EMAIL}</td>
+    <td>{select_user.user.GROUPS}</td>
+<!-- [<a href="{select_user.user.U_MOD}">{L_MODIFY}</a>] -->
+    <td>[<a href="{select_user.user.U_PERM}">{L_PERMISSIONS}</a>]</td>
+  </tr>
+  <!-- END user -->
+</table>
+<div class="navigationBar">{NAVBAR}</div>
+<!-- END select_user -->
+<!-- BEGIN modify -->
+<!-- BEGIN profile -->
+<div class="titrePage">{L_TITLE}</div>
+<!-- END profile -->
+<form method="post" action="{F_ACTION}">
+<table width="70%" align="center">
+  <tr class="admin">
+    <th colspan="2">{L_REGISTRATION_INFO}</th>
+  </tr>
+	<tr>
+	  <td width="50%">{L_USERNAME}</td>
+	  <td><input type="text" name="username" value="{USERNAME}" />
+		<input type="hidden" name="userid" value="{USERID}" /></td>
+  </tr>
+	<tr>
+	  <td>{L_EMAIL}</td>
+	  <td><input type="text" name="mail_address" value="{EMAIL}" /></td>
+  </tr>
+	<!-- BEGIN profile -->
+  <tr>
+	<td>{L_CURRENT_PASSWORD} : <br /><span class="small">{L_CURRENT_PASSWORD_HINT}</span></td>
+	<td><input type="password" name="password" value="" /></td>
+  </tr>
+	<!-- END profile -->
+	<tr>
+	<td>{L_NEW_PASSWORD} : <br /><span class="small">{L_NEW_PASSWORD_HINT}</span></td>
+	<td><input type="password" name="use_new_pwd" value="" /></td>
+  </tr>
+  <tr>
+	<td>{L_CONFIRM_PASSWORD} : <br /><span class="small">{L_CONFIRM_PASSWORD_HINT}</span></td>
+	<td><input type="password" name="passwordConf" value="" /></td>
+  </tr>
+  <tr class="admin">
+    <th colspan="2">{L_PREFERENCES}</th>
+  </tr>
+  <tr>
+    <td width="60%">{L_NB_IMAGE_LINE}</td>
+	<td width="40%"><input type="text" size="3" maxlength="2" name="nb_image_line" value="{NB_IMAGE_LINE}" /></td>
+  </tr>
+  <tr>
+    <td>{L_NB_ROW_PAGE}</td>
+	<td><input type="text" size="3" maxlength="2" name="nb_line_page" value="{NB_ROW_PAGE}" /></td>
+  </tr>
+  <tr>
+    <td>{L_STYLE_SELECT}</td>
+	<td>{STYLE_SELECT}</td>
+  </tr>
+  <tr>
+    <td>{L_LANG_SELECT}</td>
+	<td>{LANG_SELECT}</td>
+  </tr>
+   <tr>
+    <td>{L_RECENT_PERIOD}</td>
+	<td><input type="text" size="3" maxlength="2" name="recent_period" value="{RECENT_PERIOD}" /></td>
+  </tr>
+  <tr>
+    <td>{L_EXPAND_TREE}</td>
+	<td><input type="radio" class="radio" name="expand" value="true" {EXPAND_TREE_YES} />{L_YES}&nbsp;&nbsp;
+	<input type="radio" class="radio" name="expand" value="false" {EXPAND_TREE_NO} />{L_NO}</td>
+  </tr>
+  <tr>
+    <td>{L_NB_COMMENTS}</td>
+	<td><input type="radio" class="radio" name="show_nb_comments" value="true" {NB_COMMENTS_YES} />{L_YES}&nbsp;&nbsp;
+	<input type="radio" class="radio" name="show_nb_comments" value="false" {NB_COMMENTS_NO} />{L_NO}</td>
+  </tr>
+	<tr>
+    <td>{L_MAXWIDTH}</td>
+	<td><input type="text" size="4" maxlength="4" name="maxwidth" value="{MAXWIDTH}" />
+	</td>
+  </tr>
+	<tr>
+    <td>{L_MAXHEIGHT}</td>
+	<td><input type="text" size="4" maxlength="4" name="maxheight" value="{MAXHEIGHT}" />
+	</td>
+  </tr>
+<!-- BEGIN admin -->
+	<tr class="admin">
+    <th colspan="2">{modify.admin.L_ADMIN_USER}</th>
+  </tr>
+	<tr>
+    <td>{modify.admin.L_STATUS}</td>
+	<td>{modify.admin.STATUS}
+	</td>
+  </tr>
+	<tr>
+    <td>{modify.admin.L_DELETE}<br />
+		<span class="small">{modify.admin.L_DELETE_HINT}</span></td>
+	<td><input name="user_delete" type="checkbox" value="1">
+	</td>
+  </tr>
+<!-- END admin -->
+<tr>
+	<td colspan="2" align="center">
+	  <input type="submit" name="submit" value="{L_SUBMIT}" class="bouton" />
+          <input type="reset" name="reset" value="{L_RESET}" class="bouton" />
+	</td>
+  </tr>
+</table>
+</form>
+<!-- BEGIN profile -->
+<div style="text-align:center;margin:5px;">
+<a href="{U_RETURN}" title="{L_RETURN_HINT}">[{L_RETURN}]</a>
+</div>
+<!-- END profile -->
+<!-- END modify -->
Index: /branches/1.4/template/default/redirect.tpl
===================================================================
--- /branches/1.4/template/default/redirect.tpl	(revision 3249)
+++ /branches/1.4/template/default/redirect.tpl	(revision 3249)
@@ -0,0 +1,1 @@
+redirection
Index: /branches/1.4/template/default/register.tpl
===================================================================
--- /branches/1.4/template/default/register.tpl	(revision 3249)
+++ /branches/1.4/template/default/register.tpl	(revision 3249)
@@ -0,0 +1,56 @@
+<div class="titrePage">{L_TITLE}</div>
+<form method="post" action="{F_ACTION}">
+  <table style="width:60%;" align="center">
+	<!-- BEGIN errors -->
+  <tr>
+	<td colspan="2">
+	  <div class="errors">
+		<ul>
+		  <!-- BEGIN error -->
+		  <li>{errors.error.ERROR}</li>
+		  <!-- END error -->
+		</ul>
+	  </div>
+	</td>
+  </tr>
+  <!-- END errors -->
+	<tr>
+	  <td width="60%">{L_USERNAME}</td>
+	  <td width="40%">
+		<input type="text" name="login" value="{F_LOGIN}" />
+	  </td>
+	</tr>
+	<tr>
+	  <td >{L_PASSWORD}</td>
+	  <td >
+		<input type="password" name="password" />
+	  </td>
+	</tr>
+	<tr>
+	  <td >{L_CONFIRM_PASSWORD}</td>
+	  <td >
+		<input type="password" name="password_conf" />
+	  </td>
+	</tr>
+	<tr>
+	  <td >{L_EMAIL}</td>
+	  <td >
+		<input type="text" name="mail_address" value="{F_EMAIL}" />
+	  </td>
+	</tr>
+	<tr>
+	  <td colspan="2">&nbsp;</td>
+	</tr>
+	<tr>
+	<tr>
+	  <td colspan="2" align="center">
+		<input type="submit" name="submit" value="{L_SUBMIT}" class="bouton" />
+	  </td>
+	</tr>
+	<tr>
+	  <td colspan="2" align="center">
+		<a href="./category.php">[ {L_GUEST} ]</a>
+	  </td>
+	</tr>
+  </table>
+</form>
Index: /branches/1.4/template/default/search.tpl
===================================================================
--- /branches/1.4/template/default/search.tpl	(revision 3249)
+++ /branches/1.4/template/default/search.tpl	(revision 3249)
@@ -0,0 +1,131 @@
+<div class="titrePage">{L_SEARCH_TITLE}</div>
+<form method="post" name="post" action="{S_SEARCH_ACTION}">
+<!-- BEGIN errors -->
+<div class="errors">
+  <ul>
+    <!-- BEGIN error -->
+    <li>{errors.error.ERROR}</li>
+    <!-- END error -->
+  </ul>
+</div>
+<!-- END errors -->
+<table width="100%" align="center" cellpadding="2">
+  <tr class="admin">
+    <th colspan="4">{L_SEARCH_TITLE}</th>
+  </tr>
+  <tr> 
+    <td width="50%" colspan="2"><b>{L_SEARCH_KEYWORDS} : </b><br /><span class="small">{L_SEARCH_KEYWORDS_HINT}</span></td>
+    <td colspan="2" valign="top">
+	  <input type="text" style="width: 300px" name="search_allwords" size="30" />
+	  <br />
+	  <input type="radio" name="mode" value="AND" checked="checked" /> {L_SEARCH_ALL_TERMS}<br />
+	  <input type="radio" name="mode" value="OR" /> {L_SEARCH_ANY_TERMS}
+	</td>
+  </tr>
+  <tr> 
+    <td colspan="2"><b>{L_SEARCH_AUTHOR} :</b><br /><span class="small">{L_SEARCH_AUTHOR_HINT}</span></td>
+    <td colspan="2" valign="middle">
+	  <input type="text" style="width: 300px" name="search_author" size="30" />
+	</td>
+  </tr>
+  <tr> 
+    <td colspan="2"><b>{L_SEARCH_DATE} :</b><br /><span class="small">{L_SEARCH_DATE_HINT}</span></td>
+    <td colspan="2" valign="middle">
+      <table>
+        <tr>
+          <td>{L_SEARCH_DATE_FROM} :</td>
+          <td>
+            <select name="start_day">
+              <!-- BEGIN start_day -->
+              <option {start_day.SELECTED} value="{start_day.VALUE}">{start_day.OPTION}</option>
+              <!-- END start_day -->
+            </select>
+            <select name="start_month">
+              <!-- BEGIN start_month -->
+              <option {start_month.SELECTED} value="{start_month.VALUE}">{start_month.OPTION}</option>
+              <!-- END start_month -->
+            </select>
+	    <input name="start_year" type="text" size="4" maxlength="4">&nbsp;
+	    <a href="#" name="#" onClick="document.post.start_day.value={TODAY_DAY};document.post.start_month.value={TODAY_MONTH};document.post.start_year.value={TODAY_YEAR};" />{L_TODAY}</a>
+          </td>
+        </tr>
+        <tr>
+          <td>{L_SEARCH_DATE_TO} :</td>
+          <td>
+            <select name="end_day">
+              <!-- BEGIN end_day -->
+              <option {end_day.SELECTED} value="{end_day.VALUE}">{end_day.OPTION}</option>
+              <!-- END end_day -->
+            </select>
+            <select name="end_month">
+              <!-- BEGIN end_month -->
+              <option {end_month.SELECTED} value="{end_month.VALUE}">{end_month.OPTION}</option>
+              <!-- END end_month -->
+            </select>
+            <input name="end_year" type="text" size="4" maxlength="4">&nbsp;
+	    <a href="#" name="#" onClick="document.post.end_day.value={TODAY_DAY};document.post.end_month.value={TODAY_MONTH};document.post.end_year.value={TODAY_YEAR};" />{L_TODAY}</a>
+          </td>
+        </tr>
+      </table>
+    </td>
+  </tr>
+  <tr class="admin"> 
+    <th colspan="4">{L_SEARCH_OPTIONS}</th>
+  </tr>
+  <tr> 
+    <td width="25%" ><b>{L_SEARCH_CATEGORIES} : </b><br /><span class="small">{L_SEARCH_CATEGORIES_HINT}</span></td>
+    <td width="25%" nowrap="nowrap">
+	  <select style="width:200px" name="cat[]" multiple="multiple" size="8">
+      <!-- BEGIN category_option -->
+        <option value="{category_option.VALUE}">{category_option.OPTION}</option>
+      <!-- END category_option -->
+      </select>
+	</td>
+    <td width="25%" nowrap="nowrap"><b>{L_SEARCH_SUBFORUMS} : </b></td>
+    <td width="25%" nowrap="nowrap">
+	  <input type="radio" name="subcats-included" value="1" checked="checked" />{L_YES}&nbsp;&nbsp;
+	  <input type="radio" name="subcats-included" value="0" />{L_NO}
+	</td>
+   </tr>
+   <tr> 
+    <td width="25%" nowrap="nowrap"><b>{L_SEARCH_DATE_TYPE} : </b></td>
+    <td width="25%" nowrap="nowrap">
+	  <input type="radio" name="date_type" value="date_creation" checked="checked" />{L_SEARCH_CREATION}<br />
+	  <input type="radio" name="date_type" value="date_available" />{L_SEARCH_AVAILABILITY}
+	</td>
+	<td><b>{L_RESULT_SORT} : </b></td>
+    <td nowrap="nowrap">
+	  <input type="radio" name="sd" value="AND" />{L_SORT_ASCENDING}<br />
+	  <input type="radio" name="sd" value="d" checked="checked" />{L_SORT_DESCENDING}
+	</td>
+  </tr>
+<!--  <tr> 
+    <td width="25%" nowrap="nowrap"><b>{L_SEARCH_WITHIN} : </b></td>
+    <td width="25%" nowrap="nowrap">
+	  <input type="radio" name="search_fields" value="all" checked="checked" />{L_SEARCH_ALL}<br />
+	  <input type="radio" name="search_fields" value="imgonly" />{L_SEARCH_IMG_ONLY}<br />
+	  <input type="radio" name="search_fields" value="commentsonly" />{L_SEARCH_COMMENTS_ONLY}
+	</td>
+  </tr>
+  <tr>
+    <td><b>{L_RESULT_SORT} : </b></td>
+    <td nowrap="nowrap">
+	  {S_SELECT_SORT_KEY}<br />
+	  <input type="radio" name="sd" value="a" />{L_SORT_ASCENDING}<br />
+	  <input type="radio" name="sd" value="d" checked="checked" />{L_SORT_DESCENDING}
+	</td>
+    <td nowrap="nowrap"><b>{L_DISPLAY_RESULTS} : </b></td>
+    <td nowrap="nowrap">
+	  <input type="radio" name="show_results" value="images" checked="checked" />{L_IMAGES}&nbsp;&nbsp;
+	  <input type="radio" name="show_results" value="comments" /> {L_COMMENTS}
+	</td>
+  </tr>  
+  -->
+<tr> 
+<td align="center" valign="bottom" colspan="4" height="38">
+<input type="submit" name="submit" value="{L_SUBMIT}" class="bouton" />&nbsp;&nbsp;
+<input type="reset" value="{L_RESET}" class="bouton" />
+</td>
+</table>
+</form>
+<a href="{U_HOME}" title="{L_RETURN_HINT}">[ {L_RETURN} ]</a>
Index: /branches/1.4/template/default/upgrade.tpl
===================================================================
--- /branches/1.4/template/default/upgrade.tpl	(revision 3249)
+++ /branches/1.4/template/default/upgrade.tpl	(revision 3249)
@@ -0,0 +1,45 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"  />
+    <title>PhpWebGallery : Upgrade to {RELEASE}</title>
+  </head>
+
+  <body>
+    <!-- BEGIN choices -->
+    <h1>Welcome to PhpWebGallery upgrade page.</h1>
+    <p>This page proposes to upgrade your database corresponding to your old version
+      of PhpWebGallery to the current version. Select the version you wish to upgrade
+      :</p>
+
+    <ul>
+      <!-- BEGIN choice -->
+      <li><a href="{choices.choice.URL}">{choices.choice.VERSION}</a></li>
+      <!-- END choice -->
+    </ul>
+    <!-- END choices -->
+
+    <!-- BEGIN upgrade -->
+    <h1>Upgrade from version {upgrade.VERSION} to {RELEASE}</h1>
+
+    <p>Statistics</p>
+    <ul>
+      <li>total upgrade time : {upgrade.TOTAL_TIME}</li>
+      <li>total SQL time : {upgrade.SQL_TIME}</li>
+      <li>SQL queries : {upgrade.NB_QUERIES}</li>
+    </ul>
+
+    <!-- BEGIN infos -->
+    <p>Upgrade informations</p>
+
+    <ul>
+      <!-- BEGIN info -->
+      <li>{upgrade.infos.info.CONTENT}</li>
+      <!-- END info -->
+    </ul>
+    <!-- END infos -->
+    <!-- END upgrade -->
+  </body>
+
+</html>
Index: /branches/1.4/template/default/upload.tpl
===================================================================
--- /branches/1.4/template/default/upload.tpl	(revision 3249)
+++ /branches/1.4/template/default/upload.tpl	(revision 3249)
@@ -0,0 +1,93 @@
+<div class="titrePage">{L_TITLE}</div>
+<!-- BEGIN upload_not_successful -->
+<form enctype="multipart/form-data" method="post" action="{F_ACTION}">
+  <table style="width:80%;margin-left:auto;margin-right:auto;">
+	<!-- BEGIN errors -->
+		  <tr>
+			<td colspan="2">
+			  <div class="errors">
+				<ul>
+				  <!-- BEGIN error -->
+				  <li>{upload_not_successful.errors.error.ERROR}</li>
+				  <!-- END error -->
+				</ul>
+			  </div>
+			</td>
+		  </tr>
+		  <!-- END errors -->
+	<tr>
+	  <td colspan="2" class="menu">
+		<div style="text-align:center;">{ADVISE_TITLE}</div>
+		<ul>
+		  <!-- BEGIN advise -->
+		  <li>{upload_not_successful.advise.ADVISE}</li>
+		  <!-- END advise -->
+		</ul>
+	  </td>
+	</tr>
+	<tr>
+	  <td colspan="2" align="center" style="padding:10px;">
+		<input name="picture" type="file" value="" />
+	  </td>
+	</tr>
+	<!-- BEGIN fields -->
+	<!-- username  -->
+	<tr>
+	  <td class="menu">{L_USERNAME} <span style="color:red;">*</span></td>
+	  <td align="center" style="padding:10px;">
+		<input name="username" type="text" value="{NAME}" />
+	  </td>
+	</tr>
+	<!-- mail address  -->
+	<tr>
+	  <td class="menu">{L_EMAIL} <span style="color:red;">*</span></td>
+	  <td align="center" style="padding:10px;">
+		<input name="mail_address" type="text" value="{EMAIL}" />
+	  </td>
+	</tr>
+	<!-- name of the picture  -->
+	<tr>
+	  <td class="menu">{L_NAME_IMG}</td>
+	  <td align="center" style="padding:10px;">
+		<input name="name" type="text" value="{NAME_IMG}" />
+	  </td>
+	</tr>
+	<!-- author  -->
+	<tr>
+	  <td class="menu">{L_AUTHOR}</td>
+	  <td align="center" style="padding:10px;">
+		<input name="author" type="text" value="{AUTHOR_IMG}" />
+	  </td>
+	</tr>
+	<!-- date of creation  -->
+	<tr>
+	  <td class="menu">{L_CREATION_DATE}</td>
+	  <td align="center" style="padding:10px;">
+		<input name="date_creation" type="text" value="{DATE_IMG}" />
+	  </td>
+	</tr>
+	<!-- comment  -->
+	<tr>
+	  <td class="menu">{L_COMMENT}</td>
+	  <td align="center" style="padding:10px;">
+	   <textarea name="comment" rows="3" cols="40" style="overflow:auto">{COMMENT_IMG}</textarea>
+	  </td>
+	</tr>
+	<!-- END fields -->
+	<tr>
+	  <td colspan="2" align="center">
+		<input name="submit" type="submit" value="{L_SUBMIT}" class="bouton" />
+	  </td>
+	</tr>
+  </table>
+</form>
+<!-- END upload_not_successful -->
+<!-- BEGIN upload_successful -->
+{L_UPLOAD_DONE}<br />
+<!-- END upload_successful -->
+<div style="text-align:center;">
+  <a href="{U_RETURN}">[ {L_RETURN} ]</a>
+</div>
+<!-- BEGIN note -->
+<div style="text-align:left;"><span style="color:red;">*</span> : {L_MANDATORY}</div>
+<!-- END note -->
Index: /branches/1.4/tools/create_listing_file.php
===================================================================
--- /branches/1.4/tools/create_listing_file.php	(revision 3249)
+++ /branches/1.4/tools/create_listing_file.php	(revision 3249)
@@ -0,0 +1,552 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// +-----------------------------------------------------------------------+
+// |                              parameters                               |
+// +-----------------------------------------------------------------------+
+
+// prefix for thumbnails in "thumbnail" sub directories
+$conf['prefix_thumbnail'] = 'TN-';
+
+// $conf['file_ext'] lists all extensions (case insensitive) allowed for
+// your PhpWebGallery installation
+$conf['file_ext'] = array('jpg','JPG','png','PNG','gif','GIF','mpg','zip',
+                          'avi','mp3','ogg');
+
+// $conf['picture_ext'] must be a subset of $conf['file_ext']
+$conf['picture_ext'] = array('jpg','JPG','png','PNG','gif','GIF');
+
+// $conf['version'] is used to verify the compatibility of the generated
+// listing.xml file and the PhpWebGallery version you're running
+$conf['version'] = '1.4.1';
+
+// $conf['use_exif'] set to true if you want to use Exif Date as "creation
+// date" for the element, otherwise, set to false
+$conf['use_exif'] = true;
+
+// $conf['use_iptc'] set to true if you want to use IPTC informations of the
+// element according to get_sync_iptc_data function mapping, otherwise, set
+// to false
+$conf['use_iptc'] = false;
+
+// use_iptc_mapping : in which IPTC fields will PhpWebGallery find image
+// information ? This setting is used during metadata synchronisation. It
+// associates a phpwebgallery_images column name to a IPTC key
+$conf['use_iptc_mapping'] = array(
+  'keywords'        => '2#025',
+  'date_creation'   => '2#055',
+  'author'          => '2#122',
+  'name'            => '2#005',
+  'comment'         => '2#120'
+  );
+
+// +-----------------------------------------------------------------------+
+// |                               functions                               |
+// +-----------------------------------------------------------------------+
+
+/**
+ * returns informations from IPTC metadata, mapping is done at the beginning
+ * of the function
+ *
+ * @param string $filename
+ * @return array
+ */
+function get_iptc_data($filename, $map)
+{
+  $result = array();
+  
+  // Read IPTC data
+  $iptc = array();
+  
+  $imginfo = array();
+  getimagesize($filename, $imginfo);
+  
+  if (isset($imginfo['APP13']))
+  {
+    $iptc = iptcparse($imginfo['APP13']);
+    if (is_array($iptc))
+    {
+      $rmap = array_flip($map);
+      foreach (array_keys($rmap) as $iptc_key)
+      {
+        if (isset($iptc[$iptc_key][0]))
+        {
+          if ($iptc_key == '2#025')
+          {
+            $value = implode(',',
+                             array_map('clean_iptc_value',$iptc[$iptc_key]));
+          }
+          else
+          {
+            $value = clean_iptc_value($iptc[$iptc_key][0]);
+          }
+
+          foreach (array_keys($map, $iptc_key) as $pwg_key)
+          {
+            $result[$pwg_key] = $value;
+          }
+        }
+      }
+    }
+  }
+  return $result;
+}
+
+/**
+ * return a cleaned IPTC value
+ *
+ * @param string value
+ * @return string
+ */
+function clean_iptc_value($value)
+{
+  // strip leading zeros (weird Kodak Scanner software)
+  while ($value[0] == chr(0))
+  {
+    $value = substr($value, 1);
+  }
+  // remove binary nulls
+  $value = str_replace(chr(0x00), ' ', $value);
+  
+  return htmlentities($value);
+}
+
+function get_sync_iptc_data($file)
+{
+  global $conf;
+
+  $map = $conf['use_iptc_mapping'];
+  $datefields = array('date_creation', 'date_available');
+  
+  $iptc = get_iptc_data($file, $map);
+
+  foreach ($iptc as $pwg_key => $value)
+  {
+    if (in_array($pwg_key, $datefields))
+    {
+      if ( preg_match('/(\d{4})(\d{2})(\d{2})/', $value, $matches))
+      {
+        $iptc[$pwg_key] = $matches[1].'-'.$matches[2].'-'.$matches[3];
+      }
+    }
+  }
+
+  if (isset($iptc['keywords']))
+  {
+    // keywords separator is the comma, nothing else. Allowed characters in
+    // keywords : [A-Za-z0-9], "-" and "_". All other characters will be
+    // considered as separators
+    $iptc['keywords'] = preg_replace('/[^\w-]+/', ',', $iptc['keywords']);
+    $iptc['keywords'] = preg_replace('/^,+|,+$/', '', $iptc['keywords']);
+  }
+
+  return $iptc;
+}
+
+/**
+ * returns a float value coresponding to the number of seconds since the
+ * unix epoch (1st January 1970) and the microseconds are precised :
+ * e.g. 1052343429.89276600
+ *
+ * @return float
+ */
+function get_moment()
+{
+  $t1 = explode(' ', microtime());
+  $t2 = explode('.', $t1[0]);
+  $t2 = $t1[1].'.'.$t2[1];
+  return $t2;
+}
+
+/**
+ * returns the number of seconds (with 3 decimals precision) between the
+ * start time and the end time given.
+ *
+ * @param float start
+ * @param float end
+ * @return void
+ */
+function get_elapsed_time($start, $end)
+{
+  return number_format($end - $start, 3, '.', ' ').' s';
+}
+
+/**
+ * returns an array with all picture files according to $conf['file_ext']
+ *
+ * @param string $dir
+ * @return array
+ */
+function get_pwg_files($dir)
+{
+  global $conf;
+
+  $pictures = array();
+  if ($opendir = opendir($dir))
+  {
+    while ($file = readdir($opendir))
+    {
+      if (in_array(get_extension($file), $conf['file_ext']))
+      {
+        array_push($pictures, $file);
+        if (!preg_match('/^[a-zA-Z0-9-_.]+$/', $file))
+        {
+          echo 'PWG-WARNING-2: "'.$file.'" : ';
+          echo 'The name of the file should be composed of ';
+          echo 'letters, figures, "-", "_" or "." ONLY';
+          echo "\n";
+        }
+      }
+    }
+  }
+  return $pictures;
+}
+
+/**
+ * returns an array with all thumbnails according to $conf['picture_ext']
+ * and $conf['prefix_thumbnail']
+ *
+ * @param string $dir
+ * @return array
+ */
+function get_thumb_files($dir)
+{
+  global $conf;
+
+  $prefix_length = strlen($conf['prefix_thumbnail']);
+  
+  $thumbnails = array();
+  if ($opendir = @opendir($dir.'/thumbnail'))
+  {
+    while ($file = readdir($opendir))
+    {
+      if (in_array(get_extension($file), $conf['picture_ext'])
+          and substr($file,0,$prefix_length) == $conf['prefix_thumbnail'])
+      {
+        array_push($thumbnails, $file);
+      }
+    }
+  }
+  return $thumbnails;
+}
+
+/**
+ * returns an array with representative picture files of a directory
+ * according to $conf['picture_ext']
+ *
+ * @param string $dir
+ * @return array
+ */
+function get_representative_files($dir)
+{
+  global $conf;
+
+  $pictures = array();
+  if ($opendir = @opendir($dir.'/pwg_representative'))
+  {
+    while ($file = readdir($opendir))
+    {
+      if (in_array(get_extension($file), $conf['picture_ext']))
+      {
+        array_push($pictures, $file);
+      }
+    }
+  }
+  return $pictures;
+}
+
+/**
+ * search in $basedir the sub-directories and calls get_pictures
+ *
+ * @return void
+ */
+function get_dirs($basedir, $indent, $level)
+{
+  $fs_dirs = array();
+  $dirs = "";
+
+  if ($opendir = opendir($basedir))
+  {
+    while ($file = readdir($opendir))
+    {
+      if ($file != '.'
+          and $file != '..'
+          and $file != 'thumbnail'
+          and $file != 'pwg_high'
+          and $file != 'pwg_representative'
+          and is_dir ($basedir.'/'.$file))
+      {
+        array_push($fs_dirs, $file);
+        if (!preg_match('/^[a-zA-Z0-9-_.]+$/', $file))
+        {
+          echo 'PWG-WARNING-1: "'.$file.'" : ';
+          echo 'The name of the directory should be composed of ';
+          echo 'letters, figures, "-", "_" or "." ONLY';
+          echo "\n";
+        }
+      }
+    }
+  }
+  // write of the dirs
+  foreach ($fs_dirs as $fs_dir)
+  {
+    $dirs.= "\n".$indent.'<dir'.$level.' name="'.$fs_dir.'">';
+    $dirs.= get_pictures($basedir.'/'.$fs_dir, $indent.'  ');
+    $dirs.= get_dirs($basedir.'/'.$fs_dir, $indent.'  ', $level + 1);
+    $dirs.= "\n".$indent.'</dir'.$level.'>';
+  }
+  return $dirs;		
+}
+
+// get_extension returns the part of the string after the last "."
+function get_extension($filename)
+{
+  return substr(strrchr($filename, '.'), 1, strlen ($filename));
+}
+
+// get_filename_wo_extension returns the part of the string before the last
+// ".".
+// get_filename_wo_extension('test.tar.gz') -> 'test.tar'
+function get_filename_wo_extension($filename)
+{
+  return substr($filename, 0, strrpos($filename, '.'));
+}
+
+function get_pictures($dir, $indent)
+{
+  global $conf, $page;
+  
+  // fs means FileSystem : $fs_files contains files in the filesystem found
+  // in $dir that can be managed by PhpWebGallery (see get_pwg_files
+  // function), $fs_thumbnails contains thumbnails, $fs_representatives
+  // contains potentially representative pictures for non picture files
+  $fs_files = get_pwg_files($dir);
+  $fs_thumbnails = get_thumb_files($dir);
+  $fs_representatives = get_representative_files($dir);
+
+  $elements = array();
+
+  $print_dir = preg_replace('/^\.\//', '', $dir);
+  $print_dir = preg_replace('/\/*$/', '/', $print_dir);
+  
+  foreach ($fs_files as $fs_file)
+  {
+    $element = array();
+    $element['file'] = $fs_file;
+    $element['path'] = $page['url'].$print_dir.$fs_file;
+    $element['filesize'] = floor(filesize($dir.'/'.$fs_file) / 1024);
+    
+    $file_wo_ext = get_filename_wo_extension($fs_file);
+
+    foreach ($conf['picture_ext'] as $ext)
+    {
+      $test = $conf['prefix_thumbnail'].$file_wo_ext.'.'.$ext;
+      if (!in_array($test, $fs_thumbnails))
+      {
+        continue;
+      }
+      else
+      {
+        $element['tn_ext'] = $ext;
+        break;
+      }
+    }
+
+    // 2 cases : the element is a picture or not. Indeed, for a picture
+    // thumbnail is mandatory and for non picture element, thumbnail and
+    // representative is optionnal
+    if (in_array(get_extension($fs_file), $conf['picture_ext']))
+    {
+      // if we found a thumnbnail corresponding to our picture...
+      if (isset($element['tn_ext']))
+      {
+        if ($image_size = @getimagesize($dir.'/'.$fs_file))
+        {
+          $element['width'] = $image_size[0];
+          $element['height'] = $image_size[1];
+        }
+
+        if ($conf['use_exif'])
+        {
+          if ($exif = @read_exif_data($dir.'/'.$fs_file))
+          {
+            if (isset($exif['DateTime']))
+            {
+              preg_match('/^(\d{4}):(\d{2}):(\d{2})/'
+                         ,$exif['DateTime']
+                         ,$matches);
+              $element['date_creation'] =
+                $matches[1].'-'.$matches[2].'-'.$matches[3];
+            }
+          }
+        }
+
+        if ($conf['use_iptc'])
+        {
+          $iptc = get_sync_iptc_data($dir.'/'.$fs_file);
+          if (count($iptc) > 0)
+          {
+            foreach (array_keys($iptc) as $key)
+            {
+              $element[$key] = addslashes($iptc[$key]);
+            }
+          }
+        }
+        
+        array_push($elements, $element);
+      }
+      else
+      {
+        echo 'PWG-ERROR-1: The thumbnail is missing for '.$dir.'/'.$fs_file;
+        echo '-> '.$dir.'/thumbnail/';
+        echo $conf['prefix_thumbnail'].$file_wo_ext.'.xxx';
+        echo ' ("xxx" can be : ';
+        echo implode(', ', $conf['picture_ext']);
+        echo ')'."\n";
+      }
+    }
+    else
+    {
+      foreach ($conf['picture_ext'] as $ext)
+      {
+        $candidate = $file_wo_ext.'.'.$ext;
+        if (!in_array($candidate, $fs_representatives))
+        {
+          continue;
+        }
+        else
+        {
+          $element['representative_ext'] = $ext;
+          break;
+        }
+      }
+      
+      array_push($elements, $element);
+    }
+  }
+
+  $xml = "\n".$indent.'<root>';
+  $attributes = array('file','tn_ext','representative_ext','filesize',
+                      'width','height','date_creation','author','keywords',
+                      'name','comment','path');
+  foreach ($elements as $element)
+  {
+    $xml.= "\n".$indent.'  ';
+    $xml.= '<element';
+    foreach ($attributes as $attribute)
+    {
+      if (isset($element{$attribute}))
+      {
+        $xml.= ' '.$attribute.'="'.$element{$attribute}.'"';
+      }
+    }
+    $xml.= ' />';
+  }
+  $xml.= "\n".$indent.'</root>';
+
+  return $xml;
+}
+
+// +-----------------------------------------------------------------------+
+// |                                script                                 |
+// +-----------------------------------------------------------------------+
+if (isset($_GET['action']))
+{
+  $page['action'] = $_GET['action'];
+}
+else
+{
+  $page['action'] = 'generate';
+}
+echo '<pre>';
+switch ($page['action'])
+{
+  case 'generate' :
+  {
+    $start = get_moment();
+    
+    $listing = '<informations';
+    $listing.= ' generation_date="'.date('Y-m-d').'"';
+    $listing.= ' phpwg_version="'.$conf{'version'}.'"';
+    
+    $end = strrpos($_SERVER['PHP_SELF'], '/') + 1;
+    $local_folder = substr($_SERVER['PHP_SELF'], 0, $end);
+    $page['url'] = 'http://'.$_SERVER['HTTP_HOST'].$local_folder;
+    
+    $listing.= ' url="'.$page['url'].'"';
+    $listing.= '/>'."\n";
+    
+    $listing.= get_dirs('.', '', 0);
+    
+    if ($fp = @fopen("./listing.xml","w"))
+    {
+      fwrite($fp, $listing);
+      fclose($fp);
+      echo 'PWG-INFO-1: listing.xml created in ';
+      echo get_elapsed_time($start, get_moment());
+      echo "\n";
+    }
+    else
+    {
+      echo "PWG-ERROR-2: I can't write the file listing.xml"."\n";
+    }
+    break;
+  }
+  case 'test' :
+  {
+    if (isset($_GET['version']))
+    {
+      if ($_GET['version'] != $conf['version'])
+      {
+        echo 'PWG-ERROR-4: PhpWebGallery versions differs'."\n";
+      }
+      else
+      {
+        echo 'PWG-INFO-2: test successful'."\n";
+      }
+    }
+    else
+    {
+      echo 'PWG-INFO-2: test successful'."\n";
+    }
+    break;
+  }
+  case 'clean' :
+  {
+    if( @unlink('./listing.xml'))
+    {
+      echo 'PWG-INFO-3 : listing.xml file deleted'."\n";
+    }
+    else
+    {
+      echo 'PWG-ERROR-3 : listing.xml does not exist'."\n";
+    }
+    break;
+  }
+}
+echo '</pre>';
+?>
Index: /branches/1.4/tools/metadata.php
===================================================================
--- /branches/1.4/tools/metadata.php	(revision 3249)
+++ /branches/1.4/tools/metadata.php	(revision 3249)
@@ -0,0 +1,74 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+$filename = 'sample.jpg';
+echo 'Informations are read from '.$filename.'<br /><br /><br />';
+
+$iptc_result = array();
+$imginfo = array();
+getimagesize($filename, $imginfo);
+if (isset($imginfo['APP13']))
+{
+  $iptc = iptcparse($imginfo['APP13']);
+  if (is_array($iptc))
+  {
+    foreach (array_keys($iptc) as $iptc_key)
+    {
+      if (isset($iptc[$iptc_key][0]) and $value = $iptc[$iptc_key][0])
+      {
+        // strip leading zeros (weird Kodak Scanner software)
+        while ($value[0] == chr(0))
+        {
+          $value = substr($value, 1);
+        }
+        // remove binary nulls
+        $value = str_replace(chr(0x00), ' ', $value);
+      }
+      $iptc_result[$iptc_key] = $value;
+    }
+  }
+
+  echo 'IPTC Fields in '.$filename.'<br />';
+  $keys = array_keys($iptc_result);
+  sort($keys);
+  foreach ($keys as $key)
+  {
+    echo '<br />'.$key.' = '.$iptc_result[$key];
+  }
+}
+else
+{
+  echo 'no IPTC information';
+}
+
+echo '<br /><br /><br />';
+echo 'EXIF Fields in '.$filename.'<br />';
+$exif = read_exif_data($filename);
+echo '<pre>';
+print_r($exif);
+echo '</pre>';
+?>
Index: /branches/1.4/upgrade.php
===================================================================
--- /branches/1.4/upgrade.php	(revision 3249)
+++ /branches/1.4/upgrade.php	(revision 3249)
@@ -0,0 +1,200 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+define('IN_UPGRADE', true);
+define('PHPWG_ROOT_PATH', './');
+
+include_once(PHPWG_ROOT_PATH.'include/functions.inc.php');
+include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+include(PHPWG_ROOT_PATH.'include/template.php');
+
+include(PHPWG_ROOT_PATH.'include/mysql.inc.php');
+// Is PhpWebGallery already installed ?
+if (defined('PHPWG_INSTALLED'))
+{
+  $message = 'PhpWebGallery is already installed. In include/mysql.inc.php,
+remove line
+<pre style="background-color:lightgray">
+define(\'PHPWG_INSTALLED\', true);
+</pre>
+if you want to upgrade';
+  die($message);
+}
+
+include_once(PHPWG_ROOT_PATH.'include/constants.php');
+define('PREFIX_TABLE', $prefixeTable);
+
+$conf['show_queries'] = false;
+
+// Database connection
+mysql_connect( $cfgHote, $cfgUser, $cfgPassword )
+or die ( "Could not connect to database server" );
+mysql_select_db( $cfgBase )
+or die ( "Could not connect to database" );
+// +-----------------------------------------------------------------------+
+// |                            tricky output                              |
+// +-----------------------------------------------------------------------+
+echo '<!-- This is an HTML comment given in order to make IE outputs';
+echo ' the code.'."\n";
+echo ' Indeed, IE doesn\'t start to send output until a limit';
+echo ' of XXX bytes '."\n";
+echo str_repeat( ' ', 80 )."\n";
+echo str_repeat( ' ', 80 )."\n";
+echo str_repeat( ' ', 80 )."\n";
+echo '-->'."\n";
+flush();
+// +-----------------------------------------------------------------------+
+// |                              functions                                |
+// +-----------------------------------------------------------------------+
+
+/**
+ * loads an sql file and executes all queries
+ *
+ * Before executing a query, $replaced is... replaced by $replacing. This is
+ * useful when the SQL file contains generic words. Drop table queries are
+ * not executed.
+ *
+ * @param string filepath
+ * @param string replaced
+ * @param string replacing
+ * @return void
+ */
+function execute_sqlfile($filepath, $replaced, $replacing)
+{
+  $sql_lines = file($filepath);
+  $query = '';
+  foreach ($sql_lines as $sql_line)
+  {
+    $sql_line = trim($sql_line);
+    if (preg_match('/(^--|^$)/', $sql_line))
+    {
+      continue;
+    }
+    $query.= ' '.$sql_line;
+    // if we reached the end of query, we execute it and reinitialize the
+    // variable "query"
+    if (preg_match('/;$/', $sql_line))
+    {
+      $query = trim($query);
+      $query = str_replace($replaced, $replacing, $query);
+      // we don't execute "DROP TABLE" queries
+      if (!preg_match('/^DROP TABLE/i', $query))
+      {
+        mysql_query($query);
+      }
+      $query = '';
+    }
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                        template initialization                        |
+// +-----------------------------------------------------------------------+
+$template = setup_style('default');
+$template->set_filenames(array('upgrade'=>'upgrade.tpl'));
+$template->assign_vars(array('RELEASE'=>PHPWG_VERSION));
+// +-----------------------------------------------------------------------+
+// |                          versions upgradable                          |
+// +-----------------------------------------------------------------------+
+$versions = array();
+$path = PHPWG_ROOT_PATH.'install';
+if ($contents = opendir($path))
+{
+  while (($node = readdir($contents)) !== false)
+  {
+    if (is_file($path.'/'.$node)
+        and preg_match('/^upgrade_(.*?)\.php$/', $node, $match))
+    {
+      array_push($versions, $match[1]);
+    }
+  }
+}
+natcasesort($versions);
+// +-----------------------------------------------------------------------+
+// |                            upgrade choice                             |
+// +-----------------------------------------------------------------------+
+if (!isset($_GET['version']))
+{
+  $template->assign_block_vars('choices', array());
+  foreach ($versions as $version)
+  {
+    $template->assign_block_vars(
+      'choices.choice',
+      array(
+        'URL' => PHPWG_ROOT_PATH.'upgrade.php?version='.$version,
+        'VERSION' => $version
+        ));
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                            upgrade launch                             |
+// +-----------------------------------------------------------------------+
+else
+{
+  $upgrade_file = $path.'/upgrade_'.$_GET['version'].'.php';
+  if (is_file($upgrade_file))
+  {
+    $page['upgrade_start'] = get_moment();
+    include($upgrade_file);
+    $page['upgrade_end'] = get_moment();
+
+    $template->assign_block_vars(
+      'upgrade',
+      array(
+        'VERSION' => $_GET['version'],
+        'TOTAL_TIME' => get_elapsed_time($page['upgrade_start'],
+                                         $page['upgrade_end']),
+        'SQL_TIME' => number_format($page['queries_time'], 3, '.', ' ').' s',
+        'NB_QUERIES' => $page['count_queries']
+        ));
+
+    if (!isset($infos))
+    {
+      $infos = array();
+    }
+    array_push(
+      $infos,
+      '[security] delete files "upgrade.php", "install.php" and "install"
+directory');
+    
+    $template->assign_block_vars('upgrade.infos', array());
+    
+    foreach ($infos as $info)
+    {
+      $template->assign_block_vars('upgrade.infos.info',
+                                   array('CONTENT' => $info));
+    }
+  }
+  else
+  {
+    die('Hacking attempt');
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                          sending html code                            |
+// +-----------------------------------------------------------------------+
+$template->pparse('upgrade');
+?>
Index: /branches/1.4/upload.php
===================================================================
--- /branches/1.4/upload.php	(revision 3249)
+++ /branches/1.4/upload.php	(revision 3249)
@@ -0,0 +1,379 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date$
+// | last modifier : $Author$
+// | revision      : $Revision$
+// +-----------------------------------------------------------------------+
+// | 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.                                                                  |
+// +-----------------------------------------------------------------------+
+define('PHPWG_ROOT_PATH','./');
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+
+//------------------------------------------------------------------- functions
+// The validate_upload function checks if the image of the given path is valid.
+// A picture is valid when :
+//     - width, height and filesize are not higher than the maximum
+//       filesize authorized by the administrator
+//     - the type of the picture is among jpg, gif and png
+// The function returns an array containing :
+//     - $result['type'] contains the type of the image ('jpg', 'gif' or 'png')
+//     - $result['error'] contains an array with the different errors
+//       found with the picture
+function validate_upload( $temp_name, $my_max_file_size,
+                          $image_max_width, $image_max_height )
+{
+  global $conf, $lang;
+		
+  $result = array();
+  $result['error'] = array();
+  //echo $_FILES['picture']['name']."<br />".$temp_name;
+  $extension = get_extension( $_FILES['picture']['name'] );
+  if (!in_array($extension, $conf['picture_ext']))
+  {
+    array_push( $result['error'], $lang['upload_advise_filetype'] );
+    return $result;
+  }
+  if ( !isset( $_FILES['picture'] ) )
+  {
+    // do we even have a file?
+    array_push( $result['error'], "You did not upload anything!" );
+  }
+  else if ( $_FILES['picture']['size'] > $my_max_file_size * 1024 )
+  {
+    array_push( $result['error'],
+                $lang['upload_advise_filesize'].$my_max_file_size.' KB' );
+  }
+  else
+  {
+    // check if we are allowed to upload this file_type
+    // upload de la photo sous un nom temporaire
+    if ( !move_uploaded_file( $_FILES['picture']['tmp_name'], $temp_name ) )
+    {
+      array_push( $result['error'], $lang['upload_cannot_upload'] );
+    }
+    else
+    {
+      $size = getimagesize( $temp_name );
+      if ( isset( $image_max_width )
+           and $image_max_width != ""
+           and $size[0] > $image_max_width )
+      {
+        array_push( $result['error'],
+                    $lang['upload_advise_width'].$image_max_width.' px' );
+      }
+      if ( isset( $image_max_height )
+           and $image_max_height != ""
+           and $size[1] > $image_max_height )
+      {
+        array_push( $result['error'],
+                    $lang['upload_advise_height'].$image_max_height.' px' );
+      }
+      // $size[2] == 1 means GIF
+      // $size[2] == 2 means JPG
+      // $size[2] == 3 means PNG
+      switch ( $size[2] )
+      {
+      case 1 : $result['type'] = 'gif'; break;
+      case 2 : $result['type'] = 'jpg'; break;
+      case 3 : $result['type'] = 'png'; break;
+      default :
+        array_push( $result['error'], $lang['upload_advise_filetype'] );  
+      }
+    }
+  }
+  if ( sizeof( $result['error'] ) > 0 )
+  {
+    // destruction de l'image avec le nom temporaire
+    @unlink( $temp_name );
+  }
+  else
+  {
+    @chmod( $temp_name, 0644);
+  }
+  return $result;
+}	
+
+//-------------------------------------------------- access authorization check
+check_login_authorization();
+check_cat_id( $_GET['cat'] );
+if ( isset( $page['cat'] ) and is_numeric( $page['cat'] ) )
+{
+  check_restrictions( $page['cat'] );
+  $result = get_cat_info( $page['cat'] );
+  $page['cat_dir']        = get_complete_dir( $page['cat'] );
+  $page['cat_site_id']    = $result['site_id'];
+  $page['cat_name']       = $result['name'];
+  $page['cat_uploadable'] = $result['uploadable'];
+  if ($page['cat_site_id'] != 1 or !$page['cat_uploadable'])
+  {
+    echo '<div style="text-align:center;">'.$lang['upload_forbidden'].'<br />';
+    echo '<a href="'.add_session_id( './category.php' ).'">';
+    echo $lang['thumbnails'].'</a></div>';
+    exit();
+  }
+}
+
+$error = array();
+$page['upload_successful'] = false;
+if ( isset( $_GET['waiting_id'] ) )
+{
+  $page['waiting_id'] = $_GET['waiting_id'];
+}
+//-------------------------------------------------------------- picture upload
+// verfying fields
+if ( isset( $_POST['submit'] ) and !isset( $_GET['waiting_id'] ) )
+{
+  $path = $page['cat_dir'].$_FILES['picture']['name'];
+  if ( @is_file( $path ) )
+  {
+    array_push( $error, $lang['upload_file_exists'] );
+  }
+  // test de la présence des champs obligatoires
+  if ( empty($_FILES['picture']['name']))
+  {
+    array_push( $error, $lang['upload_filenotfound'] );
+  }
+  if ( !ereg( "([_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)+)",
+             $_POST['mail_address'] ) )
+  {
+    array_push( $error, $lang['reg_err_mail_address'] );
+  }
+  if ( empty($_POST['username']) )
+  {
+    array_push( $error, $lang['upload_err_username'] );
+  }
+  
+  $date_creation = '';
+  if ( !empty($_POST['date_creation']) )
+  {
+    list( $day,$month,$year ) = explode( '/', $_POST['date_creation'] );
+    // int checkdate ( int month, int day, int year)
+    if (checkdate($month, $day, $year))
+    {
+      $date_creation = $year.'-'.$month.'-'.$day;
+    }
+    else
+    {
+      array_push( $error, $lang['err_date'] );
+    }
+  }
+  // creation of the "infos" field :
+  // <infos author="Pierrick LE GALL" comment="my comment"
+  //        date_creation="2004-08-14" name="" />
+  $xml_infos = '<infos';
+  $xml_infos.= ' author="'.htmlspecialchars($_POST['author'],ENT_QUOTES).'"';
+  $xml_infos.= ' comment="'.htmlspecialchars($_POST['comment'],ENT_QUOTES).'"';
+  $xml_infos.= ' date_creation="'.$date_creation.'"';
+  $xml_infos.= ' name="'.htmlspecialchars( $_POST['name'], ENT_QUOTES).'"';
+  $xml_infos.= ' />';
+
+  if ( !preg_match( '/^[a-zA-Z0-9-_.]+$/', $_FILES['picture']['name'] ) )
+  {
+    array_push( $error, $lang['update_wrong_dirname'] );
+  }
+  
+  if ( sizeof( $error ) == 0 )
+  {
+    $result = validate_upload( $path, $conf['upload_maxfilesize'],
+                               $conf['upload_maxwidth'],
+                               $conf['upload_maxheight']  );
+    for ( $j = 0; $j < sizeof( $result['error'] ); $j++ )
+    {
+      array_push( $error, $result['error'][$j] );
+    }
+  }
+
+  if ( sizeof( $error ) == 0 )
+  {
+    $query = 'insert into '.WAITING_TABLE;
+    $query.= ' (storage_category_id,file,username,mail_address,date,infos)';
+    $query.= ' values ';
+    $query.= '('.$page['cat'].",'".$_FILES['picture']['name']."'";
+    $query.= ",'".htmlspecialchars( $_POST['username'], ENT_QUOTES)."'";
+    $query.= ",'".$_POST['mail_address']."',".time().",'".$xml_infos."')";
+    $query.= ';';
+    pwg_query( $query );
+    $page['waiting_id'] = mysql_insert_id();
+    // mail notification for administrators
+    if ( $conf['mail_notification'] )
+    {
+      notify( 'upload' );
+    }
+  }
+}
+
+//------------------------------------------------------------ thumbnail upload
+if ( isset( $_POST['submit'] ) and isset( $_GET['waiting_id'] ) )
+{
+  // upload of the thumbnail
+  $query = 'select file';
+  $query.= ' from '.WAITING_TABLE;
+  $query.= ' where id = '.$_GET['waiting_id'];
+  $query.= ';';
+  $result= pwg_query( $query );
+  $row = mysql_fetch_array( $result );
+  $file = substr ( $row['file'], 0, strrpos ( $row['file'], ".") );
+  $extension = get_extension( $_FILES['picture']['name'] );
+  $path = $page['cat_dir'].'thumbnail/';
+  $path.= $conf['prefix_thumbnail'].$file.'.'.$extension;
+  $result = validate_upload( $path, $conf['upload_maxfilesize'],
+                             $conf['upload_maxwidth_thumbnail'],
+                             $conf['upload_maxheight_thumbnail']  );
+  for ( $j = 0; $j < sizeof( $result['error'] ); $j++ )
+  {
+    array_push( $error, $result['error'][$j] );
+  }
+  if ( sizeof( $error ) == 0 )
+  {
+    $query = 'update '.WAITING_TABLE;
+    $query.= " set tn_ext = '".$extension."'";
+    $query.= ' where id = '.$_GET['waiting_id'];
+    $query.= ';';
+    pwg_query( $query );
+    $page['upload_successful'] = true;
+  }
+}
+
+//
+// Start output of page
+//
+$title= $lang['upload_title'];
+include(PHPWG_ROOT_PATH.'include/page_header.php');
+$template->set_filenames(array('upload'=>'upload.tpl'));
+
+$u_form = PHPWG_ROOT_PATH.'upload.php?cat='.$page['cat'];
+if ( isset( $page['waiting_id'] ) )
+{
+$u_form.= '&amp;waiting_id='.$page['waiting_id'];
+}
+
+if ( isset( $page['waiting_id'] ) )
+{
+  $advise_title=$lang['upload_advise_thumbnail'].$_FILES['picture']['name'];
+}
+else
+{
+  $advise_title = $lang['upload_advise'];
+  $advise_title.= get_cat_display_name($page['cat_name']);
+}
+
+$username = !empty($_POST['username'])?$_POST['username']:$user['username'];
+$mail_address = !empty($_POST['mail_address'])?$_POST['mail_address']:$user['mail_address'];
+$name = !empty($_POST['name'])?$_POST['name']:'';
+$author = !empty($_POST['author'])?$_POST['author']:'';
+$date_creation = !empty($_POST['date_creation'])?$_POST['date_creation']:'';
+$comment = !empty($_POST['comment'])?$_POST['comment']:'';
+
+$template->assign_vars(array(
+  'ADVISE_TITLE' => $advise_title,
+  'NAME' => $username,
+  'EMAIL' => $mail_address,
+  'NAME_IMG' => $name,
+  'AUTHOR_IMG' => $author,
+  'DATE_IMG' => $date_creation,
+  'COMMENT_IMG' => $comment,
+
+  'L_TITLE' => $lang['upload_title'],
+  'L_USERNAME' => $lang['upload_username'],
+  'L_EMAIL' =>  $lang['mail_address'], 
+  'L_NAME_IMG' =>  $lang['upload_name'], 
+  'L_SUBMIT' =>  $lang['submit'],
+  'L_AUTHOR' =>  $lang['upload_author'], 
+  'L_CREATION_DATE' =>  $lang['upload_creation_date'], 
+  'L_COMMENT' =>  $lang['comment'],
+  'L_RETURN' =>  $lang['home'],
+  'L_RETURN_HINT' =>  $lang['home_hint'],
+  'L_UPLOAD_DONE' =>  $lang['upload_successful'],
+  'L_MANDATORY' =>  $lang['mandatory'],
+	
+  'F_ACTION' => add_session_id( $u_form ),
+
+  'U_RETURN' => add_session_id(PHPWG_ROOT_PATH.'category.php?'.$_SERVER['QUERY_STRING'])
+  ));
+  
+if ( !$page['upload_successful'] )
+{
+  $template->assign_block_vars('upload_not_successful',array());
+//-------------------------------------------------------------- errors display
+if ( sizeof( $error ) != 0 )
+{
+  $template->assign_block_vars('upload_not_successful.errors',array());
+  for ( $i = 0; $i < sizeof( $error ); $i++ )
+  {
+    $template->assign_block_vars('upload_not_successful.errors.error',array('ERROR'=>$error[$i]));
+  }
+}
+
+//--------------------------------------------------------------------- advises
+  if ( !empty($conf['upload_maxfilesize']) )
+  {
+    $content = $lang['upload_advise_filesize'];
+    $content.= $conf['upload_maxfilesize'].' KB';
+    $template->assign_block_vars('upload_not_successful.advise',array('ADVISE'=>$content));
+  }
+
+  if ( isset( $page['waiting_id'] ) )
+  {
+    if ( $conf['upload_maxwidth_thumbnail'] != '' )
+    {
+	  $content = $lang['upload_advise_width'];
+      $content.= $conf['upload_maxwidth_thumbnail'].' px';
+	  $template->assign_block_vars('upload_not_successful.advise',array('ADVISE'=>$content));
+    }
+    if ( $conf['upload_maxheight_thumbnail'] != '' )
+    {
+      $content = $lang['upload_advise_height'];
+      $content.= $conf['upload_maxheight_thumbnail'].' px';
+	  $template->assign_block_vars('upload_not_successful.advise',array('ADVISE'=>$content));
+    }
+  }
+  else
+  {
+    if ( $conf['upload_maxwidth'] != '' )
+    {
+      $content = $lang['upload_advise_width'];
+      $content.= $conf['upload_maxwidth'].' px';
+	  $template->assign_block_vars('upload_not_successful.advise',array('ADVISE'=>$content));
+    }
+    if ( $conf['upload_maxheight'] != '' )
+    {
+      $content = $lang['upload_advise_height'];
+      $content.= $conf['upload_maxheight'].' px';
+	  $template->assign_block_vars('upload_not_successful.advise',array('ADVISE'=>$content));
+    }
+  }
+  $template->assign_block_vars('upload_not_successful.advise',array('ADVISE'=>$lang['upload_advise_filetype']));
+  
+//----------------------------------------- optionnal username and mail address
+  if ( !isset( $page['waiting_id'] ) )
+  {
+    $template->assign_block_vars('upload_not_successful.fields',array());
+	$template->assign_block_vars('note',array());
+  }
+}
+else
+{
+  $template->assign_block_vars('upload_successful',array());
+}
+//----------------------------------------------------------- html code display
+$template->parse('upload');
+include(PHPWG_ROOT_PATH.'include/page_tail.php');
+?>
