#!/usr/bin/perl # This is intended to accept email from procmail as a filter # # It takes any attached jpg files, converts them to gifs and then # turns them into a single animated gif. # The email is then passed back to procmail after the jpgs have been # dettached and the animated gif has been attached. # in addition to the MIME modules indicated below, it requires # these two external programs: # whirlgif: http://www.msg.net/utility/whirlgif/ # and # djpeg: http://freshmeat.net/projects/libjpeg/?topic_id=105%2C809 # example procmailrc snippet: # :0 # * ^TOanimblogpost # { # # filter to create animated gif # # f = filter # # h = filter the header # # b = filter the body too # :0fhb # |/home/dav/bin/anim_gif_filter.pl # # # post this to my blog # :0 c # |/home/dav/bin/blogpost.pl -c/home/dav/.blogpostrc.akuaku # } #use strict; use POSIX; use MIME::Explode; use MIME::Entity; my $pid = $$; my $datestring = strftime('%Y-%m-%d_%H%M%S', localtime); my $home_dir = $ENV{'HOME'}; my $work_dir = '$home_dir/tmp_anim'; my $unique_name = "${datestring}_${pid}"; my $anim_gif_file = "$unique_name_anim.gif"; my $anim_gif_path = "$work_dir/$anim_gif_file"; my $temp_mail = "$work_dir/$unique_name.mail"; my $from; my $to; my $subject; my @attachments; exit; # first parse STDIN for header info, and store in a temp # file so it can be exploded later open( TMPMAIL, ">$temp_mail") or exit; while () { if ($from == undef && $_ =~ /^From: (.+)/) { $from = $1; } if ($to == undef && $_ =~ /^To: (.+)/) { $to = $1; } if ($subject == undef && $_ =~ /^Subject: (.+)/) { $subject = $1; } print TMPMAIL; } close TMPMAIL; # reopen in read mode so we can explode it open( TMPMAIL, $temp_mail ); my $explode = MIME::Explode->new( output_dir => $work_dir, mkdir => 0755, decode_subject => 1, chcek_content_type => 1, exclude_types => [], ); #my $headers = $explode->parse(\*STDIN, \*TMPOUT); #my $headers = $explode->parse(\*STDIN); my $headers = $explode->parse(\*TMPMAIL); close TMPMAIL; # parse out the headers my $mail = &parseMail; my $body = $mail->{body}; # set whirlgif options from message body my $loop = '-loop'; #default to loop forever my $delay = '-time 50'; #default to half a second if ($body =~ m/noloop/) { $body =~ s/noloop//; $loop = ''; } if ($body =~ m/delay(\d+)/) { my $hundrenths = $1; $body =~ s/delay$hundrenths//; $delay = "-time $hundrenths"; } # do the actual jpeg->animated gif conversions &processAttachments; ### Create the top-level, and set up the mail headers: $top = MIME::Entity->build(Type =>"multipart/mixed", From => $from, To => $to, Subject => $subject); $top->attach(Data => $body); # attach the gif foreach $attachment (@attachments) { if ($attachment =~ /\.gif$/) { $top->attach( Path => "$work_dir/$attachment", Type => "image/gif", Encoding => "base64"); # ignore other attachments fo rnow } } # now dump it back out, since this is a procmail filter $top->print(\*STDOUT); ### clean up unlink $temp_mail; unlink "$work_dir/file.txt"; # this needs to be fixed, might delete wrong foreach $attachment (@attachments) { unlink "$work_dir/$attachment"; } ######################################################################### sub processAttachments { my @gifs; #my @jpg_to_remove; # rename images making them unique for ($count = 0; $count<=$#attachments; $count++) { $attachments[$count]=~s/;//g; # security precaution #print "ATT: $attachments[$count]\n"; $oldpath = "$work_dir/$attachments[$count]"; if ($oldpath =~ /\.([Jj][Pp][Ee]?[Gg])$/) { $newname = "${datestring}_${pid}_${count}.jpg"; $newpath = "$work_dir/$newname"; rename( $oldpath, $newpath ) && ($attachments[$count]=$newname); $tempgif = "$work_dir/${datestring}_${pid}_${count}.gif"; my $conv_cmd = "djpeg -gif $newpath > $tempgif"; #print "*** $conv_cmd\n"; system( $conv_cmd ); unshift( @gifs, $tempgif ); #unshift( @jpg_to_remove, $attachments[$count] ); } else { $attachments[$count]=$newname; } } my $anim_gif_file = "${datestring}_${pid}_anim.gif"; my $anim_gif_path = "$work_dir/$anim_gif_file"; my $animate_cmd = "whirlgif $loop $delay -o $work_dir/$anim_gif_file "; foreach $gif (@gifs) { $animate_cmd = $animate_cmd . $gif . " "; } $animate_cmd = $animate_cmd . " 2>&1 >/dev/null"; #print "*** $animate_cmd\n"; my $devnull = `$animate_cmd`; # clean up foreach $gif (@gifs) { unlink "$gif"; } unshift( @attachments, $anim_gif_file ); } sub parseMail { my $body; my $subject; my $dateline; my $jpgs=0; for my $part (sort{ $a cmp $b } keys(%{$headers})) { my $filename = $headers->{$part}->{'content-disposition'}->{filename}; my $filepath = $headers->{$part}->{'content-disposition'}->{filepath}; #print "GOT: $filename\n"; if ($filename eq 'file.txt') { $body = `cat $work_dir/$filename`; chop $body; } elsif ($filename =~ m/[Jj][Pp][Ee]?[Gg]$/) { #print "ADD: $filename\n"; $attachments[$jpgs++]=$filename; $attachments_full[$jpgs]=$filepath; chmod 0644, $filepath; #print "filename: $filename\n"; #print "filepath: $filepath\n"; } } $dateline = $headers->{'0.0'}->{date}; $subject = join("", @{$headers->{'0.0'}->{subject}->{value}}); my $mail = { body => $body, dateline => $dateline, subject => $subject }; return $mail; } #########################################################################