package JWebmail v1.2.2; use Mojo::Base Mojolicious; use Module::Load 'load'; use JWebmail::Controller::Webmail; use JWebmail::Model::ReadMails::Role; use JWebmail::Model::ReadMails::QMailAuthuser; use JWebmail::Model::WriteMails; use JWebmail::Config qw'LOGIN_SCHEME MAILDIR_READER'; sub validateConf { my $self = shift; my $conf = $self->config; exists $conf->{admin_mail} or die; $conf->{admin_mail} =~ /@/ or die; exists $conf->{i18n}{default_language} or die; $conf->{i18n}{default_language} =~ /^[\w_]+$/a or die; exists $conf->{model}{read}{virtual_user} or die; getpwnam $conf->{model}{read}{virtual_user} or die; exists $conf->{model}{read}{mailbox_path} or die; -d $conf->{model}{read}{mailbox_path} or die; return 1; } sub startup { my $self = shift; $self->moniker('jwebmail'); # load plugins push @{$self->plugins->namespaces}, 'JWebmail::Plugin'; $self->plugin('TOMLConfig'); $self->validateConf; if (fc LOGIN_SCHEME eq fc 's3d') { $self->plugin('ServerSideSessionData'); } $self->plugin('Paginate'); my $i18n_route = $self->plugin('I18N2', $self->config('i18n')); $self->secrets( [$self->config('secret')] ) if $self->config('secret'); delete $self->config->{secret}; # initialize models my $read_mails = do { my $cls = MAILDIR_READER; eval { load $cls; 1 } || die "Issue for module $cls with: $@"; $cls->new(($self->config->{model}{read} // {})->%*) }; die "given class @{[ ref $read_mails ]} does not ReadMails" unless $read_mails->DOES('JWebmail::Model::ReadMails::Role'); $self->helper(users => sub { $read_mails }); $self->helper(send_mail => sub { my ($c, $mail) = @_; JWebmail::Model::WriteMails::sendmail($mail) }); $self->validator->add_check(mail_line => \&_mail_line); $self->validator->add_filter(non_empty_ul => \&_filter_empty_upload); $self->defaults(version => __PACKAGE__->VERSION); $self->sessions->cookie_name('jwebmail_session'); $self->sessions->samesite('Strict'); $self->sessions->secure(1); $self->sessions->default_expiration(30 * 60); $self->route($i18n_route); } sub route { my $self = shift; my $r = shift || $self->routes; $r->get( '/' => 'login')->to('Webmail#noaction'); $r->post('/' => 'login')->to('Webmail#login'); $r->get('/about' )->to('Webmail#about'); $r->get('/logout' )->to('Webmail#logout'); my $a = $r->under('/')->to('Webmail#auth'); $a->get('/home/*folder' )->to('Webmail#displayheaders', folder => '')->name('displayheaders'); $a->get('/read/#id' => 'read')->to('Webmail#readmail'); $a->get('/raw/#id' => 'raw' )->to('Webmail#raw'); $a->get('/write' )->to('Webmail#writemail'); $a->post('/write' => 'send' )->to('Webmail#sendmail'); $a->post('/move' )->to('Webmail#move'); } ### filter and checks for mojo validator sub _mail_line { my ($v, $name, $value, @args) = @_; my $mail_addr = qr/\w+\@\w+\.\w+/; # my $unescaped_quote = qr/"(*nlb:\\)/; # greater perl version required my $unescaped_quote = qr/"(? ) | ( $mail_addr ) )$/xn; } sub _filter_empty_upload { my ($v, $name, $value) = @_; return $value->filename ? $value : undef; } 1 __END__ =encoding utf-8 =head1 NAME JWebmail - Provides a web based e-mail client meant to be used with s/qmail. =head1 SYNOPSIS hypnotoad script/jwebmail And use a server in reverse proxy configuration. =head1 DESCRIPTION =head1 CONFIGURATION Use the I file or for a specific I<$mode> the I. =head1 VALIDATOR =head2 mail_line A check for validator used in mail headers for fields containing email addresses. $app->validator->add_check(mail_line => \&JWebmail::Plugin::Helper::mail_line); my $v = $c->validation; $v->required('to', 'not_empty')->check('mail_line'); =head2 filter_empty_upload A filter for validator used to filter out empty uploads. $app->validator->add_filter(non_empty_ul => \&JWebmail::Plugin::Helper::filter_empty_upload); my $v = $c->validation; $v->required('file_upload', 'non_empty_ul'); =head1 AUTHORS Copyright (C) 2020-2022 Jannis M. Hoffmann L =head1 BASED ON IDEAS Copyright (C) 2001 Olivier Müller L (GPLv2+ project: oMail Webmail) Copyright (C) 2000 Ernie Miller (GPL project: Neomail) See the CREDITS file for project contributors. =head1 LICENSE This module is licensed under the terms of the GPLv3. Please take a look at the provided LICENSE file shipped with this module. =cut