/usr/local/CPAN/NNML/NNML/Active.pm


#                              -*- Mode: Perl -*- 
# Active.pm -- 
# ITIID           : $ITI$ $Header $__Header$
# Author          : Ulrich Pfeifer
# Created On      : Sat Sep 28 14:15:22 1996
# Last Modified By: Ulrich Pfeifer
# Last Modified On: Thu Feb 27 16:31:03 1997
# Language        : CPerl
# Update Count    : 86
# Status          : Unknown, Use with caution!
# 
# (C) Copyright 1996, Universität Dortmund, all rights reserved.
# 

package NNML::Active;

use strict;
use vars qw($VERSION @ISA @EXPORT_OK $ACTIVE);
require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw($ACTIVE);

use NNML::Config qw($Config);
use NNML::Group;
use IO::File;
use File::Path;

$VERSION = '0.01';
$ACTIVE = bless {}, 'NNML::Active';

my %GROUP;
my $TIME = 0;

sub last_change { $TIME }

sub _read_active {
  %GROUP  = ();
  $TIME   = time;

  my $fh = new IO::File "<" . $Config->active;
  die "Could not read active file" unless defined $fh;
  my $line;
  while (defined ($line = <$fh>)) {
    chomp($line);
    my ($group, $max, $min, $post) = split ' ', $line;
    my $dir = $group;
    $dir =~ s:\.:/:g;
    $dir = $Config->base . '/' . $dir;
    if (-e $dir) {
      my $ctime = (stat($dir))[10];
      $GROUP{$group} = NNML::Group->new(name  => $group,
                                        dir   => $dir,
                                        min   => $min,
                                        max   => $max,
                                        post  => $post,
                                        ctime => $ctime,
                                       );
    }
  }
}

sub _write_active {
  my $active = $Config->active;

  unless (rename $active, "$active~") {
    print "Could not backup '$active': $!\n";
    return 0;
  }
  my $fh = new IO::File ">" . $active;
  unless (defined $fh) {
    print "Could not write active file\n";
    return 0;
  }
  for (sort keys %GROUP) {
    $fh->printf("%s %d %d %s\n", $_,
                $GROUP{$_}->max, $GROUP{$_}->min, $GROUP{$_}->post,
               )
  }
  $fh->close;
  $TIME   = time;
}

sub _update {
  my $mtime = (stat($Config->active))[9];
  _read_active if $mtime > $TIME;
}

sub group {
  my ($self, $group) = @_;

  _update;
  if (exists $GROUP{$group}) {
    return $GROUP{$group};
  } 
}

sub delete_group {
  my ($self, $group) = @_;
  my $dir;

  _update;
  unless (exists $GROUP{$group}) {
    return;
  } else {
    $dir = $GROUP{$group}->dir;
    delete $GROUP{$group};
  }
  _write_active;
  rmtree($dir,1,1);
}
sub groups {
  _update;
  values %GROUP;
}

sub newgroups {
  my ($self, $time) = @_;
  my @result;

  _update;
  for (keys %GROUP) {
    # printf "%s %d %d\n", $_, $GROUP{$_}->ctime, $time;
    if ($GROUP{$_}->ctime > $time) {
      unshift @result, $_;
    }
  }
  @result;
}

sub list_match {
  my ($self, $expr) = @_;

  $expr =~ s/\./\\./g;
  $expr =~ s/\*/.*/g;
  my (@expr) = split /,/, $expr;

  _update;

  my $neg = join '|', grep s/^!//, @expr;
  my $pos = join '|', grep /^[^!]/, @expr;

  #print "pos = $pos\n";
  #print "neg = $neg\n";

  my @result;
  for (sort keys %GROUP) {
    next unless /^$pos$/;
    next if /^$neg$/;
    push @result, $GROUP{$_};
  }

  @result;
}

sub accept_article {
  my ($self, $header, $head, $body, $create,
      $afile, $extra_group, @groups) = @_;
  my $group;
  my $any_group = 0;
  my $overwrite_file = $afile;
  my %seen;
  
  $self->_update;

  if ($afile and -e $afile) {              # xaccept overwrites
    my $fh  = new IO::File "> $afile";
    unless (defined $fh) {
      print "Could not write '$afile': $!\n";
      return 0;
    }
    $fh->print($head, "\n", $body);
    $fh->close;
  }
  for $group (@groups) {
    next if $seen{$group}++;    # do not insert twice
    unless (exists $GROUP{$group}) {
      next unless $create;      # no permission to create group
      my $dir = $group;
      $dir =~ s:\.:/:g;
      $dir = $Config->base . '/' . $dir;
      unless (-d $dir) {
        unless (mkpath($dir,1,0700)) {
          print "Could not mkpath($dir).\n";
          return 0;
        }
      }
      $GROUP{$group} = NNML::Group->new(name  => $group,
                                        dir   => $dir,
                                        min   => 1,
                                        max   => 0,
                                        post  => 'y',
                                        ctime => time,
                                       );
    }
    my $ov   = $GROUP{$group}->overview;

    my $oano = $GROUP{$group}->article_by_id($header->{'message-id'});
    my $ano  = $oano || $GROUP{$group}->add($header->{'message-id'});
    my $dir  = $GROUP{$group}->dir;
    my $file = "$dir/$ano";
    
    if ($ano and $group eq $extra_group) { # force a copy
      $ano =  $GROUP{$group}->add($header->{'message-id'});
      $file = "$dir/$ano";
      $oano = undef;
    } else {
      if (!$oano and -e $file) {
        print "File '$file' already exists\n";
        return 0;
      }
    }
    
    # add overview entry if new article number
    unless ($oano) {
      my $fh  = new IO::File ">> $ov";
      unless (defined $fh) {
        print "Could not write '$ov': $!\n";
        return 0;
      }
      $header->{subject} =~ s/\s/ /;
      $fh->printf("%d\t%s\t%s\t%s\t%s\t%s\t%d\t%s\t%s\t\n",
                  $ano,
                  $header->{subject}, 
                  $header->{from},
                  $header->{date},
                  $header->{'message-id'},
                  $header->{references},
                  length($body),
                  $header->{lines},
                  $header->{xref});
      $fh->close;
    }
    # add the article ...
    if (defined $afile) {       # as link
      unless ($oano or link($afile, $file)) {
        print "Could not link '$file' to '$afile': $!\n";
        return 0;
      }
    } else {                    # as copy
      $afile = $file;
      my $fh  = new IO::File "> $file";
      unless (defined $fh) {
        print "Could not write '$file': $!\n";
        return 0;
      }
      $fh->print($head, "\n", $body);
      $fh->close;
    }
    $any_group++;               # we posted to one group atleast
  }
  return $self->_write_active || $any_group;
}

1;