[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: E-mail kleuterjuf



On Fri, Aug 05, 2011 at 09:59:29AM +0200, Dirk Schouten wrote:
> Geert Stappers wrote:
> >On Thu, Aug 04, 2011 at 11:10:13PM +0200, Stephan Verrips wrote:
> > >  ....
> >
> >Dank voor de reactie.
> >
> >Ik lees er in dat ik mijn probleem duidelijker moet omschrijven.
> >
> >Het aller grootste verschil met de aangedragen oplossing en de uitdaging
> >is dat er niet 1 server is maar, meerdere. Vanaf een andere server iets
> >als een "echo request" gaan versturen, is een ongewenste omweg.
> >
> >Een kleuterjuf weet wanneer haar klas compleet is. Vaak zal ze controleren
> >of de kleintjes er nog allemaal zijn. De meeste keren is het resultaat
> >"iedereen is er nog". En juist die ene keer dat er eentje gemist wordt,
> >is belangrijk.
> >
> >Stel dat ik alle servers een dagrapport laat E-mailen. Dan is er alvast
> >een dagelijkse E-mail van elke server. De kleuterjuf kan daar op controleren.
> >Niet dat het dagrapport interresant is, maar wel een acceptable omweg.
> >
> >Doel is te borgen dat in het geval dat een (cron)job een keer mis gaat,
> >dat er dan zeker een E-mail mij bereikt.
> >
> >Eigenlijk wil ik een hond die mij helpt de kudde servers te bewaken.
> >Maarja, een herdershond kan niet tellen.
> >
> >De E-mail kleuterjuf is software die een lijst van verwachte servers
> >heeft en bij een incomplete lijst alarm slaat.
> >
> >Waar is een E-mail kleuterjuf te vinden?
> >
> 
> Dat klinkt als x keer per dag/uur een uitgebreide e-mail van iedere
> server die je niet wilt lezen maar wel bewaren, want niets aan de
> hand.
> Maar als er een regel o.i.d ontbreekt, wil je 'm wel lezen.
> Een goed e-mail filter?


Wat ik zocht, heb ik ondertussen in elkaar gezet. Productie heb ik er
nog niet mee gedraaid. Wel is het rijp genoeg voor een release.

Het zijn twee scripts met een database in het midden. Alles begint
met 'emn', wat voor E-mail Nanny staat.

  emnnotice: maakt aantekeningen van geziene E-mails
  emncheck: voert de controles uit.

Ook in de bijlage:

  emncreate: soort installatie script, maar ook een test tooltje
  emnanny.ini: een configuratie bestand.


Doe er jullie voordeel mee.


Groeten
Geert Stappers
-- 
> And is there a policy on top-posting vs. bottom-posting?
Yes.
#!/usr/bin/php -f
<?
/*
     emnnotice
     E-mail Nanny program that make notices

     Usually invoked as a pipe in the mail system
     e.g. .forward contains '|/usr/bin/emnnotice'

     Reads standard in and expects a RFC2822 E-mail,
     some headers of it will be stored
     into the database indicated by the configuration file.

     Copyright 2011   Geert Stappers <stappers@stappers.it>
     Distribute under the terms of the GPL
*/

openlog("emnanny", LOG_NDELAY | LOG_PID , LOG_USER) ;
syslog(LOG_NOTICE,"Start") ;
$cf = getenv('HOME') . "/emnanny.ini" ; #  configuration file

function mail_parse_headers($headers)
{
    $headers=preg_replace('/\r\n\s+/m', '',$headers);
    preg_match_all('/([^: ]+): (.+?(?:\n\s(?:.+?))*)?\n/m',
               $headers, $matches);
    $result = array();
    foreach ($matches[1] as $key =>$value) {
       $result[strtolower($value)]=$matches[2][$key];
    }
    return($result);
} 

function getaddr($line)
{
   $result = 'unknown' ;
   $words =  preg_split( "/\s+/", $line );
   foreach ($words as $word ) {
     if ( strpos($word , '@' )) {
       $result = strtolower(trim($word,'<>')) ;
       break ; // stop further processing
     }
   }
   return($result);
}

function mydie($errmsg)
{
    syslog(LOG_ERR,$errmsg);
    closelog();
    exit();
}

# get "standard in" in memory
$stdin = fopen("php://stdin", "r");
$cannedstdin = "";
while( ! feof($stdin))
{
    $cannedstdin .= fgets($stdin, 512);
}
fclose($stdin);

$headers = mail_parse_headers($cannedstdin);

# var_dump($headers); # show headers content

if ( empty($headers) ) {
    mydie(LOG_ERR,"No Headers found ...");
}

if (   empty($headers["from"]) 
    || empty($headers["subject"])
    || empty($headers["message-id"])
   ) {
    mydie(LOG_ERR,"Not all headers that should go into the database found");
}

syslog(LOG_NOTICE,"So far, so good");

$config = parse_ini_file($cf,true);
if ( empty($config) ) {
    mydie(LOG_ERR,"Could not parse configuration file '$cf'");
}

$link = mysql_connect($config['database']['host'],
                      $config['database']['user'],
                      $config['database']['password'])
    or mydie('Could not connect: ' . mysql_error());

mysql_select_db($config['database']['name'])
    or mydie('Could not select database');

$from = getaddr($headers["from"]);

$query = "insert into emn_events
          values ( now() 
              , '" . $from . "'
              , '" . $headers['message-id'] . "'
              , '" . $headers['subject'] . "'
          )" ;
$result = mysql_query($query) or mydie('Query failed: ' . mysql_error());

# mysql_free_result($result);
mysql_close($link);

syslog(LOG_NOTICE,"Finish") ;
closelog();

?>
#!/usr/bin/php -f
<?
/*
     emncheck
     E-mail Nanny check program

     Queries E-mail Nanny database tables
     and mails when thresholds are reached.

     Copyright 2011   Geert Stappers <stappers@stappers.it>
     Distribute under the terms of the GPL
*/
if ( $argc > 2 ) {
  $cf = $argv[2];
} else {
  $cf = getenv('HOME') . "/emnanny.ini" ;
}

$config = parse_ini_file($argv[1],true);
# var_dump($config) ;  # for development tests

if ( empty($config) ) {
  die("E:Could not parse configuration file '$argv[1]'\n");
}

$lst = fopen($config["report"]["checklist"],'r');
$known = array();
$i = 0;
while(!feof($lst)){
  $line = rtrim(fgets($lst));
  if (strpos($line,'#') === 0) {
    $line = '' ; # clear the comment line
  }
  if(!empty($line) ) {
    $known[$i] = $line ;
  }
  $i++ ;
}
fclose($lst);

if ( empty($known)) {
  die("E:Empty checklist, nothing to check.\n");
}

$link = mysql_connect($config['database']['host'],
                      $config['database']['user'],
                      $config['database']['password'])
    or die('Could not connect: ' . mysql_error());

mysql_select_db($config['database']['name'])
    or die('Could not select database');

$query = "delete from emn_temp_expected" ;
$result = mysql_query($query) or die('Query failed: ' . mysql_error());

foreach ( $known as $value ) {
  # echo $value . "\n" ;
  $query = "insert into emn_temp_expected
            values ( '$value' )" ;
  $result = mysql_query($query) or die('Query failed: ' . mysql_error());
}

$overdue = array() ;
$i = 0 ;

$query = 'select distinct(sender)
          from emn_events
          where datelogged
            < date_sub( now(), interval '. $config["report"]["days"] . ' day)
          and sender in (select sender from emn_temp_expected)' ;
$result = mysql_query($query) or die('Query failed: ' . mysql_error());

while ($line = mysql_fetch_array($result, MYSQL_ASSOC)) {
  foreach ($line as $col_value) {
        $overdue[$i] = $col_value ;
	$i++ ;
  }
}

$unexpected = array() ;
$i = 0 ;

$query = 'select distinct(sender)
          from emn_events
          where sender not in (select sender from emn_temp_expected)' ;
$result = mysql_query($query) or die('Query failed: ' . mysql_error());

while ($line = mysql_fetch_array($result, MYSQL_ASSOC)) {
  foreach ($line as $col_value) {
        $unexpected[$i] = $col_value ;
	$i++ ;
  }
}

$old_enough = $config["report"]["days"] + $config["report"]["cleandelay"] ;

$query = 'delete
          from emn_events
          where datelogged
            < date_sub( now(), interval '. $old_enough . ' day )' ;
$result = mysql_query($query) or die('Query failed: ' . mysql_error());

# mysql_free_result($result);
mysql_close($link);

$mailneed = false ;
$line_overdue = "Overdue:" ;
$line_unexpected = "Unexpected:" ;

if (!empty($overdue)) {
  $mailneed = true ;
  foreach ( $overdue as $value ) {
    $line_overdue .= " " . $value ;
  }
}
$line_overdue .= "\n" ;

if (!empty($unexpected)) {
  $mailneed = true ;
  foreach ( $unexpected as $value ) {
    $line_unexpected .= " " . $value ;
  }
}
$line_unexpected .= "\n" ;

if ( $mailneed ) {

  echo $line_overdue . "\n" ; # for debugging
  echo $line_unexpected . "\n" ; # for debugging

  $headers = "From: " . $config['mail']['from'] . "\r\n" .
       "UserAgent: emncheck" ;
  $to = $config['mail']['to'] ;
  $subject = "My subject";
  $txt = "Hello,\r\n\r\nProrgram emncheck is reporting this\r\n\r\n" .
    $line_overdue  . $line_unexpected . "\r\n" .
    "Cheers,\r\nYour E-mail nanny\r\n" ;

  mail($to,$subject,$txt,$headers);

}
?>
#!/usr/bin/php -f
<?
/*
     emncreate
     E-mail Nanny utitly

     Creates several thingies, see `emncreate help` for more information

     Copyright 2011   Geert Stappers <stappers@stappers.it>
     Distribute under the terms of the GPL
*/

if ( $argc < 2 ) {
  die("E:Not enough parameters. Rerun with 'help' as parameter\n");
}

$cmd = $argv[1];

if ( $argc == 3 ) {
  $cf = $argv[2];
} else {
  $cf = getenv('HOME') . "/emnanny.ini" ;
  # echo "I:Using '$cf' as configuration file\n";
}

$config = parse_ini_file($cf,true);
if ( empty($config) ) {
  die("E:Could not parse configuration file '$cf'\n");
}

function emnc_help() {
  echo "\nemncreate cmd [configurationfile]

  configurationfile defaults to emnanny.ini

  cmd = \{ help | database | tables | event | dump | time \}

  help = this help text

  database = create database & create user SQL commands

  tables = creates tables (and tests databases access )

  event = mimicks an e-mail, feed it to emn_notice

  dump = dumps table content

  time = sets date logged back in time
  
" ;
}

function emnc_database($config) {
  echo "-- feed this to your mysql server
create database if not exists " . $config['database']['name'] . "
 default character set = 'utf8' ;
grant all on " . $config['database']['name'] . ".*
 to '" . $config['database']['user'] . "'
  identified by '" .  $config['database']['password'] . "' ;
" ;
}

function emnc_tables($config) {
$link = mysql_connect($config['database']['host'],
                      $config['database']['user'],
                      $config['database']['password'])
    or die('Could not connect: ' . mysql_error());

mysql_select_db($config['database']['name'])
    or die('Could not select database');

$query = 'create table if not exists emn_events
   (datelogged datetime, sender char(36),  msgid char(25), subject char(49))';
$result = mysql_query($query) or die('Query failed: ' . mysql_error());

$query = 'create table if not exists emn_temp_expected
    (sender char(36) )';
$result = mysql_query($query) or die('Query failed: ' . mysql_error());

# mysql_free_result($result);
mysql_close($link);
}

function emnc_event($config) {
  echo "From: " . $config['event']['from'] . "
To: emnotice <script@host.tld>
Subject: " . $config['event']['subject'] . "
Date: " . date(DATE_RFC2822) .  "
Message-ID: " . time() . "@" . $config['event']['messageid'] . "
User-Agent: emncreate event
X-KnownBug: last header is not seen

Hello

For emnotice are only the headers important.
\n" ;
}

function emnc_dump($config) {
  $link = mysql_connect($config['database']['host'],
                        $config['database']['user'],
                        $config['database']['password'])
      or die('Could not connect: ' . mysql_error());

  mysql_select_db($config['database']['name'])
    or die('Could not select database');

  $query = 'select * from emn_temp_expected' ;
  $result = mysql_query($query) or die('Query failed: ' . mysql_error());

  while ($line = mysql_fetch_array($result, MYSQL_ASSOC)) {
    foreach ($line as $col_value) {
        echo $col_value . "," ;
    }
    echo "\n";
  }
  echo "\n";

  $query = 'select * from emn_events order by datelogged asc' ;
  $result = mysql_query($query) or die('Query failed: ' . mysql_error());

  while ($line = mysql_fetch_array($result, MYSQL_ASSOC)) {
    foreach ($line as $col_value) {
        echo $col_value . "," ;
    }
    echo "\n";
  }
  echo "\n";

  mysql_free_result($result);
  mysql_close($link);
}

function emnc_time($config) {
  $link = mysql_connect($config['database']['host'],
                        $config['database']['user'],
                        $config['database']['password'])
      or die('Could not connect: ' . mysql_error());

  mysql_select_db($config['database']['name'])
    or die('Could not select database');

  $jump = $config['timejump']['amount'] . " " . $config['timejump']['unit'] ;

  $query = 'update emn_events
            set datelogged = datelogged - interval ' . $jump ;
  $result = mysql_query($query) or die('Query failed: ' . mysql_error());

  # mysql_free_result($result);
  mysql_close($link);
}

switch($cmd) {
  case "database":
    emnc_database($config);
    break;
  case "tables":
    emnc_tables($config);
    break;
  case "event":
    emnc_event($config);
    break;
  case "dump":
    emnc_dump($config);
    break;
  case "time":
    emnc_time($config);
    break;
  case "help":
    emnc_help($argv);    
    break;
  default:
    emnc_help();    
    break;
}
?>
;
; Configuration file in .ini syntax
;
[database]
host = localhost
name = notes
user = emnanny
password = debianRulez
;
[mail]
to = admins@example.com
from = E-mail Nanny <emn@example.com>
;
[report]
days = 4
cleandelay = 6
checklist = lijst
;
;
; --- emncreate items
;
[event]
from = emnanny.create@example.com
subject = emncreate event
messageid = aSingleWordWillDo

[timejump]
amount = 23
unit = hour
; 
; l l

Reply to: