Subject: Developers of Sympa
List archive
- From: doome <address@concealed>
- To: address@concealed
- Subject: archived feature
- Date: 23 Apr 2002 16:31:47 +0000
Hi!
I have a bugfix/feature here, made by Szabolcs Hock. I send You a little
description here, maybe it would be good to put it in the official
release. It was made for Sympa 3.2.1, but I think it will work in the
nowaday releses with a little modifying. (Sorry for my English :-))) )
So now, the archived.pl works that it calls mhonarc for a file, waits
till mhonarc ends his job, and it moves the file from queueotgoing to
expl/listname/arctxt/yyyy-mm/number file, and deletes the file from the
queue.
There are few problems with the parsing this way:
- The messages can only be parsed syncronous, because mhonarc gets the
filename in the queue, so the archived.pl could put it in the list
directory after mhonarc finished
- Mhonarc is a perl program, so when it starts, it takes a lot of time
to load its modules, and to compile it to byte code.
Recommendations to solve this problem:
- Call mhonarc after the file was moved to the arctxt directory, so it
could work in the background, and the archived pl could handle the queue
comfortable.
- the mhonarc should be run as a daemon, so it can archive more message
with one run, so the mhonarc loading overhead could be eliminated.
Implementation ( mailconv.pl )
It loads all the moduls of mhonarc. It waits the converting request in
its STDIN. It runs till it can read the STDIN. There is a little fun in
it, because mhonarc redefines the STDIN stream, so the original must be
saved. Format of the input:
The elements of the command line are seperated by semicolon, so the
parameters containing space could be given as one element.
Archived opens |mailconv.pl as a file, and prints the jobs to it. In
this implementation it converts 100 mails with one run, after it
refreshes the pipe. The mailcon.pl logs /var/log/mailconv.log as user
sympa.
I attach the mailconv.pl and the modified archived.pl ( v 3.2.1)
It could be the best if it would be a config-file parameter to use this
way of parsing...
Thank You!
--
doome
#!/usr/bin/perl ## Worl Wide Sympa is a front-end to Sympa Mailing Lists Manager ## Copyright Comite Reseau des Universites ## Options : F -> do not detach TTY ## : d -> debug -d is equiv to -dF ## Change this to point to your Sympa bin directory use lib '/usr/lib/sympa/bin'; use List; use Conf; use Log; use Getopt::Std; use wwslib; getopts('dF'); $Version = '0.1'; $wwsympa_conf = "/etc/sympa/wwsympa.conf"; $sympa_conf_file = '/etc/sympa/sympa.conf'; $wwsconf = {}; $adrlist = {}; # Load WWSympa configuration unless ($wwsconf = &wwslib::load_config($wwsympa_conf)) { print STDERR 'unable to load config file'; exit; } # Load sympa.conf unless (Conf::load($sympa_conf_file)) { do_log ('notice',"Unable to load sympa configuration, file $sympa_conf_file has errors."); exit(1); } ## Check databse connectivity $List::use_db = &List::probe_db(); ## Set the UserID & GroupID for the process $< = $> = (getpwnam('root'))[2]; $( = $) = (getpwnam('root'))[2]; ## Put ourselves in background if not in debug mode. unless ($opt_d || $opt_F) { open(STDERR, ">> /dev/null"); open(STDOUT, ">> /dev/null"); if (open(TTY, "/dev/tty")) { ioctl(TTY, $TIOCNOTTY, 0); close(TTY); } setpgrp(0, 0); if (($_ = fork) != 0) { do_log('debug', "Starting archive daemon, pid $_"); exit(0); } $wwsconf->{'log_facility'}||= $Conf{'syslog'}; do_openlog($wwsconf->{'log_facility'}, $Conf{'log_socket_type'}, 'archived'); } ## Sets the UMASK umask($Conf{'umask'}); ## Change to list root unless (chdir($Conf{'home'})) { &message('chdir_error'); &do_log('info','unable to change directory'); exit (-1); } my $pinfo = &List::_apply_defaults(); ## Create and write the pidfile unless (open(LOCK, "+>> $wwsconf->{'archived_pidfile'}")) { fatal_err("Could not open %s, exiting", $wwsconf->{'archived_pidfile'}); } unless (flock(LOCK, 6)) { printf STDERR "Could not lock %s: archived is probably already running",$wwsconf->{'archived_pidfile'} ; fatal_err("Could not lock %s: archived is probably already running.", $wwsconf->{'archived_pidfile'}); } unless (open(LCK, "> $wwsconf->{'archived_pidfile'}")) { fatal_err("Could not open %s, exiting", $wwsconf->{'archived_pidfile'}); } unless (truncate(LCK, 0)) { fatal_err("Could not truncate %s, exiting.", $wwsconf->{'archived_pidfile'}); } print LCK "$$\n"; close(LCK); do_log('notice', "archived $Version Started"); ## Catch SIGTERM, in order to exit cleanly, whenever possible. $SIG{'TERM'} = 'sigterm'; $end = 0; $queue = $Conf{'queueoutgoing'}; print "queue : $queue\n"; #if (!chdir($queue)) { # fatal_err("Can't chdir to %s: %m", $queue); # ## Function never returns. #} ## infinite loop scanning the queue (unless a sig TERM is received while (!$end) { &List::init_list_cache(); unless (opendir(DIR, $queue)) { fatal_err("Can't open dir %s: %m", $queue); ## No return. } my @files = (sort grep(!/^\.{1,2}$/, readdir DIR )); closedir DIR; ## this sleep is important to be raisonably sure that sympa is not currently ## writting the file this deamon is openning. sleep 2; foreach my $file (@files) { last if $end; if ($file =~ /^\.remove\.(.*)\.\d+$/ ) { do_log('debug',"remove found : $file for list $1"); unless (open REMOVE, "$queue/$file") { do_log ('notice',"Ignoring file $queue/$file because couldn't read it, archived.pl must use the same uid as sympa"); next; } my $msgid = <REMOVE> ; close REMOVE; &remove($1,$msgid); unless (unlink("$queue/$file")) { do_log ('notice',"Ignoring file $queue/$file because couldn't remove it, archived.pl must use the same uid as sympa"); next; } }elsif ($file =~ /^\.rebuild\.(.*)$/ ) { do_log('debug',"rebuild found : $file for list $1"); &rebuild($1); unless (unlink("$queue/$file")) { do_log ('notice',"Ignoring file $queue/$file because couldn't remove it, archived.pl must use the same uid as sympa"); next; } }else{ my ($yyyy, $mm, $dd, $min, $ss, $adrlist); if ($file =~ /^(\d{4})-(\d{2})-(\d{2})-(\d{2})-(\d{2})-(\d{2})-(.*)$/) { ($yyyy, $mm, $dd, $hh, $min, $ss, $adrlist) = ($1, $2, $3, $4, $5, $6, $7); }elsif ($file =~ /^(.*)\.(\d+)\.(\d+)$/) { $adrlist = $1; my $date = $2; my @now = localtime($date); $yyyy = sprintf '%04d', 1900+$now[5]; $mm = sprintf '%02d', $now[4]+1; $dd = sprintf '%02d', $now[3]; $hh = sprintf '%02d', $now[2]; $min = sprintf '%02d', $now[1]; $ss = sprintf '%02d', $now[0]; }else { do_log ('notice',"Ignoring file $queue/$file because not to be rebuild or liste archive"); unlink("$queue/$file"); next; } $adrlist =~ /^(.*)\@(.*)$/; my $listname = $1; my $hostname = $2; do_log('debug',"Archiving $file for list $adrlist"); mail2arc ($file, $listname, $hostname, $yyyy, $mm, $dd, $hh, $min, $ss); unless (unlink("$queue/$file")) { do_log ('notice',"Ignoring file $queue/$file because couldn't remove it, archived.pl must use the same uid as sympa"); do_log ('notice',"exiting because I don't want to loop until file system is full"); last; } } } } do_log('notice', 'archived exited normally due to signal'); unlink("$wwsconf->{'archived_pidfile'}"); exit(0); ## When we catch SIGTERM, just change the value of the loop ## variable. sub sigterm { $end = 1; } sub remove { my $adrlist = shift; my $msgid = shift; my $arc ; if ($adrlist =~ /^(.*)\.(\d{4}-\d{2})$/) { $adrlist = $1; $arc = $2; } do_log('debug',"Removing $msgid in list $adrlist section $2"); $arc =~ /^(\d{4})-(\d{2})$/ ; my $yyyy = $1 ; my $mm = $2 ; $msgid =~ s/\$/\\\$/g; system "$wwsconf->{'mhonarc'} -outdir $wwsconf->{'arc_path'}/$adrlist/$yyyy-$mm -rmm $msgid"; } sub rebuild { my $adrlist = shift; my $arc ; if ($adrlist =~ /^(.*)\.(\d{4}-\d{2})$/) { $adrlist = $1; $arc = $2; } $adrlist =~ /^(.*)\@(.*)$/; my $listname = $1; my $hostname = $2; do_log('debug',"Rebuilding $adrlist archive ($2)"); my $mhonarc_ressources = &get_ressources ($adrlist) ; if ($arc) { do_log('debug',"Rebuilding $arc of $adrlist archive"); $arc =~ /^(\d{4})-(\d{2})$/ ; my $yyyy = $1 ; my $mm = $2 ; my $cmd = "$wwsconf->{'mhonarc'} -rcfile $mhonarc_ressources -outdir $wwsconf->{'arc_path'}/$adrlist/$yyyy-$mm -definevars \"listname='$listname' hostname=$hostname yyyy=$yyyy mois=$mm yyyymm=$yyyy-$mm wdir=$wwsconf->{'arc_path'} base=$Conf{'wwsympa_url'}/arc \" -umask $Conf{'umask'} $wwsconf->{'arc_path'}/$adrlist/$arc/arctxt"; my $exitcode = system($cmd); if ($exitcode) { do_log('debug',"Command $cmd failed with exit code $exitcode"); } }else{ do_log('debug',"Rebuilding $adrlist archive completely"); if (!opendir(DIR, "$wwsconf->{'arc_path'}/$adrlist" )) { do_log('notice',"unable to open $wwsconf->{'arc_path'}/$adrlist to rebuild archive"); return ; } my @archives = (grep (/^\d{4}-\d{2}/, readdir(DIR))); close DIR ; foreach my $arc (@archives) { $arc =~ /^(\d{4})-(\d{2})$/ ; my $yyyy = $1 ; my $mm = $2 ; system "$wwsconf->{'mhonarc'} -rcfile $mhonarc_ressources -outdir $wwsconf->{'arc_path'}/$adrlist/$yyyy-$mm -definevars \"listname=$listname hostname=$hostname yyyy=$yyyy mois=$mm yyyymm=$yyyy-$mm wdir=$wwsconf->{'arc_path'} base=$Conf{'wwsympa_url'}/arc \" -umask $Conf{'umask'} $wwsconf->{'arc_path'}/$adrlist/$arc/arctxt"; } } } sub mail2arc { my ($file, $listname, $hostname, $yyyy, $mm, $dd, $hh, $min, $ss) = @_; my $arcpath = $wwsconf->{'arc_path'}; do_log('debug',"mail2arc $file for $listname\@$hostname yyyy:$yyyy, mm:$mm dd:$dd hh:$hh min$min ss:$ss"); # chdir($wwsconf->{'arc_path'}); if (! -d "$arcpath/$listname\@$hostname") { unless (mkdir ("$arcpath/$listname\@$hostname", 0775)) { &do_log('notice', 'Cannot create directory %s', "$arcpath/$listname\@$hostname"); return undef; } do_log('debug',"mkdir $arcpath/$listname\@$hostname"); } if (! -d "$arcpath/$listname\@$hostname/$yyyy-$mm") { unless (mkdir ("$arcpath/$listname\@$hostname/$yyyy-$mm", 0775)) { &do_log('notice', 'Cannot create directory %s', "$arcpath/$listname\@$hostname/$yyyy-$mm"); return undef; } do_log('debug',"mkdir $arcpath/$listname\@$hostname/$yyyy-$mm"); } if (! -d "$arcpath/$listname\@$hostname/$yyyy-$mm/arctxt") { unless (mkdir ("$arcpath/$listname\@$hostname/$yyyy-$mm/arctxt", 0775)) { &do_log('notice', 'Cannot create directory %s', "$arcpath/$listname\@$hostname/$yyyy-$mm/arctxt"); return undef; } do_log('debug',"mkdir $arcpath/$listname\@$hostname/$yyyy-$mm/arctxt"); } ## copy the file in the arctxt and in "mhonarc -add" opendir (DIR, "$arcpath/$listname\@$hostname/$yyyy-$mm/arctxt"); my @files = (sort { $a <=> $b;} readdir(DIR)) ; $files[$#files]+=1; my $newfile = $files[$#files]; # my $newfile = $files[$#files]+=1; my $mhonarc_ressources = &get_ressources ($listname . '@' . $hostname) ; #$psztms=time(); do_log ('notice',"calling mailconv.pl for list $listname\@$hostname") ; if ($run_mailconv>0) { if ($run_mailconv>100) { close MCF; sleep 1; open MCF,"|/usr/bin/mailconv.pl"; MCF->autoflush(1); $run_mailconv=1; do_log ('notice',"Pipe refreshed.") ; } $run_mailconv++; } else { open MCF,"|/usr/bin/mailconv.pl"; MCF->autoflush(1); $run_mailconv=1; do_log ('notice',"New pipe opened.") ; } open (ORIG, "$queue/$file") || fatal_err("couldn't open file $queue/$file"); open (DEST, ">$arcpath/$listname\@$hostname/$yyyy-$mm/arctxt/$newfile") || fatal_err("couldn't open file $newfile"); while (<ORIG>) { print DEST $_ ; } close ORIG; close DEST; my $cmd = "-add;-rcfile;$mhonarc_ressources;-stdin;$arcpath/$listname\@$hostname/$yyyy-$mm/arctxt/$newfile;-outdir;$arcpath/$listname\@$hostname/$yyyy-$mm;-definevars;listname='$listname' hostname=$hostname yyyy=$yyyy mois=$mm yyyymm=$yyyy-$mm wdir=$wwsconf->{'arc_path'} base=$Conf{'wwsympa_url'}/arc;-umask;$Conf{'umask'}\n"; print MCF $cmd; } sub get_ressources { my $adrlist = shift; my ($mhonarc_ressources, $list); if ($adrlist =~ /^([^@]*)\@[^@]*$/) { $adrlist = $1; } unless ($list = new List ($adrlist)) { do_log('notice',"get_ressources : unable to load list $1, continue anyway"); } if (-r "$Conf{'home'}/$list->{'name'}/mhonarc-ressources") { $mhonarc_ressources = "$Conf{'home'}/$list->{'name'}/mhonarc-ressources" ; }elsif (-r "$Conf{'etc'}/mhonarc-ressources"){ $mhonarc_ressources = "$Conf{'etc'}/mhonarc-ressources" ; }elsif (-r "/usr/share/sympa/mhonarc-ressources"){ $mhonarc_ressources = "/usr/share/sympa/mhonarc-ressources" ; }else { do_log('notice',"Cannot find any MhOnArc ressource file"); return undef; } return $mhonarc_ressources; }
#!/usr/bin/perl use lib "/usr/share/mhonarc"; use Getopt::Long; use Time::Local; use POSIX; use IO::Handle; require 'mhamain.pl' || die qq/ERROR: Unable to require "mhamain.pl"\n/; require 'mhtime.pl'; require 'mhfile.pl'; require 'mhinit.pl'; require 'mhutil.pl'; require 'base64.pl'; require 'mhindex.pl'; require 'mhthread.pl'; require 'mhrcfile.pl'; require 'mhrcvars.pl'; require 'mhmimetypes.pl'; require 'mhtxthtml.pl'; require 'mhexternal.pl'; #require 'mhdb.pl'; require 'rfc822.pl'; require 'iso8859.pl'; require 'readmail.pl'; require 'ewhutil.pl'; require 'mhidxrc.pl'; require 'mhdysub.pl'; require 'iso2022jp.pl'; require 'mhtxtplain.pl'; require 'mhtxtsetext.pl'; require 'mhtxttsv.pl'; require 'mhtxtenrich.pl'; require 'mhmsgextbody.pl'; require 'mhmsgfile.pl'; require 'mhnote.pl'; require 'mhnull.pl'; $sz_other=0; mhonarc::initialize(); open IH,"<&STDIN"; open OH,">>/var/log/mailconv.log"; open STDERR,">/dev/null"; open STDOUT,">/dev/null"; print OH "Program started!\n"; OH->autoflush(1); while ($sor=<IH>) { chomp($sor); @args=split(/;/,$sor); print OH "Input: $args[4]\n"; if ($sz_other>0) { $pid=fork(); if ($pid == 0) { $ptm=mhonarc::process_input(@args); print OH "Processing time: $ptm\n"; exit(0); } else { $st=waitpid($pid,0); } } else { $ptm=mhonarc::process_input(@args); print OH "Processing time: $ptm\n"; $sz_other++; } } print OH "Program finished!\n";
- archived feature, doome, 04/23/2002
Archive powered by MHonArc 2.6.19+.