#! /usr/bin/env python
###############################################################################
#                                                                             #
#   Copyright 2005 University of Cambridge Computer Laboratory.               #
#                                                                             #
#   This file is part of Nprobe.                                              #
#                                                                             #
#   Nprobe is free software; you can redistribute it and/or modify            #
#   it under the terms of the GNU General Public License as published by      #
#   the Free Software Foundation; either version 2 of the License, or         #
#   (at your option) any later version.                                       #
#                                                                             #
#   Nprobe is distributed in the hope that it will be useful,                 #
#   but WITHOUT ANY WARRANTY; without even the implied warranty of            #
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             #
#   GNU General Public License for more details.                              #
#                                                                             #
#   You should have received a copy of the GNU General Public License         #
#   along with Nprobe; if not, write to the Free Software                     #
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA #
#                                                                             #
###############################################################################


##############################################################################
## 
##
## 
## 
##
## 

############################################################################

import os
import sys
import getopt
import pcap

############################################################################
############################################################################

class FlowDmuxerException(Exception):
    '''
    Class FlowDmuxerException (file DMuxer.py)
    The only exception raised by FlowDmuxer and sub-classes - all exceptions
      raised by FlowDmuxer operations are intercepted and re-presented as
      FlowDmuxerExceptions (hence avoiding the user having to identify and
      catch all possible classes of underlying exception) - hopefully with
      a meaningful error message.

      If the underlying exceptions are required (e.g. for debugging) the
      FlowDmuxer, or sub-classes can be instantiated with the keyword argument
      'raise_natural_exceptions=1' (flag -e from dmux.py).
    '''

    def __init__(self, val):
        self.val = val

    def __str__(self):
        return self.val

############################################################################
############################################################################

class FlowDmuxer:

    '''
    Base DMuxer class (file DMuxer.py)
    
    Relies heavily on pylibpcap for access to tcpdump files and packet
    -filter operations
    
    C.L. Options:
    
    --float_timestamps: have packet filter\'s next() method return
      float timestamps (default is (sec, usec) tuple).
    '''

    def __init__(self, infile, filtexp, opath=None, raise_natural_exceptions=0, save_check_info=0):

        self.pcap = None
        self.raise_natural_exceptions = raise_natural_exceptions
        self.save_check_info = save_check_info

        if not infile:
            raise FlowDmuxerException('no input file specified')

        if infile == '-':
            self.stdin = 1
            self.infile = 'Stdin'
        else:
            self.stdin = 0
            self.infile = infile

        self.resolve_opath(opath, infile)

        self.pcap = ppc = pcap.py_pcap()

        self.pcap_next = ppc.next_tts

        try:
            ppc.open_offline(infile)
        except (IOError, TypeError), s:
            self.exception(str(s))
            
        try:
            ppc.set_filter(filtexp)
        except TypeError, s:
            self.exception(str(s))

        self.linktype = ppc.datalink()

############################################################################

    def __del__(self):

        if self.pcap:
            del self.pcap


############################################################################

    def exception(self, msg):

        if self.raise_natural_exceptions:
            raise
        else:
            raise FlowDmuxerException(msg)
            
            

############################################################################

    def tidy(self):

        pass

############################################################################

    def getopts(self, opts):

        try:
            optlist, args = getopt.getopt(opts, '', ['float_timestamps'])
        except getopt.error, s:
            self.exception('base class getopt() ' + str(s))

        for opt, par in optlist:
            if opt == '--float_timestamps':
                self.pcap_next = self.pcap.next_fts

############################################################################

    def resolve_opath(self, opath, infile):

        dir = file = ''
            
        if opath:
            dir, file = os.path.split(opath)
            if dir:
                if not os.path.isdir(dir):
                    try:
                        os.makedirs(dir)
                    except OSError, s:
                        self.exception(str(s))
                    
        if not dir and file != '-':
            dir = os.path.split(infile)[0]
            if not dir:
                dir = os.getcwd()

        self.odir = dir
        self.ofile = file

############################################################################

    def process_pkt(self, (len, data, ts)):

        pass


############################################################################

    def loop(self, count=-1):

        ftell = self.pcap.ftell
        next = self.pcap_next
        dp = self.process_pkt
    
        try:
            while count != 0:
                dp(next())
                if count > 0:
                    count -=1
        except TypeError, s:
            self.exception(str(s))
        except EOFError:
            return

############################################################################

    def report(self):

        pass

############################################################################
############################################################################
