+++ /dev/null
-#!/bin/bash
-
-SCRIPTSDIR=`dirname $0`
-STATSDIR=/home/web/stats
-
-DATE=$(date "+%d" -d "1 day ago")
-DATE2=$(date "+%m%d%y" -d "1 day ago")
-
-ANNEE=$(date "+%Y")
-
-#génère les données
-#atsar -H -n$DATE | grep access | grep -v https > /tmp/access.dat
-atsar -S -P -n$DATE | grep ':' > /tmp/load.dat
-atsar -S -u -n$DATE | grep all > /tmp/cpu.dat
-atsar -S -d -n$DATE | grep disk00 > /tmp/disk.dat
-atsar -S -r -n$DATE | grep M | tr -d "MK" > /tmp/mem.dat
-atsar -S -l -n$DATE | grep eth0 > /tmp/eth0.dat
-atsar -S -L -n$DATE | grep eth0 > /tmp/eth0err.dat
-atsar -S -t -n$DATE | grep -v -i linux | grep '\.' > /tmp/tcp.dat
-atsar -S -U -n$DATE | grep -v -i linux | grep '\.' > /tmp/udp.dat
-awk '{ if (i!=6) {a+=$2; b+=$3; c+=$4; d+=$5; e+=$6; f+=$7; i++} else { print $1,a,b,c,d,e,f; i=a=b=c=d=e=f=0; } }' $STATSDIR/nbmails > /tmp/nbmails
-mysql x4dat --skip-column-names -B -e "SELECT promo,COUNT(*) FROM auth_user_md5 WHERE (promo > 1950) and (perms in ('user','admin')) GROUP BY promo" > /tmp/promo
-
-mysql x4dat --skip-column-names -B > /tmp/promo2 << EOF
-create temporary table countx type = HEAP select promo,count(*) as nb FROM auth_user_md5 WHERE (promo > 1940) and (deces = '0000-00-00') and not(perms='ext') GROUP BY promo;
-create temporary table countinscrits type = HEAP select promo,count(*) as nb FROM auth_user_md5 WHERE (promo > 1940) and (deces = '0000-00-00') and (perms in ('admin','user')) GROUP BY promo;
-select x.promo, ins.nb*100/x.nb from countx as x, countinscrits as ins where x.promo = ins.promo;
-EOF
-
-#Inscrits (depuis le début)
-gnuplot <<EOF
-set output "$STATSDIR/graph-nb.png"
-set term png small
-set size 640/480
-set xdata time
-set timefmt "%m/%d/%y"
-set format x "%m/%y"
-set yr [0:]
-set title "Nombre d'inscrits depuis Juillet 2000"
-set key left
-plot "$STATSDIR/nbinscrits" using 1:2 title 'inscrits' with lines;
-EOF
-
-#[OK] load
-gnuplot <<EOF
-set output "$STATSDIR/graph-load.png"
-set term png small
-set size 640/480
-set timefmt "%H:%M:%S"
-set format x "%Hh"
-set xdata time
-set yr [0:]
-plot "/tmp/load.dat" using 1:5 title 'load1' with lines, "/tmp/load.dat" using 1:6 title 'load5' with lines, "/tmp/load.dat" using 1:7 title 'load15' with lines
-EOF
-
-#[OK] %usr %sys %nice
-gnuplot <<EOF
-set output "$STATSDIR/graph-cpu.png"
-set term png small
-set size 640/480
-set timefmt "%H:%M:%S"
-set format x "%Hh"
-set xdata time
-set yr [0:100]
-plot "/tmp/cpu.dat" using 1:6 title '%idle' with lines, "/tmp/cpu.dat" using 1:4 title '%sys' with lines, "/tmp/cpu.dat" using 1:5 title '%nice' with lines, "/tmp/cpu.dat" using 1:3 title '%usr' with lines
-EOF
-
-#[OK] pswch/s
-gnuplot <<EOF
-set output "$STATSDIR/graph-pswch.png"
-set term png small
-set size 640/480
-set timefmt "%H:%M:%S"
-set format x "%Hh"
-set xdata time
-set yr [0:]
-plot "/tmp/load.dat" using 1:2 title 'pswch/s' with lines;
-EOF
-
-#[OK] memfree swpfree cached
-gnuplot <<EOF
-set output "$STATSDIR/graph-mem.png"
-set term png small
-set size 640/480
-set timefmt "%H:%M:%S"
-set format x "%Hh"
-set xdata time
-set yr [0:]
-plot "/tmp/mem.dat" using 1:3 title 'memfree' with lines, "/tmp/mem.dat" using 1:6 title 'cached' with lines, "/tmp/mem.dat" using 1:8 title 'swapfree' with lines;
-EOF
-
-#[OK] eth0: inbyt/s eth0: otbyt/s
-gnuplot <<EOF
-set output "$STATSDIR/graph-bp.png"
-set term png small
-set size 640/480
-set timefmt "%H:%M:%S"
-set format x "%Hh"
-set xdata time
-set yr [0:]
-plot "/tmp/eth0.dat" using 1:4 title 'input' with lines, "/tmp/eth0.dat" using 1:5 title 'output' with lines
-EOF
-
-#[OK] eth0: coll/s
-gnuplot <<EOF
-set output "$STATSDIR/graph-coll.png"
-set term png small
-set size 640/480
-set timefmt "%H:%M:%S"
-set format x "%Hh"
-set xdata time
-set yr [0:10]
-plot "/tmp/eth0err.dat" using 1:4 title 'coll/s' with lines
-EOF
-
-#[OK] _tcp_: nowopen socknow _udp_: socknow
-gnuplot <<EOF
-set output "$STATSDIR/graph-sockets.png"
-set term png small
-set size 640/480
-set timefmt "%H:%M:%S"
-set format x "%Hh"
-set xdata time
-set yr [0:]
-set key left
-plot "/tmp/tcp.dat" using 1:6 title 'TCPopen' with lines,"/tmp/tcp.dat" using 1:7 title 'TCPnow' with lines, "/tmp/udp.dat" using 1:6 title 'UDPopen' with lines
-EOF
-
-#[OK] DISK: rdwr/s
-gnuplot <<EOF
-set output "$STATSDIR/graph-disk.png"
-set term png small
-set size 640/480
-set timefmt "%H:%M:%S"
-set format x "%Hh"
-set xdata time
-set yr [0:]
-plot "/tmp/disk.dat" using 1:3 title 'rdwr/s' with lines
-EOF
-
-#[OK] promo
-gnuplot <<EOF
-set output "$STATSDIR/graph-promo.png"
-set term png small
-set title "Nombre d'inscrits par promotion (a partir de 1950)"
-set size 640/480
-plot "/tmp/promo" using 1:2 title '' with boxes
-EOF
-
-#[OK] promo2
-gnuplot <<EOF
-max100(x)=(x>100)?100:x
-set output "$STATSDIR/graph-promo2.png"
-set term png small
-set title "Pourcentage d'inscrits par promotion (a partir de 1940)"
-set size 640/480
-set yr [0:100]
-set xr [1940:$ANNEE]
-plot "/tmp/promo2" using 1:2 title '' with boxes
-EOF
-#plot "/tmp/promo2" using 1:(max100(\$2)) title '' with boxes
-
-rm -f /tmp/cpu.dat /tmp/load.dat /tmp/disk.dat /tmp/mem.dat /tmp/eth0.dat /tmp/eth0err.dat /tmp/tcp.dat /tmp/udp.dat /tmp/nbmails /tmp/promo /tmp/promo2
+++ /dev/null
-#! /usr/bin/python
-# set:encoding=iso-8859-1:
-
-import asyncore
-import email
-import os, re, sys
-
-from email import Message, MIMEText, MIMEMultipart
-from email.Iterators import typed_subpart_iterator, _structure
-from smtpd import PureProxy
-
-import ConfigParser
-import MySQLdb
-
-IGNORE = 0
-NOTICE = 1
-ERROR = 2
-
-FROM_PORT = 20024
-TO_HOST = 'olympe.madism.org'
-TO_PORT = 25
-
-
-################################################################################
-#
-# Functions
-#
-#-------------------------------------------------------------------------------
-
-config = ConfigParser.ConfigParser()
-config.read(os.path.dirname(__file__)+'/../configs/platal.conf')
-
-def get_config(sec,val,default=None):
- try:
- return config.get(sec, val)[1:-1]
- except ConfigParser.NoOptionError, e:
- if default is None:
- print e
- sys.exit(1)
- else:
- return default
-
-def connectDB():
- db = MySQLdb.connect(
- db = 'x4dat',
- user = get_config('Core', 'dbuser'),
- passwd = get_config('Core', 'dbpwd'),
- unix_socket='/var/run/mysqld/mysqld.sock')
- db.ping()
- return db.cursor()
-
-def msg_of_str(data): return email.message_from_string(data, _class=BounceMessage)
-
-################################################################################
-#
-# Classes
-#
-#-------------------------------------------------------------------------------
-
-class BounceMessage(Message.Message):
- def body(self):
- """this method returns the part that is commonely designed as the 'body'
-
- for the multipart mails, we go into the first part that have non multipart childs, and then :
- we return its first text/plain part if it exsists
- else we return the first text/* part if it exists
- else we return None else
-
- for non multipart mails, we just return the current payload
- """
- if self.is_multipart():
- _body = self
- while _body.get_payload(0).is_multipart():
- _body = _body.get_payload(0)
-
- buffer = None
- for part in typed_subpart_iterator(_body):
- if part.get_content_subtype() == 'plain':
- return part.get_payload(decode=True)
- if buffer is None:
- buffer = part
- return buffer.get_payload(decode=True)
- return self.get_payload(decode=True)
-
- def _qmail_attached_mail(self):
- """qmail is a dumb MTA that put the mail that has bounced RAW into the bounce message,
- instead of making a traditionnal message/rfc822 attachement like any other MTA
-
- it seems to be designed like this :
-
- =============================================
- [...QMAIL crap...]
- --- Below this line is a copy of the message.
-
- Return-Path: <...>
- [rest of the embeded mail]
- =============================================
-
- so we just cut the qmail crap, and build a new message from the rest.
-
- may DJB burn into coder's hell
- """
- msg = self.get_payload(decode=True)
- pos = msg.find("\n--- Below this line is a copy of the message.")
- if pos is -1:
- return None
- pos = msg.find("Return-Path:", pos)
- return msg_of_str(msg[pos:])
-
- def attached_mail(self):
- """returns the attached mail that bounced, if it exists.
- we try this :
-
- is the mail multipart ?
- Yes :
- (1) return the first message/rfc822 part.
- (2) return the first text/rfc822-headers part (AOHell)
- (3) return None (may be a vacation + some disclaimer in attachment)
- No:
- try to return the qmail-style embeded mail (but may be a vacation)
- """
- if self.is_multipart():
- for part in typed_subpart_iterator(self, 'message', 'rfc822'):
- return part
- for part in typed_subpart_iterator(self, 'text', 'rfc822-headers'):
- return part
- return None
- return self._qmail_attached_mail()
-
- def error_level(self):
- """determine the level of an error:
- IGNORE == drop the mail
- NOTICE == vacation, or any informative message we want to forward as is
- ERROR == errors, that we want to handle
- """
-
- body = self.body()
- if not body:
- return (IGNORE, '')
-
- mysql.execute ( "SELECT lvl,re,text FROM emails_bounces_re ORDER BY pos" )
- nb = int(mysql.rowcount)
- for x in range(0,nb):
- row = mysql.fetchone()
- if re.compile(str(row[1]), re.I | re.M).search(body):
- return (int(row[0]), str(row[2]))
-
- return (NOTICE, '')
-
- def forge_error(self, alias, dest, txt):
- """we have to do our little treatments for the broken mail,
- and then we create an informative message for the original SENDER to :
- - explain to him what happened (the detailed error)
- - try to guess if the user may or may not have had the mail (by another leg)
- - if no other leg, give an information to the SENDER on how he can give to us a real good leg
- and attach any sensible information about the original mail (@see attached_mail)
- """
-
- mysql.execute("SELECT id FROM aliases WHERE alias='%s' AND type IN ('alias', 'a_vie') LIMIT 1" % (alias))
- if int(mysql.rowcount) is not 1:
- return None
- uid = mysql.fetchone()[0]
- mysql.execute("UPDATE emails SET panne = NOW() WHERE uid='%s' AND email='%s'" % (uid, dest))
- mysql.execute("REPLACE INTO emails_broken (uid,email) VALUES(%s, '%s')" % (uid, dest))
- mysql.execute("""SELECT COUNT(*),
- IFNULL(SUM(panne=0 OR (last!=0 AND ( TO_DAYS(NOW())-TO_DAYS(last) )>7 AND panne<last)), 0),
- IFNULL(SUM(panne!=0 AND last!=0 AND ( TO_DAYS(NOW())-TO_DAYS(last) )<7 AND panne<last) , 0),
- IFNULL(SUM(panne!=0 AND (last=0 OR ( TO_DAYS(NOW())-TO_DAYS(last) )<1)) , 0)
- FROM emails
- WHERE FIND_IN_SET('active', flags) AND uid=%s AND email!='%s'""" % (uid, dest))
-
- nb_act, nb_ok, nb_may, nb_bad = map(lambda x: int(x), mysql.fetchone())
-
- txt = "Une des adresses de redirection de %s\n" % (alias) \
- + "a généré une erreur (qui peut être temporaire) :\n" \
- + "------------------------------------------------------------\n" \
- + "%s\n" % (txt) \
- + "------------------------------------------------------------\n\n"
-
- if nb_ok + nb_may is 0:
- txt += "Toutes les adresses de redirection de ce correspondant\n" \
- + "sont cassées à l'heure actuelle.\n\n" \
- + "Prière de prévenir votre correspondant par d'autres moyens\n" \
- + "pour lui signaler ce problème et qu'il puisse le corriger !!!"
- elif nb_ok is 0:
- txt += "Ce correspondant possède néanmoins %i autre(s) adresse(s) active(s)\n" % (nb_may) \
- + "en erreur, mais ayant recu des mails dans les 7 derniers jours,\n" \
- + "sans -- pour le moment -- avoir créé la moindre nouvelle erreur.\n\n" \
- + "Ces adresses sont donc peut-être valides.\n"
- else:
- txt += "Ce correspondant a en ce moment %i autre(s) adresse(s) valide(s).\n" % (nb_ok) \
- + "Rien ne prouve cependant qu'elles étaient actives \n" \
- + "au moment de l'envoi qui a échoué."
-
- msg = MIMEMultipart.MIMEMultipart()
- msg['Subject'] = self['Subject']
-
- attach = self.attached_mail()
- if attach is not None:
- txt += "\nCi-joint le mail dont la livraison a échoué\n"
- msg.attach(MIMEText.MIMEText(txt))
- msg.attach(attach)
- else:
- msg.attach(MIMEText.MIMEText(txt))
-
- return msg
-
- def to_bounce(self, alias, dest):
- """this function returns a new Message, the one we really want to send.
-
- alias holds one valide plat/al alias of the user
-
- Case 0: the error is IGNORE : return None
- Case 1: the error is NOTICE : we just return self
- Case 2: we have a REAL error: use forge_error
- """
- lvl, txt = self.error_level()
-
- if lvl is IGNORE: return None
- elif lvl is NOTICE: return self
- elif lvl is ERROR : return self.forge_error(alias, dest, txt)
- else: raise
-
-
-class BounceProxy(PureProxy):
- def __init__(self, localaddr, remoteaddr):
- PureProxy.__init__(self, localaddr, remoteaddr)
- self._rcpt_re = re.compile(r'^([^_]*)__(.*)__([^_+=]*)\+(.*)=([^_+=]*)@bounces.m4x.org$')
-
-
- def process_rcpt(self, rcpttos):
- for to in rcpttos:
- m = self._rcpt_re.match(to)
- if m is None: continue
- return ( m.group(1), m.group(2)+'@'+m.group(3), m.group(4)+'@'+m.group(5) )
- return None
-
-
- def process_message(self, peer, mailfrom, rcpttos, data):
- try:
- alias, sender, dest = self.process_rcpt(rcpttos)
- bounce = msg_of_str(data).to_bounce(alias, dest)
- if bounce is not None:
- bounce['From'] = """"Serveur de courier Polytechnique.org" <MAILER-DAEMON@bounces.m4x.org>"""
- bounce['To'] = sender
- self._deliver("MAILER-DAEMON@bounces.m4x.org", [sender], bounce.as_string())
- except:
- pass
- # SPAM or broken msg, we just drop it
- return None
-
-
-################################################################################
-#
-# Main
-#
-#-------------------------------------------------------------------------------
-
-mysql = connectDB()
-Proxy = BounceProxy(('127.0.0.1', FROM_PORT), (TO_HOST, TO_PORT))
-asyncore.loop()
-