#!/usr/bin/python

## system-config-printer
## CUPS backend

## Copyright (C) 2001-2004 Red Hat, Inc.
## Copyright (C) 2002-2004 Tim Waugh <twaugh@redhat.com>

## This program 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.

## This program 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 this program; if not, write to the Free Software
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

printers_conf = "/etc/cups/printers.conf"
cupsd_conf = "/etc/cups/cupsd.conf"
cupsd_conf_backup = cupsd_conf + ".save"
ppd_dir = "/etc/cups/ppd/"
mime_types = "/etc/cups/mime.types"
mime_convs = "/etc/cups/mime.convs"
lpoptions = "/etc/cups/lpoptions"

new_suffix = ".new"

autogen = "# Lines below are automatically generated - DO NOT EDIT\n"

import glob
import os
import sys
import pwd, grp
import re
import signal

import rhpl.ethtool
import cups_import

lp_uid = pwd.getpwnam ("lp")[2]
sys_gid = grp.getgrnam ("sys")[2]

sys.path.append ("/usr/share/printconf/util")
from printconf_conf import *
from rhpl.translate import _, N_

# First job: find out which print spooler is active.

which = cups_import.which_spooler ()
debug_print ("Print spooler: %s" % which)
if which == "LPRng":
    debug_print ("Transfer control to printconf_backend.py")
    import printconf_backend
    sys.exit (0)

# We are using CUPS.

## Don't import queues here.  Instead only do it in the config tool.

# Determine if the CUPS configuration has been written by us.
# If not, we'll need to import it.
#if cups_import.import_needed ():
#    debug_print ("Import CUPS configuration")
#    import cups_import
#    init_queue_edit_or_die ()
#    foomatic_init_overview ()
#    cups_import.import_cups_queues ()
#    save_queues ()

rebuild = 0
import getopt
def help_message ():
    print """usage: printconf-backends [OPTIONS]

Options:
 --force-rebuild  Force the queues to be rebuilt
 --help           Display this usage message"""

try:
    options, args = getopt.getopt (sys.argv[1:], '',
                                   ['force-rebuild', 'help', 'test-smb'])
except getopt.error:
    help_message ()
    sys.exit (1)

def device_uri (queue):
    queue_type = queue["queue_type"].value
    queue_data = queue["queue_data"]
    if queue_type == "LOCAL":
        dev = queue_data["local_printer_device"].value
        if dev.find (':') != -1:
            # Already has the URI scheme.
            return dev
        if dev.startswith ("/dev/lp"):
            return "parallel:" + dev
        if dev.startswith ("/dev/tty"):
            return "serial:" + dev
        if (dev.startswith ("/dev/usb") or
            dev.startswith ("//")):
            return "usb:" + dev
        return "file:" + dev

    if queue_type == "IPP":
        ipp_server = queue_data["ipp_server"].value
        ipp_path = queue_data["ipp_path"].value
        return "ipp://%s%s" % (ipp_server, ipp_path)

    if queue_type == "LPD":
        lpd_server = queue_data["lpd_server"].value
        lpd_queue = queue_data["lpd_queue"].value
        reserve = ""
        if queue_data["lpd_strict_rfc1179"].value:
            reserve = "?reserve=yes"
        return "lpd://%s/%s%s" % (lpd_server, lpd_queue, reserve)

    if queue_type == "JETDIRECT":
        jetdirect_ip = queue_data["jetdirect_ip"].value
        jetdirect_port = queue_data["jetdirect_port"].value
        return "socket://%s:%s" % (jetdirect_ip, jetdirect_port)

    if queue_type == "SMB":
        smb_share = queue_data["smb_share"].value
        smb_ip = queue_data["smb_ip"].value
        smb_workgroup = queue_data["smb_workgroup"].value
        smb_user = queue_data["smb_user"].value
        smb_password = queue_data["smb_password"].value
        if smb_password:
            smb_password = ':' + smb_password

        if smb_workgroup:
            smb_workgroup = smb_workgroup + '/'

        smb_share = smb_share.replace ('\\', '/')
        smb_user = smb_user.replace ('\\', '/')
        if smb_user:
            smb_password += '@'

        if smb_share.startswith ("//"):
            smb_share = smb_share[2:]
        else:
            if smb_share[0] == "/":
                smb_share = smb_share[1:]

            smb_ip = smb_ip.replace ("/", "")
            smb_share = smb_ip + "/" + smb_share

        return "smb://%s%s%s%s" % (smb_user, smb_password,
                                   smb_workgroup, smb_share)

    if queue_type == "NCP":
        ncp_server = queue_data["ncp_server"].value
        ncp_queue = queue_data["ncp_queue"].value
        ncp_user = queue_data["ncp_user"].value
        ncp_password = queue_data["ncp_password"].value
        if ncp_user:
            ncp_password = ":" + ncp_password + "@"

        return "ncp://%s%s%s/%s" % (ncp_user, ncp_password,
                                    ncp_server, ncp_queue)

    debug_print ("Unknown queue type: %s" % queue_type)
    return "file:/dev/full"

