#!/usr/bin/perl ## ## mewinc: mewls helper for local spool ## [from imget] ## ## Author: Shun-ichi TAHARA ## Time-stamp: <00/10/25 15:35:17 jado@sophia> ## ### Configuration variables: ### Local spool path: $mailspool = '/var/spool/mail'; #$mailspool = '/usr/spool/mail'; #$mailspool = '/var/mail'; #$mailspool = '/usr/mail'; ### Mail folders path: ## If you want to use mewinc alone, set this. ## You need not to be set while you use mewinc only from mewls, even if you set ## mew-mail-path to be different from the default. $mailfolder = undef; #$mailfolder = "$ENV{HOME}/Mail"; #$mailfolder = (getpwuid($<))[7]."/Mail"; ### Use Content-Length: header: ## Solaris 2.x (and so on) needs setting this to 1. $obeycl = 0; ### Use flock() included in Perl: ## flock() function in Perl uses flock, fcntl or lockf syscall inside it. ## If your OS has flock/fcntl/lockf feature, and locking methods are same ## between Perl and mail.local(and so on), set this to 1. ## Generally, you can use this safely if your OS has flock syscall, however, ## fcntl may be used in perl and lockf in mail.local, if not (for example, ## Solaris 2.x). In this case, you could not lock your mail spool with ## flock() in Perl, so you must consider using lock file explained below. $useflock = 1; ### Use lock file: ## If your OS doesn't have flock/fcntl/lockf feature, or file locking features ## are different between Perl and mail.local(and so on), set this to 1. ## As documented above, Solaris 2.x (and so on) may need setting this to 1. $uselockfile = 0; ### System call number of fsync(): ## This may found on "SYS_fsync" macro in /usr/include/sys/syscall.h. ## If not found and your mail folders are over NFS, take care of file system ## overflow! $fsync_no = undef; #$fsync_no = "118"; # Linux #$fsync_no = "95"; # FreeBSD ### List From: header by default: ## If you want list From: header by default, set this to 1. $listfrom = 0; ### List Subject: header by default: ## If you want list Subject: header by default, set this to 1. $listsubj = 0; ### End of configuration variables. require 5.003; use Cwd; use Fcntl; use integer; $folder = 'inbox'; $keep = 0; $mbopt = 0; $mailbox = ''; $mfopt = 0; sub fsync ($) { my ($fno) = @_; if ($fsync_no and syscall($fsync_no, $fno) < 0) { return 0; } return 1; } sub LOCK_SH { 1 } sub LOCK_EX { 2 } sub LOCK_NB { 4 } sub LOCK_UN { 8 } $locked_by_file = 0; $locked_by_flock = 0; sub lockmbox ($) { my ($base) = @_; my ($retry); $retry = 0; $locked_by_file = 0; $locked_by_flock = 0; return 1 unless $useflock || $uselockfile; if ($useflock) { if (open(LOCK_FH, "+<$base") and flock(LOCK_FH, LOCK_EX | LOCK_NB)) { $locked_by_flock = 1; } } if ($uselockfile) { open(LOCKFILE, ">$base.$$") or goto NEXT; binmode(LOCKFILE); print LOCKFILE "$$\n"; close(LOCKFILE); while (!link("$base.$$", "$base.lock")) { if ($retry >= 10) { unlink("$base.$$"); goto NEXT; } $retry++; sleep(5); } unlink("$base.$$"); $locked_by_file = 1; NEXT: } return 0 unless $locked_by_flock || $locked_by_file; return 1; } sub unlockmbox ($) { my ($base) = @_; if ($locked_by_flock) { $locked_by_flock = 0; flock(LOCK_FH, LOCK_UN); } if ($locked_by_file) { $locked_by_file = 0; if (-f "$base.lock") { unlink("$base.lock"); } } } sub empty_mbox ($) { my ($mbox) = @_; local (*MBOX); unless (truncate($mbox, 0)) { unless (open(MBOX, ">$mbox")) { print STDERR "Can't clear mailbox.\n"; return; } close(MBOX); } } sub message_number { my ($number, @files); local (*DIR); opendir(DIR, '.') or die "Can't open current directory, stopped"; @files = sort {$a <=> $b} grep /^\d+$/, readdir(DIR); closedir(DIR); if (scalar(@files) == 0) { $number = 1; } else { $number = $files[$#files] + 1; } while (-e "$number" || -e ".$number.dir") { $number++; } return $number; } sub excl_create ($$) { my ($MESSAGE, $file) = @_; my ($attr); $attr = Fcntl::O_RDWR | Fcntl::O_CREAT | Fcntl::O_EXCL; umask(066); sysopen($MESSAGE, $file, $attr) or return 0; binmode($MESSAGE); return 1; } $msgnum = 0; sub new_message ($) { my ($MESSAGE) = @_; my ($try); if ($msgnum == 0) { $msgnum = message_number; } else { $msgnum++; } $try = 3; while ($try--) { if (excl_create($MESSAGE, "$msgnum")) { # created successfully return "$msgnum"; } $msgnum++; } # message creation failed return undef; } sub store_message ($) { my ($Msg) = @_; local (*ART); my ($file, $subj, $from, $nl); $file = new_message(\*ART); if ($file) { select (ART); $| = 1; select (STDOUT); foreach (@$Msg) { print ART $_ or goto ERR1; $from = $1 if (/^(From:.*)/); $subj = $1 if (/^(Subject:.*)/); } fsync(fileno(ART)) or goto ERR1; close(ART) or goto ERR2; $nl = "\n"; print "$file"; if ($listfrom) { print "\t$from\n"; $nl = undef; } if ($listsubj) { print "\t$subj\n"; $nl = undef; } print $nl; return 1; ERR1: close(ART); ERR2: print STDERR "Writing to the file \"$file\" failed ($!).\n"; unlink($file) if (-z $file); return 0; } else { print STDERR "Message can't be saved.\n"; return 0; } } sub process_mbox ($) { my ($src) = @_; my ($format, $msgs, $length, $inheader, @Message); local (*MBOX); my ($first_line); if ($src) { open(MBOX, "<$src") or return -1; } else { *MBOX = *STDIN; } chomp($first_line = ); if ($first_line =~ /^From /) { $format = 'UNIX'; } elsif ($first_line =~ /^\001\001\001\001$/) { $format = 'MMDF'; } elsif ($first_line =~ /^BABYL OPTIONS:/) { $format = 'RMAIL'; } else { print STDERR "Invalid mbox format: $src\n"; return -1; } $msgs = 0; while ($first_line ne '') { if ($msgs > 0 && $format eq 'MMDF') { $first_line = ; last if $first_line !~ /^\001\001\001\001$/; } if ($format eq 'RMAIL') { while () { last if /^\*\*\* EOOH \*\*\*$/; } } if ($format eq 'UNIX') { # convert UNIX From_ into Return-Path my ($rp); $rp = $first_line; $rp =~ s/^From +//; $rp =~ s/ +[A-Z][a-z][a-z] [A-Z][a-z][a-z] [\d ]\d \d\d:\d\d.*//; $rp = "<$rp>" if $rp !~ /^<.*>$/; @Message = ("Return-Path: $rp\n"); } else { @Message = (); } $first_line = ''; $inheader = 1; $length = -1; while () { if ($format eq 'MMDF' && /^\001\001\001\001$/) { $first_line = 'MMDF'; last; } elsif ($format eq 'UNIX' && $length <= 0 && /^From / && $Message[$#Message] eq "\n") { chomp($first_line = $_); last; } elsif ($format eq 'RMAIL' && /^\x1f/ ) { chomp($first_line = ); last; } elsif ($inheader) { # XXX continuous line processing needed push @Message, $_; # for Solaris 2.x or ... # XXX option if ($obeycl && /^Content-Length:(.*)/i) { chomp($length = $1); } $inheader = 0 if (/^\n$/); } else { push @Message, $_; $length -= length($_) if $length > 0; } } if ($Message[$#Message] eq "\n") { pop @Message; } $msgs++ if ($#Message >= 0); unless (store_message(\@Message)) { close(MBOX); return -1; } } close(MBOX); print STDERR "$msgs message(s).\n"; return $msgs; } sub getmsg ($$) { my ($src, $keep) = @_; my ($msgs); # set default unless ($src) { my ($user); $user = getlogin; if ($user eq '' || $user eq 'root') { $user = (getpwuid($<))[0]; } $src = "$mailspool/$user"; } if ($src eq '-') { # STDIN if (($msgs = process_mbox('')) < 0) { die "Can't get message from STDIN, stopped"; } return $msgs; } elsif (-s $src) { # FILE and not ZERO unless (lockmbox($src)) { unlockmbox($src); die "Can't lock mailbox \"$src\", stopped"; } if (($msgs = process_mbox($src)) < 0) { unlockmbox($src); die "Can't get message from mailbox \"$src\", stopped"; } empty_mbox($src) unless ($keep); unlockmbox($src); return $msgs; } else { print STDERR "No messages in mailbox.\n"; return 0; } } sub usage { print "Usage: mewinc [options] [+folder]\n"; print " options: -mailbox|-f mboxfile|-\n"; print " -mailfolder|-d folderpath\n"; print " -keep|-k\n"; print " -listfrom|-lf / -nofrom|-nf\n"; print " -listsubject|-ls / -nosubject|-ns\n"; exit(0); } foreach (@ARGV) { if ($mbopt) { $mbopt = 0; $mailbox = $_; } elsif ($mfopt) { $mfopt = 0; $mailfolder = $_; } elsif (/^-(ignorecl|c-)$/) { $obeycl = 0; } elsif (/^-(obeycl|c\+)$/) { $obeycl = 1; } elsif (/^-(noflock|s-)$/) { $useflock = 0; } elsif (/^-(useflock|s\+)$/) { $useflock = 1; } elsif (/^-(nolockfile|f-)$/) { $uselockfile = 0; } elsif (/^-(uselockfile|f\+)$/) { $uselockfile = 1; } elsif (/^-(keep|k)$/) { $keep = 1; } elsif (/^-(mailbox|f)$/) { $mbopt = 1; } elsif (/^-(mailfolder|d)$/) { $mfopt = 1; } elsif (/^-(nofrom|nf)$/) { $listfrom = 0; } elsif (/^-(listfrom|lf)$/) { $listfrom = 1; } elsif (/^-(nosubject|ns)$/) { $listsubj = 0; } elsif (/^-(listsubject|ls)$/) { $listsubj = 1; } elsif (/^-h/) { usage; } elsif (/^-/) { die "Unknown switch \"$_\", stopped"; } elsif (/^\+(.+)$/) { $folder = $1; } else { die "Invalid parameter \"$_\", stopped"; } } die "Filename expected after \"-mailbox\" or \"-f\", stopped" if $mbopt; die "Directory expected after \"-mailfolder\" or \"-d\", stopped" if $mfopt; if ($mailfolder) { $_ = "$mailfolder/$folder"; chdir "$_" or die "Can't chdir to \"$_\", stopped\n"; } else { $_ = ".*/$folder\$"; die "Must be executed on the folder \"$folder\", stopped" if cwd !~ /$_/; } getmsg($mailbox, $keep); exit(0); ### Copyright Notice: ## Copyright (C) 2000 Shun-ichi TAHARA ## Copyright (C) 1997, 1998, 1999 IM developing team ## All rights reserved. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted provided that the following conditions ## are met: ## ## 1. Redistributions of source code must retain the above copyright ## notice, this list of conditions and the following disclaimer. ## 2. Redistributions in binary form must reproduce the above copyright ## notice, this list of conditions and the following disclaimer in the ## documentation and/or other materials provided with the distribution. ## 3. Neither the name of the team nor the names of its contributors ## may be used to endorse or promote products derived from this software ## without specific prior written permission. ## ## THIS SOFTWARE IS PROVIDED BY THE TEAM AND CONTRIBUTORS ``AS IS'' AND ## ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TEAM OR CONTRIBUTORS BE ## LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ## BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ## WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE ## OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN ## IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### mewinc ends here.