[vhffs-dev] [1918] prepared panel for FastCGI, moved all panel code to API, updated core API to allow noconnect to backend at start, fixed CGI contexts, perlified almost all files

[ Thread Index | Date Index | More vhffs.org/vhffs-dev Archives ]


Revision: 1918
Author:   gradator
Date:     2012-01-20 00:57:57 +0100 (Fri, 20 Jan 2012)
Log Message:
-----------
prepared panel for FastCGI, moved all panel code to API, updated core API to allow noconnect to backend at start, fixed CGI contexts, perlified almost all files

Modified Paths:
--------------
    trunk/TODO
    trunk/vhffs-api/src/Vhffs/Functions.pm
    trunk/vhffs-api/src/Vhffs/Group.pm
    trunk/vhffs-api/src/Vhffs/Main.pm
    trunk/vhffs-api/src/Vhffs/Makefile.am
    trunk/vhffs-api/src/Vhffs/Object.pm
    trunk/vhffs-api/src/Vhffs/Panel/Admin.pm
    trunk/vhffs-api/src/Vhffs/Panel/Avatar.pm
    trunk/vhffs-api/src/Vhffs/Panel/Bazaar.pm
    trunk/vhffs-api/src/Vhffs/Panel/Commons.pm
    trunk/vhffs-api/src/Vhffs/Panel/Cron.pm
    trunk/vhffs-api/src/Vhffs/Panel/Cvs.pm
    trunk/vhffs-api/src/Vhffs/Panel/DNS.pm
    trunk/vhffs-api/src/Vhffs/Panel/Git.pm
    trunk/vhffs-api/src/Vhffs/Panel/Group.pm
    trunk/vhffs-api/src/Vhffs/Panel/Mail.pm
    trunk/vhffs-api/src/Vhffs/Panel/MailingList.pm
    trunk/vhffs-api/src/Vhffs/Panel/Main.pm
    trunk/vhffs-api/src/Vhffs/Panel/Mercurial.pm
    trunk/vhffs-api/src/Vhffs/Panel/Mysql.pm
    trunk/vhffs-api/src/Vhffs/Panel/Object.pm
    trunk/vhffs-api/src/Vhffs/Panel/Pgsql.pm
    trunk/vhffs-api/src/Vhffs/Panel/Repository.pm
    trunk/vhffs-api/src/Vhffs/Panel/Svn.pm
    trunk/vhffs-api/src/Vhffs/Panel/User.pm
    trunk/vhffs-api/src/Vhffs/Panel/Web.pm
    trunk/vhffs-irc/modobot.pl
    trunk/vhffs-panel/Makefile.am
    trunk/vhffs-panel/templates/acl/form.tt
    trunk/vhffs-panel/templates/acl/view.tt
    trunk/vhffs-panel/templates/admin/broadcast/create.tt
    trunk/vhffs-panel/templates/admin/broadcast/list.tt
    trunk/vhffs-panel/templates/admin/group/list.tt
    trunk/vhffs-panel/templates/admin/misc/list.tt
    trunk/vhffs-panel/templates/admin/misc/search.tt
    trunk/vhffs-panel/templates/admin/misc/su.tt
    trunk/vhffs-panel/templates/admin/moderation/index.tt
    trunk/vhffs-panel/templates/admin/object/edit.tt
    trunk/vhffs-panel/templates/admin/object/list.tt
    trunk/vhffs-panel/templates/admin/user/list.tt
    trunk/vhffs-panel/templates/anonymous/account_created.tt
    trunk/vhffs-panel/templates/anonymous/login.tt
    trunk/vhffs-panel/templates/anonymous/lost-password-ack.tt
    trunk/vhffs-panel/templates/anonymous/lost-password.tt
    trunk/vhffs-panel/templates/anonymous/subscribe.tt
    trunk/vhffs-panel/templates/bazaar/create.tt
    trunk/vhffs-panel/templates/cron/create.tt
    trunk/vhffs-panel/templates/cron/prefs.tt
    trunk/vhffs-panel/templates/cvs/create.tt
    trunk/vhffs-panel/templates/database/prefs.tt
    trunk/vhffs-panel/templates/dns/create.tt
    trunk/vhffs-panel/templates/dns/prefs.tt
    trunk/vhffs-panel/templates/git/create.tt
    trunk/vhffs-panel/templates/group/create.tt
    trunk/vhffs-panel/templates/group/index.tt
    trunk/vhffs-panel/templates/group/info.tt
    trunk/vhffs-panel/templates/group/prefs.tt
    trunk/vhffs-panel/templates/layouts/anonymous.tt
    trunk/vhffs-panel/templates/mail/create.tt
    trunk/vhffs-panel/templates/mail/prefs.tt
    trunk/vhffs-panel/templates/mailinglist/create.tt
    trunk/vhffs-panel/templates/mailinglist/prefs.tt
    trunk/vhffs-panel/templates/menu/admin.tt
    trunk/vhffs-panel/templates/menu/group.tt
    trunk/vhffs-panel/templates/menu/moderator.tt
    trunk/vhffs-panel/templates/mercurial/create.tt
    trunk/vhffs-panel/templates/misc/alert.tt
    trunk/vhffs-panel/templates/misc/header.tt
    trunk/vhffs-panel/templates/misc/languages.tt
    trunk/vhffs-panel/templates/misc/service-index.tt
    trunk/vhffs-panel/templates/misc/welcome.tt
    trunk/vhffs-panel/templates/mysql/create.tt
    trunk/vhffs-panel/templates/object/delete.tt
    trunk/vhffs-panel/templates/object/resubmit.tt
    trunk/vhffs-panel/templates/pgsql/create.tt
    trunk/vhffs-panel/templates/repository/create.tt
    trunk/vhffs-panel/templates/scm/prefs.tt
    trunk/vhffs-panel/templates/svn/create.tt
    trunk/vhffs-panel/templates/user/prefs.tt
    trunk/vhffs-panel/templates/web/create.tt
    trunk/vhffs-panel/templates/web/prefs.tt
    trunk/vhffs-public/avatar.pl

Added Paths:
-----------
    trunk/vhffs-api/src/Vhffs/Broadcast.pm
    trunk/vhffs-api/src/Vhffs/Panel/Acl.pm
    trunk/vhffs-api/src/Vhffs/Panel/Auth.pm
    trunk/vhffs-api/src/Vhffs/Panel/Broadcast.pm
    trunk/vhffs-api/src/Vhffs/Panel/Contact.pm
    trunk/vhffs-api/src/Vhffs/Panel/Home.pm
    trunk/vhffs-api/src/Vhffs/Panel/Moderation.pm
    trunk/vhffs-api/src/Vhffs/Panel/Stats.pm
    trunk/vhffs-api/src/Vhffs/Panel/Subscribe.pm
    trunk/vhffs-panel/index.pl

Removed Paths:
-------------
    trunk/vhffs-api/src/Vhffs/Mailings.pm
    trunk/vhffs-api/src/Vhffs/Panel/Mailings.pm
    trunk/vhffs-api/src/Vhffs/Panel/Modo.pm
    trunk/vhffs-panel/acl/view.pl
    trunk/vhffs-panel/admin/bazaar/
    trunk/vhffs-panel/admin/broadcast/
    trunk/vhffs-panel/admin/cron/
    trunk/vhffs-panel/admin/cvs/
    trunk/vhffs-panel/admin/dns/
    trunk/vhffs-panel/admin/git/
    trunk/vhffs-panel/admin/group/
    trunk/vhffs-panel/admin/index.pl
    trunk/vhffs-panel/admin/mail/
    trunk/vhffs-panel/admin/mailinglist/
    trunk/vhffs-panel/admin/mercurial/
    trunk/vhffs-panel/admin/moderation/
    trunk/vhffs-panel/admin/mysql/
    trunk/vhffs-panel/admin/object/
    trunk/vhffs-panel/admin/pgsql/
    trunk/vhffs-panel/admin/repository/
    trunk/vhffs-panel/admin/stats.pl
    trunk/vhffs-panel/admin/su.pl
    trunk/vhffs-panel/admin/svn/
    trunk/vhffs-panel/admin/user/
    trunk/vhffs-panel/admin/web/
    trunk/vhffs-panel/alert.pl
    trunk/vhffs-panel/alert_submit.pl
    trunk/vhffs-panel/auth.pl
    trunk/vhffs-panel/bazaar/
    trunk/vhffs-panel/cron/
    trunk/vhffs-panel/cvs/
    trunk/vhffs-panel/dns/
    trunk/vhffs-panel/getavatar.pl
    trunk/vhffs-panel/git/
    trunk/vhffs-panel/group/
    trunk/vhffs-panel/history.pl
    trunk/vhffs-panel/lost.pl
    trunk/vhffs-panel/lost_ack.pl
    trunk/vhffs-panel/mail/
    trunk/vhffs-panel/mailinglist/
    trunk/vhffs-panel/mercurial/
    trunk/vhffs-panel/mysql/
    trunk/vhffs-panel/object/delete.pl
    trunk/vhffs-panel/object/quickdelete.pl
    trunk/vhffs-panel/object/resubmit.pl
    trunk/vhffs-panel/object/upavatar.pl
    trunk/vhffs-panel/panel.pl
    trunk/vhffs-panel/pgsql/
    trunk/vhffs-panel/repository/
    trunk/vhffs-panel/subscribe.pl
    trunk/vhffs-panel/svn/
    trunk/vhffs-panel/templates/admin/bazaar/
    trunk/vhffs-panel/templates/admin/cron/
    trunk/vhffs-panel/templates/admin/cvs/
    trunk/vhffs-panel/templates/admin/dns/
    trunk/vhffs-panel/templates/admin/git/
    trunk/vhffs-panel/templates/admin/mail/
    trunk/vhffs-panel/templates/admin/mailinglist/
    trunk/vhffs-panel/templates/admin/mercurial/
    trunk/vhffs-panel/templates/admin/misc/mailings_part.tmpl
    trunk/vhffs-panel/templates/admin/mysql/
    trunk/vhffs-panel/templates/admin/pgsql/
    trunk/vhffs-panel/templates/admin/repository/
    trunk/vhffs-panel/templates/admin/svn/
    trunk/vhffs-panel/templates/admin/web/
    trunk/vhffs-panel/templates/bazaar/create.tmpl
    trunk/vhffs-panel/user/
    trunk/vhffs-panel/web/

Modified: trunk/TODO
===================================================================
--- trunk/TODO	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/TODO	2012-01-19 23:57:57 UTC (rev 1918)
@@ -0,0 +1,24 @@
+redo all $self->add_history( /// $user lost
+
+own session management using VHFFS database
+
+ECML : https://developer.mozilla.org/en/How_to_Turn_Off_Form_Autocompletion
+
+tester user mail
+
+tester user newsletter
+
+tester group mail
+
+yop (Sylvain Rochet)\xC2 -\xC2 Waiting for creation  // utf8 issue
+
+tester les tags
+
+ordre des objets dans le menu view du groupe
+
+clean description new object (\r)
+
+disparition du groupe sur le panel sur certains objets
+
+corriger tableau ACL
+

Copied: trunk/vhffs-api/src/Vhffs/Broadcast.pm (from rev 1916, trunk/vhffs-api/src/Vhffs/Mailings.pm)
===================================================================
--- trunk/vhffs-api/src/Vhffs/Broadcast.pm	                        (rev 0)
+++ trunk/vhffs-api/src/Vhffs/Broadcast.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -0,0 +1,115 @@
+#!%PERL% -w
+# Copyright (c) vhffs project and its contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without 
+# modification, are permitted provided that the following conditions 
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright 
+#   notice, this list of conditions and the following disclaimer.
+#2. Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in 
+#   the documentation and/or other materials provided with the 
+#   distribution.
+#3. Neither the name of vhffs nor the names of its contributors 
+#   may be used to endorse or promote products derived from this 
+#   software without specific prior written permission.
+#
+#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+# POSSIBILITY OF SUCH DAMAGE.
+
+
+# This file is a part of the VHFFS plateform
+# Please respect the entire licence of VHFFS
+# 
+# Author : Julien Delange < dieu at gunnm dot org >
+
+package Vhffs::Broadcast;
+
+use utf8;
+use strict;
+use Vhffs::Functions;
+use Vhffs::Constants;
+use Encode;
+
+sub add_broadcast
+{
+	my $vhffs = shift;	
+	my $subject = shift;
+	my $message = shift;
+	
+	return -1 unless defined $vhffs;
+
+	$message =~ s/\r\n/\n/g;
+
+	my $query = 'INSERT INTO vhffs_mailings (subject,message,date,state) VALUES( ? , ? , ? , ? )';
+	my $request = $vhffs->{'db'}->prepare( $query );
+	$request->execute($subject, $message, time(), Vhffs::Constants::WAITING_FOR_CREATION) or return -2;
+
+	return 1;
+}
+
+
+sub getall
+{
+	my $vhffs = shift;
+	my $state = shift;
+	my @params;
+
+	my $query = 'SELECT id_mailing,subject,message,date,state FROM vhffs_mailings ';
+	if( defined $state ) {
+		$query .= ' WHERE state=?';
+		push @params, $state;
+	}
+
+	my $request = $vhffs->{'db'}->prepare( $query );
+	$request->execute( @params ) or return undef;
+    
+	my $rows = $request->fetchall_hashref( 'id_mailing' );
+	return $rows;
+}
+
+
+
+sub del_broadcast
+{
+	my $vhffs = shift;	
+	my $id = shift;
+	my $db = $vhffs->get_db_object;
+
+	my $query = 'DELETE FROM vhffs_mailings WHERE id_mailing=?';
+	my $request = $db->prepare( $query );
+	$request->execute( $id ) or return -2;
+
+	return 1;
+}
+
+
+sub get_broadcast
+{
+	my $vhffs = shift;	
+	my $id = shift;
+	my $db = $vhffs->get_db_object;
+
+	return undef unless defined $id;
+	
+	my $query = 'SELECT id_mailing,subject,message,date,state FROM vhffs_mailings WHERE id_mailing=?';
+	my $request = $db->prepare( $query );
+	$request->execute( $id ) or return -2;
+
+	my $row = $request->fetchrow_hashref();
+	return $row;
+}
+
+1;

Modified: trunk/vhffs-api/src/Vhffs/Functions.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Functions.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Functions.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -45,7 +45,6 @@
 
 use strict;
 use utf8;
-use DBI;
 use POSIX qw(locale_h);
 use locale;
 use Locale::gettext;
@@ -403,49 +402,7 @@
     return '<script type="text/javascript">document.write(decode_mail(\''.$crypted.'\'));</script>';
 }
 
-#Connect to the database
-sub db_connect
-{
-    my $backend_config;
-    my $dbparams;
-    my $dbh;
-    my $driver;
-	my $port;
-	my $host;
 
-
-    ($backend_config) = @_;
-
-	if( ! defined $backend_config )
-	{
-		print "Oops!: I wonder if I am blind but I cannot find the backend area in the vhffs configuration file :/, could you help me ?\n";
-		exit -1;
-	}
-
-	#Default port;
-
-    if( $backend_config->{'driver'} =~  /pg/ )
-    {
-		$port 	= 5432;
-    	$driver = "Pg";
-		$host 	= "localhost";
-		$port 	= $backend_config->{'db_port'} if( defined( $backend_config->{'db_port'} ) );
-		$host 	= $backend_config->{'db_host'} if( defined( $backend_config->{'db_host'} ) );
-
-		$dbparams = "dbname=$backend_config->{'db_name'};host=$host;port=$port";
-        $dbh = DBI->connect("DBI:$driver:$dbparams",$backend_config->{'db_username'}, $backend_config->{'db_password'}) || (warn "Cant connect: $DBI::errstr\n" and return undef);
-        $dbh->{pg_enable_utf8}=1;
-        
-        return( $dbh );
-    }
-    
-    else
-    {
-        print "Oops!: The backend you specify in your config file is not supported in Vhffs\n";
-        exit -1;
-    }
-}
-
 sub generate_random_password
 {
     my $password;

Modified: trunk/vhffs-api/src/Vhffs/Group.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Group.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Group.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -309,8 +309,8 @@
 =cut
 
 sub get_label {
-    my $self = shift;
-    return $self->{groupname};
+	my $self = shift;
+	return $self->{groupname};
 }
 
 sub get_quota
@@ -321,14 +321,14 @@
 
 sub get_groupname
 {
-    my $self = shift;
-    return $self->{'groupname'};
+	my $self = shift;
+	return $self->{'groupname'};
 }
 
 sub get_gid
 {
-    my $self = shift;
-    return $self->{'gid'};
+	my $self = shift;
+	return $self->{'gid'};
 }
 
 
@@ -568,7 +568,7 @@
 sub get_by_gid {
     my ($vhffs, $gid) = @_;
     my $query = 'SELECT g.gid, o.object_id, o.owner_uid, g.groupname, g.realname, g.passwd, g.quota, g.quota_used, o.date_creation, o.description, o.state FROM vhffs_groups g INNER JOIN vhffs_object o ON o.object_id = g.object_id WHERE g.gid = ?';
-    
+
     my $dbh = $vhffs->get_db_object;
     my @params = $dbh->selectrow_array($query, undef, $gid);
     return undef unless(@params);
@@ -603,7 +603,7 @@
 	no strict 'refs';
 	my ($class, $main, $gid, $oid, $owner_uid, $groupname, $realname, $passwd, $quota, $quota_used, $date_creation, $description, $state) = @_;
 	my $self = $class->SUPER::_new($main, $oid, $owner_uid, $gid, $date_creation, $description, '', $state, Vhffs::Constants::TYPE_GROUP);
-	return undef unless(defined $self);
+	return undef unless defined $self;
 
 	$self->{gid} = $gid;
 	$self->{groupname} = $groupname;

Deleted: trunk/vhffs-api/src/Vhffs/Mailings.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Mailings.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Mailings.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,115 +0,0 @@
-#!%PERL% -w
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#   notice, this list of conditions and the following disclaimer.
-#2. Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in 
-#   the documentation and/or other materials provided with the 
-#   distribution.
-#3. Neither the name of vhffs nor the names of its contributors 
-#   may be used to endorse or promote products derived from this 
-#   software without specific prior written permission.
-#
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-
-# This file is a part of the VHFFS plateform
-# Please respect the entire licence of VHFFS
-# 
-# Author : Julien Delange < dieu at gunnm dot org >
-
-package Vhffs::Mailings;
-
-use utf8;
-use strict;
-use Vhffs::Functions;
-use Vhffs::Constants;
-use Encode;
-
-sub add_mailing
-{
-	my $vhffs = shift;	
-	my $subject = shift;
-	my $message = shift;
-	
-	return -1 unless defined $vhffs;
-
-	$message =~ s/\r\n/\n/g;
-
-	my $query = 'INSERT INTO vhffs_mailings (subject,message,date,state) VALUES( ? , ? , ? , ? )';
-	my $request = $vhffs->{'db'}->prepare( $query );
-	$request->execute($subject, $message, time(), Vhffs::Constants::WAITING_FOR_CREATION) or return -2;
-
-	return 1;
-}
-
-
-sub getall
-{
-	my $vhffs = shift;
-	my $state = shift;
-	my @params;
-
-	my $query = 'SELECT id_mailing,subject,message,date,state FROM vhffs_mailings ';
-	if( defined $state ) {
-		$query .= ' WHERE state=?';
-		push @params, $state;
-	}
-
-	my $request = $vhffs->{'db'}->prepare( $query );
-	$request->execute( @params ) or return undef;
-    
-	my $rows = $request->fetchall_hashref( 'id_mailing' );
-	return $rows;
-}
-
-
-
-sub del_mailing
-{
-	my $vhffs = shift;	
-	my $id = shift;
-	my $db = $vhffs->get_db_object;
-
-	my $query = 'DELETE FROM vhffs_mailings WHERE id_mailing=?';
-	my $request = $db->prepare( $query );
-	$request->execute( $id ) or return -2;
-
-	return 1;
-}
-
-
-sub get_mailing
-{
-	my $vhffs = shift;	
-	my $id = shift;
-	my $db = $vhffs->get_db_object;
-
-	return undef unless defined $id;
-	
-	my $query = 'SELECT id_mailing,subject,message,date,state FROM vhffs_mailings WHERE id_mailing=?';
-	my $request = $db->prepare( $query );
-	$request->execute( $id ) or return -2;
-
-	my $row = $request->fetchrow_hashref();
-	return $row;
-}
-
-1;

Modified: trunk/vhffs-api/src/Vhffs/Main.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Main.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Main.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -37,55 +37,37 @@
 use Vhffs::Functions;
 use Vhffs::Conf;
 
-use constant
-{
+use constant {
     VHFFSCONFPATH => "/etc/vhffs/vhffs.conf"
 };
 
-# Current user UID. On the panel it would be
-# the currently logged user, on IRC moderation
-# the user who talk to the bot.
-my $current_user_uid;
+sub init {
 
-sub init
-{
-	my $self;
-	my $this;
-	my $dbh;
-	my $class;
-	my $config;
-	my $db_config;
-	
-	$this = shift;
+	my $class = ref( $_[0] ) || $_[0];
+	my $opt = $_[1];
  
-	#First, create the object
-	$self={};
-	$class = ref($this) || $this;
-	bless($self , $class );
+	# First, config stuff
+	my $config = new Vhffs::Conf( VHFFSCONFPATH );
+	return undef unless defined $config;
+	$config->parse;
 
+	# Next, create the object
+	my $self={};
+	bless( $self , $class );
+	$self->{'config'} = $config;
 
-	#Then, config stuff
-	$config = new Vhffs::Conf( VHFFSCONFPATH );
-	$self->{'config'} = $config if (defined $config);
-	$self->{'config'}->parse;
-
-
-	#Finally, backend stuff
-	$db_config = $config->get_database();
-    
-    $dbh = Vhffs::Functions::db_connect $db_config;
-    if(defined $dbh) {
-    	$self->{'db'} = $dbh;
-	} else {
-        warn "Unable to open database connection\n";
+	# Finally, backend stuff
+	$opt->{backend} = 'yes' unless defined $opt->{backend};
+	if( Vhffs::Functions::strtobool( $opt->{backend} ) and not defined $self->connect ) {
 		undef $self;
+		return undef;
 	}
 
 	return $self;
 }
 
-sub get_db_object
-{
+sub get_db_object {
+
 	my $self = shift;
 
 	if( defined $self->{'db'} )
@@ -98,8 +80,8 @@
 	}
 }
 
-sub get_config
-{
+sub get_config {
+
 	my $self = shift;
 
 	if( defined $self->{'config'} )
@@ -112,29 +94,43 @@
 	}
 }
 
-sub is_valid
-{
+sub is_valid {
+
     my $self = shift;
-    return (defined $self->{db} && $self->{db}->ping() > 0);
+    return (defined $self->{db} and $self->{db}->ping() > 0);
 }
 
-sub reconnect {
-    my $self = shift;
+sub connect {
 
-    my $db_config = $self->{config}->get_database();
+	my $self = shift;
+	my $config = $self->{config}->get_database();
 
-    my $dbh = Vhffs::Functions::db_connect $db_config;
-    if(defined $dbh) {
-        $self->{'db'} = $dbh;
-    } else {
-        warn "Unable to open database connection\n";
-    }
+	unless( defined $config )  {
+		warn 'Oops!: I wonder if I am blind but I cannot find the backend area in the Vhffs configuration file :/, could you help me ?'."\n";
+		return undef;
+	}
+
+	if( $config->{'driver'} eq 'pg' )  {
+		my $port = ( $config->{'db_port'} or '5432' );
+		my $host = ( $config->{'db_host'} or 'localhost' );
+
+		my $dbh = DBI->connect('DBI:Pg:dbname='.$config->{'db_name'}.';host='.$host.';port='.$port, $config->{'db_username'}, $config->{'db_password'}, {pg_enable_utf8 => 1} )
+			or ( warn 'X10X Unable to open database connection: '.$DBI::errstr."\n" and return undef );
+		$dbh->do( 'SET CLIENT_ENCODING TO \'UTF8\'' );
+		$self->{'db'} = $dbh;
+		return $dbh;
+	}
+
+	warn 'Oops!: The specified backend in the configuration file is not supported by Vhffs'."\n";
+	return undef;
 }
 
-sub current_user_uid
-{
-	$current_user_uid = $_[0] if(defined $_[0]);
-	return $current_user_uid;
+sub reconnect {
+
+	my $self = shift;
+	return $self->{db} if defined $self->{db} and $self->{db}->ping() > 0;
+	$self->{db}->disconnect if defined $self->{db};
+	return $self->connect;
 }
 
 1;
@@ -173,8 +169,6 @@
 
 is_valid() : returns 1 if the object is valid (good database connection, ...), 0 otherwise
 
-current_user_uid([$uid]): get or set the current user's UID.
-
 =head1 SEE ALSO
 Vhffs::User, Vhffs::Group
 

Modified: trunk/vhffs-api/src/Vhffs/Makefile.am
===================================================================
--- trunk/vhffs-api/src/Vhffs/Makefile.am	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Makefile.am	2012-01-19 23:57:57 UTC (rev 1918)
@@ -11,7 +11,7 @@
 	Functions.pm \
 	Group.pm \
 	Listengine.pm \
-	Mailings.pm \
+	Broadcast.pm \
 	Main.pm \
 	ObjectFactory.pm \
 	Object.pm \
@@ -20,25 +20,31 @@
 	Stats.pm \
 	Tag.pm \
 	User.pm \
+	Panel/Acl.pm \
 	Panel/Admin.pm \
+	Panel/Auth.pm \
 	Panel/Avatar.pm \
 	Panel/Bazaar.pm \
 	Panel/Commons.pm \
+	Panel/Contact.pm \
 	Panel/Cvs.pm \
 	Panel/DNS.pm \
 	Panel/Group.pm \
+	Panel/Home.pm \
 	Panel/Mail.pm \
 	Panel/MailingList.pm \
-	Panel/Mailings.pm \
+	Panel/Broadcast.pm \
 	Panel/Main.pm \
 	Panel/Mercurial.pm \
-	Panel/Modo.pm \
+	Panel/Moderation.pm \
 	Panel/Mysql.pm \
 	Panel/Object.pm \
 	Panel/Pgsql.pm \
 	Panel/Public.pm \
 	Panel/Repository.pm \
+	Panel/Subscribe.pm \
 	Panel/Svn.pm \
+	Panel/Stats.pm \
 	Panel/Tag.pm \
 	Panel/Git.pm \
 	Panel/User.pm \

Modified: trunk/vhffs-api/src/Vhffs/Object.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Object.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Object.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -242,13 +242,12 @@
 
 sub commit
 {
-    my $self = shift;
-    my $request;
+	my $self = shift;
+	my $request;
 
-    $request = 'UPDATE vhffs_object SET state=?, description=?, refuse_reason=?, owner_uid=?, owner_gid=? WHERE object_id=?';
-    my $result = $self->{'db'}->prepare($request);
-    $result->execute( $self->{'state'} , $self->{'description'} , $self->{'refuse_reason'}, $self->{'owner_uid'} , $self->{'owner_gid'} , $self->{'object_id'} );
-
+	$request = 'UPDATE vhffs_object SET state=?, description=?, refuse_reason=?, owner_uid=?, owner_gid=? WHERE object_id=?';
+	my $result = $self->{'db'}->prepare($request);
+	$result->execute( $self->{'state'} , $self->{'description'} , $self->{'refuse_reason'}, $self->{'owner_uid'} , $self->{'owner_gid'} , $self->{'object_id'} );
 }
 
 sub get_date
@@ -259,26 +258,26 @@
 
 sub get_oid
 {
-    my $self = shift;
-    return $self->{'object_id'};
+	my $self = shift;
+	return $self->{'object_id'};
 }
 
 sub get_description
 {
-    my $self = shift;
-    return $self->{'description'};
+	my $self = shift;
+	return $self->{'description'};
 }
 
 sub set_owner_uid
 {
-   my ( $self , $value ) = @_;
-   $self->{'owner_uid'} = $value;
+	my ( $self , $value ) = @_;
+	$self->{'owner_uid'} = $value;
 }
 
 sub set_owner_gid
 {
-   my ( $self , $value ) = @_;
-   $self->{'owner_gid'} = $value;
+	my ( $self , $value ) = @_;
+	$self->{'owner_gid'} = $value;
 }
 
 
@@ -297,7 +296,7 @@
 =cut
 
 sub get_label {
-    return '????';
+	return '????';
 }
 
 sub set_status
@@ -360,6 +359,7 @@
 {
 	my ($self , $value) = @_;
 	$value =~ s/\?/ \?/g;
+	$value =~ s/\r\n/\n/g;
 	$self->{'description'} = $value ;
 }
 
@@ -369,7 +369,8 @@
 	use Vhffs::Main;
 	my $self = shift;
 	my $message = shift;
-	my $source = Vhffs::Main::current_user_uid;
+	# TODO: REDO SOURCE
+	my $source = undef;
 	$message = $message;
 
 	my $query = 'INSERT INTO vhffs_history(object_id, date, message, source_uid)  VALUES(?, ?, ?, ?)';

Added: trunk/vhffs-api/src/Vhffs/Panel/Acl.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Acl.pm	                        (rev 0)
+++ trunk/vhffs-api/src/Vhffs/Panel/Acl.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -0,0 +1,117 @@
+#!%PERL%
+# Copyright (c) vhffs project and its contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#2. Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution.
+#3. Neither the name of vhffs nor the names of its contributors
+#   may be used to endorse or promote products derived from this
+#   software without specific prior written permission.
+#
+#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use utf8;
+
+package Vhffs::Panel::Acl;
+
+use POSIX qw(locale_h);
+use locale;
+use Locale::gettext;
+use Encode;
+
+use Vhffs::Constants;
+use Vhffs::Functions;
+use Vhffs::User;
+use Vhffs::Acl;
+
+sub acl {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $oid = $cgi->param('oid');
+	unless( defined $oid ) {
+		$panel->render('misc/message.tt', { message => gettext( 'CGI Error !' ) } );
+		return;
+	}
+
+	# Object does not exist
+	my $object = Vhffs::Object::get_by_oid($vhffs, $oid);
+	unless( defined $object ) {
+		$panel->render('misc/message.tt', { message => sprintf( gettext('Cannot get informations on object #%d'), $oid) } );
+		return;
+	}
+
+	# Object exists, we need to know if access is granted to the user
+	unless( $user->can_view( $object ) ) {
+		$panel->render('misc/message.tt', { message => gettext('You\'re not allowed to view this object\'s ACL') } );
+		return;
+	}
+
+	# access OK, let's see if some action was requested
+	if(defined $cgi->param('update_acl_submit')) {
+		my $granted_oid = $cgi->param('granted_oid');
+		my $perm = $cgi->param('perm'.$granted_oid);
+		my $granted;
+		my $ret;
+		unless( defined $granted_oid and defined $perm ) {
+			$panel->add_error( gettext('CGI Error !') );
+		} elsif( not defined( $granted = Vhffs::Object::get_by_oid( $vhffs, $granted_oid ) ) ) {
+			$panel->add_error( gettext('Group or user not found') );
+		} elsif( not $user->can_manageacl( $object ) ) {
+			$panel->add_error( gettext('You\'re not allowed to manage this object\'s ACL') );
+		} else {
+			$ret = Vhffs::Acl::add_update_or_del_acl( $vhffs, $object->get_oid, $granted_oid, $perm );
+			$panel->add_error( gettext('Sorry, can\'t add or update ACL') ) if $ret < 0;
+			$panel->add_info( gettext('ACL added') ) if $ret == 1;
+			$panel->add_info( gettext('ACL updated') ) if $ret == 2;
+			$panel->add_info( gettext('ACL deleted') ) if $ret == 3;
+		}
+	}
+
+	$panel->set_title( gettext('ACL Administration') );
+	my $vars = { target => $object };
+	my $acls = Vhffs::Acl::get_object_acl( $vhffs, $object );
+	my $default_acl;
+	my $users_acl = [];
+	foreach my $acl ( @{$acls} )  {
+		if( defined $acl->{name} ) {
+			$acl->{perm} = Vhffs::Constants::ACL_UNDEFINED unless defined $acl->{perm};
+			push( @$users_acl, $acl );
+		} else  {
+			$default_acl = {
+			  granted_oid => $acl->{granted_oid},
+			  'perm' => $acl->{perm}
+			  };
+		}
+	}
+	$vars->{default_acl} = $default_acl;
+	$vars->{users_acl} = $users_acl;
+
+	$panel->render('acl/view.tt', $vars);
+}
+
+1;

Modified: trunk/vhffs-api/src/Vhffs/Panel/Admin.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Admin.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/Admin.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -38,20 +38,10 @@
 
 package Vhffs::Panel::Admin;
 
-use base qw(Vhffs::Panel::Main);
-
 use POSIX qw(locale_h);
 use locale;
 use Locale::gettext;
 
-sub new {
-	my ($class, @args) = @_;
-	my $panel = $class->SUPER::new(@args);
-    $panel->get_session();
-	$panel->check_admin();
-	return $panel;
-}
-
 =pod
 
 =head1 NAME
@@ -66,7 +56,7 @@
 
 =head2 get_modo_category
 
-    Vhffs::Panel::Admin::get_modo_category;
+	Vhffs::Panel::Admin::get_modo_category;
 
 Returns a hashref (name, items) where catname is the name of the
 general category for moderation and items the corresponding menu
@@ -75,16 +65,16 @@
 =cut
 
 sub get_modo_category {
-    my $items = [
-        { link => '/admin/stats.pl',            label => gettext( 'Get Statistics' ) },
-        { link => '/admin/moderation/index.pl', label => gettext( 'Moderation' ) }
-    ];
-    return { name => gettext( 'General' ),   items => $items, type => 'general' };
+	my $items = [
+		{ link => '?do=stats',       label => gettext( 'Get Statistics' ) },
+		{ link => '?do=moderation',  label => gettext( 'Moderation' ) }
+	];
+	return { name => gettext( 'General' ),   items => $items, type => 'general' };
 }
 
 =head2 get_admin_category
 
-    Vhffs::Panel::Admin::get_admin_category;
+	Vhffs::Panel::Admin::get_admin_category;
 
 Returns a hashref (name, items) containing general administration
 items.
@@ -92,22 +82,22 @@
 =cut
 
 sub get_admin_category {
-    my $items = [
-        { link => '/admin/stats.pl',            label => gettext( 'Get Statistics' ) },
-        { link => '/admin/su.pl',               label => gettext( 'Change user-id' ) },
-        { link => '/admin/moderation/index.pl', label => gettext( 'Moderation' ) },
-        { link => '/admin/object/list.pl',      label => gettext( 'List all objects' ) },
-        { link => '/admin/object/search.pl',    label => gettext( 'Search for an object' ) },
-        { link => '/admin/broadcast/create.pl', label => gettext( 'Mail to all hosted people' ) },
-        { link => '/admin/broadcast/list.pl',   label => gettext( 'Manage mailings' ) }
-    ];
-    return { name => gettext( 'General' ),   items => $items, type => 'general' };
+	my $items = [
+		{ link => '?do=stats',               label => gettext( 'Get Statistics' ) },
+		{ link => '?do=su',                  label => gettext( 'Change user-id' ) },
+		{ link => '?do=moderation',          label => gettext( 'Moderation' ) },
+		{ link => '?do=objectsearch&name=',  label => gettext( 'List all objects' ) },
+		{ link => '?do=objectsearch',        label => gettext( 'Search for an object' ) },
+		{ link => '?do=broadcastcreate',     label => gettext( 'Mail to all hosted people' ) },
+		{ link => '?do=broadcastlist',       label => gettext( 'Manage mailings' ) }
+	];
+	return { name => gettext( 'General' ),   items => $items, type => 'general' };
 }
 
 
 =head2 get_bazaar_category
 
-    Vhffs::Panel::Admin::get_bazaar_category;
+	Vhffs::Panel::Admin::get_bazaar_category;
 
 Returns a hashref (name, ITEM) containing bazaar's administration
 items.
@@ -115,16 +105,16 @@
 =cut
 
 sub get_bazaar_category {
-    my $items = [
-        { link => '/admin/bazaar/list.pl',        label => gettext( 'List all Bazaar repos' ) },
-        { link => '/admin/bazaar/search.pl',      label => gettext( 'Search for a Bazaar repository' ) }
-    ];
-    return { name => gettext( 'Bazaar Admin' ),    items => $items, type => 'bazaar'  };
+	my $items = [
+		{ link => '?do=bazaarsearch&name=',  label => gettext( 'List all Bazaar repos' ) },
+		{ link => '?do=bazaarsearch',        label => gettext( 'Search for a Bazaar repository' ) }
+	];
+	return { name => gettext( 'Bazaar Admin' ),    items => $items, type => 'bazaar'  };
 }
 
 =head2 get_user_category
 
-    Vhffs::Panel::Admin::get_user_category;
+	Vhffs::Panel::Admin::get_user_category;
 
 Returns a hashref (name, ITEM) containing users' administration
 items.
@@ -132,16 +122,16 @@
 =cut
 
 sub get_user_category {
-    my $items = [
-        { link => '/admin/user/list.pl',        label => gettext( 'List all users' ) },
-        { link => '/admin/user/search.pl',      label => gettext( 'Search for an user' ) }
-    ];
-    return { name => gettext( 'User Admin' ),    items => $items, type => 'user'  };
+	my $items = [
+		{ link => '?do=usersearch&name=',   label => gettext( 'List all users' ) },
+		{ link => '?do=usersearch',         label => gettext( 'Search for an user' ) }
+	];
+	return { name => gettext( 'User Admin' ),    items => $items, type => 'user'  };
 }
 
 =head2 get_user_category
 
-    Vhffs::Panel::Admin::get_group_category;
+	Vhffs::Panel::Admin::get_group_category;
 
 Returns a hashref (name, ITEM) containing groups' administration
 items.
@@ -149,11 +139,11 @@
 =cut
 
 sub get_group_category {
-    my $items = [
-        { link => '/admin/group/list.pl',        label => gettext( 'List all groups' ) },
-        { link => '/admin/group/search.pl',      label => gettext( 'Search for a group' ) }
-    ];
-    return { name => gettext( 'Group Admin' ),    items => $items, type => 'group'  };
+	my $items = [
+		{ link => '?do=groupsearch&name=',  label => gettext( 'List all groups' ) },
+		{ link => '?do=groupsearch',        label => gettext( 'Search for a group' ) }
+	];
+	return { name => gettext( 'Group Admin' ),    items => $items, type => 'group'  };
 }
 
 
@@ -179,7 +169,7 @@
 
 =head2 get_web_category
 
-    Vhffs::Panel::Admin::get_web_category;
+	Vhffs::Panel::Admin::get_web_category;
 
 Returns a hashref (name, ITEM) containing webareas' administration
 items.
@@ -187,16 +177,16 @@
 =cut
 
 sub get_web_category {
-    my $items = [
-        { link => '/admin/web/list.pl',        label => gettext( 'List all webareas' ) },
-        { link => '/admin/web/search.pl',      label => gettext( 'Search for a webarea' ) }
-    ];
-    return { name => gettext( 'Web Admin' ),    items => $items, type => 'web'  };
+	my $items = [
+		{ link => '?do=websearch&name=',  label => gettext( 'List all webareas' ) },
+		{ link => '?do=websearch',        label => gettext( 'Search for a webarea' ) }
+	];
+	return { name => gettext( 'Web Admin' ),    items => $items, type => 'web'  };
 }
 
 =head2 get_svn_category
 
-    Vhffs::Panel::Admin::get_svn_category;
+	Vhffs::Panel::Admin::get_svn_category;
 
 Returns a hashref (name, ITEM) containing svn's administration
 items.
@@ -204,17 +194,17 @@
 =cut
 
 sub get_svn_category {
-    my $items = [
-        { link => '/admin/svn/list.pl',        label => gettext( 'List all SVN repos' ) },
-        { link => '/admin/svn/search.pl',      label => gettext( 'Search for a SVN repository' ) }
-    ];
-    return { name => gettext( 'SVN Admin' ),    items => $items, type => 'svn'  };
+	my $items = [
+		{ link => '?do=svnsearch&name=',  label => gettext( 'List all SVN repos' ) },
+		{ link => '?do=svnsearch',        label => gettext( 'Search for a SVN repository' ) }
+	];
+	return { name => gettext( 'SVN Admin' ),    items => $items, type => 'svn'  };
 }
 
 
 =head2 get_cvs_category
 
-    Vhffs::Panel::Admin::get_cvs_category;
+	Vhffs::Panel::Admin::get_cvs_category;
 
 Returns a hashref (name, ITEM) containing cvs' administration
 items.
@@ -222,17 +212,17 @@
 =cut
 
 sub get_cvs_category {
-    my $items = [
-        { link => '/admin/cvs/list.pl',        label => gettext( 'List all CVS repos' ) },
-        { link => '/admin/cvs/search.pl',      label => gettext( 'Search for a CVS repository' ) }
-    ];
-    return { name => gettext( 'CVS Admin' ),    items => $items, type => 'cvs'  };
+	my $items = [
+		{ link => '?do=cvssearch&name=',   label => gettext( 'List all CVS repos' ) },
+		{ link => '?do=cvssearch',         label => gettext( 'Search for a CVS repository' ) }
+	];
+	return { name => gettext( 'CVS Admin' ),    items => $items, type => 'cvs'  };
 }
 
 
 =head2 get_git_category
 
-    Vhffs::Panel::Admin::get_git_category;
+	Vhffs::Panel::Admin::get_git_category;
 
 Returns a hashref (name, ITEM) containing git's administration
 items.
@@ -240,17 +230,17 @@
 =cut
 
 sub get_git_category {
-    my $items = [
-        { link => '/admin/git/list.pl',        label => gettext( 'List all Git repos' ) },
-        { link => '/admin/git/search.pl',      label => gettext( 'Search for a Git repository' ) }
-    ];
-    return { name => gettext( 'Git Admin' ),    items => $items, type => 'git'  };
+	my $items = [
+		{ link => '?do=gitsearch&name=',  label => gettext( 'List all Git repos' ) },
+		{ link => '?do=gitsearch',        label => gettext( 'Search for a Git repository' ) }
+	];
+	return { name => gettext( 'Git Admin' ),    items => $items, type => 'git'  };
 }
 
 
 =head2 get_mercurial_category
 
-    Vhffs::Panel::Admin::get_mercurial_category;
+	Vhffs::Panel::Admin::get_mercurial_category;
 
 Returns a hashref (name, ITEM) containing mercurial's administration
 items.
@@ -258,16 +248,16 @@
 =cut
 
 sub get_mercurial_category {
-    my $items = [
-        { link => '/admin/mercurial/list.pl',        label => gettext( 'List all Mercurial repos' ) },
-        { link => '/admin/mercurial/search.pl',      label => gettext( 'Search for a Mercurial repository' ) }
-    ];
-    return { name => gettext( 'Mercurial Admin' ),    items => $items, type => 'mercurial'  };
+	my $items = [
+		{ link => '?do=mercurialsearch&name=',  label => gettext( 'List all Mercurial repos' ) },
+		{ link => '?do=mercurialsearch',        label => gettext( 'Search for a Mercurial repository' ) }
+	];
+	return { name => gettext( 'Mercurial Admin' ),    items => $items, type => 'mercurial'  };
 }
 
 =head2 get_mysql_category
 
-    Vhffs::Panel::Admin::get_mysql_category;
+	Vhffs::Panel::Admin::get_mysql_category;
 
 Returns a hashref (name, ITEM) containing mysql's administration
 items.
@@ -275,16 +265,16 @@
 =cut
 
 sub get_mysql_category {
-    my $items = [
-        { link => '/admin/mysql/list.pl',        label => gettext( 'List all MySQL databases' ) },
-        { link => '/admin/mysql/search.pl',      label => gettext( 'Search for a MySQL database' ) }
-    ];
-    return { name => gettext( 'MySQL Admin' ),    items => $items, type => 'mysql'  };
+	my $items = [
+		{ link => '?do=mysqlsearch&name=',  label => gettext( 'List all MySQL databases' ) },
+		{ link => '?do=mysqlsearch',        label => gettext( 'Search for a MySQL database' ) }
+	];
+	return { name => gettext( 'MySQL Admin' ),    items => $items, type => 'mysql'  };
 }
 
 =head2 get_pgsql_category
 
-    Vhffs::Panel::Admin::get_pgsql_category;
+	Vhffs::Panel::Admin::get_pgsql_category;
 
 Returns a hashref (name, ITEM) containing PostgreSQL's administration
 items.
@@ -292,16 +282,16 @@
 =cut
 
 sub get_pgsql_category {
-    my $items = [
-        { link => '/admin/pgsql/list.pl',        label => gettext( 'List all Pg databases' ) },
-        { link => '/admin/pgsql/search.pl',      label => gettext( 'Search for a Pg database' ) }
-    ];
-    return { name => gettext( 'PostgreSQL Admin' ),    items => $items, type => 'pgsql'  };
+	my $items = [
+		{ link => '?do=pgsqlsearch&name=',  label => gettext( 'List all Pg databases' ) },
+		{ link => '?do=pgsqlsearch',        label => gettext( 'Search for a Pg database' ) }
+	];
+	return { name => gettext( 'PostgreSQL Admin' ),    items => $items, type => 'pgsql'  };
 }
 
 =head2 get_mail_category
 
-    Vhffs::Panel::Admin::get_mail_category;
+	Vhffs::Panel::Admin::get_mail_category;
 
 Returns a hashref (name, ITEM) containing mail domains' administration
 items.
@@ -309,17 +299,17 @@
 =cut
 
 sub get_mail_category {
-    my $items = [
-        { link => '/admin/mail/list.pl',        label => gettext( 'List all mail domains' ) },
-        { link => '/admin/mail/search.pl',      label => gettext( 'Search for a mail domain' ) }
-    ];
-    return { name => gettext( 'Mail domains Admin' ),    items => $items, type => 'mail'  };
+	my $items = [
+		{ link => '?do=mailsearch&name=',  label => gettext( 'List all mail domains' ) },
+		{ link => '?do=mailsearch',        label => gettext( 'Search for a mail domain' ) }
+	];
+	return { name => gettext( 'Mail domains Admin' ),    items => $items, type => 'mail'  };
 }
 
 
 =head2 get_mailing_category
 
-    Vhffs::Panel::Admin::get_mailing_category;
+	Vhffs::Panel::Admin::get_mailing_category;
 
 Returns a hashref (name, ITEM) containing mailing lists' administration
 items.
@@ -327,17 +317,17 @@
 =cut
 
 sub get_mailing_category {
-    my $items = [
-        { link => '/admin/mailinglist/list.pl',        label => gettext( 'List all mailing lists' ) },
-        { link => '/admin/mailinglist/search.pl',      label => gettext( 'Search for a mailing list' ) }
-    ];
-    return { name => gettext( 'Mailing lists Admin' ),    items => $items, type => 'mailing'  };
+	my $items = [
+		{ link => '?do=mailinglistsearch&name=',  label => gettext( 'List all mailing lists' ) },
+		{ link => '?do=mailinglistsearch',        label => gettext( 'Search for a mailing list' ) }
+	];
+	return { name => gettext( 'Mailing lists Admin' ),    items => $items, type => 'mailing'  };
 }
 
 
 =head2 get_dns_category
 
-    Vhffs::Panel::Admin::get_dns_category;
+	Vhffs::Panel::Admin::get_dns_category;
 
 Returns a hashref (name, ITEM) containing DNS' administration
 items.
@@ -345,17 +335,17 @@
 =cut
 
 sub get_dns_category {
-    my $items = [
-        { link => '/admin/dns/list.pl',        label => gettext( 'List all domain names' ) },
-        { link => '/admin/dns/search.pl',      label => gettext( 'Search for a domain name' ) }
-    ];
-    return { name => gettext( 'DNS Admin' ),    items => $items, type => 'dns'  };
+	my $items = [
+		{ link => '?do=dnssearch&name=',  label => gettext( 'List all domain names' ) },
+		{ link => '?do=dnssearch',        label => gettext( 'Search for a domain name' ) }
+	];
+	return { name => gettext( 'DNS Admin' ),    items => $items, type => 'dns'  };
 }
 
 
 =head2 get_repo_category
 
-    Vhffs::Panel::Admin::get_repo_category;
+	Vhffs::Panel::Admin::get_repo_category;
 
 Returns a hashref (name, ITEM) containing download repositories' administration
 items.
@@ -363,16 +353,16 @@
 =cut
 
 sub get_repo_category {
-    my $items = [
-        { link => '/admin/repository/list.pl',        label => gettext( 'List all download repositories' ) },
-        { link => '/admin/repository/search.pl',      label => gettext( 'Search for a download repository' ) }
-    ];
-    return { name => gettext( 'Download repositories Admin' ),    items => $items, type => 'repository'  };
+	my $items = [
+		{ link => '?do=repositorysearch&name=',  label => gettext( 'List all download repositories' ) },
+		{ link => '?do=repositorysearch',        label => gettext( 'Search for a download repository' ) }
+	];
+	return { name => gettext( 'Download repositories Admin' ),    items => $items, type => 'repository'  };
 }
 
 =head2 get_cron_category
 
-    Vhffs::Panel::Admin::get_cron_category;
+	Vhffs::Panel::Admin::get_cron_category;
 
 Returns a hashref (name, ITEM) containing cron jobs administration
 items.
@@ -380,16 +370,16 @@
 =cut
 
 sub get_cron_category {
-    my $items = [
-        { link => '/admin/cron/list.pl',        label => gettext( 'List all cron jobs' ) },
-        { link => '/admin/cron/search.pl',      label => gettext( 'Search for a cron job' ) }
-    ];
-    return { name => gettext( 'Crons Admin' ),    items => $items, type => 'cron'  };
+	my $items = [
+		{ link => '?do=cronsearch&name=',  label => gettext( 'List all cron jobs' ) },
+		{ link => '?do=cronsearch',        label => gettext( 'Search for a cron job' ) }
+	];
+	return { name => gettext( 'Crons Admin' ),    items => $items, type => 'cron'  };
 }
 
 =head2 get_all_admin_categories
 
-    Vhffs::Panel::Admin::get_all_admin_categories($vhffs);
+	Vhffs::Panel::Admin::get_all_admin_categories($vhffs);
 
 Return an arrayref of hashrefs (name, ITEM) containing all administration
 categories and items based on configuration of $vhffs.
@@ -397,35 +387,35 @@
 =cut
 
 sub get_all_admin_categories($) {
-    my $vhffs = shift;
-    my $config = $vhffs->get_config;
-    my $categories = [];
+	my $vhffs = shift;
+	my $config = $vhffs->get_config;
+	my $categories = [];
 
-    push @$categories, get_admin_category;
-    push @$categories, get_user_category;
-    push @$categories, get_group_category;
-    push @$categories, get_web_category       if($config->get_service_availability('web'));
-    push @$categories, get_mysql_category     if($config->get_service_availability('mysql'));
-    push @$categories, get_pgsql_category     if($config->get_service_availability('pgsql'));
-    push @$categories, get_cvs_category       if($config->get_service_availability('cvs'));
-    push @$categories, get_svn_category       if($config->get_service_availability('svn'));
-    push @$categories, get_dns_category       if($config->get_service_availability('dns'));
-    push @$categories, get_git_category       if($config->get_service_availability('git'));
-    push @$categories, get_mercurial_category if($config->get_service_availability('mercurial'));
-    push @$categories, get_bazaar_category    if($config->get_service_availability('bazaar'));
-    push @$categories, get_mail_category      if($config->get_service_availability('mail'));
-    push @$categories, get_mailing_category   if($config->get_service_availability('mailinglist'));
-    push @$categories, get_repo_category      if($config->get_service_availability('repository'));
-    push @$categories, get_cron_category      if($config->get_service_availability('cron'));
-    push @$categories, get_tag_category;
+	push @$categories, get_admin_category;
+	push @$categories, get_user_category;
+	push @$categories, get_group_category;
+	push @$categories, get_web_category       if($config->get_service_availability('web'));
+	push @$categories, get_mysql_category     if($config->get_service_availability('mysql'));
+	push @$categories, get_pgsql_category     if($config->get_service_availability('pgsql'));
+	push @$categories, get_cvs_category       if($config->get_service_availability('cvs'));
+	push @$categories, get_svn_category       if($config->get_service_availability('svn'));
+	push @$categories, get_dns_category       if($config->get_service_availability('dns'));
+	push @$categories, get_git_category       if($config->get_service_availability('git'));
+	push @$categories, get_mercurial_category if($config->get_service_availability('mercurial'));
+	push @$categories, get_bazaar_category    if($config->get_service_availability('bazaar'));
+	push @$categories, get_mail_category      if($config->get_service_availability('mail'));
+	push @$categories, get_mailing_category   if($config->get_service_availability('mailinglist'));
+	push @$categories, get_repo_category      if($config->get_service_availability('repository'));
+	push @$categories, get_cron_category      if($config->get_service_availability('cron'));
+	push @$categories, get_tag_category;
 
-    return $categories;
+	return $categories;
 }
 
 
 =head2 get_all_modo_categories
 
-    Vhffs::Panel::Admin::get_all_modo_categories($vhffs);
+	Vhffs::Panel::Admin::get_all_modo_categories($vhffs);
 
 Return an arrayref of hashrefs (name, ITEM) containing all administration
 categories and items based on configuration of $vhffs.
@@ -433,29 +423,85 @@
 =cut
 
 sub get_all_modo_categories($) {
-    my $vhffs = shift;
-    my $config = $vhffs->get_config;
-    my $categories = [];
+	my $vhffs = shift;
+	my $config = $vhffs->get_config;
+	my $categories = [];
 
-    push @$categories, get_modo_category;
-    push @$categories, get_user_category;
-    push @$categories, get_group_category;
-    push @$categories, get_web_category       if($config->get_service_availability('web'));
-    push @$categories, get_mysql_category     if($config->get_service_availability('mysql'));
-    push @$categories, get_pgsql_category     if($config->get_service_availability('pgsql'));
-    push @$categories, get_cvs_category       if($config->get_service_availability('cvs'));
-    push @$categories, get_svn_category       if($config->get_service_availability('svn'));
-    push @$categories, get_git_category       if($config->get_service_availability('git'));
-    push @$categories, get_mercurial_category if($config->get_service_availability('mercurial'));
-    push @$categories, get_bazaar_category    if($config->get_service_availability('bazaar'));
-    push @$categories, get_dns_category       if($config->get_service_availability('dns'));
-    push @$categories, get_mail_category      if($config->get_service_availability('mail'));
-    push @$categories, get_mailing_category   if($config->get_service_availability('mailinglist'));
-    push @$categories, get_repo_category      if($config->get_service_availability('repository'));
-    push @$categories, get_cron_category      if($config->get_service_availability('cron'));
-    push @$categories, get_tag_category;
+	push @$categories, get_modo_category;
+	push @$categories, get_user_category;
+	push @$categories, get_group_category;
+	push @$categories, get_web_category       if($config->get_service_availability('web'));
+	push @$categories, get_mysql_category     if($config->get_service_availability('mysql'));
+	push @$categories, get_pgsql_category     if($config->get_service_availability('pgsql'));
+	push @$categories, get_cvs_category       if($config->get_service_availability('cvs'));
+	push @$categories, get_svn_category       if($config->get_service_availability('svn'));
+	push @$categories, get_git_category       if($config->get_service_availability('git'));
+	push @$categories, get_mercurial_category if($config->get_service_availability('mercurial'));
+	push @$categories, get_bazaar_category    if($config->get_service_availability('bazaar'));
+	push @$categories, get_dns_category       if($config->get_service_availability('dns'));
+	push @$categories, get_mail_category      if($config->get_service_availability('mail'));
+	push @$categories, get_mailing_category   if($config->get_service_availability('mailinglist'));
+	push @$categories, get_repo_category      if($config->get_service_availability('repository'));
+	push @$categories, get_cron_category      if($config->get_service_availability('cron'));
+	push @$categories, get_tag_category;
 
-    return $categories;
+	return $categories;
 }
 
+sub main {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+	
+	$panel->set_title(gettext('Administration'));
+
+	my $categories = [];
+	if( $user->is_moderator ) { 
+		$categories = Vhffs::Panel::Admin::get_all_modo_categories($panel->{vhffs});
+	} else {
+		$categories = Vhffs::Panel::Admin::get_all_admin_categories($panel->{vhffs});
+	}
+
+	$panel->render('admin/index.tt', {
+	  categories => $categories
+	  });
+}
+
+sub su {
+	my $panel = shift;
+	return unless $panel->check_admin();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $username = $cgi->param('user');
+	if(defined $username) {
+		require Vhffs::User;
+		my $user = Vhffs::User::get_by_username( $vhffs, $username );
+		if(defined $user) {
+			$session->clear('username');
+			$session->clear('uid');
+			$session->param('username', $user->get_username);
+			$session->param('uid', $user->get_uid);
+			$session->flush();
+
+			$panel->render('misc/message.tt', {
+			  message => gettext( sprintf( 'Su successful with name %s' , $user->get_username) ),
+			  refresh_url => '?do=home'
+			  });
+			return;
+		}
+
+		$panel->add_error( gettext( sprintf( 'User %s does not exist' , $username) ) );
+	}
+
+	$panel->render('admin/misc/su.tt');
+}
+
 1;

Added: trunk/vhffs-api/src/Vhffs/Panel/Auth.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Auth.pm	                        (rev 0)
+++ trunk/vhffs-api/src/Vhffs/Panel/Auth.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -0,0 +1,184 @@
+#!%PERL%
+# Copyright (c) vhffs project and its contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#2. Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution.
+#3. Neither the name of vhffs nor the names of its contributors
+#   may be used to endorse or promote products derived from this
+#   software without specific prior written permission.
+#
+#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use utf8;
+
+package Vhffs::Panel::Auth;
+
+use POSIX qw(locale_h);
+use locale;
+use Locale::gettext;
+
+use Vhffs::Constants;
+
+sub display_login
+{
+	my $panel = shift;
+	my $vhffs = $panel->{'vhffs'};
+
+	my $hostname = $vhffs->get_config->get_host_name;
+	my $website = $vhffs->get_config->get_host_website;
+	my $cgi = $panel->{cgi};
+	my $vars = {};
+	$vars->{username} = $cgi->param('username');
+	$vars->{subscription_allowed} = $vhffs->get_config->get_allow_subscribe;
+	$vars->{website} = $website;
+	$vars->{hostname} = $hostname;
+	if( $vhffs->get_config->get_panel->{'stats_on_home'} eq 'yes' ) {
+		require Vhffs::Stats;
+		my $stats = new Vhffs::Stats( $vhffs );
+		$vars->{stats} = {
+			users => $stats->get_user_total,
+			groups => $stats->get_groups_activated
+		};
+	}
+	$vars->{version_info} = {
+		version => Vhffs::Constants::VHFFS_VERSION,
+		name => Vhffs::Constants::VHFFS_RELEASE_NAME
+	};
+
+	$panel->render( 'anonymous/login.tt', $vars, 'anonymous.tt' );
+}
+
+sub login {
+
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $loginsubmitted = defined( $cgi->param('login_submit') );
+
+	if( $loginsubmitted ) {
+		# User tried to log in
+		# we try to clean the previous session
+		my $oldsid = $cgi->cookie( CGI::Session::name() );
+		if( defined $oldsid ) {
+			my $oldsession = new CGI::Session(undef, $oldsid, {Directory=>'/tmp'});
+			$oldsession->delete();
+		}
+	
+		my $username = $cgi->param('username');
+		my $password = $cgi->param('password');
+		my $user = Vhffs::User::get_by_username($vhffs, $username) if defined $username;
+	
+		#Incomplete input
+		unless( defined $username  &&  defined $password  &&  defined $user  &&  $user->check_password( $password ) ) {
+			$panel->add_error( gettext('Login failed !') );
+		} elsif($user->get_status != Vhffs::Constants::ACTIVATED) {
+			$panel->add_error( gettext('User is not active yet') );
+		} else {
+			# Creates the new session
+			my $session = new CGI::Session('driver:File', undef, {Directory=>'/tmp'});
+			$session->expires('+1h');
+			$session->param('username', $user->get_username);
+			$session->param('uid', $user->get_uid);
+	
+			my $sessioncookie = new CGI::Cookie(-name => $session->name, -value => $session->id);
+	
+			# Refresh cookies (avoid theme and language loss when user deletes cookies).
+			my $themecookie = new CGI::Cookie( -name=> 'theme', -value=>$user->get_theme, -expires=>'+10y' );
+			my $langcookie = new CGI::Cookie( -name=>'language', -value=>$user->get_lang, -expires=>'+10y' );
+	
+			# Set last login panel to current time
+			$user->update_lastloginpanel;
+			$user->commit;
+
+			$panel->redirect('?do=home', [$sessioncookie, $themecookie, $langcookie]);
+		}
+	}
+	
+	display_login( $panel ) if not $loginsubmitted or $panel->has_errors;
+}
+
+sub logout {
+
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+
+	#clean session
+	my $oldsid = $cgi->cookie( CGI::Session::name() );
+	if( defined $oldsid )  {
+		my $oldsession = new CGI::Session(undef, $oldsid, {Directory=>'/tmp'});
+		$oldsession->delete();
+	}
+
+	$panel->add_info( gettext('You left your VHFFS session!') );
+
+	display_login( $panel );
+}
+
+sub lost {
+
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+
+	my $lostsubmitted = defined( $cgi->param('lost_submit') );
+
+	unless( $lostsubmitted ) {
+		$panel->render('anonymous/lost-password.tt', undef, 'anonymous.tt');
+		return;
+	}
+
+	# username submitted
+	my $username = $cgi->param('username');
+	my $user = Vhffs::User::get_by_username( $vhffs, $username );
+	if( defined $user and $user->{'state'} == Vhffs::Constants::ACTIVATED )  {
+
+		# create a new password for this user
+		my $password = Vhffs::Functions::generate_random_password;
+		$user->set_password( $password );
+		$user->commit;
+
+		my $mu = init Vhffs::Services::MailUser( $vhffs, $user );
+		$mu->changepassword( $password ) if defined $mu and $mu->exists_box;
+  
+		# Send a mail with plain text password inside
+		my $subject = sprintf('Password changed on %s', $vhffs->get_config->get_host_name );
+		my $content = sprintf("Hello %s %s,\n\nYou asked for a new password, here are your new login information:\nUser: %s\nPassword: %s\n\n%s Administrators\n", $user->get_firstname, $user->get_lastname, $user->get_username, $password , $vhffs->get_config->get_host_name );
+		$user->send_mail_user( $subject, $content );
+    
+		$panel->render('anonymous/lost-password-ack.tt',
+		  { message => sprintf( gettext('Please wait %s, a new password will be sent to you in a few minutes...'), $username ) },
+		  'anonymous.tt' );
+	}
+	else {
+		$panel->render('anonymous/lost-password-ack.tt',
+		  { message => gettext('Password recovery failed!') },
+		  'anonymous.tt' );
+	}
+}
+
+1;

Modified: trunk/vhffs-api/src/Vhffs/Panel/Avatar.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Avatar.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/Avatar.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -29,60 +29,55 @@
 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 # POSSIBILITY OF SUCH DAMAGE.
 
-package Vhffs::Panel::Avatar;
-
 use strict;
 use utf8;
 
+package Vhffs::Panel::Avatar;
+
+use POSIX qw(locale_h);
+use locale;
+use Locale::gettext;
+use Encode;
+use GD;
+use GD::Text::Wrap;
+
+use Vhffs::Constants;
 use Vhffs::Functions;
 use Digest::MD5 qw(md5_hex);
 
-sub store_avatar
-{
+sub store_avatar {
 	my $vhffs = shift;
 	my $object = shift;
-    my $file = shift;
+	my $file = shift;
 	my $type = shift;
-    my $config = $vhffs->get_config;
-    my $datadir = $config->get_datadir . "/avatar";
-	my $dir;
+	my $config = $vhffs->get_config;
+	my $datadir = $config->get_datadir . '/avatar';
 	my $oid = $object->get_oid;
-	my $path;
-	my $digest;
-	my $buffer;
 
-    if( ! -d $datadir )
-    {
-        return -1;
-    }
-    else
-    {
-		$digest = md5_hex( $oid );
-		$dir = $datadir . "/" . substr( $digest , 0 , 2 ) . "/" . substr( $digest , 2 , 2 ) . "/" .substr( $digest , 4 , 2 );
-		$path = $dir . "/" .$oid;
+	return -1 unless -d $datadir;
 
-#		$path .= ".".$type if( defined $type );
+	my $digest = md5_hex( $oid );
+	my $dir = $datadir.'/'.substr( $digest , 0 , 2 ).'/'.substr( $digest , 2 , 2 ).'/'.substr( $digest , 4 , 2 );
+	my $path = $dir.'/'.$oid;
+#	$path .= ".".$type if( defined $type );
 
-		Vhffs::Functions::create_dir( $dir );
-		open FORIG , "$file" or return -2;
-		open FCOPY , ">$path" or return -3;
+	Vhffs::Functions::create_dir( $dir );
 
-		binmode( FCOPY );
-		while( read( FORIG , $buffer , 1024 ) )
-		{
-			print FCOPY $buffer;
-		}
+	open( my $forig, '<', $file ) or return -2;
+	open( my $fcopy, '>', $path ) or return -3;
 
-		close( FCOPY ) or return( -4 );
-		close( FORIG ) or return( -4 );
+	my $buffer;
+	binmode( $fcopy );
+	while( read( $forig , $buffer , 1024 ) ) {
+		print $fcopy $buffer;
+	}
 
-		
-    }
+	close( $fcopy );
+	close( $forig );
 	return 1;
 }
 
-sub exists_avatar
-{
+sub exists_avatar {
 	my $vhffs = shift;
 	my $object = shift;
 
@@ -95,6 +90,166 @@
 	return $path;
 }
 
+sub get {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $oid	= $cgi->param( 'oid' );
+	unless( defined $oid ) {
+		$panel->render('misc/message.tt', { message => gettext( 'CGI Error !' ) } );
+		return;
+	}
+
+	unless( $panel->use_avatars ) {
+		$panel->render('misc/message.tt', { message => gettext('This platform does not provide avatar support') } );
+		return;
+	}
+
+	my $object = Vhffs::Object::get_by_oid( $vhffs , $oid );
+	unless( defined $object ) {
+		$panel->render('misc/message.tt', { message => gettext('Cannot get informations on this object') } );
+		return;
+	}
+
+	# Assume the user has set FONT_PATH or TTF_FONT_PATH
+	#$wp->font_path('/usr/share/fonts/ttfonts');
+	print $cgi->header( -type=>'image/png' );
+	binmode STDOUT;
+
+	my $path = exists_avatar( $vhffs , $object );
+	if( $path and open ( my $forig , '<', $path ) ) {
+		my $buf;
+		while( read( $forig , $buf , 1024 ) ) {
+			print STDOUT $buf;
+		}
+		close( $forig );
+
+	} else {
+		my $gd = GD::Image->new(70,100);
+		my $white = $gd->colorAllocate(255,255,255);
+		my $black = $gd->colorAllocate(  0,  0,  0);
+		my $blue  = $gd->colorAllocate(127,127,255);
+		my $wp = GD::Text::Wrap->new($gd,
+			width       => 70,
+			line_space  => 0,
+			color       => $black, 
+			text        => 'No avatar',
+		);
+		$wp->set_font(GD::Font->Large, 14);
+		$wp->set(align => 'center');
+		$wp->draw(0,5);
+		$wp->set(para_space => 10, preserve_nl => 0);
+		print STDOUT $gd->png();
+	}
+
+	close STDOUT;
+}
+
+sub put {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $oid = $cgi->param( 'oid' );
+	my $filename = $cgi->param( 'avatar' );
+	my $tmpfile = $cgi->tmpFileName( $filename ) if defined $filename;
+	unless( defined $oid and defined $filename and defined $tmpfile and -f $tmpfile ) {
+		$panel->render('misc/message.tt', { message => gettext( 'CGI Error !' ) } );
+		goto PUTEND;
+	}
+
+	unless( $panel->use_avatars ) {
+		$panel->render('misc/message.tt', { message => gettext('This platform does not provide avatar support') } );
+		goto PUTEND;
+	}
+
+	my $object = Vhffs::Object::get_by_oid( $vhffs , $oid );
+	unless( defined $object ) {
+		$panel->render('misc/message.tt', { message => gettext('Cannot get informations on this object') } );
+		goto PUTEND;
+	}
+
+	unless( $user->can_modify( $object ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) } );
+		goto PUTEND;
+	}
+
+	unless( $filename =~ /\.[Pp][Nn][Gg]$/ ) {
+		$panel->render('misc/message.tt', { message => gettext( 'Filetype not supported, only png is supported' ) } );
+		goto PUTEND;
+	}
+
+	my (undef, undef ,undef ,undef ,undef ,undef, undef, $fsize, undef, undef, undef, undef, undef) = stat( $tmpfile );
+	unless( $fsize < 200000 ) {
+		$panel->render('misc/message.tt', { message => gettext( 'Uploaded file is too big. The maximum size is 200 kbytes' ) } );
+		goto PUTEND;
+	}
+
+	my ( $type ) = ( $filename =~ ( /\.([a-zA-Z]+)$/ ) );
+	my $avatar = store_avatar( $vhffs, $object, $tmpfile, $type );
+	if( $avatar < 0 ) {
+		$panel->render('misc/message.tt', { message => gettext( 'Error when uploading avatar for this object' ) } );
+		goto PUTEND;
+	}
+
+	$panel->render('misc/message.tt', { message => gettext( 'Successfully created or updated avatar' ) } );
+
+PUTEND:
+	unlink $tmpfile if defined $tmpfile and -f $tmpfile;
+	return;
+}
+
+sub delete {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $oid = $cgi->param( 'oid' );
+	unless( defined $oid ) {
+		$panel->render('misc/message.tt', { message => gettext( 'CGI Error !' ) } );
+		return;
+	}
+
+	unless( $panel->use_avatars ) {
+		$panel->render('misc/message.tt', { message => gettext('This platform does not provide avatar support') } );
+		return;
+	}
+
+	my $object = Vhffs::Object::get_by_oid( $vhffs , $oid );
+	unless( defined $object ) {
+		$panel->render('misc/message.tt', { message => gettext('Cannot get informations on this object') } );
+		return;
+	}
+
+	unless( $user->can_modify( $object ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) } );
+		return;
+	}
+
+	my $path = exists_avatar( $vhffs , $object );
+	unless( defined $path ) {
+		$panel->render('misc/message.tt', { message => gettext( 'This object does not have an avatar' ) } );
+		return;
+	}
+
+	unless( unlink $path ) {
+		$panel->render('misc/message.tt', { message => gettext( 'Cannot delete this avatar' ) } );
+		return;
+	}
+
+	$panel->render('misc/message.tt', { message => gettext( 'Avatar deleted' ) } );
+}
+
 1;
 
 

Modified: trunk/vhffs-api/src/Vhffs/Panel/Bazaar.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Bazaar.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/Bazaar.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -55,73 +55,291 @@
 =cut
 
 
-sub getall_per_group
-{
-    my ( $main, $gid ) = @_;
+sub getall_per_group {
+	my ( $main, $gid ) = @_;
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT s.object_id AS oid, s.reponame AS displayname, o.state FROM vhffs_bazaar s INNER JOIN vhffs_object o ON s.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY s.reponame';
-    my $sth = $dbh->prepare($sql) or return -1;
-    $sth->execute($gid) or return -2;
-    my $bazaar = [];
-    while(my $s = $sth->fetchrow_hashref) {
-        $s->{active} = ($s->{state} == Vhffs::Constants::ACTIVATED);
-        $s->{refused} = ($s->{state} == Vhffs::Constants::VALIDATION_REFUSED);
-        $s->{state} = Vhffs::Functions::status_string_from_status_id($s->{state});
-        push @$bazaar, $s;
-    }
-    return $bazaar;
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT s.object_id AS oid, s.reponame AS displayname, o.state FROM vhffs_bazaar s INNER JOIN vhffs_object o ON s.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY s.reponame';
+	my $sth = $dbh->prepare($sql) or return -1;
+	$sth->execute($gid) or return -2;
+	my $bazaar = [];
+	while(my $s = $sth->fetchrow_hashref) {
+		$s->{active} = ($s->{state} == Vhffs::Constants::ACTIVATED);
+		$s->{refused} = ($s->{state} == Vhffs::Constants::VALIDATION_REFUSED);
+		$s->{state} = Vhffs::Functions::status_string_from_status_id($s->{state});
+		push @$bazaar, $s;
+	}
+	return $bazaar;
 }
 
 sub get_repos_per_group {
-    my ($main, $gid, $public_only) = @_;
-    $public_only = 1 unless(defined $public_only);
+	my ($main, $gid, $public_only) = @_;
+	$public_only = 1 unless(defined $public_only);
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT g.reponame, o.description FROM vhffs_bazaar g INNER JOIN vhffs_object o ON o.object_id = g.object_id '.
-	'WHERE '.($public_only ? 'public = 1 AND ' : '').'o.owner_gid = ? AND o.state = ?';
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, $gid, Vhffs::Constants::ACTIVATED);
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT g.reponame, o.description FROM vhffs_bazaar g INNER JOIN vhffs_object o ON o.object_id = g.object_id '.
+	  'WHERE '.($public_only ? 'public = 1 AND ' : '').'o.owner_gid = ? AND o.state = ?';
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, $gid, Vhffs::Constants::ACTIVATED);
 }
 
+sub search_bazaar {
+	my ($main, $name) = @_;
 
-sub search {
-    my ($main, $name) = @_;
+	my @params;
+	my $sql = 'SELECT bazaar.reponame as label, g.groupname as owner_group, o.state, u.username as owner_user '.
+	  'FROM vhffs_bazaar bazaar '.
+	  'INNER JOIN vhffs_object o ON (o.object_id = bazaar.object_id) '.
+	  'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
+	  'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
 
-    my @params;
-    my $sql = 'SELECT bazaar.reponame as label, g.groupname as owner_group, o.state, u.username as owner_user '.
-        'FROM vhffs_bazaar bazaar '.
-        'INNER JOIN vhffs_object o ON (o.object_id = bazaar.object_id) '.
-        'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
-        'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
+	if( defined $name ) {
+		$sql .= 'WHERE bazaar.reponame LIKE ? ';
+		push(@params, '%'.lc($name).'%');
+	}
 
-    if( defined $name ) {
-        $sql .= 'WHERE bazaar.reponame LIKE ? ';
-        push(@params, '%'.lc($name).'%');
-    }
+	$sql .= 'ORDER BY bazaar.reponame';
 
-    $sql .= 'ORDER BY bazaar.reponame';
+	my $dbh = $main->get_db_object();
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
+}
 
-    my $dbh = $main->get_db_object();
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
+sub create_bazaar {
+	my ($main, $repo, $description, $user, $group) = @_;
+	return -1 unless defined $user;
+	return -2 unless defined $group;
+    
+	my $bazaar = Vhffs::Services::Bazaar::create( $main, $repo, $description, $user, $group );
+	return -1 unless defined $bazaar;
+    
+	return -3 if Vhffs::Acl::add_acl( $user , $bazaar , Vhffs::Constants::ACL_DELETE , $main ) < 0;
+	return -3 if Vhffs::Acl::add_acl( $group , $bazaar , Vhffs::Constants::ACL_VIEW , $main ) < 0;
+    	return $bazaar;
 }
 
+sub create {
+	my $panel = shift;
 
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
 
-sub create_bazaar
-{
-    my ($main, $repo, $description, $user, $group) = @_;
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group and $user->can_modify( $group ) ) {
+		$panel->render('message/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+	$panel->set_group( $group );
 
-    return -1 unless( defined $user );
-    return -2 unless( defined $group );
-    
-    my $bazaar = Vhffs::Services::Bazaar::create( $main, $repo, $description, $user, $group );
-    
-    return -1 unless( defined $bazaar );
-    
-    return ( -3 ) if ( Vhffs::Acl::add_acl( $user , $bazaar , Vhffs::Constants::ACL_DELETE , $main ) < 0 );
-    return ( -3 ) if( Vhffs::Acl::add_acl( $group , $bazaar , Vhffs::Constants::ACL_VIEW , $main ) < 0 );
-    
-    return $bazaar;
+	my $submitted = $cgi->param('bazaar_submit');
+	my $reponame = '';
+	my $description = '';
+	my $vars = {};
+
+	if( $submitted ) {
+		$reponame = $cgi->param('reponame');
+		my $fullreponame = $group->get_groupname.'/'.$reponame;
+		$description = Encode::decode_utf8( $cgi->param('description') );
+		unless( defined $reponame and defined $description ) {
+			$panel->add_error( gettext('CGI Error !') );
+		} else {
+			$panel->add_error( gettext('Invalid reponame. It must contain between 3 and 64 characters, only lowercase letters and numbers') ) unless Vhffs::Services::Bazaar::check_name($fullreponame);
+			$panel->add_error( gettext('You must enter a description') ) unless $description !~ /^\s*$/;
+		}
+
+		unless( $panel->has_errors() ) {
+			my $bazaar = Vhffs::Panel::Bazaar::create_bazaar( $vhffs, $fullreponame, $description, $user, $group );
+			if( defined $bazaar ) {
+				my $url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('The Bazaar object was successfully created !');
+				$panel->redirect($url);
+				return;
+			}
+
+			$panel->add_error( gettext('An error occured while creating the bazaar repository') );
+		}
+
+		$vars->{reponame} = $reponame;
+		$vars->{description} = $description;
+	}
+
+	$vars->{group} = $group;
+	$panel->render('bazaar/create.tt', $vars);
 }
 
+sub prefs {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $repo_name = $cgi->param('name');
+	unless( defined $repo_name ) {
+		$panel->render('misc/message.tt', { message => gettext( 'CGI Error !' ) } );
+		return;
+	}
+
+	my $bazaar = Vhffs::Services::Bazaar::get_by_reponame( $vhffs , $repo_name );
+	unless( defined $bazaar ) {
+		$panel->render('misc/message.tt', { message => gettext( 'Cannot get informations on this object' ) } );
+		return;
+	}
+
+	unless( $user->can_view( $bazaar ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) } );
+		return;
+	}
+
+	save_prefs($panel, $bazaar) if defined $cgi->param('save_prefs_submit');
+
+	$panel->set_title( gettext("Modify Bazaar repository") );
+	my $vars = {};
+	$vars->{repository} = $bazaar;
+	$vars->{notify_from} = 'Please finish bazaar implementation'; # $vhffs->get_config->get_service('bazaar')->{notify_from};
+	$vars->{type} = 'bazaar';
+	$panel->render( 'scm/prefs.tt', $vars );
+}
+
+sub save_prefs {
+	my $panel = shift;
+	my $bazaar = shift;
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
+
+	my $public = $cgi->param('public');
+	my $ml_name = $cgi->param('ml_name');
+
+	unless( $user->can_modify($bazaar) ) {
+		$panel->add_error( gettext('You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights') );
+		return 0;
+	}
+
+	unless( defined $public and defined $ml_name ) {
+		$panel->add_error( gettext('CGI error !') );
+		return 0;
+	}
+
+	if($public != $bazaar->is_public) {
+		if($public == 1) {
+			$bazaar->set_public();
+		} else {
+			$bazaar->set_private();
+		}
+		$bazaar->set_status(Vhffs::Constants::WAITING_FOR_MODIFICATION);
+	}
+
+	if($ml_name =~ /^\s*$/ or Vhffs::Functions::valid_mail($ml_name)) {
+		if($ml_name ne $bazaar->get_ml_name) {
+			$bazaar->set_ml_name($ml_name);
+			$bazaar->set_status( Vhffs::Constants::WAITING_FOR_MODIFICATION );
+		}
+	} else {
+		$panel->add_error( gettext('Invalid mailing list address') );
+		return 0;
+	}
+
+	if($bazaar->get_status == Vhffs::Constants::WAITING_FOR_MODIFICATION) {
+		if($bazaar->commit > 0) {
+			my $group = Vhffs::Group::get_by_gid( $vhffs , $bazaar->{'owner_gid'} );
+			my $url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('Modifications applied. Please wait while your repository is being updated');
+			$panel->redirect($url);
+			return 1;
+		}
+
+		$panel->add_error( gettext('Unable to apply modifications') );
+		return 0;
+	}
+
+	return 0;
+}
+
+sub index {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group ) {
+		$panel->render('misc/message.tt', { message => gettext('You have to select a group first') } );
+		return;
+	}
+
+	unless($group->get_status == Vhffs::Constants::ACTIVATED) {
+		$panel->render( 'misc/message.tt', { message => gettext('This group is not activated yet') } );
+		return;
+	}
+
+	unless( $user->can_view( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+
+	$panel->set_group( $group );
+	$panel->set_title( sprintf(gettext('Bazaar repositories for %s'), $group->get_groupname) );
+	my $bazaar = Vhffs::Panel::Bazaar::getall_per_group( $vhffs, $group->get_gid );
+	if($bazaar < 0) {
+		$panel->render('misc/message.tt', { message => gettext('Unable to get Bazaar repositories') } );
+		return;
+	}
+
+	$panel->render( 'misc/service-index.tt', {
+	  label => 'Bazaar repositories',
+	  group => $group,
+	  list => $bazaar,
+	  help_url => 'Finish implementation', # $vhffs->get_config->get_service('bazaar')->{url_doc},
+	  type => 'bazaar'
+	  });
+}
+
+sub search {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $name = $cgi->param('name');
+	my $vars = {};
+
+	unless( defined $name ) {
+
+		$panel->render('admin/misc/search.tt', {
+		  search_title => gettext('Bazaar search'),
+		  type => 'bazaar'
+		  });
+		return;
+	}
+
+	if( $name =~ /^\s*$/ ) {
+		$vars->{list_title} = gettext('List of all bazaar repositories');
+		undef $name;
+	} else {
+		$vars->{list_title} = sprintf( gettext('Search result for %s'), $name );
+	}
+	$vars->{list} = search_bazaar( $vhffs , $name );
+	$vars->{type} = 'bazaar';
+	$panel->render('admin/misc/list.tt', $vars);
+}
+
+sub adminindex {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	$panel->set_title(gettext('Bazaar repositories administration'));
+	require Vhffs::Panel::Admin;
+	$panel->render('admin/index.tt', { categories => [ Vhffs::Panel::Admin::get_bazaar_category() ] } );
+}
+
 1;

Copied: trunk/vhffs-api/src/Vhffs/Panel/Broadcast.pm (from rev 1916, trunk/vhffs-api/src/Vhffs/Panel/Mailings.pm)
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Broadcast.pm	                        (rev 0)
+++ trunk/vhffs-api/src/Vhffs/Panel/Broadcast.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -0,0 +1,188 @@
+#!%PERL%
+# Copyright (c) vhffs project and its contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without 
+# modification, are permitted provided that the following conditions 
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright 
+#   notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in 
+#    the documentation and/or other materials provided with the 
+#    distribution.
+# 3. Neither the name of vhffs nor the names of its contributors 
+#    may be used to endorse or promote products derived from this 
+#    software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+# POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use utf8;
+
+package Vhffs::Panel::Broadcast;
+
+use POSIX qw(locale_h);
+use locale;
+use Locale::gettext;
+use Encode;
+
+use Vhffs::Broadcast;
+
+sub broadcast_list {
+	my ($main) = @_;
+
+	my $sql = 'SELECT id_mailing as id, subject, message as body, date, state '.
+	  'FROM vhffs_mailings m '.
+	  'ORDER BY m.date DESC';
+
+	my $dbh = $main->get_db_object();
+	return $dbh->selectall_arrayref($sql, { Slice => {} });
+}
+
+sub create {
+	my $panel = shift;
+	return unless $panel->check_admin();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $subject = $cgi->param('subject');
+	my $body = $cgi->param('body');
+	my $vars = {};
+
+	if(defined $subject and defined $body) {
+		$panel->add_error( gettext('You have to enter a subject') ) unless $subject =~ /\S/;
+		$panel->add_error( gettext('You have to enter a message body') ) unless $body =~ /\S/;
+
+		unless( $panel->has_errors ) {
+			if( Vhffs::Broadcast::add_broadcast( $vhffs , $subject , $body ) == 1 ) {
+				$panel->render('misc/message.tt',  {
+				  message => gettext('Mailing successfully added'),
+				  refresh_url => '?do=broadcastlist'
+				  });
+				return;
+			}
+
+			$panel->add_error( gettext('Error while queuing mailing') );
+		}
+
+		$vars->{subject} = $subject;
+		$vars->{body} = $body;
+	}
+
+	$panel->render('admin/broadcast/create.tt', $vars);
+}
+
+sub list {
+	my $panel = shift;
+	return unless $panel->check_admin();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $vars = {};
+
+	my $mailings = broadcast_list( $vhffs );
+	foreach my $m(@$mailings) {
+		if($m->{state} == 3) {
+			$m->{state} = gettext('Awaiting sending');
+		} elsif($m->{state} == 6) {
+			$m->{state} = gettext('Sent');
+		} else {
+			$m->{state} = gettext('Unknown');
+	}
+	}
+
+	$vars->{mailings} = $mailings;
+	$panel->render('admin/broadcast/list.tt', $vars);
+}
+
+sub view {
+	my $panel = shift;
+	return unless $panel->check_admin();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $mid = $cgi->param('mid');
+	unless( defined $mid ) {
+		$panel->render('misc/message.tt', {
+		  message => gettext('CGI Error'),
+		  refresh_url => '?do=broadcastlist'
+		  });
+		return;
+	}
+	my $mailing = Vhffs::Broadcast::get_broadcast( $vhffs , $mid );
+	unless( defined $mailing) {
+		$panel->render('misc/message.tt', {
+		  message => gettext('Mailing not found'),
+		  refresh_url => '?do=broadcastlist'
+		  });
+		return;
+	}
+
+	if($mailing->{state} == 3) {
+		$mailing->{state} = gettext('Awaiting sending');
+	} elsif($mailing->{state} == 6) {
+		$mailing->{state} = gettext('Sent');
+	} else {
+		$mailing->{state} = gettext('Unknown');
+	}
+
+	$panel->render('admin/broadcast/view.tt', {
+	  mailing => $mailing
+	  });
+}
+
+sub delete {
+	my $panel = shift;
+	return unless $panel->check_admin();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $mid = $cgi->param('mid');
+	unless( defined $mid ) {
+		$panel->render('misc/message.tt', {
+		  message => gettext('CGI Error'),
+		  refresh_url => '?do=broadcastlist'
+		  });
+		return;
+	}
+
+	unless( Vhffs::Broadcast::del_broadcast( $vhffs , $mid ) == 1 ) {
+		$panel->render('misc/message.tt', {
+		  message => gettext('An error occured while deleting this mailing')
+		  });
+		return;
+	}
+
+	$panel->render('misc/message.tt', {
+	  message => gettext('Mailing successfully deleted'),
+	  refresh_url => '?do=broadcastlist'
+	  });
+}
+
+
+1;

Modified: trunk/vhffs-api/src/Vhffs/Panel/Commons.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Commons.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/Commons.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -40,34 +40,6 @@
 
 use Vhffs::Constants;
 
-sub display_login
-{
-    my ($vhffs, $panel) = @_;
-
-    my $hostname = $vhffs->get_config->get_host_name;
-    my $website = $vhffs->get_config->get_host_website;
-    my $cgi = $panel->{cgi};
-    my $vars = {};
-    $vars->{username} = $cgi->param('username');
-    $vars->{subscription_allowed} = $vhffs->get_config->get_allow_subscribe;
-    $vars->{website} = $website;
-    $vars->{hostname} = $hostname;
-    if( $vhffs->get_config->get_panel->{'stats_on_home'} eq 'yes' ) {
-        require Vhffs::Stats;
-        my $stats = new Vhffs::Stats( $vhffs );
-        $vars->{stats} = {
-            users => $stats->get_user_total,
-            groups => $stats->get_groups_activated
-        };
-    }
-    $vars->{version_info} = {
-        version => Vhffs::Constants::VHFFS_VERSION,
-        name => Vhffs::Constants::VHFFS_RELEASE_NAME
-    };
-
-    $panel->render( 'anonymous/login.tt', $vars, 'anonymous.tt' );
-}
-
 =head2 paginate
 
     Vhffs::Panel::Commons::paginate($template, $current_page, $total_count, $items_per_page, $url_params);

Added: trunk/vhffs-api/src/Vhffs/Panel/Contact.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Contact.pm	                        (rev 0)
+++ trunk/vhffs-api/src/Vhffs/Panel/Contact.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -0,0 +1,75 @@
+#!%PERL%
+# Copyright (c) vhffs project and its contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#2. Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution.
+#3. Neither the name of vhffs nor the names of its contributors
+#   may be used to endorse or promote products derived from this
+#   software without specific prior written permission.
+#
+#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use utf8;
+
+package Vhffs::Panel::Contact;
+
+use POSIX qw(locale_h);
+use locale;
+use Locale::gettext;
+use Encode;
+use Vhffs::Functions;
+
+sub contact {
+
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	unless( defined $cgi->param('contact_submit') ) {
+		$panel->render('misc/alert.tt');
+		return;
+	}
+
+	my $vars = {};
+
+	if( defined  $cgi->param('subject') and defined $cgi->param('message') ) {
+		my $to = $vhffs->get_config->get_alert_mail;
+		my $from = $user->get_mail;
+		my $subject = Encode::decode_utf8( $cgi->param('subject') );
+		my $message = gettext('Message sent by the following account').': '.$user->get_username."\n\n".Encode::decode_utf8( $cgi->param('message') );
+
+		Vhffs::Functions::send_mail( $vhffs , $from , $to , undef , $subject , $message );
+		$vars->{message} = gettext('Message sent successfully');
+	}
+	else  {
+		$vars->{message} = gettext('Cannot send message, CGI error...');
+	}
+
+	$panel->render('misc/message.tt', $vars);
+}
+
+1;

Modified: trunk/vhffs-api/src/Vhffs/Panel/Cron.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Cron.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/Cron.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -52,8 +52,7 @@
 
 =cut
 
-sub getall_per_group
-{
+sub getall_per_group {
 	my ( $main, $gid ) = @_;
 
 	my $dbh = $main->get_db_object;
@@ -70,39 +69,251 @@
 	return $crons;
 }
 
-sub search {
+sub search_cron {
 	my ($main, $name) = @_;
 
 	my @params;
-    my $sql = 'SELECT cron.cronpath as label, g.groupname as owner_group, o.state, u.username as owner_user '.
-        'FROM vhffs_cron cron '.
-        'INNER JOIN vhffs_object o ON (o.object_id = cron.object_id) '.
-        'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
-        'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
+	my $sql = 'SELECT cron.cronpath as label, g.groupname as owner_group, o.state, u.username as owner_user '.
+	  'FROM vhffs_cron cron '.
+	  'INNER JOIN vhffs_object o ON (o.object_id = cron.object_id) '.
+	  'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
+	  'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
 
 	if( defined $name ) {
-        $sql .= 'WHERE cron.cronpath LIKE ? ';
+		$sql .= 'WHERE cron.cronpath LIKE ? ';
 		push(@params, '%'.lc($name).'%');
 	}
 
-    $sql .= 'ORDER BY cron.cronpath';
+	$sql .= 'ORDER BY cron.cronpath';
 
 	my $dbh = $main->get_db_object();
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
 }
 
-
-sub create_cron
-{
+sub create_cron {
 	my( $main , $cronpath , $interval , $reportmail , $description , $user , $group ) = @_;
 
 	my $cron = Vhffs::Services::Cron::create( $main , $cronpath , $interval , $reportmail , $description, $user , $group );
 	return undef unless defined $cron;
 
-	return undef if( Vhffs::Acl::add_acl( $user , $cron , Vhffs::Constants::ACL_DELETE , $main ) < 0 );
-	return undef if( Vhffs::Acl::add_acl( $group , $cron , Vhffs::Constants::ACL_VIEW , $main ) < 0 );
+	return undef if Vhffs::Acl::add_acl( $user , $cron , Vhffs::Constants::ACL_DELETE , $main ) < 0;
+	return undef if Vhffs::Acl::add_acl( $group , $cron , Vhffs::Constants::ACL_VIEW , $main ) < 0;
 
 	return $cron;
 }
 
+sub create {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group and $user->can_modify( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+	$panel->set_group( $group );
+
+	my $submitted = defined $cgi->param('cron_submit');
+	my $cronpath = '';
+	my $interval = '';
+	my $reportmail = '';
+	my $description = '';
+	my $vars = {};
+
+	if( $submitted ) {
+		$cronpath = $cgi->param('cronpath');
+		$interval = $cgi->param('interval');
+		$reportmail = $cgi->param('reportmail');
+		$description = Encode::decode_utf8( $cgi->param('description') );
+
+		unless( defined $cronpath and defined $interval and defined $reportmail and defined $description ) {
+			$panel->add_error( gettext('CGI Error !') );
+			return;
+		} else {
+			$panel->add_error( gettext('You must enter a description') ) unless $description !~ /^\s*$/;
+			$panel->add_error( gettext('Invalid cronpath, it must contain only letters, numbers, underscore, dash, dot or slash. A valid cronpath will be something like /home/group/script.sh)') ) unless Vhffs::Services::Cron::check_cronpath($cronpath);
+			$panel->add_error( gettext('Invalid interval, it must be a positive integer') ) unless $interval =~ /^\d+$/ and $interval > 0;
+			$panel->add_error( gettext('The email you entered fails syntax check') ) unless( ($reportmail eq '') or Vhffs::Functions::valid_mail( $reportmail ) );
+		}
+
+		unless( $panel->has_errors() ) {
+			my $mail = Vhffs::Panel::Cron::create_cron($vhffs, $cronpath, $interval*60, $reportmail , $description, $user, $group);
+			if( defined $mail ) {
+				my $url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('The Cron job was successfully created !');
+				$panel->redirect($url);
+				return;
+			}
+
+			$panel->add_error( 'An error occured while creating the object.' );
+		}
+
+		$vars->{cronpath} = $cronpath;
+		$vars->{interval} = $interval;
+		$vars->{reportmail} = $reportmail;
+		$vars->{description} = $description;
+	}
+
+	$vars->{group} = $group;
+	$vars->{default_interval} = $vhffs->get_config->get_service('cron')->{minimum_interval};
+	$panel->set_title( gettext('Create a Cron job') );
+	$panel->render('cron/create.tt', $vars);
+}
+
+sub prefs {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $cronpath = $cgi->param('name');
+	unless( defined $cronpath ) {
+		$panel->render('misc/message.tt', { message => gettext( 'CGI Error !' ) } );
+		return;
+	}
+
+	my $cron = Vhffs::Services::Cron::get_by_cronpath( $vhffs , $cronpath );
+	unless( defined $cron ) {
+		$panel->render('misc/message.tt', { message => gettext('Cannot get informations on this object') } );
+		return;
+	}
+
+	unless( $user->can_view($cron) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) } );
+		return;
+	}
+
+	save_prefs($panel, $cron) if defined $cgi->param('save_prefs_submit');
+
+	my $vars = { cron => $cron };
+
+	$panel->set_title( gettext("Cron job Administration") );
+	$panel->render('cron/prefs.tt', $vars);
+}
+
+sub save_prefs {
+	my $panel = shift;
+	my $cron = shift;
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
+
+	unless( $user->can_modify($cron) ) {
+		$panel->add_error( gettext('You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights') );
+		return;
+	}
+
+	my $interval = $cgi->param('interval');
+	my $reportmail = $cgi->param('reportmail');
+	unless( defined $interval and defined $reportmail ) {
+		$panel->add_error( gettext('CGI Error !') );
+		return;
+	}
+
+	$cron->set_interval( $interval*60 );
+	if( $cron->set_reportmail( $reportmail ) ) {
+		$panel->add_error( gettext('The email you entered fails syntax check') );
+		return;
+	}
+
+	if( $cron->commit < 0)  {
+		$panel->add_error( gettext('Unable to apply changes') );
+		return;
+	}
+
+	$panel->add_info( gettext('Cron job successfully updated') );
+}
+
+sub index {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group ) {
+		$panel->render('misc/message.tt', { message => gettext('You have to select a group first') } );
+		return;
+	}
+
+	unless($group->get_status == Vhffs::Constants::ACTIVATED) {
+		$panel->render( 'misc/message.tt', { message => gettext('This group is not activated yet') } );
+		return;
+	}
+
+	unless( $user->can_view($group) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+
+	$panel->set_group( $group );
+	$panel->set_title( sprintf(gettext('Cron jobs for %s'), $group->get_groupname) );
+	my $crons = Vhffs::Panel::Cron::getall_per_group( $vhffs, $group->get_gid );
+	if($crons < 0) {
+		$panel->render('misc/message.tt', { message => gettext('Unable to get cron jobs') } );
+		return;
+	}
+
+	$panel->render( 'misc/service-index.tt', {
+	  label => 'Cron jobs',
+	  group => $group,
+	  list => $crons,
+	  help_url => $vhffs->get_config->get_service('cron')->{url_doc},
+	  type => 'cron'
+	  });
+}
+
+sub search {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $name = $cgi->param('name');
+	my $vars = {};
+
+	unless( defined $name ) {
+
+		$panel->render('admin/misc/search.tt', {
+		  search_title => gettext('Cron search'),
+		  type => 'cron'
+		  });
+		return;
+	}
+
+	if( $name =~ /^\s*$/ ) {
+		$vars->{list_title} = gettext('List of all cron jobs');
+		undef $name;
+	} else {
+		$vars->{list_title} = sprintf( gettext('Search result for %s'), $name );
+	}
+	$vars->{list} = search_cron( $vhffs , $name );
+	$vars->{type} = 'cron';
+	$panel->render('admin/misc/list.tt', $vars);
+}
+
+sub adminindex {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	$panel->set_title(gettext('Cron jobs administration'));
+	require Vhffs::Panel::Admin;
+	$panel->render('admin/index.tt', { categories => [ Vhffs::Panel::Admin::get_cron_category() ] } );
+}
+
 1;

Modified: trunk/vhffs-api/src/Vhffs/Panel/Cvs.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Cvs.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/Cvs.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -41,43 +41,39 @@
 use Vhffs::Services::Cvs;
 use Vhffs::Constants;
 
-sub search
-{
-    my ($main, $name) = @_;
+sub search_cvs {
+	my ($main, $name) = @_;
 
-    my @params;
-    my $sql = 'SELECT cvs.cvsroot as label, g.groupname as owner_group, o.state, u.username as owner_user '.
-        'FROM vhffs_cvs cvs '.
-        'INNER JOIN vhffs_object o ON (o.object_id = cvs.object_id) '.
-        'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
-        'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
+	my @params;
+	my $sql = 'SELECT cvs.cvsroot as label, g.groupname as owner_group, o.state, u.username as owner_user '.
+	  'FROM vhffs_cvs cvs '.
+	  'INNER JOIN vhffs_object o ON (o.object_id = cvs.object_id) '.
+	  'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
+	  'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
     
-    if( defined $name ) {
-        $sql .= 'WHERE cvs.cvsroot LIKE ? ';
-        push(@params, '%'.lc($name).'%');
-    }
+	if( defined $name ) {
+		$sql .= 'WHERE cvs.cvsroot LIKE ? ';
+		push(@params, '%'.lc($name).'%');
+	}
 
-    $sql .= 'ORDER BY cvs.cvsroot';
+	$sql .= 'ORDER BY cvs.cvsroot';
 
-    my $dbh = $main->get_db_object();
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
+	my $dbh = $main->get_db_object();
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
 }
 
 
-sub create_cvs
-{
+sub create_cvs {
 	my( $main, $cvsroot, $description, $user, $group ) = @_;
+	return undef unless defined $user;
+	return undef unless defined $group;
 
-	return undef if( ! defined $user );
-	return undef if( ! defined $group );
+	my $cvs = Vhffs::Services::Cvs::create($main, $cvsroot, $description, $user, $group);
+	return undef unless defined $cvs;
 
-    my $cvs = Vhffs::Services::Cvs::create($main, $cvsroot, $description, $user, $group);
+	return undef if Vhffs::Acl::add_acl( $user , $cvs , Vhffs::Constants::ACL_DELETE , $main ) < 0;
+	return undef if Vhffs::Acl::add_acl( $group , $cvs , Vhffs::Constants::ACL_VIEW , $main ) < 0;
 
-	return undef if( ! defined $cvs);
-
-	return undef if ( Vhffs::Acl::add_acl( $user , $cvs , Vhffs::Constants::ACL_DELETE , $main ) < 0 );
-	return undef if( Vhffs::Acl::add_acl( $group , $cvs , Vhffs::Constants::ACL_VIEW , $main ) < 0 );
-
 	return $cvs;
 }
 
@@ -93,32 +89,221 @@
 =cut
 
 
-sub getall_per_group
-{
-    my ( $main, $gid ) = @_;
+sub getall_per_group {
+	my ( $main, $gid ) = @_;
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT c.object_id AS oid, c.cvsroot AS displayname, o.state FROM vhffs_cvs c INNER JOIN vhffs_object o ON c.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY c.cvsroot';
-    my $sth = $dbh->prepare($sql) or return -1;
-    $sth->execute($gid) or return -2;
-    my $cvs = [];
-    while(my $c = $sth->fetchrow_hashref) {
-        $c->{active} = ($c->{state} == Vhffs::Constants::ACTIVATED);
-        $c->{refused} = ($c->{state} == Vhffs::Constants::VALIDATION_REFUSED);
-        $c->{state} = Vhffs::Functions::status_string_from_status_id($c->{state});
-        push @$cvs, $c;
-    }
-    return $cvs;
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT c.object_id AS oid, c.cvsroot AS displayname, o.state FROM vhffs_cvs c INNER JOIN vhffs_object o ON c.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY c.cvsroot';
+	my $sth = $dbh->prepare($sql) or return -1;
+	$sth->execute($gid) or return -2;
+	my $cvs = [];
+	while(my $c = $sth->fetchrow_hashref) {
+		$c->{active} = ($c->{state} == Vhffs::Constants::ACTIVATED);
+		$c->{refused} = ($c->{state} == Vhffs::Constants::VALIDATION_REFUSED);
+		$c->{state} = Vhffs::Functions::status_string_from_status_id($c->{state});
+		push @$cvs, $c;
+	}
+	return $cvs;
 }
 
 sub get_repos_per_group {
-    my ($main, $gid, $public_only) = @_;
-    $public_only = 1 unless(defined $public_only);
+	my ($main, $gid, $public_only) = @_;
+	$public_only = 1 unless(defined $public_only);
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT c.cvsroot, o.description FROM vhffs_cvs c INNER JOIN vhffs_object o ON o.object_id = c.object_id '.
-	'WHERE '.($public_only ? 'c.public = true AND ' : '').'o.owner_gid = ? AND o.state = ?';
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, $gid, Vhffs::Constants::ACTIVATED);
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT c.cvsroot, o.description FROM vhffs_cvs c INNER JOIN vhffs_object o ON o.object_id = c.object_id '.
+	  'WHERE '.($public_only ? 'c.public = true AND ' : '').'o.owner_gid = ? AND o.state = ?';
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, $gid, Vhffs::Constants::ACTIVATED);
 }
 
+sub create {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group and $user->can_modify( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+	$panel->set_group( $group );
+
+	my $submitted = defined($cgi->param('cvs_submit'));
+	my $reponame = '';
+	my $description = '';
+	my $vars = {};
+
+	if($submitted) {
+		$reponame = $cgi->param('reponame');
+		my $fullreponame = $group->get_groupname.'/'.$reponame;
+		$description = Encode::decode_utf8( $cgi->param('description') );
+
+		unless( defined $reponame and defined $description ) {
+			$panel->add_error( gettext('CGI Error !') );
+		} else {
+			$panel->add_error( gettext('Invalid reponame. It must contain between 3 and 64 characters, only lowercase letters and numbers') ) unless Vhffs::Services::Cvs::check_name($fullreponame);
+			$panel->add_error( gettext('You must enter a description') ) unless $description !~ /^\s*$/;
+		}
+
+		unless( $panel->has_errors() ) {
+			#Create CVS
+			my $cvs = Vhffs::Panel::Cvs::create_cvs( $vhffs, $fullreponame, $description, $user , $group );
+			if( defined $cvs ) {
+				my $url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('The CVS object was successfully created !');
+				$panel->redirect($url);
+				return;
+			} else {
+				$panel->add_error( gettext( 'An error occured while creating the object.It probably already exists' ) );
+			}
+		}
+		$vars->{reponame} = $reponame;
+		$vars->{description} = $description;
+	}
+
+	$vars->{group} = $group;
+
+	$panel->set_title( gettext('Create a CVS Repository') );
+	$panel->render('cvs/create.tt', $vars);
+}
+
+sub prefs {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $repo_name = $cgi->param('name');
+	unless( defined $repo_name ) {
+		$panel->render('misc/message.tt', { message => gettext( 'CGI Error !' ) } );
+		return;
+	}
+
+	my $cvs = Vhffs::Services::Cvs::get_by_cvsroot($vhffs, $repo_name);
+	unless( defined $cvs ) {
+		$panel->render('misc/message.tt', { message => gettext( 'Cannot get informations on this object' ) } );
+		return;
+	}
+
+	unless( $user->can_view($cvs) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) } );
+		return;
+	}
+
+	if( defined $cgi->param('save_prefs_submit') ) {
+		unless( $user->can_modify($cvs) ) {
+			$panel->add_error( gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) );
+		} elsif( not defined($cgi->param('public')) ) {
+			$panel->add_error( gettext("CGI Error !") );
+		} else {
+			my $want_public = int($cgi->param('public'));
+			if($want_public != $cvs->is_public) {
+				$cvs->set_public($want_public);
+				$cvs->set_status(Vhffs::Constants::WAITING_FOR_MODIFICATION);
+				if($cvs->commit > 0) {
+					$panel->add_info(gettext("CVS repository updated"));
+				} else {
+					$panel->add_error(gettext("An error occured during CVS repository update"));
+				}
+			}
+		}
+	}
+
+	my $vars = {};
+	$vars->{repository} = $cvs;
+	$vars->{type} = 'cvs';
+	$panel->render( 'scm/prefs.tt', $vars );
+}
+
+sub index {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group ) {
+		$panel->render('misc/message.tt', { message => gettext('You have to select a group first') });
+		return;
+	}
+
+	unless($group->get_status == Vhffs::Constants::ACTIVATED) {
+		$panel->render( 'misc/message.tt', { message => gettext('This group is not activated yet') } );
+		return;
+	}	
+
+	unless( $user->can_view( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+
+	$panel->set_group( $group );
+	$panel->set_title( sprintf(gettext('CVS repositories for %s'), $group->get_groupname) );
+	my $cvs = Vhffs::Panel::Cvs::getall_per_group( $vhffs, $group->get_gid );
+	if($cvs < 0) {
+		$panel->render('misc/message.tt', { message => gettext('Unable to get CVS repositories') } );
+		return;
+	}
+
+	$panel->render( 'misc/service-index.tt', {
+	  label => 'CVS repositories',
+	  group => $group,
+	  list => $cvs,
+	  help_url => $vhffs->get_config->get_service('cvs')->{url_doc},
+	  type => 'cvs'
+	  });
+}
+
+sub search {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $name = $cgi->param('name');
+	my $vars = {};
+
+	unless( defined $name ) {
+
+		$panel->render('admin/misc/search.tt', {
+		  search_title => gettext('CVS search'),
+		  type => 'cvs'
+		  });
+		return;
+	}
+
+	if( $name =~ /^\s*$/ ) {
+		$vars->{list_title} = gettext('List of all CVS repositories');
+		undef $name;
+	} else {
+		$vars->{list_title} = sprintf( gettext('Search result for %s'), $name );
+	}
+	$vars->{list} = search_cvs( $vhffs , $name );
+	$vars->{type} = 'cvs';
+	$panel->render('admin/misc/list.tt', $vars);
+}
+
+sub adminindex {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	$panel->set_title(gettext('CVS repositories administration'));
+	require Vhffs::Panel::Admin;
+	$panel->render('admin/index.tt', { categories => [ Vhffs::Panel::Admin::get_cvs_category() ] } );
+}
+
 1;

Modified: trunk/vhffs-api/src/Vhffs/Panel/DNS.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/DNS.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/DNS.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -41,47 +41,44 @@
 use Vhffs::Services::DNS;
 
 
-sub search
-{
-    my ($main, $name) = @_;
+sub search_dns {
+	my ($main, $name) = @_;
 
-    my @params;
-    my $sql = 'SELECT ns.domain as label, g.groupname as owner_group, o.state, u.username as owner_user '.
-        'FROM vhffs_dns ns '.
-        'INNER JOIN vhffs_object o ON (o.object_id = ns.object_id) '.
-        'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
-        'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
+	my @params;
+	my $sql = 'SELECT ns.domain as label, g.groupname as owner_group, o.state, u.username as owner_user '.
+	  'FROM vhffs_dns ns '.
+	  'INNER JOIN vhffs_object o ON (o.object_id = ns.object_id) '.
+	  'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
+	  'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
 
-    if( defined $name ) {
-        $sql .= 'WHERE ns.domain LIKE ? ';
-        push(@params, '%'.lc($name).'%');
-    }
+	if( defined $name ) {
+		$sql .= 'WHERE ns.domain LIKE ? ';
+		push(@params, '%'.lc($name).'%');
+	}
 
-    $sql .= 'ORDER BY ns.domain';
+	$sql .= 'ORDER BY ns.domain';
 
-    my $dbh = $main->get_db_object();
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
+	my $dbh = $main->get_db_object();
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
 }
 
-sub create_dns
-{
-    my ( $main , $dns_name, $description , $user , $group ) = @_;
-    return undef if( ! defined $user );
-    return undef if( ! defined $group );
+sub create_dns {
+	my ( $main , $dns_name, $description , $user , $group ) = @_;
+	return undef unless defined $user;
+	return undef unless defined $group;
 
-    my $dns = Vhffs::Services::DNS::create( $main , $dns_name, $description, $user , $group );
-	return undef if( ! defined $dns );
+	my $dns = Vhffs::Services::DNS::create( $main , $dns_name, $description, $user , $group );
+	return undef unless defined $dns;
 
-    return undef if ( Vhffs::Acl::add_acl( $user , $dns , Vhffs::Constants::ACL_DELETE , $main ) < 0 );
-    return undef if( Vhffs::Acl::add_acl( $group , $dns , Vhffs::Constants::ACL_VIEW , $main ) < 0 );
+	return undef if Vhffs::Acl::add_acl( $user , $dns , Vhffs::Constants::ACL_DELETE , $main ) < 0;
+	return undef if Vhffs::Acl::add_acl( $group , $dns , Vhffs::Constants::ACL_VIEW , $main ) < 0;
 
-    return $dns;
+	return $dns;
 }
 
 
 #Returns an array which contains | domain_name | object_id (from DNS)
-sub getall_dns_per_user
-{
+sub getall_dns_per_user {
 	my ( $user , $main ) = @_ ;
 
 	return undef if ( ! defined $user );
@@ -107,22 +104,21 @@
 =cut
 
 
-sub getall_per_group
-{
-    my ( $main, $gid ) = @_;
+sub getall_per_group {
+	my ( $main, $gid ) = @_;
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT ns.object_id AS oid, ns.domain AS displayname, o.state FROM vhffs_dns ns INNER JOIN vhffs_object o ON ns.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY ns.domain';
-    my $sth = $dbh->prepare($sql) or return -1;
-    $sth->execute($gid) or return -2;
-    my $dns = [];
-    while(my $d = $sth->fetchrow_hashref) {
-        $d->{active} = ($d->{state} == Vhffs::Constants::ACTIVATED);
-        $d->{refused} = ($d->{state} == Vhffs::Constants::VALIDATION_REFUSED);
-        $d->{state} = Vhffs::Functions::status_string_from_status_id($d->{state});
-        push @$dns, $d;
-    }
-    return $dns;
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT ns.object_id AS oid, ns.domain AS displayname, o.state FROM vhffs_dns ns INNER JOIN vhffs_object o ON ns.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY ns.domain';
+	my $sth = $dbh->prepare($sql) or return -1;
+	$sth->execute($gid) or return -2;
+	my $dns = [];
+	while(my $d = $sth->fetchrow_hashref) {
+		$d->{active} = ($d->{state} == Vhffs::Constants::ACTIVATED);
+		$d->{refused} = ($d->{state} == Vhffs::Constants::VALIDATION_REFUSED);
+		$d->{state} = Vhffs::Functions::status_string_from_status_id($d->{state});
+		push @$dns, $d;
+	}
+	return $dns;
 }
 
 =pod
@@ -139,16 +135,16 @@
 =cut
 
 sub delete_record {
-    my ($dns, $id, $type) = @_;
-    die() unless(defined $dns && defined $id && defined $type);
-    die(gettext('You cannot delete NS records on origin')."\n") if($type eq 'NS' and defined $dns->{NS}->{$id}->{name} and $dns->{NS}->{$id}->{name} eq '@');
-    my $rval = $dns->delete_record($id, $type);
-    return 1 if($rval > 0);
-    die(gettext('Invalid record')."\n") if($rval == -1);
-    die(gettext('Record type doesn\'t exists')."\n") if($rval == -2);
-    die(gettext('Record does not exists')."\n") if($rval == -3);
-    die(gettext('Database error')."\n") if($rval == -4);
-    die(gettext('Unknown error')."\n");
+	my ($dns, $id, $type) = @_;
+	die() unless defined $dns and defined $id and defined $type;
+	die(gettext('You cannot delete NS records on origin')."\n") if $type eq 'NS' and defined $dns->{NS}->{$id}->{name} and $dns->{NS}->{$id}->{name} eq '@';
+	my $rval = $dns->delete_record($id, $type);
+	return 1 if $rval > 0;
+	die(gettext('Invalid record')."\n") if $rval == -1;
+	die(gettext('Record type doesn\'t exists')."\n") if $rval == -2;
+	die(gettext('Record does not exists')."\n") if $rval == -3;
+	die(gettext('Database error')."\n") if $rval == -4;
+	die(gettext('Unknown error')."\n");
 }
 
 
@@ -170,182 +166,505 @@
 =cut
 
 sub add_a {
-    my ($dns, $redirect, $name, $ip) = @_;
-    die() unless(defined $dns && defined $redirect && defined $name && defined $ip);
-    my $rval;
-    if($redirect) {
-        $rval = $dns->add_a($name);
-    } else {
-        $rval = $dns->add_a($name, $ip);
-    }
-    return 1 if($rval > 0);
-    die(gettext('Invalid prefix')."\n") if($rval == -1);
-    die(gettext('Prefix already exists')."\n") if($rval == -2);
-    die(gettext('Unable to find default redirection address, please contact administrators')."\n") if($rval == -3);
-    die(gettext('Invalid IP address')."\n") if($rval == -4);
-    die(gettext('Database error')."\n") if($rval == -5);
-    die(gettext('Unknown error')."\n");
+	my ($dns, $redirect, $name, $ip) = @_;
+	die() unless defined $dns and defined $redirect and defined $name and defined $ip;
+	my $rval;
+	if($redirect) {
+		$rval = $dns->add_a($name);
+	} else {
+		$rval = $dns->add_a($name, $ip);
+	}
+	return 1 if $rval > 0;
+	die(gettext('Invalid prefix')."\n") if $rval == -1;
+	die(gettext('Prefix already exists')."\n") if $rval == -2;
+	die(gettext('Unable to find default redirection address, please contact administrators')."\n") if $rval == -3;
+	die(gettext('Invalid IP address')."\n") if $rval == -4;
+	die(gettext('Database error')."\n") if $rval == -5;
+	die(gettext('Unknown error')."\n");
 }
 
 sub update_a {
-    my ($dns, $id, $ip) = @_;
-    die() unless(defined $dns && defined $id && defined $ip);
-    my $rval = $dns->update_a($id, $ip);
-    return 1 if($rval > 0);
-    die(gettext('Invalid record')."\n") if($rval == -1);
-    die(gettext('Record does not exists')."\n") if($rval == -2);
-    die(gettext('Invalid IP address')."\n") if($rval == -3);
-    die(gettext('Database error')."\n") if($rval == -4);
-    die(gettext('Unknown error')."\n");
+	my ($dns, $id, $ip) = @_;
+	die() unless defined $dns and defined $id and defined $ip;
+	my $rval = $dns->update_a($id, $ip);
+	return 1 if $rval > 0;
+	die(gettext('Invalid record')."\n") if $rval == -1;
+	die(gettext('Record does not exists')."\n") if $rval == -2;
+	die(gettext('Invalid IP address')."\n") if $rval == -3;
+	die(gettext('Database error')."\n") if $rval == -4;
+	die(gettext('Unknown error')."\n");
 }
 
 sub add_aaaa {
-    my ($dns, $redirect, $name, $ip) = @_;
-    die() unless(defined $dns && defined $redirect && defined $name && defined $ip);
-    my $rval;
-    if($redirect) {
-        $rval = $dns->add_aaaa($name);
-    } else {
-        $rval = $dns->add_aaaa($name, $ip);
-    }
-    return 1 if($rval > 0);
-    die(gettext('Invalid prefix')."\n") if($rval == -1);
-    die(gettext('Prefix already exists')."\n") if($rval == -2);
-    die(gettext('Unable to find default redirection address, please contact administrators')."\n") if($rval == -3);
-    die(gettext('Invalid IP v6 address')."\n") if($rval == -4);
-    die(gettext('Database error')."\n") if($rval == -5);
-    die(gettext('Unknown error')."\n");
+	my ($dns, $redirect, $name, $ip) = @_;
+	die() unless defined $dns and defined $redirect and defined $name and defined $ip;
+	my $rval;
+	if($redirect) {
+		$rval = $dns->add_aaaa($name);
+	} else {
+		$rval = $dns->add_aaaa($name, $ip);
+	}
+	return 1 if $rval > 0;
+	die(gettext('Invalid prefix')."\n") if $rval == -1;
+	die(gettext('Prefix already exists')."\n") if $rval == -2;
+	die(gettext('Unable to find default redirection address, please contact administrators')."\n") if $rval == -3;
+	die(gettext('Invalid IP v6 address')."\n") if $rval == -4;
+	die(gettext('Database error')."\n") if $rval == -5;
+	die(gettext('Unknown error')."\n");
 }
 
 sub update_aaaa {
-    my ($dns, $id, $ip) = @_;
-    die() unless(defined $dns && defined $id && defined $ip);
-    my $rval = $dns->update_aaaa($id, $ip);
-    return 1 if($rval > 0);
-    die(gettext('Invalid record')."\n") if($rval == -1);
-    die(gettext('Record does not exists')."\n") if($rval == -2);
-    die(gettext('Invalid IP address')."\n") if($rval == -3);
-    die(gettext('Database error')."\n") if($rval == -4);
-    die(gettext('Unknown error')."\n");
+	my ($dns, $id, $ip) = @_;
+	die() unless defined $dns and defined $id and defined $ip;
+	my $rval = $dns->update_aaaa($id, $ip);
+	return 1 if $rval > 0;
+	die(gettext('Invalid record')."\n") if $rval == -1;
+	die(gettext('Record does not exists')."\n") if $rval == -2;
+	die(gettext('Invalid IP address')."\n") if $rval == -3;
+	die(gettext('Database error')."\n") if $rval == -4;
+	die(gettext('Unknown error')."\n");
 }
 
 sub add_mx {
-    my ($dns, $name, $host, $priority) = @_;
-    die() unless(defined $dns && defined $name && defined $host && defined $priority);
-    my $rval = $dns->add_mx( $name, $host, $priority);
-    return 1 if($rval > 0);
-    die(gettext('Invalid hostname')."\n") if($rval == -1);
-    die(gettext('Invalid priority')."\n") if($rval == -2);
-    die(gettext('An MX record with the same name already exists for this domain')."\n") if($rval == -3);
-    die(gettext('Database error')."\n") if($rval == -4);
-    die(gettext('Invalid prefix')."\n") if($rval == -5);
-    die(gettext('Unknown error')."\n");
+	my ($dns, $name, $host, $priority) = @_;
+	die() unless defined $dns and defined $name and defined $host and defined $priority;
+	my $rval = $dns->add_mx( $name, $host, $priority);
+	return 1 if $rval > 0;
+	die(gettext('Invalid hostname')."\n") if $rval == -1;
+	die(gettext('Invalid priority')."\n") if $rval == -2;
+	die(gettext('An MX record with the same name already exists for this domain')."\n") if($rval == -3);
+	die(gettext('Database error')."\n") if $rval == -4;
+	die(gettext('Invalid prefix')."\n") if $rval == -5;
+	die(gettext('Unknown error')."\n");
 }
 
 sub update_mx {
-    my ($dns, $id, $host) = @_;
-    die() unless(defined $dns && defined $id && defined $host);
-    my $rval = $dns->update_mx($id, $host);
-    return 1 if($rval > 0);
-    die(gettext('Invalid record')."\n") if($rval == -1);
-    die(gettext('Record does not exists')."\n") if($rval == -2);
-    die(gettext('Invalid host')."\n") if($rval == -3);
-    die(gettext('Database error')."\n") if($rval == -4);
-    die(gettext('Unknown error')."\n"),;
+	my ($dns, $id, $host) = @_;
+	die() unless defined $dns and defined $id and defined $host;
+	my $rval = $dns->update_mx($id, $host);
+	return 1 if $rval > 0;
+	die(gettext('Invalid record')."\n") if $rval == -1;
+	die(gettext('Record does not exists')."\n") if $rval == -2;
+	die(gettext('Invalid host')."\n") if $rval == -3;
+	die(gettext('Database error')."\n") if $rval == -4;
+	die(gettext('Unknown error')."\n"),;
 }
 
 sub add_ns {
-    my ($dns, $name, $host) = @_;
-    die() unless(defined $dns && defined $name && defined $host);
-    die(gettext('You cannot add NS records on origin')."\n") if($name eq '@');
-    my $rval = $dns->add_ns($name, $host);
-    return 1 if($rval > 0);
-    die(gettext('Invalid hostname')."\n") if($rval == -1);
-    die(gettext('An NS record with the same name already exists for this domain')."\n") if($rval == -2);
-    die(gettext('Database error')."\n") if($rval == -3);
-    die(gettext('Invalid prefix')."\n") if($rval == -5);
-    die(gettext('Unknown error')."\n");
+	my ($dns, $name, $host) = @_;
+	die() unless defined $dns and defined $name and defined $host;
+	die(gettext('You cannot add NS records on origin')."\n") if $name eq '@';
+	my $rval = $dns->add_ns($name, $host);
+	return 1 if $rval > 0;
+	die(gettext('Invalid hostname')."\n") if $rval == -1;
+	die(gettext('An NS record with the same name already exists for this domain')."\n") if $rval == -2;
+	die(gettext('Database error')."\n") if $rval == -3;
+	die(gettext('Invalid prefix')."\n") if $rval == -5;
+	die(gettext('Unknown error')."\n");
 }
 
 sub update_cname {
-    my ($dns, $id, $dest) = @_;
-    die() unless(defined $dns && defined $id && defined $dest);
-    my $rval = $dns->update_cname($id, $dest);
-    return 1 if($rval > 0);
-    die(gettext('Invalid record')."\n") if($rval == -1);
-    die(gettext('Record does not exists')."\n") if($rval == -2);
-    die(gettext('Invalid destination')."\n") if($rval == -3);
-    die(gettext('Database error')."\n") if($rval == -4);
-    die(gettext('Unknown error')."\n");
+	my ($dns, $id, $dest) = @_;
+	die() unless defined $dns and defined $id and defined $dest;
+	my $rval = $dns->update_cname($id, $dest);
+	return 1 if $rval > 0;
+	die(gettext('Invalid record')."\n") if $rval == -1;
+	die(gettext('Record does not exists')."\n") if $rval == -2;
+	die(gettext('Invalid destination')."\n") if $rval == -3;
+	die(gettext('Database error')."\n") if $rval == -4;
+	die(gettext('Unknown error')."\n");
 
 }
 
 sub add_cname {
-    my ($dns, $name, $dest) = @_;
-    die() unless(defined $dns && defined $name && defined $dest);
-    my $rval = $dns->add_cname($name, $dest);
-    return 1 if($rval > 0);
-    die(gettext('Invalid alias')."\n") if($rval == -1);
-    die(gettext('Invalid destination host')."\n") if($rval == -2);
-    die(gettext('A CNAME, A or AAAA record with the same name already exists for this domain')."\n") if($rval == -3);
-    die(gettext('Database error')."\n") if($rval == -4);
-    die(gettext('Unknown error')."\n");
+	my ($dns, $name, $dest) = @_;
+	die() unless defined $dns and defined $name and defined $dest;
+	my $rval = $dns->add_cname($name, $dest);
+	return 1 if $rval > 0;
+	die(gettext('Invalid alias')."\n") if $rval == -1;
+	die(gettext('Invalid destination host')."\n") if $rval == -2;
+	die(gettext('A CNAME, A or AAAA record with the same name already exists for this domain')."\n") if $rval == -3;
+	die(gettext('Database error')."\n") if $rval == -4;
+	die(gettext('Unknown error')."\n");
 }
 
 sub add_srv {
-    my ($dns, $name, $proto, $svc, $host, $port, $priority, $weight) = @_;
-    die() unless(defined $dns && defined $name && defined $proto && defined $svc && defined $host && defined $port && defined $priority && defined $weight);
-    my $rval = $dns->add_srv($name, $proto, $svc, $host, $port, $priority, $weight);
-    return 1 if($rval > 0);
-    die(gettext('Invalid protocol syntax')."\n") if($rval == -1);
-    die(gettext('Invalid service syntax')."\n") if($rval == -2);
-    die(gettext('Invalid destination domain name')."\n") if($rval == -3);
-    die(gettext('Invalid port')."\n") if($rval == -4);
-    die(gettext('Invalid priority')."\n") if($rval == -5);
-    die(gettext('Invalid weight')."\n") if($rval == -6);
-    die(gettext('Invalid record')."\n") if($rval == -7);
-    die(gettext('This host is already registered for this service')."\n") if($rval == -8);
-    die(gettext('Database error')."\n") if($rval == -9);
-    die(gettext('Unknown error')."\n");
+	my ($dns, $name, $proto, $svc, $host, $port, $priority, $weight) = @_;
+	die() unless defined $dns and defined $name and defined $proto and defined $svc and defined $host and defined $port and defined $priority and defined $weight;
+	my $rval = $dns->add_srv($name, $proto, $svc, $host, $port, $priority, $weight);
+	return 1 if $rval > 0;
+	die(gettext('Invalid protocol syntax')."\n") if $rval == -1;
+	die(gettext('Invalid service syntax')."\n") if $rval == -2;
+	die(gettext('Invalid destination domain name')."\n") if $rval == -3;
+	die(gettext('Invalid port')."\n") if $rval == -4;
+	die(gettext('Invalid priority')."\n") if $rval == -5;
+	die(gettext('Invalid weight')."\n") if $rval == -6;
+	die(gettext('Invalid record')."\n") if $rval == -7;
+	die(gettext('This host is already registered for this service')."\n") if $rval == -8;
+	die(gettext('Database error')."\n") if $rval == -9;
+	die(gettext('Unknown error')."\n");
 }
 
 sub update_srv {
-    my ($dns, $id, $host, $port, $priority, $weight) = @_;
-    die() unless(defined $dns && defined $host && defined $port && defined $priority && defined $weight);
-    my $rval = $dns->update_srv($id, $host, $port, $priority, $weight);
-    return 1 if($rval > 0);
-    die(gettext('Invalid record')."\n") if($rval == -1);
-    die(gettext('Record does not exists')."\n") if($rval == -2);
-    die(gettext('Invalid destination domain name')."\n") if($rval == -3);
-    die(gettext('Invalid port')."\n") if($rval == -4);
-    die(gettext('Invalid priority')."\n") if($rval == -5);
-    die(gettext('Invalid weight')."\n") if($rval == -6);
-    die(gettext('Database error')."\n") if($rval == -7);
-    die(gettext('Unknown error')."\n");
+	my ($dns, $id, $host, $port, $priority, $weight) = @_;
+	die() unless defined $dns and defined $host and defined $port and defined $priority and defined $weight;
+	my $rval = $dns->update_srv($id, $host, $port, $priority, $weight);
+	return 1 if $rval > 0;
+	die(gettext('Invalid record')."\n") if $rval == -1;
+	die(gettext('Record does not exists')."\n") if $rval == -2;
+	die(gettext('Invalid destination domain name')."\n") if $rval == -3;
+	die(gettext('Invalid port')."\n") if $rval == -4;
+	die(gettext('Invalid priority')."\n") if $rval == -5;
+	die(gettext('Invalid weight')."\n") if $rval == -6;
+	die(gettext('Database error')."\n") if $rval == -7;
+	die(gettext('Unknown error')."\n");
 }
 
 sub add_txt {
-    my ($dns, $name, $txt) = @_;
-    die() unless(defined $dns && defined $name && defined $txt);
-    my $rval = $dns->add_txt($name, $txt);
-    return 1 if($rval > 0);
-    die(gettext('Invalid prefix')."\n") if($rval == -1);
-    die(gettext('Text can\'t be empty')."\n") if($rval == -2);
-    die(gettext('A TXT record with the same name already exists for this domain')."\n") if($rval == -3);
-    die(gettext('Database error')."\n") if($rval == -4);
-    die(gettext('Unknown error')."\n");
+	my ($dns, $name, $txt) = @_;
+	die() unless defined $dns and defined $name and defined $txt;
+	my $rval = $dns->add_txt($name, $txt);
+	return 1 if $rval > 0;
+	die(gettext('Invalid prefix')."\n") if $rval == -1;
+	die(gettext('Text can\'t be empty')."\n") if $rval == -2;
+	die(gettext('A TXT record with the same name already exists for this domain')."\n") if $rval == -3;
+	die(gettext('Database error')."\n") if $rval == -4;
+	die(gettext('Unknown error')."\n");
 }
 
 sub update_txt {
-    my ($dns, $id, $txt) = @_;
-    die() unless(defined $dns && defined $id && defined $txt);
-    my $rval = $dns->update_txt($id, $txt);
-    return 1 if($rval > 0);
-    die(gettext('Invalid record')."\n") if($rval == -1);
-    die(gettext('Record does not exists')."\n") if($rval == -2);
-    die(gettext('Text can\'t be empty')."\n") if($rval == -3);
-    die(gettext('Database error')."\n") if($rval == -4);
-    die(gettext('Unknown error')."\n"),;
+	my ($dns, $id, $txt) = @_;
+	die() unless defined $dns and defined $id and defined $txt;
+	my $rval = $dns->update_txt($id, $txt);
+	return 1 if $rval > 0;
+	die(gettext('Invalid record')."\n") if $rval == -1;
+	die(gettext('Record does not exists')."\n") if $rval == -2;
+	die(gettext('Text can\'t be empty')."\n") if $rval == -3;
+	die(gettext('Database error')."\n") if $rval == -4;
+	die(gettext('Unknown error')."\n"),;
 }
 
+sub create {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group and $user->can_modify( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+	$panel->set_group( $group );
+
+	my $submitted = defined($cgi->param('dns_submit'));
+	my $domain_name = '';
+	my $description = '';
+	my $vars = {};
+
+	if( $submitted ) {
+		$domain_name = $cgi->param('DOMAIN_NAME');
+		$description = Encode::decode_utf8( $cgi->param('DESCRIPTION') );
+
+		unless( defined $domain_name and defined $description ) {
+			$panel->add_error( gettext('CGI Error !') );
+		} else {
+			$panel->add_error( gettext('Invalid domain name') ) unless Vhffs::Functions::check_domain_name($domain_name);
+			$panel->add_error( gettext('You must enter a description') ) unless $description !~ /^\s*$/;
+		}
+
+		unless( $panel->has_errors() ) {
+			my $dns = Vhffs::Panel::DNS::create_dns( $vhffs, $domain_name, $description, $user, $group );
+			if( defined $dns ) {
+				my $url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('The DNS object was successfully created !');
+				$panel->redirect($url);
+				return;
+			}
+
+			$panel->add_error( gettext('An error occured while creating the object. The domain is not correct or aleady exists in Vhffs database') );
+		}
+
+		$vars->{domain} = $domain_name;
+		$vars->{description} = $description;
+	}
+
+	my $conf = $vhffs->get_config->get_service('dns');
+	$vars->{group} = $group;
+	$vars->{ns} = $conf->{init}{ns};
+	$vars->{help_url} = $conf->{url_doc};
+	$panel->render('dns/create.tt', $vars);
+}
+
+sub prefs {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $domain_name = $cgi->param('name');
+	unless( defined $domain_name ) {
+		$panel->render('misc/message.tt', { message => gettext( 'CGI Error !' ) } );
+		return;
+	}
+
+	my $dns = Vhffs::Services::DNS::get_by_domainname( $vhffs , $domain_name );
+	unless( defined $dns ) {
+		$panel->render('misc/message.tt', { message => gettext('Cannot get informations on this object') } );
+		return;
+	}
+
+	unless( $user->can_view( $dns ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) } );
+		return;
+	}
+
+	my $thirdtemplate;
+	my $template;
+	my $output = "";
+	my $message;
+
+	my $action = $cgi->param('action');
+
+	ACTION: {
+		if(defined $action) {
+
+			# Check user's rights
+			unless( $user->can_modify( $dns ) ) {
+				$panel->add_error( gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) );
+				last ACTION;
+			}
+
+			my $id = $cgi->param('rr_id');
+			my $data = $cgi->param('data');
+			my $namerr = $cgi->param('namerr');
+			my $aux = $cgi->param('aux');
+
+			if($action eq 'manage_a') {
+				if(defined $cgi->param('modify_a_submit')) {
+					# User just want to modify an A record
+					eval { Vhffs::Panel::DNS::update_a($dns, $id, $data); };
+					if($@) { $panel->add_error(sprintf(gettext('Unable to modify A record: %s'), $@)); }
+					else { $panel->add_info(gettext('A Record updated')); }
+				} else {
+					# User wants to delete it
+					eval { Vhffs::Panel::DNS::delete_record($dns, $id, 'A'); };
+					if($@) { $panel->add_error(sprintf(gettext('Unable to delete A record: %s'), $@)); }
+					else { $panel->add_info(gettext('A Record deleted')); }
+				}
+			} elsif($action eq 'manage_aaaa') {
+				if(defined $cgi->param('modify_aaaa_submit')) {
+					# User just want to modify an AAAA record
+					eval { Vhffs::Panel::DNS::update_aaaa($dns, $id, $data); };
+					if($@) { $panel->add_error(sprintf(gettext('Unable to modify AAAA record: %s'), $@)); }
+					else { $panel->add_info(gettext('AAAA Record updated')); }
+				} else {
+					# User wants to delete it
+					eval { Vhffs::Panel::DNS::delete_record($dns, $id, 'AAAA'); };
+					if($@) { $panel->add_error(sprintf(gettext('Unable to delete AAAA record: %s'), $@)); }
+					else { $panel->add_info(gettext('AAAA Record deleted')); }
+				}
+			} elsif($action eq 'add_aaaa') {
+				my $redirect = $cgi->param('redirect');
+				eval { Vhffs::Panel::DNS::add_aaaa($dns, (defined $redirect && $redirect eq 'true'), $namerr, $data); };
+				if($@) { $panel->add_error(sprintf(gettext('Unable to add AAAA record: %s'), $@)); }
+				else { $panel->add_info(gettext('AAAA record added')); }
+			} elsif($action eq 'add_a') {
+				my $redirect = $cgi->param('redirect');
+				eval { Vhffs::Panel::DNS::add_a($dns, (defined $redirect && $redirect eq 'true'), $namerr, $data); };
+				if($@) { $panel->add_error(sprintf(gettext('Unable to add A record: %s'), $@)); }
+				else { $panel->add_info(gettext('A record added')); }
+			} elsif($action eq 'manage_mx') {
+				if(defined $cgi->param('modify_mx_submit')) {
+					# User wants to modify an MX record
+					eval { Vhffs::Panel::DNS::update_mx($dns, $id, $data); };
+					if($@) { $panel->add_error(sprintf(gettext('Unable to modify MX record: %s'), $@)); }
+					else { $panel->add_info(gettext('MX Record updated')); }
+				} else {
+					# MX deletion
+					eval { Vhffs::Panel::DNS::delete_record($dns, $id, 'MX'); };
+					if($@) { $panel->add_error(sprintf(gettext('Unable to delete MX record: %s'), $@)); }
+					else { $panel->add_info(gettext('MX Record deleted')); }
+				}
+			} elsif($action eq 'add_mx') {
+				eval { Vhffs::Panel::DNS::add_mx($dns, $namerr, $data, $aux); };
+				if($@) { $panel->add_error(sprintf(gettext('Unable to add MX record: %s'), $@)); }
+				else { $panel->add_info(gettext('MX Record added')); }
+			} elsif($action eq 'manage_ns') {
+				# Only deletion is allowed for NS record
+				eval { Vhffs::Panel::DNS::delete_record($dns, $id, 'NS'); };
+				if($@) { $panel->add_error(sprintf(gettext('Unable to delete NS record: %s'), $@)); }
+				else { $panel->add_info(gettext('NS Record deleted')); }
+			} elsif($action eq 'add_ns') {
+				eval { Vhffs::Panel::DNS::add_ns($dns, $namerr, $data); };
+				if($@) { $panel->add_error(sprintf(gettext('Unable to add NS record: %s'), $@)); }
+				else { $panel->add_info(gettext('NS Record added')); }
+			} elsif($action eq 'manage_cname') {
+				if(defined $cgi->param('modify_cname_submit')) {
+					eval { Vhffs::Panel::DNS::update_cname($dns, $id, $data); };
+					if($@) { $panel->add_error(sprintf(gettext('Unable to modify CNAME record: %s'), $@)); }
+					else { $panel->add_info(gettext('CNAME Record updated')); }
+				} else {
+					eval { Vhffs::Panel::DNS::delete_record($dns, $id, 'CNAME'); };
+					if($@) { $panel->add_error(sprintf(gettext('Unable to delete CNAME record: %s'), $@)); }
+					else { $panel->add_info(gettext('CNAME Record deleted')); }
+				}
+			} elsif($action eq 'add_cname') {
+				eval { Vhffs::Panel::DNS::add_cname($dns, $namerr, $data); };
+				if($@) { $panel->add_error(sprintf(gettext('Unable to add CNAME record: %s'), $@)); }
+				else { $panel->add_info(gettext('CNAME Record added')); }
+			} elsif($action eq 'manage_srv') {
+				if(defined $cgi->param('modify_srv_submit')) {
+					my $host = $cgi->param('host');
+					my $port = $cgi->param('port');
+					my $weight = $cgi->param('weight');
+					eval { Vhffs::Panel::DNS::update_srv($dns, $id, $host, $port, $aux, $weight); };
+					if($@) { $panel->add_error(sprintf(gettext('Unable to modify SRV record: %s'), $@)); }
+					else { $panel->add_info(gettext('SRV Record updated')); }
+				} else {
+					eval { Vhffs::Panel::DNS::delete_record($dns, $id, 'SRV'); };
+					if($@) { $panel->add_error(sprintf(gettext('Unable to delete SRV record: %s'), $@)); }
+					else { $panel->add_info(gettext('SRV Record deleted')); }
+				}
+			} elsif($action eq 'add_srv') {
+				my $proto = $cgi->param('protocol');
+				my $svc = $cgi->param('service');
+				my $host = $cgi->param('host');
+				my $port = $cgi->param('port');
+				my $aux = $cgi->param('aux');
+				my $weight = $cgi->param('weight');
+				eval { Vhffs::Panel::DNS::add_srv($dns, $namerr, $proto, $svc, $host, $port, $aux, $weight); };
+				if($@) { $panel->add_error(sprintf(gettext('Unable to add SRV record: %s'), $@)); }
+				else { $panel->add_info(gettext('SRV Record added')); }
+			} elsif($action eq 'add_txt') {
+				eval { Vhffs::Panel::DNS::add_txt($dns, $namerr, $data); };
+				if($@) { $panel->add_error(sprintf(gettext('Unable to add TXT record: %s'), $@)); }
+				else { $panel->add_info(gettext('TXT Record added')); }
+			} elsif($action eq 'manage_txt') {
+				if(defined $cgi->param('modify_txt_submit')) {
+					# User wants to modify an TXT record
+					eval { Vhffs::Panel::DNS::update_txt($dns, $id, $data); };
+					if($@) { $panel->add_error(sprintf(gettext('Unable to modify TXT record: %s'), $@)); }
+					else { $panel->add_info(gettext('TXT Record updated')); }
+				} else {
+					# TXT deletion
+					eval { Vhffs::Panel::DNS::delete_record($dns, $id, 'TXT'); };
+					if($@) { $panel->add_error(sprintf(gettext('Unable to delete TXT record: %s'), $@)); }
+					else { $panel->add_info(gettext('TXT Record deleted')); }
+				}
+			}
+		}
+	}
+
+	my $vars = { dns => $dns };
+	my @sorted_a = sort {$a->{name} cmp $b->{name}} values(%{$dns->get_a_type});
+	my @sorted_aaaa = sort {$a->{name} cmp $b->{name}} values(%{$dns->get_aaaa_type});
+	my @sorted_mx = sort {$a->{aux} <=> $b->{aux}} values(%{$dns->get_mx_type});
+	my @sorted_cname = sort {$a->{name} cmp $b->{name}} values(%{$dns->get_cname_type});
+	my @sorted_ns = sort {$a->{name} cmp $b->{name}} values(%{$dns->get_ns_type});
+	my @sorted_srv = sort {$a->{name} cmp $b->{name}} values(%{$dns->get_srv_type});
+	my @sorted_txt = sort {$a->{name} cmp $b->{name}} values(%{$dns->get_txt_type});
+	$vars->{sorted_a} = \@sorted_a;
+	$vars->{sorted_aaaa} = \@sorted_aaaa;
+	$vars->{sorted_mx} = \@sorted_mx;
+	$vars->{sorted_cname} = \@sorted_cname;
+	$vars->{sorted_ns} = \@sorted_ns;
+	$vars->{sorted_srv} = \@sorted_srv;
+	$vars->{sorted_txt} = \@sorted_txt;
+
+	$panel->set_title(sprintf(gettext("DNS Administration - %s"), $domain_name));
+	$panel->render('dns/prefs.tt', $vars);
+}
+
+sub index {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined($group) ) {
+		$panel->render('misc/message.tt', { message => gettext('You have to select a group first') } );
+		return;
+	}
+
+	unless($group->get_status == Vhffs::Constants::ACTIVATED) {
+		$panel->render( 'misc/message.tt', { message => gettext('This group is not activated yet') } );
+		return;
+	}
+
+	unless( $user->can_view( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+
+	$panel->set_group( $group );
+	$panel->set_title( sprintf(gettext('Domain names for %s'), $group->get_groupname) );
+	my $dns = Vhffs::Panel::DNS::getall_per_group( $vhffs, $group->get_gid );
+	if($dns < 0) {
+		$panel->render('misc/message.tt', { message => gettext('Unable to get DNS') } );
+		return;
+	}
+
+	$panel->render( 'misc/service-index.tt', {
+	  label => 'Domain names',
+	  group => $group,
+	  list => $dns,
+	  help_url => $vhffs->get_config->get_service('dns')->{url_doc},
+	  type => 'dns'
+	  });
+}
+
+sub search {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $name = $cgi->param('name');
+	my $vars = {};
+
+	unless( defined $name ) {
+
+		$panel->render('admin/misc/search.tt', {
+		  search_title => gettext('DNS search'),
+		  type => 'dns'
+		  });
+		return;
+	}
+
+	if( $name =~ /^\s*$/ ) {
+		$vars->{list_title} = gettext('List of all DNS');
+		undef $name;
+	} else {
+		$vars->{list_title} = sprintf( gettext('Search result for %s'), $name );
+	}
+	$vars->{list} = search_dns( $vhffs , $name );
+	$vars->{type} = 'dns';
+	$panel->render('admin/misc/list.tt', $vars);
+}
+
+sub adminindex {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	$panel->set_title(gettext('DNS administration'));
+	require Vhffs::Panel::Admin;
+	$panel->render('admin/index.tt', { categories => [ Vhffs::Panel::Admin::get_dns_category() ] } );
+}
+
+
 1;

Modified: trunk/vhffs-api/src/Vhffs/Panel/Git.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Git.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/Git.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -56,73 +56,296 @@
 =cut
 
 
-sub getall_per_group
-{
-    my ( $main, $gid ) = @_;
+sub getall_per_group {
+	my ( $main, $gid ) = @_;
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT s.object_id AS oid, s.reponame AS displayname, o.state FROM vhffs_git s INNER JOIN vhffs_object o ON s.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY s.reponame';
-    my $sth = $dbh->prepare($sql) or return -1;
-    $sth->execute($gid) or return -2;
-    my $git = [];
-    while(my $s = $sth->fetchrow_hashref) {
-        $s->{active} = ($s->{state} == Vhffs::Constants::ACTIVATED);
-        $s->{refused} = ($s->{state} == Vhffs::Constants::VALIDATION_REFUSED);
-        $s->{state} = Vhffs::Functions::status_string_from_status_id($s->{state});
-        push @$git, $s;
-    }
-    return $git;
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT s.object_id AS oid, s.reponame AS displayname, o.state FROM vhffs_git s INNER JOIN vhffs_object o ON s.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY s.reponame';
+	my $sth = $dbh->prepare($sql) or return -1;
+	$sth->execute($gid) or return -2;
+	my $git = [];
+	while(my $s = $sth->fetchrow_hashref) {
+		$s->{active} = ($s->{state} == Vhffs::Constants::ACTIVATED);
+		$s->{refused} = ($s->{state} == Vhffs::Constants::VALIDATION_REFUSED);
+		$s->{state} = Vhffs::Functions::status_string_from_status_id($s->{state});
+		push @$git, $s;
+	}
+	return $git;
 }
 
 sub get_repos_per_group {
-    my ($main, $gid, $public_only) = @_;
-    $public_only = 1 unless(defined $public_only);
+	my ($main, $gid, $public_only) = @_;
+	$public_only = 1 unless(defined $public_only);
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT g.reponame, o.description FROM vhffs_git g INNER JOIN vhffs_object o ON o.object_id = g.object_id '.
-	'WHERE '.($public_only ? 'public = 1 AND ' : '').'o.owner_gid = ? AND o.state = ?';
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, $gid, Vhffs::Constants::ACTIVATED);
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT g.reponame, o.description FROM vhffs_git g INNER JOIN vhffs_object o ON o.object_id = g.object_id '.
+	  'WHERE '.($public_only ? 'public = 1 AND ' : '').'o.owner_gid = ? AND o.state = ?';
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, $gid, Vhffs::Constants::ACTIVATED);
 }
 
 
-sub search {
-    my ($main, $name) = @_;
+sub search_git {
+	my ($main, $name) = @_;
 
-    my @params;
-    my $sql = 'SELECT git.reponame as label, g.groupname as owner_group, o.state, u.username as owner_user '.
-        'FROM vhffs_git git '.
-        'INNER JOIN vhffs_object o ON (o.object_id = git.object_id) '.
-        'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
-        'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
+	my @params;
+	my $sql = 'SELECT git.reponame as label, g.groupname as owner_group, o.state, u.username as owner_user '.
+	  'FROM vhffs_git git '.
+	  'INNER JOIN vhffs_object o ON (o.object_id = git.object_id) '.
+	  'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
+	  'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
 
-    if( defined $name ) {
-        $sql .= 'WHERE git.reponame LIKE ? ';
-        push(@params, '%'.lc($name).'%');
-    }
+	if( defined $name ) {
+		$sql .= 'WHERE git.reponame LIKE ? ';
+		push(@params, '%'.lc($name).'%');
+	}
 
-    $sql .= 'ORDER BY git.reponame';
+	$sql .= 'ORDER BY git.reponame';
 
-    my $dbh = $main->get_db_object();
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
+	my $dbh = $main->get_db_object();
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
 }
 
 
 
-sub create_git
-{
-    my ($main, $repo, $description, $user, $group) = @_;
-
-    return -1 unless( defined $user );
-    return -2 unless( defined $group );
+sub create_git {
+	my ($main, $repo, $description, $user, $group) = @_;
+	return -1 unless defined $user;
+	return -2 unless defined $group;
     
-    my $git = Vhffs::Services::Git::create( $main, $repo, $description, $user, $group );
+	my $git = Vhffs::Services::Git::create( $main, $repo, $description, $user, $group );
+	return -1 unless defined $git;
     
-    return -1 unless( defined $git );
+	return -3 if Vhffs::Acl::add_acl( $user , $git , Vhffs::Constants::ACL_DELETE , $main ) < 0;
+	return -3 if Vhffs::Acl::add_acl( $group , $git , Vhffs::Constants::ACL_VIEW , $main ) < 0;
     
-    return ( -3 ) if ( Vhffs::Acl::add_acl( $user , $git , Vhffs::Constants::ACL_DELETE , $main ) < 0 );
-    return ( -3 ) if( Vhffs::Acl::add_acl( $group , $git , Vhffs::Constants::ACL_VIEW , $main ) < 0 );
-    
-    return $git;
+	return $git;
 }
 
+sub create {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group and $user->can_modify( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+	$panel->set_group( $group );
+
+	my $submitted = $cgi->param('git_submit');
+	my $reponame = '';
+	my $description = '';
+	my $vars = {};
+
+	if( $submitted ) {
+		$reponame = $cgi->param('reponame');
+		my $fullreponame = $group->get_groupname.'/'.$reponame.'.git';
+		$description = Encode::decode_utf8( $cgi->param('description') );
+		unless( defined $reponame && defined $description ) {
+			$panel->add_error( gettext('CGI Error !') );
+		} else {
+			$panel->add_error( gettext('Invalid reponame. It must contain between 3 and 64 characters, only lowercase letters and numbers') ) unless Vhffs::Services::Git::check_name($fullreponame);
+			$panel->add_error( gettext('You must enter a description') ) unless $description !~ /^\s*$/;
+		}
+
+		unless( $panel->has_errors() ) {
+			my $git = Vhffs::Panel::Git::create_git( $vhffs, $fullreponame, $description, $user, $group );
+			if( defined $git ) {
+				my $url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('The GIT object was successfully created !');
+				$panel->redirect($url);
+				return;
+			}
+
+			$panel->add_error( gettext('An error occured while creating the git repository') );
+		}
+
+		$vars->{reponame} = $reponame;
+		$vars->{description} = $description;
+	}
+
+	$vars->{group} = $group;
+	$panel->render('git/create.tt', $vars);
+}
+
+sub prefs {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $repo_name = $cgi->param('name');
+	unless( defined $repo_name ) {
+		$panel->render('misc/message.tt', { message => gettext( 'CGI Error !' ) } );
+		return;
+	}
+
+	my $git = Vhffs::Services::Git::get_by_reponame( $vhffs , $repo_name );
+	unless( defined $git ) {
+		$panel->render('misc/message.tt', { message => gettext( 'Cannot get informations on this object' ) } );
+		return;
+	}
+
+	unless( $user->can_view( $git ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) } );
+		return;
+	}
+
+	save_prefs($panel, $git) if defined $cgi->param('save_prefs_submit');
+
+	$panel->set_title( gettext('Modify Git repository') );
+	my $vars = {};
+	$vars->{repository} = $git;
+	$vars->{notify_from} = $vhffs->get_config->get_service('git')->{notify_from};
+	$vars->{type} = 'git';
+	$panel->render( 'scm/prefs.tt', $vars );
+}
+
+sub save_prefs {
+	my $panel = shift;
+	my $git = shift;
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
+
+	my $public = $cgi->param('public');
+	my $ml_name = $cgi->param('ml_name');
+
+	unless( $user->can_modify($git) ) {
+		$panel->add_error( gettext('You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights') );
+		return 0;
+	}
+
+	unless( defined $public and defined $ml_name ) {
+		$panel->add_error( gettext('CGI error !') );
+		return 0;
+	}
+
+	if($public != $git->is_public) {
+		if($public == 1) {
+			$git->set_public();
+		} else {
+			$git->set_private();
+		}
+		$git->set_status(Vhffs::Constants::WAITING_FOR_MODIFICATION);
+	}
+
+	if($ml_name =~ /^\s*$/ or Vhffs::Functions::valid_mail($ml_name)) {
+		if($ml_name ne $git->get_ml_name) {
+			$git->set_ml_name($ml_name);
+			$git->set_status( Vhffs::Constants::WAITING_FOR_MODIFICATION );
+		}
+	} else {
+		$panel->add_error( gettext('Invalid mailing list address') );
+		return 0;
+	}
+
+	if($git->get_status == Vhffs::Constants::WAITING_FOR_MODIFICATION) {
+		if($git->commit > 0) {
+			my $group = Vhffs::Group::get_by_gid( $vhffs , $git->{'owner_gid'} );
+			my $url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('Modifications applied. Please wait while your repository is being updated');
+			$panel->redirect($url);
+			return 1;
+		}
+
+		$panel->add_error( gettext('Unable to apply modifications') );
+		return 0;
+	}
+
+	return 0;
+}
+
+sub index {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined($group) ) {
+		$panel->render('misc/message.tt', { message => gettext('You have to select a group first') } );
+		return;
+	}
+
+	unless($group->get_status == Vhffs::Constants::ACTIVATED) {
+		$panel->render( 'misc/message.tt', { message => gettext('This group is not activated yet') } );
+		return;
+	}
+
+	unless( $user->can_view( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+
+	$panel->set_group( $group );
+	$panel->set_title( sprintf(gettext('Git repositories for %s'), $group->get_groupname) );
+
+	my $git = Vhffs::Panel::Git::getall_per_group( $vhffs, $group->get_gid );
+	if($git < 0) {
+		$panel->render( 'misc/message.tt', { message => gettext('Unable to get Git repositories') } );
+		return;
+	}
+
+	$panel->render( 'misc/service-index.tt', {
+	  label => 'Git repositories',
+	  group => $group,
+	  list => $git,
+	  help_url => $vhffs->get_config->get_service('git')->{url_doc},
+	  type => 'git'
+	  });
+}
+
+sub search {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $name = $cgi->param('name');
+	my $vars = {};
+
+	unless( defined $name ) {
+
+		$panel->render('admin/misc/search.tt', {
+		  search_title => gettext('Git search'),
+		  type => 'git'
+		  });
+		return;
+	}
+
+	if( $name =~ /^\s*$/ ) {
+		$vars->{list_title} = gettext('List of all git repositories');
+		undef $name;
+	} else {
+		$vars->{list_title} = sprintf( gettext('Search result for %s'), $name );
+	}
+	$vars->{list} = search_git( $vhffs , $name );
+	$vars->{type} = 'git';
+	$panel->render('admin/misc/list.tt', $vars);
+}
+
+sub adminindex {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	$panel->set_title(gettext('Git repositories administration'));
+	require Vhffs::Panel::Admin;
+	$panel->render('admin/index.tt', { categories => [ Vhffs::Panel::Admin::get_git_category() ] } );
+}
+
 1;

Modified: trunk/vhffs-api/src/Vhffs/Panel/Group.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Group.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/Group.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -40,6 +40,12 @@
 
 use Vhffs::Constants;
 
+require Vhffs::Tag;
+require Vhffs::Tag::Category;
+require Vhffs::Tag::Request;
+require Vhffs::Services::MailGroup;
+
+
 =head1 NAME
 
 Vhffs::Panel::Group - Handle group information in the panel.
@@ -57,65 +63,64 @@
 
 sub getall_users
 {
-    my ($main, $gid) = @_;
-    my $sql = 'SELECT u.uid, u.username, u.firstname, u.lastname, u.mail, ug.state FROM vhffs_users u INNER JOIN vhffs_user_group ug ON ug.uid = u.uid WHERE ug.gid = ?';
-    my $dbh = $main->get_db_object;
-    my $sth = $dbh->prepare($sql) or return -1;
-    $sth->execute($gid) or return -2;
-    my $users = [];
-    while(my $u = $sth->fetchrow_hashref) {
-        $u->{active} = ($u->{state} == Vhffs::Constants::ACTIVATED);
-        $u->{state} = Vhffs::Functions::status_string_from_status_id($u->{state});
-        push @$users, $u;
-    }
-    return $users;
+	my ($main, $gid) = @_;
+	my $sql = 'SELECT u.uid, u.username, u.firstname, u.lastname, u.mail, ug.state FROM vhffs_users u INNER JOIN vhffs_user_group ug ON ug.uid = u.uid WHERE ug.gid = ?';
+	my $dbh = $main->get_db_object;
+	my $sth = $dbh->prepare($sql) or return -1;
+	$sth->execute($gid) or return -2;
+	my $users = [];
+	while(my $u = $sth->fetchrow_hashref) {
+		$u->{active} = ($u->{state} == Vhffs::Constants::ACTIVATED);
+		$u->{state} = Vhffs::Functions::status_string_from_status_id($u->{state});
+		push @$users, $u;
+	}
+	return $users;
 }
 
 sub get_last_groups {
-    my $main = shift;
-    my @groups;
+	my $main = shift;
+	my @groups;
 
-    my $sql = 'SELECT g.gid, g.groupname, g.realname, o.description, owner.username AS owner_name FROM vhffs_groups g LEFT OUTER JOIN vhffs_users u ON u.username=g.groupname INNER JOIN vhffs_object o ON o.object_id=g.object_id INNER JOIN vhffs_users owner ON owner.uid = o.owner_uid WHERE o.state=? AND u.username IS NULL ORDER BY o.date_creation DESC LIMIT 10';
+	my $sql = 'SELECT g.gid, g.groupname, g.realname, o.description, owner.username AS owner_name FROM vhffs_groups g LEFT OUTER JOIN vhffs_users u ON u.username=g.groupname INNER JOIN vhffs_object o ON o.object_id=g.object_id INNER JOIN vhffs_users owner ON owner.uid = o.owner_uid WHERE o.state=? AND u.username IS NULL ORDER BY o.date_creation DESC LIMIT 10';
 
-    return fetch_groups_and_users($main, $sql, Vhffs::Constants::ACTIVATED);
+	 return fetch_groups_and_users($main, $sql, Vhffs::Constants::ACTIVATED);
 }
 
-sub search
+sub search_group
 {
-    my ($main, $name) = @_;
+	my ($main, $name) = @_;
 
-    my @params;
-    my $sql = 'SELECT g.groupname, o.state, u.username as owner_user '.
-        'FROM vhffs_groups g '.
-        'INNER JOIN vhffs_object o ON (g.object_id = o.object_id) '.
-        'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) '.
-        'LEFT JOIN vhffs_users uu ON (uu.username = g.groupname) '.
-        'WHERE uu.username IS NULL ';
+	my @params;
+	my $sql = 'SELECT g.groupname, o.state, u.username as owner_user '.
+	  'FROM vhffs_groups g '.
+	  'INNER JOIN vhffs_object o ON (g.object_id = o.object_id) '.
+	  'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) '.
+	  'LEFT JOIN vhffs_users uu ON (uu.username = g.groupname) '.
+	  'WHERE uu.username IS NULL ';
 
 	if( defined $name ) {
-        $sql .= ' AND g.groupname LIKE ? ';
-        push(@params, '%'.lc($name).'%');
+		$sql .= ' AND g.groupname LIKE ? ';
+		push(@params, '%'.lc($name).'%');
 	}
 
-    $sql .= 'ORDER BY g.groupname';
+	$sql .= 'ORDER BY g.groupname';
 
-    my $dbh = $main->get_db_object();
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
+	my $dbh = $main->get_db_object();
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
 }
 
 
 sub public_search {
-    my ($main, $groupname, $description, $included_tags, $excluded_tags, $start) = @_;
+	my ($main, $groupname, $description, $included_tags, $excluded_tags, $start) = @_;
 
-    my $sql =
-' FROM vhffs_groups g 
-	LEFT OUTER JOIN vhffs_users u ON u.username=g.groupname
-	INNER JOIN vhffs_object o ON o.object_id=g.object_id
-	INNER JOIN vhffs_users owner ON owner.uid = o.owner_uid
-	WHERE o.state=? AND u.username IS NULL';
+	my $sql = ' FROM vhffs_groups g 
+	  LEFT OUTER JOIN vhffs_users u ON u.username=g.groupname
+	  INNER JOIN vhffs_object o ON o.object_id=g.object_id
+	  INNER JOIN vhffs_users owner ON owner.uid = o.owner_uid
+	  WHERE o.state=? AND u.username IS NULL';
 
 	my @params;
-    push @params, Vhffs::Constants::ACTIVATED;
+	push @params, Vhffs::Constants::ACTIVATED;
     
 	if($groupname =~ /\S/) {
 		$sql .= ' AND g.groupname ILIKE ?';
@@ -198,69 +203,645 @@
 
 	my $group = Vhffs::Group::create($main, $groupname, $realname, $user->get_uid, undef, $description);
 
-    return undef unless( defined $group );
+	return undef unless( defined $group );
 
 	return undef if ($group->add_user( $user->get_uid ) < 0 );
 
-    return undef if ( Vhffs::Acl::add_acl( $user , $group , Vhffs::Constants::ACL_DELETE , $main ) < 0 ); 
-    return undef if ( Vhffs::Acl::add_acl( $group , $group , Vhffs::Constants::ACL_VIEW , $main ) < 0 );
+	return undef if ( Vhffs::Acl::add_acl( $user , $group , Vhffs::Constants::ACL_DELETE , $main ) < 0 ); 
+	return undef if ( Vhffs::Acl::add_acl( $group , $group , Vhffs::Constants::ACL_VIEW , $main ) < 0 );
 
 	return $group;
 }
 
 sub get_groups_starting_with {
-    my ($main, $letter, $starting, $count) = @_;
-    my @params;
+	my ($main, $letter, $starting, $count) = @_;
+	my @params;
 
-    my $select_clause = 'SELECT g.gid, g.groupname, g.realname, o.description, owner.username as owner_name';
-    my $sql = ' FROM vhffs_groups g '.
-    	'LEFT OUTER JOIN vhffs_users u ON u.username=g.groupname '.
-    	'INNER JOIN vhffs_object o ON o.object_id=g.object_id '.
-    	'INNER JOIN vhffs_users owner ON owner.uid = o.owner_uid '.
-    	'WHERE o.state=? AND u.username IS NULL';
-    push @params, Vhffs::Constants::ACTIVATED;
-    if(defined $letter) {
-        $sql .=  ' AND SUBSTR(g.groupname, 1, 1) = ?';
-        push @params, $letter;
-    }
+	my $select_clause = 'SELECT g.gid, g.groupname, g.realname, o.description, owner.username as owner_name';
+	my $sql = ' FROM vhffs_groups g '.
+	  'LEFT OUTER JOIN vhffs_users u ON u.username=g.groupname '.
+	  'INNER JOIN vhffs_object o ON o.object_id=g.object_id '.
+	  'INNER JOIN vhffs_users owner ON owner.uid = o.owner_uid '.
+	  'WHERE o.state=? AND u.username IS NULL';
+	push @params, Vhffs::Constants::ACTIVATED;
+	if(defined $letter) {
+		$sql .=  ' AND SUBSTR(g.groupname, 1, 1) = ?';
+		push @params, $letter;
+	}
     
-    my $order_clause = ' ORDER BY g.groupname LIMIT '.$count.' OFFSET '.$starting;
-    return Vhffs::Panel::Commons::fetch_slice_and_count($main, $select_clause, $sql, ' ORDER BY groupname', $starting, $count, \@params, \&Vhffs::Panel::Group::fetch_groups_and_users);
+	my $order_clause = ' ORDER BY g.groupname LIMIT '.$count.' OFFSET '.$starting;
+	return Vhffs::Panel::Commons::fetch_slice_and_count($main, $select_clause, $sql, ' ORDER BY groupname', $starting, $count, \@params, \&Vhffs::Panel::Group::fetch_groups_and_users);
 }
 
 sub fetch_groups_and_users {
-    my ($main, $sql, @params) = @_;
-    my @groups;
+	my ($main, $sql, @params) = @_;
+	my @groups;
 
 
-    my $dbh = $main->get_db_object;
-    my $sth = $dbh->prepare($sql);
-    $sql = 'SELECT u.username FROM vhffs_users u INNER JOIN vhffs_user_group ug ON ug.uid = u.uid WHERE ug.gid = ?';
-    my $usth = $dbh->prepare($sql);
-    # FIXME fetch object_id along with gid in every caller and suppress vhffs_groups from the query
-    $sql = 'SELECT c.tag_category_id as category_id, c.label as category_label, t.tag_id, t.label as tag_label '.
-            'FROM vhffs_tag t INNER JOIN vhffs_tag_category c ON c.tag_category_id = t.category_id '.
-            'INNER JOIN vhffs_object_tag ot ON ot.tag_id = t.tag_id '.
-            'INNER JOIN vhffs_groups g ON g.object_id = ot.object_id '.
-            'WHERE g.gid = ? AND c.visibility = ?';
-    my $tsth = $dbh->prepare($sql);
-    $sth->execute(@params);
-    while(my $row = $sth->fetchrow_hashref) {
-        $usth->execute($row->{gid});
-        $row->{users} = $usth->fetchall_arrayref({});
-        $tsth->execute($row->{gid}, Vhffs::Constants::TAG_VISIBILITY_PUBLIC);
-        $row->{tags} = $tsth->fetchall_arrayref({});
-        push @groups, $row;
-    }
+	my $dbh = $main->get_db_object;
+	my $sth = $dbh->prepare($sql);
+	$sql = 'SELECT u.username FROM vhffs_users u INNER JOIN vhffs_user_group ug ON ug.uid = u.uid WHERE ug.gid = ?';
+	my $usth = $dbh->prepare($sql);
+	# FIXME fetch object_id along with gid in every caller and suppress vhffs_groups from the query
+	$sql = 'SELECT c.tag_category_id as category_id, c.label as category_label, t.tag_id, t.label as tag_label '.
+	  'FROM vhffs_tag t INNER JOIN vhffs_tag_category c ON c.tag_category_id = t.category_id '.
+	  'INNER JOIN vhffs_object_tag ot ON ot.tag_id = t.tag_id '.
+	  'INNER JOIN vhffs_groups g ON g.object_id = ot.object_id '.
+	  'WHERE g.gid = ? AND c.visibility = ?';
+	my $tsth = $dbh->prepare($sql);
+	$sth->execute(@params);
+	while(my $row = $sth->fetchrow_hashref) {
+		$usth->execute($row->{gid});
+		$row->{users} = $usth->fetchall_arrayref({});
+		$tsth->execute($row->{gid}, Vhffs::Constants::TAG_VISIBILITY_PUBLIC);
+		$row->{tags} = $tsth->fetchall_arrayref({});
+		push @groups, $row;
+	}
 
-    return \@groups;
+	return \@groups;
 }
 
 sub get_used_letters {
-    my $main = shift;
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT substr(g.groupname, 1, 1) AS letter, COUNT(*) AS count FROM vhffs_groups g LEFT OUTER JOIN vhffs_users u ON u.username = g.groupname INNER JOIN vhffs_object o ON o.object_id = g.object_id WHERE u.username IS NULL AND o.state = ? GROUP BY substr(g.groupname, 1, 1) ORDER BY substr(g.groupname, 1, 1)';
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, Vhffs::Constants::ACTIVATED);
+	my $main = shift;
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT substr(g.groupname, 1, 1) AS letter, COUNT(*) AS count FROM vhffs_groups g LEFT OUTER JOIN vhffs_users u ON u.username = g.groupname INNER JOIN vhffs_object o ON o.object_id = g.object_id WHERE u.username IS NULL AND o.state = ? GROUP BY substr(g.groupname, 1, 1) ORDER BY substr(g.groupname, 1, 1)';
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, Vhffs::Constants::ACTIVATED);
 }
 
+sub index {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	$panel->set_title( gettext('My Projects') );
+
+	require Vhffs::Panel::User;
+	$panel->render('group/index.tt', {
+	  owned_projects => Vhffs::Panel::User::get_groups($user, $Vhffs::Panel::User::RELATION_OWNER),
+	  contributed_projects => Vhffs::Panel::User::get_groups($user, $Vhffs::Panel::User::RELATION_CONTRIB)
+	  } );
+}
+
+sub create {
+	my $panel = shift;
+
+	my $vhffs = $panel->{vhffs};
+	my $cgi = $panel->{cgi};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $submitted = defined($cgi->param('project_submit'));
+	my $groupname = $cgi->param('project_name');
+	my $realname = Encode::decode_utf8( $cgi->param('realname') );
+	my $description = Encode::decode_utf8( $cgi->param('description') );
+
+	if($submitted) {
+		# User posted the form, let's check it
+		$panel->add_error( gettext('Groupname must contain between 3 and 12 characters, only letters or numbers in lower case') ) unless $groupname =~ /^[a-z0-9]{3,12}$/;
+		$panel->add_error( gettext('You must enter a description') ) unless defined $description and $description !~ /^\s*$/;
+		$panel->add_error( gettext('You must enter a full name') ) unless defined $realname and $realname !~ /^\s*$/;
+		$panel->add_error( gettext('The first letter of groupname and full name must be the same') ) unless defined $realname and substr($groupname,0,1) eq lc substr($realname,0,1);
+
+		unless( $panel->has_errors() ) {
+			my $group = Vhffs::Panel::Group::create_group( $groupname , $realname, $user , $vhffs, $description );
+			unless( defined $group ) {
+				$panel->add_error( gettext('Error creating group (maybe a group with the same name already exists)') );
+			} else {
+				# Creation succeeded. Since we don't care about the correctness
+				# of the tags we were passed, we don't do display any error messages
+				my @tags = $cgi->param('tags');
+				foreach my $tag_id (@tags) {
+					my $tag = Vhffs::Tag::get_by_tag_id($vhffs, $tag_id);
+					$group->add_tag($tag, $user) if defined $tag and $tag->get_category()->{visibility} == Vhffs::Constants::TAG_VISIBILITY_GROUP_CREATION;
+				}
+				my $url = '?do=groupindex&amp;msg='.gettext('Project Successfully created !');
+				$panel->redirect($url);
+				return;
+			}
+		}
+	}
+
+	if( not $submitted or $panel->has_errors() ) {
+		my $vars = {};
+		$vars->{public_part_available} = $panel->is_public;
+
+		$panel->set_title( gettext('Create a Project') );
+		$vars->{owner} = $user->get_username;
+		$vars->{groupname} = $groupname;
+		$vars->{realname} = $realname;
+		$vars->{description} = $description;
+
+		require Vhffs::Tag::Category;    
+		my $categories = Vhffs::Tag::Category::get_all($vhffs, Vhffs::Constants::TAG_VISIBILITY_GROUP_CREATION);
+		foreach my $c (@{$categories}) {
+			$c->{tags} = Vhffs::Tag::get_by_category_id($vhffs, $c->{category_id});
+		}
+    
+		$vars->{tag_categories} = $categories;
+
+		$panel->render('group/create.tt', $vars);
+	}
+}
+
+sub view {
+	my $panel = shift;
+
+	my $vhffs = $panel->{vhffs};
+	my $cgi = $panel->{cgi};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You must specify a project name' ) });
+		return;
+	}
+	$panel->set_group( $group );
+
+	my $vars = { group => $group };
+	my $config = $vhffs->get_config;
+	my $groups_config = $config->get_groups;
+	my $services = {};
+	my $services_help = {};
+	my $services_labels = {
+		cvs => 'CVS repositories',
+		dns => 'Domain names',
+		mail => 'Mail domains',
+		mailinglist => 'Mailing lists',
+		mysql => 'MySQL DBs',
+		pgsql => 'PostgreSQL DBs',
+		repository => 'Download repositories',
+		svn => 'SVN repositories',
+		git => 'Git repositories',
+		mercurial => 'Mercurial repositories',
+		bazaar => 'Bazaar repositories',
+		web => 'Webareas',
+		cron => 'Cron jobs',
+	};
+
+	$panel->set_title( sprintf( gettext("Group %s") , $group->get_groupname ) );
+	$vars->{help_url} = $groups_config->{url_doc} if defined $groups_config and defined $groups_config->{url_doc};
+
+	foreach my $s(qw/web mysql pgsql cvs svn git mercurial bazaar mailinglist mail repository dns cron/) {
+		next unless $config->get_service_availability($s);
+		my $module = 'Vhffs::Panel::'.($s eq 'dns' ? 'DNS' : ($s eq 'mailinglist' ? 'MailingList' : ucfirst($s)));
+		eval("require $module;");
+		{
+			no strict 'refs';
+			$services->{$s} = &{"$module\::getall_per_group"}($vhffs, $group->get_gid);
+			$services_help->{$s} = $config->get_service($s)->{url_doc} if defined $config->get_service($s)->{url_doc};
+		}
+	}
+	$vars->{services} = $services;
+	$vars->{services_help} = $services_help;
+	$vars->{services_labels} = $services_labels;
+
+	$panel->render('group/info.tt', $vars);
+}
+
+sub prefs {
+	my $panel = shift;
+
+	my $vhffs = $panel->{vhffs};
+	my $cgi = $panel->{cgi};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	my $vars = {};
+
+	unless( defined $group ) {
+		$panel->render('misc/message.tt', { message => gettext( "Error. This group doesn't exists") });
+		return;
+	}
+
+	unless( $user->can_view( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) } );
+		return;
+	}
+
+	$panel->set_group( $group );
+
+	if( defined( $cgi->param( 'update_desc_submit' ) ) ) {
+		# Description modification
+		unless( $user->can_modify( $group ) ) {
+			$panel->add_error( gettext( 'You\'re not allowed to do this (ACL rights)' ) );
+		} else {
+			my $description = Encode::decode_utf8( $cgi->param( 'description' ) );
+			my $realname = Encode::decode_utf8( $cgi->param( 'realname' ) );
+
+			$panel->add_error( gettext('You must enter a description') ) unless defined $description and $description !~ /^\s*$/;
+			$panel->add_error( gettext('You must enter a full name') ) unless defined $realname and $realname !~ /^\s*$/;
+			$panel->add_error( gettext('The first letter of groupname and full name must be the same') ) unless defined $realname and substr($group->get_groupname,0,1) eq lc substr($realname,0,1);
+
+			unless( $panel->has_errors() ) {
+				$group->set_description($description);
+				$group->set_realname($realname);
+				if($group->commit < 0) {
+					$panel->add_error( gettext('An error occured while updating the project') );
+				} else {
+					$panel->add_info( gettext('Group updated') );
+				}
+			}
+		}
+
+	} elsif( defined( $cgi->param( 'remove_user_submit' ) ) ) {
+		# User removal
+		my $uid = $cgi->param( 'uid' );
+		unless( defined $uid and $uid =~ /^\d+$/ ) {
+			$panel->add_error( gettext('CGI Error !') );
+		} else {
+			unless( $uid == $user->get_uid or $user->can_modify( $group ) )  {
+				$panel->add_error( gettext( 'You\'re not allowed to do this (ACL rights)' ) );	
+			} elsif( $uid == $group->get_owner_uid ) {
+				$panel->add_error( gettext('You cannot remove the owner of the group') );
+			} elsif( not $user->is_admin ) {
+				$panel->add_error( gettext('Only an administrator can remove someone from a group, please contact the administration team') );
+			} elsif( $group->remove_user($uid) ) {
+				$panel->add_info( gettext('This user will be removed from this group as soon as possible') );
+			} else {
+				$panel->add_error( gettext('Unable to remove user from group') );
+			}
+		}
+
+	} elsif( defined( $cgi->param( 'add_user_submit' ) ) ) {
+		unless( $user->can_modify( $group ) ) {
+			$panel->add_error( gettext( 'You\'re not allowed to do this (ACL rights)' ) );
+		} else {
+			my $username = $cgi->param( 'username' );
+			unless( defined $username ) {
+				$panel->add_error( gettext('CGI Error !') );
+			} elsif( $username =~ /^\s*$/ ) {
+				$vars->{add_user_error} = gettext('You must enter an username');
+			} else {
+				# First, we try to get an user with the *exact* name
+				my $new_user = Vhffs::User::get_by_username( $vhffs, $username);
+				if(defined $new_user) {
+					# Fine, user exists, let's add it
+					if( $group->add_user( $new_user->get_uid ) ) {
+						$vars->{add_user_info} = gettext('User will be added as soon as possible');
+					} else {
+						$vars->{add_user_error} = gettext('Unable to add user, he might already be in the group (waiting for addition or deletion)');
+					}
+				} else {
+					# User not found with exact match,let's search
+					my $users = Vhffs::Panel::User::search( $vhffs , $username );
+					unless( @{$users} ) {
+						$vars->{add_user_error} = gettext('User not found');
+					} else {
+						$vars->{add_user_info} = gettext('Several users matched your query. Please choose between them.');
+						$vars->{add_user_list} = $users;
+					}
+				}
+			}
+		}
+
+	} elsif( defined( $cgi->param('add_user_list_submit') ) ) {
+		unless( $user->can_modify( $group ) ) {
+			$panel->add_error( gettext( 'You\'re not allowed to do this (ACL rights)' ) );
+		} else {
+			my $uid = $cgi->param( 'uid' );
+			unless( defined $uid and $uid =~ /^\d+$/ ) {
+				$panel->add_error( gettext('CGI Error !') );
+			} else {
+				if( $group->add_user( $uid ) ) {
+					$vars->{add_user_info} = gettext('User will be added as soon as possible');
+				} else {
+					$vars->{add_user_error} = gettext('Unable to add user, he might already be in the group (waiting for addition or deletion)');
+				} 
+			}
+		}
+
+	} elsif( defined( $cgi->param('contact_email_submit') ) ) {
+		unless( $vhffs->get_config->get_service_availability('mailgroup')  &&  $user->can_modify( $group ) ) {
+			$panel->add_error( gettext( 'You\'re not allowed to do this (ACL rights)' ) );
+		} else {
+			my $forward = $cgi->param( 'contact_email' );
+			unless( defined $forward  &&  ( $forward eq ''  ||  Vhffs::Functions::valid_mail( $forward ) )  ) {
+				$panel->add_error( gettext('The email you entered fails syntax check') );
+			} else {
+				my $mg = init Vhffs::Services::MailGroup( $vhffs , $group );
+				if( defined $mg ) {
+					if( $forward eq '' )  {
+						$mg->delforward( $forward );
+						$panel->add_info( gettext('Forward deleted') );
+					} else {
+						$mg->addforward( $forward );
+						$panel->add_info( gettext('Forward added') );
+					}
+				}
+			}
+		}
+
+	} elsif( defined( $cgi->param('update_quota_submit')) ) {
+		update_quota( $panel, $group );
+
+	} elsif( defined( $cgi->param('add_tag_submit') ) ) {
+		add_tag( $panel, $group );
+
+	} elsif( defined( $cgi->param('delete_tag_submit') ) ) {
+		delete_tag( $panel, $group );
+
+	} elsif( defined( $cgi->param('request_tag_submit') ) ) {
+		request_tag( $panel, $group );
+
+	} elsif( defined( $cgi->param('cancel_tag_request_submit') ) ) {
+		cancel_request( $panel, $group );
+	}
+
+	$panel->set_title( gettext('Project Preferences') );
+
+	$vars->{group} = $group;
+	$vars->{mailgroup} = init Vhffs::Services::MailGroup( $vhffs , $group );
+	$vars->{use_avatars} = $panel->use_groups_avatars;
+	$vars->{group_users} = Vhffs::Panel::Group::getall_users( $vhffs , $group->get_gid );
+
+	fill_tags( $panel, $group, $vars );
+	$panel->render('group/prefs.tt', $vars);
+}
+
+
+sub update_quota {
+	my $panel = shift;
+	my $group = shift;
+	my $cgi = $panel->{cgi};
+	my $user = $panel->{user};
+
+	my $quota = $cgi->param('new_quota');
+	unless(defined $quota and $quota =~ /^\d+$/) {
+		$panel->add_error( gettext('Invalid quota') );
+		return;
+	}
+
+	unless($user->is_admin()) {
+		$panel->add_error( gettext('Only administrators are allowed to do this') );
+		return;
+	}
+
+	$group->set_quota($quota);
+
+	if($group->commit < 0) {
+		$panel->add_error( gettext('Unable to apply modifications, please try again later') );
+	} else {
+		$panel->add_info( gettext('Group updated, please wait while quota is updated on filesystem') );
+	}
+}
+
+sub fill_tags {
+	my $panel = shift;
+	my $group = shift;
+	my $vars = shift;
+	my $vhffs = $panel->{vhffs};
+	my $user = $panel->{user};
+
+	my $visibility = ($user->is_admin() ? Vhffs::Constants::TAG_VISIBILITY_ADMINS :
+	  ($user->is_moderator() ? Vhffs::Constants::TAG_VISIBILITY_MODERATORS :
+	  Vhffs::Constants::TAG_VISIBILITY_PUBLIC) ); 
+
+	my $categories = Vhffs::Tag::Category::get_all($vhffs, $visibility);
+	foreach my $c (@{$categories}) {
+		$c->{tags} = Vhffs::Tag::get_by_category_id($vhffs, $c->{category_id});
+	}
+	$vars->{tag_categories} = $categories;
+	$vars->{current_tag_categories} = $group->get_tags($visibility);
+	$vars->{tag_requests} = $group->get_tag_requests();
+}
+
+sub add_tag {
+	my $panel = shift;
+	my $group = shift;
+	my $vhffs = $panel->{vhffs};
+	my $cgi = $panel->{cgi};
+	my $user = $panel->{user};
+
+	unless( $user->can_modify( $group ) or $user->is_moderator) {
+		$panel->add_error( gettext( 'You\'re not allowed to do this (ACL rights)' ) );
+		return 0;
+	}
+	
+	my $tag_id = $cgi->param('tag_id');
+	
+	unless(defined $tag_id) {
+		$panel->add_error( gettext('CGI error') );
+		return 0;
+	}
+	
+	my $tag = Vhffs::Tag::get_by_tag_id($vhffs, $tag_id);
+	
+	unless(defined $tag) {
+		$panel->add_error( gettext('Tag not found') );
+		return 0;
+	}
+	
+	if( ($tag->{visibility} >= Vhffs::Constants::TAG_VISIBILITY_ADMINS && !$user->is_admin()) ||
+		($tag->{visibility} >= Vhffs::Constants::TAG_VISIBILITY_MODERATORS && !$user->is_moderator())) {
+		$panel->add_error( gettext('You don\'t have enough privileges to add this tag') );
+		return 0;
+	}
+	
+	if($group->add_tag($tag, $user)) {
+		$panel->add_info( gettext('Tag added') );
+	} else {
+		$panel->add_error( gettext('Unable to add tag, check it was not already added to your project') );
+	}
+}
+
+sub delete_tag {
+	my $panel = shift;
+	my $group = shift;
+	my $vhffs = $panel->{vhffs};
+	my $cgi = $panel->{cgi};
+	my $user = $panel->{user};
+
+	unless( $user->can_modify( $group ) or $user->is_moderator) {
+		$panel->add_error( gettext( 'You\'re not allowed to do this (ACL rights)' ) );
+		return 0;
+	}
+	
+	my $tag_id = $cgi->param('tag_id');
+	
+	unless(defined $tag_id) {
+		$panel->add_error( gettext('CGI error') );
+		return 0;
+	}
+	
+	my $tag = Vhffs::Tag::get_by_tag_id($vhffs, $tag_id);
+	
+	unless(defined $tag) {
+		$panel->add_error( gettext('Tag not found') );
+		return 0;
+	}
+	
+	if( ($tag->{visibility} >= Vhffs::Constants::TAG_VISIBILITY_ADMINS && !$user->is_admin()) ||
+		($tag->{visibility} >= Vhffs::Constants::TAG_VISIBILITY_MODERATORS && !$user->is_moderator())) {
+		$panel->add_error( gettext('You don\'t have enough privileges to delete this tag') );
+		return 0;
+	}
+	
+	if($group->delete_tag($tag, $user)) {
+		$panel->add_info( gettext('Tag deleted') );
+	} else {
+		$panel->add_error( gettext('Unable to delete tag') );
+	}
+}
+
+sub request_tag {
+	my $panel = shift;
+	my $group = shift;
+	my $vhffs = $panel->{vhffs};
+	my $cgi = $panel->{cgi};
+	my $user = $panel->{user};
+
+	unless( $user->can_modify( $group ) ) {
+		$panel->add_error( gettext( 'You\'re not allowed to do this (ACL rights)' ) );
+		return 0;
+	}
+	
+	my $category_label = $cgi->param('category');
+	my $tag_label = $cgi->param('tag');
+	
+	unless(defined $category_label && defined $tag_label) {
+		$panel->add_error( gettext('CGI error') );
+		return 0;
+	}
+	
+	if($category_label =~ /^\s*$/) {
+		$panel->add_error( gettext('Category can\'t be empty') );
+		return 0;
+	}
+	
+	if($tag_label =~ /^\s*$/) {
+		$panel->add_error( gettext('Tag name can\'t be empty') );
+		return 0;
+	}
+	
+	unless( defined(Vhffs::Tag::Request::create($vhffs, $category_label, $tag_label, $user, $group) ) ) {
+		$panel->add_error( gettext('An error occured while saving your request') );
+		return;
+	}
+	
+	$panel->add_info( gettext('Tag request saved, please wait while a moderator approve it') );	
+}
+
+sub cancel_request {
+	my $panel = shift;
+	my $group = shift;
+	my $vhffs = $panel->{vhffs};
+	my $cgi = $panel->{cgi};
+	my $user = $panel->{user};
+
+	unless( $user->can_modify( $group ) ) {
+		$panel->add_error( gettext( 'You\'re not allowed to do this (ACL rights)' ) );
+		return 0;
+	}
+	
+	my $request_id = $cgi->param('request_id');
+	
+	my $request = Vhffs::Tag::Request::get_by_request_id($vhffs, $request_id);
+	
+	unless(defined $request) {
+		$panel->add_error( gettext('Request not found') );
+		return 0;
+	}
+	
+	if($request->{tagged_id} != $group->get_oid()) {
+		$panel->add_error( gettext('You can only delete requests attached to your group') );
+		return 0;
+	}
+	
+	$request->delete();
+	
+	$panel->add_info( gettext('Request canceled') );
+	return 1;
+}
+
+sub history {
+	my $panel = shift;
+
+	my $vhffs = $panel->{vhffs};
+	my $cgi = $panel->{cgi};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+
+	unless( defined $group ) {
+		$panel->render('misc/message.tt', { message => gettext( 'Error. This group doesn\'t exists') });
+		return;
+	}
+
+	unless( $group->get_status == Vhffs::Constants::ACTIVATED ) {
+		$panel->render('misc/message.tt', { message => gettext( 'This object is not functional yet. Please wait creation or moderation.') });
+		return;
+	}
+
+	unless( $user->can_view( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+
+	$panel->set_group( $group );
+	$panel->set_title( gettext('Project History') );
+
+	require DateTime;
+	require DateTime::Locale;
+	my $loc = DateTime::Locale->load($user->get_lang);
+
+	my $history = $group->get_full_history;
+	foreach (@{$history}) {
+		my $dt = DateTime->from_epoch( epoch => $_->{date}, locale => $user->get_lang);
+		$_->{object} = Vhffs::ObjectFactory::fetch_object( $vhffs , $_->{object_id} );
+		$_->{object_type} = Vhffs::Functions::type_string_from_type_id( $_->{type} );
+	}
+	$panel->render('misc/history.tt', { history => $history });
+}
+
+sub search {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $name = $cgi->param('name');
+	my $vars = {};
+
+	unless( defined $name ) {
+
+		$panel->render('admin/misc/search.tt', {
+		  search_title => gettext('Groups search'),
+		  type => 'group'
+		  });
+		return;
+	}
+
+	if( $name =~ /^\s*$/ ) {
+		$vars->{list_title} = gettext('List of all groups');
+		undef $name;
+	} else {
+		$vars->{list_title} = sprintf( gettext('Search result for %s'), $name );
+	}
+	$vars->{groups} = search_group( $vhffs , $name );
+	$panel->render('admin/group/list.tt', $vars);
+}
+
+sub adminindex {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	$panel->set_title(gettext('Groups\' administration'));
+	require Vhffs::Panel::Admin;
+	$panel->render('admin/index.tt', { categories => [ Vhffs::Panel::Admin::get_group_category() ] } );
+}
+
 1;

Added: trunk/vhffs-api/src/Vhffs/Panel/Home.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Home.pm	                        (rev 0)
+++ trunk/vhffs-api/src/Vhffs/Panel/Home.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -0,0 +1,71 @@
+#!%PERL%
+# Copyright (c) vhffs project and its contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#2. Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution.
+#3. Neither the name of vhffs nor the names of its contributors
+#   may be used to endorse or promote products derived from this
+#   software without specific prior written permission.
+#
+#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use utf8;
+
+package Vhffs::Panel::Home;
+
+use POSIX qw(locale_h);
+use locale;
+use Locale::gettext;
+use Encode;
+
+use Vhffs::Constants;
+use Vhffs::Functions;
+use Vhffs::User;
+
+
+sub home {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $vars = {};
+
+	$panel->set_title( sprintf( gettext('Hello %s, welcome in VHFFS !'), $user->get_username() ) );
+
+	# check groups quota
+	my @overquota;
+	foreach my $group ( @{$user->get_groups} ) {
+		my $quota = $group->get_quota;
+		my $curused = $group->get_quota_used;
+		push @overquota, $group->get_groupname if $curused > $quota-$quota/10;
+	}
+	$vars->{overquota} = \@overquota;
+
+	$panel->render( 'misc/welcome.tt', $vars );
+}
+
+1;

Modified: trunk/vhffs-api/src/Vhffs/Panel/Mail.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Mail.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/Mail.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -39,25 +39,25 @@
 use Locale::gettext;
 use Vhffs::Services::Mail;
 
-sub search {
-    my ($main, $name) = @_;
+sub search_mail {
+	my ($main, $name) = @_;
 
-    my @params;
-    my $sql = 'SELECT m.domain as label, g.groupname as owner_group, o.state, u.username as owner_user '.
-        'FROM vhffs_mxdomain m '.
-        'INNER JOIN vhffs_object o ON (o.object_id = m.object_id) '.
-        'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
-        'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
+	my @params;
+	my $sql = 'SELECT m.domain as label, g.groupname as owner_group, o.state, u.username as owner_user '.
+	  'FROM vhffs_mxdomain m '.
+	  'INNER JOIN vhffs_object o ON (o.object_id = m.object_id) '.
+	  'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
+	  'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
 
-    if( defined $name ) {
-        $sql .= 'WHERE m.domain LIKE ? ';
-        push(@params, '%'.lc($name).'%');
-    }
+	if( defined $name ) {
+		$sql .= 'WHERE m.domain LIKE ? ';
+		push(@params, '%'.lc($name).'%');
+	}
 
-    $sql .= 'ORDER BY label';
+	$sql .= 'ORDER BY label';
 
-    my $dbh = $main->get_db_object();
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
+	my $dbh = $main->get_db_object();
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
 }
 
 =pod
@@ -72,22 +72,21 @@
 =cut
 
 
-sub getall_per_group
-{
-    my ( $main, $gid ) = @_;
+sub getall_per_group {
+	my ( $main, $gid ) = @_;
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT m.object_id AS oid, m.domain AS displayname, o.state FROM vhffs_mxdomain m INNER JOIN vhffs_object o ON m.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY m.domain';
-    my $sth = $dbh->prepare($sql) or return -1;
-    $sth->execute($gid) or return -2;
-    my $mails = [];
-    while(my $m = $sth->fetchrow_hashref) {
-        $m->{active} = ($m->{state} == Vhffs::Constants::ACTIVATED);
-        $m->{refused} = ($m->{state} == Vhffs::Constants::VALIDATION_REFUSED);
-        $m->{state} = Vhffs::Functions::status_string_from_status_id($m->{state});
-        push @$mails, $m;
-    }
-    return $mails;
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT m.object_id AS oid, m.domain AS displayname, o.state FROM vhffs_mxdomain m INNER JOIN vhffs_object o ON m.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY m.domain';
+	my $sth = $dbh->prepare($sql) or return -1;
+	$sth->execute($gid) or return -2;
+	my $mails = [];
+	while(my $m = $sth->fetchrow_hashref) {
+		$m->{active} = ($m->{state} == Vhffs::Constants::ACTIVATED);
+		$m->{refused} = ($m->{state} == Vhffs::Constants::VALIDATION_REFUSED);
+		$m->{state} = Vhffs::Functions::status_string_from_status_id($m->{state});
+		push @$mails, $m;
+	}
+	return $mails;
 }
 
 =pod
@@ -102,31 +101,455 @@
 =cut
 
 sub is_owned_by_group($$$) {
-    my ($main, $domain, $gid) = @_;
+	my ($main, $domain, $gid) = @_;
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT COUNT(*) FROM vhffs_mxdomain m INNER JOIN vhffs_object o ON o.object_id = m.object_id WHERE m.domain = ? AND o.owner_gid = ?';
-    my $sth = $dbh->prepare( $sql );
-    $sth->execute( $domain, $gid );
-    my ($count) = $sth->fetchrow_array();
-    return $count > 0;
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT COUNT(*) FROM vhffs_mxdomain m INNER JOIN vhffs_object o ON o.object_id = m.object_id WHERE m.domain = ? AND o.owner_gid = ?';
+	my $sth = $dbh->prepare( $sql );
+	$sth->execute( $domain, $gid );
+	my ($count) = $sth->fetchrow_array();
+	return $count > 0;
 }
 
-sub create_mail
-{
-        my( $main , $domain , $description, $user , $group ) = @_;
+sub create_mail {
+	my( $main , $domain , $description, $user , $group ) = @_;
+	return undef unless defined $user;
+	return undef unless defined $group;
         
-        return undef if( ! defined $user );
-        return undef if( ! defined $group );
-        
-        my $mail = Vhffs::Services::Mail::create($main, $domain, $description, $user, $group);
+	my $mail = Vhffs::Services::Mail::create($main, $domain, $description, $user, $group);
+	return undef unless defined $mail;
 
-        return undef unless ( defined $mail );
+	return undef if Vhffs::Acl::add_acl( $user , $mail , Vhffs::Constants::ACL_DELETE , $main ) < 0;
+	return undef if Vhffs::Acl::add_acl( $group , $mail , Vhffs::Constants::ACL_VIEW , $main ) < 0;
 
-        return undef if ( Vhffs::Acl::add_acl( $user , $mail , Vhffs::Constants::ACL_DELETE , $main ) < 0 );
-        return undef if( Vhffs::Acl::add_acl( $group , $mail , Vhffs::Constants::ACL_VIEW , $main ) < 0 );
+	return $mail;
+}
 
-        return $mail;
+sub create {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group and $user->can_modify( $group ) ) {
+		$panel->render('message/misc.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+	$panel->set_group( $group );
+
+	my $submitted = defined($cgi->param('mail_submit'));
+	my $domain = '';
+	my $description = '';
+	my $vars = {};
+
+	if( $submitted ) {
+		$domain = $cgi->param('domain');
+		$description = Encode::decode_utf8( $cgi->param('description') );
+		unless( defined $domain and defined $description ) {
+			$panel->add_error( gettext('CGI Error !') );
+		} else {
+			$panel->add_error( gettext('Invalid domain name') ) unless Vhffs::Functions::check_domain_name($domain);
+			$panel->add_error( gettext('You must enter a description') ) unless $description !~ /^\s*$/;
+		}
+
+		unless( $panel->has_errors() ) {
+			my $mail = Vhffs::Panel::Mail::create_mail( $vhffs , $domain , $description, $user , $group );
+			if( defined $mail ) {
+				my $url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('Mail domain successfully created !');
+				$panel->redirect($url);
+				return;
+			}
+
+			$panel->add_error( gettext('An error occured while creating the mail area') );
+		}
+
+		$vars->{domain} = $domain;
+		$vars->{description} = $description;
+	}
+	
+	$vars->{group} = $group;
+	$panel->set_title( gettext('Create a mail space') );
+	$panel->render('mail/create.tt', $vars);
 }
 
+sub prefs {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $mail_config = $vhffs->get_config->get_service('mail');
+	my $domain = $cgi->param('name');
+
+	my $mail = Vhffs::Services::Mail::get_by_mxdomain( $vhffs , $domain );
+	unless( defined $mail ) {
+		$panel->render('misc/message.tt', { message => sprintf( gettext('Unable to get information on mail domain %s'), $domain ) } );
+		return;
+	}
+
+	unless( $user->can_view($mail) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) } );
+		return;
+	}
+
+	my $catchall_type = lc($mail_config->{allowed_catchall});
+	$catchall_type = 'domain' unless(defined $catchall_type and $catchall_type ne '');
+
+	if( defined $cgi->param('modify_catchall_submit') ) {
+		update_catchall($panel, $mail, $catchall_type);
+	} elsif( defined $cgi->param('update_box_submit') ) {
+		update_box($panel, $mail);
+	} elsif(defined $cgi->param('delete_box_submit')) {
+		delete_box($panel, $mail);
+	} elsif(defined $cgi->param('add_box_submit')) {
+		add_box($panel, $mail);
+	} elsif(defined $cgi->param('update_forward_submit')) {
+		update_forward($panel, $mail);
+	} elsif(defined $cgi->param('delete_forward_submit')) {
+		delete_forward($panel, $mail);
+	} elsif(defined $cgi->param('add_forward_submit')) {
+		add_forward($panel, $mail);
+	}
+
+	my $vars = {
+	  mail => $mail,
+	  catchall_type => $catchall_type,
+	  novirus => ($mail_config->{'use_novirus'} eq 'yes' ),
+	  nospam => ($mail_config->{'use_novirus'} eq 'yes' )
+	  };
+
+	my @sorted_boxes = sort { $a->{local_part} cmp $b->{local_part} } (values %{$mail->get_boxes});
+	$vars->{sorted_boxes} = \@sorted_boxes;
+	my @sorted_forwards = sort { $a->{local_part} cmp $b->{local_part} } (values %{$mail->get_forwards});
+	$vars->{sorted_forwards} = \@sorted_forwards;
+
+	$panel->set_title( gettext("Mail Administration for domain ") );
+	$panel->render('mail/prefs.tt', $vars);
+}
+
+sub update_catchall {
+	my $panel = shift;
+	my $mail = shift;
+	my $type = shift;
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
+
+	# User wants to modify catchall address.
+	unless( $user->can_modify($mail) ) {
+		$panel->add_error( gettext('You are not allowed to modify this object') );
+		return;
+	}
+
+	if($type eq 'none') {
+		$panel->add_error( gettext('Catchall isn\'t enabled on this platform') );
+		return;
+	}
+
+	my $catchall = $cgi->param('catchall');
+	unless( defined $catchall ) {
+		$panel->add_error( gettext('CGI Error !') );
+		return;
+	}
+
+	if($type eq 'domain' and $catchall ne '') {
+		unless( $mail->exists_box($catchall) and $mail->get_box_status($catchall) == Vhffs::Constants::ACTIVATED) {
+			$panel->add_error( gettext('Selected mailbox doesn\'t exist for this mail domain or is not yet active.') );
+			return;
+		}
+		my $domain = $mail->get_domain;
+		$catchall .= "\@$domain";
+	}
+
+	if($mail->set_catchall($catchall) < 0) {
+		$panel->add_error( sprintf( gettext('%s is not a correct mail address'), $catchall) );
+		return;
+	}
+
+	if($mail->commit() < 0) {
+		$panel->add_error( gettext('An error occured while updating the mail domain') );
+		return;
+	}
+
+	$panel->add_info(gettext('Catchall address successfully changed'));
+}
+
+sub add_box {
+	my $panel = shift;
+	my $mail = shift;
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
+
+	unless( $user->can_modify($mail) ) {
+		$panel->add_error( gettext('You are not allowed to modify this object') );
+		return;
+	}
+
+	my $box = $cgi->param('localpart');
+	my $passwd = $cgi->param('box_password');
+	unless( defined $box and defined $passwd) {
+		$panel->add_error( gettext('CGI Error !') );
+		return;
+	}
+
+	if($mail->addbox( $box, $passwd ) < 0 ) {
+		$panel->add_error(gettext( "This box already exists for this domain or parameters are not valid. Check your domain." ) );
+		return;
+	}
+
+	$panel->add_info( gettext('Box successfully added') );
+}
+
+sub update_box {
+	my $panel = shift;
+	my $mail = shift;
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
+
+	# User wants to update information about a box
+	my $box = $cgi->param('localpart');
+
+	unless( $user->can_modify($mail) and $mail->get_box_status( $box ) == Vhffs::Constants::ACTIVATED ) {
+		$panel->add_error( gettext('You are not allowed to modify this object') );
+		return;
+	}
+
+	my $passwd = $cgi->param('box_password');
+	my $use_antispam = $cgi->param('use_antispam');
+	my $use_antivirus = $cgi->param('use_antivirus');
+	my $mail_config = $vhffs->get_config->get_service('mail');
+        unless( defined $box and defined $passwd
+	  and ($mail_config->{'use_novirus'} eq 'no' or defined $use_antivirus)
+	  and ($mail_config->{'use_nospam'} eq 'no' or defined $use_antispam) ) {
+		$panel->add_error( gettext('CGI Error !') );
+		return;
+	}
+
+	if($passwd !~ /^\s*$/) {
+		if($mail->change_box_password( $box, $passwd ) < 0) {
+			$panel->add_error( gettext('Could not change box password') );
+		} else {
+			$panel->add_info( gettext('Box password updated') );
+		}
+	}
+
+	if(defined $use_antispam) {
+		# We've to explicitely pass 1 or 0 to avoid passing '' to underlying SQL query
+		if( $mail->set_spam_status($box, ($use_antispam eq 'yes' ? 1 : 0 ) ) < 0) {
+			$panel->add_error( sprintf( gettext('Could not update spam status for box %s'), $box ) );
+		} else {
+			$panel->add_info( gettext('Spam status updated') );
+		}
+	}
+
+	if(defined $use_antivirus) {
+		if( $mail->set_virus_status($box, ($use_antivirus eq 'yes' ? 1 : 0) ) < 0) {
+			$panel->add_error( sprintf( gettext('Could not update antivirus status for box %s'), $box ) );
+		} else {
+			$panel->add_info( gettext('Virus status updated') );
+		}
+	}
+}
+
+sub delete_box {
+	my $panel = shift;
+	my $mail = shift;
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
+
+	# User wants to delete a box
+	my $box = $cgi->param('localpart');
+	unless( $user->can_modify($mail) and $mail->get_box_status( $box ) == Vhffs::Constants::ACTIVATED ) {
+		$panel->add_error( gettext('You are not allowed to modify this object') );
+		return;
+	}
+
+	unless( defined $box ) {
+		$panel->add_error( gettext('CGI Error !') );
+		return;
+	}
+
+	if($mail->set_box_status($box, Vhffs::Constants::TO_DELETE) < 0) {
+		$panel->add_error( sprintf(gettext('Unable to delete box %s'), $box) );
+		return;
+	}
+
+	$panel->add_info( sprintf(gettext('Box %s deleted'), $box) );
+}
+
+sub add_forward {
+	my $panel = shift;
+	my $mail = shift;
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
+
+	unless( $user->can_modify($mail) ) {
+		$panel->add_error( gettext('You are not allowed to modify this object') );
+		return;
+	}
+
+	my $local = $cgi->param('localpart');
+	my $remote = $cgi->param('forward');
+	unless( defined $local and defined $remote ) {
+		$panel->add_error( gettext('CGI Error !') );
+		return;
+	}
+
+	if($mail->addforward( $local, $remote ) < 0) {
+		$panel->add_error( sprintf(gettext('Unable to add forward %s'), $local) );
+		return;
+	}
+
+	$panel->add_info( gettext('Forward added') );
+}
+
+sub update_forward {
+	my $panel = shift;
+	my $mail = shift;
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
+
+	unless( $user->can_modify($mail) ) {
+		$panel->add_error( gettext('You are not allowed to modify this object') );
+		return;
+	}
+
+	my $local = $cgi->param('localpart');
+	my $remote = $cgi->param('forward');
+	unless( defined $local and defined $remote ) {
+		$panel->add_error( gettext('CGI Error !') );
+		return;
+	}
+
+	if($mail->change_forward( $local, $remote ) < 0) {
+		$panel->add_error( sprintf(gettext('Unable to modify forward %s' ), $local ) );
+		return;
+	}
+
+	$panel->add_info( sprintf(gettext('Forward %s successfully updated'), $local ) );
+}
+
+sub delete_forward {
+	my $panel = shift;
+	my $mail = shift;
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
+
+	unless( $user->can_modify($mail) ) {
+		$panel->add_error( gettext('You are not allowed to modify this object') );
+		return;
+	}
+
+	my $local = $cgi->param('localpart');
+	unless( defined $local ) {
+		$panel->add_error( gettext('CGI Error !') );
+		return;
+	}
+
+	if($mail->delforward($local) < 0) {
+		$panel->add_error( sprintf(gettext('Unable to delete forward %s'), $local) );
+		return;
+	}
+
+	$panel->add_info( sprintf(gettext('Forward %s deleted'), $local) );
+}
+
+sub index {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group ) {
+		$panel->render('misc/message.tt', { message => gettext('You have to select a group first') } );
+		return;
+	}
+
+	unless($group->get_status == Vhffs::Constants::ACTIVATED) {
+		$panel->render( 'misc/message.tt', { message => gettext('This group is not activated yet') } );
+		return;
+	}
+
+	unless( $user->can_view( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+
+	$panel->set_group( $group );
+	$panel->set_title( sprintf(gettext('Mail domains for %s'), $group->get_groupname) );
+	my $mails = Vhffs::Panel::Mail::getall_per_group( $vhffs, $group->get_gid );
+	if($mails < 0) {
+		$panel->render('misc/message.tt', { message => gettext('Unable to get mail domains') } );
+		return;
+	}
+
+	$panel->render( 'misc/service-index.tt', {
+	  label => 'Mail domains',
+	  group => $group,
+	  list => $mails,
+	  help_url => $vhffs->get_config->get_service('mail')->{url_doc},
+	  type => 'mail'
+	  });
+}
+
+sub search {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $name = $cgi->param('name');
+	my $vars = {};
+
+	unless( defined $name ) {
+
+		$panel->render('admin/misc/search.tt', {
+		  search_title => gettext('Mail search'),
+		  type => 'mail'
+		  });
+		return;
+	}
+
+	if( $name =~ /^\s*$/ ) {
+		$vars->{list_title} = gettext('List of all mail domains');
+		undef $name;
+	} else {
+		$vars->{list_title} = sprintf( gettext('Search result for %s'), $name );
+	}
+	$vars->{list} = search_mail( $vhffs , $name );
+	$vars->{type} = 'mail';
+	$panel->render('admin/misc/list.tt', $vars);
+}
+
+sub adminindex {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	$panel->set_title(gettext('Mail domains\' administration'));
+	require Vhffs::Panel::Admin;
+	$panel->render('admin/index.tt', { categories => [ Vhffs::Panel::Admin::get_mail_category() ] } );
+}
+
 1;

Modified: trunk/vhffs-api/src/Vhffs/Panel/MailingList.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/MailingList.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/MailingList.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -39,26 +39,27 @@
 use Locale::gettext;
 use Vhffs::Services::MailingList;
 use Vhffs::Constants;
+require Vhffs::Panel::Mail;
 
-sub search
-{
-    my ($main, $name) = @_;
+sub search_mailinglist {
+	my ($main, $name) = @_;
 
-    my @params;
-    my $sql = 'SELECT m.local_part || \'@\' || m.domain as label, g.groupname as owner_group, o.state, u.username as owner_user '.
-        'FROM vhffs_ml m '.
-        'INNER JOIN vhffs_object o ON (o.object_id = m.object_id) '.
-        'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
-        'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
+	my @params;
+	my $sql = 'SELECT m.local_part || \'@\' || m.domain as label, g.groupname as owner_group, o.state, u.username as owner_user '.
+	  'FROM vhffs_ml m '.
+	  'INNER JOIN vhffs_object o ON (o.object_id = m.object_id) '.
+	  'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
+	  'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
 
+	if( defined $name ) {
+		$sql .= 'WHERE m.local_part LIKE ? OR m.domain LIKE ? ';
+		push(@params, '%'.lc($name).'%' , '%'.lc($name).'%' );
+	}
 
-    if( defined $name ) {
-        $sql .= 'WHERE m.local_part LIKE ? OR m.domain LIKE ? ';
-        push(@params, '%'.lc($name).'%' , '%'.lc($name).'%' );
-    }
-    $sql .= 'ORDER BY m.domain, m.local_part';
-    my $dbh = $main->get_db_object();
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
+	$sql .= 'ORDER BY m.domain, m.local_part';
+
+	my $dbh = $main->get_db_object();
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
 }
 
 =pod
@@ -73,30 +74,29 @@
 =cut
 
 
-sub getall_per_group
-{
-    my ( $main, $gid ) = @_;
+sub getall_per_group {
+	my ( $main, $gid ) = @_;
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT l.object_id AS oid, l.local_part || \'@\' || l.domain AS displayname, o.state FROM vhffs_ml l INNER JOIN vhffs_object o ON l.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY l.local_part, l.domain';
-    my $sth = $dbh->prepare($sql) or return -1;
-    $sth->execute($gid) or return -2;
-    my $mls = [];
-    while(my $l = $sth->fetchrow_hashref) {
-        $l->{active} = ($l->{state} == Vhffs::Constants::ACTIVATED);
-        $l->{refused} = ($l->{state} == Vhffs::Constants::VALIDATION_REFUSED);
-        $l->{state} = Vhffs::Functions::status_string_from_status_id($l->{state});
-        push @$mls, $l;
-    }
-    return $mls;
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT l.object_id AS oid, l.local_part || \'@\' || l.domain AS displayname, o.state FROM vhffs_ml l INNER JOIN vhffs_object o ON l.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY l.local_part, l.domain';
+	my $sth = $dbh->prepare($sql) or return -1;
+	$sth->execute($gid) or return -2;
+	my $mls = [];
+	while(my $l = $sth->fetchrow_hashref) {
+		$l->{active} = ($l->{state} == Vhffs::Constants::ACTIVATED);
+		$l->{refused} = ($l->{state} == Vhffs::Constants::VALIDATION_REFUSED);
+		$l->{state} = Vhffs::Functions::status_string_from_status_id($l->{state});
+	push @$mls, $l;
+	}
+	return $mls;
 }
 
 sub get_lists_per_group {
-    my ($main, $gid) = @_;
+	my ($main, $gid) = @_;
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT l.local_part || \'@\' || l.domain AS listname, l.local_part, l.domain, l.open_archive, o.description FROM vhffs_ml l INNER JOIN vhffs_object o ON l.object_id = o.object_id WHERE o.owner_gid = ? AND o.state = ?';
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, $gid, Vhffs::Constants::ACTIVATED);
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT l.local_part || \'@\' || l.domain AS listname, l.local_part, l.domain, l.open_archive, o.description FROM vhffs_ml l INNER JOIN vhffs_object o ON l.object_id = o.object_id WHERE o.owner_gid = ? AND o.state = ?';
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, $gid, Vhffs::Constants::ACTIVATED);
 }
 
 =pod
@@ -111,27 +111,370 @@
 =cut
 
 sub getall_mdomains_per_group($$) {
-    my ($main, $gid) = @_;
+	my ($main, $gid) = @_;
 
-    my $dbh = $main->get_db_object;
-    my $sql = q{ SELECT m.domain FROM vhffs_mxdomain m INNER JOIN vhffs_object o ON o.object_id = m.object_id WHERE o.owner_gid = ? AND o.state = ? ORDER BY m.domain };
-    return ($dbh->selectall_arrayref($sql, { Slice => {} }, $gid, Vhffs::Constants::ACTIVATED) );
+	my $dbh = $main->get_db_object;
+	my $sql = q{ SELECT m.domain FROM vhffs_mxdomain m INNER JOIN vhffs_object o ON o.object_id = m.object_id WHERE o.owner_gid = ? AND o.state = ? ORDER BY m.domain };
+	return ($dbh->selectall_arrayref($sql, { Slice => {} }, $gid, Vhffs::Constants::ACTIVATED) );
 }
 
 sub create_list
 {
-    my ($main, $lpart, $domain, $description, $user, $group) = @_;
+	my ($main, $lpart, $domain, $description, $user, $group) = @_;
+	return undef unless defined $user;
+	return undef unless defined $group; 
     
-    return undef unless( defined $user );
-    return undef unless( defined $group ); 
+	my $list = Vhffs::Services::MailingList::create( $main , $lpart , $domain, $description, $user, $group );
+	return undef unless defined $list;
     
-    my $list = Vhffs::Services::MailingList::create( $main , $lpart , $domain, $description, $user, $group );
-    return undef unless( defined $list );
+	return undef if Vhffs::Acl::add_acl( $user , $list , Vhffs::Constants::ACL_DELETE , $main ) < 0;
+	return undef if Vhffs::Acl::add_acl( $group , $list , Vhffs::Constants::ACL_VIEW , $main ) < 0; 
     
-    return undef if ( Vhffs::Acl::add_acl( $user , $list , Vhffs::Constants::ACL_DELETE , $main ) < 0 );
-    return undef if( Vhffs::Acl::add_acl( $group , $list , Vhffs::Constants::ACL_VIEW , $main ) < 0 ); 
+	return $list;
+}
+
+sub create {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group and $user->can_modify($group) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+	$panel->set_group( $group );
+
+	my $default_domain = $vhffs->get_config->get_service('mailinglist')->{'default_domain'};
+	my $domains = Vhffs::Panel::MailingList::getall_mdomains_per_group( $vhffs, $group->get_gid );
+	unless( @$domains or defined $default_domain ) {
+		$panel->render('misc/message.tt', { message => gettext('There is no default mail domain on this platform, you have to create a mail domain before creating a mailing list') } );
+		return;
+	}
+
+	my $submitted = $cgi->param('mailing_submit');
+	my $localpart = '';
+	my $domain = '';
+	my $description = '';
+	my $vars = {};
+	
+	if( $submitted ) {
+		$localpart = $cgi->param( 'localpart' );
+		$domain = $cgi->param( 'domain' );
+		$description = Encode::decode_utf8( $cgi->param( 'description' ) );
+
+		unless( defined $localpart and defined $domain and defined $description ) {
+			$panel->add_error( gettext('CGI Error !') );
+		} else {
+			$panel->add_error( gettext('You must enter a description') ) unless $description !~ /^\s*$/;
+			$panel->add_error( gettext('Invalid local part') ) unless $localpart =~ /^[a-z0-9\_\-]+$/;
+			$panel->add_error( gettext('You do not own this domain !') ) unless( ($domain eq $default_domain) or Vhffs::Panel::Mail::is_owned_by_group( $vhffs, $domain, $group->get_gid ) );
+		}
+
+		unless( $panel->has_errors() ) {
+			my $mailinglist =  Vhffs::Panel::MailingList::create_list( $vhffs, $localpart, $domain, $description, $user, $group );
+			if( defined $mailinglist ) {
+				my $url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('The mailing list object was successfully created !');
+				$panel->redirect( $url );
+				return;
+			}
+
+			$panel->add_error( gettext('An error occured while creating the object.It probably already exists') );
+		}
+
+		$vars->{local_part} = $localpart;
+		$vars->{domain} = $domain;
+		$vars->{description} = $description;
+	}
+
+	push(@$domains, { domain => $default_domain }) if defined $default_domain;
+	$vars->{domains} = $domains;
+	$vars->{group} = $group;
+
+	$panel->render('mailinglist/create.tt', $vars);
+}
+
+sub prefs {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $lpart = $cgi->param('local');
+	my $domain = $cgi->param('domain');
+
+	# Generic service management use name param
+	unless( defined $lpart and defined $domain ) {
+		my $name = $cgi->param('name');
+		( $lpart , $domain ) = ( $name =~ /(.+)\@(.+)/ ) if defined $name;
+	}
+
+	unless( defined $lpart and defined $domain ) {
+		$panel->render('misc/message.tt', { message => gettext( 'CGI Error !' ) } );
+		return;
+	}
+
+	my $list = Vhffs::Services::MailingList::get_by_mladdress( $vhffs , $lpart , $domain );
+	unless( defined $list ) {
+		$panel->render('misc/message.tt', { message => sprintf( gettext('Mailing list %s@%s not found'), $lpart, $domain) } );
+		return;
+	}
+
+	unless( $user->can_view( $list ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) } );
+		return;
+	}
+
+	if(defined $cgi->param('options_submit')) {
+		update_ml_options($panel, $list);
+	} elsif(defined $cgi->param('delete_submit')) {
+		delete_member($panel, $list);
+	} elsif(defined $cgi->param('change_rights_submit')) {
+		change_rights($panel, $list);
+	} elsif(defined $cgi->param('add_members_submit')) {
+		add_members($panel, $list);
+	}
     
-    return $list;
+	my $vars = { list => $list };
+
+	my $group = Vhffs::Group::get_by_gid( $vhffs , $list->get_owner_gid );
+	$vars->{group_emails} = join("\n", map { $_->{mail} } @{$group->get_users});
+
+	$panel->set_title( sprintf(gettext('Administration for list %s'), $list->get_localpart.'@'.$list->get_domain) );
+	$panel->render('mailinglist/prefs.tt', $vars);
 }
 
+sub update_ml_options {
+	my $panel = shift;
+	my $list = shift;
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
+
+	my $prefix = Encode::decode_utf8( $cgi->param('prefix') );
+	my $sub_ctrl = $cgi->param('subscribe_control');
+	my $post_ctrl = $cgi->param('posting_control');
+	my $sig = Encode::decode_utf8( $cgi->param('signature') );
+
+	unless( $user->can_modify($list) ) {
+		$panel->add_error( gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) );
+		return;
+	}
+
+	unless( defined $prefix and defined $sub_ctrl and defined $post_ctrl and defined $sig) {
+		$panel->add_error( gettext('CGI Error !') );
+		return;
+	}
+
+	$list->set_prefix($prefix);
+	$list->set_sub_ctrl($sub_ctrl);
+	$list->set_post_ctrl($post_ctrl);
+	$list->set_open_archive(defined $cgi->param('public_archive') ? 1 : 0);
+	$list->set_replyto(defined $cgi->param('reply_to') ? 1 : 0);
+	$list->set_signature($sig);
+
+	if($list->commit() < 0) {
+		$panel->add_error( gettext('Unable to save object') );
+		return;
+	}
+
+	$panel->add_info( gettext('List updated') );
+}
+
+sub delete_member {
+	my $panel = shift;
+	my $list = shift;
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
+
+	my $member = $cgi->param('member');
+
+	unless( $user->can_modify($list) ) {
+		$panel->add_error( gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) );
+		return;
+	}
+
+	unless(defined $member) {
+		$panel->add_error( gettext('CGI Error !') );
+		return;
+	}
+
+	if( $list->del_sub($member) < 0 ) {
+		$panel->add_error('An error occured while deleting this subscriber');
+		return;
+	}
+
+	$panel->add_info( sprintf( gettext('Subscriber %s deleted'), $member ) );
+}
+
+sub change_rights {
+	my $panel = shift;
+	my $list = shift;
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
+
+	my $member = $cgi->param('member');
+	my $right = $cgi->param('right');
+
+	unless( $user->can_modify($list) ) {
+		$panel->add_error( gettext('You are not allowed to manager subscribers\' rights (ACL rights)') );
+		return;
+	}
+
+	unless( defined $member and defined $right ) {
+		$panel->add_error( gettext('CGI Error !') );
+		return;
+	}
+
+	if( $list->change_right_for_sub( $member, $right ) < 0) {
+		$panel->add_error( sprintf( gettext('Unable to change rights for subscriber %s'), $member ) );
+		return;
+	}
+
+	$panel->add_info( sprintf( gettext('Rights for subscriber %s updated'), $member ) );
+}
+
+sub add_members {
+	my $panel = shift;
+	my $list = shift;
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
+
+	my $memberlist = $cgi->param('members');
+
+	unless( $user->can_modify($list) ) {
+		$panel->add_error( gettext('You are not allowed to add members (ACL rights)') );
+		return;
+	}
+
+	unless( defined $memberlist ) {
+		$panel->add_error( gettext('CGI Error !') );
+		return;
+	}
+
+	unless($memberlist !~ /^\s*$/) {
+		$panel->add_error( gettext('You need to enter at least one new member') );
+		return;
+	}
+
+	my @members = split /\r\n/, $memberlist;
+	my $listengineconfig = $vhffs->get_config->get_listengine;
+
+	foreach my $member ( @members )  {
+		chomp $member;
+		( $member ) = ( $member =~ /^\s*([^\s]+)\s*$/ );
+		$member = lc $member;
+		unless( Vhffs::Functions::valid_mail( $member ) )  {
+			 $panel->add_error( sprintf( gettext('%s is not a valid mail'), $member ) )
+		} elsif( $list->add_sub( $member , Vhffs::Constants::ML_RIGHT_SUB ) < 0 ) {
+			$panel->add_error( sprintf( gettext( '%s is already a member of this list' ), $member ) );
+		} else {
+			$panel->add_info( sprintf( gettext( '%s has been added' ), $member ) );
+			Vhffs::Functions::send_mail(
+			  $vhffs,
+			  $listengineconfig->{'listmaster'},
+			  $member,
+			  undef,
+			  sprintf(gettext('[%s] You\'ve been added to the list %s'), $list->get_prefix, $list->get_localpart.'@'.$list->get_domain),
+			  sprintf(gettext("Greetings,\n\nYou've been added to the list %s on platform %s.\n\nYou may get some help on listengine by sending an email to %s-request\@%s with subject help.\n\nCheers.\n"), $list->get_localpart.'@'.$list->get_domain, $vhffs->get_config->get_host_name, $list->get_localpart, $list->get_domain),
+			  );
+		}
+	}
+}
+
+sub index {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group ) {
+		$panel->render( 'misc/message.tt', { message => gettext('You have to select a group first') } );
+		return;
+	}
+
+	unless($group->get_status == Vhffs::Constants::ACTIVATED) {
+		$panel->render( 'misc/message.tt', { message => gettext('This group is not activated yet') } );
+		return;
+	}
+
+	unless( $user->can_view( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+
+	$panel->set_group( $group );
+	$panel->set_title( sprintf(gettext('Mailing lists for %s'), $group->get_groupname) );
+
+	my $mls = Vhffs::Panel::MailingList::getall_per_group( $vhffs, $group->get_gid );
+	if($mls < 0) {
+		$panel->render( 'misc/message.tt', { message => gettext('Unable to get SVN repositories') } );
+		return;
+	}
+
+	$panel->render( 'misc/service-index.tt', {
+	  label => 'Mailing lists',
+	  group => $group,
+	  list => $mls,
+	  type => 'mailinglist'
+	  });
+}
+
+sub search {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $name = $cgi->param('name');
+	my $vars = {};
+
+	unless( defined $name ) {
+
+		$panel->render('admin/misc/search.tt', {
+		  search_title => gettext('Mailing lists search'),
+		  type => 'mailinglist'
+		  });
+		return;
+	}
+
+	if( $name =~ /^\s*$/ ) {
+		$vars->{list_title} = gettext('List of all mailing lists');
+		undef $name;
+	} else {
+		$vars->{list_title} = sprintf( gettext('Search result for %s'), $name );
+	}
+	$vars->{list} = search_mailinglist( $vhffs , $name );
+	$vars->{type} = 'mailinglist';
+	$panel->render('admin/misc/list.tt', $vars);
+}
+
+sub adminindex {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	$panel->set_title(gettext('Mailing lists administration'));
+	require Vhffs::Panel::Admin;
+	$panel->render('admin/index.tt', { categories => [ Vhffs::Panel::Admin::get_mailing_category() ] } );
+}
+
 1;

Deleted: trunk/vhffs-api/src/Vhffs/Panel/Mailings.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Mailings.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/Mailings.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,49 +0,0 @@
-#!%PERL%
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#   notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-#    notice, this list of conditions and the following disclaimer in 
-#    the documentation and/or other materials provided with the 
-#    distribution.
-# 3. Neither the name of vhffs nor the names of its contributors 
-#    may be used to endorse or promote products derived from this 
-#    software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-use strict;
-use utf8;
-
-package Vhffs::Panel::Mailings;
-
-sub list {
-    my ($main) = @_;
-
-    my $sql = 'SELECT id_mailing as id, subject, message as body, date, state '.
-        'FROM vhffs_mailings m '.
-        'ORDER BY m.date DESC';
-
-    my $dbh = $main->get_db_object();
-    return $dbh->selectall_arrayref($sql, { Slice => {} });
-}
-
-1;
-

Modified: trunk/vhffs-api/src/Vhffs/Panel/Main.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Main.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/Main.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -10,7 +10,6 @@
 use POSIX qw(locale_h);
 use locale;
 use Locale::gettext;
-use CGI;
 use CGI::Session;
 use File::Spec;
 use Encode;
@@ -21,7 +20,7 @@
 use Vhffs::Group;
 use Vhffs::Functions;
 use Vhffs::Panel::User;
-use Vhffs::Panel::Commons;
+use Vhffs::Panel::Auth;
 
 =pod
 
@@ -44,17 +43,18 @@
 
     $panel->check_public;
 
-Checks that public area is available, if it's not the case show a message and exits.
+Checks that public area is available, if it's not the case show a message and returns.
 
 =cut
 
 sub check_public {
-    my $self = shift;
-    my $vhffs = $self->{vhffs};
-    if( $vhffs->get_config->get_panel->{'use_public'} ne 'yes' ) {
-        $self->render('misc/closed.tt', undef);
-        exit( 0 );
-    }
+	my $self = shift;
+	my $vhffs = $self->{vhffs};
+	if( $vhffs->get_config->get_panel->{'use_public'} ne 'yes' ) {
+		$self->render('misc/closed.tt', undef);
+		# TODO : remove exit
+		exit( 0 );
+	}
 }
 
 =pod
@@ -109,7 +109,7 @@
 	my $vhffs = $panel->{vhffs};
 	use Vhffs::Functions;
 	return ( Vhffs::Functions::strtobool( $vhffs->get_config->get_panel->{'users_avatars'} )
-		|| Vhffs::Functions::strtobool( $vhffs->get_config->get_panel->{'groups_avatars'} ) );
+	  or Vhffs::Functions::strtobool( $vhffs->get_config->get_panel->{'groups_avatars'} ) );
 }
 
 =pod
@@ -156,19 +156,20 @@
     $panel->check_modo
 
 Checks that logged in user is admin or moderator. If it is
-not the case, show a message and exits.
+not the case, show a message and returns.
 
 =cut
 
 sub check_modo {
-    my $panel = shift;
-    my $user = $panel->{user};
-    unless($user->is_moderator || $user->is_admin) {
-        $panel->set_title( gettext('Access denied') );
-        $panel->render('misc/message.tt', {
-            message => gettext('You are not allowed to access this page')
-        });
-    }
+	my $panel = shift;
+	my $user = $panel->{user};
+	unless($user->is_moderator or $user->is_admin) {
+		$panel->set_title( gettext('Access denied') );
+		$panel->render('misc/message.tt',  { message => gettext('You are not allowed to access this page') });
+		return 0;
+	}
+	$panel->{display_admin_menu} = 1;
+	return 1;
 }
 
 =head2
@@ -176,23 +177,23 @@
     $panel->check_admin
 
 Check that logged in user is an admin. If it is not
-the case, show a message and exits.
+the case, show a message and returns.
 
 =cut
 
 sub check_admin {
-    my $panel = shift;
-    my $user = $panel->{user};
-    unless($user->is_admin) {
-        $panel->set_title( gettext('Access denied') );
-        $panel->render('misc/message.tt', {
-            message => gettext('You are not allowed to access this page')
-        });
-    }
+	my $panel = shift;
+	my $user = $panel->{user};
+	unless($user->is_admin) {
+		$panel->set_title( gettext('Access denied') );
+		$panel->render('misc/message.tt', { message => gettext('You are not allowed to access this page') });
+		return 0;
+	}
+	$panel->{display_admin_menu} = 1;
+	return 1;
 }
 
-sub list_themes
-{
+sub list_themes {
 	my $vhffs = shift;
 	return -1 unless defined $vhffs;
 
@@ -217,20 +218,19 @@
 }
 
 
-sub list_languages
-{
+sub list_languages {
 	my $vhffs = shift;
 	return -1 if( ! defined $vhffs );
 
-    return $vhffs->get_config->get_available_languages;
+	return $vhffs->get_config->get_available_languages;
 }
 
 
 
 sub select_lang {
-    my $self = shift;
-    my @langs = $self->{vhffs}->get_config->get_available_languages;
-    my $txt = '';
+	my $self = shift;
+	my @langs = $self->{vhffs}->get_config->get_available_languages;
+	my $txt = '';
 	foreach my $l ( @langs )
 	{
 		$txt .= "<a href=\"auth.pl?lang=".$l."\"><img src=\"/themes/".$self->{theme}."/images/".$l.".png\" alt=\"".$l."language\"/></a>";
@@ -242,24 +242,23 @@
 sub new
 {
 	my $class = ref($_[0]) || $_[0];
+	my $vhffs = $_[1];
+	my $cgi = $_[2];
+
+	return undef unless( defined $vhffs and defined $cgi );
+
+	$cgi->charset('UTF-8');
+
 	my $self = {};
+	bless( $self, $class );
 	$self->{errors} = [];
 	$self->{infos} = [];
 	$self->{cookies} = [];
-	bless( $self, $class );
-
-	my $cgi = new CGI;
-	$cgi->charset('UTF-8');
+	$self->{vhffs} = $vhffs;
 	$self->{cgi} = $cgi;
-	$self->{url} = CGI::url();
+	$self->{url} = $cgi->url();
+	$self->{display_admin_menu} = 0;
 
-	my $vhffs = init Vhffs::Main;
-	$self->{vhffs} = $vhffs;
-	unless( defined $vhffs )  {
-		print CGI->header( -type=>'text/html', -charset=>'utf-8' ), 'Unable to open database connection';
-		exit 1;
-	}
-
 	my $config = $vhffs->get_config;
 	$self->{config} = $config;
 	my $templatedir = $config->get_templatedir;
@@ -267,40 +266,37 @@
 
 	# lang cookie
 	my $lang = $cgi->param('lang');
-	$self->add_cookie( CGI->cookie( -name=>'language', -value=>$lang, -expires=>'+10y' ) ) if defined $lang;
-	$lang = CGI->cookie('language') unless defined $lang;
+	$self->add_cookie( $cgi->cookie( -name=>'language', -value=>$lang, -expires=>'+10y' ) ) if defined $lang;
+	$lang = $cgi->cookie('language') unless defined $lang;
 	$lang = $vhffs->get_config->get_default_language() unless defined $lang;
 	$lang = 'en_US' unless defined $lang;
 	$self->{lang} = $lang;
 
-	setlocale(LC_ALL, $lang);
+	setlocale(LC_ALL, $lang );
 	bindtextdomain('vhffs', '%localedir%');
 	textdomain('vhffs');
 
 	# theme cookie
 	my $theme = $cgi->param('theme');
-	$self->add_cookie( CGI->cookie( -name=>'theme', -value=>$theme, -expires=>'+10y' ) ) if defined $theme;
-	$theme = CGI->cookie('theme') unless defined $theme;
+	$self->add_cookie( $cgi->cookie( -name=>'theme', -value=>$theme, -expires=>'+10y' ) ) if defined $theme;
+	$theme = $cgi->cookie('theme') unless defined $theme;
 	$theme = $config->get_panel->{'default_theme'} unless defined $theme;
-	$theme = 'vhffs' unless( defined $theme  &&  -f $config->get_panel->{'themesdir'}.'/'.$theme.'/main.css' );
+	$theme = 'vhffs' unless( defined $theme and -f $config->get_panel->{'themesdir'}.'/'.$theme.'/main.css' );
 	$self->{theme} = 'vhffs';
 
-	unless( $vhffs->is_valid() and $vhffs->get_config->get_panel->{'open'} eq 'yes' )
-	{
-        $self->render('misc/closed.tt', undef, 'anonymous.tt');
-        exit 0;
+	unless( $vhffs->reconnect() and $vhffs->get_config->get_panel->{'open'} eq 'yes' )  {
+		$self->render('misc/closed.tt', undef, 'anonymous.tt');
+		undef $self;
+		return undef;
 	}
-	
+
 	$self->{is_ajax_request} = (defined $self->{cgi}->http('X-Requested-With')
 		and $self->{cgi}->http('X-Requested-With') eq 'XMLHttpRequest');
 
 	return $self;
 }
 
-
-
-sub get_session
-{
+sub get_session {
 	my $panel = shift;
 	my $vhffs = $panel->{vhffs};
 	my $cgi = $panel->{cgi};
@@ -308,15 +304,15 @@
 	my $sid = $cgi->cookie( CGI::Session::name() );
 	unless( defined $sid )  {
 		$panel->add_error( gettext('No cookie found, please accept the cookie and then please login again !') );
-		Vhffs::Panel::Commons::display_login( $vhffs, $panel );
-		exit 0;
+		Vhffs::Panel::Auth::display_login( $panel );
+		return undef;
 	}
 
 	my $session = new CGI::Session( undef, $sid, {Directory=>'/tmp'} );
 	unless( defined $session )  {
 		$panel->add_error( gettext('Cannot create or fetch session file, please check that /tmp is readable and writeable') );
-		Vhffs::Panel::Commons::display_login( $vhffs, $panel );
-		exit 0;
+		Vhffs::Panel::Auth::display_login( $panel );
+		return undef;
 	}
 
 	my $username = $session->param('username');
@@ -324,69 +320,68 @@
 	unless(  defined $username  &&  defined $uid  &&  !$session->is_new()  )  {
 		$panel->add_error( gettext('Expired session ! Please login again') );
 		$session->delete();
-		Vhffs::Panel::Commons::display_login( $vhffs, $panel );
-		exit 0;
+		Vhffs::Panel::Auth::display_login( $panel );
+		return undef;
 	}
 
 	my $user = Vhffs::User::get_by_uid($vhffs, $uid);
 	unless ( defined $user )  {
 		$panel->add_error( gettext('User does not exist') );
 		$session->delete();
-		Vhffs::Panel::Commons::display_login( $vhffs, $panel );
-		exit 0;
+		Vhffs::Panel::Auth::display_login( $panel );
+		return undef;
 	}
 
 	unless( $user->get_status == Vhffs::Constants::ACTIVATED )  {
 		$panel->add_error( gettext('You\'re are not allowed to browse panel') );
 		$session->delete();
-		Vhffs::Panel::Commons::display_login( $vhffs, $panel );
-		exit 0;
+		Vhffs::Panel::Auth::display_login( $panel );
+		return undef;
 	}
 
 	$panel->{session} = $session;
 	$panel->{user} = $user;
-	Vhffs::Main::current_user_uid($uid);
+
 	return $session;
 }
 
-sub has_errors
-{
-    my $panel = shift;
-    return (@{$panel->{errors}} > 0);
+sub set_group {
+	my $panel = shift;
+	$panel->{group} = shift;
 }
 
-sub set_title
-{
-    my ($panel, $title) = @_;
-    $panel->{title} = $title;
+sub has_errors {
+	my $panel = shift;
+	return (@{$panel->{errors}} > 0);
 }
 
-sub add_error
-{
-    my ($panel, $error) = @_;
-    # TODO Do not use anonymous hash when Template::Toolkit transition is over.
-    push(@{$panel->{errors}}, {msg => $error});
+sub set_title {
+	my ($panel, $title) = @_;
+	$panel->{title} = $title;
 }
 
-sub add_info
-{
-    my ($panel, $info) = @_;
-    # TODO Do not use anonymous hash when Template::Toolkit transition is over.
-    push(@{$panel->{infos}}, {msg => $info});
+sub add_error {
+	my ($panel, $error) = @_;
+	# TODO Do not use anonymous hash when Template::Toolkit transition is over.
+	push(@{$panel->{errors}}, {msg => $error});
 }
 
-sub add_cookie
-{
-    my ($panel, $cookie) = @_;
-    push(@{$panel->{cookies}}, $cookie);
+sub add_info {
+	my ($panel, $info) = @_;
+	# TODO Do not use anonymous hash when Template::Toolkit transition is over.
+	push(@{$panel->{infos}}, {msg => $info});
 }
 
-sub clear_infos
-{
-    my $panel = shift;
-    $panel->{infos} = [];
+sub add_cookie {
+	my ($panel, $cookie) = @_;
+	push(@{$panel->{cookies}}, $cookie);
 }
 
+sub clear_infos {
+	my $panel = shift;
+	$panel->{infos} = [];
+}
+
 =head2 $panel->render($file, $vars, $layout)
 
 Renders given template with substitution variables C<$vars>.
@@ -405,55 +400,56 @@
 sub render {
 	my ($self, $file, $vars, $layout, $include_path) = @_;
 	my $conf = $self->{vhffs}->get_config;
+	my $cgi = $self->{cgi};
 	
 	# TODO Should be in parent class when Template::Toolkit switch is over
 	my $create_vars = {
-		INCLUDE_PATH => $self->{templatedir}.(defined $include_path ? "/$include_path/" : '/panel/'),
-        CONSTANTS => {
-            object_statuses => {
-                WAITING_FOR_VALIDATION      =>Vhffs::Constants::WAITING_FOR_VALIDATION,
-                VALIDATION_REFUSED          => Vhffs::Constants::VALIDATION_REFUSED,
-                WAITING_FOR_CREATION        => Vhffs::Constants::WAITING_FOR_CREATION,
-                CREATING_ERROR              => Vhffs::Constants::CREATING_ERROR,
-                ACTIVATED                   => Vhffs::Constants::ACTIVATED,
-                CREATED                     => Vhffs::Constants::CREATED,
-                SUSPEND_PENDING             => Vhffs::Constants::SUSPEND_PENDING,
-                SUSPENDED                   => Vhffs::Constants::SUSPENDED,
-                WAITING_FOR_MODIFICATION    => Vhffs::Constants::WAITING_FOR_MODIFICATION,
-                MODIFICATION_ERROR          => Vhffs::Constants::MODIFICATION_ERROR,
-                MODIFICATION_APPLIED        => Vhffs::Constants::MODIFICATION_APPLIED,
-                TO_DELETE                   => Vhffs::Constants::TO_DELETE
-            },
-            user_permissions => {
-                NORMAL                      => Vhffs::Constants::USER_NORMAL,
-                MODERATOR                   => Vhffs::Constants::USER_MODERATOR,
-                ADMIN                       => Vhffs::Constants::USER_ADMIN
-            },
-            acl => {
-                UNDEFINED                   => Vhffs::Constants::ACL_UNDEFINED,
-                DENIED                      => Vhffs::Constants::ACL_DENIED,
-                VIEW                        => Vhffs::Constants::ACL_VIEW,
-                MODIFY                      => Vhffs::Constants::ACL_MODIFY,
-                MANAGEACL                   => Vhffs::Constants::ACL_MANAGEACL,
-                DELETE                      => Vhffs::Constants::ACL_DELETE
-            },
-            mailinglist => {
-                SUBSCRIBE_NO_APPROVAL_REQUIRED          => Vhffs::Constants::ML_SUBSCRIBE_NO_APPROVAL_REQUIRED,
-                SUBSCRIBE_APPROVAL_REQUIRED             => Vhffs::Constants::ML_SUBSCRIBE_APPROVAL_REQUIRED,
-                SUBSCRIBE_CLOSED                        => Vhffs::Constants::ML_SUBSCRIBE_CLOSED,
-                POSTING_OPEN_ALL                        => Vhffs::Constants::ML_POSTING_OPEN_ALL,
-                POSTING_MODERATED_ALL                   => Vhffs::Constants::ML_POSTING_MODERATED_ALL,
-                POSTING_OPEN_MEMBERS_MODERATED_OTHERS   => Vhffs::Constants::ML_POSTING_OPEN_MEMBERS_MODERATED_OTHERS,
-                POSTING_MEMBERS_ONLY                    => Vhffs::Constants::ML_POSTING_MEMBERS_ONLY,
-                POSTING_MEMBERS_ONLY_MODERATED          => Vhffs::Constants::ML_POSTING_MEMBERS_ONLY_MODERATED,
-                POSTING_ADMINS_ONLY                     => Vhffs::Constants::ML_POSTING_ADMINS_ONLY,
-                RIGHT_SUB_WAITING_FOR_REPLY             => Vhffs::Constants::ML_RIGHT_SUB_WAITING_FOR_REPLY,
-                RIGHT_SUB_WAITING_FOR_VALIDATION        => Vhffs::Constants::ML_RIGHT_SUB_WAITING_FOR_VALIDATION,
-                RIGHT_SUB                               => Vhffs::Constants::ML_RIGHT_SUB,
-                RIGHT_SUB_WAITING_FOR_DEL               => Vhffs::Constants::ML_RIGHT_SUB_WAITING_FOR_DEL,
-                RIGHT_ADMIN                             => Vhffs::Constants::ML_RIGHT_ADMIN
-            }
-        },
+		INCLUDE_PATH => $self->{templatedir}.(defined $include_path ? '/'.$include_path.'/' : '/panel/'),
+		CONSTANTS => {
+			object_statuses => {
+				WAITING_FOR_VALIDATION      =>Vhffs::Constants::WAITING_FOR_VALIDATION,
+				VALIDATION_REFUSED          => Vhffs::Constants::VALIDATION_REFUSED,
+				WAITING_FOR_CREATION        => Vhffs::Constants::WAITING_FOR_CREATION,
+				CREATING_ERROR              => Vhffs::Constants::CREATING_ERROR,
+				ACTIVATED                   => Vhffs::Constants::ACTIVATED,
+				CREATED                     => Vhffs::Constants::CREATED,
+				SUSPEND_PENDING             => Vhffs::Constants::SUSPEND_PENDING,
+				SUSPENDED                   => Vhffs::Constants::SUSPENDED,
+				WAITING_FOR_MODIFICATION    => Vhffs::Constants::WAITING_FOR_MODIFICATION,
+				MODIFICATION_ERROR          => Vhffs::Constants::MODIFICATION_ERROR,
+				MODIFICATION_APPLIED        => Vhffs::Constants::MODIFICATION_APPLIED,
+				TO_DELETE                   => Vhffs::Constants::TO_DELETE
+			},
+			user_permissions => {
+				NORMAL                      => Vhffs::Constants::USER_NORMAL,
+				MODERATOR                   => Vhffs::Constants::USER_MODERATOR,
+				ADMIN                       => Vhffs::Constants::USER_ADMIN
+			},
+			acl => {
+				UNDEFINED                   => Vhffs::Constants::ACL_UNDEFINED,
+				DENIED                      => Vhffs::Constants::ACL_DENIED,
+				VIEW                        => Vhffs::Constants::ACL_VIEW,
+				MODIFY                      => Vhffs::Constants::ACL_MODIFY,
+				MANAGEACL                   => Vhffs::Constants::ACL_MANAGEACL,
+				DELETE                      => Vhffs::Constants::ACL_DELETE
+			},
+			mailinglist => {
+				SUBSCRIBE_NO_APPROVAL_REQUIRED          => Vhffs::Constants::ML_SUBSCRIBE_NO_APPROVAL_REQUIRED,
+				SUBSCRIBE_APPROVAL_REQUIRED             => Vhffs::Constants::ML_SUBSCRIBE_APPROVAL_REQUIRED,
+				SUBSCRIBE_CLOSED                        => Vhffs::Constants::ML_SUBSCRIBE_CLOSED,
+				POSTING_OPEN_ALL                        => Vhffs::Constants::ML_POSTING_OPEN_ALL,
+				POSTING_MODERATED_ALL                   => Vhffs::Constants::ML_POSTING_MODERATED_ALL,
+				POSTING_OPEN_MEMBERS_MODERATED_OTHERS   => Vhffs::Constants::ML_POSTING_OPEN_MEMBERS_MODERATED_OTHERS,
+				POSTING_MEMBERS_ONLY                    => Vhffs::Constants::ML_POSTING_MEMBERS_ONLY,
+				POSTING_MEMBERS_ONLY_MODERATED          => Vhffs::Constants::ML_POSTING_MEMBERS_ONLY_MODERATED,
+				POSTING_ADMINS_ONLY                     => Vhffs::Constants::ML_POSTING_ADMINS_ONLY,
+				RIGHT_SUB_WAITING_FOR_REPLY             => Vhffs::Constants::ML_RIGHT_SUB_WAITING_FOR_REPLY,
+				RIGHT_SUB_WAITING_FOR_VALIDATION        => Vhffs::Constants::ML_RIGHT_SUB_WAITING_FOR_VALIDATION,
+				RIGHT_SUB                               => Vhffs::Constants::ML_RIGHT_SUB,
+				RIGHT_SUB_WAITING_FOR_DEL               => Vhffs::Constants::ML_RIGHT_SUB_WAITING_FOR_DEL,
+				RIGHT_ADMIN                             => Vhffs::Constants::ML_RIGHT_ADMIN
+			}
+		},
 		FILTERS => {
 			i18n => \&gettext,
 			mail => sub {
@@ -470,60 +466,60 @@
 					return sprintf($format, @args);
 				}
 			}, 1],
-            stringify_status => sub {
-                return Vhffs::Functions::status_string_from_status_id( $_[0] );
-            },
-            stringify_type => sub {
-                Vhffs::Functions::type_string_from_type_id( $_[0] );
-            }
+			stringify_status => sub {
+				return Vhffs::Functions::status_string_from_status_id( $_[0] );
+			},
+			stringify_type => sub {
+				Vhffs::Functions::type_string_from_type_id( $_[0] );
+			}
 		},
-        PRE_CHOMP => 2
+		PRE_CHOMP => 2
 	};
-	
-	
+
 	$vars = {} unless(defined $vars);
-	
-	$vars->{theme} = $conf->get_panel->{default_theme} unless(defined $vars->{theme});
+
+	$vars->{do} = $cgi->param('do');	
+	$vars->{theme} = $conf->get_panel->{default_theme} unless defined $vars->{theme};
 	$vars->{panel_url} = $conf->get_panel->{url};
-    $vars->{title} = sprintf( gettext( '%s\'s Panel' ), $conf->get_host_name );
-    $vars->{page_title} = $self->{title};
-    $vars->{public_url} = $self->{vhffs}->get_config->get_panel->{'url_public'} if($self->is_public);
-    if(defined $self->{cgi}->param('msg')) {
-        $vars->{msg} = Encode::decode_utf8($self->{cgi}->param('msg'));
-    }
-    my @langs = $self->{vhffs}->get_config->get_available_languages;
-    $vars->{languages} = \@langs;
-    $vars->{language} = $self->{lang};
-    $vars->{errors} = $self->{errors};
-    $vars->{infos} = $self->{infos};
-    $vars->{current_user} = $self->{user};
-    $vars->{current_group} = ( defined $self->{cgi}->param('group') ? Vhffs::Group::get_by_groupname( $self->{vhffs} , $self->{cgi}->param('group') ) : undef );
+	$vars->{title} = sprintf( gettext( '%s\'s Panel' ), $conf->get_host_name );
+	$vars->{page_title} = $self->{title};
+	$vars->{public_url} = $self->{vhffs}->get_config->get_panel->{'url_public'} if $self->is_public;
+	$vars->{msg} = Encode::decode_utf8($self->{cgi}->param('msg')) if defined $self->{cgi}->param('msg');
+	my @langs = $self->{vhffs}->get_config->get_available_languages;
+	$vars->{languages} = \@langs;
+	$vars->{language} = $self->{lang};
+	$vars->{errors} = $self->{errors};
+	$vars->{infos} = $self->{infos};
+	$vars->{current_user} = $self->{user};
+	$vars->{current_group} = $self->{group};
 
 	# Handling ajax stuff
 	if($self->{is_ajax_request}) {
 		delete $create_vars->{PROCESS};
 	} else {
-        if(defined $layout) {
-            $create_vars->{PROCESS} = "layouts/$layout";
-        } else {
-    		$create_vars->{PROCESS} = 'layouts/panel.tt';
-            $vars->{panel_header} = {
-                help_url => $conf->get_panel->{'url_help'} || 'http://www.vhffs.org/',
-                admin_menu => (( CGI::url( -absolute => 1) =~ /^\/admin\// ) || defined $self->{cgi}->param('admin_menu')),
-                available_services => $conf->get_available_services
-            };
-        }
+		if(defined $layout) {
+			$create_vars->{PROCESS} = 'layouts/'.$layout;
+		} else {
+			$create_vars->{PROCESS} = 'layouts/panel.tt';
+			$vars->{panel_header} = {
+				help_url => $conf->get_panel->{'url_help'} || 'http://www.vhffs.org/',
+				admin_menu => $self->{display_admin_menu},
+				available_services => $conf->get_available_services
+			};
+		}
 	}
 	
 	my $template = new Template($create_vars);
 
-	binmode STDOUT , ':utf8';	
-	
-	print CGI->header( -cookie=>[ @{$self->{cookies}} ], -type=>'text/html', -charset=>'utf-8' );
+	print $cgi->header( -cookie=>[ @{$self->{cookies}} ], -type=>'text/html', -charset=>'utf-8' );
 
-	$template->process($file, $vars) 
-		|| die('Error while processing template: '.$template->error());
-    exit(0);
+	my $data;
+	unless( $template->process($file, $vars, \$data) ) {
+		warn 'Error while processing template: '.$template->error();
+		return;
+	}
+	# FCGI does not handle UTF9
+	print Encode::encode_utf8( $data );
 }
 
 =pod
@@ -544,21 +540,21 @@
 
 =cut
 sub redirect {
-    my ($panel, $dest, $cookies) = @_;
+	my ($panel, $dest, $cookies) = @_;
+	my $cgi = $panel->{cgi};
 
-    $dest = Encode::encode_utf8( $dest );
+	$dest = Encode::encode_utf8( $dest );
 
-    if(defined $cookies) {
-        if(ref($cookies)) {
-            foreach(@$cookies) {
-                print "Set-Cookie: $_\n";
-            }
-        } else {
-            print "Set-Cookie: $cookies\n";
-        }
-    }
-    print CGI::redirect($dest);
-    exit(0);
+	if(defined $cookies) {
+		if(ref($cookies)) {
+			foreach(@$cookies) {
+				print "Set-Cookie: $_\n";
+			}
+		} else {
+			print "Set-Cookie: $cookies\n";
+		}
+	}
+	print $cgi->redirect($dest);
 }
 
 1;

Modified: trunk/vhffs-api/src/Vhffs/Panel/Mercurial.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Mercurial.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/Mercurial.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -56,73 +56,296 @@
 =cut
 
 
-sub getall_per_group
-{
-    my ( $main, $gid ) = @_;
+sub getall_per_group {
+	my ( $main, $gid ) = @_;
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT s.object_id AS oid, s.reponame AS displayname, o.state FROM vhffs_mercurial s INNER JOIN vhffs_object o ON s.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY s.reponame';
-    my $sth = $dbh->prepare($sql) or return -1;
-    $sth->execute($gid) or return -2;
-    my $mercurial = [];
-    while(my $s = $sth->fetchrow_hashref) {
-        $s->{active} = ($s->{state} == Vhffs::Constants::ACTIVATED);
-        $s->{refused} = ($s->{state} == Vhffs::Constants::VALIDATION_REFUSED);
-        $s->{state} = Vhffs::Functions::status_string_from_status_id($s->{state});
-        push @$mercurial, $s;
-    }
-    return $mercurial;
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT s.object_id AS oid, s.reponame AS displayname, o.state FROM vhffs_mercurial s INNER JOIN vhffs_object o ON s.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY s.reponame';
+	my $sth = $dbh->prepare($sql) or return -1;
+	$sth->execute($gid) or return -2;
+	my $mercurial = [];
+	while(my $s = $sth->fetchrow_hashref) {
+		$s->{active} = ($s->{state} == Vhffs::Constants::ACTIVATED);
+		$s->{refused} = ($s->{state} == Vhffs::Constants::VALIDATION_REFUSED);
+		$s->{state} = Vhffs::Functions::status_string_from_status_id($s->{state});
+		push @$mercurial, $s;
+	}
+	return $mercurial;
 }
 
 sub get_repos_per_group {
-    my ($main, $gid, $public_only) = @_;
-    $public_only = 1 unless(defined $public_only);
+	my ($main, $gid, $public_only) = @_;
+	$public_only = 1 unless(defined $public_only);
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT g.reponame, o.description FROM vhffs_mercurial g INNER JOIN vhffs_object o ON o.object_id = g.object_id '.
-	'WHERE '.($public_only ? 'public = 1 AND ' : '').'o.owner_gid = ? AND o.state = ?';
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, $gid, Vhffs::Constants::ACTIVATED);
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT g.reponame, o.description FROM vhffs_mercurial g INNER JOIN vhffs_object o ON o.object_id = g.object_id '.
+	  'WHERE '.($public_only ? 'public = 1 AND ' : '').'o.owner_gid = ? AND o.state = ?';
+ 	return $dbh->selectall_arrayref($sql, { Slice => {} }, $gid, Vhffs::Constants::ACTIVATED);
 }
 
 
-sub search {
-    my ($main, $name) = @_;
+sub search_mercurial {
+	my ($main, $name) = @_;
 
-    my @params;
-    my $sql = 'SELECT m.reponame as label, g.groupname as owner_group, o.state, u.username as owner_user '.
-        'FROM vhffs_mercurial m '.
-        'INNER JOIN vhffs_object o ON (o.object_id = m.object_id) '.
-        'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
-        'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
+	my @params;
+	my $sql = 'SELECT m.reponame as label, g.groupname as owner_group, o.state, u.username as owner_user '.
+	  'FROM vhffs_mercurial m '.
+	  'INNER JOIN vhffs_object o ON (o.object_id = m.object_id) '.
+	  'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
+	  'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
 
-    if( defined $name ) {
-        $sql .= 'WHERE m.reponame LIKE ? ';
-        push(@params, '%'.lc($name).'%');
-    }
+	if( defined $name ) {
+		$sql .= 'WHERE m.reponame LIKE ? ';
+		push(@params, '%'.lc($name).'%');
+	}
 
-    $sql .= 'ORDER BY m.reponame';
+	$sql .= 'ORDER BY m.reponame';
 
-    my $dbh = $main->get_db_object();
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
+	my $dbh = $main->get_db_object();
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
 }
 
 
 
-sub create_mercurial
-{
-    my ($main, $repo, $description, $user, $group) = @_;
+sub create_mercurial {
+	my ($main, $repo, $description, $user, $group) = @_;
+	return -1 unless defined $user;
+	return -2 unless defined $group;
+    
+	my $mercurial = Vhffs::Services::Mercurial::create( $main, $repo, $description, $user, $group );    
+	return -1 unless defined $mercurial;
 
-    return -1 unless( defined $user );
-    return -2 unless( defined $group );
+	return -3 if Vhffs::Acl::add_acl( $user , $mercurial , Vhffs::Constants::ACL_DELETE , $main ) < 0;
+	return -3 if Vhffs::Acl::add_acl( $group , $mercurial , Vhffs::Constants::ACL_VIEW , $main ) < 0;
     
-    my $mercurial = Vhffs::Services::Mercurial::create( $main, $repo, $description, $user, $group );
-    
-    return -1 unless( defined $mercurial );
-    
-    return ( -3 ) if ( Vhffs::Acl::add_acl( $user , $mercurial , Vhffs::Constants::ACL_DELETE , $main ) < 0 );
-    return ( -3 ) if( Vhffs::Acl::add_acl( $group , $mercurial , Vhffs::Constants::ACL_VIEW , $main ) < 0 );
-    
-    return $mercurial;
+	return $mercurial;
 }
 
+sub create {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group and $user->can_modify( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+	$panel->set_group( $group );
+
+	my $submitted = $cgi->param('mercurial_submit');
+	my $reponame = '';
+	my $description = '';
+	my $vars = {};
+
+	if( $submitted ) {
+		$reponame = $cgi->param('reponame');
+		my $fullreponame = $group->get_groupname.'/'.$reponame;
+		$description = Encode::decode_utf8( $cgi->param('description') );
+		unless( defined $reponame and defined $description ) {
+			$panel->add_error( gettext('CGI Error !') );
+		} else {
+			$panel->add_error( gettext('Invalid repository name. It must contain between 3 and 64 characters, only lowercase letters and numbers') ) unless Vhffs::Services::Mercurial::check_name($fullreponame);
+			$panel->add_error( gettext('You must enter a description') ) unless $description !~ /^\s*$/;
+		}
+
+		unless( $panel->has_errors() ) {
+			my $mercurial = Vhffs::Panel::Mercurial::create_mercurial( $vhffs, $fullreponame, $description, $user, $group );
+			if(defined $mercurial) {
+				my $url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('The Mercurial object was successfully created !');
+				$panel->redirect($url);
+				return;
+			}
+
+			$panel->add_error( gettext('An error occured while creating the mercurial repository') );
+		}
+
+		$vars->{reponame} = $reponame;
+		$vars->{description} = $description;
+	}
+
+	$vars->{group} = $group;
+	$panel->render('mercurial/create.tt', $vars);
+}
+
+
+sub prefs {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $repo_name = $cgi->param('name');
+	unless( defined $repo_name ) {
+		$panel->render('misc/message.tt', { message => gettext( 'CGI Error !' ) } );
+		return;
+	}
+
+	my $mercurial = Vhffs::Services::Mercurial::get_by_reponame( $vhffs , $repo_name );
+	unless( defined $mercurial ) {
+		$panel->render('misc/message.tt', { message => gettext( 'Cannot get informations on this object' ) } );
+		return;
+	}
+
+	unless( $user->can_view( $mercurial ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) } );
+		return;
+	}
+
+	save_prefs($panel, $mercurial) if defined $cgi->param('save_prefs_submit');
+
+	$panel->set_title( gettext("Modify Mercurial repository") );
+	my $vars = {};
+	$vars->{repository} = $mercurial;
+	$vars->{notify_from} = $vhffs->get_config->get_service('mercurial')->{notify_from};
+	$vars->{type} = 'mercurial';
+	$panel->render( 'scm/prefs.tt', $vars );
+}
+
+sub save_prefs {
+	my $panel = shift;
+	my $mercurial = shift;
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
+
+	my $public = $cgi->param('public');
+	my $ml_name = $cgi->param('ml_name');
+
+	unless( $user->can_modify($mercurial) ) {
+		$panel->add_error( gettext('You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights') );
+		return 0;
+	}
+
+	unless( defined $public and defined $ml_name ) {
+		$panel->add_error( gettext('CGI error !') );
+		return 0;
+	}
+
+	if($public != $mercurial->is_public) {
+		if($public == 1) {
+			$mercurial->set_public();
+		} else {
+			$mercurial->set_private();
+		}
+		$mercurial->set_status(Vhffs::Constants::WAITING_FOR_MODIFICATION);
+	}
+
+	if( $ml_name =~ /^\s*$/ or Vhffs::Functions::valid_mail($ml_name) ) {
+		if($ml_name ne $mercurial->get_ml_name) {
+			$mercurial->set_ml_name($ml_name);
+			$mercurial->set_status( Vhffs::Constants::WAITING_FOR_MODIFICATION );
+		}
+	} else {
+		$panel->add_error( gettext('Invalid mailing list address') );
+		return 0;
+	}
+
+	if($mercurial->get_status == Vhffs::Constants::WAITING_FOR_MODIFICATION) {
+		if($mercurial->commit > 0) {
+			my $group = Vhffs::Group::get_by_gid( $vhffs , $mercurial->{'owner_gid'} );
+			my $url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('Modifications applied. Please wait while your repository is being updated');
+			$panel->redirect($url);
+			return 1;
+		}
+
+		$panel->add_error( gettext('Unable to apply modifications') );
+		return 0;
+	}
+
+	return 0;
+}
+
+sub index {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group ) {
+		$panel->render_template('misc/message.tt', { message => gettext('You have to select a group first') } );
+		return;
+	}
+
+	unless($group->get_status == Vhffs::Constants::ACTIVATED) {
+		$panel->render( 'misc/message.tt', { message => gettext('This group is not activated yet') } );
+		return;
+	}
+
+	unless( $user->can_view( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}	
+
+	$panel->set_group( $group );
+	$panel->set_title( sprintf(gettext('Mercurial repositories for %s'), $group->get_groupname) );
+	my $mercurial = Vhffs::Panel::Mercurial::getall_per_group( $vhffs, $group->get_gid );
+	if($mercurial < 0) {
+		$panel->render( 'misc/message.tt', { message => gettext('Unable to get Mercurial repositories') } );
+		return;
+	}
+
+	$panel->render( 'misc/service-index.tt', {
+	  label => 'Mercurial repositories',
+	  group => $group,
+	  list => $mercurial,
+	  help_url => $vhffs->get_config->get_service('mercurial')->{url_doc},
+	  type => 'mercurial'
+	  });
+}
+
+sub search {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $name = $cgi->param('name');
+	my $vars = {};
+
+	unless( defined $name ) {
+
+		$panel->render('admin/misc/search.tt', {
+		  search_title => gettext('Mercurial search'),
+		  type => 'mercurial'
+		  });
+		return;
+	}
+
+	if( $name =~ /^\s*$/ ) {
+		$vars->{list_title} = gettext('List of all mercurial repositories');
+		undef $name;
+	} else {
+		$vars->{list_title} = sprintf( gettext('Search result for %s'), $name );
+	}
+	$vars->{list} = search_mercurial( $vhffs , $name );
+	$vars->{type} = 'mercurial';
+	$panel->render('admin/misc/list.tt', $vars);
+}
+
+sub adminindex {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	$panel->set_title(gettext('Mercurial repositories administration'));
+	require Vhffs::Panel::Admin;
+	$panel->render('admin/index.tt', { categories => [ Vhffs::Panel::Admin::get_mercurial_category() ] } );
+}
+
 1;

Added: trunk/vhffs-api/src/Vhffs/Panel/Moderation.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Moderation.pm	                        (rev 0)
+++ trunk/vhffs-api/src/Vhffs/Panel/Moderation.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -0,0 +1,109 @@
+#!%PERL%
+# Copyright (c) vhffs project and its contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#2. Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution.
+#3. Neither the name of vhffs nor the names of its contributors
+#   may be used to endorse or promote products derived from this
+#   software without specific prior written permission.
+#
+#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use utf8;
+
+package Vhffs::Panel::Moderation;
+
+use POSIX qw(locale_h);
+use locale;
+use Locale::gettext;
+use Encode;
+
+use Vhffs::Constants;
+use Vhffs::Functions;
+use Vhffs::ObjectFactory;
+
+sub moderation {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $accept = $cgi->param('accept');
+	my $refuse = $cgi->param('refuse');
+
+	if(defined $accept or defined $refuse) {
+		# Submitted
+		my $oid = $cgi->param('oid');
+		my $message = Encode::decode_utf8( $cgi->param('message') );
+
+		unless(defined $oid and defined $message) {
+			$panel->render('misc/message.tt', { message => gettext( 'CGI Error !' ) } );
+			return;
+		}
+
+		my $object = Vhffs::ObjectFactory::fetch_object( $vhffs , $oid );
+		unless(defined $object) {
+			$panel->render('misc/message.tt', { message => gettext( 'Object not found' ) } );
+			return;
+		}
+
+		if( defined $refuse and $message !~ /\S/) {
+			$panel->add_error( gettext('You have to enter a refuse reason') );
+		} else {
+			if(defined $refuse) {
+				if($object->moderate_refuse( $message ) >= 0) {
+					$panel->add_info( gettext('Object refused') );
+				} else {
+					$panel->add_error( gettext('Error while updating object') );
+				}
+			} else {
+				if($object->moderate_accept( $message ) >= 0) {
+					$panel->add_info( gettext('Object accepted') );
+				} else {
+					$panel->add_error( gettext('Error while updating object') );
+				}
+			}
+		}
+	}
+
+	$panel->set_title( gettext('Moderation') );	
+
+	# TODO This is pure crap but I'm currently working
+	# on Template::Toolkit and sweared no to touch anything
+	# else...
+	my $objects = Vhffs::Object::getall( $vhffs, undef, Vhffs::Constants::WAITING_FOR_VALIDATION );
+	my $vars = {
+		objects => [],
+		use_notation => ( $vhffs->get_config->get_users->{'use_notation'} eq 'yes' )
+	};
+	foreach my $o(@$objects) {
+		push @{$vars->{objects}}, Vhffs::ObjectFactory::fetch_object( $vhffs, $o->{object_id});
+	}
+	$panel->render('admin/moderation/index.tt', $vars);
+}
+
+1;

Deleted: trunk/vhffs-api/src/Vhffs/Panel/Modo.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Modo.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/Modo.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,63 +0,0 @@
-#!%PERL%
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#    notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-#    notice, this list of conditions and the following disclaimer in 
-#    the documentation and/or other materials provided with the 
-#    distribution.
-# 3. Neither the name of vhffs nor the names of its contributors 
-#    may be used to endorse or promote products derived from this 
-#    software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-use strict;
-use utf8;
-
-package Vhffs::Panel::Modo;
-
-use base qw(Vhffs::Panel::Main);
-
-use locale;
-use Locale::gettext;
-use POSIX qw(locale_h);
-
-use lib '%VHFFS_LIB_DIR%';
-use Vhffs::Tag;
-use Vhffs::Functions;
-
-=head1 Vhffs::Panel::Modo
-
-C<Vhffs::Panel> specialization that performs necessary checks on the user
-to ensure it is moderator.
-
-=cut
-
-sub new {
-	my ($class, @args) = @_;
-	my $panel = $class->SUPER::new(@args);
-    $panel->get_session();
-	$panel->check_modo();
-	return $panel;
-}
-
-1;
-

Modified: trunk/vhffs-api/src/Vhffs/Panel/Mysql.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Mysql.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/Mysql.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -52,47 +52,38 @@
 =cut
 
 
-sub search
-{
-    my ($main, $name) = @_; 
+sub search_mysql {
+	my ($main, $name) = @_; 
     
-    my @params;
-    my $sql = 'SELECT m.dbname as label, g.groupname as owner_group, o.state, u.username as owner_user '.
-        'FROM vhffs_mysql m '.
-        'INNER JOIN vhffs_object o ON (o.object_id = m.object_id) '.
-        'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
-        'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
+	my @params;
+	my $sql = 'SELECT m.dbname as label, g.groupname as owner_group, o.state, u.username as owner_user '.
+	  'FROM vhffs_mysql m '.
+	  'INNER JOIN vhffs_object o ON (o.object_id = m.object_id) '.
+	  'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
+	  'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
 
-    if( defined $name ) {
-        $sql .= 'WHERE m.dbname LIKE ? ';
-        push(@params, '%'.lc($name).'%' );
-    }
+	if( defined $name ) {
+		$sql .= 'WHERE m.dbname LIKE ? ';
+		push(@params, '%'.lc($name).'%' );
+	}
 
-    $sql .= 'ORDER BY label';
+	$sql .= 'ORDER BY label';
 
-    my $dbh = $main->get_db_object();
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
+	my $dbh = $main->get_db_object();
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
 }
 
-
-
-
-sub create_mysql($$$$$$$)
-{
-    my( $main , $dbname , $user , $group , $dbuser, $dbpass, $description ) = @_;
-
-    return undef if( ! defined $user );
-    return undef if( ! defined $group );
-
+sub create_mysql($$$$$$$) {
+	my( $main , $dbname , $user , $group , $dbuser, $dbpass, $description ) = @_;
+	return undef unless defined $user and defined $group;
     
-    my $mysql = Vhffs::Services::Mysql::create($main, $dbname, $dbuser, $dbpass, $description, $user, $group);
+	my $mysql = Vhffs::Services::Mysql::create($main, $dbname, $dbuser, $dbpass, $description, $user, $group);
+	return undef unless defined $mysql;
 
-    return undef unless( defined $mysql );
+	return undef if Vhffs::Acl::add_acl( $user , $mysql , Vhffs::Constants::ACL_DELETE , $main ) < 0;
+	return undef if Vhffs::Acl::add_acl( $group , $mysql , Vhffs::Constants::ACL_VIEW , $main ) < 0;
 
-    return undef if ( Vhffs::Acl::add_acl( $user , $mysql , Vhffs::Constants::ACL_DELETE , $main ) < 0 );
-    return undef if ( Vhffs::Acl::add_acl( $group , $mysql , Vhffs::Constants::ACL_VIEW , $main ) < 0 );
-
-    return $mysql;
+	return $mysql;
 }
 
 =pod
@@ -107,22 +98,238 @@
 =cut
 
 
-sub getall_per_group
-{
-    my ( $main, $gid ) = @_;
+sub getall_per_group {
+	my ( $main, $gid ) = @_;
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT m.object_id AS oid, m.dbname AS displayname, o.state FROM vhffs_mysql m INNER JOIN vhffs_object o ON m.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY m.dbname';
-    my $sth = $dbh->prepare($sql) or return -1;
-    $sth->execute($gid) or return -2;
-    my $mysql = [];
-    while(my $m = $sth->fetchrow_hashref) {
-        $m->{active} = ($m->{state} == Vhffs::Constants::ACTIVATED);
-        $m->{refused} = ($m->{state} == Vhffs::Constants::VALIDATION_REFUSED);
-        $m->{state} = Vhffs::Functions::status_string_from_status_id($m->{state});
-        push @$mysql, $m;
-    }
-    return $mysql;
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT m.object_id AS oid, m.dbname AS displayname, o.state FROM vhffs_mysql m INNER JOIN vhffs_object o ON m.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY m.dbname';
+	my $sth = $dbh->prepare($sql) or return -1;
+	$sth->execute($gid) or return -2;
+	my $mysql = [];
+	while(my $m = $sth->fetchrow_hashref) {
+		$m->{active} = ($m->{state} == Vhffs::Constants::ACTIVATED);
+		$m->{refused} = ($m->{state} == Vhffs::Constants::VALIDATION_REFUSED);
+		$m->{state} = Vhffs::Functions::status_string_from_status_id($m->{state});
+		push @$mysql, $m;
+	}
+	return $mysql;
 }
 
+
+sub create {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group and $user->can_modify( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+	$panel->set_group( $group );
+
+	my $submitted = defined($cgi->param('mysql_submit'));
+	my $dbsuffix = '';
+	my $description = '';
+	my $dbpass = '';
+	my $vars = {};
+
+	if( $submitted ) {
+		$dbsuffix = $cgi->param('db_suffix');
+		my $dbname = $group->get_groupname.'_'.$dbsuffix;
+		my $dbuser = $dbname;
+		$dbpass = $cgi->param('db_pass');
+		$description = Encode::decode_utf8( $cgi->param('description') );
+
+		unless( defined $dbpass and defined $dbsuffix and defined $description ) {
+			$panel->add_error( gettext('CGI Error !') );
+		} else {
+			$panel->add_error( gettext('You must enter a description') ) unless $description !~ /^\s*$/;
+			$panel->add_error( gettext('Invalid database name, it must contain only numbers, lowercase letters and underscore (the latter isn\'t allowed in first or last position) and be between 3 and 32 characters.') ) unless Vhffs::Services::Mysql::check_dbname($dbname);
+			$panel->add_error( gettext('Invalid password. It must contain at least 3 characters') ) unless Vhffs::Services::Mysql::check_dbpass($dbpass);
+		}
+
+		unless( $panel->has_errors() ) {
+			if(defined Vhffs::Panel::Mysql::create_mysql($vhffs, $dbname, $user, $group, $dbuser, $dbpass, $description)) {
+				my $url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('The MySQL DB was successfully created !');
+				$panel->redirect($url);
+				return;
+			} else {
+				$panel->add_error( 'An error occured while creating the object.' );
+			}
+		}
+
+		$vars->{db_suffix} = $dbsuffix;
+		$vars->{description} = $description;
+	}
+
+	$vars->{group} = $group;
+	$panel->render('mysql/create.tt', $vars);
+}
+
+sub prefs {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $dbname = $cgi->param('name');
+	my $mysql = Vhffs::Services::Mysql::get_by_dbname( $vhffs , $dbname );
+
+	unless( defined $dbname ) {
+		$panel->render('misc/message.tt', { message => gettext( 'CGI Error !' ) } );
+		return;
+	}
+
+	unless( defined $mysql ) {
+		$panel->render('misc/message.tt', { message => gettext('Cannot get informations on this object') } );
+		return;
+	}
+
+	unless( $user->can_view( $mysql ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) } );
+		return;
+	}
+	
+	if(defined $cgi->param('save_prefs_submit')) {
+		return if save_prefs($panel, $mysql);
+	}
+
+	my $vars = { db => $mysql, type => 'mysql' };
+
+	$panel->set_title( gettext('MySQL Administration') );
+	$panel->render('database/prefs.tt', $vars);
+}
+
+sub save_prefs {
+	my $panel = shift;
+	my $mysql = shift;
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_gid( $vhffs , $mysql->{'owner_gid'} ) if defined $mysql;
+
+	unless( defined $group and $user->can_modify($mysql) ) {
+		$panel->add_error( gettext('You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights') );
+		return 0;
+	}
+	$panel->set_group( $group );
+
+	my $new_passwd = $cgi->param('newpassword');
+	unless(defined $new_passwd) {
+		$panel->add_error( gettext('CGI Error !') );
+		return 0;
+	}
+
+	if($mysql->set_dbpassword($new_passwd) < 0) {
+		$panel->add_error( gettext('Bad password, should be at least 3 chars') );
+		return 0;
+	}
+
+	$mysql->set_status( Vhffs::Constants::WAITING_FOR_MODIFICATION );
+	if($mysql->commit < 0) {
+		$panel->add_error( gettext('Unable to apply changes') );
+		$mysql->blank_password;
+		return 0;
+	}
+
+	my $url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('Password change request taken in account, please wait for processing');
+	$panel->redirect($url);
+	return 1;
+}
+
+sub index {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+
+	unless( defined $group ) {
+		$panel->render('misc/message.tt', { message => gettext('You have to select a group first') } );
+		return;
+	}
+
+	unless( $group->get_status == Vhffs::Constants::ACTIVATED ) {
+		$panel->render( 'misc/message.tt', { message => gettext('This group is not activated yet') } );
+		return;
+	}
+
+	unless( $user->can_view($group) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+
+	$panel->set_group( $group );
+	$panel->set_title( sprintf(gettext('MySQL DBs for %s'), $group->get_groupname) );
+	my $mysql = Vhffs::Panel::Mysql::getall_per_group( $vhffs, $group->get_gid );
+	if($mysql < 0) {
+		$panel->render('misc/message.tt', { message => gettext('Unable to get MySQL databases.') } );
+		return;
+	}
+
+	$panel->render( 'misc/service-index.tt', {
+	  label => 'MySQL databases',
+	  group => $group,
+	  list => $mysql,
+	  help_url => $vhffs->get_config->get_service('mysql')->{url_doc},
+	  type => 'mysql'
+	  });
+}
+
+sub search {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $name = $cgi->param('name');
+	my $vars = {};
+
+	unless( defined $name ) {
+
+		$panel->render('admin/misc/search.tt', {
+		  search_title => gettext('MySQL search'),
+		  type => 'mysql'
+		  });
+		return;
+	}
+
+	if( $name =~ /^\s*$/ ) {
+		$vars->{list_title} = gettext('List of all MySQL databases');
+		undef $name;
+	} else {
+		$vars->{list_title} = sprintf( gettext('Search result for %s'), $name );
+	}
+	$vars->{list} = search_mysql( $vhffs , $name );
+	$vars->{type} = 'mysql';
+	$panel->render('admin/misc/list.tt', $vars);
+}
+
+sub adminindex {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	$panel->set_title(gettext('MySQL databases administration'));
+	require Vhffs::Panel::Admin;
+	$panel->render('admin/index.tt', { categories => [ Vhffs::Panel::Admin::get_mysql_category() ] } );
+}
+
 1;

Modified: trunk/vhffs-api/src/Vhffs/Panel/Object.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Object.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/Object.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -38,25 +38,280 @@
 use locale;
 use Locale::gettext;
 
-sub search
-{
-    my ($main, $name) = @_;
+sub search_object {
+	my ($main, $name) = @_;
 
-    my @params;
-    my $sql = 'SELECT o.object_id AS oid, u.username as owner_user, g.groupname as owner_group, o.type, o.state '.
-        'FROM vhffs_object o '.
-        'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) '.
-        'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) ';
+	my @params;
+	my $sql = 'SELECT o.object_id AS oid, u.username as owner_user, g.groupname as owner_group, o.type, o.state '.
+	  'FROM vhffs_object o '.
+	  'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) '.
+	  'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) ';
 
-    if( defined $name ) {
-        $sql .= ' WHERE ( o.description ILIKE ? ) OR ( o.object_id = ? ) OR ( o.owner_uid = ? ) OR ( o.owner_gid = ? ) OR ( state = ? ) OR ( u.username LIKE ? ) OR ( g.groupname LIKE ? ) OR ( o.type = ? ) ';
-        push(@params, '%'.$name.'%', $name, $name, $name, $name, '%'.lc($name).'%', '%'.lc($name).'%', $name );
-    }
+	if( defined $name ) {
+		$sql .= ' WHERE ( o.description ILIKE ? ) OR ( o.object_id = ? ) OR ( o.owner_uid = ? ) OR ( o.owner_gid = ? ) OR ( state = ? ) OR ( u.username LIKE ? ) OR ( g.groupname LIKE ? ) OR ( o.type = ? ) ';
+		push(@params, '%'.$name.'%', $name, $name, $name, $name, '%'.lc($name).'%', '%'.lc($name).'%', $name );
+	}
 
-    $sql .= 'ORDER BY o.object_id';
+	$sql .= 'ORDER BY o.object_id';
 
-    my $dbh = $main->get_db_object();
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
+	my $dbh = $main->get_db_object();
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
 }
 
+sub history {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	require Vhffs::Object;
+	my $object = Vhffs::Object::get_by_oid( $vhffs , $cgi->param('oid') );
+
+	unless( defined $object ) {
+		$panel->render('misc/message.tt', { message => gettext( 'Cannot get information on this object') });
+		return;
+	}
+
+	unless( $user->can_view($object) ) {
+		$panel->render('misc/message.tt', { message => gettext('You\'re not allowed to view this object\'s ACL') });
+		return;
+	}
+
+	$panel->set_title( gettext('History') );
+	$panel->render('misc/history.tt', { history => $object->get_history });
+}
+
+sub resubmit {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $oid = $cgi->param('oid');
+	unless( defined $oid ) {
+		$panel->render('misc/message.tt', { message => gettext('CGI Error !') } );
+		return;
+	}
+
+	my $object = Vhffs::ObjectFactory::fetch_object( $vhffs , $oid );
+	unless(defined $object) {
+		$panel->render('misc/message.tt', { message => gettext('This object does not exist') } );
+		return;
+	}
+
+	unless($object->get_status == Vhffs::Constants::VALIDATION_REFUSED )  {
+		$panel->render('misc/message.tt', { message => gettext('This object is not in refused state') } );
+		return;
+	}
+
+	unless($object->get_owner_uid == $user->get_uid )  {
+		$panel->render('misc/message.tt', { message => gettext('You are not allowed to do it, you don\'t own this object') } );
+		return;
+	}
+
+	my $submitted = defined $cgi->param('submitted');
+	if( $submitted ) {
+		my $description = Encode::decode_utf8( $cgi->param('description') );
+		unless( defined $description ) {
+			$panel->add_error( gettext('CGI Error !') );
+			return;
+		}
+
+		unless( $description !~ /^\s*$/ ) {
+			$panel->add_error( gettext('You must enter a description') );
+			return;
+		}
+
+		if ( $object->resubmit_for_moderation( $description ) ) {
+			my $url;
+			if( $object->get_type == Vhffs::Constants::TYPE_GROUP ) {
+				$url = '?do=groupindex&msg='.gettext('The new description has been submitted');
+			} else {
+				my $group = Vhffs::Group::get_by_gid( $vhffs , $object->get_owner_gid );
+				$url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('The new description has been submitted');
+			}
+			$panel->redirect( $url );
+			return;
+		}
+
+		$panel->add_error( gettext('An error occured while updating this object.') );
+	}
+
+	$panel->set_title( gettext('Propose a new description') );
+
+	my $vars = { object => $object };
+	$panel->render('object/resubmit.tt', $vars);
+}
+
+sub cancel {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $oid = $cgi->param('oid');
+	unless(defined $oid) {
+		$panel->render('misc/message.tt', { message => gettext('CGI Error !') } );
+		return;
+	}
+
+	my $object = Vhffs::ObjectFactory::fetch_object( $vhffs , $oid );
+	unless(defined $object) {
+		$panel->render('misc/message.tt', { message => gettext('This object does not exist') } );
+		return;
+	}
+
+	unless($object->get_status == Vhffs::Constants::VALIDATION_REFUSED )  {
+		$panel->render('misc/message.tt', { message => gettext('This object is not in refused state') } );
+		return;
+	}
+
+	unless($object->get_owner_uid == $user->get_uid )  {
+		$panel->render('misc/message.tt', { message => gettext('You are not allowed to do it, you don\'t own this object') } );
+		return;
+	}
+
+	if( $object->delete )  {
+		my $url;
+		if( $object->get_type == Vhffs::Constants::TYPE_GROUP ) {
+			$url = '?do=groupindex&msg='.gettext('This object has been deleted');
+		} else {
+			my $group = Vhffs::Group::get_by_gid( $vhffs , $object->get_owner_gid );
+			$url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('This object has been deleted');
+		}
+		$panel->redirect( $url );
+		return;
+	}
+
+	$panel->render('misc/message.tt', { message => gettext('An error occured while deleting this object.') } );
+}
+
+sub delete {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $oid = $cgi->param('oid');
+	my $sure = $cgi->param('delete');
+	my $object = Vhffs::Object::get_by_oid( $vhffs, $oid );
+
+	my $message;
+
+	unless( defined $oid and defined $sure ) {
+		$message = gettext( 'CGI Error !' );
+	} elsif( not defined $object ) {
+		$message = gettext( 'Cannot retrieve informations about this object' );
+	} elsif( not $user->can_delete( $object ) ) {
+		$message = gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' );
+	} elsif( $sure == 0 ) {
+		$message = gettext( 'This object will NOT be deleted' );
+	} else {
+		$object->set_status( Vhffs::Constants::TO_DELETE );
+
+		# Commit all the changes for the current user
+		if( $object->commit < 0 ) {
+			$message = gettext( 'An error occured while deleting this object' );
+		} else {
+			$message = gettext( 'This object will be deleted' );
+		}
+	}	
+
+	my $vars = { message => $message };
+
+	if( $object->get_type == Vhffs::Constants::TYPE_GROUP ) {
+		$vars->{refresh_url} = '?do=groupindex';
+	} else {
+		$vars->{refresh_url} = '?do=groupview&group='.$object->get_owner_group;
+	}
+
+	$panel->render('misc/message.tt', $vars );
+}
+
+sub search {
+	my $panel = shift;
+	return unless $panel->check_admin();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $name = $cgi->param('name');
+	my $vars = {};
+
+	unless( defined $name ) {
+
+		$panel->render('admin/misc/search.tt', {
+		  search_title => gettext('Object search'),
+		  type => 'object'
+		  });
+		return;
+	}
+
+	if( $name =~ /^\s*$/ ) {
+		$vars->{list_title} = gettext('List of all objects');
+		undef $name;
+	} else {
+		$vars->{list_title} = sprintf( gettext('Search result for %s'), $name );
+	}
+	$vars->{objects} = search_object( $vhffs , $name );
+	$panel->render('admin/object/list.tt', $vars);
+}
+
+sub edit {
+	my $panel = shift;
+	return unless $panel->check_admin();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $oid = $cgi->param('oid');
+	my $status = $cgi->param('status');
+	my $description = Encode::decode_utf8( $cgi->param('description') );
+
+	unless(defined $oid) {
+		$panel->render('misc/message.tt', {
+	          message => gettext('CGI Error!')
+		  });
+		return;
+	}
+
+	require Vhffs::ObjectFactory;
+	my $object = Vhffs::ObjectFactory::fetch_object( $vhffs, $oid);
+	unless( defined $object ) {
+		$panel->render('misc/message.tt', {
+		  message => gettext('Object not found')
+		  });
+		return;
+	}
+
+	if(defined $status and defined $description) {
+		$object->set_status( $status );
+		$object->set_description( $description );
+		if($object->commit() >= 0) {
+			$panel->add_info( gettext('Object updated') );
+		} else {
+			$panel->add_error( gettext('Error while updating object') );
+		}
+	}
+
+
+	$panel->render('admin/object/edit.tt', {
+	  object => $object,
+	  use_avatars => ($object->get_type == Vhffs::Constants::TYPE_USER and $panel->use_users_avatars) || ($object->get_type == Vhffs::Constants::TYPE_GROUP and $panel->use_groups_avatars)
+	  });
+}
+
+
 1;

Modified: trunk/vhffs-api/src/Vhffs/Panel/Pgsql.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Pgsql.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/Pgsql.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -42,25 +42,25 @@
 use Vhffs::Services::Pgsql;
 
 
-sub search {
-    my ($main, $name) = @_;
+sub search_pgsql {
+	my ($main, $name) = @_;
 
-    my @params;
-    my $sql = 'SELECT p.dbname as label, g.groupname as owner_group, o.state, u.username as owner_user '.
-        'FROM vhffs_pgsql p '.
-        'INNER JOIN vhffs_object o ON (o.object_id = p.object_id) '.
-        'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
-        'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
+	my @params;
+	my $sql = 'SELECT p.dbname as label, g.groupname as owner_group, o.state, u.username as owner_user '.
+	  'FROM vhffs_pgsql p '.
+	  'INNER JOIN vhffs_object o ON (o.object_id = p.object_id) '.
+	  'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
+	  'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
 
-    if( defined $name ) {
-        $sql .= 'WHERE p.dbname LIKE ? ';
-        push(@params, '%'.lc($name).'%');
-    }
+	if( defined $name ) {
+		$sql .= 'WHERE p.dbname LIKE ? ';
+		push(@params, '%'.lc($name).'%');
+	}
 
-    $sql .= 'ORDER BY label';
+	$sql .= 'ORDER BY label';
 
-    my $dbh = $main->get_db_object();
-    return $dbh->selectall_arrayref( $sql, { Slice => {} }, @params);
+	my $dbh = $main->get_db_object();
+	return $dbh->selectall_arrayref( $sql, { Slice => {} }, @params);
 }
 
 
@@ -76,40 +76,250 @@
 =cut
 
 
-sub getall_per_group
-{
-    my ( $main, $gid ) = @_;
+sub getall_per_group {
+	my ( $main, $gid ) = @_;
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT p.object_id AS oid, p.dbname AS displayname, o.state FROM vhffs_pgsql p INNER JOIN vhffs_object o ON p.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY p.dbname';
-    my $sth = $dbh->prepare($sql) or return -1;
-    $sth->execute($gid) or return -2;
-    my $pgsql = [];
-    while(my $p = $sth->fetchrow_hashref) {
-        $p->{active} = ($p->{state} == Vhffs::Constants::ACTIVATED);
-        $p->{refused} = ($p->{state} == Vhffs::Constants::VALIDATION_REFUSED);
-        $p->{state} = Vhffs::Functions::status_string_from_status_id($p->{state});
-        push @$pgsql, $p;
-    }
-    return $pgsql;
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT p.object_id AS oid, p.dbname AS displayname, o.state FROM vhffs_pgsql p INNER JOIN vhffs_object o ON p.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY p.dbname';
+	my $sth = $dbh->prepare($sql) or return -1;
+	$sth->execute($gid) or return -2;
+	my $pgsql = [];
+	while(my $p = $sth->fetchrow_hashref) {
+		$p->{active} = ($p->{state} == Vhffs::Constants::ACTIVATED);
+		$p->{refused} = ($p->{state} == Vhffs::Constants::VALIDATION_REFUSED);
+		$p->{state} = Vhffs::Functions::status_string_from_status_id($p->{state});
+		push @$pgsql, $p;
+	}
+	return $pgsql;
 }
 
-sub create_pgsql
-{
-    my( $main , $dbname , $user , $group , $dbuser , $dbpass, $description ) = @_;
-
-    return -1 if( ! defined $user );
-    return -2 if( ! defined $group );
+sub create_pgsql {
+	my( $main , $dbname , $user , $group , $dbuser , $dbpass, $description ) = @_;
+	return -1 unless defined $user;
+	return -2 unless defined $group;
     
-    my $pgsql = Vhffs::Services::Pgsql::create($main, $dbname, $dbuser, $dbpass, $description, $user, $group);
+	my $pgsql = Vhffs::Services::Pgsql::create($main, $dbname, $dbuser, $dbpass, $description, $user, $group);
+	return undef unless defined $pgsql;
+	
+	return undef if Vhffs::Acl::add_acl( $user , $pgsql , Vhffs::Constants::ACL_DELETE , $main ) < 0;
+	return undef if Vhffs::Acl::add_acl( $group , $pgsql , Vhffs::Constants::ACL_VIEW , $main ) < 0;
+	return $pgsql;
+}
 
-	return undef if( ! defined $pgsql );
+sub create {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group and $user->can_modify( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+	$panel->set_group( $group );
+
+	my $submitted = defined($cgi->param('pgsql_submit'));
+	my $dbsuffix = '';
+	my $description = '';
+	my $dbpass = '';
+	my $vars = {};
+
+	if( $submitted ) {
+		$dbsuffix = $cgi->param('db_suffix');
+		my $dbname = $group->get_groupname.'_'.$dbsuffix;
+		my $dbuser = $dbname;
+		$dbpass = $cgi->param('db_pass');
+		$description = Encode::decode_utf8( $cgi->param('description') );
+
+		unless( defined $dbpass and defined $dbsuffix and defined $description ) {
+			$panel->add_error( gettext('CGI Error !') );
+		} else {
+			$panel->add_error( gettext('You must enter a description') ) unless $description !~ /^\s*$/;
+			$panel->add_error( gettext('Invalid database name, it must contain only numbers, lowercase letters and underscore (the latter isn\'t allowed in first or last position) and be between 3 and 32 characters.') ) unless Vhffs::Services::Pgsql::check_dbname($dbname);
+			$panel->add_error( gettext('Invalid password. It must contain at least 3 characters') ) unless Vhffs::Services::Pgsql::check_dbpass($dbpass);
+		}
+
+		unless( $panel->has_errors() ) {
+			if(defined Vhffs::Panel::Pgsql::create_pgsql($vhffs, $dbname, $user, $group, $dbuser, $dbpass, $description)) {
+				my $url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('The PostgreSQL DB was successfully created !');
+				$panel->redirect($url);
+				return;
+			} else {
+				$panel->add_error( 'An error occured while creating the object.' );
+			}
+		}
+
+		$vars->{db_suffix} = $dbsuffix;
+		$vars->{description} = $description;
+	}
+
+	$vars->{group} = $group;
+	$panel->render('pgsql/create.tt', $vars);
+}
+
+sub prefs {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $dbname = $cgi->param('name');
+	my $pgsql = Vhffs::Services::Pgsql::get_by_dbname( $vhffs , $dbname );
+
+	unless( defined $dbname ) {
+		$panel->render('misc/message.tt', { message => gettext( 'CGI Error !' ) } );
+		return;
+	}
+
+	unless( defined $pgsql ) {
+		$panel->render('misc/message.tt', { message => gettext('Cannot get informations on this object') } );
+		return;
+	}
+
+	unless( $user->can_view( $pgsql ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) } );
+		return;
+	}
 	
-    return undef if ( Vhffs::Acl::add_acl( $user , $pgsql , Vhffs::Constants::ACL_DELETE , $main ) < 0 );
-    return undef if( Vhffs::Acl::add_acl( $group , $pgsql , Vhffs::Constants::ACL_VIEW , $main ) < 0 );
+	if(defined $cgi->param('save_prefs_submit')) {
+		return if save_prefs($panel, $pgsql);
+	}
 
-	return $pgsql;
+	my $vars = { db => $pgsql, type => 'pgsql' };
+
+	$panel->set_title( gettext('PostgreSQL Administration') );
+	$panel->render('database/prefs.tt', $vars);
 }
 
+sub save_prefs {
+	my $panel = shift;
+	my $pgsql = shift;
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
 
+	my $group = Vhffs::Group::get_by_gid( $vhffs , $pgsql->{'owner_gid'} ) if defined $pgsql;
+
+	unless( defined $group and $user->can_modify($pgsql) ) {
+		$panel->add_error( gettext('You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights') );
+		return 0;
+	}
+	$panel->set_group( $group );
+
+	my $new_passwd = $cgi->param('newpassword');
+	unless(defined $new_passwd) {
+		$panel->add_error( gettext('CGI Error !') );
+		return 0;
+	}
+
+	if($pgsql->set_dbpassword($new_passwd) < 0) {
+		$panel->add_error( gettext('Bad password, should be at least 3 chars') );
+		return 0;
+	}
+
+	$pgsql->set_status( Vhffs::Constants::WAITING_FOR_MODIFICATION );
+	if($pgsql->commit < 0) {
+		$panel->add_error( gettext('Unable to apply changes') );
+		$pgsql->blank_password;
+		return 0;
+	}
+
+	my $url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('Password change request taken in account, please wait for processing');
+	$panel->redirect($url);
+	return 1;
+}
+
+sub index {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+
+	unless( defined $group ) {
+		$panel->render('misc/message.tt', { message => gettext('You have to select a group first') } );
+		return;
+	}
+
+	unless( $group->get_status == Vhffs::Constants::ACTIVATED ) {
+		$panel->render( 'misc/message.tt', { message => gettext('This group is not activated yet') } );
+		return;
+	}
+
+	unless( $user->can_view($group) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+
+	$panel->set_group( $group );
+	$panel->set_title( sprintf(gettext('PostgreSQL DBs for %s'), $group->get_groupname) );
+	my $pgsql = Vhffs::Panel::Pgsql::getall_per_group( $vhffs, $group->get_gid );
+	if($pgsql < 0) {
+		$panel->render('misc/message.tt', { message => gettext('Unable to get PostgreSQL databases.') } );
+		return;
+	}
+
+	$panel->render( 'misc/service-index.tt', {
+	  label => 'PostgreSQL databases',
+	  group => $group,
+	  list => $pgsql,
+	  help_url => $vhffs->get_config->get_service('pgsql')->{url_doc},
+	  type => 'pgsql'
+	  });
+}
+
+sub search {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $name = $cgi->param('name');
+	my $vars = {};
+
+	unless( defined $name ) {
+
+		$panel->render('admin/misc/search.tt', {
+		  search_title => gettext('PostgreSQL search'),
+		  type => 'pgsql'
+		  });
+		return;
+	}
+
+	if( $name =~ /^\s*$/ ) {
+		$vars->{list_title} = gettext('List of all PostgreSQL databases');
+		undef $name;
+	} else {
+		$vars->{list_title} = sprintf( gettext('Search result for %s'), $name );
+	}
+	$vars->{list} = search_pgsql( $vhffs , $name );
+	$vars->{type} = 'pgsql';
+	$panel->render('admin/misc/list.tt', $vars);
+}
+
+sub adminindex {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	$panel->set_title(gettext('PostgreSQL databases administration'));
+	require Vhffs::Panel::Admin;
+	$panel->render('admin/index.tt', { categories => [ Vhffs::Panel::Admin::get_pgsql_category() ] } );
+}
+
 1;

Modified: trunk/vhffs-api/src/Vhffs/Panel/Repository.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Repository.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/Repository.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -52,43 +52,42 @@
 
 =cut
 
-sub getall_per_group
-{
-    my ( $main, $gid ) = @_;
+sub getall_per_group {
+	my ( $main, $gid ) = @_;
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT r.object_id AS oid, r.name AS displayname, o.state FROM vhffs_repository r INNER JOIN vhffs_object o ON r.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY r.name';
-    my $sth = $dbh->prepare($sql) or return -1;
-    $sth->execute($gid) or return -2;
-    my $mysql = [];
-    while(my $m = $sth->fetchrow_hashref) {
-        $m->{active} = ($m->{state} == Vhffs::Constants::ACTIVATED);
-        $m->{refused} = ($m->{state} == Vhffs::Constants::VALIDATION_REFUSED);
-        $m->{state} = Vhffs::Functions::status_string_from_status_id($m->{state});
-        push @$mysql, $m;
-    }
-    return $mysql;
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT r.object_id AS oid, r.name AS displayname, o.state FROM vhffs_repository r INNER JOIN vhffs_object o ON r.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY r.name';
+	my $sth = $dbh->prepare($sql) or return -1;
+	$sth->execute($gid) or return -2;
+	my $mysql = [];
+	while(my $m = $sth->fetchrow_hashref) {
+		$m->{active} = ($m->{state} == Vhffs::Constants::ACTIVATED);
+		$m->{refused} = ($m->{state} == Vhffs::Constants::VALIDATION_REFUSED);
+		$m->{state} = Vhffs::Functions::status_string_from_status_id($m->{state});
+		push @$mysql, $m;
+	}
+	return $mysql;
 }
 
-sub search {
-    my ($main, $name) = @_;
+sub search_repository {
+	my ($main, $name) = @_;
 
-    my @params;
-    my $sql = 'SELECT r.name as label, g.groupname as owner_group, o.state, u.username as owner_user '.
-        'FROM vhffs_repository r '.
-        'INNER JOIN vhffs_object o ON (o.object_id = r.object_id) '.
-        'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
-        'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
+	my @params;
+	my $sql = 'SELECT r.name as label, g.groupname as owner_group, o.state, u.username as owner_user '.
+	  'FROM vhffs_repository r '.
+	  'INNER JOIN vhffs_object o ON (o.object_id = r.object_id) '.
+	  'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
+	  'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
 
 	if( defined $name ) {
-        $sql .= 'WHERE r.name LIKE ? ';
-        push(@params, '%'.lc($name).'%');
-    }
+		$sql .= 'WHERE r.name LIKE ? ';
+		push(@params, '%'.lc($name).'%');
+	}
 
-    $sql .= 'ORDER BY label';
+	$sql .= 'ORDER BY label';
 
-    my $dbh = $main->get_db_object();
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
+	my $dbh = $main->get_db_object();
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
 }
 
 
@@ -96,17 +95,209 @@
 sub create_repository
 {
 	my( $main , $name , $user , $group, $description ) = @_;
+	return undef unless defined $user and defined $group;
 
-    return undef unless(defined $user && defined $group);
-
 	my $repo = Vhffs::Services::Repository::create( $main , $name , $description, $user , $group );
+	return undef unless defined $repo;
 
-	return undef if( ! defined $repo);
+	return undef if Vhffs::Acl::add_acl( $user , $repo , Vhffs::Constants::ACL_DELETE , $main ) < 0;
+	return undef if Vhffs::Acl::add_acl( $group , $repo , Vhffs::Constants::ACL_VIEW , $main ) < 0;
 
-	return undef if ( Vhffs::Acl::add_acl( $user , $repo , Vhffs::Constants::ACL_DELETE , $main ) < 0 );
-	return undef if( Vhffs::Acl::add_acl( $group , $repo , Vhffs::Constants::ACL_VIEW , $main ) < 0 );
-
 	return $repo;
 }
 
+sub create {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group and $user->can_modify( $group ) ) {
+		$panel->render( 'misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+	$panel->set_group( $group );
+
+	my $submitted = $cgi->param('repo_submit');
+	my $description = '';
+	my $vars = {};
+
+	if( $submitted ) {
+		$description = Encode::decode_utf8( $cgi->param('description') );
+
+		unless( defined $description ) {
+			$panel->add_error( gettext('CGI Error !') );
+		} else {
+			$panel->add_error( gettext('You must enter a description') ) unless $description !~ /^\s*$/;
+		}
+
+		unless( $panel->has_errors() ) {		
+			my $repository = Vhffs::Panel::Repository::create_repository( $vhffs, $group->get_groupname, $user, $group , $description );
+			if( defined $repository ) {
+				my $url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('The repository was successfully created !');
+				$panel->redirect($url);
+				return;
+			}
+
+			$panel->add_error( gettext('An error occured while creating the object. Check that this group doesn\'t already have a download repository') );
+		}
+
+		$vars->{description} = $description;
+	}
+
+	$panel->set_title( gettext('Create a Download Repository') );
+	$vars->{group} = $group;
+	$panel->render( 'repository/create.tt', $vars );
+}
+
+sub prefs {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $repo_name = $cgi->param('name');
+	unless( defined $repo_name ) {
+		$panel->render('misc/message.tt', { message => gettext('CGI Error !') });
+		return;
+	}
+
+	my $repo = Vhffs::Services::Repository::get_by_reponame( $vhffs , $repo_name );
+	unless( defined $repo ) {
+		$panel->render('misc/message.tt', { message => gettext('Cannot get informations on this object') });
+		return;
+	}
+
+	unless( $user->can_view( $repo ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' )} );
+		return;
+	}
+
+	update_quota($panel, $repo) if defined $cgi->param('update_quota_submit');
+
+	my $vars = { repository => $repo };
+	$panel->set_title( gettext('Admin Download repository') );
+	$panel->render('repository/prefs.tt', $vars);
+}
+
+sub update_quota {
+	my $panel = shift;
+	my $repo = shift;
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
+
+	unless($user->is_admin()) {
+		$panel->add_error( gettext('Only administrators are allowed to do this') );
+		return;
+	}
+
+	my $quota = $cgi->param('new_quota');
+	unless(defined $quota and $quota =~ /^\d+$/) {
+		$panel->add_error( gettext('Invalid quota') );
+		return;
+	}
+ 
+	$repo->set_quota($quota);
+
+	if($repo->commit < 0) {
+		$panel->add_error( gettext('Unable to apply modifications, please try again later') );
+		return;
+	}
+
+	$panel->add_info( gettext('Repository updated, please wait while quota is updated on filesystem') );
+}
+
+sub index {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group ) {
+		$panel->render('misc/message.tt', { message => gettext('You have to select a group first') } );
+		return;
+	}
+
+	unless($group->get_status == Vhffs::Constants::ACTIVATED) {
+		$panel->render( 'misc/message.tt', { message => gettext('This group is not activated yet') } );
+		return;
+	}
+
+	unless( $user->can_modify( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+
+	$panel->set_group( $group );
+	$panel->set_title( sprintf(gettext('Download repositories for %s'), $group->get_groupname) );
+
+	my $repositories = Vhffs::Panel::Repository::getall_per_group( $vhffs, $group->get_gid );
+	if($repositories < 0) {
+		$panel->render( 'misc/message.tt', { message => gettext('Unable to get download repositories') } );
+		return;
+	}
+
+	$panel->render( 'misc/service-index.tt', {
+	  label => 'Download repositories',
+	  group => $group,
+	  list => $repositories,
+	  help_url => $vhffs->get_config->get_service('repository')->{url_doc},
+	  type => 'repository'
+	  });
+}
+
+sub search {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $name = $cgi->param('name');
+	my $vars = {};
+
+	unless( defined $name ) {
+
+		$panel->render('admin/misc/search.tt', {
+		  search_title => gettext('Download repositories search'),
+		  type => 'repository'
+		  });
+		return;
+	}
+
+	if( $name =~ /^\s*$/ ) {
+		$vars->{list_title} = gettext('List of all download repositories');
+		undef $name;
+	} else {
+		$vars->{list_title} = sprintf( gettext('Search result for %s'), $name );
+	}
+	$vars->{list} = search_repository( $vhffs , $name );
+	$vars->{type} = 'repository';
+	$panel->render('admin/misc/list.tt', $vars);
+}
+
+sub adminindex {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	$panel->set_title(gettext('Download repositories administration'));
+	require Vhffs::Panel::Admin;
+	$panel->render('admin/index.tt', { categories => [ Vhffs::Panel::Admin::get_repo_category() ] } );
+}
+
 1;

Added: trunk/vhffs-api/src/Vhffs/Panel/Stats.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Stats.pm	                        (rev 0)
+++ trunk/vhffs-api/src/Vhffs/Panel/Stats.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -0,0 +1,117 @@
+#!%PERL%
+# Copyright (c) vhffs project and its contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#2. Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution.
+#3. Neither the name of vhffs nor the names of its contributors
+#   may be used to endorse or promote products derived from this
+#   software without specific prior written permission.
+#
+#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use utf8;
+
+package Vhffs::Panel::Stats;
+
+use POSIX qw(locale_h);
+use locale;
+use Locale::gettext;
+use Encode;
+
+use Vhffs::Constants;
+use Vhffs::Functions;
+use Vhffs::Stats;
+
+
+sub stats {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $stats = new Vhffs::Stats( $vhffs );
+	unless( defined $stats ) {
+		$panel->render('misc/message.tt', { message => gettext( "Cannot get statistics") } );
+		return;
+	}
+
+	my $vars = {
+	  users_count => $stats->get_user_total,
+	  administrators_count => $stats->get_user_total_admin,
+	  moderators_count => $stats->get_user_total_moderator,
+
+	  groups_count => $stats->get_groups_total,
+	  activated_groups_count => $stats->get_groups_activated,
+
+	  waiting_web_count => $stats->get_web_in_moderation,
+	  activated_web_count => $stats->get_web_activated,
+
+	  waiting_dns_count => $stats->get_dns_in_moderation,
+	  activated_dns_count => $stats->get_dns_activated,
+
+	  waiting_cvs_count => $stats->get_cvs_in_moderation,
+	  activated_cvs_count => $stats->get_cvs_activated,
+
+	  waiting_svn_count => $stats->get_svn_in_moderation,
+	  activated_svn_count => $stats->get_svn_activated,
+
+	  waiting_git_count => $stats->get_git_in_moderation,
+	  activated_git_count => $stats->get_git_activated,
+
+	  waiting_mercurial_count => $stats->get_mercurial_in_moderation,
+	  activated_mercurial_count => $stats->get_mercurial_activated,
+
+	  waiting_bazaar_count => $stats->get_bazaar_in_moderation,
+	  activated_bazaar_count => $stats->get_bazaar_activated,
+
+	  waiting_mail_domains_count => $stats->get_mail_in_moderation,
+	  activated_mail_domains_count => $stats->get_mail_activated,
+	  mail_boxes_count => $stats->get_mail_total_boxes,
+	  mail_forwards_count => $stats->get_mail_total_forwards,
+
+	  waiting_mysql_count => $stats->get_mysql_in_moderation,
+	  activated_mysql_count => $stats->get_mysql_activated,
+
+	  waiting_pgsql_count => $stats->get_pgsql_in_moderation,
+	  activated_pgsql_count => $stats->get_pgsql_activated,
+
+	  waiting_ml_count => $stats->get_lists_in_moderation,
+	  activated_ml_count => $stats->get_lists_activated,
+	  ml_subscribers_count => $stats->get_lists_totalsubs,
+
+	  tag_categories_count => $stats->get_tags_categories_total,
+	  used_tags_count => $stats->get_tags_used_total,
+	  total_tags_count => $stats->get_tags_total,
+	  tagged_groups_count => $stats->get_tags_groups_total,
+	  max_tags_count => $stats->get_tags_groups_max,
+	  top10_tags => $stats->get_most_popular_tags
+	  };
+
+	$panel->render('admin/misc/stats.tt', $vars);
+}
+
+1;

Added: trunk/vhffs-api/src/Vhffs/Panel/Subscribe.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Subscribe.pm	                        (rev 0)
+++ trunk/vhffs-api/src/Vhffs/Panel/Subscribe.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -0,0 +1,173 @@
+#!%PERL%
+# Copyright (c) vhffs project and its contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#2. Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution.
+#3. Neither the name of vhffs nor the names of its contributors
+#   may be used to endorse or promote products derived from this
+#   software without specific prior written permission.
+#
+#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use utf8;
+
+package Vhffs::Panel::Subscribe;
+
+use POSIX qw(locale_h);
+use locale;
+use Locale::gettext;
+use Encode;
+use Captcha::reCAPTCHA;
+
+use Vhffs::Constants;
+use Vhffs::Functions;
+use Vhffs::User;
+
+
+sub subscribe {
+
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+
+	my $submitted = $cgi->param( 'create_submit' );
+	my $message;
+
+	my $usecaptcha = Vhffs::Functions::strtobool( $vhffs->get_config->get_panel->{'use_captcha'} );
+	my $captcha_pubkey = $vhffs->get_config->get_panel->{'captcha_pubkey'};
+	my $captcha_privkey = $vhffs->get_config->get_panel->{'captcha_privkey'};
+
+	unless( $vhffs->get_config->get_allow_subscribe )  {
+		# Subscribe isn't allowed, inform user
+		$panel->render('misc/message.tt', { message => gettext('You cannot subscribe to VHFFS') }, 'anonymous.tt');
+		return;
+	}
+
+	my $vars = {};
+
+	if( defined $submitted ) {
+
+		# get filled in parameters
+		my $mail       = $cgi->param('mail');
+		my $username   = $cgi->param('username');
+		my $firstname  = Encode::decode_utf8( $cgi->param('firstname') );
+		my $lastname   = Encode::decode_utf8( $cgi->param('lastname') );
+		my $city       = Encode::decode_utf8( $cgi->param('city') );
+		my $zipcode    = Encode::decode_utf8( $cgi->param('zipcode') );
+		my $country    = Encode::decode_utf8( $cgi->param('country') );
+		my $address    = Encode::decode_utf8( $cgi->param('address') );
+		my $newslettercheckbox = $cgi->param('newsletter');
+		$newslettercheckbox = ( defined $newslettercheckbox and $newslettercheckbox eq 'on' );
+	
+		if( $usecaptcha ) {
+			my $captcha = new Captcha::reCAPTCHA();
+			my $challenge = $cgi->param('recaptcha_challenge_field');
+			my $response = $cgi->param('recaptcha_response_field');
+			# TODO: use CGI supplied REMOTE_ADDR if any
+			my $result = $captcha->check_answer( $captcha_privkey, $ENV{REMOTE_ADDR}, $challenge, $response);
+			$panel->add_error( gettext('Codes do not match')) unless $result->{is_valid};
+		}
+	
+		$panel->add_error( gettext('You must declare your username') ) unless defined $username;
+		$panel->add_error( gettext('Invalid username, it must contain between 3 and 12 alphanumeric characters, all in lowercase') ) unless Vhffs::User::check_username($username);
+		$panel->add_error( gettext('You must declare your country') ) unless defined $country;
+		$panel->add_error( gettext('You must declare your city') ) unless defined $city;
+		$panel->add_error( gettext('You must declare your zipcode') ) unless defined $zipcode;
+		$panel->add_error( gettext('You must declare your firstname') ) unless defined $firstname;
+		$panel->add_error( gettext('You must declare your lastname') ) unless defined $lastname;
+		$panel->add_error( gettext('You must declare your mail address') ) unless defined $mail and length( $mail ) >= 6;
+		$panel->add_error( gettext('You must declare a valid mail address') ) unless Vhffs::Functions::valid_mail( $mail );
+		$panel->add_error( gettext('Your zipcode is not correct! Please enter a correct zipcode')) unless defined $zipcode and $zipcode =~ /^[\w\d\s\-]+$/;
+		$panel->add_error( gettext('Please enter a correct firstname') ) unless defined $firstname and $firstname =~ /^[^<>"]+$/;
+		$panel->add_error( gettext('Please enter a correct lastname') ) unless defined $lastname and $lastname =~ /^[^<>"]+$/;
+		$panel->add_error( gettext('Please enter a correct city') ) unless defined $city and $city =~ /^[^<>"]+$/;
+		$panel->add_error( gettext('Please enter a correct country') ) unless defined $country and $country !~ /^[<>"]+$/;
+	
+		unless( $panel->has_errors ) {
+			my $user = Vhffs::User::create( $vhffs, $username, Vhffs::Functions::generate_random_password(), 
+			  0, $mail, $firstname, $lastname, $city, $zipcode, $country, $address, '');
+			
+			unless( defined $user )  {
+				$panel->add_error( gettext('Cannot create user, the username you entered already exists') );
+			}
+			else {
+				#We set informations user fill in the form
+				$user->set_status( Vhffs::Constants::WAITING_FOR_CREATION );
+			    
+				#Commit all the changes for the current user
+				if( $user->commit < 0 ) {
+					$panel->add_error( gettext('Cannot apply changes to the user') );
+				}
+				else {
+					Vhffs::Acl::add_acl( $user , $user , Vhffs::Constants::ACL_DELETE , $vhffs );
+					Vhffs::Acl::add_acl( $user->get_group , $user , Vhffs::Constants::ACL_DENIED , $vhffs );
+	
+					# Newsletter
+					if( $vhffs->get_config->get_service_availability('newsletter') ) {
+						require Vhffs::Services::Newsletter;
+						my $newsletter = init Vhffs::Services::Newsletter( $vhffs , $user );
+						if( defined $newsletter and ( 
+						  ( $newsletter->get_collectmode == Vhffs::Services::Newsletter::ACTIVE_OPTIN && $newslettercheckbox )
+						  or ( $newsletter->get_collectmode == Vhffs::Services::Newsletter::PASSIVE_OPTIN && $newslettercheckbox )
+						  or ( $newsletter->get_collectmode == Vhffs::Services::Newsletter::ACTIVE_OPTOUT && !$newslettercheckbox )
+						  or ( $newsletter->get_collectmode == Vhffs::Services::Newsletter::PASSIVE_OPTOUT )
+						  or ( $newsletter->get_collectmode == Vhffs::Services::Newsletter::PERMANENT )
+						) ) {
+							$newsletter->add;
+						}
+					}
+					$panel->render('anonymous/account_created.tt', $vars, 'anonymous.tt');
+					return;
+				}
+			}
+		}
+
+		if ( $panel->has_errors ) {
+			$vars->{username} = $username;
+			$vars->{mail} = $mail;
+			$vars->{firstname} = $firstname;
+			$vars->{lastname} = $lastname;
+			$vars->{zipcode} = $zipcode;
+			$vars->{city} = $city;
+			$vars->{country} = $country;
+			$vars->{address} = $address;
+			$vars->{newsletter_checked} = $newslettercheckbox;
+		}
+	}
+	
+	if( not defined $submitted or $panel->has_errors )  {
+	        $vars->{captcha_pubkey} = $captcha_pubkey if $usecaptcha;
+	
+		if( $vhffs->get_config->get_service_availability('newsletter') ) {
+			my $conf = $vhffs->get_config->get_service('newsletter');
+			$vars->{newsletter} = { prompt => ($conf->{'collectmode'} eq 'active_optout' ? gettext('Don\'t subscribe to the newsletter') : gettext('Subscribe to the newsletter') ) };
+			$vars->{newsletter_checked} = 1 if $conf->{'collectmode'} eq 'passive_optin' and not defined $submitted;
+		}
+	
+		$panel->render('anonymous/subscribe.tt', $vars, 'anonymous.tt');
+	}
+}
+
+1;

Modified: trunk/vhffs-api/src/Vhffs/Panel/Svn.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Svn.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/Svn.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -58,71 +58,291 @@
 
 sub getall_per_group
 {
-    my ( $main, $gid ) = @_;
+	my ( $main, $gid ) = @_;
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT s.object_id AS oid, s.reponame AS displayname, o.state FROM vhffs_svn s INNER JOIN vhffs_object o ON s.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY s.reponame';
-    my $sth = $dbh->prepare($sql) or return -1;
-    $sth->execute($gid) or return -2;
-    my $svn = [];
-    while(my $s = $sth->fetchrow_hashref) {
-        $s->{active} = ($s->{state} == Vhffs::Constants::ACTIVATED);
-        $s->{refused} = ($s->{state} == Vhffs::Constants::VALIDATION_REFUSED);
-        $s->{state} = Vhffs::Functions::status_string_from_status_id($s->{state});
-        push @$svn, $s;
-    }
-    return $svn;
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT s.object_id AS oid, s.reponame AS displayname, o.state FROM vhffs_svn s INNER JOIN vhffs_object o ON s.object_id = o.object_id WHERE o.owner_gid = ? ORDER BY s.reponame';
+	my $sth = $dbh->prepare($sql) or return -1;
+	$sth->execute($gid) or return -2;
+	my $svn = [];
+	while(my $s = $sth->fetchrow_hashref) {
+		$s->{active} = ($s->{state} == Vhffs::Constants::ACTIVATED);
+		$s->{refused} = ($s->{state} == Vhffs::Constants::VALIDATION_REFUSED);
+		$s->{state} = Vhffs::Functions::status_string_from_status_id($s->{state});
+		push @$svn, $s;
+	}
+	return $svn;
 }
 
 sub get_repos_per_group {
-    my ($main, $gid, $public_only) = @_;
-    $public_only = 1 unless(defined $public_only);
+	my ($main, $gid, $public_only) = @_;
+	$public_only = 1 unless(defined $public_only);
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT s.reponame, o.description FROM vhffs_svn s INNER JOIN vhffs_object o ON o.object_id = s.object_id '.
-	'WHERE '.($public_only ? 's.public = 1 AND ' : '').'o.owner_gid = ? AND o.state = ?';
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, $gid, Vhffs::Constants::ACTIVATED);
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT s.reponame, o.description FROM vhffs_svn s INNER JOIN vhffs_object o ON o.object_id = s.object_id '.
+	  'WHERE '.($public_only ? 's.public = 1 AND ' : '').'o.owner_gid = ? AND o.state = ?';
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, $gid, Vhffs::Constants::ACTIVATED);
 }
 
-sub search {
-    my ($main, $name) = @_;
+sub search_svn {
+	my ($main, $name) = @_;
 
-    my @params;
-    my $svns = [];
-    my $sql = 'SELECT s.reponame as label,  g.groupname as owner_group, o.state, u.username as owner_user '.
-        'FROM vhffs_svn s '.
-        'INNER JOIN vhffs_object o ON (o.object_id = s.object_id) '.
-        'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
-        'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
+	my @params;
+	my $svns = [];
+	my $sql = 'SELECT s.reponame as label,  g.groupname as owner_group, o.state, u.username as owner_user '.
+	  'FROM vhffs_svn s '.
+	  'INNER JOIN vhffs_object o ON (o.object_id = s.object_id) '.
+	  'INNER JOIN vhffs_groups g ON (g.gid = o.owner_gid) '.
+	  'INNER JOIN vhffs_users u ON (u.uid = o.owner_uid) ';
 
-    if( defined $name ) {
-        $sql .= 'WHERE s.reponame ILIKE ? ';
-        push(@params, '%'.lc($name).'%');
-    }
+	if( defined $name ) {
+		$sql .= 'WHERE s.reponame ILIKE ? ';
+		push(@params, '%'.lc($name).'%');
+	}
 
-    $sql .= 'ORDER BY label';
+	$sql .= 'ORDER BY label';
 
-    my $dbh = $main->get_db_object();
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
+	my $dbh = $main->get_db_object();
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
 }
 
-
-
 sub create_svn
 {
-    my ($main, $repo, $description, $user, $group) = @_;
-
-    return -1 unless( defined $user );
-    return -2 unless( defined $group );
+	my ($main, $repo, $description, $user, $group) = @_;
+	return -1 unless defined $user;
+	return -2 unless defined $group;
     
-    my $svn = Vhffs::Services::Svn::create( $main, $repo, $description, $user, $group );
+	my $svn = Vhffs::Services::Svn::create( $main, $repo, $description, $user, $group );
+	return -1 unless defined $svn;
     
-    return -1 unless( defined $svn );
+	return -3 if Vhffs::Acl::add_acl( $user , $svn , Vhffs::Constants::ACL_DELETE , $main ) < 0;
+	return -3 if Vhffs::Acl::add_acl( $group , $svn , Vhffs::Constants::ACL_VIEW , $main ) < 0;
     
-    return ( -3 ) if ( Vhffs::Acl::add_acl( $user , $svn , Vhffs::Constants::ACL_DELETE , $main ) < 0 );
-    return ( -3 ) if( Vhffs::Acl::add_acl( $group , $svn , Vhffs::Constants::ACL_VIEW , $main ) < 0 );
-    
-    return $svn;
+	return $svn;
 }
 
+sub create {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group and $user->can_modify( $group ) ) {
+		$panel->render( 'misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) });
+		return;
+	}
+	$panel->set_group( $group );
+
+	my $submitted = $cgi->param('svn_submit');
+	my $vars = {};
+	my $reponame = '';
+	my $description = '';
+
+	if( $submitted ) {
+		$reponame = $cgi->param('reponame');
+		my $fullreponame = $group->get_groupname.'/'.$reponame;
+		$description = Encode::decode_utf8( $cgi->param('description') );
+
+		unless( defined $reponame && defined $description ) {
+			$panel->add_error( gettext('CGI Error !') );
+		} else {
+			$panel->add_error( gettext('Invalid reponame. It must contain between 3 and 64 characters, only lowercase letters and numbers') ) unless Vhffs::Services::Svn::check_name($fullreponame);
+			$panel->add_error( gettext('You must enter a description') ) unless $description !~ /^\s*$/;
+		}
+
+		unless( $panel->has_errors() ) {
+			my $svn = Vhffs::Panel::Svn::create_svn( $vhffs, $fullreponame, $description, $user, $group );
+			if( defined $svn ) {
+				my $url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('The SVN object was successfully created !');
+				$panel->redirect($url);
+				return;
+			}
+			$panel->add_error( gettext('An error occured while creating the svn repository') );
+		}
+		$vars->{reponame} = $reponame;
+		$vars->{description} = $description;
+	}
+
+	# Since redirect exits, we've error or have not been submitted
+	$vars->{group} = $group;
+	$panel->render('svn/create.tt', $vars);
+}
+
+sub prefs {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $repo_name = $cgi->param("name");
+	unless( defined $repo_name ) {
+		$panel->render('misc/message.tt', { message => gettext('CGI Error !') });
+		return;
+	}
+
+	my $svn = Vhffs::Services::Svn::get_by_reponame( $vhffs , $repo_name );
+	unless( defined $svn ) {
+		$panel->render('misc/message.tt', { message => gettext('Cannot get informations on this object') } );
+		return;
+	}
+
+	unless( $user->can_view( $svn ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) } );
+		return;
+	}
+
+	save_prefs($panel, $svn) if defined $cgi->param('save_prefs_submit');
+
+	$panel->set_title( gettext("Modify Subversion repository") );
+	my $vars = {};
+	$vars->{repository} = $svn;
+	$vars->{notify_from} = $vhffs->get_config->get_service('svn')->{notify_from};
+	$vars->{type} = 'svn';
+	$panel->render( 'scm/prefs.tt', $vars );
+}
+
+sub save_prefs {
+	my $panel = shift;
+	my $svn = shift;
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
+
+	my $public = $cgi->param('public');
+	my $ml_name = $cgi->param('ml_name');
+
+	unless( $user->can_modify($svn) ) {
+		$panel->add_error( gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) );
+		return;
+	}
+
+	unless( defined $ml_name and defined $public) {
+		$panel->add_error( gettext('CGI Error !') );
+		return;
+	}
+
+	if($public == 1 and not $svn->is_public) {
+		$svn->set_public;
+		$svn->set_status( Vhffs::Constants::WAITING_FOR_MODIFICATION );
+	} elsif($public == 0 and $svn->is_public) {
+		$svn->set_status( Vhffs::Constants::WAITING_FOR_MODIFICATION );
+		$svn->set_private;
+	}
+
+	if($ml_name =~ /^\s*$/ or Vhffs::Functions::valid_mail($ml_name)) {
+		if($ml_name ne $svn->get_ml_name) {
+			$svn->set_status( Vhffs::Constants::WAITING_FOR_MODIFICATION );
+			$svn->set_ml_name($ml_name);
+		}
+	} else {
+		$panel->add_error( gettext('Mailing list address is invalid') );
+		return;
+	}
+
+	if($svn->get_status == Vhffs::Constants::WAITING_FOR_MODIFICATION) {
+		if($svn->commit > 0) {
+			my $group = Vhffs::Group::get_by_gid( $vhffs , $svn->{'owner_gid'} );
+			my $url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('Modifications applied. Please wait while your repository is being updated');
+			$panel->redirect($url);
+			return;
+		}
+
+		$panel->add_error( gettext('Unable to update repository') );
+		return;
+	}
+}
+
+sub index {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group ) {
+		$panel->render('misc/message.tt', { message => gettext('You have to select a group first') });
+		return;
+	}
+
+	unless($group->get_status == Vhffs::Constants::ACTIVATED) {
+		$panel->render( 'misc/message.tt', { message => gettext('This group is not activated yet') } );
+		return;
+	}
+
+	unless( $user->can_view( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+
+	$panel->set_group( $group );
+	$panel->set_title( sprintf(gettext('SVN repositories for %s'), $group->get_groupname) );
+
+	my $svn = Vhffs::Panel::Svn::getall_per_group( $vhffs, $group->get_gid );
+	if($svn < 0) {
+		$panel->render( 'misc/message.tt', { message => gettext('Unable to get SVN repositories') } );
+		return;
+	}
+
+	$panel->render( 'misc/service-index.tt', {
+	  label => 'SVN repositories',
+	  group => $group,
+	  list => $svn,
+	  help_url => $vhffs->get_config->get_service('svn')->{url_doc},
+	  type => 'svn'
+	  });
+}
+
+sub search {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $name = $cgi->param('name');
+	my $vars = {};
+
+	unless( defined $name ) {
+
+		$panel->render('admin/misc/search.tt', {
+		  search_title => gettext('Subversion search'),
+		  type => 'svn'
+		  });
+		return;
+	}
+
+	if( $name =~ /^\s*$/ ) {
+		$vars->{list_title} = gettext('List of all subversion repositories');
+		undef $name;
+	} else {
+		$vars->{list_title} = sprintf( gettext('Search result for %s'), $name );
+	}
+	$vars->{list} = search_svn( $vhffs , $name );
+	$vars->{type} = 'svn';
+	$panel->render('admin/misc/list.tt', $vars);
+}
+
+sub adminindex {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	$panel->set_title(gettext('Subversion repositories administration'));
+	require Vhffs::Panel::Admin;
+	$panel->render('admin/index.tt', { categories => [ Vhffs::Panel::Admin::get_svn_category() ] } );
+}
+
 1;

Modified: trunk/vhffs-api/src/Vhffs/Panel/User.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/User.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/User.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -34,12 +34,19 @@
 
 package Vhffs::Panel::User;
 
-use DBI;
 use POSIX qw(locale_h);
 use locale;
 use Locale::gettext;
+use Encode;
 
 use Vhffs::Constants;
+use Vhffs::User;
+use Vhffs::Main;
+use Vhffs::Panel::Main;
+use Vhffs::Panel::User;
+use Vhffs::Panel::Object;
+use Vhffs::Services::MailUser;
+use Vhffs::Services::Newsletter;
 
 =pod
 
@@ -84,13 +91,13 @@
 	my ($main) = @_;
 
 	my $sql = 'SELECT u.uid, u.username, u.firstname, u.lastname '.
-		'FROM vhffs_users u '.
-		'INNER JOIN vhffs_object o ON o.object_id=u.object_id '.
-		'WHERE o.state=? ORDER BY o.date_creation DESC LIMIT 10';
+	  'FROM vhffs_users u '.
+	  'INNER JOIN vhffs_object o ON o.object_id=u.object_id '.
+	  'WHERE o.state=? ORDER BY o.date_creation DESC LIMIT 10';
 	
 	my $dbh = $main->get_db_object();
     
-    my $users = $dbh->selectall_hashref($sql, 'uid', undef, Vhffs::Constants::ACTIVATED);
+	my $users = $dbh->selectall_hashref($sql, 'uid', undef, Vhffs::Constants::ACTIVATED);
 	
 	fill_groups($main, $users);
 	
@@ -99,23 +106,23 @@
 	return \@val;	
 }
 
-sub search {
+sub search_user {
 	my ($main, $name) = @_;
 
-    my @params;
-    my $sql = 'SELECT u.uid, u.username, u.firstname || \' \' || u.lastname as realname, o.state '.
-        'FROM vhffs_users u '.
-        'INNER JOIN vhffs_object o ON (o.object_id = u.object_id) ';
+	my @params;
+	my $sql = 'SELECT u.uid, u.username, u.firstname || \' \' || u.lastname as realname, o.state '.
+	  'FROM vhffs_users u '.
+	  'INNER JOIN vhffs_object o ON (o.object_id = u.object_id) ';
 
-    if( defined $name ) {
-        $sql .= 'WHERE u.username LIKE ? OR u.firstname ILIKE ? OR u.lastname ILIKE ? ';
-        push(@params, '%'.lc($name).'%', '%'.$name.'%', '%'.$name.'%');
+	if( defined $name ) {
+		$sql .= 'WHERE u.username LIKE ? OR u.firstname ILIKE ? OR u.lastname ILIKE ? ';
+		push(@params, '%'.lc($name).'%', '%'.$name.'%', '%'.$name.'%');
 	}
 
-    $sql .= 'ORDER BY u.username';
+	$sql .= 'ORDER BY u.username';
 
 	my $dbh = $main->get_db_object();
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
 }
 
 =head2 public_search
@@ -127,29 +134,29 @@
 =cut
 
 sub public_search {
-    my ($main, $username, $start) = @_;
-    my $result = {};
+	my ($main, $username, $start) = @_;
+	my $result = {};
 
-    my $select_clause = 'SELECT u.uid, u.username, u.firstname, u.lastname ';
-    my $sql = 
-    	'FROM vhffs_users u '.
-    	'INNER JOIN vhffs_object o ON o.object_id = u.object_id '.
-    	'WHERE o.state = ? ';
-    my @params;
-    push @params, Vhffs::Constants::ACTIVATED;
+	my $select_clause = 'SELECT u.uid, u.username, u.firstname, u.lastname ';
+	my $sql = 
+	  'FROM vhffs_users u '.
+	  'INNER JOIN vhffs_object o ON o.object_id = u.object_id '.
+	  'WHERE o.state = ? ';
+	my @params;
+	push @params, Vhffs::Constants::ACTIVATED;
 
-    if(defined $username) {
-        # usernames are enforced in lowercase
-        $sql .= ' AND username ILIKE ?';
-        push @params, '%'.$username.'%';
-    }
+	if(defined $username) {
+		# usernames are enforced in lowercase
+		$sql .= ' AND username ILIKE ?';
+		push @params, '%'.$username.'%';
+	}
 
-    my $limit = ' LIMIT 10';
-    $limit .= ' OFFSET '.($start * 10) if(defined $start); 
+	my $limit = ' LIMIT 10';
+	$limit .= ' OFFSET '.($start * 10) if(defined $start); 
     
-    my $dbh = $main->get_db_object();
+	my $dbh = $main->get_db_object();
     
-    my $users = $dbh->selectall_hashref($select_clause.$sql.' ORDER BY u.username '.$limit, 'uid', undef, @params);
+	my $users = $dbh->selectall_hashref($select_clause.$sql.' ORDER BY u.username '.$limit, 'uid', undef, @params);
 	
 	my ($count) = $dbh->selectrow_array('SELECT COUNT(*) '.$sql, undef, @params);
 	
@@ -186,39 +193,36 @@
 	
 	# Fetch all groups in one shot
 	my $sql = 'SELECT g.groupname, u.uid FROM vhffs_groups g '.
-		'INNER JOIN vhffs_user_group ug ON ug.gid = g.gid '.
-		'INNER JOIN vhffs_users u ON u.uid = ug.uid '.
-		'WHERE g.groupname != u.username AND u.uid IN ( '.join(', ', @uids).') '.
-		'ORDER BY g.groupname';
+	  'INNER JOIN vhffs_user_group ug ON ug.gid = g.gid '.
+	  'INNER JOIN vhffs_users u ON u.uid = ug.uid '.
+	  'WHERE g.groupname != u.username AND u.uid IN ( '.join(', ', @uids).') '.
+	  'ORDER BY g.groupname';
 	
 	my $groups = $dbh->selectall_arrayref($sql, { Slice => {}});
 	my $i = 0;
 	
 	foreach my $g(@$groups) {
-		if(!exists $users->{$g->{uid}}{groups}) {
-			$users->{$g->{uid}}{groups} = [];
-		}
+		$users->{$g->{uid}}{groups} = [] unless exists $users->{$g->{uid}}{groups};
 		push(@{$users->{$g->{uid}}{groups}}, $g->{groupname});
 	}
 }
 
 sub fetch_users_and_groups {
-    my ($main, $sql, @params) = @_;
-    my @users;
+	my ($main, $sql, @params) = @_;
+	my @users;
 
-    my $dbh = $main->get_db_object;
-    my $sth = $dbh->prepare($sql);
-    $sth->execute( @params );
-    $sql = 'SELECT g.groupname FROM vhffs_groups g INNER JOIN vhffs_user_group ug ON ug.gid = g.gid WHERE ug.uid = ? AND g.groupname != ?';
-    my $ssth = $dbh->prepare($sql);
-    while(my $row = $sth->fetchrow_hashref) {
-       $ssth->execute($row->{uid}, $row->{username});
-       $row->{groups} = $ssth->fetchall_arrayref({});
-       push @users, $row;
-    }
+	my $dbh = $main->get_db_object;
+	my $sth = $dbh->prepare($sql);
+	$sth->execute( @params );
+	$sql = 'SELECT g.groupname FROM vhffs_groups g INNER JOIN vhffs_user_group ug ON ug.gid = g.gid WHERE ug.uid = ? AND g.groupname != ?';
+	my $ssth = $dbh->prepare($sql);
+	while(my $row = $sth->fetchrow_hashref) {
+		$ssth->execute($row->{uid}, $row->{username});
+		$row->{groups} = $ssth->fetchall_arrayref({});
+		push @users, $row;
+	}
 
-    return \@users;
-
+	return \@users;
 }
 
 sub set_lang
@@ -306,33 +310,444 @@
 =cut
 
 sub get_groups {
-    my $user = shift;
-    my $relation = shift;
-    my @params;
+	my $user = shift;
+	my $relation = shift;
+	my @params;
     
+	my $groups = [];
+	my $sql;
+	push @params, $user->get_uid;
+	if( defined $relation) {
+		if( $relation == $RELATION_OWNER ) {
+			$sql = 'SELECT g.groupname, o.state , o.object_id AS oid FROM vhffs_groups g INNER JOIN vhffs_object o ON o.object_id = g.object_id WHERE o.owner_uid = ? AND g.groupname != ? ORDER BY g.groupname';
+			push @params, $user->get_username;
+		} else {
+			$sql = 'SELECT g.groupname, o.state , o.object_id AS oid FROM vhffs_groups g INNER JOIN vhffs_user_group ug ON g.gid=ug.gid INNER JOIN vhffs_object o ON o.object_id = g.object_id WHERE ug.uid=? AND o.owner_uid != ug.uid ORDER BY g.groupname';
+		}
+	} else {
+		$sql = 'SELECT g.groupname, o.state , o.object_id AS oid FROM vhffs_groups g INNER JOIN vhffs_user_group ug ON g.gid=ug.gid INNER JOIN vhffs_object o ON o.object_id = g.object_id WHERE ug.uid=? ORDER BY g.groupname';
+	}
+	my $sth = $user->get_db_object->prepare( $sql );
+	return undef unless $sth->execute(@params);
+	while(my $g = $sth->fetchrow_hashref) {
+		$g->{active} = ($g->{state} == Vhffs::Constants::ACTIVATED);
+		$g->{refused} = ($g->{state} == Vhffs::Constants::VALIDATION_REFUSED);
+		$g->{state} = Vhffs::Functions::status_string_from_status_id($g->{state});
+		push @$groups, $g;
+	}
+	return $groups;
+}
 
-    my $groups = [];
-    my $sql;
-    push @params, $user->get_uid;
-    if( defined $relation) {
-        if( $relation == $RELATION_OWNER ) {
-            $sql = 'SELECT g.groupname, o.state , o.object_id AS oid FROM vhffs_groups g INNER JOIN vhffs_object o ON o.object_id = g.object_id WHERE o.owner_uid = ? AND g.groupname != ? ORDER BY g.groupname';
-            push @params, $user->get_username;
-        } else {
-            $sql = 'SELECT g.groupname, o.state , o.object_id AS oid FROM vhffs_groups g INNER JOIN vhffs_user_group ug ON g.gid=ug.gid INNER JOIN vhffs_object o ON o.object_id = g.object_id WHERE ug.uid=? AND o.owner_uid != ug.uid ORDER BY g.groupname';
-        }
-    } else {
-        $sql = 'SELECT g.groupname, o.state , o.object_id AS oid FROM vhffs_groups g INNER JOIN vhffs_user_group ug ON g.gid=ug.gid INNER JOIN vhffs_object o ON o.object_id = g.object_id WHERE ug.uid=? ORDER BY g.groupname';
-    }
-    my $sth = $user->get_db_object->prepare( $sql );
-    return undef if( ! $sth->execute(@params) );
-    while(my $g = $sth->fetchrow_hashref) {
-        $g->{active} = ($g->{state} == Vhffs::Constants::ACTIVATED);
-        $g->{refused} = ($g->{state} == Vhffs::Constants::VALIDATION_REFUSED);
-        $g->{state} = Vhffs::Functions::status_string_from_status_id($g->{state});
-        push @$groups, $g;
-    }
-    return $groups;
+
+sub prefs {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $userp;
+	my $vars = {};
+
+	my $username = $cgi->param('name');
+	if( defined $username ) {
+		$userp = Vhffs::User::get_by_username( $vhffs, $username );
+	} else {
+		$userp = $user;
+	}
+
+	unless( defined $userp )  {
+		$panel->render( 'misc/message.tt', { message => gettext('Cannot get informations on this object')} );
+		return;
+	}
+
+	unless( $user->can_view( $userp ) ) {
+		$panel->render( 'misc/message.tt', { message => gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) } );
+		return;
+	}
+
+	if( defined $cgi->param('prefs_submit') ) {
+		unless( $user->can_modify( $userp ) ) {
+			$panel->add_error( gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' ) );
+		} else {
+			my $mail = $cgi->param( 'mail' );
+			my $firstname = Encode::decode_utf8( $cgi->param( 'firstname' ) );
+			my $lastname = Encode::decode_utf8( $cgi->param( 'lastname' ) );
+			my $city = Encode::decode_utf8( $cgi->param( 'city' ) );
+			my $zipcode = Encode::decode_utf8( $cgi->param( 'zipcode' ) );
+			my $country = Encode::decode_utf8( $cgi->param( 'country' ) );
+			my $address = Encode::decode_utf8( $cgi->param( 'address' ) );
+			my $pass1 = $cgi->param( 'password1' );
+			my $pass2 = $cgi->param( 'password2' );
+			my $theme = $cgi->param( 'theme' );
+			my $lang = $cgi->param( 'lang' );
+			my $shell = $cgi->param( 'shell' );
+			my $newslettercheckbox = $cgi->param('newsletter');
+			$newslettercheckbox = ( defined $newslettercheckbox && $newslettercheckbox eq 'on' );
+
+			my $pwd_change = 0;
+			my $mail_change = 0;
+
+			if( $userp->{'uid'} == $user->{'uid'} )  {
+				# Checks data and perform requested modifications
+				$panel->add_cookie( $cgi->cookie( -name=>'theme', -value=>$theme, -expires=>'+10y' ) );
+				Vhffs::Panel::User::set_theme( $userp, $theme );
+
+				$panel->add_cookie( $cgi->cookie( -name=>'language', -value=>$lang, -expires=>'+10y' ) );
+				Vhffs::Panel::User::set_lang( $userp, $lang );
+			}
+
+			# Commit all the changes for the current user
+			unless( defined $firstname && defined $lastname && defined $city && defined $mail && defined $zipcode && defined $country && defined $address && defined $shell )  {
+				$panel->add_error( gettext( 'CGI Error !' ) );
+			}
+			else {
+				# We don't really care about what user use as firstname, lastname, ... we just
+				# want it not to break everything
+
+				$panel->add_error( gettext( 'Firstname is not correct !') ) unless defined $firstname and $firstname =~ /^[^<">]+$/;
+				$panel->add_error( gettext( 'Lastname is not correct !') ) unless defined $lastname and $lastname =~ /^[^<">]+$/;
+				$panel->add_error( gettext( 'City is not correct !') ) unless defined $city and $city =~ /^[^<">]+$/;
+				$panel->add_error( gettext( 'Email is not correct !') ) unless Vhffs::Functions::valid_mail($mail);
+				$panel->add_error( gettext( "Zipcode is not correct !" ) ) unless defined $zipcode and $zipcode =~ /^[\w\d\s\-]+$/;
+				$panel->add_error( gettext( 'Country is not correct !') ) unless defined $country and $country =~ /^[^<">]+$/;
+				$panel->add_error( gettext( 'Address is not correct !') ) unless defined $address and $address =~ /^[^<">]+$/;
+				$panel->add_error( gettext( "Passwords don't match" ) ) unless defined $pass1 and defined $pass2 and $pass1 eq $pass2;
+
+				if( $userp->have_activegroups > 0 ) {
+					my $valid=0;
+					foreach( Vhffs::Panel::User::list_shells( $vhffs ) ) {
+						$valid = 1 if $shell eq $_;
+					}
+					$panel->add_error( gettext( 'Wanted shell is not in the shell list' ) ) unless $valid;
+				}
+				else {
+					$shell = Vhffs::Panel::User::default_shell( $ vhffs );
+				}
+
+				unless( $panel->has_errors) {
+					$userp->set_firstname( $firstname );
+					$userp->set_lastname( $lastname );
+					$userp->set_city( $city );
+					$userp->set_zipcode( $zipcode );
+					$userp->set_country( $country );
+					$userp->set_address( $address );
+					$userp->set_shell( $shell );
+
+					if( length( $pass1 ) > 1 and $pass1 eq $pass2 ) { 
+						$pwd_change = 1;
+						$userp->set_password( $pass1 );
+						$panel->add_info( gettext('Password changed') );
+
+						my $mu = init Vhffs::Services::MailUser( $vhffs , $userp );
+						$mu->changepassword( $pass1 ) if defined $mu and $mu->exists_box;
+					}
+
+					my $prevmail = $userp->get_mail();
+					if( $prevmail ne $mail ) {
+						$mail_change = 1;
+
+						my $newsletter = init Vhffs::Services::Newsletter( $vhffs , $userp );
+						$newsletter->del if defined $newsletter;
+
+						$userp->set_mail( $mail );
+						my $subject = gettext('Mailbox modified');
+						my $content = sprintf( gettext("Hello %s %s,\n\nYou changed your email, here are your new personal information :\n\nUser: %s\nMail: %s\n\nVHFFS administrators\n"), $userp->get_firstname, $userp->get_lastname, $userp->get_username, $userp->get_mail);
+						$userp->send_mail_user( $subject, $content );
+						$panel->add_info( gettext('Email address changed') );
+					}
+
+					if( $userp->commit < 0 ) {
+						$panel->clear_infos();
+						$panel->add_error( gettext('An error occured while updating the user account') );
+					}
+
+					# -- Mail User
+					my $mu = init Vhffs::Services::MailUser( $vhffs , $userp );
+					if( defined $mu )  {
+					
+						my $mail_activate = $cgi->param( 'mail_activate' );
+						my $nospam = $cgi->param( 'mail_nospam' );
+						my $novirus = $cgi->param( 'mail_novirus' );
+						$nospam = ( defined $nospam and $nospam eq 'on' );
+						$novirus = ( defined $novirus and $novirus eq 'on' );
+    
+						if( defined $mail_activate and $mail_activate eq 'on' ) {
+							my $usage = $cgi->param( 'mail_usage' );
+							unless( defined $usage ) {
+								$panel->add_error( gettext('You must choose a method for your mail') );
+							}
+							elsif( $usage == 1 ) {
+								#Delete forward if necessary
+								#In this case, we treat for popable accounts
+								if( $mu->exists_box == 0 ) {
+									# Box doesn't exists, need a password
+									if( $pwd_change == 0 ) {
+										$panel->add_error( gettext('Error ! You MUST provide a password in your account when you create your popable account') );
+									} else  {
+										# Del forward if needed
+										$mu->delforward;
+										if( $mu->addbox($pass1) < 0 ) {
+											$panel->add_error( gettext('An error occured while adding the box') );
+										} elsif( $nospam and $mu->change_spam_status < 0 ) {
+											$panel->add_error( gettext('An error occured while adding the box (anti-spam adding)') );
+										} elsif( $novirus and $mu->change_virus_status < 0 ) {
+											$panel->add_error( gettext('An error occured while adding the box (anti-virus adding)') );
+										} else {
+											$panel->add_info( gettext('Mailbox successfully added') );
+										}
+									}
+								} else {
+									#Box already exists
+									# The user changed his password, we must update password for mail
+									if( $pwd_change ) {
+										$mu->changepassword( $pass1);
+									}
+
+									# We change the spam status. if the spam status changed
+									if( $vhffs->get_config->get_service('mail')->{'use_nospam'} eq 'yes' ) {
+										if( $nospam != $mu->use_nospam ) {
+											if( $mu->change_spam_status == 1 ) {
+												$panel->add_info( gettext( 'Changed spam protection status for your account' ) );
+											} else {
+												$panel->add_error( gettext( 'Error for spam protection' ) );
+											}
+										}
+									}
+
+									# As spam, the virus status changes only if the user changed values
+									if( $vhffs->get_config->get_service('mail')->{'use_novirus'} eq 'yes' ) {
+										if( $novirus != $mu->use_novirus ) {
+											if( $mu->change_virus_status == 1 ) {
+												$panel->add_info( gettext( 'Changed anti-virus status for your account' ) );
+											} else {
+												$panel->add_error( gettext( 'Error for virus protection' ) );
+											}
+										}
+									}
+								}
+							}
+							elsif( $usage == 2 ) {
+								#Here, we create the forward
+								my $ad = $userp->get_mail;
+								unless( $mu->exists_forward ) {
+									unless( defined $ad ) {
+										$panel->add_error( gettext('There is a problem with the address you filled in your profile, unable to add forwarding') );
+									} else {
+										# Delete the box if necessary
+										$mu->delbox;
+										if( $mu->addforward( $userp->get_mail ) < 0) {
+											$panel->add_error(  gettext('An error occured while adding the forwarding') );
+										} else {
+											$panel->add_info( gettext('Forward added') );
+										}
+									}
+								}
+								elsif( $mail_change ) {
+									$mu->delforward;
+									if( $mu->addforward( $mail ) < 0 ) {
+										$panel->add_error( gettext('An error occured while the forwarding') );
+									} else {
+										$panel->add_info( gettext('Forward updated') );
+									}
+								}
+							}	
+						} elsif($mu->exists_box || $mu->exists_forward) {
+							$panel->add_info( gettext('Mail deleted') );
+							# User doesn't want mail anymore
+							$mu->delbox;
+							$mu->delforward;
+						}
+					}
+
+					# -- Newsletter
+					my $newsletter = init Vhffs::Services::Newsletter( $vhffs , $userp );
+					if( defined $newsletter )  {
+						if( $newslettercheckbox and not $newsletter->exists ) {
+							$newsletter->add;
+						} elsif( not $newslettercheckbox and $newsletter->exists and $newsletter->get_collectmode != Vhffs::Services::Newsletter::PERMANENT ) {
+							$newsletter->del;
+						}
+					}
+
+				}
+			}
+		}
+	}
+
+	elsif( defined $cgi->param('delete_submit') ) {
+
+		my $delete = $cgi->param('delete');
+		my $message;
+
+		# We make sure the current user is allowed to delete the specified user
+		unless( $user->can_delete( $userp ) ) {
+			$message = gettext('You\'re not allowed to delete this user');
+		} else {
+			if( $delete == 1 ) {
+				if( $userp->have_activegroups ) {
+					$message = gettext('This user is still in a group');
+				} else {
+					$userp->set_status( Vhffs::Constants::TO_DELETE );
+					if( $userp->commit < 0 ) {
+						$message = gettext('An error occured while applying changes. This user will NOT be deleted');
+					} else {
+						$message = gettext('This user will BE DELETED');
+					}
+				}
+			} else {
+				$message = gettext('This user will NOT be DELETED');
+			}
+		}
+
+		$panel->render('misc/message.tt', { message => $message, refresh_url => '/panel.pl' });
+		return;
+	}
+
+	elsif( defined $cgi->param('update_ircnick_submit') ) {
+		update_ircnick( $panel, $userp );
+	}
+
+	elsif( defined $cgi->param('update_permissions_submit') ) {
+		update_permissions( $panel, $userp );
+	}
+
+	$panel->set_title( gettext('User Preferences') );
+	$vars->{user} = $userp;
+	$vars->{current_language} = Vhffs::Panel::User::get_lang( $userp );
+	my @themes = Vhffs::Panel::Main::list_themes( $vhffs );
+	$vars->{themes} = \@themes;
+	$vars->{current_theme} = Vhffs::Panel::User::get_theme( $userp );
+	$vars->{user_help_url} = $vhffs->get_config->get_users()->{url_doc};
+
+	if( $userp->have_activegroups )  {
+	        my @shells = Vhffs::Panel::User::list_shells( $vhffs );
+	        $vars->{shells} = \@shells;
+        	$vars->{current_shell} = Vhffs::Panel::User::get_shell( $userp );
+	} else {
+	        $vars->{shells} = [ Vhffs::Panel::User::default_shell( $vhffs ) ];
+	}
+
+	my $newsletter = init Vhffs::Services::Newsletter( $vhffs , $userp );
+	$vars->{newsletter} = { active => 1, subscribed => $newsletter->exists } if defined $newsletter and $newsletter->get_collectmode != Vhffs::Services::Newsletter::PERMANENT;
+
+	my $mu = init Vhffs::Services::MailUser( $vhffs , $userp );
+	if(defined $mu) {
+		my $mu_config = $vhffs->get_config->get_service( 'mailuser' );
+		my $mail_config = $vhffs->get_config->get_service('mail');
+		$vars->{mail_user} = {
+		  service => $mu,
+		  domain => $mu_config->{domain},
+		  help_url => $mu_config->{url_doc},
+		  nospam => $mail_config->{use_nospam} eq 'yes',
+		  novirus => $mail_config->{use_novirus} eq 'yes'
+		};
+	}
+
+	$vars->{use_avatars} = $panel->use_users_avatars;
+
+	$panel->render('user/prefs.tt', $vars);
 }
 
+sub update_ircnick {
+	my $panel = shift;
+	my $userp = shift;
+	my $user = $panel->{user};
+	my $cgi = $panel->{cgi};
+
+	unless( $user->is_admin ) {
+		$panel->add_error( gettext('Only administrators can do this') );
+		return;
+	}
+
+	my $ircnick = $cgi->param('ircnick');
+	unless(defined $ircnick) {
+		$panel->add_error( gettext('CGI Error !') );
+		return;
+	}
+
+	if( $ircnick !~ /^[^<">\s]*$/ ) {
+		$panel->add_error( gettext( 'IRC nick is not correct !') );
+		return;
+	}
+
+	$userp->set_ircnick($ircnick);
+	if($userp->commit < 0) {
+		$panel->add_error( gettext('Unable to update user, please try again later') );
+	} else {
+		$panel->add_info( gettext('User successfully updated') );
+	}
+}
+
+sub update_permissions {
+	my $panel = shift;
+	my $userp = shift;
+	my $user = $panel->{user};
+	my $cgi = $panel->{cgi};
+
+	unless( $user->is_admin ) {
+		$panel->add_error( gettext('Only administrators can do this') );
+		return;
+	}
+
+	my $permissions = $cgi->param('permissions');
+	unless(defined $permissions) {
+		$panel->add_error( gettext('CGI Error !') );
+		return;
+	}
+
+	$userp->set_admin($permissions);
+	if($userp->commit < 0) {
+		$panel->add_error( gettext('Unable to update user, please try again later') );
+	} else {
+		$panel->add_info( gettext('User successfully updated') );
+	}
+}
+
+sub search {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $name = $cgi->param('name');
+	my $vars = {};
+
+	unless( defined $name ) {
+
+		$panel->render('admin/misc/search.tt', {
+		  search_title => gettext('Users search'),
+		  type => 'user'
+		  });
+		return;
+	}
+
+	if( $name =~ /^\s*$/ ) {
+		$vars->{list_title} = gettext('List of all users');
+		undef $name;
+	} else {
+		$vars->{list_title} = sprintf( gettext('Search result for %s'), $name );
+	}
+	$vars->{users} = search_user( $vhffs , $name );
+	$panel->render('admin/user/list.tt', $vars);
+}
+
+sub adminindex {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	$panel->set_title(gettext('Users\' administration'));
+	require Vhffs::Panel::Admin;
+	$panel->render('admin/index.tt', { categories => [ Vhffs::Panel::Admin::get_user_category() ] } );
+}
+
 1;

Modified: trunk/vhffs-api/src/Vhffs/Panel/Web.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Panel/Web.pm	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-api/src/Vhffs/Panel/Web.pm	2012-01-19 23:57:57 UTC (rev 1918)
@@ -61,20 +61,20 @@
 =cut
 
 sub getall_per_group {
-    my ($main, $gid) = @_;
+	my ($main, $gid) = @_;
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT w.servername AS displayname, w.object_id AS oid, o.state FROM vhffs_httpd w INNER JOIN vhffs_object o ON o.object_id = w.object_id WHERE o.owner_gid = ? ORDER BY w.servername';
-    my $sth = $dbh->prepare($sql) or return -1;
-    $sth->execute($gid) or return -2;
-    my $web = [];
-    while(my $w = $sth->fetchrow_hashref) {
-        $w->{active} = ($w->{state} == Vhffs::Constants::ACTIVATED);
-        $w->{refused} = ($w->{state} == Vhffs::Constants::VALIDATION_REFUSED);
-        $w->{state} = Vhffs::Functions::status_string_from_status_id($w->{state});
-        push @$web, $w;
-    }
-    return $web;
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT w.servername AS displayname, w.object_id AS oid, o.state FROM vhffs_httpd w INNER JOIN vhffs_object o ON o.object_id = w.object_id WHERE o.owner_gid = ? ORDER BY w.servername';
+	my $sth = $dbh->prepare($sql) or return -1;
+	$sth->execute($gid) or return -2;
+	my $web = [];
+	while(my $w = $sth->fetchrow_hashref) {
+		$w->{active} = ($w->{state} == Vhffs::Constants::ACTIVATED);
+		$w->{refused} = ($w->{state} == Vhffs::Constants::VALIDATION_REFUSED);
+		$w->{state} = Vhffs::Functions::status_string_from_status_id($w->{state});
+		push @$web, $w;
+	}
+	return $web;
 }
 
 =head2 get_websites_per_group
@@ -85,53 +85,53 @@
 =cut
 
 sub get_websites_per_group {
-    my ($main, $gid) = @_;
+	my ($main, $gid) = @_;
 
-    my $dbh = $main->get_db_object;
-    my $sql = 'SELECT w.servername, o.description FROM vhffs_httpd w INNER JOIN vhffs_object o ON o.object_id = w.object_id WHERE o.owner_gid = ? AND o.state = ?';
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, $gid, Vhffs::Constants::ACTIVATED);
+	my $dbh = $main->get_db_object;
+	my $sql = 'SELECT w.servername, o.description FROM vhffs_httpd w INNER JOIN vhffs_object o ON o.object_id = w.object_id WHERE o.owner_gid = ? AND o.state = ?';
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, $gid, Vhffs::Constants::ACTIVATED);
 }
 
-sub search {
-    my ($main, $name) = @_;
+sub search_web {
+	my ($main, $name) = @_;
 
-    my @params;
-    my $webs = [];
-    my $sql = 'SELECT w.servername as label, o.state, g.groupname as owner_group, u.username as owner_user '.  
-            'FROM vhffs_httpd w '.
-            'INNER JOIN vhffs_object o ON o.object_id = w.object_id '.
-            'INNER JOIN vhffs_groups g ON g.gid = o.owner_gid '.
-            'INNER JOIN vhffs_users u ON u.uid = o.owner_uid ';
+	my @params;
+	my $webs = [];
+	my $sql = 'SELECT w.servername as label, o.state, g.groupname as owner_group, u.username as owner_user '.  
+	  'FROM vhffs_httpd w '.
+	  'INNER JOIN vhffs_object o ON o.object_id = w.object_id '.
+	  'INNER JOIN vhffs_groups g ON g.gid = o.owner_gid '.
+	  'INNER JOIN vhffs_users u ON u.uid = o.owner_uid ';
 
-    if( defined $name ) {
-        $sql .= 'WHERE w.servername ILIKE ? ';
-        push(@params, '%'.lc($name).'%');
-    }
+	if( defined $name ) {
+		$sql .= 'WHERE w.servername ILIKE ? ';
+		push(@params, '%'.lc($name).'%');
+	}
 
-    $sql .= 'ORDER BY label';
+	$sql .= 'ORDER BY label';
 
-    my $dbh = $main->get_db_object();
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
+	my $dbh = $main->get_db_object();
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, @params);
 }
 
 sub public_search {
-    my ($main, $servername, $description, $start, $count) = @_;
+	my ($main, $servername, $description, $start, $count) = @_;
 
-    my $select = 'SELECT w.servername, g.groupname, o.description';
-    my $from = ' FROM vhffs_httpd w INNER JOIN vhffs_object o ON o.object_id = w.object_id INNER JOIN vhffs_groups g ON g.gid = o.owner_gid WHERE o.state = ?';
-    my @params;
-    push @params, Vhffs::Constants::ACTIVATED;
-    if(defined $servername) {
-        $from .= ' AND w.servername LIKE ?';
-        push @params, '%'.lc($servername).'%';
-    }
+	my $select = 'SELECT w.servername, g.groupname, o.description';
+	my $from = ' FROM vhffs_httpd w INNER JOIN vhffs_object o ON o.object_id = w.object_id INNER JOIN vhffs_groups g ON g.gid = o.owner_gid WHERE o.state = ?';
+	my @params;
+	push @params, Vhffs::Constants::ACTIVATED;
+	if(defined $servername) {
+		$from .= ' AND w.servername LIKE ?';
+		push @params, '%'.lc($servername).'%';
+	}
 
-    if(defined $description) {
-        $from .= ' AND o.description ILIKE ?';
-        push @params, '%'.$description.'%';
-    }
+	if(defined $description) {
+		$from .= ' AND o.description ILIKE ?';
+		push @params, '%'.$description.'%';
+	}
 
-   return Vhffs::Panel::Commons::fetch_slice_and_count($main, $select, $from, ' ORDER BY w.servername', $start, $count, \@params);
+	return Vhffs::Panel::Commons::fetch_slice_and_count($main, $select, $from, ' ORDER BY w.servername', $start, $count, \@params);
 }
 
 
@@ -151,18 +151,18 @@
 }
 
 sub get_websites_starting_with {
-    my ($vhffs, $letter, $start, $count) = @_;
+	my ($vhffs, $letter, $start, $count) = @_;
 
-    my @params;
-    my $select = 'SELECT w.servername, g.groupname, o.description';
-    my $from = ' FROM vhffs_httpd w INNER JOIN vhffs_object o ON o.object_id = w.object_id INNER JOIN vhffs_groups g ON g.gid = o.owner_gid WHERE o.state = ?';
-    push @params, Vhffs::Constants::ACTIVATED;
-    if(defined $letter) {
-        $from .= ' AND substr(w.servername, 1, 1) = ?';
-        push @params, $letter;
-    }
-    my $dbh = $vhffs->get_db_object;
-    return Vhffs::Panel::Commons::fetch_slice_and_count($vhffs, $select, $from, ' ORDER BY w.servername', $start, $count, \@params);
+	my @params;
+	my $select = 'SELECT w.servername, g.groupname, o.description';
+	my $from = ' FROM vhffs_httpd w INNER JOIN vhffs_object o ON o.object_id = w.object_id INNER JOIN vhffs_groups g ON g.gid = o.owner_gid WHERE o.state = ?';
+	push @params, Vhffs::Constants::ACTIVATED;
+	if(defined $letter) {
+		$from .= ' AND substr(w.servername, 1, 1) = ?';
+		push @params, $letter;
+	}
+	my $dbh = $vhffs->get_db_object;
+	return Vhffs::Panel::Commons::fetch_slice_and_count($vhffs, $select, $from, ' ORDER BY w.servername', $start, $count, \@params);
 }
 
 =head2 get_used_letters
@@ -174,12 +174,214 @@
 =cut
 
 sub get_used_letters {
-    my $main = shift;
-    my $sql = 'SELECT substr(servername, 1, 1) as letter, COUNT(*) as count FROM vhffs_httpd h INNER JOIN vhffs_object o ON o.object_id = h.object_id WHERE state = ? GROUP BY substr(servername, 1, 1) ORDER BY substr(servername, 1, 1)';
-    my $dbh = $main->get_db_object;
-    return $dbh->selectall_arrayref($sql, { Slice => {} }, Vhffs::Constants::ACTIVATED);
+	my $main = shift;
+	my $sql = 'SELECT substr(servername, 1, 1) as letter, COUNT(*) as count FROM vhffs_httpd h INNER JOIN vhffs_object o ON o.object_id = h.object_id WHERE state = ? GROUP BY substr(servername, 1, 1) ORDER BY substr(servername, 1, 1)';
+	my $dbh = $main->get_db_object;
+	return $dbh->selectall_arrayref($sql, { Slice => {} }, Vhffs::Constants::ACTIVATED);
+}
 
+sub create {
+	my $panel = shift;
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined $group and $user->can_modify( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+	$panel->set_group( $group );
+
+	my $submitted = defined($cgi->param('web_submit'));
+	my $vars = {};
+	my $servername = '';
+	my $description = '';
+
+	if( $submitted ) {
+		$servername = $cgi->param('servername');
+		$description = Encode::decode_utf8( $cgi->param('description') );
+		unless( defined $servername and defined $description ) {
+			$panel->add_error( gettext('CGI Error !') );
+		} else { 
+			$panel->add_error( gettext('Invalid servername (doesn\'t conform to domain names rules)') ) unless Vhffs::Functions::check_domain_name($servername);
+			$panel->add_error( gettext('You must enter a description') ) unless defined $description and $description !~ /^\s*$/;
+		}
+
+		unless( $panel->has_errors() ) {
+			if( defined Vhffs::Panel::Web::create_web( $vhffs, $servername, $description, $user, $group) ) {
+				my $url = '?do=groupview&group='.$group->get_groupname.'&msg='.gettext('The webarea was successfully created !');
+				$panel->redirect($url);
+				return;
+			} else {
+				$panel->add_error( gettext('Error creating webarea.') );
+			}
+		}		
+		$vars->{servername} = $servername;
+		$vars->{description} = $description;
+	} else {
+		my $webconfig = $vhffs->get_config->get_service('web');
+		$vars->{servername} = sprintf( gettext('<new site>.%s'), $webconfig->{default_domain} ) if( defined $webconfig->{default_domain} );
+	}
+
+	$panel->set_title( gettext('Create a web space') );
+	$vars->{group} = $group;
+	$panel->render('web/create.tt', $vars);
 }
 
+sub prefs {
+	my $panel = shift;
 
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $servername = $cgi->param("name");
+	my $web = Vhffs::Services::Web::get_by_servername( $vhffs , $servername );
+
+	unless( defined($web) ) {
+		$panel->render('misc/message.tt', { message => gettext('Cannot get informations on this object') } );;
+		return;
+	}
+
+	unless( $web->get_status == Vhffs::Constants::ACTIVATED ) {
+		$panel->render('misc/message.tt', { message => gettext('This object is not functionnal yet. Please wait creation or moderation.') } );
+		return;
+	}
+
+	unless( $user->can_view($web) ) {
+		$panel->render('misc/message.tt', { message => gettext('You\'re not allowed to do this (ACL rights)') } );
+		return;
+	}
+
+	if(defined($cgi->param('save_prefs_submit'))) {
+		save_prefs($panel, $web);
+	}
+
+	my $vars = { web => $web };
+
+	$panel->set_title( gettext("Modify webarea") );
+	$panel->render('web/prefs.tt', $vars);
+}
+
+sub save_prefs {
+	my $panel = shift;
+	my $web = shift;
+	my $cgi = $panel->{'cgi'};
+	my $user = $panel->{'user'};
+
+	my $description = Encode::decode_utf8( $cgi->param('description') );
+
+	unless( $user->can_modify($web) ) {
+		$panel->add_error( gettext('You are not allowed to modify this web area') );
+		return;
+	}
+
+	unless( defined $description ) {
+		$panel->add_error( gettext('CGI Error !') );
+		return;
+	}
+
+	unless( $description !~ /^\s*$/ ) {
+		$panel->add_error( gettext('You have to enter a description') );
+		return;
+	}
+
+	$web->set_description($description);
+	if($web->commit < 0) {
+		$panel->add_error( gettext('Unable to apply modifications') );
+	} else {
+		$panel->add_info( gettext('Web area successfully modified') );
+	}
+}
+
+sub index {
+	my $panel = shift;
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $group = Vhffs::Group::get_by_groupname( $vhffs , $cgi->param('group') );
+	unless( defined($group) ) {
+		$panel->render( 'misc/message.tt', { message => gettext('You have to select a group first') });
+		return;
+	}
+
+	unless($group->get_status == Vhffs::Constants::ACTIVATED) {
+		$panel->render( 'misc/message.tt', { message => gettext('This group is not activated yet') } );
+		return;
+	}
+
+	unless( $user->can_view( $group ) ) {
+		$panel->render('misc/message.tt', { message => gettext( 'You\'re not allowed to do this (ACL rights)' ) } );
+		return;
+	}
+
+	$panel->set_group( $group );
+	$panel->set_title( sprintf(gettext('Webareas for %s'), $group->get_groupname) );
+	my $web = Vhffs::Panel::Web::getall_per_group( $vhffs, $group->get_gid );
+	if($web < 0) {
+		$panel->render( 'misc/message.tt', { message => gettext('Unable to get webareas') } );
+		return;
+	}
+	
+	$panel->render( 'misc/service-index.tt', {
+	  label => 'Webareas',
+	  group => $group,
+	  list => $web,
+	  help_url => $vhffs->get_config->get_service('web')->{url_doc},
+	  type => 'web'
+	  });
+}
+
+sub search {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	my $name = $cgi->param('name');
+	my $vars = {};
+
+	unless( defined $name ) {
+
+		$panel->render('admin/misc/search.tt', {
+		  search_title => gettext('Webareas search'),
+		  type => 'web'
+		  });
+		return;
+	}
+
+	if( $name =~ /^\s*$/ ) {
+		$vars->{list_title} = gettext('List of all web areas');
+		undef $name;
+	} else {
+		$vars->{list_title} = sprintf( gettext('Search result for %s'), $name );
+	}
+	$vars->{list} = search_web( $vhffs , $name );
+	$vars->{type} = 'web';
+	$panel->render('admin/misc/list.tt', $vars);
+}
+
+sub adminindex {
+	my $panel = shift;
+	return unless $panel->check_modo();
+
+	my $vhffs = $panel->{'vhffs'};
+	my $cgi = $panel->{'cgi'};
+	my $session = $panel->{'session'};
+	my $user = $panel->{'user'};
+
+	$panel->set_title(gettext('Webareas\' administration'));
+	require Vhffs::Panel::Admin;
+	$panel->render('admin/index.tt', { categories => [ Vhffs::Panel::Admin::get_web_category() ] } );
+}
+
 1;

Modified: trunk/vhffs-irc/modobot.pl
===================================================================
--- trunk/vhffs-irc/modobot.pl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-irc/modobot.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -137,6 +137,7 @@
 sub moderate
 {
 	my $oid = shift;
+	my $user = shift;
 	my $status = shift; # 0 = refuse , 1 = accept
 	my $reason = shift;
 
@@ -191,6 +192,7 @@
 sub moderatetag
 {
 	my $rid = shift;
+	my $user = shift;
 	my $status = shift; # 0 = refuse , 1 = accept
 	my $reason = shift;
 
@@ -217,8 +219,6 @@
 	{
 		if( $status == 1 )
 		{
-			my $user = Vhffs::User::get_by_uid($vhffs, Vhffs::Main::current_user_uid);
-
 			my $category = Vhffs::Tag::Category::get_by_label($vhffs, $request->{category_label});
 			unless( defined $category )
 			{
@@ -485,8 +485,7 @@
     my ($self, $event)=@_;
     my ($nick, $mynick)=($event->nick, $self->nick);
     my $texte=$event->{args}[0];
-    my $user = Vhffs::User::get_by_ircnick($vhffs, $nick);
-    $user = Vhffs::User::get_by_username($vhffs, $nick) unless(defined $user);
+    my $user = ( Vhffs::User::get_by_ircnick($vhffs, $nick) or Vhffs::User::get_by_username($vhffs, $nick) );
 
     $texte =~ s/\s*$//;
 
@@ -495,16 +494,14 @@
 		if (is_modo ($user) == 1)
 		{
 			my ( $oid , $reason ) = ( $texte =~ /^${mynick}:\s+accept\s+([0-9]+)(?:\s+)?(.+)?$/ );
-			Vhffs::Main::current_user_uid( $user->get_uid );
-			moderate( $oid , 1 , $reason );
+			moderate( $oid , $user, 1 , $reason );
 		}
     }
     elsif ($texte =~ m/^${mynick}:\s+refuse\s+[0-9]+\s+.+$/)
     {
 		if (is_modo ($user) == 1) {
 			my ( $oid , $reason ) = ( $texte =~ /^${mynick}:\s+refuse\s+([0-9]+)(?:\s+)(.+)$/ );
-			Vhffs::Main::current_user_uid($user->get_uid);
-			moderate( $oid , 0 , $reason );
+			moderate( $oid , $user, 0 , $reason );
 		}
     }
     elsif ($texte =~ m/^${mynick}:\s+help$/)
@@ -578,7 +575,6 @@
         {
             my $groupname = $texte;
             my $quotavalue = $texte;
-			Vhffs::Main::current_user_uid($user->get_uid);
             $quotavalue =~ s/^${mynick}:\s+setquota\s+[a-z0-9]+\s+//;
             $groupname =~ s/^${mynick}:\s+setquota\s+([a-z0-9]+)\s+.*$/$1/;
             set_quota($groupname,$quotavalue);
@@ -606,8 +602,7 @@
 		if (is_modo ($user) == 1)
 		{
 			my ( $rid , $reason ) = ( $texte =~ /^${mynick}:\s+accepttag\s+([0-9]+)(?:\s+)?(.+)?$/ );
-			Vhffs::Main::current_user_uid( $user->get_uid );
-			moderatetag( $rid , 1 , $reason );
+			moderatetag( $rid , $user, 1 , $reason );
 		}
     }
     elsif ($texte =~ m/^${mynick}:\s+refusetag\s+[0-9]+\s*$/)
@@ -615,7 +610,7 @@
 		if (is_modo ($user) == 1) {
 			my $rid = $texte;
 			$rid =~ s/^${mynick}:\s+refusetag\s+([0-9]+)\s*$/$1/;
-			moderatetag( $rid , 0 , '' );
+			moderatetag( $rid , $user, 0 , '' );
 		}
     }
     elsif ($texte =~ m/^${mynick}:\s+fetch\s+[a-z0-9]+$/)

Modified: trunk/vhffs-panel/Makefile.am
===================================================================
--- trunk/vhffs-panel/Makefile.am	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/Makefile.am	2012-01-19 23:57:57 UTC (rev 1918)
@@ -794,51 +794,7 @@
 
 paneldir = @PANELDIR@
 nobase_dist_panel_DATA = favicon.ico
-nobase_dist_panel_SCRIPTS = alert_submit.pl \
-	alert.pl \
-	auth.pl \
-	getavatar.pl \
-	history.pl \
-	lost.pl \
-	lost_ack.pl \
-	panel.pl \
-	subscribe.pl \
-	acl/view.pl \
-	admin/index.pl \
-	admin/bazaar/index.pl \
-	admin/bazaar/list.pl \
-	admin/bazaar/search.pl \
-	admin/cvs/index.pl \
-	admin/cvs/list.pl \
-	admin/cvs/search.pl \
-	admin/dns/index.pl \
-	admin/dns/list.pl \
-	admin/dns/search.pl \
-	admin/group/index.pl \
-	admin/group/list.pl \
-	admin/group/search.pl \
-	admin/mail/index.pl \
-	admin/mail/list.pl \
-	admin/mail/search.pl \
-	admin/mailinglist/index.pl \
-	admin/mailinglist/list.pl \
-	admin/mailinglist/search.pl \
-	admin/mysql/index.pl \
-	admin/mysql/list.pl \
-	admin/mysql/search.pl \
-	admin/object/delete_avatar.pl \
-	admin/object/edit.pl \
-	admin/object/list.pl \
-	admin/object/search.pl \
-	admin/pgsql/index.pl \
-	admin/pgsql/list.pl \
-	admin/pgsql/search.pl \
-	admin/repository/index.pl \
-	admin/repository/list.pl \
-	admin/repository/search.pl \
-	admin/svn/index.pl \
-	admin/svn/list.pl \
-	admin/svn/search.pl \
+nobase_dist_panel_SCRIPTS = index.pl \
 	admin/tag/create.pl \
 	admin/tag/edit.pl \
 	admin/tag/index.pl \
@@ -847,81 +803,8 @@
 	admin/tag/category/edit.pl \
 	admin/tag/category/list.pl \
 	admin/tag/request/details.pl \
-	admin/tag/request/list.pl \
-	admin/git/index.pl \
-	admin/git/list.pl \
-	admin/git/search.pl \
-	admin/mercurial/index.pl \
-	admin/mercurial/list.pl \
-	admin/mercurial/search.pl \
-	admin/user/index.pl \
-	admin/user/list.pl \
-	admin/user/search.pl \
-	admin/web/index.pl \
-	admin/web/list.pl \
-	admin/web/search.pl \
-	admin/cron/index.pl \
-	admin/cron/list.pl \
-	admin/cron/search.pl \
-	admin/broadcast/delete.pl \
-	admin/broadcast/list.pl \
-	admin/broadcast/view.pl \
-	admin/broadcast/create.pl \
-	admin/moderation/index.pl \
-	admin/stats.pl \
-	admin/su.pl \
-	cvs/create.pl \
-	cvs/index.pl \
-	cvs/prefs.pl \
-	dns/create.pl \
-	dns/index.pl \
-	dns/prefs.pl \
-	group/create.pl \
-	group/prefs.pl \
-	group/history.pl \
-	group/index.pl \
-	group/view.pl \
-	mail/create.pl \
-	mail/index.pl \
-	mail/prefs.pl \
-	mailinglist/create.pl \
-	mailinglist/index.pl \
-	mailinglist/prefs.pl \
-	mysql/create.pl \
-	mysql/index.pl \
-	mysql/prefs.pl \
-	object/delete.pl \
-	object/upavatar.pl \
-	object/resubmit.pl \
-	object/quickdelete.pl \
-	pgsql/create.pl \
-	pgsql/index.pl \
-	pgsql/prefs.pl \
-	repository/create.pl \
-	repository/index.pl \
-	repository/prefs.pl \
-	svn/create.pl \
-	svn/index.pl \
-	svn/prefs.pl \
-	git/create.pl \
-	git/index.pl \
-	git/prefs.pl \
-	mercurial/create.pl \
-	mercurial/index.pl \
-	mercurial/prefs.pl \
-	bazaar/create.pl \
-	bazaar/index.pl \
-	bazaar/prefs.pl \
-	user/delete.pl \
-	user/prefs.pl \
-	web/create.pl \
-	web/index.pl \
-	web/prefs.pl \
-	cron/index.pl \
-	cron/prefs.pl \
-	cron/create.pl
+	admin/tag/request/list.pl
 
-
 # Define the substitution we need to point perl script at correct location
 do_sed = $(SED) --in-place \
 	-e 's,%PERL%,$(PERL),g' \

Deleted: trunk/vhffs-panel/acl/view.pl
===================================================================
--- trunk/vhffs-panel/acl/view.pl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/acl/view.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,115 +0,0 @@
-#!%PERL% -w
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#   notice, this list of conditions and the following disclaimer.
-#2. Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in 
-#   the documentation and/or other materials provided with the 
-#   distribution.
-#3. Neither the name of vhffs nor the names of its contributors 
-#   may be used to endorse or promote products derived from this 
-#   software without specific prior written permission.
-#
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-
-use utf8;
-use POSIX qw(locale_h);
-use locale;
-use Locale::gettext;
-use CGI;
-use CGI::Session;
-use strict;
-
-use lib '%VHFFS_LIB_DIR%';
-use Vhffs::User;
-use Vhffs::Main;
-use Vhffs::Panel::Main;
-use Vhffs::Acl;
-use Vhffs::Constants;
-
-my $panel = new Vhffs::Panel::Main();
-exit 0 unless $panel;
-my $session = $panel->get_session;
-exit 0 unless $session;
-
-my $vhffs = $panel->{vhffs};
-my $user = $panel->{user};
-my $cgi = $panel->{cgi};
-my $oid = $cgi->param('target_oid');
-my $templatedir = $vhffs->get_config->get_templatedir;
-my $template;
-
-my $object = Vhffs::Object::get_by_oid($vhffs, $oid);
-my $access_level = Vhffs::Acl::get_perm( $vhffs , $object , $user );
-
-# Object does not exists
-unless( defined $object ) {
-    $panel->render('misc/message.tt', { message => sprintf( gettext('Cannot get informations on object #%d'), $oid) } );
-} else {
-    # Object exists, we need to know if access is granted to the user
-    unless( $user->can_view( $object ) ) {
-        $panel->render('misc/message.tt', { message => gettext('You\'re not allowed to view this object\'s ACL') } );
-    } else {
-        # access OK, let's see if some action was requested
-        if(defined $cgi->param('update_acl_submit')) {
-            my $granted_oid = $cgi->param('granted_oid');
-            my $perm = $cgi->param('perm'.$granted_oid);
-            my $granted;
-            my $ret;
-            if(! (defined $granted_oid && defined $perm) ) {
-                $panel->add_error( gettext('CGI Error !') );
-            } elsif( ! defined( $granted = Vhffs::Object::get_by_oid( $vhffs, $granted_oid ) ) ) {
-                $panel->add_error( gettext('Group or user not found') );
-            }  elsif( ! $user->can_manageacl( $object ) ) {
-                $panel->add_error( gettext('You\'re not allowed to manage this object\'s ACL') );
-            } else {
-                $ret = Vhffs::Acl::add_update_or_del_acl( $vhffs, $object->get_oid, $granted_oid, $perm );
-                $panel->add_error( gettext('Sorry, can\'t add or update ACL') ) if( $ret < 0 );
-                $panel->add_info( gettext('ACL added') ) if( $ret == 1);
-                $panel->add_info( gettext('ACL updated') ) if( $ret == 2);
-                $panel->add_info( gettext('ACL deleted') ) if( $ret == 3);
-            }
-        }
-
-        $panel->set_title( gettext('ACL Administration') );
-        my $vars = {
-            target => $object
-        };
-        my $acls = Vhffs::Acl::get_object_acl( $vhffs, $object );
-        my $default_acl;
-        my $users_acl = [];
-        foreach my $acl ( @{$acls} )  {
-            if( defined $acl->{name} ) {
-                $acl->{perm} = Vhffs::Constants::ACL_UNDEFINED unless(defined $acl->{perm});
-                push( @$users_acl, $acl );
-            } else  {
-                $default_acl = {
-                    granted_oid => $acl->{granted_oid},
-                    'perm' => $acl->{perm}
-                 };
-            }
-        }
-        $vars->{default_acl} = $default_acl;
-        $vars->{users_acl} = $users_acl;
-
-        $panel->render('acl/view.tt', $vars);
-    }
-}

Deleted: trunk/vhffs-panel/admin/index.pl
===================================================================
--- trunk/vhffs-panel/admin/index.pl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/admin/index.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,59 +0,0 @@
-#!%PERL% -w 
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#   notice, this list of conditions and the following disclaimer.
-#2. Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in 
-#   the documentation and/or other materials provided with the 
-#   distribution.
-#3. Neither the name of vhffs nor the names of its contributors 
-#   may be used to endorse or promote products derived from this 
-#   software without specific prior written permission.
-#
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-
-use utf8;
-use POSIX qw(locale_h);
-use locale;
-use Locale::gettext;
-use strict;
-
-
-use lib '%VHFFS_LIB_DIR%';
-use Vhffs::Panel::Admin;
-use Vhffs::Panel::Modo;
-
-my $panel = new Vhffs::Panel::Modo();
-
-my $user = $panel->{user};
-
-$panel->set_title(gettext('Administration'));
-
-my $categories = [];
-if( $user->is_moderator ) { 
-    $categories = Vhffs::Panel::Admin::get_all_modo_categories($panel->{vhffs});
-} else {
-    $categories = Vhffs::Panel::Admin::get_all_admin_categories($panel->{vhffs});
-}
-
-$panel->render('admin/index.tt', {
-    categories => $categories
-});

Deleted: trunk/vhffs-panel/admin/stats.pl
===================================================================
--- trunk/vhffs-panel/admin/stats.pl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/admin/stats.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,107 +0,0 @@
-#!%PERL% -w 
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#   notice, this list of conditions and the following disclaimer.
-#2. Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in 
-#   the documentation and/or other materials provided with the 
-#   distribution.
-#3. Neither the name of vhffs nor the names of its contributors 
-#   may be used to endorse or promote products derived from this 
-#   software without specific prior written permission.
-#
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-
-use utf8;
-use POSIX qw(locale_h);
-use locale;
-use Locale::gettext;
-use CGI;
-use CGI::Session;
-use strict;
-
-
-use lib '%VHFFS_LIB_DIR%';
-use Vhffs::Panel::Modo;
-use Vhffs::Stats;
-
-my $panel = new Vhffs::Panel::Modo();
-
-my $vhffs = $panel->{'vhffs'};
-
-my $stats = new Vhffs::Stats( $vhffs );
-
-if( ! defined $stats ) {
-    $panel->render('misc/message.tt', { message => gettext( "Cannot get statistics") } );
-} else {
-    my $vars = {
-        users_count => $stats->get_user_total,
-        administrators_count => $stats->get_user_total_admin,
-        moderators_count => $stats->get_user_total_moderator,
-
-        groups_count => $stats->get_groups_total,
-        activated_groups_count => $stats->get_groups_activated,
-
-        waiting_web_count => $stats->get_web_in_moderation,
-        activated_web_count => $stats->get_web_activated,
-
-        waiting_dns_count => $stats->get_dns_in_moderation,
-        activated_dns_count => $stats->get_dns_activated,
-
-        waiting_cvs_count => $stats->get_cvs_in_moderation,
-        activated_cvs_count => $stats->get_cvs_activated,
-
-        waiting_svn_count => $stats->get_svn_in_moderation,
-        activated_svn_count => $stats->get_svn_activated,
-
-        waiting_git_count => $stats->get_git_in_moderation,
-        activated_git_count => $stats->get_git_activated,
-
-        waiting_mercurial_count => $stats->get_mercurial_in_moderation,
-        activated_mercurial_count => $stats->get_mercurial_activated,
-
-        waiting_bazaar_count => $stats->get_bazaar_in_moderation,
-        activated_bazaar_count => $stats->get_bazaar_activated,
-
-        waiting_mail_domains_count => $stats->get_mail_in_moderation,
-        activated_mail_domains_count => $stats->get_mail_activated,
-        mail_boxes_count => $stats->get_mail_total_boxes,
-        mail_forwards_count => $stats->get_mail_total_forwards,
-
-        waiting_mysql_count => $stats->get_mysql_in_moderation,
-        activated_mysql_count => $stats->get_mysql_activated,
-
-        waiting_pgsql_count => $stats->get_pgsql_in_moderation,
-        activated_pgsql_count => $stats->get_pgsql_activated,
-
-        waiting_ml_count => $stats->get_lists_in_moderation,
-        activated_ml_count => $stats->get_lists_activated,
-        ml_subscribers_count => $stats->get_lists_totalsubs,
-
-        tag_categories_count => $stats->get_tags_categories_total,
-        used_tags_count => $stats->get_tags_used_total,
-        total_tags_count => $stats->get_tags_total,
-        tagged_groups_count => $stats->get_tags_groups_total,
-        max_tags_count => $stats->get_tags_groups_max,
-        top10_tags => $stats->get_most_popular_tags
-    };
-    $panel->render('admin/misc/stats.tt', $vars);
-}

Deleted: trunk/vhffs-panel/admin/su.pl
===================================================================
--- trunk/vhffs-panel/admin/su.pl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/admin/su.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,71 +0,0 @@
-#!%PERL% -w 
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#   notice, this list of conditions and the following disclaimer.
-#2. Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in 
-#   the documentation and/or other materials provided with the 
-#   distribution.
-#3. Neither the name of vhffs nor the names of its contributors 
-#   may be used to endorse or promote products derived from this 
-#   software without specific prior written permission.
-#
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-
-use utf8;
-use POSIX qw(locale_h);
-use locale;
-use Locale::gettext;
-use CGI;
-use CGI::Session;
-use strict;
-
-use lib '%VHFFS_LIB_DIR%';
-use Vhffs::Panel::Admin;
-use Vhffs::Constants;
-
-my $panel = new Vhffs::Panel::Admin();
-
-my $vhffs = $panel->{vhffs};
-my $cgi = $panel->{cgi};
-
-my $username = $cgi->param('user');
-
-if(defined $username) {
-    my $user = Vhffs::User::get_by_username( $vhffs , $username );
-    if(defined $user) {
-        my $session = $panel->get_session;
-        $session->clear('username');
-        $session->clear('uid');
-        $session->param('username', $user->get_username);
-        $session->param('uid', $user->get_uid);
-        $session->flush();
-
-        $panel->render('misc/message.tt', {
-            message => gettext( sprintf( 'Su successful with name %s' , $user->get_username) ),
-            refresh_url => '/panel.pl'
-        });
-    } else {
-        $panel->add_error( gettext('User %s does not exist'), $username);
-    }
-}
-
-$panel->render('admin/misc/su.tt');

Deleted: trunk/vhffs-panel/alert.pl
===================================================================
--- trunk/vhffs-panel/alert.pl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/alert.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,49 +0,0 @@
-#!%PERL% -w 
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#   notice, this list of conditions and the following disclaimer.
-#2. Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in 
-#   the documentation and/or other materials provided with the 
-#   distribution.
-#3. Neither the name of vhffs nor the names of its contributors 
-#   may be used to endorse or promote products derived from this 
-#   software without specific prior written permission.
-#
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-use strict;
-use utf8;
-use POSIX qw(locale_h);
-use locale;
-use Locale::gettext;
-use CGI;
-use CGI::Session;
-
-use lib '%VHFFS_LIB_DIR%';
-use Vhffs::Main;
-use Vhffs::Panel::Main;
-
-my $panel = new Vhffs::Panel::Main();
-exit 0 unless $panel;
-my $session = $panel->get_session;
-exit 0 unless $session;
-
-$panel->render('misc/alert.tt')

Deleted: trunk/vhffs-panel/alert_submit.pl
===================================================================
--- trunk/vhffs-panel/alert_submit.pl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/alert_submit.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,73 +0,0 @@
-#!%PERL% -w 
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#   notice, this list of conditions and the following disclaimer.
-#2. Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in 
-#   the documentation and/or other materials provided with the 
-#   distribution.
-#3. Neither the name of vhffs nor the names of its contributors 
-#   may be used to endorse or promote products derived from this 
-#   software without specific prior written permission.
-#
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-use strict;
-use utf8;
-use POSIX qw(locale_h);
-use locale;
-use Locale::gettext;
-use CGI;
-use CGI::Session;
-use Encode;
-
-use lib '%VHFFS_LIB_DIR%';
-use Vhffs::User;
-use Vhffs::Main;
-use Vhffs::Panel::Main;
-use Vhffs::Functions;
-
-my $panel = new Vhffs::Panel::Main();
-exit 0 unless $panel;
-my $session = $panel->get_session;
-exit 0 unless $session;
-
-my $vhffs = $panel->{'vhffs'};
-my $user = $panel->{'user'};
-my $cgi = $panel->{'cgi'};
-
-my $vars = {};
-
-if( defined  $cgi->param('SUBJECT')  &&  defined $cgi->param('MESSAGE') )
-{
-	my $to = $vhffs->get_config->get_alert_mail;
-	my $from = $user->get_mail;
-	my $subject = Encode::decode_utf8( $cgi->param('SUBJECT') );
-	my $message = gettext('Message sent by the following account').': '.$user->get_username."\n\n".Encode::decode_utf8( $cgi->param('MESSAGE') );
-
-	Vhffs::Functions::send_mail( $vhffs , $from , $to , undef , $subject , $message );
-    $vars->{message} = gettext('Message sent successfully');
-}
-else
-{
-    $vars->{message} = gettext('Cannot send message, CGI error...');
-}
-
-$panel->render('misc/message.tt', $vars);

Deleted: trunk/vhffs-panel/auth.pl
===================================================================
--- trunk/vhffs-panel/auth.pl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/auth.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,111 +0,0 @@
-#!%PERL% -w
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#   notice, this list of conditions and the following disclaimer.
-#2. Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in 
-#   the documentation and/or other materials provided with the 
-#   distribution.
-#3. Neither the name of vhffs nor the names of its contributors 
-#   may be used to endorse or promote products derived from this 
-#   software without specific prior written permission.
-#
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-
-require 5.004;
-use utf8;
-use POSIX;
-use strict;
-use locale;
-use Locale::gettext;
-use CGI;
-use lib '%VHFFS_LIB_DIR%';
-use Vhffs::Main;
-use Vhffs::Panel::Main;
-use Vhffs::Panel::Commons;
-use Vhffs::Constants;
-
-my $panel = new Vhffs::Panel::Main();
-exit 0 unless $panel;
-
-my $vhffs = $panel->{'vhffs'};
-my $templatedir = $panel->{'templatedir'};
-my $cgi = $panel->{cgi};
-my $loginsubmitted = defined( $cgi->param('login_submit') );
-my $logoutsubmitted = defined( $cgi->param('logout') );
-
-if( $loginsubmitted ) {
-    # User tried to log in
-    # we try to clean the previous session
-    my $oldsid = CGI->cookie( CGI::Session::name() );
-    if( defined $oldsid ) {
-        my $oldsession = new CGI::Session(undef, $oldsid, {Directory=>'/tmp'});
-        $oldsession->delete();
-    }
-
-    my $username = $cgi->param('username');
-    my $password = $cgi->param('password');
-    my $user;
-    $user = Vhffs::User::get_by_username($vhffs, $username) if(defined $username);
-
-    #Incomplete input
-    unless( defined $username  &&  defined $password  &&  defined $user  &&  $user->check_password( $password ) ) {
-        $panel->add_error( gettext('Login failed !') );
-    } elsif($user->get_status != Vhffs::Constants::ACTIVATED) {
-        $panel->add_error( gettext('User is not active yet') );
-    } else {
-        # Creates the new session
-        my $session = new CGI::Session("driver:File", undef, {Directory=>'/tmp'});
-        $session->expires("+1h");
-        $session->param("username", $user->get_username);
-        $session->param("uid", $user->get_uid);
-
-        my $sessioncookie = new CGI::Cookie(-name => $session->name, -value => $session->id);
-
-        # Refresh cookies (avoid theme and language loss when user
-        # deletes cookies).
-        my $themecookie = new CGI::Cookie( -name=> 'theme', -value=>$user->get_theme, -expires=>'+10y' );
-        my $langcookie = new CGI::Cookie( -name=>'language', -value=>$user->get_lang, -expires=>'+10y' );
-
-	# Set last login panel to current time
-	$user->update_lastloginpanel;
-	$user->commit;
-
-        $panel->redirect('/panel.pl', [$sessioncookie, $themecookie, $langcookie]);
-    }
-}
-
-if( $logoutsubmitted )  {
-	#clean session
-	my $oldsid = CGI->cookie( CGI::Session::name() );
-	if( defined $oldsid )  {
-		my $oldsession = new CGI::Session(undef, $oldsid, {Directory=>'/tmp'});
-		$oldsession->delete();
-	}
-
-	$panel->add_info( gettext('You left your VHFFS session!') );
-
-	Vhffs::Panel::Commons::display_login($vhffs, $panel);
-}
-
-if( ( ! $loginsubmitted  &&  ! $logoutsubmitted )  ||  $panel->has_errors ) {
-	Vhffs::Panel::Commons::display_login($vhffs, $panel);
-}

Deleted: trunk/vhffs-panel/getavatar.pl
===================================================================
--- trunk/vhffs-panel/getavatar.pl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/getavatar.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,128 +0,0 @@
-#!%PERL% -w
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#   notice, this list of conditions and the following disclaimer.
-#2. Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in 
-#   the documentation and/or other materials provided with the 
-#   distribution.
-#3. Neither the name of vhffs nor the names of its contributors 
-#   may be used to endorse or promote products derived from this 
-#   software without specific prior written permission.
-#
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-use strict;
-use utf8;
-use CGI;
-use GD;
-use GD::Text::Wrap;
-use lib '%VHFFS_LIB_DIR%';
-use Vhffs::Main;
-use Vhffs::Object;
-use Vhffs::Panel::Avatar;
-use Vhffs::Functions;
-
-#Get some basics informations with CGI
-my $cgi;
-my $oid;
-my $code;
-my $vhffs;
-my $gd;
-my $wp;
-my $black;
-my $white;
-my $blue;
-my $path;
-my $buf;
-my $object;
-
-$cgi 		= new CGI;
-$cgi->charset('utf-8');
-$vhffs		= init Vhffs::Main;	
-$oid 		= $cgi->param( "oid" );
-
-$object = Vhffs::Object::get_by_oid( $vhffs , $oid );
-
-$path = Vhffs::Panel::Avatar::exists_avatar( $vhffs , $object );
-
-if( ! ( defined $oid ) )
-{
-	print CGI->header( -type=>"text/html", -charset=>"utf-8" );
-	print "oid error";
-	exit 1;
-}
-
-$gd = GD::Image->new(70,100);
-$white = $gd->colorAllocate(255,255,255);
-$black = $gd->colorAllocate(  0,  0,  0);
-$blue  = $gd->colorAllocate(127,127,255);
-
-#print "No colours: $black ", $gd->colorsTotal, "\n";
-    
-
-# Assume the user has set FONT_PATH or TTF_FONT_PATH
-#$wp->font_path('/usr/share/fonts/ttfonts');
-print CGI->header( -type=>"image/png" );
-
-binmode STDOUT;
-
-unless( Vhffs::Functions::strtobool( $vhffs->get_config->get_panel->{'users_avatars'} ) or Vhffs::Functions::strtobool( $vhffs->get_config->get_panel->{'groups_avatars'} ) )
-{
-	$wp = GD::Text::Wrap->new($gd,
-		width       => 70,
-		line_space  => 0,
-		color       => $black, 
-		text        => "This platform does not support avatar",
-	);
-	$wp->set_font(gdLargeFont, 14);
-	$wp->set(align => 'center');
-	$wp->draw(0,5);
-	$wp->set(para_space => 10, preserve_nl => 0);
-	print STDOUT $gd->png();
-}
-else
-{
-	if( defined $path )
-	{
-		open FORIG , "$path";
-		while( read( FORIG , $buf , 1024 ) )
-		{
-			print STDOUT $buf;
-		}
-		close( FORIG );
-	}
-	else
-	{
-		$wp = GD::Text::Wrap->new($gd,
-			width       => 70,
-			line_space  => 0,
-			color       => $black, 
-			text        => "No avatar",
-		);
-		$wp->set_font(gdLargeFont, 14);
-		$wp->set(align => 'center');
-		$wp->draw(0,5);
-		$wp->set(para_space => 10, preserve_nl => 0);
-		print STDOUT $gd->png();
-	}
-}
-
-close STDOUT;

Deleted: trunk/vhffs-panel/history.pl
===================================================================
--- trunk/vhffs-panel/history.pl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/history.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,73 +0,0 @@
-#!%PERL% -w
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#   notice, this list of conditions and the following disclaimer.
-#2. Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in 
-#   the documentation and/or other materials provided with the 
-#   distribution.
-#3. Neither the name of vhffs nor the names of its contributors 
-#   may be used to endorse or promote products derived from this 
-#   software without specific prior written permission.
-#
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-
-use utf8;
-use POSIX qw(locale_h);
-use locale;
-use Locale::gettext;
-use CGI;
-use CGI::Session;
-use strict;
-
-use lib '%VHFFS_LIB_DIR%';
-use Vhffs::Panel::Main;
-use Vhffs::Object;
-
-my $panel = new Vhffs::Panel::Main();
-exit 0 unless $panel;
-my $session = $panel->get_session;
-exit 0 unless $session;
-
-my $vhffs = $panel->{'vhffs'};
-my $user = $panel->{'user'};
-my $cgi = $panel->{'cgi'};
-my $oid = $cgi->param("OID");
-
-$oid = $cgi->param("oid") if( ! defined $oid );
-
-my $object;
-
-$object = Vhffs::Object::get_by_oid( $vhffs , $oid );
-
-if( ! defined $oid ) {
-    $panel->render('misc/message.tt', { message => gettext( "CGI Error !") });
-} elsif( !defined $object ) {
-    $panel->render('misc/message.tt', { message => gettext( "Cannot get information on this object") });
-} elsif( !$user->can_view($object) ) {
-    $panel->render('misc/message.tt', { message => gettext("You're not allowed to view this object's ACL") });
-} else {
-    $panel->set_title( gettext("History") );
-
-	my $history = $object->get_history;
-    $panel->render('misc/history.tt', { history => $history });
-}
-

Added: trunk/vhffs-panel/index.pl
===================================================================
--- trunk/vhffs-panel/index.pl	                        (rev 0)
+++ trunk/vhffs-panel/index.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -0,0 +1,374 @@
+#!%PERL% -w
+# Copyright (c) vhffs project and its contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without 
+# modification, are permitted provided that the following conditions 
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright 
+#   notice, this list of conditions and the following disclaimer.
+#2. Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in 
+#   the documentation and/or other materials provided with the 
+#   distribution.
+#3. Neither the name of vhffs nor the names of its contributors 
+#   may be used to endorse or promote products derived from this 
+#   software without specific prior written permission.
+#
+#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+# POSSIBILITY OF SUCH DAMAGE.
+
+
+require 5.004;
+use utf8;
+use POSIX;
+use strict;
+use locale;
+use Locale::gettext;
+#use CGI::Fast qw(:standard);
+use CGI();
+use CGI::Fast();
+use lib '%VHFFS_LIB_DIR%';
+use Vhffs::Main;
+use Vhffs::Panel::Main;
+
+# -- prefork
+CGI->compile();
+
+my $vhffs = init Vhffs::Main( { backend => 'no' } );
+exit 1 unless defined $vhffs;
+
+$vhffs->connect;
+
+# -- requests loop
+while (my $cgi = new CGI::Fast) {
+
+	my $panel = new Vhffs::Panel::Main( $vhffs, $cgi );
+	next unless defined $panel;
+
+	my $do = ( $cgi->param('do') or 'login' );
+
+	# -- anonymous
+	if( $do eq 'login' or $do eq 'lost' or $do eq 'subscribe' or $do eq 'logout' ) {
+		if( $do eq 'login' ) {
+			require Vhffs::Panel::Auth;
+			Vhffs::Panel::Auth::login( $panel );
+		} elsif( $do eq 'lost' ) {
+			require Vhffs::Panel::Auth;
+			Vhffs::Panel::Auth::lost( $panel );
+		} elsif( $do eq 'subscribe' ) {
+			require Vhffs::Panel::Subscribe;
+			Vhffs::Panel::Subscribe::subscribe( $panel );
+		} elsif( $do eq 'logout' ) {
+			require Vhffs::Panel::Auth;
+			Vhffs::Panel::Auth::logout( $panel );
+		}
+
+		next;
+	}
+
+	# -- session required
+	my $session = ( $panel->get_session or next );
+
+	if( $do eq 'home' ) {
+		require Vhffs::Panel::Home;
+		Vhffs::Panel::Home::home( $panel );
+	} elsif( $do eq 'contact' ) {
+		require Vhffs::Panel::Contact;
+		Vhffs::Panel::Contact::contact( $panel );
+	} elsif( $do eq 'acl' ) {
+		require Vhffs::Panel::Acl;
+		Vhffs::Panel::Acl::acl( $panel );
+	} elsif( $do eq 'objecthistory' ) {
+		require Vhffs::Panel::Object;
+		Vhffs::Panel::Object::history( $panel );
+	} elsif( $do eq 'objectresubmit' ) {
+		require Vhffs::Panel::Object;
+		Vhffs::Panel::Object::resubmit( $panel );
+	} elsif( $do eq 'objectcancel' ) {
+		require Vhffs::Panel::Object;
+		Vhffs::Panel::Object::cancel( $panel );
+	} elsif( $do eq 'objectdelete' ) {
+		require Vhffs::Panel::Object;
+		Vhffs::Panel::Object::delete( $panel );
+	} elsif( $do eq 'avatarget' ) {
+		require Vhffs::Panel::Avatar;
+		Vhffs::Panel::Avatar::get( $panel );
+	} elsif( $do eq 'avatarput' ) {
+		require Vhffs::Panel::Avatar;
+		Vhffs::Panel::Avatar::put( $panel );
+	} elsif( $do eq 'avatardelete' ) {
+		require Vhffs::Panel::Avatar;
+		Vhffs::Panel::Avatar::delete( $panel );
+	} elsif( $do eq 'userprefs' ) {
+		require Vhffs::Panel::User;
+		Vhffs::Panel::User::prefs( $panel );
+	} elsif( $do eq 'groupindex' ) {
+		require Vhffs::Panel::Group;
+		Vhffs::Panel::Group::index( $panel );
+	} elsif( $do eq 'groupcreate' ) {
+		require Vhffs::Panel::Group;
+		Vhffs::Panel::Group::create( $panel );
+	} elsif( $do eq 'groupview' ) {
+		require Vhffs::Panel::Group;
+		Vhffs::Panel::Group::view( $panel );
+	} elsif( $do eq 'groupprefs' ) {
+		require Vhffs::Panel::Group;
+		Vhffs::Panel::Group::prefs( $panel );
+	} elsif( $do eq 'grouphistory' ) {
+		require Vhffs::Panel::Group;
+		Vhffs::Panel::Group::history( $panel );
+	} elsif( $do eq 'webcreate' ) {
+		require Vhffs::Panel::Web;
+		Vhffs::Panel::Web::create( $panel );
+	} elsif( $do eq 'webprefs' ) {
+		require Vhffs::Panel::Web;
+		Vhffs::Panel::Web::prefs( $panel );
+	} elsif( $do eq 'webindex' ) {
+		require Vhffs::Panel::Web;
+		Vhffs::Panel::Web::index( $panel );
+	} elsif( $do eq 'mysqlcreate' ) {
+		require Vhffs::Panel::Mysql;
+		Vhffs::Panel::Mysql::create( $panel );
+	} elsif( $do eq 'mysqlprefs' ) {
+		require Vhffs::Panel::Mysql;
+		Vhffs::Panel::Mysql::prefs( $panel );
+	} elsif( $do eq 'mysqlindex' ) {
+		require Vhffs::Panel::Mysql;
+		Vhffs::Panel::Mysql::index( $panel );
+	} elsif( $do eq 'pgsqlcreate' ) {
+		require Vhffs::Panel::Pgsql;
+		Vhffs::Panel::Pgsql::create( $panel );
+	} elsif( $do eq 'pgsqlprefs' ) {
+		require Vhffs::Panel::Pgsql;
+		Vhffs::Panel::Pgsql::prefs( $panel );
+	} elsif( $do eq 'pgsqlindex' ) {
+		require Vhffs::Panel::Pgsql;
+		Vhffs::Panel::Pgsql::index( $panel );
+	} elsif( $do eq 'cvscreate' ) {
+		require Vhffs::Panel::Cvs;
+		Vhffs::Panel::Cvs::create( $panel );
+	} elsif( $do eq 'cvsprefs' ) {
+		require Vhffs::Panel::Cvs;
+		Vhffs::Panel::Cvs::prefs( $panel );
+	} elsif( $do eq 'cvsindex' ) {
+		require Vhffs::Panel::Cvs;
+		Vhffs::Panel::Cvs::index( $panel );
+	} elsif( $do eq 'svncreate' ) {
+		require Vhffs::Panel::Svn;
+		Vhffs::Panel::Svn::create( $panel );
+	} elsif( $do eq 'svnprefs' ) {
+		require Vhffs::Panel::Svn;
+		Vhffs::Panel::Svn::prefs( $panel );
+	} elsif( $do eq 'svnindex' ) {
+		require Vhffs::Panel::Svn;
+		Vhffs::Panel::Svn::index( $panel );
+	} elsif( $do eq 'gitcreate' ) {
+		require Vhffs::Panel::Git;
+		Vhffs::Panel::Git::create( $panel );
+	} elsif( $do eq 'gitprefs' ) {
+		require Vhffs::Panel::Git;
+		Vhffs::Panel::Git::prefs( $panel );
+	} elsif( $do eq 'gitindex' ) {
+		require Vhffs::Panel::Git;
+		Vhffs::Panel::Git::index( $panel );
+	} elsif( $do eq 'mercurialcreate' ) {
+		require Vhffs::Panel::Mercurial;
+		Vhffs::Panel::Mercurial::create( $panel );
+	} elsif( $do eq 'mercurialprefs' ) {
+		require Vhffs::Panel::Mercurial;
+		Vhffs::Panel::Mercurial::prefs( $panel );
+	} elsif( $do eq 'mercurialindex' ) {
+		require Vhffs::Panel::Mercurial;
+		Vhffs::Panel::Mercurial::index( $panel );
+	} elsif( $do eq 'bazaarcreate' ) {
+		require Vhffs::Panel::Bazaar;
+		Vhffs::Panel::Bazaar::create( $panel );
+	} elsif( $do eq 'bazaarprefs' ) {
+		require Vhffs::Panel::Bazaar;
+		Vhffs::Panel::Bazaar::prefs( $panel );
+	} elsif( $do eq 'bazaarindex' ) {
+		require Vhffs::Panel::Bazaar;
+		Vhffs::Panel::Bazaar::index( $panel );
+	} elsif( $do eq 'dnscreate' ) {
+		require Vhffs::Panel::DNS;
+		Vhffs::Panel::DNS::create( $panel );
+	} elsif( $do eq 'dnsprefs' ) {
+		require Vhffs::Panel::DNS;
+		Vhffs::Panel::DNS::prefs( $panel );
+	} elsif( $do eq 'dnsindex' ) {
+		require Vhffs::Panel::DNS;
+		Vhffs::Panel::DNS::index( $panel );
+	} elsif( $do eq 'repositorycreate' ) {
+		require Vhffs::Panel::Repository;
+		Vhffs::Panel::Repository::create( $panel );
+	} elsif( $do eq 'repositoryprefs' ) {
+		require Vhffs::Panel::Repository;
+		Vhffs::Panel::Repository::prefs( $panel );
+	} elsif( $do eq 'repositoryindex' ) {
+		require Vhffs::Panel::Repository;
+		Vhffs::Panel::Repository::index( $panel );
+	} elsif( $do eq 'mailcreate' ) {
+		require Vhffs::Panel::Mail;
+		Vhffs::Panel::Mail::create( $panel );
+	} elsif( $do eq 'mailprefs' ) {
+		require Vhffs::Panel::Mail;
+		Vhffs::Panel::Mail::prefs( $panel );
+	} elsif( $do eq 'mailindex' ) {
+		require Vhffs::Panel::Mail;
+		Vhffs::Panel::Mail::index( $panel );
+	} elsif( $do eq 'mailinglistcreate' ) {
+		require Vhffs::Panel::MailingList;
+		Vhffs::Panel::MailingList::create( $panel );
+	} elsif( $do eq 'mailinglistprefs' ) {
+		require Vhffs::Panel::MailingList;
+		Vhffs::Panel::MailingList::prefs( $panel );
+	} elsif( $do eq 'mailinglistindex' ) {
+		require Vhffs::Panel::MailingList;
+		Vhffs::Panel::MailingList::index( $panel );
+	} elsif( $do eq 'croncreate' ) {
+		require Vhffs::Panel::Cron;
+		Vhffs::Panel::Cron::create( $panel );
+	} elsif( $do eq 'cronprefs' ) {
+		require Vhffs::Panel::Cron;
+		Vhffs::Panel::Cron::prefs( $panel );
+	} elsif( $do eq 'cronindex' ) {
+		require Vhffs::Panel::Cron;
+		Vhffs::Panel::Cron::index( $panel );
+
+	# -- admins and moderators stuff
+	} elsif( $do eq 'admin' ) {
+		require Vhffs::Panel::Admin;
+		Vhffs::Panel::Admin::main( $panel );
+	} elsif( $do eq 'stats' ) {
+		require Vhffs::Panel::Stats;
+		Vhffs::Panel::Stats::stats( $panel );
+	} elsif( $do eq 'moderation' ) {
+		require Vhffs::Panel::Moderation;
+		Vhffs::Panel::Moderation::moderation( $panel );
+	} elsif( $do eq 'su' ) {
+		require Vhffs::Panel::Admin;
+		Vhffs::Panel::Admin::su( $panel );
+	} elsif( $do eq 'broadcastcreate' ) {
+		require Vhffs::Panel::Broadcast;
+		Vhffs::Panel::Broadcast::create( $panel );
+	} elsif( $do eq 'broadcastlist' ) {
+		require Vhffs::Panel::Broadcast;
+		Vhffs::Panel::Broadcast::list( $panel );
+	} elsif( $do eq 'broadcastview' ) {
+		require Vhffs::Panel::Broadcast;
+		Vhffs::Panel::Broadcast::view( $panel );
+	} elsif( $do eq 'broadcastdelete' ) {
+		require Vhffs::Panel::Broadcast;
+		Vhffs::Panel::Broadcast::delete( $panel );
+	} elsif( $do eq 'objectsearch' ) {
+		require Vhffs::Panel::Object;
+		Vhffs::Panel::Object::search( $panel );
+	} elsif( $do eq 'objectedit' ) {
+		require Vhffs::Panel::Object;
+		Vhffs::Panel::Object::edit( $panel );
+	} elsif( $do eq 'usersearch' ) {
+		require Vhffs::Panel::User;
+		Vhffs::Panel::User::search( $panel );
+	} elsif( $do eq 'adminuserindex' ) {
+		require Vhffs::Panel::User;
+		Vhffs::Panel::User::adminindex( $panel );
+	} elsif( $do eq 'groupsearch' ) {
+		require Vhffs::Panel::Group;
+		Vhffs::Panel::Group::search( $panel );
+	} elsif( $do eq 'admingroupindex' ) {
+		require Vhffs::Panel::Group;
+		Vhffs::Panel::Group::adminindex( $panel );
+	} elsif( $do eq 'websearch' ) {
+		require Vhffs::Panel::Web;
+		Vhffs::Panel::Web::search( $panel );
+	} elsif( $do eq 'adminwebindex' ) {
+		require Vhffs::Panel::Web;
+		Vhffs::Panel::Web::adminindex( $panel );
+	} elsif( $do eq 'mysqlsearch' ) {
+		require Vhffs::Panel::Mysql;
+		Vhffs::Panel::Mysql::search( $panel );
+	} elsif( $do eq 'adminmysqlindex' ) {
+		require Vhffs::Panel::Mysql;
+		Vhffs::Panel::Mysql::adminindex( $panel );
+	} elsif( $do eq 'pgsqlsearch' ) {
+		require Vhffs::Panel::Pgsql;
+		Vhffs::Panel::Pgsql::search( $panel );
+	} elsif( $do eq 'adminpgsqlindex' ) {
+		require Vhffs::Panel::Pgsql;
+		Vhffs::Panel::Pgsql::adminindex( $panel );
+	} elsif( $do eq 'cvssearch' ) {
+		require Vhffs::Panel::Cvs;
+		Vhffs::Panel::Cvs::search( $panel );
+	} elsif( $do eq 'admincvsindex' ) {
+		require Vhffs::Panel::Cvs;
+		Vhffs::Panel::Cvs::adminindex( $panel );
+	} elsif( $do eq 'svnsearch' ) {
+		require Vhffs::Panel::Svn;
+		Vhffs::Panel::Svn::search( $panel );
+	} elsif( $do eq 'adminsvnindex' ) {
+		require Vhffs::Panel::Svn;
+		Vhffs::Panel::Svn::adminindex( $panel );
+	} elsif( $do eq 'gitsearch' ) {
+		require Vhffs::Panel::Git;
+		Vhffs::Panel::Git::search( $panel );
+	} elsif( $do eq 'admingitindex' ) {
+		require Vhffs::Panel::Git;
+		Vhffs::Panel::Git::adminindex( $panel );
+	} elsif( $do eq 'mercurialsearch' ) {
+		require Vhffs::Panel::Mercurial;
+		Vhffs::Panel::Mercurial::search( $panel );
+	} elsif( $do eq 'adminmercurialindex' ) {
+		require Vhffs::Panel::Mercurial;
+		Vhffs::Panel::Mercurial::adminindex( $panel );
+	} elsif( $do eq 'bazaarsearch' ) {
+		require Vhffs::Panel::Bazaar;
+		Vhffs::Panel::Bazaar::search( $panel );
+	} elsif( $do eq 'adminbazaarindex' ) {
+		require Vhffs::Panel::Bazaar;
+		Vhffs::Panel::Bazaar::adminindex( $panel );
+	} elsif( $do eq 'dnssearch' ) {
+		require Vhffs::Panel::DNS;
+		Vhffs::Panel::DNS::search( $panel );
+	} elsif( $do eq 'admindnsindex' ) {
+		require Vhffs::Panel::DNS;
+		Vhffs::Panel::DNS::adminindex( $panel );
+	} elsif( $do eq 'mailsearch' ) {
+		require Vhffs::Panel::Mail;
+		Vhffs::Panel::Mail::search( $panel );
+	} elsif( $do eq 'adminmailindex' ) {
+		require Vhffs::Panel::Mail;
+		Vhffs::Panel::Mail::adminindex( $panel );
+	} elsif( $do eq 'mailinglistsearch' ) {
+		require Vhffs::Panel::MailingList;
+		Vhffs::Panel::MailingList::search( $panel );
+	} elsif( $do eq 'adminmailinglistindex' ) {
+		require Vhffs::Panel::MailingList;
+		Vhffs::Panel::MailingList::adminindex( $panel );
+	} elsif( $do eq 'repositorysearch' ) {
+		require Vhffs::Panel::Repository;
+		Vhffs::Panel::Repository::search( $panel );
+	} elsif( $do eq 'adminrepositoryindex' ) {
+		require Vhffs::Panel::Repository;
+		Vhffs::Panel::Repository::adminindex( $panel );
+	} elsif( $do eq 'cronsearch' ) {
+		require Vhffs::Panel::Cron;
+		Vhffs::Panel::Cron::search( $panel );
+	} elsif( $do eq 'admincronindex' ) {
+		require Vhffs::Panel::Cron;
+		Vhffs::Panel::Cron::adminindex( $panel );
+	}
+}
+
+exit 0;


Property changes on: trunk/vhffs-panel/index.pl
___________________________________________________________________
Added: svn:executable
   + *

Deleted: trunk/vhffs-panel/lost.pl
===================================================================
--- trunk/vhffs-panel/lost.pl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/lost.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,46 +0,0 @@
-#!%PERL% -w
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#   notice, this list of conditions and the following disclaimer.
-#2. Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in 
-#   the documentation and/or other materials provided with the 
-#   distribution.
-#3. Neither the name of vhffs nor the names of its contributors 
-#   may be used to endorse or promote products derived from this 
-#   software without specific prior written permission.
-#
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-
-require 5.004;
-use utf8;
-use POSIX;
-use strict;
-use locale;
-use Locale::gettext;
-use CGI;
-use lib '%VHFFS_LIB_DIR%';
-use Vhffs::Panel::Main;
-
-my $panel = new Vhffs::Panel::Main();
-exit 0 unless $panel;
-
-$panel->render('anonymous/lost-password.tt', undef, 'anonymous.tt');

Deleted: trunk/vhffs-panel/lost_ack.pl
===================================================================
--- trunk/vhffs-panel/lost_ack.pl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/lost_ack.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,82 +0,0 @@
-#!%PERL% -w
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#   notice, this list of conditions and the following disclaimer.
-#2. Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in 
-#   the documentation and/or other materials provided with the 
-#   distribution.
-#3. Neither the name of vhffs nor the names of its contributors 
-#   may be used to endorse or promote products derived from this 
-#   software without specific prior written permission.
-#
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-
-use utf8;
-use POSIX qw(locale_h);
-use locale;
-use Locale::gettext;
-use CGI;
-use CGI::Session;
-use strict;
-
-use lib '%VHFFS_LIB_DIR%';
-use Vhffs::User;
-use Vhffs::Main;
-use Vhffs::Panel::Main;
-use Vhffs::Services::MailUser;
-use Vhffs::Functions;
-
-my $panel = new Vhffs::Panel::Main();
-exit 0 unless $panel;
-
-my $vhffs = $panel->{'vhffs'};
-my $cgi = $panel->{'cgi'};
-my $username = $cgi->param('username');
-my $user = Vhffs::User::get_by_username( $vhffs, $username );
-
-if ( defined $user && $user->{'state'} == Vhffs::Constants::ACTIVATED )
-{
-    #create a new password for this user
-    my $password = Vhffs::Functions::generate_random_password;
-    $user->set_password( $password );
-    $user->commit;
-    my $mu = init Vhffs::Services::MailUser( $vhffs , $user );
-    if( defined $mu  &&  $mu->exists_box) {
-        $mu->changepassword( $password );
-    } 
-  
-    # Send a mail with plain password inside
-    my $subject = sprintf("Password changed on %s", $vhffs->get_config->get_host_name );
-    my $content = sprintf("Hello %s %s,\n\nYou asked for a new password, here are your new login information:\nUser: %s\nPassword: %s\n\n%s Administrators\n", $user->get_firstname, $user->get_lastname, $user->get_username, $password , $vhffs->get_config->get_host_name );
-    $user->send_mail_user( $subject, $content );
-    
-    $panel->render('anonymous/lost-password-ack.tt', {
-        message => sprintf( gettext("Please wait %s, a new password will be sent to you in a few minutes..."), $username )
-    }, 'anonymous.tt');
-}
-else
-{
-    $panel->render('anonymous/lost-password-ack.tt', {
-        message => gettext("Password recovery failed!"),
-    }, 'anonymous.tt');
-}
-

Deleted: trunk/vhffs-panel/object/delete.pl
===================================================================
--- trunk/vhffs-panel/object/delete.pl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/object/delete.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,88 +0,0 @@
-#!%PERL% -w
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#    notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-#    notice, this list of conditions and the following disclaimer in 
-#    the documentation and/or other materials provided with the 
-#    distribution.
-# 3. Neither the name of vhffs nor the names of its contributors 
-#    may be used to endorse or promote products derived from this 
-#    software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-
-use utf8;
-use POSIX qw(locale_h);
-use locale;
-use Locale::gettext;
-use CGI;
-use CGI::Session;
-use strict;
-
-use lib '%VHFFS_LIB_DIR%';
-use Vhffs::Panel::Main;
-
-my $panel = new Vhffs::Panel::Main();
-exit 0 unless $panel;
-my $session = $panel->get_session;
-exit 0 unless $session;
-
-my $vhffs = $panel->{'vhffs'};
-my $user = $panel->{'user'};
-my $cgi = $panel->{'cgi'};
-my $message;
-
-my $oid = $cgi->param( "oid" );
-my $sure = $cgi->param( "delete" );
-
-my $object = Vhffs::Object::get_by_oid( $vhffs, $oid );
-
-if( ( ! defined $oid ) || ( ! defined $sure ) ) {
-    $message = gettext( 'CGI Error !' );
-} elsif( ! defined $object ) {
-	$message = gettext( 'Cannot retrieve informations about this object' );
-} elsif( !$user->can_delete( $object ) ) {
-	$message = gettext( 'You\'re not allowed to do this, object is not in active state or you don\'t have enough ACL rights' );
-} elsif( $sure == 0 ) {
-	$message = gettext( 'This object will NOT be deleted' );
-} else {
-	$object->set_status( Vhffs::Constants::TO_DELETE );
-
-	# Commit all the changes for the current user
-	if( $object->commit < 0 ) {
-        $message = gettext( 'An error occured while deleting this object' );
-	} else {
-        $message = gettext( 'This object will be deleted' );
-	}
-}
-
-my $vars = {
-    message => $message
-};
-
-if( $object->get_type == Vhffs::Constants::TYPE_GROUP ) {
-    $vars->{refresh_url} = '/group/index.pl';
-} else {
-    $vars->{refresh_url} = '/group/view.pl?group='.$object->get_owner_group unless($object->get_type == Vhffs::Constants::TYPE_GROUP);
-}
-
-$panel->render('misc/message.tt', $vars );

Deleted: trunk/vhffs-panel/object/quickdelete.pl
===================================================================
--- trunk/vhffs-panel/object/quickdelete.pl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/object/quickdelete.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,91 +0,0 @@
-#!%PERL% -w
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#   notice, this list of conditions and the following disclaimer.
-#2. Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in 
-#   the documentation and/or other materials provided with the 
-#   distribution.
-#3. Neither the name of vhffs nor the names of its contributors 
-#   may be used to endorse or promote products derived from this 
-#   software without specific prior written permission.
-#
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-use utf8;
-use POSIX qw(locale_h);
-use locale;
-use Locale::gettext;
-use CGI;
-use CGI::Session;
-use strict;
-
-use lib '%VHFFS_LIB_DIR%';
-use Vhffs::Panel::Main;
-use Vhffs::Group;
-use Vhffs::Constants;
-use Vhffs::ObjectFactory;
-
-my $panel = new Vhffs::Panel::Main();
-exit 0 unless $panel;
-my $session = $panel->get_session;
-exit 0 unless $session;
-
-my $vhffs = $panel->{vhffs};
-my $templatedir = $panel->{templatedir};
-my $user = $panel->{user};
-my $cgi = $panel->{cgi};
-
-my $oid = $cgi->param('oid');
-
-unless(defined $oid) {
-    $panel->render('misc/message.tt', { message => gettext('CGI Error !') } );
-}
-
-my $object = Vhffs::ObjectFactory::fetch_object( $vhffs , $oid );
-
-unless(defined $object) {
-	$panel->render('misc/message.tt', { message => gettext('This object does not exist') } );
-}
-
-unless($object->get_status == Vhffs::Constants::VALIDATION_REFUSED )  {
-    $panel->render('misc/message.tt', { message => gettext('This object is not in refused state') } );
-}
-
-unless($object->get_owner_uid == $user->get_uid )  {
-    $panel->render('misc/message.tt', { message => gettext('You are not allowed to do it, you don\'t own this object') } );
-}
-
-if( $object ) {
-	my $url;
-
-	if( $object->get_type == Vhffs::Constants::TYPE_GROUP ) {
-		$url = '/group/index.pl?msg='.gettext('This object has been deleted');
-	} else {
-		my $group = Vhffs::Group::get_by_gid( $vhffs , $object->get_owner_gid );
-		$url = '/group/view.pl?group='.$group->get_groupname.'&msg='.gettext('This object has been deleted');
-	}
-
-	if( $object->delete )  {
-		$panel->redirect( $url );
-	} else {
-        $panel->render('misc/message.tt', { message => gettext('An error occured while deleting this object.') } );
-	}
-}

Deleted: trunk/vhffs-panel/object/resubmit.pl
===================================================================
--- trunk/vhffs-panel/object/resubmit.pl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/object/resubmit.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,105 +0,0 @@
-#!%PERL% -w
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#   notice, this list of conditions and the following disclaimer.
-#2. Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in 
-#   the documentation and/or other materials provided with the 
-#   distribution.
-#3. Neither the name of vhffs nor the names of its contributors 
-#   may be used to endorse or promote products derived from this 
-#   software without specific prior written permission.
-#
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-use utf8;
-use POSIX qw(locale_h);
-use locale;
-use Locale::gettext;
-use CGI;
-use CGI::Session;
-use strict;
-
-use lib '%VHFFS_LIB_DIR%';
-use Vhffs::Panel::Main;
-use Vhffs::Group;
-use Vhffs::Constants;
-use Vhffs::ObjectFactory;
-
-my $panel = new Vhffs::Panel::Main();
-exit 0 unless $panel;
-my $session = $panel->get_session;
-exit 0 unless $session;
-
-my $vhffs = $panel->{vhffs};
-my $templatedir = $panel->{templatedir};
-my $user = $panel->{user};
-my $cgi = $panel->{cgi};
-
-my $oid = $cgi->param('oid');
-
-unless(defined $oid) {
-    $panel->render('misc/message.tt', { message => gettext('CGI Error !') } );
-}
-
-my $object = Vhffs::ObjectFactory::fetch_object( $vhffs , $oid );
-unless(defined $object) {
-	$panel->render('misc/message.tt', { message => gettext('This object does not exist') } );
-}
-
-unless($object->get_status == Vhffs::Constants::VALIDATION_REFUSED )  {
-    $panel->render('misc/message.tt', { message => gettext('This object is not in refused state') } );
-}
-
-unless($object->get_owner_uid == $user->get_uid )  {
-    $panel->render('misc/message.tt', { message => gettext('You are not allowed to do it, you don\'t own this object') } );
-}
-
-my $submitted = $cgi->param('submitted');
-
-if( $submitted && $object ) {
-
-	my $description = Encode::decode_utf8( $cgi->param('description') );
-	unless( defined $description ) {
-		$panel->add_error( gettext('CGI Error !') );
-	} elsif( $description =~ /^\s*$/ ) {
-		$panel->add_error( gettext('You must enter a description') );
-	} elsif ( $object->resubmit_for_moderation( $description ) ) {
-		my $url;
-		if( $object->get_type == Vhffs::Constants::TYPE_GROUP ) {
-			$url = '/group/index.pl?msg='.gettext('The new description has been submitted');
-		} else {
-			my $group = Vhffs::Group::get_by_gid( $vhffs , $object->get_owner_gid );
-			$url = '/group/view.pl?group='.$group->get_groupname.'&msg='.gettext('The new description has been submitted');
-		}
-		$panel->redirect( $url );
-	}
-	else {
-		$panel->add_error( gettext('An error occured while updating this object.') );
-	}
-}
-
-
-$panel->set_title( gettext('Propose a new description') );
-my $vars = {
-    object => $object
-};
-$panel->render('object/resubmit.tt', $vars);
-

Deleted: trunk/vhffs-panel/object/upavatar.pl
===================================================================
--- trunk/vhffs-panel/object/upavatar.pl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/object/upavatar.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,103 +0,0 @@
-#!%PERL% 
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#   notice, this list of conditions and the following disclaimer.
-#2. Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in 
-#   the documentation and/or other materials provided with the 
-#   distribution.
-#3. Neither the name of vhffs nor the names of its contributors 
-#   may be used to endorse or promote products derived from this 
-#   software without specific prior written permission.
-#
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-
-use utf8;
-use POSIX qw(locale_h);
-use locale;
-use Locale::gettext;
-use CGI qw(:standard);
-use CGI::Session;
-use strict;
-
-use lib '%VHFFS_LIB_DIR%';
-use Vhffs::Panel::Main;
-use Vhffs::Panel::Avatar;
-
-my $panel = new Vhffs::Panel::Main();
-exit 0 unless $panel;
-my $session = $panel->get_session;
-exit 0 unless $session;
-
-my $data;
-			   
-my $vhffs = $panel->{'vhffs'};
-my $user = $panel->{'user'};
-my $cgi = $panel->{'cgi'};
-my $type;
-
-my $message;
-my $cgioid;
-my $filename;
-my $tmpfile;
-my @rstat;
-my $fsize;
-my $object;
-
-
-$cgioid = $cgi->param( 'OID' );
-$filename = $cgi->param( 'avatar' );
-$object = Vhffs::Object::get_by_oid( $vhffs , $cgioid );
-
-$message;
-
-if( $filename ) {
-	$tmpfile = $cgi->tmpFileName( $filename );	
-}
-
-# Commit all the changes for the current user
-if( $panel->use_avatars == 0 ) {
-	$message = gettext( "This platform does not provide avatar support" );
-} elsif( ! defined $cgioid ) {
-	$message = gettext( "Object-ID error" );
-} elsif( ! defined( $object ) ) {
-	$message = gettext( "Cannot find object" );
-} elsif( !$user->can_modify( $object ) ) {
-	$message = gettext( "No enough rights" );
-} else {
-	@rstat = stat ( $tmpfile );
-	$fsize = $rstat[7];
-
-	if( $filename !~ /\.[Pp][Nn][Gg]$/ ) {
-		$message .= gettext( "Filetype not supported, only png is supported" );
-	} elsif( $fsize > 20000 ) {
-		$message .= gettext( "Uploaded file is too big. The maximum size is 20 Kbytes." );
-	} else {
-		( $type ) = ( $filename =~ ( /\.([a-zA-Z]+$)/ ) );
-		if( ( Vhffs::Panel::Avatar::store_avatar( $vhffs , $object , $tmpfile , $type ) ) > 0 ) {
-			$message = gettext( "Successfully created or updated avatar" );
-		} else {
-			$message = gettext( "Error when uploading avatar for this object" );
-		}
-	}
-}
-
-$panel->render('misc/message.tt', { message => $message });

Deleted: trunk/vhffs-panel/panel.pl
===================================================================
--- trunk/vhffs-panel/panel.pl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/panel.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,69 +0,0 @@
-#!%PERL% -w
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#   notice, this list of conditions and the following disclaimer.
-#2. Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in 
-#   the documentation and/or other materials provided with the 
-#   distribution.
-#3. Neither the name of vhffs nor the names of its contributors 
-#   may be used to endorse or promote products derived from this 
-#   software without specific prior written permission.
-#
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-
-use utf8;
-use POSIX qw(locale_h);
-use locale;
-use Locale::gettext;
-use CGI;
-use CGI::Session;
-use strict;
-
-use lib '%VHFFS_LIB_DIR%';
-use Vhffs::Panel::Main;
-
-my $panel = new Vhffs::Panel::Main();
-exit 0 unless $panel;
-my $session = $panel->get_session;
-exit 0 unless $session;
-
-my $vhffs = $panel->{'vhffs'};
-my $user = $panel->{'user'};
-my $templatedir = $panel->{'templatedir'};
-
-my $vars = {};
-
-$panel->set_title( sprintf( gettext('Hello %s, welcome in VHFFS !'), $user->get_username() ) );
-
-# check groups quota
-my @overquota;
-foreach my $group ( @{$user->get_groups} ) {
-    my $quota = $group->get_quota;
-    my $curused = $group->get_quota_used;
-    if( $curused > $quota-$quota/10 ) {
-        push @overquota, $group->get_groupname;
-    }
-}
-
-$vars->{overquota} = \@overquota;
-
-$panel->render( 'misc/welcome.tt', $vars );

Deleted: trunk/vhffs-panel/subscribe.pl
===================================================================
--- trunk/vhffs-panel/subscribe.pl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/subscribe.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,231 +0,0 @@
-#!%PERL% -w
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#   notice, this list of conditions and the following disclaimer.
-#2. Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in 
-#   the documentation and/or other materials provided with the 
-#   distribution.
-#3. Neither the name of vhffs nor the names of its contributors 
-#   may be used to endorse or promote products derived from this 
-#   software without specific prior written permission.
-#
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-# subscribe.pl
-# Handle subscription for VHFFS
-# If the subscribe form has been submitted
-# we try to create the user, else display
-# the form. If there is an error we inform the
-# user and redisplay the form (already filled)
-#
-
-use strict;
-use utf8;
-use POSIX qw(locale_h);
-use CGI;
-use locale;
-use Locale::gettext;
-use Encode;
-use Captcha::reCAPTCHA;
-
-use lib '%VHFFS_LIB_DIR%';
-use Vhffs::User;
-use Vhffs::Functions;
-use Vhffs::Constants;
-use Vhffs::Panel::Main;
-
-my $panel = new Vhffs::Panel::Main();
-exit 0 unless $panel;
-
-my $vhffs = $panel->{'vhffs'};
-my $cgi = $panel->{'cgi'};
-
-my $submitted = $cgi->param( 'CREATE_SUBMIT' );
-my $message;
-
-my $usecaptcha = Vhffs::Functions::strtobool( $vhffs->get_config->get_panel->{'use_captcha'} );
-my $captcha_pubkey = $vhffs->get_config->get_panel->{'captcha_pubkey'};
-my $captcha_privkey = $vhffs->get_config->get_panel->{'captcha_privkey'};
-
-if( $vhffs->get_config->get_allow_subscribe == 0 )
-{
-	# Subscribe isn't allowed, inform user
-    $panel->render('misc/message.tt', { message => gettext('You cannot subscribe to VHFFS') }, 'anonymous.tt');
-	exit 0;
-}
-
-my $vars = {};
-
-if( defined $submitted ) {
-# don't check if form hasn't been submitted
-
-	# get filled in parameters
-	my $mail       = $cgi->param( "MAIL" );
-	my $username   = $cgi->param( "USERNAME" );
-	my $firstname  = Encode::decode_utf8( $cgi->param( "FIRSTNAME") );
-	my $lastname   = Encode::decode_utf8( $cgi->param( "LASTNAME" ) );
-	my $city       = Encode::decode_utf8( $cgi->param("CITY") );
-	my $zipcode    = Encode::decode_utf8( $cgi->param("ZIPCODE") );
-	my $country    = Encode::decode_utf8( $cgi->param("COUNTRY") );
-	my $address    = Encode::decode_utf8( $cgi->param("ADDRESS") );
-	my $newslettercheckbox = $cgi->param('NEWSLETTER');
-	$newslettercheckbox = ( defined $newslettercheckbox && $newslettercheckbox eq 'on' );
-
-	if( $usecaptcha ) {
-        my $captcha = new Captcha::reCAPTCHA();
-        my $challenge = $cgi->param('recaptcha_challenge_field');
-        my $response = $cgi->param('recaptcha_response_field');
-        my $result = $captcha->check_answer(
-            $captcha_privkey, $ENV{REMOTE_ADDR}, $challenge, $response);
-        unless( $result->{is_valid} ) {
-			$panel->add_error( gettext("Codes do not match"));
-        }
-	}
-
-	if( ! defined $username )
-	{
-		$panel->add_error( gettext("You must declare your username"));
-	}
-	if( ! Vhffs::User::check_username($username) )
-	{
-		$panel->add_error( gettext('Invalid username, it must contain between 3 and 12 alphanumeric characters, all in lowercase'));
-	}
-	if( ! defined $country )
-	{
-		$panel->add_error( gettext("You must declare your country"));
-	}
-	if( ! defined $city )
-	{
-		$panel->add_error( gettext("You must declare your city"));
-	}
-	if( ! defined $zipcode )
-	{
-		$panel->add_error( gettext("You must declare your zipcode"));
-	}
-	if( ! defined $firstname )
-	{
-		$panel->add_error( gettext("You must declare your firstname"));
-	}
-	if( ! defined $lastname )
-	{
-		$panel->add_error( gettext("You must declare your lastname"));
-	}
-	if( ( ! defined $mail ) || ( length( $mail ) < 6 ) )
-	{
-		$panel->add_error( gettext("You must declare your mail address"));
-	}
-	if( ! Vhffs::Functions::valid_mail( $mail ) )
-	{
-		$panel->add_error( gettext("You must declare a valid mail address"));
-	}
-	if( $zipcode !~ /^[\w\d\s\-]+$/ )
-	{
-		$panel->add_error( gettext("Your zipcode is not correct! Please enter a correct zipcode"));
-	}
-	if( $firstname !~ /^[^<>"]+$/ )
-	{
-         $panel->add_error( gettext("Please enter a correct firstname"));
-	}
-	if( $lastname !~ /^[^<>"]+$/ )
-	{
-         $panel->add_error( gettext("Please enter a correct lastname"));
-	}
-	if( $city !~ /^[^<>"]+$/ )
-	{
-         $panel->add_error( gettext("Please enter a correct city"));
-	}
-	if( $country =~ /^[<>"]+$/ )
-	{
-         $panel->add_error( gettext("Please enter a correct country"));
-	}
-
-	if( !$panel->has_errors )
-	{
-        my $user = Vhffs::User::create( $vhffs, $username, &Vhffs::Functions::generate_random_password(), 
-            0, $mail, $firstname, $lastname, $city, $zipcode, $country, $address, "");
-		
-		if(! defined $user )
-		{
-		    $panel->add_error( gettext("Cannot create user, the username you entered already exists") );
-		}
-		else
-		{
-		    #We set informations user fill in the form
-		    $user->set_status( Vhffs::Constants::WAITING_FOR_CREATION );
-		    
-		    #Commit all the changes for the current user
-		    if( $user->commit < 0 )
-		    {
-                $panel->add_error( gettext("Cannot apply changes to the user") );
-		    }
-		    else
-		    {
-                Vhffs::Acl::add_acl( $user , $user , Vhffs::Constants::ACL_DELETE , $vhffs );
-                Vhffs::Acl::add_acl( $user->get_group , $user , Vhffs::Constants::ACL_DENIED , $vhffs );
-
-                # Newsletter
-                if( $vhffs->get_config->get_service_availability('newsletter') ) {
-                    require Vhffs::Services::Newsletter;
-                    my $newsletter = init Vhffs::Services::Newsletter( $vhffs , $user );
-                    if( $newsletter ) {
-                        if(  ( $newsletter->get_collectmode == Vhffs::Services::Newsletter::ACTIVE_OPTIN && $newslettercheckbox )
-                          || ( $newsletter->get_collectmode == Vhffs::Services::Newsletter::PASSIVE_OPTIN && $newslettercheckbox )
-                          || ( $newsletter->get_collectmode == Vhffs::Services::Newsletter::ACTIVE_OPTOUT && !$newslettercheckbox )
-                          || ( $newsletter->get_collectmode == Vhffs::Services::Newsletter::PASSIVE_OPTOUT )
-                          || ( $newsletter->get_collectmode == Vhffs::Services::Newsletter::PERMANENT )
-                          ) {
-                            $newsletter->add;
-                        }
-                    }
-                }
-                $panel->render('anonymous/account_created.tt', $vars, 'anonymous.tt');
-                exit 0;
-		    }
-		}
-	}
-	if ( $panel->has_errors ) {
-        $vars->{username} = $username;
-        $vars->{mail} = $mail;
-        $vars->{firstname} = $firstname;
-        $vars->{lastname} = $lastname;
-        $vars->{zipcode} = $zipcode;
-        $vars->{city} = $city;
-        $vars->{country} = $country;
-        $vars->{address} = $address;
-        $vars->{newsletter_checked} = $newslettercheckbox;
-	}
-}
-
-if( ( ! defined $submitted ) || $panel->has_errors )  {
-	if( $usecaptcha ) {
-        $vars->{captcha_pubkey} = $captcha_pubkey;
-	}
-
-	if( $vhffs->get_config->get_service_availability('newsletter') ) {
-		my $conf = $vhffs->get_config->get_service('newsletter');
-        $vars->{newsletter} = {
-            prompt => ($conf->{'collectmode'} eq 'active_optout' ? gettext('Don\'t subscribe to the newsletter') : gettext('Subscribe to the newsletter') )
-        };
-        $vars->{newsletter_checked} = 1 if($conf->{'collectmode'} eq 'passive_optin' and !defined $submitted);
-	}
-
-    $panel->render('anonymous/subscribe.tt', $vars, 'anonymous.tt');
-}

Modified: trunk/vhffs-panel/templates/acl/form.tt
===================================================================
--- trunk/vhffs-panel/templates/acl/form.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/acl/form.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,10 +1,11 @@
 <h2>[% 'Access rights management for this object' | i18n | html %]</h2>
 
-<form method="post" action="/acl/view.pl" accept-charset="utf-8">
+<form method="post" action="?do=acl&amp;oid=[% object.get_oid %]" accept-charset="utf-8">
 	<p>[% 'You can adjust rights on this group for each user in the VHFFS database. Please read help before manage it.' | i18n | html %]</p>
-	<input type="hidden" name="target_oid" value="[% object.get_oid %]" />
+	<input type="hidden" name="oid" value="[% object.get_oid %]" />
 	<p class="button" id="buttonAclAdmin">
 		<input type="submit" value="[% 'OK, go to ACL management' | i18n | html %]" />
 	</p>
+	<input type="hidden" name="do" value="acl"/>
 </form>
 

Modified: trunk/vhffs-panel/templates/acl/view.tt
===================================================================
--- trunk/vhffs-panel/templates/acl/view.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/acl/view.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -13,7 +13,7 @@
   </p>
 </div>
 <div class="tablebody">
-  <form method="post" action="view.pl" accept-charset="utf-8">
+  <form method="post" action="#" accept-charset="utf-8">
     <p>
       <span><b>[% 'Default' | i18n | html %]</b></span>
       <span> </span>
@@ -23,14 +23,15 @@
       <span><input type="radio" name="perm[% default_acl.granted_oid %]" value="[% constants.acl.MANAGEACL %]"[% ' checked="checked"' IF default_acl.perm == constants.acl.MANAGEACL %]/></span>
       <span><input type="radio" name="perm[% default_acl.granted_oid %]" value="[% constants.acl.DELETE %]"[% ' checked="checked"' IF default_acl.perm == constants.acl.DELETE %]/></span>
       <span>
-        <input type="hidden" NAME="granted_oid" VALUE="[% default_acl.granted_oid %]" />
-        <input type="hidden" NAME="target_oid" VALUE="[% target.get_oid %]" />
+        <input type="hidden" name="granted_oid" VALUE="[% default_acl.granted_oid %]" />
+        <input type="hidden" name="oid" VALUE="[% target.get_oid %]" />
         <input type="submit" value="[% 'Modify' | i18n | html %]" name="update_acl_submit"/>
       </span>
     </p>
+    <input type="hidden" name="do" value="acl"/>
   </form>
 [% FOREACH acl IN users_acl %]
-  <form method="post" action="view.pl" accept-charset="utf-8">
+  <form method="post" action="#" accept-charset="utf-8">
     <p>
       <span>[% acl.name %]</span>
       <span><input type="radio" name="perm[% acl.granted_oid %]" value="[% constants.acl.UNDEFINED %]"[% ' checked="checked"' IF acl.perm == constants.acl.UNDEFINED %]/></span>
@@ -40,11 +41,12 @@
       <span><input type="radio" name="perm[% acl.granted_oid %]" value="[% constants.acl.MANAGEACL %]"[% ' checked="checked"' IF acl.perm == constants.acl.MANAGEACL %]/></span>
       <span><input type="radio" name="perm[% acl.granted_oid %]" value="[% constants.acl.DELETE %]"[% ' checked="checked"' IF acl.perm == constants.acl.DELETE %]/></span>
       <span>
-        <input type="hidden" NAME="granted_oid" VALUE="[% acl.granted_oid %]" />
-        <input type="hidden" NAME="target_oid" VALUE="[% target.get_oid %]" />
+        <input type="hidden" name="granted_oid" VALUE="[% acl.granted_oid %]" />
+        <input type="hidden" name="oid" VALUE="[% target.get_oid %]" />
         <input type="submit" value="[% 'Modify' | i18n | html %]" name="update_acl_submit"/>
       </span>
     </p>
+    <input type="hidden" name="do" value="acl"/>
   </form>
 [% END %]
 <span class="clear">&nbsp;</span>

Modified: trunk/vhffs-panel/templates/admin/broadcast/create.tt
===================================================================
--- trunk/vhffs-panel/templates/admin/broadcast/create.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/admin/broadcast/create.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,16 +1,16 @@
 <h1>[% 'Send an email to all hosted people' | i18n | html %]</h1>
 
-<form class="table-like" method="post" action="/admin/broadcast/create.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
 	<p>
-		<label for="SUBJECT">[% 'Subject:' | i18n | html %]</label>
-		<input type="text" name="SUBJECT" id="SUBJECT" value="[% subject | html %]"/>
+		<label for="subject">[% 'Subject:' | i18n | html %]</label>
+		<input type="text" name="subject" id="subject" value="[% subject | html %]"/>
 	</p>
 	<p>
-		<label for="BODY">[% 'Message:' | i18n | html %]</label>
-		<textarea name="BODY" id="BODY" cols="60" rows="30">[% body | html %]</textarea>
+		<label for="body">[% 'Message:' | i18n | html %]</label>
+		<textarea name="body" id="body" cols="60" rows="30">[% body | html %]</textarea>
 	</p>
 	<p class="button" id="buttonSend">
 		<input type="submit" value="[% 'Send' | i18n | html %]" />
 	</p>
+	<input type="hidden" name="do" value="broadcastcreate"/>
 </form>
-

Modified: trunk/vhffs-panel/templates/admin/broadcast/list.tt
===================================================================
--- trunk/vhffs-panel/templates/admin/broadcast/list.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/admin/broadcast/list.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -20,13 +20,15 @@
     <td class="mainColumn">[% m.body | truncate(200) | html_para %]</td>
 	<td>[% m.state %]</td>
 	<td>
-		<form method="post" action="/admin/broadcast/delete.pl" accept-charset="utf-8">
-			<p><input type="hidden" name="ID" value="[% m.id %]" />
+		<form method="post" action="?do=broadcastdelete&amp;mid=[% m.id %]" accept-charset="utf-8">
+			<p><input type="hidden" name="mid" value="[% m.id %]" />
 			<input type="submit" value="[% 'Delete' | i18n | html %]" /></p>
+			<input type="hidden" name="do" value="broadcastdelete"/>
 		</form>
-		<form method="post" action="/admin/broadcast/view.pl" accept-charset="utf-8">
-			<p><input type="hidden" name="ID" value="[% m.id %]" />
+		<form method="post" action="?do=broadcastview&amp;mid=[% m.id %]" accept-charset="utf-8">
+			<p><input type="hidden" name="mid" value="[% m.id %]" />
 			<input type="submit" value="[% 'View' | i18n | html %]" /></p>
+			<input type="hidden" name="do" value="broadcastview"/>
 		</form>
 	</td>
 </tr>

Modified: trunk/vhffs-panel/templates/admin/group/list.tt
===================================================================
--- trunk/vhffs-panel/templates/admin/group/list.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/admin/group/list.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -16,7 +16,7 @@
             <td>[% g.groupname | html %]</td>
             <td>[% g.owner_user | html %]</td>
             <td>[% g.state | stringify_status | html %]</td>
-            <td><a href="/group/prefs.pl?group=[% g.groupname | html %]">[% 'Preferences' | i18n | html %]</a></td>
+            <td><a href="?do=groupprefs&amp;group=[% g.groupname | html %]">[% 'Preferences' | i18n | html %]</a></td>
         </tr>
 [% END %]
     </tbody>

Modified: trunk/vhffs-panel/templates/admin/misc/list.tt
===================================================================
--- trunk/vhffs-panel/templates/admin/misc/list.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/admin/misc/list.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -18,7 +18,7 @@
             <td>[% o.owner_user | html %]</td>
             <td>[% o.owner_group | html %]</td>
             <td>[% o.state | stringify_status | html %]</td>
-            <td><a href="/[% type %]/prefs.pl?name=[% o.label %]">[% 'Preferences' | i18n | html %]</a></td>
+            <td><a href="?do=[% type %]prefs&amp;name=[% o.label %]">[% 'Preferences' | i18n | html %]</a></td>
         </tr>
 [% END %]
     </tbody>

Deleted: trunk/vhffs-panel/templates/admin/misc/mailings_part.tmpl
===================================================================
--- trunk/vhffs-panel/templates/admin/misc/mailings_part.tmpl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/admin/misc/mailings_part.tmpl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,32 +0,0 @@
-<tr>
-	<td>
-		<TMPL_VAR ESCAPE=1 NAME="NAME">
-	</td>
-	<td>
-		<TMPL_VAR ESCAPE=1 NAME="OWNER"> 
-	</td>
-	<td>
-		<TMPL_VAR ESCAPE=1 NAME="GROUP">
-	</td>
-	<td class="mainColumn">
-		<TMPL_VAR ESCAPE=1 NAME="DESCRIPTION"> 
-	</td>
-	<td>
-		<form method="post" action="moderation/submit.pl" accept-charset="utf-8">
-			<input type="hidden" name="OID" value="<TMPL_VAR ESCAPE=1 NAME="OID">" />
-			<input type="hidden" name="UID_ASKER" value="<TMPL_VAR ESCAPE=1 NAME="UID_ASKER">" />
-			<input type="hidden" name="ACCEPT" value="1" />
-			<input type="submit" value="<TMPL_VAR ESCAPE=1 NAME="ACCEPT">" />
-		</form>
-	</td>
-	<td>
-
-		<form method="post" action="moderation/submit.pl" accept-charset="utf-8">
-			<textarea name="reason" cols="30" rows="4"></textarea>
-			<input type="hidden" name="OID" value="<TMPL_VAR ESCAPE=1 NAME="OID">" />
-			<input type="hidden" name="UID_ASKER" value="<TMPL_VAR ESCAPE=1 NAME="UID_ASKER">" />
-			<input type="hidden" name="ACCEPT" value="0" />
-			<input type="submit" value="<TMPL_VAR ESCAPE=1 NAME="REFUSE">" />
-		</form>
-	</td>
-</tr>

Modified: trunk/vhffs-panel/templates/admin/misc/search.tt
===================================================================
--- trunk/vhffs-panel/templates/admin/misc/search.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/admin/misc/search.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,4 +1,5 @@
 <h1>[% search_title | html %]</h1>
-<form method="post" action="list.pl" accept-charset="utf-8">
-    <p><input type="text" name="NAME"/><input type="submit" value="[% 'Search' | i18n | html %]"/></p>
+<form method="post" action="?do=[% type %]search" accept-charset="utf-8">
+    <p><input type="text" name="name"/><input type="submit" value="[% 'Search' | i18n | html %]"/></p>
+    <input type="hidden" name="do" value="[% type %]search"/>
 </form>

Modified: trunk/vhffs-panel/templates/admin/misc/su.tt
===================================================================
--- trunk/vhffs-panel/templates/admin/misc/su.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/admin/misc/su.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,9 +1,10 @@
 <h1>[% 'Change user ID' | i18n | html %]</h1>
 
-<form class="table-like" method="post" action="/admin/su.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
 	<p><label for="TEXT">[% 'Username:' | i18n | html %]</label>
 		<input type="text" name="user" id="user" /></p>
 	<p class="button" id="buttonSend">
 		<input type="submit" value="[% 'Su!' | i18n | html %]" />
 	</p>
+	<input type="hidden" name="do" value="su"/>
 </form>

Modified: trunk/vhffs-panel/templates/admin/moderation/index.tt
===================================================================
--- trunk/vhffs-panel/templates/admin/moderation/index.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/admin/moderation/index.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -15,17 +15,18 @@
         <tr>
             <td>[% o.type | stringify_type | i18n | html %]</td>
             <td>[% o.label | html %]</td>
-            <td><a href="/user/prefs.pl?name=[% o.get_user.get_username | html %]">[% o.get_user.get_username | html %]</a>
+            <td><a href="?do=userprefs&amp;name=[% o.get_user.get_username | html %]">[% o.get_user.get_username | html %]</a>
                 [% '(' _ o.get_user.get_note _ ')' IF use_notation %]</td>
-            <td><a href="/group/view.pl?group=[% o.get_group.get_groupname | html %]">[% o.get_group.get_groupname | html %]</a></td>
+            <td><a href="?do=groupview&amp;group=[% o.get_group.get_groupname | html %]">[% o.get_group.get_groupname | html %]</a></td>
             <td class="mainColumn">[% o.get_description | html_para %]</td>
             <td>
-                <form action="/admin/moderation/index.pl" method="post" accept-charset="utf-8">
+                <form action="?do=moderation" method="post" accept-charset="utf-8">
                    <p><textarea name="message" cols="30" rows="4"></textarea></p>
                    <p>
                     <input type="hidden" name="oid" value="[% o.get_oid %]"/>
                     <input type="submit" name="accept" value="[% 'Accept' | i18n | html %]"/>
                     <input type="submit" name="refuse" value="[% 'Refuse' | i18n | html %]"/></p>
+                    <input type="hidden" name="do" value="moderation"/>
                 </form>
             </td>
         </tr>

Modified: trunk/vhffs-panel/templates/admin/object/edit.tt
===================================================================
--- trunk/vhffs-panel/templates/admin/object/edit.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/admin/object/edit.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,7 +1,7 @@
 [% USE date %]
 <h1>[% 'Object administration' | i18n | html %]</h1>
 	
-<form class="table-like" method="post" action="/admin/object/edit.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
 	<p>
 		<label>[% 'Object ID:' | i18n | html %]</label>
 		[% object.get_oid %]
@@ -15,8 +15,8 @@
             [% object.get_date ? date.format(object.get_date, '%x %X') : 'N/A' %]
 	</p>
 	<p>
-		<label for="STATUS">[% 'Status:' | i18n | html %]</label>
-			<select name="STATUS" id="STATUS">
+		<label for="status">[% 'Status:' | i18n | html %]</label>
+			<select name="status" id="status">
 				<option value="[% constants.object_statuses.WAITING_FOR_VALIDATION %]"[% ' selected="selected"' IF object.get_status == constants.object_statuses.WAITING_FOR_VALIDATION %]>
                     [% 'Waiting for validation' | i18n | html %]</option>
 				<option value="[% constants.object_statuses.VALIDATION_REFUSED %]"[% ' selected="selected"' IF object.get_status == constants.object_statuses.VALIDATION_REFUSED %]>
@@ -49,10 +49,10 @@
 	</p>
 
 	<p class="button" id="buttonSend">
-		<input type="hidden" name="OID" value="[% object.get_oid %]" />
+		<input type="hidden" name="oid" value="[% object.get_oid %]" />
 		<input type="submit" value="[% 'Update' | i18n | html %]" />
 	</p>
-
+	<input type="hidden" name="do" value="objectedit"/>
 </form>
 
 <h2>[% 'Object history' | i18n | html %]</h2>
@@ -61,6 +61,6 @@
 
 [% IF use_avatars %]
 <h2>[% 'Avatar management' | i18n | html %]</h2>
-<p><a href="delete_avatar.pl?OID=[% object.get_oid %]">[% 'Delete avatar for this object' | i18n | html %]</a></p>
+<p><a href="?do=avatardelete&amp;oid=[% object.get_oid %]">[% 'Delete avatar for this object' | i18n | html %]</a></p>
 [% END %]
 

Modified: trunk/vhffs-panel/templates/admin/object/list.tt
===================================================================
--- trunk/vhffs-panel/templates/admin/object/list.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/admin/object/list.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -18,7 +18,7 @@
             <td>[% o.owner_user | html %]</td>
             <td>[% o.owner_group | html %]</td>
             <td>[% o.state | stringify_status | html %]</td>
-            <td><a href="/admin/object/edit.pl?OID=[% o.oid %]">[% 'Edit' | i18n | html %]</a></td>
+            <td><a href="?do=objectedit&amp;oid=[% o.oid %]">[% 'Edit' | i18n | html %]</a></td>
         </tr>
 [% END %]
     </tbody>

Modified: trunk/vhffs-panel/templates/admin/user/list.tt
===================================================================
--- trunk/vhffs-panel/templates/admin/user/list.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/admin/user/list.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -16,7 +16,7 @@
             <td>[% u.username | html %]</td>
             <td>[% u.realname | html %]</td>
             <td>[% u.state | stringify_status | html %]</td>
-            <td><a href="/user/prefs.pl?name=[% u.username %]">[% 'Preferences' | i18n | html %]</a></td>
+            <td><a href="?do=userprefs&amp;name=[% u.username %]">[% 'Preferences' | i18n | html %]</a></td>
         </tr>
 [% END %]
     </tbody>

Modified: trunk/vhffs-panel/templates/anonymous/account_created.tt
===================================================================
--- trunk/vhffs-panel/templates/anonymous/account_created.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/anonymous/account_created.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -2,5 +2,5 @@
 <div class="login">
     <h1>[% 'Account successfully created' | i18n | html %]</h1>
     <p class="info">[% 'Your registration request as been sent. Please wait while we\'re creating you account, it may take several minutes.' | i18n | html %]</p>
-    <p class="button"><a href="/auth.pl">[% 'Back to login' %]</a></p>
+    <p class="button"><a href="?do=login">[% 'Back to login' %]</a></p>
 </div>

Modified: trunk/vhffs-panel/templates/anonymous/login.tt
===================================================================
--- trunk/vhffs-panel/templates/anonymous/login.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/anonymous/login.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,18 +1,18 @@
 		<div class="misc" id="misc">
-            [% IF website.defined() %]
-                [% website = website | html %]
-                <h1>[% 'Welcome on %s' | i18n | pretty_print('<a href="' _ website _ '">' _ hostname _ '</a>') %]</h1>
-            [% ELSE %]
-                <h1>[% 'Welcome on %s' | i18n | pretty_print(hostname) %]</h1>
-            [% END %]
+	[% IF website.defined() %]
+		[% website = website | html %]
+		<h1>[% 'Welcome on %s' | i18n | pretty_print('<a href="' _ website _ '">' _ hostname _ '</a>') %]</h1>
+	[% ELSE %]
+		<h1>[% 'Welcome on %s' | i18n | pretty_print(hostname) %]</h1>
+	[% END %]
 			
-			<form id="login-form" class="table-like" action="/auth.pl" method="post" accept-charset="utf-8">
+			<form id="login-form" class="table-like" action="?do=login" method="post" accept-charset="utf-8">
 			<h2>[% 'Please enter your username and password' | i18n %]</h2>
-                [% INCLUDE 'misc/errors.tt' %]
-                [% INCLUDE 'misc/infos.tt' %]
+		[% INCLUDE 'misc/errors.tt' %]
+		[% INCLUDE 'misc/infos.tt' %]
 				<p>
 					<label for="login-username">
-                        [% 'Username' | i18n | html %]
+			[% 'Username' | i18n | html %]
 					</label>
 					<input type="text" class="validation-identifier" tabindex="1" name="username" id="login-username" maxlength="32" value="[% username | html %]"/>
 				</p>
@@ -25,25 +25,26 @@
 				<p class="button">
 					<input type="submit" tabindex="3" value="[% 'Access to panel' | i18n %]" id="login-submit" name="login_submit"/>
 				</p>
+				<input type="hidden" name="do" value="login"/>
 			</form>
 			<div id="sub_opts">
 			<ul>
-                [% IF subscription_allowed %]
+		[% IF subscription_allowed %]
 				<li>
-				<a class="loginLinks" href="/subscribe.pl">[% 'Subscribe' | i18n %]</a>
+				<a class="loginLinks" href="?do=subscribe">[% 'Subscribe' | i18n %]</a>
 				</li>
 				[% END %]
 				
 				<li>
-				<a class="loginLinks" href="/lost.pl">[% 'I\'ve lost my password' | i18n %]</a>
+				<a class="loginLinks" href="?do=lost">[% 'I\'ve lost my password' | i18n %]</a>
 				</li>
 			</ul>
 			</div>
 		</div>
 
 		<div class="foothome">
-        [% IF stats.defined() %]
-            <p>[% 'Woah, %s users and %s groups already trust %s' | i18n | pretty_print(stats.users, stats.groups, hostname) | html %]</p>
-        [% END %]
+	[% IF stats.defined() %]
+	<p>[% 'Woah, %s users and %s groups already trust %s' | i18n | pretty_print(stats.users, stats.groups, hostname) | html %]</p>
+	[% END %]
 		</div>
-        <script type="text/javascript" charset="utf-8" src="/js/vhffs/anonymous/login.js"></script>
+	<script type="text/javascript" charset="utf-8" src="/js/vhffs/anonymous/login.js"></script>

Modified: trunk/vhffs-panel/templates/anonymous/lost-password-ack.tt
===================================================================
--- trunk/vhffs-panel/templates/anonymous/lost-password-ack.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/anonymous/lost-password-ack.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,5 +1,5 @@
 <div class="logo"></div>
 <div class="misc" id="misc">
     <h1>[% message %]</h1>
-    <p class="button"><a href="/auth.pl">[% 'Back to login' | i18n | html %]</a></p>
+    <p class="button"><a href="?do=login">[% 'Back to login' | i18n | html %]</a></p>
 </div>

Modified: trunk/vhffs-panel/templates/anonymous/lost-password.tt
===================================================================
--- trunk/vhffs-panel/templates/anonymous/lost-password.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/anonymous/lost-password.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -5,7 +5,7 @@
 		
 <h1>[% 'You lost your password? You\'re a bad guy!' | i18n | html %]</h1>
 
-<form class="table-like" action="/lost_ack.pl" method="post" accept-charset="utf-8">
+<form class="table-like" action="?lost" method="post" accept-charset="utf-8">
 <p>[% 'But fortunately we\'re smart, so just type your login here and a new password will be sent to you by email!' | i18n | html %]</p>
 <p>
 	<label for="username">
@@ -14,12 +14,13 @@
 	<input type="text" name="username" id="username" maxlength="32"/>
 </p>
 <p class="button">
-	<input type="submit" value="[% 'Give me a new password!' | i18n | html %]" />
+	<input type="submit" value="[% 'Give me a new password!' | i18n | html %]" id="lost-submit" name="lost_submit"/>
 </p>
+<input type="hidden" name="do" value="lost"/>
 </form>
 
 <p>
-	<a href="/auth.pl">[% 'Back to login page' | i18n | html %]</a>
+	<a href="?do=login">[% 'Back to login page' | i18n | html %]</a>
 </p>
 
 </div>

Modified: trunk/vhffs-panel/templates/anonymous/subscribe.tt
===================================================================
--- trunk/vhffs-panel/templates/anonymous/subscribe.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/anonymous/subscribe.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -3,46 +3,46 @@
 			<h1>[% 'Subscription' | i18n | html %]</h1>
                 <p class="info">[% 'Please fill in all fields, you\'ll be sent a mail containing your password' | i18n | html %]</p>
                 <div class="subscribe">
-                <form id="subscribe-form" class="table-like" method="post" action="subscribe.pl" accept-charset="utf-8">
+                <form id="subscribe-form" class="table-like" method="post" action="?do=subscribe" accept-charset="utf-8">
                 [% INCLUDE 'misc/errors.tt' %]
 				<p>
 					<label for="subscribe-username">[% 'Username:' | i18n | html %]</label>
-					<input type="text" class="validation-identifier" name="USERNAME" id="subscribe-username" maxlength="12" value="[% username | html %]"/>
+					<input type="text" class="validation-identifier" name="username" id="subscribe-username" maxlength="12" value="[% username | html %]"/>
                 </p>
 				<p>
 					<label for="subscribe-email">[% 'Email:' | i18n | html %]</label>
-					<input type="text" class="validation-email" name="MAIL" id="subscribe-email" maxlength="200" value="[% mail | html %]"/>
+					<input type="text" class="validation-email" name="mail" id="subscribe-email" maxlength="200" value="[% mail | html %]"/>
 				</p>
 				<p>
 					<label for="subscribe-firstname">[% 'Firstname:' | i18n | html %]</label>
-                    <input type="text" class="validation-string" name="FIRSTNAME" id="subscribe-firstname" maxlength="256" value="[% firstname | html %]"/>
+                    <input type="text" class="validation-string" name="firstname" id="subscribe-firstname" maxlength="256" value="[% firstname | html %]"/>
 				</p>
 				<p>
 					<label for="subscribe-lastname">[% 'Lastname: ' | i18n | html %]</label>
-                    <input type="text" class="validation-string" name="LASTNAME" id="subscribe-lastname" maxlength="256" value="[% lastname | html %]"/>
+                    <input type="text" class="validation-string" name="lastname" id="subscribe-lastname" maxlength="256" value="[% lastname | html %]"/>
 				</p>
 				<p>
 					<label for="subscribe-address">[% 'Address:' | i18n | html %]</label>
-                    <input type="text" class="validation-string" name="ADDRESS" id="subscribe-address" maxlength="512" value="[% address | html %]"/>
+                    <input type="text" class="validation-string" name="address" id="subscribe-address" maxlength="512" value="[% address | html %]"/>
 				</p>
 				<p>
 					<label for="subscribe-city">[% 'City:' | i18n | html %]</label>
-                    <input type="text" class="validation-string" name="CITY" id="subscribe-city" maxlength="64" value="[% city | html %]"/>
+                    <input type="text" class="validation-string" name="city" id="subscribe-city" maxlength="64" value="[% city | html %]"/>
 				</p>
 				<p>
 					<label for="subscribe-country">[% 'Country:' | i18n | html %]</label>
-                    <input type="text" class="validation-string" name="COUNTRY" id="subscribe-country" maxlength="32" value="[% country | html %]"/>
+                    <input type="text" class="validation-string" name="country" id="subscribe-country" maxlength="32" value="[% country | html %]"/>
 				</p>
 				<p>
 					<label for="subscribe-zipcode">[% 'Zipcode' | i18n | html %]</label>
-					<input type="text" class="validation-zipcode" name="ZIPCODE" id="subscribe-zipcode" maxlength="16" value="[% zipcode | html %]"/>
+					<input type="text" class="validation-zipcode" name="zipcode" id="subscribe-zipcode" maxlength="16" value="[% zipcode | html %]"/>
 				</p>
 [% IF newsletter %]
 				<p>
-					<label for="NEWSLETTER">
+					<label for="newsletter">
                         [% newsletter.prompt | html %]
 					</label>
-					<span><input type="checkbox" name="NEWSLETTER" id="NEWSLETTER"[% ' checked="checked"' IF newsletter_checked %]/></span>
+					<span><input type="checkbox" name="newsletter" id="newsletter"[% ' checked="checked"' IF newsletter_checked %]/></span>
 				</p>
 [% END %]
 [% IF captcha_pubkey %]
@@ -61,11 +61,12 @@
                 </noscript>
 [% END %]
 				<p class="button" style="clear:both">
-					<input type="submit" value="[% 'Subscribe' | i18n | html %]" name="CREATE_SUBMIT"/>
+					<input type="submit" value="[% 'Subscribe' | i18n | html %]" name="create_submit"/>
 				</p>
+			<input type="hidden" name="do" value="subscribe"/>
 			</form>
 			</div>
-		    <p class="home"><a href="/auth.pl">[% 'Back to login' %]</a></p>
+		    <p class="home"><a href="?do=login">[% 'Back to login' %]</a></p>
 		</div>
         <script type="text/javascript" charset="utf-8" src="/js/vhffs/anonymous/subscribe.js"></script>
 </div>

Deleted: trunk/vhffs-panel/templates/bazaar/create.tmpl
===================================================================
--- trunk/vhffs-panel/templates/bazaar/create.tmpl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/bazaar/create.tmpl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,24 +0,0 @@
-<form class="table-like" method="post" action="#" accept-charset="utf-8">
-	<p>
-		<label>		
-			<TMPL_VAR ESCAPE=1 NAME="GROUP_NAME">: 
-		</label>
-		<TMPL_VAR ESCAPE=1 NAME="GROUP">
-	</p>
-	<p>
-		<label for="reponame">
-			<TMPL_VAR ESCAPE=1 NAME="REPOSITORY_NAME">: 
-		</label>	
-		<TMPL_VAR ESCAPE=1 NAME="GROUP">/<input type="text" name="reponame" id="reponame" value="<TMPL_VAR ESCAPE=1 NAME="REPOSITORY_VALUE">"/>
-	</p>
-	<p>
-		<label for="PROJECT_USAGE">
-			<TMPL_VAR ESCAPE=1 NAME="description">:
-		</label>
-		<textarea name="description" id="description"  cols="45" rows="7"><TMPL_VAR ESCAPE=1 NAME="DESCRIPTION_VALUE"></textarea>
-	</p>
-	<p class="button" id="buttonSend">
-		<input type="hidden" name="group" value="<TMPL_VAR ESCAPE=1 NAME="GROUP">" />
-		<input type="submit" value="<TMPL_VAR ESCAPE=1 NAME="SEND">" name="bazaar_submit"/>
-	</p>
-</form>

Modified: trunk/vhffs-panel/templates/bazaar/create.tt
===================================================================
--- trunk/vhffs-panel/templates/bazaar/create.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/bazaar/create.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -15,4 +15,5 @@
 		<input type="hidden" name="group" value="[% group.get_groupname | html %]" />
 		<input type="submit" value="[% 'Send' | i18n | html %]" name="bazaar_submit"/>
 	</p>
+	<input type="hidden" name="do" value="bazaarcreate"/>
 </form>

Modified: trunk/vhffs-panel/templates/cron/create.tt
===================================================================
--- trunk/vhffs-panel/templates/cron/create.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/cron/create.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -27,5 +27,5 @@
 		<input type="hidden" name="group" value="[% group.get_groupname %]" />
 		<input type="submit" value="[% 'Send' | i18n | html %]" name="cron_submit"/>
 	</p>
+	<input type="hidden" name="do" value="croncreate"/>
 </form>
- 

Modified: trunk/vhffs-panel/templates/cron/prefs.tt
===================================================================
--- trunk/vhffs-panel/templates/cron/prefs.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/cron/prefs.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,7 +1,7 @@
 [% USE date %]
 <fieldset>
 <legend>[% 'Options' | i18n | html %]</legend>
-<form class="table-like" method="post" action="/cron/prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
 	<p>
 		<label for="name">[% 'Path:' | i18n | html %]</label>
         [% cron.cronpath | html %]
@@ -50,6 +50,7 @@
 	<p class="button">
 		<input type="submit" value="[% 'Update' | i18n | html %]" name="save_prefs_submit"/>
 	</p>
+	<input type="hidden" name="do" value="cronprefs"/>
 </form>
 </fieldset>
 

Modified: trunk/vhffs-panel/templates/cvs/create.tt
===================================================================
--- trunk/vhffs-panel/templates/cvs/create.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/cvs/create.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -15,4 +15,5 @@
 		<input type="hidden" name="group" value="[% group.get_groupname | html %]" />
 		<input type="submit" value="[% 'Send' | i18n | html %]" name="cvs_submit"/>
 	</p>
+	<input type="hidden" name="do" value="cvscreate"/>
 </form>

Modified: trunk/vhffs-panel/templates/database/prefs.tt
===================================================================
--- trunk/vhffs-panel/templates/database/prefs.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/database/prefs.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,4 +1,4 @@
-<form class="table-like" method="post" action="/[% type | html %]/prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="?do=[% type | html %]prefs&amp;name=[% db.get_dbname | html %]" accept-charset="utf-8">
 	<p>
 		<label>[% 'Name of the database:' | i18n | html %]</label>
 		[% db.get_dbname | html %]
@@ -16,6 +16,7 @@
         <input type="hidden" name="name" value="[% db.get_dbname | html %]"/>
 		<input type="submit" value="[% 'Update' | i18n | html %]" name="save_prefs_submit"/>
 	</p>
+	<input type="hidden" name="do" value="[% type | html %]prefs"/>
 </form>
 
 [% INCLUDE 'acl/form.tt' 

Modified: trunk/vhffs-panel/templates/dns/create.tt
===================================================================
--- trunk/vhffs-panel/templates/dns/create.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/dns/create.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,4 +1,4 @@
-<form class="table-like" method="post" action="create.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
 	<p>[% 'Be careful ! You must give the reason why you want to host this domain on our servers.' | i18n | html %]</p>
 [% IF help_url %]
     <p>[% 'Please read the %sdocumentation%s carefully before submitting your request' | i18n | html | pretty_print('<a href="' _ help_url _ '">', '</a>') %]</p>
@@ -24,4 +24,5 @@
 		<input type="hidden" name="group" value="[% group.get_groupname | html %]" />
 		<input type="submit" value="[% 'Send' | i18n | html %]" name="dns_submit" />
 	</p>
+	<input type="hidden" name="do" value="dnscreate"/>
 </form>

Modified: trunk/vhffs-panel/templates/dns/prefs.tt
===================================================================
--- trunk/vhffs-panel/templates/dns/prefs.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/dns/prefs.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -8,25 +8,26 @@
 [% END %]
 
 [% FOREACH a IN sorted_a %]
-<form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
     <p>
         <label for="data_[% a.id %]">[% (a.name == '@' ? dns.get_domain : a.name) | html %]-&gt;</label>
         <input type="text" name="data" id="data_[% a.id %]" value="[% a.data | html %]" />
-        <input type="hidden" name="domain" value="[% a.domain | html %]" />
+        <input type="hidden" name="name" value="[% dns.get_domain | html %]" />
         <input type="hidden" name="rr_id" value="[% a.id %]" />
         <input type="hidden" name="action" value="manage_a"/>
         <input type="submit" value="[% 'Update' | i18n | html %]" class="autowidth" name="modify_a_submit" />
         <input type="submit" value="[% 'Delete' | i18n | html %]" name="delete_a_submit" class="autowidth"/>
     </p>
+    <input type="hidden" name="do" value="dnsprefs"/>
 </form>
 [% END # a In sorted_a %]
 
 <h3>[% 'Add a A record' | i18n | html %]</h3>
-<form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
     <p class="help">[% 'Use @ for ORIGIN (%s)' | i18n| pretty_print(dns.get_domain) | html %]</p>
 	<p>
 		<label for="add_a_prefix">[% 'Name for the record:' | i18n | html %]</label>
-		<input type="text" name="name"  id="add_a_prefix" /><strong>.[% dns.get_domain | html %]</strong>
+		<input type="text" name="namerr" id="add_a_prefix" /><strong>.[% dns.get_domain | html %]</strong>
 	</p>
 	<p>[% 'Use our servers as destination IP for this A record?' | i18n | html %]
 		<input type="radio" name="redirect" id="redirect_true" value="true" checked="checked"
@@ -41,10 +42,11 @@
 		<input type="text" name="data" id="add_a_data" />
 	</p>
 	<p class="button">
-		<input type="hidden" name="domain" value="[% dns.get_domain | html %]" />
+		<input type="hidden" name="name" value="[% dns.get_domain | html %]" />
         <input type="hidden" name="action" value="add_a"/>
 		<input type="submit" value="[% 'Add record' | i18n | html %]" />
 	</p>
+	<input type="hidden" name="do" value="dnsprefs"/>
 </form>
 
 <h2>[% 'AAAA records (name -> IPv6)' | i18n | html %]</h2>
@@ -57,25 +59,26 @@
 [% END %]
 
 [% FOREACH aaaa IN sorted_aaaa %]
-<form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
     <p>
     <label for="data_[% aaaa.id %]">[% (aaaa.name == '@' ? dns.get_domain : aaaa.name) | html %]-&gt;</label>
         <input type="text" name="data" id="data_[% aaaa.id %]" value="[% aaaa.data | html %]" />
-        <input type="hidden" name="domain" value="[% dns.get_domain | html %]"/>
+        <input type="hidden" name="name" value="[% dns.get_domain | html %]"/>
         <input type="hidden" name="rr_id" value="[% aaaa.id %]"/>
         <input type="hidden" name="action" value="manage_aaaa"/>
         <input type="submit" value="[% 'Update' | i18n | html %]" class="autowidth" name="modify_aaaa_submit" />
         <input type="submit" value="[% 'Delete' | i18n | html %]" name="delete_aaaa_submit" class="autowidth"/>
     </p>
+    <input type="hidden" name="do" value="dnsprefs"/>
 </form>
 [% END # aaaa IN sorted_aaaa %]
 
 <h3>[% 'Add a AAAA record' | i18n | html %]</h3>
-<form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
     <p class="help">[% 'Use @ for ORIGIN (%s)' | i18n| pretty_print(dns.get_domain) | html %]</p>
 	<p>
 		<label for="add_aaaa_prefix">[% 'Name for the record:' | i18n | html %]</label>
-		<input type="text" name="name" id="add_aaaa_prefix" /><strong>.[% dns.get_domain | html %]</strong>
+		<input type="text" name="namerr" id="add_aaaa_prefix" /><strong>.[% dns.get_domain | html %]</strong>
 	</p>
 	<p>[% 'Use our servers as destination IP for this AAAA record?' | i18n | html %]
 		<input type="radio" name="redirect" id="redirect_aaaa_true" value="true" checked="checked"
@@ -90,10 +93,11 @@
 		<input type="text" name="data" id="add_aaaa_data" />
 	</p>
 	<p class="button">
-		<input type="hidden" name="domain" value="[% dns.get_domain | html %]" />
+		<input type="hidden" name="name" value="[% dns.get_domain | html %]" />
         <input type="hidden" name="action" value="add_aaaa"/>
 		<input type="submit" value="[% 'Add record' | i18n | html %]" />
 	</p>
+	<input type="hidden" name="do" value="dnsprefs"/>
 </form>
 
 
@@ -105,26 +109,27 @@
 [% END %]
 
 [% FOREACH mx IN sorted_mx %]
-<form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
 <p><label for="data_[% mx.id %]">
     [% (mx.name == '@' ? dns.get_domain : mx.name) | html %] ([% 'Priority:' | i18n | html %] [% mx.aux | html %])-&gt;
 </label>
     <input type="text" name="data"  id="data_[% mx.id %]" value="[% mx.data | html %]" />
-    <input type="hidden" name="domain" value="[% dns.get_domain | html %]" />
+    <input type="hidden" name="name" value="[% dns.get_domain | html %]" />
     <input type="hidden" name="rr_id" value="[% mx.id %]" />
     <input type="hidden" name="action" value="manage_mx" />
     <input type="submit" value="[% 'Update' | i18n | html %]" name="modify_mx_submit" class="autowidth"/>
     <input type="submit" value="[% 'Delete' | i18n | html %]" name="delete_mx_submit" class="autowidth"/>
 </p>
+<input type="hidden" name="do" value="dnsprefs"/>
 </form>
 [% END %]
 
 <h3>[% 'Add a MX record' | i18n | html %]</h3>
-<form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
     <p class="help">[% 'Use @ for ORIGIN (%s)' | i18n| pretty_print(dns.get_domain) | html %]</p>
 	<p>
 		<label for="add_mx_prefix">[% 'Name of the record:' | i18n | html %]</label>
-		<input type="text" name="name" id="add_mx_prefix" value="@"/><strong>.[% dns.get_domain | html %]</strong>
+		<input type="text" name="namerr" id="add_mx_prefix" value="@"/><strong>.[% dns.get_domain | html %]</strong>
 	</p>
 	<p>
 		<label for="add_mx_data">[% 'MX name:' | i18n | html %]</label>
@@ -136,9 +141,10 @@
 	</p>
 	<p class="button">
         <input type="hidden" name="action" value="add_mx" />
-		<input type="hidden" name="domain" value="[% dns.get_domain | html %]" />
+		<input type="hidden" name="name" value="[% dns.get_domain | html %]" />
 		<input type="submit" value="[% 'Add record' | i18n | html %]" />
 	</p>
+<input type="hidden" name="do" value="dnsprefs"/>
 </form>
 
 
@@ -150,25 +156,26 @@
 [% END %]
 
 [% FOREACH cname IN sorted_cname %]
-<form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
 	<p>
 		<label for="data_[% cname.id %]">[% (cname.name == '@' ? dns.get_domain : cname.name) | html %]-&gt;</label>
 		<input type="text" name="data" id="data_[% cname.id %]"value="[% cname.data | html %]" />
         <input type="hidden" name="action" value="manage_cname" />
         <input type="hidden" name="rr_id" value="[% cname.id %]"/>
-		<input type="hidden" name="domain" value="[% dns.get_domain | html %]" />
+		<input type="hidden" name="name" value="[% dns.get_domain | html %]" />
 		<input type="submit" name="modify_cname_submit" value="[% 'Update' | i18n | html %]" class="autowidth" />
 		<input type="submit" name="delete_cname_submit" value="[% 'Delete' | i18n | html %]" class="autowidth" />
 	</p>
+	<input type="hidden" name="do" value="dnsprefs"/>
 </form>
 [% END %]
 
 <h3>[% 'Add a CNAME record' | i18n | html %]</h3>
 
-<form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
 	<p>
 		<label for="add_cname_name">[% 'Subdomain name:' | i18n | html %]</label>
-		<input type="text" name="name" id="add_cname_name" /><strong>.[% dns.get_domain | html %]</strong>
+		<input type="text" name="namerr" id="add_cname_name" /><strong>.[% dns.get_domain | html %]</strong>
 	</p>
 	<p>
 		<label for="add_cname_data">[% 'Destination:' | i18n | html %]</label>
@@ -176,9 +183,10 @@
 	</p>
 	<p class="button">
         <input type="hidden" name="action" value="add_cname" />
-		<input type="hidden" name="domain" value="[% dns.get_domain | html %]" />
+		<input type="hidden" name="name" value="[% dns.get_domain | html %]" />
 		<input type="submit" value="[% 'Add record' | i18n | html %]" />
 	</p>
+	<input type="hidden" name="do" value="dnsprefs"/>
 </form>
 
 <h2>[% 'NS records for this domain (nameservers)' | i18n | html %]</h2>
@@ -190,26 +198,28 @@
 [% END %]
 
 [% FOREACH ns IN sorted_ns %]
-<form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
 <p>
     <label>[% (ns.name == '@' ? dns.get_domain : ns.name) | html %] -&gt; [% ns.data | html %]</label>
     <input type="hidden" name="action" value="manage_ns" />
     <input type="hidden" name="rr_id" value="[% ns.id %]" />
-    <input type="hidden" name="domain" value="[% dns.domain | html %]" />
+    <input type="hidden" name="name" value="[% dns.domain | html %]" />
     <input type="submit" name="delete_ns_submit" value="[% 'Delete' | i18n | html %]" class="autowidth"/>
 </p>
+<input type="hidden" name="do" value="dnsprefs"/>
 </form>
 [% END %]
 
 <h3>[% 'Add a NS record' | i18n | html %]</h3>
-<form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
     <p><label for="add_ns_prefix">[% 'Name of the record:' | i18n | html %]</label>
-    <input type="text" name="name" id="add_ns_prefix"/><strong>.[% dns.get_domain | html %]</strong></p>
+    <input type="text" name="namerr" id="add_ns_prefix"/><strong>.[% dns.get_domain | html %]</strong></p>
     <p><label for="add_ns_data">[% 'Host of your name server:' | i18n | html %]</label>
     <input type="text" name="data" id="add_ns_data"/></p>
     <input type="hidden" name="action" value="add_ns"/>
-    <input type="hidden" name="domain" value="[% dns.get_domain | html %]"/>
+    <input type="hidden" name="name" value="[% dns.get_domain | html %]"/>
     <input type="submit" value="[% 'Add record' | i18n | html %]" class="autowidth"/>
+    <input type="hidden" name="do" value="dnsprefs"/>
 </form>
 
 <h2>[% 'SRV records (servers)' | i18n | html %]</h2>
@@ -220,26 +230,27 @@
 [% END %]
 
 [% FOREACH srv IN sorted_srv %]
-<form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
     <p>
     <label>[% srv.name | html %] -&gt;</label>
     <input type="text" name="host" id="host_[% srv.id %]" value="[% srv.host | html %]" title="[% 'Host' | i18n | html %]"/>
     <input type="text" name="port" id="port_[% srv.id %]" value="[% srv.port %]" maxlength="5" size="5" style="width:auto" title="[% 'Port' | i18n | html %]"/>
     <input type="text" name="aux" id="aux_[% srv.id %]" value="[% srv.aux %]" maxlength="5" size="5" style="width:auto" title="[% 'Priority' | i18n | html %]"/>
     <input type="text" name="weight" id="weight_[% srv.id %]" value="[% srv.weight %]" maxlength="5" size="5" style="width:auto" title="[% 'Weight' | i18n | html %]"/>
-        <input type="hidden" name="domain" value="[% dns.get_domain %]"/>
+        <input type="hidden" name="name" value="[% dns.get_domain %]"/>
         <input type="hidden" name="rr_id" value="[% srv.id %]" />
         <input type="hidden" name="action" value="manage_srv"/>
         <input type="submit" value="[% 'Update' | i18n | html %]" class="autowidth" name="modify_srv_submit" />
         <input type="submit" value="[% 'Delete' | i18n | html %]" name="delete_srv_submit" class="autowidth"/>
     </p>
+    <input type="hidden" name="do" value="dnsprefs"/>
 </form>
 [% END %]
 <h3>[% 'Add a SRV record' | i18n | html %]</h3>
-<form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
     <p class="help">[% 'Use @ for ORIGIN (%s)' | i18n| pretty_print(dns.get_domain) | html %]</p>
     <p><label for="add_srv_name">[% 'Record name:' | i18n | html %]</label>
-        <input type="text" name="name" id="add_srv_name" /><strong>.[% dns.get_domain | html %]</strong></p>
+        <input type="text" name="namerr" id="add_srv_name" /><strong>.[% dns.get_domain | html %]</strong></p>
     <p><label for="add_srv_protocol">[% 'Protocol:' | i18n | html %]</label>
         <input type="text" name="protocol" id="add_srv_protocol"/></p>
     <p><label for="add_srv_service">[% 'Service:' | i18n | html %]</label>
@@ -254,9 +265,10 @@
         <input type="text" name="weight" id="add_srv_weight" size="5" maxlength="5"/></p>
     <p class="button">
         <input type="hidden" name="action" value="add_srv" />
-        <input type="hidden" name="domain" value="[% dns.get_domain | html %]" />
+        <input type="hidden" name="name" value="[% dns.get_domain | html %]" />
         <input type="submit" value="[% 'Add record' | i18n | html %]" />
     </p>
+    <input type="hidden" name="do" value="dnsprefs"/>
 </form>
 
 <h2>[% 'TXT records for this domain (textual information)' | i18n | html %]</h2>
@@ -267,35 +279,37 @@
 [% END %]
 
 [% FOREACH txt IN sorted_txt %]
-<form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
     <p>
         <label for="data_[% txt.id %]">[% (txt.name == '@' ? dns.get_domain : txt.name) | html %]</label>
         <input type="text" name="data" id="data_[% txt.id %]" value="[% txt.data | html %]" />
-        <input type="hidden" name="domain" value="[% dns.get_domain | html %]" />
+        <input type="hidden" name="name" value="[% dns.get_domain | html %]" />
         <input type="hidden" name="rr_id" value="[% txt.id %]" />
         <input type="hidden" name="action" value="manage_txt"/>
         <input type="submit" value="[% 'Update' | i18n | html %]" class="autowidth" name="modify_txt_submit" />
         <input type="submit" value="[% 'Delete' | i18n | html %]" name="delete_txt_submit" class="autowidth"/>
     </p>
+    <input type="hidden" name="do" value="dnsprefs"/>
 </form>
 [% END %]
 
 <h3>[% 'Add a TXT record' | i18n | html %]</h3>
-<form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
     <p class="help">[% 'Use @ for ORIGIN (%s)' | i18n| pretty_print(dns.get_domain) | html %]</p>
 	<p>
 		<label for="add_txt_prefix">[% 'Record name:' | i18n | html %]</label>
-		<input type="text" name="name"  id="add_txt_prefix" /><strong>.[% dns.get_domain | html %]</strong>
+		<input type="text" name="namerr"  id="add_txt_prefix" /><strong>.[% dns.get_domain | html %]</strong>
 	</p>
 	<p>
 		<label for="add_txt_data">[% 'Textual information:' | i18n | html %]</label>
 		<textarea name="data" id="add_txt_data"></textarea>
 	</p>
 	<p class="button">
-		<input type="hidden" name="domain" value="[% dns.get_domain | html %]" />
+		<input type="hidden" name="name" value="[% dns.get_domain | html %]" />
         <input type="hidden" name="action" value="add_txt"/>
 		<input type="submit" value="[% 'Add record' | i18n | html %]" />
 	</p>
+	<input type="hidden" name="do" value="dnsprefs"/>
 </form>
 
 [% INCLUDE 'acl/form.tt' 

Modified: trunk/vhffs-panel/templates/git/create.tt
===================================================================
--- trunk/vhffs-panel/templates/git/create.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/git/create.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -15,4 +15,5 @@
 		<input type="hidden" name="group" value="[% group.get_groupname | html %]" />
 		<input type="submit" value="[% 'Send' | i18n | html %]" name="git_submit"/>
 	</p>
+	<input type="hidden" name="do" value="gitcreate"/>
 </form>

Modified: trunk/vhffs-panel/templates/group/create.tt
===================================================================
--- trunk/vhffs-panel/templates/group/create.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/group/create.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,4 +1,4 @@
-<form class="table-like" method="post" action="#" accept-charset="utf-8">
+<form class="table-like" method="post" action="?do=groupcreate" accept-charset="utf-8">
 	<p>
 		<label>[% 'Owner:' | i18n | html %]
 		</label>
@@ -40,4 +40,5 @@
 	<p class="button"  id="buttonSend">
 		<input type="submit" value="[% 'Send' | i18n %]" name="project_submit"/>
 	</p>
+	<input type="hidden" name="do" value="groupcreate"/>
 </form>

Modified: trunk/vhffs-panel/templates/group/index.tt
===================================================================
--- trunk/vhffs-panel/templates/group/index.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/group/index.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -4,12 +4,12 @@
 <ul>
 [% FOR p IN owned_projects %]
 [% IF p.active %]
-    <li><a href="/group/view.pl?group=[% p.groupname | html %]">[% p.groupname | html %]</a></li>
+    <li><a href="?do=groupview&amp;group=[% p.groupname | html %]">[% p.groupname | html %]</a></li>
 [% ELSE %]
     <li>[% p.groupname | html %]&nbsp;&mdash;&nbsp;[% p.state | html %]
     [% IF p.refused %]
-       - <a href="/object/resubmit.pl?oid=[% p.oid %]">[% 'Propose a new description' | i18n | html %]</a>
-       - <a href="/object/quickdelete.pl?oid=[% p.oid %]">[% 'Delete' | i18n | html %]</a>
+       - <a href="?do=objectresubmit&amp;oid=[% p.oid %]">[% 'Propose a new description' | i18n | html %]</a>
+       - <a href="?do=objectcancel&amp;oid=[% p.oid %]">[% 'Delete' | i18n | html %]</a>
     [% END %]
     </li>
 [% END %]
@@ -23,12 +23,12 @@
 <ul>
 [% FOR p IN contributed_projects %]
 [% IF p.active %]
-    <li><a href="/group/view.pl?group=[% p.groupname | html %]">[% p.groupname | html %]</a></li>
+    <li><a href="?do=groupview&amp;group=[% p.groupname | html %]">[% p.groupname | html %]</a></li>
 [% ELSE %]
     <li>[% p.groupname | html %]&nbsp;&mdash;&nbsp;[% p.state | html %]
     [% IF p.refused %]
-       - <a href="/object/resubmit.pl?oid=[% p.oid %]">[% 'Propose a new description' | i18n | html %]</a>
-       - <a href="/object/quickdelete.pl?oid=[% p.oid %]">[% 'Delete' | i18n | html %]</a>
+       - <a href="?do=objectresubmit&amp;oid=[% p.oid %]">[% 'Propose a new description' | i18n | html %]</a>
+       - <a href="?do=objectcancel&amp;oid=[% p.oid %]">[% 'Delete' | i18n | html %]</a>
     [% END %]
     </li>
 [% END %]
@@ -36,4 +36,4 @@
 </ul>
 </div>
 [% END %]
-<a href="/group/create.pl">[% 'Create new project' | i18n | html %]</a>
+<a href="?do=groupcreate">[% 'Create new project' | i18n | html %]</a>

Modified: trunk/vhffs-panel/templates/group/info.tt
===================================================================
--- trunk/vhffs-panel/templates/group/info.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/group/info.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -8,8 +8,8 @@
             <span class="quota-used" style="width:[% (group.get_quota_used / group.get_quota * 100) | format('%d') %]%" title="[% (group.get_quota_used / group.get_quota * 100) | format('%.2f') %]%"></span>
         </span>
 	</li>
-        <li><a href="/group/history.pl?group=[% group.get_groupname | html %]">[% 'Full history' | i18n | html %]</a></li>
-        <li><a href="/group/prefs.pl?group=[% group.get_groupname | html %]">[% 'Preferences' | i18n | html %]</a></li>
+        <li><a href="?do=grouphistory&amp;group=[% group.get_groupname | html %]">[% 'Full history' | i18n | html %]</a></li>
+        <li><a href="?do=groupprefs&amp;group=[% group.get_groupname | html %]">[% 'Preferences' | i18n | html %]</a></li>
 [% IF help_url.defined %]
         <li><a href="[% help_url %]">[% 'Help' | i18n | html %]</a></li>
 [% END %]

Modified: trunk/vhffs-panel/templates/group/prefs.tt
===================================================================
--- trunk/vhffs-panel/templates/group/prefs.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/group/prefs.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -14,6 +14,7 @@
         <input type="hidden" name="group" value="[% group.get_groupname | html %]"/>
         <input type="submit" value="[% 'Modify' | i18n | html %]" name="update_desc_submit"/>
     </p>
+    <input type="hidden" name="do" value="groupprefs"/>
 </form>
 
 [% IF mailgroup.defined() %]
@@ -25,6 +26,7 @@
 <input type="text" name="contact_email" id="contact_email" value="[% mailgroup.getforward %]"/> 
 <input type="hidden" name="group" value="[% group.get_groupname %]"/>
 <input type="submit" value="[% 'Modify' | i18n %]" name="contact_email_submit"/>
+<input type="hidden" name="do" value="groupprefs"/>
 </form>
 [% IF mailgroup.config.url_doc.defined() %]
 <a href="[% mailgroup.config.url_doc | html %]">[% 'Help' | i18n | html %]</a>
@@ -44,6 +46,7 @@
 <input type="hidden" name="group" value="[% g.get_groupname | html %]"/>
 <p><label>[% u.username | html %] ([% u.firstname | html %] [% u.lastname | html %])</label>
     <input type="submit" value="[% 'Remove' | i18n | html %]" name="remove_user_submit"/></p>
+<input type="hidden" name="do" value="groupprefs"/>
 </form>
 [% ELSE %]
 <p>[% u.username | html %] ([% u.firstname | html %] [% u.lastname | html %]) &mdash; [% u.state %]</p>
@@ -61,7 +64,7 @@
 <a name="add_user"></a>
 <h3>[% 'Add a user in this group' | i18n | html %]</h3>
 
-<form class="table-like" method="post" action="prefs.pl#add_user" accept-charset="utf-8">
+<form class="table-like" method="post" action="#add_user" accept-charset="utf-8">
 	<p>
 		<label for="username_add">
             [% 'Username:' | i18n | html %]
@@ -70,6 +73,7 @@
                 <input type="hidden" name="group" value="[% group.get_groupname | html %]"/>
 		<input type="submit" value="[% 'Add' | i18n | html %]" name="add_user_submit"/>
 	</p>
+	<input type="hidden" name="do" value="groupprefs"/>
 </form>
 
 [% IF add_user_error %]<p class="error">[% add_user_error | html %]</p>[% END %]
@@ -81,6 +85,7 @@
 <input type="hidden" name="group" value="[% group.get_groupname | html %]"/>
 <p><label>[% u.username | html %] ([% u.firstname | html %] [% u.lastname | html %])</label>
 <input type="submit" name="add_user_list_submit" value="[% 'Add' | i18n | html %]"/></p>
+<input type="hidden" name="do" value="groupprefs"/>
 </form>
 [% END %]
 
@@ -89,13 +94,14 @@
 [% IF use_avatars %]
 <h2>[% 'Logo' | i18n | html %]</h2>
 <h3>[% 'Current logo' | i18n | html %]</h3>
-    <p><img src="../getavatar.pl?oid=[% group.get_oid %]" alt="[% 'Group logo' | i18n | html %]"/></p>
+    <p><img src="?do=avatarget&amp;oid=[% group.get_oid %]" alt="[% 'Group logo' | i18n | html %]"/></p>
 <h3>[% 'Update logo' | i18n | html %]</h3>
-<form class="table-like" method="post" action="../object/upavatar.pl" enctype="multipart/form-data" accept-charset="utf-8">
+<form class="table-like" method="post" action="?do=avatarput&amp;oid=[% group.get_oid %]" enctype="multipart/form-data" accept-charset="utf-8">
     <p>[% 'You can upload a custom logo for your group.' | i18n | html %]</p>
-    <input type="hidden" name="OID" value="[% group.get_oid %]"/>
+    <input type="hidden" name="oid" value="[% group.get_oid %]"/>
     <p><input type="file" name="avatar"/></p>
     <p><input type="submit" value="[% 'Update' %]" /></p>
+    <input type="hidden" name="do" value="avatarput"/>
 </form>
 [% END %]
 
@@ -116,5 +122,6 @@
            <input type="text" name="new_quota" id="new_quota" value="[% group.get_quota %]"/>&nbsp;[% 'MB' | i18n | html %]</p>
            <input type="hidden" name="group" value="[% group.get_groupname | html %]"/>
         <p><input type="submit" name="update_quota_submit" value="[% 'Update quota' | i18n | html %]"/></p>
+        <input type="hidden" name="do" value="groupprefs"/>
     </form>
 [% END %]

Modified: trunk/vhffs-panel/templates/layouts/anonymous.tt
===================================================================
--- trunk/vhffs-panel/templates/layouts/anonymous.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/layouts/anonymous.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -22,9 +22,9 @@
     <div id="top-menu">
                         <ul>
 [% IF(subscribe) %]
-        <li><a href="/subscribe.pl" class="ajax">[% 'Subscribe' | i18n %]</a></li>
+        <li><a href="?do=subscribe" class="ajax">[% 'Subscribe' | i18n %]</a></li>
 [% END %]
-        <li><a href="/lost.pl" class="ajax">[% 'Lost password' | i18n %]</a></li>
+        <li><a href="?do=lost" class="ajax">[% 'Lost password' | i18n %]</a></li>
 [% IF public_url.defined() %]
         <li><a href="[% public_url | html %]">[% 'Public area' | i18n %]</a></li>
 [% END %]

Modified: trunk/vhffs-panel/templates/mail/create.tt
===================================================================
--- trunk/vhffs-panel/templates/mail/create.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/mail/create.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -15,4 +15,5 @@
 		<input type="hidden" name="group" value="[% group.get_groupname | html %]" />
 		<input type="submit" value="[% 'Send' | i18n | html %]" name="mail_submit"/>
 	</p>
+	<input type="hidden" name="do" value="mailcreate"/>
 </form>

Modified: trunk/vhffs-panel/templates/mail/prefs.tt
===================================================================
--- trunk/vhffs-panel/templates/mail/prefs.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/mail/prefs.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,7 +1,7 @@
 [% UNLESS catchall_type == 'none' %]
 <h2>[% 'Catchall address' | i18n | html %]</h2>
 
-<form class="table-like" method="post" action="/mail/prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
 	<p>[% 'Catchall address receive all emails for which no box nor forward exists on this domain.' | i18n | html %]</p>
 [% IF catchall_type == 'open' %]
 	<p>
@@ -27,6 +27,7 @@
 		<input type="hidden" name="name" value="[% mail.get_domain | html %]" />
 		<input type="submit" name="modify_catchall_submit" value="[% 'Change catchall forward' | i18n | html %]"/>
 	</p>
+	<input type="hidden" name="do" value="mailprefs"/>
 </form>
 [% END # catchall_type == 'none' %]
 
@@ -37,8 +38,8 @@
 <fieldset>
 <legend>[% b.local_part _ '@' _ b.domain | html %]</legend>
 [% IF b.state == constants.object_statuses.ACTIVATED %]
-		<form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
-                <p>[% 'New password:' | i18n | html %]<input type="password" name="box_password" value=""/></p>
+		<form class="table-like" method="post" action="#" accept-charset="utf-8">
+                <p>[% 'New password:' | i18n | html %]<input type="password" name="box_password" value="" autocomplete="off"/></p>
 [% IF nospam %]
                 <p>[% 'Enable antispam?' | i18n | html %]
                   <input type="radio" name="use_antispam"[% ' checked="checked"' IF b.nospam %] value="yes"/>&nbsp;[% 'Yes' | i18n | html %]
@@ -52,6 +53,7 @@
                 <p><input type="submit" name="update_box_submit" value="[% 'Update' | i18n | html %]"/>&nbsp;<input type="submit" name="delete_box_submit" value="[% 'Delete this mail account' | i18n | html %]"/></p>
 			<input type="hidden" name="localpart" value="[% b.local_part | html %]" />
 			<input type="hidden" name="name" value="[% b.domain | html %]" />
+			<input type="hidden" name="do" value="mailprefs"/>
 		</form>
 [% ELSE %]
     <p>[% b.state | stringify_status | html %]</p>
@@ -61,19 +63,20 @@
 
 <h3>[% 'Add an account' | i18n | html %]</h3>
 
-<form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
 	<p>
 		<label for="new_box_localpart">[% 'Local part (left side of the @):' | i18n | html %]</label>
 		<input type="text" name="localpart" id="new_box_localpart" />@[% mail.get_domain | html %]
 	</p>
 	<p>
 		<label for="new_box_password">[% 'Password:' | i18n | html %]</label>
-		<input type="password" name="box_password" id="new_box_password" />
+		<input type="password" name="box_password" id="new_box_password" autocomplete="off"/>
 	</p>
 	<p class="button">
 		<input type="hidden" name="name" value="[% mail.get_domain | html %]" />
 		<input type="submit" value="[% 'Add mailbox' | i18n | html %]" name="add_box_submit"/>
 	</p>
+	<input type="hidden" name="do" value="mailprefs"/>
 </form>
 
 <h2>[% 'Forwards' | i18n | html %]</h2>
@@ -83,7 +86,7 @@
 [% FOREACH f IN sorted_forwards %]
 <fieldset>
 <legend>[% f.local_part _ '@' _ f.domain | html %]</legend>
-    <form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
+    <form class="table-like" method="post" action="#" accept-charset="utf-8">
 		<p>
             <input type="text" name="forward" value="[% f.remote_name | html %]" /></p>
         <p><input type="submit" value="[% 'Update forward' | i18n | html %]"
@@ -92,12 +95,13 @@
             name="delete_forward_submit"/></p>
 		<input type="hidden" name="localpart" value="[% f.local_part | html %]" />
 		<input type="hidden" name="name" value="[% f.domain | html %]" />
+		<input type="hidden" name="do" value="mailprefs"/>
     </form>
 </fieldset>
 [% END %]
 
 <h3>[% 'Add forward' | i18n | html %]</h3>
-<form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
 	<p>
 		<label for="new_forward_localpart">[% 'Local part (left side of the @):' | i18n | html %]</label>
 		<input type="text" name="localpart" id="new_forward_localpart" />@[% mail.domain | html %]
@@ -110,6 +114,7 @@
 		<input type="hidden" name="name" value="[% mail.domain | html %]" />
 		<input type="submit" value="[% 'Add forward' | i18n | html %]" name="add_forward_submit"/>
 	</p>
+	<input type="hidden" name="do" value="mailprefs"/>
 </form>
 
 [% INCLUDE 'acl/form.tt' 

Modified: trunk/vhffs-panel/templates/mailinglist/create.tt
===================================================================
--- trunk/vhffs-panel/templates/mailinglist/create.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/mailinglist/create.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -21,4 +21,5 @@
 		<input type="hidden" name="group" value="[% group.get_groupname %]" />
 		<input type="submit" value="[% 'Send' | i18n | html %]" name="mailing_submit"/>
 	</p>
+	<input type="hidden" name="do" value="mailinglistcreate"/>
 </form>

Modified: trunk/vhffs-panel/templates/mailinglist/prefs.tt
===================================================================
--- trunk/vhffs-panel/templates/mailinglist/prefs.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/mailinglist/prefs.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,4 +1,4 @@
-<form class="table-like" method="post" action="/mailinglist/prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#">
 	<fieldset>
 		<legend>[% 'Options' | i18n | html %]</legend>
 		<p>[% 'Prefix on subject:' | i18n | html %]
@@ -45,7 +45,7 @@
 		</p>
 		<p>
 			<input type="checkbox" name="reply_to"  id="reply_to"[% ' checked="checked"' IF list.get_replyto %] class="labeled"/>
-			<label for="reply_to">[% 'Add "Reply-To" header:' | i18n | html %]</label>
+			<label for="reply_to">[% 'Add "Reply-To" header' | i18n | html %]</label>
 		</p>
     <p>[% 'Signature:' | i18n | html %]</p>
     <p><textarea name="signature" rows="7" cols="50">[% list.get_signature | html %]</textarea></p>
@@ -54,6 +54,7 @@
 		<input type="submit" name="options_submit" value="[% 'Save options' | i18n | html %]"/>
 	</p>
     </fieldset>
+    <input type="hidden" name="do" value="mailinglistprefs"/>
 </form>
 
 <h2>[% 'Manage members' | i18n | html %]</h2>
@@ -62,7 +63,7 @@
 [% FOREACH m IN list.get_members.values() %]
 <fieldset>
 <legend>[% m.member | html %]</legend>
-    <form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
+    <form class="table-like" method="post" action="#">
         <p><select name="right">
             <option value="[% constants.mailinglist.RIGHT_SUB_WAITING_FOR_REPLY %]"[% ' selected="selected"' IF m.perm == constants.mailinglist.RIGHT_SUB_WAITING_FOR_REPLY %]>
                 [% 'Waiting for confirmation' | i18n | html %]</option>
@@ -79,14 +80,15 @@
         <input type="hidden" name="local" value="[% list.get_localpart | html %]" />
         <input type="hidden" name="domain" value="[% list.get_domain | html %]" />
         <input type="submit" name="change_rights_submit" value="[% 'Update permissions' | i18n | html %]" />
-		<input type="submit" name="delete_submit" value="[% 'Delete from list' | i18n | html %]" />
+	<input type="submit" name="delete_submit" value="[% 'Delete from list' | i18n | html %]" />
+	<input type="hidden" name="do" value="mailinglistprefs"/>
 	</form>
 </fieldset>
 [% END %]
 
 <h3>[% 'Add members' | i18n | html %]</h3>
 
-<form class="table-like" method="post" action="prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#">
 	<div style="display:none;">
 		<textarea name="projectmembers" id="projectmembers">[% group_emails | html %]</textarea>
 	</div>
@@ -111,6 +113,7 @@
     </p>
     <p>
 	</p>
+	<input type="hidden" name="do" value="mailinglistprefs"/>
 </form>
 
 [% INCLUDE 'acl/form.tt' 

Modified: trunk/vhffs-panel/templates/menu/admin.tt
===================================================================
--- trunk/vhffs-panel/templates/menu/admin.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/menu/admin.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,18 +1,18 @@
 <ul>
-<li><a href="/admin/index.pl">[% 'General' | i18n | html %]</a></li>
-<li><a href="/admin/user/index.pl">[% 'Users' | i18n | html %]</a></li>
-<li><a href="/admin/group/index.pl">[% 'Groups' | i18n | html %]</a></li>
-[% IF panel_header.available_services.web %]<li><a/ href="/admin/web/index.pl">[% 'Web' | i18n | html %]</a></li>[% END %]
-[% IF panel_header.available_services.mysql %]<li><a/ href="/admin/mysql/index.pl">[% 'MySQL' | i18n | html %]</a></li>[% END %]
-[% IF panel_header.available_services.pgsql %]<li><a/ href="/admin/pgsql/index.pl">[% 'PgSQL' | i18n | html %]</a></li>[% END %]
-[% IF panel_header.available_services.cvs %]<li><a/ href="/admin/cvs/index.pl">[% 'CVS' | i18n | html %]</a></li>[% END %]
-[% IF panel_header.available_services.svn %]<li><a/ href="/admin/svn/index.pl">[% 'SVN' | i18n | html %]</a></li>[% END %]
-[% IF panel_header.available_services.git %]<li><a/ href="/admin/git/index.pl">[% 'Git' | i18n | html %]</a></li>[% END %]
-[% IF panel_header.available_services.mercurial %]<li><a/ href="/admin/mercurial/index.pl">[% 'Mercurial' | i18n | html %]</a></li>[% END %]
-[% IF panel_header.available_services.bazaar %]<li><a/ href="/admin/bazaar/index.pl">[% 'Bazaar' | i18n | html %]</a></li>[% END %]
-[% IF panel_header.available_services.dns %]<li><a/ href="/admin/dns/index.pl">[% 'DNS' | i18n | html %]</a></li>[% END %]
-[% IF panel_header.available_services.repository %]<li><a/ href="/admin/repository/index.pl">[% 'Dl repos' | i18n | html %]</a></li>[% END %]
-[% IF panel_header.available_services.mail %]<li><a/ href="/admin/mail/index.pl">[% 'Mail' | i18n | html %]</a></li>[% END %]
-[% IF panel_header.available_services.mailinglist %]<li><a/ href="/admin/mailinglist/index.pl">[% 'ML' | i18n | html %]</a></li>[% END %]
-[% IF panel_header.available_services.cron %]<li><a/ href="/admin/cron/index.pl">[% 'Crons' | i18n | html %]</a></li>[% END %]
+<li><a href="?do=admin">[% 'General' | i18n | html %]</a></li>
+<li><a href="?do=adminuserindex">[% 'Users' | i18n | html %]</a></li>
+<li><a href="?do=admingroupindex">[% 'Groups' | i18n | html %]</a></li>
+[% IF panel_header.available_services.web %]<li><a/ href="?do=adminwebindex">[% 'Web' | i18n | html %]</a></li>[% END %]
+[% IF panel_header.available_services.mysql %]<li><a/ href="?do=adminmysqlindex">[% 'MySQL' | i18n | html %]</a></li>[% END %]
+[% IF panel_header.available_services.pgsql %]<li><a/ href="?do=adminpgsqlindex">[% 'PgSQL' | i18n | html %]</a></li>[% END %]
+[% IF panel_header.available_services.cvs %]<li><a/ href="?do=admincvsindex">[% 'CVS' | i18n | html %]</a></li>[% END %]
+[% IF panel_header.available_services.svn %]<li><a/ href="?do=adminsvnindex">[% 'SVN' | i18n | html %]</a></li>[% END %]
+[% IF panel_header.available_services.git %]<li><a/ href="?do=admingitindex">[% 'Git' | i18n | html %]</a></li>[% END %]
+[% IF panel_header.available_services.mercurial %]<li><a/ href="?do=adminmercurialindex">[% 'Mercurial' | i18n | html %]</a></li>[% END %]
+[% IF panel_header.available_services.bazaar %]<li><a/ href="?do=adminbazaarindex">[% 'Bazaar' | i18n | html %]</a></li>[% END %]
+[% IF panel_header.available_services.dns %]<li><a/ href="?do=admindnsindex">[% 'DNS' | i18n | html %]</a></li>[% END %]
+[% IF panel_header.available_services.repository %]<li><a/ href="?do=adminrepositoryindex">[% 'Dl repos' | i18n | html %]</a></li>[% END %]
+[% IF panel_header.available_services.mail %]<li><a/ href="?do=adminmailindex">[% 'Mail' | i18n | html %]</a></li>[% END %]
+[% IF panel_header.available_services.mailinglist %]<li><a/ href="?do=adminmailinglistindex">[% 'ML' | i18n | html %]</a></li>[% END %]
+[% IF panel_header.available_services.cron %]<li><a/ href="?do=admincronindex">[% 'Crons' | i18n | html %]</a></li>[% END %]
 </ul>

Modified: trunk/vhffs-panel/templates/menu/group.tt
===================================================================
--- trunk/vhffs-panel/templates/menu/group.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/menu/group.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,88 +1,88 @@
 <ul>
 <li><a href="#">[% 'Project' | i18n | html %]</a>
   <ul>
-    <li><a href="/group/view.pl?group=[% current_group.get_groupname %]">[% 'Home' | i18n | html %]</a></li>
-    <li><a href="/group/prefs.pl?group=[% current_group.get_groupname %]">[% 'Preferences' | i18n | html %]</a></li>
+    <li><a href="?do=groupview&amp;group=[% current_group.get_groupname %]">[% 'Home' | i18n | html %]</a></li>
+    <li><a href="?do=groupprefs&amp;group=[% current_group.get_groupname %]">[% 'Preferences' | i18n | html %]</a></li>
   </ul>
 </li>
 <li><a href="#">[% 'Services' | i18n | html %]</a>
   <ul>
-    [% IF panel_header.available_services.web %]<li><a href="/web/index.pl?group=[% current_group.get_groupname %]">[% 'Web' | i18n | html %]</a>
+    [% IF panel_header.available_services.web %]<li><a href="?do=webindex&amp;group=[% current_group.get_groupname %]">[% 'Web' | i18n | html %]</a>
       <ul>
-        <li><a href="/web/index.pl?group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
-        <li><a href="/web/create.pl?group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
+        <li><a href="?do=webindex&amp;group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
+        <li><a href="?do=webcreate&amp;group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
       </ul>
     </li>[% END %]
-    [% IF panel_header.available_services.mysql %]<li><a href="/mysql/index.pl?group=[% current_group.get_groupname %]">[% 'MySQL' | i18n | html %]</a>
+    [% IF panel_header.available_services.mysql %]<li><a href="?do=mysqlindex&amp;group=[% current_group.get_groupname %]">[% 'MySQL' | i18n | html %]</a>
       <ul>
-        <li><a href="/mysql/index.pl?group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
-        <li><a href="/mysql/create.pl?group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
+        <li><a href="?do=mysqlindex&amp;group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
+        <li><a href="?do=mysqlcreate&amp;group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
       </ul>
     </li>[% END %]
-    [% IF panel_header.available_services.pgsql %]<li><a href="/pgsql/index.pl?group=[% current_group.get_groupname %]">[% 'PgSQL' | i18n | html %]</a>
+    [% IF panel_header.available_services.pgsql %]<li><a href="?do=pgsqlindex&amp;group=[% current_group.get_groupname %]">[% 'PgSQL' | i18n | html %]</a>
       <ul>
-        <li><a href="/pgsql/index.pl?group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
-        <li><a href="/pgsql/create.pl?group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
+        <li><a href="?do=pgsqlindex&amp;group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
+        <li><a href="?do=pgsqlcreate&amp;group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
       </ul>
     </li>[% END %]
-    [% IF panel_header.available_services.cvs %]<li><a href="/cvs/index.pl?group=[% current_group.get_groupname %]">[% 'CVS' | i18n | html %]</a>
+    [% IF panel_header.available_services.cvs %]<li><a href="?do=cvsindex&amp;group=[% current_group.get_groupname %]">[% 'CVS' | i18n | html %]</a>
       <ul>
-        <li><a href="/cvs/index.pl?group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
-        <li><a href="/cvs/create.pl?group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
+        <li><a href="?do=cvsindex&amp;group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
+        <li><a href="?do=cvscreate&amp;group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
       </ul>
     </li>[% END %]
-    [% IF panel_header.available_services.svn %]<li><a href="/svn/index.pl?group=[% current_group.get_groupname %]">[% 'SVN' | i18n | html %]</a>
+    [% IF panel_header.available_services.svn %]<li><a href="?do=svnindex&amp;group=[% current_group.get_groupname %]">[% 'SVN' | i18n | html %]</a>
       <ul>
-        <li><a href="/svn/index.pl?group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
-        <li><a href="/svn/create.pl?group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
+        <li><a href="?do=svnindex&amp;group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
+        <li><a href="?do=svncreate&amp;group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
       </ul>
     </li>[% END %]
-    [% IF panel_header.available_services.git %]<li><a href="/git/index.pl?group=[% current_group.get_groupname %]">[% 'Git' | i18n | html %]</a>
+    [% IF panel_header.available_services.git %]<li><a href="?do=gitindex&amp;group=[% current_group.get_groupname %]">[% 'Git' | i18n | html %]</a>
       <ul>
-        <li><a href="/git/index.pl?group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
-        <li><a href="/git/create.pl?group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
+        <li><a href="?do=gitindex&amp;group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
+        <li><a href="?do=gitcreate&amp;group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
       </ul>
     </li>[% END %]
-    [% IF panel_header.available_services.mercurial %]<li><a href="/mercurial/index.pl?group=[% current_group.get_groupname %]">[% 'Mercurial' | i18n | html %]</a>
+    [% IF panel_header.available_services.mercurial %]<li><a href="?do=mercurialindex&amp;group=[% current_group.get_groupname %]">[% 'Mercurial' | i18n | html %]</a>
       <ul>
-        <li><a href="/mercurial/index.pl?group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
-        <li><a href="/mercurial/create.pl?group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
+        <li><a href="?do=mercurialindex&amp;group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
+        <li><a href="?do=mercurialcreate&amp;group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
       </ul>
     </li>[% END %]
-    [% IF panel_header.available_services.bazaar %]<li><a href="/bazaar/index.pl?group=[% current_group.get_groupname %]">[% 'Bazaar' | i18n | html %]</a>
+    [% IF panel_header.available_services.bazaar %]<li><a href="?do=bazaarindex&amp;group=[% current_group.get_groupname %]">[% 'Bazaar' | i18n | html %]</a>
       <ul>
-        <li><a href="/bazaar/index.pl?group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
-        <li><a href="/bazaar/create.pl?group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
+        <li><a href="?do=bazaarindex&amp;group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
+        <li><a href="?do=bazaarcreate&amp;group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
       </ul>
     </li>[% END %]
-    [% IF panel_header.available_services.dns %]<li><a href="/dns/index.pl?group=[% current_group.get_groupname %]">[% 'DNS' | i18n | html %]</a>
+    [% IF panel_header.available_services.dns %]<li><a href="?do=dnsindex&amp;group=[% current_group.get_groupname %]">[% 'DNS' | i18n | html %]</a>
       <ul>
-        <li><a href="/dns/index.pl?group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
-        <li><a href="/dns/create.pl?group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
+        <li><a href="?do=dnsindex&amp;group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
+        <li><a href="?do=dnscreate&amp;group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
       </ul>
     </li>[% END %]
-    [% IF panel_header.available_services.repository %]<li><a href="/repository/index.pl?group=[% current_group.get_groupname %]">[% 'Dl repos' | i18n | html %]</a>
+    [% IF panel_header.available_services.repository %]<li><a href="?do=repositoryindex&amp;group=[% current_group.get_groupname %]">[% 'Dl repos' | i18n | html %]</a>
       <ul>
-        <li><a href="/repository/index.pl?group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
-        <li><a href="/repository/create.pl?group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
+        <li><a href="?do=repositoryindex&amp;group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
+        <li><a href="?do=repositorycreate&amp;group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
       </ul>
     </li>[% END %]
-    [% IF panel_header.available_services.mail %]<li><a href="/mail/index.pl?group=[% current_group.get_groupname %]">[% 'Mail' | i18n | html %]</a>
+    [% IF panel_header.available_services.mail %]<li><a href="?do=mailindex&amp;group=[% current_group.get_groupname %]">[% 'Mail' | i18n | html %]</a>
       <ul>
-        <li><a href="/mail/index.pl?group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
-        <li><a href="/mail/create.pl?group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
+        <li><a href="?do=mailindex&amp;group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
+        <li><a href="?do=mailcreate&amp;group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
       </ul>
     </li>[% END %]
-    [% IF panel_header.available_services.mailinglist %]<li><a href="/mailinglist/index.pl?group=[% current_group.get_groupname %]">[% 'ML' | i18n | html %]</a>
+    [% IF panel_header.available_services.mailinglist %]<li><a href="?do=mailinglistindex&amp;group=[% current_group.get_groupname %]">[% 'ML' | i18n | html %]</a>
       <ul>
-        <li><a href="/mailinglist/index.pl?group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
-        <li><a href="/mailinglist/create.pl?group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
+        <li><a href="?do=mailinglistindex&amp;group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
+        <li><a href="?do=mailinglistcreate&amp;group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
       </ul>
     </li>[% END %]
-    [% IF panel_header.available_services.cron %]<li><a href="/cron/index.pl?group=[% current_group.get_groupname %]">[% 'Crons' | i18n | html %]</a>
+    [% IF panel_header.available_services.cron %]<li><a href="?do=cronindex&amp;group=[% current_group.get_groupname %]">[% 'Crons' | i18n | html %]</a>
       <ul>
-        <li><a href="/cron/index.pl?group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
-        <li><a href="/cron/create.pl?group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
+        <li><a href="?do=cronindex&amp;group=[% current_group.get_groupname %]">[% 'List' | i18n | html %]</a></li>
+        <li><a href="?do=croncreate&amp;group=[% current_group.get_groupname %]">[% 'Create' | i18n | html %]</a></li>
       </ul>
     </li>[% END %]
   </ul>

Modified: trunk/vhffs-panel/templates/menu/moderator.tt
===================================================================
--- trunk/vhffs-panel/templates/menu/moderator.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/menu/moderator.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,2 +1,4 @@
-<a href="/admin/stats.pl">[% 'Get statistics' | i18n | html %]</a>
-<a href="/admin/moderation/index.pl">[% 'Moderation' | i18n | html %]</a>
+<ul>
+<li><a href="?do=stats">[% 'Get statistics' | i18n | html %]</a></li>
+<li><a href="?do=moderation">[% 'Moderation' | i18n | html %]</a></li>
+</ul>

Modified: trunk/vhffs-panel/templates/mercurial/create.tt
===================================================================
--- trunk/vhffs-panel/templates/mercurial/create.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/mercurial/create.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -15,4 +15,5 @@
 		<input type="hidden" name="group" value="[% group.get_groupname | html %]" />
 		<input type="submit" value="[% 'Send' | i18n | html %]" name="mercurial_submit"/>
 	</p>
+	<input type="hidden" name="do" value="mercurialcreate"/>
 </form>

Modified: trunk/vhffs-panel/templates/misc/alert.tt
===================================================================
--- trunk/vhffs-panel/templates/misc/alert.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/misc/alert.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -2,24 +2,25 @@
 
 <h2>[% 'Here, you can send a message to the admin team' | i18n | html %]</h2>
 
-<form class="table-like" method="post" action="alert_submit.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="?do=contact" accept-charset="utf-8">
 	<p>
-		<label for="MESSAGE" style="float:none">
+		<label for="message" style="float:none">
             [% 'Subject:' | i18n | html %]
 		</label>
 	</p>
 	<p>
-		<input type="text" name="SUBJECT" id="SUBJECT" size="90" value=""/>
+		<input type="text" name="subject" id="subject" size="90" value=""/>
 	</p>
 	<p>
-		<label for="MESSAGE" style="float:none">
+		<label for="message" style="float:none">
 			[% 'Your message:' | i18n | html %]
 		</label>
     </p>
     <p>
-		<textarea name="MESSAGE" id="MESSAGE" cols="90" rows="15" style="width:auto"></textarea>
+		<textarea name="message" id="message" cols="90" rows="15" style="width:auto"></textarea>
 	</p>
+	<input type="hidden" name="do" value="contact"/>
 	<p class="button" id="sendButton">
-		<input type="submit" value="[% 'Send' | i18n | html %]" />
+		<input type="submit" value="[% 'Send' | i18n | html %]" id="contact-submit" name="contact_submit"/>
 	</p>
 </form>

Modified: trunk/vhffs-panel/templates/misc/header.tt
===================================================================
--- trunk/vhffs-panel/templates/misc/header.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/misc/header.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -4,22 +4,22 @@
   </div>
   <!-- Flag navigations -->
   <div class="navflag">
-    <a href="/?lang=en_US"><img src="/themes/light-grey/img/en_US.png" alt="en_US"/></a>
-    <a href="/?lang=fr_FR"><img src="/themes/light-grey/img/fr_FR.png" alt="fr_FR"/></a>
-    <a href="/?lang=es_ES"><img src="/themes/light-grey/img/es_ES.png" alt="es_ES"/></a>
+    <a href="?do=[% do %]&amp;lang=en_US"><img src="/themes/light-grey/img/en_US.png" alt="en_US"/></a>
+    <a href="?do=[% do %]&amp;lang=fr_FR"><img src="/themes/light-grey/img/fr_FR.png" alt="fr_FR"/></a>
+    <a href="?do=[% do %]&amp;lang=es_ES"><img src="/themes/light-grey/img/es_ES.png" alt="es_ES"/></a>
   </div>
 
   <!-- Navigation Level 1 -->
 
   <div class="nav1">
-    <a href="/panel.pl">[% 'Home' | i18n | html %]</a>
-    <a  href="/user/prefs.pl">[% 'Preferences' | i18n | html %]</a>
-    <a href="/group/index.pl">[% 'Projects' | i18n | html %]</a>
+    <a href="?do=home">[% 'Home' | i18n | html %]</a>
+    <a href="?do=userprefs">[% 'Preferences' | i18n | html %]</a>
+    <a href="?do=groupindex">[% 'Projects' | i18n | html %]</a>
     [% IF current_user.is_admin() OR current_user.is_moderator() %]
-    <a href="/admin/index.pl">[% 'Administration' | i18n | html %]</a>
+    <a href="?do=admin">[% 'Administration' | i18n | html %]</a>
     [% END %]
-    <a href="/alert.pl">[% 'Contact' | i18n | html %]</a>
-    <a href="/auth.pl?logout=1">[% 'Logout' | i18n | html %]</a>
+    <a href="?do=contact">[% 'Contact' | i18n | html %]</a>
+    <a href="?do=logout">[% 'Logout' | i18n | html %]</a>
     <span id="username">[% current_user.get_username() %]</span>
   </div>
 

Modified: trunk/vhffs-panel/templates/misc/languages.tt
===================================================================
--- trunk/vhffs-panel/templates/misc/languages.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/misc/languages.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,5 +1,5 @@
 <div class="navflag">
 [% FOREACH l IN languages %]
-    <a href="/auth.pl?lang=[% l | html %]"><img src="/themes/[% theme %]/img/[% l | html %].png" alt="[% l %]"/></a>
+    <a href="?do=login&amp;lang=[% l | html %]"><img src="/themes/[% theme %]/img/[% l | html %].png" alt="[% l %]"/></a>
 [% END %]
 </div>

Modified: trunk/vhffs-panel/templates/misc/service-index.tt
===================================================================
--- trunk/vhffs-panel/templates/misc/service-index.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/misc/service-index.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -5,21 +5,21 @@
 [% FOREACH s IN list %]
         <li>[% s.displayname | html %]
             [% IF s.active %]
-                &mdash; <a href="/[% type %]/prefs.pl?name=[% s.displayname | html %]&amp;group=[% group.get_groupname %]">[% 'Go to administration' | i18n | html %]</a>
+                &mdash; <a href="?do=[% type %]prefs&amp;name=[% s.displayname | html %]">[% 'Go to administration' | i18n | html %]</a>
             [% ELSE %]
                 ([% s.state | html %])
                 [% IF s.refused %]
-                &mdash;  <a href="/object/resubmit.pl?oid=[% s.oid %]">[% 'Propose a new description' | i18n | html %]</a>
-                &mdash; <a href="/object/quickdelete.pl?oid=[% s.oid %]">[% 'Cancel request' | i18n | html %]</a>
+                &mdash;  <a href="?do=objectresubmit&amp;oid=[% s.oid %]">[% 'Propose a new description' | i18n | html %]</a>
+                &mdash; <a href="?do=objectcancel&amp;oid=[% s.oid %]">[% 'Cancel request' | i18n | html %]</a>
                 [% END %]
             [% END %]
-            &mdash; <a href="/history.pl?OID=[% s.oid %]">[% 'History' | i18n | html %]</a>
+            &mdash; <a href="?do=objecthistory&amp;oid=[% s.oid %]">[% 'History' | i18n | html %]</a>
         </li>
 [% END # s IN list %]
 [% ELSE %]
         <li>[% 'None' | i18n | html %]</li>
 [% END # list.size() %]
-        <li><a href="/[% type %]/create.pl?group=[% group.get_groupname | html %]">[% 'New' | i18n | html %]</a></li>
+        <li><a href="?do=[% type %]create&amp;group=[% group.get_groupname | html %]">[% 'New' | i18n | html %]</a></li>
 [% IF help_url %]
         <li><a href="[% help_url | html %]"> [% 'Help' | i18n | html %]</a></li>
 [% END %]

Modified: trunk/vhffs-panel/templates/misc/welcome.tt
===================================================================
--- trunk/vhffs-panel/templates/misc/welcome.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/misc/welcome.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -4,7 +4,7 @@
 <h2>[% 'The following projects have reached or are going to reach the disk quota limit, please take a look !' | i18n | html %]</h2>
 <ul>
 [% FOR g IN overquota %]
-    <li><a href="/group/view.pl?group=[% g %]">[% g %]</a></li>
+    <li><a href="?do=groupview&amp;group=[% g %]">[% g %]</a></li>
 [% END %]
 </ul>
 </div>

Modified: trunk/vhffs-panel/templates/mysql/create.tt
===================================================================
--- trunk/vhffs-panel/templates/mysql/create.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/mysql/create.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,5 +1,5 @@
 <form class="table-like" method="post" action="#" class="largeLabel" accept-charset="utf-8">
-    <p class="info">[% 'The database name is prefixed by your groupname followed by an underscore (%s_dbname). The database user is the database full name (%s_dbname).' | i18n | pretty_print(group.get_groupname, group.get_groupname) | html %]</p>
+	<p class="info">[% 'The database name is prefixed by your groupname followed by an underscore (%s_dbname). The database user is the database full name (%s_dbname).' | i18n | pretty_print(group.get_groupname, group.get_groupname) | html %]</p>
 	<p>
 		<label>[% 'Group owning this database:' | i18n | html %]</label>
 		[% group.get_groupname | html %]
@@ -10,7 +10,7 @@
 	</p>
 	<p>
 		<label for="db_pass">[% 'MySQL password for this database:' | i18n | html %]</label>
-		<input type="password" name="db_pass" id="db_pass"/>
+		<input type="password" name="db_pass" id="db_pass" autocomplete="off"/>
 	</p>
 	<p>
 		<label for="description">[% 'Description:' | i18n | html %]</label>
@@ -20,4 +20,5 @@
 		<input type="hidden" name="group" value="[% group.get_groupname | html %]" />
 		<input type="submit" value="[% 'Send' | i18n | html %]" name="mysql_submit"/>
 	</p>
+	<input type="hidden" name="do" value="mysqlcreate"/>
 </form>

Modified: trunk/vhffs-panel/templates/object/delete.tt
===================================================================
--- trunk/vhffs-panel/templates/object/delete.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/object/delete.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -4,26 +4,26 @@
 %]
 <h2>[% 'Delete this object' | i18n | html %]</h2>
 
-<form method="post" action="/object/delete.pl" accept-charset="utf-8">
+<form method="post" action="#" accept-charset="utf-8">
 	<fieldset class="delete">
 		<legend>
-			[% 'Are you SURE you want DELETE this object?' | i18n | html %]
+			[% 'Are you SURE you want to DELETE this object?' | i18n | html %]
 		</legend>
 
-		<p class="warning">[% 'This action is non-reversible. The object will be physically destroyed and deleted from the database, there is no way to recover your data.' | i18n | html %]</p>
+		<p class="warning">[% 'This action is non-reversible. This object will be physically destroyed and deleted from the database, there is no way to recover your data.' | i18n | html %]</p>
 [% IF type == 'group' %]
         <p class="warning">[% 'Moreover all associated services will be DESTROYED' | i18n | html %]</p>
 [% END %]
 		<p>
 			<input type="radio" name="delete" id="DELETE_NO"  value="0" checked="checked" />
 			<label for="DELETE_NO">
-				[% 'No, I\'m not sure, I prefer to keep this object. All these warnings scare me' | i18n | html %]
+				[% 'No, I\'m not sure, I prefer to keep this object. All these warnings scare me.' | i18n | html %]
 			</label>
 		</p>
 		<p>
 			<input type="radio" name="delete" id="DELETE_YES" value="1" />
 			<label for="DELETE_YES">
-				[% 'Yes I\'m sure of what I do, I do not know the fear' | i18n | html %]
+				[% 'Yes I\'m sure of what I do, I do not know the fear.' | i18n | html %]
 			</label>
 		</p>
 	</fieldset>
@@ -32,5 +32,5 @@
 		<input type="hidden" name="oid" value="[% oid %]" />
 		<input type="submit" value="[% 'Delete' | i18n | html %]" />
 	</p>
-
+	<input type="hidden" name="do" value="objectdelete"/>
 </form>

Modified: trunk/vhffs-panel/templates/object/resubmit.tt
===================================================================
--- trunk/vhffs-panel/templates/object/resubmit.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/object/resubmit.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,4 +1,4 @@
-<form class="table-like" method="post" action="" class="largeLabel" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" class="largeLabel" accept-charset="utf-8">
 	<p>
 		<label>[% 'Object type:' | i18n | html %]</label>
             [% object.get_type | stringify_type | html %]
@@ -22,4 +22,5 @@
 	<p class="button" id="buttonSend">
 		<input type="submit" value="[% 'Update' | i18n | html %]" name="submitted" />
 	</p>
+	<input type="hidden" name="do" value="objectresubmit"/>
 </form>

Modified: trunk/vhffs-panel/templates/pgsql/create.tt
===================================================================
--- trunk/vhffs-panel/templates/pgsql/create.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/pgsql/create.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,5 +1,5 @@
 <form class="table-like" method="post" action="#" class="largeLabel" accept-charset="utf-8">
-    <p class="info">[% 'The database name is prefixed by your groupname followed by an underscore (%s_dbname). The database user is the database full name (%s_dbname).' | i18n | pretty_print(group.get_groupname, group.get_groupname) | html %]</p>
+	<p class="info">[% 'The database name is prefixed by your groupname followed by an underscore (%s_dbname). The database user is the database full name (%s_dbname).' | i18n | pretty_print(group.get_groupname, group.get_groupname) | html %]</p>
 	<p>
 		<label>[% 'Group owning this database:' | i18n | html %]</label>
 		[% group.get_groupname | html %]
@@ -20,4 +20,5 @@
 		<input type="hidden" name="group" value="[% group.get_groupname | html %]" />
 		<input type="submit" value="[% 'Send' | i18n | html %]" name="pgsql_submit"/>
 	</p>
+	<input type="hidden" name="do" value="pgsqlcreate"/>
 </form>

Modified: trunk/vhffs-panel/templates/repository/create.tt
===================================================================
--- trunk/vhffs-panel/templates/repository/create.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/repository/create.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -15,4 +15,5 @@
 		<input type="hidden" name="group" value="[% group.get_groupname | html %]" />
 		<input type="submit" value="[% 'Create' %]" name="repo_submit"/>
 	</p>
+	<input type="hidden" name="do" value="repositorycreate"/>
 </form>

Modified: trunk/vhffs-panel/templates/scm/prefs.tt
===================================================================
--- trunk/vhffs-panel/templates/scm/prefs.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/scm/prefs.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,4 +1,4 @@
-<form class="table-like" method="post" action="/[% type %]/prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
 <h2>[% 'Public' | i18n | html %]</h2>
 	<p>
 		<label for="is-public">[% 'Is this a public repository?' | i18n | html %]</label>
@@ -20,6 +20,7 @@
 		<input type="hidden" name="name" value="[% repository.get_reponame %]" />
 		<input type="submit" value="[% 'Update' | i18n | html %]" name="save_prefs_submit"/>
 	</p>
+	<input type="hidden" name="do" value="[% type %]prefs"/>
 </form>
 
 [% INCLUDE 'acl/form.tt' 

Modified: trunk/vhffs-panel/templates/svn/create.tt
===================================================================
--- trunk/vhffs-panel/templates/svn/create.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/svn/create.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -15,4 +15,5 @@
 		<input type="hidden" name="group" value="[% group.get_groupname | html %]" />
 		<input type="submit" value="[% 'Send' | i18n | html %]" name="svn_submit"/>
 	</p>
+	<input type="hidden" name="do" value="svncreate"/>
 </form>

Modified: trunk/vhffs-panel/templates/user/prefs.tt
===================================================================
--- trunk/vhffs-panel/templates/user/prefs.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/user/prefs.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,57 +1,57 @@
-			<form class="table-like" method="post" action="/user/prefs.pl" accept-charset="utf-8">
+			<form class="table-like" method="post" action="?do=userprefs" accept-charset="utf-8">
 				<p>
 					<label>[% 'Username:' | i18n | html %]</label>
 					<span class="formInput">[% user.get_username | html %]</span>
 				</p>
 	
 				<p>
-					<label for="FIRSTNAME">[% 'Firstname:' | i18n | html %]</label>
-					<input name="FIRSTNAME" id="FIRSTNAME" value="[% user.get_firstname | html %]" type="text" />
+					<label for="firstname">[% 'Firstname:' | i18n | html %]</label>
+					<input name="firstname" id="firstname" value="[% user.get_firstname | html %]" type="text" />
 				</p>
 				
 				<p>
-					<label for="LASTNAME">[% 'Last name:' | i18n | html %]</label>
-					<input name="LASTNAME" id="LASTNAME"  value="[% user.get_lastname %]" type="text" />
+					<label for="lastname">[% 'Last name:' | i18n | html %]</label>
+					<input name="lastname" id="lastname"  value="[% user.get_lastname %]" type="text" />
 				</p>
 			
 				<p>
-					<label for="MAIL">[% 'Email address:' | i18n | html %]</label>
-					<input name="MAIL" id="MAIL" maxlength="200" value="[% user.get_mail | html %]" type="text" />
+					<label for="mail">[% 'Email address:' | i18n | html %]</label>
+					<input name="mail" id="MAIL" maxlength="200" value="[% user.get_mail | html %]" type="text" />
 				</p>
 				
 				<p>
-					<label for="ADDRESS">[% 'Address:' | i18n |html %]</label>
-					<input name="ADDRESS" id="ADDRESS" value="[% user.get_address | html %]" type="text" />
+					<label for="address">[% 'Address:' | i18n |html %]</label>
+					<input name="address" id="address" value="[% user.get_address | html %]" type="text" />
 				</p>
 
 				<p>
-					<label for="CITY">[% 'City:' | i18n | html %]</label>
-					<input name="CITY" id="CITY" value="[% user.get_city | html %]" type="text" />
+					<label for="city">[% 'City:' | i18n | html %]</label>
+					<input name="city" id="city" value="[% user.get_city | html %]" type="text" />
 				</p>
 
 				<p>
-					<label for="ZIPCODE">[% 'Zipcode:' | i18n | html %]</label>
-					<input name="ZIPCODE" id="ZIPCODE" value="[% user.get_zipcode | html %]" type="text" />
+					<label for="zipcode">[% 'Zipcode:' | i18n | html %]</label>
+					<input name="zipcode" id="zipcode" value="[% user.get_zipcode | html %]" type="text" />
 				</p>
 	
 				<p>
-					<label for="COUNTRY">[% 'Country:' | i18n | html %]</label>
-					<input name="COUNTRY" id="COUNTRY" value="[% user.get_country %]" type="text" />
+					<label for="country">[% 'Country:' | i18n | html %]</label>
+					<input name="country" id="country" value="[% user.get_country %]" type="text" />
 				</p>
 
 				<p>
-					<label for="PASSWORD1">[% 'Password:' | i18n | html %]</label>
-					<input name="PASSWORD1" id="PASSWORD1" value="" type="password" />
+					<label for="password1">[% 'Password:' | i18n | html %]</label>
+					<input name="password1" id="password1" value="" type="password" autocomplete="off"/>
 				</p>
 				
 				<p>
-					<label for="PASSWORD2">[% 'Password (confirm):' | i18n | html %]</label>
-					<input name="PASSWORD2" id="PASSWORD2" value="" type="password" />
+					<label for="password2">[% 'Password (confirm):' | i18n | html %]</label>
+					<input name="password2" id="password2" value="" type="password" autocomplete="off"/>
 				</p>
 
 				<p>
-					<label for="LANG">[% 'Panel language:' | i18n | html %]</label>
-                    <select name="LANG" id="LANG">
+					<label for="lang">[% 'Panel language:' | i18n | html %]</label>
+                    <select name="lang" id="lang">
 [% FOREACH l IN languages %]
                         <option value="[% l | html %]"[% ' selected="selected"' IF current_language == l %]>[% l | html %]</option>
 [% END %]
@@ -59,8 +59,8 @@
 				</p>
 
 				<p>
-					<label for="THEME">[% 'Panel UI theme:' | i18n | html %]</label>
-					<select name="THEME" id="THEME">
+					<label for="theme">[% 'Panel UI theme:' | i18n | html %]</label>
+					<select name="theme" id="theme">
 [% FOREACH t IN themes %]
                         <option value="[% t | html %]"[% ' selected="selected"' IF current_theme == t %]>[% t | html %]</option>
 [% END %]
@@ -68,8 +68,8 @@
 				</p>
 
 				<p>
-					<label for="SHELL">[% 'Shell:' | i18n | html %]</label>
-					<select name="SHELL" id="SHELL">
+					<label for="shell">[% 'Shell:' | i18n | html %]</label>
+					<select name="shell" id="shell">
 [% FOREACH s IN shells %]
                         <option value="[% s | html %]"[% ' selected="selected"' IF current_shell == s %]>[% s | html %]</option>
 [% END %]
@@ -77,8 +77,8 @@
 				</p>
 [% IF newsletter.active %]
 				<p>
-					<label for="NEWSLETTER">[% 'Subscribe to newsletter' | i18n | html %]</label>
-					<input type="checkbox" name="NEWSLETTER" id="NEWSLETTER"[% ' selected="selected"' IF newsletter.subscribed %]/>
+					<label for="newsletter">[% 'Subscribe to newsletter' | i18n | html %]</label>
+					<input type="checkbox" name="newsletter" id="newsletter"[% ' selected="selected"' IF newsletter.subscribed %]/>
 				</p>
 [% END %]
 
@@ -140,44 +140,47 @@
 					<input  type="submit"  value="[% 'Update' | i18n | html %]" name="prefs_submit" id="prefs_submit"/>
 				</p>
 
-				<input type="hidden" name="name" value="[% user.get_username | html %]" />
+				<input type="hidden" name="name" value="[% user.get_username | html %]"/>
+				<input type="hidden" name="do" value="userprefs"/>
 			</form>
 
 [% IF use_avatars %]
 			<h2>[% 'Send my avatar' | i18n | html %]</h2>
-			<form class="table-like" method="post" action="/object/upavatar.pl" enctype="multipart/form-data" accept-charset="utf-8">
+			<form class="table-like" method="post" action="?do=avatarput&amp;oid=[% user.get_oid %]" enctype="multipart/form-data" accept-charset="utf-8">
 				<h3>[% 'Current avatar' | i18n | html %]</h3>
-				<img alt="[% 'User\'s avatar' | i18n | html %]" src="/getavatar.pl?oid=[% user.get_oid %]"/>
+				<img alt="[% 'User\'s avatar' | i18n | html %]" src="?do=avatarget&amp;oid=[% user.get_oid %]"/>
 				<p>[% 'The avatar is a PNG image that will appear next to your username in the public section.' | i18n | html %]
 				</p>
-		        <input type="hidden" name="OID" value="[% user.get_oid %]"/>
+		        <input type="hidden" name="oid" value="[% user.get_oid %]"/>
 
 				<p><input type="file" name="avatar" tabindex="1" size="45"/></p>
 				<p><input type="submit" value="[% 'Update my avatar' | i18n | html %]" /></p>
+				<input type="hidden" name="do" value="avatarput"/>
 			</form>
 [% END %]
 
 			<h2>[% 'Delete YOUR user' | i18n | html %]</h2>
 			
-			<form method="post" action="/user/delete.pl" accept-charset="utf-8">
+			<form method="post" action="?do=userprefs" accept-charset="utf-8">
 			
 				<p>[% 'This action is non-reversible. Your user will be DESTROYED.' | i18n | html %]</p>
 				
 				<fieldset id="deleteUser" class="delete">
 					<legend>[% 'Are you SURE you want DELETE this user?' | i18n | html %]</legend>
 					<p>
-						<input type="radio" name="DELETE" id="DELETENo" value="0" checked="checked" />
+						<input type="radio" name="delete" id="deleteno" value="0" checked="checked" />
 						<label for="DELETENo">[% 'No, I\'m not sure, I\'d prefer to keep it.' | i18n | html %]</label>
 					</p>
 					<p>
-						<input type="radio" name="DELETE" id="DELETEYes" value="1" />
+						<input type="radio" name="delete" id="deleteyes" value="1" />
 						<label for="DELETEYes">[% 'Yes I\'m sure of what I do' | i18n | html %]</label>
 					</p>
 				</fieldset>
 				
 				<p class="button" id="buttonDelete">
-					<input type="hidden" name="name" value="[% user.get_username | html %]" />
-					<input type="submit" value="[% 'Delete my user' | i18n | html %]" />
+					<input type="hidden" name="name" value="[% user.get_username | html %]"/>
+					<input type="hidden" name="do" value="userprefs"/>
+					<input type="submit" value="[% 'Delete my user' | i18n | html %]" name="delete_submit" id="delete_submit"/>
 				</p>
                                 
 			</form>

Modified: trunk/vhffs-panel/templates/web/create.tt
===================================================================
--- trunk/vhffs-panel/templates/web/create.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/web/create.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -4,7 +4,7 @@
         [% group.get_groupname %]
 	</p>
 	<p>
-		<label for="servername">'Address (ServerName directive):'</label>
+		<label for="servername">Address (ServerName directive):</label>
 		<input type="text" name="servername" id="servername" value="[% servername | html %]"/>
 	</p>
 	<p class="warning">
@@ -21,4 +21,5 @@
 		<input type="hidden" name="group" value="[% group.get_groupname | html %]" />
 		<input type="submit" value="[% 'Send' %]" name="web_submit" />
 	</p>
+	<input type="hidden" name="do" value="webcreate"/>
 </form>

Modified: trunk/vhffs-panel/templates/web/prefs.tt
===================================================================
--- trunk/vhffs-panel/templates/web/prefs.tt	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-panel/templates/web/prefs.tt	2012-01-19 23:57:57 UTC (rev 1918)
@@ -1,6 +1,6 @@
 <h1>[% 'Web area administration' | i18n | html %]</h1>
 	
-<form class="table-like" method="post" action="/web/prefs.pl" accept-charset="utf-8">
+<form class="table-like" method="post" action="#" accept-charset="utf-8">
 	<p>
 		<label>[% 'Address (Servername):' | i18n | html %]</label>
 		[% web.get_servername | html %]
@@ -15,7 +15,7 @@
 	<p class="button">
 		<input value="[% 'Update' | i18n | html %]" type="submit" name="save_prefs_submit"/>
 	</p>
-
+	<input type="hidden" name="do" value="webprefs"/>
 </form>
 
 [% INCLUDE 'acl/form.tt'

Modified: trunk/vhffs-public/avatar.pl
===================================================================
--- trunk/vhffs-public/avatar.pl	2012-01-16 23:15:32 UTC (rev 1917)
+++ trunk/vhffs-public/avatar.pl	2012-01-19 23:57:57 UTC (rev 1918)
@@ -65,7 +65,7 @@
 
 if( ! ( defined $oid ) )
 {
-	print CGI->header( -type=>"text/html", -charset=>"utf-8" );
+	print $cgi->header( -type=>"text/html", -charset=>"utf-8" );
 	print "oid error";
 	exit 1;
 }
@@ -80,7 +80,7 @@
 
 # Assume the user has set FONT_PATH or TTF_FONT_PATH
 #$wp->font_path('/usr/share/fonts/ttfonts');
-print CGI->header( -type=>"image/png" );
+print $cgi->header( -type=>"image/png" );
 
 binmode STDOUT;
 


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/