def test_smb_uris ():
    class datum:
        def __init__ (self, value = ""):
            self.value = value

    fail = 0
    for test in [{'smb_share': datum ('//server/printer'),
                  'smb_ip': datum (''),
                  'smb_workgroup': datum (''),
                  'smb_user': datum (''),
                  'smb_password': datum (''),
                  'expected': 'smb://server/printer'},

                 {'smb_share': datum ('//server/printer'),
                  'smb_ip': datum (''),
                  'smb_workgroup': datum ('workgroup'),
                  'smb_user': datum (''),
                  'smb_password': datum (''),
                  'expected': 'smb://workgroup/server/printer'},

                 {'smb_share': datum ('//server/printer'),
                  'smb_ip': datum (''),
                  'smb_workgroup': datum (''),
                  'smb_user': datum ('user'),
                  'smb_password': datum (''),
                  'expected': 'smb://user@server/printer'},

                 {'smb_share': datum ('//server/printer'),
                  'smb_ip': datum (''),
                  'smb_workgroup': datum ('workgroup'),
                  'smb_user': datum ('user'),
                  'smb_password': datum (''),
                  'expected': 'smb://user@workgroup/server/printer'},

                 {'smb_share': datum ('//server/printer'),
                  'smb_ip': datum (''),
                  'smb_workgroup': datum (''),
                  'smb_user': datum ('user'),
                  'smb_password': datum ('password'),
                  'expected': 'smb://user:password@server/printer'},

                 {'smb_share': datum ('//server/printer'),
                  'smb_ip': datum (''),
                  'smb_workgroup': datum ('workgroup'),
                  'smb_user': datum ('user'),
                  'smb_password': datum ('password'),
                  'expected': 'smb://user:password@workgroup/server/printer'}]:

        queue = { 'queue_type': datum ('SMB'),
                  'queue_data': test }
        uri = device_uri (queue)
        if uri != test['expected']:
            print "Expected %s; got %s" % (test['expected'], uri)
            fail += 1
        else:
            print "OK: %s" % uri

    return fail

for each in options:
    if each[0] == '--force-rebuild':
        debug_print ("Rebuild forced on command line")
        rebuild = 1
        break

    if each[0] == '--help':
        help_message ()
        sys.exit (0)

    if each[0] == '--test-smb':
        sys.exit (test_smb_uris ())

if not checkNspMark (namespace = "printconf",
                     mark = "_PRINTCONF_BACKEND_"):
    debug_print ("Namespace dirty")
    rebuild = 1

if not rebuild:
    debug_print ("No rebuild needed")
    sys.exit (0)

def safely_create (filename, mode = None, uid = None, gid = None):
    if os.path.exists (filename):
        os.unlink (filename)

    flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
    if mode:
        fd = os.open (filename, flags, mode)
    else:
        fd = os.open (filename, flags)

    if uid and gid:
        os.chown (filename, uid, gid)

    file = os.fdopen (fd, "w")
    return file

def remove_printers_conf (queue, printers_conf_lines):
    finished = 0
    while not finished:
        found = 0
        line = None
        for tag in ['<Printer ', '<DefaultPrinter ']:
            try:
                line = printers_conf_lines.index (tag + queue + '>\n')
            except:
                pass

        if line:
            start_line = line
            try:
                rest = printers_conf_lines[start_line + 1:]
                end_line = start_line + 1 + rest.index ('</Printer>\n') + 1
            except:
                end_line = len (printers_conf_lines)

            del printers_conf_lines[start_line:end_line]
            found = 1

        finished = not found

    return printers_conf_lines

def add_printers_conf (queue, default_queue, printers_conf_lines):
    # Search for existing queue with that name.
    printers_conf_lines = remove_printers_conf (queue.name,
                                                printers_conf_lines)

    # Is this queue the default?
    if queue.name == default_queue:
        tag = '<DefaultPrinter '
    else:
        tag = '<Printer '

    conf = [ tag + queue.name + '>\n' ]

    conf.append (cups_import.marker_line)
    conf.append ('DeviceURI %s\n' % device_uri (queue))

    try:
        conf.append ('Location %s\n' % queue["queue_description"])
    except:
        pass

    try:
        jobsheets = queue["jobsheets"]
        start_banner = jobsheets["start"].value
        end_banner = jobsheets["end"].value
    except:
        (start_banner, end_banner) = ('none', 'none')

    conf.append ('State Idle\n')
    conf.append ('Accepting Yes\n')
    conf.append ('JobSheets %s %s\n' % (start_banner, end_banner))
    conf.append ('QuotaPeriod 0\n')
    conf.append ('PageLimit 0\n')
    conf.append ('KLimit 0\n')
    conf.append ('</Printer>\n')
    printers_conf_lines.extend (conf)
    return printers_conf_lines

def remove_cupsd_conf (location, cupsd_conf_lines):
    finished = 0
    while not finished:
        found = 0
        for i in range (len (cupsd_conf_lines)):
            if cupsd_conf_lines[i] == "<Location %s>\n" % location:
                for j in range (i + 1, len (cupsd_conf_lines)):
                    if cupsd_conf_lines[j].startswith ("</Location"):
                        j += 1
                        break

                del cupsd_conf_lines[i:j]
                found = 1
                break

        finished = not found

    return cupsd_conf_lines

def add_cupsd_conf (queue, cupsd_conf_lines):
    cupsd_conf_lines = remove_cupsd_conf ("/printers/" + queue.name,
                                          cupsd_conf_lines)
    conf = [ "<Location /printers/%s>\n" % queue.name ]
    conf.append ("Order Deny,Allow\n")
    conf.append ("Deny From All\n")
    conf.append ("Allow From 127.0.0.1\n")
    conf.append ("AuthType None\n")

    try:
        sharing = queue["sharing"]
        for each in sharing:
            allowed = each.value
            if allowed == "ALL":
                allowed = "All"

            netdev_re = re.compile ("^[a-z]+[0-9]+$")
            if netdev_re.match (allowed):
                allowed = "@IF(%s)" % allowed

            conf.append ("Allow from %s\n" % allowed)

            # Add this to the list of interfaces (for browsing, IPP)
            found = 0
            for each in interfaces:
                if each == allowed:
                    found = 1
                    break

            if not found:
                interfaces.append (allowed)
    except:
        pass

    conf.append ("</Location>\n")
    cupsd_conf_lines.extend (conf)
    return cupsd_conf_lines

def remove_cupsd_conf_globals (opts, cupsd_conf_lines):
    finished = 0
    while not finished:
        found = 0
        for i in range (len (cupsd_conf_lines)):
            if cupsd_conf_lines[i] == autogen:
                del cupsd_conf_lines[i]
                found = 1
            else:
                for each in opts:
                    if cupsd_conf_lines[i].startswith (each + " "):
                        del cupsd_conf_lines[i]
                        found = 1
                        break

            if found:
                break

        finished = not found

    return cupsd_conf_lines

def set_filter_options (queue):
    """Set the filter options."""

    try:
        opt = file (lpoptions).readlines ()
    except:
        opt = []

    try:
        options = queue["lpoptions"]
    except:
        # Get sensible options from printconf_conf
        options = conf.default_lpoptions

    str = "Dest %s" % queue.name
    for o in options.keys ():
        str += " %s=%s" % (o, options[o])

    str += "\n"

    found = 0
    for i in range (len (opt)):
        words = opt[i].split (' ')
        if len (words) > 0 and words[1] == queue.name:
            opt[i] = str
            found = 1
            break

    if not found:
        opt.append (str)

    f = safely_create (lpoptions + new_suffix, 0644)
    f.writelines (opt)
    f.close ()
    os.rename (lpoptions + new_suffix, lpoptions)

