#!/usr/bin/python
"""
    Tool for measuring pop traffic

    Copyright  Afrihost.com (PTY) Ltd 2009
    Original file by: Ed Pascoe <ed@pascoe.co.za>
"""
__author__  = "Ed Pascoe <ed@pascoe.co.za>"
__credits__ = "Afrihost.com -- The best webhosting. Ever."

import os.path, sys, re
import optparse
import logging #We just use this for debugging

log=logging.getLogger('PopCalculator')


#Jun 23 13:21:24 dimitrios imapd: LOGOUT, user=zane.ally@reagola.com, ip=[::ffff:127.0.0.1], headers=0, body=21316, rcvd=197, sent=22357, time=0
class PopCalculator:
    """Generate statistics for all pop accounts"""
    emailaddresses={}
    totalin=0
    totalout=0
    def __init__(self):
        log.debug("Init PopCalulator")
    def processLine(self,line):
        """Process a single line from the logs"""
        parts=line.split(",")
        data={}
        for p in parts:
            p=p.strip()
            fields=p.split('=',1)
            if len(fields) != 2: continue #Nothing we are interested in
            try: data[fields[0]]=int(fields[1]) #Its probably a field with an integer value
            except: data[fields[0]]=fields[1]   #But otherwise just store the name
        if not data.has_key('user') or not data.has_key('sent') or not data.has_key('rcvd') : return #Not a valid line
        try:
           if self.emailaddresses.has_key(data['user']): #We've already got logs for this user
               self.emailaddresses[data['user']]['sent'] += data['sent']
               self.emailaddresses[data['user']]['rcvd'] += data['rcvd']
           else:
               self.emailaddresses[data['user']]={'sent':data['sent'],'rcvd':data['rcvd']}
        except KeyError:
            print "Fail on " , line,
            print data
            raise
        try:
            self.totalin +=data['rcvd']
            self.totalout +=data['sent']
        except TypeError,e:
            log.critical("Type conversion issue. Data: %s " % (repr(data)))
            log.debug(repr(data['rcvd']))
            #log.exception(e)
            raise
        
    def report(self):
        """Report some stats from our calculations"""
        for box in self.emailaddresses.keys():
            print "%5.3f %s" % ((self.emailaddresses[box]['sent']+0.0)/1000000,box)
        print "Total Out: %5.3f(MB) i.e. Recieved by users. Total In: %5.3f(MB) i.e uploaded by users (should be very small vs Out) " % ((self.totalout+0.0)/1000000 ,(self.totalin+0.0)/1000000)
            
if __name__=='__main__':
    logging.basicConfig(level=logging.ERROR, format="%(levelname)s T:%(thread)d %(module)s:%(lineno)d %(message)s")
    
    usage="Usage: %prog [<options>] [<maillog files>|-]" +"\n"+__doc__+"\n"
    parser=optparse.OptionParser(usage)

    parser.add_option("--domain", dest="domain", type="string", default=None, help="Domain to search for, can be a full email address as well")
    parser.add_option("--date", dest="date", type="string", default=None, help="If set only report for given day")
    (options,args) = parser.parse_args()

    sys.stderr=sys.stdout #For handling error messages sent into regqueue.log
    
    if not args and not options.domain and not options.date: 
        parser.print_help()
        sys.exit(1)

    if not args:args=["-",]
    popcalc=PopCalculator()
    for fname in args:
        if fname =="-":
            log.debug("Reading from stdin")
            fhandle=sys.stdin 
        else:
            log.debug("Opening '%s'" % (fname))
            fhandle=file(fname,"r")
        for line in fhandle:    
            if options.domain:
                if line.find(options.domain)==-1: continue #Not the domain we are looking for
            if options.date:
                if line.find(options.date)==-1: continue #Not the date we are looking for
            if line.find("LOGOUT,")==-1: continue #We only need the stats which get displayed at the end of a line    
            popcalc.processLine(line)
        fhandle.close()
    popcalc.report()
           
           
