.\" -*- mode: troff; coding: utf-8 -*-
.\" Automatically generated by Pod::Man v6.0.2 (Pod::Simple 3.45)
.\"
.\" Standard preamble:
.\" ========================================================================
.de Sp \" Vertical space (when we can't use .PP)
.if t .sp .5v
.if n .sp
..
.de Vb \" Begin verbatim text
.ft CW
.nf
.ne \\$1
..
.de Ve \" End verbatim text
.ft R
.fi
..
.\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>.
.ie n \{\
.    ds C` ""
.    ds C' ""
'br\}
.el\{\
.    ds C`
.    ds C'
'br\}
.\"
.\" Escape single quotes in literal strings from groff's Unicode transform.
.ie \n(.g .ds Aq \(aq
.el       .ds Aq '
.\"
.\" If the F register is >0, we'll generate index entries on stderr for
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
.\" entries marked with X<> in POD.  Of course, you'll have to process the
.\" output yourself in some meaningful fashion.
.\"
.\" Avoid warning from groff about undefined register 'F'.
.de IX
..
.nr rF 0
.if \n(.g .if rF .nr rF 1
.if (\n(rF:(\n(.g==0)) \{\
.    if \nF \{\
.        de IX
.        tm Index:\\$1\t\\n%\t"\\$2"
..
.        if !\nF==2 \{\
.            nr % 0
.            nr F 2
.        \}
.    \}
.\}
.rr rF
.\"
.\" Required to disable full justification in groff 1.23.0.
.if n .ds AD l
.\" ========================================================================
.\"
.IX Title "Mail::SpamAssassin::Handler::Archive 3pm"
.TH Mail::SpamAssassin::Handler::Archive 3pm 2026-11-05 "perl v5.42.3" "User Contributed Perl Documentation"
.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
.nh
.SH NAME
Mail::SpamAssassin::Handler::Archive \- A MIME\-part handler for archive files
.SH SYNOPSIS
.IX Header "SYNOPSIS"
.Vb 1
\&  loadhandler  Mail::SpamAssassin::Handler::Archive
.Ve
.SH DESCRIPTION
.IX Header "DESCRIPTION"
A MIME\-part handler that opens \f(CW\*(C`zip\*(C'\fR and \f(CW\*(C`rar\*(C'\fR archive attachments, extracts a
bounded number of the files inside, and returns each as a child part.  The
handler framework then re\-dispatches every extracted file by its
\&\f(CW\*(C`effective_type\*(C'\fR (filename extension first), so an \f(CW\*(C`inner.js\*(C'\fR reaches the
JavaScript handler, an \f(CW\*(C`inner.html\*(C'\fR reaches the HTML handler, an \f(CW\*(C`inner.pdf\*(C'\fR
the PDF handler, an image the image handler, and a nested archive comes back to
this handler \-\- all bounded by the framework\*(Aqs depth, part\-count and byte
budgets.
.PP
The handler is intentionally thin: its main job is to make the archive\*(Aqs contents
visible to the other handlers and to ordinary body rules.  It also provides one
eval rule, \f(CW\*(C`check_archive_file_count\*(C'\fR, for matching on the number of files an
archive declares (see "EVAL RULES").
.SH REQUIREMENTS
.IX Header "REQUIREMENTS"
.IP zip 2
.IX Item "zip"
Extraction uses Archive::Zip.  If it is not installed, the handler still
loads (with a warning at startup) and skips zip archives.
.IP rar 2
.IX Item "rar"
Extraction shells out to the \f(CW\*(C`unrar\*(C'\fR executable.  Set \f(CW\*(C`archive_unrar_path\*(C'\fR if
it is not on the \f(CW\*(C`PATH\*(C'\fR.  If it cannot be found, rar extraction is disabled with
a debug message, so \f(CW\*(C`\-\-lint\*(C'\fR never fails merely because the binary is absent.
.SH CONFIGURATION
.IX Header "CONFIGURATION"
.IP "archive_max_files N    (default: 2)" 4
.IX Item "archive_max_files N (default: 2)"
Extract at most N files from each archive.  Bounds the work done downstream and
is a countermeasure against archives that pack a very large number of entries.
.IP "archive_unrar_path /path/to/unrar" 4
.IX Item "archive_unrar_path /path/to/unrar"
Full path to the \f(CW\*(C`unrar\*(C'\fR executable.  If unset, the handler looks for \f(CW\*(C`unrar\*(C'\fR
on the \f(CW\*(C`PATH\*(C'\fR.
.SH "EVAL RULES"
.IX Header "EVAL RULES"
.IP "check_archive_file_count(min[, max])" 4
.IX Item "check_archive_file_count(min[, max])"
Fires when any archive in the message declares an entry count of at least \f(CW\*(C`min\*(C'\fR
(and, if \f(CW\*(C`max\*(C'\fR is given and non\-zero, at most \f(CW\*(C`max\*(C'\fR).  The count is the
archive\*(Aqs full declared total \-\- read from the zip End Of Central Directory
record, or from \f(CW\*(C`unrar\*(C'\fR\*(Aqs member listing \-\- and is therefore independent of
\&\f(CW\*(C`archive_max_files\*(C'\fR: an archive that packs thousands of files but from which only
four are extracted still reports its true size.  Useful for flagging archives that
pack an implausible number of entries.
.Sp
.Vb 2
\&  body  ARC_MANY_FILES   eval:check_archive_file_count(100)
\&  body  ARC_FILES_RANGE  eval:check_archive_file_count(2,10)
.Ve