def set_page_margins (queue, ppd):
    """Adjust the PPD imageable area margins.
    queue: queue ADL
    ppd: array of lines from PPD file.

    Returns new array of PPD file lines."""

    try:
        margins = queue["margins"]
        left = margins["left"].value
        top = margins["top"].value
        right = margins["right"].value
        bottom = margins["bottom"].value
    except:
        margins = conf.default_margins
        left = margins["left"]
        top = margins["top"]
        right = margins["right"]
        bottom = margins["bottom"]

    size = None
    n = 0
    for i in range (len (ppd)):
        default = "*DefaultImageableArea: "
        if ppd[i].startswith (default):
            size = ppd[i][len (default):].strip ()
            n = i
            break

    if not size:
        # Shouldn't happen.
        return ppd

    for i in range (n, len (ppd)):
        if ppd[i].startswith ("*ImageableArea %s/" % size):
            try:
                border = ppd[i].split ('"')[1].split (" ")
                if border.find ('.') != -1:
                    border = border[:border.index ('.')]
            except:
                return ppd

            if int (border[0]):
                debug_print ("Page margins already set.")
                return ppd

            str = ppd[i].split ('"')[0] + '"'
            str += "%d %d %d %d" % (int (border[0]) + left,
                                    int (border[1]) + bottom,
                                    int (border[2]) - right,
                                    int (border[3]) - top) + '"\n'
            ppd[i] = str
            debug_print ("Set page margins: %s" % str.strip ())
            break

    return ppd

def create_ppd (queue):
    """Returns 1 if the queue is raw and 0 otherwise."""
    ppd = None

    options = {}
    filter_type = queue["filter_type"].value
    if (filter_type == drivers.foomatic.filter_type and
        queue["filter_data"]["mf_type"].value == drivers.foomatic.mf_type):
        filter_data = queue["filter_data"]
        printer = filter_data["printer_id"].value
        driver = filter_data["gs_driver"].value
        datafile_cmd = "/usr/bin/foomatic-ppdfile -d %s -p %s" \
                       % (driver, printer)
        ppd_pipe = os.popen (datafile_cmd)
        ppd = ppd_pipe.readlines ()
        if ppd_pipe.close ():
            print "Error generating PPD file"
            return 0

        foomatic_defaults = filter_data["foomatic_defaults"]
        for option_default in foomatic_defaults:
            name = option_default["name"].value
            value = option_default["default"].value
            options[name] = value
    elif filter_type == drivers.postscript.filter_type:
        postscript_cmd = "/bin/gzip -dc %s" \
                         % "/usr/share/cups/model/postscript.ppd.gz"
        ppd_pipe = os.popen (postscript_cmd)
        ppd = ppd_pipe.readlines ()
        if ppd_pipe.close ():
            print "Error generating PPD file"
            return 0

        try:
            page = filter_data["page_size"].value
            options["PageSize"] = page
        except:
            pass
    elif (filter_type == drivers.raw.filter_type or
          filter_type == drivers.text.filter_type):
        debug_print ("No PPD file needed (%s)" % filter_type)
	try:
            os.remove (ppd_dir + queue.name + ".ppd")
	except:
            pass

        if filter_type == drivers.raw.filter_type:
            return 1

        return 0
    else:
        print "Unknown filter type: %s" % filter_type
        return 0

    if not ppd:
        print "Couldn't generate PPD"
        return 0

    debug_print ("PPD generated.  Adjusting options.")

    try:
        page = options["PageSize"]
        options["PageRegion"] = page
        options["ImageableArea"] = page
        options["PaperDimension"] = page
    except:
        pass

    for option in options.keys ():
        search = "*Default%s:" % option
        found = 0
        for n in range (len (ppd)):
            if ppd[n].startswith (search):
                ppd[n] = "*Default%s: %s\n" % (option, options[option])
                found = 1
                break

        if not found:
            print "No %s option to change!" % option

    set_filter_options (queue)
    ppd = set_page_margins (queue, ppd)

    # Handle CJK encodings.
    try:
        filter_locale = queue["filter_data"]["filter_locale"].value
    except:
        filter_locale = "C"

    octet_stream_allowed = 0
    if filter_locale == "ja_JP" or filter_locale == "ko_KR" or filter_locale == "zh_CN" or filter_locale == "zh_TW":
        # Use mpage or h2ps or bg5ps to convert text to PS instead of the default texttops
        # filter, since mpage handles EUC-JP, JIS, and SJIS, and h2ps handles EUC-KR, and
	# bg5ps handles GB2312 and Big5.
        ppd.append ('*% CJK [This line causes text conversion to use the appropriate utilities]\n')
	global cjk_needed
        cjk_needed = 1
        octet_stream_allowed = 1

    filename = ppd_dir + queue.name + ".ppd"
    f = safely_create (filename + new_suffix, 0644)
    f.writelines (ppd)
    f.close ()
    os.rename (filename + new_suffix, filename)
    return octet_stream_allowed

