use Time::Local; sub badcheck { $fromname = '' unless defined $fromname; $toname = '' unless defined $toname; $subject = '' unless defined $subject; $date = '' unless defined $date; $text = '' unless defined $text; my $reason = ''; # Check if From, To or Subject are empty or begin with whitespace $reason .= 'From ' if ($fromname eq '' || $fromname =~ /^\s/); $reason .= 'To ' if ($toname eq '' || $toname =~ /^\s/); $reason .= 'Subj ' if ($subject eq '' || $subject =~ /^\s/); # Check if date is missing, invalid or too far in past/future if ($date eq '') { $reason .= 'DateMissing '; } else { my %mon = ( Jan => 0, Feb => 1, Mar => 2, Apr => 3, May => 4, Jun => 5, Jul => 6, Aug => 7, Sep => 8, Oct => 9, Nov => 10, Dec => 11, ); if ($date !~ /^\s*(\d{1,2})\s+([A-Z][a-z]{2})\s+(\d{2})\s+(\d{2}):(\d{2}):(\d{2})\s*$/) { $reason .= "DateFormat[$date] "; } elsif (!exists $mon{$2}) { $reason .= "DateMonth[$date] "; } else { my $year = ($3 >= 70) ? (1900 + $3) : (2000 + $3); my $t; eval { $t = Time::Local::timelocal($6, $5, $4, $1, $mon{$2}, $year); }; if ($@) { $reason .= "DateParse[$date] "; } else { my $now = time(); my $days = 90; # Allowed drift in days (past/future) my $win = $days * 24 * 60 * 60; # days × hours × minutes × seconds $reason .= "DatePast[$date] " if $t < ($now - $win); $reason .= "DateFuture[$date] " if $t > ($now + $win); } } } # Check if message body is empty my $body = $text; # Normalize line endings $body =~ s/\r\n/\n/g; $body =~ s/\r/\n/g; # Remove NUL bytes $body =~ s/\x00//g; # Strip non-content lines $body =~ s/^[ \t]*\n//mg; # blank / whitespace-only lines $body =~ s/^AREA:.*\n?//img; # AREA line $body =~ s/^\x01.*\n?//mg; # all ^A kludge lines $body =~ s/^---.*\n?//mg; # tear line $body =~ s/^ \* Origin: .*\n?//mg; # origin line $body =~ s/^SEEN-BY:.*\n?//img; # seen-by line $body =~ s/^(?:\x01)?PATH:.*\n?//img; # PATH or ^APATH line # If nothing meaningful remains, flag it $reason .= 'Body ' if $body !~ /\S/; return "Invalid fields: $reason" if $reason ne ''; return; # explicitly return undef if OK } 1;