#!/usr/bin/python2.2

import sys
PROGNAME="redhat-config-bind"
bindconf_dir = '/usr/share/'+PROGNAME
sys.path.append(bindconf_dir)

VERSION = "1.9.0"

try:
    import gtk
except RuntimeError,e:
    print "Unable to initialize graphical environment. Most likely cause of failure"
    print "is that the tool was not run using a graphical environment. Please either"
    print "start your graphical user interface or set your DISPLAY variable."
    print "Caught exception: %s" % e
    sys.exit(-1)
    
import gnome
import gnome.ui
import gtk.glade
import dnsdata
import Alchemist
import FileBlackBox
import string
import signal
import os
import gettext
import re
import gobject
import socket

import FwdZone

from gtk import TRUE
from gtk import FALSE
from FwdZone import verify_delete
from FwdZone import generic_error_dialog
from FwdZone import add_dot
from dnsdata import TestError

hostname_pattern = '^[a-zA-Z0-9.\-@]+$'

#Columns for "bindconf_treeview"
COLUMN_PIXBUF=0
COLUMN_TEXT=1
COLUMN_DATA=2

#columns for "rev_zone_treeview", "fwd_zone_treeview"
COLUMN_TEXT2=3
COLUMN_PARENT=4

##
## I18N
## 

gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
gettext.textdomain(PROGNAME)
#try:
#    gettext.install(PROGNAME, "/usr/share/locale", 1)
#except IOError:
#    print "IOError"
#    import __builtin__
#    __builtin__.__dict__['_'] = unicode
_=gettext.gettext

gnome.program_init (PROGNAME,VERSION)
gnome.app_version =VERSION
FORMALNAME=_("Domain Name Service")

##
## Global values
##

gladepath = "bindconf.glade"
if not os.path.exists(gladepath):
    gladepath = bindconf_dir + "/bindconf.glade"

gtk.glade.bindtextdomain(PROGNAME)
xml = gtk.glade.XML (gladepath, domain=PROGNAME)

image_domain = FwdZone.load_image("domain.png")
image_reverse = FwdZone.load_image("reverse.png")
image_slave = FwdZone.load_image("slave.png")

cfg = dnsdata.DNS()

class UpdateClass:
    UPDATE=FALSE
    def set(self,val):
        self.UPDATE=val
    def get(self):
        return self.UPDATE

update = UpdateClass()

fwd_zone_first_time = gtk.TRUE

##
## JRBs rewrite code.
##

class MyTreeModel(gtk.TreeStore):
    '''This class represents the model of a tree.  The iterators used
    to represent positions are converted to python objects when passed
    to the on_* methods.  This means you can use any python object to
    represent a node in the tree.  The None object represents a NULL
    iterator.

    In this tree, we use simple tuples to represent nodes, which also
    happen to be the tree paths for those nodes.  This model is a tree
    of depth 3 with 5 nodes at each level of the tree.  The values in
    the tree are just the string representations of the nodes.'''

    TREE_DEPTH = 4
    TREE_SIBLINGS = 5
    def __init__(self):
	'''constructor for the model.  Make sure you call
	PyTreeModel.__init__'''
	gtk.TreeStore.__init__(self, gtk.gdk.Pixbuf, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT, gobject.TYPE_STRING,gobject.TYPE_PYOBJECT)
    # the implementations for TreeModel methods are prefixed with on_
    def on_get_flags(self):
	'''returns the GtkTreeModelFlags for this particular type of model'''
	return 0
    def on_get_n_columns(self):
	'''returns the number of columns in the model'''
	return 1
    def on_get_column_type(self, index):
	'''returns the type of a column in the model'''
	return gobject.TYPE_STRING
    def on_get_path(self, node):
	'''returns the tree path (a tuple of indices at the various
	levels) for a particular node.'''
	return node
    def on_get_iter(self, path):
        '''returns the node corresponding to the given path.  In our
        case, the node is the path'''
        return path
    def on_get_value(self, node, column):
	'''returns the value stored in a particular column for the node'''
	assert column == 0
	return `node`
    def on_iter_next(self, node):
	'''returns the next node at this level of the tree'''
	if node[-1] == self.TREE_SIBLINGS - 1: # last node at level
	    return None
	return node[:-1] + (node[-1]+1,)
    def on_iter_children(self, node):
	'''returns the first child of this node'''
	if node == None: # top of tree
	    return (0,)
	if len(node) >= self.TREE_DEPTH: # no more levels
	    return None
	return node + (0,)
    def on_iter_has_child(self, node):
	'''returns true if this node has children'''
	return len(node) < self.TREE_DEPTH
    def on_iter_n_children(self, node):
	'''returns the number of children of this node'''
	if len(node) < self.TREE_DEPTH:
	    return self.TREE_SIBLINGS
	else:
	    return 0
    def on_iter_nth_child(self, node, n):
	'''returns the nth child of this node'''
        if node == None:
            return (n,)
	if len(node) < self.TREE_DEPTH and n < self.TREE_SIBLINGS:
	    return node + (n,)
	else:
	    return None
    def on_iter_parent(self, node):
	'''returns the parent of this node'''
	if len(node) == 0:
	    return None
	else:
	    return node[:-1]
    # the implementations for TreeModel methods are prefixed with on_
    def on_get_flags(self):
	'''returns the GtkTreeModelFlags for this particular type of model'''
	return 0
    def on_get_n_columns(self):
	'''returns the number of columns in the model'''
	return 1
    def on_get_column_type(self, index):
	'''returns the type of a column in the model'''
	return gobject.TYPE_STRING
    def on_get_path(self, node):
	'''returns the tree path (a tuple of indices at the various
	levels) for a particular node.'''
	return node
    def on_get_iter(self, path):
        '''returns the node corresponding to the given path.  In our
        case, the node is the path'''
        return path
    def on_get_value(self, node, column):
	'''returns the value stored in a particular column for the node'''
	assert column == 0
	return `node`
    def on_iter_next(self, node):
	'''returns the next node at this level of the tree'''
	if node[-1] == self.TREE_SIBLINGS - 1: # last node at level
	    return None
	return node[:-1] + (node[-1]+1,)
    def on_iter_children(self, node):
	'''returns the first child of this node'''
	if node == None: # top of tree
	    return (0,)
	if len(node) >= self.TREE_DEPTH: # no more levels
	    return None
	return node + (0,)
    def on_iter_has_child(self, node):
	'''returns true if this node has children'''
	return len(node) < self.TREE_DEPTH
    def on_iter_n_children(self, node):
	'''returns the number of children of this node'''
	if len(node) < self.TREE_DEPTH:
	    return self.TREE_SIBLINGS
	else:
	    return 0
    def on_iter_nth_child(self, node, n):
	'''returns the nth child of this node'''
        if node == None:
            return (n,)
	if len(node) < self.TREE_DEPTH and n < self.TREE_SIBLINGS:
	    return node + (n,)
	else:
	    return None
    def on_iter_parent(self, node):
	'''returns the parent of this node'''
	if len(node) == 0:
	    return None
	else:
	    return node[:-1]


##
## Callbacks
##
def on_bindconf_treeview_expand_row(tree_view, iter, *args):
    model = tree_view.get_model()
    zone = model.get_value (iter, COLUMN_DATA)

def on_alias_edit_button_click (*args):
    xml.get_widget ('a_edit_button').clicked ()

def on_zone_ns_add_button_clicked (clicked):
    fwdzone = xml.get_widget ('fwd_master_dialog').get_data ('fwdzone')
    tree_view = xml.get_widget ('zone_ns_treeview')
    selected = tree_view.get_selection().get_selected ()
    ns = FwdZone.NSProxy ()
    if ns.run_add_dialog (fwdzone, xml, xml.get_widget ('fwd_master_dialog'),TRUE)==gtk.RESPONSE_OK:
        fwdzone.set_dirty()
        model = tree_view.get_model ()
        iter = model.append ()
        model.set (iter,
                   COLUMN_PIXBUF, ns.get_pix (),
                   COLUMN_TEXT, ns.getHost(),
                   COLUMN_TEXT2, '',
                   COLUMN_DATA, ns)
        tree_view.get_selection ().select_iter (iter)
    
def on_zone_ns_edit_button_clicked (*args):
    fwdzone = xml.get_widget ('fwd_master_dialog').get_data ('fwdzone')
    tree_view = xml.get_widget ('zone_ns_treeview')
    selected = tree_view.get_selection().get_selected ()
    if selected != None:
        (model, iter) = selected
        ns = model.get_value (iter, COLUMN_DATA)
        if ns.run_edit_dialog (fwdzone, xml, xml.get_widget ('fwd_master_dialog'),TRUE)==gtk.RESPONSE_OK:
            fwdzone.set_dirty()
            model.set (iter,
                       COLUMN_TEXT, ns.getHost(),
                       COLUMN_DATA, ns)
            tree_view.get_selection ().select_iter (iter)

def on_zone_ns_delete_button_clicked (clicked):
    fwdzone = xml.get_widget ('fwd_master_dialog').get_data ('fwdzone')
    tree_view = xml.get_widget ('zone_ns_treeview')
    result = tree_view.get_selection().get_selected ()
    if result != None:
        fwdzone.set_dirty()
        (model, iter) = result
        path = model.get_path (iter)
        ns = model.get_value (iter, COLUMN_DATA)
        
        if verify_delete(_("nameserver '%s'") % ns.getHost()) == gtk.RESPONSE_YES:
            model.remove (iter)
            try:
                iter = model.get_iter (path)
            except:
                pass
            if iter == None:
                path = (0)
            tree_view.get_selection().select_path (path)

def on_zone_mx_add_button_clicked (clicked):
    fwdzone = xml.get_widget ('fwd_master_dialog').get_data ('fwdzone')
    tree_view = xml.get_widget ('zone_mx_treeview')
    mx = FwdZone.MXProxy ()
    if mx.run_add_dialog (fwdzone, xml,xml.get_widget ('fwd_master_dialog'))==gtk.RESPONSE_OK:
        fwdzone.set_dirty()
        model = tree_view.get_model ()
        iter = model.append ()
        model.set (iter,
                   FwdZone.COLUMN_PIXBUF,mx.get_pix (),
                   FwdZone.COLUMN_MAIL_XCHANGE,mx.getHost(),
                   FwdZone.COLUMN_PRIORITY, str (mx.priority),
                   FwdZone.COLUMN_DATA,mx)
        tree_view.get_selection ().select_iter (iter)

