[vhffs-dev] [807] Renaming Vhffs::Services::Mailing to Vhffs::Services::MailingList ( part two)

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


Revision: 807
Author:   gradator
Date:     2007-08-29 23:43:28 +0000 (Wed, 29 Aug 2007)

Log Message:
-----------
Renaming Vhffs::Services::Mailing to Vhffs::Services::MailingList (part two)

Modified Paths:
--------------
    trunk/vhffs-api/src/Vhffs/Makefile.am
    trunk/vhffs-tests/src/Makefile.am

Added Paths:
-----------
    trunk/vhffs-api/src/Vhffs/Services/MailingList.pm
    trunk/vhffs-tests/src/Services/MailingList.pl

Removed Paths:
-------------
    trunk/vhffs-api/src/Vhffs/Services/Mailing.pm
    trunk/vhffs-tests/src/Services/Mailing.pl


Modified: trunk/vhffs-api/src/Vhffs/Makefile.am
===================================================================
--- trunk/vhffs-api/src/Vhffs/Makefile.am	2007-08-29 23:41:26 UTC (rev 806)
+++ trunk/vhffs-api/src/Vhffs/Makefile.am	2007-08-29 23:43:28 UTC (rev 807)
@@ -57,7 +57,7 @@
 	Services/DNS.pm \
 	Services/Web.pm \
 	Services/Mail.pm \
-	Services/Mailing.pm \
+	Services/MailingList.pm \
 	Services/MailUser.pm \
 	Services/MailGroup.pm \
 	Services/Mysql.pm \

