#!/usr/bin/env perl
# This file was Copyright 2004 Dewey M. Sasser and is hereby
# explicitly placed in the public domain
# Canonical release site:
# http://www.thesassers.com/dewey/UseMod.html
# Monitor a set of pages and email various interested parties when it changes
# Allow individual users to specify the pages in which they have interest.
# Instructions for use:
#
# Arrange for this script to run periodically with the current
# directory being the directory to monitor. It will read the wiki
# page file 'EmailOnChange' and pull email addresss that are on lines
# by themselves as the target of monitor email. It will not send
# email if nothing has changed.
#
# By default it will create 1 extra file, called .wmon, in the
# location given by the HOME environment variable. This file can be
# relocated by changing the configuration section.
#
# Configuration:
#
# See the config section at the top of the code. Set the variables
# appropriately.
#
# I use this with the following crontab entry:
# WIKILOC=/usr/apache/htdocs/wiki
# */5 * * * * (cd $WIKILOC; $HOME/bin/wmon)
#
# Notes:
# this is not a perfect implementation. I can think of much better.
# This is a simple thing that will mostly work
# $Revision: 1.9 $
# $Log: wmon,v $
# Revision 1.9 2004/08/11 20:51:29 dewey
# Added reference to dist site
#
# Revision 1.8 2004/08/11 20:31:34 dewey
# Cleaned up for posting
#
# Revision 1.7 2004/08/10 18:13:06 dewey
# Minor change in emailed message
#
# Revision 1.6 2004/08/10 17:59:05 dewey
# Now truncates subject line at reasonable length
#
# Revision 1.5 2004/08/10 17:49:24 dewey
# good-enough parsing of page database for email list
#
# Revision 1.4 2004/08/10 17:45:52 dewey
# Support for strange wiki page storage format
#
# Revision 1.3 2004/08/10 14:58:19 dewey
# Changed default location of .wmon
#
# Revision 1.2 2004/08/10 14:55:10 dewey
# Updated docs on .wmon file location
#
# Revision 1.1 2004/08/10 14:50:46 dewey
# Initial revision of wiki monitor
$Config{timeLoc}="$ENV{HOME}/.wmon";
$Config{wikiURL}="http://intranet1/cgi-bin/wiki.pl?";
$Config{interestedPartiesPage}="page/E/EmailOnChange.db";
$Config{pagePath}="page";
$Config{strangeWikiFormat}=1;
$Config{sendMail}=0;
$Config{mail}="| mail -s '\$subject' \$to ";
$Config{sendJustBody}=1;
$Config{wikiPageRegexp}="page/[A-Z]/.*\.db";
use strict 'vars';
use vars ( '%Config');
&main;
sub main
{
my $fromTime = &readLastTime();
my $toTime = time;
my @changedFiles = &getFilesBetween($fromTime,$toTime);
&mailAboutFiles(@changedFiles) &&
&writeLastTime($toTime);
}
# read the list of interested parties from a "Mail on Change" page
sub readGeeks
{
my @geeks;
open(GEEKS,$Config{interestedPartiesPage}) ||
return ("nobody");
if ($Config{strangeWikiFormat})
{
# throw away first line
<GEEKS>;
}
while(<GEEKS>)
{
chop;
# it seems that we also want to ignore lines with the char
# 263, but this works unless someone uses > or < as the first
# character on a line
if ($Config{strangeWikiFormat})
{
last if /^[<>]/;
}
next unless /^[ \t]*([^ \t]*\@[^ \t]*)[ \t]*$/;
push(@geeks, $1);
}
close(GEEKS);
return @geeks;
}
sub mailAboutFiles
{
my @files = @_;
# if there's nothing to mail, then don't
return 1 unless @files;
my $subject = "Changed Pages: " . join(", ", @files);
my $bodyList = join("\n\t", &prefixWith($Config{wikiURL},@files));
my @geeks = &readGeeks();
my $geeks = join(", ", @geeks);
my $tolist = join(" ", @geeks);
my $mailprog = $Config{mail};
# I'm allowing the special symbols "$to" and "$subject" in the
# mail prog to resolve appropriately
if(length($subject)>60)
{
$subject = substr($subject, 0, 60) . "...";
}
$mailprog =~ s/\$to/$tolist/g;
$mailprog =~ s/\$subject/$subject/g;
my $emailChangePage = &getPageName($Config{interestedPartiesPage});
if ($Config{sendMail})
{
open(MAIL, $mailprog) || return &choke("Couldn't open $Config{mail}: $!");
select(MAIL);
}
unless ($Config{sendJustBody} && $Config{sendMail})
{
print << "EOF";
To: $geeks
Subject: $subject
EOF
}
print << "EOF";
Just thought you might want to know, the following pages have all
changed:
$bodyList
Edit the page wiki page $Config{wikiURL}$emailChangePage if you want
to remove yourself from this subscription.
EOF
if($Config{sendMail})
{
select STDOUT;
close(MAIL);
}
return 1;
}
sub prefixWith
{
my ($prefix, @strings)=@_;
my @results;
foreach my $string (@strings)
{
push(@results, "$prefix$string");
}
return @results;
}
sub getFilesBetween
{
my ($start, $end) = @_;
my $dir = ".";
my @results;
my @pagefiles=&getPageFiles();
foreach my $file (@pagefiles)
{
my $fileMod = &getModTime("$dir/$file");
my $page = &getPageName($file);
push @results, $page if ($start < $fileMod && $fileMod < $end);
}
return @results;
}
sub getPageName
{
my $file = shift @_;
$file =~ /([^\/\.]+)(\.[^\/]*)?$/;
return $1;
}
sub getPageFiles
{
my $dir = shift @_;
my @results;
open(FIND,"find $Config{pagePath} -type f|") || &choke("Couldn't launch find: $!");
while(<FIND>)
{
next if /~$/; # emacs style backup file
next if /CVS\/(Entries|Repository|Root)/; # nothing in the CVS directories, please
if($Config{wikiPageRegexp})
{
next unless /$Config{wikiPageRegexp}/;
}
chop;
push(@results,$_);
}
close(FIND);
return @results;
}
sub readLastTime()
{
return 0 unless -r $Config{timeLoc};
return `cat $Config{timeLoc}`;
}
sub writeLastTime()
{
my $time = shift @_;
system "echo $time > $Config{timeLoc}";
}
sub getModTime
{
my $file = shift @_;
return (stat($file))[9];
}
sub choke
{
warn(@_);
return 1;
}