def on_zone_mx_edit_button_clicked (*args):
    fwdzone = xml.get_widget ('fwd_master_dialog').get_data ('fwdzone')
    tree_view = xml.get_widget ('zone_mx_treeview')
    selected = tree_view.get_selection().get_selected ()
    if selected != None:
        (model, iter) = selected
        mx = model.get_value (iter, COLUMN_DATA)
        if mx.run_edit_dialog (fwdzone, xml,xml.get_widget ('fwd_master_dialog'))==gtk.RESPONSE_OK:
            fwdzone.set_dirty()
            model.set (iter,
                   FwdZone.COLUMN_PIXBUF,mx.get_pix (),
                   FwdZone.COLUMN_MAIL_XCHANGE,mx.getHost(),
                   FwdZone.COLUMN_PRIORITY, str (mx.priority),
                   FwdZone.COLUMN_DATA,mx)
            tree_view.get_selection ().select_iter (iter)

def on_zone_mx_delete_button_clicked (clicked):
    tree_view = xml.get_widget ('zone_mx_treeview')
    result = tree_view.get_selection().get_selected ()
    if result != None:
        (model, iter) = result
        path = model.get_path (iter)
        mx = model.get_value (iter, COLUMN_DATA)
        if verify_delete(_("mail exchanger '%s'") % mx.get_str()) == gtk.RESPONSE_YES:
            model.remove (iter)
            try:
                iter = model.get_iter (path)
            except:
                pass
            if iter == None:
                path = (0)
            tree_view.get_selection().select_path (path)


# FIXME add some GTK parameters here
def on_save_activate():
    cfg.saveLocal()

# FIXME add some GTK parameters here
def on_apply_activate():
    cfg.saveBind()
    update.set(FALSE)
    os.system("/sbin/service named reload &>/dev/null")

# FIXME add some GTK parameters here
def on_apply_and_save_activate(*args):
    on_save_activate()
    on_apply_activate()

def on_generic_tree_view_selection_changed (selection, button1, button2,add_record_button,add_record_menu=None):
    response = selection.get_selected ()
    if response == None:
        button1.set_sensitive (FALSE)
        button2.set_sensitive (FALSE)
        button3.set_sensitive (FALSE)
    else:
        button1.set_sensitive (TRUE)
        button2.set_sensitive (TRUE)
        (model, iter) = response
        if iter!=None:
            zone = model.get_value (iter, COLUMN_DATA)
            if isinstance (zone, dnsdata.SlaveZone):
                add_record_button.set_sensitive (FALSE)
                if add_record_menu!= None:
                    add_record_menu.set_sensitive (FALSE)
            else:
                add_record_button.set_sensitive (TRUE)
                if add_record_menu != None:
                    add_record_menu.set_sensitive (TRUE)

def on_generic_tree_view_row_activated (tree_view, path, column, func):
    apply (func)

def on_generic_treeview_select_row (treeview, row, column, event, button1, button2):
    button1.set_sensitive (TRUE)
    button2.set_sensitive (TRUE)

def on_generic_treeview_unselect_row (treeview, row, column, event, button1, button2):
    button1.set_sensitive (FALSE)
    button2.set_sensitive (FALSE)

def on_generic_entry_insert_text (entry, partial_text, length, pos, str):
    text = partial_text[0:length]
    if re.match (str, text):
        return
    entry.emit_stop_by_name ('insert_text')

def on_new_activate (*args):
    on_bindconf_add_button_clicked (None)

def on_properties_activate (*args):
    on_bindconf_edit_button_clicked (None)

def on_delete_activate (*args):
    on_bindconf_delete_button_clicked (None)

def on_add_record_activate (*args):
    on_bindconf_add_record_button_clicked (None)

def on_exit_activate (*args):
    dialog = xml.get_widget("query_save_dialog")
    dialog.set_transient_for (xml.get_widget ('bindconf'))
    if update.get():
        status = dialog.run()
        if status == gtk.RESPONSE_APPLY:
            on_apply_and_save_activate()
        elif status != gtk.RESPONSE_REJECT:
            dialog.hide()
            return
    gtk.mainquit()
    dialog.hide()

def on_bindconf_delete_event(*args):
    on_exit_activate(args)
    return TRUE

def find_browser():
    try:
        path = '/usr/bin/mozilla'
        os.stat(path)
        return path
    except:
        try:
            path = '/usr/bin/galeon'
            os.stat(path)
            return path
        except:
            try:
                path = '/usr/bin/konqueror'
                os.stat(path)
                return path
            except:
                return None
            
#----------------------------------------------------------------------------
# Methods pertaining to the "Help" menu items, there will be more here
# once I have "real" help :)
#----------------------------------------------------------------------------
def on_manual_activate(args):
    page = "file:///usr/share/doc/redhat-config-bind-" + VERSION + "/index.html"
#    gnome.help_display_uri(page)
    gnome.url_show(page)

def on_about_activate (*args):
#    dialog = xml.get_widget("about")
    dialog = gnome.ui.About(PROGNAME,
                          VERSION,
                          '(C) 2002 Red Hat, Inc.',
                          FORMALNAME + "\n"+ _('Configures zone files'),
                          [ 'Jonathan Blanford <jrb@redhat.com>', 'Elliot Lee <sopwith@redhat.com>', 'Harald Hoyer <harald@redhat.com>','Daniel Walsh <dwalsh@redhat.com'],[ 'Tammy Fox <tfox@redhat.com>'],_("translator_credits"))
    dialog.set_title (FORMALNAME)
    dialog.set_transient_for (xml.get_widget ('bindconf'))
    dialog.show()

def reverse_ip_address (ip):
    foo = string.split(ip, '.')
    foo.reverse()
    return string.join(foo, '.')

def last_octet (ip):
    foo = ip.split('.')
    foo.reverse()
    return foo[0]

def get_subnet (ip):
    foo = ip.split('.')
    if len(foo) == 4:
        return "%s.%s.%s." % (foo[0],foo[1],foo[2])
    else:
        return ""


def ip_to_strhash (ip):
    if int (ip) < 10:
        return "00" + str (ip)
    if int (ip) < 100:
        return "0" + str (ip)
    return str (ip)

def on_rev_zone_changed(widget):
    zone = xml.get_widget ('rev_master_dialog').get_data ('zone')
    zone.this_dirty = TRUE

def on_rev_zone_name_entry_changed (entry):
    label = xml.get_widget ('rev_zone_reverse_label')
    text = reverse_ip_address (entry.get_text ())
    label.set_text (text + ".in-addr.arpa")
    tree_view = xml.get_widget ('rev_zone_treeview')

    model = tree_view.get_model ()
    def foreach_func (model, path, iter, text):
        ptr = model.get_value (iter, COLUMN_DATA)
	try:
	        model.set_value (iter, COLUMN_TEXT, text + ptr[2].getIp())
	except:
		pass
        return FALSE
    model.foreach (foreach_func, add_dot (entry.get_text ()))
    on_rev_zone_changed(0)

def on_rev_zone_pns_changed (entry):
    text = entry.get_text ()
    on_rev_zone_changed(0)
    #FIXME: What's up with this????  Makes no sense.

def run_rev_zone_address_dialog (dialog, tree_view, parent, edit=FALSE):
    result = tree_view.get_selection().get_selected ()
    if result != None:
        (model, iter) = result
        if iter != None:
            selected_path = model.get_path (iter)
    else:
        model = tree_view.get_model ()
        iter = None
        selected_path = (0)
        if not edit:
            return None

    text = xml.get_widget ('rev_zone_name_entry').get_text ()
    xml.get_widget ('rev_master_address_label').set_text (add_dot (text))

    spin = xml.get_widget ('rev_master_address_spin')
    entry = xml.get_widget ('rev_master_address_entry')

    if edit:
        array = model.get_value (iter, COLUMN_DATA)
        spin.set_text (array[0])
        entry.set_text (array[1])
    else:
        spin.set_text ("")
        entry.set_text ("")
        ptr = None

    while 1:
        status = dialog.run ()
        if status != gtk.RESPONSE_OK:
            dialog.hide ()
            return status

        ip = spin.get_text ()
        host = entry.get_text ()
        if ip == "":
            generic_error_dialog (_("You must enter an octet."), dialog, broken_widget=spin)
            continue
        if host == "":
            generic_error_dialog (_("You must enter a hostname."), dialog, broken_widget=entry)
            continue

        try:
            host=add_dot(host)
            ptrg = dnsdata.PTR()
            brw = spin
            ptrg.testIp(ip)
            brw = entry
            ptrg.testHost(host)
        except TestError, e:
            generic_error_dialog (e.args, dialog, broken_widget=brw)
            continue
        
        try:
            def check_foreach (model, path, iter, text):
                if edit and path == selected_path:
                    return FALSE
	        val = model.get_value (iter, COLUMN_DATA)
	        if isinstance (val, tuple):
		    if val[0] == ip: 
			raise 'Duplicate'
                return None
            model.foreach (check_foreach, add_dot (entry.get_text ()))
        except 'Duplicate':
            generic_error_dialog (_("A host with that octet already exists"), dialog, broken_widget=spin)
            continue
        dialog.hide ()
        break

    if edit:
	ptr=array[2]
	ptr.setIp(ip)
	ptr.setHost(host)
        model.set (iter,
                   COLUMN_TEXT, add_dot (text) + ip,
                   COLUMN_TEXT2, host,
                   COLUMN_PARENT, parent,
                   COLUMN_DATA, (ip,host,ptr))
    else:
        if iter == None:
            iter = model.prepend ()
        else:
            iter = model.insert_before (iter)

        model.set (iter,
                   COLUMN_TEXT, add_dot (text) + ip,
                   COLUMN_TEXT2, host,
                   COLUMN_PARENT, parent,
                   COLUMN_DATA, (ip,host,ptr))
    on_rev_zone_changed(0)
    tree_view.get_selection().select_iter (iter)
    update.set(TRUE)
    return status 