Deleted: trunk/vhffs-api/src/Vhffs/Services/Mailing.pm
===================================================================
--- trunk/vhffs-api/src/Vhffs/Services/Mailing.pm	2007-08-29 23:41:26 UTC (rev 806)
+++ trunk/vhffs-api/src/Vhffs/Services/Mailing.pm	2007-08-29 23:43:28 UTC (rev 807)
@@ -1,597 +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.
-
-
-# This file is a part of VHFFS4 software, a hosting platform suite
-# Please respect the licence of this file and whole program
-
-=pod
-
-=head1 NAME
-
-Vhffs::Services::MailingList - Handle mailing lists in VHFFS.
-
-=head1 SYNOPSIS
-
-TODO
-
-=head1 METHODS
-
-=cut
-
-package Vhffs::Services::MailingList;
-
-use base qw(Vhffs::Object);
-use strict;
-use DBI;
-
-=pod
-
-=head2 create
-
-    my $ml = Vhffs::Services::MailingList::create($local, $domain, $admin, $description, $user, $group);
-    die('Unable to create list') unless defined $ml;
-
-Creates a new mailing list in database and returns the corresponding fully functional object.
-Returns undef if an error occurs (box, forward or mailing list with the same address already
-exists, domain not found, ...).
-
-=cut
-sub create
-{
-    my ($main, $local, $domain, $admin, $description, $user, $group) = @_;
-    
-    return undef unless(defined $user && defined $group);
-    return undef unless($local =~ /^[a-z0-9\_\-]+$/);
-    return undef unless(Vhffs::Functions::check_domain_name($domain));
-    return undef if(Vhffs::Services::Mail::address_exists($main, $local, $domain));
-    $admin = $user->get_mail() unless(defined $admin);
-
-    my $ml;
-
-    my $dbh = $main->get_db_object();
-    local $dbh->{RaiseError} = 1;
-    local $dbh->{PrintError} = 0;
-    $dbh->begin_work;
-
-    eval {
-        # Group must be the mail domain owner or use default mail domain.
-        my $sql = 'SELECT mxdomain_id FROM vhffs_mxdomain m INNER JOIN vhffs_object o ON o.object_id = m.object_id WHERE m.domain = ? AND o.owner_gid = ?';
-        die('Mail domain not found') unless($domain eq $main->get_config()->get_service("mailing")->{'default_domain'} ||
-                            $dbh->do($sql, undef, $domain, $group->get_gid) > 0);
-
-        my $parent = Vhffs::Object::create($main, $user->get_uid, $group->get_gid, $description, undef, Vhffs::Constants::TYPE_ML);
-        die('Unable to create parent object') unless(defined $parent);
-
-	# open sub, post members only
-        $sql = 'INSERT INTO vhffs_ml(local_part, domain, prefix, object_id, admin, open_archive, reply_to, sub_ctrl, post_ctrl) VALUES(?, ?, ?, ?, ?, FALSE, TRUE, ?, ? )';
-        my $sth = $dbh->prepare($sql);
-        $sth->execute($local, $domain, $local, $parent->get_oid, $admin, Vhffs::Constants::ML_SUBSCRIBE_NO_APPROVAL_REQUIRED, Vhffs::Constants::ML_POSTING_MEMBERS_ONLY);
-        $dbh->commit;
-        $ml = get_by_mladdress($main, $local, $domain);
-    };
-
-    if($@) {
-        warn "Unable to create mailing list $local\@$domain: $@\n";
-        $dbh->rollback;
-    }
-
-    return $ml;
-
-}
-
-=pod
-
-=head2 get_by_mladdress
-
-    my $ml = Vhffs::Services::MailingList::get_by_mladdress($main, $local_part, $domain);
-    die("Mailing list $localpart\@$domain not found\n") unless(defined $ml);
-
-Fetches the mailing list $local_part@$domain.
-
-=cut
-
-sub get_by_mladdress {
-    my ($main, $local, $domain) = @_;
-    
-    my $dbh = $main->get_db_object();
-    my $sql = 'SELECT ml.ml_id, ml.local_part, ml.domain, ml.prefix, o.owner_gid, ml.admin, ml.open_archive, ml.reply_to, ml.sub_ctrl, ml.post_ctrl, ml.signature, o.object_id, o.owner_uid, o.date_creation, o.state, o.description FROM vhffs_ml ml INNER JOIN vhffs_object o ON o.object_id = ml.object_id WHERE domain = ? and local_part = ?';
-    my $sth = $dbh->prepare($sql);
-    return undef unless ($sth->execute($domain, $local) > 0);
-    my @params = $sth->fetchrow_array;
-
-    push @params, fetch_subs($dbh, $params[0]);
-    return _new Vhffs::Services::MailingList($main, @params);
-}
-
-=head2 fetch_subs
-
-    my $subs = fetch_subs($dbh, $ml_id);
-
-Returns an hashref of hashrefs containing all subscribers indexed on their
-mail addresses.
-
-Internal module use only.
-
-=cut
-
-sub fetch_subs {
-
-    my ($dbh, $ml_id) = @_;
-
-    my $sql = q{SELECT sub_id, member, perm, hash, ml_id, language
-        FROM vhffs_ml_subscribers WHERE ml_id = ?};
-    return $dbh->selectall_hashref($sql, 'member', undef, $ml_id);
-}
-
-=head2 fill_object
-
-See C<Vhffs::Object::fill_object>.
-
-=cut
-
-sub fill_object {
-    my ($class, $obj) = @_;
-    my $sql = q{SELECT ml_id, local_part, domain, prefix, admin, open_archive,
-        reply_to, sub_ctrl, post_ctrl, signature FROM vhffs_ml
-        WHERE object_id = ?};
-    $obj = $class->SUPER::_fill_object($obj, $sql);
-    if($obj->isa('Vhffs::Services::MailingList')) {
-        $obj->{subs} = fetch_subs($obj->get_db_object, $obj->{ml_id});
-    }
-    return $obj;
-}
-
-sub _new {
-    my ($class, $main, $ml_id, $local_part, $domain, $prefix, $owner_gid, $admin, $open_archive, $reply_to, $sub_ctrl, $post_ctrl, $signature, $oid, $owner_uid, $date_creation, $state, $description, $subs) = @_;
-
-    my $self = $class->SUPER::_new($main, $oid, $owner_uid, $owner_gid, $date_creation, $description, $state, Vhffs::Constants::TYPE_ML);
-    return undef unless defined($self);
-
-    $self->{ml_id} = $ml_id;
-    $self->{local_part} = $local_part;
-    $self->{domain} = $domain,
-    $self->{prefix} = $prefix;
-    $self->{admin} = $admin;
-    $self->{open_archive} = $open_archive;
-    $self->{reply_to} = $reply_to;
-    $self->{sub_ctrl} = $sub_ctrl;
-    $self->{post_ctrl} = $post_ctrl;
-    $self->{signature} = $signature;
-    $self->{subs} = $subs;
-
-    return $self;
-}
-
-# Commit all changes of the current instance in the database
-sub commit
-{
-    my $self = shift;	
-
-    my $sql = 'UPDATE vhffs_ml SET prefix = ?, admin = ?, open_archive = ?, reply_to = ?, sub_ctrl = ?, post_ctrl = ?, signature = ? WHERE ml_id = ?';
-    my $dbh = $self->get_main->get_db_object();
-    $dbh->do($sql, undef, $self->{prefix}, $self->{admin}, $self->{open_archive}, $self->{reply_to}, $self->{sub_ctrl}, $self->{post_ctrl}, $self->{signature}, $self->{ml_id});
-
-    return -3 if( $self->SUPER::commit < 0 );
-
-    return 1;
-}
-
-sub change_right_for_sub
-{
-    my ($self, $subscriber, $right) = @_;
-
-    my $sql = 'UPDATE vhffs_ml_subscribers SET perm = ? WHERE ml_id = ? AND member = ?';
-    my $dbh = $self->get_main->get_db_object();
-    # FIXME compatibility hack, we should return a boolean
-    return -1 unless($dbh->do($sql, undef, $right, $self->{ml_id}, $subscriber) > 0);
-    $self->{subs}->{$subscriber}->{perm} = $right;
-    return 1;
-}
-
-
-sub add_sub
-{
-    my $self = shift;
-    my $subscriber = shift;
-    my $right = shift;
-
-    return -1 if( Vhffs::Functions::valid_mail( $subscriber ) != 1 );
-    return -2 if( $subscriber =~ /.*<.*/ );
-    return -2 if( $subscriber =~ /.*>.*/ );
-    return -2 if( $subscriber =~ /.*\s.*/ );
-    return -1 if( ! ( $right =~ /^[\d]+$/ ) );
-
-    my $sql = 'INSERT INTO vhffs_ml_subscribers (member, perm, hash, ml_id, language) VALUES (?, ?, NULL, ?, NULL)';
-    my $dbh = $self->get_main->get_db_object();
-    $dbh->do($sql, undef, $subscriber, $right, $self->{ml_id}) or return -2;
-
-    my $id = $dbh->last_insert_id(undef, undef, 'vhffs_ml_subscribers', undef);
-
-    $self->{subs}->{$subscriber} = {
-        sub_id => $id,
-        member => $subscriber,
-        perm => $right,
-        hash => undef,
-        ml_id => $self->{ml_id},
-        language => undef
-    };
-
-    return 1;
-}
-
-
-
-#add a subscriber, return undef if already exists
-sub add_sub_with_reply
-{
-    my $self = shift;
-    my $subscriber = shift;
-
-    return undef if( Vhffs::Functions::valid_mail( $subscriber ) != 1 );
-    return undef if( $subscriber =~ /.*<.*/ );
-    return undef if( $subscriber =~ /.*>.*/ );
-    return undef if( $subscriber =~ /.*\s.*/ );
-
-    my $pass = Vhffs::Functions::generate_random_password;
-
-    my $sql = 'INSERT INTO vhffs_ml_subscribers(member, perm, hash, ml_id, language) VALUES(?, ?, ?, ?, NULL)';
-    my $dbh = $self->get_main->get_db_object();
-    $dbh->do($sql, undef, $subscriber, Vhffs::Constants::ML_RIGHT_SUB_WAITING_FOR_REPLY, $pass, $self->{ml_id}) or return undef;
-
-    my $id = $dbh->last_insert_id(undef, undef, 'vhffs_ml_subscribers', undef);
-
-    $self->{subs}->{$subscriber} = {
-        sub_id => $id,
-        member => $subscriber,
-        perm => Vhffs::Constants::ML_RIGHT_SUB_WAITING_FOR_REPLY,
-        hash => $pass,
-        ml_id => $self->{ml_id},
-        language => undef
-    };
-
-    return $pass;
-}
-
-
-
-sub del_sub
-{
-    my $self = shift;
-    my $subscriber = shift;
-
-    my $sql = 'DELETE FROM vhffs_ml_subscribers WHERE ml_id = ? AND member = ?';
-    # FIXME we should return a boolean
-    return -1 unless($self->get_main->get_db_object->do($sql, undef, $self->{ml_id}, $subscriber) > 0);
-
-    delete $self->{subs}->{$subscriber};
-    return 1;
-}
-
-# FIXME useless
-sub change_state_for_sub
-{
-    return change_right_for_sub(@_);
-}
-
-sub set_randomhash
-{
-    my $self = shift;
-    my $subscriber = shift;
-    my $pass = Vhffs::Functions::generate_random_password;
-
-    my $sql = 'UPDATE vhffs_ml_subscribers SET hash = ? WHERE ml_id = ? AND member = ?';
-    return undef unless($self->get_main->get_db_object->do($sql, undef, $pass, $self->{ml_id}, $subscriber) > 0);
-    
-    $self->{subs}->{$subscriber}->{hash} = $pass;
-    return $pass;
-}
-
-
-sub clear_hash
-{
-    my $self = shift;
-    my $subscriber = shift;
-
-    my $sql = 'UPDATE vhffs_ml_subscribers SET hash = NULL WHERE ml_id = ? AND member = ?';
-    # FIXME we should return a boolean
-    return -1 unless($self->get_main->get_db_object->do($sql, undef, $self->{ml_id}, $subscriber) > 0);
-    
-    $self->{subs}->{$subscriber}->{hash} = undef;
-    return 1;
-}
-
-=head2 address_exists
-
-    print("A mailing list with the same address already exists\n")
-        if Vhffs::Mailing::address_exists($vhffs, $local_part, $domain);
-
-Return true if a mailing list C<$local_part>@C<$domain> already exists.
-
-=cut
-
-sub address_exists($$$) {
-    my ($vhffs, $local_part, $domain) = @_;
-
-    my $sql = 'SELECT COUNT(*) FROM vhffs_ml WHERE local_part = ? AND domain = ?';
-    my $dbh = $vhffs->get_db_object();
-    my $res = $dbh->selectrow_array($sql, {}, $local_part, $domain);
-    return (defined($res) && $res > 0);
-}
-
-sub del_sub_with_reply
-{
-    use Digest::MD5;
-
-    my $self = shift;
-    my $subscriber = shift;
-
-    
-    my $hash = Digest::MD5::md5_hex( Vhffs::Functions::generate_random_password );
-
-    my $sql = 'UPDATE vhffs_ml_subscribers SET perm = ?, hash = ? WHERE ml_id = ? AND member = ? AND perm IN (?, ?)';
-    # FIXME we should return a boolean
-    return undef unless($self->get_main->get_db_object->do($sql, undef, Vhffs::Constants::ML_RIGHT_SUB_WAITING_FOR_DEL, $hash, $self->{ml_id}, $subscriber, Vhffs::Constants::ML_RIGHT_SUB, Vhffs::Constants::ML_RIGHT_ADMIN) > 0);
-
-    $self->{subs}->{$subscriber}->{hash} = $hash;
-    $self->{subs}->{$subscriber}->{perm} = Vhffs::Constants::ML_RIGHT_SUB_WAITING_FOR_DEL;
-    return $hash;
-}
-
-sub get_language_for_sub
-{
-    my ($main, $sub) = @_;
-
-    my $sql = 'SELECT language FROM vhffs_ml_subscribers WHERE member = ?';
-    my $lang = $main->get_db_object->selectrow_array($sql, undef, $sub);
-    return $lang;
-}
-
-sub set_language_for_sub
-{
-    my ($main, $sub, $language) = @_;
-
-    $language = 'en_US' unless( $language =~ /^\w+$/ );
-    my $sql = 'UPDATE vhffs_ml_subscribers SET language = ? WHERE member = ?';
-    $main->get_db_object->do($sql, undef, $language, $sub) or return -1;
-}
-
-sub get_localpart
-{
-    my $self = shift;
-    return $self->{'local_part'};
-}
-
-sub get_signature
-{
-    my $self = shift;
-    return $self->{signature};
-}
-
-sub set_signature
-{
-    my ($self, $sig) = @_;
-    $sig =~ s/\r\n/\n/;
-    $self->{signature} = $sig;
-}
-
-sub get_open_archive
-{
-    my $self = shift;
-    return $self->{'open_archive'};
-}
-
-sub get_sub_ctrl
-{
-    my $self = shift;
-    return $self->{'sub_ctrl'};
-}
-
-sub get_post_ctrl
-{
-    my $self = shift;
-    return $self->{'post_ctrl'};
-}
-
-sub get_replyto
-{
-    my $self = shift;
-    return $self->{'reply_to'};
-}
-
-sub get_admin
-{
-    my $self = shift;
-    return $self->{'admin'};
-}
-
-sub get_domain
-{
-    my $self = shift;
-    return $self->{'domain'};
-}
-
-sub get_prefix
-{
-    my $self = shift;
-    return $self->{'prefix'};
-}
-
-sub get_members
-{
-    my $self = shift;
-    return $self->{subs};
-}
-
-sub set_replytolist
-{
-    my $self;
-    my $string = $self->{'local_part'} ."\@" . $self->{'domain'} ;
-    return $self->set_replyto( $string );
-}
-
-sub set_replyto
-{
-    my( $self , $value ) = @_;
-	return -2 if( ( $value != 0 ) && ( $value != 1 ) );
-    $self->{'reply_to'} = $value;
-    return 1;
-}
-
-sub set_open_archive
-{
-    my( $self , $value ) = @_;
-    $self->{'open_archive'} = $value;
-}
-
-sub set_sub_ctrl
-{
-	my( $self , $value ) = @_;
-	return -1 unless ( $value =~ /\d+/ );
-	return -1 if( $value < Vhffs::Constants::ML_SUBSCRIBE_NO_APPROVAL_REQUIRED || $value > Vhffs::Constants::ML_SUBSCRIBE_CLOSED );
-	$self->{'sub_ctrl'} = $value;
-	return 0;
-}
-
-sub set_post_ctrl
-{
-	my( $self , $value ) = @_;
-	return -1 unless ( $value =~ /\d+/ );
-	return -1 if ( $value < Vhffs::Constants::ML_POSTING_OPEN_ALL || $value > Vhffs::Constants::ML_POSTING_ADMINS_ONLY );
-	$self->{'post_ctrl'} = $value;
-	return 0;
-}
-
-sub set_admin
-{
-    my $self = shift;
-    my $value = shift;
-    $self->{'admin'} = $value;
-}
-
-sub set_prefix
-{
-    my( $self , $value ) = @_;
-
-    $self->{'prefix'} = $value;
-}
-
-sub getall_subs
-{
-    my $self = shift;
-    return ( keys %{$self->{subs}} );
-}
-
-sub getall
-{
-    my ($vhffs, $state, $name, $group, $domain) = @_;
-
-    return undef if( ! defined $vhffs );
-
-    my $mls = [];
-    my @params;
-    my $sql = 'SELECT local_part, domain FROM vhffs_ml ml, vhffs_object o WHERE o.object_id = ml.object_id';
-
-    if(defined $state) {
-        $sql .= ' AND o.state = ?';
-        push @params, $state;
-    }
-    if(defined $group) {
-        $sql .= ' AND o.owner_gid = ?';
-        push @params, $group->get_gid;
-    }
-    if(defined $name) {
-        $sql .= ' AND ( local_part LIKE ? OR domain LIKE ?)';
-        push @params, '%'.$name.'%', '%'.$name.'%';
-    }
-    if(defined $domain) {
-        $sql .= ' AND domain = ?';
-        push @params, $domain;
-    }
-
-    $sql .= ' ORDER BY local_part, domain';
-
-    my $dbh = $vhffs->get_db_object;
-    my $sth = $dbh->prepare($sql);
-    $sth->execute(@params) or return -3;
-
-    while(my @ml = $sth->fetchrow_array) {
-        push @$mls, get_by_mladdress($vhffs, @ml);
-    }
-    return $mls;
-}
-
-
-
-#Returns all the lists for a group
-# FIXME useless
-sub getall_by_group
-{
-    my $vhffs = shift;
-    my $group = shift;
-
-    return getall($vhffs, undef, undef, $group);
-}
-
-=head2 get_label
-
-See C<Vhffs::Object::get_label>.
-
-=cut
-
-sub get_label {
-    my $self = shift;
-    return $self->{local_part}.'@'.$self->{domain};
-}
-
-
-
-sub get_title
-{
-    my $self = shift;
-    return $self->{local_part} . "\@" . $self->{domain};
-}
-
-sub get_listname
-{
-    my $self = shift;
-    return $self->get_localpart."\@".$self->get_domain;
-}
-
-1;
-
-__END__
-
-=head1 AUTHORS
-
-Julien Delange < god at gunnm dot org >
-Sebastien Le Ray < beuss at tuxfamily dot org >
-Sylvain Rochet < gradator at gradator dot net >

