#!/usr/bin/env python
# This file is part of jobservice.
# Copyright 2010 Jacob Peddicord <jpeddicord@ubuntu.com>
#
# jobservice 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 3 of the License, or
# (at your option) any later version.
#
# jobservice 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 jobservice.  If not, see <http://www.gnu.org/licenses/>.

import sys
import os

def p(t):
    print >> sys.stderr, t
    return t

iface = sys.argv[1].split('/')[1]
mode = sys.argv[2]

def main():
    interfaces = Interfaces()

    if mode == 'get':
        # manual mode
        if iface in interfaces.auto:
            print "manual yes"
        else:
            print "manual no"
            return
        # network mode
        if iface in interfaces.family and iface in interfaces.method:
            fam = interfaces.family[iface]
            meth = interfaces.method[iface]
            if fam == 'inet' and (meth == 'static' or meth == 'dhcp'):
                print "netmode {0}".format(meth)
        # address
        if iface in interfaces.address:
            print "address {0}".format(interfaces.address[iface])
        # netmask
        if iface in interfaces.netmask:
            print "netmask {0}".format(interfaces.netmask[iface])
        # gateway
        if iface in interfaces.gateway:
            print "gateway {0}".format(interfaces.gateway[iface])
    elif mode == 'set':
        for line in sys.stdin.readlines():
            setting, value = line.split()
            if setting == 'address' or setting == 'netmask' or setting == 'gateway':
                interfaces.update_option(iface, setting, value)
            elif setting == 'netmode':
                interfaces.update_mode(iface, value)
            elif setting == 'manual':
                interfaces.update_manual(iface, value == 'yes')

class Interfaces:
    def __init__(self):
        self.auto = []
        self.iface_stanza = {}
        self.family = {}
        self.method = {}
        self.address = {}
        self.netmask = {}
        self.gateway = {}
        # parse it!
        f = open('/etc/network/interfaces')
        current_iface = None
        for line in f:
            data = line.strip().split()
            if not data:
                continue
            # check the type of line
            if data[0] == 'auto':
                current_iface = None
                self.auto.extend(data[1:])
            elif data[0].find('allow-') == 0 or data[0].find('mapping') == 0:
                current_iface = None
            elif data[0] == 'iface':
                current_iface = data[1]
                self.iface_stanza[current_iface] = []
                self.family[data[1]] = data[2]
                self.method[data[1]] = data[3]
            elif data[0] == 'address':
                self.address[current_iface] = data[1]
            elif data[0] == 'netmask':
                self.netmask[current_iface] = data[1]
            elif data[0] == 'gateway':
                self.gateway[current_iface] = data[1]
            # store stanzas
            if current_iface and data[0] != 'iface':
                self.iface_stanza[current_iface].append(line)
        f.close()
    
    def open_change_files(self):
        orig = open('/etc/network/interfaces')
        new = open('/etc/network/interfaces.new', 'w')
        return (orig, new)
    
    def finalize_change_files(self, orig, new):
        orig.close()
        new.close()
        os.rename(orig.name, orig.name + '~')
        os.rename(new.name, orig.name)
    
    def update_manual(self, iface, manual):
        """Remove or add an auto line & iface stanza."""
        orig, f = self.open_change_files()
        # adding an auto line & iface stanza
        if manual and not iface in self.auto:
            for line in orig:
                f.write(line)
            f.write('\nauto ' + iface + '\n')
            # only write an iface section if it's not already there
            if not iface in self.iface_stanza:
                # dhcp will be replaced in a later run if it's different
                f.write(' '.join(('iface', iface, 'inet', 'dhcp')) + '\n')
        # removing the auto line
        elif not manual and iface in self.auto:
            for line in orig:
                if line.strip() == 'auto ' + iface:
                    continue
                f.write(line)
        self.finalize_change_files(orig, f)
    
    def update_mode(self, iface, mode):
        """Update an iface's mode (dhcp/static)."""
        orig, f = self.open_change_files()
        for line in orig:
            lstrip = line.strip()
            if lstrip.find('iface ' + iface) == 0:
                data = lstrip.split()
                f.write(' '.join(('iface', iface, data[2], mode)) + '\n')
                continue
            f.write(line)
        self.finalize_change_files(orig, f)
    
    def update_option(self, iface, setting, value):
        """Update an option inside a stanza."""
        orig, f = self.open_change_files()
        stanza = False
        finished = False
        for line in orig:
            # if we've found our stanza
            lstrip = line.strip()
            if not stanza and lstrip.find('iface ' + iface) == 0:
                stanza = True
                f.write(line)
                # if it was already in the stanza
                if self.in_stanza(iface, setting):
                    for s in self.iface_stanza[iface]:
                        if s.find(setting) == 0:
                            f.write(setting + ' ' + value + '\n')
                        else:
                            f.write(s)
                # not previously in file, write it
                else:
                    f.write(setting + ' ' + value + '\n')
                    f.write(''.join(self.iface_stanza[iface]))
                continue
            # figure out where to end the stanza
            if stanza:
                data = lstrip.split()
                if not data:
                    f.write(line)
                    continue
                if self.is_stanza_begin(data):
                    stanza = False
            if not stanza:
                f.write(line)
        self.finalize_change_files(orig, f)
    
    def in_stanza(self, iface, setting):
        for s in self.iface_stanza[iface]:
            if s.find(setting) == 0:
                return True
        return False
    
    def is_stanza_begin(self, data):
        if data[0] == 'iface' or data[0] == 'mapping' or \
                data[0] == 'auto' or data[0].find('allow-') == 0:
            return True
        else:
            return False

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