def on_rev_zone_add_button_clicked (*args):
    dialog = xml.get_widget ('rev_master_address_dialog')
    dialog.set_title (_("New Reverse Zone Pointer"))
    dialog.set_transient_for (xml.get_widget ('rev_master_dialog'))
    tree_view = xml.get_widget ('rev_zone_treeview')
    parent = xml.get_widget ('rev_master_dialog').get_data ('zone')
    run_rev_zone_address_dialog (dialog,tree_view,parent)

def on_rev_zone_edit_button_clicked (*args):
    dialog = xml.get_widget ('rev_master_address_dialog')
    dialog.set_title (_("Edit Reverse Zone Pointer"))
    dialog.set_transient_for (xml.get_widget ('rev_master_dialog'))
    tree_view = xml.get_widget ('rev_zone_treeview')
    parent = xml.get_widget ('rev_master_dialog').get_data ('zone')
    run_rev_zone_address_dialog (dialog, tree_view, parent, TRUE)

def on_rev_zone_delete_button_clicked (button):
    tree_view = xml.get_widget ('rev_zone_treeview')
    result = tree_view.get_selection().get_selected ()
    if result != None:
        (model, iter) = result
        path = model.get_path (iter)
        rev = model.get_value (iter, COLUMN_DATA)
        if verify_delete(_("reverse address '%s'") % rev[1]) == gtk.RESPONSE_YES:
            model.remove (iter)
            try:
                iter = model.get_iter (path)
            except:
                pass
            if iter == None:
                path = (0)
            tree_view.get_selection().select_path (path)
            on_rev_zone_changed(0)

def on_rev_master_ns_add_button_clicked (button):
    tree_view = xml.get_widget ('rev_master_ns_treeview')
    selected = tree_view.get_selection().get_selected ()
    ns = FwdZone.NSProxy ()
    host_entry = xml.get_widget ('ns_host_entry')
    applies_to_entry = xml.get_widget ('ns_applies_to_entry')
    if ns.run_dialog (xml.get_widget ('rev_zone_reverse_label').get (), xml, FALSE, TRUE, xml.get_widget ('rev_master_dialog'), TRUE) == gtk.RESPONSE_OK:
        update.set(TRUE)
        model = tree_view.get_model ()
        iter = model.append ()
        model.set (iter,
                   COLUMN_PIXBUF, ns.get_pix (),
                   COLUMN_TEXT, ns.getHost(),
                   COLUMN_DATA, ns)
        tree_view.get_selection ().select_iter (iter)
        on_rev_zone_changed(0)

def on_rev_master_ns_edit_button_clicked (*args):
    fwdzone = xml.get_widget ('fwd_master_dialog').get_data ('fwdzone')
    tree_view = xml.get_widget ('rev_master_ns_treeview')
    selected = tree_view.get_selection().get_selected ()
    if selected != None:
        (model, iter) = selected
        ns = model.get_value (iter, COLUMN_DATA)
        host_entry = xml.get_widget ('ns_host_entry')
        applies_to_entry = xml.get_widget ('ns_applies_to_entry')
        if ns.run_dialog (xml.get_widget ('rev_zone_reverse_label').get (), xml, TRUE, TRUE, xml.get_widget ('fwd_master_dialog'), TRUE) == gtk.RESPONSE_OK:
            model.set (iter,
                       COLUMN_TEXT, ns.getHost())
            on_rev_zone_changed(0)


def on_rev_master_ns_delete_button_clicked (button):
    tree_view = xml.get_widget ('rev_master_ns_treeview')
    result = tree_view.get_selection().get_selected ()
    if result != None:
        (model, iter) = result
        path = model.get_path (iter)
        ns = model.get_value (iter, COLUMN_DATA)
        if verify_delete(_("nameserver '%s'") % ns.getHost()) == gtk.RESPONSE_YES:
            model.remove (iter)
            try:
                iter = model.get_iter (path)
            except:
                pass
            if iter == None:
                path = (0)
            tree_view.get_selection().select_path (path)
            on_rev_zone_changed(0)

def on_fwd_zone_set_button_clicked (button):
    fwdzone = xml.get_widget ('fwd_master_dialog').get_data ('fwdzone')
    dialog = xml.get_widget ('serial_dialog')
    dialog.set_transient_for (xml.get_widget ('fwd_master_dialog'))
    entry = xml.get_widget ('serial_entry')
    entry.grab_focus ()
    entry.set_text (str (fwdzone.serial))
    status = dialog.run ()
    dialog.hide ()

    if status != gtk.RESPONSE_OK: return status

    update.set(TRUE)

    serial = entry.get_text ()

    if serial == "": fwdzone.serial = 0
    else: fwdzone.serial = int (serial)

    fwdzone.dirty = TRUE
    fwdzone.zone.dirty = TRUE
    xml.get_widget ('fwd_zone_serial_entry').set_text (str (fwdzone.serial))
    return status

def on_rev_zone_set_button_clicked (button):
    zone = xml.get_widget ('rev_master_dialog').get_data ('zone')
    dialog = xml.get_widget ('serial_dialog')
    dialog.set_transient_for (xml.get_widget ('rev_master_dialog'))
    entry = xml.get_widget ('serial_entry')
    entry.grab_focus ()
    entry.set_text (str (zone.getSerial()))
    status = dialog.run ()
    dialog.hide ()

    if status != gtk.RESPONSE_OK: return status

    update.set(TRUE)

    serial = entry.get_text ()

    if serial == "": zone.serial = 0
    else: zone.serial = int (serial)

    zone.dirty = TRUE
    xml.get_widget ('rev_zone_serial_entry').set_text (str (zone.serial))
    return status

def on_rev_zone_soa_button_clicked (button):
    zone = xml.get_widget ('rev_master_dialog').get_data ('zone')
    soa = zone.getSOA()
    xml.get_widget ('soa_refresh_entry').set_text (str (soa.getRefresh()))
    xml.get_widget ('soa_retry_entry').set_text (str (soa.getRetry()))
    xml.get_widget ('soa_expire_entry').set_text (str (soa.getExpire()))
    xml.get_widget ('soa_minimum_entry').set_text (str (soa.getMinimum()))
    dialog = xml.get_widget ('soa_dialog')
    dialog.set_transient_for (xml.get_widget ('fwd_master_dialog'))

    status = dialog.run ()
    dialog.hide ()
    if status != gtk.RESPONSE_OK:
        return status

    def my_int (str):
        try:
            i = int (str)
            return i
        except:
            return 0
    soa.setRefresh(my_int (xml.get_widget ('soa_refresh_entry').get_text ()))
    soa.setRetry(my_int (xml.get_widget ('soa_retry_entry').get_text ()))
    soa.setExpire(my_int (xml.get_widget ('soa_expire_entry').get_text ()))
    soa.setMinimum(my_int (xml.get_widget ('soa_minimum_entry').get_text ()))
    return status

def on_fwd_zone_soa_button_clicked (button):
    fwdzone = xml.get_widget ('fwd_master_dialog').get_data ('fwdzone')
    fwdzone.hydrate_soa ()
    dialog = xml.get_widget ('soa_dialog')
    dialog.set_transient_for (xml.get_widget ('fwd_master_dialog'))
    status = dialog.run ()
    dialog.hide ()
    if status == gtk.RESPONSE_OK:
        fwdzone.dehydrate_soa ()
        fwdzone.set_dirty()
    return status

def on_fwd_zone_name_entry_changed (*args):
    fwdzone = xml.get_widget ('fwd_master_dialog').get_data ('fwdzone')
    fwdzone.set_name (xml.get_widget ('fwd_zone_name_entry').get_text ())

def on_fwd_zone_treeview_select_row (selection):
    result = selection.get_selected ()
    if result == None:
        xml.get_widget ('fwd_zone_delete_button').set_sensitive (FALSE)
        xml.get_widget ('fwd_zone_edit_button').set_sensitive (FALSE)
    else:
        xml.get_widget ('fwd_zone_delete_button').set_sensitive (TRUE)
        xml.get_widget ('fwd_zone_edit_button').set_sensitive (TRUE)

def on_rr_toggled (toggle):
    label1 = xml.get_widget ('rr_label1')
    label2 = xml.get_widget ('rr_label2')

    if xml.get_widget ('rr_address_rbutton').get_active ():
        label1.set_text (_("Host or Domain Name:"))
        label2.set_text (_("Served By:"))
    elif xml.get_widget ('rr_address_rbutton').get_active ():
        label1.set_text (_("Alias:"))
        label2.set_text (_("Host Name:"))
    else:
        label1.set_text (_("Host Name:"))
        label2.set_text (_("Resolves To:"))

def on_rr_type_menu_selection_done (menu, *args):
    i = menu.get_children().index(menu.get_active())

    xml.get_widget ('rr_type_notebook').set_current_page (i)