Copied: trunk/vhffs-api/src/Vhffs/Services/MailingList.pm (from rev 806, trunk/vhffs-api/src/Vhffs/Services/Mailing.pm)
===================================================================
--- trunk/vhffs-api/src/Vhffs/Services/MailingList.pm	                        (rev 0)
+++ trunk/vhffs-api/src/Vhffs/Services/MailingList.pm	2007-08-29 23:43:28 UTC (rev 807)
@@ -0,0 +1,597 @@
+#!%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.
+
+
+# This file is a part of VHFFS4 software, a hosting platform suite
+# Please respect the licence of this file and whole program
+
+=pod
+
+=head1 NAME
+
+Vhffs::Services::MailingList - Handle mailing lists in VHFFS.
+
+=head1 SYNOPSIS
+
+TODO
+
+=head1 METHODS
+
+=cut
+
+package Vhffs::Services::MailingList;
+
+use base qw(Vhffs::Object);
+use strict;
+use DBI;
+
+=pod
+
+=head2 create
+
+    my $ml = Vhffs::Services::MailingList::create($local, $domain, $admin, $description, $user, $group);
+    die('Unable to create list') unless defined $ml;
+
+Creates a new mailing list in database and returns the corresponding fully functional object.
+Returns undef if an error occurs (box, forward or mailing list with the same address already
+exists, domain not found, ...).
+
+=cut
+sub create
+{
+    my ($main, $local, $domain, $admin, $description, $user, $group) = @_;
+    
+    return undef unless(defined $user && defined $group);
+    return undef unless($local =~ /^[a-z0-9\_\-]+$/);
+    return undef unless(Vhffs::Functions::check_domain_name($domain));
+    return undef if(Vhffs::Services::Mail::address_exists($main, $local, $domain));
+    $admin = $user->get_mail() unless(defined $admin);
+
+    my $ml;
+
+    my $dbh = $main->get_db_object();
+    local $dbh->{RaiseError} = 1;
+    local $dbh->{PrintError} = 0;
+    $dbh->begin_work;
+
+    eval {
+        # Group must be the mail domain owner or use default mail domain.
+        my $sql = 'SELECT mxdomain_id FROM vhffs_mxdomain m INNER JOIN vhffs_object o ON o.object_id = m.object_id WHERE m.domain = ? AND o.owner_gid = ?';
+        die('Mail domain not found') unless($domain eq $main->get_config()->get_service("mailing")->{'default_domain'} ||
+                            $dbh->do($sql, undef, $domain, $group->get_gid) > 0);
+
+        my $parent = Vhffs::Object::create($main, $user->get_uid, $group->get_gid, $description, undef, Vhffs::Constants::TYPE_ML);
+        die('Unable to create parent object') unless(defined $parent);
+
+	# open sub, post members only
+        $sql = 'INSERT INTO vhffs_ml(local_part, domain, prefix, object_id, admin, open_archive, reply_to, sub_ctrl, post_ctrl) VALUES(?, ?, ?, ?, ?, FALSE, TRUE, ?, ? )';
+        my $sth = $dbh->prepare($sql);
+        $sth->execute($local, $domain, $local, $parent->get_oid, $admin, Vhffs::Constants::ML_SUBSCRIBE_NO_APPROVAL_REQUIRED, Vhffs::Constants::ML_POSTING_MEMBERS_ONLY);
+        $dbh->commit;
+        $ml = get_by_mladdress($main, $local, $domain);
+    };
+
+    if($@) {
+        warn "Unable to create mailing list $local\@$domain: $@\n";
+        $dbh->rollback;
+    }
+
+    return $ml;
+
+}
+
+=pod
+
+=head2 get_by_mladdress
+
+    my $ml = Vhffs::Services::MailingList::get_by_mladdress($main, $local_part, $domain);
+    die("Mailing list $localpart\@$domain not found\n") unless(defined $ml);
+
+Fetches the mailing list $local_part@$domain.
+
+=cut
+
+sub get_by_mladdress {
+    my ($main, $local, $domain) = @_;
+    
+    my $dbh = $main->get_db_object();
+    my $sql = 'SELECT ml.ml_id, ml.local_part, ml.domain, ml.prefix, o.owner_gid, ml.admin, ml.open_archive, ml.reply_to, ml.sub_ctrl, ml.post_ctrl, ml.signature, o.object_id, o.owner_uid, o.date_creation, o.state, o.description FROM vhffs_ml ml INNER JOIN vhffs_object o ON o.object_id = ml.object_id WHERE domain = ? and local_part = ?';
+    my $sth = $dbh->prepare($sql);
+    return undef unless ($sth->execute($domain, $local) > 0);
+    my @params = $sth->fetchrow_array;
+
+    push @params, fetch_subs($dbh, $params[0]);
+    return _new Vhffs::Services::MailingList($main, @params);
+}
+
+=head2 fetch_subs
+
+    my $subs = fetch_subs($dbh, $ml_id);
+
+Returns an hashref of hashrefs containing all subscribers indexed on their
+mail addresses.
+
+Internal module use only.
+
+=cut
+
+sub fetch_subs {
+
+    my ($dbh, $ml_id) = @_;
+
+    my $sql = q{SELECT sub_id, member, perm, hash, ml_id, language
+        FROM vhffs_ml_subscribers WHERE ml_id = ?};
+    return $dbh->selectall_hashref($sql, 'member', undef, $ml_id);
+}
+
+=head2 fill_object
+
+See C<Vhffs::Object::fill_object>.
+
+=cut
+
+sub fill_object {
+    my ($class, $obj) = @_;
+    my $sql = q{SELECT ml_id, local_part, domain, prefix, admin, open_archive,
+        reply_to, sub_ctrl, post_ctrl, signature FROM vhffs_ml
+        WHERE object_id = ?};
+    $obj = $class->SUPER::_fill_object($obj, $sql);
+    if($obj->isa('Vhffs::Services::MailingList')) {
+        $obj->{subs} = fetch_subs($obj->get_db_object, $obj->{ml_id});
+    }
+    return $obj;
+}
+
+sub _new {
+    my ($class, $main, $ml_id, $local_part, $domain, $prefix, $owner_gid, $admin, $open_archive, $reply_to, $sub_ctrl, $post_ctrl, $signature, $oid, $owner_uid, $date_creation, $state, $description, $subs) = @_;
+
+    my $self = $class->SUPER::_new($main, $oid, $owner_uid, $owner_gid, $date_creation, $description, $state, Vhffs::Constants::TYPE_ML);
+    return undef unless defined($self);
+
+    $self->{ml_id} = $ml_id;
+    $self->{local_part} = $local_part;
+    $self->{domain} = $domain,
+    $self->{prefix} = $prefix;
+    $self->{admin} = $admin;
+    $self->{open_archive} = $open_archive;
+    $self->{reply_to} = $reply_to;
+    $self->{sub_ctrl} = $sub_ctrl;
+    $self->{post_ctrl} = $post_ctrl;
+    $self->{signature} = $signature;
+    $self->{subs} = $subs;
+
+    return $self;
+}
+
+# Commit all changes of the current instance in the database
+sub commit
+{
+    my $self = shift;	
+
+    my $sql = 'UPDATE vhffs_ml SET prefix = ?, admin = ?, open_archive = ?, reply_to = ?, sub_ctrl = ?, post_ctrl = ?, signature = ? WHERE ml_id = ?';
+    my $dbh = $self->get_main->get_db_object();
+    $dbh->do($sql, undef, $self->{prefix}, $self->{admin}, $self->{open_archive}, $self->{reply_to}, $self->{sub_ctrl}, $self->{post_ctrl}, $self->{signature}, $self->{ml_id});
+
+    return -3 if( $self->SUPER::commit < 0 );
+
+    return 1;
+}
+
+sub change_right_for_sub
+{
+    my ($self, $subscriber, $right) = @_;
+
+    my $sql = 'UPDATE vhffs_ml_subscribers SET perm = ? WHERE ml_id = ? AND member = ?';
+    my $dbh = $self->get_main->get_db_object();
+    # FIXME compatibility hack, we should return a boolean
+    return -1 unless($dbh->do($sql, undef, $right, $self->{ml_id}, $subscriber) > 0);
+    $self->{subs}->{$subscriber}->{perm} = $right;
+    return 1;
+}
+
+
+sub add_sub
+{
+    my $self = shift;
+    my $subscriber = shift;
+    my $right = shift;
+
+    return -1 if( Vhffs::Functions::valid_mail( $subscriber ) != 1 );
+    return -2 if( $subscriber =~ /.*<.*/ );
+    return -2 if( $subscriber =~ /.*>.*/ );
+    return -2 if( $subscriber =~ /.*\s.*/ );
+    return -1 if( ! ( $right =~ /^[\d]+$/ ) );
+
+    my $sql = 'INSERT INTO vhffs_ml_subscribers (member, perm, hash, ml_id, language) VALUES (?, ?, NULL, ?, NULL)';
+    my $dbh = $self->get_main->get_db_object();
+    $dbh->do($sql, undef, $subscriber, $right, $self->{ml_id}) or return -2;
+
+    my $id = $dbh->last_insert_id(undef, undef, 'vhffs_ml_subscribers', undef);
+
+    $self->{subs}->{$subscriber} = {
+        sub_id => $id,
+        member => $subscriber,
+        perm => $right,
+        hash => undef,
+        ml_id => $self->{ml_id},
+        language => undef
+    };
+
+    return 1;
+}
+
+
+
+#add a subscriber, return undef if already exists
+sub add_sub_with_reply
+{
+    my $self = shift;
+    my $subscriber = shift;
+
+    return undef if( Vhffs::Functions::valid_mail( $subscriber ) != 1 );
+    return undef if( $subscriber =~ /.*<.*/ );
+    return undef if( $subscriber =~ /.*>.*/ );
+    return undef if( $subscriber =~ /.*\s.*/ );
+
+    my $pass = Vhffs::Functions::generate_random_password;
+
+    my $sql = 'INSERT INTO vhffs_ml_subscribers(member, perm, hash, ml_id, language) VALUES(?, ?, ?, ?, NULL)';
+    my $dbh = $self->get_main->get_db_object();
+    $dbh->do($sql, undef, $subscriber, Vhffs::Constants::ML_RIGHT_SUB_WAITING_FOR_REPLY, $pass, $self->{ml_id}) or return undef;
+
+    my $id = $dbh->last_insert_id(undef, undef, 'vhffs_ml_subscribers', undef);
+
+    $self->{subs}->{$subscriber} = {
+        sub_id => $id,
+        member => $subscriber,
+        perm => Vhffs::Constants::ML_RIGHT_SUB_WAITING_FOR_REPLY,
+        hash => $pass,
+        ml_id => $self->{ml_id},
+        language => undef
+    };
+
+    return $pass;
+}
+
+
+
+sub del_sub
+{
+    my $self = shift;
+    my $subscriber = shift;
+
+    my $sql = 'DELETE FROM vhffs_ml_subscribers WHERE ml_id = ? AND member = ?';
+    # FIXME we should return a boolean
+    return -1 unless($self->get_main->get_db_object->do($sql, undef, $self->{ml_id}, $subscriber) > 0);
+
+    delete $self->{subs}->{$subscriber};
+    return 1;
+}
+
+# FIXME useless
+sub change_state_for_sub
+{
+    return change_right_for_sub(@_);
+}
+
+sub set_randomhash
+{
+    my $self = shift;
+    my $subscriber = shift;
+    my $pass = Vhffs::Functions::generate_random_password;
+
+    my $sql = 'UPDATE vhffs_ml_subscribers SET hash = ? WHERE ml_id = ? AND member = ?';
+    return undef unless($self->get_main->get_db_object->do($sql, undef, $pass, $self->{ml_id}, $subscriber) > 0);
+    
+    $self->{subs}->{$subscriber}->{hash} = $pass;
+    return $pass;
+}
+
+
+sub clear_hash
+{
+    my $self = shift;
+    my $subscriber = shift;
+
+    my $sql = 'UPDATE vhffs_ml_subscribers SET hash = NULL WHERE ml_id = ? AND member = ?';
+    # FIXME we should return a boolean
+    return -1 unless($self->get_main->get_db_object->do($sql, undef, $self->{ml_id}, $subscriber) > 0);
+    
+    $self->{subs}->{$subscriber}->{hash} = undef;
+    return 1;
+}
+
+=head2 address_exists
+
+    print("A mailing list with the same address already exists\n")
+        if Vhffs::Mailing::address_exists($vhffs, $local_part, $domain);
+
+Return true if a mailing list C<$local_part>@C<$domain> already exists.
+
+=cut
+
+sub address_exists($$$) {
+    my ($vhffs, $local_part, $domain) = @_;
+
+    my $sql = 'SELECT COUNT(*) FROM vhffs_ml WHERE local_part = ? AND domain = ?';
+    my $dbh = $vhffs->get_db_object();
+    my $res = $dbh->selectrow_array($sql, {}, $local_part, $domain);
+    return (defined($res) && $res > 0);
+}
+
+sub del_sub_with_reply
+{
+    use Digest::MD5;
+
+    my $self = shift;
+    my $subscriber = shift;
+
+    
+    my $hash = Digest::MD5::md5_hex( Vhffs::Functions::generate_random_password );
+
+    my $sql = 'UPDATE vhffs_ml_subscribers SET perm = ?, hash = ? WHERE ml_id = ? AND member = ? AND perm IN (?, ?)';
+    # FIXME we should return a boolean
+    return undef unless($self->get_main->get_db_object->do($sql, undef, Vhffs::Constants::ML_RIGHT_SUB_WAITING_FOR_DEL, $hash, $self->{ml_id}, $subscriber, Vhffs::Constants::ML_RIGHT_SUB, Vhffs::Constants::ML_RIGHT_ADMIN) > 0);
+
+    $self->{subs}->{$subscriber}->{hash} = $hash;
+    $self->{subs}->{$subscriber}->{perm} = Vhffs::Constants::ML_RIGHT_SUB_WAITING_FOR_DEL;
+    return $hash;
+}
+
+sub get_language_for_sub
+{
+    my ($main, $sub) = @_;
+
+    my $sql = 'SELECT language FROM vhffs_ml_subscribers WHERE member = ?';
+    my $lang = $main->get_db_object->selectrow_array($sql, undef, $sub);
+    return $lang;
+}
+
+sub set_language_for_sub
+{
+    my ($main, $sub, $language) = @_;
+
+    $language = 'en_US' unless( $language =~ /^\w+$/ );
+    my $sql = 'UPDATE vhffs_ml_subscribers SET language = ? WHERE member = ?';
+    $main->get_db_object->do($sql, undef, $language, $sub) or return -1;
+}
+
+sub get_localpart
+{
+    my $self = shift;
+    return $self->{'local_part'};
+}
+
+sub get_signature
+{
+    my $self = shift;
+    return $self->{signature};
+}
+
+sub set_signature
+{
+    my ($self, $sig) = @_;
+    $sig =~ s/\r\n/\n/;
+    $self->{signature} = $sig;
+}
+
+sub get_open_archive
+{
+    my $self = shift;
+    return $self->{'open_archive'};
+}
+
+sub get_sub_ctrl
+{
+    my $self = shift;
+    return $self->{'sub_ctrl'};
+}
+
+sub get_post_ctrl
+{
+    my $self = shift;
+    return $self->{'post_ctrl'};
+}
+
+sub get_replyto
+{
+    my $self = shift;
+    return $self->{'reply_to'};
+}
+
+sub get_admin
+{
+    my $self = shift;
+    return $self->{'admin'};
+}
+
+sub get_domain
+{
+    my $self = shift;
+    return $self->{'domain'};
+}
+
+sub get_prefix
+{
+    my $self = shift;
+    return $self->{'prefix'};
+}
+
+sub get_members
+{
+    my $self = shift;
+    return $self->{subs};
+}
+
+sub set_replytolist
+{
+    my $self;
+    my $string = $self->{'local_part'} ."\@" . $self->{'domain'} ;
+    return $self->set_replyto( $string );
+}
+
+sub set_replyto
+{
+    my( $self , $value ) = @_;
+	return -2 if( ( $value != 0 ) && ( $value != 1 ) );
+    $self->{'reply_to'} = $value;
+    return 1;
+}
+
+sub set_open_archive
+{
+    my( $self , $value ) = @_;
+    $self->{'open_archive'} = $value;
+}
+
+sub set_sub_ctrl
+{
+	my( $self , $value ) = @_;
+	return -1 unless ( $value =~ /\d+/ );
+	return -1 if( $value < Vhffs::Constants::ML_SUBSCRIBE_NO_APPROVAL_REQUIRED || $value > Vhffs::Constants::ML_SUBSCRIBE_CLOSED );
+	$self->{'sub_ctrl'} = $value;
+	return 0;
+}
+
+sub set_post_ctrl
+{
+	my( $self , $value ) = @_;
+	return -1 unless ( $value =~ /\d+/ );
+	return -1 if ( $value < Vhffs::Constants::ML_POSTING_OPEN_ALL || $value > Vhffs::Constants::ML_POSTING_ADMINS_ONLY );
+	$self->{'post_ctrl'} = $value;
+	return 0;
+}
+
+sub set_admin
+{
+    my $self = shift;
+    my $value = shift;
+    $self->{'admin'} = $value;
+}
+
+sub set_prefix
+{
+    my( $self , $value ) = @_;
+
+    $self->{'prefix'} = $value;
+}
+
+sub getall_subs
+{
+    my $self = shift;
+    return ( keys %{$self->{subs}} );
+}
+
+sub getall
+{
+    my ($vhffs, $state, $name, $group, $domain) = @_;
+
+    return undef if( ! defined $vhffs );
+
+    my $mls = [];
+    my @params;
+    my $sql = 'SELECT local_part, domain FROM vhffs_ml ml, vhffs_object o WHERE o.object_id = ml.object_id';
+
+    if(defined $state) {
+        $sql .= ' AND o.state = ?';
+        push @params, $state;
+    }
+    if(defined $group) {
+        $sql .= ' AND o.owner_gid = ?';
+        push @params, $group->get_gid;
+    }
+    if(defined $name) {
+        $sql .= ' AND ( local_part LIKE ? OR domain LIKE ?)';
+        push @params, '%'.$name.'%', '%'.$name.'%';
+    }
+    if(defined $domain) {
+        $sql .= ' AND domain = ?';
+        push @params, $domain;
+    }
+
+    $sql .= ' ORDER BY local_part, domain';
+
+    my $dbh = $vhffs->get_db_object;
+    my $sth = $dbh->prepare($sql);
+    $sth->execute(@params) or return -3;
+
+    while(my @ml = $sth->fetchrow_array) {
+        push @$mls, get_by_mladdress($vhffs, @ml);
+    }
+    return $mls;
+}
+
+
+
+#Returns all the lists for a group
+# FIXME useless
+sub getall_by_group
+{
+    my $vhffs = shift;
+    my $group = shift;
+
+    return getall($vhffs, undef, undef, $group);
+}
+
+=head2 get_label
+
+See C<Vhffs::Object::get_label>.
+
+=cut
+
+sub get_label {
+    my $self = shift;
+    return $self->{local_part}.'@'.$self->{domain};
+}
+
+
+
+sub get_title
+{
+    my $self = shift;
+    return $self->{local_part} . "\@" . $self->{domain};
+}
+
+sub get_listname
+{
+    my $self = shift;
+    return $self->get_localpart."\@".$self->get_domain;
+}
+
+1;
+
+__END__
+
+=head1 AUTHORS
+
+Julien Delange < god at gunnm dot org >
+Sebastien Le Ray < beuss at tuxfamily dot org >
+Sylvain Rochet < gradator at gradator dot net >

