[Mimedefang] Re: replace_with_url with multiple small

Yizhar Hurwitz yizhar at mail.com
Sat Dec 23 09:16:57 EST 2006


From: "Matthew S. Cramer" <mscramer at armstrong.com>
> I haven't really thought about it until now, so if anyone else wants
> to comment with suggestions or with sample code to handle this situation
> with all links together (in one text part replacement, ideally I
> guess), please do!  That would be more elegant than what I've done.
I have also researched and played with this.

First - replace_with_url is really a great feature,
so one more thank to David.

Below is my custom implementation which is intended for the following goals:

* It works in a similar way to what "AddWarningsInline" does,
but AddWarningsInline breaks the html links and this is why I used a 
custom code.

* Make it user friendly for those who use Microsoft Outlook,
by placing the links inline the message body.
MS Outlook doesn't display multiple inline text attachments.

* Place the links in both text and html parts.

* List all replaced attachments in a single list.
Currently in my script the generated message contains each link doubled
(once as another text/html attachment, and once again in the body).

* Create a subdirectory for each month,
this is to make maintenance easier.
For example:

My "sub custom_action_replace_with_url" code is a copy of the original 
one with the addition of the lines:
### Begin modified section: ###
    push (@DetachedFiles, $cd_data. "\n". $url. "\n");
### End modified section. ###

To David - when you find the right time,
please try to polish the built in replace_with_url function to work in a 
similar way,
and test the generated output with MS Outlook in the eyes of an end user,
which doesn't know what to do unless he gets a clickable and easy to use 

=============== mimedefang-filter ====================

### Global variables (constants):

$HostName = hostname();
$DetachBigEnable = 0;
$DetachBigSizeMB = 10;
$DetachMultimediaEnable = 0;
$DetachMultimediaExt = 'asf|avi|mov|mpeg|mpg|wmv';
$DetachBasePath = '/var/www/detach';
$DetachBaseURL = 'http://'. $HostName;
$DetachText =
 "The following file was detached from the original message:\n".
 "Size: _FILESIZE_\n".
 "You can download it here:\n\n".
 "Please note that the download process can take some time.\n" .
 "Please note that the files will later be deleted from the mail server.\n";
$DetachListTextTop =
 "The following files were detached:\n\n";
$DetachListTextBot =
 "Please note that the files will later be deleted from the mail server.\n";

sub filter_initialize {
 $DetachSubdir = '/'. substr(time_str, 0, 7);
 $DetachPath = $DetachBasePath. $DetachSubdir;
 $DetachURL = $DetachBaseURL. $DetachSubdir;
 if ($DetachBigEnable or $DetachMultimediaEnable) {
  unless (-e $DetachPath) {
   mkdir ($DetachPath);
   chmod (0755, $DetachPath);
# Other code .....

sub filter_begin {
    my($entity) = @_;

    @DetachedFiles = ();
# other code...

sub custom_action_replace_with_url ($$$$;$$) {
    my($entity, $doc_root, $base_url, $msg, $cd_data, $salt) = @_;
    my($fname, $ext, $name, $url);
    my $extension = "";

    return 0 unless in_filter_context("action_replace_with_url");
    return 0 unless defined($entity->bodyhandle);
    $path = $entity->bodyhandle->path;
    return 0 unless defined($path);
    open(IN, "<$path") or return 0;

    $ctx = Digest::SHA1->new;
    $ctx->add($salt) if defined($salt);

    $fname = takeStabAtFilename($entity);
    $fname = "" unless defined($fname);
    $extension = $1 if ($fname =~ /(\.[^.]*)$/);

    # Use extension if it is .[alpha,digit,underscore]
    $extension = "" unless ($extension =~ /^\.[A-Za-z0-9_]*$/);

    # Filename to save
    $name = $ctx->hexdigest . $extension;
    $fname = $doc_root . "/" . $name;
    $url = $base_url . "/" . $name;

    if (-r $fname) {
        # If file exists, then this is either a duplicate or someone
        # has defeated SHA1.  Just update the mtime on the file.
        $now = time;
        utime($now, $now, $fname);
    } else {
        copy_or_link($path, $fname) or return 0;
        # In case umask is whacked...
        chmod 0644, $fname;

    # save optional Content-Disposition data
    if (defined($cd_data) and ($cd_data ne "")) {
        if (open CDF, ">$doc_root/.$name") {
            print CDF $cd_data;
            close CDF;
            chmod 0644, "$doc_root/.$name";

    $msg =~ s/_URL_/$url/g;

### Begin modified section: ###
    push (@DetachedFiles, $cd_data. "\n". $url. "\n");
### End modified section. ###

    return 1;

sub filter {
    my($entity, $fname, $ext, $type) = @_;
    my $FileSize;
    my $detach_msg;
# Other code ...
    $FileSize = (stat($entity->bodyhandle->path))[7];
    if (($DetachBigEnable and ($FileSize >= $DetachBigSizeMB*1000000)) 
or ($DetachMultimediaEnable and ($ext =~ /^\.($DetachMultimediaExt)$/i))) {
        md_graphdefang_log('detached', $fname, $FileSize);
        $detach_msg = $DetachText;
        $detach_msg =~ s/_FILENAME_/$fname/g;
        $detach_msg =~ s/_FILESIZE_/$FileSize/g;
        return custom_action_replace_with_url($entity, $DetachPath, 
$DetachURL, $detach_msg, $fname);
# Other code ...

# %PROCEDURE: list_detached_files
sub list_detached_files ($) {
    my($entity) = @_;
    my $plain = $DetachListTextTop. join("\n", @DetachedFiles). 
    my $html = $plain;
    $html =~ s|(http://\S*)|<a href="$1">$1</a>|g;
    $html =~ s/\n/<br>\n/g;
    append_text_boilerplate($entity, $plain, 0);
    append_html_boilerplate($entity, $html, 0);

sub filter_end {
    my($entity) = @_;

    # No sense doing any extra work
    return if message_rejected();

    if (@DetachedFiles > 0) {
# Other code ...

=============== mimedefang-filter ====================

Comments are welcome.

BTW - Sample CGI scripts for downloading the files are welcome also,
as currently my users get the SHA1 filename instead of the original one.
I guess that it is easy but didn't play with it yet.

Yizhar Hurwitz

More information about the MIMEDefang mailing list