On Thu, 2003-07-10 at 05:19, Ken Murchison wrote: > What is this perl script trying to do? Can you get a protocol dump?
The script: I require a server-side sent directory. That way, I don't have to try to synchronize the sent directory on the three clients that I use, and we have a copy of every outgoing mail sent So, in Postfix, I say: always_bcc = storesent and in /etc/aliases: storesent: |/usr/sbin/storesent That way, Postfix invokes this script on every message that passes through the mail server. The script throws out the messages with non-local origin and then saves the rest in the appropriate user's mailbox. I've been doing this for years on Courier -- it takes about a 10-line script. Here's where the authentication happens: my $userid = shift; my $cl = Cyrus::IMAP::Admin->new('localhost'); die "Could not connect to Cyrus server" . ($! ? ": $!\n" : "\n") unless $cl; my $rc = $cl->authenticate('-user' => $user, '-password' => $pass); die "Could not log in: " . $cl->error . "\n" unless $rc; # check for the existence of the Sent folder unless( $cl->list("user.$userid.$sent") ) { # doesn't exist, so create it. $cl->create("user.$userid.$sent"); die "Could not create user.$userid.$sent: " . $cl->error . "\n" if $cl->error; } ... I've included the entire script as an attachment. It must be possible to get a protocol dump, but I'm not sure how. Is there a flag I can turn on in Perl to get the Cyrus::IMAP::Admin module to log all LMTP traffic? Feel free to comment, no matter how harshly. :) Thanks, - Scott
#!/usr/bin/perl -w # storesent # Scott Bronson # 3 July 2003 # TODO: should report errors via an email message. # TODO: right now Return-Path on stored messages is [EMAIL PROTECTED] Prolly want to fix this. # This script is called by the Postfix local transport to automatically # deliver messages into a user's Sent mail folder. # This works for Cyrus. Simple modifications would be needed for Courier. # How to install: # 1) Put "always_bcc = storesent" in /etc/postfix/main.cf # 2) Put "storesent = |/usr/local/sbin/storesent" in /etc/aliases # 3) Run "newaliases" and "postdfix reload". That's it! # 4) On my system, I need to do this to get it to work (I haven't # figured out why): "chown cyrus storesent; chmod u+s storesent" # This is a very minor but totally unnecessary security risk. # 5) "chmod go-r" so regular users can't see the password. # There is only one known bug: if you send a message to a mailing # list, that message will usually be reflected back to you. Since # you are listed as the sender in that message, and there's no easy # way to tell that it is from a mailing list and not directly from # the user, it will be stored in your Sent folder. This is not a # problem if your IMAP server removes dupes (like Cyrus). use strict; # the following three lines are only used by ensure_folder_exists(). # If you create all the Sent folders ahead of time, you can delete # these three lines, the routine itself, and the one line that calls it. use Cyrus::IMAP::Admin; my $user = 'root'; # username of an IMAP administrator my $pass = 'PASSPASS'; # his/her PASSWORD < < < % % % % % # These should be configured for the local site: my $sent = "Sent"; # name of the sent mail mailbox my %ignores = ( 'root' => 1, 'daemon' => 1 ); my $deliver = "/usr/sbin/cyrdeliver"; # allow this script to run suid $ENV{PATH} = '/bin:/usr/bin'; # # Use postconf to tell us the value of $mydomain # open(CONF, "-|", "/usr/sbin/postconf", "-h", "mydomain") or die "Could not execute /usr/sbin/postconf: $!\n"; my $mydomain = <CONF>; chomp $mydomain; close CONF or die "Error running /usr/sbin/postconf: $1\n"; # # Read headers into @msgheaders. Each header will be a # single element in this ordered set of multi-line strings. # my @msgheaders; while( <STDIN> ) { last if /^\s*$/; # empty line markes the end of the headers if( /^\s/ ) { # Any line in the header beginning with whitespace is a # continuation of the previous header. $msgheaders[$#msgheaders] .= $_; } else { push @msgheaders, $_; } } # # Decide whether to store in sent mail or not. If the sender's # domain is the same as $mydomain, then sender is local. If # not, we throw it away. # my $sender = $ENV{'SENDER'}; if( $sender =~ /^\s*([EMAIL PROTECTED])\@(?:\S+\.)?$mydomain\s*$/ && !$ignores{$1} ) { my $userid = $1; ensure_folder_exists($userid); open(OUT, "|-", $deliver, "-m", $sent, $userid) or die "Could not execute $deliver: $!\n"; } else { # not local: dump this mesage open(OUT, ">/dev/null") or die "Could not open /dev/null??? $!\n"; } # # Send message to cyrdeliver. First send headers, then # a blank line, then the message body. # # The first header: output a custom Recieved header print OUT "Received: from $mydomain (Postfix) by $mydomain (storesent)\n"; # Then output for( @msgheaders ) { # Get rid of Postfix's delivery headers. Cyrus will supply its own. next if /^From[ \t]/is; next if /^Return-Path:/is; next if /^X-Original-To:/is; next if /^Delivered-To:/is; # Cyrus thinks it's a dupe if we don't munge the Message-ID s/\@/.570@/ if /^Message-ID:/is; print OUT $_; } print OUT "\n"; # print body print OUT while <STDIN>; # # we're done! # close OUT or die "storesent could not save message: $! ($?)\n"; exit 0; # # This function should not be necessary! cyrdeliver needs an # option to create the mail folder if it doesn't already # exist. # sub ensure_folder_exists { my $userid = shift; my $cl = Cyrus::IMAP::Admin->new('localhost'); die "Could not connect to Cyrus server" . ($! ? ": $!\n" : "\n") unless $cl; my $rc = $cl->authenticate('-user' => $user, '-password' => $pass); die "Could not log in: " . $cl->error . "\n" unless $rc; # check for the existence of the Sent folder unless( $cl->list("user.$userid.$sent") ) { # doesn't exist, so create it. $cl->create("user.$userid.$sent"); die "Could not create user.$userid.$sent: " . $cl->error . "\n" if $cl->error; } $cl->setacl("user.$userid.$sent", 'anyone', 'p'); die "Could not set acl for anyone on user.$userid.$sent: " . $cl->error . "\n" if $cl->error; }