Modified: trunk/vhffs-tests/src/Makefile.am
===================================================================
--- trunk/vhffs-tests/src/Makefile.am	2007-08-29 23:41:26 UTC (rev 806)
+++ trunk/vhffs-tests/src/Makefile.am	2007-08-29 23:43:28 UTC (rev 807)
@@ -1,5 +1,5 @@
 TESTS_ENVIRONMENT = @PERL@ -I . -I ../../vhffs-api/src/
 TESTS = Object.pl Group.pl User.pl Stats.pl Services/Svn.pl \
 	Services/Cvs.pl Services/Web.pl Services/DNS.pl Services/Mail.pl \
-	Services/Mailing.pl Services/Mysql.pl Services/Pgsql.pl \
+	Services/MailingList.pl Services/Mysql.pl Services/Pgsql.pl \
 	Functions.pl Services/Repository.pl

Deleted: trunk/vhffs-tests/src/Services/Mailing.pl
===================================================================
--- trunk/vhffs-tests/src/Services/Mailing.pl	2007-08-29 23:41:26 UTC (rev 806)
+++ trunk/vhffs-tests/src/Services/Mailing.pl	2007-08-29 23:43:28 UTC (rev 807)
@@ -1,45 +0,0 @@
-use strict;
-use Vhffs::Tests::Main;
-use Vhffs::Tests::Utils;
-use Vhffs::Constants;
-use Vhffs::User;
-use Vhffs::Services::Mail;
-use Vhffs::Services::MailingList;
-use Test::More 'no_plan';
-
-my $main = init Vhffs::Tests::Main;
-isa_ok($main, 'Vhffs::Tests::Main', '$main');
-
-Vhffs::Tests::Utils::init_db($main->get_db_object);
-
-my $user1 = Vhffs::User::create($main, 'test1', 'abcdef', 0, 'test1@xxxxxxxx');
-isa_ok($user1, 'Vhffs::User', '$user1');
-
-my $group1 = Vhffs::Group::create($main, 'mailgroup1', $user1->get_uid, undef, 'Test group for Mail Domain');
-isa_ok($group1, 'Vhffs::Group', '$group1');
-
-my $mail1 = Vhffs::Services::Mail::create($main, 'test.com', 'Test mail domain 1', $user1, $group1);
-isa_ok($mail1, 'Vhffs::Services::Mail', '$mail1');
-cmp_ok($mail1->get_owner_uid, '==', $user1->get_uid, 'uid matches');
-cmp_ok($mail1->get_owner_gid, '==', $group1->get_gid, 'gid matches');
-
-my $ml1 = Vhffs::Services::MailingList::create($main, 'list1', 'test.com', 'admin@xxxxxxxx', 'Test ml 1', $user1, $group1);
-isa_ok($ml1, 'Vhffs::Services::MailingList', '$ml1');
-cmp_ok($ml1->get_localpart, 'eq', 'list1', 'Local part matches');
-cmp_ok($ml1->get_domain, 'eq', 'test.com', 'Mail domain matches');
-
-my ($max_oid) = $main->get_db_object->selectrow_array('SELECT MAX(object_id) FROM vhffs_object');
-ok(! defined(Vhffs::Services::MailingList::create($main, 'list1', 'test.com', 'admin@xxxxxxxx', 'Test ml 1', $user1, $group1)), 'Unable to create 2 lists with the same name');
-my ($new_max_oid) = $main->get_db_object->selectrow_array('SELECT MAX(object_id) FROM vhffs_object');
-cmp_ok($new_max_oid, '==', $max_oid, 'Mailing list service creation is a "all or nothing" process');
-
-$ml1->add_sub('toto@xxxxxxxx', Vhffs::Constants::ML_RIGHT_SUB);
-cmp_ok(keys(%{$ml1->{subs}}), '==', 1, 'One subscriber registered');
-
-my $tmpml = Vhffs::Services::MailingList::get_by_mladdress($main, 'list1', 'test.com');
-my $subs = $tmpml->{subs};
-cmp_ok(keys(%$subs), '==', 1, 'One subscriber registered (fetched)');
-ok(defined $subs->{'toto@xxxxxxxx'}, 'Subscriber key is email address');
-my $sub = $subs->{'toto@xxxxxxxx'};
-cmp_ok($sub->{member}, 'eq', 'toto@xxxxxxxx', 'Email address matches');
-cmp_ok($sub->{perm}, '==', Vhffs::Constants::ML_RIGHT_SUB, 'Permissions matches');