def adjust_mime_convs (use_cjktexttops):
    """Set or unset cjktexttops as the handler for text/plain."""

    type = "text/plain"
    texttops = "texttops"
    cjktexttops = "cjktexttops"
    modified = 0
    ls = file (mime_convs).readlines ()
    for i in range (len (ls)):
        try:
            fields = ls[i].split ()
            this_type = fields[0].strip ()
            handler = fields[3].strip ()
        except:
            continue

        if this_type != type:
            continue

        if handler != cjktexttops and use_cjktexttops:
            handler = cjktexttops
            modified = 1
        elif handler == cjktexttops and not use_cjktexttops:
            handler = texttops
            modified = 1

        if modified:
            ls[i] = "%s\t\t%s\t%s\t%s\n" % (this_type, fields[1],
                                            fields[2], handler)
            break

    if modified:
	if use_cjktexttops:
	    debug_print ("Using cjktexttops for text/plain")
	else:
	    debug_print ("Using texttops for text/plain")

        m = safely_create (mime_convs + new_suffix, 0644)
        m.writelines (ls)
        m.close ()
        os.rename (mime_convs + new_suffix, mime_convs)

def adjust_mime_types (allow_octet_stream):
    """Set or unset 'application/octet-stream' in the mime.types file.
    It needs to be set if there are any raw queues."""
    type = "application/octet-stream"
    commented = re.compile ("^# *%s$" % type)
    ls = file (mime_types).readlines ()
    found_commented = 0
    found_uncommented = 0
    for i in range (len (ls)):
        if ls[i].strip () == type:
            if allow_octet_stream:
                return

            found_uncommented = 1
            debug_print ("Disabling %s MIME type" % type)
            ls[i] = "# %s\n" % type
        elif commented.match (ls[i]):
            found_commented = 1
            if allow_octet_stream:
                debug_print ("Enabling %s MIME type" % type)
                ls[i] = "%s\n" % type
                break

    if allow_octet_stream and not found_commented:
        debug_print ("Adding %s MIME type" % type)
        ls.append ("%s\n" % type)

    if not allow_octet_stream and not found_uncommented:
        return

    m = safely_create (mime_types + new_suffix, 0644)
    m.writelines (ls)
    m.close ()
    os.rename (mime_types + new_suffix, mime_types)