def add_fwd_zone (parent,fwdzone):
    global    fwd_zone_first_time
    dialog = xml.get_widget ('rr_type_dialog')
    dialog.set_transient_for (parent)

    notebook = xml.get_widget ('rr_type_notebook')
    add_reverse_check=xml.get_widget ('rr_add_reverse_checkbutton')

    if fwd_zone_first_time:
        notebook.set_current_page (0)
        add_reverse_check.set_active(gtk.TRUE)
        fwd_zone_first_time=gtk.FALSE

    xml.get_widget ('rr_host_label').set_text ("." + fwdzone.name)
    xml.get_widget ('rr_alias_label').set_text ("." + fwdzone.name)
    xml.get_widget ('rr_nameserver_label').set_text ("." + fwdzone.name)
    xml.get_widget ('rr_host_host_entry').set_text ('')
    prev_add=xml.get_widget ('rr_host_address_entry').get_text ()
    xml.get_widget ('rr_host_address_entry').set_text (get_subnet(prev_add))
    xml.get_widget ('rr_alias_alias_entry').set_text ('')
    xml.get_widget ('rr_alias_host_entry').set_text ('')
    xml.get_widget ('rr_nameserver_host_entry').set_text ('')
    xml.get_widget ('rr_nameserver_handled_entry').set_text ('')
    rev_tree_view=xml.get_widget ('rr_add_reverse_treeview')
    rev_model = rev_tree_view.get_model()
    sel_path = (0,)
    result = rev_tree_view.get_selection().get_selected ()
    if result != None:
        (model, iter) = result
	if iter != None:
            sel_path = model.get_path (iter)
    rev_model.clear ()

    zlist = cfg.getMReverseZoneList()
    if zlist:
        num = zlist.getNumMReverseZone()
        for i in xrange(0, num):
            zone = zlist.getMReverseZone(i)
            iter = rev_model.append()
            rev_model.set (iter,
                       COLUMN_PIXBUF, image_reverse,
                       COLUMN_TEXT, zone.getName(),
                       COLUMN_DATA, zone)
        rev_tree_view.get_selection().select_path (sel_path)
            
    while 1:
        status = dialog.run ()
        if status != gtk.RESPONSE_OK:
            dialog.hide ()
            return status
        tree_view = xml.get_widget ('fwd_zone_treeview')
        i = notebook.get_current_page()
        result = tree_view.get_selection().get_selected ()
        if result != None:
            (model, iter) = result
        else:
            model = tree_view.get_model ()
            iter = None

        update.set(TRUE)
        try:
            if i == 0:
                ag = dnsdata.A()
                zone = FwdZone.AProxy ()
                broken_widget = xml.get_widget ('rr_host_host_entry')
                zone.host = broken_widget.get_text ()
                ag.testHost(zone.host)
                broken_widget = xml.get_widget ('rr_host_address_entry')
                zone.ip = broken_widget.get_text ()
                ag.testIp(zone.ip)
                fwdzone.a.append(zone)
                if add_reverse_check.get_active():
                    result = rev_tree_view.get_selection().get_selected ()
                    if result != None:
                        (rev_model, rev_iter) = result
                        if rev_iter != None:
                            rev_zone = rev_model.get_value (rev_iter, COLUMN_DATA)
                            PTRlist = rev_zone.getPTRList ()
                            ptr = PTRlist.addPTR ()
                            ptr.setIp (last_octet (zone.ip))
                            ptr.setHost (add_dot(zone.host))
                            rev_zone.this_dirty=TRUE
                            rev_zone.incr_soa()
                            bindconf_model= xml.get_widget ('bindconf_treeview').get_model()

                            def set_foreach (model, path, iter, data):
                                val = model.get_value (iter, COLUMN_DATA)
                                if isinstance (val, dnsdata.MReverseZone):
                                    if val.getName() == data:
                                        loadReverseZone(model,iter,rev_zone)
                                        return TRUE
                                return FALSE

                            bindconf_model.foreach (set_foreach, rev_zone.getName())


            elif i == 1:
                cg = dnsdata.CNAME()
                zone = FwdZone.CNAMEProxy ()
                broken_widget = xml.get_widget ('rr_alias_alias_entry')
                zone.alias = broken_widget.get_text ()
                cg.testAlias(zone.alias)
                broken_widget = xml.get_widget ('rr_alias_host_entry')
                zone.host = broken_widget.get_text ()
                cg.testHost(zone.host)
                #FIXE: check this value
                fwdzone.cname.append(zone)
            elif i == 2:
                nsg = dnsdata.NS()
                zone = FwdZone.NSProxy ()
                broken_widget = xml.get_widget ('rr_nameserver_host_entry')
                zone.host = broken_widget.get_text ()
                nsg.testHost(zone.host)
                broken_widget = xml.get_widget ('rr_nameserver_handled_entry')
                zone.applies_to = broken_widget.get_text ()
                nsg.testAppliesTo(zone.applies_to)
                #FIXME: check this value
                fwdzone.ns.append(zone)
        except TestError, message:
            generic_error_dialog (message.args, dialog, broken_widget=broken_widget)
            continue
        break


    if iter == None:
        iter = model.append ()
    else:
        iter = model.insert_after (iter)

    model.set (iter,
               COLUMN_PIXBUF, zone.get_pix (),
               COLUMN_TEXT, zone.get_str(),
               COLUMN_TEXT2, '',
               COLUMN_DATA, zone)

    tree_view.get_selection().select_iter (iter)
    fwdzone.dirty = TRUE
    dialog.hide ()
    return status


def on_fwd_zone_add_button_clicked (button):
    fwdzone = xml.get_widget ('fwd_master_dialog').get_data ('fwdzone')
    add_fwd_zone (xml.get_widget ('fwd_master_dialog'),fwdzone)


def on_fwd_zone_edit_button_clicked (*args):
    fwdzone = xml.get_widget ('fwd_master_dialog').get_data ('fwdzone')
    tree_view = xml.get_widget ('fwd_zone_treeview')
    (model, iter) = tree_view.get_selection().get_selected ()
    zone = model.get_value (iter, COLUMN_DATA)
    if zone.run_edit_dialog (fwdzone, xml,xml.get_widget ('fwd_master_dialog')) == gtk.RESPONSE_OK:
        update.set(TRUE)
        model.set (iter,
                   COLUMN_TEXT, '',
                   COLUMN_TEXT, zone.get_str(),
                   )

def on_fwd_zone_delete_button_clicked (button):
    fwdzone = xml.get_widget ('fwd_master_dialog').get_data ('fwdzone')
    tree_view = xml.get_widget ('fwd_zone_treeview')
    (model, iter) = tree_view.get_selection().get_selected ()

    data = model.get_value (iter, COLUMN_DATA)
    parent = model.get_value (iter, COLUMN_PARENT)
    if verify_delete(data.get_str()) == gtk.RESPONSE_YES:
        if isinstance (data, FwdZone.AProxy):
            fwdzone.a.remove (data)
        elif isinstance (data, FwdZone.CNAMEProxy):
            fwdzone.cname.remove (data)
        elif isinstance (data, FwdZone.NSProxy):
            fwdzone.ns.remove (data)
        path = model.get_path (iter)
        model.remove (iter)
        tree_view.get_selection().select_path (path)
        update.set(TRUE)

def zone_changed(*args):
    fwdzone = xml.get_widget ('fwd_master_dialog').get_data ('fwdzone')
    if fwdzone:
        on_fwd_zone_changed(0)
    else:
        on_rev_zone_changed(0)

def on_fwd_zone_changed (*args):
    fwdzone = xml.get_widget ('fwd_master_dialog').get_data ('fwdzone')
    fwdzone.set_dirty ()

def on_mx_button_toggled (toggle):
    active = xml.get_widget ('mx_other_rbutton').get_active ()
    xml.get_widget ('mx_applies_to_entry').set_sensitive (active)

###
### Edit zones
###

def on_edit_forward_zone (zone):
    dialog = xml.get_widget ('fwd_master_dialog')
    dialog.set_transient_for (xml.get_widget ('bindconf'))
    fwdzone = FwdZone.FwdZone (zone, xml)
    dialog.set_data ('fwdzone', fwdzone)
    fwdzone.hydrate ()
    tree_view = xml.get_widget ('fwd_zone_treeview')
    tree_view.get_selection().select_path ((0,))
    while 1:
        status = dialog.run ()
        if status != gtk.RESPONSE_OK:
            dialog.hide ()
            dialog.set_data ('fwdzone', None)
            return status

        try:
            fwdzone.check ()
        except TestError, e:
            generic_error_dialog (e.args, dialog)
            continue
        break

    update.set(TRUE)
    dialog.set_data ('fwdzone', None)
    dialog.hide ()
    fwdzone.dehydrate ()
    return status

def getZoneSubnet(zone):
    match = re.match (r'(.*).in-addr.arpa', zone.getName ())
    if match:
        return reverse_ip_address (match.group (1))
    else:
        return ""

def on_edit_reverse_zone (zone):
    zone.dirty = FALSE
    zone.this_dirty = TRUE # bad hack
    dialog = xml.get_widget ('rev_master_dialog')
    dialog.set_transient_for (xml.get_widget ('bindconf'))
    dialog.set_data('zone', zone)
    zone_entry = xml.get_widget ('rev_zone_name_entry')
    contact_entry = xml.get_widget ('rev_zone_contact_entry')
    serial_entry = xml.get_widget ('rev_zone_serial_entry')
    file_entry = xml.get_widget ('rev_zone_file_entry')
    pns_entry = xml.get_widget('rev_zone_pns_entry')
    tree_view = xml.get_widget ('rev_zone_treeview')
    ns_tree_view = xml.get_widget ('rev_master_ns_treeview')
    xml.get_widget ('rev_zone_edit_button').set_sensitive (FALSE)
    xml.get_widget ('rev_zone_delete_button').set_sensitive (FALSE)
    xml.get_widget ('rev_master_ns_edit_button').set_sensitive (FALSE)
    xml.get_widget ('rev_master_ns_delete_button').set_sensitive (FALSE)
    xml.get_widget ('rev_master_ok_button').grab_default ()
    zone_entry.grab_focus ()
    text=getZoneSubnet(zone)
    zone_entry.set_text (text)
    file_entry.set_text (zone.getFile ())
    contact_entry.set_text (zone.getSOA().getContact ())
    serial_entry.set_text (str(zone.getSOA().getSerial ()))
    pns_entry.set_text (zone.getSOA().getPNS())

    model = tree_view.get_model()
    model.clear ()
    ptrlist = zone.getPTRList ()
    if ptrlist:
        for i in xrange (0, ptrlist.getNumPTR ()):
            ptr = ptrlist.getPTR (i)
            ip = str(ptr.getIp ())
            host = ptr.getHost ()
            if len (text) > 1 and text[-1] != '.':
                realip = text + '.' + ip
            else:
                realip = text + ip
            iter = model.append()
            model.set (iter,
                       COLUMN_TEXT, realip,
                       COLUMN_TEXT2, host,
                       COLUMN_PARENT, zone,
                       COLUMN_DATA, (ip,host,ptr))

    tree_view.get_selection().select_path ((0,))
    
    ns_model = ns_tree_view.get_model()
    ns_model.clear ()
    nslist = zone.getNSList ()
    if nslist:
        for i in xrange (0, nslist.getNumNS ()):
            ns = nslist.getNS (i)
            proxy = FwdZone.NSProxy (ns)
            iter = ns_model.append()
            ns_model.set (iter,COLUMN_TEXT, proxy.host,
                          COLUMN_DATA, proxy)
    ns_tree_view.get_selection().select_path ((0,))

    zone.this_dirty = FALSE # Bad hack, part deux
    while 1:
        status = dialog.run ()
        if status != gtk.RESPONSE_OK:
            dialog.hide ()
            return status

        text = zone_entry.get_text ()
        #FIXME4: fix wording
        if text == "" or not re.match (r'^\d+\.\d+\.\d+$', text):
            generic_error_dialog (_("You must have a valid IP domain."), dialog, broken_widget=zone_entry)
            continue

        # tests
        try:
            broken_widget = zone_entry
            text = reverse_ip_address (text)
            zone.testName (text + '.in-addr.arpa')
            
            broken_widget = pns_entry
            zone.getSOA().testPNS(pns_entry.get_text())

            broken_widget = file_entry
            zone.testFile(file_entry.get_text())
            
        except TestError, message:
            generic_error_dialog (message.args, dialog, broken_widget=broken_widget)
            continue


        if zone.this_dirty and not zone.dirty:
            serial = int(serial_entry.get_text()) + 1
            serial_entry.set_text(str(serial))
            
        zone.setFile(file_entry.get_text())
        zone.setContact(contact_entry.get_text())
        zone.setSerial(int(serial_entry.get_text()))
        zone.setName (text + '.in-addr.arpa')
        zone.getSOA().setPNS(pns_entry.get_text())

        # Delete the existing PTR list
        zone.delPTRList()

        if model.iter_n_children (None) > 0:
            ptrlist = zone.createPTRList ()
            def set_foreach (model, path, iter, data):
                val = model.get_value (iter, COLUMN_DATA)
                nptr = ptrlist.addPTR ()
                nptr.setIp (val[0])
                nptr.setHost (val[1])
                return FALSE

            model.foreach (set_foreach, None )

        zone.delNSList ()
        if ns_model.iter_n_children (None) > 0:
            nslist = zone.createNSList ()
            def set_foreach (model, path, iter, data):
                proxy = model.get_value (iter, COLUMN_DATA)
                ns = nslist.addNS ()
                ns.setAppliesTo ('@')
                ns.setHost (proxy.host)

            ns_model.foreach (set_foreach, None )
                
        # Overall test
        try:
            broken_widget = None
            zone.test()
        except TestError, message:
            generic_error_dialog (message.args, dialog, broken_widget=broken_widget)
            continue

        # all tests passed and all values are set
        break
    update.set(TRUE)
    dialog.hide ()
    return status

