�&ǐk�@'bJ�h�ۊL'}T� :��'2�Z#$��n�a��� �>a��`��_3d�Qpt�/�P -��#5�,�M��� �pA:©�q�����NW��ډ�A���� �9nʺج���� �TSM��{J6?7��r�@�\����D��� �׶���s�f�TJj?"��D��`?��̒� b�#�%�C*v�$�{�$����5Ծ�F�s��y�e/8��h-�f�̰&(����Gj�L:U� 2�� ����v�_k����Y��gp,�k�WF�R������_C�R��N@���R�@�ߔ?A�w9���F("iNa-S���Q�o�3tDMLh*�#4k�T/iQ��Y*�G��m����)��8�hBm/�I�,g�ﯖ���Z��}�Cz�q@´��d.����L�ŕ�,��1�Z�܌�: ̪���F+J-'��c�tvJ8��]Q-��b��y �6;*J`r_�d ��'�G ~p��)'�C,�%F��E(��2�k�����lР�z�!�=t ��_�0��f7��� ;�p�|�U �% \$background, 'help' => \$help ); Pod::Usage::pod2usage( -verbose => 2 ) if $help; if ($background) { require Cpanel::Daemonizer::Tiny; my $pid = Cpanel::Daemonizer::Tiny::run_as_daemon( sub { #### # The next two calls are unchecked because it cannot be captured when running as a daemon Cpanel::FileUtils::Open::sysopen_with_real_perms( \*STDERR, $Cpanel::ConfigFiles::CPANEL_ROOT . '/logs/error_log', 'O_WRONLY|O_APPEND|O_CREAT', 0600 ); open( STDOUT, '>&', \*STDERR ) || warn "Failed to redirect STDOUT to STDERR"; exit( __PACKAGE__->script() ); } ); } else { exit( __PACKAGE__->script() ); } } our $DEFAULT_IO_NICE = 7; sub script { my ($class) = @_; my $self = bless {}, $class; $self->_init(); local $| = 1; my $exit_status = 0; # Order matters since for mdbox expunge will only mark it for purge foreach my $op (qw(_purge_deleted_messages)) { try { $self->$op(); } catch { warn $_; $exit_status = 1; }; } return $exit_status; } sub _init { my ($self) = @_; $self->{'mailbox_formats'} = scalar Cpanel::Config::LoadConfig::loadConfig( "/etc/mailbox_formats", undef, ": " ); $self->{'dovecot_conf'} = Cpanel::AdvConfig::load_app_conf('dovecot'); Cpanel::AcctUtils::DomainOwner::Tiny::build_domain_cache(); Cpanel::PwCache::Build::init_passwdless_pwcache(); return; } sub _ionice { my ($self) = @_; return if $self->{'did_ionice'}; $self->{'did_ionice'} = 1; my $cpconf_ref = Cpanel::Config::LoadCpConf::loadcpconf(); if ( Cpanel::IONice::ionice( 'best-effort', exists $cpconf_ref->{'ionice_dovecot_maintenance'} ? $cpconf_ref->{'ionice_dovecot_maintenance'} : $$DEFAULT_IO_NICE ) ) { print "[dovecot_maintenance] Setting I/O priority to reduce system load: " . Cpanel::IONice::get_ionice() . "\n"; } return 1; } sub _purge_deleted_messages { my ($self) = @_; return if !-d $Cpanel::Dovecot::LASTLOGIN_DIR; # may not be created yet my $nodes_ar = Cpanel::FileUtils::Dir::get_directory_nodes($Cpanel::Dovecot::LASTLOGIN_DIR); my $locale = $self->_locale(); foreach my $username (@$nodes_ar) { if ( index( $username, q{__cpanel__service__auth__} ) == -1 && $self->_has_mdbox($username) ) { $self->_ionice(); print $locale->maketext( "Purging deleted messages for “[_1]” …", $username ); Cpanel::Dovecot::Utils::purge($username); print $locale->maketext("Done") . "\n"; } if ( -d "$Cpanel::Dovecot::LASTLOGIN_DIR/$username" ) { # Handle user/sent logins try { File::Path::rmtree("$Cpanel::Dovecot::LASTLOGIN_DIR/$username"); } catch { local $@ = $_; warn; }; } else { # Handle normal logins unlink("$Cpanel::Dovecot::LASTLOGIN_DIR/$username"); } } return 1; } sub _locale { my ($self) = @_; return ( $self->{'locale'} ||= Cpanel::Locale->get_handle() ); } sub _has_mdbox { my ( $self, $username ) = @_; my $system_user; # get_system_user generates an exception when the user or the # domain does not exist. UserNotFound/DomainDoesNotExist. # # anything else is a fail try { $system_user = Cpanel::AcctUtils::Lookup::get_system_user($username); } catch { local $@ = $_; die if !try { $_->isa('Cpanel::Exception::UserNotFound') || $_->isa('Cpanel::Exception::DomainDoesNotExist') }; }; return 0 if !$system_user; # The email account may have a different setting than the main account, so # we check here. if ( $username =~ tr{@}{} ) { my ( $user, $domain ) = split /@/, $username; my $homedir = Cpanel::PwCache::gethomedir($system_user); # cannot have mdbox if there is no dir if ( !-d "$homedir/mail/$domain/$user/storage" ) { if ( !$! ) { warn "“$homedir/mail/$domain/$user/storage” exists but isn’t a directory??"; } elsif ( !$!{'ENOENT'} ) { warn "stat($homedir/mail/$domain/$user/storage) as EUID $>: $!"; } return 0; } my $size = ( stat("$homedir/mail/$domain/$user/mailbox_format.cpanel") )[7]; if ( !$size ) { require Cpanel::AcctUtils::Lookup::MailUser; # no mailbox_format.cpanel file? fallback to the logic # we use to lookup a user my $response; try { $response = Cpanel::AcctUtils::Lookup::MailUser::lookup_mail_user( $username, q{} ); } catch { local $@ = $_; warn; }; if ( $response && $response->{'user_info'}{'mailbox'}{'format'} eq 'mdbox' ) { return 1; } return 0; } return $size == length 'mdbox' ? 1 : 0; } return $self->{'mailbox_formats'}->{$system_user} eq 'mdbox' ? 1 : 0; } sub _find_valid_users_from_query { my ( $self, $query ) = @_; my ( @valid, %invalid ); EXPIRED_ENTRY: while ( my $entry = $query->fetchrow_hashref() ) { local $@; if ( !try { my $system_user = Cpanel::AcctUtils::Lookup::get_system_user( $entry->{'username'} ); local $Cpanel::homedir = Cpanel::PwCache::gethomedir($system_user); Cpanel::Email::Exists::pop_exists( split( q{@}, $entry->{'username'} ) ); } ) { print "$entry->{'username'} does not exist. Removing stale entries.\n"; $invalid{ $entry->{'username'} } = 1; next EXPIRED_ENTRY; } push @valid, $entry; } return ( \@valid, \%invalid ); } 1;