def grok_sysconfig_files (interfaces):
    """Given a list of interface specifications (allow from ...),
    return a tuple of arrays representing IP addresses and broadcast
    addresses for each relevant interface.  Do this by parsing
    /etc/sysconfig/network-scripts/* if necessary."""
    ipaddr = []
    broadcast = []

    ipaddr_re_str = "([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)"
    ipaddr_re = re.compile ("^%s$" % ipaddr_re_str)
    network_re = re.compile ("^%s/%s$" % (ipaddr_re_str, ipaddr_re_str))
    if_re = re.compile ("^@IF\((.*)\)$")
    for each in interfaces:
        if each == "All":
            ipaddr = [ "*" ]
            broadcast = [ "255.255.255.255" ]
            break

        # If it's an IP address, search for the right interface
        match = ipaddr_re.match (each)
        if match:
            quad = match.groups ()
            ipallowedn = map (lambda x: int (x), quad)
            found = 0
            for dev in rhpl.ethtool.get_devices ():
                try:
                    ips = rhpl.ethtool.get_ipaddr (dev)
                    nms = rhpl.ethtool.get_netmask (dev)
                    ipmatch = ipaddr_re.match (ips)
                    nmmatch = ipaddr_re.match (nms)
                    ipn = map (lambda x: int (x), ipmatch.groups ())
                    nmn = map (lambda x: int (x), nmmatch.groups ())
                    nwn = map (lambda x: ipn[x] & nmn[x], range (4))
                    nwallowedn = map (lambda x: ipallowedn[x] & nmn[x],
                                      range (4))
                    if nwn == nwallowedn:
                        ips = rhpl.ethtool.get_ipaddr (dev)
                        ipmatch = ipaddr_re.match (ips)
                        ipn = map (lambda x: int (x), ipmatch.groups ())
                        ips = "%d.%d.%d.%d" % tuple (ipn)

                        bcs = rhpl.ethtool.get_broadcast (dev)
                        bcmatch = ipaddr_re.match (bcs)
                        bcn = map (lambda x: int (x), bcmatch.groups ())
                        bcs = "%d.%d.%d.%d" % tuple (bcn)

                        if ips not in ipaddr:
                            ipaddr.append (ips)

                        if bcs not in broadcast:
                            broadcast.append (bcs)

                        found = 1
                        break

                except:
                    pass

            if not found:
                ipaddr = [ "*" ]

            continue

        # If it's an interface name, scan the appropriate config file.
        match = if_re.match (each)
        if match:
            dev = match.groups ()[0]
            try:
                ips = rhpl.ethtool.get_ipaddr (dev)
                bcs = rhpl.ethtool.get_broadcast (dev)
                ipmatch = ipaddr_re.match (ips)
                bcmatch = ipaddr_re.match (bcs)
                ipn = "%d.%d.%d.%d" % tuple (map (lambda x: int (x),
                                                  ipmatch.groups ()))
                bcn = "%d.%d.%d.%d" % tuple (map (lambda x: int (x),
                                                  bcmatch.groups ()))
                ipaddr.append (ipn)
                broadcast.append (bcn)
            except:
                pass

            continue

        # If it's a network address, search all of them.
        match = network_re.match (each)
        if match:
            quad = match.groups ()
            network = map (lambda x: int (x), quad[:4])
            netmask = map (lambda x: int (x), quad[4:])
            for dev in rhpl.ethtool.get_devices ():
                try:
                    ips = rhpl.ethtool.get_ipaddr (dev)
                    ipmatch = ipaddr_re.match (ips)
                    ipn = map (lambda x: int (x), ipmatch.groups ())
                    nwn = map (lambda x: ipn[x] & netmask[x], range (4))
                    spn = map (lambda x: network[x] & netmask[x], range (4))
                    if nwn == spn:
                        bcs = rhpl.ethtool.get_broadcast (dev)
                        bcmatch = ipaddr_re.match (bcs)
                        bcn = map (lambda x: int (x), bcmatch.groups ())
                        broadcast.append ("%d.%d.%d.%d" % tuple (bcn))
                        ipaddr.append ("%d.%d.%d.%d" % tuple (ipn))
                except:
                    pass

            continue

    if ipaddr.count ("*"):
        ipaddr = [ "*" ]

    if broadcast.count ("255.255.255.255"):
        broadcast = [ "255.255.255.255" ]

    return (ipaddr, broadcast)

context = readNsp (namespace = "printconf")
markNsp (namespace = "printconf", mark = "_PRINTCONF_BACKEND_")
if not context:
    print "Error getting context"
    sys.exit (1)

print_queues = context.data['/printconf/print_queues']
try:
    print_queues[context.data['/printconf/default_queue'].value].pos = 0
except:
    pass

cupsd_conf_lines = file (cupsd_conf).readlines ()
printers_conf_lines = file (printers_conf).readlines ()
configured_queues = []

# Back up cupsd.conf if this is the first time we are changing it
# (bug #97089).
if not os.access (cupsd_conf_backup, os.F_OK):
    file (cupsd_conf_backup, 'w').writelines (cupsd_conf_lines)

cupsd_conf_lines = remove_cupsd_conf ("/", cupsd_conf_lines)
cupsd_conf_lines = remove_cupsd_conf_globals (["Browsing",
                                               "BrowseProtocols",
                                               "BrowseOrder",
                                               "BrowseAllow",
                                               "BrowseDeny",
                                               "BrowseAddress",
                                               "Listen",
                                               "Port"],
                                              cupsd_conf_lines)

