Index: /branches/1.5/about.php
===================================================================
--- /branches/1.5/about.php	(revision 3250)
+++ /branches/1.5/about.php	(revision 3250)
@@ -0,0 +1,56 @@
+<?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'];
+$page['body_id'] = 'theAboutPage';
+include(PHPWG_ROOT_PATH.'include/page_header.php');
+
+$template->set_filenames(
+  array(
+    'about'=>'about.tpl',
+    'about_content' => get_language_filepath('about.html')
+    )
+  );
+  
+$template->assign_vars(
+  array(
+    'U_HOME' => add_session_id(PHPWG_ROOT_PATH.'category.php')
+    )
+  );
+
+$template->assign_var_from_handle('ABOUT_MESSAGE', 'about_content');
+  
+$template->parse('about');
+include(PHPWG_ROOT_PATH.'include/page_tail.php');
+?>
Index: /branches/1.5/admin.php
===================================================================
--- /branches/1.5/admin.php	(revision 3250)
+++ /branches/1.5/admin.php	(revision 3250)
@@ -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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+//----------------------------------------------------------- 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' );
+
+// +-----------------------------------------------------------------------+
+// |                    synchronize user informations                      |
+// +-----------------------------------------------------------------------+
+
+sync_users();
+
+// +-----------------------------------------------------------------------+
+// |                            variables init                             |
+// +-----------------------------------------------------------------------+
+
+if (isset($_GET['page'])
+    and preg_match('/^[a-z_]*$/', $_GET['page'])
+    and is_file(PHPWG_ROOT_PATH.'admin/'.$_GET['page'].'.php'))
+{
+  $page['page'] = $_GET['page'];
+}
+else
+{
+  $page['page'] = 'intro';
+}
+
+$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
+$title = l10n('PhpWebGallery Administration'); // for include/page_header.php
+$page['gallery_title'] = l10n('PhpWebGallery Administration');
+$page['body_id'] = 'theAdminPage';
+include(PHPWG_ROOT_PATH.'include/page_header.php');
+
+$template->set_filenames(array('admin' => 'admin.tpl'));
+
+$template->assign_vars(
+  array(
+    '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_MAINTENANCE'=>add_session_id($link_start.'maintenance'),
+    '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_CATEGORIES'=>add_session_id($link_start.'cat_list' ),
+    'U_MOVE'=>add_session_id($link_start.'cat_move' ),
+    '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_CADDIE'=>add_session_id($link_start.'element_set&amp;cat=caddie'),
+    'U_THUMBNAILS'=>add_session_id($link_start.'thumbnail' ),
+    'U_USERS'=>add_session_id($link_start.'user_list' ),
+    'U_GROUPS'=>add_session_id($link_start.'group_list' ),
+    'U_ADMIN'=>add_session_id( PHPWG_ROOT_PATH.'admin.php' ),
+    'U_RETURN'=>add_session_id(PHPWG_ROOT_PATH.'category.php')
+    )
+  );
+
+if ($conf['allow_random_representative'])
+{
+  $template->assign_block_vars(
+    'representative',
+    array(
+      'URL' => add_session_id($opt_link.'representative')
+      )
+    );
+}
+  
+//------------------------------------------------------------- content display
+$page['errors'] = array();
+$page['infos']  = array();
+
+include(PHPWG_ROOT_PATH.'admin/'.$page['page'].'.php');
+
+// +-----------------------------------------------------------------------+
+// |                            errors & infos                             |
+// +-----------------------------------------------------------------------+
+
+if (count($page['errors']) != 0)
+{
+  $template->assign_block_vars('errors',array());
+  foreach ($page['errors'] as $error)
+  {
+    $template->assign_block_vars('errors.error',array('ERROR'=>$error));
+  }
+}
+
+if (count($page['infos']) != 0)
+{
+  $template->assign_block_vars('infos',array());
+  foreach ($page['infos'] as $info)
+  {
+    $template->assign_block_vars('infos.info',array('INFO'=>$info));
+  }
+}
+
+$template->parse('admin');
+include(PHPWG_ROOT_PATH.'include/page_tail.php');
+
+// +-----------------------------------------------------------------------+
+// |                     order permission refreshment                      |
+// +-----------------------------------------------------------------------+
+
+$query = '
+UPDATE '.USER_CACHE_TABLE.'
+  SET need_update = \'true\'
+;';
+pwg_query($query);
+?>
Index: /branches/1.5/admin/cat_list.php
===================================================================
--- /branches/1.5/admin/cat_list.php	(revision 3250)
+++ /branches/1.5/admin/cat_list.php	(revision 3250)
@@ -0,0 +1,365 @@
+<?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');
+
+// +-----------------------------------------------------------------------+
+// |                               functions                               |
+// +-----------------------------------------------------------------------+
+
+/**
+ * save the rank depending on given categories order
+ *
+ * The list of ordered categories id is supposed to be in the same parent
+ * category
+ *
+ * @param array categories
+ * @return void
+ */
+function save_categories_order($categories)
+{
+  $current_rank = 0;
+  $datas = array();
+  foreach ($categories as $id)
+  {
+    array_push($datas, array('id' => $id, 'rank' => ++$current_rank));
+  }
+  $fields = array('primary' => array('id'), 'update' => array('rank'));
+  mass_updates(CATEGORIES_TABLE, $fields, $datas);
+
+  update_global_rank(@$_GET['parent_id']);
+}
+
+// +-----------------------------------------------------------------------+
+// |                            initialization                             |
+// +-----------------------------------------------------------------------+
+
+$categories = array();
+
+$base_url = PHPWG_ROOT_PATH.'admin.php?page=cat_list';
+$navigation = '<a class="" href="'.add_session_id($base_url).'">';
+$navigation.= $lang['home'];
+$navigation.= '</a>';
+
+// +-----------------------------------------------------------------------+
+// |                    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($page['infos'], $lang['cat_virtual_deleted']);
+  ordering();
+  update_global_rank();
+}
+// request to add a virtual category
+else if (isset($_POST['submitAdd']))
+{
+  // is the given category name only containing blank spaces ?
+  if (preg_match('/^\s*$/', $_POST['virtual_name']))
+  {
+    array_push($page['errors'], $lang['cat_error_name']);
+  }
+	
+  if (!count($page['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($page['infos'], $lang['cat_virtual_added']);
+  }
+}
+else if (isset($_POST['submitOrder']))
+{
+  asort($_POST['catOrd'], SORT_NUMERIC);
+  save_categories_order(array_keys($_POST['catOrd']));
+}
+// +-----------------------------------------------------------------------+
+// |                           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']))
+{
+  $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);
+}
+// +-----------------------------------------------------------------------+
+// |                       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_EDIT'=>$lang['edit'],
+  'L_DELETE'=>$lang['delete'],
+ ));
+  
+$tpl = array('cat_first','cat_last');
+// +-----------------------------------------------------------------------+
+// |                          Categories display                           |
+// +-----------------------------------------------------------------------+
+
+$categories = array();
+
+$query = '
+SELECT id, name, dir, rank, nb_images, status
+  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_array($result))
+{
+  $categories[$row['id']] = $row;
+  // by default, let's consider there is no sub-categories. This will be
+  // calculated after.
+  $categories[$row['id']]['nb_subcats'] = 0;
+}
+
+if (count($categories) > 0)
+{
+  $query = '
+SELECT id_uppercat, COUNT(*) AS nb_subcats
+  FROM '. CATEGORIES_TABLE.'
+  WHERE id_uppercat IN ('.implode(',', array_keys($categories)).')
+  GROUP BY id_uppercat
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    $categories[$row['id_uppercat']]['nb_subcats'] = $row['nb_subcats'];
+  }
+}
+
+foreach ($categories as $category)
+{
+  $images_folder = PHPWG_ROOT_PATH.'template/';
+  $images_folder.= $user['template'].'/admin/images';
+  
+  $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(
+      'NAME'=>$category['name'],
+      'ID'=>$category['id'],
+      'RANK'=>$category['rank']*10,
+
+      'U_JUMPTO'=>
+      add_session_id(PHPWG_ROOT_PATH.'category.php?cat='.$category['id']),
+      
+      'U_CHILDREN'=>
+      add_session_id($cat_list_url.'&amp;parent_id='.$category['id']),
+      
+      'U_EDIT'=>
+      add_session_id($base_url.'cat_modify&amp;cat_id='.$category['id'])
+      )
+    );
+  
+  if (empty($category['dir']))
+  {
+    $template->assign_block_vars(
+      'category.delete',
+      array(
+        'URL'=>add_session_id($self_url.'&amp;delete='.$category['id'])
+        )
+      );
+  }
+  
+  if ($category['nb_images'] > 0)
+  {
+    $template->assign_block_vars(
+      'category.elements',
+      array(
+        'URL'=>add_session_id($base_url.'element_set&amp;cat='.$category['id'])
+        )
+      );
+  }
+
+  if ('private' == $category['status'])
+  {
+    $template->assign_block_vars(
+      'category.permissions',
+      array(
+        'URL'=>add_session_id($base_url.'cat_perm&amp;cat='.$category['id'])
+        )
+      );
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                          sending html code                            |
+// +-----------------------------------------------------------------------+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'categories');
+?>
Index: /branches/1.5/admin/cat_modify.php
===================================================================
--- /branches/1.5/admin/cat_modify.php	(revision 3250)
+++ /branches/1.5/admin/cat_modify.php	(revision 3250)
@@ -0,0 +1,318 @@
+<?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']))
+{
+  $data =
+    array(
+      'id' => $_GET['cat_id'],
+      'name' => @$_POST['name'],
+      'commentable' => $_POST['commentable'],
+      'uploadable' =>
+        isset($_POST['uploadable']) ? $_POST['uploadable'] : 'false',
+      'comment' =>
+        $conf['allow_html_descriptions'] ?
+          @$_POST['comment'] : strip_tags(@$_POST['comment'])
+      );
+
+  mass_updates(
+    CATEGORIES_TABLE,
+    array(
+      'primary' => array('id'),
+      'update' => array_diff(array_keys($data), array('id'))
+      ),
+    array($data)
+    );
+  
+  set_cat_visible(array($_GET['cat_id']), $_POST['visible']);
+  set_cat_status(array($_GET['cat_id']), $_POST['status']);
+
+  if (isset($_POST['parent']))
+  {
+    move_categories(
+      array($_GET['cat_id']),
+      $_POST['parent']
+      );
+  }
+
+  array_push($page['infos'], $lang['editcat_confirm']);
+}
+else if (isset($_POST['set_random_representant']))
+{
+  set_random_representant(array($_GET['cat_id']));
+}
+else if (isset($_POST['delete_representant']))
+{
+  $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET representative_picture_id = NULL
+  WHERE id = '.$_GET['cat_id'].'
+;';
+  pwg_query($query);
+}
+
+$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', 'id_uppercat') as $nullable)
+{
+  if (!isset($category[$nullable]))
+  {
+    $category[$nullable] = '';
+  }
+}
+
+$category['is_virtual'] = empty($category['dir']) ? true : false;
+
+// Navigation path
+$url = PHPWG_ROOT_PATH.'admin.php?page=cat_modify&amp;cat_id=';
+
+$navigation = get_cat_display_name_cache(
+  $category['uppercats'],
+  PHPWG_ROOT_PATH.'admin.php?page=cat_modify&amp;cat_id='
+  );
+
+$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
+
+$base_url = PHPWG_ROOT_PATH.'admin.php?page=';
+$cat_list_url = $base_url.'cat_list';
+  
+$self_url = $cat_list_url;
+if (!empty($category['id_uppercat']))
+{
+  $self_url.= '&amp;parent_id='.$category['id_uppercat'];
+}
+
+$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_NAME'=>$lang['name'],
+  'L_STORAGE'=>$lang['storage'],
+  'L_REMOTE_SITE'=>$lang['remote_site'],
+  'L_EDIT_COMMENT'=>$lang['description'],
+  'L_EDIT_STATUS'=>$lang['conf_access'],
+  'L_STATUS_PUBLIC'=>$lang['public'],
+  'L_STATUS_PRIVATE'=>$lang['private'],
+  'L_EDIT_LOCK'=>$lang['lock'],
+  'L_EDIT_UPLOADABLE'=>$lang['editcat_uploadable'],
+  'L_EDIT_COMMENTABLE'=>$lang['comments'],
+  'L_YES'=>$lang['yes'],
+  'L_NO'=>$lang['no'],
+  'L_SUBMIT'=>$lang['submit'],
+  'L_SET_RANDOM_REPRESENTANT'=>$lang['cat_representant'],
+
+  'U_JUMPTO'=>
+    add_session_id(PHPWG_ROOT_PATH.'category.php?cat='.$category['id']),
+  'U_CHILDREN'=>
+    add_session_id($cat_list_url.'&amp;parent_id='.$category['id']),
+  'U_HELP' => PHPWG_ROOT_PATH.'/popuphelp.php?page=cat_modify',
+   
+  'F_ACTION'=>add_session_id($form_action)
+  ));
+
+
+if ('private' == $category['status'])
+{
+  $template->assign_block_vars(
+    'permissions',
+    array(
+      'URL'=>add_session_id($base_url.'cat_perm&amp;cat='.$category['id'])
+        )
+    );
+}
+
+// manage category elements link
+if ($category['nb_images'] > 0)
+{
+  $template->assign_block_vars(
+    'elements',
+    array(
+      'URL'=>add_session_id($base_url.'element_set&amp;cat='.$category['id'])
+      )
+    );
+}
+
+// representant management
+if ($category['nb_images'] > 0
+    or !empty($category['representative_picture_id']))
+{
+  $template->assign_block_vars('representant', array());
+
+  // picture to display : the identified representant or the generic random
+  // representant ?
+  if (!empty($category['representative_picture_id']))
+  {
+    $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.picture',
+      array(
+        'SRC' => $src,
+        'URL' => $url
+        )
+      );
+  }
+  else // $category['nb_images'] > 0
+  {
+    $template->assign_block_vars('representant.random', array());
+  }
+
+  // can the admin choose to set a new random representant ?
+  if ($category['nb_images'] > 0)
+  {
+    $template->assign_block_vars('representant.set_random', array());
+  }
+
+  // can the admin delete the current representant ?
+  if (
+    ($category['nb_images'] > 0
+     and $conf['allow_random_representative'])
+    or
+    ($category['nb_images'] == 0
+     and !empty($category['representative_picture_id'])))
+  {
+    $template->assign_block_vars('representant.delete_representant', array());
+  }
+}
+
+if (!$category['is_virtual']) //!empty($category['dir']))
+{
+  $template->assign_block_vars(
+    'storage',
+    array('CATEGORY_DIR'=>preg_replace('/\/$/',
+                                       '',
+                                       get_complete_dir($category['id']))));
+  $template->assign_block_vars('upload' ,array());
+}
+else
+{
+  $template->assign_block_vars(
+    'delete',
+    array(
+      'URL'=>add_session_id($self_url.'&amp;delete='.$category['id'])
+      )
+    );
+
+  $template->assign_block_vars('move', array());
+
+  // the category can be moved in any category but in itself, in any
+  // sub-category
+  $unmovables = get_subcat_ids(array($category['id']));
+  
+  $blockname = 'move.parent_option';
+
+  $template->assign_block_vars(
+    $blockname,
+    array(
+      'SELECTED'
+        => empty($category['id_uppercat']) ? 'selected="selected"' : '',
+      'VALUE'=> 0,
+      'OPTION' => '------------'
+      )
+    );
+  
+  $query = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id NOT IN ('.implode(',', $unmovables).')
+;';
+  
+  display_select_cat_wrapper(
+    $query,
+    empty($category['id_uppercat']) ? array() : array($category['id_uppercat']),
+    $blockname
+    );
+}
+
+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.5/admin/cat_move.php
===================================================================
--- /branches/1.5/admin/cat_move.php	(revision 3250)
+++ /branches/1.5/admin/cat_move.php	(revision 3250)
@@ -0,0 +1,117 @@
+<?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');
+
+// +-----------------------------------------------------------------------+
+// |                               functions                               |
+// +-----------------------------------------------------------------------+
+
+
+// +-----------------------------------------------------------------------+
+// |                          categories movement                          |
+// +-----------------------------------------------------------------------+
+
+if (isset($_POST['submit']))
+{
+  if (count($_POST['selection']) > 0)
+  {
+    // TODO: tests
+    move_categories($_POST['selection'], $_POST['parent']);
+  }
+  else
+  {
+    array_push(
+      $page['errors'],
+      l10n('Select at least one category')
+      );
+  }
+}
+
+// +-----------------------------------------------------------------------+
+// |                       template initialization                         |
+// +-----------------------------------------------------------------------+
+
+$template->set_filenames(
+  array(
+    'cat_move' => 'admin/cat_move.tpl'
+    )
+  );
+
+$template->assign_vars(
+  array(
+    'F_ACTION' => add_session_id(PHPWG_ROOT_PATH.'admin.php?page=cat_move'),
+    )
+  );
+  
+// +-----------------------------------------------------------------------+
+// |                          Categories display                           |
+// +-----------------------------------------------------------------------+
+
+$query = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE dir IS NULL
+;';
+
+display_select_cat_wrapper(
+  $query,
+  array(),
+  'category_option_selection'
+  );
+
+$blockname = 'category_option_parent';
+
+$template->assign_block_vars(
+  $blockname,
+  array(
+    'VALUE'=> 0,
+    'OPTION' => '------------'
+    )
+  );
+
+$query = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+;';
+
+display_select_cat_wrapper(
+  $query,
+  array(),
+  $blockname
+  );
+
+// +-----------------------------------------------------------------------+
+// |                          sending html code                            |
+// +-----------------------------------------------------------------------+
+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'cat_move');
+?>
Index: /branches/1.5/admin/cat_options.php
===================================================================
--- /branches/1.5/admin/cat_options.php	(revision 3250)
+++ /branches/1.5/admin/cat_options.php	(revision 3250)
@@ -0,0 +1,297 @@
+<?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;
+    }
+    case 'representative' :
+    {
+      $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET representative_picture_id = NULL
+  WHERE id IN ('.implode(',', $_POST['cat_true']).')
+;';
+      pwg_query($query);
+      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;
+    }
+    case 'representative' :
+    {
+      // theoretically, all categories in $_POST['cat_false'] contain at
+      // least one element, so PhpWebGallery can find a representant.
+      set_random_representant($_POST['cat_false']);
+      break;
+    }
+  }
+}
+
+// +-----------------------------------------------------------------------+
+// |                             template init                             |
+// +-----------------------------------------------------------------------+
+
+$template->set_filenames(
+  array(
+    'cat_options' => 'admin/cat_options.tpl',
+    'double_select' => 'admin/double_select.tpl'
+    )
+  );
+
+$page['section'] = isset($_GET['section']) ? $_GET['section'] : 'upload';
+$base_url = PHPWG_ROOT_PATH.'admin.php?page=cat_options&amp;section=';
+
+$template->assign_vars(
+  array(
+    'L_SUBMIT'=>$lang['submit'],
+    'L_RESET'=>$lang['reset'],
+
+    'U_HELP' => PHPWG_ROOT_PATH.'/popuphelp.php?page=cat_options',
+    
+    'F_ACTION'=>add_session_id($base_url.$page['section'])
+   )
+ );
+
+// +-----------------------------------------------------------------------+
+// |                              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_SECTION' => $lang['cat_upload_title'],
+        'L_CAT_OPTIONS_TRUE' => $lang['authorized'],
+        'L_CAT_OPTIONS_FALSE' => $lang['forbidden'],
+        )
+      );
+    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_SECTION' => $lang['cat_comments_title'],
+        'L_CAT_OPTIONS_TRUE' => $lang['authorized'],
+        'L_CAT_OPTIONS_FALSE' => $lang['forbidden'],
+        )
+      );
+    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_SECTION' => $lang['cat_lock_title'],
+        'L_CAT_OPTIONS_TRUE' => $lang['unlocked'],
+        'L_CAT_OPTIONS_FALSE' => $lang['locked'],
+        )
+      );
+    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_SECTION' => $lang['cat_status_title'],
+        'L_CAT_OPTIONS_TRUE' => $lang['cat_public'],
+        'L_CAT_OPTIONS_FALSE' => $lang['cat_private'],
+        )
+      );
+    break;
+  }
+  case 'representative' :
+  {
+    $query_true = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE representative_picture_id IS NOT NULL
+;';
+    $query_false = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+  WHERE nb_images != 0
+    AND representative_picture_id IS NULL
+;';
+    $template->assign_vars(
+      array(
+        'L_SECTION' => l10n('Representative'),
+        'L_CAT_OPTIONS_TRUE' => l10n('singly represented'),
+        'L_CAT_OPTIONS_FALSE' => l10n('randomly represented')
+        )
+      );
+    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('DOUBLE_SELECT', 'double_select');
+$template->assign_var_from_handle('ADMIN_CONTENT', 'cat_options');
+?>
Index: /branches/1.5/admin/cat_perm.php
===================================================================
--- /branches/1.5/admin/cat_perm.php	(revision 3250)
+++ /branches/1.5/admin/cat_perm.php	(revision 3250)
@@ -0,0 +1,377 @@
+<?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');
+
+// +-----------------------------------------------------------------------+
+// |                       variable initialization                         |
+// +-----------------------------------------------------------------------+
+
+// if the category is not correct (not numeric, not private)
+if (isset($_GET['cat']) and is_numeric($_GET['cat']))
+{
+  $query = '
+SELECT status
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id = '.$_GET['cat'].'
+;';
+  list($status) = mysql_fetch_array(pwg_query($query));
+  
+  if ('private' == $status)
+  {
+    $page['cat'] = $_GET['cat'];
+  }
+}
+
+if (!isset($page['cat']))
+{
+  $query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE status = \'private\'
+  LIMIT 0,1
+;';
+
+  list($page['cat']) = mysql_fetch_array(pwg_query($query));
+}
+
+// +-----------------------------------------------------------------------+
+// |                           form submission                             |
+// +-----------------------------------------------------------------------+
+
+if (isset($_POST) and false)
+{
+  echo '<pre>';
+  print_r($_POST);
+  echo '</pre>';
+}
+
+if (isset($_POST['deny_groups_submit'])
+         and isset($_POST['deny_groups'])
+         and count($_POST['deny_groups']) > 0)
+{
+  // if you forbid access to a category, all sub-categories become
+  // automatically forbidden
+  $query = '
+DELETE
+  FROM '.GROUP_ACCESS_TABLE.'
+  WHERE group_id IN ('.implode(',', $_POST['deny_groups']).')
+    AND cat_id IN ('.implode(',', get_subcat_ids(array($page['cat']))).')
+;';
+  pwg_query($query);
+}
+else if (isset($_POST['grant_groups_submit'])
+         and isset($_POST['grant_groups'])
+         and count($_POST['grant_groups']) > 0)
+{
+  $query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id IN ('.implode(',', get_uppercat_ids(array($page['cat']))).')
+  AND status = \'private\'
+;';
+  $private_uppercats = array_from_query($query, 'id');
+
+  // We must not reinsert already existing lines in group_access table
+  $granteds = array();
+  foreach ($private_uppercats as $cat_id)
+  {
+    $granteds[$cat_id] = array();
+  }
+  
+  $query = '
+SELECT group_id, cat_id
+  FROM '.GROUP_ACCESS_TABLE.'
+  WHERE cat_id IN ('.implode(',', $private_uppercats).')
+    AND group_id IN ('.implode(',', $_POST['grant_groups']).')
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($granteds[$row['cat_id']], $row['group_id']);
+  }
+
+  $inserts = array();
+  
+  foreach ($private_uppercats as $cat_id)
+  {
+    $group_ids = array_diff($_POST['grant_groups'], $granteds[$cat_id]);
+    foreach ($group_ids as $group_id)
+    {
+      array_push($inserts, array('group_id' => $group_id,
+                                 'cat_id' => $cat_id));
+    }
+  }
+
+  mass_inserts(GROUP_ACCESS_TABLE, array('group_id','cat_id'), $inserts);
+}
+else if (isset($_POST['deny_users_submit'])
+         and isset($_POST['deny_users'])
+         and count($_POST['deny_users']) > 0)
+{
+  // if you forbid access to a category, all sub-categories become
+  // automatically forbidden
+  $query = '
+DELETE
+  FROM '.USER_ACCESS_TABLE.'
+  WHERE user_id IN ('.implode(',', $_POST['deny_users']).')
+    AND cat_id IN ('.implode(',', get_subcat_ids(array($page['cat']))).')
+;';
+  pwg_query($query);
+}
+else if (isset($_POST['grant_users_submit'])
+         and isset($_POST['grant_users'])
+         and count($_POST['grant_users']) > 0)
+{
+  $query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id IN ('.implode(',', get_uppercat_ids(array($page['cat']))).')
+  AND status = \'private\'
+;';
+  $private_uppercats = array_from_query($query, 'id');
+
+  // We must not reinsert already existing lines in user_access table
+  $granteds = array();
+  foreach ($private_uppercats as $cat_id)
+  {
+    $granteds[$cat_id] = array();
+  }
+  
+  $query = '
+SELECT user_id, cat_id
+  FROM '.USER_ACCESS_TABLE.'
+  WHERE cat_id IN ('.implode(',', $private_uppercats).')
+    AND user_id IN ('.implode(',', $_POST['grant_users']).')
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($granteds[$row['cat_id']], $row['user_id']);
+  }
+
+  $inserts = array();
+  
+  foreach ($private_uppercats as $cat_id)
+  {
+    $user_ids = array_diff($_POST['grant_users'], $granteds[$cat_id]);
+    foreach ($user_ids as $user_id)
+    {
+      array_push($inserts, array('user_id' => $user_id,
+                                 'cat_id' => $cat_id));
+    }
+  }
+
+  mass_inserts(USER_ACCESS_TABLE, array('user_id','cat_id'), $inserts);
+}
+
+// +-----------------------------------------------------------------------+
+// |                       template initialization                         |
+// +-----------------------------------------------------------------------+
+
+$template->set_filenames(array('cat_perm'=>'admin/cat_perm.tpl'));
+
+$template->assign_vars(
+  array(
+    'CATEGORIES_NAV' =>
+      get_cat_display_name_from_id(
+        $page['cat'],
+        'admin.php?page=cat_modify&amp;cat_id='
+        ),
+    'U_HELP' => PHPWG_ROOT_PATH.'/popuphelp.php?page=cat_perm',
+    'F_ACTION' =>
+      add_session_id(
+        PHPWG_ROOT_PATH.'admin.php?page=cat_perm&amp;cat='.$page['cat']
+        )
+    )
+  );
+
+// +-----------------------------------------------------------------------+
+// |                          form construction                            |
+// +-----------------------------------------------------------------------+
+
+// groups denied are the groups not granted. So we need to find all groups
+// minus groups granted to find groups denied.
+
+$groups = array();
+
+$query = '
+SELECT id, name
+  FROM '.GROUPS_TABLE.'
+;';
+$result = pwg_query($query);
+
+while ($row = mysql_fetch_array($result))
+{
+  $groups[$row['id']] = $row['name'];
+}
+
+$query = '
+SELECT group_id
+  FROM '.GROUP_ACCESS_TABLE.'
+  WHERE cat_id = '.$page['cat'].'
+;';
+$group_granted_ids = array_from_query($query, 'group_id');
+
+// groups granted to access the category
+foreach ($group_granted_ids as $group_id)
+{
+  $template->assign_block_vars(
+    'group_granted',
+    array(
+      'NAME'=>$groups[$group_id],
+      'ID'=>$group_id
+      )
+    );
+}
+
+// groups denied
+foreach (array_diff(array_keys($groups), $group_granted_ids) as $group_id)
+{
+  $template->assign_block_vars(
+    'group_denied',
+    array(
+      'NAME'=>$groups[$group_id],
+      'ID'=>$group_id
+      )
+    );
+}
+
+// users...
+$users = array();
+
+$query = '
+SELECT '.$conf['user_fields']['id'].' AS id,
+       '.$conf['user_fields']['username'].' AS username
+  FROM '.USERS_TABLE.'
+  WHERE '.$conf['user_fields']['id'].' != '.$conf['guest_id'].'
+;';
+$result = pwg_query($query);
+while($row = mysql_fetch_array($result))
+{
+  $users[$row['id']] = $row['username'];
+}
+
+$query = '
+SELECT user_id
+  FROM '.USER_ACCESS_TABLE.'
+  WHERE cat_id = '.$page['cat'].'
+;';
+$user_granted_direct_ids = array_from_query($query, 'user_id');
+
+foreach ($user_granted_direct_ids as $user_id)
+{
+  $template->assign_block_vars(
+    'user_granted',
+    array(
+      'NAME'=>$users[$user_id],
+      'ID'=>$user_id
+      )
+    );
+}
+
+$user_granted_indirect_ids = array();
+if (count($group_granted_ids) > 0)
+{
+  $granted_groups = array();
+
+  $query = '
+SELECT user_id, group_id
+  FROM '.USER_GROUP_TABLE.'
+  WHERE group_id IN ('.implode(',', $group_granted_ids).') 
+';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    if (!isset($granted_groups[$row['group_id']]))
+    {
+      $granted_groups[$row['group_id']] = array();
+    }
+    array_push($granted_groups[$row['group_id']], $row['user_id']);
+  }
+
+  $user_granted_by_group_ids = array();
+
+  foreach ($granted_groups as $group_users)
+  {
+    $user_granted_by_group_ids = array_merge($user_granted_by_group_ids,
+                                             $group_users);
+  }
+  $user_granted_by_group_ids = array_unique($user_granted_by_group_ids);
+  
+  
+  $user_granted_indirect_ids = array_diff($user_granted_by_group_ids,
+                                          $user_granted_direct_ids);
+  
+  foreach ($user_granted_indirect_ids as $user_id)
+  {
+    $group = '';
+    
+    foreach ($granted_groups as $group_id => $group_users)
+    {
+      if (in_array($user_id, $group_users))
+      {
+        $group = $groups[$group_id];
+        break;
+      }
+    }
+    
+    $template->assign_block_vars(
+      'user_granted_indirect',
+      array(
+        'NAME'=>$users[$user_id],
+        'GROUP'=>$group
+        )
+      );
+  }
+}
+
+$user_denied_ids = array_diff(array_keys($users),
+                              $user_granted_indirect_ids,
+                              $user_granted_direct_ids);
+
+foreach ($user_denied_ids as $user_id)
+{
+  $template->assign_block_vars(
+    'user_denied',
+    array(
+      'NAME'=>$users[$user_id],
+      'ID'=>$user_id
+      )
+    );
+}
+
+
+// +-----------------------------------------------------------------------+
+// |                           sending html code                           |
+// +-----------------------------------------------------------------------+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'cat_perm');
+?>
Index: /branches/1.5/admin/comments.php
===================================================================
--- /branches/1.5/admin/comments.php	(revision 3250)
+++ /branches/1.5/admin/comments.php	(revision 3250)
@@ -0,0 +1,171 @@
+<?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');
+
+// +-----------------------------------------------------------------------+
+// |                                actions                                |
+// +-----------------------------------------------------------------------+
+
+if (isset($_POST))
+{
+  $to_validate = array();
+  $to_reject = array();
+  
+  if (isset($_POST['submit']))
+  {    
+    foreach (explode(',', $_POST['list']) as $comment_id)
+    {
+      if (isset($_POST['action-'.$comment_id]))
+      {
+        switch ($_POST['action-'.$comment_id])
+        {
+          case 'reject' :
+          {
+            array_push($to_reject, $comment_id);
+            break;
+          }
+          case 'validate' :
+          {
+            array_push($to_validate, $comment_id);
+            break;
+          }
+        }
+      }
+    }
+  }
+  else if (isset($_POST['validate-all']))
+  {
+    $to_validate = explode(',', $_POST['list']);
+  }
+  else if (isset($_POST['reject-all']))
+  {
+    $to_reject = explode(',', $_POST['list']);
+  }
+
+  if (count($to_validate) > 0)
+  {
+    $query = '
+UPDATE '.COMMENTS_TABLE.'
+  SET validated = \'true\'
+    , validation_date = NOW()
+  WHERE id IN ('.implode(',', $to_validate).')
+;';
+    pwg_query($query);
+
+    array_push(
+      $page['infos'],
+      sprintf(
+        l10n('%d user comments validated'),
+        count($to_validate)
+        )
+      );
+  }
+
+  if (count($to_reject) > 0)
+  {
+    $query = '
+DELETE
+  FROM '.COMMENTS_TABLE.'
+  WHERE id IN ('.implode(',', $to_reject).')
+;';
+    pwg_query($query);
+
+    array_push(
+      $page['infos'],
+      sprintf(
+        l10n('%d user comments rejected'),
+        count($to_reject)
+        )
+      );
+  }
+}
+
+// +-----------------------------------------------------------------------+
+// |                             template init                             |
+// +-----------------------------------------------------------------------+
+
+$template->set_filenames(array('comments'=>'admin/comments.tpl'));
+
+$template->assign_vars(
+  array(
+    'F_ACTION' => add_session_id(PHPWG_ROOT_PATH.'admin.php?page=comments')
+    )
+  );
+
+// +-----------------------------------------------------------------------+
+// |                           comments display                            |
+// +-----------------------------------------------------------------------+
+
+$list = array();
+
+$query = '
+SELECT c.id, c.image_id, c.date, c.author, c.content, i.path, i.tn_ext
+  FROM '.COMMENTS_TABLE.' AS c
+    INNER JOIN '.IMAGES_TABLE.' AS i
+      ON i.id = c.image_id
+  WHERE validated = \'false\'
+;';
+$result = pwg_query($query);
+while ($row = mysql_fetch_array($result))
+{
+  $template->assign_block_vars(
+    'comment',
+    array(
+      'U_PICTURE' =>
+        add_session_id(
+          PHPWG_ROOT_PATH.'admin.php?page=picture_modify'.
+          '&amp;image_id='.$row['image_id']
+          ),
+      'ID' => $row['id'],
+      'TN_SRC' => get_thumbnail_src($row['path'], @$row['tn_ext']),
+      'AUTHOR' => $row['author'],
+      'DATE' => format_date($row['date'],'mysql_datetime',true),
+      'CONTENT' => parse_comment_content($row['content'])
+      )
+    );
+
+  array_push($list, $row['id']);
+}
+
+$template->assign_vars(
+  array(
+    'LIST' => implode(',', $list)
+    )
+  );
+
+// +-----------------------------------------------------------------------+
+// |                           sending html code                           |
+// +-----------------------------------------------------------------------+
+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'comments');
+
+?>
Index: /branches/1.5/admin/configuration.php
===================================================================
--- /branches/1.5/admin/configuration.php	(revision 3250)
+++ /branches/1.5/admin/configuration.php	(revision 3250)
@@ -0,0 +1,279 @@
+<?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
+if (isset($_POST['submit']))
+{
+  $int_pattern = '/^\d+$/';
+  switch ($page['section'])
+  {
+    case 'general' :
+    {
+      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($page['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($page['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($page['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($page['errors'], $lang['maxheight_error']);
+      }
+      break;
+    }
+  }
+  
+  // updating configuration if no error found
+  if (count($page['errors']) == 0)
+  {
+//    echo '<pre>'; print_r($_POST); echo '</pre>';
+    $result = pwg_query('SELECT * FROM '.CONFIG_TABLE);
+    while ($row = mysql_fetch_array($result))
+    {
+      if (isset($_POST[$row['param']]))
+      {
+        $value = $_POST[$row['param']];
+      
+        if ('gallery_title' == $row['param']
+            or 'gallery_description' == $row['param'])
+        {
+          if (!$conf['allow_html_descriptions'])
+          {
+            $value = strip_tags($value);
+          }
+        }
+        
+        $query = '
+UPDATE '.CONFIG_TABLE.'
+  SET value = \''. str_replace("\'", "''", $value).'\'
+  WHERE param = \''.$row['param'].'\'
+;';
+        pwg_query($query);
+      }
+    }
+    array_push($page['infos'], $lang['conf_confirmation']);
+  }
+}
+
+//----------------------------------------------------- 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_YES'=>$lang['yes'],
+    'L_NO'=>$lang['no'],
+    'L_SUBMIT'=>$lang['submit'],
+    'L_RESET'=>$lang['reset'],
+
+    'U_HELP' => PHPWG_ROOT_PATH.'/popuphelp.php?page=configuration',
+    
+    '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"':'';
+    $lock_yes = ($conf['gallery_locked']=='true')?'checked="checked"':'';
+    $lock_no = ($conf['gallery_locked']=='false')?'checked="checked"':'';
+    
+    $template->assign_block_vars(
+      'general',
+      array(
+        'HISTORY_YES'=>$history_yes,
+        'HISTORY_NO'=>$history_no,
+        'GALLERY_LOCKED_YES'=>$lock_yes,
+        'GALLERY_LOCKED_NO'=>$lock_no,
+        'CONF_GALLERY_TITLE' => $conf['gallery_title'],
+        'CONF_GALLERY_DESCRIPTION' => $conf['gallery_description'],
+        ));
+    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(
+        '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(
+        'NB_IMAGE_LINE'=>$conf['nb_image_line'],
+        'NB_ROW_PAGE'=>$conf['nb_line_page'],
+        '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
+        ));
+    
+    $blockname = 'default.language_option';
+    
+    foreach (get_languages() as $language_code => $language_name)
+    {
+      if (isset($_POST['submit']))
+      {
+        $selected =
+          $_POST['default_language'] == $language_code
+            ? 'selected="selected"' : '';
+      }
+      else if ($conf['default_language'] == $language_code)
+      {
+        $selected = 'selected="selected"';
+      }
+      else
+      {
+        $selected = '';
+      }
+      
+      $template->assign_block_vars(
+        $blockname,
+        array(
+          'VALUE'=> $language_code,
+          'CONTENT' => $language_name,
+          'SELECTED' => $selected
+          ));
+    }
+
+    $blockname = 'default.template_option';
+
+    foreach (get_templates() as $pwg_template)
+    {
+      if (isset($_POST['submit']))
+      {
+        $selected =
+          $_POST['default_template'] == $pwg_template
+            ? 'selected="selected"' : '';
+      }
+      else if ($conf['default_template'] == $pwg_template)
+      {
+        $selected = 'selected="selected"';
+      }
+      else
+      {
+        $selected = '';
+      }
+      
+      $template->assign_block_vars(
+        $blockname,
+        array(
+          'VALUE'=> $pwg_template,
+          'CONTENT' => $pwg_template,
+          'SELECTED' => $selected
+          )
+        );
+    }
+
+ 
+    break;
+  }
+}
+//----------------------------------------------------------- sending html code
+$template->assign_var_from_handle('ADMIN_CONTENT', 'config');
+?>
Index: /branches/1.5/admin/element_set.php
===================================================================
--- /branches/1.5/admin/element_set.php	(revision 3250)
+++ /branches/1.5/admin/element_set.php	(revision 3250)
@@ -0,0 +1,199 @@
+<?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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+/**
+ * Management of elements set. Elements can belong to a category or to the
+ * user caddie.
+ * 
+ */
+ 
+if (!defined('PHPWG_ROOT_PATH'))
+{
+  die('Hacking attempt!');
+}
+include_once(PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php');
+
+// +-----------------------------------------------------------------------+
+// |                          caddie management                            |
+// +-----------------------------------------------------------------------+
+
+if (isset($_POST['submit_caddie']))
+{
+  if (isset($_POST['caddie_action']))
+  {
+    switch ($_POST['caddie_action'])
+    {
+      case 'empty_all' :
+      {
+          $query = '
+DELETE FROM '.CADDIE_TABLE.'
+  WHERE user_id = '.$user['id'].'
+;';
+          pwg_query($query);
+          break;
+      }
+      case 'empty_selected' :
+      {
+        if (isset($_POST['selection']) and count($_POST['selection']) > 0)
+        {
+          $query = '
+DELETE
+  FROM '.CADDIE_TABLE.'
+  WHERE element_id IN ('.implode(',', $_POST['selection']).')
+    AND user_id = '.$user['id'].'
+;';
+          pwg_query($query);
+        }
+        else
+        {
+          // TODO : add error
+        }
+        break;
+      }
+      case 'add_selected' :
+      {
+        if (isset($_POST['selection']) and count($_POST['selection']) > 0)
+        {
+          fill_caddie($_POST['selection']);
+        }
+        else
+        {
+          // TODO : add error
+        }
+        break;
+      }
+    }
+  }
+  else
+  {
+    // TODO : add error
+  }
+}
+
+// +-----------------------------------------------------------------------+
+// |                    initialize info about category                     |
+// +-----------------------------------------------------------------------+
+
+// To element_set_(global|unit).php, we must provide the elements id of the
+// managed category in $page['cat_elements_id'] array.
+
+if (is_numeric($_GET['cat']))
+{
+  $cat_infos = get_cat_info($_GET['cat']);
+  $page['title'] =
+    get_cat_display_name(
+      $cat_infos['name'],
+      PHPWG_ROOT_PATH.'admin.php?page=cat_modify&amp;cat_id=',
+      false
+      );
+  
+  $query = '
+SELECT image_id
+  FROM '.IMAGE_CATEGORY_TABLE.'
+  WHERE category_id = '.$_GET['cat'].'
+;';
+  $page['cat_elements_id'] = array_from_query($query, 'image_id');
+}
+else if ('caddie' == $_GET['cat'])
+{
+  $page['title'] = $lang['caddie'];
+  
+  $query = '
+SELECT element_id
+  FROM '.CADDIE_TABLE.'
+  WHERE user_id = '.$user['id'].'
+;';
+  $page['cat_elements_id'] = array_from_query($query, 'element_id');
+}
+else if ('not_linked' == $_GET['cat'])
+{
+  $page['title'] = 'elements not linked to any virtual categories';
+  
+  // we are searching elements not linked to any virtual category
+  $query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE dir IS NULL
+;';
+  $virtual_categories = array_from_query($query, 'id');
+
+  $query = '
+SELECT DISTINCT(image_id)
+  FROM '.IMAGE_CATEGORY_TABLE.'
+;';
+  $all_elements = array_from_query($query, 'image_id');
+  
+  $query = '
+SELECT DISTINCT(image_id)
+  FROM '.IMAGE_CATEGORY_TABLE.'
+  WHERE category_id IN ('.implode(',', $virtual_categories).')
+;';
+  $linked_to_virtual = array_from_query($query, 'image_id');
+
+  $page['cat_elements_id'] = array_diff($all_elements, $linked_to_virtual);
+}
+
+// +-----------------------------------------------------------------------+
+// |                       first element to display                        |
+// +-----------------------------------------------------------------------+
+
+// $page['start'] contains the number of the first element in its
+// category. For exampe, $page['start'] = 12 means we must show elements #12
+// and $page['nb_images'] next elements
+
+if (!isset($_GET['start'])
+    or !is_numeric($_GET['start'])
+    or $_GET['start'] < 0
+    or (isset($_GET['display']) and 'all' == $_GET['display']))
+{
+  $page['start'] = 0;
+}
+else
+{
+  $page['start'] = $_GET['start'];
+}
+
+// +-----------------------------------------------------------------------+
+// |                         open specific mode                            |
+// +-----------------------------------------------------------------------+
+
+$_GET['mode'] = !empty($_GET['mode']) ? $_GET['mode'] : 'global';
+
+switch ($_GET['mode'])
+{
+  case 'global' :
+  {
+    include(PHPWG_ROOT_PATH.'admin/element_set_global.php');
+    break;
+  }
+  case 'unit' :
+  {
+    include(PHPWG_ROOT_PATH.'admin/element_set_unit.php');
+    break;
+  }
+}
+?>
Index: /branches/1.5/admin/element_set_global.php
===================================================================
--- /branches/1.5/admin/element_set_global.php	(revision 3250)
+++ /branches/1.5/admin/element_set_global.php	(revision 3250)
@@ -0,0 +1,484 @@
+<?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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+/**
+ * Management of elements set. Elements can belong to a category or to the
+ * user caddie.
+ * 
+ */
+ 
+if (!defined('PHPWG_ROOT_PATH'))
+{
+  die('Hacking attempt!');
+}
+include_once(PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php');
+
+// +-----------------------------------------------------------------------+
+// |                               functions                               |
+// +-----------------------------------------------------------------------+
+
+/**
+ * returns the list of uniq keywords among given elements
+ *
+ * @param array element_ids
+ */
+function get_elements_keywords($element_ids)
+{
+  if (0 == count($element_ids))
+  {
+    return array();
+  }
+  
+  $keywords = array();
+  
+  $query = '
+SELECT keywords
+  FROM '.IMAGES_TABLE.'
+  WHERE id IN ('.implode(',', $element_ids).')
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    if (isset($row['keywords']) and !empty($row['keywords']))
+    {
+      $keywords = array_merge($keywords, explode(',', $row['keywords']));
+    }
+  }
+  return array_unique($keywords);
+}
+
+// +-----------------------------------------------------------------------+
+// |                       global mode form submission                     |
+// +-----------------------------------------------------------------------+
+
+if (isset($_POST['submit']))
+{
+  $collection = array();
+  
+//   echo '<pre>';
+//   print_r($_POST);
+//   echo '</pre>';
+//   exit();
+
+  switch ($_POST['target'])
+  {
+    case 'all' :
+    {
+      $collection = $page['cat_elements_id'];
+      break;
+    }
+    case 'selection' :
+    {
+      if (!isset($_POST['selection']) or count($_POST['selection']) == 0)
+      {
+        array_push($page['errors'], l10n('Select at least one picture'));
+      }
+      else
+      {
+        $collection = $_POST['selection'];
+      }
+      break;
+    }
+  }
+
+  if ($_POST['associate'] != 0 and count($collection) > 0)
+  {
+    $datas = array();
+
+    $query = '
+SELECT image_id
+  FROM '.IMAGE_CATEGORY_TABLE.'
+  WHERE category_id = '.$_POST['associate'].'
+;';
+    $associated = array_from_query($query, 'image_id');
+
+    $associable = array_diff($collection, $associated);
+
+    if (count($associable) != 0)
+    {
+      foreach ($associable as $item)
+      {
+        array_push(
+          $datas,
+          array(
+            'category_id' => $_POST['associate'],
+            'image_id' => $item
+            )
+          );
+      }
+  
+      mass_inserts(
+        IMAGE_CATEGORY_TABLE,
+        array('image_id', 'category_id'),
+        $datas
+        );
+      
+      update_category(array($_POST['associate']));
+    }
+  }
+
+  if ($_POST['dissociate'] != 0 and count($collection) > 0)
+  {
+    // physical links must not be broken, so we must first retrieve image_id
+    // which create virtual links with the category to "dissociate from".
+    $query = '
+SELECT id
+  FROM '.IMAGE_CATEGORY_TABLE.' INNER JOIN '.IMAGES_TABLE.' ON image_id = id
+  WHERE category_id = '.$_POST['dissociate'].'
+    AND category_id != storage_category_id
+    AND id IN ('.implode(',', $collection).')
+;';
+    $dissociables = array_from_query($query, 'id');
+
+    $query = '
+DELETE FROM '.IMAGE_CATEGORY_TABLE.'
+  WHERE category_id = '.$_POST['dissociate'].'
+  AND image_id IN ('.implode(',', $dissociables).')
+';
+    pwg_query($query);
+
+    update_category(array($_POST['dissociate']));
+  }
+
+  $datas = array();
+  $dbfields = array('primary' => array('id'), 'update' => array());
+
+  if (!empty($_POST['add_keywords']) or $_POST['remove_keyword'] != '0')
+  {
+    array_push($dbfields['update'], 'keywords');
+  }
+
+  $formfields = array('author', 'name', 'date_creation');
+  foreach ($formfields as $formfield)
+  {
+    if ($_POST[$formfield.'_action'] != 'leave')
+    {
+      array_push($dbfields['update'], $formfield);
+    }
+  }
+  
+  // updating elements is useful only if needed...
+  if (count($dbfields['update']) > 0 and count($collection) > 0)
+  {
+    $query = '
+SELECT id, keywords
+  FROM '.IMAGES_TABLE.'
+  WHERE id IN ('.implode(',', $collection).')
+;';
+    $result = pwg_query($query);
+
+    while ($row = mysql_fetch_array($result))
+    {
+      $data = array();
+      $data['id'] = $row['id'];
+      
+      if (!empty($_POST['add_keywords']))
+      {
+        $data['keywords'] =
+          implode(
+            ',',
+            array_unique(
+              array_merge(
+                get_keywords(empty($row['keywords']) ? '' : $row['keywords']),
+                get_keywords($_POST['add_keywords'])
+                )
+              )
+            );
+      }
+
+      if ($_POST['remove_keyword'] != '0')
+      {
+        if (!isset($data['keywords']))
+        {
+          $data['keywords'] = empty($row['keywords']) ? '' : $row['keywords'];
+        }
+        
+        $data['keywords'] =
+          implode(
+            ',',
+            array_unique(
+              array_diff(
+                get_keywords($data['keywords']),
+                array($_POST['remove_keyword'])
+                )
+              )
+            );
+
+        if ($data['keywords'] == '')
+        {
+          unset($data['keywords']);
+        }
+      }
+
+      if ('set' == $_POST['author_action'])
+      {
+        $data['author'] = $_POST['author'];
+
+        if ('' == $data['author'])
+        {
+          unset($data['author']);
+        }
+      }
+
+      if ('set' == $_POST['name_action'])
+      {
+        $data['name'] = $_POST['name'];
+
+        if ('' == $data['name'])
+        {
+          unset($data['name']);
+        }
+      }
+
+      if ('set' == $_POST['date_creation_action'])
+      {
+        $data['date_creation'] =
+          $_POST['date_creation_year']
+          .'-'.$_POST['date_creation_month']
+          .'-'.$_POST['date_creation_day']
+          ;
+      }
+      
+      array_push($datas, $data);
+    }
+    // echo '<pre>'; print_r($datas); echo '</pre>';
+    mass_updates(IMAGES_TABLE, $dbfields, $datas);
+  }
+}
+
+// +-----------------------------------------------------------------------+
+// |                             template init                             |
+// +-----------------------------------------------------------------------+
+$template->set_filenames(
+  array('element_set_global' => 'admin/element_set_global.tpl'));
+
+$base_url = PHPWG_ROOT_PATH.'admin.php';
+
+// $form_action = $base_url.'?page=element_set_global';
+
+$template->assign_vars(
+  array(
+    'CATEGORIES_NAV'=>$page['title'],
+    
+    'L_SUBMIT'=>$lang['submit'],
+
+    'U_COLS'=>$base_url.get_query_string_diff(array('cols')),
+    'U_DISPLAY'=>$base_url.get_query_string_diff(array('display')),
+    
+    'U_UNIT_MODE'
+    =>
+    $base_url
+    .get_query_string_diff(array('mode','display'))
+    .'&amp;mode=unit',
+    
+    'F_ACTION'=>$base_url.get_query_string_diff(array()),
+   )
+ );
+
+// +-----------------------------------------------------------------------+
+// |                            caddie options                             |
+// +-----------------------------------------------------------------------+
+
+if ('caddie' == $_GET['cat'])
+{
+  $template->assign_block_vars('in_caddie', array());
+}
+else
+{
+  $template->assign_block_vars('not_in_caddie', array());
+}
+
+// +-----------------------------------------------------------------------+
+// |                           global mode form                            |
+// +-----------------------------------------------------------------------+
+
+// Virtualy associate a picture to a category
+$blockname = 'associate_option';
+
+$template->assign_block_vars(
+  $blockname,
+  array('SELECTED' => '',
+        'VALUE'=> 0,
+        'OPTION' => '------------'
+    ));
+
+$query = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE.'
+;';
+display_select_cat_wrapper($query, array(), $blockname, true);
+
+// Dissociate from a category : categories listed for dissociation can
+// only represent virtual links. Links to physical categories can't be
+// broken
+$blockname = 'dissociate_option';
+
+$template->assign_block_vars(
+  $blockname,
+  array('SELECTED' => '',
+        'VALUE'=> 0,
+        'OPTION' => '------------'
+    ));
+
+if (count($page['cat_elements_id']) > 0)
+{
+  $query = '
+SELECT DISTINCT(category_id) AS id, c.name, uppercats, global_rank
+  FROM '.IMAGE_CATEGORY_TABLE.' AS ic,
+       '.CATEGORIES_TABLE.' AS c,
+       '.IMAGES_TABLE.' AS i
+  WHERE ic.image_id IN ('.implode(',', $page['cat_elements_id']).')
+    AND ic.category_id = c.id
+    AND ic.image_id = i.id
+    AND ic.category_id != i.storage_category_id
+;';
+  display_select_cat_wrapper($query, array(), $blockname, true);
+}
+
+$blockname = 'remove_keyword_option';
+
+$template->assign_block_vars(
+  $blockname,
+  array('VALUE'=> 0,
+        'OPTION' => '------------'
+    ));
+
+$keywords = get_elements_keywords($page['cat_elements_id']);
+
+foreach ($keywords as $keyword)
+{
+  $template->assign_block_vars(
+  $blockname,
+  array('VALUE'=> $keyword,
+        'OPTION' => $keyword
+    ));
+}
+
+// creation date
+$day =
+empty($_POST['date_creation_day']) ? date('j') : $_POST['date_creation_day'];
+get_day_list('date_creation_day', $day);
+
+if (!empty($_POST['date_creation_month']))
+{
+  $month = $_POST['date_creation_month'];
+}
+else
+{
+  $month = date('n');
+}
+get_month_list('date_creation_month', $month);
+
+if (!empty($_POST['date_creation_year']))
+{
+  $year = $_POST['date_creation_year'];
+}
+else
+{
+  $year = date('Y');
+}
+$template->assign_vars(array('DATE_CREATION_YEAR_VALUE'=>$year));
+
+// +-----------------------------------------------------------------------+
+// |                        global mode thumbnails                         |
+// +-----------------------------------------------------------------------+
+
+$page['cols'] = !empty($_GET['cols']) ? intval($_GET['cols']) : 5;
+
+// how many items to display on this page
+if (!empty($_GET['display']))
+{
+  if ('all' == $_GET['display'])
+  {
+    $page['nb_images'] = count($page['cat_elements_id']);
+  }
+  else
+  {
+    $page['nb_images'] = intval($_GET['display']);
+  }
+}
+else
+{
+  $page['nb_images'] = 20;
+}
+
+if (count($page['cat_elements_id']) > 0)
+{
+  $nav_bar = create_navigation_bar(
+    $base_url.get_query_string_diff(array('start')),
+    count($page['cat_elements_id']),
+    $page['start'],
+    $page['nb_images'],
+    '');
+  $template->assign_vars(array('NAV_BAR' => $nav_bar));
+
+  $query = '
+SELECT id,path,tn_ext
+  FROM '.IMAGES_TABLE.'
+  WHERE id IN ('.implode(',', $page['cat_elements_id']).')
+  '.$conf['order_by'].'
+  LIMIT '.$page['start'].', '.$page['nb_images'].'
+;';
+  //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))
+  {
+    $src = get_thumbnail_src($row['path'], @$row['tn_ext']);
+    
+    $template->assign_block_vars(
+      'thumbnails.line.thumbnail',
+      array(
+        'ID' => $row['id'],
+        'SRC' => $src,
+        'ALT' => 'TODO',
+        'TITLE' => 'TODO'
+        )
+      );
+    
+    // create a new line ?
+    if (++$row_number == $page['cols'])
+    {
+    $template->assign_block_vars('thumbnails.line', array());
+    $row_number = 0;
+    }
+  }
+}
+
+//----------------------------------------------------------- sending html code
+$template->assign_var_from_handle('ADMIN_CONTENT', 'element_set_global');
+?>
Index: /branches/1.5/admin/element_set_unit.php
===================================================================
--- /branches/1.5/admin/element_set_unit.php	(revision 3250)
+++ /branches/1.5/admin/element_set_unit.php	(revision 3250)
@@ -0,0 +1,252 @@
+<?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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+/**
+ * Management of elements set. Elements can belong to a category or to the
+ * user caddie.
+ * 
+ */
+ 
+if (!defined('PHPWG_ROOT_PATH'))
+{
+  die('Hacking attempt!');
+}
+include_once(PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php');
+
+// +-----------------------------------------------------------------------+
+// |                        unit mode form submission                      |
+// +-----------------------------------------------------------------------+
+
+if (isset($_POST['submit']))
+{
+  $collection = explode(',', $_POST['list']);
+  
+  $datas = array();
+  
+  $query = '
+SELECT id, date_creation
+  FROM '.IMAGES_TABLE.'
+  WHERE id IN ('.implode(',', $collection).')
+;';
+  $result = pwg_query($query);
+
+  while ($row = mysql_fetch_array($result))
+  {
+    $data = array();
+
+    $data{'id'} = $row['id'];
+    $data{'name'} = $_POST['name-'.$row['id']];
+    $data{'author'} = $_POST['author-'.$row['id']];
+
+    foreach (array('name', 'author') as $field)
+    {
+      if (!empty($_POST[$field.'-'.$row['id']]))
+      {
+        $data{$field} = strip_tags($_POST[$field.'-'.$row['id']]);
+      }
+    }
+    
+    if ($conf['allow_html_descriptions'])
+    {
+      $data{'comment'} = @$_POST['description-'.$row['id']];
+    }
+    else
+    {
+      $data{'comment'} = strip_tags(@$_POST['description-'.$row['id']]);
+    }
+
+    if (isset($_POST['date_creation_action-'.$row['id']]))
+    {
+      if ('set' == $_POST['date_creation_action-'.$row['id']])
+      {
+        $data{'date_creation'} =
+          $_POST['date_creation_year-'.$row['id']]
+            .'-'.$_POST['date_creation_month-'.$row['id']]
+            .'-'.$_POST['date_creation_day-'.$row['id']];
+      }
+      else if ('unset' == $_POST['date_creation_action-'.$row['id']])
+      {
+        $data{'date_creation'} = '';
+      }
+    }
+    else
+    {
+      $data{'date_creation'} = $row['date_creation'];
+    }
+
+    $keywords = get_keywords($_POST['keywords-'.$row['id']]);
+    if (count($keywords) > 0)
+    {
+      $data{'keywords'} = implode(',', $keywords);
+    }
+    else
+    {
+      $data{'keywords'} = '';
+    }
+
+    array_push($datas, $data);
+  }
+  
+  mass_updates(
+    IMAGES_TABLE,
+    array(
+      'primary' => array('id'),
+      'update' => array('name','author','comment','date_creation','keywords')
+      ),
+    $datas
+    );
+  
+  array_push($page['infos'], l10n('Picture informations updated'));
+}
+
+// +-----------------------------------------------------------------------+
+// |                             template init                             |
+// +-----------------------------------------------------------------------+
+
+$template->set_filenames(
+  array('element_set_unit' => 'admin/element_set_unit.tpl'));
+
+$base_url = PHPWG_ROOT_PATH.'admin.php';
+
+// $form_action = $base_url.'?page=element_set_global';
+
+$template->assign_vars(
+  array(
+    'CATEGORIES_NAV'=>$page['title'],
+
+    'L_SUBMIT'=>$lang['submit'],
+    
+    'U_ELEMENTS_PAGE'
+    =>$base_url.get_query_string_diff(array('display','start')),
+    
+    'U_GLOBAL_MODE'
+    =>
+    $base_url
+    .get_query_string_diff(array('mode','display'))
+    .'&amp;mode=global',
+    
+    'F_ACTION'=>$base_url.get_query_string_diff(array()),
+    )
+  );
+
+// +-----------------------------------------------------------------------+
+// |                        global mode thumbnails                         |
+// +-----------------------------------------------------------------------+
+
+// how many items to display on this page
+if (!empty($_GET['display']))
+{
+  if ('all' == $_GET['display'])
+  {
+    $page['nb_images'] = count($page['cat_elements_id']);
+  }
+  else
+  {
+    $page['nb_images'] = intval($_GET['display']);
+  }
+}
+else
+{
+  $page['nb_images'] = 5;
+}
+
+
+
+if (count($page['cat_elements_id']) > 0)
+{
+  $nav_bar = create_navigation_bar(
+    $base_url.get_query_string_diff(array('start')),
+    count($page['cat_elements_id']),
+    $page['start'],
+    $page['nb_images'],
+    '');
+  $template->assign_vars(array('NAV_BAR' => $nav_bar));
+
+ 
+  $element_ids = array();
+
+  $query = '
+SELECT id,path,tn_ext,name,date_creation,comment,keywords,author,file
+  FROM '.IMAGES_TABLE.'
+  WHERE id IN ('.implode(',', $page['cat_elements_id']).')
+  '.$conf['order_by'].'
+  LIMIT '.$page['start'].', '.$page['nb_images'].'
+;';
+  $result = pwg_query($query);
+
+  while ($row = mysql_fetch_array($result))
+  {
+    // echo '<pre>'; print_r($row); echo '</pre>';
+    array_push($element_ids, $row['id']);
+    
+    $src = get_thumbnail_src($row['path'], @$row['tn_ext']);
+    
+    // creation date
+    if (!empty($row['date_creation']))
+    {
+      list($year,$month,$day) = explode('-', $row['date_creation']);
+    }
+    else
+    {
+      list($year,$month,$day) = array('','','');
+    }
+    
+    $template->assign_block_vars(
+      'element',
+      array(
+        'LEGEND' =>
+          !empty($row['name']) ?
+            $row['name'] : get_name_from_file($row['file']),
+        'U_EDIT' =>
+          add_session_id(
+            PHPWG_ROOT_PATH.'admin.php?page=picture_modify'.
+            '&amp;image_id='.$row['id']
+            ),
+        'ID' => $row['id'],
+        'FILENAME' => $row['path'],
+        'TN_SRC' => $src,
+        'NAME' => @$row['name'],
+        'AUTHOR' => @$row['author'],
+        'DESCRIPTION' => @$row['comment'],
+        'DATE_CREATION_YEAR' => $year,
+        'KEYWORDS' => @$row['keywords']
+        )
+      );
+    
+    get_day_list('element.date_creation_day', $day);
+    get_month_list('element.date_creation_month', $month);
+  }
+
+  $template->assign_vars(array('IDS_LIST' => implode(',', $element_ids)));
+}
+
+// +-----------------------------------------------------------------------+
+// |                           sending html code                           |
+// +-----------------------------------------------------------------------+
+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'element_set_unit');
+?>
Index: /branches/1.5/admin/group_list.php
===================================================================
--- /branches/1.5/admin/group_list.php	(revision 3250)
+++ /branches/1.5/admin/group_list.php	(revision 3250)
@@ -0,0 +1,177 @@
+<?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                            |
+// +-----------------------------------------------------------------------+
+
+if (isset($_GET['delete']) and is_numeric($_GET['delete']))
+{
+  // destruction of the access linked to the group
+  $query = '
+DELETE
+  FROM '.GROUP_ACCESS_TABLE.'
+  WHERE group_id = '.$_GET['delete'].'
+;';
+  pwg_query($query);
+  
+  // destruction of the users links for this group
+  $query = '
+DELETE
+  FROM '.USER_GROUP_TABLE.'
+  WHERE group_id = '.$_GET['delete'].'
+;';
+  pwg_query($query);
+
+  $query = '
+SELECT name
+  FROM '.GROUPS_TABLE.'
+  WHERE id = '.$_GET['delete'].'
+;';
+  list($groupname) = mysql_fetch_row(pwg_query($query));
+  
+  // destruction of the group
+  $query = '
+DELETE
+  FROM '.GROUPS_TABLE.'
+  WHERE id = '.$_GET['delete'].'
+;';
+  pwg_query($query);
+
+  array_push(
+    $page['infos'],
+    sprintf(l10n('group "%s" deleted'), $groupname)
+    );
+}
+
+// +-----------------------------------------------------------------------+
+// |                              add a group                              |
+// +-----------------------------------------------------------------------+
+
+if (isset($_POST['submit_add']))
+{
+  if (empty($_POST['groupname']))
+  {
+    array_push($page['errors'], $lang['group_add_error1']);
+  }
+  if (count($page['errors']) == 0)
+  {
+    // is the group not already existing ?
+    $query = '
+SELECT COUNT(*)
+  FROM '.GROUPS_TABLE.'
+  WHERE name = \''.$_POST['groupname'].'\'
+;';
+    list($count) = mysql_fetch_row(pwg_query($query));
+    if ($count != 0)
+    {
+      array_push($page['errors'], $lang['group_add_error2']);
+    }
+  }
+  if (count($page['errors']) == 0)
+  {
+    // creating the group
+    $query = '
+INSERT INTO '.GROUPS_TABLE.'
+  (name)
+  VALUES
+  (\''.mysql_escape_string($_POST['groupname']).'\')
+;';
+    pwg_query($query);
+
+    array_push(
+      $page['infos'],
+      sprintf(l10n('group "%s" added'), $_POST['groupname'])
+      );
+  }
+}
+
+// +-----------------------------------------------------------------------+
+// |                             template init                             |
+// +-----------------------------------------------------------------------+
+
+$template->set_filenames(array('group_list' => 'admin/group_list.tpl'));
+
+$template->assign_vars(
+  array(
+    'F_ADD_ACTION' =>
+      add_session_id(PHPWG_ROOT_PATH.'admin.php?page=group_list')
+    )
+  );
+
+// +-----------------------------------------------------------------------+
+// |                              group list                               |
+// +-----------------------------------------------------------------------+
+
+$query = '
+SELECT id, name
+  FROM '.GROUPS_TABLE.'
+  ORDER BY id ASC
+;';
+$result = pwg_query($query);
+
+$admin_url = PHPWG_ROOT_PATH.'admin.php?page=';
+$perm_url    = $admin_url.'group_perm&amp;group_id=';
+$del_url     = $admin_url.'group_list&amp;delete=';
+$members_url = $admin_url.'user_list&amp;group=';
+
+$num = 0;
+while ($row = mysql_fetch_array($result))
+{
+  $query = '
+SELECT COUNT(*)
+  FROM '.USER_GROUP_TABLE.'
+  WHERE group_id = '.$row['id'].'
+;';
+  list($counter) = mysql_fetch_row(pwg_query($query));
+  
+  $template->assign_block_vars(
+    'group',
+    array(
+      'CLASS' => ($num++ % 2 == 1) ? 'row2' : 'row1',
+      'NAME' => $row['name'],
+      'MEMBERS' => sprintf(l10n('%d members'), $counter),
+      'U_MEMBERS' => $members_url.$row['id'],
+      'U_DELETE' => add_session_id($del_url.$row['id']),
+      'U_PERM' => add_session_id($perm_url.$row['id'])
+      )
+    );
+}
+
+// +-----------------------------------------------------------------------+
+// |                           sending html code                           |
+// +-----------------------------------------------------------------------+
+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'group_list');
+
+?>
Index: /branches/1.5/admin/group_perm.php
===================================================================
--- /branches/1.5/admin/group_perm.php	(revision 3250)
+++ /branches/1.5/admin/group_perm.php	(revision 3250)
@@ -0,0 +1,187 @@
+<?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' );
+
+// +-----------------------------------------------------------------------+
+// |                            variables init                             |
+// +-----------------------------------------------------------------------+
+
+if (isset($_GET['group_id']) and is_numeric($_GET['group_id']))
+{
+  $page['group'] = $_GET['group_id'];
+}
+else
+{
+  echo l10n('group_id URL parameter is missing');
+  exit();
+}
+
+// +-----------------------------------------------------------------------+
+// |                                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 = '.$page['group'].'
+  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 = '.$page['group'].'
+;';
+  $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' => $page['group'],
+        'cat_id' => $to_autorize_id
+        )
+      );
+  }
+
+  mass_inserts(GROUP_ACCESS_TABLE, array('group_id','cat_id'), $inserts);
+}
+
+// +-----------------------------------------------------------------------+
+// |                             template init                             |
+// +-----------------------------------------------------------------------+
+
+$template->set_filenames(
+  array(
+    'group_perm' => 'admin/group_perm.tpl',
+    'double_select' => 'admin/double_select.tpl'
+    )
+  );
+
+$template->assign_vars(
+  array(
+    'TITLE' =>
+      sprintf(
+        l10n('Manage permissions for group "%s"'),
+        get_groupname($page['group']
+          )
+        ),
+    'L_CAT_OPTIONS_TRUE'=>$lang['authorized'],
+    'L_CAT_OPTIONS_FALSE'=>$lang['forbidden'],
+    'L_CAT_OPTIONS_INFO'=>$lang['permuser_info'],
+    
+    'F_ACTION' =>
+      add_session_id(
+        PHPWG_ROOT_PATH.
+        'admin.php?page=group_perm&amp;group_id='.
+        $page['group']
+        )
+    )
+  );
+  
+// 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 = '.$page['group'].'
+;';
+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');
+
+// +-----------------------------------------------------------------------+
+// |                           html code display                           |
+// +-----------------------------------------------------------------------+
+
+$template->assign_var_from_handle('DOUBLE_SELECT', 'double_select');
+$template->assign_var_from_handle('ADMIN_CONTENT', 'group_perm');
+
+?>
Index: /branches/1.5/admin/help.php
===================================================================
--- /branches/1.5/admin/help.php	(revision 3250)
+++ /branches/1.5/admin/help.php	(revision 3250)
@@ -0,0 +1,37 @@
+<?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->set_filenames(
+  array(
+    'help_content' => get_language_filepath('help.html')
+    )
+  );
+  
+$template->assign_var_from_handle('ADMIN_CONTENT', 'help_content');
+?>
Index: /branches/1.5/admin/images/daily_stats.img.php
===================================================================
--- /branches/1.5/admin/images/daily_stats.img.php	(revision 3250)
+++ /branches/1.5/admin/images/daily_stats.img.php	(revision 3250)
@@ -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_daily_graph_title'];
+$imageHeight = 256;
+$imageWidth = 512;
+$sql = '
+SELECT DISTINCT COUNT(*)
+     , HOUR(DATE_FORMAT(date, \'%H:%i:%s\'))
+  FROM '.HISTORY_TABLE.'
+  WHERE YEAR(date) = '.$_GET['year'].'
+    AND MONTH(date) = '.$_GET['month'].'
+    AND DAYOFMONTH(date) = '.$_GET['day'].'
+  GROUP BY DATE_FORMAT(date, \'%H\') 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);
+
+$hours = array();
+for ($i = 0; $i <= 23; $i++)
+{
+  $hours[$i] = 0;
+}
+
+while ($r = mysql_fetch_row($result))
+{ 
+  $hours[$r[1]]= $r[0];
+}
+$o=0;
+while (list ($key,$value) = each($hours ))
+{
+  $myBarGraph->AddValue($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.5/admin/images/global_stats.img.php
===================================================================
--- /branches/1.5/admin/images/global_stats.img.php	(revision 3250)
+++ /branches/1.5/admin/images/global_stats.img.php	(revision 3250)
@@ -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.5/admin/images/index.htm
===================================================================
--- /branches/1.5/admin/images/index.htm	(revision 3250)
+++ /branches/1.5/admin/images/index.htm	(revision 3250)
@@ -0,0 +1,8 @@
+<html>
+    <head>
+        <title>PhpWebGallery</title>
+    </head>
+    <body>
+        No access authorized
+    </body>
+</html>
Index: /branches/1.5/admin/images/monthly_stats.img.php
===================================================================
--- /branches/1.5/admin/images/monthly_stats.img.php	(revision 3250)
+++ /branches/1.5/admin/images/monthly_stats.img.php	(revision 3250)
@@ -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_monthly_graph_title'];
+$imageHeight = 256;
+$imageWidth = 512;
+$sql = '
+SELECT DISTINCT COUNT(*)
+     , DAYOFMONTH(date) 
+  FROM '.HISTORY_TABLE.'
+  WHERE YEAR(date) = '.$_GET['year'].'
+    AND MONTH(date) = '.$_GET['month'].'
+  GROUP BY DATE_FORMAT(date, \'%Y-%m-%d\') 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);
+
+$days = array();
+for ($i = 1; $i <= 31; $i++)
+{
+  $days[$i] = 0;
+}
+
+while ($r = mysql_fetch_row($result))
+{ 
+  $days[$r[1]]= $r[0];
+}
+$o=0;
+while (list ($key,$value) = each($days ))
+{
+  $myBarGraph->AddValue($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.5/admin/images/phpBarGraph.php
===================================================================
--- /branches/1.5/admin/images/phpBarGraph.php	(revision 3250)
+++ /branches/1.5/admin/images/phpBarGraph.php	(revision 3250)
@@ -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.5/admin/include/functions.php
===================================================================
--- /branches/1.5/admin/include/functions.php	(revision 3250)
+++ /branches/1.5/admin/include/functions.php	(revision 3250)
@@ -0,0 +1,1492 @@
+<?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');
+
+/**
+ * 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;
+}
+
+// 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 rates associated to this element
+  $query = '
+DELETE FROM '.CADDIE_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)
+{
+  global $conf;
+  
+  // 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_CACHE_TABLE.'
+  WHERE user_id = '.$user_id.'
+;';
+  pwg_query($query);
+
+  // deletion of phpwebgallery specific informations
+  $query = '
+DELETE FROM '.USER_INFOS_TABLE.'
+  WHERE user_id = '.$user_id.'
+;';
+  pwg_query($query);
+
+  // destruction of the user
+  $query = '
+DELETE FROM '.USERS_TABLE.'
+  WHERE '.$conf['user_fields']['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)
+{
+  global $conf;
+  
+  // 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.= '
+;';
+  $cat_ids = array_unique(array_from_query($query, 'id'));
+
+  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);
+
+  // representative pictures
+  if (count($cat_ids) > 0)
+  {
+    // find all categories where the setted representative is not possible :
+    // the picture does not exist
+    $query = '
+SELECT c.id
+  FROM '.CATEGORIES_TABLE.' AS c LEFT JOIN '.IMAGES_TABLE.' AS i
+    ON c.representative_picture_id = i.id
+  WHERE representative_picture_id IS NOT NULL
+    AND c.id IN ('.wordwrap(implode(', ', $cat_ids), 80, "\n").')
+    AND i.id IS NULL
+;';
+    $wrong_representant = array_from_query($query, 'id');
+
+    if ($conf['allow_random_representative'])
+    {
+      if (count($wrong_representant) > 0)
+      {
+        $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET representative_picture_id = NULL
+  WHERE id IN ('.wordwrap(implode(', ', $wrong_representant), 80, "\n").')
+;';
+        pwg_query($query);
+      }
+    }
+    else
+    {
+      $to_null = array();
+      $to_rand = array();
+
+      if (count($wrong_representant) > 0)
+      {
+        // among the categories with an unknown representant, we dissociate
+        // categories containing pictures and categories containing no
+        // pictures. Indeed, the representant must set to NULL if no picture
+        // in the category and set to a random picture otherwise.
+        $query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id IN ('.wordwrap(implode(', ', $wrong_representant), 80, "\n").')
+    AND nb_images = 0
+;';
+        $to_null = array_from_query($query, 'id');
+        $to_rand = array_diff($wrong_representant, $to_null);
+      }
+      
+      if (count($to_null) > 0)
+      {
+        $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET representative_picture_id = NULL
+  WHERE id IN ('.wordwrap(implode(', ', $to_null), 80, "\n").')
+;';
+        pwg_query($query);
+      }
+      
+      // If the random representant is not allowed, we need to find
+      // categories with elements and with no representant. Those categories
+      // must be added to the list of categories to set to a random
+      // representant.
+      $query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE representative_picture_id IS NULL
+    AND nb_images != 0
+    AND id IN ('.wordwrap(implode(', ', $cat_ids), 80, "\n").')
+;';
+      $to_rand =
+        array_unique(
+          array_merge(
+            $to_rand,
+            array_from_query($query, 'id')
+            )
+          );
+      
+      if (count($to_rand) > 0)
+      {
+        set_random_representant($to_rand);
+      }
+    }
+  }
+}
+
+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 '';
+  }
+}
+
+/**
+ * returns an array with relevant keywords found in the given string.
+ *
+ * Keywords must be separated by comma or space characters.
+ *
+ * @param string keywords_string
+ * @return array
+ */
+function get_keywords($keywords_string)
+{
+  return
+    array_unique(
+      preg_split(
+        '/[\s,]+/',
+        $keywords_string
+        )
+      );
+}
+
+/**
+ * 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 != '.svn'
+            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;';
+  list($mysql_version) = mysql_fetch_array(pwg_query($query));
+  if (count($datas) < 10 or version_compare($mysql_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 ';
+      $is_first = true;
+      foreach ($dbfields['update'] as $num => $key)
+      {
+        if (!$is_first)
+        {
+          $query.= ",\n      ";
+        }
+        $query.= $key.' = ';
+        if (isset($data[$key]) and $data[$key] != '')
+        {
+          $query.= '\''.$data[$key].'\'';
+        }
+        else
+        {
+          $query.= 'NULL';
+        }
+        $is_first = false;
+      }
+      $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 ('.implode(',', $dbfields['primary']).')
+)
+;';
+    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;
+}
+
+/**
+ * synchronize base users list and related users list
+ *
+ * compares and synchronizes base users table (USERS_TABLE) with its child
+ * tables (USER_INFOS_TABLE, USER_ACCESS, USER_CACHE, USER_GROUP) : each
+ * base user must be present in child tables, users in child tables not
+ * present in base table must be deleted.
+ *
+ * @return void
+ */
+function sync_users()
+{
+  global $conf;
+  
+  $query = '
+SELECT '.$conf['user_fields']['id'].' AS id
+  FROM '.USERS_TABLE.'
+;';
+  $base_users = array_from_query($query, 'id');
+
+  $query = '
+SELECT user_id
+  FROM '.USER_INFOS_TABLE.'
+;';
+  $infos_users = array_from_query($query, 'user_id');
+
+  // users present in $base_users and not in $infos_users must be added
+  $to_create = array_diff($base_users, $infos_users);
+
+  if (count($to_create) > 0)
+  {
+    $inserts = array();
+
+    list($dbnow) = mysql_fetch_row(pwg_query('SELECT NOW();'));
+
+    foreach ($to_create as $user_id)
+    {
+      $insert = array();
+      $insert['user_id'] = $user_id;
+      $insert['status'] = 'guest';
+      $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']);
+      $insert['maxwidth'] = $conf['default_maxwidth'];
+      $insert['maxheight'] = $conf['default_maxheight'];
+      $insert['registration_date'] = $dbnow;
+
+      array_push($inserts, $insert);
+    }
+
+    mass_inserts(USER_INFOS_TABLE,
+                 array_keys($inserts[0]),
+                 $inserts);
+  }
+
+  // users present in user related tables must be present in the base user
+  // table
+  $tables =
+    array(
+      USER_FEED_TABLE,
+      USER_INFOS_TABLE,
+      USER_ACCESS_TABLE,
+      USER_CACHE_TABLE,
+      USER_GROUP_TABLE
+      );
+  foreach ($tables as $table)
+  {
+    $query = '
+SELECT user_id
+  FROM '.$table.'
+;';
+    $to_delete =
+      array_diff(
+        array_from_query($query, 'user_id'),
+        $base_users
+        );
+    
+    if (count($to_delete) > 0)
+    {
+      $query = '
+DELETE
+  FROM '.$table.'
+  WHERE user_id in ('.implode(',', $to_delete).')
+;';
+      pwg_query($query);
+    }
+  }
+}
+
+/**
+ * updates categories.uppercats field based on categories.id +
+ * categories.id_uppercat
+ *
+ * @return void
+ */
+function update_uppercats()
+{
+  $uppercat_ids = array();
+  
+  $query = '
+SELECT id, id_uppercat
+  FROM '.CATEGORIES_TABLE.'
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    $uppercat_ids[$row['id']] =
+      !empty($row['id_uppercat']) ? $row['id_uppercat'] : 'NULL';
+  }
+  
+  // uppercats array associates a category id to the list of uppercats id.
+  $uppercats = array();
+  
+  foreach (array_keys($uppercat_ids) as $id)
+  {
+    $uppercats[$id] = array();
+
+    $uppercat = $id;
+
+    while ($uppercat != 'NULL')
+    {
+      array_push($uppercats[$id], $uppercat);
+      $uppercat = $uppercat_ids[$uppercat];
+    }
+  }
+
+  $datas = array();
+
+  foreach ($uppercats as $id => $list)
+  {
+    array_push(
+      $datas,
+      array(
+        'id' => $id,
+        'uppercats' => implode(',', array_reverse($list))
+        )
+      );
+  }
+
+  $fields = array('primary' => array('id'), 'update' => array('uppercats'));
+  mass_updates(CATEGORIES_TABLE, $fields, $datas);
+}
+
+/**
+ * update images.path field
+ *
+ * @return void
+ */
+function update_path()
+{
+  $query = '
+SELECT DISTINCT(storage_category_id)
+  FROM '.IMAGES_TABLE.'
+;';
+  $cat_ids = array_from_query($query, '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);
+  }
+}
+
+/**
+ * update images.average_rate field
+ *
+ * @return void
+ */
+function update_average_rate()
+{
+  $average_rates = array();
+  
+  $query = '
+SELECT element_id,
+       ROUND(AVG(rate),2) AS average_rate
+  FROM '.RATE_TABLE.'
+  GROUP BY element_id
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($average_rates, $row);
+  }
+
+  $datas = array();
+  foreach ($average_rates as $item)
+  {
+    array_push(
+      $datas,
+      array(
+        'id' => $item['element_id'],
+        'average_rate' => $item['average_rate']
+        )
+      );
+  }
+  $fields = array('primary' => array('id'), 'update' => array('average_rate'));
+  mass_updates(IMAGES_TABLE, $fields, $datas);
+}
+
+/**
+ * change the parent category of the given categories. The categories are
+ * supposed virtual.
+ *
+ * @param array category identifiers
+ * @param int parent category identifier
+ * @return void
+ */
+function move_categories($category_ids, $new_parent = -1)
+{
+  global $page;
+
+  if (count($category_ids) == 0)
+  {
+    return;
+  }
+
+  $new_parent = $new_parent < 1 ? 'NULL' : $new_parent;
+
+  $categories = array();
+  
+  $query = '
+SELECT id, id_uppercat, status, uppercats
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id IN ('.implode(',', $category_ids).')
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    $categories[$row['id']] =
+      array(
+        'parent' => empty($row['id_uppercat']) ? 'NULL' : $row['id_uppercat'],
+        'status' => $row['status'],
+        'uppercats' => $row['uppercats']
+        );
+  }
+  
+  // is the movement possible? The movement is impossible if you try to move
+  // a category in a sub-category or itself
+  if ('NULL' != $new_parent)
+  {
+    $query = '
+SELECT uppercats
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id = '.$new_parent.'
+;';
+    list($new_parent_uppercats) = mysql_fetch_row(pwg_query($query));
+
+    foreach ($categories as $category)
+    {
+      // technically, you can't move a category with uppercats 12,125,13,14
+      // into a new parent category with uppercats 12,125,13,14,24
+      if (preg_match('/^'.$category['uppercats'].'/', $new_parent_uppercats))
+      {
+        array_push(
+          $page['errors'],
+          l10n('You cannot move a category in its own sub category')
+          );
+        return;
+      }
+    }
+  }
+  
+  $tables =
+    array(
+      USER_ACCESS_TABLE => 'user_id',
+      GROUP_ACCESS_TABLE => 'group_id'
+      );
+  
+  $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET id_uppercat = '.$new_parent.'
+  WHERE id IN ('.implode(',', $category_ids).')
+;';
+  pwg_query($query);
+
+  update_uppercats();
+  ordering();
+  update_global_rank();
+
+  // status and related permissions management
+  if ('NULL' == $new_parent)
+  {
+    $parent_status = 'public';
+  }
+  else
+  {
+    $query = '
+SELECT status
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id = '.$new_parent.'
+;';
+    list($parent_status) = mysql_fetch_row(pwg_query($query));
+  }
+
+  if ('private' == $parent_status)
+  {
+    foreach ($categories as $cat_id => $category)
+    {
+      switch ($category['status'])
+      {
+        case 'public' :
+        {
+          set_cat_status(array($cat_id), 'private');
+          break;
+        }
+        case 'private' :
+        {
+          $subcats = get_subcat_ids(array($cat_id));
+        
+          foreach ($tables as $table => $field)
+          {
+            $query = '
+SELECT '.$field.'
+  FROM '.$table.'
+  WHERE cat_id = '.$cat_id.'
+;';
+            $category_access = array_from_query($query, $field);
+
+            $query = '
+SELECT '.$field.'
+  FROM '.$table.'
+  WHERE cat_id = '.$new_parent.'
+;';
+            $parent_access = array_from_query($query, $field);
+          
+            $to_delete = array_diff($parent_access, $category_access);
+          
+            if (count($to_delete) > 0)
+            {
+              $query = '
+DELETE FROM '.$table.'
+  WHERE '.$field.' IN ('.implode(',', $to_delete).')
+    AND cat_id IN ('.implode(',', $subcats).')
+;';
+              pwg_query($query);
+            }
+          }
+          break;
+        }
+      }
+    }
+  }
+
+  array_push(
+    $page['infos'],
+    sprintf(
+      l10n('%d categories moved'),
+      count($categories)
+      )
+    );
+}
+?>
Index: /branches/1.5/admin/include/functions_metadata.php
===================================================================
--- /branches/1.5/admin/include/functions_metadata.php	(revision 3250)
+++ /branches/1.5/admin/include/functions_metadata.php	(revision 3250)
@@ -0,0 +1,242 @@
+<?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');
+
+$page['datefields'] = array('date_creation', 'date_available');
+
+function get_sync_iptc_data($file)
+{
+  global $conf, $page;
+  
+  $map = $conf['use_iptc_mapping'];
+  
+  $iptc = get_iptc_data($file, $map);
+
+  foreach ($iptc as $pwg_key => $value)
+  {
+    if (in_array($pwg_key, $page['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 get_sync_exif_data($file)
+{
+  global $conf, $page;
+
+  $exif = get_exif_data($file, $conf['use_exif_mapping']);
+
+  foreach ($exif as $pwg_key => $value)
+  {
+    if (in_array($pwg_key, $page['datefields']))
+    {
+      if (preg_match('/^(\d{4}).(\d{2}).(\d{2})/', $value, $matches))
+      {
+        $exif[$pwg_key] = $matches[1].'-'.$matches[2].'-'.$matches[3];
+      }
+    }
+  }
+
+  return $exif;
+}
+
+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'])
+    {
+      $exif = get_sync_exif_data($file);
+
+      if (count($exif) > 0)
+      {
+        foreach (array_keys($exif) as $key)
+        {
+          $data[$key] = addslashes($exif[$key]);
+        }
+      }
+    }
+
+    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'])
+    {
+      $update_fields =
+        array_merge(
+          $update_fields,
+          array_keys($conf['use_exif_mapping'])
+          );
+    }
+    
+    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.5/admin/include/index.htm
===================================================================
--- /branches/1.5/admin/include/index.htm	(revision 3250)
+++ /branches/1.5/admin/include/index.htm	(revision 3250)
@@ -0,0 +1,8 @@
+<html>
+    <head>
+        <title>PhpWebGallery</title>
+    </head>
+    <body>
+        No access authorized
+    </body>
+</html>
Index: /branches/1.5/admin/include/isadmin.inc.php
===================================================================
--- /branches/1.5/admin/include/isadmin.inc.php	(revision 3250)
+++ /branches/1.5/admin/include/isadmin.inc.php	(revision 3250)
@@ -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.5/admin/index.htm
===================================================================
--- /branches/1.5/admin/index.htm	(revision 3250)
+++ /branches/1.5/admin/index.htm	(revision 3250)
@@ -0,0 +1,8 @@
+<html>
+    <head>
+        <title>PhpWebGallery</title>
+    </head>
+    <body>
+        No access authorized
+    </body>
+</html>
Index: /branches/1.5/admin/intro.php
===================================================================
--- /branches/1.5/admin/intro.php	(revision 3250)
+++ /branches/1.5/admin/intro.php	(revision 3250)
@@ -0,0 +1,251 @@
+<?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');
+
+// +-----------------------------------------------------------------------+
+// |                                actions                                |
+// +-----------------------------------------------------------------------+
+
+// Check for upgrade : code inspired from punbb
+if (isset($_GET['action']) and 'check_upgrade' == $_GET['action'])
+{
+  if (!ini_get('allow_url_fopen'))
+  {
+    array_push(
+      $page['errors'],
+      l10n('Unable to check for upgrade since allow_url_fopen is disabled.')
+      );
+  }
+  else
+  {
+    $versions = array('current' => PHPWG_VERSION);
+    $lines = @file('http://www.phpwebgallery.net/latest_version');
+    
+    // if the current version is a BSF (development branch) build, we check
+    // the first line, for stable versions, we check the second line
+    if (preg_match('/^BSF/', $versions{'current'}))
+    {
+      $versions{'latest'} = trim($lines[0]);
+
+      // because integer are limited to 4,294,967,296 we need to split BSF
+      // versions in date.time
+      foreach ($versions as $key => $value)
+      {
+        $versions{$key} =
+          preg_replace('/BSF_(\d{8})(\d{4})/', '$1.$2', $value);
+      }
+    }
+    else
+    {
+      $versions{'latest'} = trim($lines[1]);
+    }
+
+    if ('' == $versions{'latest'})
+    {
+      array_push(
+        $page['errors'],
+        l10n('Check for upgrade failed for unknown reasons.')
+        );
+    }
+    // concatenation needed to avoid automatic transformation by release
+    // script generator
+    else if ('%'.'PWGVERSION'.'%' == $versions{'current'})
+    {
+      array_push(
+        $page['infos'],
+        l10n('You are running on development sources, no check possible.')
+        );
+    }
+    else if (version_compare($versions{'current'}, $versions{'latest'}) < 0)
+    {
+      array_push(
+        $page['infos'],
+        l10n('A new version of PhpWebGallery is available.')
+        );
+    }
+    else
+    {
+      array_push(
+        $page['infos'],
+        l10n('You are running the latest version of PhpWebGallery.')
+        );
+    }
+  }
+}
+// Show phpinfo() output
+else if (isset($_GET['action']) and 'phpinfo' == $_GET['action'])
+{
+  phpinfo();
+  exit();
+}
+
+// +-----------------------------------------------------------------------+
+// |                             template init                             |
+// +-----------------------------------------------------------------------+
+
+$template->set_filenames(array('intro' => 'admin/intro.tpl'));
+
+list($mysql_version) = mysql_fetch_row(pwg_query('SELECT VERSION();'));
+
+$query = '
+SELECT COUNT(*)
+  FROM '.IMAGES_TABLE.'
+;';
+list($nb_elements) = mysql_fetch_row(pwg_query($query));
+
+$query = '
+SELECT COUNT(*)
+  FROM '.CATEGORIES_TABLE.'
+;';
+list($nb_categories) = mysql_fetch_row(pwg_query($query));
+
+$query = '
+SELECT COUNT(*)
+  FROM '.CATEGORIES_TABLE.'
+  WHERE dir IS NULL
+;';
+list($nb_virtual) = mysql_fetch_row(pwg_query($query));
+
+$query = '
+SELECT COUNT(*)
+  FROM '.CATEGORIES_TABLE.'
+  WHERE dir IS NOT NULL
+;';
+list($nb_physical) = mysql_fetch_row(pwg_query($query));
+
+$query = '
+SELECT COUNT(*)
+  FROM '.USERS_TABLE.'
+;';
+list($nb_users) = mysql_fetch_row(pwg_query($query));
+
+$query = '
+SELECT COUNT(*)
+  FROM '.GROUPS_TABLE.'
+;';
+list($nb_groups) = mysql_fetch_row(pwg_query($query));
+
+$query = '
+SELECT COUNT(*)
+  FROM '.COMMENTS_TABLE.'
+;';
+list($nb_comments) = mysql_fetch_row(pwg_query($query));
+
+$template->assign_vars(
+  array(
+    'PWG_VERSION' => PHPWG_VERSION,
+    'OS' => PHP_OS,
+    'PHP_VERSION' => phpversion(),
+    'MYSQL_VERSION' => $mysql_version,
+    'DB_ELEMENTS' => sprintf(l10n('%d elements'), $nb_elements),
+    'DB_CATEGORIES' =>
+      sprintf(
+        l10n('%d categories including %d physical and %d virtual'),
+        $nb_categories,
+        $nb_physical,
+        $nb_virtual
+        ),
+    'DB_USERS' => sprintf(l10n('%d users'), $nb_users),
+    'DB_GROUPS' => sprintf(l10n('%d groups'), $nb_groups),
+    'DB_COMMENTS' => sprintf(l10n('%d comments'), $nb_comments),
+    'U_CHECK_UPGRADE' =>
+      add_session_id(PHPWG_ROOT_PATH.'admin.php?action=check_upgrade'),
+    'U_PHPINFO' =>
+      add_session_id(PHPWG_ROOT_PATH.'admin.php?action=phpinfo')
+    )
+  );
+
+if ($nb_elements > 0)
+{
+  $query = '
+SELECT MIN(date_available)
+  FROM '.IMAGES_TABLE.'
+;';
+  list($first_date) = mysql_fetch_row(pwg_query($query));
+
+  $template->assign_block_vars(
+    'first_added',
+    array(
+      'DB_DATE' =>
+      sprintf(
+        l10n('first element added on %s'),
+        format_date($first_date, 'mysql_datetime')
+        )
+      )
+    );
+}
+
+// waiting elements
+$query = '
+SELECT COUNT(*)
+  FROM '.WAITING_TABLE.'
+  WHERE validated=\'false\'
+;';
+list($nb_waiting) = mysql_fetch_row(pwg_query($query));
+
+if ($nb_waiting > 0)
+{
+  $template->assign_block_vars(
+    'waiting',
+    array(
+      'URL' => add_session_id(PHPWG_ROOT_PATH.'admin.php?page=waiting'),
+      'INFO' => sprintf(l10n('%d waiting for validation'), $nb_waiting)
+      )
+    );
+}
+
+// unvalidated comments
+$query = '
+SELECT COUNT(*)
+  FROM '.COMMENTS_TABLE.'
+  WHERE validated=\'false\'
+;';
+list($nb_comments) = mysql_fetch_row(pwg_query($query));
+
+if ($nb_comments > 0)
+{
+  $template->assign_block_vars(
+    'unvalidated',
+    array(
+      'URL' => add_session_id(PHPWG_ROOT_PATH.'admin.php?page=comments'),
+      'INFO' => sprintf(l10n('%d waiting for validation'), $nb_comments)
+      )
+    );
+}
+
+// +-----------------------------------------------------------------------+
+// |                           sending html code                           |
+// +-----------------------------------------------------------------------+
+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'intro');
+
+?>
Index: /branches/1.5/admin/maintenance.php
===================================================================
--- /branches/1.5/admin/maintenance.php	(revision 3250)
+++ /branches/1.5/admin/maintenance.php	(revision 3250)
@@ -0,0 +1,115 @@
+<?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');
+
+// +-----------------------------------------------------------------------+
+// |                                actions                                |
+// +-----------------------------------------------------------------------+
+
+$action = isset($_GET['action']) ? $_GET['action'] : '';
+
+switch ($action)
+{
+  case 'categories' :
+  {
+    update_uppercats();
+    update_category('all');
+    ordering();
+    update_global_rank();
+    break;
+  }
+  case 'images' :
+  {
+    update_path();
+    update_average_rate();
+    break;
+  }
+  case 'history' :
+  {
+    $query = '
+DELETE
+  FROM '.HISTORY_TABLE.'
+;';
+    pwg_query($query);
+    break;
+  }
+  case 'sessions' :
+  {
+    $query = '
+DELETE
+  FROM '.SESSIONS_TABLE.'
+  WHERE expiration < NOW()
+;';
+    pwg_query($query);
+    break;
+  }
+  case 'feeds' :
+  {
+    $query = '
+DELETE
+  FROM '.USER_FEED_TABLE.'
+  WHERE last_check IS NULL
+;';
+    pwg_query($query);
+    break;
+  }
+  default :
+  {
+    break;
+  }
+}
+
+// +-----------------------------------------------------------------------+
+// |                             template init                             |
+// +-----------------------------------------------------------------------+
+
+$template->set_filenames(array('maintenance'=>'admin/maintenance.tpl'));
+
+$start_url = PHPWG_ROOT_PATH.'admin.php?page=maintenance&amp;action=';
+
+$template->assign_vars(
+  array(
+    'U_MAINT_CATEGORIES' => add_session_id($start_url.'categories'),
+    'U_MAINT_IMAGES' => add_session_id($start_url.'images'),
+    'U_MAINT_HISTORY' => add_session_id($start_url.'history'),
+    'U_MAINT_SESSIONS' => add_session_id($start_url.'sessions'),
+    'U_MAINT_FEEDS' => add_session_id($start_url.'feeds'),
+    'U_HELP' => PHPWG_ROOT_PATH.'/popuphelp.php?page=maintenance',
+    )
+  );
+  
+// +-----------------------------------------------------------------------+
+// |                           sending html code                           |
+// +-----------------------------------------------------------------------+
+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'maintenance');
+?>
Index: /branches/1.5/admin/picture_modify.php
===================================================================
--- /branches/1.5/admin/picture_modify.php	(revision 3250)
+++ /branches/1.5/admin/picture_modify.php	(revision 3250)
@@ -0,0 +1,384 @@
+<?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');
+
+// +-----------------------------------------------------------------------+
+// |                          synchronize metadata                         |
+// +-----------------------------------------------------------------------+
+
+if (isset($_GET['sync_metadata']))
+{
+  $query = '
+SELECT path
+  FROM '.IMAGES_TABLE.'
+  WHERE id = '.$_GET['image_id'].'
+;';
+  list($path) = mysql_fetch_row(pwg_query($query));
+  update_metadata(array($_GET['image_id'] => $path));
+
+  array_push($page['infos'], l10n('Metadata synchronized from file'));
+}
+
+//--------------------------------------------------------- update informations
+
+// first, we verify whether there is a mistake on the given creation date
+if (isset($_POST['date_creation_action'])
+    and 'set' == $_POST['date_creation_action'])
+{
+  if (!checkdate(
+        $_POST['date_creation_month'],
+        $_POST['date_creation_day'],
+        $_POST['date_creation_year'])
+    )
+  {
+    array_push($page['errors'], $lang['err_date']);
+  }
+}
+
+if (isset($_POST['submit']) and count($page['errors']) == 0)
+{
+  $data = array();
+  $data{'id'} = $_GET['image_id'];
+  $data{'name'} = $_POST['name'];
+  $data{'author'} = $_POST['author'];
+
+  if ($conf['allow_html_descriptions'])
+  {
+    $data{'comment'} = @$_POST['description'];
+  }
+  else
+  {
+    $data{'comment'} = strip_tags(@$_POST['description']);
+  }
+
+  if (isset($_POST['date_creation_action']))
+  {
+    if ('set' == $_POST['date_creation_action'])
+    {
+      $data{'date_creation'} = $_POST['date_creation_year']
+                                 .'-'.$_POST['date_creation_month']
+                                 .'-'.$_POST['date_creation_day'];
+    }
+    else if ('unset' == $_POST['date_creation_action'])
+    {
+      $data{'date_creation'} = '';
+    }
+  }
+
+  $keywords = get_keywords($_POST['keywords']);
+  if (count($keywords) > 0)
+  {
+    $data{'keywords'} = implode(',', $keywords);
+  }
+  else
+  {
+    $data{'keywords'} = '';
+  }
+
+  mass_updates(
+    IMAGES_TABLE,
+    array(
+      'primary' => array('id'),
+      'update' => array_diff(array_keys($data), array('id'))
+      ),
+    array($data)
+    );
+
+  array_push($page['infos'], l10n('Picture informations updated'));
+}
+// 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 *
+  FROM '.IMAGES_TABLE.'
+  WHERE id = '.$_GET['image_id'].'
+;';
+$row = mysql_fetch_array(pwg_query($query));
+
+$storage_category_id = $row['storage_category_id'];
+
+// Navigation path
+
+$date = isset($_POST['date_creation']) && empty($page['errors'])
+?$_POST['date_creation']:date_convert_back(@$row['date_creation']);
+
+// +-----------------------------------------------------------------------+
+// |                             template init                             |
+// +-----------------------------------------------------------------------+
+
+$template->set_filenames(
+  array(
+    'picture_modify' => 'admin/picture_modify.tpl'
+    )
+  );
+
+$template->assign_vars(
+  array(
+    'U_SYNC' =>
+      add_session_id(
+        PHPWG_ROOT_PATH.'admin.php?page=picture_modify'.
+        '&amp;image_id='.$_GET['image_id'].
+        (isset($_GET['cat_id']) ? '&amp;cat_id='.$_GET['cat_id'] : '').
+        '&amp;sync_metadata=1'
+        ),
+    
+    'PATH'=>$row['path'],
+    
+    'TN_SRC' => get_thumbnail_src($row['path'], @$row['tn_ext']),
+    
+    'NAME' =>
+      isset($_POST['name']) ?
+        stripslashes($_POST['name']) : @$row['name'],
+    
+    'DIMENSIONS' => @$row['width'].' * '.@$row['height'],
+    
+    'FILESIZE' => @$row['filesize'].' KB',
+    
+    'REGISTRATION_DATE' =>
+      format_date($row['date_available'], 'mysql_datetime', false),
+    
+    'AUTHOR' => isset($_POST['author']) ? $_POST['author'] : @$row['author'],
+    
+    'CREATION_DATE' => $date,
+    
+    'KEYWORDS' =>
+      isset($_POST['keywords']) ?
+        stripslashes($_POST['keywords']) : @$row['keywords'],
+    
+    'DESCRIPTION' =>
+      isset($_POST['description']) ?
+        stripslashes($_POST['description']) : @$row['comment'],
+  
+    'F_ACTION' =>
+      add_session_id(
+        PHPWG_ROOT_PATH.'admin.php'
+        .get_query_string_diff(array('sync_metadata'))
+        )
+    )
+  );
+
+// creation date
+unset($day, $month, $year);
+
+if (isset($_POST['date_creation_action'])
+    and 'set' == $_POST['date_creation_action'])
+{
+  foreach (array('day', 'month', 'year') as $varname)
+  {
+    $$varname = $_POST['date_creation_'.$varname];
+  }
+}
+else if (isset($row['date_creation']) and !empty($row['date_creation']))
+{
+  list($year, $month, $day) = explode('-', $row['date_creation']);
+}
+else
+{
+  list($year, $month, $day) = array('', 0, 0);
+}
+get_day_list('date_creation_day', $day);
+get_month_list('date_creation_month', $month);
+$template->assign_vars(array('DATE_CREATION_YEAR_VALUE' => $year));
+  
+$query = '
+SELECT category_id, uppercats
+  FROM '.IMAGE_CATEGORY_TABLE.' AS ic
+    INNER JOIN '.CATEGORIES_TABLE.' AS c
+      ON c.id = ic.category_id
+  WHERE image_id = '.$_GET['image_id'].'
+;';
+$result = pwg_query($query);
+
+if (mysql_num_rows($result) > 1)
+{
+  $template->assign_block_vars('links', array());
+}
+
+while ($row = mysql_fetch_array($result))
+{
+  $name =
+    get_cat_display_name_cache(
+      $row['uppercats'],
+      PHPWG_ROOT_PATH.'admin.php?page=cat_modify&amp;cat_id=',
+      false
+      );
+    
+  if ($row['category_id'] == $storage_category_id)
+  {
+    $template->assign_vars(array('STORAGE_CATEGORY' => $name));
+  }
+  else
+  {
+    $template->assign_block_vars('links.category', array('NAME' => $name));
+  }
+}
+
+// jump to link
+//
+// 1. find all linked categories that are reachable for the current user.
+// 2. if a category is available in the URL, use it if reachable
+// 3. if URL category not available or reachable, use the first reachable
+//    linked category
+// 4. if no category reachable, no jumpto link
+$base_url_img = PHPWG_ROOT_PATH.'picture.php';
+$base_url_img.= '?image_id='.$_GET['image_id'];
+$base_url_img.= '&amp;cat=';
+unset($url_img);
+
+$query = '
+SELECT category_id
+  FROM '.IMAGE_CATEGORY_TABLE.'
+  WHERE image_id = '.$_GET['image_id'].'
+;';
+$authorizeds = array_diff(
+  array_from_query($query, 'category_id'),
+  explode(',', calculate_permissions($user['id'], $user['status']))
+  );
+
+if (isset($_GET['cat_id'])
+    and in_array($_GET['cat_id'], $authorizeds))
+{
+  $url_img = $base_url_img.$_GET['cat_id'];
+}
+else
+{
+  foreach ($authorizeds as $category)
+  {
+    $url_img = $base_url_img.$category;
+    break;
+  }
+}
+
+if (isset($url_img))
+{
+  $template->assign_block_vars(
+    'jumpto',
+    array(
+      'URL' => $url_img
+      )
+    );
+}
+  
+// 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 representative_picture_id != '.$_GET['image_id'].'
+    OR representative_picture_id IS NULL
+;';
+display_select_cat_wrapper($query, array(), 'dismissed_option');
+
+//----------------------------------------------------------- sending html code
+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'picture_modify');
+?>
Index: /branches/1.5/admin/remote_site.php
===================================================================
--- /branches/1.5/admin/remote_site.php	(revision 3250)
+++ /branches/1.5/admin/remote_site.php	(revision 3250)
@@ -0,0 +1,745 @@
+<?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');
+
+list($dbnow) = mysql_fetch_row(pwg_query('SELECT NOW();'));
+define('CURRENT_DATE', $dbnow);
+// +-----------------------------------------------------------------------+
+// |                               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, $page, $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($page['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, $page;
+  
+  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($page['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'],
+
+    'U_HELP' => PHPWG_ROOT_PATH.'/popuphelp.php?page=remote_site',
+    
+    'F_ACTION'=>add_session_id(PHPWG_ROOT_PATH.'admin.php?page=remote_site')
+   )
+ );
+ 
+// +-----------------------------------------------------------------------+
+// |                        new site creation form                         |
+// +-----------------------------------------------------------------------+
+if (isset($_POST['submit']))
+{
+  // site must start by http:// or https://
+  if (!preg_match('/^https?:\/\/[~\/\.\w-]+$/', $_POST['galleries_url']))
+  {
+    array_push($page['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($page['errors'], $lang['remote_site_already_exists']);
+    }
+  }
+
+  if (count($page['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($page['errors'],
+                   $lang['remote_site_error'].' : '.$first_line);
+      }
+    }
+    else
+    {
+      array_push($page['errors'], $lang['remote_site_file_not_found']);
+    }
+  }
+  
+  if (count($page['errors']) == 0)
+  {
+    $query = '
+INSERT INTO '.SITES_TABLE.'
+  (galleries_url)
+  VALUES
+  (\''.$page['galleries_url'].'\')
+;';
+    pwg_query($query);
+
+    array_push($page['infos'],
+               $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']);
+      array_push($page['infos'],
+                 $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);
+
+if (mysql_num_rows($result) > 0)
+{
+  $template->assign_block_vars('sites', array());
+}
+
+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(
+    'sites.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')
+     )
+   );
+}
+// +-----------------------------------------------------------------------+
+// |                           sending html code                           |
+// +-----------------------------------------------------------------------+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'remote_site');
+?>
Index: /branches/1.5/admin/stats.php
===================================================================
--- /branches/1.5/admin/stats.php	(revision 3250)
+++ /branches/1.5/admin/stats.php	(revision 3250)
@@ -0,0 +1,313 @@
+<?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 = PHPWG_ROOT_PATH.'admin/images/'; 
+$nls_value_title = $lang['w_month'];
+$group_clause = "DATE_FORMAT(date,'%Y-%m') DESC";
+$where_clause = "1";
+
+
+if (isset($_GET['day']) && isset($_GET['month']) && isset($_GET['year']) )
+{
+  $url_img .= 'daily_stats.img.php?year='.$_GET['year'].'&month='.$_GET['month'].'&day='.$_GET['day'];
+  $nls_value_title = $lang['w_day'];
+  $group_clause = "DATE_FORMAT(date,'%Y-%m-%d') ASC";
+  $where_clause = "(YEAR(date) = ".$_GET['year']." AND MONTH(date) = ".$_GET['month']." )";
+}
+elseif (isset($_GET['month']) && isset($_GET['year']) )
+{
+  $url_img .= 'monthly_stats.img.php?year='.$_GET['year'].'&month='.$_GET['month'];
+  $nls_value_title = $lang['w_day'];
+  $group_clause = "DATE_FORMAT(date,'%Y-%m-%d') ASC";
+  $where_clause = "(YEAR(date) = ".$_GET['year']." AND MONTH(date) = ".$_GET['month']." )";
+}
+else 
+{
+  $url_img .= 'global_stats.img.php';
+}
+
+
+//----------------------------------------------------- template initialization
+if (isset($_GET['day']) && isset($_GET['month']) && isset($_GET['year']) )
+{
+  $date_of_day=$_GET['day'].' '.$lang['month'][$_GET['month']].' '.$_GET['year'];
+  $title_page=$lang['stats_day_title'].' : '.$date_of_day;
+  $url_back = PHPWG_ROOT_PATH."admin.php?page=stats";
+  $url_back = add_session_id($url_back);
+  $title_details='<a href='.$url_back.'>'.$lang['stats_day_title'].'</a>';
+  $title_day = $date_of_day;
+}
+elseif ( isset($_GET['month']) && isset($_GET['year']) )
+{
+  $date_of_day=$lang['month'][$_GET['month']].' '.$_GET['year'];
+  $title_page=$lang['stats_month_title'].' : '.$date_of_day;
+  $url_back = PHPWG_ROOT_PATH."admin.php?page=stats";
+  $url_back = add_session_id($url_back);
+  $title_details='<a href='.$url_back.'>'.$lang['stats_day_title'].'</a>';
+  $title_day=$lang['today'];
+}
+else
+{
+  $date_of_day='';
+  $title_page=$lang['stats_title'];
+  $title_details=$lang['stats_month_title'];
+  $title_day=$lang['today'];
+}
+
+
+$template->set_filenames( array('stats'=>'admin/stats.tpl') );
+
+$template->assign_vars(array(
+  'L_VALUE'=>$nls_value_title,
+  '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'],
+  'L_STAT_TITLE'=>$title_page,
+  'L_STAT_DETAIL_TITLE'=>$title_details,
+  'L_DATE_TITLE'=>$title_day,
+  'L_STAT_MONTHLY_ALT'=>$lang['stats_global_graph_title'],
+  'L_STAT_HOUR'=>$lang['stats_hour'],
+  'L_STAT_LOGIN'=>$lang['stats_login'],
+  'L_STAT_ADDR'=>$lang['stats_addr'],
+  'L_STAT_CATEGORY'=>$lang['stats_category'],
+  'L_STAT_FILE'=>$lang['stats_file'],
+  'L_STAT_PICTURE'=>$lang['stats_picture'],
+  
+  'IMG_REPORT'=>add_session_id($url_img)
+  ));
+
+//---------------------------------------------------------------- log  history
+$query = '
+SELECT DISTINCT COUNT(*) as p,
+       DAYOFMONTH(date) as d,
+       MONTH(date) as m,
+       YEAR(date) as y
+  FROM '.HISTORY_TABLE.' 
+  WHERE '.$where_clause.'
+  GROUP BY '.$group_clause.';';
+
+$result = pwg_query( $query );
+$i=0;
+while ( $row = mysql_fetch_array( $result ) )
+{
+  $where_clause="";
+  $value = '';
+  if (isset($_GET['month']) && isset($_GET['year']) )
+  {
+    $where_clause = 'DAYOFMONTH(date) = '.$row['d'].'
+    AND MONTH(date) = '.$row['m'].'
+    AND YEAR(date) = '.$row['y'];
+    
+    $week_day =
+      $lang['day'][date('w', mktime(12,0,0,$row['m'],$row['d'],$row['y']))];
+
+    $url =
+      PHPWG_ROOT_PATH.'admin.php'
+      .'?page=stats'
+      .'&amp;year='.$row['y']
+      .'&amp;month='.$row['m']
+      .'&amp;day='.$row['d']
+      ;
+
+    $value = '<a href="'.add_session_id($url).'">';
+    $value.= $row['d'].' ('.$week_day.')';
+    $value.= "</a>";
+  }
+  else
+  {
+    $current_month = $row['y']."-";
+    if ($row['m'] <10) {$current_month.='0';}
+    $current_month .= $row['m'];
+    
+    $where_clause = "DATE_FORMAT(date,'%Y-%m') = '".$current_month."'";
+
+    $url =
+      PHPWG_ROOT_PATH.'admin.php'
+      .'?page=stats'
+      .'&amp;year='.$row['y']
+      .'&amp;month='.$row['m']
+      ;
+    
+    $value = '<a href="'.add_session_id($url).'">';
+    $value.= $lang['month'][$row['m']].' '.$row['y'];
+    $value.= "</a>";
+  }
+  
+  // Number of pictures seen
+  $query = '
+SELECT COUNT(*) as p
+    FROM '.HISTORY_TABLE.' 
+    WHERE '.$where_clause.'
+    AND FILE = \'picture\'
+;';
+  $pictures = mysql_fetch_array(pwg_query( $query ));
+  
+  // Number of different visitors
+  $query = '
+SELECT COUNT(*) as p, login
+  FROM '.HISTORY_TABLE.' 
+  WHERE '.$where_clause.'
+  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('statrow',array(
+      'VALUE'=>$value,
+	'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;
+
+//----------------------------------------------------------- stats / jour
+
+if ( isset( $_GET['month'] ) && isset( $_GET['month'] ) && isset( $_GET['day'] ) )
+{  if ($_GET['day'] <10) {$current_day='0';
+  	$current_day.= $_GET['day'];}
+  else {$current_day = $_GET['day'];}
+  if ($_GET['month'] <10) {$current_month='0';
+  	$current_month.= $_GET['month'];}
+  else {$current_month = $_GET['month'];}
+  $current_year = $_GET['year'];
+}
+
+else
+{  $current_date = GetDate();
+  if ($current_date['mday'] <10) {$current_day='0';
+  	$current_day.= $current_date['mday'];}
+  else {$current_day = $current_date['mday'];}
+  if ($current_date['mon'] <10) {$current_month='0';
+  	$current_month.= $current_date['mon'];}
+  else {$current_month = $current_date['mon'];}
+  $current_year = $current_date['year'];  
+}
+
+// Set WHERE clause
+$where = ' WHERE DATE_FORMAT(date,\'%Y-%m-%d\') = \''.$current_year."-".$current_month."-".$current_day.'\'';
+  
+// Set LIMIT clause
+$limit = ' LIMIT ';
+$page['start'] = 0;
+if (isset($_GET['start']) and is_numeric($_GET['start'])) $page['start'] = abs($_GET['start']);
+$limit .= $page['start'];
+$limit .= ','.$conf['nb_logs_page'];
+
+$query = '
+SELECT DATE_FORMAT(date,\'%H:%i:%s\') AS hour,
+     login,
+     IP,
+     category,
+     file,
+     picture
+  FROM '.HISTORY_TABLE.
+  $where.'
+  ORDER BY date DESC'.
+  $limit.
+  ';';
+
+
+$result = pwg_query( $query );
+
+$i=0;
+ 
+while ( $row = mysql_fetch_array( $result ) )
+{
+  $class = ($i % 2)? 'row1':'row2'; $i++;
+    $template->assign_block_vars('detail',array(
+    'HOUR'=>$row['hour'],
+    'LOGIN'=>$row['login'],
+    'IP'=>$row['IP'],
+    'CATEGORY'=>$row['category'],
+    'FILE'=>$row['file'],
+    'PICTURE'=>$row['picture'],
+    'T_CLASS'=>$class
+  ));
+  }
+
+
+// Get total number of logs
+$query = '
+    SELECT COUNT(date) as nb_logs
+     FROM '.HISTORY_TABLE.
+  $where.'
+    ;';
+
+  $result = pwg_query($query);
+  $row = mysql_fetch_array($result);
+  $page['nb_logs']=$row['nb_logs'];
+
+  //display nav bar
+$url = $_SERVER['PHP_SELF'].'?page=stats';
+$url.= isset($_GET['year']) ? '&amp;year='.$_GET['year'] : '';
+$url.= isset($_GET['month']) ? '&amp;month='.$_GET['month'] : '';
+$url.= isset($_GET['day']) ? '&amp;day='.$_GET['day'] : '';
+
+$page['navigation_bar'] =
+create_navigation_bar(
+  $url,
+  $page['nb_logs'],
+  $page['start'],
+  $conf['nb_logs_page'],
+  'admin'
+  );
+
+$template->assign_block_vars(
+  'navigation',
+  array(
+    'NAV_BAR' => $page['navigation_bar']
+    )
+  );
+
+//----------------------------------------------------------- sending html code
+$template->assign_var_from_handle('ADMIN_CONTENT', 'stats');
+?>
+
Index: /branches/1.5/admin/thumbnail.php
===================================================================
--- /branches/1.5/admin/thumbnail.php	(revision 3250)
+++ /branches/1.5/admin/thumbnail.php	(revision 3250)
@@ -0,0 +1,402 @@
+<?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, $page;
+
+  $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($page['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($page['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();
+  }
+}
+
+$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_CREATE'=>$lang['tn_params_create'],
+  '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'],
+
+  'U_HELP' => PHPWG_ROOT_PATH.'/popuphelp.php?page=thumbnail',
+  
+  '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']))
+{
+  $times = array();
+  $infos = array();
+  
+  // checking criteria
+  if (!ereg('^[0-9]{2,3}$', $_POST['width']) or $_POST['width'] < 10)
+  {
+    array_push($page['errors'], $lang['tn_err_width'].' 10');
+  }
+  if (!ereg('^[0-9]{2,3}$', $_POST['height']) or $_POST['height'] < 10)
+  {
+    array_push($page['errors'], $lang['tn_err_height'].' 10');
+  }
+  
+  // picture miniaturization
+  if (count($page['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
+            ));
+      }
+    }
+  }
+}
+// +-----------------------------------------------------------------------+
+// |             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.5/admin/update.php
===================================================================
--- /branches/1.5/admin/update.php	(revision 3250)
+++ /branches/1.5/admin/update.php	(revision 3250)
@@ -0,0 +1,770 @@
+<?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');
+
+list($dbnow) = mysql_fetch_row(pwg_query('SELECT NOW();'));
+define('CURRENT_DATE', $dbnow);
+
+$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. By default, each category id
+  // has 1 for next rank on its sub-categories to create
+  $next_rank['NULL'] = 1;
+  
+  $query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.'
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    $next_rank[$row['id']] = 1;
+  }
+
+  // let's see if some categories already have some sub-categories...
+  $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 and count($cat_ids) > 0)
+  {
+    $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
+    ));
+
+$template->assign_vars(
+  array(
+    'U_HELP' => PHPWG_ROOT_PATH.'/popuphelp.php?page=synchronize'
+    )
+  );
+// +-----------------------------------------------------------------------+
+// |                        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.update_errors', array());
+    foreach ($errors as $error)
+    {
+      $template->assign_block_vars(
+        'update.update_errors.update_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.update_infos', array());
+    foreach ($infos as $info)
+    {
+      $template->assign_block_vars(
+        'update.update_infos.update_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.5/admin/user_list.php
===================================================================
--- /branches/1.5/admin/user_list.php	(revision 3250)
+++ /branches/1.5/admin/user_list.php	(revision 3250)
@@ -0,0 +1,808 @@
+<?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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+/**
+ * Add users and manage users list
+ */
+
+// +-----------------------------------------------------------------------+
+// |                              functions                                |
+// +-----------------------------------------------------------------------+
+
+/**
+ * returns a list of users depending on page filters (in $_GET)
+ *
+ * Each user comes with his related informations : id, username, mail
+ * address, list of groups.
+ *
+ * @return array
+ */
+function get_filtered_user_list()
+{
+  global $conf, $page;
+
+  $users = array();
+  
+  // filter
+  $filter = array();
+  
+  if (isset($_GET['username']) and !empty($_GET['username']))
+  {
+    $username = str_replace('*', '%', $_GET['username']);
+    if (function_exists('mysql_real_escape_string'))
+    {
+      $filter['username'] = mysql_real_escape_string($username);
+    }
+    else
+    {
+      $filter['username'] = mysql_escape_string($username);
+    }
+  }
+
+  if (isset($_GET['group'])
+      and -1 != $_GET['group']
+      and is_numeric($_GET['group']))
+  {
+    $filter['group'] = $_GET['group'];
+  }
+
+  if (isset($_GET['status'])
+      and in_array($_GET['status'], get_enums(USER_INFOS_TABLE, 'status')))
+  {
+    $filter['status'] = $_GET['status'];
+  }
+
+  // how to order the list?
+  $order_by = 'id';
+  if (isset($_GET['order_by'])
+      and in_array($_GET['order_by'], array_keys($page['order_by_items'])))
+  {
+    $order_by = $_GET['order_by'];
+  }
+  
+  $direction = 'ASC';
+  if (isset($_GET['direction'])
+      and in_array($_GET['direction'], array_keys($page['direction_items'])))
+  {
+    $direction = strtoupper($_GET['direction']);
+  }
+
+  // search users depending on filters and order
+  $query = '
+SELECT DISTINCT u.'.$conf['user_fields']['id'].' AS id,
+                u.'.$conf['user_fields']['username'].' AS username,
+                u.'.$conf['user_fields']['email'].' AS email,
+                ui.status
+  FROM '.USERS_TABLE.' AS u
+    INNER JOIN '.USER_INFOS_TABLE.' AS ui
+      ON u.'.$conf['user_fields']['id'].' = ui.user_id
+    LEFT JOIN '.USER_GROUP_TABLE.' AS ug
+      ON u.'.$conf['user_fields']['id'].' = ug.user_id
+  WHERE u.'.$conf['user_fields']['id'].' != '.$conf['guest_id'];
+  if (isset($filter['username']))
+  {
+    $query.= '
+  AND u.'.$conf['user_fields']['username'].' LIKE \''.$filter['username'].'\'';
+  }
+  if (isset($filter['group']))
+  {
+    $query.= '
+    AND ug.group_id = '.$filter['group'];
+  }
+  if (isset($filter['status']))
+  {
+    $query.= '
+    AND ui.status = \''.$filter['status']."'";
+  }
+  $query.= '
+  ORDER BY '.$order_by.' '.$direction.'
+;';
+
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    $user = $row;
+    $user['groups'] = array();
+
+    array_push($users, $user);
+  }
+
+  // add group lists
+  $user_ids = array();
+  foreach ($users as $i => $user)
+  {
+    $user_ids[$i] = $user['id'];
+  }
+  $user_nums = array_flip($user_ids);
+  
+  if (count($user_ids) > 0)
+  {
+    $query = '
+SELECT user_id, group_id
+  FROM '.USER_GROUP_TABLE.'
+  WHERE user_id IN ('.implode(',', $user_ids).')
+;';
+    $result = pwg_query($query);
+    while ($row = mysql_fetch_array($result))
+    {
+      array_push(
+        $users[$user_nums[$row['user_id']]]['groups'],
+        $row['group_id']
+        );
+    }
+  }
+    
+  return $users;
+}
+
+// +-----------------------------------------------------------------------+
+// |                           initialization                              |
+// +-----------------------------------------------------------------------+
+
+if (!defined('PHPWG_ROOT_PATH'))
+{
+  die('Hacking attempt!');
+}
+include_once(PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php');
+
+$page['order_by_items'] = array(
+  'id' => $lang['registration_date'],
+  'username' => $lang['Username']
+  );
+
+$page['direction_items'] = array(
+  'asc' => $lang['ascending'],
+  'desc' => $lang['descending']
+  );
+
+// +-----------------------------------------------------------------------+
+// |                              add a user                               |
+// +-----------------------------------------------------------------------+
+
+if (isset($_POST['submit_add']))
+{
+  $page['errors'] = register_user($_POST['login'], $_POST['password'], '');
+
+  if (count($page['errors']) == 0)
+  {
+    array_push(
+      $page['infos'],
+      sprintf(
+        l10n('user "%s" added'),
+        $_POST['login']
+        )
+      );
+  }
+}
+
+// +-----------------------------------------------------------------------+
+// |                               user list                               |
+// +-----------------------------------------------------------------------+
+
+$page['filtered_users'] = get_filtered_user_list();
+
+// +-----------------------------------------------------------------------+
+// |                            selected users                             |
+// +-----------------------------------------------------------------------+
+
+if (isset($_POST['delete']) or isset($_POST['pref_submit']))
+{
+  $collection = array();
+  
+  switch ($_POST['target'])
+  {
+    case 'all' :
+    {
+      foreach($page['filtered_users'] as $local_user)
+      {
+        array_push($collection, $local_user['id']);
+      }
+      break;
+    }
+    case 'selection' :
+    {
+      if (isset($_POST['selection']))
+      {
+        $collection = $_POST['selection'];
+      }
+      break;
+    }
+  }
+
+  if (count($collection) == 0)
+  {
+    array_push($page['errors'], l10n('Select at least one user'));
+  }
+}
+
+// +-----------------------------------------------------------------------+
+// |                             delete users                              |
+// +-----------------------------------------------------------------------+
+
+if (isset($_POST['delete']) and count($collection) > 0)
+{
+  if (in_array($conf['webmaster_id'], $collection))
+  {
+    array_push($page['errors'], l10n('Webmaster cannot be deleted'));
+  }
+  else
+  {
+    if (isset($_POST['confirm_deletion']) and 1 == $_POST['confirm_deletion'])
+    {
+      foreach ($collection as $user_id)
+      {
+        delete_user($user_id);
+      }
+      array_push(
+        $page['infos'],
+        sprintf(
+          l10n('%d users deleted'),
+          count($collection)  
+          )
+        );
+      foreach ($page['filtered_users'] as $filter_key => $filter_user)
+      {
+	if (in_array($filter_user['id'], $collection))
+	{
+	  unset($page['filtered_users'][$filter_key]);
+	}
+      }
+    }
+    else
+    {
+      array_push($page['errors'], l10n('You need to confirm deletion'));
+    }
+  }
+}
+
+// +-----------------------------------------------------------------------+
+// |                       preferences form submission                     |
+// +-----------------------------------------------------------------------+
+
+if (isset($_POST['pref_submit']) and count($collection) > 0)
+{
+  if (-1 != $_POST['associate'])
+  {
+    $datas = array();
+    
+    $query = '
+SELECT user_id
+  FROM '.USER_GROUP_TABLE.'
+  WHERE group_id = '.$_POST['associate'].'
+;';
+    $associated = array_from_query($query, 'user_id');
+    
+    $associable = array_diff($collection, $associated);
+    
+    if (count($associable) > 0)
+    {
+      foreach ($associable as $item)
+      {
+        array_push($datas,
+                   array('group_id'=>$_POST['associate'],
+                         'user_id'=>$item));
+      }
+        
+      mass_inserts(USER_GROUP_TABLE,
+                   array('group_id', 'user_id'),
+                   $datas);
+    }
+  }
+  
+  if (-1 != $_POST['dissociate'])
+  {
+    $query = '
+DELETE FROM '.USER_GROUP_TABLE.'
+  WHERE group_id = '.$_POST['dissociate'].'
+  AND user_id IN ('.implode(',', $collection).')
+';
+    pwg_query($query);
+  }
+  
+  // properties to set for the collection (a user list)
+  $datas = array();
+  $dbfields = array('primary' => array('user_id'), 'update' => array());
+  
+  $formfields =
+    array('nb_image_line', 'nb_line_page', 'template', 'language',
+          'recent_period', 'maxwidth', 'expand', 'show_nb_comments',
+          'maxheight', 'status');
+  
+  $true_false_fields = array('expand', 'show_nb_comments');
+  
+  foreach ($formfields as $formfield)
+  {
+    // special for true/false fields
+    if (in_array($formfield, $true_false_fields))
+    {
+      $test = $formfield;
+    }
+    else
+    {
+      $test = $formfield.'_action';
+    }
+    
+    if ($_POST[$test] != 'leave')
+    {
+      array_push($dbfields['update'], $formfield);
+    }
+  }
+  
+  // updating elements is useful only if needed...
+  if (count($dbfields['update']) > 0)
+  {
+    $datas = array();
+    
+    foreach ($collection as $user_id)
+    {
+      $data = array();
+      $data['user_id'] = $user_id;
+      
+      // TODO : verify if submited values are semanticaly correct
+      foreach ($dbfields['update'] as $dbfield)
+      {
+        // if the action is 'unset', the key won't be in row and
+        // mass_updates function will set this field to NULL
+        if (in_array($dbfield, $true_false_fields)
+            or 'set' == $_POST[$dbfield.'_action'])
+        {
+          $data[$dbfield] = $_POST[$dbfield];
+        }
+      }
+      
+      // Webmaster status must not be changed
+      if ($conf['webmaster_id'] == $user_id and isset($data['status']))
+      {
+        $data['status'] = 'admin';
+      }
+      
+      array_push($datas, $data);
+    }
+    
+//       echo '<pre>';
+//       print_r($datas);
+//       echo '</pre>';
+    
+    mass_updates(USER_INFOS_TABLE, $dbfields, $datas);
+  }
+
+  redirect(
+    PHPWG_ROOT_PATH.
+    'admin.php'.
+    get_query_string_diff(
+      array(
+        'start'
+        )
+      )
+    );
+}
+
+// +-----------------------------------------------------------------------+
+// |                              groups list                              |
+// +-----------------------------------------------------------------------+
+
+$groups = array();
+
+$query = '
+SELECT id, name
+  FROM '.GROUPS_TABLE.'
+;';
+$result = pwg_query($query);
+
+while ($row = mysql_fetch_array($result))
+{
+  $groups[$row['id']] = $row['name'];
+}
+
+// +-----------------------------------------------------------------------+
+// |                             template init                             |
+// +-----------------------------------------------------------------------+
+
+$template->set_filenames(array('user_list'=>'admin/user_list.tpl'));
+
+$base_url = add_session_id(PHPWG_ROOT_PATH.'admin.php?page=user_list');
+
+if (isset($_GET['start']) and is_numeric($_GET['start']))
+{
+  $start = $_GET['start'];
+}
+else
+{
+  $start = 0;
+}
+
+$template->assign_vars(
+  array(
+    '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_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'],
+    'L_LANGUAGE' => $lang['language'],
+    'L_NB_IMAGE_LINE' => $lang['nb_image_per_row'],
+    'L_NB_LINE_PAGE' => $lang['nb_row_per_page'],
+    'L_TEMPLATE' => $lang['theme'],
+    'L_RECENT_PERIOD' => $lang['recent_period'],
+    'L_EXPAND' => $lang['auto_expand'],
+    'L_SHOW_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_DELETE' => $lang['user_delete'],
+    'L_DELETE_HINT' => $lang['user_delete_hint'],
+
+    'U_HELP' => PHPWG_ROOT_PATH.'/popuphelp.php?page=user_list',
+    
+    'F_ADD_ACTION' => $base_url,
+    'F_USERNAME' => @$_GET['username'],
+    'F_FILTER_ACTION' => PHPWG_ROOT_PATH.'admin.php'
+    ));
+
+if (isset($_GET['id']))
+{
+  $template->assign_block_vars('session', array('ID' => $_GET['id']));
+}
+
+foreach ($page['order_by_items'] as $item => $label)
+{
+  $selected = (isset($_GET['order_by']) and $_GET['order_by'] == $item) ?
+    'selected="selected"' : '';
+  $template->assign_block_vars(
+    'order_by',
+    array(
+      'VALUE' => $item,
+      'CONTENT' => $label,
+      'SELECTED' => $selected
+      ));
+}
+
+foreach ($page['direction_items'] as $item => $label)
+{
+  $selected = (isset($_GET['direction']) and $_GET['direction'] == $item) ?
+    'selected="selected"' : '';
+  $template->assign_block_vars(
+    'direction',
+    array(
+      'VALUE' => $item,
+      'CONTENT' => $label,
+      'SELECTED' => $selected
+      ));
+}
+
+$blockname = 'group_option';
+
+$template->assign_block_vars(
+  $blockname,
+  array(
+    'VALUE'=> -1,
+    'CONTENT' => '------------',
+    'SELECTED' => ''
+    ));
+
+foreach ($groups as $group_id => $group_name)
+{
+  $selected = (isset($_GET['group']) and $_GET['group'] == $group_id) ?
+    'selected="selected"' : '';
+  $template->assign_block_vars(
+    $blockname,
+    array(
+      'VALUE' => $group_id,
+      'CONTENT' => $group_name,
+      'SELECTED' => $selected
+      ));
+}
+
+$blockname = 'status_option';
+
+$template->assign_block_vars(
+  $blockname,
+  array(
+    'VALUE'=> -1,
+    'CONTENT' => '------------',
+    'SELECTED' => ''
+    ));
+
+foreach (get_enums(USER_INFOS_TABLE, 'status') as $status)
+{
+  $selected = (isset($_GET['status']) and $_GET['status'] == $status) ?
+    'selected="selected"' : '';
+  $template->assign_block_vars(
+    $blockname,
+    array(
+      'VALUE' => $status,
+      'CONTENT' => $lang['user_status_'.$status],
+      'SELECTED' => $selected
+      ));
+}
+
+// ---
+//   $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 (isset($_POST['pref_submit']))
+{
+//  echo '<pre>'; print_r($_POST); echo '</pre>';
+  $template->assign_vars(
+    array(
+      'NB_IMAGE_LINE' => $_POST['nb_image_line'],
+      'NB_LINE_PAGE' => $_POST['nb_line_page'],
+      'MAXWIDTH' => $_POST['maxwidth'],
+      'MAXHEIGHT' => $_POST['maxheight'],
+      'RECENT_PERIOD' => $_POST['recent_period'],
+      'EXPAND_YES' => 'true' == $_POST['expand'] ? 'checked="checked"' : '',
+      'EXPAND_NO' => 'false' == $_POST['expand'] ? 'checked="checked"' : '',
+      'SHOW_NB_COMMENTS_YES' =>
+        'true' == $_POST['show_nb_comments'] ? 'checked="checked"' : '',
+      'SHOW_NB_COMMENTS_NO' =>
+        'false' == $_POST['show_nb_comments'] ? 'checked="checked"' : ''
+      ));
+}
+else
+{
+  $template->assign_vars(
+    array(
+      'NB_IMAGE_LINE' => $conf['nb_image_line'],
+      'NB_LINE_PAGE' => $conf['nb_line_page'],
+      'MAXWIDTH' => @$conf['default_maxwidth'],
+      'MAXHEIGHT' => @$conf['default_maxheight'],
+      'RECENT_PERIOD' => $conf['recent_period'],
+      ));
+}
+
+$blockname = 'template_option';
+
+foreach (get_templates() as $pwg_template)
+{
+  if (isset($_POST['pref_submit']))
+  {
+    $selected = $_POST['template']==$pwg_template ? 'selected="selected"' : '';
+  }
+  else if ($conf['default_template'] == $pwg_template)
+  {
+    $selected = 'selected="selected"';
+  }
+  else
+  {
+    $selected = '';
+  }
+  
+  $template->assign_block_vars(
+    $blockname,
+    array(
+      'VALUE'=> $pwg_template,
+      'CONTENT' => $pwg_template,
+      'SELECTED' => $selected
+      ));
+}
+
+$blockname = 'language_option';
+
+foreach (get_languages() as $language_code => $language_name)
+{
+  if (isset($_POST['pref_submit']))
+  {
+    $selected = $_POST['language']==$language_code ? 'selected="selected"':'';
+  }
+  else if ($conf['default_language'] == $language_code)
+  {
+    $selected = 'selected="selected"';
+  }
+  else
+  {
+    $selected = '';
+  }
+  
+  $template->assign_block_vars(
+    $blockname,
+    array(
+      'VALUE'=> $language_code,
+      'CONTENT' => $language_name,
+      'SELECTED' => $selected
+      ));
+}
+
+$blockname = 'pref_status_option';
+
+foreach (get_enums(USER_INFOS_TABLE, 'status') as $status)
+{
+  if (isset($_POST['pref_submit']))
+  {
+    $selected = $_POST['status'] == $status ? 'selected="selected"' : '';
+  }
+  else if ('guest' == $status)
+  {
+    $selected = 'selected="selected"';
+  }
+  else
+  {
+    $selected = '';
+  }
+  
+  $template->assign_block_vars(
+    $blockname,
+    array(
+      'VALUE' => $status,
+      'CONTENT' => $lang['user_status_'.$status],
+      'SELECTED' => $selected
+      ));
+}
+
+// associate
+$blockname = 'associate_option';
+
+$template->assign_block_vars(
+  $blockname,
+  array(
+    'VALUE'=> -1,
+    'CONTENT' => '------------',
+    'SELECTED' => ''
+    ));
+
+foreach ($groups as $group_id => $group_name)
+{
+  if (isset($_POST['pref_submit']))
+  {
+    $selected = $_POST['associate'] == $group_id ? 'selected="selected"' : '';
+  }
+  else
+  {
+    $selected = '';
+  }
+    
+  $template->assign_block_vars(
+    $blockname,
+    array(
+      'VALUE' => $group_id,
+      'CONTENT' => $group_name,
+      'SELECTED' => $selected
+      ));
+}
+
+// dissociate
+$blockname = 'dissociate_option';
+
+$template->assign_block_vars(
+  $blockname,
+  array(
+    'VALUE'=> -1,
+    'CONTENT' => '------------',
+    'SELECTED' => ''
+    ));
+
+foreach ($groups as $group_id => $group_name)
+{
+  if (isset($_POST['pref_submit']))
+  {
+    $selected = $_POST['dissociate'] == $group_id ? 'selected="selected"' : '';
+  }
+  else
+  {
+    $selected = '';
+  }
+    
+  $template->assign_block_vars(
+    $blockname,
+    array(
+      'VALUE' => $group_id,
+      'CONTENT' => $group_name,
+      'SELECTED' => $selected
+      ));
+}
+
+// +-----------------------------------------------------------------------+
+// |                            navigation bar                             |
+// +-----------------------------------------------------------------------+
+
+$url = PHPWG_ROOT_PATH.'admin.php'.get_query_string_diff(array('start'));
+
+$navbar = create_navigation_bar(
+  $url,
+  count($page['filtered_users']),
+  $start,
+  $conf['users_page'],
+  ''
+  );
+
+$template->assign_vars(array('NAVBAR' => $navbar));
+
+// +-----------------------------------------------------------------------+
+// |                               user list                               |
+// +-----------------------------------------------------------------------+
+
+$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=';
+
+foreach ($page['filtered_users'] as $num => $local_user)
+{
+  // simulate LIMIT $start, $conf['users_page']
+  if ($num < $start)
+  {
+    continue;
+  }
+  if ($num >= $start + $conf['users_page'])
+  {
+    break;
+  }
+
+  $groups_string = preg_replace(
+    '/(\d+)/e',
+    "\$groups['$1']",
+    implode(
+      ', ',
+      $local_user['groups']
+      )
+    );
+
+  if (isset($_POST['pref_submit'])
+      and isset($_POST['selection'])
+      and in_array($local_user['id'], $_POST['selection']))
+  {
+    $checked = 'checked="checked"';
+  }
+  else
+  {
+    $checked = '';
+  }
+    
+  $template->assign_block_vars(
+    'user',
+    array(
+      'CLASS' => ($num % 2 == 1) ? 'row2' : 'row1',
+      'ID' => $local_user['id'],
+      'CHECKED' => $checked,
+      'U_MOD' => add_session_id($profile_url.$local_user['id']),
+      'U_PERM' => add_session_id($perm_url.$local_user['id']),
+      'USERNAME' => $local_user['username'],
+      'STATUS' => $lang['user_status_'.$local_user['status']],
+      'EMAIL' => isset($local_user['email']) ? $local_user['email'] : '',
+      'GROUPS' => $groups_string
+      )
+    );
+}
+
+// +-----------------------------------------------------------------------+
+// |                           html code display                           |
+// +-----------------------------------------------------------------------+
+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'user_list');
+?>
Index: /branches/1.5/admin/user_perm.php
===================================================================
--- /branches/1.5/admin/user_perm.php	(revision 3250)
+++ /branches/1.5/admin/user_perm.php	(revision 3250)
@@ -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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if (!defined('IN_ADMIN'))
+{
+  die('Hacking attempt!');
+}
+include_once(PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php');
+
+// +-----------------------------------------------------------------------+
+// |                            variables init                             |
+// +-----------------------------------------------------------------------+
+
+if (isset($_GET['user_id']) and is_numeric($_GET['user_id']))
+{
+  $page['user'] = $_GET['user_id'];
+}
+else
+{
+  echo l10n('user_id URL parameter is missing');
+  exit();
+}
+
+// +-----------------------------------------------------------------------+
+// |                                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 '.USER_ACCESS_TABLE.'
+  WHERE user_id = '.$page['user'].'
+    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 '.USER_ACCESS_TABLE.'
+  WHERE user_id = '.$page['user'].'
+;';
+  $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' => $page['user'],
+                               'cat_id' => $to_autorize_id));
+  }
+
+  mass_inserts(USER_ACCESS_TABLE, array('user_id','cat_id'), $inserts);
+}
+
+// +-----------------------------------------------------------------------+
+// |                             template init                             |
+// +-----------------------------------------------------------------------+
+
+$template->set_filenames(
+  array(
+    'user_perm' => 'admin/user_perm.tpl',
+    'double_select' => 'admin/double_select.tpl'
+    )
+  );
+
+$template->assign_vars(
+  array(
+    'TITLE' =>
+      sprintf(
+        l10n('Manage permissions for user "%s"'),
+        get_username($page['user']
+          )
+        ),
+    'L_CAT_OPTIONS_TRUE'=>$lang['authorized'],
+    'L_CAT_OPTIONS_FALSE'=>$lang['forbidden'],
+    
+    'F_ACTION' =>
+      add_session_id(
+        PHPWG_ROOT_PATH.
+        'admin.php?page=user_perm'.
+        '&amp;user_id='.$page['user']
+        )
+    )
+  );
+
+
+// retrieve category ids authorized to the groups the user belongs to
+$group_authorized = array();
+
+$query = '
+SELECT DISTINCT cat_id, c.uppercats, c.global_rank
+  FROM '.USER_GROUP_TABLE.' AS ug
+    INNER JOIN '.GROUP_ACCESS_TABLE.' AS ga
+      ON ug.group_id = ga.group_id
+    INNER JOIN '.CATEGORIES_TABLE.' AS c
+      ON c.id = ga.cat_id
+  WHERE ug.user_id = '.$page['user'].'
+;';
+$result = pwg_query($query);
+
+if (mysql_num_rows($result) > 0)
+{
+  $template->assign_block_vars('groups', array());
+
+  $cats = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($cats, $row);
+    array_push($group_authorized, $row['cat_id']);
+  }
+  usort($cats, 'global_rank_compare');
+
+  foreach ($cats as $category)
+  {
+    $template->assign_block_vars(
+      'groups.category',
+      array(
+        'NAME' => get_cat_display_name_cache($category['uppercats'], '', false)
+        )
+      );
+  }
+}
+
+// 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 = '.$page['user'];
+if (count($group_authorized) > 0)
+{
+  $query_true.= '
+    AND cat_id NOT IN ('.implode(',', $group_authorized).')';
+}
+$query_true.= '
+;';
+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).')';
+}
+if (count($group_authorized) > 0)
+{
+  $query_false.= '
+    AND id NOT IN ('.implode(',', $group_authorized).')';
+}
+$query_false.= '
+;';
+display_select_cat_wrapper($query_false,array(),'category_option_false');
+
+// +-----------------------------------------------------------------------+
+// |                           sending html code                           |
+// +-----------------------------------------------------------------------+
+
+$template->assign_var_from_handle('DOUBLE_SELECT', 'double_select');
+$template->assign_var_from_handle('ADMIN_CONTENT', 'user_perm');
+?>
Index: /branches/1.5/admin/waiting.php
===================================================================
--- /branches/1.5/admin/waiting.php	(revision 3250)
+++ /branches/1.5/admin/waiting.php	(revision 3250)
@@ -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.                                                                  |
+// +-----------------------------------------------------------------------+
+if( !defined("PHPWG_ROOT_PATH") )
+{
+  die ("Hacking attempt!");
+}
+include_once( PHPWG_ROOT_PATH.'admin/include/isadmin.inc.php');
+//--------------------------------------------------------------------- updates
+
+if (isset($_POST))
+{
+  $to_validate = array();
+  $to_reject = array();
+  
+  if (isset($_POST['submit']))
+  {    
+    foreach (explode(',', $_POST['list']) as $waiting_id)
+    {
+      if (isset($_POST['action-'.$waiting_id]))
+      {
+        switch ($_POST['action-'.$waiting_id])
+        {
+          case 'reject' :
+          {
+            array_push($to_reject, $waiting_id);
+            break;
+          }
+          case 'validate' :
+          {
+            array_push($to_validate, $waiting_id);
+            break;
+          }
+        }
+      }
+    }
+  }
+  else if (isset($_POST['validate-all']))
+  {
+    $to_validate = explode(',', $_POST['list']);
+  }
+  else if (isset($_POST['reject-all']))
+  {
+    $to_reject = explode(',', $_POST['list']);
+  }
+
+  if (count($to_validate) > 0)
+  {
+    $query = '
+UPDATE '.WAITING_TABLE.'
+  SET validated = \'true\'
+  WHERE id IN ('.implode(',', $to_validate).')
+;';
+    pwg_query($query);
+
+    array_push(
+      $page['infos'],
+      sprintf(
+        l10n('%d waiting pictures validated'),
+        count($to_validate)
+        )
+      );
+  }
+
+  if (count($to_reject) > 0)
+  {
+    // The uploaded element was refused, we have to delete its reference in
+    // the database and to delete the element as well.
+    $query = '
+SELECT id, storage_category_id, file, tn_ext
+  FROM '.WAITING_TABLE.'
+  WHERE id IN ('.implode(',', $to_reject).')
+;';
+    $result = pwg_query($query);
+    while($row = mysql_fetch_array($result))
+    {
+      $dir = get_complete_dir($row['storage_category_id']);
+      unlink($dir.$row['file']);
+      if (isset($row['tn_ext']) and $row['tn_ext'] != '')
+      {
+        unlink(
+          get_thumbnail_src(
+            $dir.$row['file'],
+            $row['tn_ext']
+            )
+          );
+      }
+      else if (@is_file(get_thumbnail_src($dir.$row['file'], 'jpg')))
+      {
+        unlink(
+          get_thumbnail_src(
+            $dir.$row['file'],
+            'jpg'
+            )
+          );
+      }
+    }
+    
+    $query = '
+DELETE
+  FROM '.WAITING_TABLE.'
+  WHERE id IN ('.implode(',', $to_reject).')
+;';
+    pwg_query($query);
+
+    array_push(
+      $page['infos'],
+      sprintf(
+        l10n('%d waiting pictures rejected'),
+        count($to_reject)
+        )
+      );
+  }
+}
+
+//----------------------------------------------------- template initialization
+$template->set_filenames(array('waiting'=>'admin/waiting.tpl'));
+$template->assign_vars(array(
+  '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'] ))
+  ));
+  
+//---------------------------------------------------------------- form display
+$cat_names = array();
+$list = 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' => date('Y-m-d H:i:s', $row['date']),
+      'FILE_TITLE'=>$row['file'],
+      'FILE_IMG' =>
+        (strlen($row['file']) > 10) ?
+          (substr($row['file'], 0, 10)).'...' : $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' =>
+          (strlen($thumbnail) > 10) ?
+            (substr($thumbnail, 0, 10)).'...' : $thumbnail,
+        'FILE_TN_TITLE' => $thumbnail
+        )
+      );
+  }
+
+  array_push($list, $row['id']);
+}
+
+$template->assign_vars(
+  array(
+    'LIST' => implode(',', $list)
+    )
+  );
+  
+//----------------------------------------------------------- sending html code
+$template->assign_var_from_handle('ADMIN_CONTENT', 'waiting');
+?>
Index: /branches/1.5/category.php
===================================================================
--- /branches/1.5/category.php	(revision 3250)
+++ /branches/1.5/category.php	(revision 3250)
@@ -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
+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();
+
+// caddie filling :-)
+if (isset($_GET['caddie']))
+{
+//  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+  
+  $query = '
+SELECT DISTINCT(id)
+  FROM '.IMAGES_TABLE.' AS i
+    INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id
+  '.$page['where'].'
+;';
+  fill_caddie(array_from_query($query, 'id'));
+}
+
+// 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'];
+$page['body_id'] = 'theCategoryPage';
+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_PASSWORD' => $lang['password'],
+  'L_HELLO' => $lang['hello'],
+  'L_REGISTER' => $lang['ident_register'],
+  '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_LOST_PASSWORD' => add_session_id(PHPWG_ROOT_PATH.'password.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')
+  )
+);
+//-------------------------------------------------------------- external links
+if (count($conf['links']) > 0)
+{
+  $template->assign_block_vars('links', array());
+
+  foreach ($conf['links'] as $url => $label)
+  {
+    $template->assign_block_vars(
+      'links.link',
+      array(
+        'URL' => $url,
+        'LABEL' => $label
+        ));
+  }
+}
+//---------------------------------------------------------- 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('register', array());
+  $template->assign_block_vars('login', array());
+  
+  $template->assign_block_vars('quickconnect', array());
+  if ($conf['authorize_remembering'])
+  {
+    $template->assign_block_vars('quickconnect.remember_me', array());
+  }
+}
+else
+{
+  $template->assign_block_vars('hello', array());
+  $template->assign_block_vars('profile', array());
+
+  // the logout link has no meaning with Apache authentication : it is not
+  // possible to logout with this kind of authentication.
+  if (!$conf['apache_authentication'])
+  {
+    $template->assign_block_vars('logout', array());
+  }
+
+  if ('admin' == $user['status'])
+  {
+    $template->assign_block_vars('admin', 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['about_page_title'],
+'NAME'=>$lang['About'],
+'U_SUMMARY'=>add_session_id( 'about.php?'.str_replace( '&', '&amp;', $_SERVER['QUERY_STRING'] ) )
+));
+
+// notification
+$template->assign_block_vars(
+  'summary',
+  array(
+    'TITLE'=>l10n('notification'),
+    'NAME'=>l10n('Notification'),
+    'U_SUMMARY'=>add_session_id(PHPWG_ROOT_PATH.'notification.php')
+));
+
+if (isset($page['cat'])
+    and is_numeric($page['cat'])
+    and 'admin' == $user['status'])
+{
+  $template->assign_block_vars(
+    'edit',
+    array(
+      'URL' =>
+        add_session_id(
+          PHPWG_ROOT_PATH.'admin.php?page=cat_modify'
+          .'&amp;cat_id='.$page['cat']
+          )
+      )
+    );
+}
+
+//------------------------------------------------------ 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');
+
+  if ('admin' == $user['status'])
+  {
+    $template->assign_block_vars(
+      'caddie',
+      array(
+        'URL' =>
+          add_session_id(
+            PHPWG_ROOT_PATH.'category.php'
+            .get_query_string_diff(array('caddie')).'&amp;caddie=1')
+        )
+      );
+  }
+}
+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'] );
+
+$template->parse('category');
+include(PHPWG_ROOT_PATH.'include/page_tail.php');
+?>
Index: /branches/1.5/comments.php
===================================================================
--- /branches/1.5/comments.php	(revision 3250)
+++ /branches/1.5/comments.php	(revision 3250)
@@ -0,0 +1,501 @@
+<?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');
+}
+
+$sort_order = array(
+  'descending' => 'DESC',
+  'ascending' => 'ASC'
+  );
+
+// sort_by : database fields proposed for sorting comments list
+$sort_by = array(
+  'date' => 'comment date',
+  'image_id' => 'picture'
+  );
+
+// items_number : list of number of items to display per page
+$items_number = array(5,10,20,50,'all');
+
+// since when display comments ?
+//
+$since_options = array(
+  1 => array('label' => l10n('today'),
+             'clause' => 'date > SUBDATE(CURDATE(), INTERVAL 1 DAY)'),
+  2 => array('label' => sprintf(l10n('last %d days'), 7),
+             'clause' => 'date > SUBDATE(CURDATE(), INTERVAL 7 DAY)'),
+  3 => array('label' => sprintf(l10n('last %d days'), 30),
+             'clause' => 'date > SUBDATE(CURDATE(), INTERVAL 30 DAY)'),
+  4 => array('label' => l10n('the beginning'),
+             'clause' => '1=1') // stupid but generic
+  );
+
+// since
+//
+$page['since'] = 1;
+if (isset($_GET['since']))
+{
+  if (!isset($since_options{ $_GET['since'] }))
+  {
+    die('Hacking attempt on "since" GET parameter');
+  }
+  else
+  {
+    $page['since'] = $_GET['since'];
+  }
+}
+
+// on which field sorting
+//
+$page['sort_by'] = 'date';
+// if the form was submitted, it overloads default behaviour
+if (isset($_GET['sort_by']))
+{
+  if (!isset($sort_by{ $_GET['sort_by'] }))
+  {
+    die('Hacking attempt on "sort_by" GET parameter');
+  }
+  else
+  {
+    $page['sort_by'] = $_GET['sort_by'];
+  }
+}
+
+// order to sort
+//
+$page['sort_order'] = $sort_order['descending'];
+// if the form was submitted, it overloads default behaviour
+if (isset($_GET['sort_order']))
+{
+  if (!isset($sort_order{ $_GET['sort_order'] }))
+  {
+    die('Hacking attempt on "sort_order" GET parameter');
+  }
+  else
+  {
+    $page['sort_order'] = $sort_order[$_GET['sort_order']];
+  }
+}
+
+// number of items to display
+//
+$page['items_number'] = 5;
+if (isset($_GET['items_number']))
+{
+  if (!in_array($_GET['items_number'], $items_number))
+  {
+    die('Hacking attempt on "items_number" GET parameter');
+  }
+  else
+  {
+    $page['items_number'] = $_GET['items_number'];
+  }
+}
+
+// which category to filter on ?
+$page['cat_clause'] = '1=1';
+if (isset($_GET['cat']))
+{
+  if (''.intval($_GET['cat']) != ''.$_GET['cat'])
+  {
+    die('Hacking attempt on "cat" GET parameter');
+  }
+  else if (0 != $_GET['cat'])
+  {
+    $page['cat_clause'] =
+      'category_id IN ('.
+      implode(
+        ',',
+        get_subcat_ids(array($_GET['cat']))
+        ).
+      ')'
+      ;
+  }
+}
+
+// search a particular author
+$page['author_clause'] = '1=1';
+if (isset($_GET['author']) and !empty($_GET['author']))
+{
+  if (function_exists('mysql_real_escape_string'))
+  {
+    $author = mysql_real_escape_string($_GET['author']);
+  }
+  else
+  {
+    $author = mysql_escape_string($_GET['author']);
+  }
+
+  $page['author_clause'] = 'author = \''.$author.'\'';
+}
+
+// search a substring among comments content
+$page['keyword_clause'] = '1=1';
+if (isset($_GET['keyword']) and !empty($_GET['keyword']))
+{
+  if (function_exists('mysql_real_escape_string'))
+  {
+    $keyword = mysql_real_escape_string($_GET['keyword']);
+  }
+  else
+  {
+    $keyword = mysql_escape_string($_GET['keyword']);
+  }
+  $page['keyword_clause'] =
+    '('.
+    implode(
+      ' AND ',
+      array_map(
+        create_function(
+          '$s',
+          'return "content LIKE \'%$s%\'";'
+          ),
+        preg_split('/[\s,;]+/', $keyword)
+        )
+      ).
+    ')'
+    ;
+}
+
+// +-----------------------------------------------------------------------+
+// |                         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\'
+    , validation_date = NOW()
+  WHERE id IN ('.implode(',', $_POST['comment_id']).')
+;';
+  pwg_query($query);
+}
+// +-----------------------------------------------------------------------+
+// |                       page header and options                         |
+// +-----------------------------------------------------------------------+
+
+$title= l10n('title_comments');
+$page['body_id'] = 'theCommentsPage';
+include(PHPWG_ROOT_PATH.'include/page_header.php');
+
+$template->set_filenames(array('comments'=>'comments.tpl'));
+$template->assign_vars(
+  array(
+    'L_COMMENT_TITLE' => $title,
+
+    'F_ACTION'=>PHPWG_ROOT_PATH.'comments.php',
+    'F_KEYWORD'=>@$_GET['keyword'],
+    'F_AUTHOR'=>@$_GET['author'],
+    
+    'U_HOME' => add_session_id(PHPWG_ROOT_PATH.'category.php')
+    )
+  );
+
+// +-----------------------------------------------------------------------+
+// |                          form construction                            |
+// +-----------------------------------------------------------------------+
+
+// Search in a particular category
+$blockname = 'category';
+
+$template->assign_block_vars(
+  $blockname,
+  array('SELECTED' => '',
+        'VALUE'=> 0,
+        'OPTION' => '------------'
+    ));
+
+$query = '
+SELECT id,name,uppercats,global_rank
+  FROM '.CATEGORIES_TABLE;
+if ($user['forbidden_categories'] != '')
+{
+  $query.= '
+    WHERE id NOT IN ('.$user['forbidden_categories'].')';
+}
+$query.= '
+;';
+display_select_cat_wrapper($query, array(@$_GET['cat']), $blockname, true);
+
+// Filter on recent comments...
+$blockname = 'since_option';
+
+foreach ($since_options as $id => $option)
+{
+  $selected = ($id == $page['since']) ? 'selected="selected"' : '';
+  
+  $template->assign_block_vars(
+    $blockname,
+    array('SELECTED' => $selected,
+          'VALUE'=> $id,
+          'CONTENT' => $option['label']
+      ));
+}
+
+// Sort by
+$blockname = 'sort_by_option';
+
+foreach ($sort_by as $key => $value)
+{
+  $selected = ($key == $page['sort_by']) ? 'selected="selected"' : '';
+
+  $template->assign_block_vars(
+    $blockname,
+    array('SELECTED' => $selected,
+          'VALUE'=> $key,
+          'CONTENT' => l10n($value)
+      ));
+}
+
+// Sorting order
+$blockname = 'sort_order_option';
+
+foreach (array_keys($sort_order) as $option)
+{
+  $selected = ($option == $page['sort_order']) ? 'selected="selected"' : '';
+
+  $template->assign_block_vars(
+    $blockname,
+    array('SELECTED' => $selected,
+          'VALUE'=> $option,
+          'CONTENT' => l10n($option)
+      ));
+}
+
+// Number of items
+$blockname = 'items_number_option';
+
+foreach ($items_number as $option)
+{
+  $selected = ($option == $page['items_number']) ? 'selected="selected"' : '';
+
+  $template->assign_block_vars(
+    $blockname,
+    array('SELECTED' => $selected,
+          'VALUE'=> $option,
+          'CONTENT' => is_numeric($option) ? $option : l10n($option)
+      ));
+}
+
+// +-----------------------------------------------------------------------+
+// |                            navigation bar                             |
+// +-----------------------------------------------------------------------+
+
+if (isset($_GET['start']) and is_numeric($_GET['start']))
+{
+  $start = $_GET['start'];
+}
+else
+{
+  $start = 0;
+}
+
+$query = '
+SELECT COUNT(DISTINCT(id))
+  FROM '.IMAGE_CATEGORY_TABLE.' AS ic
+    INNER JOIN '.COMMENTS_TABLE.' AS com
+    ON ic.image_id = com.image_id
+  WHERE validated = \'true\'
+    AND '.$since_options[$page['since']]['clause'].'
+    AND '.$page['cat_clause'].'
+    AND '.$page['author_clause'].'
+    AND '.$page['keyword_clause'];
+if ($user['forbidden_categories'] != '')
+{
+  $query.= '
+    AND category_id NOT IN ('.$user['forbidden_categories'].')';
+}
+$query.= '
+;';
+list($counter) = mysql_fetch_row(pwg_query($query));
+
+$url = PHPWG_ROOT_PATH.'comments.php?t=1'.get_query_string_diff(array('start'));
+
+$navbar = create_navigation_bar($url,
+                                $counter,
+                                $start,
+                                $page['items_number'],
+                                '');
+
+$template->assign_vars(array('NAVBAR' => $navbar));
+
+// +-----------------------------------------------------------------------+
+// |                        last comments display                          |
+// +-----------------------------------------------------------------------+
+
+$comments = array();
+$element_ids = array();
+$category_ids = array();
+
+$query = '
+SELECT com.id AS comment_id
+     , com.image_id
+     , ic.category_id
+     , com.author
+     , com.date
+     , com.content
+     , com.id AS comment_id
+  FROM '.IMAGE_CATEGORY_TABLE.' AS ic
+    INNER JOIN '.COMMENTS_TABLE.' AS com
+    ON ic.image_id = com.image_id
+  WHERE validated = \'true\'
+    AND '.$since_options[$page['since']]['clause'].'
+    AND '.$page['cat_clause'].'
+    AND '.$page['author_clause'].'
+    AND '.$page['keyword_clause'];
+if ($user['forbidden_categories'] != '')
+{
+  $query.= '
+    AND category_id NOT IN ('.$user['forbidden_categories'].')';
+}
+$query.= '
+  GROUP BY comment_id
+  ORDER BY '.$page['sort_by'].' '.$page['sort_order'];
+if ('all' != $page['items_number'])
+{
+  $query.= '
+  LIMIT '.$start.','.$page['items_number'];
+}
+$query.= '
+;';
+$result = pwg_query($query);
+while ($row = mysql_fetch_array($result))
+{
+  array_push($comments, $row);
+  array_push($element_ids, $row['image_id']);
+  array_push($category_ids, $row['category_id']);
+}
+
+if (count($comments) > 0)
+{
+  // retrieving element informations
+  $elements = array();
+  $query = '
+SELECT id, name, file, path, tn_ext
+  FROM '.IMAGES_TABLE.'
+  WHERE id IN ('.implode(',', $element_ids).')
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    $elements[$row['id']] = $row;
+  }
+
+  // retrieving category informations
+  $categories = array();
+  $query = '
+SELECT id, uppercats
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id IN ('.implode(',', $category_ids).')
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    $categories[$row['id']] = $row;
+  }
+
+  foreach ($comments as $comment)
+  {
+    // name of the picture
+    $name = get_cat_display_name_cache(
+      $categories[$comment['category_id']]['uppercats'], '', false);
+    $name.= $conf['level_separator'];
+    if (!empty($elements[$comment['image_id']]['name']))
+    {
+      $name.= $elements[$comment['image_id']]['name'];
+    }
+    else
+    {
+      $name.= get_name_from_file($elements[$comment['image_id']]['file']);
+    }
+    
+    // source of the thumbnail picture
+    $thumbnail_src = get_thumbnail_src(
+      $elements[$comment['image_id']]['path'],
+      @$elements[$comment['image_id']]['tn_ext']
+      );
+  
+    // link to the full size picture
+    $url = PHPWG_ROOT_PATH.'picture.php?cat='.$comment['category_id'];
+    $url.= '&amp;image_id='.$comment['image_id'];
+    
+    $template->assign_block_vars(
+      'picture',
+      array(
+        'TITLE_IMG'=>$name,
+        'I_THUMB'=>$thumbnail_src,
+        'U_THUMB'=>add_session_id($url)
+        ));
+    
+    $author = $comment['author'];
+    if (empty($comment['author']))
+    {
+      $author = l10n('guest');
+    }
+    
+    $template->assign_block_vars(
+      'comment',
+      array(
+        'U_PICTURE' => add_session_id($url),
+        'TN_SRC' => $thumbnail_src,
+        'AUTHOR' => $author,
+        'DATE'=>format_date($comment['date'],'mysql_datetime',true),
+        'CONTENT'=>parse_comment_content($comment['content']),
+        ));
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                           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.5/doc/COPYING
===================================================================
--- /branches/1.5/doc/COPYING	(revision 3250)
+++ /branches/1.5/doc/COPYING	(revision 3250)
@@ -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.5/doc/ChangeLog
===================================================================
--- /branches/1.5/doc/ChangeLog	(revision 3250)
+++ /branches/1.5/doc/ChangeLog	(revision 3250)
@@ -0,0 +1,831 @@
+2005-11-08 Pierrick LE GALL
+	
+	* bug 180 fixed: (report from BSF) remote_site.tpl doesn't
+	validate.
+
+	* translation bug fixed: (report from BSF)
+	generate_file_listing.php doesn't exist, it's
+	create_listing_file.php !
+
+2005-11-08 Pierrick LE GALL
+
+	* Branch 1.5 creation
+
+	* modification: on a fix branch, version is not shown, neither
+	generation time.
+
+2005-11-07 Pierrick LE GALL
+
+	* bug 184 fixed: for the third time...
+
+2005-11-07 Pierrick LE GALL
+
+	* improvement: use a "filter" form for adding user comments.
+
+2005-11-05 Pierrick LE GALL
+
+	* bug 186 fixed: useless template theme icons deleted. Remaining
+	icons in GIF converted to PNG.
+
+2005-10-31 Pierrick LE GALL
+
+	* bug 185 fixed: errors in language items.
+
+2005-10-31 Pierrick LE GALL
+
+	* modification: use "filter" class for quickconnect box (with some
+	custom modifications)
+
+	* bug fixed: the total number of pictures had disappeared
+
+2005-10-30 volcom
+	
+	* bug 190 fixed: issue in stats.tpl display
+	* bug fixed: labels of monthly, daily graph fixed
+
+2005-10-26 chrisaga
+
+	* bug 177 fixed: for Safari (was fixed for Konqueror only)
+
+2005-10-25 Pierrick LE GALL
+
+	* bug 183 fixed: Warning when trying to associate an image with an
+	already associated category. Just coded the TODO instructions I
+	had let some time ago.
+
+2005-10-23 chrisaga
+
+	* bug 184 fixed: .png button left aligned in IE
+
+2005-10-23 Pierrick LE GALL
+
+	* bug 182 fixed: newly created user is not displayed in the user
+	list.
+
+2005-10-23 Pierrick LE GALL
+
+	* bug fixed: during file tree synchronization, warning on finding
+	the next rank of category which has no sub-categories yet.
+	
+2005-10-23 chrisaga
+
+	* bug fixed: cat-list.tpl validate now
+
+	* improvement: removed some unnecessary css rules from old tests in 
+	FROM  design in file default-layout.css
+
+2005-10-23 Pierrick LE GALL
+
+	* bug 181 fixed: "Parameters not created in phpwebgallery_config
+	during upgrade". gallery_title and gallery_description had not
+	been added to config table. (use|show)_(exif|iptc) and
+	authorize_remembering have also been removed...
+
+2005-10-22 chrisaga
+
+	* bug 177 fixed: icon tools wrong position in Safari and Konqueror
+	Needed a little trick to fix it. Put the trick in a fix-khtml.css
+	Loading in header.tpl and protected from IE, Geko and Opera,
+	just in case (couldn't found a safari css-only filter wich validate)
+	
+	* bug fixed: issue in the FORM in remote_site.tpl which prevented
+	HTML validation (still something to do with the TABLE).
+
+2005-10-22 Pierrick LE GALL
+
+	* bug fixed: link on a single day in
+	Administration>General>History was missing
+
+2005-10-22 Pierrick LE GALL
+
+	* bug 173 fixed: due to phpBB user identifiers management, the
+	method to find the next user identifier has changer to MAX+1.
+
+	* improvement: information message when new user added
+
+	* bug fixed: language item "Username" used instead of "login".
+	
+2005-10-20 chrisaga
+
+	* bug 176 fixed: need a javascript to handle transparent PNG
+	background in IE (tribute to Bob Osola
+	http://homepage.ntlworld.com/bobosola/index.htm)
+
+	* display: fixed another IE childselector bug in Categories
+	Management admin page and improved display of this page in all
+	browsers too.
+
+2005-10-18 Pierrick LE GALL
+
+	* bug 174 fixed: use_exif_mapping configuration parameter was not
+	used to list database fields to update from EXIF values.
+
+2005-10-18 Pierrick LE GALL
+
+	* bug 172 fixed: crash when changing password with an external
+	users table. The same kind of correction was also made in
+	picture.php and register.php.
+
+2005-10-18 Pierrick LE GALL
+
+	* bug 159 and 166 fixed: parameter "options" for mail() function
+	disabled by default.
+
+2005-10-18 chrisaga
+
+	* display : smaller font-size and, as requested, fonts more like 1.4
+
+	* bug 165 fixed : La largeur par défaut en PIXELS pas en Kb
+
+2005-10-18 chrisaga
+
+	* display : in group_list.tpl - wrong form class, mixed html tags, ...
+
+	* display : suppress bullets in admin->synchronize and checkbox
+	under select
+
+	* display : set standard font size to 12pt
+
+2005-10-17 Pierrick LE GALL
+
+	* improvement: use new function get_language_filepath in about.php
+	(complement of bug 168 correction)
+	
+2005-10-17 Pierrick LE GALL
+
+	* bug 154 fixed: "Calendar category, too precise dates". Bug came
+	from the bigger precision of creation_date and available_date in
+	images tables. Need to retrieve only the year-month-day
+	information.
+	
+2005-10-17 volcom
+
+	* new: history details by month,day
+	
+2005-10-15 Pierrick LE GALL
+
+	* modification: localized labels in Administration>Pictures>Caddie
+
+	* translation: bug fixed on special categories title in French
+
+	* translation: all help pages were translated in french
+
+2005-10-09 Pierrick LE GALL
+
+	* new: "quick start" section in Administration>General>Instructions
+	
+2005-10-08 Pierrick LE GALL
+
+	* translation: new items related to configuration parameters
+	gallery_title and gallery_description in GUI.
+
+2005-10-08 Pierrick LE GALL
+
+	* modification: configuration parameters gallery_title and
+	gallery_description are GUI managed in
+	Administration>Configuration>General
+
+	* bug fixed: configuration parameters (use|show)_(exif|iptc) and
+	authorize_remembering should have been deleted from config table
+	some time ago.
+	
+2005-10-08 Pierrick LE GALL
+
+	* new: mass virtual categories movement manager in
+	Administration>Categories>Move screen.
+
+2005-10-05 Pierrick LE GALL
+
+	* bug 160 fixed: (part one of the bug) hard coded column name of
+	users table had to be replaced by the configurable column
+	name. This correction was made by a full rewrite of filtered users
+	list management. The other bug (not submited in bugtracker) that
+	needed this rewrite was that when you choose "all" as target for
+	mass users modification, you expected to apply modification on
+	filtered users, not all users.
+
+	* bug 160 fixed: (part two of the bug) hard coded column name for
+	primary key in mass_updates function.
+
+	* modification: configuration parameter users_page is now located
+	in the correct file (include/config_default.inc.php instead of
+	admin/user_list.php)
+
+2005-09-27 Pierrick LE GALL
+	
+	* bug 168 fixed: crash when language file does not
+	exists. Constant PHPWG_DEFAULT_LANGUAGE added. New function
+	get_language_filepath always used to find language files.
+
+2005-09-26 Pierrick LE GALL
+
+	* bug 158 fixed: display error on "double selects" screens (with
+	MSIE, strange behavior). VDigital modification optimizes width
+	usage :-)
+
+2005-09-25 Pierrick LE GALL
+
+	* bug 163 fixed: link error when cookies disabled in admin/stats
+
+2005-09-24 Pierrick LE GALL
+
+	* bug fixed: HTML error on nested UL in categories menu.
+
+	* bug 161 fixed: guest_id not taken into account for history table
+	insert.
+
+	* bug 164 fixed: category inserted in history table becomes too
+	long if HTML tags are kept.
+
+2005-09-24 Pierrick LE GALL
+
+	* bug 162 fixed: division by zero when trying to view "all" items
+	in admin/element_set_(global|unit)
+
+	* bug 156 fixed: error when selection is empty was not catched.
+	
+2005-09-21 Pierrick LE GALL
+
+	* bug 151 fixed: default maxheight was not proposed as "set to"
+	option in admin/user_list
+
+2005-09-21 Pierrick LE GALL
+
+	* bug 150 fixed: in category permissions management, wrong column
+	name when using an external users table.
+
+2005-09-20 Pierrick LE GALL
+
+	* update: upgrade from 1.4.0 or 1.4.1. Upgrade from 1.3.x is not
+	available anymore.
+
+	* update: README files updated for very near branch 1.5 :-)
+
+	* new: file tools/config_local.inc.php as example for optional
+	include/config_local.inc.php
+
+	* bug fixed: configuration parameter show_picture_name_on_title
+	was useless
+
+2005-09-18 Pierrick LE GALL
+
+	* bug 111 fixed: "Can't add virtual category when cookie
+	disabled". Correction reported from branch 1.4.
+
+	* bug 109 fixed : "disabled "best rated" menu item when rating is
+	not enabled". Correction reported from branch 1.4.
+
+	* bug 95 fixed : "default maxwidth and maxheight not registered
+	". Correction reported from branch 1.4.
+
+2005-09-18 Pierrick LE GALL
+
+	* bug 107 fixed: crash when logging visit on a category containing
+	"'" character. Correction reported from branch 1.4
+
+	* bug fixed: in admin/stats, incorrect SQL queries gave no result.
+
+2005-09-18 Pierrick LE GALL
+
+	* bug 101 fixed: "problem with IE search on keywords". correction
+	reported from branch 1.4
+
+2005-09-17 Pierrick LE GALL
+
+	* new: automatic new password sent by mail when requested by user
+
+2005-09-17 Pierrick LE GALL
+
+	* improvement: add information about how to use an external table
+	for users
+	
+	* bug fixed: uses user configuration fields for filtering in
+	admin/user_list
+
+	* bug fixed: don't try to create feeds automatically during
+	sync_users (when line in user_infos is missing)
+
+	* bug fixed: create_user_infos function gives status admin if user
+	id matches $conf['webmaster_id']
+
+2005-09-17 Pierrick LE GALL
+
+	* new: the number of elements waiting for validation is notified
+	in RSS feed.
+
+2005-09-17 Pierrick LE GALL
+
+	* translation: common and admin strings translated in french from
+	english files
+
+2005-09-14 Pierrick LE GALL
+
+	* improvement: long localized messages are in HTML files instead
+	of $lang array. This is the case of admin/help and about pages.
+
+	* deletion: of unused functions (ts_to_mysqldt, is_image,
+	TN_exists, check_date_format, date_convert,
+	get_category_directories, get_used_metadata_list, array_remove,
+	pwg_write_debug, get_group_restrictions,
+	get_all_group_restrictions, is_group_allowed, style_select,
+	deprecated_getAttribute).
+
+	* new: many new contextual help pages to replace descriptions
+	previously included in pages.
+
+	* modification: reorganisation of language files. Deletion of
+	unused language keys, alphabetical sort. No faq.lang.php anymore
+	(replaced by help.html). Only done for en_UK.iso-8859-1.
+
+2005-09-03 Pierrick LE GALL
+
+	* bug fixed : no display of first added element date in
+	admin/intro if no element in the gallery.
+
+2005-09-03 Pierrick LE GALL
+
+	* new : template yoga, made by yoDan, helped by chrisaga for
+	integration becomes the official template.
+
+2005-09-03 Pierrick LE GALL
+
+	* modification : less configuration parameters in administration
+	screen. These parameters are move to
+	include/config_default.inc.php.
+
+	* new : ability to add a single picture to caddie from picture.php
+
+	* new : contextual help, only a few pages are available.
+
+	* new : ability to delete users from admin/user_list
+
+	* modification : reorganization of configuration file
+
+	* new : configuration parameter use_exif_mapping
+
+	* improvement : MOD hidemail added to standard
+
+2005-08-26 Pierrick LE GALL
+
+	* new : HTML BODY identifier to let CSS stylesheets manage
+	specific behaviour.
+
+	* deletion : admin/search useless
+
+	* improvement : in admin/user_list, special behaviour for
+	true/false fields (expand, show_comments)
+
+	* new : gallery_title and gallery_description are displayed at the
+	top of each page.
+
+	* improvement : simplification in HTML for categories menu.
+
+	* improvement : standardization of presentation in all public
+	pages (identification, registration, search, profile,
+	notification, comments, etc.)
+
+2005-08-25 Pierrick LE GALL
+
+	* deletion : no mail notification anymore. Feature replaced by RSS
+	feed notification.
+
+	* improvement : on waiting pictures management. Ability to
+	validate all or reject all in one clic.
+
+2005-08-21 Pierrick LE GALL
+
+	* modification : adaptation of template variables and blocks in
+	comments page to display comment by comment instead of picture by
+	picture.
+
+2005-08-20 Pierrick LE GALL
+
+	* improvement : dedicated page for user comments validation/reject
+	in administration. (screen is not shared with public part of the
+	gallery). Ability to validate all or reject all in one clic.
+
+2005-08-19 Pierrick LE GALL
+
+	* improvement : less compact presentation of screen
+	admin/element_set_unit.
+
+2005-08-19 Pierrick LE GALL
+
+	* improvement : standardization of categories navigation bar on
+	top of administration screen element_set_(global|unit),
+	cat_modify, cat_list, cat_perm.
+
+	* new : direct link to admin/cat_modify from category.php.
+
+2005-08-19 Pierrick LE GALL
+
+	* modification : RSS feed work only with a given feed
+	identifier. Thus we can avoid fixed frequency notification to
+	concentrate on variable frequency notification, which is much more
+	interesting. To do this, feeds have moved to a dedicated table
+	allowing each user (including guest user) to have more than on
+	feed.
+	
+2005-08-18 Pierrick LE GALL
+
+	* bug 133 fixed : (report from branch 1.4) Deleting user favorites
+	is too restrictive. Instead of deleting a favorite because it
+	belongs to at least one forbidden category, a favorite is deleted
+	if it belongs to no authorized category (which was the expected
+	behaviour).
+
+2005-08-18 Pierrick LE GALL
+
+	* bug 134 fixed : "Nb of images incorectly rendered in "tool tip"
+	near category in category menu". Correction reported (and
+	improved) from branch 1.4
+
+2005-08-18 Pierrick LE GALL
+
+	* improvement : screen admin/picture_modify
+	rewritten. Presentation copied from admin/cat_modify : fieldsets
+	regroup fields. Ability to synchronize metadata for the displayed
+	item.
+
+	* bug 110 fixed : "return to element view from element edition
+	fails depending on permissions". If a reachable (for the connected
+	admin) category is available, a "jump to" link is displayed, by
+	default, using the category given in URL.
+
+	* bug fixed : in mass_updates function, the first item of
+	$fields['update'] has not always 0 for id (as in any array).
+
+	* modification : get_keywords function understands spaces as
+	separator, allow less than 3 chars keywords, allow quotes.
+
+	* new : ability to allow HTML in picture or category description
+	(false by default)
+
+2005-08-17 Pierrick LE GALL
+
+	* improvement : in admin/user_perm, already authorized categories
+	thanks to group associations are displayed and not taken into
+	account for user specific permissions.
+
+2005-08-17 Pierrick LE GALL
+
+	* modification : major simplification of admin.php. Titles are
+	managed by included page, localized items are managed directly in
+	the template.
+
+	* new : sub template admin/double_select is included in templates
+	admin/cat_options, admin/user_perm and admin/group_perm. I haven't
+	been able to use it in admin/picture_modify because it seems
+	impossible to have two instance of the same sub-template without
+	interfering.
+
+	* modification : bug 99, in profile manager, no auto submit when
+	changing language (useless and generate accessibility problem).
+
+	* improvement : HTML semantically correct for administration menu,
+	simpler syntax, less tags, correct tags (dl/dt/dd instead of
+	div/div).
+
+	* modification : number of waiting elements and unvalidated
+	comments are displayed in admin/intro instead of administration
+	menu (with a link to the dedicated pages).
+
+	* deletion : no link to profile from admin/user_list anymore (no
+	need).
+
+2005-08-16 Pierrick LE GALL
+
+	* modification : admin/group_list screen completely rewrite to
+	present the list of existing groups and a form to add a new
+	group. Here you can delete a group, go to permissions management
+	for a group, go to member list of a group (on admin/user_list with
+	a filter on group).
+	
+	* modification : admin/user_perm and admin/group_perm are not
+	directly reachable by the admin menu anymore. Only the user/group
+	list lets you reach user/group permissions management screen.
+
+2005-08-15 Pierrick LE GALL
+
+	* new : introduction page to administration section. This page
+	gives informations about PhpWebGallery version, PHP version, MySQL
+	version, gallery database informations (number of categories,
+	elements, users, comments). Ability to request phpwebgallery.net
+	for upgrade.
+
+	* deletion : of obsolete admin/admin_phpinfo.php page replaced by
+	a link in introduction page.
+
+2005-08-14 Pierrick LE GALL
+
+	* modification : simplification of HTML/CSS code for double select
+	screen to manage categories properties (admin/cat_options)
+
+2005-08-14 Pierrick LE GALL
+
+	* new : ability to set an element as representant of its category
+	directly from picture.php screen.
+
+	* improvement : dedicated icon to add elements into caddie. Ths
+	icon is displayed in the category title bar.
+	
+2005-08-14 Pierrick LE GALL
+
+	* new : maintenance screen in administration. There you can update
+	categories informations (number of images, date of the last added
+	element), update images informations (path, average rate), purge
+	obsolete sessions, purge history.
+
+	* new : ability to have random representative for categories. This
+	configuration parameter is set to false by default.
+
+	* new : ability to set an element as representative of a category
+	without belonging to the category. Thus, administrator can choose
+	representative even for empty categories.
+
+	* improvement : semantically superior design for category edition
+	screen by regrouping fields in fieldsets. The improved screen
+	contains action buttons as in category list screen.
+
+	* new : ability to move a virtual category (ie change its parent
+	category).
+
+	* bug fixed : the sync_users function checks all user children
+	tables (access, cache, group association).
+
+2005-08-08 Pierrick LE GALL
+
+	* new : external authentication in another users table. Previous
+	users table is divided between users (common properties with any
+	web application) and user_infos (phpwebgallery specific
+	informations). External table and fields can be configured.
+	
+	* modification : profile.php is not reachable through
+	administration anymore (not useful).
+
+	* modification : in profile.php, current password is mandatory
+	only if user tries to change his password. Username can't be
+	changed.
+
+	* deletion : of obsolete functions get_user_restrictions,
+	update_user_restrictions, get_user_all_restrictions,
+	is_user_allowed, update_user
+
+	* modification : $user['forbidden_categories'] equals at least
+	"-1" so that category_id NOT IN ($user['forbidden_categories'])
+	can always be used.
+
+	* modification : user_forbidden table becomes user_cache so that
+	not only restriction informations can be stored in this table.
+	
+2005-07-17 Pierrick LE GALL
+
+	* improvement : in admin/element_set_global, javascript is not
+	used anymore to select an item with its thumbnail
+
+2005-07-17 Pierrick LE GALL
+
+	* bug fixed : in admin/user_list, if target is "selection" and
+	that no user is selected, an error occurs
+
+2005-07-17 Pierrick LE GALL
+
+	* new feature : use Apache authentication. If
+	$conf['apache_authentication'] is set true : if no user matches
+	$_SERVER['REMOTE_USER'] in "users" table, PWG automatically
+	creates one. This way, users can customize the behaviour of the
+	application.
+
+	* template : new organisation of identification menu
+	(category.php). Simplification is required for Apache
+	authentication (no logout link even if user is externally logged
+	in)
+
+	* new : usernames can contain quotes (required because Apache
+	authentication authorized quotes in usernames)
+
+2005-07-17 Pierrick LE GALL
+
+	* new configuration parameter : hide thumbnail captions on main
+	page with $conf['show_thumbnail_caption']
+
+	* new configuration parameter : hide picture name in title on
+	picture presentation page with $conf['show_picture_name_on_title']
+
+	* template : new CSS classes to manage picture.php title
+	
+2005-07-16 Pierrick LE GALL
+
+	* new feature : RSS notification feed. Feed generator is an
+	external tool (FeedCreator class v1.7.2). New file feed.php
+
+	* new database field : comments.validation_date (datetime). This
+	field is required for notification feed.
+
+	* new database field : users.feed_id (varchar(50)). users.feed_id
+	is an alias of users.id but is much more complicated to find (50
+	characters, figures or letters, case sensitive) : the purpose is
+	to keep it secret (as far as possible).
+
+	* new database field : users.last_feed_check (datetime)
+
+	* new database field : users.registration_date (datetime)
+
+	* bug fixed : no need to add the (unavailable) session id to
+	install.php in the installation form.
+
+	* modified database field : images.date_available become more
+	precise (date to datetime). This precision is needed for
+	notification feed.
+
+	* new index : comments_i1 (validation_date). Might be useful for
+	feed queries.
+
+	* new index : comments_i2 (image_id). Useful each time you want to
+	have informations about an element and its associated comments.
+
+	* version 9.11 of mysqldump outputs database field names and table
+	names with backquote "`" (didn't find how to take them off)
+	
+2005-06-30 Pierrick LE GALL
+	
+	* category permissions management comes back! (it disappeared in
+	branch 1.4) This time, it is designed to support better long users
+	list. On this screen, for a particular category, admin can say
+	which groups and users are permitted.
+	
+2005-06-30 Pierrick LE GALL
+
+	* users managment : change display of filter (according to filter
+	on user comments)
+
+2005-06-30 Pierrick LE GALL
+
+	* categories management : new display with icon for actions
+	(delete, sub-categories, elements, edit, jump to, permissions)
+
+	* categories management : semantic HTML layout (using common
+	lists)
+
+	* categories management : new way to order categories of the same
+	level : a text field let the admin reorder all categories at once.
+	
+2005-06-25 Pierrick LE GALL
+
+	* new feature : ability to add links on the main page (see
+	include/config_default.inc.php)
+	
+2005-06-21 Pierrick LE GALL
+
+	* comments page rewritten : comments are displayed one by one,
+	with filters and display options available. The list of comments
+	is paginated.
+	
+2005-06-21 Pierrick LE GALL
+
+	* direct communication between templates and language items,
+	without needing a mapping in the PHP code.
+
+2005-06-21 Pierrick LE GALL
+
+	* new function get_name_from_file to centralize the construction
+	of displayed name from the filename
+
+	* new function l10n which returns the corresponding value from
+	$lang if existing. Else, the key is returned. This means that if a
+	language item is not translated, the key is displayed instead
+	(better than nothing).
+
+2005-06-11 Pierrick LE GALL
+
+	* errors and informations boxes : management centralized in
+	admin.php, $errors and $infos arrays replaced by $page['errors']
+	and $page['infos'], special management for admin/update.php (more
+	complex management)
+
+2005-06-11 Pierrick LE GALL
+
+	* bug 96 (informations given by uploaders are lost) correction
+	reported from branch 1.4
+
+2005-05-10 Pierrick LE GALL
+
+	* user list : links to profile page and permissions page are
+	represented by icons (more compact)
+
+	* user list : ability to associate to a group or to dissociate
+	from a group a list of selected users
+
+	* user list : ability to set user properties in "batch" mode (a
+	selection of users at once)
+
+	* user list : alternate background color for each line
+	
+2005-04-30 Pierrick LE GALL
+
+	* user list updated : ability to filter list on status. Function
+	get_enums comes back to retrieve the list of possible status in
+	the database.
+	
+2005-04-28 Pierrick LE GALL
+
+	* user list updated : ability to filter list on group
+
+2005-04-25 Pierrick LE GALL
+
+	* include/config.inc.php becomes include/config_default.inc.php :
+	this file should not be modified. A new file
+	include/config_local.inc.php can be used for overwriting
+	configuration parameters
+	
+2005-04-25 Pierrick LE GALL
+
+	* come back to previous version of include/constants.php :
+	%PWGVERSION% was not a mistake
+
+2005-04-25 Pierrick LE GALL
+
+	* profile.php is no longer used for listing users :
+	admin/user_list.php comes back (as in 1.3 branch)
+
+	* user list updated : ability to filter list on username
+
+2005-04-25 Gweltas
+
+	* ability to install even if file include/mysql.inc.php doesn't
+	exist
+
+	* monthly statistics
+
+	* installation labels updated (english only)
+
+2005-04-16 Pierrick LE GALL <pierrick /at/ phpwebgallery {dot} net>
+
+	* elements batch management : element_set page becomes the
+	frontend to element_set_global and element_set_unit, infos_images
+	(after a long time of use) become deprecated : the more powerful
+	element_set is used instead. Consequently, batch management
+	concerns caddie but also "normal categories".
+	
+	* refactoring code in admin.php to include the sub-file (clearer)
+
+	* caddie : function fill_caddie replaces the code in category.php
+	and can be used in admin/element_set.php
+
+	* caddie : caddie table is added in delete_elements function
+
+2005-04-16 Pierrick LE GALL <pierrick /at/ phpwebgallery {dot} net>
+
+	* elements batch management : in addition to global mode, a unit
+	mode is added : ability to manage a set of elements, element by
+	element. This screen is very close to the existing "infos_images"
+	(which will soon disappear).
+
+	* elements batch management : in screen element_set_global, the
+	display options are displayed at the top as in element_set_unit
+	
+2005-04-11 Pierrick LE GALL <pierrick /at/ phpwebgallery {dot} net>
+
+	* functions get_day_list and get_month_list moved from search.php
+	to include/functions.inc.php : these functions are now also used
+	in admin/element_set_global.php
+
+	* elements batch management improved : ability to set the number
+	of elements to display per line, ability to set {author, name,
+	creation date} fields, ability to add and remove keywords, ability
+	to take selected elements out of caddie
+
+2005-03-31 Pierrick LE GALL <pierrick at phpwebgallery dot net>
+
+	* apply category name and element name separation in calendar
+	special category
+
+	* change method of counting total number of viewable pictures :
+	pictures linked to more than one category are not counted twice.
+	
+2005-03-26 Pierrick LE GALL <pierrick at phpwebgallery dot net>
+
+	* "add to caddie" link is visible only when categories contains
+	elements. Only admin users can see this link
+
+	* elements batch management : impossible to create a link between
+	category and element that already exists
+
+	* logical separation of category name under thumbnail and element
+	name
+
+2005-03-25 Pierrick LE GALL <pierrick at phpwebgallery dot net>
+
+	* application version is defined at build or release
+	creation. This way, include/constants.php won't change at each
+	build.
+
+2005-03-25 Pierrick LE GALL <pierrick at phpwebgallery dot net>
+
+	* typo fixed : wrong block name closed in template
+
+2005-03-25 Pierrick LE GALL <pierrick at phpwebgallery dot net>
+	
+	* new feature : caddie. The purpose is batch management,
+	especially concerning elements to categories associations.This is
+	the very first release, needs many improvements.
Index: /branches/1.5/doc/README_en.txt
===================================================================
--- /branches/1.5/doc/README_en.txt	(revision 3250)
+++ /branches/1.5/doc/README_en.txt	(revision 3250)
@@ -0,0 +1,101 @@
+=============
+PhpWebGallery
+=============
+
+http://phpwebgallery.net
+
+
+Installation
+============
+
+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
+=======
+
+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.
+
+Communication
+=============
+
+Newsletter
+----------
+
+https://gna.org/mail/?group=phpwebgallery
+
+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 :
+
+No spam, no commercial use.
+
+Freshmeat
+---------
+
+http://freshmeat.net/projects/phpwebgallery
+
+Want to stay informed at each release, stable and development
+release. Development releases notification are not send in the newsletter.
+
+Bugtracker
+----------
+
+http://bugs.phpwebgallery.net
+
+Bugs and change requests tracking. The best way to have your bug corrected:
+it won't be forgotten (as in the forum).
+
+Wiki
+----
+
+http://phpwebgallery.net/doc
+
+Wiki documentation: everyone can participate to improve documentation
+content.
+
+Message board
+-------------
+
+http://forum.phpwebgallery.net
+
+All communications (installation help, technical discussions) that can't be
+done in other channels.
Index: /branches/1.5/doc/README_fr.txt
===================================================================
--- /branches/1.5/doc/README_fr.txt	(revision 3250)
+++ /branches/1.5/doc/README_fr.txt	(revision 3250)
@@ -0,0 +1,112 @@
+=============
+PhpWebGallery
+=============
+
+http://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.
+
+Communication
+=============
+
+Newsletter
+----------
+
+https://gna.org/mail/?group=phpwebgallery
+
+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 :
+
+Pas de spam, pas d'utilisation commerciale.
+
+Freshmeat
+---------
+
+http://freshmeat.net/projects/phpwebgallery
+
+Permet d'être au courant des sorties de toutes les releases, et en
+exclusivité les builds de la branche de développement (ce qui n'est pas
+prévu sur les mailing lists "announce").
+
+Outil de suivi de bogues
+------------------------
+
+http://bugs.phpwebgallery.net
+
+Gestion des bugs, mais aussi demande de nouvelles fonctionnalités. Rien de
+plus efficace pour qu'un bug soit corrigé : tant qu'il ne l'est pas, la
+"fiche" reste là à attendre, on ne l'oublie pas comme un topic sur le
+forum.
+
+Les demandes d'évolutions sont également gérées dans cet outil. Ce n'est pas
+forcément idéal car il ne s'agit pas de la même chose, mais le suivi du dev
+d'une nouvelle fonctionnalité peut se modéliser de la même façon que le
+suivi de la correction d'un bug.
+
+Wiki
+----
+
+http://phpwebgallery.net/doc
+
+Documentation suivant le système du wiki. Chacun peut participer à
+l'amélioration de la doc.
+
+Forum de discussion
+-------------------
+
+http://forum.phpwebgallery.net
+
+Un forum est disponible et recommandé pour toutes les questions autres que
+les demandes d'évolution et rapport de bogue (installation, discussions
+techniques).
Index: /branches/1.5/feed.php
===================================================================
--- /branches/1.5/feed.php	(revision 3250)
+++ /branches/1.5/feed.php	(revision 3250)
@@ -0,0 +1,360 @@
+<?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                               |
+// +-----------------------------------------------------------------------+
+
+/**
+ * new comments between two dates, according to authorized categories
+ *
+ * @param string start (mysql datetime format)
+ * @param string end (mysql datetime format)
+ * @param string forbidden categories (comma separated)
+ * @return array comment ids
+ */
+function new_comments($start, $end)
+{
+  global $user;
+  
+  $query = '
+SELECT DISTINCT c.id AS comment_id
+  FROM '.COMMENTS_TABLE.' AS c
+     , '.IMAGE_CATEGORY_TABLE.' AS ic
+  WHERE c.image_id = ic.image_id
+    AND c.validation_date > \''.$start.'\'
+    AND c.validation_date <= \''.$end.'\'
+    AND category_id NOT IN ('.$user['forbidden_categories'].')
+;';
+  return array_from_query($query, 'comment_id');
+}
+
+/**
+ * unvalidated at a precise date
+ *
+ * Comments that are registered and not validated yet on a precise date
+ *
+ * @param string date (mysql datetime format)
+ * @return array comment ids
+ */
+function unvalidated_comments($date)
+{
+  $query = '
+SELECT DISTINCT id
+  FROM '.COMMENTS_TABLE.'
+  WHERE date <= \''.$date.'\'
+    AND (validated = \'false\'
+         OR validation_date > \''.$date.'\')
+;';
+  return array_from_query($query, 'id');
+}
+
+/**
+ * new elements between two dates, according to authorized categories
+ *
+ * @param string start (mysql datetime format)
+ * @param string end (mysql datetime format)
+ * @param string forbidden categories (comma separated)
+ * @return array element ids
+ */
+function new_elements($start, $end)
+{
+  global $user;
+  
+  $query = '
+SELECT DISTINCT image_id
+  FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON image_id = id
+  WHERE date_available > \''.$start.'\'
+    AND date_available <= \''.$end.'\'
+    AND category_id NOT IN ('.$user['forbidden_categories'].')
+;';
+  return array_from_query($query, 'image_id');
+}
+
+/**
+ * updated categories between two dates, according to authorized categories
+ *
+ * @param string start (mysql datetime format)
+ * @param string end (mysql datetime format)
+ * @param string forbidden categories (comma separated)
+ * @return array element ids
+ */
+function updated_categories($start, $end)
+{
+  global $user;
+  
+  $query = '
+SELECT DISTINCT category_id
+  FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON image_id = id
+  WHERE date_available > \''.$start.'\'
+    AND date_available <= \''.$end.'\'
+    AND category_id NOT IN ('.$user['forbidden_categories'].')
+;';
+  return array_from_query($query, 'category_id');
+}
+
+/**
+ * new registered users between two dates
+ *
+ * @param string start (mysql datetime format)
+ * @param string end (mysql datetime format)
+ * @return array user ids
+ */
+function new_users($start, $end)
+{
+  $query = '
+SELECT user_id
+  FROM '.USER_INFOS_TABLE.'
+  WHERE registration_date > \''.$start.'\'
+    AND registration_date <= \''.$end.'\'
+;';
+  return array_from_query($query, 'user_id');
+}
+
+/**
+ * currently waiting pictures
+ *
+ * @return array waiting ids
+ */
+function waiting_elements()
+{
+  $query = '
+SELECT id
+  FROM '.WAITING_TABLE.'
+  WHERE validated = \'false\'
+;';
+
+  return array_from_query($query, 'id');
+}
+
+/**
+ * What's new between two dates ?
+ *
+ * Informations : number of new comments, number of new elements, number of
+ * updated categories. Administrators are also informed about : number of
+ * unvalidated comments, number of new users (TODO : number of unvalidated
+ * elements)
+ *
+ * @param string start date (mysql datetime format)
+ * @param string end date (mysql datetime format)
+ */
+function news($start, $end)
+{
+  global $user;
+
+  $news = array();
+  
+  $nb_new_comments = count(new_comments($start, $end));
+  if ($nb_new_comments > 0)
+  {
+    array_push($news, sprintf(l10n('%d new comments'), $nb_new_comments));
+  }
+
+  $nb_new_elements = count(new_elements($start, $end));
+  if ($nb_new_elements > 0)
+  {
+    array_push($news, sprintf(l10n('%d new elements'), $nb_new_elements));
+  }
+
+  $nb_updated_categories = count(updated_categories($start, $end));
+  if ($nb_updated_categories > 0)
+  {
+    array_push($news, sprintf(l10n('%d categories updated'),
+                              $nb_updated_categories));
+  }
+  
+  if ('admin' == $user['status'])
+  {
+    $nb_unvalidated_comments = count(unvalidated_comments($end));
+    if ($nb_unvalidated_comments > 0)
+    {
+      array_push($news, sprintf(l10n('%d comments to validate'),
+                                $nb_unvalidated_comments));
+    }
+
+    $nb_new_users = count(new_users($start, $end));
+    if ($nb_new_users > 0)
+    {
+      array_push($news, sprintf(l10n('%d new users'), $nb_new_users));
+    }
+
+    $nb_waiting_elements = count(waiting_elements());
+    if ($nb_waiting_elements > 0)
+    {
+      array_push(
+        $news,
+        sprintf(
+          l10n('%d waiting elements'),
+          $nb_waiting_elements
+          )
+        );
+    }
+  }
+
+  return $news;
+}
+
+/**
+ * explodes a MySQL datetime format (2005-07-14 23:01:37) in fields "year",
+ * "month", "day", "hour", "minute", "second".
+ *
+ * @param string mysql datetime format
+ * @return array
+ */
+function explode_mysqldt($mysqldt)
+{
+  $date = array();
+  list($date['year'],
+       $date['month'],
+       $date['day'],
+       $date['hour'],
+       $date['minute'],
+       $date['second'])
+    = preg_split('/[-: ]/', $mysqldt);
+
+  return $date;
+}
+
+/**
+ * creates a Unix timestamp (number of seconds since 1970-01-01 00:00:00
+ * GMT) from a MySQL datetime format (2005-07-14 23:01:37)
+ *
+ * @param string mysql datetime format
+ * @return int timestamp
+ */
+function mysqldt_to_ts($mysqldt)
+{
+  $date = explode_mysqldt($mysqldt);
+  return mktime($date['hour'], $date['minute'], $date['second'],
+                $date['month'], $date['day'], $date['year']);
+}
+
+/**
+ * creates an ISO 8601 format date (2003-01-20T18:05:41+04:00) from Unix
+ * timestamp (number of seconds since 1970-01-01 00:00:00 GMT)
+ *
+ * function copied from Dotclear project http://dotclear.net
+ *
+ * @param int timestamp
+ * @return string ISO 8601 date format
+ */
+function ts_to_iso8601($ts)
+{
+  $tz = date('O',$ts);
+  $tz = substr($tz, 0, -2).':'.substr($tz, -2);
+  return date('Y-m-d\\TH:i:s',$ts).$tz;
+}
+
+// +-----------------------------------------------------------------------+
+// |                            initialization                             |
+// +-----------------------------------------------------------------------+
+
+// clean $user array (include/user.inc.php has been executed)
+$user = array();
+
+// echo '<pre>'.generate_key(50).'</pre>';
+if (isset($_GET['feed'])
+    and preg_match('/^[A-Za-z0-9]{50}$/', $_GET['feed']))
+{
+  $query = '
+SELECT uf.user_id AS id,
+       ui.status,
+       uf.last_check,
+       u.'.$conf['user_fields']['username'].' AS username
+  FROM '.USER_FEED_TABLE.' AS uf
+    INNER JOIN '.USER_INFOS_TABLE.' AS ui
+      ON ui.user_id = uf.user_id
+    INNER JOIN '.USERS_TABLE.' AS u
+      ON u.'.$conf['user_fields']['id'].' = uf.user_id
+  WHERE uf.id = \''.$_GET['feed'].'\'
+;';
+  $user = mysql_fetch_array(pwg_query($query));
+}
+else
+{
+  echo l10n('Unknown feed identifier');
+  exit();
+}
+
+$user['forbidden_categories'] = calculate_permissions($user['id'],
+                                                      $user['status']);
+if ('' == $user['forbidden_categories'])
+{
+  $user['forbidden_categories'] = '0';
+}
+
+list($dbnow) = mysql_fetch_row(pwg_query('SELECT NOW();'));
+
+include_once(PHPWG_ROOT_PATH.'include/feedcreator.class.php');
+
+$rss = new UniversalFeedCreator();
+
+$rss->title = $conf['gallery_title'].', notifications';
+$rss->title.= ' (as '.$user['username'].')';
+
+$rss->link = $conf['gallery_url'];
+
+// +-----------------------------------------------------------------------+
+// |                            Feed creation                              |
+// +-----------------------------------------------------------------------+
+
+$news = news($user['last_check'], $dbnow);
+
+if (count($news) > 0)
+{
+  $item = new FeedItem(); 
+  $item->title = sprintf(l10n('New on %s'), $dbnow);
+  $item->link = $conf['gallery_url'];
+  
+  // content creation
+  $item->description = '<ul>';
+  foreach ($news as $line)
+  {
+    $item->description.= '<li>'.$line.'</li>';
+  }
+  $item->description.= '</ul>';
+  $item->descriptionHtmlSyndicated = true;
+  
+  $item->date = ts_to_iso8601(mysqldt_to_ts($dbnow));
+  $item->author = 'PhpWebGallery notifier'; 
+  
+  $rss->addItem($item);
+}
+
+$query = '
+UPDATE '.USER_FEED_TABLE.'
+  SET last_check = \''.$dbnow.'\'
+  WHERE id = \''.$_GET['feed'].'\'
+;';
+pwg_query($query);
+
+// send XML feed
+echo $rss->saveFeed('RSS2.0', '', true);
+?>
Index: /branches/1.5/galleries/.cvsignore
===================================================================
--- /branches/1.5/galleries/.cvsignore	(revision 3250)
+++ /branches/1.5/galleries/.cvsignore	(revision 3250)
@@ -0,0 +1,1 @@
+*
Index: /branches/1.5/galleries/index.htm
===================================================================
--- /branches/1.5/galleries/index.htm	(revision 3250)
+++ /branches/1.5/galleries/index.htm	(revision 3250)
@@ -0,0 +1,8 @@
+<html>
+    <head>
+        <title>PhpWebGallery</title>
+    </head>
+    <body>
+        No access authorized
+    </body>
+</html>
Index: /branches/1.5/identification.php
===================================================================
--- /branches/1.5/identification.php	(revision 3250)
+++ /branches/1.5/identification.php	(revision 3250)
@@ -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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+//--------------------------------------------------------------------- include
+define('PHPWG_ROOT_PATH','./');
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+
+//-------------------------------------------------------------- identification
+$errors = array();
+if (isset($_POST['login']))
+{
+  $username = mysql_escape_string($_POST['username']);
+  // retrieving the encrypted password of the login submitted
+  $query = '
+SELECT '.$conf['user_fields']['id'].' AS id,
+       '.$conf['user_fields']['password'].' AS password
+  FROM '.USERS_TABLE.'
+  WHERE '.$conf['user_fields']['username'].' = \''.$username.'\'
+;';
+  $row = mysql_fetch_array(pwg_query($query));
+  if ($row['password'] == $conf['pass_convert']($_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'];
+$page['body_id'] = 'theIdentificationPage';
+include(PHPWG_ROOT_PATH.'include/page_header.php');
+
+$template->set_filenames( array('identification'=>'identification.tpl') );
+
+$template->assign_vars(
+  array(
+    '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'],
+
+    'U_REGISTER' => add_session_id(PHPWG_ROOT_PATH.'register.php'),
+    'U_LOST_PASSWORD' => add_session_id(PHPWG_ROOT_PATH.'password.php'),
+    'U_HOME' => add_session_id(PHPWG_ROOT_PATH.'category.php'),
+    
+    'F_LOGIN_ACTION' => add_session_id(PHPWG_ROOT_PATH.'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.5/include/category_calendar.inc.php
===================================================================
--- /branches/1.5/include/category_calendar.inc.php	(revision 3250)
+++ /branches/1.5/include/category_calendar.inc.php	(revision 3250)
@@ -0,0 +1,462 @@
+<?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 DATE_FORMAT('.$conf['calendar_datefield'].', \'%Y-%m-%d\') 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 DATE_FORMAT('.$conf['calendar_datefield'].', \'%Y-%c-%e\')'
+    .' = \''.$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,
+          
+        'U_IMG_LINK'=>add_session_id($url_link)
+       )
+     );
+
+    $template->assign_block_vars(
+      'thumbnails.line.thumbnail.category_name',
+      array(
+        'NAME' => $name
+        )
+      );
+
+    // 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,
+          
+        'U_IMG_LINK'=>add_session_id($url_link)
+       )
+     );
+
+    $template->assign_block_vars(
+      'thumbnails.line.thumbnail.category_name',
+      array(
+        'NAME' => $name
+        )
+      );
+
+    // 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 DATE_FORMAT('.$conf['calendar_datefield'].', \'%Y-%m-%d\')'
+      .' = \''.$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,
+          
+        'U_IMG_LINK'=>add_session_id($url_link)
+         )
+       );
+
+    $template->assign_block_vars(
+      'thumbnails.line.thumbnail.category_name',
+      array(
+        'NAME' => $name
+        )
+      );
+
+    // 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 DATE_FORMAT('.$conf['calendar_datefield'].', \'%Y-%c-%e\')'
+      .' = \''.$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,
+          
+        'U_IMG_LINK'=>add_session_id($url_link)
+         )
+       );
+
+    $template->assign_block_vars(
+      'thumbnails.line.thumbnail.category_name',
+      array(
+        'NAME' => $name
+        )
+      );
+    
+    // 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.5/include/category_default.inc.php
===================================================================
--- /branches/1.5/include/category_default.inc.php	(revision 3250)
+++ /branches/1.5/include/category_default.inc.php	(revision 3250)
@@ -0,0 +1,148 @@
+<?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))
+{
+  $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_TS'           => get_icon($row['date_available']),
+      
+      'U_IMG_LINK'         => add_session_id($url_link)
+      )
+    );
+
+  if ($conf['show_thumbnail_caption'])
+  {
+    // 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']);
+    }
+  
+    $template->assign_block_vars(
+      'thumbnails.line.thumbnail.element_name',
+      array(
+        'NAME' => $name
+        )
+      );
+  }
+    
+  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.5/include/category_recent_cats.inc.php
===================================================================
--- /branches/1.5/include/category_recent_cats.inc.php	(revision 3250)
+++ /branches/1.5/include/category_recent_cats.inc.php	(revision 3250)
@@ -0,0 +1,100 @@
+<?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'],
+        
+      'U_IMG_LINK'              => add_session_id($url_link)
+      )
+    );
+
+  $template->assign_block_vars(
+    'thumbnails.line.thumbnail.category_name',
+    array(
+      'NAME' => $name
+      )
+    );
+  
+  // 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.5/include/category_subcats.inc.php
===================================================================
--- /branches/1.5/include/category_subcats.inc.php	(revision 3250)
+++ /branches/1.5/include/category_subcats.inc.php	(revision 3250)
@@ -0,0 +1,174 @@
+<?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, representative_picture_id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id_uppercat ';
+if (!isset($page['cat']) or !is_numeric($page['cat']))
+{
+  $query.= 'is NULL';
+}
+else
+{
+  $query.= '= '.$page['cat'];
+}
+  $query.= '
+    AND id NOT IN ('.$user['forbidden_categories'].')
+  ORDER BY rank
+;';
+$result = pwg_query($query);
+
+// $conf['allow_random_representative']
+
+$cat_thumbnails = array();
+
+while ($row = mysql_fetch_array($result))
+{
+  if (isset($row['representative_picture_id'])
+      and is_numeric($row['representative_picture_id']))
+  {
+    // if a representative picture is set, it has priority
+    $image_id = $row['representative_picture_id'];
+  }
+  else if ($conf['allow_random_representative'])
+  {
+    // searching a random representant among elements in sub-categories
+    $query = '
+SELECT image_id
+  FROM '.CATEGORIES_TABLE.' AS c INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic
+    ON ic.category_id = c.id
+  WHERE uppercats REGEXP \'(^|,)'.$row['id'].'(,|$)\'
+    AND c.id NOT IN ('.$user['forbidden_categories'].')
+  ORDER BY RAND()
+  LIMIT 0,1
+;';
+    $subresult = pwg_query($query);
+    if (mysql_num_rows($result) > 0)
+    {
+      list($image_id) = mysql_fetch_row($subresult);
+    }
+  }
+  else
+  {
+    // searching a random representant among representant of sub-categories
+    $query = '
+SELECT representative_picture_id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE uppercats REGEXP \'(^|,)'.$row['id'].'(,|$)\'
+    AND id NOT IN ('.$user['forbidden_categories'].')
+    AND representative_picture_id IS NOT NULL
+  ORDER BY RAND()
+  LIMIT 0,1
+;';
+    $subresult = pwg_query($query);
+    if (mysql_num_rows($subresult) > 0)
+    {
+      list($image_id) = mysql_fetch_row($subresult);
+    }
+  }
+
+  if (isset($image_id))
+  {
+    array_push(
+      $cat_thumbnails,
+      array(
+        'category' => $row['id'],
+        'picture' => $image_id,
+        'name' => $row['name'],
+        'date_last' => @$row['date_last']
+        )
+      );
+  }
+
+  unset($image_id);
+}
+
+if (count($cat_thumbnails) > 0)
+{
+  $images = array();
+  
+  foreach ($cat_thumbnails as $item)
+  {
+    $images[$item['picture']] = '';
+  }
+
+  $query = '
+SELECT id, path, tn_ext
+  FROM '.IMAGES_TABLE.'
+  WHERE id IN ('.implode(',', array_keys($images)).')
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    $images[$row['id']] = get_thumbnail_src($row['path'], @$row['tn_ext']);
+  }
+
+  $template->assign_block_vars('thumbnails', array());
+  // first line
+  $template->assign_block_vars('thumbnails.line', array());
+  // current row displayed
+  $row_number = 0;
+  
+  foreach ($cat_thumbnails as $item)
+  {
+    $url_link = PHPWG_ROOT_PATH.'category.php?cat='.$row['id'];
+
+    $template->assign_block_vars(
+      'thumbnails.line.thumbnail',
+      array(
+        'IMAGE' => $images[$item['picture']],
+        'IMAGE_ALT' => $item['name'],
+        'IMAGE_TITLE' => $lang['hint_category'],
+        'IMAGE_TS' => get_icon(@$item['date_last']),
+        'U_IMG_LINK' =>
+          add_session_id(PHPWG_ROOT_PATH.'category.php?cat='.$item['category'])
+        )
+      );
+    
+    $template->assign_block_vars(
+      'thumbnails.line.thumbnail.category_name',
+      array(
+        'NAME' => $item['name']
+        )
+      );
+    
+    // create a new line ?
+    if (++$row_number == $user['nb_image_line'])
+    {
+      $template->assign_block_vars('thumbnails.line', array());
+      $row_number = 0;
+    }
+  }
+}
+?>
Index: /branches/1.5/include/common.inc.php
===================================================================
--- /branches/1.5/include/common.inc.php	(revision 3250)
+++ /branches/1.5/include/common.inc.php	(revision 3250)
@@ -0,0 +1,185 @@
+<?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/config_default.inc.php');
+@include(PHPWG_ROOT_PATH. 'include/config_local.inc.php');
+include(PHPWG_ROOT_PATH . 'include/constants.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');
+
+// language files
+include_once(get_language_filepath('common.lang.php'));
+
+if (defined('IN_ADMIN') and IN_ADMIN)
+{
+  include_once(get_language_filepath('admin.lang.php'));
+}
+
+// only now we can set the localized username of the guest user (and not in
+// include/user.inc.php)
+if ($user['is_the_guest'])
+{
+  $user['username'] = $lang['guest'];
+}
+
+// template instance
+$template = new Template(PHPWG_ROOT_PATH.'template/'.$user['template']);
+?>
Index: /branches/1.5/include/config_default.inc.php
===================================================================
--- /branches/1.5/include/config_default.inc.php	(revision 3250)
+++ /branches/1.5/include/config_default.inc.php	(revision 3250)
@@ -0,0 +1,377 @@
+<?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_default.inc.php.
+ *
+ * It is recommended to let config_default.inc.php as provided and to
+ * overwrite configuration in your local configuration file
+ * config_local.inc.php. See tools/config_local.inc.php as an example.
+ *
+ * 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
+ */
+
+// +-----------------------------------------------------------------------+
+// |                                 misc                                  |
+// +-----------------------------------------------------------------------+
+
+// 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;
+
+// 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;
+
+// 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;
+
+// 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;
+
+// links : list of external links to add in the menu. An example is the best
+// than a long explanation :
+//
+// $conf['links'] = array(
+//   'http://phpwebgallery.net' => 'PWG website',
+//   'http://forum.phpwebgallery.net' => 'PWG forum',
+//   'http://phpwebgallery.net/doc' => 'PWG wiki'
+//   );
+//
+// If the array is empty, the "Links" box won't be displayed on the main
+// page.
+$conf['links'] = array();
+
+// show_thumbnail_caption : on thumbnails page, show thumbnail captions ?
+$conf['show_thumbnail_caption'] = true;
+
+// show_picture_name_on_title : on picture presentation page, show picture
+// name ?
+$conf['show_picture_name_on_title'] = true;
+
+// allow_random_representative : do you wish PhpWebGallery to search among
+// categories elements a new representative at each reload ?
+//
+// If false, an element is randomly or manually chosen to represent its
+// category and remains the representative as long as an admin does not
+// change it.
+//
+// Warning : setting this parameter to true is CPU consuming. Each time you
+// change the value of this parameter from false to true, an administrator
+// must update categories informations in screen [Admin > General >
+// Maintenance].
+$conf['allow_random_representative'] = false;
+
+// allow_html_descriptions : authorize administrators to use HTML in
+// category and element description.
+$conf['allow_html_descriptions'] = true;
+
+// galery_url : URL given in RSS feed
+$conf['gallery_url'] = 'http://demo.phpwebgallery.net';
+
+// prefix_thumbnail : string before filename. Thumbnail's prefix must only
+// contain characters among : a to z (case insensitive), "-" or "_".
+$conf['prefix_thumbnail'] = 'TN-';
+
+// users_page: how many users to display in screen
+// Administration>Identification>Users?
+$conf['users_page'] = 20;
+
+// mail_options: only set it true if you have a send mail warning with
+// "options" parameter missing on mail() function execution.
+$conf['mail_options'] = false;
+
+// +-----------------------------------------------------------------------+
+// |                               metadata                                |
+// +-----------------------------------------------------------------------+
+
+// show_iptc: Show IPTC metadata on picture.php if asked by user
+$conf['show_iptc'] = false;
+
+// 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: Use IPTC data during database synchronization with files
+// metadata
+$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'
+  );
+
+// show_exif: Show EXIF metadata on picture.php (table or line presentation
+// avalaible)
+$conf['show_exif'] = true;
+
+// 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',
+  'DateTimeOriginal',
+  'COMPUTED;ApertureFNumber'
+  );
+
+// use_exif: Use EXIF data during database synchronization with files
+// metadata
+$conf['use_exif'] = false;
+
+// use_exif_mapping: same behaviour as use_iptc_mapping
+$conf['use_exif_mapping'] = array(
+  'date_creation' => 'DateTimeOriginal'
+  );
+
+// +-----------------------------------------------------------------------+
+// |                               sessions                                |
+// +-----------------------------------------------------------------------+
+
+// authorize_remembering : permits user to stay logged for a long time. It
+// creates a cookie on client side.
+$conf['authorize_remembering'] = 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;
+
+// +-----------------------------------------------------------------------+
+// |                                debug                                  |
+// +-----------------------------------------------------------------------+
+
+// 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'] = false;
+
+// debug_l10n : display a warning message each time an unset language key is
+// accessed
+$conf['debug_l10n'] = false;
+
+// +-----------------------------------------------------------------------+
+// |                            authentication                             |
+// +-----------------------------------------------------------------------+
+
+// apache_authentication : use Apache authentication as reference instead of
+// users table ?
+$conf['apache_authentication'] = false;
+
+// users_table: which table is the reference for users? Can be a different
+// table than PhpWebGallery table
+//
+// If you decide to use another table than the default one, you need to
+// prepare your database by deleting some datas :
+//
+// delete from phpwebgallery_user_access;
+// delete from phpwebgallery_user_cache;
+// delete from phpwebgallery_user_feed;
+// delete from phpwebgallery_user_group;
+// delete from phpwebgallery_user_infos;
+// delete from phpwebgallery_sessions;
+// delete from phpwebgallery_rate;
+// update phpwebgallery_images set average_rate = NULL;
+// delete from phpwebgallery_caddie;
+// delete from phpwebgallery_favorites;
+//
+// All informations contained in these tables and column are related to
+// phpwebgallery_users table.
+$conf['users_table'] = $prefixeTable.'users';
+
+// user_fields : mapping between generic field names and table specific
+// field names. For example, in PWG, the mail address is names
+// "mail_address" and in punbb, it's called "email".
+$conf['user_fields'] = array(
+  'id' => 'id',
+  'username' => 'username',
+  'password' => 'password',
+  'email' => 'mail_address'
+  );
+
+// pass_convert : function to crypt or hash the clear user password to store
+// it in the database
+$conf['pass_convert'] = create_function('$s', 'return md5($s);');
+
+// guest_id : id of the anonymous user
+$conf['guest_id'] = 2;
+
+// webmaster_id : webmaster'id.
+$conf['webmaster_id'] = 1;
+
+// +-----------------------------------------------------------------------+
+// |                                upload                                 |
+// +-----------------------------------------------------------------------+
+
+// upload_maxfilesize: maximum filesize for the uploaded pictures. In
+// kilobytes.
+$conf['upload_maxfilesize'] = 200;
+
+// upload_maxheight: maximum height authorized for the uploaded images. In
+// pixels.
+$conf['upload_maxheight'] = 800;
+
+// upload_maxwidth: maximum width authorized for the uploaded images. In
+// pixels.
+$conf['upload_maxwidth'] = 800;
+
+// upload_maxheight_thumbnail: maximum height authorized for the uploaded
+// thumbnails
+$conf['upload_maxheight_thumbnail'] = 100;
+
+// upload_maxwidth_thumbnail: maximum width authorized for the uploaded
+// thumbnails
+$conf['upload_maxwidth_thumbnail'] = 150;
+
+// +-----------------------------------------------------------------------+
+// |                               history                                 |
+// +-----------------------------------------------------------------------+
+
+// nb_logs_page :  how many logs to display on a page
+$conf['nb_logs_page'] = 300;
+
+// history_admin : history admin visits  ?
+$conf['history_admin'] = false;
+
+?>
Index: /branches/1.5/include/constants.php
===================================================================
--- /branches/1.5/include/constants.php	(revision 3250)
+++ /branches/1.5/include/constants.php	(revision 3250)
@@ -0,0 +1,62 @@
+<?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', '%PWGVERSION%');
+define('PHPWG_URL', 'http://www.phpwebgallery.net');
+define('PHPWG_FORUM_URL', 'http://forum.phpwebgallery.net');
+define('PHPWG_DEFAULT_LANGUAGE', 'en_UK.iso-8859-1');
+
+// 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', $conf['users_table']);
+define('USER_INFOS_TABLE', $prefixeTable.'user_infos');
+define('USER_FEED_TABLE', $prefixeTable.'user_feed');
+define('WAITING_TABLE', $prefixeTable.'waiting');
+define('IMAGE_METADATA_TABLE', $prefixeTable.'image_metadata');
+define('RATE_TABLE', $prefixeTable.'rate');
+define('USER_CACHE_TABLE', $prefixeTable.'user_cache');
+define('CADDIE_TABLE', $prefixeTable.'caddie');
+?>
Index: /branches/1.5/include/feedcreator.class.php
===================================================================
--- /branches/1.5/include/feedcreator.class.php	(revision 3250)
+++ /branches/1.5/include/feedcreator.class.php	(revision 3250)
@@ -0,0 +1,1541 @@
+<?php
+/***************************************************************************
+
+FeedCreator class v1.7.2
+originally (c) Kai Blankenhorn
+www.bitfolge.de
+kaib@bitfolge.de
+v1.3 work by Scott Reynen (scott@randomchaos.com) and Kai Blankenhorn
+v1.5 OPML support by Dirk Clemens
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+****************************************************************************
+
+
+Changelog:
+
+v1.7.2	10-11-04
+	license changed to LGPL
+
+v1.7.1
+	fixed a syntax bug
+	fixed left over debug code
+
+v1.7	07-18-04
+	added HTML and JavaScript feeds (configurable via CSS) (thanks to Pascal Van Hecke)
+	added HTML descriptions for all feed formats (thanks to Pascal Van Hecke)
+	added a switch to select an external stylesheet (thanks to Pascal Van Hecke)
+	changed default content-type to application/xml
+	added character encoding setting
+	fixed numerous smaller bugs (thanks to Sören Fuhrmann of golem.de)
+	improved changing ATOM versions handling (thanks to August Trometer)
+	improved the UniversalFeedCreator's useCached method (thanks to Sören Fuhrmann of golem.de)
+	added charset output in HTTP headers (thanks to Sören Fuhrmann of golem.de)
+	added Slashdot namespace to RSS 1.0 (thanks to Sören Fuhrmann of golem.de)
+
+v1.6	05-10-04
+	added stylesheet to RSS 1.0 feeds
+	fixed generator comment (thanks Kevin L. Papendick and Tanguy Pruvot)
+	fixed RFC822 date bug (thanks Tanguy Pruvot)
+	added TimeZone customization for RFC8601 (thanks Tanguy Pruvot)
+	fixed Content-type could be empty (thanks Tanguy Pruvot)
+	fixed author/creator in RSS1.0 (thanks Tanguy Pruvot)
+
+v1.6 beta	02-28-04
+	added Atom 0.3 support (not all features, though)
+	improved OPML 1.0 support (hopefully - added more elements)
+	added support for arbitrary additional elements (use with caution)
+	code beautification :-)
+	considered beta due to some internal changes
+
+v1.5.1	01-27-04
+	fixed some RSS 1.0 glitches (thanks to Stéphane Vanpoperynghe)
+	fixed some inconsistencies between documentation and code (thanks to Timothy Martin)
+
+v1.5	01-06-04
+	added support for OPML 1.0
+	added more documentation
+
+v1.4	11-11-03
+	optional feed saving and caching
+	improved documentation
+	minor improvements
+
+v1.3    10-02-03
+	renamed to FeedCreator, as it not only creates RSS anymore
+	added support for mbox
+	tentative support for echo/necho/atom/pie/???
+        
+v1.2    07-20-03
+	intelligent auto-truncating of RSS 0.91 attributes
+	don't create some attributes when they're not set
+	documentation improved
+	fixed a real and a possible bug with date conversions
+	code cleanup
+
+v1.1    06-29-03
+	added images to feeds
+	now includes most RSS 0.91 attributes
+	added RSS 2.0 feeds
+
+v1.0    06-24-03
+	initial release
+
+
+
+***************************************************************************/
+
+/*** GENERAL USAGE *********************************************************
+
+include("feedcreator.class.php"); 
+
+$rss = new UniversalFeedCreator(); 
+$rss->useCached(); // use cached version if age<1 hour
+$rss->title = "PHP news"; 
+$rss->description = "daily news from the PHP scripting world"; 
+
+//optional
+$rss->descriptionTruncSize = 500;
+$rss->descriptionHtmlSyndicated = true;
+
+$rss->link = "http://www.dailyphp.net/news"; 
+$rss->syndicationURL = "http://www.dailyphp.net/".$_SERVER["PHP_SELF"]; 
+
+$image = new FeedImage(); 
+$image->title = "dailyphp.net logo"; 
+$image->url = "http://www.dailyphp.net/images/logo.gif"; 
+$image->link = "http://www.dailyphp.net"; 
+$image->description = "Feed provided by dailyphp.net. Click to visit."; 
+
+//optional
+$image->descriptionTruncSize = 500;
+$image->descriptionHtmlSyndicated = true;
+
+$rss->image = $image; 
+
+// get your news items from somewhere, e.g. your database: 
+mysql_select_db($dbHost, $dbUser, $dbPass); 
+$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC"); 
+while ($data = mysql_fetch_object($res)) { 
+    $item = new FeedItem(); 
+    $item->title = $data->title; 
+    $item->link = $data->url; 
+    $item->description = $data->short; 
+    
+    //optional
+    item->descriptionTruncSize = 500;
+    item->descriptionHtmlSyndicated = true;
+
+    $item->date = $data->newsdate; 
+    $item->source = "http://www.dailyphp.net"; 
+    $item->author = "John Doe"; 
+     
+    $rss->addItem($item); 
+} 
+
+// valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1 (deprecated),
+// MBOX, OPML, ATOM, ATOM0.3, HTML, JS
+echo $rss->saveFeed("RSS1.0", "news/feed.xml");
+
+
+***************************************************************************
+*          A little setup                                                 *
+**************************************************************************/
+
+// your local timezone, set to "" to disable or for GMT
+define("TIME_ZONE","+01:00");
+
+
+
+
+/**
+ * Version string.
+ **/
+define("FEEDCREATOR_VERSION", "FeedCreator 1.7.2");
+
+
+
+/**
+ * A FeedItem is a part of a FeedCreator feed.
+ *
+ * @author Kai Blankenhorn <kaib@bitfolge.de>
+ * @since 1.3
+ */
+class FeedItem extends HtmlDescribable {
+	/**
+	 * Mandatory attributes of an item.
+	 */
+	var $title, $description, $link;
+	
+	/**
+	 * Optional attributes of an item.
+	 */
+	var $author, $authorEmail, $image, $category, $comments, $guid, $source, $creator;
+	
+	/**
+	 * Publishing date of an item. May be in one of the following formats:
+	 *
+	 *	RFC 822:
+	 *	"Mon, 20 Jan 03 18:05:41 +0400"
+	 *	"20 Jan 03 18:05:41 +0000"
+	 *
+	 *	ISO 8601:
+	 *	"2003-01-20T18:05:41+04:00"
+	 *
+	 *	Unix:
+	 *	1043082341
+	 */
+	var $date;
+	
+	/**
+	 * Any additional elements to include as an assiciated array. All $key => $value pairs
+	 * will be included unencoded in the feed item in the form
+	 *     <$key>$value</$key>
+	 * Again: No encoding will be used! This means you can invalidate or enhance the feed
+	 * if $value contains markup. This may be abused to embed tags not implemented by
+	 * the FeedCreator class used.
+	 */
+	var $additionalElements = Array();
+
+	// on hold
+	// var $source;
+}
+
+
+
+/**
+ * An FeedImage may be added to a FeedCreator feed.
+ * @author Kai Blankenhorn <kaib@bitfolge.de>
+ * @since 1.3
+ */
+class FeedImage extends HtmlDescribable {
+	/**
+	 * Mandatory attributes of an image.
+	 */
+	var $title, $url, $link;
+	
+	/**
+	 * Optional attributes of an image.
+	 */
+	var $width, $height, $description;
+}
+
+
+
+/**
+ * An HtmlDescribable is an item within a feed that can have a description that may
+ * include HTML markup.
+ */
+class HtmlDescribable {
+	/**
+	 * Indicates whether the description field should be rendered in HTML.
+	 */
+	var $descriptionHtmlSyndicated;
+	
+	/**
+	 * Indicates whether and to how many characters a description should be truncated.
+	 */
+	var $descriptionTruncSize;
+	
+	/**
+	 * Returns a formatted description field, depending on descriptionHtmlSyndicated and
+	 * $descriptionTruncSize properties
+	 * @return    string    the formatted description  
+	 */
+	function getDescription() {
+		$descriptionField = new FeedHtmlField($this->description);
+		$descriptionField->syndicateHtml = $this->descriptionHtmlSyndicated;
+		$descriptionField->truncSize = $this->descriptionTruncSize;
+		return $descriptionField->output();
+	}
+
+}
+
+
+/**
+ * An FeedHtmlField describes and generates
+ * a feed, item or image html field (probably a description). Output is 
+ * generated based on $truncSize, $syndicateHtml properties.
+ * @author Pascal Van Hecke <feedcreator.class.php@vanhecke.info>
+ * @version 1.6
+ */
+class FeedHtmlField {
+	/**
+	 * Mandatory attributes of a FeedHtmlField.
+	 */
+	var $rawFieldContent;
+	
+	/**
+	 * Optional attributes of a FeedHtmlField.
+	 * 
+	 */
+	var $truncSize, $syndicateHtml;
+	
+	/**
+	 * Creates a new instance of FeedHtmlField.
+	 * @param  $string: if given, sets the rawFieldContent property
+	 */
+	function FeedHtmlField($parFieldContent) {
+		if ($parFieldContent) {
+			$this->rawFieldContent = $parFieldContent;
+		}
+	}
+		
+		
+	/**
+	 * Creates the right output, depending on $truncSize, $syndicateHtml properties.
+	 * @return string    the formatted field
+	 */
+	function output() {
+		// when field available and syndicated in html we assume 
+		// - valid html in $rawFieldContent and we enclose in CDATA tags
+		// - no truncation (truncating risks producing invalid html)
+		if (!$this->rawFieldContent) {
+			$result = "";
+		}	elseif ($this->syndicateHtml) {
+			$result = "<![CDATA[".$this->rawFieldContent."]]>";
+		} else {
+			if ($this->truncSize and is_int($this->truncSize)) {
+				$result = FeedCreator::iTrunc(htmlspecialchars($this->rawFieldContent),$this->truncSize);
+			} else {
+				$result = htmlspecialchars($this->rawFieldContent);
+			}
+		}
+		return $result;
+	}
+
+}
+
+
+
+/**
+ * UniversalFeedCreator lets you choose during runtime which
+ * format to build.
+ * For general usage of a feed class, see the FeedCreator class
+ * below or the example above.
+ *
+ * @since 1.3
+ * @author Kai Blankenhorn <kaib@bitfolge.de>
+ */
+class UniversalFeedCreator extends FeedCreator {
+	var $_feed;
+	
+	function _setFormat($format) {
+		switch (strtoupper($format)) {
+			
+			case "2.0":
+				// fall through
+			case "RSS2.0":
+				$this->_feed = new RSSCreator20();
+				break;
+			
+			case "1.0":
+				// fall through
+			case "RSS1.0":
+				$this->_feed = new RSSCreator10();
+				break;
+			
+			case "0.91":
+				// fall through
+			case "RSS0.91":
+				$this->_feed = new RSSCreator091();
+				break;
+			
+			case "PIE0.1":
+				$this->_feed = new PIECreator01();
+				break;
+			
+			case "MBOX":
+				$this->_feed = new MBOXCreator();
+				break;
+			
+			case "OPML":
+				$this->_feed = new OPMLCreator();
+				break;
+				
+			case "ATOM":
+				// fall through: always the latest ATOM version
+				
+			case "ATOM0.3":
+				$this->_feed = new AtomCreator03();
+				break;
+				
+			case "HTML":
+				$this->_feed = new HTMLCreator();
+				break;
+			
+			case "JS":
+				// fall through
+			case "JAVASCRIPT":
+				$this->_feed = new JSCreator();
+				break;
+			
+			default:
+				$this->_feed = new RSSCreator091();
+				break;
+		}
+        
+		$vars = get_object_vars($this);
+		foreach ($vars as $key => $value) {
+			// prevent overwriting of properties "contentType", "encoding"; do not copy "_feed" itself
+			if (!in_array($key, array("_feed", "contentType", "encoding"))) {
+				$this->_feed->{$key} = $this->{$key};
+			}
+		}
+	}
+	
+	/**
+	 * Creates a syndication feed based on the items previously added.
+	 *
+	 * @see        FeedCreator::addItem()
+	 * @param    string    format    format the feed should comply to. Valid values are:
+	 *			"PIE0.1", "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3", "HTML", "JS"
+	 * @return    string    the contents of the feed.
+	 */
+	function createFeed($format = "RSS0.91") {
+		$this->_setFormat($format);
+		return $this->_feed->createFeed();
+	}
+	
+	
+	
+	/**
+	 * Saves this feed as a file on the local disk. After the file is saved, an HTTP redirect
+	 * header may be sent to redirect the use to the newly created file.
+	 * @since 1.4
+	 * 
+	 * @param	string	format	format the feed should comply to. Valid values are:
+	 *			"PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM", "ATOM0.3", "HTML", "JS"
+	 * @param	string	filename	optional	the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()).
+	 * @param	boolean	displayContents	optional	send the content of the file or not. If true, the file will be sent in the body of the response.
+	 */
+	function saveFeed($format="RSS0.91", $filename="", $displayContents=true) {
+		$this->_setFormat($format);
+		$this->_feed->saveFeed($filename, $displayContents);
+	}
+
+
+   /**
+    * Turns on caching and checks if there is a recent version of this feed in the cache.
+    * If there is, an HTTP redirect header is sent.
+    * To effectively use caching, you should create the FeedCreator object and call this method
+    * before anything else, especially before you do the time consuming task to build the feed
+    * (web fetching, for example).
+    *
+    * @param   string   format   format the feed should comply to. Valid values are:
+    *       "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3".
+    * @param filename   string   optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()).
+    * @param timeout int      optional the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour)
+    */
+   function useCached($format="RSS0.91", $filename="", $timeout=3600) {
+      $this->_setFormat($format);
+      $this->_feed->useCached($filename, $timeout);
+   }
+
+}
+
+
+/**
+ * FeedCreator is the abstract base implementation for concrete
+ * implementations that implement a specific format of syndication.
+ *
+ * @abstract
+ * @author Kai Blankenhorn <kaib@bitfolge.de>
+ * @since 1.4
+ */
+class FeedCreator extends HtmlDescribable {
+
+	/**
+	 * Mandatory attributes of a feed.
+	 */
+	var $title, $description, $link;
+	
+	
+	/**
+	 * Optional attributes of a feed.
+	 */
+	var $syndicationURL, $image, $language, $copyright, $pubDate, $lastBuildDate, $editor, $editorEmail, $webmaster, $category, $docs, $ttl, $rating, $skipHours, $skipDays;
+
+	/**
+	* The url of the external xsl stylesheet used to format the naked rss feed.
+	* Ignored in the output when empty.
+	*/
+	var $xslStyleSheet = "";
+	
+	
+	/**
+	 * @access private
+	 */
+	var $items = Array();
+ 	
+	
+	/**
+	 * This feed's MIME content type.
+	 * @since 1.4
+	 * @access private
+	 */
+	var $contentType = "application/xml";
+	
+	
+	/**
+	 * This feed's character encoding.
+	 * @since 1.6.1
+	 **/
+	var $encoding = "ISO-8859-1";
+	
+	
+	/**
+	 * Any additional elements to include as an assiciated array. All $key => $value pairs
+	 * will be included unencoded in the feed in the form
+	 *     <$key>$value</$key>
+	 * Again: No encoding will be used! This means you can invalidate or enhance the feed
+	 * if $value contains markup. This may be abused to embed tags not implemented by
+	 * the FeedCreator class used.
+	 */
+	var $additionalElements = Array();
+   
+    
+	/**
+	 * Adds an FeedItem to the feed.
+	 *
+	 * @param object FeedItem $item The FeedItem to add to the feed.
+	 * @access public
+	 */
+	function addItem($item) {
+		$this->items[] = $item;
+	}
+	
+	
+	/**
+	 * Truncates a string to a certain length at the most sensible point.
+	 * First, if there's a '.' character near the end of the string, the string is truncated after this character.
+	 * If there is no '.', the string is truncated after the last ' ' character.
+	 * If the string is truncated, " ..." is appended.
+	 * If the string is already shorter than $length, it is returned unchanged.
+	 * 
+	 * @static
+	 * @param string    string A string to be truncated.
+	 * @param int        length the maximum length the string should be truncated to
+	 * @return string    the truncated string
+	 */
+	function iTrunc($string, $length) {
+		if (strlen($string)<=$length) {
+			return $string;
+		}
+		
+		$pos = strrpos($string,".");
+		if ($pos>=$length-4) {
+			$string = substr($string,0,$length-4);
+			$pos = strrpos($string,".");
+		}
+		if ($pos>=$length*0.4) {
+			return substr($string,0,$pos+1)." ...";
+		}
+		
+		$pos = strrpos($string," ");
+		if ($pos>=$length-4) {
+			$string = substr($string,0,$length-4);
+			$pos = strrpos($string," ");
+		}
+		if ($pos>=$length*0.4) {
+			return substr($string,0,$pos)." ...";
+		}
+		
+		return substr($string,0,$length-4)." ...";
+			
+	}
+	
+	
+	/**
+	 * Creates a comment indicating the generator of this feed.
+	 * The format of this comment seems to be recognized by
+	 * Syndic8.com.
+	 */
+	function _createGeneratorComment() {
+		return "<!-- generator=\"".FEEDCREATOR_VERSION."\" -->\n";
+	}
+	
+	
+	/**
+	 * Creates a string containing all additional elements specified in
+	 * $additionalElements.
+	 * @param	elements	array	an associative array containing key => value pairs
+	 * @param indentString	string	a string that will be inserted before every generated line
+	 * @return    string    the XML tags corresponding to $additionalElements
+	 */
+	function _createAdditionalElements($elements, $indentString="") {
+		$ae = "";
+		if (is_array($elements)) {
+			foreach($elements AS $key => $value) {
+				$ae.= $indentString."<$key>$value</$key>\n";
+			}
+		}
+		return $ae;
+	}
+	
+	function _createStylesheetReferences() {
+		$xml = "";
+		if (isset($this->cssStyleSheet)) $xml .= "<?xml-stylesheet href=\"".$this->cssStyleSheet."\" type=\"text/css\"?>\n";
+		if ($this->xslStyleSheet) $xml .= "<?xml-stylesheet href=\"".$this->xslStyleSheet."\" type=\"text/xsl\"?>\n";
+		return $xml;
+	}
+	
+	
+	/**
+	 * Builds the feed's text.
+	 * @abstract
+	 * @return    string    the feed's complete text 
+	 */
+	function createFeed() {
+	}
+	
+	/**
+	 * Generate a filename for the feed cache file. The result will be $_SERVER["PHP_SELF"] with the extension changed to .xml.
+	 * For example:
+	 * 
+	 * echo $_SERVER["PHP_SELF"]."\n";
+	 * echo FeedCreator::_generateFilename();
+	 * 
+	 * would produce:
+	 * 
+	 * /rss/latestnews.php
+	 * latestnews.xml
+	 *
+	 * @return string the feed cache filename
+	 * @since 1.4
+	 * @access private
+	 */
+	function _generateFilename() {
+		$fileInfo = pathinfo($_SERVER["PHP_SELF"]);
+		return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".xml";
+	}
+	
+	
+	/**
+	 * @since 1.4
+	 * @access private
+	 */
+	function _redirect($filename) {
+		// attention, heavily-commented-out-area
+		
+		// maybe use this in addition to file time checking
+		//Header("Expires: ".date("r",time()+$this->_timeout));
+		
+		/* no caching at all, doesn't seem to work as good:
+		Header("Cache-Control: no-cache");
+		Header("Pragma: no-cache");
+		*/
+		
+		// HTTP redirect, some feed readers' simple HTTP implementations don't follow it
+		//Header("Location: ".$filename);
+
+		Header("Content-Type: ".$this->contentType."; charset=".$this->encoding."; filename=".basename($filename));
+		Header("Content-Disposition: inline; filename=".basename($filename));
+		readfile($filename, "r");
+		die();
+	}
+    
+	/**
+	 * Turns on caching and checks if there is a recent version of this feed in the cache.
+	 * If there is, an HTTP redirect header is sent.
+	 * To effectively use caching, you should create the FeedCreator object and call this method
+	 * before anything else, especially before you do the time consuming task to build the feed
+	 * (web fetching, for example).
+	 * @since 1.4
+	 * @param filename	string	optional	the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()).
+	 * @param timeout	int		optional	the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour)
+	 */
+	function useCached($filename="", $timeout=3600) {
+		$this->_timeout = $timeout;
+		if ($filename=="") {
+			$filename = $this->_generateFilename();
+		}
+		if (file_exists($filename) AND (time()-filemtime($filename) < $timeout)) {
+			$this->_redirect($filename);
+		}
+	}
+	
+	
+	/**
+	 * Saves this feed as a file on the local disk. After the file is saved, a redirect
+	 * header may be sent to redirect the user to the newly created file.
+	 * @since 1.4
+	 * 
+	 * @param filename	string	optional	the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()).
+	 * @param redirect	boolean	optional	send an HTTP redirect header or not. If true, the user will be automatically redirected to the created file.
+	 */
+	function saveFeed($filename="", $displayContents=true) {
+		if ($filename=="") {
+			$filename = $this->_generateFilename();
+		}
+		$feedFile = fopen($filename, "w+");
+		if ($feedFile) {
+			fputs($feedFile,$this->createFeed());
+			fclose($feedFile);
+			if ($displayContents) {
+				$this->_redirect($filename);
+			}
+		} else {
+			echo "<br /><b>Error creating feed file, please check write permissions.</b><br />";
+		}
+	}
+	
+}
+
+
+/**
+ * FeedDate is an internal class that stores a date for a feed or feed item.
+ * Usually, you won't need to use this.
+ */
+class FeedDate {
+	var $unix;
+	
+	/**
+	 * Creates a new instance of FeedDate representing a given date.
+	 * Accepts RFC 822, ISO 8601 date formats as well as unix time stamps.
+	 * @param mixed $dateString optional the date this FeedDate will represent. If not specified, the current date and time is used.
+	 */
+	function FeedDate($dateString="") {
+		if ($dateString=="") $dateString = date("r");
+		
+		if (is_integer($dateString)) {
+			$this->unix = $dateString;
+			return;
+		}
+		if (preg_match("~(?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\\s+)?(\\d{1,2})\\s+([a-zA-Z]{3})\\s+(\\d{4})\\s+(\\d{2}):(\\d{2}):(\\d{2})\\s+(.*)~",$dateString,$matches)) {
+			$months = Array("Jan"=>1,"Feb"=>2,"Mar"=>3,"Apr"=>4,"May"=>5,"Jun"=>6,"Jul"=>7,"Aug"=>8,"Sep"=>9,"Oct"=>10,"Nov"=>11,"Dec"=>12);
+			$this->unix = mktime($matches[4],$matches[5],$matches[6],$months[$matches[2]],$matches[1],$matches[3]);
+			if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') {
+				$tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60;
+			} else {
+				if (strlen($matches[7])==1) {
+					$oneHour = 3600;
+					$ord = ord($matches[7]);
+					if ($ord < ord("M")) {
+						$tzOffset = (ord("A") - $ord - 1) * $oneHour;
+					} elseif ($ord >= ord("M") AND $matches[7]!="Z") {
+						$tzOffset = ($ord - ord("M")) * $oneHour;
+					} elseif ($matches[7]=="Z") {
+						$tzOffset = 0;
+					}
+				}
+				switch ($matches[7]) {
+					case "UT":
+					case "GMT":	$tzOffset = 0;
+				}
+			}
+			$this->unix += $tzOffset;
+			return;
+		}
+		if (preg_match("~(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(.*)~",$dateString,$matches)) {
+			$this->unix = mktime($matches[4],$matches[5],$matches[6],$matches[2],$matches[3],$matches[1]);
+			if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') {
+				$tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60;
+			} else {
+				if ($matches[7]=="Z") {
+					$tzOffset = 0;
+				}
+			}
+			$this->unix += $tzOffset;
+			return;
+		}
+		$this->unix = 0;
+	}
+
+	/**
+	 * Gets the date stored in this FeedDate as an RFC 822 date.
+	 *
+	 * @return a date in RFC 822 format
+	 */
+	function rfc822() {
+		//return gmdate("r",$this->unix);
+		$date = gmdate("D, d M Y H:i:s", $this->unix);
+		if (TIME_ZONE!="") $date .= " ".str_replace(":","",TIME_ZONE);
+		return $date;
+	}
+	
+	/**
+	 * Gets the date stored in this FeedDate as an ISO 8601 date.
+	 *
+	 * @return a date in ISO 8601 format
+	 */
+	function iso8601() {
+		$date = gmdate("Y-m-d\TH:i:sO",$this->unix);
+		$date = substr($date,0,22) . ':' . substr($date,-2);
+		if (TIME_ZONE!="") $date = str_replace("+00:00",TIME_ZONE,$date);
+		return $date;
+	}
+	
+	/**
+	 * Gets the date stored in this FeedDate as unix time stamp.
+	 *
+	 * @return a date as a unix time stamp
+	 */
+	function unix() {
+		return $this->unix;
+	}
+}
+
+
+/**
+ * RSSCreator10 is a FeedCreator that implements RDF Site Summary (RSS) 1.0.
+ *
+ * @see http://www.purl.org/rss/1.0/
+ * @since 1.3
+ * @author Kai Blankenhorn <kaib@bitfolge.de>
+ */
+class RSSCreator10 extends FeedCreator {
+
+	/**
+	 * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0.
+	 * The feed will contain all items previously added in the same order.
+	 * @return    string    the feed's complete text 
+	 */
+	function createFeed() {     
+		$feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
+		$feed.= $this->_createGeneratorComment();
+		if ($this->cssStyleSheet=="") {
+			$cssStyleSheet = "http://www.w3.org/2000/08/w3c-synd/style.css";
+		}
+		$feed.= $this->_createStylesheetReferences();
+		$feed.= "<rdf:RDF\n";
+		$feed.= "    xmlns=\"http://purl.org/rss/1.0/\"\n";
+		$feed.= "    xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n"; 
+		$feed.= "    xmlns:slash=\"http://purl.org/rss/1.0/modules/slash/\"\n";
+		$feed.= "    xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n";
+		$feed.= "    <channel rdf:about=\"".$this->syndicationURL."\">\n";
+		$feed.= "        <title>".htmlspecialchars($this->title)."</title>\n";
+		$feed.= "        <description>".htmlspecialchars($this->description)."</description>\n";
+		$feed.= "        <link>".$this->link."</link>\n";
+		if ($this->image!=null) {
+			$feed.= "        <image rdf:resource=\"".$this->image->url."\" />\n";
+		}
+		$now = new FeedDate();
+		$feed.= "       <dc:date>".htmlspecialchars($now->iso8601())."</dc:date>\n";
+		$feed.= "        <items>\n";
+		$feed.= "            <rdf:Seq>\n";
+		for ($i=0;$i<count($this->items);$i++) {
+			$feed.= "                <rdf:li rdf:resource=\"".htmlspecialchars($this->items[$i]->link)."\"/>\n";
+		}
+		$feed.= "            </rdf:Seq>\n";
+		$feed.= "        </items>\n";
+		$feed.= "    </channel>\n";
+		if ($this->image!=null) {
+			$feed.= "    <image rdf:about=\"".$this->image->url."\">\n";
+			$feed.= "        <title>".$this->image->title."</title>\n";
+			$feed.= "        <link>".$this->image->link."</link>\n";
+			$feed.= "        <url>".$this->image->url."</url>\n";
+			$feed.= "    </image>\n";
+		}
+		$feed.= $this->_createAdditionalElements($this->additionalElements, "    ");
+		
+		for ($i=0;$i<count($this->items);$i++) {
+			$feed.= "    <item rdf:about=\"".htmlspecialchars($this->items[$i]->link)."\">\n";
+			//$feed.= "        <dc:type>Posting</dc:type>\n";
+			$feed.= "        <dc:format>text/html</dc:format>\n";
+			if ($this->items[$i]->date!=null) {
+				$itemDate = new FeedDate($this->items[$i]->date);
+				$feed.= "        <dc:date>".htmlspecialchars($itemDate->iso8601())."</dc:date>\n";
+			}
+			if ($this->items[$i]->source!="") {
+				$feed.= "        <dc:source>".htmlspecialchars($this->items[$i]->source)."</dc:source>\n";
+			}
+			if ($this->items[$i]->author!="") {
+				$feed.= "        <dc:creator>".htmlspecialchars($this->items[$i]->author)."</dc:creator>\n";
+			}
+			$feed.= "        <title>".htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"\n\r","  ")))."</title>\n";
+			$feed.= "        <link>".htmlspecialchars($this->items[$i]->link)."</link>\n";
+			$feed.= "        <description>".htmlspecialchars($this->items[$i]->description)."</description>\n";
+			$feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, "        ");
+			$feed.= "    </item>\n";
+		}
+		$feed.= "</rdf:RDF>\n";
+		return $feed;
+	}
+}
+
+
+
+/**
+ * RSSCreator091 is a FeedCreator that implements RSS 0.91 Spec, revision 3.
+ *
+ * @see http://my.netscape.com/publish/formats/rss-spec-0.91.html
+ * @since 1.3
+ * @author Kai Blankenhorn <kaib@bitfolge.de>
+ */
+class RSSCreator091 extends FeedCreator {
+
+	/**
+	 * Stores this RSS feed's version number.
+	 * @access private
+	 */
+	var $RSSVersion;
+
+	function RSSCreator091() {
+		$this->_setRSSVersion("0.91");
+		$this->contentType = "application/rss+xml";
+	}
+	
+	/**
+	 * Sets this RSS feed's version number.
+	 * @access private
+	 */
+	function _setRSSVersion($version) {
+		$this->RSSVersion = $version;
+	}
+
+	/**
+	 * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0.
+	 * The feed will contain all items previously added in the same order.
+	 * @return    string    the feed's complete text 
+	 */
+	function createFeed() {
+		$feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
+		$feed.= $this->_createGeneratorComment();
+		$feed.= $this->_createStylesheetReferences();
+		$feed.= "<rss version=\"".$this->RSSVersion."\">\n"; 
+		$feed.= "    <channel>\n";
+		$feed.= "        <title>".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</title>\n";
+		$this->descriptionTruncSize = 500;
+		$feed.= "        <description>".$this->getDescription()."</description>\n";
+		$feed.= "        <link>".$this->link."</link>\n";
+		$now = new FeedDate();
+		$feed.= "        <lastBuildDate>".htmlspecialchars($now->rfc822())."</lastBuildDate>\n";
+		$feed.= "        <generator>".FEEDCREATOR_VERSION."</generator>\n";
+
+		if ($this->image!=null) {
+			$feed.= "        <image>\n";
+			$feed.= "            <url>".$this->image->url."</url>\n"; 
+			$feed.= "            <title>".FeedCreator::iTrunc(htmlspecialchars($this->image->title),100)."</title>\n"; 
+			$feed.= "            <link>".$this->image->link."</link>\n";
+			if ($this->image->width!="") {
+				$feed.= "            <width>".$this->image->width."</width>\n";
+			}
+			if ($this->image->height!="") {
+				$feed.= "            <height>".$this->image->height."</height>\n";
+			}
+			if ($this->image->description!="") {
+				$feed.= "            <description>".$this->image->getDescription()."</description>\n";
+			}
+			$feed.= "        </image>\n";
+		}
+		if ($this->language!="") {
+			$feed.= "        <language>".$this->language."</language>\n";
+		}
+		if ($this->copyright!="") {
+			$feed.= "        <copyright>".FeedCreator::iTrunc(htmlspecialchars($this->copyright),100)."</copyright>\n";
+		}
+		if ($this->editor!="") {
+			$feed.= "        <managingEditor>".FeedCreator::iTrunc(htmlspecialchars($this->editor),100)."</managingEditor>\n";
+		}
+		if ($this->webmaster!="") {
+			$feed.= "        <webMaster>".FeedCreator::iTrunc(htmlspecialchars($this->webmaster),100)."</webMaster>\n";
+		}
+		if ($this->pubDate!="") {
+			$pubDate = new FeedDate($this->pubDate);
+			$feed.= "        <pubDate>".htmlspecialchars($pubDate->rfc822())."</pubDate>\n";
+		}
+		if ($this->category!="") {
+			$feed.= "        <category>".htmlspecialchars($this->category)."</category>\n";
+		}
+		if ($this->docs!="") {
+			$feed.= "        <docs>".FeedCreator::iTrunc(htmlspecialchars($this->docs),500)."</docs>\n";
+		}
+		if ($this->ttl!="") {
+			$feed.= "        <ttl>".htmlspecialchars($this->ttl)."</ttl>\n";
+		}
+		if ($this->rating!="") {
+			$feed.= "        <rating>".FeedCreator::iTrunc(htmlspecialchars($this->rating),500)."</rating>\n";
+		}
+		if ($this->skipHours!="") {
+			$feed.= "        <skipHours>".htmlspecialchars($this->skipHours)."</skipHours>\n";
+		}
+		if ($this->skipDays!="") {
+			$feed.= "        <skipDays>".htmlspecialchars($this->skipDays)."</skipDays>\n";
+		}
+		$feed.= $this->_createAdditionalElements($this->additionalElements, "    ");
+
+		for ($i=0;$i<count($this->items);$i++) {
+			$feed.= "        <item>\n";
+			$feed.= "            <title>".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."</title>\n";
+			$feed.= "            <link>".htmlspecialchars($this->items[$i]->link)."</link>\n";
+			$feed.= "            <description>".$this->items[$i]->getDescription()."</description>\n";
+			
+			if ($this->items[$i]->author!="") {
+				$feed.= "            <author>".htmlspecialchars($this->items[$i]->author)."</author>\n";
+			}
+			/*
+			// on hold
+			if ($this->items[$i]->source!="") {
+					$feed.= "            <source>".htmlspecialchars($this->items[$i]->source)."</source>\n";
+			}
+			*/
+			if ($this->items[$i]->category!="") {
+				$feed.= "            <category>".htmlspecialchars($this->items[$i]->category)."</category>\n";
+			}
+			if ($this->items[$i]->comments!="") {
+				$feed.= "            <comments>".htmlspecialchars($this->items[$i]->comments)."</comments>\n";
+			}
+			if ($this->items[$i]->date!="") {
+			$itemDate = new FeedDate($this->items[$i]->date);
+				$feed.= "            <pubDate>".htmlspecialchars($itemDate->rfc822())."</pubDate>\n";
+			}
+			if ($this->items[$i]->guid!="") {
+				$feed.= "            <guid>".htmlspecialchars($this->items[$i]->guid)."</guid>\n";
+			}
+			$feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, "        ");
+			$feed.= "        </item>\n";
+		}
+		$feed.= "    </channel>\n";
+		$feed.= "</rss>\n";
+		return $feed;
+	}
+}
+
+
+
+/**
+ * RSSCreator20 is a FeedCreator that implements RDF Site Summary (RSS) 2.0.
+ *
+ * @see http://backend.userland.com/rss
+ * @since 1.3
+ * @author Kai Blankenhorn <kaib@bitfolge.de>
+ */
+class RSSCreator20 extends RSSCreator091 {
+
+    function RSSCreator20() {
+        parent::_setRSSVersion("2.0");
+    }
+    
+}
+
+
+/**
+ * PIECreator01 is a FeedCreator that implements the emerging PIE specification,
+ * as in http://intertwingly.net/wiki/pie/Syntax.
+ *
+ * @deprecated
+ * @since 1.3
+ * @author Scott Reynen <scott@randomchaos.com> and Kai Blankenhorn <kaib@bitfolge.de>
+ */
+class PIECreator01 extends FeedCreator {
+	
+	function PIECreator01() {
+		$this->encoding = "utf-8";
+	}
+    
+	function createFeed() {
+		$feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
+		$feed.= $this->_createStylesheetReferences();
+		$feed.= "<feed version=\"0.1\" xmlns=\"http://example.com/newformat#\">\n"; 
+		$feed.= "    <title>".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</title>\n";
+		$this->truncSize = 500;
+		$feed.= "    <subtitle>".$this->getDescription()."</subtitle>\n";
+		$feed.= "    <link>".$this->link."</link>\n";
+		for ($i=0;$i<count($this->items);$i++) {
+			$feed.= "    <entry>\n";
+			$feed.= "        <title>".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."</title>\n";
+			$feed.= "        <link>".htmlspecialchars($this->items[$i]->link)."</link>\n";
+			$itemDate = new FeedDate($this->items[$i]->date);
+			$feed.= "        <created>".htmlspecialchars($itemDate->iso8601())."</created>\n";
+			$feed.= "        <issued>".htmlspecialchars($itemDate->iso8601())."</issued>\n";
+			$feed.= "        <modified>".htmlspecialchars($itemDate->iso8601())."</modified>\n";
+			$feed.= "        <id>".htmlspecialchars($this->items[$i]->guid)."</id>\n";
+			if ($this->items[$i]->author!="") {
+				$feed.= "        <author>\n";
+				$feed.= "            <name>".htmlspecialchars($this->items[$i]->author)."</name>\n";
+				if ($this->items[$i]->authorEmail!="") {
+					$feed.= "            <email>".$this->items[$i]->authorEmail."</email>\n";
+				}
+				$feed.="        </author>\n";
+			}
+			$feed.= "        <content type=\"text/html\" xml:lang=\"en-us\">\n";
+			$feed.= "            <div xmlns=\"http://www.w3.org/1999/xhtml\">".$this->items[$i]->getDescription()."</div>\n";
+			$feed.= "        </content>\n";
+			$feed.= "    </entry>\n";
+		}
+		$feed.= "</feed>\n";
+		return $feed;
+	}
+}
+
+
+/**
+ * AtomCreator03 is a FeedCreator that implements the atom specification,
+ * as in http://www.intertwingly.net/wiki/pie/FrontPage.
+ * Please note that just by using AtomCreator03 you won't automatically
+ * produce valid atom files. For example, you have to specify either an editor
+ * for the feed or an author for every single feed item.
+ *
+ * Some elements have not been implemented yet. These are (incomplete list):
+ * author URL, item author's email and URL, item contents, alternate links, 
+ * other link content types than text/html. Some of them may be created with
+ * AtomCreator03::additionalElements.
+ *
+ * @see FeedCreator#additionalElements
+ * @since 1.6
+ * @author Kai Blankenhorn <kaib@bitfolge.de>, Scott Reynen <scott@randomchaos.com>
+ */
+class AtomCreator03 extends FeedCreator {
+
+	function AtomCreator03() {
+		$this->contentType = "application/atom+xml";
+		$this->encoding = "utf-8";
+	}
+	
+	function createFeed() {
+		$feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
+		$feed.= $this->_createGeneratorComment();
+		$feed.= $this->_createStylesheetReferences();
+		$feed.= "<feed version=\"0.3\" xmlns=\"http://purl.org/atom/ns#\"";
+		if ($this->language!="") {
+			$feed.= " xml:lang=\"".$this->language."\"";
+		}
+		$feed.= ">\n"; 
+		$feed.= "    <title>".htmlspecialchars($this->title)."</title>\n";
+		$feed.= "    <tagline>".htmlspecialchars($this->description)."</tagline>\n";
+		$feed.= "    <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->link)."\"/>\n";
+		$feed.= "    <id>".htmlspecialchars($this->link)."</id>\n";
+		$now = new FeedDate();
+		$feed.= "    <modified>".htmlspecialchars($now->iso8601())."</modified>\n";
+		if ($this->editor!="") {
+			$feed.= "    <author>\n";
+			$feed.= "        <name>".$this->editor."</name>\n";
+			if ($this->editorEmail!="") {
+				$feed.= "        <email>".$this->editorEmail."</email>\n";
+			}
+			$feed.= "    </author>\n";
+		}
+		$feed.= "    <generator>".FEEDCREATOR_VERSION."</generator>\n";
+		$feed.= $this->_createAdditionalElements($this->additionalElements, "    ");
+		for ($i=0;$i<count($this->items);$i++) {
+			$feed.= "    <entry>\n";
+			$feed.= "        <title>".htmlspecialchars(strip_tags($this->items[$i]->title))."</title>\n";
+			$feed.= "        <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->items[$i]->link)."\"/>\n";
+			if ($this->items[$i]->date=="") {
+				$this->items[$i]->date = time();
+			}
+			$itemDate = new FeedDate($this->items[$i]->date);
+			$feed.= "        <created>".htmlspecialchars($itemDate->iso8601())."</created>\n";
+			$feed.= "        <issued>".htmlspecialchars($itemDate->iso8601())."</issued>\n";
+			$feed.= "        <modified>".htmlspecialchars($itemDate->iso8601())."</modified>\n";
+			$feed.= "        <id>".htmlspecialchars($this->items[$i]->link)."</id>\n";
+			$feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, "        ");
+			if ($this->items[$i]->author!="") {
+				$feed.= "        <author>\n";
+				$feed.= "            <name>".htmlspecialchars($this->items[$i]->author)."</name>\n";
+				$feed.= "        </author>\n";
+			}
+			if ($this->items[$i]->description!="") {
+				$feed.= "        <summary>".htmlspecialchars($this->items[$i]->description)."</summary>\n";
+			}
+			$feed.= "    </entry>\n";
+		}
+		$feed.= "</feed>\n";
+		return $feed;
+	}
+}
+
+
+/**
+ * MBOXCreator is a FeedCreator that implements the mbox format
+ * as described in http://www.qmail.org/man/man5/mbox.html
+ *
+ * @since 1.3
+ * @author Kai Blankenhorn <kaib@bitfolge.de>
+ */
+class MBOXCreator extends FeedCreator {
+
+	function MBOXCreator() {
+		$this->contentType = "text/plain";
+		$this->encoding = "ISO-8859-15";
+	}
+    
+	function qp_enc($input = "", $line_max = 76) { 
+		$hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); 
+		$lines = preg_split("/(?:\r\n|\r|\n)/", $input); 
+		$eol = "\r\n"; 
+		$escape = "="; 
+		$output = ""; 
+		while( list(, $line) = each($lines) ) { 
+			//$line = rtrim($line); // remove trailing white space -> no =20\r\n necessary 
+			$linlen = strlen($line); 
+			$newline = ""; 
+			for($i = 0; $i < $linlen; $i++) { 
+				$c = substr($line, $i, 1); 
+				$dec = ord($c); 
+				if ( ($dec == 32) && ($i == ($linlen - 1)) ) { // convert space at eol only 
+					$c = "=20"; 
+				} elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required 
+					$h2 = floor($dec/16); $h1 = floor($dec%16); 
+					$c = $escape.$hex["$h2"].$hex["$h1"]; 
+				} 
+				if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted 
+					$output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay 
+					$newline = ""; 
+				} 
+				$newline .= $c; 
+			} // end of for 
+			$output .= $newline.$eol; 
+		} 
+		return trim($output); 
+	}
+	
+
+	/**
+	 * Builds the MBOX contents.
+	 * @return    string    the feed's complete text 
+	 */
+	function createFeed() {
+		for ($i=0;$i<count($this->items);$i++) {
+			if ($this->items[$i]->author!="") {
+				$from = $this->items[$i]->author;
+			} else {
+				$from = $this->title;
+			}
+			$itemDate = new FeedDate($this->items[$i]->date);
+			$feed.= "From ".strtr(MBOXCreator::qp_enc($from)," ","_")." ".date("D M d H:i:s Y",$itemDate->unix())."\n";
+			$feed.= "Content-Type: text/plain;\n";
+			$feed.= "	charset=\"".$this->encoding."\"\n";
+			$feed.= "Content-Transfer-Encoding: quoted-printable\n";
+			$feed.= "Content-Type: text/plain\n";
+			$feed.= "From: \"".MBOXCreator::qp_enc($from)."\"\n";
+			$feed.= "Date: ".$itemDate->rfc822()."\n";
+			$feed.= "Subject: ".MBOXCreator::qp_enc(FeedCreator::iTrunc($this->items[$i]->title,100))."\n";
+			$feed.= "\n";
+			$body = chunk_split(MBOXCreator::qp_enc($this->items[$i]->description));
+			$feed.= preg_replace("~\nFrom ([^\n]*)(\n?)~","\n>From $1$2\n",$body);
+			$feed.= "\n";
+			$feed.= "\n";
+		}
+		return $feed;
+	}
+	
+	/**
+	 * Generate a filename for the feed cache file. Overridden from FeedCreator to prevent XML data types.
+	 * @return string the feed cache filename
+	 * @since 1.4
+	 * @access private
+	 */
+	function _generateFilename() {
+		$fileInfo = pathinfo($_SERVER["PHP_SELF"]);
+		return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".mbox";
+	}
+}
+
+
+/**
+ * OPMLCreator is a FeedCreator that implements OPML 1.0.
+ * 
+ * @see http://opml.scripting.com/spec
+ * @author Dirk Clemens, Kai Blankenhorn
+ * @since 1.5
+ */
+class OPMLCreator extends FeedCreator {
+
+	function OPMLCreator() {
+		$this->encoding = "utf-8";
+	}
+    
+	function createFeed() {     
+		$feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n";
+		$feed.= $this->_createGeneratorComment();
+		$feed.= $this->_createStylesheetReferences();
+		$feed.= "<opml xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n";
+		$feed.= "    <head>\n";
+		$feed.= "        <title>".htmlspecialchars($this->title)."</title>\n";
+		if ($this->pubDate!="") {
+			$date = new FeedDate($this->pubDate);
+			$feed.= "         <dateCreated>".$date->rfc822()."</dateCreated>\n";
+		}
+		if ($this->lastBuildDate!="") {
+			$date = new FeedDate($this->lastBuildDate);
+			$feed.= "         <dateModified>".$date->rfc822()."</dateModified>\n";
+		}
+		if ($this->editor!="") {
+			$feed.= "         <ownerName>".$this->editor."</ownerName>\n";
+		}
+		if ($this->editorEmail!="") {
+			$feed.= "         <ownerEmail>".$this->editorEmail."</ownerEmail>\n";
+		}
+		$feed.= "    </head>\n";
+		$feed.= "    <body>\n";
+		for ($i=0;$i<count($this->items);$i++) {
+			$feed.= "    <outline type=\"rss\" ";
+			$title = htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"\n\r","  ")));
+			$feed.= " title=\"".$title."\"";
+			$feed.= " text=\"".$title."\"";
+			//$feed.= " description=\"".htmlspecialchars($this->items[$i]->description)."\"";
+			$feed.= " url=\"".htmlspecialchars($this->items[$i]->link)."\"";
+			$feed.= "/>\n";
+		}
+		$feed.= "    </body>\n";
+		$feed.= "</opml>\n";
+		return $feed;
+	}
+}
+
+
+
+/**
+ * HTMLCreator is a FeedCreator that writes an HTML feed file to a specific 
+ * location, overriding the createFeed method of the parent FeedCreator.
+ * The HTML produced can be included over http by scripting languages, or serve
+ * as the source for an IFrame.
+ * All output by this class is embedded in <div></div> tags to enable formatting
+ * using CSS. 
+ *
+ * @author Pascal Van Hecke
+ * @since 1.7
+ */
+class HTMLCreator extends FeedCreator {
+
+	var $contentType = "text/html";
+	
+	/**
+	 * Contains HTML to be output at the start of the feed's html representation.
+	 */
+	var $header;
+	
+	/**
+	 * Contains HTML to be output at the end of the feed's html representation.
+	 */
+	var $footer ;
+	
+	/**
+	 * Contains HTML to be output between entries. A separator is only used in 
+	 * case of multiple entries.
+	 */
+	var $separator;
+	
+	/**
+	 * Used to prefix the stylenames to make sure they are unique 
+	 * and do not clash with stylenames on the users' page.
+	 */
+	var $stylePrefix;
+	
+	/**
+	 * Determines whether the links open in a new window or not.
+	 */
+	var $openInNewWindow = true;
+	
+	var $imageAlign ="right";
+	
+	/**
+	 * In case of very simple output you may want to get rid of the style tags,
+	 * hence this variable.  There's no equivalent on item level, but of course you can 
+	 * add strings to it while iterating over the items ($this->stylelessOutput .= ...)
+	 * and when it is non-empty, ONLY the styleless output is printed, the rest is ignored
+	 * in the function createFeed().
+	 */
+	var $stylelessOutput ="";
+
+	/**
+	 * Writes the HTML.
+	 * @return    string    the scripts's complete text 
+	 */
+	function createFeed() {
+		// if there is styleless output, use the content of this variable and ignore the rest
+		if ($this->stylelessOutput!="") {
+			return $this->stylelessOutput;
+		}
+		
+		//if no stylePrefix is set, generate it yourself depending on the script name
+		if ($this->stylePrefix=="") {
+			$this->stylePrefix = str_replace(".", "_", $this->_generateFilename())."_";
+		}
+
+		//set an openInNewWindow_token_to be inserted or not
+		if ($this->openInNewWindow) {
+			$targetInsert = " target='_blank'";
+		}
+		
+		// use this array to put the lines in and implode later with "document.write" javascript
+		$feedArray = array();
+		if ($this->image!=null) {
+			$imageStr = "<a href='".$this->image->link."'".$targetInsert.">".
+							"<img src='".$this->image->url."' border='0' alt='".
+							FeedCreator::iTrunc(htmlspecialchars($this->image->title),100).
+							"' align='".$this->imageAlign."' ";
+			if ($this->image->width) {
+				$imageStr .=" width='".$this->image->width. "' ";
+			}
+			if ($this->image->height) {
+				$imageStr .=" height='".$this->image->height."' ";
+			}
+			$imageStr .="/></a>";
+			$feedArray[] = $imageStr;
+		}
+		
+		if ($this->title) {
+			$feedArray[] = "<div class='".$this->stylePrefix."title'><a href='".$this->link."' ".$targetInsert." class='".$this->stylePrefix."title'>".
+				FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</a></div>";
+		}
+		if ($this->getDescription()) {
+			$feedArray[] = "<div class='".$this->stylePrefix."description'>".
+				str_replace("]]>", "", str_replace("<![CDATA[", "", $this->getDescription())).
+				"</div>";
+		}
+		
+		if ($this->header) {
+			$feedArray[] = "<div class='".$this->stylePrefix."header'>".$this->header."</div>";
+		}
+		
+		for ($i=0;$i<count($this->items);$i++) {
+			if ($this->separator and $i > 0) {
+				$feedArray[] = "<div class='".$this->stylePrefix."separator'>".$this->separator."</div>";
+			}
+			
+			if ($this->items[$i]->title) {
+				if ($this->items[$i]->link) {
+					$feedArray[] = 
+						"<div class='".$this->stylePrefix."item_title'><a href='".$this->items[$i]->link."' class='".$this->stylePrefix.
+						"item_title'".$targetInsert.">".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100).
+						"</a></div>";
+				} else {
+					$feedArray[] = 
+						"<div class='".$this->stylePrefix."item_title'>".
+						FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100).
+						"</div>";
+				}
+			}
+			if ($this->items[$i]->getDescription()) {
+				$feedArray[] = 
+				"<div class='".$this->stylePrefix."item_description'>".
+					str_replace("]]>", "", str_replace("<![CDATA[", "", $this->items[$i]->getDescription())).
+					"</div>";
+			}
+		}
+		if ($this->footer) {
+			$feedArray[] = "<div class='".$this->stylePrefix."footer'>".$this->footer."</div>";
+		}
+		
+		$feed= "".join($feedArray, "\r\n");
+		return $feed;
+	}
+    
+	/**
+	 * Overrrides parent to produce .html extensions
+	 *
+	 * @return string the feed cache filename
+	 * @since 1.4
+	 * @access private
+	 */
+	function _generateFilename() {
+		$fileInfo = pathinfo($_SERVER["PHP_SELF"]);
+		return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".html";
+	}
+}	
+
+
+/**
+ * JSCreator is a class that writes a js file to a specific 
+ * location, overriding the createFeed method of the parent HTMLCreator.
+ *
+ * @author Pascal Van Hecke
+ */
+class JSCreator extends HTMLCreator {
+	var $contentType = "text/javascript";
+	
+	/**
+	 * writes the javascript
+	 * @return    string    the scripts's complete text 
+	 */
+	function createFeed() 
+	{
+		$feed = parent::createFeed();
+		$feedArray = explode("\n",$feed);
+		
+		$jsFeed = "";
+		foreach ($feedArray as $value) {
+			$jsFeed .= "document.write('".trim(addslashes($value))."');\n";
+		}
+		return $jsFeed;
+	}
+    
+	/**
+	 * Overrrides parent to produce .js extensions
+	 *
+	 * @return string the feed cache filename
+	 * @since 1.4
+	 * @access private
+	 */
+	function _generateFilename() {
+		$fileInfo = pathinfo($_SERVER["PHP_SELF"]);
+		return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".js";
+	}
+	
+}	
+
+
+
+/*** TEST SCRIPT *********************************************************
+
+//include("feedcreator.class.php"); 
+
+$rss = new UniversalFeedCreator(); 
+$rss->useCached(); 
+$rss->title = "PHP news"; 
+$rss->description = "daily news from the PHP scripting world"; 
+
+//optional
+//$rss->descriptionTruncSize = 500;
+//$rss->descriptionHtmlSyndicated = true;
+//$rss->xslStyleSheet = "http://feedster.com/rss20.xsl";
+
+$rss->link = "http://www.dailyphp.net/news"; 
+$rss->feedURL = "http://www.dailyphp.net/".$PHP_SELF; 
+
+$image = new FeedImage(); 
+$image->title = "dailyphp.net logo"; 
+$image->url = "http://www.dailyphp.net/images/logo.gif"; 
+$image->link = "http://www.dailyphp.net"; 
+$image->description = "Feed provided by dailyphp.net. Click to visit."; 
+
+//optional
+$image->descriptionTruncSize = 500;
+$image->descriptionHtmlSyndicated = true;
+
+$rss->image = $image; 
+
+// get your news items from somewhere, e.g. your database: 
+//mysql_select_db($dbHost, $dbUser, $dbPass); 
+//$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC"); 
+//while ($data = mysql_fetch_object($res)) { 
+	$item = new FeedItem(); 
+	$item->title = "This is an the test title of an item"; 
+	$item->link = "http://localhost/item/"; 
+	$item->description = "<b>description in </b><br/>HTML"; 
+	
+	//optional
+	//item->descriptionTruncSize = 500;
+	$item->descriptionHtmlSyndicated = true;
+	
+	$item->date = time(); 
+	$item->source = "http://www.dailyphp.net"; 
+	$item->author = "John Doe"; 
+	 
+	$rss->addItem($item); 
+//} 
+
+// valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1, MBOX, OPML, ATOM0.3, HTML, JS
+echo $rss->saveFeed("RSS0.91", "feed.xml"); 
+
+
+
+***************************************************************************/
+
+?>
Index: /branches/1.5/include/functions.inc.php
===================================================================
--- /branches/1.5/include/functions.inc.php	(revision 3250)
+++ /branches/1.5/include/functions.inc.php	(revision 3250)
@@ -0,0 +1,730 @@
+<?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
+
+/**
+ * returns an array containing the possible values of an enum field
+ *
+ * @param string tablename
+ * @param string fieldname
+ */
+function get_enums($table, $field)
+{
+  // retrieving the properties of the table. Each line represents a field :
+  // columns are 'Field', 'Type'
+  $result = pwg_query('desc '.$table);
+  while ($row = mysql_fetch_array($result))
+  {
+    // we are only interested in the the field given in parameter for the
+    // function
+    if ($row['Field'] == $field)
+    {
+      // retrieving possible values of the enum field
+      // enum('blue','green','black')
+      $options = explode(',', substr($row['Type'], 5, -1));
+      foreach ($options as $i => $option)
+      {
+        $options[$i] = str_replace("'", '',$option);
+      }
+    }
+  }
+  mysql_free_result($result);
+  return $options;
+}
+
+// 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;
+  }
+}
+
+// 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'])
+  {
+   if ( ($conf['history_admin'] ) or  ( (! $conf['history_admin'])  and ($user['status'] != 'admin')  ) )
+	  {
+    $login = ($user['id'] == $conf['guest_id'])
+      ? 'guest' : addslashes($user['username']);
+    
+    $query = '
+INSERT INTO '.HISTORY_TABLE.'
+  (date,login,IP,file,category,picture)
+  VALUES
+  (NOW(),
+  \''.$login.'\',
+  \''.$_SERVER['REMOTE_ADDR'].'\',
+  \''.addslashes($file).'\',
+  \''.addslashes(strip_tags($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;
+}
+
+function pwg_query($query)
+{
+  global $conf,$page,$debug;
+  
+  $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.= '<b>'.number_format($time, 3, '.', ' ').' s)</b>';
+    $output.= "\n".'(total SQL time  : ';
+    $output.= number_format($page['queries_time'], 3, '.', ' ').' s)';
+    $output.= "</pre>\n";
+    
+    $debug .= $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 .= '<p>';
+  $debug.= '['.$time.', ';
+  $debug.= $count_queries.' queries] : '.$string;
+  $debug.= "</p>\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))
+    {
+      $query_string.= $is_first ? '?' : '&amp;';
+      $is_first = false;
+      $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);
+}
+
+/**
+ * creates an array based on a query, this function is a very common pattern
+ * used here
+ *
+ * @param string $query
+ * @param string $fieldname
+ * @return array
+ */
+function array_from_query($query, $fieldname)
+{
+  $array = array();
+  
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($array, $row[$fieldname]);
+  }
+
+  return $array;
+}
+
+/**
+ * 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]));
+  }
+}
+
+/**
+ * fill the current user caddie with given elements, if not already in
+ * caddie
+ *
+ * @param array elements_id
+ */
+function fill_caddie($elements_id)
+{
+  global $user;
+  
+  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+  
+  $query = '
+SELECT element_id
+  FROM '.CADDIE_TABLE.'
+  WHERE user_id = '.$user['id'].'
+;';
+  $in_caddie = array_from_query($query, 'element_id');
+
+  $caddiables = array_diff($elements_id, $in_caddie);
+
+  $datas = array();
+
+  foreach ($caddiables as $caddiable)
+  {
+    array_push($datas, array('element_id' => $caddiable,
+                             'user_id' => $user['id']));
+  }
+
+  if (count($caddiables) > 0)
+  {
+    mass_inserts(CADDIE_TABLE, array('element_id','user_id'), $datas);
+  }
+}
+
+/**
+ * returns the element name from its filename
+ *
+ * @param string filename
+ * @return string name
+ */
+function get_name_from_file($filename)
+{
+  return str_replace('_',' ',get_filename_wo_extension($filename));
+}
+
+/**
+ * returns the corresponding value from $lang if existing. Else, the key is
+ * returned
+ *
+ * @param string key
+ * @return string
+ */
+function l10n($key)
+{
+  global $lang, $conf;
+
+  if ($conf['debug_l10n'] and !isset($lang[$key]))
+  {
+    echo '[l10n] language key "'.$key.'" is not defined<br />';
+  }
+  
+  return isset($lang[$key]) ? $lang[$key] : $key;
+}
+?>
Index: /branches/1.5/include/functions_category.inc.php
===================================================================
--- /branches/1.5/include/functions_category.inc.php	(revision 3250)
+++ /branches/1.5/include/functions_category.inc.php	(revision 3250)
@@ -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, explode(',', $user['forbidden_categories'])))
+  {
+    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.'
+  WHERE category_id NOT IN ('.$user['forbidden_categories'].')
+;';
+  list($total) = mysql_fetch_array(pwg_query($query));
+  
+  return $total;
+}
+
+/**
+ * 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' )
+      {
+        // SQL injection hacking attempt?
+        if (strpos($_GET['search'], ';') !== false)
+        {
+          die('Hacking attempt on "search" GET parameter');
+        }
+        
+        // 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 = 'DATE_FORMAT('.$datefield.", '%Y-%m-%d') = '";
+            $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.5/include/functions_group.inc.php
===================================================================
--- /branches/1.5/include/functions_group.inc.php	(revision 3250)
+++ /branches/1.5/include/functions_group.inc.php	(revision 3250)
@@ -0,0 +1,30 @@
+<?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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// with 1.5 preparation, no group dedicated function is used.
+
+?>
Index: /branches/1.5/include/functions_html.inc.php
===================================================================
--- /branches/1.5/include/functions_html.inc.php	(revision 3250)
+++ /branches/1.5/include/functions_html.inc.php	(revision 3250)
@@ -0,0 +1,442 @@
+<?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 )
+{
+  // TODO $page['icon_cache'], for each date, associate the HTML icon
+  global $user, $conf, $lang;
+
+  if (!preg_match('/^(\d{4})-(\d{2})-(\d{2})/', $date, $matches))
+  {
+    // date can be empty, no icon to display
+    return '';
+  }
+  
+  list($devnull, $year, $month, $day) = $matches;
+  $unixtime = mktime( 0, 0, 0, $month, $day, $year );
+
+  if ($unixtime === false  // PHP 5.1.0 and above
+      or $unixtime === -1) // PHP prior to 5.1.0
+  {
+    return '';
+  }
+  
+  $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.png';
+    $title .= $user['recent_period'];
+    $title .=  '&nbsp;'.$lang['days'];
+    $size = getimagesize( $icon_url );
+    $output = '<img title="'.$title.'" src="'.$icon_url.'" class="icon" 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 . '">';
+  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;
+}
+
+/**
+ * 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=""';
+      $output.= ' href="'.add_session_id(PHPWG_ROOT_PATH.$url.$id).'">';
+      $output.= $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;
+  $level = 0;
+  $menu = '';
+  
+  foreach ($categories as $category)
+  {
+    $level = substr_count($category['global_rank'], '.') + 1;
+    if ($level > $ref_level)
+    {
+      $menu.= "\n<ul>";
+    }
+    else if ($level == $ref_level)
+    {
+      $menu.= "\n</li>";
+    }
+    else if ($level < $ref_level)
+    {
+      // we may have to close more than one level at the same time...
+      $menu.= "\n</li>";
+      $menu.= str_repeat("\n</ul></li>",($ref_level-$level));
+    }
+    $ref_level = $level;
+
+    $menu.= "\n\n".'<li';
+    if (isset($page['cat'])
+        and is_numeric($page['cat'])
+        and $category['id'] == $page['cat'])
+    {
+      $menu.= ' class="selected"';
+    }
+    $menu.= '>';
+  
+    $url = add_session_id(PHPWG_ROOT_PATH.'category.php?cat='.$category['id']);
+    $menu.= "\n".'<a href="'.$url.'">'.$category['name'].'</a>';
+
+    if ($category['nb_images'] > 0)
+    {
+      $menu.= "\n".'<span class="menuInfoCat"';
+      $menu.= ' title="'.$category['nb_images'];
+      $menu.= ' '.$lang['images_available'].'">';
+      $menu.= '['.$category['nb_images'].']';
+      $menu.= '</span>';
+      $menu.= get_icon($category['date_last']);
+    }
+  }
+
+  $menu.= str_repeat("\n</li></ul>",($level));
+  
+  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);
+
+  $pattern = '/(http?:\/\/\S*)/';
+  $replacement = '<a href="$1">$1</a>';
+  $content = preg_replace($pattern, $replacement, $content);
+  
+  // replace _word_ by an underlined word
+  $pattern = '/\b_(\S*)_\b/';
+  $replacement = '<span style="text-decoration:underline;">$1</span>';
+  $content = preg_replace($pattern, $replacement, $content);
+  
+  // replace *word* by a bolded word
+  $pattern = '/\b\*(\S*)\*\b/';
+  $replacement = '<span style="font-weight:bold;">$1</span>';
+  $content = preg_replace($pattern, $replacement, $content);
+  
+  // replace /word/ by an italic word
+   $pattern = "/\/(\S*)\/(\s)/";
+   $replacement = '<span style="font-style:italic;">$1$2</span>';
+   $content = preg_replace($pattern, $replacement, $content);
+
+  return $content;
+}
+
+function get_cat_display_name_from_id($cat_id,
+                                      $url = 'category.php?cat=',
+                                      $replace_space = true)
+{
+  $cat_info = get_cat_info($cat_id);
+  return get_cat_display_name($cat_info['name'], $url, $replace_space);
+}
+?>
Index: /branches/1.5/include/functions_metadata.inc.php
===================================================================
--- /branches/1.5/include/functions_metadata.inc.php	(revision 3250)
+++ /branches/1.5/include/functions_metadata.inc.php	(revision 3250)
@@ -0,0 +1,136 @@
+<?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;
+}
+
+/**
+ * returns informations from EXIF metadata, mapping is done at the beginning
+ * of the function
+ *
+ * @param string $filename
+ * @return array
+ */
+function get_exif_data($filename, $map)
+{
+  $result = array();
+
+  if (!function_exists('read_exif_data'))
+  {
+    die('Exif extension not available, admin should disable exif use');
+  }
+  
+  // Read EXIF data
+  if ($exif = @read_exif_data($filename))
+  {
+    foreach ($map as $key => $field)
+    {
+      if (strpos($field, ';') === false)
+      {
+        if (isset($exif[$field]))
+        {
+          $result[$key] = $exif[$field];
+        }
+      }
+      else
+      {
+        $tokens = explode(';', $field);
+        if (isset($exif[$tokens[0]][$tokens[1]]))
+        {
+          $result[$key] = $exif[$tokens[0]][$tokens[1]];
+        }
+      }
+    }
+  }
+
+  return $result;
+}
+?>
Index: /branches/1.5/include/functions_session.inc.php
===================================================================
--- /branches/1.5/include/functions_session.inc.php	(revision 3250)
+++ /branches/1.5/include/functions_session.inc.php	(revision 3250)
@@ -0,0 +1,139 @@
+<?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, $conf;
+
+  if ($user['is_the_guest']
+      or $user['has_cookie']
+      or $conf['apache_authentication'])
+  {
+    return $url;
+  }
+
+  if (preg_match('/\.php\?/', $url))
+  {
+    $separator = $redirect ? '&' : '&amp;';
+  }
+  else
+  {
+    $separator = '?';
+  }
+
+  return $url.$separator.'id='.$page['session_id'];
+}
+
+// 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.5/include/functions_user.inc.php
===================================================================
--- /branches/1.5/include/functions_user.inc.php	(revision 3250)
+++ /branches/1.5/include/functions_user.inc.php	(revision 3250)
@@ -0,0 +1,545 @@
+<?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$
+// | 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, $mail_address)
+{
+  global $lang, $conf;
+
+  $errors = array();
+  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 (get_userid($login))
+  {
+    array_push($errors, $lang['reg_err_login5']);
+  }
+  $mail_error = validate_mail_address($mail_address);
+  if ('' != $mail_error)
+  {
+    array_push($errors, $mail_error);
+  }
+
+  // if no error until here, registration of the user
+  if (count($errors) == 0)
+  {
+    // what will be the inserted id ?
+    $query = '
+SELECT MAX('.$conf['user_fields']['id'].') + 1
+  FROM '.USERS_TABLE.'
+;';
+    list($next_id) = mysql_fetch_array(pwg_query($query));
+    
+    $insert =
+      array(
+        $conf['user_fields']['id'] => $next_id,
+        $conf['user_fields']['username'] => mysql_escape_string($login),
+        $conf['user_fields']['password'] => $conf['pass_convert']($password),
+        $conf['user_fields']['email'] => $mail_address
+        );
+
+    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+    mass_inserts(USERS_TABLE, array_keys($insert), array($insert));
+    
+    create_user_infos($next_id);
+  }
+
+  return $errors;
+}
+
+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);
+}
+
+/**
+ * find informations related to the user identifier
+ *
+ * @param int user identifier
+ * @param boolean use_cache
+ * @param array
+ */
+function getuserdata($user_id, $use_cache)
+{
+  global $conf;
+
+  $userdata = array();
+  
+  $query = '
+SELECT ';
+  $is_first = true;
+  foreach ($conf['user_fields'] as $pwgfield => $dbfield)
+  {
+    if ($is_first)
+    {
+      $is_first = false;
+    }
+    else
+    {
+      $query.= '
+     , ';
+    }
+    $query.= $dbfield.' AS '.$pwgfield;
+  }
+  $query.= '
+  FROM '.USERS_TABLE.'
+  WHERE '.$conf['user_fields']['id'].' = \''.$user_id.'\'
+;';
+  
+  $row = mysql_fetch_array(pwg_query($query));
+
+  while (true)
+  {
+    $query = '
+SELECT ui.*, uc.*
+  FROM '.USER_INFOS_TABLE.' AS ui LEFT JOIN '.USER_CACHE_TABLE.' AS uc
+    ON ui.user_id = uc.user_id
+  WHERE ui.user_id = \''.$user_id.'\'
+;';
+    $result = pwg_query($query);
+    if (mysql_num_rows($result) > 0)
+    {
+      break;
+    }
+    else
+    {
+      create_user_infos($user_id);
+    }
+  }
+  
+  $row = array_merge($row, mysql_fetch_array($result));
+  
+  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')
+      {
+        $userdata[$key] = get_boolean($value);
+      }
+      else
+      {
+        $userdata[$key] = $value;
+      }
+    }
+  }
+
+  if ($use_cache)
+  {
+    if (!isset($userdata['need_update'])
+        or !is_bool($userdata['need_update'])
+        or $userdata['need_update'] == true)
+    {
+      $userdata['forbidden_categories'] =
+        calculate_permissions($userdata['id'], $userdata['status']);
+
+      // update user cache
+      $query = '
+DELETE FROM '.USER_CACHE_TABLE.'
+  WHERE user_id = '.$userdata['id'].'
+;';
+      pwg_query($query);
+  
+      $query = '
+INSERT INTO '.USER_CACHE_TABLE.'
+  (user_id,need_update,forbidden_categories)
+  VALUES
+  ('.$userdata['id'].',\'false\',\''.$userdata['forbidden_categories'].'\')
+;';
+      pwg_query($query);
+    }
+  }
+
+  return $userdata;
+}
+
+/*
+ * 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);
+  }
+}
+
+/**
+ * calculates the list of forbidden categories for a given user
+ *
+ * Calculation is based on private categories minus categories authorized to
+ * the groups the user belongs to minus the categories directly authorized
+ * to the user. The list contains at least -1 to be compliant with queries
+ * such as "WHERE category_id NOT IN ($forbidden_categories)"
+ *
+ * @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.'
+;';
+  $authorized_array = array_from_query($query, '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.'
+;';
+  $authorized_array =
+    array_merge(
+      $authorized_array,
+      array_from_query($query, '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);
+
+  // at least, the list contains -1 values. This category does not exists so
+  // where clauses such as "WHERE category_id NOT IN(-1)" will always be
+  // true.
+  if (count($forbidden_array) == 0)
+  {
+    array_push($forbidden_array, 0);
+  }
+  
+  return implode(',', $forbidden_array);
+}
+
+/**
+ * returns the username corresponding to the given user identifier if exists
+ *
+ * @param int user_id
+ * @return mixed
+ */
+function get_username($user_id)
+{
+  global $conf;
+  
+  $query = '
+SELECT '.$conf['user_fields']['username'].'
+  FROM '.USERS_TABLE.'
+  WHERE '.$conf['user_fields']['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;
+}
+
+/**
+ * returns user identifier thanks to his name, false if not found
+ *
+ * @param string username
+ * @param int user identifier
+ */
+function get_userid($username)
+{
+  global $conf;
+
+  $username = mysql_escape_string($username);
+
+  $query = '
+SELECT '.$conf['user_fields']['id'].'
+  FROM '.USERS_TABLE.'
+  WHERE '.$conf['user_fields']['username'].' = \''.$username.'\'
+;';
+  $result = pwg_query($query);
+
+  if (mysql_num_rows($result) == 0)
+  {
+    return false;
+  }
+  else
+  {
+    list($user_id) = mysql_fetch_row($result);
+    return $user_id;
+  }
+}
+
+/**
+ * search an available feed_id
+ *
+ * @return string feed identifier
+ */
+function find_available_feed_id()
+{
+  while (true)
+  {
+    $key = generate_key(50);
+    $query = '
+SELECT COUNT(*)
+  FROM '.USER_FEED_TABLE.'
+  WHERE id = \''.$key.'\'
+;';
+    list($count) = mysql_fetch_row(pwg_query($query));
+    if (0 == $count)
+    {
+      return $key;
+    }
+  }
+}
+
+/**
+ * add user informations based on default values
+ *
+ * @param int user_id
+ */
+function create_user_infos($user_id)
+{
+  global $conf;
+  
+  list($dbnow) = mysql_fetch_row(pwg_query('SELECT NOW();'));
+
+  $insert =
+    array(
+      'user_id' => $user_id,
+      'status' => $user_id == $conf['webmaster_id'] ? 'admin' : 'guest',
+      'template' => $conf['default_template'],
+      'nb_image_line' => $conf['nb_image_line'],
+      'nb_line_page' => $conf['nb_line_page'],
+      'language' => $conf['default_language'],
+      'recent_period' => $conf['recent_period'],
+      'expand' => boolean_to_string($conf['auto_expand']),
+      'show_nb_comments' => boolean_to_string($conf['show_nb_comments']),
+      'maxwidth' => $conf['default_maxwidth'],
+      'maxheight' => $conf['default_maxheight'],
+      'registration_date' => $dbnow
+      );
+
+  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+  mass_inserts(USER_INFOS_TABLE, array_keys($insert), array($insert));
+}
+
+/**
+ * returns the groupname corresponding to the given group identifier if
+ * exists
+ *
+ * @param int group_id
+ * @return mixed
+ */
+function get_groupname($group_id)
+{
+  $query = '
+SELECT name
+  FROM '.GROUPS_TABLE.'
+  WHERE id = '.intval($group_id).'
+;';
+  $result = pwg_query($query);
+  if (mysql_num_rows($result) > 0)
+  {
+    list($groupname) = mysql_fetch_row($result);
+  }
+  else
+  {
+    return false;
+  }
+  
+  return $groupname;
+}
+
+/**
+ * return the file path of the given language filename, depending on the
+ * availability of the file
+ *
+ * in descending order of preference: user language, default language,
+ * PhpWebGallery default language.
+ *
+ * @param string filename
+ * @return string filepath
+ */
+function get_language_filepath($filename)
+{
+  global $user, $conf;
+  
+  $directories =
+    array(
+      PHPWG_ROOT_PATH.'language/'.$user['language'],
+      PHPWG_ROOT_PATH.'language/'.$conf['default_language'],
+      PHPWG_ROOT_PATH.'language/'.PHPWG_DEFAULT_LANGUAGE
+      );
+
+  foreach ($directories as $directory)
+  {
+    $filepath = $directory.'/'.$filename;
+    
+    if (file_exists($filepath))
+    {
+      return $filepath;
+    }
+  }
+  
+  return false;
+}
+?>
Index: /branches/1.5/include/functions_xml.inc.php
===================================================================
--- /branches/1.5/include/functions_xml.inc.php	(revision 3250)
+++ /branches/1.5/include/functions_xml.inc.php	(revision 3250)
@@ -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( '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 '';
+}
+	
+// 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.5/include/index.php
===================================================================
--- /branches/1.5/include/index.php	(revision 3250)
+++ /branches/1.5/include/index.php	(revision 3250)
@@ -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.5/include/page_header.php
===================================================================
--- /branches/1.5/include/page_header.php	(revision 3250)
+++ /branches/1.5/include/page_header.php	(revision 3250)
@@ -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.                                                                  |
+// +-----------------------------------------------------------------------+
+ 
+//
+// 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(
+    'GALLERY_TITLE' =>
+      isset($page['gallery_title']) ?
+        $page['gallery_title'] : $conf['gallery_title'],
+    
+    'GALLERY_DESCRIPTION' =>
+      isset($page['gallery_description']) ?
+        $page['gallery_description'] : $conf['gallery_description'],
+    
+    'BODY_ID' =>
+      isset($page['body_id']) ?
+        $page['body_id'] : '',
+    
+    '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.5/include/page_tail.php
===================================================================
--- /branches/1.5/include/page_tail.php	(revision 3250)
+++ /branches/1.5/include/page_tail.php	(revision 3250)
@@ -0,0 +1,91 @@
+<?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 : '',
+    
+    'L_GEN_TIME' => $lang['generation_time'],
+    'L_SQL_QUERIES_IN' => $lang['sql_queries_in'],
+    'L_SEND_MAIL' => $lang['send_mail'],
+    'L_TITLE_MAIL' => urlencode($lang['title_send_mail']),
+    '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'));
+}
+
+if ($conf['show_queries']) 
+{
+  $template->assign_block_vars(
+    'debug',
+    array('QUERIES_LIST' => $debug)
+  );
+}
+
+//--------------------------------------------------------------------- contact
+
+if (!$user['is_the_guest'])
+{
+  $query = '
+SELECT '.$conf['user_fields']['email'].'
+  FROM '.USERS_TABLE.'
+  WHERE '.$conf['user_fields']['id'].' = '.$conf['webmaster_id'].'
+;';
+  list($email) = mysql_fetch_array(pwg_query($query));
+  
+  $template->assign_block_vars(
+    'contact',
+    array(
+      'MAIL' => $email
+      )
+    );
+}
+
+//
+// Generate the page
+//
+
+$template->parse('tail');
+
+$template->p();
+?>
Index: /branches/1.5/include/pngfix.js
===================================================================
--- /branches/1.5/include/pngfix.js	(revision 3250)
+++ /branches/1.5/include/pngfix.js	(revision 3250)
@@ -0,0 +1,37 @@
+
+// Correctly handle PNG transparency in Win IE 5.5 or higher.
+// http://homepage.ntlworld.com/bobosola. Updated 02-March-2004
+// 15-Jully-2006 : chrisaga use \" instead of ' in imgTitle
+//		 : to fix ' display in tooltips
+//		 : keep the alt attribute
+
+function correctPNG() 
+   {
+   for(var i=0; i<document.images.length; i++)
+      {
+      var img = document.images[i]
+      if (img.className == "button" || img.className == "icon")
+          {
+	  var imgName = img.src.toUpperCase()
+	  if (imgName.substring(imgName.length-3, imgName.length) == "PNG")
+	     {
+		 var imgID = (img.id) ? "id='" + img.id + "' " : ""
+		 var imgClass = (img.className) ? "class='" + img.className + "' " : ""
+		 //var imgTitle = (img.title) ? "title=\"" + img.title + "\" " : "alt=\"" + img.alt + "\" "
+		 var imgTitle = (img.title) ? "title=\"" + img.title + "\" " : "";
+		 imgTitle = imgTitle + (img.alt) ? "title=\"" + img.alt + "\" " : "";
+		 var imgStyle = "display:inline-block;" + img.style.cssText 
+		 if (img.align == "left") imgStyle = "float:left;" + imgStyle
+		 if (img.align == "right") imgStyle = "float:right;" + imgStyle
+		 if (img.parentElement.href) imgStyle = "cursor:hand;" + imgStyle		
+		 var strNewHTML = "<span " + imgID + imgClass + imgTitle
+		 + " style=\"" + "width:" + img.width + "px; height:" + img.height + "px;" + imgStyle + ";"
+	     + "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader"
+		 + "(src=\'" + img.src + "\', sizingMethod='scale');\"></span>" 
+		 img.outerHTML = strNewHTML
+		 i = i-1
+	     }
+          }
+      }
+   }
+window.attachEvent("onload", correctPNG);
Index: /branches/1.5/include/scripts.js
===================================================================
--- /branches/1.5/include/scripts.js	(revision 3250)
+++ /branches/1.5/include/scripts.js	(revision 3250)
@@ -0,0 +1,42 @@
+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);
+}
+
+function popuphelp(url)
+{
+  window.open(
+    url,
+    'dc_popup',
+    'alwaysRaised=yes,dependent=yes,toolbar=no,height=420,width=500,menubar=no,resizable=yes,scrollbars=yes,status=no'
+  );
+}
+
Index: /branches/1.5/include/template.php
===================================================================
--- /branches/1.5/include/template.php	(revision 3250)
+++ /branches/1.5/include/template.php	(revision 3250)
@@ -0,0 +1,527 @@
+<?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) != '/')
+      if (preg_match('/^[a-z_]/i', $filename))
+      {
+        $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 = '')
+    {
+      // PWG specific : communication between template and $lang
+      $code = preg_replace('/\{lang:([^}]+)\}/e', "l10n('$1')", $code);
+            
+      // 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.5/include/user.inc.php
===================================================================
--- /branches/1.5/include/user.inc.php	(revision 3250)
+++ /branches/1.5/include/user.inc.php	(revision 3250)
@@ -0,0 +1,111 @@
+<?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'] = $conf['guest_id'];
+  $user['is_the_guest'] = true;
+}
+
+// using Apache authentication override the above user search
+if ($conf['apache_authentication'] and isset($_SERVER['REMOTE_USER']))
+{
+  if (!($user['id'] = get_userid($_SERVER['REMOTE_USER'])))
+  {
+    register_user($_SERVER['REMOTE_USER'], '', '');
+    $user['id'] = get_userid($_SERVER['REMOTE_USER']);
+  }
+  
+  $user['is_the_guest'] = false;
+}
+
+$use_cache = (defined('IN_ADMIN') and IN_ADMIN) ? false : true;
+$user = array_merge($user, getuserdata($user['id'], $use_cache));
+
+// 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'];
+}
+
+// calculation of the number of picture to display per page
+$user['nb_image_page'] = $user['nb_image_line'] * $user['nb_line_page'];
+?>
Index: /branches/1.5/index.php
===================================================================
--- /branches/1.5/index.php	(revision 3250)
+++ /branches/1.5/index.php	(revision 3250)
@@ -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.5/install.php
===================================================================
--- /branches/1.5/install.php	(revision 3250)
+++ /branches/1.5/install.php	(revision 3250)
@@ -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
+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
+// 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/config_default.inc.php');
+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('yoga');
+$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.'
+  (id,username,password,mail_address)
+  VALUES
+  (1,\''.$admin_name.'\',\''.md5($admin_pass1).'\',\''.$admin_mail.'\')
+;';
+    mysql_query($query);
+
+    $query = '
+INSERT INTO '.USER_INFOS_TABLE.'
+  (user_id,status,language)
+  VALUES
+  (1, \'admin\', \''.$language.'\')
+;';
+    mysql_query($query);
+
+    $query = '
+UPDATE '.USER_INFOS_TABLE.'
+  SET feed_id = \''.find_available_feed_id().'\'
+  WHERE user_id = 1
+;';
+    mysql_query($query);
+
+    // guest user
+    $query = '
+INSERT INTO '.USERS_TABLE.'
+  (id,username,password,mail_address)
+  VALUES
+  (2,\'guest\',\'\',\'\')
+;';
+    mysql_query($query);
+
+    $query = '
+INSERT INTO '.USER_INFOS_TABLE.'
+  (user_id,status,language)
+  VALUES
+  (2, \'guest\', \''.$language.'\')
+;';
+    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'=>'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.5/install/config.sql
===================================================================
--- /branches/1.5/install/config.sql	(revision 3250)
+++ /branches/1.5/install/config.sql	(revision 3250)
@@ -0,0 +1,19 @@
+-- initial configuration for PhpWebGallery
+
+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','yoga','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 ('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 ('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 ('gallery_locked','false','Lock your gallery temporary for non admin users');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('gallery_title','PhpWebGallery demonstration site','Title at top of each page and for RSS feed');
+INSERT INTO phpwebgallery_config (param,value,comment) VALUES ('gallery_description','My photos web site','Short description displayed with gallery title');
+
Index: /branches/1.5/install/phpwebgallery_structure.sql
===================================================================
--- /branches/1.5/install/phpwebgallery_structure.sql	(revision 3250)
+++ /branches/1.5/install/phpwebgallery_structure.sql	(revision 3250)
@@ -0,0 +1,301 @@
+-- MySQL dump 9.11
+--
+-- Host: localhost    Database: pwg-bsf
+-- ------------------------------------------------------
+-- Server version	4.0.24_Debian-10-log
+
+--
+-- Table structure for table `phpwebgallery_caddie`
+--
+
+DROP TABLE IF EXISTS `phpwebgallery_caddie`;
+CREATE TABLE `phpwebgallery_caddie` (
+  `user_id` smallint(5) NOT NULL default '0',
+  `element_id` mediumint(8) NOT NULL default '0',
+  PRIMARY KEY  (`user_id`,`element_id`)
+) TYPE=MyISAM;
+
+--
+-- 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` datetime 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',
+  `validation_date` datetime default NULL,
+  PRIMARY KEY  (`id`),
+  KEY `comments_i2` (`validation_date`),
+  KEY `comments_i1` (`image_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) 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` datetime NOT NULL default '0000-00-00 00: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) 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) 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) 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_cache`
+--
+
+DROP TABLE IF EXISTS `phpwebgallery_user_cache`;
+CREATE TABLE `phpwebgallery_user_cache` (
+  `user_id` smallint(5) 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_feed`
+--
+
+DROP TABLE IF EXISTS `phpwebgallery_user_feed`;
+CREATE TABLE `phpwebgallery_user_feed` (
+  `id` varchar(50) binary NOT NULL default '',
+  `user_id` smallint(5) NOT NULL default '0',
+  `last_check` datetime default NULL,
+  PRIMARY KEY  (`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) 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_user_infos`
+--
+
+DROP TABLE IF EXISTS `phpwebgallery_user_infos`;
+CREATE TABLE `phpwebgallery_user_infos` (
+  `user_id` smallint(5) NOT NULL default '0',
+  `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 'yoga',
+  `registration_date` datetime NOT NULL default '0000-00-00 00:00:00',
+  UNIQUE KEY `user_infos_ui1` (`user_id`)
+) TYPE=MyISAM;
+
+--
+-- Table structure for table `phpwebgallery_users`
+--
+
+DROP TABLE IF EXISTS `phpwebgallery_users`;
+CREATE TABLE `phpwebgallery_users` (
+  `id` smallint(5) NOT NULL auto_increment,
+  `username` varchar(20) binary NOT NULL default '',
+  `password` varchar(32) default NULL,
+  `mail_address` varchar(255) default NULL,
+  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.5/install/upgrade_1.4.0.php
===================================================================
--- /branches/1.5/install/upgrade_1.4.0.php	(revision 3250)
+++ /branches/1.5/install/upgrade_1.4.0.php	(revision 3250)
@@ -0,0 +1,366 @@
+<?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 ('This page cannot be loaded directly, load upgrade.php');
+}
+else
+{
+  if (!defined('PHPWG_IN_UPGRADE') or !PHPWG_IN_UPGRADE)
+  {
+    die ('Hacking attempt!');
+  }
+}
+
+$last_time = get_moment();
+
+// will the user have to edit include/config_local.inc.php for
+// prefix_thumbnail configuration parameter
+$query = '
+SELECT value
+  FROM '.CONFIG_TABLE.'
+  WHERE param = \'prefix_thumbnail\'
+;';
+list($prefix_thumbnail) = mysql_fetch_array(pwg_query($query));
+
+// delete obsolete configuration
+$query = '
+DELETE
+  FROM '.PREFIX_TABLE.'config
+  WHERE param IN (
+   \'prefix_thumbnail\',
+   \'mail_webmaster\',
+   \'upload_maxfilesize\',
+   \'upload_maxwidth\',
+   \'upload_maxheight\',
+   \'upload_maxwidth_thumbnail\',
+   \'upload_maxheight_thumbnail\',
+   \'mail_notification\',
+   \'use_iptc\',
+   \'use_exif\',
+   \'show_iptc\',
+   \'show_exif\',
+   \'authorize_remembering\'
+   )
+;';
+mysql_query($query);
+
+$queries = array(
+
+  "
+ALTER TABLE phpwebgallery_categories
+  CHANGE COLUMN date_last date_last datetime default NULL
+;",
+
+  "
+ALTER TABLE phpwebgallery_comments
+  ADD COLUMN validation_date datetime default NULL
+;",
+
+  "
+UPDATE phpwebgallery_comments
+  SET validation_date = date
+",
+
+  "
+ALTER TABLE phpwebgallery_comments
+  ADD INDEX comments_i1 (image_id)
+;",
+
+  "
+ALTER TABLE phpwebgallery_comments
+  ADD INDEX comments_i2 (validation_date)
+;",
+
+  "
+ALTER TABLE phpwebgallery_favorites
+  CHANGE COLUMN user_id user_id smallint(5) NOT NULL default '0'
+;",
+
+  "
+ALTER TABLE phpwebgallery_images
+  CHANGE COLUMN date_available
+    date_available datetime NOT NULL default '0000-00-00 00:00:00'
+;",
+
+  "
+ALTER TABLE phpwebgallery_rate
+  CHANGE COLUMN user_id user_id smallint(5) NOT NULL default '0'
+;",
+
+  "
+ALTER TABLE phpwebgallery_sessions
+  CHANGE COLUMN user_id user_id smallint(5) NOT NULL default '0'
+;",
+
+  "
+ALTER TABLE phpwebgallery_user_access
+  CHANGE COLUMN user_id user_id smallint(5) NOT NULL default '0'
+;",
+
+  "
+DROP TABLE phpwebgallery_user_forbidden
+;",
+
+  "
+ALTER TABLE phpwebgallery_user_group
+ CHANGE COLUMN user_id user_id smallint(5) NOT NULL default '0'
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  CHANGE COLUMN id id smallint(5) NOT NULL auto_increment
+;",
+
+  "
+CREATE TABLE phpwebgallery_caddie (
+  user_id smallint(5) NOT NULL default '0',
+  element_id mediumint(8) NOT NULL default '0',
+  PRIMARY KEY  (user_id,element_id)
+) TYPE=MyISAM
+;",
+
+  "
+CREATE TABLE phpwebgallery_user_cache (
+  user_id smallint(5) NOT NULL default '0',
+  need_update enum('true','false') NOT NULL default 'true',
+  forbidden_categories text,
+  PRIMARY KEY  (user_id)
+) TYPE=MyISAM
+;",
+
+  "
+CREATE TABLE phpwebgallery_user_feed (
+  id varchar(50) binary NOT NULL default '',
+  user_id smallint(5) NOT NULL default '0',
+  last_check datetime default NULL,
+  PRIMARY KEY  (id)
+) TYPE=MyISAM
+;",
+
+  "
+CREATE TABLE phpwebgallery_user_infos (
+  user_id smallint(5) NOT NULL default '0',
+  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 'yoga',
+  registration_date datetime NOT NULL default '0000-00-00 00:00:00',
+  UNIQUE KEY user_infos_ui1 (user_id)
+) TYPE=MyISAM
+;"
+  );
+
+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;
+
+// user datas migration from phpwebgallery_users to phpwebgallery_user_infos
+$query = '
+SELECT *
+  FROM '.USERS_TABLE.'
+;';
+
+$datas = array();
+list($dbnow) = mysql_fetch_row(pwg_query('SELECT NOW();'));
+
+$result = pwg_query($query);
+while ($row = mysql_fetch_array($result))
+{
+  $row['user_id'] = $row['id'];
+  $row['registration_date'] = $dbnow;
+  array_push($datas, $row);
+}
+
+include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+mass_inserts(
+  USER_INFOS_TABLE,
+  array(
+    'user_id',
+    'nb_image_line',
+    'nb_line_page',
+    'status',
+    'language',
+    'maxwidth',
+    'maxheight',
+    'expand',
+    'show_nb_comments',
+    'recent_period',
+    'template',
+    'registration_date'
+    ),
+  $datas
+  );
+
+$queries = array(
+
+  "
+UPDATE ".USER_INFOS_TABLE."
+  SET template = 'yoga'
+;",
+
+  "
+UPDATE ".USER_INFOS_TABLE."
+  SET language = 'en_UK.iso-8859-1'
+  WHERE language NOT IN ('en_UK.iso-8859-1', 'fr_FR.iso-8859-1')
+;",
+
+  "
+UPDATE ".CONFIG_TABLE."
+  SET value = 'en_UK.iso-8859-1'
+  WHERE param = 'default_language'
+    AND value NOT IN ('en_UK.iso-8859-1', 'fr_FR.iso-8859-1')
+;",
+
+  "
+UPDATE ".CONFIG_TABLE."
+  SET value = 'yoga'
+  WHERE param = 'default_template'
+;",
+
+  "
+INSERT INTO ".CONFIG_TABLE."
+  (param,value,comment)
+  VALUES
+  (
+    'gallery_title',
+    'PhpWebGallery demonstration site',
+    'Title at top of each page and for RSS feed'
+  )
+;",
+
+  "
+INSERT INTO ".CONFIG_TABLE."
+  (param,value,comment)
+  VALUES
+  (
+    'gallery_description',
+    'My photos web site',
+    'Short description displayed with gallery title'
+  )
+;"
+
+  );
+
+foreach ($queries as $query)
+{
+  $query = str_replace('phpwebgallery_', PREFIX_TABLE, $query);
+  pwg_query($query);
+}
+
+// delete obsolete users table colums
+$queries = array(
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN status
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN nb_image_line
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN maxheight
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN language
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN nb_line_page
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN expand
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN template
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN maxwidth
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN show_nb_comments
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN recent_period
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  CHANGE COLUMN password password varchar(32) default NULL
+;"
+  );
+
+foreach ($queries as $query)
+{
+  $query = str_replace('phpwebgallery_', PREFIX_TABLE, $query);
+  pwg_query($query);
+}
+
+$infos = array();
+
+if ($prefix_thumbnail != 'TN-')
+{
+  array_push(
+    $infos,
+    'the thumbnail prefix configuration parameter was moved to configuration
+file, copy config_local.inc.php from "tools" directory to "include" directory
+and edit $conf[\'prefix_thumbnail\'] = '.$prefix_thumbnail
+    );
+}
+
+?>
Index: /branches/1.5/install/upgrade_1.4.1.php
===================================================================
--- /branches/1.5/install/upgrade_1.4.1.php	(revision 3250)
+++ /branches/1.5/install/upgrade_1.4.1.php	(revision 3250)
@@ -0,0 +1,366 @@
+<?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 ('This page cannot be loaded directly, load upgrade.php');
+}
+else
+{
+  if (!defined('PHPWG_IN_UPGRADE') or !PHPWG_IN_UPGRADE)
+  {
+    die ('Hacking attempt!');
+  }
+}
+
+$last_time = get_moment();
+
+// will the user have to edit include/config_local.inc.php for
+// prefix_thumbnail configuration parameter
+$query = '
+SELECT value
+  FROM '.CONFIG_TABLE.'
+  WHERE param = \'prefix_thumbnail\'
+;';
+list($prefix_thumbnail) = mysql_fetch_array(pwg_query($query));
+
+// delete obsolete configuration
+$query = '
+DELETE
+  FROM '.PREFIX_TABLE.'config
+  WHERE param IN (
+   \'prefix_thumbnail\',
+   \'mail_webmaster\',
+   \'upload_maxfilesize\',
+   \'upload_maxwidth\',
+   \'upload_maxheight\',
+   \'upload_maxwidth_thumbnail\',
+   \'upload_maxheight_thumbnail\',
+   \'mail_notification\',
+   \'use_iptc\',
+   \'use_exif\',
+   \'show_iptc\',
+   \'show_exif\',
+   \'authorize_remembering\'
+   )
+;';
+mysql_query($query);
+
+$queries = array(
+
+  "
+ALTER TABLE phpwebgallery_categories
+  CHANGE COLUMN date_last date_last datetime default NULL
+;",
+
+  "
+ALTER TABLE phpwebgallery_comments
+  ADD COLUMN validation_date datetime default NULL
+;",
+
+  "
+UPDATE phpwebgallery_comments
+  SET validation_date = date
+",
+
+  "
+ALTER TABLE phpwebgallery_comments
+  ADD INDEX comments_i1 (image_id)
+;",
+
+  "
+ALTER TABLE phpwebgallery_comments
+  ADD INDEX comments_i2 (validation_date)
+;",
+
+  "
+ALTER TABLE phpwebgallery_favorites
+  CHANGE COLUMN user_id user_id smallint(5) NOT NULL default '0'
+;",
+
+  "
+ALTER TABLE phpwebgallery_images
+  CHANGE COLUMN date_available
+    date_available datetime NOT NULL default '0000-00-00 00:00:00'
+;",
+
+  "
+ALTER TABLE phpwebgallery_rate
+  CHANGE COLUMN user_id user_id smallint(5) NOT NULL default '0'
+;",
+
+  "
+ALTER TABLE phpwebgallery_sessions
+  CHANGE COLUMN user_id user_id smallint(5) NOT NULL default '0'
+;",
+
+  "
+ALTER TABLE phpwebgallery_user_access
+  CHANGE COLUMN user_id user_id smallint(5) NOT NULL default '0'
+;",
+
+  "
+DROP TABLE phpwebgallery_user_forbidden
+;",
+
+  "
+ALTER TABLE phpwebgallery_user_group
+ CHANGE COLUMN user_id user_id smallint(5) NOT NULL default '0'
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  CHANGE COLUMN id id smallint(5) NOT NULL auto_increment
+;",
+
+  "
+CREATE TABLE phpwebgallery_caddie (
+  user_id smallint(5) NOT NULL default '0',
+  element_id mediumint(8) NOT NULL default '0',
+  PRIMARY KEY  (user_id,element_id)
+) TYPE=MyISAM
+;",
+
+  "
+CREATE TABLE phpwebgallery_user_cache (
+  user_id smallint(5) NOT NULL default '0',
+  need_update enum('true','false') NOT NULL default 'true',
+  forbidden_categories text,
+  PRIMARY KEY  (user_id)
+) TYPE=MyISAM
+;",
+
+  "
+CREATE TABLE phpwebgallery_user_feed (
+  id varchar(50) binary NOT NULL default '',
+  user_id smallint(5) NOT NULL default '0',
+  last_check datetime default NULL,
+  PRIMARY KEY  (id)
+) TYPE=MyISAM
+;",
+
+  "
+CREATE TABLE phpwebgallery_user_infos (
+  user_id smallint(5) NOT NULL default '0',
+  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 'yoga',
+  registration_date datetime NOT NULL default '0000-00-00 00:00:00',
+  UNIQUE KEY user_infos_ui1 (user_id)
+) TYPE=MyISAM
+;"
+  );
+
+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;
+
+// user datas migration from phpwebgallery_users to phpwebgallery_user_infos
+$query = '
+SELECT *
+  FROM '.USERS_TABLE.'
+;';
+
+$datas = array();
+list($dbnow) = mysql_fetch_row(pwg_query('SELECT NOW();'));
+
+$result = pwg_query($query);
+while ($row = mysql_fetch_array($result))
+{
+  $row['user_id'] = $row['id'];
+  $row['registration_date'] = $dbnow;
+  array_push($datas, $row);
+}
+
+include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+mass_inserts(
+  USER_INFOS_TABLE,
+  array(
+    'user_id',
+    'nb_image_line',
+    'nb_line_page',
+    'status',
+    'language',
+    'maxwidth',
+    'maxheight',
+    'expand',
+    'show_nb_comments',
+    'recent_period',
+    'template',
+    'registration_date'
+    ),
+  $datas
+  );
+
+$queries = array(
+
+  "
+UPDATE ".USER_INFOS_TABLE."
+  SET template = 'yoga'
+;",
+
+  "
+UPDATE ".USER_INFOS_TABLE."
+  SET language = 'en_UK.iso-8859-1'
+  WHERE language NOT IN ('en_UK.iso-8859-1', 'fr_FR.iso-8859-1')
+;",
+
+  "
+UPDATE ".CONFIG_TABLE."
+  SET value = 'en_UK.iso-8859-1'
+  WHERE param = 'default_language'
+    AND value NOT IN ('en_UK.iso-8859-1', 'fr_FR.iso-8859-1')
+;",
+
+  "
+UPDATE ".CONFIG_TABLE."
+  SET value = 'yoga'
+  WHERE param = 'default_template'
+;",
+
+  "
+INSERT INTO ".CONFIG_TABLE."
+  (param,value,comment)
+  VALUES
+  (
+    'gallery_title',
+    'PhpWebGallery demonstration site',
+    'Title at top of each page and for RSS feed'
+  )
+;",
+
+  "
+INSERT INTO ".CONFIG_TABLE."
+  (param,value,comment)
+  VALUES
+  (
+    'gallery_description',
+    'My photos web site',
+    'Short description displayed with gallery title'
+  )
+;"
+
+  );
+
+foreach ($queries as $query)
+{
+  $query = str_replace('phpwebgallery_', PREFIX_TABLE, $query);
+  pwg_query($query);
+}
+
+// delete obsolete users table colums
+$queries = array(
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN status
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN nb_image_line
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN maxheight
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN language
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN nb_line_page
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN expand
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN template
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN maxwidth
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN show_nb_comments
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN recent_period
+;",
+
+  "
+ALTER TABLE phpwebgallery_users
+  CHANGE COLUMN password password varchar(32) default NULL
+;"
+  );
+
+foreach ($queries as $query)
+{
+  $query = str_replace('phpwebgallery_', PREFIX_TABLE, $query);
+  pwg_query($query);
+}
+
+$infos = array();
+
+if ($prefix_thumbnail != 'TN-')
+{
+  array_push(
+    $infos,
+    'the thumbnail prefix configuration parameter was moved to configuration
+file, copy config_local.inc.php from "tools" directory to "include" directory
+and edit $conf[\'prefix_thumbnail\'] = '.$prefix_thumbnail
+    );
+}
+
+?>
Index: /branches/1.5/install/upgrade_1.5.0.php
===================================================================
--- /branches/1.5/install/upgrade_1.5.0.php	(revision 3250)
+++ /branches/1.5/install/upgrade_1.5.0.php	(revision 3250)
@@ -0,0 +1,89 @@
+<?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: 2005-10-23 23:02:21 +0200 (dim, 23 oct 2005) $
+// | last modifier : $Author: plg $
+// | revision      : $Revision: 911 $
+// +-----------------------------------------------------------------------+
+// | 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 ('This page cannot be loaded directly, load upgrade.php');
+}
+else
+{
+  if (!defined('PHPWG_IN_UPGRADE') or !PHPWG_IN_UPGRADE)
+  {
+    die ('Hacking attempt!');
+  }
+}
+
+// depending on the way the 1.5.0 was installed (from scratch or by upgrade)
+// the database structure has small differences that should be corrected.
+
+$query = '
+ALTER TABLE phpwebgallery_users
+  CHANGE COLUMN password password varchar(32) default NULL
+;';
+
+pwg_query(
+  str_replace(
+    'phpwebgallery_',
+    PREFIX_TABLE,
+    $query
+    )
+  );
+
+$to_keep = array('id', 'username', 'password', 'mail_address');
+  
+$query = '
+DESC phpwebgallery_users
+;';
+
+$result =
+pwg_query(
+  str_replace(
+    'phpwebgallery_',
+    PREFIX_TABLE,
+    $query
+    )
+  );
+
+while ($row = mysql_fetch_array($result))
+{
+  if (!in_array($row['Field'], $to_keep))
+  {
+    $query = '
+ALTER TABLE phpwebgallery_users
+  DROP COLUMN '.$row['Field'].'
+;';
+    pwg_query(
+      str_replace(
+        'phpwebgallery_',
+        PREFIX_TABLE,
+        $query
+        )
+      );
+  }
+}
+
+?>
Index: /branches/1.5/language/en_UK.iso-8859-1/about.html
===================================================================
--- /branches/1.5/language/en_UK.iso-8859-1/about.html	(revision 3250)
+++ /branches/1.5/language/en_UK.iso-8859-1/about.html	(revision 3250)
@@ -0,0 +1,13 @@
+<ul>
+
+  <li>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">PhpWebGallery</a> official site, and
+  its dedicated <a href="http://forum.phpwebgallery.net">forum</a>.</li>
+
+</ul>
Index: /branches/1.5/language/en_UK.iso-8859-1/admin.lang.php
===================================================================
--- /branches/1.5/language/en_UK.iso-8859-1/admin.lang.php	(revision 3250)
+++ /branches/1.5/language/en_UK.iso-8859-1/admin.lang.php	(revision 3250)
@@ -0,0 +1,370 @@
+<?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['%d categories including %d physical and %d virtual'] = '%d categories including %d physical and %d virtual';
+$lang['%d categories moved'] = '%d categories moved';
+$lang['%d comments'] = '%d comments';
+$lang['%d elements'] = '%d elements';
+$lang['%d groups'] = '%d groups';
+$lang['%d members'] = '%d members';
+$lang['%d user comments rejected'] = '%d user comments rejected';
+$lang['%d user comments validated'] = '%d user comments validated';
+$lang['%d users deleted'] = '%d users deleted';
+$lang['%d users'] = '%d users';
+$lang['%d waiting for validation'] = '%d waiting for validation';
+$lang['%d waiting pictures rejected'] = '%d waiting pictures rejected';
+$lang['%d waiting pictures validated'] = '%d waiting pictures validated';
+$lang['A new version of PhpWebGallery is available.'] = 'A new version of PhpWebGallery is available.';
+$lang['Actions'] = 'Actions';
+$lang['Add a user'] = 'Add a user';
+$lang['Add group'] = 'Add group';
+$lang['Add selected elements to caddie'] = 'Add selected elements to caddie';
+$lang['Add'] = 'Add';
+$lang['Associated'] = 'Associated';
+$lang['Association to categories'] = 'Association to categories';
+$lang['Batch management'] = 'Batch management';
+$lang['Caddie management'] = 'Caddie management';
+$lang['Caddie'] = 'Caddie';
+$lang['Categories authorized thanks to group associations'] = 'Categories authorized thanks to group associations';
+$lang['Check for upgrade failed for unknown reasons.'] = 'Check for upgrade failed for unknown reasons.';
+$lang['Check for upgrade'] = 'Check for upgrade';
+$lang['Comments for all'] = 'Comments for all';
+$lang['Creation date'] = 'Creation date';
+$lang['Database'] = 'Database';
+$lang['Delete Representant'] = 'Delete Representant';
+$lang['Delete selected users'] = 'Delete selected users';
+$lang['Deletions'] = 'Deletions';
+$lang['Deny selected groups'] = 'Deny selected groups';
+$lang['Deny selected users'] = 'Deny selected users';
+$lang['Description'] = 'Description';
+$lang['Display options'] = 'Display options';
+$lang['Dissociated'] = 'Dissociated';
+$lang['Does not represent'] = 'Does not represent';
+$lang['Edit all picture informations'] = 'Edit all picture informations';
+$lang['Elements'] = 'Elements';
+$lang['Empty caddie'] = 'Empty caddie';
+$lang['Environment'] = 'Environment';
+$lang['Expand all categories'] = 'Expand all categories';
+$lang['Form'] = 'Form';
+$lang['Gallery description'] = 'Gallery description';
+$lang['Gallery title'] = 'Gallery title';
+$lang['Grant selected groups'] = 'Grant selected groups';
+$lang['Grant selected users'] = 'Grant selected users';
+$lang['Group name'] = 'Group name';
+$lang['Groups'] = 'Groups';
+$lang['History'] = 'History';
+$lang['Informations'] = 'Informations';
+$lang['Interface theme'] = 'Interface theme';
+$lang['Language'] = 'Language';
+$lang['Linked categories'] = 'Linked categories';
+$lang['Lock gallery'] = 'Lock gallery';
+$lang['Maintenance'] = 'Maintenance';
+$lang['Manage permissions for a category'] = 'Manage permissions for a category';
+$lang['Manage permissions for group "%s"'] = 'Manage permissions for group "%s"';
+$lang['Manage permissions for user "%s"'] = 'Manage permissions for user "%s"';
+$lang['Maximum height of the pictures'] = 'Maximum height of the pictures';
+$lang['Maximum width of the pictures'] = 'Maximum width of the pictures';
+$lang['Members'] = 'Members';
+$lang['Metadata synchronized from file'] = 'Metadata synchronized from file';
+$lang['Move categories'] = 'Move categories';
+$lang['Move'] = 'Move';
+$lang['Name'] = 'Name';
+$lang['New parent category'] = 'New parent category';
+$lang['No'] = 'No';
+$lang['Number of comments per page'] = 'Number of comments per page';
+$lang['Number of images per row'] = 'Number of images per row';
+$lang['Number of rows per page'] = 'Number of rows per page';
+$lang['Number of thumbnails to create'] = 'Number of thumbnails to create';
+$lang['Only private categories are listed'] = 'Only private categories are listed';
+$lang['Operating system'] = 'Operating system';
+$lang['Options'] = 'Options';
+$lang['Order by'] = 'Order by';
+$lang['Other private categories'] = 'Other private categories';
+$lang['Parent category'] = 'Parent category';
+$lang['Path'] = 'Path';
+$lang['Permission denied'] = 'Permission denied';
+$lang['Permission granted thanks to a group'] = 'Permission granted thanks to a group';
+$lang['Permission granted'] = 'Permission granted';
+$lang['PhpWebGallery Administration'] = 'PhpWebGallery Administration';
+$lang['PhpWebGallery version'] = 'PhpWebGallery version';
+$lang['Picture informations updated'] = 'Picture informations updated';
+$lang['Position'] = 'Position';
+$lang['Preferences'] = 'Preferences';
+$lang['Properties'] = 'Properties';
+$lang['Random picture'] = 'Random picture';
+$lang['Recent period'] = 'Recent period';
+$lang['Registration date'] = 'Registration date';
+$lang['Reject All'] = 'Reject All';
+$lang['Reject'] = 'Reject';
+$lang['Representant'] = 'Representant';
+$lang['Representation of categories'] = 'Representation of categories';
+$lang['Representative'] = 'Representative';
+$lang['Represents'] = 'Represents';
+$lang['Save order'] = 'Save order';
+$lang['Select at least one category'] = 'Select at least one category';
+$lang['Select at least one picture'] = 'Select at least one picture';
+$lang['Select at least one user'] = 'Select at least one user';
+$lang['Show info'] = 'Show info';
+$lang['Show number of comments'] = 'Show number of comments';
+$lang['Status'] = 'Status';
+$lang['Storage category'] = 'Storage category';
+$lang['Submit'] = 'Submit';
+$lang['Take selected elements out of caddie'] = 'Take selected elements out of caddie';
+$lang['Unable to check for upgrade since allow_url_fopen is disabled.'] = 'Unable to check for upgrade since allow_url_fopen is disabled.';
+$lang['User comments validation'] = 'User comments validation';
+$lang['Users'] = 'Users';
+$lang['Validate All'] = 'Validate All';
+$lang['Validate'] = 'Validate';
+$lang['Validation'] = 'Validation';
+$lang['Virtual categories movement'] = 'Virtual categories movement';
+$lang['Virtual categories to move'] = 'Virtual categories to move';
+$lang['Webmaster cannot be deleted'] = 'Webmaster cannot be deleted';
+$lang['Yes'] = 'Yes';
+$lang['You are running on development sources, no check possible.'] = 'You are running on development sources, no check possible.';
+$lang['You are running the latest version of PhpWebGallery.'] = 'You are running the latest version of PhpWebGallery.';
+$lang['You cannot move a category in its own sub category'] = 'You cannot move a category in its own sub category';
+$lang['You need to confirm deletion'] = 'You need to confirm deletion';
+$lang['actions'] = 'actions';
+$lang['add keywords'] = 'add keywords';
+$lang['associate to category'] = 'associate to category';
+$lang['associate to group'] = 'associate to group';
+$lang['author'] = 'author';
+$lang['authorized'] = 'Authorized';
+$lang['cat_add'] = 'Add a virtual category';
+$lang['cat_comments_title'] = 'Authorize users to add comments on selected categories';
+$lang['cat_error_name'] = 'The name of a category should not be empty';
+$lang['cat_image_info'] = 'Images info';
+$lang['cat_lock_title'] = 'Lock categories';
+$lang['cat_private'] = 'Private category';
+$lang['cat_public'] = 'Public category';
+$lang['cat_representant'] = 'Find a new representant by random';
+$lang['cat_security'] = 'Public / Private';
+$lang['cat_status_title'] = 'Manage authorizations for selected categories';
+$lang['cat_upload_title'] = 'Select uploadable categories';
+$lang['cat_virtual_added'] = 'Virtual category added';
+$lang['cat_virtual_deleted'] = 'Virtual category deleted';
+$lang['category'] = 'category';
+$lang['conf_access'] = 'Access type';
+$lang['conf_comments_title'] = 'Users comments';
+$lang['conf_confirmation'] = 'Information data registered in database';
+$lang['conf_default'] = 'Default display';
+$lang['conf_default_title'] = 'Default display';
+$lang['conf_general_title'] = 'Main configuration';
+$lang['conf_nb_comment_page_error'] = 'The number of comments a page must be between 5 and 50 included.';
+$lang['config'] = 'Configuration';
+$lang['confirm'] = 'confirm';
+$lang['creation date'] = 'creation date';
+$lang['date'] = 'date';
+$lang['delete category'] = 'delete category';
+$lang['description'] = 'description';
+$lang['dissociate from category'] = 'dissociate from category';
+$lang['dissociate from group'] = 'dissociate from group';
+$lang['down'] = 'Move down';
+$lang['edit category permissions'] = 'edit category permissions';
+$lang['edit'] = 'Edit';
+$lang['editcat_confirm'] = 'Category informations updated successfully.';
+$lang['editcat_uploadable'] = 'Authorize upload';
+$lang['elements per line'] = 'elements per line';
+$lang['elements per page'] = 'elements per page';
+$lang['elements'] = 'elements';
+$lang['file'] = 'file';
+$lang['filesize'] = 'filesize';
+$lang['first element added on %s'] = 'first element added on %s';
+$lang['forbidden'] = 'Forbidden';
+$lang['general'] = 'General';
+$lang['global mode'] = 'global mode';
+$lang['group "%s" added'] = 'group "%s" added';
+$lang['group "%s" deleted'] = 'group "%s" deleted';
+$lang['group'] = '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_add_user']= 'Add user';
+$lang['group_id URL parameter is missing'] = 'group_id URL parameter is missing';
+$lang['groups'] = 'Groups';
+$lang['history'] = 'History';
+$lang['instructions'] = 'Instructions';
+$lang['jump to category'] = 'jump to category';
+$lang['jump to image'] = 'jump to image';
+$lang['jump to'] = 'jump to';
+$lang['leave'] = 'leave';
+$lang['links'] = 'Links';
+$lang['lock'] = 'Lock';
+$lang['locked'] = 'Locked';
+$lang['manage category elements'] = 'manage category elements';
+$lang['manage sub-categories'] = 'manage sub-categories';
+$lang['manage'] = 'Manage';
+$lang['metadata_basic'] = 'basic';
+$lang['metadata_exif'] = 'EXIF';
+$lang['metadata_iptc'] = 'IPTC';
+$lang['name'] = 'name';
+$lang['no_write_access'] = 'no write access';
+$lang['order_by'] = 'order by';
+$lang['path'] = 'path';
+$lang['permissions'] = 'Permissions';
+$lang['permuser_info'] = 'Only private categories are listed. Private/Public category status can be set in screen "Categories &gt; Public / Private"';
+$lang['permuser_only_private'] = 'Only private categories are shown';
+$lang['pictures'] = 'pictures';
+$lang['private'] = 'private';
+$lang['public'] = 'public';
+$lang['purge history'] = 'purge history';
+$lang['purge never used notification feeds'] = 'purge never used notification feeds';
+$lang['purge sessions'] = 'purge sessions';
+$lang['randomly represented'] = 'randomly represented';
+$lang['registration_date'] = 'registration date';
+$lang['remote_site'] = 'Remote site';
+$lang['remote_site_already_exists'] = 'This site already exists';
+$lang['remote_site_clean'] = 'clean';
+$lang['remote_site_clean_hint'] = 'remove remote listing.xml file';
+$lang['remote_site_create'] = 'Create a new site : (give its URL to create_listing_file.php)';
+$lang['remote_site_created'] = 'created';
+$lang['remote_site_delete'] = 'delete';
+$lang['remote_site_delete_hint'] = 'delete this site and all its attached elements';
+$lang['remote_site_deleted'] = 'deleted';
+$lang['remote_site_error'] = 'an error happened';
+$lang['remote_site_file_not_found'] = 'file create_listing_file.php on remote site was not found';
+$lang['remote_site_generate'] = 'generate listing';
+$lang['remote_site_generate_hint'] = 'generate file listing.xml on remote site';
+$lang['remote_site_listing_not_found'] = 'listing.xml file was not found';
+$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';
+$lang['remote_site_removed'] = 'was removed on remote site';
+$lang['remote_site_removed_title'] = 'Removed elements';
+$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_update'] = 'update';
+$lang['remote_site_update_hint'] = 'read remote listing.xml and updates database';
+$lang['remote_sites'] = 'Remote sites';
+$lang['remove keyword'] = 'remove keyword';
+$lang['selection'] = 'selection';
+$lang['set to'] = 'set to';
+$lang['singly represented'] = 'singly represented';
+$lang['stats_addr'] = 'IP Address';
+$lang['stats_category'] = 'Category';
+$lang['stats_daily_graph_title'] = 'Pages seen by hour';
+$lang['stats_day_title'] = 'Daily statistics';
+$lang['stats_file'] = 'File';
+$lang['stats_global_graph_title'] = 'Pages seen by month';
+$lang['stats_hour'] = 'Hour';
+$lang['stats_login'] = 'Login';
+$lang['stats_month_title'] = 'Monthly statistics';
+$lang['stats_monthly_graph_title'] = 'Pages seen by day';
+$lang['stats_pages_seen'] = 'Pages seen';
+$lang['stats_picture'] = 'Picture';
+$lang['stats_title'] = 'Last year statistics';
+$lang['status'] = 'status';
+$lang['storage'] = 'Directory';
+$lang['sub-categories'] = 'sub-categories';
+$lang['synchronize metadata'] = 'synchronize metadata';
+$lang['synchronize'] = 'synchronize';
+$lang['target'] = 'target';
+$lang['thumbnail'] = 'thumbnail';
+$lang['title'] = 'title';
+$lang['title_cat_options'] = 'Categories options';
+$lang['title_categories'] = 'Categories management';
+$lang['title_configuration'] = 'PhpWebGallery configuration';
+$lang['title_default'] = 'PhpWebGallery administration';
+$lang['title_edit_cat'] = 'Edit a category';
+$lang['title_groups'] = 'Groups management';
+$lang['title_history'] = 'History';
+$lang['title_liste_users'] = 'Users list';
+$lang['title_picmod'] = 'Modify informations about a picture';
+$lang['title_thumbnails'] = 'Thumbnail creation';
+$lang['title_update'] = 'Database synchronization with files';
+$lang['title_waiting'] = 'Pictures waiting for validation';
+$lang['tn_all'] = 'all';
+$lang['tn_alone_title'] = 'pictures without thumbnail (jpeg and png only)';
+$lang['tn_dirs_alone'] = 'pictures without thumbnail';
+$lang['tn_dirs_title'] = 'Directories list';
+$lang['tn_err_height'] = 'height must be a number superior to';
+$lang['tn_err_width'] = 'width must be a number superior to';
+$lang['tn_format'] = 'for the file format';
+$lang['tn_height'] = 'height';
+$lang['tn_no_missing'] = 'No missing thumbnail';
+$lang['tn_no_support'] = 'Picture unreachable or no support';
+$lang['tn_params_GD'] = 'GD version';
+$lang['tn_params_create'] = 'create';
+$lang['tn_params_title'] = 'Miniaturization parameters';
+$lang['tn_results_gen_time'] = 'generated in';
+$lang['tn_results_title'] = 'Results of miniaturization';
+$lang['tn_stats'] = 'General statistics';
+$lang['tn_stats_max'] = 'max time';
+$lang['tn_stats_mean'] = 'average time';
+$lang['tn_stats_min'] = 'min time';
+$lang['tn_stats_nb'] = 'number of miniaturized pictures';
+$lang['tn_stats_total'] = 'total time';
+$lang['tn_thisformat'] = 'for this file format';
+$lang['tn_width'] = 'width';
+$lang['unit mode'] = 'unit mode';
+$lang['unlocked'] = 'Unlocked';
+$lang['unset'] = 'unset';
+$lang['up'] = 'Move up';
+$lang['update categories informations'] = 'update categories informations';
+$lang['update images informations'] = 'update images informations';
+$lang['update'] = 'Synchronize';
+$lang['update_cats_subset'] = 'reduce to single existing categories';
+$lang['update_default_title'] = 'Choose an option';
+$lang['update_display_info'] = 'display maximum informations (added categories and elements, deleted categories and elements)';
+$lang['update_elements_metadata_sync'] = 'elements informations synchronized with files metadata';
+$lang['update_error_list_title'] = 'Error list';
+$lang['update_errors_caption'] = 'Errors caption';
+$lang['update_infos_title'] = 'Detailed informations';
+$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_missing_tn_short'] = 'missing thumbnail';
+$lang['update_nb_del_categories'] = 'categories deleted in the database';
+$lang['update_nb_del_elements'] = 'elements deleted in the database';
+$lang['update_nb_errors'] = 'errors during synchronization';
+$lang['update_nb_new_categories'] = 'categories added in the database';
+$lang['update_nb_new_elements'] = 'elements added in the database';
+$lang['update_part_research'] = 'Search for new images in the directories';
+$lang['update_research_added'] = 'added';
+$lang['update_research_deleted'] = 'deleted';
+$lang['update_result_metadata'] = 'Metadata synchronization results';
+$lang['update_simulate'] = 'only perform a simulation (no change in database will be made)';
+$lang['update_simulation_title'] = '[Simulation]';
+$lang['update_sync_all'] = 'directories + files';
+$lang['update_sync_dirs'] = 'only directories';
+$lang['update_sync_files'] = 'synchronize files structure with database';
+$lang['update_sync_metadata'] = 'synchronize files metadata with database elements informations';
+$lang['update_sync_metadata_all'] = 'even already synchronized elements';
+$lang['update_sync_metadata_new'] = 'only never synchronized elements';
+$lang['update_used_metadata'] = 'Used metadata';
+$lang['update_wrong_dirname_info'] = 'The name of directories and files must be composed of letters, figures, "-", "_" or "."';
+$lang['update_wrong_dirname_short'] = 'wrong filename';
+$lang['upload'] = 'Upload';
+$lang['user "%s" added'] = 'user "%s" added';
+$lang['user_delete'] = 'Delete user';
+$lang['user_delete_hint'] = 'Click here to delete this user. Warning! This operation cannot be undone!';
+$lang['user_id URL parameter is missing'] = 'user_id URL parameter is missing';
+$lang['user_status'] = 'User status';
+$lang['user_status_admin'] = 'Administrator';
+$lang['user_status_guest'] = 'User';
+$lang['username'] = 'username';
+$lang['users'] = 'Users';
+$lang['visitors'] = 'Visitors';
+$lang['w_day'] = 'Day';
+$lang['waiting'] = 'Waiting';
+?>
Index: /branches/1.5/language/en_UK.iso-8859-1/common.lang.php
===================================================================
--- /branches/1.5/language/en_UK.iso-8859-1/common.lang.php	(revision 3250)
+++ /branches/1.5/language/en_UK.iso-8859-1/common.lang.php	(revision 3250)
@@ -0,0 +1,307 @@
+<?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';
+
+$lang['%.2f (rated %d times, standard deviation = %.2f)'] = '%.2f (rated %d times, standard deviation = %.2f)';
+$lang['%d Kb'] = '%d Kb';
+$lang['%d categories updated'] = '%d categories updated';
+$lang['%d comments to validate'] = '%d comments to validate';
+$lang['%d new comments'] = '%d new comments';
+$lang['%d new elements'] = '%d new elements';
+$lang['%d new users'] = '%d new users';
+$lang['%d waiting elements'] = '%d waiting elements';
+$lang['About'] = 'About';
+$lang['Author'] = 'Author';
+$lang['Average rate'] = 'Average rate';
+$lang['Categories'] = 'Categories';
+$lang['Category'] = 'Category';
+$lang['Close this window'] = 'Close this window';
+$lang['Confirm Password'] = 'Confirm Password';
+$lang['Connection'] = 'Connection';
+$lang['Connection settings'] = 'Connection settings';
+$lang['Contact webmaster'] = 'Contact webmaster';
+$lang['Create a new account'] = 'Create a new account';
+$lang['Created on'] = 'Created on';
+$lang['Current password is wrong'] = 'Current password is wrong';
+$lang['Dimensions'] = 'Dimensions';
+$lang['Display'] = 'Display';
+$lang['Email address is missing'] = 'Email address is missing';
+$lang['Email address'] = 'Email address';
+$lang['Enter your personnal informations'] = 'Enter your personnal informations';
+$lang['Error sending email'] = 'Error sending email';
+$lang['File'] = 'File';
+$lang['Filesize'] = 'Filesize';
+$lang['Filter and display'] = 'Filter and display';
+$lang['Filter'] = 'Filter';
+$lang['Forgot your password?'] = 'Forgot your password?';
+$lang['Go through the gallery as a visitor'] = 'Go through the gallery as a visitor';
+$lang['Help'] = 'Help';
+$lang['Identification'] = 'Identification';
+$lang['Keyword'] = 'Keyword';
+$lang['Keywords'] = 'Keywords';
+$lang['Links'] = 'Links';
+$lang['Mail address'] = 'Mail address';
+$lang['N/A'] = 'N/A';
+$lang['New on %s'] = 'New on %s';
+$lang['New password confirmation does not correspond'] = 'New password confirmation does not correspond';
+$lang['New password sent by email'] = 'New password sent by email';
+$lang['No email address'] = 'No email address';
+$lang['No user matches this email address'] = 'No user matches this email address';
+$lang['Notification'] = 'Notification';
+$lang['Number of items'] = 'Number of items';
+$lang['Original dimensions'] = 'Original dimensions';
+$lang['Password forgotten'] = 'Password forgotten';
+$lang['Password'] = 'Password';
+$lang['PhpWebGallery Help'] = 'PhpWebGallery Help';
+$lang['Profile'] = 'Profile';
+$lang['RSS feed'] = 'RSS feed';
+$lang['Register'] = 'Register';
+$lang['Registered on'] = 'Registered on';
+$lang['Registration'] = 'Registration';
+$lang['Reset'] = 'Reset';
+$lang['Retrieve password'] = 'Retrieve password';
+$lang['Search'] = 'Search';
+$lang['Send new password'] = 'Send new password';
+$lang['Since'] = 'Since';
+$lang['Sort by'] = 'Sort by';
+$lang['Sort order'] = 'Sort order';
+$lang['The RSS notification feed provides notification on news from this website : new pictures, updated categories, new comments. Use a RSS feed reader.'] = 'The RSS notification feed provides notification on news from this website : new pictures, updated categories, new comments. Use a RSS feed reader.';
+$lang['Unknown feed identifier'] = 'Unknown feed identifier';
+$lang['User comments'] = 'User comments';
+$lang['Username'] = 'Username';
+$lang['Visits'] = 'Visits';
+$lang['Webmaster'] = 'Webmaster';
+$lang['about_page_title'] = 'About PhpWebGallery';
+$lang['access_forbiden'] = 'You are not authorized to access this page';
+$lang['add to caddie'] = 'add to caddie';
+$lang['add_favorites_alt'] = 'Add to favorites';
+$lang['add_favorites_hint'] = 'Add this picture to your favorites';
+$lang['admin'] = 'Administration';
+$lang['all_categories'] = 'all categories';
+$lang['already_rated'] = 'You\'ve already rated this item';
+$lang['auto_expand'] = 'Expand all categories';
+$lang['best_rated_cat'] = 'best rated';
+$lang['best_rated_cat_hint'] = 'displays best rated items';
+$lang['caddie'] = 'caddie';
+$lang['calendar'] = 'Calendar';
+$lang['calendar_hint'] = 'displays each day with pictures, month per month';
+$lang['calendar_picture_hint'] = 'displays pictures added on ';
+$lang['categories'] = 'Categories';
+$lang['comment'] = 'Comment';
+$lang['comment_added'] = 'Your comment has been registered';
+$lang['comment_anti-flood'] = 'Anti-flood system : please wait for a moment before trying to post another comment';
+$lang['comment_to_validate'] = 'An administrator must authorize your comment before it is visible.';
+$lang['comment_user_exists'] = 'This login is already used by another user';
+$lang['comments'] = 'Comments';
+$lang['comments_add'] = 'Add a comment';
+$lang['comments_del'] = 'delete this comment';
+$lang['comments_title'] = 'Comments from the users of the site';
+$lang['confirm_password_hint'] = 'You only have to confirm your new password if you wish to change it.';
+$lang['customize'] = 'Customize';
+$lang['customize_page_title'] = 'Your Gallery Customization ';
+$lang['customize_title'] = 'Customization';
+$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['days'] = 'days';
+$lang['del_favorites_alt'] = 'Delete from favorites';
+$lang['del_favorites_hint'] = 'Delete this picture from your favorites';
+$lang['delete'] = 'Delete';
+$lang['download'] = 'download';
+$lang['download_hint'] = 'download this file';
+$lang['edit category informations'] = 'edit category informations';
+$lang['edit'] = 'edit';
+$lang['err_date'] = 'wrong date';
+$lang['favorite_cat'] = 'My favorites';
+$lang['favorite_cat_hint'] = 'display my favorites pictures';
+$lang['favorites'] = 'Favorites';
+$lang['first_page'] = 'First';
+$lang['gallery_locked_message'] = 'The gallery is locked for maintenance. Please, come back later.';
+$lang['generation_time'] = 'Page generated in';
+$lang['guest'] = 'guest';
+$lang['hello'] = 'Hello';
+$lang['hint_admin'] = 'available for administrators only';
+$lang['hint_category'] = 'shows images at the root of this categry';
+$lang['hint_comments'] = 'See last users comments';
+$lang['hint_customize'] = 'customize the appareance of the gallery';
+$lang['hint_search'] = 'search';
+$lang['home'] = 'Home';
+$lang['home_hint'] = 'Back to the home page';
+$lang['ident_forgotten_password'] = 'Forget your password ?';
+$lang['ident_guest_visit'] = 'Go through the gallery as a visitor';
+$lang['ident_register'] = 'Register';
+$lang['ident_title'] = 'ident_title';
+$lang['identification'] = 'Identification';
+$lang['images_available'] = 'images in this category';
+$lang['invalid_pwd'] = 'Invalid password!';
+$lang['language']='Language';
+$lang['last %d days'] = 'last %d days';
+$lang['last_page'] = 'Last';
+$lang['link_info_image'] = 'Modify information';
+$lang['login'] = 'Login';
+$lang['logout'] = 'Logout';
+$lang['mail_address'] = 'E-mail address';
+$lang['mandatory'] = 'obligatory';
+$lang['maxheight'] = 'Maximum height of the pictures';
+$lang['maxheight_error'] = 'Maximum height must be a number superior to 50';
+$lang['maxwidth'] = 'Maximum width of the pictures';
+$lang['maxwidth_error'] = 'Maximum width must be a number superior to 50';
+$lang['month'][10] = 'October';
+$lang['month'][11] = 'November';
+$lang['month'][12] = 'December';
+$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['most_visited_cat'] = 'Most visited';
+$lang['most_visited_cat_hint'] = 'displays most visited pictures';
+$lang['nb_image_per_row'] = 'Number of images per row';
+$lang['nb_row_per_page'] = 'Number of rows per page';
+$lang['never_rated'] = 'You\'ve never rated this item';
+$lang['new_password'] = 'New password';
+$lang['new_password_hint'] = 'You only have to give a password if you wish to change it.';
+$lang['next_page'] = 'Next';
+$lang['no'] = 'No';
+$lang['no_category'] = 'Home';
+$lang['no_rate'] = 'no rate';
+$lang['notification'] = 'notification';
+$lang['only_members'] = 'Only members can access this page';
+$lang['password updated'] = 'password updated';
+$lang['password'] = 'Password';
+$lang['password_hint'] = 'You only have to give your password if you wish to change your e-mail';
+$lang['periods_error'] = 'Recent period must be a positive integer value';
+$lang['picture_high'] = 'Click on the picture to see it in high definition';
+$lang['picture_show_metadata'] = 'Show file metadata';
+$lang['powered_by'] = 'Powered by';
+$lang['preferences'] = 'Preferences';
+$lang['previous_page'] = 'Previous';
+$lang['random_cat'] = 'Random pictures';
+$lang['random_cat_hint'] = 'Displays a set of random pictures';
+$lang['recent_cats_cat'] = 'Last categories';
+$lang['recent_cats_cat_hint'] = 'Displays recently updated categories';
+$lang['recent_image'] = 'Image within the';
+$lang['recent_period'] = 'Recent period';
+$lang['recent_pics_cat'] = 'Last pictures';
+$lang['recent_pics_cat_hint'] = 'Displays most recent pictures';
+$lang['reg_confirm'] = 'Confirm password';
+$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_login5'] = 'this login is already used';
+$lang['reg_err_mail_address'] = 'mail address must be like xxx@yyy.eee (example : jack@altern.org)';
+$lang['reg_err_pass'] = 'please enter your password again';
+$lang['register'] = 'register';
+$lang['register_page_title'] = 'Registration';
+$lang['register_title'] = 'Registration';
+$lang['remember_me'] = 'Auto login';
+$lang['representative'] = 'representative';
+$lang['reset'] = 'Reset';
+$lang['return to homepage'] = 'return to homepage';
+$lang['search'] = 'Search';
+$lang['search_ascending'] = 'Ascending';
+$lang['search_author'] = 'Search for Author';
+$lang['search_categories'] = 'Search in Categories';
+$lang['search_date'] = 'Search by Date';
+$lang['search_date_available'] = 'Availability';
+$lang['search_date_creation'] = 'Creation';
+$lang['search_date_from'] = 'Date';
+$lang['search_date_to'] = 'End-Date';
+$lang['search_date_type'] = 'Kind of date';
+$lang['search_descending'] = 'Descending';
+$lang['search_explain'] = 'Use * as a wildcard for partial matches';
+$lang['search_keywords'] = 'Search for words';
+$lang['search_mode_and'] = 'Search for all terms ';
+$lang['search_mode_or'] = 'Search for any terms';
+$lang['search_one_clause_at_least'] = 'Empty query. No criteria has been entered.';
+$lang['search_options'] = 'Search Options';
+$lang['search_result'] = 'Search results';
+$lang['search_sort'] = 'Sort results by';
+$lang['search_subcats_included'] = 'Search in subcategroies';
+$lang['search_title'] = 'Search';
+$lang['send_mail'] = 'Contact';
+$lang['set as category representative'] = 'set as category representative';
+$lang['show_nb_comments'] = 'Show number of comments';
+$lang['slideshow'] = 'slideshow';
+$lang['slideshow_stop'] = 'stop the slideshow';
+$lang['special_categories'] = 'Specials';
+$lang['sql_queries_in'] = 'SQL queries in';
+$lang['sub-cat'] = 'subcategories';
+$lang['submit'] = 'Submit';
+$lang['the beginning'] = 'the beginning';
+$lang['theme'] = 'Interface theme';
+$lang['thumbnails'] = 'Thumbnails';
+$lang['title_comments'] = 'Users comments';
+$lang['title_menu'] = 'Menu';
+$lang['title_send_mail'] = 'A comment on your site';
+$lang['to_rate'] = 'Rate';
+$lang['today'] = 'today';
+$lang['total'] = 'images';
+$lang['update_rate'] = 'Update your rating';
+$lang['update_wrong_dirname'] = 'wrong filename';
+$lang['upload_advise'] = 'Choose an image to place in the category : ';
+$lang['upload_advise_filesize'] = 'the filesize of the picture must not exceed : ';
+$lang['upload_advise_filetype'] = 'the picture must be to the fileformat jpg, gif or png';
+$lang['upload_advise_height'] = 'the height of the picture must not exceed : ';
+$lang['upload_advise_thumbnail'] = 'Optional, but recommended : choose a thumbnail to associate to ';
+$lang['upload_advise_width'] = 'the width of the picture must not exceed : ';
+$lang['upload_author'] = 'Author (eg "Pierrick LE GALL")';
+$lang['upload_cannot_upload'] = 'can\'t upload the picture on the server';
+$lang['upload_creation_date'] = 'Creation date (DD/MM/YYYY)';
+$lang['upload_err_username'] = 'the username must be given';
+$lang['upload_file_exists'] = 'A picture\'s name already used';
+$lang['upload_filenotfound'] = 'You must choose a picture fileformat for the image';
+$lang['upload_forbidden'] = 'You can\'t upload pictures in this category';
+$lang['upload_name'] = 'Name of the picture';
+$lang['upload_picture'] = 'Upload a picture';
+$lang['upload_successful'] = 'Picture uploaded with success, an administrator will validate it as soon as possible';
+$lang['upload_title'] = 'Upload a picture';
+$lang['upload_username'] = 'Username';
+$lang['useful when password forgotten'] = 'useful when password forgotten';
+$lang['w_month'] = 'Month';
+$lang['yes'] = 'Yes';
+
+$lang['descending'] = 'descending';
+$lang['all'] = 'all';
+$lang['ascending'] = 'ascending';
+$lang['comment date'] = 'comment date';
+$lang['picture'] = 'picture';
+?>
Index: /branches/1.5/language/en_UK.iso-8859-1/help.html
===================================================================
--- /branches/1.5/language/en_UK.iso-8859-1/help.html	(revision 3250)
+++ /branches/1.5/language/en_UK.iso-8859-1/help.html	(revision 3250)
@@ -0,0 +1,259 @@
+<h2>Help</h2>
+
+<h3>Quick start</h3>
+
+<ol>
+  
+  <li>Create a local directory "test_category".</li>
+
+  <li>Copy pictures in "test_category".</li>
+
+  <li>Open an FTP connection to this remote gallery.</li>
+
+  <li>Upload local directory "test_category" into your remote directory
+  names "galleries". Set authorizations to 777 on directory
+  "galleries/test_category".</li>
+
+  <li>Connect to your PhpWebGallery as an admin.</li>
+
+  <li>Go to <span class="pwgScreen">Administration, Pictures,
+  Thumbnails</span>. PhpWebGallery find the picture from "test_category"
+  without thumbnails. Ask to create thumbnails.</li>
+
+  <li>Go to <span class="pwgScreen">Administration, General,
+  Synchronize</span>. Check "directories + files" option, uncheck "only
+  perform a simulation" and submit the synchronization.</li>
+
+  <li>Job's done. You've created a category "test_category" at the root of
+your gallery.</li>
+  
+</ol>
+
+<h3>Adding elements</h3>
+
+<ul>
+
+  <li>
+
+    <p>Category directories are in the PhpWebGallery directory
+    "galleries". Here follow the directory tree of a very small gallery (but
+    using many features) :</p>
+
+    <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>
+
+  </li>
+  
+  <li>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.</li>
+
+  <li>Basically, an element is represented by a file. A file can be a
+  PhpWebGallery element if its extenstion is among <code>file_ext</code>
+  configuration parameter possibilities (see <span
+  class="filename">include/config_default.inc.php</span> file). A file can
+  be a picture if its extension is among <code>picture_ext</code>
+  configuration parameter possibilities.</li>
+
+  <li>Picture elements must have an associated thumbnail (see section below
+  about thumbnails)</li>
+
+  <li>Picture elements can have a high quality file associated. As for
+  wedding.jpgin the example above. No prefix on the high quality picture is
+  required.</li>
+
+  <li>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).</li>
+
+  <li><em>Warning</em> : the name of directories and files must be composed
+of letters, figures, "-", "_" or ".". No blank space, no accentuated
+characters</li>
+
+  <li><em>Advise</em> : 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 <strong>or</strong> category
+containing sub-categories.</li>
+
+  <li>Once files, thumbnails and representatives are correctly placed in the
+  directories, go to : <span class="pwgScreen">Administration, General,
+  Synchronize</span></li>
+
+</ul>
+
+<h3>Thumbnails</h3>
+
+<ul>
+
+  <li>As said earlier, each element of picture type must be associated with
+  a thumbnail.</li>
+
+  <li>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).</li>
+
+  <li>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).</li>
+
+  <li>Advise: use an external module for thumbnails creation.</li>
+
+  <li>You can also use the thumbnail creation page (<span
+  class="pwgScreen">Administration, Pictures, Thumbnails</span>), but it is
+  not recommended. Indeed, thumbnail quality may be poor and it uses a high
+  CPU load which can be a problem if you use free web hosting.</li>
+
+  <li>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).</li>
+
+</ul>
+
+<h3>Access authorization</h3>
+
+<ul>
+
+  <li>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.</li>
+
+  <li>You can set a category to private by editing a single category (<span
+  class="pwgScreen">Administration, Categories, Manage, edit</span>) or by
+  setting options to your whole category tree (<span
+  class="pwgScreen">Administration, Categories, Public/Private</span>).</li>
+
+  <li>
+
+    <p>Once the category is private, you can manage permissions for groups
+    and users through 3 screens :(administration panel, Permissions).</p>
+
+    <ul>
+
+      <li><span class="pwgScreen">Administration, Identification, Users,
+      permissions action (one link per user)</span></li>
+
+      <li><span class="pwgScreen">Administration, Identification, Groups,
+      permissions action (one link per group)</span></li>
+
+      <li><span class="pwgScreen">Administration, Categories, Manage, edit
+      category permissions action (one link per category)</span></li>
+
+    </ul>
+
+  </li>
+
+</ul>
+
+<h3>Users Groups</h3>
+
+<ul>
+
+  <li>PhpWebGallery is able to manage groups of users. It can be very useful
+  to have common permission access for private categories.</li>
+
+  <li>You can create groups in <span class="pwgScreen">Administration,
+  Identification, Groups</span> and associate users to this group in <span
+  class="pwgScreen">Administration, Identication, Users</span>.</li>
+
+  <li>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".</li>
+
+</ul>
+
+<h3>Files upload by users</h3>
+
+<p>PhpWebGallery offers the possibility for users to upload images. in
+order to do it:</p>
+
+<ol>
+
+  <li>authorize upload on any categories (<span
+  class="pwgScreen">Administration, Categories, Manage, edit</span> or <span
+  class="pwgScreen">Administration panel, Categories, Upload</span>)</li>
+
+  <li>give write rights on directories for ugo (user, group, other)</li>
+
+</ol>
+
+<p>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 in <span class="pwgScreen">Administration, Pictures, Waiting</span>
+in order to validate or to refuse the files proposed, then to synchronize
+filesystem with database.</p>
+
+
+<h3>Links between elements and categories, virtual categories</h3>
+
+<ul>
+
+  <li>PhpWebGallery dissociates categories where elements are stored and
+  categories where they are shown.</li>
+
+  <li>By default, elements are shown only in their real categories : the
+  ones corresponding to directories on the web server.</li>
+
+  <li>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.</li>
+
+  <li>Using this principle, it is possible to create virtual categories : no
+  directory coresponds to this category. You can create virtual categories
+  in <span class="pwgScreen">Administration, Categories, Manage</span>.</li>
+
+</ul>
+
+<h3>Miscellanous informations</h3>
+
+<ul>
+
+  <li>As soon as you created your gallery, modify default display properties
+  in <span class="pwgScreen">Administration panel, Configuration,
+  Default</span>. Indeed, every new registered user will have by default the
+  same display properties.</li>
+
+  <li>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">forum</a> (message board) is
+  available on the presentation site of PhpWebGallery. Check the <a
+  href="http://doc.phpwebgallery.net">official PhpWebGallery
+  documentation</a> for further reading.</li>
+
+</ul>
+
Index: /branches/1.5/language/en_UK.iso-8859-1/help/cat_modify.html
===================================================================
--- /branches/1.5/language/en_UK.iso-8859-1/help/cat_modify.html	(revision 3250)
+++ /branches/1.5/language/en_UK.iso-8859-1/help/cat_modify.html	(revision 3250)
@@ -0,0 +1,95 @@
+<h2>Edit a category</h2>
+
+<p>Modify informations and options of a single category.</p>
+
+<h3>Action links</h3>
+
+<p>This page offers you link to modification page of parent categories and
+action links :</p>
+
+<ul>
+  <li>jump to category</li>
+  <li>manage category elements (if category contains elements)</li>
+  <li>manage sub-categories</li>
+  <li>manage permissions (if category is private)</li>
+  <li>delete category (if category is virtual).</li>
+</ul>
+
+<h3>Move</h3>
+
+<p>If the category is virtual, you can move it. Moving a category means
+changing its parent category.</p>
+
+<h3>Options</h3>
+
+<ul>
+
+  <li><strong>Access type</strong>: 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.</li>
+
+  <li><strong>Lock</strong>: The category and its sub-categories will
+  temporary been disabled for maintenance.</li>
+
+  <li><strong>Comments</strong>: Authorize users to comment elements of this
+  category.</li>
+
+  <li><strong>Authorize upload</strong>: Authorize users to upload
+  files. This option is available only if category is physical (not
+  virtual).</li>
+
+</ul>
+
+<p>You can also manage these options with multi-categories options
+management screen (screens <span class="pwgScreen">Upload</span>, <span
+class="pwgScreen">Comments</span>, <span class="pwgScreen">Lock</span>,
+<span class="pwgScreen">Public/Private</span>, <span
+class="pwgScreen">Representative</span> in <span
+class="pwgScreen">Administration, Categories</span>).</p>
+
+<h3>Representation</h3>
+
+<p>The representant of the category is the thumbnail displayed to represent
+the category on main page (<span class="pwgScreen">category.php</span>) when
+a category contains only sub-categories (just as the root category).</p>
+
+<p>There are 4 ways to set the representative picture of a category :</p>
+
+<ul>
+
+  <li><span class="pwgScreen">picture.php</span>: in the action buttons bar,
+  one of them let you set the displayed picture as representative for the
+  displayed category. This button is available only for administrators.</li>
+
+  <li><span class="pwgScreen">Modify informations about a picture</span> in
+  administration. This screen can be reach from <span
+  class="pwgScreen">picture.php</span> or <span class="pwgScreen">Batch
+  management</span> in <em>unit mode</em>. See the help of this screen for
+  details.</li>
+
+  <li><span class="pwgScreen">Administration, Categories,
+  Representative</span>. See the help of this screen for details.</li>
+
+  <li><span class="pwgScreen">Edit a category</span> (this screen).</li>
+
+</ul>
+
+<p>The representation depends on configuration parameter
+<code>allow_random_representative</code> (see <span
+class="filename">include/config_default.inc.php</span>).</p>
+
+<p>In default mode (<code>allow_random_representative</code> set to false)
+each category containing at least one element is represented by a fixed
+element. Once set (at category creation), the representative changes only
+when an administrator ask for it. If the representant is not appropriate,
+you can ask to <strong>Find a new representant by random</strong>.</p>
+
+<p>If configuration parameter <code>allow_random_representative</code> is
+set to true, a category containing elements can have no fixed
+representant. Just use <strong>Delete representant</strong> button.</p>
+
+<p>If the category contains no element (but only sub-categories) it can be
+represented by any element thanks to screen <span class="pwgScreen">Modify
+informations about a picture</span>. The only option on the current screen
+is to <strong>Delete representant</strong> button, after using this button,
+no representant option to set anymore.</p>
Index: /branches/1.5/language/en_UK.iso-8859-1/help/cat_options.html
===================================================================
--- /branches/1.5/language/en_UK.iso-8859-1/help/cat_options.html	(revision 3250)
+++ /branches/1.5/language/en_UK.iso-8859-1/help/cat_options.html	(revision 3250)
@@ -0,0 +1,36 @@
+<h2>Category options</h2>
+
+<p>This screen lets the administrator manage categories option for many
+categories at once.</p>
+
+<dl>
+
+  <dt>Upload</dt>
+  <dd>Make categories uploadable for gallery visitors. Only non virtual and
+  non remote categories are shown.</dd>
+
+  <dt>Comments</dt>
+  <dd>Authorize users to add comments on selected categories. By
+  inheritance, an element is commentable if it belongs at least to one
+  commentable category.</dd>
+
+  <dt>Lock</dt>
+  <dd>Selected categories will temporary been disabled for maintenance. If
+  you lock a category, all its child categories become locked. If you unlock
+  a category, all its parent categories become unlocked.</dd>
+
+  <dt>Public / private</dt>
+  <dd>Manage authorizations for selected categories. Selected categories are
+  private : you will need to authorize users and/or groups to access to
+  them. If you make a category private, all its child categories becomes
+  private. If you make a category public, all its parent categories becomes
+  public</dd>
+
+  <dt>Representative</dt>
+  <dd>This option can be managed only if you set configuration parameter
+  <code>allow_random_representative</code> (see <span
+  class="filename">include/config_defaults.inc.php</span>) to
+  <em>true</em>. Each category can be randomly represented or singly
+  represented (by a unique picture).</dd>
+
+</dl>
Index: /branches/1.5/language/en_UK.iso-8859-1/help/cat_perm.html
===================================================================
--- /branches/1.5/language/en_UK.iso-8859-1/help/cat_perm.html	(revision 3250)
+++ /branches/1.5/language/en_UK.iso-8859-1/help/cat_perm.html	(revision 3250)
@@ -0,0 +1,15 @@
+<h2>Manage permissions for a category</h2>
+
+<p>This screen is available only for a private category. Here you can select
+users and groups authorized for this category.</p>
+
+<h3>Groups</h3>
+
+<p>You can deny or grant groups for the current category. By modifying
+groups authorizations, you'll probably modify the list of users granted to
+the category thanks to group belongings.</p>
+
+<h3>Users</h3>
+
+<p>You can deny or grant individual users. Users granted thanks to group
+belongings can be denied or granted specifically.</p>
Index: /branches/1.5/language/en_UK.iso-8859-1/help/configuration.html
===================================================================
--- /branches/1.5/language/en_UK.iso-8859-1/help/configuration.html	(revision 3250)
+++ /branches/1.5/language/en_UK.iso-8859-1/help/configuration.html	(revision 3250)
@@ -0,0 +1,93 @@
+<h2>Configuration</h2>
+
+<p>This screen let the administrator do basic configuration. Indeed, this
+screen only shows simple configuration parameters that should be enough for
+the vast majority of administrators. If you want to see other numerous (and
+advanced) configuration parameters, read file <span
+cass="filename">include/config_default.inc.php</span>.</p>
+
+<p>This screen is divided in several sections, regrouping configuration
+parameters by theme.</p>
+
+<h3>General</h3>
+
+<ul>
+
+  <li><strong>Gallery title</strong>: displayed on top of each public
+  page.</li>
+
+  <li><strong>Gallery description</strong>: displayed under gallery
+  title.</li>
+
+  <li><strong>History</strong>: visits on pages <span
+  class="pwgScreen">category.php</span> and <span
+  class="pwgScreen">picture.php</span> will be registered in
+  <code>history</code> table. Visits will be shown in <span
+  class="pwgScreen">Administration, General, History</span>.</li>
+
+  <li><strong>Lock gallery</strong>: Lock the entire gallery for
+  maintenance. Only administrator users will be able to reach the
+  gallery.</li>
+
+</ul>
+
+
+<h3>User comments</h3>
+
+<ul>
+
+  <li><strong>Comments for all</strong>: Even guest not registered can post
+  comments.</li>
+
+  <li><strong>Number of comments per page</strong>.</li>
+
+  <li><strong>Validation</strong>: an administrator validate users posted
+  comments before they become visible on the site. User comments validation
+  takes place in screen <span class="pwgScreen">Administration, Pictures,
+  Comments</span>.</li>
+
+</ul>
+
+<h3>Default display</h3>
+
+<p>Here you can change display options used by default, when guest is not
+connected. Once connected, these options are overloaded by user own options
+(modifiable in <span class="pwgScreen">profile</span>).</p>
+
+<p>It is possible to change display options for all existing users, but the
+screen to consider is <span class="pwgScreen">Administration,
+Identification, Users</span>, where you can options for a selected list of
+users.</p>
+
+<ul>
+
+  <li><strong>Language</strong>: concerns only PhpWebGallery
+  labels. Category names, picture names and all descriptions are not
+  localized.</li>
+
+  <li><strong>Number of images per row</strong></li>
+
+  <li><strong>Number of rows per page</strong></li>
+
+  <li><strong>Interface theme</strong></li>
+
+  <li><strong>Recent period</strong>: By days. Period within a picture is
+  shown as new. Must be superior to 1 day.</li>
+
+  <li><strong>Expand all categories</strong>: Expand all categories by
+  default in the menu? <em>Warning</em>: this option is resources consuming
+  and may generate a huge menu if your category tree is contains many
+  categories.</li>
+
+  <li><strong>Show number of comments</strong>: show the number of comments
+  for each picture on the thumbnails page. Resource consuming.</li>
+
+  <li><strong>Maximum width of the pictures</strong>: maximum displayed
+  width. If pictures are larger than this setting, they will be resized on
+  display. If you consider filling this option, you'd better consider
+  modifying the width of your pictures instead.</li>
+
+  <li><strong>Maximum height of the pictures</strong>: same remarks as for
+  previous setting.</li>
+
+</ul>
Index: /branches/1.5/language/en_UK.iso-8859-1/help/maintenance.html
===================================================================
--- /branches/1.5/language/en_UK.iso-8859-1/help/maintenance.html	(revision 3250)
+++ /branches/1.5/language/en_UK.iso-8859-1/help/maintenance.html	(revision 3250)
@@ -0,0 +1,38 @@
+<h2>Maintenance</h2>
+
+<p>To optimize page generation time, PhpWebGallery uses cached
+information. For example, instead of counting the number of pictures
+contained in each category at each page reload, this information is stored
+in the database. In theory, this information should always be correct, but
+sometimes an error can occur and cached information becomes wrong.</p>
+
+<p>Some informations become useless with time. Deleting this useless
+information from database make you save disk space.</p>
+
+<ul>
+
+  <li><strong>update categories informations</strong>. For each category,
+  informations to update or control are the following : list of parent
+  categories, number of pictures, date of the last picture, position among
+  brother categories, position among all categories. This action also checks
+  the coherence of representative picture.</li>
+
+  <li><strong>update images informations</strong>. For each picture,
+  informations to update are : full path to file, average
+  rate. <em>Warning</em>: do not get confuse with metadata informations
+  which can be synchronized from <span class="pwgScreen">Administration,
+  General, Synchronize</span> or by reaching the modification screen of a
+  single picture (through <span class="pwgScreen">Picture</span> for
+  example).</li>
+
+  <li><strong>purge history</strong>. Delete all lines from
+  <code>history</code> table. Screen <span class="pwgScreen">Administration,
+  General, History</span> shows no informations anymore on past
+  history. <em>Warning</em>: all data will be lost and there is no way to
+  get informations back.</li>
+
+  <li><strong>purge sessions</strong>. Delete expired user sessions.</li>
+
+  <li><strong>purge never used notification feeds</strong></li>
+
+</ul>
Index: /branches/1.5/language/en_UK.iso-8859-1/help/remote_site.html
===================================================================
--- /branches/1.5/language/en_UK.iso-8859-1/help/remote_site.html	(revision 3250)
+++ /branches/1.5/language/en_UK.iso-8859-1/help/remote_site.html	(revision 3250)
@@ -0,0 +1,51 @@
+<h2>Remote site</h2>
+
+<p>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.</p>
+
+<ol>
+
+  <li>edit file <span class="filename">tools/create_listing_file.php</span>,
+  by modifying parameters section such as
+  <code>$conf['prefix_thumbnail']</code> or
+  <code>$conf['use_exif']</code>.</li>
+
+  <li>place file <span class="filename">tools/create_listing_file.php</span>
+  modified on your distant website, in the same directory than your category
+  directories (as the directory <span class="filename">galleries</span> of
+  this website) by ftp. For the example, let's say that you can access <span
+  class="filename">http://example.com/galleries/create_listing_file.php</span>.</li>
+
+  <li>go to <span class="pwgScreen">administration panel, General, Remote
+  sites</span>. Ask to create a new site, for example <span
+  class="filename">http://example.com/galleries</span>.</li>
+
+  <li>a new remote site is registered. You can perform 4 actions :
+
+    <ol>
+
+      <li><strong>generate listing</strong> : launches a distant request to
+      generate a distant file listing</li>
+
+      <li><strong>update</strong> : reads the distant <span
+      class="filename">listing.xml</span> file and synchronizes with
+      database informations.</li>
+
+      <li><strong>clean</strong> : removes distant <span
+      class="filename">listing.xml</span> file.</li>
+
+      <li><strong>delete</strong> : deletes the site (and all related
+      categories and elements) in the database.</li>
+
+    </ol>
+  </li>
+</ol>
+
+<p>You can do all this by hand by generating yourself the <span
+class="filename">listing.xml</span> 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.</p>
+
Index: /branches/1.5/language/en_UK.iso-8859-1/help/search.html
===================================================================
--- /branches/1.5/language/en_UK.iso-8859-1/help/search.html	(revision 3250)
+++ /branches/1.5/language/en_UK.iso-8859-1/help/search.html	(revision 3250)
@@ -0,0 +1,24 @@
+<h2>Search</h2>
+
+<p>This page let you search pictures among the whole gallery.</p>
+
+<dl>
+
+  <dt>Search for words</dt>
+  <dd>Search for entered words in all the attributes related to the pictures
+  displayed in the gallery. Use * as a wildcard for partial matches.</dd>
+
+  <dt>Search for Author</dt>
+  <dd>Use * as a wildcard for partial matches.</dd>
+
+  <dt>Search by Date</dt>
+  <dd>Select a date and/or an ending date for your query. Leave date empty
+  if you want to make a "before" query. The year must be entered in the last
+  field in the following format : 0000 (i.e. 2004)</dd>
+
+  <dt>Search in Categories</dt>
+  <dd>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.</dd>
+
+</dl>
Index: /branches/1.5/language/en_UK.iso-8859-1/help/synchronize.html
===================================================================
--- /branches/1.5/language/en_UK.iso-8859-1/help/synchronize.html	(revision 3250)
+++ /branches/1.5/language/en_UK.iso-8859-1/help/synchronize.html	(revision 3250)
@@ -0,0 +1,13 @@
+<h2>Synchronize</h2>
+
+<p>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.</p>
+
+<p>The first synchronization must be the directories/files one.</p>
+
+<p>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.</p>
Index: /branches/1.5/language/en_UK.iso-8859-1/help/thumbnail.html
===================================================================
--- /branches/1.5/language/en_UK.iso-8859-1/help/thumbnail.html	(revision 3250)
+++ /branches/1.5/language/en_UK.iso-8859-1/help/thumbnail.html	(revision 3250)
@@ -0,0 +1,28 @@
+<h2>Thumbnails creation</h2>
+
+<p>This page let you create missing thumbnails.</p>
+
+<dl>
+
+  <dt>GD version</dt>
+
+  <dd>GD is the picture manipulating library for PHP. 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.</dd>
+
+  <dt>Width and height</dt>
+
+  <dd>Maximum dimensions that thumbnails can take. Aspect ratio is
+  maintained.</dd>
+
+  <dt>Number of thumbnails to create</dt>
+
+  <dd>Do not try to miniaturize too many pictures in the same time. 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.</dd>
+
+  <dt>File format</dt>
+
+  <dd>Only JPEG file format is supported for thumbnail creation. Thumbnails
+  can be created only from PNG and JPEG pictures.</dd>
+
+</dl>
Index: /branches/1.5/language/en_UK.iso-8859-1/help/user_list.html
===================================================================
--- /branches/1.5/language/en_UK.iso-8859-1/help/user_list.html	(revision 3250)
+++ /branches/1.5/language/en_UK.iso-8859-1/help/user_list.html	(revision 3250)
@@ -0,0 +1,32 @@
+<h2>Users list</h2>
+
+<p>This is the place where you can manage registered users. Only permissions
+are managed in different several screens.</p>
+
+<h3>Add a user</h3>
+
+<p>Administrator can manually add users.</p>
+
+<h3>Users list</h3>
+
+<p>The list can be filtered on username (use * as wildcard), group or
+status. The list can be order by registration date or username, in ascending
+or descending order.</p>
+
+<p>This screen works be managing several users at once on different actions
+:</p>
+
+<ul>
+
+  <li>delete users (require a confirmation checkbox)</li>
+
+  <li>change status</li>
+
+  <li>associate or dissociate from groups</li>
+
+  <li>modify display properties</li>
+
+</ul>
+
+<p>The target is the set users selected (by default) or all users is
+asked.</p>
Index: /branches/1.5/language/en_UK.iso-8859-1/install.lang.php
===================================================================
--- /branches/1.5/language/en_UK.iso-8859-1/install.lang.php	(revision 3250)
+++ /branches/1.5/language/en_UK.iso-8859-1/install.lang.php	(revision 3250)
@@ -0,0 +1,77 @@
+<?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 gallery 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'] = 'Password [confirm]';
+$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>';
+$lang['conf_mail_webmaster'] = 'Webmaster mail adress';
+$lang['conf_mail_webmaster_info'] = 'Visitors will be able to contact site administrator with this mail';
+?>
Index: /branches/1.5/language/en_UK.iso-8859-1/iso.txt
===================================================================
--- /branches/1.5/language/en_UK.iso-8859-1/iso.txt	(revision 3250)
+++ /branches/1.5/language/en_UK.iso-8859-1/iso.txt	(revision 3250)
@@ -0,0 +1,1 @@
+English [UK]
Index: /branches/1.5/language/fr_FR.iso-8859-1/about.html
===================================================================
--- /branches/1.5/language/fr_FR.iso-8859-1/about.html	(revision 3250)
+++ /branches/1.5/language/fr_FR.iso-8859-1/about.html	(revision 3250)
@@ -0,0 +1,13 @@
+<ul>
+
+  <li>PhpWebGallery est une application web permettant de créer facilement
+une galerie d'images en ligne.</li>
+
+  <li>Techniquement, PhpWebGallery est développée en PHP avec une base de
+données MySQL.</li>
+
+  <li>Si vous avez des suggestions ou des commentaires, visitez le <a
+  href="http://www.phpwebgallery.net">site
+officiel</a>.</li>
+
+</ul>
Index: /branches/1.5/language/fr_FR.iso-8859-1/admin.lang.php
===================================================================
--- /branches/1.5/language/fr_FR.iso-8859-1/admin.lang.php	(revision 3250)
+++ /branches/1.5/language/fr_FR.iso-8859-1/admin.lang.php	(revision 3250)
@@ -0,0 +1,368 @@
+<?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['%d categories including %d physical and %d virtual'] = '%d catégories dont %d physiques et %d virtuelles';
+$lang['%d categories moved'] = '%d catégories déplacées';
+$lang['%d comments'] = '%d commentaires utilisateur';
+$lang['%d elements'] = '%d éléments';
+$lang['%d groups'] = '%d groupes';
+$lang['%d members'] = '%d membres';
+$lang['%d user comments rejected'] = '%d commentaires utilisateur rejetés';
+$lang['%d user comments validated'] = '%d commentaires utilisateur validés';
+$lang['%d users deleted'] = '%d utilisateurs supprimés';
+$lang['%d users'] = '%d utilisateurs';
+$lang['%d waiting for validation'] = '%d en attente de validation';
+$lang['%d waiting pictures rejected'] = '%d images en attente rejetées';
+$lang['%d waiting pictures validated'] = '%d images en attente validées';
+$lang['A new version of PhpWebGallery is available.'] = 'Une nouvelle version de PhpWebGallery est disponible.';
+$lang['Actions'] = 'Actions';
+$lang['Add a user'] = 'Ajouter un utilisateur';
+$lang['Add group'] = 'Ajouter un groupe';
+$lang['Add selected elements to caddie'] = 'Ajouter les éléments sélectionnés au panier';
+$lang['Add'] = 'Ajouter';
+$lang['Associated'] = 'Associée à';
+$lang['Association to categories'] = 'Association aux catégories';
+$lang['Batch management'] = 'Gestion par lot';
+$lang['Caddie management'] = 'Gestion du panier';
+$lang['Caddie'] = 'Panier';
+$lang['Categories authorized thanks to group associations'] = 'Catégories accessibles grâce à l\'appartenance aux groupes';
+$lang['Check for upgrade failed for unknown reasons.'] = 'La vérification de la dernière version sur le serveur a échouée pour une raison inconnue.';
+$lang['Check for upgrade'] = 'Dernière version ?';
+$lang['Comments for all'] = 'Commentaires utilisateur pour tous';
+$lang['Creation date'] = 'Date de création';
+$lang['Database'] = 'Base de données';
+$lang['Delete Representant'] = 'Supprimer le représentant';
+$lang['Delete selected users'] = 'Supprimer les utilisateurs sélectionnés';
+$lang['Deletions'] = 'Suppressions';
+$lang['Deny selected groups'] = 'Interdire l\'accès aux groupes sélectionnés';
+$lang['Deny selected users'] = 'Interdire l\'accès aux utilisateurs sélectionnés';
+$lang['Description'] = 'Description';
+$lang['Display options'] = 'Options d\'affichage';
+$lang['Dissociated'] = 'Dissociée de';
+$lang['Does not represent'] = 'Ne représente pas';
+$lang['Edit all picture informations'] = 'Modifier toutes les informations liées à cette image';
+$lang['Elements'] = 'Éléments';
+$lang['Empty caddie'] = 'Vider le panier';
+$lang['Environment'] = 'Environnement';
+$lang['Expand all categories'] = 'Développer toutes les catégories';
+$lang['Form'] = 'Formulaire';
+$lang['Gallery description'] = 'Description de la galerie';
+$lang['Gallery title'] = 'Titre de la galerie';
+$lang['Grant selected groups'] = 'Donner l\'accès aux groupes sélectionnés';
+$lang['Grant selected users'] = 'Donner l\'accès aux utilisateurs sélectionnés';
+$lang['Group name'] = 'Nom du groupe';
+$lang['Groups'] = 'Groupes';
+$lang['History'] = 'Historique';
+$lang['Informations'] = 'Informations';
+$lang['Interface theme'] = 'Theme de l\'interface';
+$lang['Language'] = 'Langue';
+$lang['Linked categories'] = 'Catégories associées';
+$lang['Lock gallery'] = 'Verrouiller la galerie';
+$lang['Maintenance'] = 'Maintenance';
+$lang['Manage permissions for a category'] = 'Gérer les permissions pour une catégorie';
+$lang['Manage permissions for group "%s"'] = 'Gérer les permissions pour le groupe "%s"';
+$lang['Manage permissions for user "%s"'] = 'Gérer les permissions pour l\'utilisateur "%s"';
+$lang['Maximum height of the pictures'] = 'Hauteur maximum des images';
+$lang['Maximum width of the pictures'] = 'Largeur maximum des images';
+$lang['Members'] = 'Membres';
+$lang['Metadata synchronized from file'] = 'Meta-données synchronisées à partir du fichier';
+$lang['Move categories'] = 'Déplacer les catégories';
+$lang['Move'] = 'Déplacer';
+$lang['Name'] = 'Nom';
+$lang['New parent category'] = 'Nouvelle catégorie parente';
+$lang['No'] = 'Non';
+$lang['Number of comments per page'] = 'Nombre de commentaires utilisateur par page';
+$lang['Number of images per row'] = 'Nombre de miniatures par ligne';
+$lang['Number of rows per page'] = 'Nombre de lignes par page';
+$lang['Number of thumbnails to create'] = 'Nombre de miniatures à créer';
+$lang['Only private categories are listed'] = 'Seules les catégories privées sont listées';
+$lang['Operating system'] = 'System d\'exploitation';
+$lang['Options'] = 'Options';
+$lang['Order by'] = 'Trier selon';
+$lang['Other private categories'] = 'Autres catégories privées';
+$lang['Parent category'] = 'Catégorie parente';
+$lang['Path'] = 'Chemin';
+$lang['Permission denied'] = 'Accès interdit';
+$lang['Permission granted thanks to a group'] = 'Accès autorisé grâce à l\'appartenance aux groupes';
+$lang['Permission granted'] = 'Accès autorisé';
+$lang['PhpWebGallery Administration'] = 'Administration de PhpWebGallery';
+$lang['PhpWebGallery version'] = 'Version de PhpWebGallery';
+$lang['Picture informations updated'] = 'Informations de l\'image mises à jour';
+$lang['Position'] = 'Position';
+$lang['Preferences'] = 'Préférences';
+$lang['Properties'] = 'Propriétés';
+$lang['Random picture'] = 'Au hasard';
+$lang['Recent period'] = 'Période récente';
+$lang['Registration date'] = 'Date d\'enregistrement';
+$lang['Reject All'] = 'Tout rejeter';
+$lang['Reject'] = 'Rejeter';
+$lang['Representant'] = 'Représentant';
+$lang['Representation of categories'] = 'Représentation des catégories';
+$lang['Representative'] = 'Représentant';
+$lang['Represents'] = 'Représente';
+$lang['Save order'] = 'Sauvegarder l\'ordre';
+$lang['Select at least one category'] = 'Sélectionner au moins une catégorie';
+$lang['Select at least one picture'] = 'Sélectionner au moins une image';
+$lang['Select at least one user'] = 'Séléctionner au moins un utilisateur';
+$lang['Show info'] = 'Montrer les informations';
+$lang['Show number of comments'] = 'Montrer le nombre de commentaires';
+$lang['Status'] = 'Statut';
+$lang['Storage category'] = 'Catégorie de stockage';
+$lang['Submit'] = 'Valider';
+$lang['Take selected elements out of caddie'] = 'Sortir les éléments sélectionnés du panier';
+$lang['Unable to check for upgrade since allow_url_fopen is disabled.'] = 'Impossible de connaître la dernière version cat la fonction allow_url_fopen est désactivée.';
+$lang['User comments validation'] = 'Validation des commentaires utilisateur';
+$lang['Users'] = 'Utilisateurs';
+$lang['Validate All'] = 'Tout valider';
+$lang['Validate'] = 'Valider';
+$lang['Validation'] = 'Validation';
+$lang['Virtual categories movement'] = 'Déplacement de catégories virtuelles';
+$lang['Virtual categories to move'] = 'Catégories virtuelles à déplacer';
+$lang['Webmaster cannot be deleted'] = 'Le webmestre ne peut pas être supprimé';
+$lang['Yes'] = 'Oui';
+$lang['You are running on development sources, no check possible.'] = 'Vous travaillez avec les sources de développement, impossible de vérifier la dernière version.';
+$lang['You are running the latest version of PhpWebGallery.'] = 'Vous utilisez la dernière version de PhpWebGallery.';
+$lang['You cannot move a category in its own sub category'] = 'Vous ne pouvez pas déplacer une catégorie dans sa propre sous-catégorie';
+$lang['You need to confirm deletion'] = 'Vous devez confirmer la suppression';
+$lang['actions'] = 'actions';
+$lang['add keywords'] = 'ajouter des mots-clef';
+$lang['associate to category'] = 'associer à la catégorie';
+$lang['associate to group'] = 'associer au groupe';
+$lang['author'] = 'auteur';
+$lang['authorized'] = 'Autorisés';
+$lang['cat_add'] = 'Ajouter une catégorie virtuelle';
+$lang['cat_comments_title'] = 'Autoriser les utilisateurs à ajouter des commentaires dans les catégories sélectionnées';
+$lang['cat_error_name'] = 'Le nom de la catégorie ne doit pas être vide';
+$lang['cat_lock_title'] = 'Verrouiller les catégories';
+$lang['cat_private'] = 'Catégorie privée';
+$lang['cat_public'] = 'Catégorie publique';
+$lang['cat_representant'] = 'Trouver un nouveau représentant au hasard';
+$lang['cat_security'] = 'Publique / Privée';
+$lang['cat_status_title'] = 'Gérer le type d\'accès pour les catégories sélectionnées';
+$lang['cat_upload_title'] = 'Sélectionner les catégories autorisées à l\'ajout';
+$lang['cat_virtual_added'] = 'Catégorie virtuelle ajoutée';
+$lang['cat_virtual_deleted'] = 'Catégorie virtuelle supprimée';
+$lang['category'] = 'catégorie';
+$lang['conf_access'] = 'Type d\'accès';
+$lang['conf_comments_title'] = 'Commentaires utilisateur';
+$lang['conf_confirmation'] = 'Informations enregistrées dans la base de données';
+$lang['conf_default'] = 'Affichage par défaut';
+$lang['conf_default_title'] = 'Affichage par défaut';
+$lang['conf_general_title'] = 'Configuration principale';
+$lang['conf_nb_comment_page_error'] = 'Le nombre de commentaires utilisateurs par page doit être compris entre 5 et 50.';
+$lang['config'] = 'Configuration';
+$lang['confirm'] = 'confirmer';
+$lang['creation date'] = 'date de création';
+$lang['date'] = 'date';
+$lang['delete category'] = 'supprimer la catégorie';
+$lang['description'] = 'description';
+$lang['dissociate from category'] = 'dissocier de la catégorie';
+$lang['dissociate from group'] = 'dissocier du groupe';
+$lang['edit category permissions'] = 'Modifier les permissions de la catégorie';
+$lang['edit'] = 'Modifier';
+$lang['editcat_confirm'] = 'Les informations de la catégorie ont été mises à jour avec succès.';
+$lang['editcat_uploadable'] = 'Autoriser l\'ajout d\'images';
+$lang['elements per line'] = 'éléments par ligne';
+$lang['elements per page'] = 'éléments par page';
+$lang['elements'] = 'éléments';
+$lang['file'] = 'fichier';
+$lang['filesize'] = 'poids';
+$lang['first element added on %s'] = 'premier élément ajouté le %s';
+$lang['forbidden'] = 'interdit';
+$lang['general'] = 'Général';
+$lang['global mode'] = 'mode global';
+$lang['group "%s" added'] = 'groupe "%s" ajouté';
+$lang['group "%s" deleted'] = 'groupe "%s" supprimé';
+$lang['group'] = 'groupe';
+$lang['group_add_error1'] = 'Le nom du groupe ne doit pas contenir " or \' et ne doit pas être vide.';
+$lang['group_add_error2'] = 'Ce nom est déjà utilisé par un autre groupe.';
+$lang['group_add_user']= 'Ajouter un utilisateur';
+$lang['group_id URL parameter is missing'] = 'Le paramètre d\'URL "group_id" est manquant';
+$lang['groups'] = 'Groupes';
+$lang['history'] = 'Historique';
+$lang['instructions'] = 'Instructions';
+$lang['jump to category'] = 'se rendre dans la catégorie';
+$lang['jump to image'] = 'se rendre à l\'image';
+$lang['jump to'] = 's\'y rendre';
+$lang['leave'] = 'laisser';
+$lang['links'] = 'Liens';
+$lang['lock'] = 'Verrouiller';
+$lang['locked'] = 'Verrouillé';
+$lang['manage category elements'] = 'gérer les éléments de la catégorie';
+$lang['manage sub-categories'] = 'gérer les sous-catégories';
+$lang['manage'] = 'Gérer';
+$lang['metadata_basic'] = 'basique';
+$lang['metadata_exif'] = 'EXIF';
+$lang['metadata_iptc'] = 'IPTC';
+$lang['name'] = 'nom';
+$lang['no_write_access'] = 'pas d\'accès en écriture';
+$lang['order_by'] = 'trier selon';
+$lang['path'] = 'chemin';
+$lang['permissions'] = 'Permissions';
+$lang['permuser_info'] = 'Seules les catégories privées sont listées.';
+$lang['permuser_only_private'] = 'Seules les catégories privées sont listées.';
+$lang['pictures'] = 'images';
+$lang['private'] = 'privée';
+$lang['public'] = 'publique';
+$lang['purge history'] = 'purger l\'historique';
+$lang['purge never used notification feeds'] = 'purger les flux de notification jamais utilisés';
+$lang['purge sessions'] = 'purger les sessions';
+$lang['randomly represented'] = 'représentant au hasard';
+$lang['registration_date'] = 'date d\'enregistrement';
+$lang['remote_site'] = 'Site distant';
+$lang['remote_site_already_exists'] = 'Ce site existe déjà';
+$lang['remote_site_clean'] = 'nettoyer';
+$lang['remote_site_clean_hint'] = 'supprimer le fichier listing.xml distant';
+$lang['remote_site_create'] = 'Créer un nouveau site distant : (donner son URL vers create_listing_file.php)';
+$lang['remote_site_created'] = 'créé';
+$lang['remote_site_delete'] = 'supprimer';
+$lang['remote_site_delete_hint'] = 'supprimer ce site distant et toutes les informations associées';
+$lang['remote_site_deleted'] = 'supprimé';
+$lang['remote_site_error'] = 'une erreur est survenue';
+$lang['remote_site_file_not_found'] = 'le fichier create_listing_file.php est introuvable sur le site distant';
+$lang['remote_site_generate'] = 'générer le listing';
+$lang['remote_site_generate_hint'] = 'générer le fichier listing.xml sur le site distant';
+$lang['remote_site_listing_not_found'] = 'le fichier listing.xml est introuvable';
+$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 le listing.xml local et mettre à jour';
+$lang['remote_site_removed'] = 'a été supprimé du site distant';
+$lang['remote_site_removed_title'] = 'Éléments supprimés';
+$lang['remote_site_uncorrect_url'] = 'L\'URL d\'un site distant doit commencer par "http" ou "https" et ne doit contenir des caractères que parmi "/", "a-zA-Z0-9", "-" ou "_"';
+$lang['remote_site_update'] = 'synchronisation';
+$lang['remote_site_update_hint'] = 'lit le fichier listing.xml distant et met à jour la base de données';
+$lang['remote_sites'] = 'Sites distants';
+$lang['remove keyword'] = 'supprimer mot-clef';
+$lang['selection'] = 'sélection';
+$lang['set to'] = 'changer en';
+$lang['singly represented'] = 'représentant fixe';
+$lang['stats_addr'] = 'Adresse IP';
+$lang['stats_category'] = 'Catégorie';
+$lang['stats_daily_graph_title'] = 'Pages vues par heure';
+$lang['stats_day_title'] = 'Statistiques journalières';
+$lang['stats_file'] = 'Fichier';
+$lang['stats_global_graph_title'] = 'Pages vues par mois';
+$lang['stats_hour'] = 'Heure';
+$lang['stats_login'] = 'Identifiant';
+$lang['stats_month_title'] = 'Statistiques mensuelles';
+$lang['stats_monthly_graph_title'] = 'Pages vues par jour';
+$lang['stats_pages_seen'] = 'Pages vues';
+$lang['stats_picture'] = 'Image';
+$lang['stats_title'] = 'Statistiques de la dernière année';
+$lang['status'] = 'statut';
+$lang['storage'] = 'Répertoire';
+$lang['sub-categories'] = 'sous-catégories';
+$lang['synchronize metadata'] = 'synchroniser les méta-données';
+$lang['synchronize'] = 'synchroniser';
+$lang['target'] = 'cible';
+$lang['thumbnail'] = 'miniature';
+$lang['title'] = 'titre';
+$lang['title_cat_options'] = 'Options des catégories';
+$lang['title_categories'] = 'Gestion des catégorie';
+$lang['title_configuration'] = 'Configuration de PhpWebGallery';
+$lang['title_default'] = 'Administration de PhpWebGallery';
+$lang['title_edit_cat'] = 'Modifier une catégorie';
+$lang['title_groups'] = 'Gestion des groupes';
+$lang['title_history'] = 'Historique';
+$lang['title_liste_users'] = 'Liste des utilisateurs';
+$lang['title_picmod'] = 'Modifier les informations d\'une image';
+$lang['title_thumbnails'] = 'Création des miniatures';
+$lang['title_update'] = 'Synchronisation de la base de données à partir des fichiers';
+$lang['title_waiting'] = 'Images en attente de validation';
+$lang['tn_all'] = 'tout';
+$lang['tn_alone_title'] = 'image sans miniature (jpeg et png uniquement)';
+$lang['tn_dirs_alone'] = 'images sans miniature';
+$lang['tn_dirs_title'] = 'Liste des répertoires';
+$lang['tn_err_height'] = 'la hauteur doit un entier supérieur à';
+$lang['tn_err_width'] = 'la largeur doit être un entier supérieur à';
+$lang['tn_format'] = 'pour le format de fichier';
+$lang['tn_height'] = 'hauteur';
+$lang['tn_no_missing'] = 'Aucune miniature ne manque';
+$lang['tn_no_support'] = 'Image innaccessible ou non supportée';
+$lang['tn_params_GD'] = 'version de GD';
+$lang['tn_params_create'] = 'créer';
+$lang['tn_params_title'] = 'Paramètre de miniaturisation';
+$lang['tn_results_gen_time'] = 'générée en';
+$lang['tn_results_title'] = 'Résultats de la miniaturisation';
+$lang['tn_stats'] = 'Statistiques générales';
+$lang['tn_stats_max'] = 'temps maximal';
+$lang['tn_stats_mean'] = 'temps moyen';
+$lang['tn_stats_min'] = 'temps minimal';
+$lang['tn_stats_nb'] = 'nombre de miniatures créées';
+$lang['tn_stats_total'] = 'temps total';
+$lang['tn_thisformat'] = 'pour ce format de fichier';
+$lang['tn_width'] = 'largeur';
+$lang['unit mode'] = 'mode unitaire';
+$lang['unlocked'] = 'déverrouillée';
+$lang['unset'] = 'vider';
+$lang['up'] = 'Déplacer vers le haut';
+$lang['update categories informations'] = 'Mettre à jour les informations des catégories';
+$lang['update images informations'] = 'Mettre à jour les informations des images';
+$lang['update'] = 'Synchroniser';
+$lang['update_cats_subset'] = 'traiter uniquement une catégorie';
+$lang['update_default_title'] = 'Choisir une option';
+$lang['update_display_info'] = 'afficher un maximum d\'informations (catégories ajoutées, éléments ajoutés, catégories et éléments supprimés)';
+$lang['update_elements_metadata_sync'] = 'informations des images synchronisées avec les méta-données';
+$lang['update_error_list_title'] = 'Liste des erreurs';
+$lang['update_errors_caption'] = 'Légende des erreurs';
+$lang['update_infos_title'] = 'Informations détaillées';
+$lang['update_missing_tn_info'] = 'Chaque fichier image requiert une miniature. La miniature doit être présente dans le sous-répertoire "thumbnail" du répertoire de la catégorie. Le nom du fichier de la miniature doit commencer avec le paramètre de configuration "prefix_thumbnail" et l\'extension du nom du fichier doit être parmi la liste suivante :';
+$lang['update_missing_tn_short'] = 'miniature manquante';
+$lang['update_nb_del_categories'] = 'catégories supprimées de la base de données';
+$lang['update_nb_del_elements'] = 'éléments supprimés de la base de données';
+$lang['update_nb_errors'] = 'erreurs survenues durant la synchronisation';
+$lang['update_nb_new_categories'] = 'catégories ajoutées dans la base de données';
+$lang['update_nb_new_elements'] = 'éléments ajoutés dans la base de données';
+$lang['update_part_research'] = 'Chercher les nouvelles images dans les répertoires';
+$lang['update_research_added'] = 'ajouté';
+$lang['update_research_deleted'] = 'supprimé';
+$lang['update_result_metadata'] = 'Résultat de la synchronisation des méta-données';
+$lang['update_simulate'] = 'Simuler uniquement (aucun changement dans la base de données ne sera effectué)';
+$lang['update_simulation_title'] = '[Simulation]';
+$lang['update_sync_all'] = 'répertoires + fichiers';
+$lang['update_sync_dirs'] = 'répertoires uniquement';
+$lang['update_sync_files'] = 'synchroniser la structure des fichiers avec la base de données';
+$lang['update_sync_metadata'] = 'synchroniser les informations des éléments dans la base de données à partir des méta-données des fichiers';
+$lang['update_sync_metadata_all'] = 'même les éléments déjà synchronisés';
+$lang['update_sync_metadata_new'] = 'uniquement les éléments jamais synchronisés';
+$lang['update_used_metadata'] = 'Méta-données employées';
+$lang['update_wrong_dirname_info'] = 'Le nom des répertoires et des fichiers ne doit être constitué que de lettres, de chiffres, de "-", "_" et "."';
+$lang['update_wrong_dirname_short'] = 'nom de fichier erroné';
+$lang['upload'] = 'Ajout';
+$lang['user "%s" added'] = 'utilisateur "%s" ajouté';
+$lang['user_delete'] = 'Supprimer utilisateur';
+$lang['user_delete_hint'] = 'Cliquer ici pour supprimer cet utilisateur. Attention :  cette opération ne peut pas être annulée !';
+$lang['user_id URL parameter is missing'] = 'le paramètre d\'URL "user_id" manque';
+$lang['user_status'] = 'Statut de l\'utilisateur';
+$lang['user_status_admin'] = 'Administrateur';
+$lang['user_status_guest'] = 'Visiteur';
+$lang['username'] = 'nom utilisateur';
+$lang['users'] = 'Utilisateurs';
+$lang['visitors'] = 'Visiteurs';
+$lang['w_day'] = 'Jour';
+$lang['waiting'] = 'En attente';
+?>
Index: /branches/1.5/language/fr_FR.iso-8859-1/common.lang.php
===================================================================
--- /branches/1.5/language/fr_FR.iso-8859-1/common.lang.php	(revision 3250)
+++ /branches/1.5/language/fr_FR.iso-8859-1/common.lang.php	(revision 3250)
@@ -0,0 +1,305 @@
+<?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';
+
+$lang['%.2f (rated %d times, standard deviation = %.2f)'] = '%.2f (noté %d fois, déviation standard = %.2f)';
+$lang['%d Kb'] = '%d Ko';
+$lang['%d categories updated'] = '%d catégories mises à jour';
+$lang['%d comments to validate'] = '%d commentaires utilisateur à valider';
+$lang['%d new comments'] = '%d nouveaux commentaires utilisateur';
+$lang['%d new elements'] = '%d nouveaux éléments';
+$lang['%d new users'] = '%d nouveaux utilisateurs';
+$lang['About'] = 'À propos';
+$lang['Author'] = 'Auteur';
+$lang['Average rate'] = 'Note moyenne';
+$lang['Categories'] = 'Catégories';
+$lang['Category'] = 'Catégorie';
+$lang['Close this window'] = 'Fermer cette fenêtre';
+$lang['Confirm Password'] = 'Confirmer le mot de passe';
+$lang['Connection'] = 'Connexion';
+$lang['Connection settings'] = 'Paramètres de connexion';
+$lang['Contact webmaster'] = 'Contacter le webmestre';
+$lang['Create a new account'] = 'Créer un nouveau compte';
+$lang['Created on'] = 'Créée le';
+$lang['Current password is wrong'] = 'Erreur sur le mot de passe actuel';
+$lang['Dimensions'] = 'Dimensions';
+$lang['Display'] = 'Affichage';
+$lang['Email address is missing'] = 'L\'adresse e-mail manque';
+$lang['Email address'] = 'Adresse e-mail';
+$lang['Enter your personnal informations'] = 'Entrer vos informations personnelles';
+$lang['Error sending email'] = 'Erreur à l\'envoi du mail';
+$lang['File'] = 'Fichier';
+$lang['Filesize'] = 'Poids';
+$lang['Filter and display'] = 'Filtrer et afficher';
+$lang['Filter'] = 'Filtre';
+$lang['Forgot your password?'] = 'Mot de passe oublié ?';
+$lang['Go through the gallery as a visitor'] = 'Parcourir la galerie en tant que visiteur';
+$lang['Help'] = 'Aide';
+$lang['Identification'] = 'Identification';
+$lang['Keyword'] = 'Mot-clef';
+$lang['Keywords'] = 'Mots-clef';
+$lang['Links'] = 'Liens';
+$lang['Mail address'] = $lang['Email address'];
+$lang['N/A'] = 'non disponible';
+$lang['New on %s'] = 'Nouveau le %s';
+$lang['New password confirmation does not correspond'] = 'Erreur de confirmation de mot de passe';
+$lang['New password sent by email'] = 'Nouveau mot de passe envoyé par e-mail';
+$lang['No email address'] = 'Pas d\'adresse e-mail';
+$lang['No user matches this email address'] = 'Cette adresse e-mail ne correspond à aucun utilisateur';
+$lang['Notification'] = 'Notification';
+$lang['Number of items'] = 'Nombre d\'élément';
+$lang['Original dimensions'] = 'Dimensions d\'origine';
+$lang['Password forgotten'] = 'Mot de passe oublié';
+$lang['Password'] = 'Mot de passe';
+$lang['PhpWebGallery Help'] = 'Aide de PhpWebGallery';
+$lang['Profile'] = 'Profil';
+$lang['RSS feed'] = 'flux RSS';
+$lang['Register'] = 'S\'enregistrer';
+$lang['Registered on'] = 'Enregistrée le';
+$lang['Registration'] = 'Enregistrement';
+$lang['Reset'] = 'Annuler';
+$lang['Retrieve password'] = 'Récupérer un mot de passe';
+$lang['Search'] = 'Rechercher';
+$lang['Send new password'] = 'Envoyer le nouveau mot de passe';
+$lang['Since'] = 'Depuis';
+$lang['Sort by'] = 'Trier selon';
+$lang['Sort order'] = 'Ordre de tri';
+$lang['The RSS notification feed provides notification on news from this website : new pictures, updated categories, new comments. Use a RSS feed reader.'] = 'Le flux RSS notifie les évênements de la galerie : nouvelles images, catégories mises à jour, nouveaux commentaires utiliseur. À utiliser avec un lecteur de flux RSS.';
+$lang['Unknown feed identifier'] = 'Identifiant de flux inconnu';
+$lang['User comments'] = 'Commentaires utilisateur';
+$lang['Username'] = 'Nom d\'utilisateur';
+$lang['Visits'] = 'Visites';
+$lang['Webmaster'] = 'Webmestre';
+$lang['about_page_title'] = 'À propos de PhpWebGallery';
+$lang['access_forbiden'] = 'Vous n\'êtes pas autorisé sur cette page';
+$lang['add to caddie'] = 'ajouter au panier';
+$lang['add_favorites_alt'] = 'Ajouter aux favoris';
+$lang['add_favorites_hint'] = 'Ajouter cette image à vos favoris';
+$lang['admin'] = 'Administration';
+$lang['all'] = 'tout';
+$lang['all_categories'] = 'toutes les catégories';
+$lang['already_rated'] = 'Vous avez déjà voté pour cette image';
+$lang['ascending'] = 'croissant';
+$lang['auto_expand'] = 'Développer toutes les catégories';
+$lang['best_rated_cat'] = 'Mieux notées';
+$lang['best_rated_cat_hint'] = 'affiche les images les mieux notées';
+$lang['caddie'] = 'Panier';
+$lang['calendar'] = 'Calendrier';
+$lang['calendar_hint'] = 'affichage année par année, mois par mois, jour par jour';
+$lang['calendar_picture_hint'] = 'affiche les images du ';
+$lang['categories'] = 'Catégories';
+$lang['comment date'] = 'date du commentaire';
+$lang['comment'] = 'Commentaire';
+$lang['comment_added'] = 'Votre commentaire a été enregistré';
+$lang['comment_anti-flood'] = 'Système anti-abus : merci de patienter avant d\'ajouter un nouveau commentaire';
+$lang['comment_to_validate'] = 'Un administrateur doit valider votre commentaire afin qu\'il soit visible.';
+$lang['comment_user_exists'] = 'Ce nom d\'utilisateur est déjà pris';
+$lang['comments'] = 'Commentaires';
+$lang['comments_add'] = 'Ajouter un commentaire';
+$lang['comments_del'] = 'Supprimer ce commentaire';
+$lang['comments_title'] = 'Commentaires des utilisateurs';
+$lang['confirm_password_hint'] = 'Vous n\'avez à confirmer votre mot de passe que si vous désirez en changer.';
+$lang['customize'] = 'Personnaliser';
+$lang['customize_page_title'] = 'Personnalisation de votre affichage ';
+$lang['customize_title'] = 'Personnaliser';
+$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['days'] = 'jours';
+$lang['del_favorites_alt'] = 'Supprimer des favoris';
+$lang['del_favorites_hint'] = 'Supprimer cette image de vos favoris';
+$lang['delete'] = 'Supprimer';
+$lang['descending'] = 'décroissant';
+$lang['download'] = 'télécharger';
+$lang['download_hint'] = 'télécharger ce fichier';
+$lang['edit category informations'] = 'éditer les informations de cette catégorie';
+$lang['edit'] = 'éditer';
+$lang['err_date'] = 'date erronée';
+$lang['favorite_cat'] = 'Mes favorites';
+$lang['favorite_cat_hint'] = 'afficher mes images favorites';
+$lang['favorites'] = 'Favoris';
+$lang['first_page'] = 'Premier';
+$lang['gallery_locked_message'] = 'La galerie est verrouillée pour cause de maintenance. Revenir plus tard.';
+$lang['generation_time'] = 'Page fabriquée en';
+$lang['guest'] = 'visiteur';
+$lang['hello'] = 'Bonjour';
+$lang['hint_admin'] = 'disponible uniquement pour les administrateurs';
+$lang['hint_category'] = 'montre les images à la racine de cette catégorie';
+$lang['hint_comments'] = 'Voir les derniers commentaires utilisateur';
+$lang['hint_customize'] = 'personnaliser l\'apparence de la galerie';
+$lang['hint_search'] = 'recherche';
+$lang['home'] = 'Accueil';
+$lang['home_hint'] = 'Retour à la page d\'accueil';
+$lang['ident_forgotten_password'] = 'Mot de passe oublié ?';
+$lang['ident_guest_visit'] = 'Parcourir la galerie en tant que visiteur';
+$lang['ident_register'] = 'S\'enregistrer';
+$lang['ident_title'] = 'Identification (FIXME)';
+$lang['identification'] = 'Identification';
+$lang['images_available'] = 'images dans cette catégorie';
+$lang['invalid_pwd'] = 'Mot de passe invalide !';
+$lang['language'] = 'Langue';
+$lang['last %d days'] = '%d derniers jours';
+$lang['last_page'] = 'Dernier';
+$lang['link_info_image'] = 'Modifier les informations';
+$lang['login'] = 'Connexion';
+$lang['logout'] = 'Déconnexion';
+$lang['mail_address'] = $lang['Email address'];
+$lang['mandatory'] = 'obligatoire';
+$lang['maxheight'] = 'Hauteur maximum des images';
+$lang['maxheight_error'] = 'La hauteur maximum des images doit être supérieure à 50';
+$lang['maxwidth'] = 'Largeur maximum des images';
+$lang['maxwidth_error'] = 'La largeur des images doit être supérieure à 50';
+$lang['month'][10] = 'Octobre';
+$lang['month'][11] = 'Novembre';
+$lang['month'][12] = 'Decembre';
+$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['most_visited_cat'] = 'Plus vues';
+$lang['most_visited_cat_hint'] = 'afficher les images les plus vues';
+$lang['nb_image_per_row'] = 'Nombre de miniatures par ligne';
+$lang['nb_row_per_page'] = 'Nombre de lignes par page';
+$lang['never_rated'] = 'Vous n\'avez jamais voté pour cette image';
+$lang['new_password'] = 'Nouveau mot de passe';
+$lang['new_password_hint'] = 'Vous n\'avez à confirmer votre mot de passe que si vous désirez en changer.';
+$lang['next_page'] = 'Suivant';
+$lang['no'] = 'Non';
+$lang['no_category'] = 'Accueil';
+$lang['no_rate'] = 'pas de note';
+$lang['notification'] = 'notification';
+$lang['only_members'] = 'Seuls les membres enregistrés peuvent accéder à cette page';
+$lang['password updated'] = 'mot de passe mis à jour';
+$lang['password'] = 'Mot de passe';
+$lang['password_hint'] = 'Vous n\'avez à donner votre mot de passe que si vous désirez en changer.';
+$lang['periods_error'] = 'La période de nouveauté doit être un entier positif';
+$lang['picture'] = 'image';
+$lang['picture_high'] = 'Cliquer sur l\'image pour la visualiser en haute définition';
+$lang['picture_show_metadata'] = 'Monter les méta-données du fichier';
+$lang['powered_by'] = 'Propulsé par';
+$lang['preferences'] = 'Préférences';
+$lang['previous_page'] = 'Précédent';
+$lang['random_cat'] = 'Images au hasard';
+$lang['random_cat_hint'] = 'Affiche un ensemble aléatoire d\'images';
+$lang['recent_cats_cat'] = 'Dernières catégories';
+$lang['recent_cats_cat_hint'] = 'Affiche les catégories récemment mises à jour ou créées';
+$lang['recent_image'] = 'Image de moins de';
+$lang['recent_period'] = 'Période récente';
+$lang['recent_pics_cat'] = 'Dernières images';
+$lang['recent_pics_cat_hint'] = 'Affiche les images les plus récentes';
+$lang['reg_confirm'] = 'Confirmer le mot de passe';
+$lang['reg_err_login1'] = 'S\'il vous plaît, entrer un nom utilisateur';
+$lang['reg_err_login2'] = 'le nom utilisateur ne doit pas terminer par un espace';
+$lang['reg_err_login3'] = 'le nom utilisateur ne doit pas commencer par un espace';
+$lang['reg_err_login5'] = 'ce nom utilisateur est déjà pris';
+$lang['reg_err_mail_address'] = 'l\'adresse e-mail doit être de la forme xxx@yyy.eee (example : jack@altern.org)';
+$lang['reg_err_pass'] = 'S\'il vous plaît, entrez à nouveau votre mot de passe';
+$lang['register'] = 's\'enregistrer';
+$lang['register_page_title'] = 'Enregistrement';
+$lang['register_title'] = 'Enregistrement';
+$lang['remember_me'] = 'Connexion auto';
+$lang['representative'] = 'représentant';
+$lang['reset'] = 'Annuler';
+$lang['return to homepage'] = 'retour à la page d\'accueil';
+$lang['search'] = 'Recherche';
+$lang['search_ascending'] = 'Croissant';
+$lang['search_author'] = 'Rechercher un auteur';
+$lang['search_categories'] = 'Rechercher dans les catégories';
+$lang['search_date'] = 'Recherche par date';
+$lang['search_date_available'] = 'Disponibilité';
+$lang['search_date_creation'] = 'Création';
+$lang['search_date_from'] = 'Date';
+$lang['search_date_to'] = 'Date de fin';
+$lang['search_date_type'] = 'Type de date';
+$lang['search_descending'] = 'Décroissant';
+$lang['search_explain'] = 'Utiliser * comme un joker pour une recherche partielle';
+$lang['search_keywords'] = 'Recherche de mot';
+$lang['search_mode_and'] = 'Rechercher tous les mots';
+$lang['search_mode_or'] = 'Rechercher un des mots';
+$lang['search_one_clause_at_least'] = 'Requête vide. Aucun critère fourni.';
+$lang['search_options'] = 'Options de recherche';
+$lang['search_result'] = 'Résultats de recherche';
+$lang['search_sort'] = 'Trier les résultats de recherche selon';
+$lang['search_subcats_included'] = 'Rechercher dans les sous-catégories';
+$lang['search_title'] = 'Recherche';
+$lang['send_mail'] = 'Contacter';
+$lang['set as category representative'] = 'élire comme représentant de cette catégorie';
+$lang['show_nb_comments'] = 'Montrer le nombre de commentaires';
+$lang['slideshow'] = 'diaporama';
+$lang['slideshow_stop'] = 'arrêter le diaporama';
+$lang['special_categories'] = 'Spéciales';
+$lang['sql_queries_in'] = 'requêtes SQL en';
+$lang['sub-cat'] = 'sous-catégories';
+$lang['submit'] = 'Valider';
+$lang['the beginning'] = 'le début';
+$lang['theme'] = 'Thème de l\'interface';
+$lang['thumbnails'] = 'Miniatures';
+$lang['title_comments'] = 'Commentaires utilisateurs';
+$lang['title_menu'] = 'Menu';
+$lang['title_send_mail'] = 'Un commentaire sur le site';
+$lang['to_rate'] = 'Note';
+$lang['today'] = 'aujourd\'hui';
+$lang['total'] = 'images';
+$lang['update_rate'] = 'Mettre à jour votre note';
+$lang['update_wrong_dirname'] = 'wrong filename';
+$lang['upload_advise'] = 'Choisir une image à ajouter dans cette catégorie : ';
+$lang['upload_advise_filesize'] = 'le poids de l\'image ne doit dépasser : ';
+$lang['upload_advise_filetype'] = 'le format de l\'image doit être jpg, png ou gif';
+$lang['upload_advise_height'] = 'la hauteur de l\'image ne doit pas dépasser : ';
+$lang['upload_advise_thumbnail'] = 'Optionnel, mais recommendé : choisir une miniature à associer ';
+$lang['upload_advise_width'] = 'la largeur de l\'image ne doit pas dépasser : ';
+$lang['upload_author'] = 'Auteur';
+$lang['upload_cannot_upload'] = 'impossible de transférer le fichier sur le serveur';
+$lang['upload_creation_date'] = 'Date de création (JJ/MM/AAAA)';
+$lang['upload_err_username'] = 'nom d\'utilisateur manquant';
+$lang['upload_file_exists'] = 'ce fichier existe déjà';
+$lang['upload_filenotfound'] = 'le format du fichier n\'est pas un format d\'image';
+$lang['upload_forbidden'] = 'impossible d\'ajouter une image dans cette catégorie';
+$lang['upload_name'] = 'Nom de l\'image';
+$lang['upload_picture'] = 'Ajouter une image';
+$lang['upload_successful'] = 'Image ajoutée avec succès, un administrateur doit valider l\'ajout pour le rendre visible';
+$lang['upload_title'] = 'Ajouter une image';
+$lang['upload_username'] = 'Nom d\'utilisateur';
+$lang['useful when password forgotten'] = 'utile en cas d\'oubli de mot de passe';
+$lang['w_month'] = 'Mois';
+$lang['yes'] = 'Oui';
+?>
Index: /branches/1.5/language/fr_FR.iso-8859-1/help.html
===================================================================
--- /branches/1.5/language/fr_FR.iso-8859-1/help.html	(revision 3250)
+++ /branches/1.5/language/fr_FR.iso-8859-1/help.html	(revision 3250)
@@ -0,0 +1,247 @@
+<h2>Aide</h2>
+
+<h3>Démarrage rapide</h3>
+
+<ol>
+
+  <li>Créer un répertoire local "categorie_test".</li>
+
+  <li>Remplir le répetoire "categorie_test" avec des photos.</li>
+
+  <li>Ouvrir une connexion FTP vers la galerie distante.</li>
+
+  <li>Télécharger le répertoire local "categorie_test" dans le répertoire
+distant "galleries". Donner tous les droits (777) au nouveau répertoire
+"galleries/categorie_test".</li>
+
+  <li>Se connecter à votre installation de PhpWebGallery en tant
+qu'administrateur.</li>
+
+  <li>Se rendre sur <span class="pwgScreen">Administration, Images,
+Miniatures</span>. Demander à créer les miniatures absentes selon l'analyse
+de PhpWebGallery.</li>
+
+  <li>Se rendre sur <span class="pwgScreen">Administration, Général,
+Synchroniser</span>. Cocher "répertoires + fichiers", décocher "Simuler
+uniquement" et valider la synchronisation.</li>
+
+  <li>Et voilà. Vous avez créer la catégorie "categorie_test" à la racine de
+votre galerie.</li>
+  
+</ol>
+
+<h3>Ajouts d'éléments</h3>
+
+<ul>
+
+  <li>
+
+    <p>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) : </p>
+  
+<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>
+
+  </li>
+  
+  <li>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.</li>
+
+  <li>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 du paramètre de configuration <code>file_ext</code> (voir
+fichier <span class="filename">include/config.inc.php</span>). Un fichier
+peut être une image si son extension est parmi le paramètre de configuration
+<code>picture_ext</code>.</li>
+
+  <li>Les éléments de type image doivent avoir une miniature associée (voir la
+section suivante à propos des miniatures).</li>
+
+  <li>Les éléments de type image peuvent avoir un image en grand format
+associé.  Comme pour le fichier <span class="filename">mariage.jpg</span>
+dans l'exemple ci-dessus. Aucun préfix n'est nécessaire sur le nom du
+fichier.</li>
+
+  <li>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 <span
+class="filename">video.avi</span> dans l'exemple).</li>
+
+  <li><em>Attention</em> : 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.</li>
+
+  <li><em>Conseil</em> : 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 <strong>ou bien</strong>
+des sous-catégories.</li>
+
+  <li>Une fois que les fichiers, les miniatures et les représentants sont
+correctement placés dans les répertoires, se rendre sur l'écran <span
+class="pwgScreen">Administration, Général, Synchroniser</span>.</li>
+
+</ul>
+
+<h3>Miniatures</h3>
+
+<ul>
+  
+  <li>Comme mentionné précédemment, chaque élément de type image doit être
+associé à une miniature.</li>
+
+  <li>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 de configuration <code>prefix_thumbnail</code>
+(voir <span class="filename">include/config.inc.php</span>).</li>
+
+  <li>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).</li>
+
+  <li>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).</li>
+
+  <li>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é).</li>
+
+  <li>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).</li>
+
+</ul>
+
+<h3>Autorisations</h3>
+
+<ul>
+
+  <li>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.</li>
+  
+  <li>Vous pouvez rendre une catégorie privée en l'éditant (<span
+class="pwgScreen">Administration, Catégories, Gestion, Editer</span>) ou en
+gérant les options pour votre arbre complet des catégories (<span
+class="pwgScreen">Administration, Catégories, Publique/Privée</span>).</li>
+
+  <li>Une fois que certaines catégories sont privées, vous pouvez gérer les
+autorisations pour les groupes et les utilisateurs (<span
+class="pwgScreen">Administration, Autorisations</span>).</li>
+
+</ul>
+
+<h3>Groupes d'utilisateurs</h3>
+
+<ul>
+
+  <li>PhpWebGallery peut gérer des groupes d'utilisateurs. Très pratique
+pour gérer des autorisations communes sur les catégories privées.</li>
+
+  <li>Vous pouvez créer des groupes et y ajouter des utilisateurs dans la
+<span class="pwgScreen">Administration, Identification, Groupes</span>.</li>
+
+  <li>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.</li>
+  
+</ul>
+
+<h3>Ajout de fichiers par les utilisateurs</h3>
+
+<p>Pour permettre aux utilisateurs d'ajouter des fichiers :</p>
+
+<ol>
+
+  <li>autoriser l'ajout d'images sur n'importe quelle catégorie (<span
+class="pwgScreen">Administation, Catégories, Gestion, Edit</span> ou <span
+class="pwgScreen">Administration, Catégories, Ajout d'images</span>).</li>
+
+  <li>donner les droits en écriture (pour tous les utilisateurs) sur les
+répertoires correspondant aux catégories qui sont autorisées à l'ajout.</li>
+
+  <li>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.</li>
+
+</ol>
+
+<h3>Liens entre les éléments et les catégories, catégories virtuelles</h3>
+
+<ul>
+
+  <li>PhpWebGallery dissocie les catégories qui stockent les éléments et les
+catégories où les éléments sont montrés.</li>
+
+  <li>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.</li>
+
+  <li>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), sur la page
+regroupant les informations sur tous les éléments d'une catégorie ou bien
+encore à l'aide du caddie.</li>
+
+  <li>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 <span class="pwgScreen">Administration,
+Catégorie, Gestion</span>.</li>
+
+</ul>
+
+<h3>Informations diverses</h3>
+
+<ul>
+  
+  <li>Dès que vous aurez créer votre galerie, configurez l'affichage par
+défaut tel que désiré dans <span class="pwgScreen">Administation,
+Configuration, Affichage par défaut</span>. En effet, chaque nouvel
+utilisateur héritera de ces propriétés d'affichage.</li>
+
+  <li>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">forum</a> est disponible sur le site de PhpWebGallery. Consulter également la <a href="http://phpwebgallery.net/doc">documentation officielle de
+PhpWebGallery</a> pour obtenir plus de détails.</li>
+
+</ul>
Index: /branches/1.5/language/fr_FR.iso-8859-1/help/cat_modify.html
===================================================================
--- /branches/1.5/language/fr_FR.iso-8859-1/help/cat_modify.html	(revision 3250)
+++ /branches/1.5/language/fr_FR.iso-8859-1/help/cat_modify.html	(revision 3250)
@@ -0,0 +1,103 @@
+<h2>Modifier une catégorie</h2>
+
+<p>Modifier les informations et options d'une catégorie.</p>
+
+<h3>Liens d'action</h3>
+
+<p>Cette page est liée à la page de modification de chaque catégorie parente
+ainsi qu'aux actions suivantes:</p>
+
+<ul>
+  <li>se rendre dans la catégorie</li>
+  <li>gérer le éléments (si la catégorie en contient)</li>
+  <li>gérer les sous-catégories</li>
+  <li>gérer les permissions (si la catégorie est privée)</li>
+  <li>supprimer la catégorie (si la catégorie est virtuelle)</li>
+</ul>
+
+<h3>Déplacer</h3>
+
+<p>Si la catégorie est virtuelle, vous pouvez la déplacer. Déplacer une
+catégorie signifie changer de catégorie parente.</p>
+
+<h3>Options</h3>
+
+<ul>
+
+  <li><strong>Type d'accès</strong>: gestion des permissions. Si vous rendez
+une catégorie privée, toutes ses catégories filles deviennent privées. Si
+vous rendez une catégorie publique, toutes ses catégories mères deviennent
+publiques.</li>
+
+  <li><strong>Vérouiller</strong>: la catégorie et toutes ses catégories
+filles deviennent temporairement inaccessibles pour maintenance.</li>
+
+  <li><strong>Commentaires</strong>: autorise les utilisateurs à commenter
+les éléments de cette catégorie.</li>
+
+  <li><strong>Autoriser l'ajout d'images</strong>: autorise les utilisateurs
+à télécharger des fichiers. Cette option n'est disponible que si la
+catégorie est physique (et non virtuelle).</li>
+
+</ul>
+
+<p>Vous pouvez aussi gérer ces options dans la gestion globale des options
+multi-catégories (écrans <span class="pwgScreen">Ajout</span>, <span
+class="pwgScreen">Commentaires</span>, <span
+class="pwgScreen">Vérouiller</span>, <span
+class="pwgScreen">Publique/Privée</span>, <span
+class="pwgScreen">Représentant</span> dans <span
+class="pwgScreen">Administration, Catégories</span>).</p>
+
+<h3>Représentant</h3>
+
+<p>Le représentant d'une catégorie est la miniature affichée pour
+représenter la catégorie sur la page principale (<span
+class="pwgScreen">category.php</span>) lorsqu'une catégorie contient
+uniquement des sous-catégories et pas d'éléments directs (comme à la
+racine)</p>
+
+<p>Il existe 4 moyens de choisir le représentant d'une catégorie:</p>
+
+<ul>
+
+  <li><span class="pwgScreen">picture.php</span>: dans la barre des boutons
+d'action, l'un d'eux permet de choisir l'élément affiché comme représentant
+de la catégorie affichée. Ce bouton d'action n'est disponible que pour les
+administrateurs.</li>
+
+  <li><span class="pwgScreen">Modifier les informations d'une image</span>
+dans l'administration. Cet écran peut être atteint depuis <span
+class="pwgScreen">picture.php</span> ou <span class="pwgScreen">Gestion par
+lot</span> dans le <em>mode unitaire</em>. Voir l'aide de cet écran pour les
+détails.</li>
+
+  <li><span class="pwgScreen">Administration, Catégories,
+Représentant</span>. Voir l'aide de cet écran pour les détails.</li>
+
+  <li><span class="pwgScreen">Modifier une catégorie</span> (le présent
+écran).</li>
+
+</ul>
+
+<p>La représentation dépent du paramètre de configuration
+<code>allow_random_representative</code> (voir <span
+class="filename">include/config_default.inc.php</span>).</p>
+
+<p>Par défaut (<code>allow_random_representative</code> à false) chaque
+catégorie contenant au moins un élément est représenté par un élément
+fixe. Une fois fixé (à la création de la catégorie), le représentant change
+uniquement lorsque l'administrateur le demande. Si le représentant ne
+convient pas, vous pouvez demander à <strong>Trouver un nouveau représentant
+au hasard</strong>.</p>
+
+<p>Si le paramètre de configuration <code>allow_random_representative</code>
+està true, une catégorie contenant des éléments peut ne pas avoir de
+représentant fixe. Utiliser simplement le bouton <strong>Supprimer le
+représentant</strong>.</p>
+
+<p>Si la catégorie ne contient aucun élément (mais uniquement des sous
+catégories) elle peut quand même être représentée par n'importe quel élément
+grâce à l'écran <span class="pwgScreen">Modifier les informations d'une
+image</span>. La seule option du présent écran est le bouton
+<strong>Supprimer le représentant</strong>.</p>
Index: /branches/1.5/language/fr_FR.iso-8859-1/help/cat_options.html
===================================================================
--- /branches/1.5/language/fr_FR.iso-8859-1/help/cat_options.html	(revision 3250)
+++ /branches/1.5/language/fr_FR.iso-8859-1/help/cat_options.html	(revision 3250)
@@ -0,0 +1,43 @@
+<h2>Options des catégories</h2>
+
+<p>Gestion des options pour plusieurs catégories à la fois.</p>
+
+<dl>
+
+  <dt>Autorisation à l'ajout</dt>
+
+  <dd>Rendre les catégories autorisées à l'ajout par les visiteurs. Cette
+option n'est pas disponible pour les catégories virtuelles et
+distantes.</dd>
+  
+  <dt>Commentaires utilisateur</dt>
+
+  <dd>Autoriser les utilisateurs à commenter les images des catégories
+sélectionnées. Par héritage, une image est commentable si elle appartient à
+au moins une catégorie commentable.</dd>
+  
+  <dt>Vérouiller</dt>
+
+  <dd>Les catégories sélectionnées deviennent temporairement inactives pour
+maintenance. Lorsqu'une catégorie est verrouillée, toutes les catégories
+enfant sont verrouillées. Lorsqu'une catégorie est déverrouillée, toutes les
+catégories parentes sont déverrouillées.</dd>
+
+  <dt>Publique / Privée</dt>
+
+  <dd>Gestion du status des catégories. Les permissions ne sont possibles
+que pour les catégories privées. Une fois qu'une catégorie est privée, vous
+devez explicitement autoriser les utilisateurs ou les groupes à y
+accéder. Lorsqu'une catégorie devient privée, toutes les catégories enfant
+deviennent privées. Lorsqu'une catégorie devient publique, toutes les
+catégories parentes deviennent publiques.</dd>
+
+  <dt>Représentant</dt>
+
+  <dd>Cette option est disponible uniquement si le paramètre de
+configuration <code>allow_random_representative</code> (voir <span
+class="filename">include/config_default.inc.php</span>) est
+<em>true</em>. Chaque catégorie peut-être représentée au hasard ou par une
+miniature fixe unique.</dd>
+
+</dl>
Index: /branches/1.5/language/fr_FR.iso-8859-1/help/cat_perm.html
===================================================================
--- /branches/1.5/language/fr_FR.iso-8859-1/help/cat_perm.html	(revision 3250)
+++ /branches/1.5/language/fr_FR.iso-8859-1/help/cat_perm.html	(revision 3250)
@@ -0,0 +1,16 @@
+<h2>Gérer les permissions pour une catégorie</h2>
+
+<p>Cette écran n'est disponible que pour les catégories privée. Ici vous
+pourrez sélectionner les utilisateurs et les groupes autorisés pour cette
+catégorie.</p>
+
+<h3>Groupes</h3>
+
+<p>Vous pouvez autoriser ou interdire l'accès aux groupes. En modifiant les
+autorisations des groupes, vous modifierez probablement la liste des
+utilisateurs autorisés grâce à l'appartenance aux groupes.</p>
+
+<h3>Utilisateurs</h3>
+
+<p>Vous pouvez autoriser ou interdire l'accès aux utilisateurs
+individuellement.</p>
Index: /branches/1.5/language/fr_FR.iso-8859-1/help/configuration.html
===================================================================
--- /branches/1.5/language/fr_FR.iso-8859-1/help/configuration.html	(revision 3250)
+++ /branches/1.5/language/fr_FR.iso-8859-1/help/configuration.html	(revision 3250)
@@ -0,0 +1,98 @@
+<h2>Configuration</h2>
+
+<p>Cet écran permet de gérer la configuration basique. En effet, seuls sont
+montrés les paramètres de configuration qui doivent suffire à la majorité
+des administrateurs. Si vous souhaitez voir la liste des nombreux (et
+avancés) paramètres, lire le fichier <span
+cass="filename">include/config_default.inc.php</span></p>
+
+<p>Cet écran est divisié en plusieurs sections, regroupant les paramètres
+par thème.</p>
+
+<h3>Général</h3>
+
+<ul>
+
+  <li><strong>Titre de la galerie</strong>: affiché en haut de chaque page
+de la partie publique.</li>
+
+  <li><strong>Description de la galerie</strong>: affiché en dessous du
+titre de la galerie.</li>
+
+  <li><strong>Historique</strong>: visites des pages <span
+class="pwgScreen">category.php</span> et <span
+class="pwgScreen">picture.php</span> sont enregistrées dans la table
+<code>history</code>. Les visites sont affichées dans l'écran <span
+class="pwgScreen">Administration, Général, Historique</span>.</li>
+
+  <li><strong>Vérouiller la galerie</strong>: Vérouiller l'ensemble de la
+galerie pour maintenance. Seul les administrateurs pourront accéder à la
+galerie.</li>
+
+</ul>
+
+
+<h3>Commentaires utilisateur</h3>
+
+<ul>
+
+  <li><strong>Commentaires utilisateur pour tous</strong>: même les
+utilisateurs non enregistrés peuvent enregistrer des commentaires.</li>
+
+  <li><strong>Nombre de commentaires utilisateur par page</strong>.</li>
+
+  <li><strong>Validation</strong>: un administrateur doit valider les
+commentaires utilisateurs avant qu'ils puissent devenir visibles dans la
+partie publique. La validation des commentaires utilisateurs a lieu dans
+l'écran <span class="pwgScreen">Administration, Images,
+Commentaires</span>.</li>
+
+</ul>
+
+<h3>Affichage par défaut</h3>
+
+<p>Modifier les options d'affichage par défaut: pour les visiteurs non
+connectés. Une fois connecté, ces options sont surchargées par celles de
+l'utilisateur, qu'il peut modifier dans l'écran <span
+class="pwgScreen">profile</span>.</p>
+
+<p>Il est possible de changer ces options pour les utilisateurs existants,
+mais il s'agit d'un autre écran : <span class="pwgScreen">Administration,
+Identification, Utilisateurs</span>, dans lequel vous pouvez modifier ces
+options pour une liste d'utilisateurs sélectionnés.</p>
+
+<ul>
+
+  <li><strong>Langue</strong>: ne concerne que les libellés de
+PhpWebGallery. Les noms de catégories, d'image et les descriptions ne sont
+pas localisés (ie multilingue).</li>
+
+  <li><strong>Nombre de miniatures par ligne</strong></li>
+
+  <li><strong>Nombre de lignes par page</strong></li>
+
+  <li><strong>Theme de l'interface</strong></li>
+
+  <li><strong>Période récente</strong>: en jours. Période pendant laquelle
+une image est considérée comment nouvelle. Cette période doit être
+supérieure à 1 jour.</li>
+
+  <li><strong>Développer toutes les catégories</strong>: développer toutes
+les catégories dans le menu? <em>Attention</em>: cette option est
+susceptible de consommer inutilement des ressources si votre arbre de
+catégories contient de nombreux éléments.</li>
+
+  <li><strong>Montrer le nombre de commentaires</strong>: montrer les nombre
+de commentaires utilisateur en dessous de chaque miniature. Consomme des
+ressources.</li>
+
+  <li><strong>Largeur maximum des images</strong>: à l'affichage. Si l'image
+est plus large que ce paramètre, alors elle sera redimensionnée à
+l'affichage. Si vous pensez nécessaire de modifier ce paramétrage (donc pour
+un affichage par défaut), il serait pertinent de redimensionner directement
+vos images stockées.</li>
+
+  <li><strong>Hauteur maximum des images</strong>: même remarque que pour la
+largeur.</li>
+
+</ul>
Index: /branches/1.5/language/fr_FR.iso-8859-1/help/maintenance.html
===================================================================
--- /branches/1.5/language/fr_FR.iso-8859-1/help/maintenance.html	(revision 3250)
+++ /branches/1.5/language/fr_FR.iso-8859-1/help/maintenance.html	(revision 3250)
@@ -0,0 +1,42 @@
+<h2>Maintenance</h2>
+
+<p>Pour optimiser le temps de génération des pages, PhpWebGallery utilise
+des informations en cache. Par exemple, au lieu de compter le nombre
+d'éléments contenus dans chaque catégorie à chaque rechargement de page,
+cette information est stockée dans la base de données. En théorie, cette
+information doit toujours être correcte, mais parfois une erreur peut
+survenir et l'information en cache devient fausse.</p>
+
+<p>Des informations deviennent inutiles avec le temps. Les supprimer de la
+base de données libère de l'espace disque.</p>
+
+<ul>
+
+  <li><strong>Mettre à jour les informations des catégories</strong>. Pour
+chaque catégorie, les informations à controller et/ou mettre à jour sont les
+suivantes: liste des catégories mères, nombre d'éléments, date du dernièr
+élément, position parmi les catégories soeur, position dans l'arbre complet
+des catégories. Cette action vérifie également la cohérence des
+représentants.</li>
+
+  <li><strong>Mettre à jour les informations des images</strong>. Pour
+chaque image, les informations à mettre à jour sont: chemin complet vers le
+fichier, note moyenne. <em>Attention</em>: ne pas confondre avec les
+métadonnées qui sont synchronisées sur l'écran <span
+class="pwgScreen">Administration, Général, Synchroniser</span> ou sur
+l'écran <span class="pwgScreen">Modifier les informations d'une image</span>
+(accessible depuis la page de visualisation d'une image <span
+class="pwgScreen">picture.php</span>).</li>
+
+  <li><strong>purger l'historique</strong>. Supprimes toutes les lignes de
+la table <code>history</code>. L'écran <span
+class="pwgScreen">Administration, Général, Historique</span> ne montre alors
+plus aucune information sur le passé. <em>Attention</em>: toutes les données
+seront perdues et il n'existe aucun moyen de les récupérer.</li>
+
+  <li><strong>purger les sessions</strong>. Supprimer les sessions
+expirées..</li>
+
+  <li><strong>purger les flux de notification jamais utilisés</strong></li>
+
+</ul>
Index: /branches/1.5/language/fr_FR.iso-8859-1/help/remote_site.html
===================================================================
--- /branches/1.5/language/fr_FR.iso-8859-1/help/remote_site.html	(revision 3250)
+++ /branches/1.5/language/fr_FR.iso-8859-1/help/remote_site.html	(revision 3250)
@@ -0,0 +1,56 @@
+<h2>Sites distant</h2>
+
+<p>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.</p>
+
+
+<ol>
+
+  <li>éditer le fichier <span
+class="filename">tools/create_listing_file.php</span> en modifiant la
+section des paramètres comme <code>$conf['prefix_thumbnail']</code> ou
+<code>$conf['use_exif']</code>.</li>
+
+  <li>placer le fichier <span
+class="filename">tools/create_listing_file.php</span> modifié sur votre site
+distant, dans le même répertoire que les répertoires représentant vos
+catégories (comme le répertoire <span class="filename">galleries</span> de
+ce site) par FTP. Par exemple, disons que vous pouvez accéder à <span
+class="filename">http://exemple.com/galleries/create_listing_file.php</span>.</li>
+
+  <li>Se rendre sur <span class="pwgScreen">Administration, Général, Sites
+distant</span>. Demander à créer un nouveau site, par exemple <span
+class="filename">http://exemple.com/galleries</span>.</li>
+
+  <li>
+
+    <p>un nouveau site distant est enregistré. 4 actions possibles :</p>
+
+    <ol>
+
+      <li><strong>générer la liste</strong> : lance une requête distant pour
+générer le fichier de listing distant</li>
+
+      <li><strong>mettre à jour</strong> : lit le fichier distant <span
+class="filename">listing.xml</span> et synchronise avec la base de données
+locale</li>
+
+      <li><strong>nettoyer</strong> : supprime le fichier distant de
+listing</li>
+
+      <li><strong>détruire</strong> : supprime le site (et tous les éléments
+qui y sont associés) dans la base de données</li>
+
+    </ol>
+
+  </li>
+
+</ol>
+
+<p>Vous pouvez également effectuer ces opérations manuellement en éditant
+le fichier <span class="filename">listing.xml</span> à la main et en le
+déplaçant vers votre répertoire racine. Se rendre sur <span
+class="pwgScreen">Administration, Général, Sites distant</span> :
+PhpWebGallery détecte le fichier et propose de s'en servir.</p>
Index: /branches/1.5/language/fr_FR.iso-8859-1/help/search.html
===================================================================
--- /branches/1.5/language/fr_FR.iso-8859-1/help/search.html	(revision 3250)
+++ /branches/1.5/language/fr_FR.iso-8859-1/help/search.html	(revision 3250)
@@ -0,0 +1,27 @@
+<h2>Recherche</h2>
+
+<p>Recherche d'images à travers l'ensemble de la galerie.</p>
+
+<dl>
+
+  <dt>Rechercher un mot</dt>
+
+  <dd>Recherche un ou plusieurs mots dans tous les attributs liés aux
+images. Utiliser * comme joker pour les recherches partielles.</dd>
+  
+  <dt>Recherche d'un auteur</dt>
+
+  <dd>Utiliser * comme joker pour les recherches partielles.</dd>
+
+  <dt>Recherche par date</dt>
+
+  <dd>Sélectionner une date et/ou une date de fin. Laisser la date vide si
+vous souhaiter faire une recherche "avant". L'année doit être entrée dans le
+dernier champ sous forme de 4 chiffres (2005 par exemple).</dd>
+
+  <dt>Recherche dans les catégories</dt>
+
+  <dd>Sélectionner les catégories sur lesquelles restreindre la
+recherche.</dd>
+
+</dl>
Index: /branches/1.5/language/fr_FR.iso-8859-1/help/synchronize.html
===================================================================
--- /branches/1.5/language/fr_FR.iso-8859-1/help/synchronize.html	(revision 3250)
+++ /branches/1.5/language/fr_FR.iso-8859-1/help/synchronize.html	(revision 3250)
@@ -0,0 +1,19 @@
+<h2>Synchroniser</h2>
+
+<ul>
+
+  <li>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.</li>
+
+  <li>La première synchronisation à effectuer doit être celle sur la
+structure.</li>
+
+  <li>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.</li>
+
+</ul>
Index: /branches/1.5/language/fr_FR.iso-8859-1/help/thumbnail.html
===================================================================
--- /branches/1.5/language/fr_FR.iso-8859-1/help/thumbnail.html	(revision 3250)
+++ /branches/1.5/language/fr_FR.iso-8859-1/help/thumbnail.html	(revision 3250)
@@ -0,0 +1,36 @@
+<h2>Création des miniatures</h2>
+
+<p>Création des miniatures manquantes. L'utilisation de cette fonctionnalité
+n'est pas conseillé si votre galerie est hébergée sur un serveur
+mutualisé (resources machine partagées).</p>
+
+<dl>
+
+  <dt>Version de GD</dt>
+
+  <dd>GD est une librairie graphique de manipulation d'images pour
+PHP. Choisissez la version installée sur votre serveur. Si vous choisissez
+la mauvaise, des messages d'erreurs apparaîtront, revenez sur la page
+précédente et choisissez l'autre version. Si aucune version ne marche, cela
+signifie que GD n'est pas disponible.</dd>
+
+  <dt>Largeur et hauteur</dt>
+
+  <dd>Dimensions maximum que les miniatures peuvent prendre. Le ratio
+largeur/hauteur original est conservée. Les valeurs par défaut sont
+modifiables grâce aux paramètres de configuration <code>tn_width</code> et
+<code>tn_height</code> (voir le fichier <span
+class="filename">include/config_default.inc.php</span>).</dd>
+  
+  <dt>Nombre de miniatures à créer</dt>
+
+  <dd>N'hésayez pas de miniaturiser un trop grand nombre d'images à la
+fois. En effet, la miniaturisation requiert une relativement grosse
+utilisation processeur.</dd>
+
+  <dt>Format de fichier</dt>
+
+  <dd>Les miniatures sont créées au format JPEG. Seuls les formats PNG et
+JPEG peuvent être miniaturisés.</dd>
+
+</dl>
Index: /branches/1.5/language/fr_FR.iso-8859-1/help/user_list.html
===================================================================
--- /branches/1.5/language/fr_FR.iso-8859-1/help/user_list.html	(revision 3250)
+++ /branches/1.5/language/fr_FR.iso-8859-1/help/user_list.html	(revision 3250)
@@ -0,0 +1,33 @@
+<h2>Liste des utilisateurs</h2>
+
+<p>Manipulation des propriétés des utilisateurs enregistrés. Seules les
+permissions sont gérées dans un écran différent.</p>
+
+<h3>Ajouter un utilisateur</h3>
+
+<p>L'administrateur peut ajouter manuellement des utilisateurs.</p>
+
+<h3>Liste des utilisateurs</h3>
+
+<p>La liste peut être filtrée avec le nom d'utilisateur (* = joker), avec le
+groupe ou encore le status. La liste peut être ordonnée selon la date
+d'enregistrement ou le nom d'utilisateur, par ordre croissant on
+décroissant.</p>
+
+<p>Cet écran fonctionne par modification de plusieurs utilisateurs
+simultanément:</p>
+
+<ul>
+
+  <li>supprimer des utilisateurs (nécessite une confirmation)</li>
+
+  <li>changer le status</li>
+
+  <li>associer ou dissocier des groupes</li>
+
+  <li>modifier les propriétés d'affichage</li>
+
+</ul>
+
+<p>La cible est la liste des utilisateurs sélectionnés (par défaut) ou bien
+touts les utilisateurs de la liste filtrée.</p>
Index: /branches/1.5/language/fr_FR.iso-8859-1/install.lang.php
===================================================================
--- /branches/1.5/language/fr_FR.iso-8859-1/install.lang.php	(revision 3250)
+++ /branches/1.5/language/fr_FR.iso-8859-1/install.lang.php	(revision 3250)
@@ -0,0 +1,72 @@
+<?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>';
+$lang['conf_mail_webmaster'] = 'Adresse e-mail de l\'Administrateur';
+$lang['conf_mail_webmaster_info'] = 'Les visiteurs pourront vous contacter par ce mail';
+?>
Index: /branches/1.5/language/fr_FR.iso-8859-1/iso.txt
===================================================================
--- /branches/1.5/language/fr_FR.iso-8859-1/iso.txt	(revision 3250)
+++ /branches/1.5/language/fr_FR.iso-8859-1/iso.txt	(revision 3250)
@@ -0,0 +1,1 @@
+Français [FR]
Index: /branches/1.5/language/index.htm
===================================================================
--- /branches/1.5/language/index.htm	(revision 3250)
+++ /branches/1.5/language/index.htm	(revision 3250)
@@ -0,0 +1,8 @@
+<html>
+    <head>
+        <title>PhpWebGallery</title>
+    </head>
+    <body>
+        No access authorized
+    </body>
+</html>
Index: /branches/1.5/notification.php
===================================================================
--- /branches/1.5/notification.php	(revision 3250)
+++ /branches/1.5/notification.php	(revision 3250)
@@ -0,0 +1,72 @@
+<?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                              |
+// +-----------------------------------------------------------------------+
+
+define('PHPWG_ROOT_PATH','./');
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+
+// +-----------------------------------------------------------------------+
+// |                          new feed creation                            |
+// +-----------------------------------------------------------------------+
+
+$page['feed'] = find_available_feed_id();
+
+$query = '
+INSERT INTO '.USER_FEED_TABLE.'
+  (id, user_id, last_check)
+  VALUES
+  (\''.$page['feed'].'\', '.$user['id'].', NULL)
+;';
+pwg_query($query);
+
+// +-----------------------------------------------------------------------+
+// |                        template initialization                        |
+// +-----------------------------------------------------------------------+
+
+$title = l10n('Notification');
+$page['body_id'] = 'theNotificationPage';
+include(PHPWG_ROOT_PATH.'include/page_header.php');
+$template->set_filenames(array('notification'=>'notification.tpl'));
+
+$template->assign_vars(
+  array(
+    'FEED_URL' => PHPWG_ROOT_PATH.'feed.php?feed='.$page['feed'],
+    'U_HOME' => add_session_id(PHPWG_ROOT_PATH.'category.php')
+    )
+  );
+
+// +-----------------------------------------------------------------------+
+// |                           html code display                           |
+// +-----------------------------------------------------------------------+
+
+$template->parse('notification');
+include(PHPWG_ROOT_PATH.'include/page_tail.php');
+
+?>
Index: /branches/1.5/password.php
===================================================================
--- /branches/1.5/password.php	(revision 3250)
+++ /branches/1.5/password.php	(revision 3250)
@@ -0,0 +1,224 @@
+<?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                              |
+// +-----------------------------------------------------------------------+
+
+define('PHPWG_ROOT_PATH','./');
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+
+// +-----------------------------------------------------------------------+
+// |                              functions                                |
+// +-----------------------------------------------------------------------+
+
+/**
+ * sends an email, using PhpWebGallery specific informations
+ */
+function pwg_mail($to, $from, $infos = '')
+{
+  global $conf;
+
+  $headers = 'From: <'.$from.'>'."\n";
+  $headers.= 'Reply-To: '.$from."\n";
+
+  $options = '-f '.$from;
+  
+  $subject = l10n('password updated');
+  
+  $content = $infos;
+  $content.= "\n\n-- \nPhpWebGallery ".PHPWG_VERSION;
+
+  if ($conf['mail_options'])
+  {
+    return mail($to, $subject, $content, $headers, $options);
+  }
+  else
+  {
+    return mail($to, $subject, $content, $headers);
+  }
+}
+
+// +-----------------------------------------------------------------------+
+// |                          send a new password                          |
+// +-----------------------------------------------------------------------+
+
+$page['errors'] = array();
+$page['infos'] = array();
+
+if (isset($_POST['submit']))
+{
+  // in case of error, creation of mailto link
+  $query = '
+SELECT '.$conf['user_fields']['email'].'
+  FROM '.USERS_TABLE.'
+  WHERE '.$conf['user_fields']['id'].' = '.$conf['webmaster_id'].'
+;';
+  list($mail_webmaster) = mysql_fetch_array(pwg_query($query));
+
+  $mailto =
+    '<a href="mailto:'.$mail_webmaster.'">'
+    .l10n('Contact webmaster')
+    .'</a>'
+    ;
+
+  if (isset($_POST['no_mail_address']) and $_POST['no_mail_address'] == 1)
+  {
+    array_push($page['infos'], l10n('Email address is missing'));
+    array_push($page['infos'], $mailto);
+  }
+  else if (isset($_POST['mail_address']) and !empty($_POST['mail_address']))
+  {
+    $mail_address = mysql_escape_string($_POST['mail_address']);
+    
+    $query = '
+SELECT '.$conf['user_fields']['id'].' AS id
+     , '.$conf['user_fields']['username'].' AS username
+     , '.$conf['user_fields']['email'].' AS email
+  FROM '.USERS_TABLE.'
+  WHERE '.$conf['user_fields']['email'].' = \''.$mail_address.'\'
+;';
+    $result = pwg_query($query);
+
+    if (mysql_num_rows($result) > 0)
+    {
+      $error_on_mail = false;
+      $datas = array();
+      
+      while ($row = mysql_fetch_array($result))
+      {
+        $new_password = generate_key(6);
+
+        $infos =
+          l10n('Username').': '.$row['username']
+          ."\n".l10n('Password').': '.$new_password
+          ;
+
+        if (pwg_mail($row['email'], $mail_webmaster, $infos))
+        {
+          $data =
+            array(
+              $conf['user_fields']['id']
+              => $row['id'],
+              
+              $conf['user_fields']['password']
+              => $conf['pass_convert']($new_password)
+              );
+
+          array_push($datas, $data);
+        }
+        else
+        {
+          $error_on_mail = true;
+        }
+      }
+      
+      if ($error_on_mail)
+      {
+        array_push($page['errors'], l10n('Error sending email'));
+        array_push($page['errors'], $mailto);
+      }
+      else
+      {
+        include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+        mass_updates(
+          USERS_TABLE,
+          array(
+            'primary' => array($conf['user_fields']['id']),
+            'update' => array($conf['user_fields']['password'])
+          ),
+          $datas
+          );
+
+        array_push($page['infos'], l10n('New password sent by email'));
+      }
+    }
+    else
+    {
+      array_push($page['errors'], l10n('No user matches this email address'));
+      array_push($page['errors'], $mailto);
+    }
+  }
+}
+
+// +-----------------------------------------------------------------------+
+// |                        template initialization                        |
+// +-----------------------------------------------------------------------+
+
+$title = l10n('Forgot your password?');
+$page['body_id'] = 'thePasswordPage';
+include(PHPWG_ROOT_PATH.'include/page_header.php');
+$template->set_filenames(array('password'=>'password.tpl'));
+
+$template->assign_vars(
+  array(
+    'U_HOME' => add_session_id(PHPWG_ROOT_PATH.'category.php')
+    )
+  );
+
+// +-----------------------------------------------------------------------+
+// |                        infos & errors display                         |
+// +-----------------------------------------------------------------------+
+
+if (count($page['errors']) != 0)
+{
+  $template->assign_block_vars('errors', array());
+  
+  foreach ($page['errors'] as $error)
+  {
+    $template->assign_block_vars(
+      'errors.error',
+      array(
+        'ERROR' => $error
+        )
+      );
+  }
+}
+
+if (count($page['infos']) != 0)
+{
+  $template->assign_block_vars('infos', array());
+  
+  foreach ($page['infos'] as $info)
+  {
+    $template->assign_block_vars(
+      'infos.info',
+      array(
+        'INFO' => $info
+        )
+      );
+  }
+}
+
+// +-----------------------------------------------------------------------+
+// |                           html code display                           |
+// +-----------------------------------------------------------------------+
+
+$template->parse('password');
+include(PHPWG_ROOT_PATH.'include/page_tail.php');
+
+?>
Index: /branches/1.5/picture.php
===================================================================
--- /branches/1.5/picture.php	(revision 3250)
+++ /branches/1.5/picture.php	(revision 3250)
@@ -0,0 +1,1087 @@
+<?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'] );
+}
+
+if (!is_numeric($_GET['image_id']))
+{
+  die('Hacking attempt on "image_id" GET parameter');
+}
+
+//---------------------------------------- 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();
+}
+//-------------------------------------------------------------- representative
+if ('admin' == $user['status'] and isset($_GET['representative']))
+{
+  $query = '
+UPDATE '.CATEGORIES_TABLE.'
+  SET representative_picture_id = '.$_GET['image_id'].'
+  WHERE id = '.$page['cat'].'
+;';
+  pwg_query($query);
+
+  $url =
+    PHPWG_ROOT_PATH
+    .'picture.php'
+    .get_query_string_diff(array('representative'));
+  redirect($url);
+}
+
+//-------------------------------------------------------------- caddie filling
+
+if (isset($_GET['caddie']))
+{
+  fill_caddie(array($_GET['image_id']));
+
+  $url =
+    PHPWG_ROOT_PATH
+    .'picture.php'
+    .get_query_string_diff(array('caddie'));
+  redirect($url);
+}
+
+//---------------------------------------------------------- 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'].'
+    AND category_id NOT IN ('.$user['forbidden_categories'].')
+;';
+$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 '.$conf['user_fields']['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 )
+    {
+      list($dbnow) = mysql_fetch_row(pwg_query('SELECT NOW();'));
+
+      $data = array();
+      $data{'author'} = $author;
+      $data{'date'} = $dbnow;
+      $data{'image_id'} = $_GET['image_id'];
+      $data{'content'} = htmlspecialchars( $_POST['content'], ENT_QUOTES);
+      
+      if (!$conf['comments_validation'] or $user['status'] == 'admin')
+      {
+        $data{'validated'} = 'true';
+        $data{'validation_date'} = $dbnow;
+      }
+      else
+      {
+        $data{'validated'} = 'false';
+      }
+      
+      include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+      $fields = array('author', 'date', 'image_id', 'content', 'validated',
+                      'validation_date');
+      mass_inserts(COMMENTS_TABLE, $fields, array($data));
+      
+      // information message
+      $message =
+        $lang['comment_added']
+        .(
+          ($conf['comments_validation'] and $user['status'] != 'admin')
+          ?
+          '<br />'.$lang['comment_to_validate']
+          :
+          ''
+          )
+        ;
+      
+      $template->assign_block_vars(
+        'information',
+        array('INFORMATION'=>$message)
+        );
+    }
+    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';
+}
+
+$page['body_id'] = 'thePicturePage';
+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['upload_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'] ))
+  )
+);
+
+if ($conf['show_picture_name_on_title'])
+{
+  $template->assign_block_vars('title', array());
+}
+
+//------------------------------------------------------- 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)
+	));
+}
+// button to set the current picture as representative
+if ('admin' == $user['status'] and is_numeric($page['cat']))
+{
+  $template->assign_block_vars(
+    'representative',
+    array(
+      'URL' =>
+        PHPWG_ROOT_PATH.'picture.php'
+        .get_query_string_diff(array())
+        .'&amp;representative=1'
+      )
+    );
+}
+
+if ('admin' == $user['status'])
+{
+  $template->assign_block_vars(
+    'caddie',
+    array(
+      'URL' =>
+      add_session_id(
+        PHPWG_ROOT_PATH.'picture.php'
+        .get_query_string_diff(array('caddie')).'&amp;caddie=1')
+      )
+    );
+}
+
+//------------------------------------------------------- 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.png',
+        '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.png',
+        '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'])
+      ));
+}
+
+$infos = array();
+
+// author
+if (!empty($picture['current']['author']))
+{
+  $infos['INFO_AUTHOR'] =
+    '<a href="'.
+    add_session_id(
+      PHPWG_ROOT_PATH.'category.php?cat=search'.
+      '&amp;search=author:'.$picture['current']['author']
+      ).
+    '">'.$picture['current']['author'].'</a>';
+}
+else
+{
+  $infos['INFO_AUTHOR'] = l10n('N/A');
+}
+
+// creation date
+if (!empty($picture['current']['date_creation']))
+{
+  $infos['INFO_CREATION_DATE'] =
+    '<a href="'.
+    add_session_id(
+      PHPWG_ROOT_PATH.'category.php?cat=search'.
+      '&amp;search=date_creation:'.$picture['current']['date_creation']
+      ).
+    '">'.format_date($picture['current']['date_creation']).'</a>';
+}
+else
+{
+  $infos['INFO_CREATION_DATE'] = l10n('N/A');
+}
+
+// date of availability
+$infos['INFO_AVAILABILITY_DATE'] =
+  '<a href="'.
+  add_session_id(
+    PHPWG_ROOT_PATH.'category.php?cat=search'.
+    '&amp;search=date_available:'.
+    substr($picture['current']['date_available'], 0, 10)
+    ).
+    '">'.
+  format_date($picture['current']['date_available'], 'mysql_datetime').
+  '</a>';
+
+// size in pixels
+if ($picture['current']['is_picture'])
+{
+  if ($original_width != $picture_size[0]
+      or $original_height != $picture_size[1])
+  {
+    $infos['INFO_DIMENSIONS'] =
+      '<a href="'.$picture['current']['src'].'" title="'.
+      l10n('Original dimensions').'">'.
+      $original_width.'*'.$original_height.'</a>';
+  }
+  else
+  {
+    $infos['INFO_DIMENSIONS'] = $original_width.'*'.$original_height;
+  }
+}
+else
+{
+  $infos['INFO_DIMENSIONS'] = l10n('N/A');
+}
+
+// filesize
+if (!empty($picture['current']['filesize']))
+{
+  $infos['INFO_FILESIZE'] =
+    sprintf(l10n('%d Kb'), $picture['current']['filesize']);
+}
+else
+{
+  $infos['INFO_FILESIZE'] = l10n('N/A');
+}
+
+// number of visits
+$infos['INFO_VISITS'] = $picture['current']['hit'];
+
+// file
+$infos['INFO_FILE'] = $picture['current']['file'];
+
+// keywords
+if (!empty($picture['current']['keywords']))
+{
+  $infos['INFO_KEYWORDS'] =
+    preg_replace(
+      '/([^,]+)/',
+      '<a href="'.
+      add_session_id(
+        PHPWG_ROOT_PATH.'category.php?cat=search&amp;search=keywords:$1'
+        ).
+      '">$1</a>',
+      $picture['current']['keywords']
+      );
+}
+else
+{
+  $infos['INFO_KEYWORDS'] = l10n('N/A');
+}
+
+$template->assign_vars($infos);
+
+// related categories
+foreach ($related_categories as $category)
+{
+  $template->assign_block_vars(
+    'category',
+    array(
+      'LINE' => count($related_categories) > 3
+        ? get_cat_display_name_cache($category['uppercats'])
+        : get_cat_display_name_from_id($category['category_id'])
+      )
+    );
+}
+
+//-------------------------------------------------------------------  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'] )
+  ));
+}
+
+//------------------------------------------------------------------- rating
+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 = sprintf(
+      l10n('%.2f (rated %d times, standard deviation = %.2f)'),
+      $row['average'],
+      $row['count'],
+      $row['STD']
+      );
+  }
+  
+  if (!$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(
+      'CONTENT' => $value,
+      'SENTENCE' => $sentence
+      ));
+
+  $template->assign_block_vars('info_rate', array('CONTENT' => $value));
+  
+  $template->assign_vars(
+    array(
+      'INFO_RATE' => $value
+      )
+    );
+  
+  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
+
+// the picture is commentable if it belongs at least to one category which
+// is commentable
+$page['show_comments'] = false;
+foreach ($related_categories as $category)
+{
+  if ($category['commentable'] == 'true')
+  {
+    $page['show_comments'] = true;
+  }
+}
+
+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'] );
+
+$template->parse('picture');
+include(PHPWG_ROOT_PATH.'include/page_tail.php');
+?>
Index: /branches/1.5/popuphelp.php
===================================================================
--- /branches/1.5/popuphelp.php	(revision 3250)
+++ /branches/1.5/popuphelp.php	(revision 3250)
@@ -0,0 +1,56 @@
+<?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                              |
+// +-----------------------------------------------------------------------+
+
+define('PHPWG_ROOT_PATH','./');
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+
+$page['body_id'] = 'thePopuphelpPage';
+$page['gallery_title'] = $title = l10n('PhpWebGallery Help');
+include(PHPWG_ROOT_PATH.'include/page_header.php');
+
+$template->set_filenames(
+  array(
+    'help_content' => get_language_filepath('help/'.$_GET['page'].'.html')
+    )
+  );
+
+$template->set_filenames(array('popuphelp' => 'popuphelp.tpl'));
+
+$template->assign_var_from_handle('HELP_CONTENT', 'help_content');
+
+// +-----------------------------------------------------------------------+
+// |                           html code display                           |
+// +-----------------------------------------------------------------------+
+
+$template->parse('popuphelp');
+
+include(PHPWG_ROOT_PATH.'include/page_tail.php');
+?>
Index: /branches/1.5/profile.php
===================================================================
--- /branches/1.5/profile.php	(revision 3250)
+++ /branches/1.5/profile.php	(revision 3250)
@@ -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.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// customize appearance of the site for a user
+// +-----------------------------------------------------------------------+
+// |                           initialization                              |
+// +-----------------------------------------------------------------------+
+
+define('PHPWG_ROOT_PATH','./');
+include_once(PHPWG_ROOT_PATH.'include/common.inc.php');
+check_login_authorization(false);
+$userdata = $user;
+
+//------------------------------------------------------ update & customization
+$errors = array();
+if (isset($_POST['validate']))
+{
+  $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']);
+  }
+
+  $mail_error = validate_mail_address($_POST['mail_address']);
+  if (!empty($mail_error))
+  {
+    array_push($errors, $mail_error);
+  }
+    
+  if (!empty($_POST['use_new_pwd']))
+  {
+    // password must be the same as its confirmation
+    if ($_POST['use_new_pwd'] != $_POST['passwordConf'])
+    {
+      array_push($errors,
+                 l10n('New password confirmation does not correspond'));
+    }
+    
+    // changing password requires old password
+    $query = '
+SELECT '.$conf['user_fields']['password'].' AS password
+  FROM '.USERS_TABLE.'
+  WHERE '.$conf['user_fields']['id'].' = \''.$userdata['id'].'\'
+;';
+    list($current_password) = mysql_fetch_row(pwg_query($query));
+    
+    if ($conf['pass_convert']($_POST['password']) != $current_password)
+    {
+      array_push($errors, l10n('Current password is wrong'));
+    }
+  }
+  
+  if (count($errors) == 0)
+  {
+    // mass_updates function
+    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+    
+    // update common user informations
+    $fields = array($conf['user_fields']['email']);
+
+    $data = array();
+    $data{$conf['user_fields']['id']} = $_POST['userid'];
+    $data{$conf['user_fields']['email']} = $_POST['mail_address'];
+
+    // password is updated only if filled
+    if (!empty($_POST['use_new_pwd']))
+    {
+      array_push($fields, $conf['user_fields']['password']);
+      // password is encrpyted with function $conf['pass_convert']
+      $data{$conf['user_fields']['password']} =
+        $conf['pass_convert']($_POST['use_new_pwd']);
+    }
+    mass_updates(USERS_TABLE,
+                 array('primary' => array($conf['user_fields']['id']),
+                       'update' => $fields),
+                 array($data));
+    
+    // update user "additional" informations (specific to PhpWebGallery)
+    $fields = array(
+      'nb_image_line', 'nb_line_page', 'language', 'maxwidth', 'maxheight',
+      'expand', 'show_nb_comments', 'recent_period', 'template'
+      );
+    
+    $data = array();
+    $data{'user_id'} = $_POST['userid'];
+    
+    foreach ($fields as $field)
+    {
+      if (isset($_POST[$field]))
+      {
+        $data{$field} = $_POST[$field];
+      }
+    }
+    mass_updates(USER_INFOS_TABLE,
+                 array('primary' => array('user_id'), 'update' => $fields),
+                 array($data));
+    
+    // redirection
+    $url = PHPWG_ROOT_PATH.'category.php?'.$_SERVER['QUERY_STRING'];
+    redirect(add_session_id($url));
+  }
+}
+// +-----------------------------------------------------------------------+
+// |                       page header and options                         |
+// +-----------------------------------------------------------------------+
+
+$title= $lang['customize_page_title'];
+$page['body_id'] = 'theProfilePage';
+include(PHPWG_ROOT_PATH.'include/page_header.php');
+
+$url_action = PHPWG_ROOT_PATH.'profile.php';
+
+//----------------------------------------------------- template initialization
+$template->set_filenames(array('profile_body'=>'profile.tpl'));
+
+$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_vars(
+  array(
+    'USERNAME'=>$userdata['username'],
+    'USERID'=>$userdata['id'],
+    'EMAIL'=>@$userdata['email'],
+    'NB_IMAGE_LINE'=>$userdata['nb_image_line'],
+    'NB_ROW_PAGE'=>$userdata['nb_line_page'],
+    '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'],
+
+    'U_RETURN' => add_session_id(PHPWG_ROOT_PATH.'category.php'),
+    
+    'F_ACTION'=>add_session_id($url_action),
+    ));
+
+$blockname = 'template_option';
+
+foreach (get_templates() as $pwg_template)
+{
+  if (isset($_POST['submit']))
+  {
+    $selected = $_POST['template']==$pwg_template ? 'selected="selected"' : '';
+  }
+  else if ($userdata['template'] == $pwg_template)
+  {
+    $selected = 'selected="selected"';
+  }
+  else
+  {
+    $selected = '';
+  }
+  
+  $template->assign_block_vars(
+    $blockname,
+    array(
+      'VALUE'=> $pwg_template,
+      'CONTENT' => $pwg_template,
+      'SELECTED' => $selected
+      ));
+}
+
+$blockname = 'language_option';
+
+foreach (get_languages() as $language_code => $language_name)
+{
+  if (isset($_POST['submit']))
+  {
+    $selected = $_POST['language']==$language_code ? 'selected="selected"':'';
+  }
+  else if ($userdata['language'] == $language_code)
+  {
+    $selected = 'selected="selected"';
+  }
+  else
+  {
+    $selected = '';
+  }
+  
+  $template->assign_block_vars(
+    $blockname,
+    array(
+      'VALUE'=> $language_code,
+      'CONTENT' => $language_name,
+      'SELECTED' => $selected
+      ));
+}
+
+// +-----------------------------------------------------------------------+
+// |                             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                           |
+// +-----------------------------------------------------------------------+
+$template->assign_block_vars('profile',array());
+$template->parse('profile_body');
+include(PHPWG_ROOT_PATH.'include/page_tail.php');
+?>
Index: /branches/1.5/random.php
===================================================================
--- /branches/1.5/random.php	(revision 3250)
+++ /branches/1.5/random.php	(revision 3250)
@@ -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.5/register.php
===================================================================
--- /branches/1.5/register.php	(revision 3250)
+++ /branches/1.5/register.php	(revision 3250)
@@ -0,0 +1,98 @@
+<?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']))
+{
+  if ($_POST['password'] != $_POST['password_conf'])
+  {
+    array_push($errors, $lang['reg_err_pass']);
+  }
+  else
+  {
+    $errors =
+      register_user(
+        $_POST['login'],
+        $_POST['password'],
+        $_POST['mail_address']
+        );
+  }
+  
+  if (count($errors) == 0)
+  {
+    $user_id = get_userid($_POST['login']);
+    $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'];
+$page['body_id'] = 'theRegisterPage';
+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'],
+
+  'U_HOME' => add_session_id(PHPWG_ROOT_PATH.'category.php'),
+  
+  '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.5/search.php
===================================================================
--- /branches/1.5/search.php	(revision 3250)
+++ /branches/1.5/search.php	(revision 3250)
@@ -0,0 +1,217 @@
+<?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
+
+// 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'];
+$page['body_id'] = 'theSearchPage';
+include(PHPWG_ROOT_PATH.'include/page_header.php');
+
+$template->set_filenames( array('search'=>'search.tpl') );
+$template->assign_vars(array(
+  '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_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_SUBFORUMS'=>$lang['search_subcats_included'],
+  'L_YES' => $lang['yes'],
+  'L_NO' => $lang['no'],
+  'L_SEARCH_DATE' => $lang['search_date'],
+  '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_HELP' => PHPWG_ROOT_PATH.'/popuphelp.php?page=search',
+  '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 );
+$template->parse('search');
+include(PHPWG_ROOT_PATH.'include/page_tail.php');
+?>
Index: /branches/1.5/template/yoga/about.tpl
===================================================================
--- /branches/1.5/template/yoga/about.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/about.tpl	(revision 3250)
@@ -0,0 +1,12 @@
+<div id="content">
+
+  <div class="titrePage">
+    <ul class="categoryActions">
+      <li><a href="{U_HOME}" title="{lang:return to homepage}"><img src="./template/yoga/theme/home.png" class="button" alt="{lang:home}"/></a></li>
+    </ul>
+    <h2>{lang:About}</h2>
+  </div>
+
+  {ABOUT_MESSAGE}
+
+</div>
Index: /branches/1.5/template/yoga/admin.tpl
===================================================================
--- /branches/1.5/template/yoga/admin.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin.tpl	(revision 3250)
@@ -0,0 +1,90 @@
+<!-- $Id$ -->
+
+<div id="menubar">
+  <dl>
+    <dt>{lang:links}</dt>
+    <dd>
+      <ul>
+	<li><a href="{U_RETURN}">{lang:home}</a></li>
+        <li><a href="{U_ADMIN}" >{lang:admin}</a></li>
+      </ul>
+    </dd>
+
+    <dt>{lang:general}</dt>
+    <dd>
+      <ul>
+	<li><a href="{U_FAQ}">{lang:instructions}</a></li>
+	<li><a href="{U_SITES}">{lang:remote_sites}</a></li>
+	<li><a href="{U_HISTORY}">{lang:history}</a></li>
+	<li><a href="{U_CAT_UPDATE}">{lang:update}</a></li>
+	<li><a href="{U_MAINTENANCE}">{lang:Maintenance}</a></li>
+      </ul>
+    </dd>
+
+    <dt>{lang:config}</dt>
+    <dd>
+      <ul>
+	<li><a href="{U_CONFIG_GENERAL}">{lang:general}</a></li>
+	<li><a href="{U_CONFIG_COMMENTS}">{lang:comments}</a></li>
+	<li><a href="{U_CONFIG_DISPLAY}">{lang:conf_default}</a></li>
+      </ul>
+    </dd>
+
+    <dt>{lang:categories}</dt>
+    <dd>
+      <ul>
+	<li><a href="{U_CATEGORIES}">{lang:manage}</a></li>
+	<li><a href="{U_MOVE}">{lang:Move}</a></li>
+	<li><a href="{U_CAT_UPLOAD}">{lang:upload}</a></li>
+	<li><a href="{U_CAT_COMMENTS}">{lang:comments}</a></li>
+	<li><a href="{U_CAT_VISIBLE}">{lang:lock}</a></li>
+	<li><a href="{U_CAT_STATUS}">{lang:cat_security}</a></li>
+	<!-- BEGIN representative -->
+	<li><a href="{representative.URL}">{lang:Representative}</a></li>
+	<!-- END representative -->
+      </ul>
+    </dd>
+
+    <dt>{lang:pictures}</dt>
+    <dd>
+      <ul>
+	<li><a href="{U_WAITING}">{lang:waiting}</a></li>
+	<li><a href="{U_THUMBNAILS}">{lang:thumbnails}</a></li>
+	<li><a href="{U_COMMENTS}">{lang:comments}</a></li>
+	<li><a href="{U_CADDIE}">{lang:Caddie}</a></li>
+      </ul>
+    </dd>
+
+    <dt>{lang:identification}</dt>
+    <dd>
+      <ul>
+	<li><a href="{U_USERS}">{lang:users}</a></li>
+	<li><a href="{U_GROUPS}">{lang:groups}</a></li>
+      </ul>
+    </dd>
+  </dl>
+</div> <!-- menubar -->
+
+<div id="content">
+  <!-- BEGIN errors -->
+  <div id="errors">
+    <ul>
+      <!-- BEGIN error -->
+      <li>{errors.error.ERROR}</li>
+      <!-- END error -->
+    </ul>
+  </div>
+  <!-- END errors -->
+
+  <!-- BEGIN infos -->
+  <div class="infos">
+    <ul>
+      <!-- BEGIN info -->
+      <li>{infos.info.INFO}</li>
+      <!-- END info -->
+    </ul>
+  </div>
+  <!-- END infos -->
+
+  {ADMIN_CONTENT}
+</div>
Index: /branches/1.5/template/yoga/admin/cat_list.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/cat_list.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/cat_list.tpl	(revision 3250)
@@ -0,0 +1,51 @@
+<!-- $Id$ -->
+<h2>{lang:title_categories}</h2>
+
+<h3>{CATEGORIES_NAV}</h3>
+
+<form id="categoryOrdering" action="" method="post">
+
+  <ul class="categoryUl">
+
+    <!-- BEGIN category -->
+    <li class="categoryLi"> <!-- category {category.ID} -->
+
+      <ul class="categoryActions">
+        <li><a href="{category.U_JUMPTO}" title="{lang:jump to category}"><img src="./template/yoga/theme/category_jump-to.png" class="button" alt="{lang:jump to}" /></a></li> 
+        <li><a href="{category.U_EDIT}" title="{lang:edit category informations}"><img src="./template/yoga/theme/category_edit.png" class="button" alt="{lang:edit}"/></a></li>
+        <!-- BEGIN elements -->
+        <li><a href="{category.elements.URL}" title="{lang:manage category elements}"><img src="./template/yoga/theme/category_elements.png" class="button" alt="{lang:elements}" /></a></li>
+        <!-- END elements -->
+        <li><a href="{category.U_CHILDREN}" title="{lang:manage sub-categories}"><img src="./template/yoga/theme/category_children.png" class="button" alt="{lang:sub-categories}" /></a></li> 
+        <!-- BEGIN permissions -->
+        <li><a href="{category.permissions.URL}" title="{lang:edit category permissions}" ><img src="./template/yoga/theme/category_permissions.png" class="button" alt="{lang:permissions}" /></a></li>
+        <!-- END permissions -->
+        <!-- BEGIN delete -->
+        <li><a href="{category.delete.URL}" title="{lang:delete category}"><img src="./template/yoga/theme/category_delete.png" class="button" alt="{lang:delete}" /></a></li>
+        <!-- END delete -->
+      </ul>
+
+      <p><strong>{category.NAME}</strong></p>
+
+      <p>
+        <label>
+          {lang:Position} :
+          <input type="text" size="4" name="catOrd[{category.ID}]" maxlength="4" value="{category.RANK}" />
+        </label>
+      </p>
+
+    </li>
+    <!-- END category -->
+
+  </ul>
+  <p><input name="submitOrder" type="submit" value="{lang:Save order}" /></p>
+
+</form>
+
+<form id="addVirtual" action="{F_ACTION}" method="post">
+  <p>
+    {L_ADD_VIRTUAL} : <input type="text" name="virtual_name" />
+    <input type="hidden" name="rank" value="{NEXT_RANK}"/>
+    <input type="submit" value="{L_SUBMIT}" name="submitAdd" />
+  </p>
+</form>
Index: /branches/1.5/template/yoga/admin/cat_modify.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/cat_modify.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/cat_modify.tpl	(revision 3250)
@@ -0,0 +1,138 @@
+<!-- $Id$ -->
+<div class="titrePage">
+  <ul class="categoryActions">
+    <li><a href="{U_HELP}" onclick="popuphelp(this.href); return false;" title="{lang:Help}"><img src="template/yoga/theme/help.png" class="button" alt="(?)"></a></li>
+  </ul>
+  <h2>{lang:title_edit_cat}</h2>
+</div>
+
+<h3>{CATEGORIES_NAV}</h3>
+
+<ul class="categoryActions">
+  <li><a href="{U_JUMPTO}" title="{lang:jump to category}"><img src="./template/yoga/theme/category_jump-to.png" class="button" alt="{lang:jump to}" /></a></li>
+  <!-- BEGIN elements -->
+  <li><a href="{elements.URL}" title="{lang:manage category elements}"><img src="./template/yoga/theme/category_elements.png" class="button" alt="{lang:elements}" /></a></li>
+  <!-- END elements -->
+  <li><a href="{U_CHILDREN}" title="{lang:manage sub-categories}"><img src="./template/yoga/theme/category_children.png" class="button" alt="{lang:sub-categories}" /></a></li>
+  <!-- BEGIN permissions -->
+  <li><a href="{permissions.URL}" title="{lang:edit category permissions}" ><img src="./template/yoga/theme/category_permissions.png" class="button" alt="{lang:permissions}" /></a></li>
+  <!-- END permissions -->
+  <!-- BEGIN delete -->
+  <li><a href="{delete.URL}" title="{lang:delete category}"><img src="./template/yoga/theme/category_delete.png" class="button" alt="{lang:delete}" /></a></li>
+  <!-- END delete -->
+</ul>
+
+<form action="{F_ACTION}" method="POST" id="cat_modify">
+
+<fieldset>
+  <legend>{lang:Informations}</legend>
+  <table>
+    <!-- BEGIN server -->
+    <tr>
+      <td><strong>{L_REMOTE_SITE}</strong></td>
+      <td>{server.SITE_URL}</td>
+    </tr>
+    <!-- END server -->
+    <!-- BEGIN storage -->
+    <tr>
+      <td><strong>{L_STORAGE}</strong></td>
+      <td class="row1">{storage.CATEGORY_DIR}</td>
+    </tr>
+    <!-- END storage -->
+    <tr>
+      <td><strong>{L_EDIT_NAME}</strong></td>
+      <td>
+        <input type="text" name="name" value="{CAT_NAME}" maxlength="60"/>
+      </td>
+    </tr>
+    <tr>
+      <td><strong>{L_EDIT_COMMENT}</strong></td>
+      <td>
+        <textarea name="comment" class="description">{CAT_COMMENT}</textarea>
+      </td>
+    </tr>
+  </table>
+</fieldset>
+
+<!-- BEGIN move -->
+<fieldset>
+  <legend>{lang:Move}</legend>
+  {lang:Parent category}
+  <select name="parent">
+    <!-- BEGIN parent_option -->
+    <option class="{move.parent_option.CLASS}" {move.parent_option.SELECTED} value="{move.parent_option.VALUE}">{move.parent_option.OPTION}</option>
+    <!-- END parent_option -->
+  </select>  
+</fieldset>
+<!-- END move -->
+
+<fieldset>
+  <legend>{lang:Options}</legend>
+  <table>
+    <tr>
+      <td><strong>{L_EDIT_STATUS}</strong>
+      <td>
+	  <input type="radio" name="status" value="public" {STATUS_PUBLIC} />{L_STATUS_PUBLIC}
+	  <input type="radio" name="status" value="private" {STATUS_PRIVATE} />{L_STATUS_PRIVATE}
+      </td>
+    </tr>
+    <tr>
+      <td><strong>{L_EDIT_LOCK}</strong>
+      <td>
+	  <input type="radio" name="visible" value="false" {LOCKED} />{L_YES}
+	  <input type="radio" name="visible" value="true" {UNLOCKED} />{L_NO}
+      </td>
+    </tr>
+    <tr>
+      <td><strong>{L_EDIT_COMMENTABLE}</strong>
+      <td>
+          <input type="radio" name="commentable" value="true" {COMMENTABLE_TRUE} />{L_YES}
+          <input type="radio"  name="commentable" value="false" {COMMENTABLE_FALSE} />{L_NO}
+      </td>
+    </tr>
+    <!-- BEGIN upload -->
+    <tr>
+      <td><strong>{L_EDIT_UPLOADABLE}</strong>
+      <td>
+          <input type="radio" name="uploadable" value="true" {UPLOADABLE_TRUE} />{L_YES}
+          <input type="radio" name="uploadable" value="false" {UPLOADABLE_FALSE} />{L_NO}
+      </td>
+    </tr>
+    <!-- END upload -->
+  </table>
+</fieldset>
+
+<p style="text-align:center;">
+  <input type="submit" value="{L_SUBMIT}" name="submit" />
+  <input type="reset" value="{lang:Reset}" name="reset" />
+</p>
+
+<!-- BEGIN representant -->
+<fieldset>
+  <legend>{lang:Representant}</legend>
+  <table>
+    <tr>
+      <td align="center">
+        <!-- BEGIN picture -->
+        <a href="{representant.picture.URL}"><img src="{representant.picture.SRC}" alt="" class="miniature" /></a>
+        <!-- END picture -->
+
+        <!-- BEGIN random -->
+        <img src="./template/yoga/theme/category_representant_random.png" class="button" alt="{lang:Random picture}" class="miniature" />
+        <!-- END random -->
+      </td>
+      <td>
+        <!-- BEGIN set_random --> 
+        <p><input type="submit" name="set_random_representant" value="{L_SET_RANDOM_REPRESENTANT}" /></p>
+        <!-- END set_random -->
+
+        <!-- BEGIN delete_representant -->
+        <p><input type="submit" name="delete_representant" value="{lang:Delete Representant}" /></p>
+        <!-- END delete_representant -->
+      </td>
+    </tr>
+  </table>
+</fieldset>
+<!-- END representant -->
+
+</form>
Index: /branches/1.5/template/yoga/admin/cat_move.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/cat_move.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/cat_move.tpl	(revision 3250)
@@ -0,0 +1,40 @@
+<!-- $Id$ -->
+<div class="titrePage">
+  <ul class="categoryActions">
+    <li><a href="{U_HELP}" onclick="popuphelp(this.href); return false;" title="{lang:Help}"><img src="template/yoga/theme/help.png" class="button" alt="(?)"></a></li>
+  </ul>
+  <h2>{lang:Move categories}</h2>
+</div>
+
+<form method="post" action="{F_ACTION}">
+  <fieldset>
+    <legend>{lang:Virtual categories movement}</legend>
+
+    <label>
+      {lang:Virtual categories to move}
+
+      <select class="categoryList" name="selection[]" multiple="multiple" size="30">
+        <!-- BEGIN category_option_selection -->
+        <option {category_option_selection.SELECTED} value="{category_option_selection.VALUE}">{category_option_selection.OPTION}</option>
+        <!-- END category_option_selection -->
+      </select>
+    </label>
+
+    <label>
+      {lang:New parent category}
+
+      <select class="categoryList" name="parent">
+        <!-- BEGIN category_option_parent -->
+        <option {category_option_parent.SELECTED} value="{category_option_parent.VALUE}">{category_option_parent.OPTION}</option>
+        <!-- END category_option_parent -->
+      </select>
+    </label>
+
+  </fieldset>
+
+  <p>
+    <input type="submit" name="submit" value="{lang:Submit}">
+    <input type="reset" name="reset" value="{lang:Reset}">
+  </p>
+
+</form>
Index: /branches/1.5/template/yoga/admin/cat_options.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/cat_options.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/cat_options.tpl	(revision 3250)
@@ -0,0 +1,17 @@
+<!-- $Id$ -->
+<div class="titrePage">
+  <ul class="categoryActions">
+    <li><a href="{U_HELP}" onclick="popuphelp(this.href); return false;" title="{lang:Help}"><img src="template/yoga/theme/help.png" class="button" alt="(?)"></a></li>
+  </ul>
+  <h2>{lang:title_cat_options}</h2>
+</div>
+
+<form method="post" action="{F_ACTION}" id="cat_options">
+  <fieldset>
+    <legend>{L_SECTION}</legend>
+    {DOUBLE_SELECT}
+  </fieldset>
+</form>
+
+<p class="information">{L_CAT_OPTIONS_INFO}</div>
+
Index: /branches/1.5/template/yoga/admin/cat_perm.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/cat_perm.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/cat_perm.tpl	(revision 3250)
@@ -0,0 +1,65 @@
+<div class="titrePage">
+  <ul class="categoryActions">
+    <li><a href="{U_HELP}" onclick="popuphelp(this.href); return false;" title="{lang:Help}"><img src="template/yoga/theme/help.png" class="button" alt="(?)"></a></li>
+  </ul>
+  <h2>{lang:Manage permissions for a category}</h2>
+</div>
+
+<h3>{CATEGORIES_NAV}</h3>
+
+<form action="{F_ACTION}" method="post" id="categoryPermissions">
+
+  <h4>{lang:Groups}</h4>
+
+  <fieldset>
+    <legend>{lang:Permission granted}</legend>
+    <ul>
+      <!-- BEGIN group_granted -->
+      <li><label><input type="checkbox" name="deny_groups[]" value="{group_granted.ID}" /> {group_granted.NAME}</label></li>
+      <!-- END group_granted -->
+    </ul>
+    <input type="submit" name="deny_groups_submit" value="{lang:Deny selected groups}" />
+  </fieldset>
+
+  <fieldset>
+    <legend>{lang:Permission denied}</legend>
+    <ul>
+      <!-- BEGIN group_denied -->
+      <li><label><input type="checkbox" name="grant_groups[]" value="{group_denied.ID}"> {group_denied.NAME}</label></li>
+      <!-- END group_denied -->
+    </ul>
+    <input type="submit" name="grant_groups_submit" value="{lang:Grant selected groups}" />
+  </fieldset>
+
+  <h4>{lang:Users}</h4>
+  
+  <fieldset>
+    <legend>{lang:Permission granted}</legend>
+    <ul>
+      <!-- BEGIN user_granted -->
+      <li><label><input type="checkbox" name="deny_users[]" value="{user_granted.ID}" /> {user_granted.NAME}</label></li>
+      <!-- END user_granted -->
+    </ul>
+    <input type="submit" name="deny_users_submit" value="{lang:Deny selected users}" />
+  </fieldset>
+
+  <fieldset>
+    <legend>{lang:Permission granted thanks to a group}</legend>
+    <ul>
+      <!-- BEGIN user_granted_indirect -->
+      <li>{user_granted_indirect.NAME} ({user_granted_indirect.GROUP})</li>
+      <!-- END user_granted_indirect -->
+    </ul>
+  </fieldset>
+
+  <fieldset>
+    <legend>{lang:Permission denied}</legend>
+    <ul>
+      <!-- BEGIN user_denied -->
+      <li><label><input type="checkbox" name="grant_users[]" value="{user_denied.ID}"> {user_denied.NAME}</label></li>
+      <!-- END user_denied -->
+    </ul>
+    <input type="submit" name="grant_users_submit" value="{lang:Grant selected users}" />
+  </fieldset>
+
+</form>
Index: /branches/1.5/template/yoga/admin/comments.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/comments.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/comments.tpl	(revision 3250)
@@ -0,0 +1,26 @@
+<h2>{lang:User comments validation}</h2>
+
+<form method="post" action="{F_ACTION}">
+
+  <input type="hidden" name="list" value="{LIST}" />
+
+  <!-- BEGIN comment -->
+  <div class="comment">
+    <a class="illustration" href="{comment.U_PICTURE}"><img src="{comment.TN_SRC}" /></a>
+    <p class="commentHeader"><strong>{comment.AUTHOR}</strong> - <em>{comment.DATE}</em></p>
+    <blockquote>{comment.CONTENT}</blockquote>
+    <ul class="actions">
+      <li><label><input type="radio" name="action-{comment.ID}" value="reject" />{lang:Reject}</label></li>
+      <li><label><input type="radio" name="action-{comment.ID}" value="validate" />{lang:Validate}</label></li>
+    </ul>
+  </div>
+  <!-- END comment -->
+
+  <p class="bottomButtons">
+    <input type="submit" name="submit" value="{lang:Submit}" />
+    <input type="submit" name="validate-all" value="{lang:Validate All}" />
+    <input type="submit" name="reject-all" value="{lang:Reject All}" />
+    <input type="reset" value="{lang:Reset}" />
+  </p>
+
+</form>
Index: /branches/1.5/template/yoga/admin/configuration.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/configuration.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/configuration.tpl	(revision 3250)
@@ -0,0 +1,128 @@
+<!-- $Id$ -->
+<div class="titrePage">
+  <ul class="categoryActions">
+    <li><a href="{U_HELP}" onclick="popuphelp(this.href); return false;" title="{lang:Help}"><img src="template/yoga/theme/help.png" class="button" alt="(?)"></a></li>
+  </ul>
+  <h2>{lang:title_configuration}</h2>
+</div>
+
+<form method="post" action="{F_ACTION}" class="properties">
+
+<fieldset>
+<!-- BEGIN general -->
+  <legend>{lang:conf_general_title}</legend>
+
+  <ul>
+    <li>
+      <label for="gallery_title"><strong>{lang:Gallery title}</strong></label>
+      <input type="text" maxlength="255" size="50" name="gallery_title" id="gallery_title" value="{general.CONF_GALLERY_TITLE}" />
+    </li>
+
+    <li>
+      <label for="gallery_description"><strong>{lang:Gallery description}</strong></label>
+      <textarea cols="50" rows="5" name="gallery_description" id="gallery_description">{general.CONF_GALLERY_DESCRIPTION}</textarea>
+    </li>
+
+    <li>
+      <label><strong>{lang:History}</strong></label>
+      <input type="radio" class="radio" name="log" value="true" {general.HISTORY_YES} />{lang:Yes}
+      <input type="radio" class="radio" name="log" value="false" {general.HISTORY_NO} />{lang:No}
+    </li>
+
+    <li>
+      <label><strong>{lang:Lock gallery}</strong></label>
+      <input type="radio" class="radio" name="gallery_locked" value="true" {general.GALLERY_LOCKED_YES} />{lang:Yes}
+      <input type="radio" class="radio" name="gallery_locked" value="false" {general.GALLERY_LOCKED_NO} />{lang:No}
+    </li>
+  </ul>
+<!-- END general -->
+
+<!-- BEGIN comments -->
+  <legend>{lang:conf_comments_title}</legend>
+
+  <ul>
+    <li>
+      <label><strong>{lang:Comments for all}</strong></label>
+      <input type="radio" class="radio" name="comments_forall" value="true" {comments.COMMENTS_ALL_YES} />{lang:Yes}
+      <input type="radio" class="radio" name="comments_forall" value="false" {comments.COMMENTS_ALL_NO} />{lang:No}
+    </li>
+
+    <li>
+      <label for="nb_comment_page"><strong>{lang:Number of comments per page}</strong></label>
+      <input type="text" size="3" maxlength="4" name="nb_comment_page" id="nb_comment_page" value="{comments.NB_COMMENTS_PAGE}" />
+    </li>
+
+    <li>
+      <label><strong>{lang:Validation}</strong></label>
+      <input type="radio" class="radio" name="comments_validation" value="true" {comments.VALIDATE_YES} />{lang:Yes}
+      <input type="radio" class="radio" name="comments_validation" value="false" {comments.VALIDATE_NO} />{lang:No}
+    </li>
+  </ul>
+<!-- END comments -->
+<!-- BEGIN default -->
+  <legend>{lang:conf_default_title}</legend>
+
+  <ul>
+    <li>
+      <label for="language"><strong>{lang:Language}</strong></label>
+      <select name="default_language" id="default_language">
+        <!-- BEGIN language_option -->
+        <option value="{default.language_option.VALUE}" {default.language_option.SELECTED}>{default.language_option.CONTENT}</option>
+        <!-- END language_option -->
+      </select>
+    </li>
+
+    <li>
+      <label for="nb_image_line"><strong>{lang:Number of images per row}</strong></label>
+      <input type="text" size="3" maxlength="2" name="nb_image_line" value="{default.NB_IMAGE_LINE}" />
+    </li>
+
+    <li>
+      <label><strong>{lang:Number of rows per page}</strong></label>
+      <input type="text" size="3" maxlength="2" name="nb_line_page" value="{default.NB_ROW_PAGE}" />
+    </li>
+
+    <li>
+      <label><strong>{lang:Interface theme}</strong></label>
+      <select name="default_template" id="default_template">
+        <!-- BEGIN template_option -->
+        <option value="{default.template_option.VALUE}" {default.template_option.SELECTED}>{default.template_option.CONTENT}</option>
+        <!-- END template_option -->
+      </select>
+    </li>
+
+    <li>
+      <label for="recent_period"><strong>{lang:Recent period}</strong></label>
+      <input type="text" size="3" maxlength="2" name="recent_period" id="recent_period" value="{default.CONF_RECENT}" />
+    </li>
+
+    <li>
+      <label><strong>{lang:Expand all categories}</strong></label>
+      <input type="radio" class="radio" name="auto_expand" value="true" {default.EXPAND_YES} />{lang:Yes}
+      <input type="radio" class="radio" name="auto_expand" value="false" {default.EXPAND_NO} />{lang:No}
+    </li>
+
+    <li>
+      <label><strong>{lang:Show number of comments}</strong></label>
+      <input type="radio" class="radio" name="show_nb_comments" value="true" {default.SHOW_COMMENTS_YES} />{lang:Yes}
+      <input type="radio" class="radio" name="show_nb_comments" value="false" {default.SHOW_COMMENTS_NO} />{lang:No}
+    </li>
+
+    <li>
+      <label><strong>{lang:Maximum width of the pictures}</strong></label>
+      <input type="text" size="4" maxlength="4" name="default_maxwidth" value="{default.MAXWIDTH}" />
+    </li>
+
+    <li>
+      <label><strong>{lang:Maximum height of the pictures}</strong></label>
+      <input type="text" size="4" maxlength="4" name="default_maxheight" value="{default.MAXHEIGHT}" />
+    </li>
+  </ul>
+<!-- END default -->
+  </fieldset>
+  
+  <p>
+    <input type="submit" name="submit" value="{lang:Submit}">
+    <input type="reset" name="reset" value="{lang:Reset}">
+  </p>
+</form>
Index: /branches/1.5/template/yoga/admin/double_select.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/double_select.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/double_select.tpl	(revision 3250)
@@ -0,0 +1,23 @@
+<table class="doubleSelect">
+  <tr>
+    <td>
+      <h3>{L_CAT_OPTIONS_TRUE}</h3>
+      <select class="categoryList" name="cat_true[]" multiple="multiple" size="30">
+        <!-- BEGIN category_option_true -->
+        <option {category_option_true.SELECTED} value="{category_option_true.VALUE}">{category_option_true.OPTION}</option>
+        <!-- END category_option_true -->
+      </select>
+      <p><input type="submit" value="&raquo;" name="falsify" style="font-size:15px;"/></p>
+    </td>
+
+    <td>
+      <h3>{L_CAT_OPTIONS_FALSE}</h3>
+      <select class="categoryList" name="cat_false[]" multiple="multiple" size="30">
+        <!-- BEGIN category_option_false -->
+        <option {category_option_false.SELECTED} value="{category_option_false.VALUE}">{category_option_false.OPTION}</option>
+        <!-- END category_option_false -->
+      </select>
+      <p><input type="submit" value="&laquo;" name="trueify" style="font-size:15px;" /></p>
+    </td>
+  </tr>
+</table>
Index: /branches/1.5/template/yoga/admin/element_set_global.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/element_set_global.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/element_set_global.tpl	(revision 3250)
@@ -0,0 +1,187 @@
+<!-- $Id$ -->
+<h2>{lang:Batch management}</h2>
+
+<h3>{CATEGORIES_NAV}</h3>
+
+<p style="text-align:center;">
+  {lang:global mode}
+  | <a href="{U_UNIT_MODE}">{lang:unit mode}</a>
+</p>
+
+<form action="{F_ACTION}" method="post">
+
+<fieldset>
+
+  <legend>{lang:Caddie management}</legend>
+
+  <ul style="list-style-type:none;">
+
+    <!-- BEGIN in_caddie -->
+    <li><label><input type="radio" name="caddie_action" value="empty_all" /> {lang:Empty caddie}</label></li>
+    <li><label><input type="radio" name="caddie_action" value="empty_selected" /> {lang:Take selected elements out of caddie}</label></li>
+    <!-- END in_caddie -->
+
+    <!-- BEGIN not_in_caddie -->
+    <li><input type="radio" name="caddie_action" value="add_selected" /> {lang:Add selected elements to caddie}</li>
+    <!-- END not_in_caddie -->
+  
+  </ul>
+
+  <p style="text-align:center;"><input type="submit" value="{L_SUBMIT}" name="submit_caddie" /></p>
+
+</fieldset>
+
+<fieldset>
+
+  <legend>{lang:Display options}</legend>
+
+  <p>{lang:elements per line}:
+      <a href="{U_COLS}&amp;cols=4">4</a>
+    | <a href="{U_COLS}&amp;cols=5">5</a>
+    | <a href="{U_COLS}&amp;cols=6">6</a>
+    | <a href="{U_COLS}&amp;cols=7">7</a>
+    | <a href="{U_COLS}&amp;cols=8">8</a>
+    | <a href="{U_COLS}&amp;cols=9">9</a>
+    | <a href="{U_COLS}&amp;cols=10">10</a>
+  </p>
+
+  <p>{lang:elements per page}:
+      <a href="{U_DISPLAY}&amp;display=20">20</a>
+    | <a href="{U_DISPLAY}&amp;display=50">50</a>
+    | <a href="{U_DISPLAY}&amp;display=100">100</a>
+    | <a href="{U_DISPLAY}&amp;display=all">{lang:all}</a>
+  </p>
+
+</fieldset>
+
+<fieldset>
+
+  <legend>{lang:Form}</legend>
+
+  <table>
+
+    <tr>
+      <td>{lang:associate to category}</td>
+      <td>
+       <select style="width:400px" name="associate" size="1">
+         <!-- BEGIN associate_option -->
+         <option {associate_option.SELECTED} value="{associate_option.VALUE}">{associate_option.OPTION}</option>
+         <!-- END associate_option -->
+       </select>
+      </td>
+    </tr>
+
+    <tr>
+      <td>{lang:dissociate from category}</td>
+      <td>
+        <select style="width:400px" name="dissociate" size="1">
+          <!-- BEGIN dissociate_option -->
+          <option {dissociate_option.SELECTED} value="{dissociate_option.VALUE}">{dissociate_option.OPTION}</option>
+          <!-- END dissociate_option -->
+        </select>
+      </td>
+    </tr>
+
+    <tr>
+      <td>{lang:add keywords}</td>
+      <td><input type="text" name="add_keywords" value="" /></td>
+    </tr>
+
+    <tr>
+      <td>{lang:remove keyword}</td>
+      <td>
+        <select name="remove_keyword">
+          <!-- BEGIN remove_keyword_option -->
+          <option value="{remove_keyword_option.VALUE}">{remove_keyword_option.OPTION}</option>
+          <!-- END remove_keyword_option -->
+        </select>
+      </td>
+    </tr>
+
+    <tr>
+      <td>{lang:author}</td>
+      <td>
+        <input type="radio" name="author_action" value="leave" checked="checked" /> {lang:leave}
+        <input type="radio" name="author_action" value="unset" /> {lang:unset}
+        <input type="radio" name="author_action" value="set" id="author_action_set" /> {lang:set to}
+        <input onmousedown="document.getElementById('author_action_set').checked = true;" type="text" name="author" value="" />
+      </td>
+    </tr>
+
+    <tr>
+      <td>{lang:title}</td>
+      <td>
+        <input type="radio" name="name_action" value="leave" checked="checked" /> {lang:leave}
+        <input type="radio" name="name_action" value="unset" /> {lang:unset}
+        <input type="radio" name="name_action" value="set" id="name_action_set" /> {lang:set to}
+        <input onmousedown="document.getElementById('name_action_set').checked = true;" type="text" name="name" value="" />
+      </td>
+    </tr>
+
+    <tr>
+      <td>{lang:creation date}</td>
+      <td>
+        <input type="radio" name="date_creation_action" value="leave" checked="checked" /> {lang:leave}
+        <input type="radio" name="date_creation_action" value="unset" /> {lang:unset}
+        <input type="radio" name="date_creation_action" value="set" id="date_creation_action_set" /> {lang:set to}
+        <select onmousedown="document.getElementById('date_creation_action_set').checked = true;" name="date_creation_day">
+          <!-- BEGIN date_creation_day -->
+          <option {date_creation_day.SELECTED} value="{date_creation_day.VALUE}">{date_creation_day.OPTION}</option>
+          <!-- END date_creation_day -->
+        </select>
+        <select onmousedown="document.getElementById('date_creation_action_set').checked = true;" name="date_creation_month">
+          <!-- BEGIN date_creation_month -->
+          <option {date_creation_month.SELECTED} value="{date_creation_month.VALUE}">{date_creation_month.OPTION}</option>
+          <!-- END date_creation_month -->
+        </select>
+        <input onmousedown="document.getElementById('date_creation_action_set').checked = true;"
+               name="date_creation_year"
+               type="text"
+               size="4"
+               maxlength="4"
+               value="{DATE_CREATION_YEAR_VALUE}" />
+      </td>
+    </tr>
+
+  </table>
+
+  <p style="text-align:center;">
+    {lang:target}
+    <input type="radio" name="target" value="all" /> {lang:all}
+    <input type="radio" name="target" value="selection" checked="checked" /> {lang:selection}
+  </p>
+
+    
+  <p style="text-align:center;"><input type="submit" value="{L_SUBMIT}" name="submit" /></p>
+
+</fieldset>
+
+<fieldset>
+
+  <legend>{lang:Elements}</legend>
+
+  <div class="navigationBar">{NAV_BAR}</div>
+
+  <!-- BEGIN thumbnails -->
+  <table valign="top" align="center" class="thumbnail">
+    <!-- BEGIN line -->
+    <tr>
+      <!-- BEGIN thumbnail -->
+      <td class="thumbnail">
+        <label>
+        <img src="{thumbnails.line.thumbnail.SRC}"
+             alt="{thumbnails.line.thumbnail.ALT}"
+             title="{thumbnails.line.thumbnail.TITLE}"
+             class="thumbLink" />
+        <br /><input type="checkbox" name="selection[]" value="{thumbnails.line.thumbnail.ID}" />
+        </label>
+      </td>
+      <!-- END thumbnail -->
+    </tr>
+    <!-- END line -->
+  </table>
+  <!-- END thumbnails -->
+
+</fieldset>
+
+</form>
Index: /branches/1.5/template/yoga/admin/element_set_unit.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/element_set_unit.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/element_set_unit.tpl	(revision 3250)
@@ -0,0 +1,92 @@
+<h2>{lang:Batch management}</h2>
+
+<h3>{CATEGORIES_NAV}</h3>
+
+<p style="text-align:center;">
+  <a href="{U_GLOBAL_MODE}">{lang:global mode}</a>
+  | {lang:unit mode}
+</p>
+
+<form action="{F_ACTION}" method="POST">
+
+<input type="hidden" name="list" value="{IDS_LIST}" />
+
+<fieldset>
+
+  <legend>{lang:Display options}</legend>
+
+  <p>{lang:elements per page} :
+      <a href="{U_ELEMENTS_PAGE}&amp;display=5">5</a>
+    | <a href="{U_ELEMENTS_PAGE}&amp;display=10">10</a>
+    | <a href="{U_ELEMENTS_PAGE}&amp;display=50">50</a>
+    | <a href="{U_ELEMENTS_PAGE}&amp;display=all">{lang:all}</a>
+  </p>
+
+</fieldset>
+
+<div class="navigationBar">{NAV_BAR}</div>
+
+<!-- BEGIN element -->
+<fieldset class="elementEdit">
+  <legend>{element.LEGEND}</legend>
+
+  <a href="{element.U_EDIT}"><img src="{element.TN_SRC}" alt="" class="miniature" title="{lang:Edit all picture informations}" /></a>
+
+  <table>
+
+    <tr>
+      <td><strong>{lang:Name}</strong></td>
+      <td><input type="text" name="name-{element.ID}" value="{element.NAME}" /></td>
+    </tr>
+
+    <tr>
+      <td><strong>{lang:Author}</strong></td>
+      <td><input type="text" name="author-{element.ID}" value="{element.AUTHOR}" /></td>
+    </tr>
+
+    <tr>
+      <td><strong>{lang:Creation date}</strong></td>
+      <td>
+        <label><input type="radio" name="date_creation_action-{element.ID}" value="unset" /> {lang:unset}</label>
+        <input type="radio" name="date_creation_action-{element.ID}" value="set" id="date_creation_action_set-{element.ID}" /> {lang:set to}
+        <select onmousedown="document.getElementById('date_creation_action_set-{element.ID}').checked = true;" name="date_creation_day-{element.ID}">
+          <!-- BEGIN date_creation_day -->
+          <option {element.date_creation_day.SELECTED} value="{element.date_creation_day.VALUE}">{element.date_creation_day.OPTION}</option>
+          <!-- END date_creation_day -->
+        </select>
+        <select onmousedown="document.getElementById('date_creation_action_set-{element.ID}').checked = true;" name="date_creation_month-{element.ID}">
+          <!-- BEGIN date_creation_month -->
+          <option {element.date_creation_month.SELECTED} value="{element.date_creation_month.VALUE}">{element.date_creation_month.OPTION}</option>
+          <!-- END date_creation_month -->
+        </select>
+        <input onmousedown="document.getElementById('date_creation_action_set-{element.ID}').checked = true;"
+               name="date_creation_year-{element.ID}"
+               type="text"
+               size="4"
+               maxlength="4"
+               value="{element.DATE_CREATION_YEAR}" />
+      </td>
+    </tr>
+
+    <tr>
+      <td><strong>{lang:Keywords}</strong></td>
+      <td><input type="text" name="keywords-{element.ID}" value="{element.KEYWORDS}" size="50" /></td>
+    </tr>
+
+    <tr>
+      <td><strong>{lang:Description}</strong></td>
+      <td><textarea name="description-{element.ID}" class="description">{element.DESCRIPTION}</textarea></td>
+    </tr>
+
+  </table>
+
+</fieldset>
+<!-- END element -->
+
+<p>
+  <input type="submit" value="{L_SUBMIT}" name="submit" />
+  <input type="reset" value="{lang:Reset}" />
+</p>
+
+
+</form>
Index: /branches/1.5/template/yoga/admin/group_list.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/group_list.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/group_list.tpl	(revision 3250)
@@ -0,0 +1,28 @@
+<!-- $Id$ -->
+<h2>{lang:title_groups}</h2>
+
+<form method="post" name="add_user" action="{F_ADD_ACTION}" class="properties">
+  <fieldset>
+    <legend>{lang:Add group}</legend>
+    <label>{lang:Group name}</label><input type="text" name="groupname" maxlength="50" size="20" />
+    <p><input type="submit" name="submit_add" value="{lang:Add}" /></p>
+  </fieldset>
+</form>
+
+<table class="table2">
+  <tr class="throw">
+    <th>{lang:Group name}</th>
+    <th>{lang:Members}</th>
+    <th>{lang:Actions}</th>
+  </tr>
+  <!-- BEGIN group -->
+  <tr class="{group.CLASS}">
+    <td>{group.NAME}</td>
+    <td><a href="{group.U_MEMBERS}">{group.MEMBERS}</a></td>
+    <td style="text-align:center;">
+      <a href="{group.U_PERM}"><img src="./template/yoga/theme/permissions.png" class="button" style="border:none" alt="permissions" title="{lang:permissions}" /></a>
+      <a href="{group.U_DELETE}"><img src="./template/yoga/theme/delete.png" class="button" style="border:none" alt="delete" title="{lang:delete}" /></a>
+    </td>
+  </tr>
+  <!-- END group -->
+</table>
Index: /branches/1.5/template/yoga/admin/group_perm.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/group_perm.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/group_perm.tpl	(revision 3250)
@@ -0,0 +1,7 @@
+<h2>{TITLE}</h2>
+
+<form method="post" action="{F_ACTION}">
+  {DOUBLE_SELECT}
+</form>
+
+<p>{lang:Only private categories are listed}</p>
Index: /branches/1.5/template/yoga/admin/intro.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/intro.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/intro.tpl	(revision 3250)
@@ -0,0 +1,47 @@
+<!-- $Id$ -->
+<h2>{lang:title_default}</h2>
+
+<dl>
+  <dt>{lang:PhpWebGallery version}</dt>
+  <dd>
+    <ul>
+      <li>PhpWebGallery {PWG_VERSION}</li>
+      <li><a href="{U_CHECK_UPGRADE}">{lang:Check for upgrade}</a></li>
+    </ul>
+  </dd>
+
+  <dt>{lang:Environment}</dt>
+  <dd>
+    <ul>
+      <li>{lang:Operating system}: {OS}</li>
+      <li>PHP: {PHP_VERSION} (<a href="{U_PHPINFO}">{lang:Show info}</a>)</li>
+      <li>MySQL: {MYSQL_VERSION}</li>
+    </ul>
+  </dd>
+
+  <dt>{lang:Database}</dt>
+  <dd>
+    <ul>
+      <li>
+        {DB_ELEMENTS}
+        <!-- BEGIN waiting -->
+        (<a href="{waiting.URL}">{waiting.INFO}</a>)
+        <!-- END waiting -->
+
+        <!-- BEGIN first_added -->
+        ({first_added.DB_DATE})
+        <!-- END first_added -->
+      </li>
+      <li>{DB_CATEGORIES}</li>
+      <li>{DB_USERS}</li>
+      <li>{DB_GROUPS}</li>
+      <li>
+        {DB_COMMENTS}
+        <!-- BEGIN unvalidated -->
+        (<a href="{unvalidated.URL}">{unvalidated.INFO}</a>)
+        <!-- END unvalidated -->
+      </li>
+    </ul>
+  </dd>
+
+</dl>
Index: /branches/1.5/template/yoga/admin/maintenance.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/maintenance.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/maintenance.tpl	(revision 3250)
@@ -0,0 +1,15 @@
+<!-- $Id$ -->
+<div class="titrePage">
+  <ul class="categoryActions">
+    <li><a href="{U_HELP}" onclick="popuphelp(this.href); return false;" title="{lang:Help}"><img src="template/yoga/theme/help.png" class="button" alt="(?)"></a></li>
+  </ul>
+  <h2>{lang:Maintenance}</h2>
+</div>
+
+<ul>
+  <li><a href="{U_MAINT_CATEGORIES}">{lang:update categories informations}</a></li>
+  <li><a href="{U_MAINT_IMAGES}">{lang:update images informations}</a></li>
+  <li><a href="{U_MAINT_HISTORY}">{lang:purge history}</a></li>
+  <li><a href="{U_MAINT_SESSIONS}">{lang:purge sessions}</a></li>
+  <li><a href="{U_MAINT_FEEDS}">{lang:purge never used notification feeds}</a></li>
+</ul>
Index: /branches/1.5/template/yoga/admin/picture_modify.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/picture_modify.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/picture_modify.tpl	(revision 3250)
@@ -0,0 +1,182 @@
+<!-- $Id$ -->
+<h2>{lang:title_picmod}</h2>
+
+<img src="{TN_SRC}" alt="{lang:thumbnail}" class="thumbnail" />
+
+<ul class="categoryActions">
+  <!-- BEGIN jumpto -->
+  <li><a href="{jumpto.URL}" title="{lang:jump to image}"><img src="./template/yoga/theme/category_jump-to.png" class="button" alt="{lang:jump to}" /></a></li>
+  <!-- END jumpto -->
+  <li><a href="{U_SYNC}" title="{lang:synchronize metadata}"><img src="./template/yoga/theme/sync_metadata.png" class="button" alt="{lang:synchronize}" /></a></li>
+</ul>
+
+<form action="{F_ACTION}" method="post" id="properties">
+
+  <fieldset>
+    <legend>{lang:Informations}</legend>
+
+    <table>
+
+      <tr>
+        <td><strong>{lang:Path}</strong></td>
+        <td>{PATH}</td>
+      </tr>
+
+      <tr>
+        <td><strong>{lang:Registration date}</strong></td>
+        <td>{REGISTRATION_DATE}</td>
+      </tr>
+
+      <tr>
+        <td><strong>{lang:Dimensions}</strong></td>
+        <td>{DIMENSIONS}</td>
+      </tr>
+
+      <tr>
+        <td><strong>{lang:Filesize}</strong></td>
+        <td>{FILESIZE}</td>
+      </tr>
+
+      <tr>
+        <td><strong>{lang:Storage category}</strong></td>
+        <td>{STORAGE_CATEGORY}</td>
+      </tr>
+
+      <!-- BEGIN links -->
+      <tr>
+        <td><strong>{lang:Linked categories}</strong></td>
+        <td>
+          <ul>
+            <!-- BEGIN category -->
+            <li>{links.category.NAME}</li>
+            <!-- END category -->
+          </ul>
+        </td>
+      </tr>
+      <!-- END links -->
+
+    </table>
+
+  </fieldset>
+
+  <fieldset>
+    <legend>{lang:Properties}</legend>
+
+    <table>
+
+      <tr>
+        <td><strong>{lang:Name}</strong></td>
+        <td><input type="text" name="name" value="{NAME}" /></td>
+      </tr>
+
+      <tr>
+        <td><strong>{lang:Author}</strong></td>
+        <td><input type="text" name="author" value="{AUTHOR}" /></td>
+      </tr>
+
+      <tr>
+        <td><strong>{lang:Creation date}</strong></td>
+        <td>
+          <label><input type="radio" name="date_creation_action" value="unset" /> {lang:unset}</label>
+          <input type="radio" name="date_creation_action" value="set" id="date_creation_action_set" /> {lang:set to}
+          <select onmousedown="document.getElementById('date_creation_action_set').checked = true;" name="date_creation_day">
+            <!-- BEGIN date_creation_day -->
+            <option {date_creation_day.SELECTED} value="{date_creation_day.VALUE}">{date_creation_day.OPTION}</option>
+            <!-- END date_creation_day -->
+          </select>
+          <select onmousedown="document.getElementById('date_creation_action_set').checked = true;" name="date_creation_month">
+            <!-- BEGIN date_creation_month -->
+            <option {date_creation_month.SELECTED} value="{date_creation_month.VALUE}">{date_creation_month.OPTION}</option>
+            <!-- END date_creation_month -->
+          </select>
+          <input onmousedown="document.getElementById('date_creation_action_set').checked = true;"
+                 name="date_creation_year"
+                 type="text"
+                 size="4"
+                 maxlength="4"
+                 value="{DATE_CREATION_YEAR_VALUE}" />
+        </td>
+      </tr>
+
+      <tr>
+        <td><strong>{lang:Keywords}</strong></td>
+        <td><input type="text" name="keywords" value="{KEYWORDS}" size="50" /></td>
+      </tr>
+
+      <tr>
+        <td><strong>{lang:Description}</strong></td>
+        <td><textarea name="description" class="description">{DESCRIPTION}</textarea></td>
+      </tr>
+
+    </table>
+
+    <p style="text-align:center;">
+      <input type="submit" value="{lang:Submit}" name="submit" />
+      <input type="reset" value="{lang:Reset}" name="reset" />
+    </p>
+
+  </fieldset>
+
+</form>
+
+<form id="associations" method="post" action="{F_ACTION}#associations">
+  <fieldset>
+    <legend>{lang:Association to categories}</legend>
+
+    <table class="doubleSelect">
+      <tr>
+        <td>
+          <h3>{lang:Associated}</h3>
+          <select class="categoryList" name="cat_associated[]" multiple="multiple" size="30">
+            <!-- BEGIN associated_option -->
+            <option {associated_option.SELECTED} value="{associated_option.VALUE}">{associated_option.OPTION}</option>
+            <!-- END associated_option -->
+          </select>
+          <p><input type="submit" value="&raquo;" name="dissociate" style="font-size:15px;"/></p>
+        </td>
+
+        <td>
+          <h3>{lang:Dissociated}</h3>
+          <select class="categoryList" name="cat_dissociated[]" multiple="multiple" size="30">
+            <!-- BEGIN dissociated_option -->
+            <option {dissociated_option.SELECTED} value="{dissociated_option.VALUE}">{dissociated_option.OPTION}</option>
+            <!-- END dissociated_option -->
+          </select>
+          <p><input type="submit" value="&laquo;" name="associate" style="font-size:15px;" /></p>
+        </td>
+      </tr>
+    </table>
+
+  </fieldset>
+</form>
+
+<form id="representation" method="post" action="{F_ACTION}#representation">
+  <fieldset>
+    <legend>{lang:Representation of categories}</legend>
+
+    <table class="doubleSelect">
+      <tr>
+        <td>
+          <h3>{lang:Represents}</h3>
+          <select class="categoryList" name="cat_elected[]" multiple="multiple" size="30">
+            <!-- BEGIN elected_option -->
+            <option {elected_option.SELECTED} value="{elected_option.VALUE}">{elected_option.OPTION}</option>
+            <!-- END elected_option -->
+          </select>
+          <p><input type="submit" value="&raquo;" name="dismiss" style="font-size:15px;"/></p>
+        </td>
+
+        <td>
+          <h3>{lang:Does not represent}</h3>
+          <select class="categoryList" name="cat_dismissed[]" multiple="multiple" size="30">
+            <!-- BEGIN dismissed_option -->
+            <option {dismissed_option.SELECTED} value="{dismissed_option.VALUE}">{dismissed_option.OPTION}</option>
+            <!-- END dismissed_option -->
+          </select>
+          <p><input type="submit" value="&laquo;" name="elect" style="font-size:15px;" /></p>
+        </td>
+      </tr>
+    </table>
+
+  </fieldset>
+</form>
Index: /branches/1.5/template/yoga/admin/remote_site.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/remote_site.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/remote_site.tpl	(revision 3250)
@@ -0,0 +1,83 @@
+<!-- $Id$ -->
+<div class="titrePage">
+  <ul class="categoryActions">
+    <li><a href="{U_HELP}" onclick="popuphelp(this.href); return false;" title="{lang:Help}"><img src="template/yoga/theme/help.png" class="button" alt="(?)"></a></li>
+  </ul>
+  <h2>{lang:remote_sites}</h2>
+</div>
+
+<!-- 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">
+  <p>
+    <label for="galleries_url" >{L_REMOTE_SITE_CREATE}</label> 
+    <input type="text" name="galleries_url" id="galleries_url" value="{F_GALLERIES_URL}" />
+  </p>
+  <p>
+    <input type="submit" name="submit" value="{L_SUBMIT}" />
+  </p>
+</form>
+
+<!-- BEGIN sites -->
+<table>
+  <!-- BEGIN site -->
+  <tr>
+    <td>{sites.site.NAME}</td>
+    <td>[<a href="{sites.site.U_GENERATE}" title="{L_REMOTE_SITE_GENERATE_HINT}">{L_REMOTE_SITE_GENERATE}</a>]</td>
+    <td>[<a href="{sites.site.U_UPDATE}" title="{L_REMOTE_SITE_UPDATE_HINT}">{L_REMOTE_SITE_UPDATE}</a>]</td>
+    <td>[<a href="{sites.site.U_CLEAN}" title="{L_REMOTE_SITE_CLEAN_HINT}">{L_REMOTE_SITE_CLEAN}</a>]</td>
+    <td>[<a href="{sites.site.U_DELETE}" title="{L_REMOTE_SITE_DELETE_HINT}">{L_REMOTE_SITE_DELETE}</a>]</td>
+  </tr>
+  <!-- END site -->
+</table>
+<!-- END sites -->
Index: /branches/1.5/template/yoga/admin/stats.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/stats.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/stats.tpl	(revision 3250)
@@ -0,0 +1,52 @@
+<!-- $Id$ -->
+<h2>{lang:title_history}</h2>
+
+<h3>{L_STAT_TITLE}</h3>
+<img class="image" src="{IMG_REPORT}" alt="{L_STAT_MONTHLY_ALT}" />
+
+<h3>{L_STAT_DETAIL_TITLE}</h3>
+<table class="table2" width="60%">
+<tr class="throw">
+    <th>{L_VALUE}</th>
+    <th>{L_PAGES_SEEN}</th>
+    <th>{L_VISITORS}</th>
+    <th>{L_PICTURES}</th>
+</tr>
+<!-- BEGIN statrow -->
+  <tr class="{statrow.T_CLASS}">
+    <td>{statrow.VALUE}</td>
+    <td>{statrow.PAGES}</td>
+    <td>{statrow.VISITORS}</td>
+    <td>{statrow.IMAGES}</td>
+  </tr>
+<!-- END statrow -->
+</table>
+
+<h3>{L_DATE_TITLE}</h3>
+<table class="table2" width="98%">
+<tr class="throw">
+    <th>{L_STAT_HOUR}</th>
+    <th>{L_STAT_LOGIN}</th>
+    <th>{L_STAT_ADDR}</th>
+    <th>{L_STAT_CATEGORY}</th>
+    <th>{L_STAT_FILE}</th>
+    <th>{L_STAT_PICTURE}</th>
+</tr>
+<!-- BEGIN detail -->
+  <tr class="{detail.T_CLASS}">
+    <td nowrap>{detail.HOUR}</td>
+    <td>{detail.LOGIN}</td>
+    <td>{detail.IP}</td>
+  <td>{detail.CATEGORY}</td>
+  <td>{detail.FILE}</td>
+  <td>{detail.PICTURE}</td>
+  </tr>
+<!-- END detail -->
+</table>
+
+
+<!-- BEGIN navigation -->
+<div class="admin">
+{navigation.NAV_BAR}
+</div>
+<!-- END navigation -->
Index: /branches/1.5/template/yoga/admin/thumbnail.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/thumbnail.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/thumbnail.tpl	(revision 3250)
@@ -0,0 +1,121 @@
+<!-- $Id$ -->
+<div class="titrePage">
+  <ul class="categoryActions">
+    <li><a href="{U_HELP}" onclick="popuphelp(this.href); return false;" title="{lang:Help}"><img src="template/yoga/theme/help.png" class="button" alt="(?)"></a></li>
+  </ul>
+  <h2>{lang:title_thumbnails}</h2>
+</div>
+
+<!-- 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}" class="properties">
+
+  <fieldset>
+    <legend>{L_PARAMS}</legend>
+
+    <ul>
+      <li>
+        <label><strong>{L_GD}</strong></label>
+	<input type="radio" name="gd" value="2" {params.GD2_CHECKED} />2.x
+	<input type="radio" name="gd" value="1" {params.GD1_CHECKED} />1.x
+      </li>
+
+      <li>
+        <label><strong>{L_WIDTH}</strong></label>
+	<input type="text" name="width" value="{params.WIDTH_TN}"/>
+      </li>
+
+      <li>
+        <label><strong>{L_HEIGHT}</strong></label>
+	<input type="text" name="height" value="{params.HEIGHT_TN}"/>
+      </li>
+
+      <li>
+        <label><strong>{lang:Number of thumbnails to create}</strong></label>
+	<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}
+      </li>
+    </ul>
+  </fieldset>
+
+  <p><input type="submit" name="submit" value="{L_SUBMIT}"/></p>
+</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.5/template/yoga/admin/update.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/update.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/update.tpl	(revision 3250)
@@ -0,0 +1,95 @@
+<!-- $Id$ -->
+
+<div class="titrePage">
+  <ul class="categoryActions">
+    <li><a href="{U_HELP}" onclick="popuphelp(this.href); return false;" title="{lang:Help}"><img src="template/yoga/theme/help.png" class="button" alt="(?)"></a></li>
+  </ul>
+  <h2>{lang:title_update}</h2>
+</div>
+
+<!-- BEGIN update -->
+<h3>{L_RESULT_UPDATE}</h3>
+<ul>
+  <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 update_errors -->
+<h3>{L_UPDATE_ERROR_LIST_TITLE}</h3>
+<ul>
+  <!-- BEGIN update_error -->
+  <li>[{update.update_errors.update_error.ELEMENT}] {update.update_errors.update_error.LABEL}</li>
+  <!-- END update_error -->
+</ul>
+<h3>{L_UPDATE_ERRORS_CAPTION}</h3>
+<ul>
+  <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 update_errors -->
+<!-- BEGIN update_infos -->
+<h3>{L_UPDATE_INFOS_TITLE}</h3>
+<ul>
+  <!-- BEGIN update_info -->
+  <li>[{update.update_infos.update_info.ELEMENT}] {update.update_infos.update_info.LABEL}</li>
+  <!-- END update_info -->
+</ul>
+<!-- END update_infos -->
+<!-- END update -->
+
+<!-- BEGIN metadata_result -->
+<h3>{L_RESULT_METADATA}</h3>
+<ul>
+  <li>{metadata_result.NB_ELEMENTS} {L_ELEMENTS_METADATA_SYNC}</li>
+  <li>{L_USED_METADATA} : {METADATA_LIST}</li>
+</ul>
+<!-- END metadata_result -->
+
+<!-- BEGIN introduction -->
+<h3>{L_UPDATE_TITLE}</h3>
+<form action="{F_ACTION}" method="post" id="update">
+
+  <fieldset>
+    <legend>{L_UPDATE_SYNC_FILES}</legend>
+
+    <ul>
+      <li><label><input type="radio" name="sync" value="dirs" {SYNC_DIRS_CHECKED} /> {L_UPDATE_SYNC_DIRS}</label></li>
+      <li><label><input type="radio" name="sync" value="files" {SYNC_ALL_CHECKED} /> {L_UPDATE_SYNC_ALL}</label></li>
+      <li><label><input type="checkbox" name="display_info" value="1" {DISPLAY_INFO_CHECKED} /> {L_UPDATE_DISPLAY_INFO}</label></li>
+      <li><label><input type="checkbox" name="simulate" value="1" checked="checked" /> {L_UPDATE_SIMULATE}</label></li>
+    </ul>
+  </fieldset>
+
+  <fieldset>
+    <legend>{L_UPDATE_SYNC_METADATA}</legend>
+    <p> {L_USED_METADATA} : {METADATA_LIST}.</p>
+    <ul>
+      <li><label><input type="radio" name="sync" value="metadata_new" /> {L_UPDATE_SYNC_METADATA_NEW}</label></li>
+      <li><label><input type="radio" name="sync" value="metadata_all" /> {L_UPDATE_SYNC_METADATA_ALL}</label></li>
+    </ul>
+  </fieldset>
+  
+  <fieldset>
+    <legend>{L_UPDATE_CATS_SUBSET}</legend>
+    <ul>
+    <li> 
+    <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>
+    </li>
+  
+    <li><label><input type="checkbox" name="subcats-included" value="1" {SUBCATS_INCLUDED_CHECKED} /> {L_SEARCH_SUBCATS_INCLUDED}</label></li>
+    </ul>
+  </fieldset>
+
+  <p class="bottomButtons">
+    <input type="submit" value="{L_SUBMIT}" name="submit" />
+    <input type="reset"  value="{L_RESET}"  name="reset"  />
+  </p>
+
+</form>
+<!-- END introduction -->
Index: /branches/1.5/template/yoga/admin/user_list.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/user_list.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/user_list.tpl	(revision 3250)
@@ -0,0 +1,280 @@
+<div class="titrePage">
+  <ul class="categoryActions">
+    <li><a href="{U_HELP}" onclick="popuphelp(this.href); return false;" title="{lang:Help}"><img src="template/yoga/theme/help.png" class="button" alt="(?)"></a></li>
+  </ul>
+  <h2>{lang:title_liste_users}</h2>
+</div>
+
+<form class="filter" method="post" name="add_user" action="{F_ADD_ACTION}">
+  <fieldset>
+    <legend>{lang:Add a user}</legend>
+    <label>{lang:Username} <input type="text" name="login" maxlength="50" size="20" /></label>
+    <label>{L_PASSWORD} <input type="text" name="password" /></label>
+    <input type="submit" name="submit_add" value="{L_SUBMIT}" />
+  </fieldset>
+</form>
+
+<form class="filter" method="get" name="filter" action="{F_FILTER_ACTION}">
+
+  <input type="hidden" name="page" value="user_list" />
+  
+  <!-- BEGIN session -->
+  <input type="hidden" name="id" value="{session.ID}" />
+  <!-- END session -->
+
+<fieldset>
+
+  <legend>{lang:Filter}</legend>
+
+
+  <label>{lang:Username} <input type="text" name="username" value="{F_USERNAME}" /></label>
+
+  <label>
+  {lang:status}
+  <select name="status">
+    <!-- BEGIN status_option -->
+    <option value="{status_option.VALUE}" {status_option.SELECTED} > {status_option.CONTENT}</option>
+    <!-- END status_option -->
+  </select>
+  </label>
+
+  <label>
+  {lang:group}
+  <select name="group">
+    <!-- BEGIN group_option -->
+    <option value="{group_option.VALUE}" {group_option.SELECTED} > {group_option.CONTENT}</option>
+    <!-- END group_option -->
+  </select>
+  </label>
+
+  <label>
+  {lang:Order by}
+  <select name="order_by">
+    <!-- BEGIN order_by -->
+    <option value="{order_by.VALUE}" {order_by.SELECTED} >{order_by.CONTENT}</option>
+    <!-- END order_by -->
+  </select>
+  </label>
+
+  <label>
+  {lang:Sort order}
+  <select name="direction">
+    <!-- BEGIN direction -->
+    <option value="{direction.VALUE}" {direction.SELECTED} >{direction.CONTENT}</option>
+    <!-- END direction -->
+  </select>
+  </label>
+
+  <input type="submit" name="submit_filter" value="{L_SUBMIT}" />
+
+</fieldset>
+
+</form>
+
+<form method="post" name="preferences" action="{F_PREF_ACTION}">
+
+<table class="table2">
+  <tr class="throw">
+    <th>&nbsp;</th>
+    <th>{lang:Username}</th>
+    <th>{L_STATUS}</th>
+    <th>{L_EMAIL}</th>
+    <th>{lang:Groups}</th>
+    <th>{L_ACTIONS}</th>
+  </tr>
+  <!-- BEGIN user -->
+  <tr class="{user.CLASS}">
+    <td><input type="checkbox" name="selection[]" value="{user.ID}" {user.CHECKED} id="selection-{user.ID}" /></td>
+    <td><label for="selection-{user.ID}">{user.USERNAME}</label></td>
+    <td>{user.STATUS}</td>
+    <td>{user.EMAIL}</td>
+    <td>{user.GROUPS}</td>
+    <td style="text-align:center;">
+      <a href="{user.U_PERM}"><img src="./template/yoga/theme/permissions.png" class="button" style="border:none" alt="{L_PERMISSIONS}" title="{L_PERMISSIONS}" /></a>
+    </td>
+  </tr>
+  <!-- END user -->
+</table>
+
+<div class="navigationBar">{NAVBAR}</div>
+
+<!-- delete the selected users ? -->
+<fieldset>
+  <legend>{lang:Deletions}</legend>
+  <label><input type="checkbox" name="confirm_deletion" value="1" /> {lang:confirm}</label>
+  <input type="submit" value="{lang:Delete selected users}" name="delete" />
+</fieldset>
+
+<fieldset>
+  <legend>{lang:Status}</legend>
+
+  <table>
+    <tr>
+      <td>{L_STATUS}</td>
+      <td>
+        <label><input type="radio" name="status_action" value="leave" checked="checked" /> {lang:leave}</label>
+        <label><input type="radio" name="status_action" value="set" id="status_action_set" /> {lang:set to}</label>
+        <select onmousedown="document.getElementById('status_action_set').checked = true;" name="status" size="1">
+          <!-- BEGIN pref_status_option -->
+          <option {pref_status_option.SELECTED} value="{pref_status_option.VALUE}">{pref_status_option.CONTENT}</option>
+          <!-- END pref_status_option -->
+        </select>
+      </td>
+    </tr>
+  </table>
+
+</fieldset>
+
+<!-- form to set properties for many users at once -->
+<fieldset>
+  <legend>{lang:Groups}</legend>
+
+<table>
+
+  <tr>
+    <td>{lang:associate to group}</td>
+    <td>
+      <select name="associate" size="1">
+        <!-- BEGIN associate_option -->
+        <option {associate_option.SELECTED} value="{associate_option.VALUE}">{associate_option.CONTENT}</option>
+        <!-- END associate_option -->
+      </select>
+    </td>
+  </tr>
+
+  <tr>
+    <td>{lang:dissociate from group}</td>
+    <td>
+      <select name="dissociate" size="1">
+        <!-- BEGIN dissociate_option -->
+        <option {dissociate_option.SELECTED} value="{dissociate_option.VALUE}">{dissociate_option.CONTENT}</option>
+        <!-- END dissociate_option -->
+      </select>
+    </td>
+  </tr>
+
+</table>
+
+</fieldset>
+
+<fieldset>
+  <legend>{lang:Preferences}</legend>
+
+<table>
+
+  <tr>
+    <td>{L_NB_IMAGE_LINE}</td>
+    <td>
+      <label><input type="radio" name="nb_image_line_action" value="leave" checked="checked" /> {lang:leave}</label>
+      <label><input type="radio" name="nb_image_line_action" value="set" id="nb_image_line_action_set" /> {lang:set to}</label>
+      <input onmousedown="document.getElementById('nb_image_line_action_set').checked = true;"
+             size="3" maxlength="2" type="text" name="nb_image_line" value="{NB_IMAGE_LINE}" />
+    </td>
+  </tr>
+
+  <tr>
+    <td>{L_NB_LINE_PAGE}</td>
+    <td>
+      <label><input type="radio" name="nb_line_page_action" value="leave" checked="checked" /> {lang:leave}</label>
+      <label><input type="radio" name="nb_line_page_action" value="set" id="nb_line_page_action_set" /> {lang:set to}</label>
+      <input onmousedown="document.getElementById('nb_line_page_action_set').checked = true;"
+             size="3" maxlength="2" type="text" name="nb_line_page" value="{NB_LINE_PAGE}" />
+    <td>
+  </tr>
+
+  <tr>
+    <td>{L_TEMPLATE}</td>
+    <td>
+      <label><input type="radio" name="template_action" value="leave" checked="checked" /> {lang:leave}</label>
+      <label><input type="radio" name="template_action" value="set" id="template_action_set" /> {lang:set to}</label>
+      <select onmousedown="document.getElementById('template_action_set').checked = true;" name="template" size="1">
+        <!-- BEGIN template_option -->
+        <option {template_option.SELECTED} value="{template_option.VALUE}">{template_option.CONTENT}</option>
+        <!-- END template_option -->
+      </select>
+    </td>
+  </tr>
+
+  <tr>
+    <td>{L_LANGUAGE}</td>
+    <td>
+      <label><input type="radio" name="language_action" value="leave" checked="checked" /> {lang:leave}</label>
+      <label><input type="radio" name="language_action" value="set" id="language_action_set" /> {lang:set to}</label>
+      <select onmousedown="document.getElementById('language_action_set').checked = true;" name="language" size="1">
+        <!-- BEGIN language_option -->
+        <option {language_option.SELECTED} value="{language_option.VALUE}">{language_option.CONTENT}</option>
+        <!-- END language_option -->
+      </select>
+    </td>
+  </tr>
+
+  <tr>
+    <td>{L_RECENT_PERIOD}</td>
+    <td>
+      <label><input type="radio" name="recent_period_action" value="leave" checked="checked" /> {lang:leave}</label>
+      <label><input type="radio" name="recent_period_action" value="set" id="recent_period_action_set" /> {lang:set to}</label>
+      <input onmousedown="document.getElementById('recent_period_action_set').checked = true;"
+             type="text" size="3" maxlength="2" name="recent_period" value="{RECENT_PERIOD}" />
+    </td>
+  </tr>
+
+  <tr>
+    <td>{L_EXPAND}</td>
+    <td>
+      <label><input type="radio" name="expand" value="leave" checked="checked" /> {lang:leave}</label>
+      / {lang:set to}
+      <label><input type="radio" name="expand" value="true"  {EXPAND_YES} />{L_YES}</label>
+      <label><input type="radio" name="expand" value="false" {EXPAND_NO}  />{L_NO}</label>
+    </td>
+  </tr>
+
+  <tr>
+    <td>{L_SHOW_NB_COMMENTS}</td>
+    <td>
+      <label><input type="radio" name="show_nb_comments" value="leave" checked="checked" /> {lang:leave}</label>
+      / {lang:set to}
+      <label><input type="radio" name="show_nb_comments" value="true" {SHOW_NB_COMMENTS_YES} />{L_YES}</label>
+      <label><input type="radio" name="show_nb_comments" value="false" {SHOW_NB_COMMENTS_NO} />{L_NO}</label>
+    </td>
+  </tr>
+
+  <tr>
+    <td>{L_MAXWIDTH}</td>
+    <td>
+      <label><input type="radio" name="maxwidth_action" value="leave" checked="checked" /> {lang:leave}</label>
+      <label><input type="radio" name="maxwidth_action" value="unset" /> {lang:unset}</label>
+      <label><input type="radio" name="maxwidth_action" value="set" id="maxwidth_action_set" /> {lang:set to}</label>
+      <input onmousedown="document.getElementById('maxwidth_action_set').checked = true;"
+             type="text" size="4" maxlength="4" name="maxwidth" value="{MAXWIDTH}" />
+    </td>
+  </tr>
+
+
+  <tr>
+    <td>{L_MAXHEIGHT}</td>
+    <td>
+      <label><input type="radio" name="maxheight_action" value="leave" checked="checked" /> {lang:leave}</label>
+      <label><input type="radio" name="maxheight_action" value="unset" /> {lang:unset}</label>
+      <label><input type="radio" name="maxheight_action" value="set" id="maxheight_action_set" /> {lang:set to}</label>
+      <input onmousedown="document.getElementById('maxheight_action_set').checked = true;"
+             type="text" size="4" maxlength="4" name="maxheight" value="{MAXHEIGHT}" />
+    </td>
+  </tr>
+
+
+</table>
+
+</fieldset>
+
+<p>
+  {lang:target}
+  <label><input type="radio" name="target" value="all" /> {lang:all}
+  <label><input type="radio" name="target" value="selection" checked="checked" /> {lang:selection}
+</p>
+
+<p>
+  <input type="submit" value="{L_SUBMIT}" name="pref_submit" />
+  <input type="reset" value="{L_RESET}" name="pref_reset" />
+</p>
+
+</form>
Index: /branches/1.5/template/yoga/admin/user_perm.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/user_perm.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/user_perm.tpl	(revision 3250)
@@ -0,0 +1,21 @@
+<h2>{TITLE}</h2>
+
+<!-- BEGIN groups -->
+<fieldset>
+  <legend>{lang:Categories authorized thanks to group associations}</legend>
+
+  <ul>
+    <!-- BEGIN category -->
+    <li>{groups.category.NAME}</li>
+    <!-- END category -->
+  </ul>
+</fieldset>
+<!-- END groups -->
+
+<fieldset>
+  <legend>{lang:Other private categories}</legend>
+
+  <form method="post" action="{F_ACTION}">
+    {DOUBLE_SELECT}
+  </form>
+</fieldset>
Index: /branches/1.5/template/yoga/admin/waiting.tpl
===================================================================
--- /branches/1.5/template/yoga/admin/waiting.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/admin/waiting.tpl	(revision 3250)
@@ -0,0 +1,47 @@
+<!-- $Id$ -->
+<h2>{lang:title_waiting}</h2>
+
+<form action="{F_ACTION}" method="post" id="waiting">
+
+  <input type="hidden" name="list" value="{LIST}" />
+
+  <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}" title="{picture.FILE_TITLE}">{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}" title="{picture.thumbnail.FILE_TN_TITLE}">{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;">
+        <label><input type="radio" name="action-{picture.ID_IMG}" value="validate" /> {lang:Validate}</label>
+        <label><input type="radio" name="action-{picture.ID_IMG}" value="reject" /> {lang:Reject}</label>
+      </td>
+    </tr>
+    <!-- END picture -->
+  </table>
+
+  <p class="bottomButtons">
+    <input type="submit" name="submit" value="{lang:Submit}" />
+    <input type="submit" name="validate-all" value="{lang:Validate All}" />
+    <input type="submit" name="reject-all" value="{lang:Reject All}" />
+    <input type="reset" value="{lang:Reset}" />
+  </p>
+
+</form>
Index: /branches/1.5/template/yoga/category.tpl
===================================================================
--- /branches/1.5/template/yoga/category.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/category.tpl	(revision 3250)
@@ -0,0 +1,168 @@
+<!-- $Id$ -->
+<div id="menubar">
+<!-- BEGIN links -->
+<dl>
+  <dt>{lang:Links}</dt>
+  <dd>
+    <ul>
+      <!-- BEGIN link -->
+      <li><a href="{links.link.URL}">{links.link.LABEL}</a></li>
+      <!-- END link -->
+    </ul>
+  </dd>
+</dl>
+<!-- END links -->
+<dl>
+  <dt><a href="{U_HOME}">{L_CATEGORIES}</a></dt>
+  <dd>
+    {MENU_CATEGORIES_CONTENT}
+    <p class="totalImages">{NB_PICTURE} {L_TOTAL}</p>
+  </dd>
+</dl>
+<dl>
+  <dt>{L_SPECIAL_CATEGORIES}</dt>
+  <dd>
+    <ul>
+      <!-- BEGIN special_cat -->
+      <li><a href="{special_cat.URL}" title="{special_cat.TITLE}">{special_cat.NAME}</a></li>
+      <!-- END special_cat -->
+    </ul>
+  </dd>
+</dl>
+<dl>
+  <dt>{L_SUMMARY}</dt>
+  <dd>
+    <ul>
+      <!-- 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>
+  </dd>
+</dl>
+<dl>
+  <dt>{L_IDENTIFY}</dt>
+  <dd>
+    <!-- BEGIN hello -->
+    <p>{L_HELLO}&nbsp;{USERNAME}&nbsp;!</p>
+    <!-- END hello -->
+    <ul>
+      <!-- BEGIN register -->
+      <li><a href="{U_REGISTER}">{L_REGISTER}</a></li>
+      <!-- END register -->
+      <!-- BEGIN login -->
+      <li><a href="{F_IDENTIFY}">{lang:Connection}</a></li>
+      <!-- END login -->
+      <!-- BEGIN logout -->
+      <li><a href="{U_LOGOUT}">{L_LOGOUT}</a></li>
+      <!-- END logout -->
+      <!-- BEGIN profile -->
+      <li><a href="{U_PROFILE}" title="{L_PROFILE_HINT}">{L_PROFILE}</a></li>
+      <!-- END profile -->
+      <!-- BEGIN admin -->
+      <li><a href="{U_ADMIN}" title="{L_ADMIN_HINT}">{L_ADMIN}</a></li>
+      <!-- END admin -->
+    </ul>
+    <!-- BEGIN quickconnect -->
+    <form method="post" action="{F_IDENTIFY}" class="filter" id="quickconnect">
+      <fieldset>
+        <legend>{lang:Connection}</legend>
+    
+        <label>
+          {lang:Username}
+          <input type="text" name="username" size="15" value="">
+        </label>
+        
+        <label>
+          {L_PASSWORD}
+          <input type="password" name="password" size="15">
+        </label>
+        
+        <!-- BEGIN remember_me -->
+        <label>
+          {L_REMEMBER_ME}
+          <input type="checkbox" name="remember_me" value="1">
+        </label>
+        <!-- END remember_me -->
+    
+        <p>
+         <input type="submit" name="login" value="{lang:submit}">
+        </p>
+    <ul class="actions">
+      <li><a href="{U_LOST_PASSWORD}" title="{lang:Forgot your password?}"><img src="template/yoga/theme/lost_password.png" class="button" alt="{lang:Forgot your password?}"></a></li>
+      <li><a href="{U_REGISTER}" title="{lang:Create a new account}"><img src="template/yoga/theme/register.png" class="button" alt="{lang:register}"/></a></li>
+    </ul>
+
+      </fieldset>    
+    </form>
+    <!-- END quickconnect -->
+
+  </dd>
+</dl>
+</div> <!-- menubar -->
+
+<div id="content">
+  <div class="titrePage">
+    <ul class="categoryActions">
+      <li>&nbsp;</li>
+      <!-- BEGIN caddie -->
+      <li><a href="{caddie.URL}" title="{lang:add to caddie}"><img src="./template/yoga/theme/caddie_add.png" class="button" alt="{lang:caddie}"/></a></li>
+      <!-- END caddie -->
+      <!-- BEGIN edit -->
+      <li><a href="{edit.URL}" title="{lang:edit category informations}"><img src="./template/yoga/theme/category_edit.png" class="button" alt="{lang:edit}"/></a></li>
+      <!-- END edit -->
+    </ul>
+    <h2>{TITLE}</h2>
+  </div>
+<!-- BEGIN calendar -->
+<div class="navigationBar">{calendar.YEARS_NAV_BAR}</div>
+<div class="navigationBar">{calendar.MONTHS_NAV_BAR}</div>
+<!-- END calendar -->
+
+<!-- BEGIN thumbnails -->
+<ul class="thumbnails">
+  <!-- BEGIN line -->
+  <!-- BEGIN thumbnail -->
+  <li>
+    <span class="wrap1">
+      <span class="wrap2">
+        <a href="{thumbnails.line.thumbnail.U_IMG_LINK}">
+            <img class="thumbnail" src="{thumbnails.line.thumbnail.IMAGE}"
+	    alt="{thumbnails.line.thumbnail.IMAGE_ALT}"
+	    title="{thumbnails.line.thumbnail.IMAGE_TITLE}">
+        </a>
+      </span>
+      <span class="thumbLegend">
+      <!-- BEGIN element_name -->
+      {thumbnails.line.thumbnail.element_name.NAME}
+      <!-- END element_name -->
+      <!-- BEGIN category_name -->
+      [{thumbnails.line.thumbnail.category_name.NAME}]
+      <!-- END category_name -->
+      {thumbnails.line.thumbnail.IMAGE_TS}
+      <!-- BEGIN nb_comments -->
+      <br />{thumbnails.line.thumbnail.nb_comments.NB_COMMENTS} {L_COMMENT}
+      <!-- END nb_comments -->
+      </span>
+    </span>
+  </li>
+  <!-- END thumbnail -->
+  <!-- END line -->
+
+</ul>
+<!-- END thumbnails -->
+
+<!-- BEGIN cat_infos -->
+<!-- BEGIN navigation -->
+<div class="navigationBar">
+{cat_infos.navigation.NAV_BAR}
+</div>
+<!-- END navigation -->
+<!-- BEGIN comment -->
+<div class="additional_info">{cat_infos.comment.COMMENTS}</div>
+<!-- END comment -->
+<!-- END cat_infos -->
+
+</div> <!-- content -->
Index: /branches/1.5/template/yoga/comments.tpl
===================================================================
--- /branches/1.5/template/yoga/comments.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/comments.tpl	(revision 3250)
@@ -0,0 +1,93 @@
+<!-- $Id$ -->
+<div id="content">
+
+  <div class="titrePage">
+    <ul class="categoryActions">
+      <li><a href="{U_HOME}" title="{lang:return to homepage}"><img src="./template/yoga/theme/home.png" class="button" alt="{lang:home}"/></a></li>
+    </ul>
+    <h2>{lang:User comments}</h2>
+  </div>
+
+<form class="filter" action="{F_ACTION}" method="get">
+
+  <fieldset>
+    <legend>{lang:Filter}</legend>
+
+    <label>{lang:Keyword}<input type="text" name="keyword" value="{F_KEYWORD}" /></label>
+
+    <label>{lang:Author}<input type="text" name="author" value="{F_AUTHOR}" /></label>
+
+    <label>
+      {lang:Category}
+      <select name="cat">
+        <!-- BEGIN category -->
+        <option class="{category.CLASS}" {category.SELECTED} value="{category.VALUE}">{category.OPTION}</option>
+        <!-- END category -->
+      </select>
+    </label>
+
+    <label>
+      {lang:Since}
+      <select name="since">
+        <!-- BEGIN since_option -->
+        <option {since_option.SELECTED} value="{since_option.VALUE}">{since_option.CONTENT}</option>
+        <!-- END since_option -->
+      </select>
+    </label>
+
+  </fieldset>
+
+  <fieldset>
+
+    <legend>{lang:Display}</legend>
+
+    <label>
+      {lang:Sort by}
+      <select name="sort_by">
+        <!-- BEGIN sort_by_option -->
+        <option value="{sort_by_option.VALUE}" {sort_by_option.SELECTED} >{sort_by_option.CONTENT}</option>
+        <!-- END sort_by_option -->
+      </select>
+    </label>
+
+    <label>
+      {lang:Sort order}
+      <select name="sort_order">
+        <!-- BEGIN sort_order_option -->
+        <option value="{sort_order_option.VALUE}" {sort_order_option.SELECTED} >{sort_order_option.CONTENT}</option>
+        <!-- END sort_order_option -->
+      </select>
+    </label>
+
+    <label>
+      {lang:Number of items}
+      <select name="items_number">
+        <!-- BEGIN items_number_option -->
+        <option value="{items_number_option.VALUE}" {items_number_option.SELECTED} >{items_number_option.CONTENT}</option>
+        <!-- END items_option -->
+      </select>
+    </label>
+
+  </fieldset>
+
+  <p><input type="submit" name="submit" value="{lang:Filter and display}"></p>
+
+</form>
+
+<div class="navigationBar">{NAVBAR}</div>
+
+<div id="comments">
+
+  <!-- BEGIN comment -->
+  <div class="comment">
+    <a class="illustration" href="{comment.U_PICTURE}"><img src="{comment.TN_SRC}" /></a>
+    <p class="commentHeader"><span class="author">{comment.AUTHOR}</span> - <span class="date">{comment.DATE}</span></p>
+    <blockquote>{comment.CONTENT}</blockquote>
+    <hr class="separation">
+  </div>
+
+  <!-- END comment -->
+
+</div>
+
+</div> <!-- content -->
Index: /branches/1.5/template/yoga/content.css
===================================================================
--- /branches/1.5/template/yoga/content.css	(revision 3250)
+++ /branches/1.5/template/yoga/content.css	(revision 3250)
@@ -0,0 +1,193 @@
+/* $Id$ */
+#content {
+    margin-left: 24em;
+    margin-right: 1em;
+    margin-bottom: 1em; /* when it's longer than menu bar */
+}
+BODY#theAdminPage #content {
+    margin-left: 14em;
+}
+
+BODY#theCommentsPage #content,
+BODY#theRegisterPage #content,
+BODY#theIdentificationPage #content,
+BODY#theProfilePage #content,
+BODY#theSearchPage #content,
+BODY#theAboutPage #content,
+BODY#thePopuphelpPage #content,
+BODY#thePasswordPage #content,
+BODY#theNotificationPage #content
+{
+  margin: 1em;
+}
+
+#content H2 {
+    margin-bottom: 1ex;
+}
+
+#content H3 {
+    margin-bottom: 1ex;
+}
+
+/* Thumbnails customization */
+#content UL.thumbnails SPAN, #content UL.thumbnails SPAN.wrap2 A {
+  width: 140px;			/* max thumbnail width + 2px */
+}
+#content UL.thumbnails SPAN.wrap2 {
+  height: 140px;		/* max thumbnail height + 2px */
+}
+#content UL.thumbnails SPAN.wrap2 {
+  border: 1px solid #aaaaaa;	/* thumbnails border color and style */
+  -moz-border-radius: 4px;	/* round corners with Geko */
+  border-radius: 4px 4px;	/* round corners with CSS3 compliant browsers */
+}
+#content UL.thumbnails SPAN.wrap2:hover {
+  border-color: yellow;		/* thumbnails border color when mouse cursor is over it */
+}
+#content UL.thumbnails SPAN.thumbLegend {
+  font-size: 80%;		/* font size */
+  height: 3em;			/* max legend height (don't set auto to be Geko friendly)*/
+  display: block;		/* display: hide if you don't want legend */
+  overflow: hidden;		/* oversized legend is clipped */
+}
+/* Thumbnail "elastic" layout */
+#content UL.thumbnails {
+  margin: 0;
+  padding: 0;
+  list-style: none;
+  text-align: center;	/* to center the whole collection in #content */
+}
+#content UL.thumbnails LI { display: inline }
+
+#content UL.thumbnails SPAN.wrap1 {
+  margin: 0 5px 5px 5px;
+  display: table-cell; display: inline-table; display: inline-block;
+  vertical-align: top;		/* OK with Opera and IE6 not Geko */
+  text-align: center;		/* to center the thumbnail and legend in Geko/Opera */
+}
+#content UL.thumbnails SPAN.wrap2 {
+  margin: 0;			/* important reset the margins */
+  display: table-cell;		/* block prevents vertical-align here */
+  vertical-align: middle;	/* Ok with Opera and Geko not IE6 */
+}
+#content UL.thumbnails SPAN.wrap2 A {
+  display: block;
+  border-bottom: none;
+}
+#content UL.thumbnails IMG {
+  margin-bottom: -4px;  /* why ??? something wrong with Geko and Opera ignored by IE6*/
+}
+
+/* fix IE with another layout */
+* html #content UL.thumbnails SPAN.wrap2 {
+  display: block;
+  position: relative;
+  text-align: left;
+}
+* html #content UL.thumbnails SPAN.wrap2 A {
+  overflow: visible;
+  position: absolute;
+  top: 50%;
+  text-align: center;
+}
+* html #content UL.thumbnails IMG.thumbnail {
+  position: relative;
+  top: -50%;
+}
+
+#content .navigationBar, #content .additional_info {
+    margin: 10px 0;
+    text-align: center;
+}
+
+#content .pageNumberSelected {
+    font-style: italic;
+}
+
+#content .additional_info {
+    font-size: 110%;
+}
+
+#content FORM {
+    text-align: left;
+}
+
+/* content defaults */
+#content dl, dd { margin: 10px; }
+#content dt {
+  margin-bottom: 5px;
+  font-style: italic;
+  font-size: 110%;
+}
+
+/* actions */
+ul.categoryActions {
+  margin: 0 0 0 0;
+  width: auto;
+  padding: 0;
+  text-indent: 0;
+  list-style: none;
+  text-align: center;
+}
+
+#content div.titrePage ul.categoryActions {
+  float: right;
+  text-align: center;
+}
+
+#content ul.categoryActions li {
+  display: inline;
+}
+
+#content ul.categoryActions a img, ul.categoryActions a {
+  border: none;
+}
+
+/* User comments */
+
+#content DIV#comments {
+  padding-left: 5px;
+  padding-right: 5px;
+  -moz-box-sizing: padding-box;
+}
+#content DIV.comment {
+  margin: 0 0 0.5em 0;
+  padding: 0;
+  overflow: hidden; /* these 2 lines ensure the floating child is kept in the DIV */
+  width: 100%;	    /* don't ask why. It's a very usefull trick                   */
+}
+
+#content DIV.comment A.illustration {
+  display: block;
+  float: left;
+  margin: 0.5em 0 0 0.5em;
+}
+
+#content DIV.comment P.commentHeader {
+  text-align: right;
+  margin: 0.5em 0.5em 0 0;
+}
+
+#content DIV.comment UL.actions {
+  text-align: center;
+  margin: 0.2em;
+}
+
+#content DIV.comment BLOCKQUOTE {
+  margin: 1em 0.5em 0.5em 150px; /* margin-left corresponds to maximum thumbnail width + ~10px */
+  padding: 0.5em;
+}
+
+/* should be in admin.css ? CSS properties also used in popuphelp */
+
+SPAN.pwgScreen {
+  border-bottom: 1px dotted black;
+}
+
+SPAN.filename:before {
+  content: "[";
+}
+
+SPAN.filename:after {
+  content: "]";
+}
Index: /branches/1.5/template/yoga/default-colors.css
===================================================================
--- /branches/1.5/template/yoga/default-colors.css	(revision 3250)
+++ /branches/1.5/template/yoga/default-colors.css	(revision 3250)
@@ -0,0 +1,166 @@
+BODY {
+	color:#696969; /* dimgray */
+    /*color:#111111;*/
+    background: #ffffff;
+}
+
+H1 {
+    color: #696969;
+    background: transparent;
+}
+
+H2 {
+    color: #696969;
+    background: #d3d3d3;
+}
+
+H3 {
+    color: #696969;
+    background: #ffffff;
+}
+
+A {
+    color: #005e89;
+    background: transparent;
+}
+
+A:hover {
+    color: #858460;
+}
+
+
+.pleaseNote {
+    background: #9c9c9c;
+    color: #ffff99;
+    padding: 1ex;
+    font-weight: bold;
+}
+
+#imageHeaderBar {
+    background: #d3d3d3;
+}
+#imageToolBar {
+    background: #eeeeee;
+    border: 1px solid #d3d3d3;
+}
+#imageToolBar * {
+    background: inherit;
+}
+
+#imageToolBar A, #imageToolBar A:hover {
+    border-bottom: none;
+}
+#imageToolBar A:hover {
+    background: #d3d3d3;
+}
+
+#theImage IMG {
+    border: 3px solid #d3d3d3;
+}
+A.navThumb, A.navThumb:hover {
+    border-bottom: none;
+}
+
+
+#content {
+    border: 1px solid #d3d3d3;
+    background:#eeeeee;
+}
+
+#content H3 {
+    text-align: center;
+}
+
+#content UL.thumbnail IMG {
+    border: 1px solid #a0a0a0;
+}
+
+/* So that non-links are slightly greyed out */
+#content .navigationBar {
+    color: #696969;
+}
+#content .pageNumberSelected {
+    color: #000000;
+}
+
+
+#menubar DL {
+    border: 1px solid #d3d3d3;
+    background: #eeeeee;
+}
+
+#menubar DT {
+    color: #696969;
+    background: #d3d3d3;
+}
+
+#menubar DD {
+    background:#eeeeee;
+}
+
+/* User comments */
+#content DIV.comment {
+  border: 1px solid gray;
+}
+
+#content DIV.comment  A.illustration IMG {
+  border: 1px solid gray;
+}
+
+#comments DIV.comment BLOCKQUOTE {
+    border: 1px solid #d3d3d3;
+    border-left: 2px solid #696969;
+    background-color: #eee;
+}
+
+/* Tables & forms */
+.throw {
+	background-color:white;
+}
+input, select, textarea {
+	color:black;
+	background-color: lightgrey;
+        border: 1px solid gray;
+}
+
+.errors { /* Errors display */
+  color: red;
+  background-color: #ffe1e1;
+  font-weight: bold;
+  text-align: left;
+  margin: 5px;
+  border: 1px solid red;
+  background-image: url(admin/images/errors.png);
+  background-repeat: no-repeat;
+  background-position: top right;
+  padding: 10px 50px 10px 10px;
+}
+
+.errors ul li
+{
+  font-weight: normal;
+}
+
+/**
+ * Informations box in administration
+ */
+.infos {
+  text-align: left;
+  background-color: palegreen;
+  background-image: url(admin/images/infos.png);
+  background-repeat: no-repeat;
+  background-position: top right;
+  color: darkgreen;
+  font-weight: bold;
+  margin: 5px;
+  border:1px solid gray;
+  padding: 10px 50px 10px 10px;
+}
+
+LEGEND {
+  font-style: italic;
+}
+
+FIELDSET {
+  border: 1px solid gray;
+}
Index: /branches/1.5/template/yoga/default-layout.css
===================================================================
--- /branches/1.5/template/yoga/default-layout.css	(revision 3250)
+++ /branches/1.5/template/yoga/default-layout.css	(revision 3250)
@@ -0,0 +1,257 @@
+
+@import "menubar.css";
+@import "content.css";
+@import "image.css";
+@import "popuphelp.css";
+
+/* $Id$ */
+
+/* * { padding: 0 !important; margin: 0 !important; } */
+
+BODY {
+    margin: 5px;
+    padding: 0;
+    font-size: 0.8em;
+    font-family: Bitsream Vera Sans, Helvetica, Arial, sans-serif;
+    text-align: center; /* be nice to IE5 */
+}
+
+#the_page {
+    /* Just in case another template needs an inner frame */
+}
+
+H1 {
+    text-align: center;
+    font-size: 150%;
+    font-weight: bold;
+    padding: 0; margin: 1ex 0 2ex 0;
+}
+
+H2 {
+    margin: 0;
+    padding: 5px;
+    text-align: left;
+    font-size: 120%;
+}
+
+A {
+    text-decoration:none;
+    border-bottom: 1px dotted #005e89;
+}
+A:hover {
+    border-bottom: 1px solid #858460;
+}
+
+IMG {
+    border: none;
+}
+
+HR.separation {
+  visibility: hidden;
+  clear: both;
+}
+
+#copyright {
+    clear: both;
+    font-size: 83%;
+    text-align: center;
+    margin: 0 0 10px 0;
+}
+
+/** General defaults **/
+INPUT {margin: 0;}
+ul, dl, li { text-align: left;}
+/* for debugging purpose */
+pre { text-align:left; }
+
+/** forms **/
+
+form { padding: 0em; }
+
+form p {
+	text-align: center;
+	margin-top: 2em;
+	margin-bottom: 2em;
+}
+.small {
+	font-size: 80%;
+}
+
+textarea.description {
+  height: 100px;
+  width: 500px;
+  overflow: auto;
+}
+select.categoryList {
+  width: 100%;
+}
+
+/** go to an admin.css ? **/
+
+.table2 {
+  border: 1px solid black; 
+  margin: 1em auto;
+  padding: 0;
+}
+
+.table2 TD, .table2 TH {
+  padding: 0 1em;
+}
+
+form#add_virtual p { text-align: left; }
+FORM#categoryOrdering, FORM#addVirtual {
+  padding-left: 1em; /* same as FIELDSET margin (there is no fieldset in this form) */
+  padding-right: 1em; /* same as FIELDSET margin (there is no fieldset in this form) */
+}
+FORM#categoryOrdering p {
+	text-align: left;
+	margin-top: 1em;
+	margin-bottom: 1em;
+}
+UL.categoryUl {
+  list-style: none;
+  padding: 0;
+  margin: 0;
+}
+
+LI.categoryLi {
+  border: 1px solid gray;
+  padding: 0px 5px;
+  margin-bottom: 5px;
+}
+
+form#categoryOrdering ul.categoryActions {
+  float: right;
+  margin-top: 5px;
+}
+
+form#cat_modify table { width: auto; }
+
+/**
+ * Filter forms are displayed label by label with the input (or select...)
+ * below the label
+ */
+FIELDSET {
+  padding: 1em;
+  margin: 1em;
+}
+
+FORM.filter FIELDSET LABEL {
+  display: block;
+  float: left;
+  width: auto;
+  margin-right: 10px;
+  padding: 0;
+}
+
+FORM.filter FIELDSET LABEL INPUT,
+FORM.filter FIELDSET LABEL SELECT,
+FORM.filter FIELDSET LABEL TEXTAREA {
+  display: block;
+  margin: 0.5em 0;
+}
+
+FORM.filter FIELDSET P,
+FORM.filter FIELDSET INPUT,
+FORM.filter FIELDSET TEXTAREA {
+  clear: left;
+  display: block;
+}
+
+FORM.filter INPUT[type="submit"] {
+  margin-top: 1em;
+}
+
+FORM.properties UL, FORM#update UL {
+  list-style-type: none;
+  margin: 0;
+  padding: 0;
+}
+
+FORM.properties LI, FORM#update UL  {
+  margin-bottom: 0.5em;
+  padding: 0;
+  line-height: 1.8em;
+}
+
+FORM.properties LABEL {
+  float: left;
+  width: 50%;
+  text-align: right;
+  margin: 0;
+  padding: 0 0.5em 0 0;
+}
+
+FORM.properties LABEL.mandatory {
+  font-weight: bold;
+}
+
+FORM.properties .focus {
+  background-color: whitesmoke;
+}
+
+FORM.properties .nofocus {
+  background-color: lightgrey; /* must be the same as input background-color */
+}
+
+FIELDSET.elementEdit A {
+  display: block;
+  float: right;
+}
+
+TABLE.doubleSelect {
+  text-align: center;
+  margin: 0 auto;
+  width: 100%;
+}
+
+TABLE.doubleSelect TD {
+  padding: 0 5px;
+  width: 50%;
+}
+
+FORM#categoryPermissions LI {
+  display:inline;
+  white-space: nowrap;
+}
+
+#theHeader {
+}
+
+#theHeader H1 {
+  margin-bottom: 0.5em;
+}
+
+#theHeader P {
+  margin-top: 0;
+  padding: 0;
+}
+
+BODY#theAdminPage #theHeader P { 
+  display: none;
+}
+
+BODY#thePopuphelpPage #copyright {
+  color: green;
+  display: none;
+}
+
+FORM#addComment FIELDSET LABEL {
+  clear: both;
+}
+
+FORM#addComment FIELDSET INPUT[type="hidden"] {
+  display: none;
+}
+
+/* button tools */
+UL.actions {
+  text-indent: 0;
+  list-style: none;
+}
+UL.actions  LI {
+  display: inline;
+}
+UL.actions  A {
+  border: none;
+}
Index: /branches/1.5/template/yoga/fix-khtml.css
===================================================================
--- /branches/1.5/template/yoga/fix-khtml.css	(revision 3250)
+++ /branches/1.5/template/yoga/fix-khtml.css	(revision 3250)
@@ -0,0 +1,14 @@
+/* $Id:*/
+/* Issue in Safari/Konqueror only                                                 */
+/* If H2 has a 0 margin-top categoryActions doesn't float right but overwrites H2 */
+#content>DIV.titrePage>H2 {
+    margin: 1px 0 0 0;	/* add an arbitrary margin-top */
+}
+
+#content>div.titrePage {
+    position: relative;
+    top: -1px;		/* move the container up by the same amount */
+    margin-bottom: 5px; 
+}
+/* end Safari/Konqueror */
+
Index: /branches/1.5/template/yoga/footer.tpl
===================================================================
--- /branches/1.5/template/yoga/footer.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/footer.tpl	(revision 3250)
@@ -0,0 +1,24 @@
+<div id="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 us on http://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}
+  <!-- BEGIN contact -->
+  - {L_SEND_MAIL}
+  <a href="mailto:{contact.MAIL}?subject={L_TITLE_MAIL}">{lang:Webmaster}</a>
+  <!-- END contact -->
+
+</div> <!-- copyright -->
+</div> <!-- the_page -->
+
+<!-- BEGIN debug -->
+  {debug.QUERIES_LIST}
+<!-- END debug -->
+</body>
+</html>
Index: /branches/1.5/template/yoga/header.tpl
===================================================================
--- /branches/1.5/template/yoga/header.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/header.tpl	(revision 3250)
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+"http://www.w3.org/TR/html4/strict.dtd">
+<html lang="{LANG}" dir="{DIR}">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset={CONTENT_ENCODING}">
+<!-- BIG FIX ME BELOW (paths) -->
+<link rel="stylesheet" type="text/css" href="template/yoga/default-layout.css">
+<link rel="stylesheet" type="text/css" href="template/yoga/default-colors.css">
+<!-- the next css is used to fix khtml (Konqueror/Safari) issue
+the "text/nonsense" prevents geko based browsers to load it -->
+<link rel="stylesheet" type="text/nonsense" href="template/yoga/fix-khtml.css">
+<link rel="stylesheet" type="text/css" media="print" href="template/yoga/print.css">
+<!-- AN OTHER FIX ME -->
+<style type="text/css">
+.notDoneYet {
+        background: yellow;
+        color: red;
+}
+</style>
+<!-- BEGIN refresh -->
+<meta http-equiv="refresh" content="{REFRESH_TIME};url={U_REFRESH}">
+<!-- END refresh -->
+<title>{GALLERY_TITLE}:{PAGE_TITLE}</title>
+<script type="text/javascript" src="include/scripts.js"></script>
+<!--[if gte IE 5.5000]>
+<script type="text/javascript" src="include/pngfix.js"></script>
+<![endif]-->
+</head>
+
+<body id="{BODY_ID}">
+<div id="the_page">
+
+<div id="theHeader">
+  <h1>{GALLERY_TITLE}</h1>
+  <p>{GALLERY_DESCRIPTION}</p>
+</div>
Index: /branches/1.5/template/yoga/identification.tpl
===================================================================
--- /branches/1.5/template/yoga/identification.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/identification.tpl	(revision 3250)
@@ -0,0 +1,55 @@
+<!-- $Id$ -->
+<div id="content">
+
+  <div class="titrePage">
+    <ul class="categoryActions">
+      <li><a href="{U_LOST_PASSWORD}" title="{lang:Forgot your password?}"><img src="template/yoga/theme/lost_password.png" class="button" alt="{lang:Forgot your password?}"></a></li>
+      <li><a href="{U_REGISTER}" title="{lang:Create a new account}"><img src="./template/yoga/theme/register.png" class="button" alt="{lang:register}"/></a></li>
+      <li><a href="{U_HOME}" title="{lang:Go through the gallery as a visitor}"><img src="./template/yoga/theme/home.png" class="button" alt="{lang:home}"/></a></li>
+    </ul>
+    <h2>{lang:Identification}</h2>
+  </div>
+
+  <!-- BEGIN errors -->
+  <div class="errors">
+    <ul>
+      <!-- BEGIN error -->
+      <li>{errors.error.ERROR}</li>
+      <!-- END error -->
+    </ul>
+  </div>
+  <!-- END errors -->
+
+<form action="{F_LOGIN_ACTION}" method="post" class="properties">
+  <fieldset>
+    <legend>{lang:Connection settings}</legend>
+
+    <ul>
+      <li> 
+        <label for="username">{L_USERNAME}</label>
+        <input class="login" type="text" name="username" id="username" size="25" maxlength="40" value="{USERNAME}">
+      </li>
+  
+      <li>
+        <label for="password">{L_PASSWORD}</label>
+        <input class="login" type="password" name="password" id="password" size="25" maxlength="25">
+      </li>
+  
+      <!-- BEGIN remember_me -->
+      <li>
+        <label>{L_REMEMBER_ME}</label>
+        <input type="checkbox" name="remember_me" value="1">
+      </li>
+      <!-- END remember_me -->
+    </ul>
+  </fieldset>
+
+  <p><input type="submit" name="login" value="{L_LOGIN}"></p>
+</form>
+ 
+  <p>
+    <a href="{U_REGISTER}"><img src="template/yoga/theme/register.png" class="button" alt=""> {L_REGISTER}</a>
+    <a href="{U_LOST_PASSWORD}"><img src="template/yoga/theme/lost_password.png" class="button" alt=""> {lang:Forgot your password?}</a>
+  </p>
+
+</div> <!-- content -->
Index: /branches/1.5/template/yoga/image.css
===================================================================
--- /branches/1.5/template/yoga/image.css	(revision 3250)
+++ /branches/1.5/template/yoga/image.css	(revision 3250)
@@ -0,0 +1,144 @@
+#imageHeaderBar {
+    padding: 2px 10px;
+    margin: 4px 0;
+}
+#imageHeaderBar .browsePath { float: left; }
+#imageHeaderBar .imageNumber { float: right; }
+
+#imageHeaderBar H2 {
+    /*margin: 1ex 0;  override default-layout for less bottom-margin */
+    text-align: center;
+    padding: 0;
+    clear: both;
+}
+
+#imageToolBar {
+    text-align: center;
+    position: relative;
+    clear: both;
+    margin: 4px 0; padding: 0;
+}
+
+/* Moi, je preferais les boutons "imgPrec" et "imgSuiv" au milieu, au-dessus
+de l'image...
+
+#imageToolBar IMG, #imageToolBar A {
+    display: inline;
+    border: none; margin: auto; padding: 0;
+}
+
+#imageToolBar .randomButtons {
+    position: absolute;
+    left: 0;
+}
+#imageToolBar .randomButtons IMG {
+    padding: 0 4px; /* au pire: 3 * (4+24+4) = 96 < 100 * /
+}
+
+#imageToolBar .prevNnext {
+    text-align: center;
+}
+#imageToolBar .prevNnext IMG {
+    padding: 0 100px;
+}
+*/
+
+#imageToolBar {
+    height: 28px;
+}
+#imageToolBar A, #imageToolBar IMG {
+    display: block;
+    border: none;
+    margin: 0; padding: 0;
+}
+#imageToolBar A { width: 48px; }
+#imageToolBar IMG { margin: 2px auto; }
+#imageToolBar .randomButtons A { float: left; }
+#imageToolBar .navButtons    A { float: right; }
+
+#theImage {
+    clear: left;
+}
+
+#theImage>IMG {
+    display: block;
+    margin: 0 auto;
+}
+
+.navThumb {
+    margin-top: 2px;
+}
+#thumbPrev {
+    float: left;
+}
+
+#thumbNext {
+    float: right;
+}
+
+#linkPrev {
+    margin-right: 10px;
+    margin-left: 5px;
+}
+
+#linkNext {
+    margin-right: 5px;
+    margin-left: 10px;
+}
+
+TABLE.infoTable {
+    margin: auto;
+}
+TABLE.infoTable .value {
+    text-align: left;
+}
+
+TABLE.infoTable .label {
+    font-weight: bold;
+    text-align: right;
+    padding-right: 0.5em; 
+}
+
+TABLE.infoTable TD.value UL {
+  margin: 0;
+  padding: 0 0 0 1.5em;
+  list-style-type: square;
+}
+
+#comments {
+    text-align: left;
+}
+
+#comments .comment {
+    margin: 3ex 0;
+}
+
+#comments H2 {
+    margin: 1ex 0;
+}
+
+#comments P {
+    margin: 0;
+}
+
+#comments .author {
+    font-weight: bold;
+}
+
+#comments BLOCKQUOTE {
+    margin: 1ex 0 1ex 2em;
+    padding: 4px 4px 0 /* IE bug */ 4px;
+}
+
+#comments BLOCKQUOTE P {
+    margin: 0;
+    padding-bottom: 4px; /* IE bug follow-up */
+}
+#comments BLOCKQUOTE P+P {
+    margin-top: 1ex;
+}
+
+#comments P.userCommentDelete {
+    float: right;
+    margin: 0;
+}
Index: /branches/1.5/template/yoga/install.tpl
===================================================================
--- /branches/1.5/template/yoga/install.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/install.tpl	(revision 3250)
@@ -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.5/template/yoga/menubar.css
===================================================================
--- /branches/1.5/template/yoga/menubar.css	(revision 3250)
+++ /branches/1.5/template/yoga/menubar.css	(revision 3250)
@@ -0,0 +1,108 @@
+#menubar {
+    /* Do not put font-size: 90% here for it makes it harder to have correct
+       margin for contentarea */
+    float: left;
+    left: 0px;
+
+    width: 22em;
+    margin: 0 0 10px 1em;
+    padding: 0;
+    /* Fix against the "double margin of a floated item" IE bug */
+    /* Damned: that screws up top_navbar in opera 7.54/Linux! */
+    display: inline;
+    text-align: left; /* follow-up of the "be nice to IE5" rule */
+}
+
+BODY#theAdminPage #menubar {
+    width: 12em;
+}
+
+#menubar DL, #menubar DT, #menubar DD {
+    margin: 0; padding: 0; display: block;
+}
+
+/* H2 properties copied here */
+#menubar DT {
+    font-weight: bold; /* default for h2 */
+
+    margin: 0;
+    padding: 5px 10px;
+    font-size: 120%;
+
+    text-align: center;
+}
+
+#menubar UL,
+#menubar HR,
+#menubar FORM,
+#menubar P, /* ooh, careful... */
+#menubar .totalImages {
+    font-size: 92%;
+    margin: 10px 0 10px 10px;
+}
+#menubar UL {
+    list-style-type: square;
+    list-style-position: inside;
+    padding: 0 0 0 2px;
+}
+#menubar UL UL {
+    font-size: 100%;
+    margin-top: 0;
+}
+
+#menubar LI.selected A {
+  font-weight: bold;
+}
+
+#menubar LI.selected LI A {
+  font-weight: normal;
+}
+
+#menubar HR {
+    display: block;
+    margin: 10px auto;
+    width: 90%;
+}
+#menubar FORM P {
+    margin: 5px;
+    font-size: 100%;
+}
+#menubar INPUT {
+    text-indent: 2px;
+}
+
+/* quickconnect form */
+FORM#quickconnect { 
+  margin: 0;
+  padding: 5px;
+}
+
+FORM#quickconnect FIELDSET {
+  margin: 0;
+  padding: 0 0 0.5em 0;
+  overflow: hidden;	/* Correct float issue with Opera 7.5 */
+  width: 100%;		/*        //			      */
+}
+
+FORM#quickconnect P {
+  float: left;
+}
+
+FORM#quickconnect P INPUT {
+  margin: 0;
+}
+
+FORM#quickconnect UL.actions {
+  display: inline;
+  float: right;
+  padding: 0;
+  text-align: right;	/* Opera 7.5 */
+  width: 40%;		/* Opera 7.5 cannot find why width:auto fails :-( */
+}
+
+FORM#quickconnect UL.actions,
+FORM#quickconnect P, 
+FORM#quickconnect LABEL {
+  margin: 0 0.5em 0 0.5em;
+}
+
Index: /branches/1.5/template/yoga/notification.tpl
===================================================================
--- /branches/1.5/template/yoga/notification.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/notification.tpl	(revision 3250)
@@ -0,0 +1,13 @@
+<div id="content">
+
+  <div class="titrePage">
+    <ul class="categoryActions">
+      <li><a href="{U_HOME}" title="{lang:return to homepage}"><img src="./template/yoga/theme/home.png" class="button" alt="{lang:home}"/></a></li>
+    </ul>
+    <h2>{lang:Notification}</h2>
+  </div>
+
+  <p>{lang:The RSS notification feed provides notification on news from this website : new pictures, updated categories, new comments. Use a RSS feed reader.}</p>
+
+  <p><a href="{FEED_URL}">{lang:RSS feed}</a></p>
+</div>
Index: /branches/1.5/template/yoga/password.tpl
===================================================================
--- /branches/1.5/template/yoga/password.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/password.tpl	(revision 3250)
@@ -0,0 +1,51 @@
+<!-- $Id$ -->
+<div id="content">
+
+  <div class="titrePage">
+    <ul class="categoryActions">
+      <li><a href="{U_HOME}" title="{lang:Go through the gallery as a visitor}"><img src="./template/yoga/theme/home.png" class="button" alt="{lang:home}"/></a></li>
+    </ul>
+    <h2>{lang:Password forgotten}</h2>
+  </div>
+
+  <!-- BEGIN errors -->
+  <div class="errors">
+    <ul>
+      <!-- BEGIN error -->
+      <li>{errors.error.ERROR}</li>
+      <!-- END error -->
+    </ul>
+  </div>
+  <!-- END errors -->
+
+  <!-- BEGIN infos -->
+  <div class="infos">
+    <ul>
+      <!-- BEGIN info -->
+      <li>{infos.info.INFO}</li>
+      <!-- END info -->
+    </ul>
+  </div>
+  <!-- END infos -->
+
+<form action="{F_ACTION}" method="post" class="properties">
+  <fieldset>
+    <legend>{lang:Retrieve password}</legend>
+
+    <ul>
+      <li> 
+        <label for="mail_address">{lang:Email address}</label>
+        <input class="login" type="text" name="mail_address" id="mail_address" size="40" maxlength="40">
+      </li>
+
+      <li>
+        <label>{lang:No email address}</label>
+        <input type="checkbox" name="no_mail_address" value="1">
+      </li>
+    </ul>
+  </fieldset>
+
+  <p><input type="submit" name="submit" value="{lang:Send new password}"></p>
+</form>
+
+</div> <!-- content -->
Index: /branches/1.5/template/yoga/picture.tpl
===================================================================
--- /branches/1.5/template/yoga/picture.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/picture.tpl	(revision 3250)
@@ -0,0 +1,197 @@
+<!-- BEGIN information -->
+<div class="pleaseNote">{information.INFORMATION}</div>
+<!-- END information -->
+
+<div id="imageHeaderBar">
+  <div class="browsePath"><a href="{U_HOME}">{L_HOME}</a>{LEVEL_SEPARATOR}{CATEGORY}</div>
+  <div class="imageNumber">{PHOTO}</div>
+  <!-- BEGIN title -->
+  <h2>{TITLE}</h2>
+  <!-- END title -->
+  <hr class="separation">
+</div>
+
+<div id="imageToolBar">
+
+<div class="randomButtons">
+  <a href="{U_SLIDESHOW}" title="{L_SLIDESHOW}"><img src="template/yoga/theme/slideshow.png" class="button" alt="{L_SLIDESHOW}"></a>
+  <a href="{U_METADATA}" title="{L_PICTURE_METADATA}"><img src="template/yoga/theme/metadata.png" class="button" alt="{L_PICTURE_METADATA}"></a>
+<!-- BEGIN representative -->
+  <a href="{representative.URL}" title="{lang:set as category representative}"><img src="template/yoga/theme/representative.png" class="button" alt="{lang:representative}" /></a>
+<!-- END representative -->
+<!-- BEGIN favorite -->
+  <a href="{favorite.U_FAVORITE}" title="{favorite.FAVORITE_HINT}"><img src="{favorite.FAVORITE_IMG}" class="button" alt="{favorite.FAVORITE_ALT}"></a>
+<!-- END favorite -->
+<!-- BEGIN download -->
+  <a href="{download.U_DOWNLOAD}" title="{L_DOWNLOAD}"><img src="template/yoga/theme/save.png" class="button" alt="{L_DOWNLOAD}"></a>
+<!-- END download -->
+<!-- BEGIN admin -->
+  <a href="{U_ADMIN}" title="{L_ADMIN}"><img src="template/yoga/theme/preferences.png" class="button" alt="{L_ADMIN}"></a>
+<!-- END admin -->
+<!-- BEGIN caddie -->
+  <a href="{caddie.URL}" title="{lang:add to caddie}"><img src="./template/yoga/theme/caddie_add.png" class="button" alt="{lang:caddie}"/></a>
+<!-- END caddie -->
+</div>
+
+<div class="navButtons">
+<!-- BEGIN next -->
+  <a class="navButton next" href="{next.U_IMG}" title="{L_NEXT_IMG}{next.TITLE_IMG}"><img src="template/yoga/theme/right.png" class="button" alt="next"></a>
+<!-- END next -->
+  <a class="navButton up" href="{U_UP}" title="{L_UP_HINT}"><img src="template/yoga/theme/up.png" class="button" alt="{L_UP_ALT}"></a>
+<!-- BEGIN previous -->
+  <a class="navButton prev" href="{previous.U_IMG}" title="{L_PREV_IMG}{previous.TITLE_IMG}"><img src="template/yoga/theme/left.png" class="button" alt="previous"></a>
+<!-- END previous -->
+</div>
+
+</div> <!-- imageToolBar -->
+
+<div id="theImage">
+<!-- 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 src="{SRC_IMG}" style="width:{WIDTH_IMG}px;height:{HEIGHT_IMG}px;" alt="{ALT_IMG}">
+<!-- BEGIN high -->
+</a>
+  <p>{L_PICTURE_HIGH}</p>
+<!-- END high -->
+<!-- BEGIN legend -->
+<p>{legend.COMMENT_IMG}</p>
+<!-- END legend -->
+<!-- BEGIN stop_slideshow -->
+<p>
+  [ <a href="{stop_slideshow.U_SLIDESHOW}">{L_STOP_SLIDESHOW}</a> ]
+</p>
+<!-- END stop_slideshow -->
+</div>
+
+<!-- BEGIN previous -->
+<a class="navThumb" id="thumbPrev" href="{previous.U_IMG}" title="{L_PREV_IMG}{previous.TITLE_IMG}">
+  <img src="{previous.IMG}" class="thumbLink" id="linkPrev" alt="{previous.TITLE_IMG}">
+</a>
+<!-- END previous -->
+<!-- BEGIN next -->
+<a class="navThumb" id="thumbNext" href="{next.U_IMG}" title="{L_NEXT_IMG}{next.TITLE_IMG}">
+  <img src="{next.IMG}" class="thumbLink" id="linkNext" alt="{next.TITLE_IMG}">
+</a>
+<!-- END next -->
+
+<table class="infoTable" summary="Some info about this picture">
+  <tr>
+    <td class="label">{lang:Author}</td>
+    <td class="value">{INFO_AUTHOR}</td>
+  </tr>
+  <tr>
+    <td class="label">{lang:Created on}</td>
+    <td class="value">{INFO_CREATION_DATE}</td>
+  </tr>
+  <tr>
+    <td class="label">{lang:Registered on}</td>
+    <td class="value">{INFO_AVAILABILITY_DATE}</td>
+  </tr>
+  <tr>
+    <td class="label">{lang:Dimensions}</td>
+    <td class="value">{INFO_DIMENSIONS}</td>
+  </tr>
+  <tr>
+    <td class="label">{lang:File}</td>
+    <td class="value">{INFO_FILE}</td>
+  </tr>
+  <tr>
+    <td class="label">{lang:Filesize}</td>
+    <td class="value">{INFO_FILESIZE}</td>
+  </tr>
+  <tr>
+    <td class="label">{lang:Keywords}</td>
+    <td class="value">{INFO_KEYWORDS}</td>
+  </tr>
+  <tr>
+    <td class="label">{lang:Categories}</td>
+    <td class="value">
+      <ul>
+        <!-- BEGIN category -->
+        <li>{category.LINE}</li>
+        <!-- END category -->
+      </ul>
+    </td>
+  </tr>
+  <tr>
+    <td class="label">{lang:Visits}</td>
+    <td class="value">{INFO_VISITS}</td>
+  </tr>
+  <!-- BEGIN info_rate -->
+  <tr>
+    <td class="label">{lang:Average rate}</td>
+    <td class="value">{info_rate.CONTENT}</td>
+  </tr>
+  <!-- END info_rate -->
+</table>
+
+<!-- BEGIN metadata -->
+<table class="infoTable" summary="Some more (technical) info about this picture">
+  <!-- BEGIN headline -->
+  <tr>
+    <th colspan="2">{metadata.headline.TITLE}</th>
+  </tr>
+  <!-- END headline -->
+  <!-- BEGIN line -->
+  <tr>
+    <td class="label">{metadata.line.KEY}</td>
+    <td class="value">{metadata.line.VALUE}</td>
+  </tr>
+  <!-- END line -->
+</table>
+<!-- END metadata -->
+
+<!-- BEGIN rate -->
+<p>
+{rate.SENTENCE} :
+<!-- BEGIN rate_option -->
+{rate.rate_option.SEPARATOR} <a href="{rate.rate_option.URL}">{rate.rate_option.OPTION}</a>
+<!-- END rate_option -->
+</p>
+<!-- END rate -->
+
+<hr class="separation">
+
+<!-- BEGIN comments -->
+<div id="comments">
+<h2>[{comments.NB_COMMENT}] {L_COMMENT_TITLE}</h2>
+
+<div class="navigationBar">{comments.NAV_BAR}</div>
+
+<!-- BEGIN comment -->
+<div class="comment">
+  <!-- BEGIN delete -->
+  <p class="userCommentDelete">
+  <a href="{comments.comment.delete.U_COMMENT_DELETE}" title="{L_DELETE_COMMENT}">
+    <img src="template/yoga/theme/delete.png" class="button" style="border:none;vertical-align:middle; margin-left:5px;" alt="[{L_DELETE}]"/>
+  </a>
+  </p>
+  <!-- END delete -->
+  <p class="commentInfo"><span class="author">{comments.comment.COMMENT_AUTHOR}</span> - {comments.comment.COMMENT_DATE}</p>
+  <blockquote>{comments.comment.COMMENT}</blockquote>
+</div>
+<!-- END comment -->
+
+<!-- BEGIN add_comment -->
+<form  method="post" action="{U_ADD_COMMENT}" class="filter" id="addComment">
+  <fieldset>
+    <legend>{L_ADD_COMMENT}</legend>
+
+    <!-- BEGIN author_field -->
+    <label>{L_AUTHOR}<input type="text" name="author"></label>
+    <!-- END author_field -->
+
+    <!-- BEGIN author_known -->
+    <input type="hidden" name="author"  value="{comments.add_comment.author_known.KNOWN_AUTHOR}">
+    <!-- END author_known -->
+
+    <label>{L_COMMENT}<textarea name="content" rows="10" cols="80"></textarea></label>
+
+    <input type="submit" value="{L_SUBMIT}">
+  </fieldset>
+</form>
+<!-- END add_comment -->
+<!-- END comments -->
+
+</div>
Index: /branches/1.5/template/yoga/popuphelp.css
===================================================================
--- /branches/1.5/template/yoga/popuphelp.css	(revision 3250)
+++ /branches/1.5/template/yoga/popuphelp.css	(revision 3250)
@@ -0,0 +1,22 @@
+BODY#thePopuphelpPage #copyright {
+  display: none;
+}
+
+BODY#thePopuphelpPage #theHeader P {
+  display: none;
+}
+
+BODY#thePopuphelpPage #content P {
+  text-align: justify;
+  padding: 0.5em;
+}
+
+BODY#thePopuphelpPage #content OL LI,
+BODY#thePopuphelpPage #content UL LI
+{
+  margin-bottom: 0.5em;
+}
+
+BODY#thePopuphelpPage P#pageBottomActions A {
+  border: none;
+}
Index: /branches/1.5/template/yoga/popuphelp.tpl
===================================================================
--- /branches/1.5/template/yoga/popuphelp.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/popuphelp.tpl	(revision 3250)
@@ -0,0 +1,5 @@
+<div id="content">
+{HELP_CONTENT}
+</div> <!-- content -->
+
+<p id="pageBottomActions"><a href="#" onclick="window.close();" title="{lang:Close this window}"><img src="template/yoga/theme/exit.png" class="button" alt="close"></a></p>
Index: /branches/1.5/template/yoga/print.css
===================================================================
--- /branches/1.5/template/yoga/print.css	(revision 3250)
+++ /branches/1.5/template/yoga/print.css	(revision 3250)
@@ -0,0 +1,13 @@
+#menubar, #categoryContent .navigationBar, #imageToolBar, .navThumb, TABLE.infoTable, #add_a_comment {
+    display: none;
+}
+
+BODY {
+    margin: 0;
+    color: #000000;
+    background: #ffffff;
+}
+
+#categoryContent {
+    margin: 0;
+}
Index: /branches/1.5/template/yoga/profile.tpl
===================================================================
--- /branches/1.5/template/yoga/profile.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/profile.tpl	(revision 3250)
@@ -0,0 +1,128 @@
+<div id="content">
+
+<!-- BEGIN errors -->
+<div class="errors">
+  <ul>
+    <!-- BEGIN error -->
+    <li>{errors.error.ERROR}</li>
+    <!-- END error -->
+  </ul>
+</div>
+<!-- END errors -->
+
+  <div class="titrePage">
+    <ul class="categoryActions">
+      <li><a href="{U_RETURN}" title="{lang:return to homepage}"><img src="./template/yoga/theme/home.png" class="button" alt="{lang:home}"/></a></li>
+    </ul>
+    <h2>{lang:Profile}</h2>
+  </div>
+
+<form method="post" name="profile" action="{F_ACTION}" id="profile" class="properties">
+
+  <input type="hidden" name="userid" value="{USERID}" />
+
+  <fieldset>
+    <legend>{L_REGISTRATION_INFO}</legend>
+
+    <ul>
+      <li>
+        <label>{lang:Username}</label>
+        <strong>{USERNAME}</strong>
+      </li>
+
+      <li>
+        <label for="mail_address">{lang:Email address}</label>
+        <input type="text" name="mail_address" id="mail_address" value="{EMAIL}" onfocus="this.className='focus';" onblur="this.className='nofocus';">
+      </li>
+
+      <li>
+        <label for="password">{L_CURRENT_PASSWORD}</label>
+        <input type="password" name="password" id="password" value="" onfocus="this.className='focus';" onblur="this.className='nofocus';">
+      </li>
+
+      <li>
+        <label for="use_new_pwd">{L_NEW_PASSWORD}</label>
+        <input type="password" name="use_new_pwd" id="use_new_pwd" value="" onfocus="this.className='focus';" onblur="this.className='nofocus';">
+      </li>
+
+      <li>
+        <label for="passwordConf">{L_CONFIRM_PASSWORD}</label>
+        <input type="password" name="passwordConf" id="passwordConf" value="" onfocus="this.className='focus';" onblur="this.className='nofocus';">
+      </li>
+    </ul>
+  </fieldset>
+
+  <fieldset>
+    <legend>{L_PREFERENCES}</legend>
+
+    <ul>
+      <li>
+        <label for="nb_image_line">{L_NB_IMAGE_LINE}</label>
+        <input type="text" size="3" maxlength="2" name="nb_image_line" id="nb_image_line" value="{NB_IMAGE_LINE}"
+               onfocus="this.className='focus';" onblur="this.className='nofocus';">
+      </li>
+
+      <li>
+        <label for="nb_line_page">{L_NB_ROW_PAGE}</label>
+        <input type="text" size="3" maxlength="2" name="nb_line_page" id="nb_line_page" value="{NB_ROW_PAGE}"
+               onfocus="this.className='focus';" onblur="this.className='nofocus';">
+      </li>
+
+      <li>
+        <label for="template">{L_STYLE_SELECT}</label>
+        <select name="template" id="template"> <!-- FIXME: if onfocus is used, the behaviour becomes weird in Firefox -->
+          <!-- BEGIN template_option -->
+          <option value="{template_option.VALUE}" {template_option.SELECTED}>{template_option.CONTENT}</option>
+          <!-- END template_option -->
+        </select>
+      </li>
+
+      <li>
+        <label for="language">{L_LANG_SELECT}</label>
+        <select name="language" id="language"> <!-- same FIXME -->
+          <!-- BEGIN language_option -->
+          <option value="{language_option.VALUE}" {language_option.SELECTED}>{language_option.CONTENT}</option>
+          <!-- END language_option -->
+        </select>
+      </li>
+
+      <li>
+        <label for="recent_period">{L_RECENT_PERIOD}</label>
+        <input type="text" size="3" maxlength="2" name="recent_period" id="recent_period" value="{RECENT_PERIOD}"
+               onfocus="this.className='focus';" onblur="this.className='nofocus';">
+      </li>
+
+      <li>
+        <label>{L_EXPAND_TREE}</label>
+        <input type="radio" class="radio" name="expand" value="true" {EXPAND_TREE_YES}> {L_YES}
+        <input type="radio" class="radio" name="expand" value="false" {EXPAND_TREE_NO}> {L_NO}
+      </li>
+
+      <li>
+        <label>{L_NB_COMMENTS}</label>
+        <input type="radio" class="radio" name="show_nb_comments" value="true" {NB_COMMENTS_YES}> {L_YES}
+        <input type="radio" class="radio" name="show_nb_comments" value="false" {NB_COMMENTS_NO}> {L_NO}
+      </li>
+ 
+      <li>
+        <label for"maxwidth">{L_MAXWIDTH}</label>
+        <input type="text" size="4" maxlength="4" name="maxwidth" id="maxwidth" value="{MAXWIDTH}"
+               onfocus="this.className='focus';" onblur="this.className='nofocus';">
+      </li>
+
+      <li>
+        <label for="maxheight">{L_MAXHEIGHT}</label>
+        <input type="text" size="4" maxlength="4" name="maxheight" id="maxheight" value="{MAXHEIGHT}"
+               onfocus="this.className='focus';" onblur="this.className='nofocus';">
+      </li>
+    </ul>
+  </fieldset>
+
+  <p class="bottomButtons">
+    <input type="submit" name="validate" value="{L_SUBMIT}">
+    <input type="reset" name="reset" value="{L_RESET}">
+  </p>
+
+</form>
+
+</div> <!-- content -->
Index: /branches/1.5/template/yoga/redirect.tpl
===================================================================
--- /branches/1.5/template/yoga/redirect.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/redirect.tpl	(revision 3250)
@@ -0,0 +1,1 @@
+redirection
Index: /branches/1.5/template/yoga/register.tpl
===================================================================
--- /branches/1.5/template/yoga/register.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/register.tpl	(revision 3250)
@@ -0,0 +1,59 @@
+<div id="registerPage">
+
+<div id="content">
+
+  <div class="titrePage">
+    <ul class="categoryActions">
+      <li><a href="{U_HOME}" title="{lang:return to homepage}"><img src="./template/yoga/theme/home.png" class="button" alt="{lang:home}"/></a></li>
+    </ul>
+    <h2>{lang:Registration}</h2>
+  </div>
+
+  <!-- BEGIN errors -->
+  <div class="errors">
+    <ul>
+      <!-- BEGIN error -->
+      <li>{errors.error.ERROR}</li>
+      <!-- END error -->
+    </ul>
+  </div>
+  <!-- END errors -->
+
+<form method="post" action="{F_ACTION}" class="properties">
+  <fieldset>
+    <legend>{lang:Enter your personnal informations}</legend>
+
+    <ul>
+      <li>
+        <label for="login" class="mandatory">* {lang:Username}</label>
+        <input type="text" name="login" id="login" value="{F_LOGIN}" onfocus="this.className='focus';" onblur="this.className='nofocus';">
+      </li>
+
+      <li>
+        <label for="password" class="mandatory">* {lang:Password}</label>
+        <input type="password" name="password" id="password" onfocus="this.className='focus';" onblur="this.className='nofocus';">
+      </li>
+
+      <li>
+        <label for="password_conf" class="mandatory">* {lang:Confirm Password}</label>
+        <input type="password" name="password_conf" id="password_conf" onfocus="this.className='focus';" onblur="this.className='nofocus';">
+      </li>
+
+      <li>
+        <label for="mail_address">{lang:Mail address}</label>
+        <input type="text" name="mail_address" id="mail_address" value="{F_EMAIL}" onfocus="this.className='focus';" onblur="this.className='nofocus';">
+        ({lang:useful when password forgotten})
+      </li>
+    </ul>
+
+  </fieldset>
+
+  <p class="bottomButtons">
+    <input type="submit" name="submit" value="{lang:Register}">
+    <input type="reset" value="{lang:Reset}">
+  </p>
+
+</form>
+
+</div> <!-- content -->
+</div> <!-- registerPage -->
Index: /branches/1.5/template/yoga/search.tpl
===================================================================
--- /branches/1.5/template/yoga/search.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/search.tpl	(revision 3250)
@@ -0,0 +1,139 @@
+<div id="content">
+
+  <div class="titrePage">
+    <ul class="categoryActions">
+      <li><a href="{U_HELP}" onclick="popuphelp(this.href); return false;" title="{lang:Help}"><img src="template/yoga/theme/help.png" class="button" alt="(?)"></a></li>
+      <li><a href="{U_HOME}" title="{lang:return to homepage}"><img src="./template/yoga/theme/home.png" class="button" alt="{lang:home}"/></a></li>
+    </ul>
+    <h2>{lang:Search}</h2>
+  </div>
+
+<!-- TO DO -->
+<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> 
+    <td width="50%" colspan="2"><b>{L_SEARCH_KEYWORDS} : </b>
+    <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>
+    <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>
+    <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>
+    <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>
+
+</div> <!-- content -->
Index: /branches/1.5/template/yoga/upgrade.tpl
===================================================================
--- /branches/1.5/template/yoga/upgrade.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/upgrade.tpl	(revision 3250)
@@ -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.5/template/yoga/upload.tpl
===================================================================
--- /branches/1.5/template/yoga/upload.tpl	(revision 3250)
+++ /branches/1.5/template/yoga/upload.tpl	(revision 3250)
@@ -0,0 +1,93 @@
+<h2>{L_TITLE}</h2>
+<!-- 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.5/tools/config_local.inc.php
===================================================================
--- /branches/1.5/tools/config_local.inc.php	(revision 3250)
+++ /branches/1.5/tools/config_local.inc.php	(revision 3250)
@@ -0,0 +1,8 @@
+<?php
+// this file is provided as an example. It does not modify the configuration
+// as long as it remains in "tools" directory. Move it to "include"
+// directory if you want to modify default configuration.
+
+$conf['prefix_thumbnail'] = 'thumb_';
+$conf['show_gt'] = true;
+?>
Index: /branches/1.5/tools/create_listing_file.php
===================================================================
--- /branches/1.5/tools/create_listing_file.php	(revision 3250)
+++ /branches/1.5/tools/create_listing_file.php	(revision 3250)
@@ -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'] = '%PWGVERSION%';
+
+// $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.5/tools/metadata.php
===================================================================
--- /branches/1.5/tools/metadata.php	(revision 3250)
+++ /branches/1.5/tools/metadata.php	(revision 3250)
@@ -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.5/upgrade.php
===================================================================
--- /branches/1.5/upgrade.php	(revision 3250)
+++ /branches/1.5/upgrade.php	(revision 3250)
@@ -0,0 +1,213 @@
+<?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/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_IN_UPGRADE') or !PHPWG_IN_UPGRADE)
+{
+  $message = 'PhpWebGallery is not in upgrade mode. In include/mysql.inc.php,
+insert line
+<pre style="background-color:lightgray">
+define(\'PHPWG_IN_UPGRADE\', true);
+</pre>
+if you want to upgrade';
+  die($message);
+}
+
+// concerning upgrade, we use the default users table
+$conf['users_table'] = $prefixeTable.'users';
+
+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 = new Template(PHPWG_ROOT_PATH.'template/yoga');
+$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'
+      );
+
+    array_push(
+      $infos,
+      'in include/mysql.inc.php, remove
+<pre style="background-color:lightgray">
+define(\'PHPWG_IN_UPGRADE\', true);
+</pre>'
+      );
+    
+    $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.5/upload.php
===================================================================
--- /branches/1.5/upload.php	(revision 3250)
+++ /branches/1.5/upload.php	(revision 3250)
@@ -0,0 +1,374 @@
+<?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();
+  }
+}
+
+//------------------------------------------------------------ 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');
+?>
