Article 115353 of comp.os.vms:

[NOTE CROSSPOSTING IF REPLYING]

Hi,

Since I've had four requests for this by mail, I'm posting
it here... it's a bit nasty, in that it relies on the output
format of the VMS extract command being as expected... it
also contains some site-specific things... e.g. the hardwired
address translation in the first subroutine, and the part
that strips the "MX%" that our brain-dead mail package used
to append to SMTP-type addresses.

Hope this is useful to someone.

  Dave

#!/usr/local/bin/perl
#
# Script to convert a VMS extracted mail folder on the standard input into a
# unix-type mail folder on the standard output (works with pine).
#
# Dave Newbold (dave.newbold@cern.ch), University of Bristol, 1996.
#
# This subroutine takes an array of email addresses and converts dodgy ones
# into some kind of RFC-like format. BRSPVA:: becomes @siva.bris.ac.uk.
# Returns an array of new addresses in the same order.
#
sub DoAddrs{
  @Return=();
  foreach $Addr (@_){
    if($Addr=~m/::/){
      $Host=substr($Addr,0,index($Addr,"::"));
      if($Host eq "BRSPVA"){
        $Host="siva.bris.ac.uk";
      }
      elsif($Host eq "JUNO"){
        $Host="juno.phy.bris.ac.uk";
      }
      elsif($Host eq "VXCERN"){
        $Host="vxcern.cern.ch";
      }
      else{
        $Host=$Host.".decnet";
      }
      $NewAddr="\L".substr($Addr,index($Addr,"::")+2)."\@$Host";
    }
    elsif(-1==index($Addr,"\@")){
      $NewAddr="\L".$Addr."\@siva.bris.ac.uk";
    }
    elsif($Addr=~m/^MX\%/){
      @Split=split("\"",$Addr);
      $NewAddr=$Split[1];
    }
    else{
      $NewAddr=$Addr;
    }
    $NewAddr=`/usr/lib/mh/ap $NewAddr`;
    chop($NewAddr);
    $Return[$#Return+1]=$NewAddr;
  }
  @Return;
}
#
# The main event.
#
# You don't want to know what the line below means. Trust me, and blame VMS.
#
$DPFormat="\"%(day{text}) %(month{text}) %<(mday{text})%>%<(gt 9)%(mday{text})%| %(mday{text})%> %<(hour{text})%>%<(gt 9)%(hour{text})%|0%(hour{text})%>:%<(min{text})%>%<(gt 9)%(min{text})%|0%(min{text})%>:%<(sec{text})%>%<(gt 9)%(sec{text})%|0%(sec{text})%> 19%(year{text})\"";
#
# State machines... you either love `em or hate `em.
#
$InVMSHeader=1;
$InHeader=1;
$HeaderStage=0;
#
while(<STDIN>){
#
# Get rid of form feeds - but they mark the start of each message block
# At this point, we are in the header, and in the VMS header.
#
  if(substr($_,0,1) eq "\f"){
    if($InHeader==0){
      $InHeader=1;
      $InVMSHeader=1;
      print "\n";
    }
    next;
  }
#
# If we see a linefeed in the proper header, we are at the end of the header.
#
  if(($_ eq "\n")&&($InVMSHeader==0)&&($InHeader==1)){
    print "X-ConvertedBy: vmsmail-1.0 by Dave Newbold, University of Bristol UK\n";
    print "X-ConvertedAt: ".`/usr/bin/date`."\n";
    $InHeader=2;
    next;
  }
#
# If we see a non-linefeed after the end of the header, this is the start
# of the message text, and we insert an extra linefeed after the header.
#
  if($InHeader==2){
    if($_ ne "\n"){
      $InHeader=0;
      print "\n$_";
    }
    next;
  }
#
# This part deals with normal message text lines. We escape "From ".
#
  if($InHeader==0){
    if("\L".substr($_,0,5) eq "from "){
      print ">";
    }
    print $_;
    next;
  }
#
# This part deals with header lines.
#
# If we are in the VMS header, keep some information in case we need it
# to make an RFC header later. Sigh.
#
  if($HeaderStage!=0){
    $HeaderStage++;
    $VMSToLine=$_ if $HeaderStage==2;
    $VMSCCLine=$_ if $HeaderStage==3;
    $VMSSuLine=$_ if $HeaderStage==4;
    next if $HeaderStage<6;
    $HeaderStage=0;
    $InVMSHeader=0;
#
# If we find there is no RFC header following the linefeed after the VMS
# header, we try to make one from the VMS header information.
#
    if(!m/^[A-Za-z]+-[A-Za-z]+:/){
        print $VMSFrLine;
        print $VMSDaLine;
        print "Subject: ",substr($VMSSuLine,6);
        chop($VMSToLine);
        chop($VMSCCLine);
        print "To: ",join(",",&DoAddrs(split(",",substr($VMSToLine,4)))),"\n";
        print "CC: ",join(",",&DoAddrs(split(",",substr($VMSCCLine,4)))),"\n";
        print "\n$_";
        $InHeader=0;
        next;
    }
  }
#
# This is the first line in the VMS header, so must be the From: line.
# We take it to pieces and make a "From" line for pine, and store a different
# one for making the RFC header, if necessary.
#
  if($InVMSHeader==1){
    @Line=split;
    $Place=1;
lp: foreach $Piece (@Line[2..$#Line]){
      $Place++;
      if($Piece=~m/^[0-9]{1,2}:[0-9]{1,2}:/){
        $Date="\"".join(" ",@Line[$Place-1..$#Line])."\"";
        last lp;
      }
    }    
    @RetVal=&DoAddrs($Line[1]);
    $RFCAddr=@RetVal[0];
    $PineDate=`/usr/lib/mh/dp -format $DPFormat $Date`;
    chop($PineDate);
    $RFCDate=`/usr/lib/mh/dp $Date`;
    chop($RFCDate);
    print "From $RFCAddr $PineDate\n";
    $VMSFrLine="From: $RFCAddr\n";
    $VMSDaLine="Date: $RFCDate\n";
    $HeaderStage=1;
  }
#
# Otherwise, it's an RFC header line, and we print it.
#
  else{
    print;
  }
# 
# Fin
#
}

-- 
     "Humour is the very essence of a democratic society" -- Anon

        dave.newbold@cern.ch / http://www.phy.bris.ac.uk/~phdmn