def on_slave_zone_masters_add_button_clicked(button):
    masters_widget = xml.get_widget ('slave_zone_masters_entry')
    masters_treeview = xml.get_widget ('slave_zone_masters_treeview')
    model=masters_treeview.get_model()
    ip=masters_widget.get_text() 
    if dnsdata.checkIpNum(ip):
        iter = model.append()
        model.set (iter,
                   COLUMN_TEXT, ip)
        masters_widget.set_text("")

def on_slave_zone_masters_delete_button_clicked(button):
    tree_view = xml.get_widget ('slave_zone_masters_treeview')
    result = tree_view.get_selection().get_selected()
    if result == None:
        return
    (model, iter) = result
    ip = model.get_value (iter, COLUMN_TEXT)
    if verify_delete(_("master '%s'") % ip) == gtk.RESPONSE_YES:
        model.remove (iter)

def on_edit_slave_zone (zone):
    dialog = xml.get_widget ('slave_zone_dialog')
    dialog.set_transient_for (xml.get_widget ('bindconf'))
    name_widget = xml.get_widget ('slave_zone_name_entry')
    masters_widget = xml.get_widget ('slave_zone_masters_entry')
    masters_treeview = xml.get_widget ('slave_zone_masters_treeview')
    model=masters_treeview.get_model()
    model.clear()
    
    file_widget = xml.get_widget ('slave_zone_file_entry')

    masters = zone.getMasters ()
    if masters:
        for i in xrange (0,masters.getNumIp ()):
            iter = model.append()
            model.set (iter,
                       COLUMN_TEXT, masters.getIp (i))

    name_widget.set_text (zone.getName ())
    file_widget.set_text (zone.getFile ())

    while 1:
        status = dialog.run ()
        dialog.hide ()
        if status != gtk.RESPONSE_OK:
            return status

        name_str = name_widget.get_text ()
        masters_list=[]
        def foreach_func (model, path, iter, text):
            ip = model.get_value (iter, COLUMN_TEXT)
            masters_list.append(ip)
            return FALSE
        
        model.foreach (foreach_func, "")
        file_str = file_widget.get_text ()

        try:
            broken_widget = name_widget
            zone.testName (name_str)
            broken_widget = file_str
            zone.testFile (file_str)            
            broken_widget = masters_widget
            mg = dnsdata.Masters()
            for ip in masters_list:
                mg.testIp (ip)            
        except TestError, message:
            generic_error_dialog (message.args, dialog, broken_widget=broken_widget)
            continue
            

        zone.setName (name_str)
        zone.setFile (file_str)
        zone.delMasters ()
        masters = zone.createMasters ()
        for ip in masters_list:
            masters.setIp (masters.addIp (), ip)
            
        try:
            zone.test()
        except TestError, message:
            generic_error_dialog (message.args, dialog)
            continue
            
        break
    update.set(TRUE)
    return status
    
def on_zone_type_toggled (button):
    notebook = xml.get_widget ('zone_type_notebook')
    if xml.get_widget ('fwd_zone_rbutton').get_active ():
        notebook.set_current_page (0)
    elif xml.get_widget ('rev_zone_rbutton').get_active ():
        notebook.set_current_page (1)
    else:
        notebook.set_current_page (2)
    xml.get_widget ('zone_type_entry').set_text ("")

def on_bindconf_add_button_clicked (button):
    tree_view = xml.get_widget ('bindconf_treeview')
    dialog = xml.get_widget ('zone_type_dialog')
    dialog.set_transient_for (xml.get_widget ('bindconf'))
    # bit of a hack, but we do this to avoid setting the size
    # on the widget
    xml.get_widget ('fwd_zone_rbutton').set_active (TRUE)
    xml.get_widget ('rev_zone_rbutton').set_active (TRUE)
    xml.get_widget ('slave_zone_rbutton').set_active (TRUE)
    xml.get_widget ('fwd_zone_rbutton').set_active (TRUE)
    xml.get_widget ('zone_type_entry').grab_focus ()
    result = tree_view.get_selection().get_selected ()
    if result == None:
        model = tree_view.get_model ()
        iter = None
    else:
        (model, iter) = result

    while 1:
        status = dialog.run ()

        if status != gtk.RESPONSE_OK:
            dialog.hide ()
            return
        name = xml.get_widget ('zone_type_entry').get_text ()

        if xml.get_widget ('fwd_zone_rbutton').get_active ():
            file = name + ".zone"

            try:
                fwz = dnsdata.MForwardZone ()
                brw = xml.get_widget ('zone_type_entry')
                fwz.testName(name)
                fwz.testFile(file)
            except TestError, e:
                generic_error_dialog (e.args, dialog, broken_widget=brw)
                continue
            
            zone = cfg.getMForwardZoneList ().addMForwardZone ()
            zone.setName (name)
            zone.setFile (file)

            iter = model.append(None)
            model.set (iter,
                       COLUMN_PIXBUF, image_domain,
                       COLUMN_TEXT, name,
                       COLUMN_DATA, zone)
        elif xml.get_widget ('rev_zone_rbutton').get_active ():
            name = reverse_ip_address (name) + ".in-addr.arpa"
            file = name + ".zone"
            try:
                rwz = dnsdata.MReverseZone ()
                brw = xml.get_widget ('zone_type_entry')
                rwz.testName(name)
                rwz.testFile(file)
            except TestError, e:
                generic_error_dialog (e.args, dialog, broken_widget=brw)
                continue
            
            zone = cfg.getMReverseZoneList ().addMReverseZone ()
            zone.setName (name)
            zone.setFile (file)
            iter = model.append(None)
            model.set (iter,
                       COLUMN_PIXBUF, image_reverse,
                       COLUMN_TEXT, name,
                       COLUMN_DATA, zone)
        else:
            file = name + ".zone"

            try:
                sz = dnsdata.SlaveZone ()
                brw = xml.get_widget ('zone_type_entry')
                sz.testName(name)
                sz.testFile(file)
            except TestError, e:
                generic_error_dialog (e.args, dialog, broken_widget=brw)
                continue
            
            zone = cfg.getSlaveZoneList ().addSlaveZone ()
            zone.setName (name)
            zone.setFile (name + ".zone")
            iter = model.append(None)
            model.set (iter,
                       COLUMN_PIXBUF, image_slave,
                       COLUMN_TEXT, name,
                       COLUMN_DATA, zone)
        break
    dialog.hide ()
    tree_view.get_selection ().select_iter (iter)
    if on_bindconf_edit_button_clicked() != gtk.RESPONSE_OK:
        return deleteCurrentRecord()

def on_bindconf_add_record_button_clicked (button):
    status = gtk.RESPONSE_CANCEL
    tree_view = xml.get_widget ('bindconf_treeview')
    result = tree_view.get_selection().get_selected()
    if result == None:
        return status
    (model, iter) = result
    zone = model.get_value (iter, COLUMN_DATA)
    try:
        parentZone = model.get_value (iter, COLUMN_PARENT)
        if (parentZone != None):
            zone=parentZone
            parent = model.iter_parent(iter)
        else:
            parent=iter
            
    except:
        pass
    if isinstance (zone, dnsdata.MForwardZone):
        fwdzone = FwdZone.FwdZone (zone, xml)
        dialog = xml.get_widget ('fwd_master_dialog')
        dialog.set_data ('fwdzone', fwdzone)
        fwdzone.hydrate ()
        status=add_fwd_zone (xml.get_widget ('bindconf'),fwdzone)
        if status != gtk.RESPONSE_OK:
            return status
        try:
            fwdzone.check ()
            fwdzone.dehydrate ()
        except TestError, e:
            generic_error_dialog (e.args, dialog)
        loadForwardZone(model,parent,zone)
        path=model.get_path (parent)
        tree_view.expand_row(path,0)
        tree_view.get_selection().select_path (path)
        
    elif isinstance (zone, dnsdata.MReverseZone):
        dialog = xml.get_widget ('rev_master_address_dialog')
        dialog.set_title (_("New Reverse Zone Pointer"))
        dialog.set_transient_for (xml.get_widget ('bindconf'))
        status=add_rev_zone_address_dialog (dialog,zone)
        if status != gtk.RESPONSE_OK:
            return status
        loadReverseZone(model,parent,zone)
        path=model.get_path (parent)
        tree_view.expand_row(path,0)
        tree_view.get_selection().select_path (path)

    else: #Unrecognized zone.
	print "unrecognized",type(zone),dir(zone)
        return status

    zone.incr_soa()

