#!/usr/athena/bin/perl
#
# Automatic bounce handler for majordomo/qmail
#
# kolya@MIT.EDU  February 2000

require '/usr/local/majordomo/bounces/bounce-handler.cf';

sub max {
  local ($x, $y) = @_;
  return ($x > $y) ? $x : $y;
}

sub init_bounces {
  open(BOUNCE_STATE, "+<$BOUNCE_STATE_FILE");
  flock(BOUNCE_STATE, LOCK_EX);
  while(<BOUNCE_STATE>) {
    chop; ($bouncer, @bounce_times) = split(/\s/, $_);
    $bouncers{$bouncer} = join('|', @bounce_times);
  }
}

sub save_bounces {
  seek(BOUNCE_STATE, 0, 0);
  foreach $bouncer (sort keys %bouncers) {
    next if($bouncers{$bouncer} eq '');
    @bounce_times = split(/\|/, $bouncers{$bouncer});
    print BOUNCE_STATE "$bouncer";
    for($i=(&max(0,$#bounce_times-6)); $i<=$#bounce_times; $i++) {
      print BOUNCE_STATE " ", $bounce_times[$i];
    }
    print BOUNCE_STATE "\n";
  }
  truncate BOUNCE_STATE, tell(BOUNCE_STATE);
  flock(BOUNCE_STATE, LOCK_UN);
  close(BOUNCE_STATE);
}

sub add_bouncer {
  local ($bouncer) = @_;
  $now = time+0;
  if($bouncers{$bouncer}) {
    $bouncers{$bouncer}.="|$now";
  } else {
    $bouncers{$bouncer}="$now";
  }
}

sub scan_and_bounce {
  $now = time+0;
  $threshold = $now - 30*24*60*60;
  foreach $bouncer (sort keys %bouncers) {
    # do two things: if all bounce times for a particular user are more
    # than a month old, discard them. if all 7 bounce times are within
    # the last month (30 days), unsubscribe the user.
    $bounce_times = $bouncers{$bouncer};
    @bounce_times = split(/\|/, $bounce_times);

    $stale_bouncer = 1;
    $dead_bouncer = 1;
    $death_count = 0;

    foreach $time (@bounce_times) {
      if ($time > $threshold) {
        $stale_bouncer=0;
      } else {
        $dead_bouncer=0;
      }
      $death_count++;
    }

    $dead_bouncer &&= ($death_count >= 7);

    if ($dead_bouncer) {
      &blast_user($bouncer);
      $stale_bouncer = 1;
    }

    if ($stale_bouncer) {
      $bouncers{$bouncer} = '';
    }
  }
}

sub blast_user {
  local ($address) = @_;

  @unsub_list = ();
  $unsub_count = 0;

  foreach $list_name (sort keys %lists) {
    $list_file = $lists{$list_name};

    open(LIST, "$list_file");
    while(<LIST>) {
      if(/^$address$/i) {
        @unsub_list = (@unsub_list, $list_name);
        $unsub_count++;
      }
    }
    close(LIST);
  }

  return unless $unsub_count;

  open(MAIL, "|/usr/lib/sendmail -t");
  print MAIL
	"From: dev-null\@news-digests.mit.edu\n",
	"To: majordomo\@news-digests.mit.edu\n",
	#"Cc: digests\@news-digests.mit.edu\n",
	"\n";
  foreach $list (@unsub_list) {
    print MAIL
	"approve $magic_password unsubscribe $list $address\n";
  }
  close(MAIL);

  open(MAIL, "|/usr/lib/sendmail -t -f dev-null\@news-digests.mit.edu");
  print MAIL
	"From: dev-null\@news-digests.mit.edu\n",
	"To: $address\n",
	#"Cc: digests\@news-digests.mit.edu\n",
	"Reply-To: digests\@news-digests.mit.edu\n",
	"\n",
	"Hello,\n",
	"\n",
	"This is an automated message from the list management software\n",
	"on news-digests.mit.edu. You are being unsubscribed from the\n",
	"following lists because your address has bounced over 7 times\n",
	"in the past 30 days:\n",
	"\n";
  foreach $list (@unsub_list) {
    print MAIL
	"    $list\n";
  }
  print MAIL
	"\n",
	"If for some reason you are certain that your address is valid,\n",
	"and you are receiving this message in error, you can re-subscribe\n",
	"to these lists, and send mail to digests\@news-digests.mit.edu to\n",
	"inform us of problems in the bounce management program.\n",
	"\n",
	"Instructions for re-subscribing can be obtained by sending an email\n",
	"to majordomo\@news-digests.mit.edu, containing the word \"help\".\n",
	"\n",
	"-- News-digests.mit.edu maintainers,\n",
	"   digests\@news-digests.mit.edu.\n";
  close(MAIL);
}

sub main {
  $address = $ARGV[0];

  &init_bounces();
  &add_bouncer($address);
  &scan_and_bounce();
  &save_bounces();
}

&main();

