##---------------------------------------------------------------------------## ## File: ## @(#) mhamain.pl 2.19 00/02/13 04:21:32 ## Author: ## Earl Hood mhonarc@pobox.com ## Description: ## Main library for MHonArc. ##---------------------------------------------------------------------------## ## MHonArc -- Internet mail-to-HTML converter ## Copyright (C) 1995-1999 Earl Hood, mhonarc@pobox.com ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA ## 02111-1307, USA ##---------------------------------------------------------------------------## package mhonarc; $VERSION = "2.4.5"; $VINFO =<); } return annotate(@ARGV, $NoteText); } ## Removing messages if ($RMM) { print STDOUT "Removing messages from $OUTDIR ...\n" unless $QUIET; return rmm(@ARGV); } ## HTML message listing to standard output. if ($IDXONLY) { IDXPAGE: { &compute_page_total(); if ($IdxPageNum && $MULTIIDX) { if ($IdxPageNum =~ /first/i) { $IdxPageNum = 1; last IDXPAGE; } if ($IdxPageNum =~ /last/i) { $IdxPageNum = $NumOfPages; last IDXPAGE; } $IdxPageNum = int($IdxPageNum); last IDXPAGE if $IdxPageNum; } $MULTIIDX = 0; $IdxPageNum = 1; $NumOfPages = 1; } if ($THREAD) { &compute_threads(); &write_thread_index($IdxPageNum); } else { &write_main_index($IdxPageNum); } return 1; } ## Get here, we are processing mail folders local($mesg, $tmp, $index, $sub, $from, $i, $date, $fh); local(%fields); $i = $NumOfMsgs; ##-------------------## ## Read mail folders ## ##-------------------## ## Just editing pages if ($EDITIDX) { print STDOUT "Editing $OUTDIR layout ...\n" unless $QUIET; ## Adding a single message } elsif ($ADDSINGLE) { print STDOUT "Adding message to $OUTDIR\n" unless $QUIET; $handle = $ADD; ## Read mail head ($index,$from,$date,$sub,$header) = &read_mail_header($handle, *mesg, *fields); if ($index ne '') { ($From{$index},$Date{$index},$Subject{$index}) = ($from,$date,$sub); $AddIndex{$index} = 1; $IndexNum{$index} = &getNewMsgNum(); $MsgHead{$index} = $mesg; ## Read rest of message $Message{$index} = &read_mail_body( $handle, $index, $header, *fields, $NoMsgPgs); } ## Adding/converting mail{boxes,folders} } else { print STDOUT ($ADD ? "Adding" : "Converting"), " messages to $OUTDIR" unless $QUIET; local($mbox, $mesgfile, @files); foreach $mbox (@ARGV) { ## MH mail folder (a directory) if (-d $mbox) { if (!opendir(MAILDIR, $mbox)) { warn "\nWarning: Unable to open $mbox\n"; next; } $MBOX = 0; $MH = 1; print STDOUT "\nReading $mbox " unless $QUIET; @files = sort { $a <=> $b } grep(/$MHPATTERN/o, readdir(MAILDIR)); closedir(MAILDIR); foreach (@files) { $mesgfile = "${mbox}${DIRSEP}${_}"; if (!($fh = &file_open($mesgfile))) { warn "\nWarning: Unable to open message $mesgfile\n"; next; } print STDOUT "." unless $QUIET; $mesg = ''; ($index,$from,$date,$sub,$header) = &read_mail_header($fh, *mesg, *fields); # Process message if valid if ($index ne '') { ($From{$index},$Date{$index},$Subject{$index}) = ($from,$date,$sub); $MsgHead{$index} = $mesg; if ($ADD && !$SLOW) { $AddIndex{$index} = 1; } $IndexNum{$index} = &getNewMsgNum(); $Message{$index} = &read_mail_body( $fh, $index, $header, *fields, $NoMsgPgs); # Check if conserving memory if ($SLOW && $DoArchive) { &output_mail($index, 1, 1); $Update{$IndexNum{$index}} = 1; } if ($SLOW || !$DoArchive) { delete $MsgHead{$index}; delete $Message{$index}; } } close($fh); } ## UUCP mail box file } else { if ($mbox eq "-") { $fh = $MhaStdin; } elsif (!($fh = &file_open($mbox))) { warn "\nWarning: Unable to open $mbox\n"; next; } $MBOX = 1; $MH = 0; print STDOUT "\nReading $mbox " unless $QUIET; # while (<$fh>) { last if /$FROM/o; } MBOX: while (!eof($fh)) { print STDOUT "." unless $QUIET; $mesg = ''; ($index,$from,$date,$sub,$header) = &read_mail_header($fh, *mesg, *fields); if ($index ne '') { ($From{$index},$Date{$index},$Subject{$index}) = ($from,$date,$sub); $MsgHead{$index} = $mesg; if ($ADD && !$SLOW) { $AddIndex{$index} = 1; } $IndexNum{$index} = &getNewMsgNum(); $Message{$index} = &read_mail_body( $fh, $index, $header, *fields, $NoMsgPgs); if ($SLOW && $DoArchive) { &output_mail($index, 1, 1); $Update{$IndexNum{$index}} = 1; } if ($SLOW || !$DoArchive) { delete $MsgHead{$index}; delete $Message{$index}; } } else { &read_mail_body($fh, $index, $header, *fields, 1); } } close($fh); } # END: else UUCP mailbox } # END: foreach $mbox } # END: Else converting mailboxes print "\n" unless $QUIET; ## All done if not creating an archive if (!$DoArchive) { return 1; } ## Check if there are any new messages if (!$EDITIDX && ($i == $NumOfMsgs)) { print STDOUT "No new messages\n" unless $QUIET; return 1; } ## Write pages &write_pages(); 1; } ##--------------------------------------------------------------------------- ## write_pages writes out all archive pages and db ## sub write_pages { local($i, $key, $index, $tmp, $tmp2); my(@array2); ## Remove old message if hit maximum size or expiration if (($MAXSIZE && ($NumOfMsgs > $MAXSIZE)) || $ExpireTime || $ExpireDateTime) { ## Set @MListOrder and %Index2MLoc for properly marking messages ## to be updated when a related messages are removed. Thread ## data should be around from db. @MListOrder = sort_messages(); @Index2MLoc{@MListOrder} = (0 .. $#MListOrder); # Ignore termination signals &ign_signals(); ## Expiration based upon time my($mloc, $tloc); foreach $index (sort_messages(0,0,0,0)) { last unless ($MAXSIZE && ($NumOfMsgs > $MAXSIZE)) || (&expired_time(&get_time_from_index($index))); &delmsg($index); # Mark messages that need to be updated if (!$NoMsgPgs) { $mloc = $Index2MLoc{$index}; $tloc = $Index2TLoc{$index}; $Update{$IndexNum{$MListOrder[$mloc-1]}} = 1 if $mloc-1 >= 0; $Update{$IndexNum{$MListOrder[$mloc+1]}} = 1 if $mloc+1 <= $#MListOrder; $Update{$IndexNum{$TListOrder[$tloc-1]}} = 1 if $tloc-1 >= 0; $Update{$IndexNum{$TListOrder[$tloc+1]}} = 1 if $tloc+1 <= $#TListOrder; for ($i=2; $i <= $TSliceNBefore; ++$i) { $Update{$IndexNum{$TListOrder[$tloc-$i]}} = 1 if $tloc-$i >= 0; } for ($i=2; $i <= $TSliceNAfter; ++$i) { $Update{$IndexNum{$TListOrder[$tloc+$i]}} = 1 if $tloc-$i >= $#TListOrder; } foreach (split(/$bs/o, $FollowOld{$index})) { $Update{$IndexNum{$_}} = 1; } } # Mark where index page updates start if ($MULTIIDX) { $tmp = int($Index2MLoc{$index}/$IDXSIZE)+1; $IdxMinPg = $tmp if ($tmp < $IdxMinPg || $IdxMinPg < 0); $tmp = int($Index2TLoc{$index}/$IDXSIZE)+1; $TIdxMinPg = $tmp if ($tmp < $TIdxMinPg || $TIdxMinPg < 0); } } } ## Reset MListOrder @MListOrder = sort_messages(); @Index2MLoc{@MListOrder} = (0 .. $#MListOrder); ## Compute follow up messages &compute_follow_ups(\@MListOrder); ## Compute thread information (sets ThreadList, TListOrder, Index2TLoc) &compute_threads(); ## Check for which messages to update when adding to archive if ($ADD) { if ($UPDATE_ALL) { foreach $index (@MListOrder) { $Update{$IndexNum{$index}} = 1; } $IdxMinPg = 0; $TIdxMinPg = 0; } else { $i = 0; foreach $index (@MListOrder) { ## Check for New follow-up links if ($FollowOld{$index} ne $Follow{$index}) { $Update{$IndexNum{$index}} = 1; } ## Check if new message; must update links in prev/next msgs if ($AddIndex{$index}) { # Mark where main index page updates start if ($MULTIIDX) { $tmp = int($Index2MLoc{$index}/$IDXSIZE)+1; $IdxMinPg = $tmp if ($tmp < $IdxMinPg || $IdxMinPg < 0); } # Mark previous/next messages $Update{$IndexNum{$MListOrder[$i-1]}} = 1 if $i > 0; $Update{$IndexNum{$MListOrder[$i+1]}} = 1 if $i < $#MListOrder; } ## Check for New reference links foreach (split(/$X/o, $Refs{$index})) { $tmp = $MsgId{$_}; if (defined($IndexNum{$tmp}) && $AddIndex{$tmp}) { $Update{$IndexNum{$index}} = 1; } } $i++; } $i = 0; foreach $index (@TListOrder) { ## Check if new message; must update links in prev/next msgs if ($AddIndex{$index}) { # Mark where thread index page updates start if ($MULTIIDX) { $tmp = int($Index2TLoc{$index}/$IDXSIZE)+1; $TIdxMinPg = $tmp if ($tmp < $TIdxMinPg || $TIdxMinPg < 0); } # Mark previous/next message in thread $Update{$IndexNum{$TListOrder[$i-1]}} = 1 if $i > 0; $Update{$IndexNum{$TListOrder[$i+1]}} = 1 if $i < $#TListOrder; } $i++; } } } ## Compute total number of pages $i = $NumOfPages; &compute_page_total(); ## Update all pages for $LASTPG$ if ($UsingLASTPG && ($i != $NumOfPages)) { $IdxMinPg = 0; $TIdxMinPg = 0; } ##------------## ## Write Data ## ##------------## &ign_signals(); # Ignore termination signals print STDOUT "\n" unless $QUIET; ## Write indexes and mail &write_mail() unless $NoMsgPgs; &write_main_index() if $MAIN; &write_thread_index() if $THREAD; ## Write database print STDOUT "Writing database ...\n" unless $QUIET; &output_db($DBPathName); ## Write any alternate indexes $IdxMinPg = 0; $TIdxMinPg = 0; my($rc, $rcfile); OTHERIDX: foreach $rc (@OtherIdxs) { $THREAD = 0; ## find other index resource file IDXFIND: { if (! -e $rc) { $rcfile = join($DIRSEP, $OUTDIR, $rc); if (! -e $rcfile) { # look thru @INC to find file local($_); foreach (@INC) { $rcfile = join($DIRSEP, $_, $rc); if (-e $rcfile) { last IDXFIND; } } warn qq/Warning: Unable to find resource file "$rc"\n/; next OTHERIDX; } } else { $rcfile = $rc; } } ## read resource file and print index if (&read_fmt_file($rcfile)) { if ($THREAD) { @TListOrder = (); &write_thread_index(); } else { @MListOrder = (); &write_main_index(); } } } print STDOUT "$NumOfMsgs messages\n" unless $QUIET; } ##--------------------------------------------------------------------------- ## Compute follow-ups ## sub compute_follow_ups { my $idxlst = shift; my($index, $tmp, $tmp2); my(@array); %Follow = (); foreach $index (@$idxlst) { $FolCnt{$index} = 0 unless $FolCnt{$index}; if ( defined($Refs{$index}) && (@array = split(/$X/o, $Refs{$index}))) { $tmp2 = $array[$#array]; next unless defined($MsgId{$tmp2}) && defined($IndexNum{$MsgId{$tmp2}}); $tmp = $MsgId{$tmp2}; if ($Follow{$tmp}) { $Follow{$tmp} .= $bs . $index; } else { $Follow{$tmp} = $index; } ++$FolCnt{$tmp}; } } } ##--------------------------------------------------------------------------- ## Compute total number of pages ## sub compute_page_total { if ($MULTIIDX && $IDXSIZE) { $NumOfPages = int($NumOfMsgs/$IDXSIZE); ++$NumOfPages if ($NumOfMsgs/$IDXSIZE) > $NumOfPages; $NumOfPages = 1 if $NumOfPages == 0; } else { $NumOfPages = 1; } } ##--------------------------------------------------------------------------- ## write_mail outputs converted mail. It takes a reference to an ## array containing indexes of messages to output. ## sub write_mail { local($hack) = (0); print STDOUT "Writing mail " unless $QUIET; if ($SLOW && !$ADD) { $ADD = 1; $hack = 1; } foreach $index (@MListOrder) { print STDOUT "." unless $QUIET; &output_mail($index, $AddIndex{$index}, 0); } if ($hack) { $ADD = 0; } print STDOUT "\n" unless $QUIET; } ##--------------------------------------------------------------------------- ## read_mail_header() is responsible for parsing the header of ## a mail message. ## sub read_mail_header { local($handle, *mesg, *fields) = @_; my(%l2o, $header, $index, $date, $tmp, @array); local(@refs); local($from, $sub, $msgid); local($_); $header = &readmail::MAILread_file_header($handle, *fields, *l2o); @refs = (); @array = (); ##---------------------------## ## Check for no archive flag ## ##---------------------------## if ( $CheckNoArchive && ($fields{'restrict'} =~ /no-external-archive/i || $fields{'x-no-archive'} =~ /yes/i) ) { return ("", "", "", "", ""); } ##----------------------------------## ## Check for user-defined exclusion ## ##----------------------------------## if ( $MsgExcFilter ) { return ("", "", "", "", "") if &mhonarc::message_exclude($header); } ##------------## ## Get Msg-ID ## ##------------## $msgid = $fields{'message-id'} || $fields{'msg-id'} || $fields{'content-id'}; if (defined($msgid)) { if ($msgid =~ /<([^>]*)>/) { $msgid = $1; } else { $msgid =~ s/^\s+//; $msgid =~ s/\s+$//; } } else { # create bogus ID if none exists eval { require Digest::MD5; }; if ($@) { # unable to require, so create arbitary message-id $msgid = join("", $$,'.',time,'.',$_msgid_cnt++, '@NO-ID-FOUND.mhonarc.org'); } else { # create message-id using md5 digest of header; # can potentially skip over already archived messages w/o id $msgid = join("", Digest::MD5::md5_hex($header), '@NO-ID-FOUND.mhonarc.org'); } } ## Return if message already exists in archive if ($msgid && defined($MsgId{$msgid})) { return ("", "", "", "", ""); } ##----------## ## Get date ## ##----------## $date = ""; $index = ""; foreach (@DateFields) { next unless $fields{$_}; ## Treat received field specially if ($_ eq 'received') { @array = split(/;/, (split(/$readmail::FieldSep/o, $fields{$_}))[0]); $date = pop @array; ## Any other field should just be a date } else { $date = (split(/$readmail::FieldSep/o, $fields{$_}))[0]; } $date =~ s/^\s+//; $date =~ s/\s+$//; ## See if time_t can be determined. if (($date =~ /\w/) && (@array = &parse_date($date))) { $index = &get_time_from_date(@array[1..$#array]); last; } } if ($index eq "") { warn qq/\nWarning: Could not parse date for message\n/, qq/ Message-Id: <$msgid>\n/; # Use current time $index = time; # Set date string to local date if not defined $date = &time2str("", $index, 1) unless $date =~ /\S/; } ## Return if message too old to add if (&expired_time($index)) { return ("", "", "", "", ""); } ##-------------## ## Get Subject ## ##-------------## if (defined($fields{'subject'}) and $fields{'subject'} =~ /\S/) { ($sub = $fields{'subject'}) =~ s/\s+$//; $sub = subject_strip($sub) if $SubStripCode; } else { $sub = 'No Subject'; } ##----------## ## Get From ## ##----------## $from = ""; foreach (@FromFields) { next unless $fields{$_}; $from = $fields{$_}; last; } $from = 'Anonymous' unless $from; ##----------------## ## Get References ## ##----------------## if (defined($tmp = $fields{'references'})) { while ($tmp =~ s/<([^<>]+)>//) { push(@refs, $1); } } if (defined($tmp = $fields{'in-reply-to'})) { my $irtoid = ""; while ($tmp =~ s/<([^<>]+)>//) { $irtoid = $1 }; push(@refs, $irtoid) if $irtoid; } ##------------------------## ## Create HTML for header ## ##------------------------## $mesg .= &htmlize_header(*fields, *l2o); ## Insure uniqueness of index $index .= $X . sprintf("%d",$LastMsgNum+1); if ($fields{'content-type'}) { ($tmp = $fields{'content-type'}) =~ m%^\s*([\w-\./]+)%; $tmp = $1 || 'text/plain'; $tmp =~ tr/A-Z/a-z/; } else { $tmp = 'text/plain'; } $ContentType{$index} = $tmp; if ($msgid) { $MsgId{$msgid} = $index; $NewMsgId{$msgid} = $index; # Track new message-ids $Index2MsgId{$index} = $msgid; } &remove_dups(*refs); # Remove duplicate msg-ids $Refs{$index} = join($X, @refs) if (@refs); ($index,$from,$date,$sub,$header); } ##--------------------------------------------------------------------------- ## read_mail_body() reads in the body of a message. The returned ## filtered body is in $ret. ## sub read_mail_body { local($handle, $index, $header, *fields, $skip) = @_; my($ret, $data) = ('', ''); my(@files) = (); local($_); ## Define "globals" for use by filters ## NOTE: This stuff can be handled better, and will be done ## when/if I get around to rewriting mhonarc in (OO) Perl 5. $MHAmsgnum = &fmt_msgnum($IndexNum{$index}) unless $skip; ## Slurp up message body ## UUCP mailbox if ($MBOX) { if ($CONLEN && $fields{"content-length"}) { # Check for content-length my($len, $cnt) = ($fields{"content-length"}, 0); if ($len) { while (<$handle>) { $cnt += length($_); # Increment byte count $data .= $_ unless $skip; # Save data last if $cnt >= $len # Last if hit length } } # Slurp up bogus data if required (should I do this?) while (!/$FROM/o && !eof($handle)) { $_ = <$handle>; } } else { # No content-length while (<$handle>) { last if /$FROM/o; $data .= $_ unless $skip; } } ## MH message file } elsif (!$skip) { local $/ = undef; $data = <$handle>; } ## Filter data return '' if $skip; $fields{'content-type'} = 'text/plain' if (!defined($fields{'content-type'})) || ($fields{'content-type'} !~ /\S/); ($ret, @files) = &readmail::MAILread_body($header, $data, $fields{'content-type'}, $fields{'content-transfer-encoding'}); if ($ret) { # no-op } else { $ret = join('', "
\n", "
Warning
\n", "
Could not process message with given Content-Type: \n", "", &htmlize($fields{'content-type'}), "\n", "
\n", "
\n" ); } if (@files) { $Derived{$index} = join($X, @files); } $ret; } ##--------------------------------------------------------------------------- ## Output/edit a mail message. ## $index => current index (== $array[$i]) ## $force => flag if mail is written and not editted, regardless ## $nocustom => ignore sections with user customization ## sub output_mail { local($index, $force, $nocustom) = @_; local($msgi, $tmp, $tmp2, $template, @array2); local($filepathname, $tmppathname, $i_p0, $filename, $msghandle, $msginfh, $drvfh); local($adding) = ($ADD && !$force && !$SINGLE); $i_p0 = &fmt_msgnum($IndexNum{$index}); $filename = &msgnum_filename($IndexNum{$index}); $filepathname = join($DIRSEP, $OUTDIR, $filename); $tmppathname = join($DIRSEP, $OUTDIR, "msgtmp.$$"); if ($adding) { return ($i_p0,$filename) unless $Update{$IndexNum{$index}}; #&file_rename($filepathname, $tmppathname); $msginfh = &file_open($filepathname); } if ($SINGLE) { $msghandle = 'STDOUT'; } else { $msghandle = &file_create($tmppathname, $GzipFiles); } ## Output HTML header if ($adding) { while (<$msginfh>) { last if /\n", "\n", "\n", "\n", "\n", "\n"; #ContentType if (defined($Refs{$index})) { foreach (split(/$X/o, $Refs{$index})) { print $msghandle "\n"; #Reference-Id } } if (defined($Derived{$index})) { foreach (split(/$X/o, $Derived{$index})) { print $msghandle "\n"; } } print $msghandle "\n"; # Add in user defined markup ($template = $MSGPGBEG) =~ s/$VarExp/&replace_li_var($1,$index)/geo; print $msghandle $template; } print $msghandle "\n"; ## Output header if ($adding) { while (<$msginfh>) { last if /\n"; if (!$nocustom) { ($template = $MSGHEAD) =~ s/$VarExp/&replace_li_var($1,$index)/geo; print $msghandle $template; } print $msghandle "\n"; ## Output Prev/Next/Index links at top if ($adding) { while (<$msginfh>) { last if /\n"; if (!$nocustom && !$SINGLE) { ($template = $TOPLINKS) =~ s/$VarExp/&replace_li_var($1,$index)/geo; print $msghandle $template; } print $msghandle "\n\n"; ## Output message data if ($adding) { $tmp2 = ""; while (<$msginfh>) { # check if subject header delimited if (/\n"; if (!$nocustom) { ($template = $SUBJECTHEADER) =~ s/$VarExp/&replace_li_var($1,$index)/geo; print $msghandle $template; } print $msghandle "\n"; next; } # check if head/body separator delimited if (/\n"; if (!$nocustom) { ($template = $HEADBODYSEP) =~ s/$VarExp/&replace_li_var($1,$index)/geo; print $msghandle $template; } print $msghandle "\n"; next; } $tmp2 .= $_; last if /\n"; print $msghandle "\n"; ($template = $SUBJECTHEADER) =~ s/$VarExp/&replace_li_var($1,$index)/geo; print $msghandle $template; print $msghandle "\n"; $MsgHead{$index} =~ s%($AddrExp)%&link_refmsgid($1)%geo; $Message{$index} =~ s%($AddrExp)%&link_refmsgid($1)%geo; print $msghandle "\n"; print $msghandle $MsgHead{$index}; print $msghandle "\n"; print $msghandle "\n"; ($template = $HEADBODYSEP) =~ s/$VarExp/&replace_li_var($1,$index)/geo; print $msghandle $template; print $msghandle "\n"; print $msghandle "\n"; print $msghandle $Message{$index}, "\n"; print $msghandle "\n"; print $msghandle "\n"; } ## Output any followup messages if ($adding) { while (<$msginfh>) { last if /\n"; ($template = $MSGBODYEND) =~ s/$VarExp/&replace_li_var($1,$index)/geo; print $msghandle $template; if (!$nocustom && $DoFolRefs && defined($Follow{$index})) { @array2 = split(/$bs/o, $Follow{$index}); if ($#array2 >= 0) { ($template = $FOLUPBEGIN) =~ s/$VarExp/&replace_li_var($1,$index)/geo; print $msghandle $template; foreach (@array2) { ($template = $FOLUPLITXT) =~ s/$VarExp/&replace_li_var($1,$_)/geo; print $msghandle $template; } ($template = $FOLUPEND) =~ s/$VarExp/&replace_li_var($1,$index)/geo; print $msghandle $template; } } print $msghandle "\n"; ## Output any references if ($adding) { while (<$msginfh>) { last if /\n"; if (!$nocustom && $DoFolRefs && defined($Refs{$index})) { @array2 = split(/$X/o, $Refs{$index}); $tmp2 = 0; # flag for when first ref printed if ($#array2 >= 0) { foreach (@array2) { next unless defined($MsgId{$_}); next unless defined($IndexNum{$MsgId{$_}}); if (!$tmp2) { ($template = $REFSBEGIN) =~ s/$VarExp/&replace_li_var($1,$index)/geo; print $msghandle $template; $tmp2 = 1; } ($template = $REFSLITXT) =~ s/$VarExp/&replace_li_var($1,$MsgId{$_})/geo; print $msghandle $template; } if ($tmp2) { ($template = $REFSEND) =~ s/$VarExp/&replace_li_var($1,$index)/geo; print $msghandle $template; } } } print $msghandle "\n"; ## Output verbose links to prev/next message in list if ($adding) { while (<$msginfh>) { last if /\n"; if (!$nocustom && !$SINGLE) { ($template = $BOTLINKS) =~ s/$VarExp/&replace_li_var($1,$index)/geo; print $msghandle $template; } print $msghandle "\n\n"; ## Output footer if ($adding) { while (<$msginfh>) { last if /\n"; if (!$nocustom) { ($template = $MSGFOOT) =~ s/$VarExp/&replace_li_var($1,$index)/geo; print $msghandle $template; } print $msghandle "\n"; if (!$nocustom) { ($template = $MSGPGEND) =~ s/$VarExp/&replace_li_var($1,$index)/geo; print $msghandle $template; } close($msghandle) if (!$SINGLE); if ($adding) { close($msginfh); #&file_remove($tmppathname); } &file_rename($tmppathname, $filepathname) unless $SINGLE; ## Create user defined files foreach (keys %UDerivedFile) { ($tmp = $_) =~ s/$VarExp/&replace_li_var($1,$index)/geo; $tmp2 = join($DIRSEP, $OUTDIR, $tmp); if ($drvfh = &file_create($tmp2, $GzipFiles)) { ($template = $UDerivedFile{$_}) =~ s/$VarExp/&replace_li_var($1,$index)/geo; print $drvfh $template; close($drvfh); if ($Derived{$index}) { $Derived{$index} .= $X . $tmp; } else { $Derived{$index} = $tmp; } } else { warn "Warning: Unable to create $tmp2\n"; } } if (defined($Derived{$index}) && (@array2 = split(/$X/o, $Derived{$index}))) { &remove_dups(*array2); $Derived{$index} = join($X, @array2); } ## Set modification times -- Use eval incase OS does not support utime. if ($MODTIME && !$SINGLE) { eval { $tmp = &get_time_from_index($index); @array2 = split(/$X/o, $Derived{$index}); grep($_ = $OUTDIR . $DIRSEP . $_, @array2); unshift(@array2, $filepathname); &file_utime($tmp, $tmp, @array2); }; } ($i_p0, $filename); } ############################################################################# ## Miscellaneous routines ############################################################################# ##--------------------------------------------------------------------------- ## delmsg delets a message from the archive. ## sub delmsg { local($key) = @_; local($filename); local($pathname); #&defineIndex2MsgId(); $msgnum = $IndexNum{$key}; return 0 if ($msgnum eq ''); $filename = join($DIRSEP, $OUTDIR, &msgnum_filename($msgnum)); delete $ContentType{$key}; delete $Date{$key}; delete $From{$key}; delete $IndexNum{$key}; delete $Refs{$key}; delete $Subject{$key}; delete $MsgId{$Index2MsgId{$key}}; &file_remove($filename); foreach $filename (split(/$X/o, $Derived{$key})) { $pathname = (&OSis_absolute_path($filename)) ? $filename : join($DIRSEP, $OUTDIR, $filename); if (-d $pathname) { &dir_remove($pathname); } else { &file_remove($pathname); } } delete $Derived{$key}; $NumOfMsgs--; 1; } ##--------------------------------------------------------------------------- ## Routine to convert a msgid to an anchor ## sub link_refmsgid { local($refmsgid, $onlynew) = @_; if (defined($MsgId{$refmsgid}) && defined($IndexNum{$MsgId{$refmsgid}}) && (!$onlynew || $NewMsgId{$refmsgid})) { local($lreftmpl) = $MSGIDLINK; $lreftmpl =~ s/$VarExp/&replace_li_var($1,$MsgId{$refmsgid})/geo; $lreftmpl; } else { $refmsgid; } } ##--------------------------------------------------------------------------- ## Retrieve next available message number. Should only be used ## when an archive is locked. ## sub getNewMsgNum { $NumOfMsgs++; $LastMsgNum++; $LastMsgNum; } ##--------------------------------------------------------------------------- ## ign_signals() sets mhonarc to ignore termination signals. This ## routine is called right before an archive is written/edited to ## help prevent archive corruption. ## sub ign_signals { @SIG{@_term_sigs} = ('IGNORE') x scalar(@_term_sigs); } ##--------------------------------------------------------------------------- ## set_handler() sets up the signal_catch() routine to be called when ## termination signals are sent to mhonarc. ## sub set_handler { %_sig_org = ( ); @_sig_org{@_term_sigs} = @SIG{@_term_sigs}; @SIG{@_term_sigs} = (\&mhonarc::signal_catch) x scalar(@_term_sigs); } ##--------------------------------------------------------------------------- ## reset_handler() resets the original signal handlers. ## sub reset_handler { @SIG{@_term_sigs} = @_sig_org{@_term_sigs}; } ##--------------------------------------------------------------------------- ## signal_catch(): Function for handling signals that would cause ## termination. ## sub signal_catch { my $signame = shift; close_archive(1); &{$_sig_org{$signame}}($signame) if defined(&{$_sig_org{$signame}}); reset_handler(); die qq/Processing stopped, signal caught: SIG$signame\n/; } ##--------------------------------------------------------------------------- ## Create Index2MsgId if not defined ## sub defineIndex2MsgId { if (!defined(%Index2MsgId)) { foreach (keys %MsgId) { $Index2MsgId{$MsgId{$_}} = $_; } } } ##--------------------------------------------------------------------------- 1;