#!/usr/bin/env python

from __future__ import with_statement

import os
import re
from email.mime.text import MIMEText
from smtplib import SMTP
from email.Header import Header
from email.Utils import parseaddr, formataddr
import sys
from collections import defaultdict
from time import sleep
from subprocess import Popen, PIPE
from datetime import datetime
from ConfigParser import RawConfigParser

class Config(defaultdict):
    PATH = '/root/checker.conf'
    DEFAULT = {'mail': {'sender': 'xivo@olympiquelyonnais.com',
                        'recipient': 'rbignon@avencall.com',
                        'smtp': '127.0.0.1',
                       },
              }

    def __init__(self, _ = None):
        defaultdict.__init__(self, dict)

    def cleanup(self):
        for key in self.keys():
            if not len(self[key]):
                del self[key]

    def read(self):
        config = RawConfigParser()
        try:
            with open(self.PATH, 'r') as fp:
                config.readfp(fp)
        except IOError:
            for sec, items in self.DEFAULT.iteritems():
                self[sec] = items.copy()
        else:
            for sec in config.sections():
                self[sec] = dict([(k,v.decode('utf-8')) for k,v in config.items(sec)])

    def write(self):
        config = RawConfigParser()
        for sec, items in self.iteritems():
            config.add_section(sec)
            for key, value in items.iteritems():
                if isinstance(value, unicode):
                    value = value.encode('utf-8')
                config.set(sec, key, value)
        with open(self.PATH, 'wb') as fp:
            config.write(fp)

class Checker(object):
    CORE_PATH = '/var/spool/asterisk/'

    def __init__(self):
        self.config = Config()
        self.last_check = datetime.now()

    def run(self):
        print '[%s] Checking now..' % datetime.now()
        self.check_crash()
        #self.check_deadlock()
        self.check_longcalls()
        self.last_check = datetime.now()
        self.config.write()

    def send_email(self, subject, body):
        subject = '[OL-Checker] %s' % subject

        msg = MIMEText(body, 'plain', 'utf-8')
        msg['From'] = self.config['mail']['sender']
        msg['To'] = self.config['mail']['recipient']
        msg['Subject'] = Header(unicode(subject), 'UTF-8')

        try:
            smtp = SMTP(self.config['mail']['smtp'])
            smtp.sendmail(self.config['mail']['sender'], self.config['mail']['recipient'].split(', '), msg.as_string())
        finally:
            smtp.quit()

    def check_crash(self):
        for filename in os.listdir(self.CORE_PATH):
            if not filename.startswith('core.'):
                continue
            path = os.path.join(self.CORE_PATH, filename)
            mtime = datetime.fromtimestamp(os.path.getmtime(path))
            if mtime > self.last_check:
                print 'New crash, send email now.'
                self.send_email('Asterisk crashed', "Hi,\n\n Asterisk has crashed at %s.\nCore in %s\n\nTcho.\n" % (mtime, path))

    def check_longcalls(self):
        p = Popen(['asterisk', "-rx", "core show channels verbose"], stdout=PIPE)
        for line in p.stdout.xreadlines():
            m = re.match('([^ ]+)\s+([^ ]+)\s+([^ ]*)\s+(\d+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]*)\s+([^ ]+)', line.strip())
            if not m:
                continue

            time = line[127:].split(' ')[0]

            hh, mm, ss = time.split(':')
            if int(hh) >= 1 and int(hh) < 2:
                print 'Strange long call, send email now.'
                self.send_email('Strange call', "Hi,\n\nThere is a strange long call (%s) with channel %s:\n%s\n\nTcho.\n" % (time, m.group(1), line))
            elif m.group(5) != 'Up' and not 'billetterie' in m.group(7) and int(mm) >= 2 and int(hh) < 1:
                print 'Strange long dial, send email now.'
                self.send_email('Strange long dial', "Hi,\n\nThere is a strange long dial (%s) with channel %s:\n%s\n\nTcho.\n" % (time, m.group(1), line))

    def main(self):
        self.config.read()
        while 1:
            self.run()

            try:
                sleep(300)
            except KeyboardInterrupt:
                print 'Interrupted.'
                return 0

if __name__ == '__main__':
    checker = Checker()
    sys.exit(checker.main())