cupsd_conf_lines.append (autogen)

this_name = None
for l in printers_conf_lines:
    if l.startswith ("<Printer") or l.startswith ("<DefaultPrinter"):
        start_index = l.index (" ") + 1
        end_index = l.index (">")
        this_name = l[start_index:end_index]

    if l == cups_import.marker_line:
        configured_queues.append (this_name)

try:
    default_queue = print_queues[0].name
except:
    try:
        default_queue = context.data['/printconf/default_queue'].value
    except:
        default_queue = ''

raw_queues = 0
cjk_needed = 0
interfaces = []
for queue in print_queues:
    debug_print ("Add '%s' configuration to %s" % (queue.name, printers_conf))
    printers_conf_lines = add_printers_conf (queue, default_queue,
                                             printers_conf_lines)

    debug_print ("Add '%s' configuration to %s" % (queue.name, cupsd_conf))
    cupsd_conf_lines = add_cupsd_conf (queue, cupsd_conf_lines)

    debug_print ("Create %s%s.ppd" % (ppd_dir, queue.name))
    raw_queues += create_ppd (queue)

    try:
        configured_queues.remove (queue.name)
    except:
        pass

adjust_mime_types (raw_queues)
adjust_mime_convs (cjk_needed)

conf = [ "<Location />\n" ]
conf.append ("Order Deny,Allow\n")
conf.append ("Deny From All\n")
conf.append ("Allow From 127.0.0.1\n")
conf.append ("</Location>\n")
cupsd_conf_lines.extend (conf)

for queue in configured_queues:
    debug_print ("Remove '%s' configuration" % queue)
    printers_conf_lines = remove_printers_conf (queue, printers_conf_lines)
    cupsd_conf_lines = remove_cupsd_conf (queue, cupsd_conf_lines)
    try:
        os.remove (ppd_dir + queue + ".ppd")
    except:
        pass

# Globals
browse_interfaces = [ "@LOCAL" ]
try:
    browsing = context.data['/printconf/sharing_globals/browsing'].value
    if not browsing:
        browse_interfaces = [ ]
except:
    pass

try:
    # 'All' overrides everything else.
    interfaces = [interfaces[interfaces.index ("All")]]
except:
    pass

(ipaddr, broadcast) = grok_sysconfig_files (interfaces)
debug_print ("For interfaces: " + str (interfaces))
debug_print ("ipaddr: " + str (ipaddr))
debug_print ("broadcast: " + str (broadcast))

browsing = 0
if len (browse_interfaces):
    browsing = 1

if browsing:
    conf = [ "Browsing On\n" ]
    conf.append ("BrowseProtocols cups\n")
    conf.append ("BrowseOrder Deny,Allow\n")

    if len (browse_interfaces) == 0:
        conf.append ("BrowseDeny from All\n")

    for each in browse_interfaces:
        conf.append ("BrowseAllow from %s\n" % each)

    for each in broadcast:
        conf.append ("BrowseAddress %s\n" % each)

    cupsd_conf_lines.extend (conf)
else:
    cupsd_conf_lines.append ("Browsing Off\n")

# Interfaces to listen on
if len (ipaddr) != 1 or ipaddr[0] != "*":
    localhost = "127.0.0.1"
    if not localhost in ipaddr:
        ipaddr.append ("127.0.0.1")

for each in ipaddr:
    cupsd_conf_lines.append ("Listen %s:631\n" % each)

# Write out configuration files
f = safely_create (cupsd_conf + new_suffix, 0600, lp_uid, sys_gid)
f.writelines (cupsd_conf_lines)
f.close ()
os.rename (cupsd_conf + new_suffix, cupsd_conf)
f = safely_create (printers_conf + new_suffix, 0600, lp_uid, sys_gid)
f.writelines (printers_conf_lines)
f.close ()
os.rename (printers_conf + new_suffix, printers_conf)

# Set the default queue (even if it's remote)
os.environ["DEFAULT"] = default_queue
os.system ("/usr/bin/lpoptions -d $DEFAULT >/dev/null 2>/dev/null")
