aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorGuilhem Moulin <guilhem.moulin@fripost.org>2012-09-10 20:01:06 +0200
committerGuilhem Moulin <guilhem.moulin@fripost.org>2012-09-10 20:01:06 +0200
commiteaacbeb2d5fece7fe9cab570f262a8f29be96863 (patch)
tree8d77aa2d9a4add00265cd729934deb3af6726fd8 /lib
parent3cc6e0f15836c94338762c364c1d451755dc261b (diff)
Internationalization.
Diffstat (limited to 'lib')
-rw-r--r--lib/Fripost/Panel/Interface.pm128
-rw-r--r--lib/Fripost/Panel/Login.pm25
-rw-r--r--lib/Fripost/Schema.pm6
-rw-r--r--lib/Fripost/Schema/Alias.pm24
-rw-r--r--lib/Fripost/Schema/Domain.pm20
-rw-r--r--lib/Fripost/Schema/List.pm20
-rw-r--r--lib/Fripost/Schema/Local.pm20
-rw-r--r--lib/Fripost/Schema/Mailbox.pm28
-rw-r--r--lib/Fripost/Schema/Misc.pm5
9 files changed, 150 insertions, 126 deletions
diff --git a/lib/Fripost/Panel/Interface.pm b/lib/Fripost/Panel/Interface.pm
index 6859e57..0b7860e 100644
--- a/lib/Fripost/Panel/Interface.pm
+++ b/lib/Fripost/Panel/Interface.pm
@@ -15,6 +15,7 @@ use parent 'Fripost::Panel::Login';
use Fripost::Schema;
use Fripost::Password;
use HTML::Entities;
+use Net::IDN::Encode qw/email_to_unicode/;
# This method is called right before the 'setup' method below. It
@@ -34,7 +35,7 @@ sub ListDomains : StartRunmode {
my $self = shift;
my %CFG = $self->cfg;
- my ($ul,$ud) = split /\@/, $self->authen->username, 2;
+ my ($ul,$ud) = split /\@/, email_to_unicode($self->authen->username), 2;
my $fp = Fripost::Schema->SASLauth( $self->authen->username, %CFG );
my @domains = $fp->domain->search( -concat => "\n", -die => 403);
@@ -44,9 +45,12 @@ sub ListDomains : StartRunmode {
, loop_context_vars => 1
, global_vars => 1 );
$template->param( url => $self->query->url
- , user_localpart => $ul
- , user_domainpart => $ud
- , domains => [ @domains ]
+ , user_localpart => encode_entities($ul)
+ , user_domainpart => encode_entities($ud)
+ , domains => [ map { { domain => encode_entities($_->{domain})
+ , isactive => $_->{isactive}
+ , description => $_->{description} } }
+ @domains ]
);
return $template->output;
}
@@ -58,8 +62,9 @@ sub ListLocals : Runmode {
my $self = shift;
my %CFG = $self->cfg;
- my ($ul,$ud) = split /\@/, $self->authen->username, 2;
- my $d = (split /\//, $ENV{PATH_INFO}, 3)[1];
+ my ($ul,$ud) = split /\@/, email_to_unicode($self->authen->username), 2;
+ my $d = decode_entities ((split /\//, $ENV{PATH_INFO}, 3)[1]);
+ Encode::_utf8_on($d);
my $fp = Fripost::Schema::->SASLauth( $self->authen->username, %CFG );
# Query *the* matching domain
@@ -79,10 +84,10 @@ sub ListLocals : Runmode {
, global_vars => 1 );
$template->param( url => $self->query->url
- , user_localpart => $ul
- , user_domainpart => $ud
+ , user_localpart => encode_entities($ul)
+ , user_domainpart => encode_entities($ud)
);
- $template->param( domain => $domain{domain}
+ $template->param( domain => encode_entities($domain{domain})
, isactive => $domain{isactive}
, description => join ("\n", @{$domain{description}}) );
# Can the user edit the domain (change description, toggle
@@ -95,10 +100,11 @@ sub ListLocals : Runmode {
$template->param( listMailboxes => $#mailboxes >= 0 ||
$domain{permissions} =~ /p/ );
$template->param( mailboxes => [
- map { { user => $_->{user}
+ map { { user => encode_entities($_->{user})
, description => join ("\n", @{$_->{description}})
, isactive => $_->{isactive}
- , forwards => [ map { {forward => $_} } @{$_->{forwards}} ]
+ , forwards => [ map { {forward => encode_entities($_)} }
+ @{$_->{forwards}} ]
, quota => $_->{quota}
};
}
@@ -111,16 +117,16 @@ sub ListLocals : Runmode {
$template->param( listAliases => $#aliases >= 0 ||
$domain{permissions} =~ /[aop]/ );
$template->param( aliases => [
- map { { alias => $_->{alias}
+ map { { alias => encode_entities($_->{alias})
, description => join ("\n", @{$_->{description}})
, isactive => $_->{isactive}
- , destinations => [ map { {destination => $_} }
+ , destinations => [ map { {destination => encode_entities($_)} }
@{$_->{maildrop}} ]
};
}
@aliases
]);
- $template->param( catchalls => [ map { {catchall => $_} }
+ $template->param( catchalls => [ map { {catchall => encode_entities($_)} }
@{$domain{catchalls}} ]
, CAodd => not $#aliases % 2);
@@ -129,7 +135,7 @@ sub ListLocals : Runmode {
# Should we list lists?
$template->param( listLists => $#lists >= 0 || $domain{permissions} =~ /[lop]/ );
$template->param( lists => [
- map { { list => $_->{list}
+ map { { list => encode_entities($_->{list})
, description => join ("\n", @{$_->{description}})
, isactive => $_->{isactive}
, transport => $_->{transport}
@@ -147,8 +153,9 @@ sub EditDomain : Runmode {
my $self = shift;
my %CFG = $self->cfg;
- my ($ul,$ud) = split /\@/, $self->authen->username, 2;
- my $d = (split /\//, $ENV{PATH_INFO}, 3)[1];
+ my ($ul,$ud) = split /\@/, email_to_unicode($self->authen->username), 2;
+ my $d = decode_entities ((split /\//, $ENV{PATH_INFO}, 3)[1]);
+ Encode::_utf8_on($d);
my $q = $self->query;
return $self->redirect($q->url .'/') if defined $q->param('cancel');
@@ -172,9 +179,9 @@ sub EditDomain : Runmode {
, loop_context_vars => 1
, global_vars => 1 );
$template->param( url => $q->url
- , user_localpart => $ul
- , user_domainpart => $ud
- , domain => $d
+ , user_localpart => encode_entities($ul)
+ , user_domainpart => encode_entities($ud)
+ , domain => encode_entities($d)
);
if ($error) {
# Preserve the (incorrect) form
@@ -188,7 +195,8 @@ sub EditDomain : Runmode {
, description => join ("\x{0D}\x{0A}",
@{$domain{description}})
, catchalls => join ("\x{0D}\x{0A}",
- @{$domain{catchalls}}) );
+ map { encode_entities ($_) }
+ @{$domain{catchalls}}) );
}
$template->param( newChanges => defined $q->param('submit') );
return $template->output;
@@ -201,8 +209,10 @@ sub EditLocal : Runmode {
my $self = shift;
my %CFG = $self->cfg;
- my ($ul,$ud) = split /\@/, $self->authen->username, 2;
+ my ($ul,$ud) = split /\@/, email_to_unicode($self->authen->username), 2;
my ($null,$d,$l,$crap) = split /\//, $ENV{PATH_INFO}, 4;
+ my $du = decode_entities ($d); Encode::_utf8_on($du);
+ my $lu = decode_entities ($l); Encode::_utf8_on($lu);
my $q = $self->query;
return $self->redirect($q->url.'/'.$d.'/') if defined $q->param('cancel');
@@ -210,8 +220,8 @@ sub EditLocal : Runmode {
my $fp = Fripost::Schema::->SASLauth( $self->authen->username, %CFG );
# Search for *the* matching mailbox, alias or list.
- my %local = $fp->local->get ($l, $d, -die => 404,
- -concat => "\x{0D}\x{0A}");
+ my %local = $fp->local->get ($lu.'@'.$du, -die => 404,
+ -concat => "\x{0D}\x{0A}");
die "Unknown type" unless grep { $local{type} eq $_ }
qw/mailbox alias list/;
@@ -220,17 +230,17 @@ sub EditLocal : Runmode {
if (defined $q->param('a') and $q->param('a') eq 'delete') {
# Delete the entry
- $error = $fp->$t->delete($l, $d, -die => 0);
+ $error = $fp->$t->delete($lu.'@'.$du, -die => 0);
unless ($error) {
$fp->done;
return $self->redirect($q->url .'/'. $d .'/');
}
}
- elsif (defined $q->param('submit')) {
+ if (defined $q->param('submit')) {
# Changes have been submitted: process them
my %entry;
if ($t eq 'mailbox') {
- $entry{user} = $l.'@'.$d;
+ $entry{user} = $lu.'@'.$du;
$entry{forwards} = $q->param('forwards');
if ($q->param('oldpw') ne '' or
@@ -250,13 +260,14 @@ sub EditLocal : Runmode {
else {
my $fp;
eval {
+ my $u = email_to_unicode($self->authen->username);
$fp = Fripost::Schema::->auth(
- $self->authen->username,
+ $u,
$q->param('oldpw'),
ldap_uri => $CFG{ldap_uri},
ldap_suffix => $CFG{ldap_suffix},
-die => "Wrong password (for ‘"
- .$self->authen->username."‘)." );
+ .encode_entities($u)."‘)." );
};
$error = $@ || $fp->mailbox->passwd(
$entry{user},
@@ -267,66 +278,60 @@ sub EditLocal : Runmode {
}
}
elsif ($t eq 'alias') {
- $entry{alias} = $l.'@'.$d;
+ $entry{alias} = $lu.'@'.$du;
$entry{maildrop} = $q->param('maildrop');
}
elsif ($t eq 'list') {
- $entry{list} = $l.'@'.$d;
+ $entry{list} = $lu.'@'.$du;
$entry{transport} = $q->param('transport');
}
- else {
- # Unknown type
- return $self->redirect($q->url .'/'. $d .'/');
- }
$entry{isactive} = $q->param('isactive');
$entry{description} = $q->param('description');
$error = $fp->$t->replace( \%entry, -concat => "(\n|\x{0D}\x{0A})")
unless $error;
}
- $fp->done;
-
my $template = $self->load_tmpl( "edit-$t.html",
cache => 1, utf8 => 1 );
$template->param( url => $q->url
- , user_localpart => $ul
- , user_domainpart => $ud
- , domain => $d
+ , user_localpart => encode_entities($ul)
+ , user_domainpart => encode_entities($ud)
+ , domain => encode_entities($du)
);
if ($error and defined $q->param('submit')) {
# Preserve the (incorrect) form, except the passwords
- if ($local{type} eq 'mailbox') {
- $template->param( user => $l
+ if ($t eq 'mailbox') {
+ $template->param( user => encode_entities($l)
, forwards => $q->param('forwards') );
}
- elsif ($local{type} eq 'alias') {
- $template->param( alias => $l
+ elsif ($t eq 'alias') {
+ $template->param( alias => encode_entities($l)
, maildrop => $q->param('maildrop') );
}
- elsif ($local{type} eq 'list') {
- $template->param( list => $l );
- }
- else {
- die "Unknown type";
+ elsif ($t eq 'list') {
+ $template->param( list => encode_entities($l) );
}
$template->param( isactive => $q->param('isactive')
, description => $q->param('description') );
}
else {
+ %local = $fp->local->get ($lu.'@'.$du, -die => 404,
+ -concat => "\x{0D}\x{0A}");
if ($t eq 'mailbox') {
- $template->param( user => $local{user}
- , forwards => $local{forwards} );
+ $template->param( user => encode_entities($local{user})
+ , forwards => encode_entities($local{forwards}) );
}
elsif ($t eq 'alias') {
- $template->param( alias => $local{alias}
- , maildrop => $local{maildrop} );
+ $template->param( alias => encode_entities($local{alias})
+ , maildrop => encode_entities($local{maildrop}) );
}
elsif ($t eq 'list') {
- $template->param( list => $local{list} );
+ $template->param( list => encode_entities($local{list}) );
}
$template->param( isactive => $local{isactive}
, description => $local{description} );
}
+ $fp->done;
my $news = (defined $q->param('submit') or
(defined $q->param('a') and $q->param('a') eq 'delete'));
$template->param( newChanges => $news );
@@ -343,8 +348,9 @@ sub AddLocal : Runmode {
my $self = shift;
my %CFG = $self->cfg;
- my ($ul,$ud) = split /\@/, $self->authen->username, 2;
+ my ($ul,$ud) = split /\@/, email_to_unicode($self->authen->username), 2;
my $d = (split /\//, $ENV{PATH_INFO}, 3)[1];
+ my $du = decode_entities ($d); Encode::_utf8_on($du);
my $q = $self->query;
return $self->redirect($q->url.'/'.$d.'/') if defined $q->param('cancel');
@@ -355,7 +361,7 @@ sub AddLocal : Runmode {
# Changes have been submitted: process them
my %entry;
if ($t eq 'mailbox') {
- $entry{user} = $q->param('user').'@'.$d;
+ $entry{user} = $q->param('user').'@'.$du;
$entry{forwards} = $q->param('forwards');
if ($q->param('password') ne $q->param('password2')) {
$error = "Passwords do not match";
@@ -371,11 +377,11 @@ sub AddLocal : Runmode {
# TODO: inherit the quota from the postmaster's?
}
elsif ($t eq 'alias') {
- $entry{alias} = $q->param('alias').'@'.$d;
+ $entry{alias} = $q->param('alias').'@'.$du;
$entry{maildrop} = $q->param('maildrop');
}
elsif ($t eq 'list') {
- $entry{list} = $q->param('list').'@'.$d;
+ $entry{list} = $q->param('list').'@'.$du;
$entry{transport} = $q->param('transport');
}
else {
@@ -395,9 +401,9 @@ sub AddLocal : Runmode {
my $template = $self->load_tmpl( "add-$t.html", cache => 1, utf8 => 1 );
$template->param( url => $q->url
- , user_localpart => $ul
- , user_domainpart => $ud
- , domain => $d
+ , user_localpart => encode_entities($ul)
+ , user_domainpart => encode_entities($ud)
+ , domain => encode_entities($du)
);
if ($error) {
# Preserve the (incorrect) form, except the passwords
diff --git a/lib/Fripost/Panel/Login.pm b/lib/Fripost/Panel/Login.pm
index 8dcfd2b..a147371 100644
--- a/lib/Fripost/Panel/Login.pm
+++ b/lib/Fripost/Panel/Login.pm
@@ -19,10 +19,10 @@ use CGI::Application::Plugin::Authentication;
use CGI::Application::Plugin::Redirect;
use CGI::Application::Plugin::ConfigAuto 'cfg';
-use Net::LDAP;
-use Authen::SASL;
+use Fripost::Schema;
use File::Spec::Functions qw/catfile catdir/;
use HTML::Entities;
+use Net::IDN::Encode qw/email_to_ascii/;
# This method is called right before the 'setup' method below. It
@@ -56,19 +56,22 @@ sub cgiapp_init {
$self->authen->config(
DRIVER => [ 'Generic', sub {
my ($u,$p) = @_;
- my ($l,$d) = split /\@/, $u, 2;
+ my $d = (split /\@/, $u, 2)[1];
unless (defined $d) {
$CFG{default_realm} // return 0;
- $d = $CFG{default_realm};
- $u .= '@'.$d;
+ $u .= '@'.$CFG{default_realm};
}
- my $bind_dn = "fvu=$l,fvd=$d,". join (',', @{$CFG{ldap_suffix}});
-
- my $ldap = Net::LDAP->new( $CFG{ldap_uri} );
- my $mesg = $ldap->bind ( $bind_dn, password => $p );
- $ldap->unbind;
- $mesg->code ? 0 : $u;
+ Encode::_utf8_on($u);
+ $u = Net::IDN::Encode::email_to_ascii($u);
+ my $fp = Fripost::Schema::->auth($u, $p,
+ ldap_uri => $CFG{ldap_uri},
+ ldap_suffix => $CFG{ldap_suffix},
+ -die => 0
+ );
+ return 0 unless defined $fp;
+ $fp->done;
+ return $u;
} ],
STORE => 'Session',
LOGIN_RUNMODE => 'login',
diff --git a/lib/Fripost/Schema.pm b/lib/Fripost/Schema.pm
index 36b7d54..3e89e6c 100644
--- a/lib/Fripost/Schema.pm
+++ b/lib/Fripost/Schema.pm
@@ -25,6 +25,7 @@ use Fripost::Schema::Mailbox;
use Fripost::Schema::Alias;
use Fripost::Schema::List;
use Fripost::Schema::Local;
+use Net::IDN::Encode qw/email_to_ascii/;
=head1 METHODS
@@ -83,7 +84,10 @@ sub auth {
my $mesg = $self->ldap->bind( $self->whoami, password => $pw );
if ($mesg->code) {
- die $cfg{'-die'}."\n" if defined $cfg{'-die'};
+ if (defined $cfg{'-die'}) {
+ return unless $cfg{'-die'};
+ die $cfg{'-die'}."\n";
+ }
die $mesg->error;
}
return $self;
diff --git a/lib/Fripost/Schema/Alias.pm b/lib/Fripost/Schema/Alias.pm
index 0976093..556a7d3 100644
--- a/lib/Fripost/Schema/Alias.pm
+++ b/lib/Fripost/Schema/Alias.pm
@@ -18,6 +18,8 @@ use utf8;
use parent 'Fripost::Schema';
use Fripost::Schema::Misc qw/concat explode must_attrs email_valid/;
+use Net::IDN::Encode qw/domain_to_ascii
+ email_to_ascii email_to_unicode/;
=head1 METHODS
@@ -33,7 +35,7 @@ is a array of hash references, sorted by alias.
sub search {
my $self = shift;
- my $domain = shift;
+ my $domain = domain_to_ascii(shift);
my %options = @_;
my $concat = $options{'-concat'};
@@ -49,10 +51,11 @@ sub search {
die $options{'-die'}."\n" if defined $options{'-die'};
die $aliases->error;
}
- return map { { alias => $_->get_value('fva')
+ return map { { alias => email_to_unicode($_->get_value('fva'))
, isactive => $_->get_value('fripostIsStatusActive') eq 'TRUE'
, description => concat($concat, $_->get_value('description'))
- , maildrop => concat($concat, $_->get_value('fripostMaildrop'))
+ , maildrop => concat($concat, map { email_to_unicode ($_) }
+ $_->get_value('fripostMaildrop'))
}
}
$aliases->sorted('fva')
@@ -75,9 +78,8 @@ sub replace {
if defined $a->{$_};
}
- my ($l,$d) = split /\@/, $a->{alias}, 2;
-
eval {
+ my ($l,$d) = split /\@/, email_to_ascii($a->{alias}), 2;
&_is_valid($a);
my $mesg = $self->ldap->modify(
"fva=$l,fvd=$d,".$self->suffix,
@@ -108,13 +110,12 @@ sub add {
if defined $a->{$_};
}
- my ($l,$d) = split /\@/, $a->{alias}, 2;
-
eval {
+ my ($l,$d) = split /\@/, email_to_ascii($a->{alias}), 2;
die "Missing alias name\n" if $l eq '';
&_is_valid($a);
die "‘".$a->{alias}."‘ alread exists\n"
- if $self->local->exists($l,$d,%options);
+ if $self->local->exists($a->{alias},%options);
my %attrs = ( objectClass => 'FripostVirtualAlias'
, fripostIsStatusActive => $a->{isactive} ? 'TRUE' : 'FALSE'
@@ -135,7 +136,7 @@ sub add {
}
-=item B<delete> (I<alias>, I<domain>, I<OPTIONS>)
+=item B<delete> (I<alias>, I<OPTIONS>)
Delete the given alias.
@@ -143,8 +144,7 @@ Delete the given alias.
sub delete {
my $self = shift;
- my $l = shift;
- my $d = shift;
+ my ($l,$d) = split /\@/, email_to_ascii(shift), 2;
my %options = @_;
my $mesg = $self->ldap->delete( "fva=$l,fvd=$d,".$self->suffix );
@@ -175,7 +175,7 @@ The B<-die> option, if present, overides LDAP croaks and errors.
sub _is_valid {
my $a = shift;
must_attrs( $a, qw/alias isactive maildrop/ );
- email_valid( $a->{alias}, -exact => 1 );
+ $a->{alias} = email_valid( $a->{alias}, -exact => 1 );
$a->{maildrop} = [ map { email_valid($_) } @{$a->{maildrop}} ];
# TODO: check for cycles?
}
diff --git a/lib/Fripost/Schema/Domain.pm b/lib/Fripost/Schema/Domain.pm
index e1b855f..3f2c9c5 100644
--- a/lib/Fripost/Schema/Domain.pm
+++ b/lib/Fripost/Schema/Domain.pm
@@ -17,8 +17,10 @@ use warnings;
use utf8;
use parent 'Fripost::Schema';
-use Fripost::Schema::Misc qw/concat get_perms explode must_attrs email_valid/;
-use Email::Valid;
+use Fripost::Schema::Misc qw/concat get_perms explode
+ must_attrs email_valid/;
+use Net::IDN::Encode qw/domain_to_ascii domain_to_unicode
+ email_to_ascii email_to_unicode/;
=head1 METHODS
@@ -48,7 +50,7 @@ sub search {
die $options{'-die'}."\n" if defined $options{'-die'};
die $domains->error;
}
- return map { { domain => $_->get_value('fvd')
+ return map { { domain => domain_to_unicode($_->get_value('fvd'))
, isactive => $_->get_value('fripostIsStatusActive') eq 'TRUE'
, description => concat($concat, $_->get_value('description'))
}
@@ -65,7 +67,7 @@ Returns a hash with all the (visible) attributes for the given domain.
sub get {
my $self = shift;
- my $d = shift;
+ my $d = domain_to_ascii(shift);
my %options = @_;
my $concat = $options{'-concat'};
@@ -95,10 +97,11 @@ sub get {
die "No such such domain ‘$d‘.\n";
}
- return ( domain => $domain->get_value('fvd')
+ return ( domain => domain_to_unicode($domain->get_value('fvd'))
, isactive => $domain->get_value('fripostIsStatusActive') eq 'TRUE'
, description => concat($concat, $domain->get_value('description'))
- , catchalls => concat($concat, $domain->get_value('fripostOptionalMaildrop'))
+ , catchalls => concat($concat, map { email_to_unicode ($_) }
+ $domain->get_value('fripostOptionalMaildrop'))
, permissions => get_perms($domain, $self->whoami)
)
}
@@ -157,8 +160,9 @@ The B<-die> option, if present, overides LDAP croaks and errors.
sub _is_valid {
my $d = shift;
must_attrs( $d, qw/domain isactive/ );
- email_valid( $d->{domain}, -prefix => 'fake@', -error => 'Invalid domain',
- -exact => 1 );
+ $d->{domain} = email_valid( $d->{domain}, -prefix => 'fake@',
+ -error => 'Invalid domain',
+ -exact => 1 );
$d->{catchalls} = [ map { email_valid($_, -prefix => 'fake') }
@{$d->{catchalls}} ];
}
diff --git a/lib/Fripost/Schema/List.pm b/lib/Fripost/Schema/List.pm
index ec66f76..c6fb4f2 100644
--- a/lib/Fripost/Schema/List.pm
+++ b/lib/Fripost/Schema/List.pm
@@ -18,6 +18,8 @@ use utf8;
use parent 'Fripost::Schema';
use Fripost::Schema::Misc qw/concat explode must_attrs email_valid/;
+use Net::IDN::Encode qw/domain_to_ascii
+ email_to_ascii email_to_unicode/;
=head1 METHODS
@@ -33,7 +35,7 @@ is a array of hash references, sorted by list.
sub search {
my $self = shift;
- my $domain = shift;
+ my $domain = domain_to_ascii(shift);
my %options = @_;
my $concat = $options{'-concat'};
@@ -49,7 +51,7 @@ sub search {
die $options{'-die'}."\n" if defined $options{'-die'};
die $lists->error;
}
- return map { { list => $_->get_value('fvl')
+ return map { { list => email_to_unicode($_->get_value('fvl'))
, isactive => $_->get_value('fripostIsStatusActive') eq 'TRUE'
, description => concat($concat, $_->get_value('description'))
, transport => $_->get_value('fripostListManager')
@@ -73,9 +75,8 @@ sub replace {
$l->{description} = explode ($options{'-concat'}, $l->{description})
if defined $l->{description};
- my ($l2,$d) = split /\@/, $l->{list}, 2;
-
eval {
+ my ($l2,$d) = split /\@/, email_to_ascii($l->{list}), 2;
&_is_valid($l);
my $l3 = { fripostIsStatusActive => $l->{isactive} ? 'TRUE' : 'FALSE'
, description => $l->{description} };
@@ -103,14 +104,14 @@ sub add {
$l->{description} = explode ($options{'-concat'}, $l->{description})
if defined $l->{description};
- my ($l2,$d) = split /\@/, $l->{list}, 2;
eval {
+ my ($l2,$d) = split /\@/, email_to_ascii($l->{list}), 2;
die "Missing list name\n" if $l eq '';
must_attrs( $l, 'transport' );
&_is_valid($l);
die "‘".$l->{list}."‘ alread exists\n"
- if $self->local->exists($l2,$d,%options);
+ if $self->local->exists($l->{list},%options);
my %attrs = ( objectClass => 'FripostVirtualList'
, fripostIsStatusActive => $l->{isactive} ? 'TRUE' : 'FALSE'
@@ -143,7 +144,7 @@ sub add {
}
-=item B<delete> (I<list>, I<domain>, I<OPTIONS>)
+=item B<delete> (I<list>, I<OPTIONS>)
Delete the given list. Note: this will NOT wipe the archives off the
disk, but merely delete the list entry in the LDAP directory.
@@ -152,8 +153,7 @@ disk, but merely delete the list entry in the LDAP directory.
sub delete {
my $self = shift;
- my $l = shift;
- my $d = shift;
+ my ($l,$d) = split /\@/, email_to_ascii(shift), 2;
my %options = @_;
my $mesg = $self->ldap->delete( "fvl=$l,fvd=$d,".$self->suffix );
@@ -184,7 +184,7 @@ The B<-die> option, if present, overides LDAP croaks and errors.
sub _is_valid {
my $l = shift;
must_attrs( $l, qw/list isactive/ );
- email_valid( $l->{list}, -exact => 1 );
+ $l->{list} = email_valid( $l->{list}, -exact => 1 );
die "Invalid transport: ‘".$l->{transport}."‘\n"
if defined $l->{transport} and
diff --git a/lib/Fripost/Schema/Local.pm b/lib/Fripost/Schema/Local.pm
index 79c5420..64dd622 100644
--- a/lib/Fripost/Schema/Local.pm
+++ b/lib/Fripost/Schema/Local.pm
@@ -18,13 +18,14 @@ use utf8;
use parent 'Fripost::Schema';
use Fripost::Schema::Misc 'concat';
+use Net::IDN::Encode qw/email_to_ascii email_to_unicode/;
=head1 METHODS
=over 4
-=item B<get> (I<local>,I<domain>, I<OPTIONS>)
+=item B<get> (I<local>, I<OPTIONS>)
Returns a hash with all the (visible) attributes for the given entry. An
additional 'type' attribute gives the type of *the* found entry
@@ -34,11 +35,11 @@ additional 'type' attribute gives the type of *the* found entry
sub get {
my $self = shift;
- my $l = shift;
- my $d = shift;
+ my $loc = shift;
my %options = @_;
my $concat = $options{'-concat'};
+ my ($l,$d) = split /\@/, email_to_ascii($loc), 2;
my $locals = $self->ldap->search(
base => "fvd=$d,".$self->suffix,
scope => 'one',
@@ -67,19 +68,21 @@ sub get {
unless (defined $local) {
die $options{'-die'}."\n" if defined $options{'-die'};
- die "No such such entry ‘".$l.'@'.$d."‘.\n";
+ die "No such such entry ‘".$loc."‘.\n";
}
my %ret;
if ($local->dn =~ /^fvu=/) {
$ret{type} = 'mailbox';
$ret{user} = $local->get_value('fvu');
- $ret{forwards} = concat($concat, $local->get_value('fripostOptionalMaildrop'))
+ $ret{forwards} = concat($concat, map { email_to_unicode($_) }
+ $local->get_value('fripostOptionalMaildrop'))
}
elsif ($local->dn =~ /^fva=/) {
$ret{type} = 'alias';
$ret{alias} = $local->get_value('fva');
- $ret{maildrop} = concat($concat, $local->get_value('fripostMaildrop'))
+ $ret{maildrop} = concat($concat, map { email_to_unicode($_) }
+ $local->get_value('fripostMaildrop'))
}
elsif ($local->dn =~ /^fvl=/) {
$ret{type} = 'list';
@@ -92,7 +95,7 @@ sub get {
}
-=item B<exists> (I<local>,I<domain>, I<OPTIONS>)
+=item B<exists> (I<local>, I<OPTIONS>)
Returns 1 if the given I<local>@I<domain> exists, and 0 otherwise.
The authenticated user needs to have search access to the 'entry'
@@ -102,8 +105,7 @@ attribute.
sub exists {
my $self = shift;
- my $l = shift;
- my $d = shift;
+ my ($l,$d) = split /\@/, email_to_ascii(shift), 2;
my %options = @_;
# We may not have read access to the list commands
diff --git a/lib/Fripost/Schema/Mailbox.pm b/lib/Fripost/Schema/Mailbox.pm
index 28ef376..c7d93a2 100644
--- a/lib/Fripost/Schema/Mailbox.pm
+++ b/lib/Fripost/Schema/Mailbox.pm
@@ -18,6 +18,8 @@ use utf8;
use parent 'Fripost::Schema';
use Fripost::Schema::Misc qw/concat explode must_attrs email_valid/;
+use Net::IDN::Encode qw/domain_to_ascii
+ email_to_ascii email_to_unicode/;
=head1 METHODS
@@ -33,12 +35,12 @@ output is a array of hash references, sorted by mailbox.
sub search {
my $self = shift;
- my $domain = shift;
+ my $d = domain_to_ascii(shift);
my %options = @_;
my $concat = $options{'-concat'};
my $mailboxes = $self->ldap->search(
- base => "fvd=$domain,".$self->suffix,
+ base => "fvd=$d,".$self->suffix,
scope => 'one',
deref => 'never',
filter => 'objectClass=FripostVirtualMailbox',
@@ -50,10 +52,11 @@ sub search {
die $options{'-die'}."\n" if defined $options{'-die'};
die $mailboxes->error;
}
- return map { { user => $_->get_value('fvu')
+ return map { { user => email_to_unicode($_->get_value('fvu'))
, isactive => $_->get_value('fripostIsStatusActive') eq 'TRUE'
, description => concat($concat, $_->get_value('description'))
- , forwards => concat($concat, $_->get_value('fripostOptionalMaildrop'))
+ , forwards => concat($concat, map { email_to_unicode($_) }
+ $_->get_value('fripostOptionalMaildrop'))
, quota => $_->get_value('fripostMailboxQuota') // undef
}
}
@@ -77,9 +80,8 @@ sub replace {
if defined $m->{$_};
}
- my ($l,$d) = split /\@/, $m->{user}, 2;
-
eval {
+ my ($l,$d) = split /\@/, email_to_ascii($m->{user}), 2;
&_is_valid($m);
my $mesg = $self->ldap->modify(
"fvu=$l,fvd=$d,".$self->suffix,
@@ -103,7 +105,7 @@ may want to hash it before hand.
sub passwd {
my $self = shift;
- my ($l,$d) = split /\@/, shift, 2;
+ my ($l,$d) = split /\@/, email_to_ascii(shift), 2;
my $pw = shift;
my %options = @_;
@@ -131,13 +133,12 @@ sub add {
if defined $m->{$_};
}
- my ($l,$d) = split /\@/, $m->{user}, 2;
-
eval {
+ my ($l,$d) = split /\@/, email_to_ascii($m->{user}), 2;
die "Missing user name\n" if $l eq '';
&_is_valid($m);
die "‘".$m->{user}."‘ alread exists\n"
- if $self->local->exists($l,$d,%options);
+ if $self->local->exists($m->{user},%options);
my %attrs = ( objectClass => 'FripostVirtualMailbox'
, fripostIsStatusActive => $m->{isactive} ? 'TRUE' : 'FALSE'
@@ -160,7 +161,7 @@ sub add {
}
-=item B<delete> (I<mailbox>, I<domain>, I<OPTIONS>)
+=item B<delete> (I<mailbox>, I<OPTIONS>)
Delete the given mailbox. Note: this will NOT wipe the mailbox off the
disk, but merely delete its entry in the LDAP directory.
@@ -169,8 +170,7 @@ disk, but merely delete its entry in the LDAP directory.
sub delete {
my $self = shift;
- my $l = shift;
- my $d = shift;
+ my ($l,$d) = split /\@/, email_to_ascii(shift), 2;
my %options = @_;
my $mesg = $self->ldap->delete( "fvu=$l,fvd=$d,".$self->suffix );
@@ -201,7 +201,7 @@ The B<-die> option, if present, overides LDAP croaks and errors.
sub _is_valid {
my $m = shift;
must_attrs( $m, qw/user isactive/ );
- email_valid( $m->{user}, -exact => 1);
+ $m->{user} = email_valid( $m->{user}, -exact => 1);
$m->{forwards} = [ map { email_valid($_) } @{$m->{forwards}} ];
# TODO: match 'quota' against the Dovecot specifications
}
diff --git a/lib/Fripost/Schema/Misc.pm b/lib/Fripost/Schema/Misc.pm
index 4898764..39fa3b7 100644
--- a/lib/Fripost/Schema/Misc.pm
+++ b/lib/Fripost/Schema/Misc.pm
@@ -10,11 +10,14 @@ use 5.010_000;
use strict;
use warnings;
use utf8;
+use feature "unicode_strings";
use Exporter 'import';
our @EXPORT_OK = qw /concat get_perms explode
must_attrs email_valid/;
use Email::Valid;
+use Net::IDN::Encode;
+use Encode;
# Let the first argument, if defined, intersperse the other arguments.
@@ -99,6 +102,8 @@ sub email_valid {
$i =~ s/^[^<>]+\s<([^>]+)>/$1/;
my $mesg = $options{'-error'} // "Invalid e-mail";
$in = $options{'-prefix'}.$i if defined $options{'-prefix'};
+ Encode::_utf8_on($in);
+ $in = Net::IDN::Encode::email_to_ascii($in);
my $addr = Email::Valid::->address( -address => $in,
-tldcheck => 1,