def on_bindconf_edit_button_clicked (*args):
    status = gtk.RESPONSE_CANCEL
    tree_view = xml.get_widget ('bindconf_treeview')
    result = tree_view.get_selection().get_selected()
    if result == None:
        return status
    
    (model, iter) = result
    zone = model.get_value (iter, COLUMN_DATA)
    if isinstance (zone, dnsdata.MForwardZone):
        status=on_edit_forward_zone (zone)
        if status != gtk.RESPONSE_OK:
            return status
        pix = image_domain
        loadForwardZone(model,iter,zone)
        tree_view.expand_row(model.get_path (iter),0)
    elif isinstance (zone, dnsdata.MReverseZone):
        status=on_edit_reverse_zone (zone)
        if status != gtk.RESPONSE_OK:
            return status
        loadReverseZone(model,iter,zone)
        tree_view.expand_row(model.get_path (iter),0)
        pix = image_reverse
    elif isinstance (zone, dnsdata.SlaveZone):
        status=on_edit_slave_zone (zone)
        if status != gtk.RESPONSE_OK:
            return status
        pix = image_slave
    elif isinstance (zone, dnsdata.A):
        parent = model.get_value (iter, COLUMN_PARENT)
        if (parent != None):
            fwdzone = FwdZone.FwdZone (parent, xml)
            proxy = FwdZone.AProxy (zone)
	    status = proxy.run_edit_dialog (fwdzone, xml,xml.get_widget ('bindconf'))
            
            if status != gtk.RESPONSE_OK:
                return status

            parent.delMXList ()
            if len (fwdzone.mx) > 0:
                mxlist = parent.createMXList ()
                for mx in fwdzone.mx:
                    mxg = mxlist.addMX ()
                    mxg.setHost (mx.getHost())
                    mxg.setAppliesTo (mx.applies_to)
                    mxg.setPriority (mx.priority)

	    zone.setIp(proxy.ip)
	    zone.setHost(proxy.host)
            model.set (iter,
                       COLUMN_PIXBUF, proxy.get_pix (),
                       COLUMN_TEXT, proxy.get_str(),
                       COLUMN_TEXT2, '',
                       COLUMN_PARENT, parent,
                       COLUMN_DATA, zone
                       )
            update.set(TRUE)
            parent.getSOA().setSerial(parent.getSOA().getSerial()+1)
            
        return status
    elif isinstance (zone, dnsdata.CNAME):
        parent = model.get_value (iter, COLUMN_PARENT)
        if (parent != None):
            fwdzone = FwdZone.FwdZone (parent, xml)
            for proxy in fwdzone.cname:
                if proxy.alias != zone.getAlias():
                    continue
                if proxy.host != zone.getHost():
                    continue
            status = proxy.run_edit_dialog (fwdzone, xml,xml.get_widget ('bindconf'))
            if status == gtk.RESPONSE_OK:
                zone.setAlias(proxy.alias)
                zone.setHost(proxy.host)
                model.set (iter,
                           COLUMN_PIXBUF, proxy.get_pix (),
                           COLUMN_TEXT, proxy.get_str(),
                           COLUMN_TEXT2, '',
                           COLUMN_DATA, zone,
                           COLUMN_PARENT, parent)
                update.set(TRUE)
                parent.getSOA().setSerial(parent.getSOA().getSerial()+1)
        return status
    elif isinstance (zone, dnsdata.NS):
        parent = model.get_value (iter, COLUMN_PARENT)
        if (parent != None):
            fwdzone = FwdZone.FwdZone (parent, xml)
            proxy = FwdZone.NSProxy (zone)
            status = proxy.run_edit_dialog (fwdzone, xml,xml.get_widget ('bindconf'))
            if status == gtk.RESPONSE_OK:
                zone.setHost(proxy.host)
                zone.setAppliesTo(proxy.applies_to)
                model.set (iter,
                           COLUMN_PIXBUF, proxy.get_pix (),
                           COLUMN_TEXT, proxy.get_str(),
                           COLUMN_TEXT2, '',
                           COLUMN_DATA, zone,
                           COLUMN_PARENT, parent)
                update.set(TRUE)
                parent.getSOA().setSerial(parent.getSOA().getSerial()+1)
        return status
    elif isinstance (zone, tuple):
        parent = model.get_value (iter, COLUMN_PARENT)
        dialog = xml.get_widget ('rev_master_address_dialog')
        dialog.set_title (_("Edit Reverse Zone Pointer"))
	master=xml.get_widget ('rev_master_dialog')
	ptr=zone[2]
	master.set_data('zone', ptr)
	dialog.set_transient_for (xml.get_widget ('bindconf'))
        xml.get_widget ('rev_zone_name_entry').set_text (getZoneSubnet(parent))
        tree_view = xml.get_widget ('bindconf_treeview')
        status = run_rev_zone_address_dialog (dialog, tree_view,parent, TRUE)
        if status == gtk.RESPONSE_OK:
            parent.getSOA().setSerial(parent.getSOA().getSerial()+1)
        return status
    else: #Unrecognized zone.
        print "edit unrecognized",type(zone),dir(zone)
        return status

    name = zone.getName ()
    model.set (iter,
               COLUMN_PIXBUF, pix,
               COLUMN_TEXT, name)
    return status

def deleteCurrentRecord():
    tree_view = xml.get_widget ('bindconf_treeview')
    result = tree_view.get_selection().get_selected()
    if result == None:
        return
    (model, iter) = result
    data = model.get_value (iter, COLUMN_DATA)
    if isinstance (data, tuple):
        if verify_delete(data[2].get_str()) == gtk.RESPONSE_NO:
            return
        data[2].unlink()
    else:
        if verify_delete(data.get_str()) == gtk.RESPONSE_NO:
            return
        data.unlink ()
    
    zone = model.get_value (iter, COLUMN_PARENT)
    if zone != None:
        zone.getSOA().setSerial(zone.getSOA().getSerial()+1)

    path = model.get_path (iter)
    model.remove (iter)
    tree_view.get_selection ().select_path (path)
    result = tree_view.get_selection().get_selected()
    if result == None or result[1] == None:
        tree_view.get_selection().select_path ((0,))

def on_bindconf_delete_button_clicked (button):
    deleteCurrentRecord()
    update.set(TRUE)
    
def loadReverseZone(model,parent,zone):
    name = zone.getName ()
    model.set (parent,
               COLUMN_PIXBUF, image_reverse,
               COLUMN_TEXT, name,
               COLUMN_TEXT2, "",
               COLUMN_DATA, zone)
            
    total=model.iter_n_children(parent)
    for i in xrange(0,total):
        child = model.iter_nth_child(parent,total-i-1 )
        model.remove(child)

    text=getZoneSubnet(zone)
    ptrlist = zone.getPTRList ()
    if ptrlist:
        for i in xrange (0, ptrlist.getNumPTR ()):
            ptr = ptrlist.getPTR (i)
            ip = str(ptr.getIp ())
            host = ptr.getHost ()
            iter = model.append (parent)
            if len (text) > 1 and text[-1] != '.':
                realip = text + '.' + ip
            else:
                realip = text + ip
            model.set (iter,
                       COLUMN_PIXBUF, image_reverse,
                       COLUMN_TEXT, realip,
                       COLUMN_TEXT2, host,
	               COLUMN_DATA, (ip,host,ptr),
                       COLUMN_PARENT, zone)
            
def loadForwardZone(model,parent,zone):
    name = zone.getName()
    model.set (parent,
               COLUMN_PIXBUF, image_domain,
               COLUMN_TEXT, name,
               COLUMN_TEXT2, "",
               COLUMN_DATA, zone)
    total=model.iter_n_children(parent)
    for i in xrange(0,total):
        child=model.iter_nth_child(parent,total-i-1 )
        model.remove(child)
    nslist = zone.getNSList ()
    if nslist:
        for i in xrange (0, nslist.getNumNS ()):
            ns = nslist.getNS (i)
            proxy = FwdZone.NSProxy (ns)
            if proxy.applies_to == '@':
                continue
            iter = model.append (parent)
            model.set (iter,
                       COLUMN_PIXBUF, proxy.get_pix (),
                       COLUMN_TEXT, proxy.get_str(),
                       COLUMN_TEXT2, '',
                       COLUMN_DATA, ns,
                       COLUMN_PARENT, zone)

    alist = zone.getAList ()
    if alist:
        for i in xrange (0, alist.getNumA ()):
            a = alist.getA (i)
            proxy = FwdZone.AProxy (a)
            if proxy.host == '@':
                continue
            iter = model.append (parent)
            model.set (iter,
                       COLUMN_PIXBUF, FwdZone.image_a,
                       COLUMN_TEXT, proxy.get_str(),
                       COLUMN_TEXT2, '',
                       COLUMN_DATA, a,
                       COLUMN_PARENT, zone)
                    
    cnamelist = zone.getCNAMEList ()
    if cnamelist:
        for i in xrange (0, cnamelist.getNumCNAME ()):
            cname = cnamelist.getCNAME (i)
            proxy = FwdZone.CNAMEProxy (cname)
            if proxy.host == '@':
                continue
            iter = model.append (parent)
            model.set (iter,
                       COLUMN_PIXBUF, proxy.get_pix (),
                       COLUMN_TEXT, proxy.get_str(),
                       COLUMN_TEXT2, '',
                       COLUMN_DATA, cname,
                       COLUMN_PARENT, zone)