Copied: trunk/vhffs-tests/src/Services/MailingList.pl (from rev 806, trunk/vhffs-tests/src/Services/Mailing.pl)
===================================================================
--- trunk/vhffs-tests/src/Services/MailingList.pl	                        (rev 0)
+++ trunk/vhffs-tests/src/Services/MailingList.pl	2007-08-29 23:43:28 UTC (rev 807)
@@ -0,0 +1,45 @@
+use strict;
+use Vhffs::Tests::Main;
+use Vhffs::Tests::Utils;
+use Vhffs::Constants;
+use Vhffs::User;
+use Vhffs::Services::Mail;
+use Vhffs::Services::MailingList;
+use Test::More 'no_plan';
+
+my $main = init Vhffs::Tests::Main;
+isa_ok($main, 'Vhffs::Tests::Main', '$main');
+
+Vhffs::Tests::Utils::init_db($main->get_db_object);
+
+my $user1 = Vhffs::User::create($main, 'test1', 'abcdef', 0, 'test1@xxxxxxxx');
+isa_ok($user1, 'Vhffs::User', '$user1');
+
+my $group1 = Vhffs::Group::create($main, 'mailgroup1', $user1->get_uid, undef, 'Test group for Mail Domain');
+isa_ok($group1, 'Vhffs::Group', '$group1');
+
+my $mail1 = Vhffs::Services::Mail::create($main, 'test.com', 'Test mail domain 1', $user1, $group1);
+isa_ok($mail1, 'Vhffs::Services::Mail', '$mail1');
+cmp_ok($mail1->get_owner_uid, '==', $user1->get_uid, 'uid matches');
+cmp_ok($mail1->get_owner_gid, '==', $group1->get_gid, 'gid matches');
+
+my $ml1 = Vhffs::Services::MailingList::create($main, 'list1', 'test.com', 'admin@xxxxxxxx', 'Test ml 1', $user1, $group1);
+isa_ok($ml1, 'Vhffs::Services::MailingList', '$ml1');
+cmp_ok($ml1->get_localpart, 'eq', 'list1', 'Local part matches');
+cmp_ok($ml1->get_domain, 'eq', 'test.com', 'Mail domain matches');
+
+my ($max_oid) = $main->get_db_object->selectrow_array('SELECT MAX(object_id) FROM vhffs_object');
+ok(! defined(Vhffs::Services::MailingList::create($main, 'list1', 'test.com', 'admin@xxxxxxxx', 'Test ml 1', $user1, $group1)), 'Unable to create 2 lists with the same name');
+my ($new_max_oid) = $main->get_db_object->selectrow_array('SELECT MAX(object_id) FROM vhffs_object');
+cmp_ok($new_max_oid, '==', $max_oid, 'Mailing list service creation is a "all or nothing" process');
+
+$ml1->add_sub('toto@xxxxxxxx', Vhffs::Constants::ML_RIGHT_SUB);
+cmp_ok(keys(%{$ml1->{subs}}), '==', 1, 'One subscriber registered');
+
+my $tmpml = Vhffs::Services::MailingList::get_by_mladdress($main, 'list1', 'test.com');
+my $subs = $tmpml->{subs};
+cmp_ok(keys(%$subs), '==', 1, 'One subscriber registered (fetched)');
+ok(defined $subs->{'toto@xxxxxxxx'}, 'Subscriber key is email address');
+my $sub = $subs->{'toto@xxxxxxxx'};
+cmp_ok($sub->{member}, 'eq', 'toto@xxxxxxxx', 'Email address matches');
+cmp_ok($sub->{perm}, '==', Vhffs::Constants::ML_RIGHT_SUB, 'Permissions matches');


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