def setup_main_tree ():
    tree_view = xml.get_widget ('bindconf_treeview')
    model = MyTreeModel()
    tree_view.set_model (model)
    column = gtk.TreeViewColumn (None, gtk.CellRendererPixbuf(), pixbuf=COLUMN_PIXBUF)
    tree_view.append_column (column)
    column = gtk.TreeViewColumn (None, gtk.CellRendererText(), text=COLUMN_TEXT)
    tree_view.append_column (column)
    column = gtk.TreeViewColumn (None, gtk.CellRendererText(), text=COLUMN_TEXT2)
    tree_view.append_column (column)

    tree_view.get_selection().connect ("changed",
                                       on_generic_tree_view_selection_changed,
                                       xml.get_widget ('bindconf_edit_button'), xml.get_widget ('bindconf_delete_button'),xml.get_widget ('bindconf_add_record_button'),xml.get_widget('add_record_menu'))
    tree_view.connect ("row_activated",
                       on_generic_tree_view_row_activated, on_bindconf_edit_button_clicked)

    zlist = cfg.getSlaveZoneList()
    if zlist:
        num = zlist.getNumSlaveZone()
        for i in xrange(0, num):
            zone = zlist.getSlaveZone(i)
            name = zone.getName ()
            iter = model.append (None)
            model.set (iter,
                       COLUMN_PIXBUF, image_slave,
                       COLUMN_TEXT, name,
                       COLUMN_TEXT2, "",
                       COLUMN_DATA, zone)

    zlist = cfg.getMForwardZoneList()
    if zlist:
        num = zlist.getNumMForwardZone()
        for i in xrange(0, num):
            zone = zlist.getMForwardZone(i)
            parent = model.append (None)
            loadForwardZone(model,parent,zone)

    zlist = cfg.getMReverseZoneList()
    if zlist:
        num = zlist.getNumMReverseZone()
        for i in xrange(0, num):
            zone = zlist.getMReverseZone(i)
            parent = model.append (None)
            loadReverseZone(model,parent,zone)
            
    tree_view.get_selection().select_path ((0,))

def setup_a_treeview():
    tree_view = xml.get_widget ('a_treeview')
    model = gtk.ListStore (gtk.gdk.Pixbuf, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT,gobject.TYPE_STRING,gobject.TYPE_STRING)
    tree_view.set_model (model)
    column = gtk.TreeViewColumn (_("Mail Exchanger"), gtk.CellRendererText (), text=FwdZone.COLUMN_MAIL_XCHANGE)
    column.set_sizing (gtk.TREE_VIEW_COLUMN_AUTOSIZE)
    tree_view.append_column (column)

    column = gtk.TreeViewColumn (_("Priority"), gtk.CellRendererText (), text=FwdZone.COLUMN_PRIORITY)
    column.set_sizing (gtk.TREE_VIEW_COLUMN_AUTOSIZE)
    tree_view.append_column (column)

    model.set_sort_column_id (FwdZone.COLUMN_PRIORITY, gtk.SORT_ASCENDING)
    tree_view.get_selection().connect ("changed",
                                       on_generic_tree_view_selection_changed,
                                       xml.get_widget ('a_edit_button'), xml.get_widget ('a_delete_button'),xml.get_widget ('bindconf_add_record_button'))
    tree_view.connect ("row_activated",
                       on_generic_tree_view_row_activated, on_alias_edit_button_click)

def setup_zone_mx_treeview():
    tree_view = xml.get_widget ('zone_mx_treeview')
    model = gtk.ListStore (gtk.gdk.Pixbuf, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT,gobject.TYPE_STRING,gobject.TYPE_STRING)

    tree_view.set_model (model)
    column = gtk.TreeViewColumn (_("Mail Exchanger"), gtk.CellRendererText (), text=FwdZone.COLUMN_MAIL_XCHANGE)
    column.set_sizing (gtk.TREE_VIEW_COLUMN_AUTOSIZE)
    tree_view.append_column (column)

    column = gtk.TreeViewColumn (_("Priority"), gtk.CellRendererText (), text=FwdZone.COLUMN_PRIORITY)
    column.set_sizing (gtk.TREE_VIEW_COLUMN_AUTOSIZE)
    tree_view.append_column (column)

    model.set_sort_column_id (FwdZone.COLUMN_PRIORITY, gtk.SORT_ASCENDING)
    tree_view.get_selection().connect ("changed",
                                       on_generic_tree_view_selection_changed,
                                       xml.get_widget ('zone_mx_edit_button'), xml.get_widget ('zone_mx_delete_button'),xml.get_widget ('bindconf_add_record_button'))
    tree_view.connect ("row_activated",
                       on_generic_tree_view_row_activated, on_zone_mx_edit_button_clicked)

def setup_slave_zone_treeview():
    tree_view = xml.get_widget ('slave_zone_masters_treeview')
    model = gtk.ListStore (gtk.gdk.Pixbuf, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)

    tree_view.set_model (model)
    column = gtk.TreeViewColumn (None, gtk.CellRendererText (), text=COLUMN_TEXT)
    column.set_sizing (gtk.TREE_VIEW_COLUMN_AUTOSIZE)
    tree_view.append_column (column)

    model.set_sort_column_id (FwdZone.COLUMN_TEXT, gtk.SORT_ASCENDING)


def setup_fwd_zone_treeview():
    tree_view = xml.get_widget ('fwd_zone_treeview')
    model = gtk.ListStore (gtk.gdk.Pixbuf, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT, gobject.TYPE_STRING, gobject.TYPE_STRING)
    tree_view.set_model (model)
    column = gtk.TreeViewColumn (None, gtk.CellRendererPixbuf (), pixbuf=COLUMN_PIXBUF)
    column.set_sizing (gtk.TREE_VIEW_COLUMN_FIXED)
    column.set_fixed_width (20)
    tree_view.append_column (column)

    column = gtk.TreeViewColumn (None, gtk.CellRendererText (), text=COLUMN_TEXT2)
    column.set_sizing (gtk.TREE_VIEW_COLUMN_AUTOSIZE)
    tree_view.append_column (column)

    column = gtk.TreeViewColumn (None, gtk.CellRendererText (), text=COLUMN_TEXT)
    column.set_sizing (gtk.TREE_VIEW_COLUMN_AUTOSIZE)
    tree_view.append_column (column)


    model.set_sort_column_id (COLUMN_TEXT, gtk.SORT_ASCENDING)
    tree_view.get_selection().connect ("changed",
                                       on_fwd_zone_treeview_select_row)
    tree_view.connect ("row_activated",
                       on_generic_tree_view_row_activated, on_fwd_zone_edit_button_clicked)
    xml.get_widget ('fwd_zone_delete_button').set_sensitive (FALSE)
    xml.get_widget ('fwd_zone_edit_button').set_sensitive (FALSE)

def setup_add_reverse_treeview():
    tree_view=xml.get_widget ('rr_add_reverse_treeview')
    model = gtk.ListStore (gtk.gdk.Pixbuf, gobject.TYPE_STRING,gobject.TYPE_PYOBJECT)
    tree_view.set_model (model)
    column = gtk.TreeViewColumn (None, gtk.CellRendererPixbuf(), pixbuf=COLUMN_PIXBUF)
    tree_view.append_column (column)
    column = gtk.TreeViewColumn (None, gtk.CellRendererText(), text=COLUMN_TEXT)
    tree_view.append_column (column)

def setup_ns_treeview():
    tree_view = xml.get_widget ('rev_master_ns_treeview')
    model = gtk.ListStore (gtk.gdk.Pixbuf, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)
    tree_view.set_model (model)
    column = gtk.TreeViewColumn (_("Nameserver"), gtk.CellRendererText (), text=COLUMN_TEXT)
    column.set_sizing (gtk.TREE_VIEW_COLUMN_AUTOSIZE)
    tree_view.append_column (column)
    model.set_sort_column_id (COLUMN_TEXT, gtk.SORT_ASCENDING)
    tree_view.get_selection().connect ("changed",
                                       on_generic_tree_view_selection_changed,
                                       xml.get_widget ('rev_master_ns_edit_button'), xml.get_widget ('rev_master_ns_delete_button'),xml.get_widget ('bindconf_add_record_button'))
    tree_view.connect ("row_activated",
                       on_generic_tree_view_row_activated, on_rev_master_ns_edit_button_clicked)

    
def setup_zone_ns_treeview():
    tree_view = xml.get_widget ('zone_ns_treeview')
    model = gtk.ListStore (gtk.gdk.Pixbuf, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT,gobject.TYPE_STRING,gobject.TYPE_STRING)
    tree_view.set_model (model)

    column = gtk.TreeViewColumn (_("Filler"), gtk.CellRendererText (), text=COLUMN_TEXT)
    column.set_sizing (gtk.TREE_VIEW_COLUMN_AUTOSIZE)
    tree_view.append_column (column)

    column = gtk.TreeViewColumn (_("Nameserver"), gtk.CellRendererText (), text=COLUMN_TEXT2)
    column.set_sizing (gtk.TREE_VIEW_COLUMN_AUTOSIZE)
    tree_view.append_column (column)

    model.set_sort_column_id (COLUMN_TEXT, gtk.SORT_ASCENDING)
    tree_view.get_selection().connect ("changed",
                                       on_generic_tree_view_selection_changed,
                                       xml.get_widget ('zone_ns_edit_button'), xml.get_widget ('zone_ns_delete_button'),xml.get_widget ('bindconf_add_record_button'))
    tree_view.connect ("row_activated",
                       on_generic_tree_view_row_activated, on_zone_ns_edit_button_clicked)

    
def setup_dialogs ():
    tree_view = xml.get_widget ('rev_zone_treeview')
    model = gtk.ListStore (gtk.gdk.Pixbuf, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT, gobject.TYPE_STRING, gobject.TYPE_STRING)
    tree_view.set_model (model)
    column = gtk.TreeViewColumn (_("Address"), gtk.CellRendererText (), text=COLUMN_TEXT)
    column.set_sizing (gtk.TREE_VIEW_COLUMN_AUTOSIZE)
    tree_view.append_column (column)
    column = gtk.TreeViewColumn (_("Host or Domain"), gtk.CellRendererText (), text=COLUMN_TEXT2)
    column.set_sizing (gtk.TREE_VIEW_COLUMN_AUTOSIZE)
    tree_view.append_column (column)
    model.set_sort_column_id (COLUMN_TEXT, gtk.SORT_ASCENDING)
    tree_view.get_selection().connect ("changed",
                                       on_generic_tree_view_selection_changed,
                                       xml.get_widget ('rev_zone_edit_button'), xml.get_widget ('rev_zone_delete_button'),xml.get_widget ('bindconf_add_record_button'))
    tree_view.connect ("row_activated",
                       on_generic_tree_view_row_activated, on_rev_zone_edit_button_clicked)


    setup_fwd_zone_treeview()

    setup_a_treeview()

    setup_zone_mx_treeview()

    setup_zone_ns_treeview()

    setup_ns_treeview()

    setup_add_reverse_treeview()

    setup_slave_zone_treeview()

def main ():
    xml.signal_autoconnect (
        {
        'on_bindconf_delete_event' : on_bindconf_delete_event,
        'on_new_activate' : on_new_activate,
        'on_properties_activate' : on_properties_activate,
        'on_delete_activate' : on_delete_activate,
        'on_add_record_activate' : on_add_record_activate,
        'on_exit_activate' : on_exit_activate,
        'on_apply_and_save_activate' : on_apply_and_save_activate,
        "on_manual_activate" : on_manual_activate,
        'on_about_activate' : on_about_activate,
        'on_bindconf_add_button_clicked' : on_bindconf_add_button_clicked,
        'on_bindconf_edit_button_clicked' : on_bindconf_edit_button_clicked,
        'on_bindconf_delete_button_clicked' : on_bindconf_delete_button_clicked,
        'on_bindconf_add_record_button_clicked' : on_bindconf_add_record_button_clicked,

        "on_fwd_zone_rbutton_toggled" : on_zone_type_toggled,
        "on_rev_zone_rbutton_toggled" : on_zone_type_toggled,
        "on_slave_zone_rbutton_toggled" : on_zone_type_toggled,

        #slave
        'on_slave_zone_masters_add_button_clicked' : on_slave_zone_masters_add_button_clicked,
        'on_slave_zone_masters_delete_button_clicked' : on_slave_zone_masters_delete_button_clicked,
        'on_slave_zone_masters_entry_insert_text' : (on_generic_entry_insert_text, r'^[0-9. ]+$'),
        'on_slave_zone_file_entry_insert_text' : (on_generic_entry_insert_text, r'^[^/ ]+$'),

        #rev
        'on_rev_zone_changed':on_rev_zone_changed,
        'on_rev_zone_name_entry_insert_text' : (on_generic_entry_insert_text, r'^[0-9.]+$'),
        'on_rev_zone_name_entry_changed' : on_rev_zone_name_entry_changed,
        'on_rev_zone_pns_changed' : on_rev_zone_pns_changed,
        'on_rev_zone_file_entry_insert_text' : (on_generic_entry_insert_text, r'^[^/ ]+$'),
        'on_rev_zone_soa_button_clicked':on_rev_zone_soa_button_clicked,
        'on_rev_zone_add_button_clicked' : on_rev_zone_add_button_clicked,
        'on_rev_zone_edit_button_clicked' : on_rev_zone_edit_button_clicked,
        'on_rev_zone_delete_button_clicked' : on_rev_zone_delete_button_clicked,

        'on_rev_master_ns_treeview_select_row' : (on_generic_treeview_select_row, xml.get_widget ('rev_master_ns_edit_button'), xml.get_widget ('rev_master_ns_delete_button')),
        'on_rev_master_ns_treeview_unselect_row' : (on_generic_treeview_unselect_row, xml.get_widget ('rev_master_ns_edit_button'), xml.get_widget ('rev_master_ns_delete_button')),
        'on_rev_master_ns_add_button_clicked' : on_rev_master_ns_add_button_clicked,
        'on_rev_master_ns_edit_button_clicked' : on_rev_master_ns_edit_button_clicked,
        'on_rev_master_ns_delete_button_clicked' : on_rev_master_ns_delete_button_clicked,
        'on_rev_zone_contact_entry_changed' : on_rev_zone_changed,
        'on_rev_zone_set_button_clicked' : on_rev_zone_set_button_clicked,

        #fwd
        'on_fwd_zone_set_button_clicked' : on_fwd_zone_set_button_clicked,
        'on_fwd_zone_soa_button_clicked' : on_fwd_zone_soa_button_clicked,
        'on_fwd_zone_name_entry_changed' : on_fwd_zone_name_entry_changed,
        'on_fwd_zone_file_entry_insert_text' : (on_generic_entry_insert_text, r'^[^/ ]+$'),
        'on_fwd_zone_file_entry_changed' : on_fwd_zone_changed,
        'on_fwd_zone_add_button_clicked' : on_fwd_zone_add_button_clicked,
        'on_fwd_zone_edit_button_clicked' : on_fwd_zone_edit_button_clicked,
        'on_fwd_zone_delete_button_clicked' : on_fwd_zone_delete_button_clicked,
        'on_fwd_zone_contact_entry_changed' : on_fwd_zone_changed,

        'on_soa_refresh_entry_changed' : zone_changed,
        'on_soa_retry_entry_changed' : zone_changed,
        'on_soa_expire_entry_changed' : zone_changed,
        'on_soa_minimum_entry_changed' : zone_changed,
        'on_serial_entry_insert_text' : (on_generic_entry_insert_text, r'^[0-9]+$'),
        'on_soa_refresh_entry_insert_text' : (on_generic_entry_insert_text, r'^[0-9]+$'),
        'on_soa_retry_entry_insert_text' : (on_generic_entry_insert_text, r'^[0-9]+$'),
        'on_soa_expire_entry_insert_text' : (on_generic_entry_insert_text, r'^[0-9]+$'),
        'on_soa_minimum_entry_insert_text' : (on_generic_entry_insert_text, r'^[0-9]+$'),

        'on_mx_priority_entry_insert_text' : (on_generic_entry_insert_text, r'^[0-9]+$'),
        'on_mx_button_toggled' : on_mx_button_toggled,
        'on_rr_toggled' : on_rr_toggled,

        'on_a_treeview_select_row' : (on_generic_treeview_select_row, xml.get_widget ('a_edit_button'), xml.get_widget ('a_delete_button')),
        'on_a_treeview_unselect_row' : (on_generic_treeview_unselect_row, xml.get_widget ('a_edit_button'), xml.get_widget ('a_delete_button')),
        'on_zone_ns_treeview_select_row' : (on_generic_treeview_select_row, xml.get_widget ('zone_ns_edit_button'), xml.get_widget ('zone_ns_delete_button')),
        'on_zone_ns_treeview_unselect_row' : (on_generic_treeview_unselect_row, xml.get_widget ('zone_ns_edit_button'), xml.get_widget ('zone_ns_delete_button')),
        'on_zone_ns_add_button_clicked' : on_zone_ns_add_button_clicked,
        'on_zone_ns_edit_button_clicked' : on_zone_ns_edit_button_clicked,
        'on_zone_ns_delete_button_clicked' : on_zone_ns_delete_button_clicked,
        'on_zone_mx_treeview_select_row' : (on_generic_treeview_select_row, xml.get_widget ('zone_mx_edit_button'), xml.get_widget ('zone_mx_delete_button')),
        'on_zone_mx_treeview_unselect_row' : (on_generic_treeview_unselect_row, xml.get_widget ('zone_mx_edit_button'), xml.get_widget ('zone_mx_delete_button')),
        'on_zone_mx_add_button_clicked' : on_zone_mx_add_button_clicked,
        'on_zone_mx_edit_button_clicked' : on_zone_mx_edit_button_clicked,
        'on_zone_mx_delete_button_clicked' : on_zone_mx_delete_button_clicked,

        'hostname_check' : (on_generic_entry_insert_text, hostname_pattern),
        'on_bindconf_treeview_expand_row' : on_bindconf_treeview_expand_row
        })
    setup_main_tree ()
    setup_dialogs ()
    xml.get_widget ('bindconf').set_title (FORMALNAME)
    xml.get_widget ('bindconf').show_all ()
    gtk.mainloop()

def duplicate_rev_address(zone,newhost,address):
    ptrlist = zone.getPTRList ()
    if ptrlist:
        for i in xrange (0, ptrlist.getNumPTR ()):
            ptr = ptrlist.getPTR (i)
            ip = str(ptr.getIp ())
            host = ptr.getHost ()
            if ip==address:
                return 1
            if host==newhost:
                return 2
    return 0
    
def add_rev_zone_address_dialog (dialog,zone):
    text=getZoneSubnet(zone)
    xml.get_widget ('rev_master_address_label').set_text (add_dot (text))
    spin = xml.get_widget ('rev_master_address_spin')
    entry = xml.get_widget ('rev_master_address_entry')

    spin.set_text ("")
    entry.set_text ("")
    ptr = None

    while 1:
        status = dialog.run ()
        if status != gtk.RESPONSE_OK:
            dialog.hide ()
            return status

        ip = spin.get_text ()
        host = entry.get_text ()
        if ip == "":
            generic_error_dialog (_("You must enter an octet."), dialog, broken_widget=spin)
            continue
        if host == "":
            generic_error_dialog (_("You must enter a hostname."), dialog, broken_widget=entry)
            continue

        try:
            host=add_dot(host)
            ptrg = dnsdata.PTR()
            brw = spin
            ptrg.testIp(ip)
            brw = entry
            ptrg.testHost(host)
        except TestError, e:
            generic_error_dialog (e.args, dialog, broken_widget=brw)
            continue
        

        if duplicate_rev_address(zone,add_dot (entry.get_text ()),ip)==1:
            generic_error_dialog (_("A reverse address record with that octet or hostname already exists"), dialog, broken_widget=spin)
            continue
        dialog.hide ()

        PTRlist = zone.getPTRList ()
        ptr = PTRlist.addPTR ()
        ptr.setIp (ip)
        ptr.setHost (host)
        zone.this_dirty=TRUE
        update.set(TRUE)
        return status

# make ctrl-C work
if __name__ == "__main__":
    signal.signal (signal.SIGINT, signal.SIG_DFL)
    main ()


