#!/usr/bin/python

# configlet-capplet -- GNOME Control Center "capplet" frontend

# $Progeny$

# Copyright (C) 2001  Progeny Linux Systems, Inc.
# AUTHORS: Jeff Licquia <jlicquia@progeny.com>

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,  as
# published by the Free Software Foundation.

# 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

import sys
import os
import signal
import popen2
import pty
import time
import string
import re

# We have to load the debconf database here manually before we can
# load the configlet module.  The reason for this is because the
# control center won't accept capplets if they take too long to open,
# and the control center is started the moment the capplet module is
# imported.  Unfortunately, the capplet module also insists on being
# imported before gtk, which means the configlet module also has to
# wait.

def make_temp_dir():
    temp_path = "/tmp/configlet.%d.%d" % (os.getpid(), time.time())
    os.mkdir(temp_path, 0700)
    return temp_path

temp_path = make_temp_dir()

# Information on which security apps are available.

su_command_info_list = [ "gnome-sudo", "xsu" ]
su_command_info = { "gnome-sudo": { "path": "/usr/bin/gnome-sudo",
                                    "command": "gnome-sudo -- %s",
                                    "failflag": ".no_gnome_sudo" },
                    "xsu":        { "path": "/usr/bin/xsu",
                                    "command": "xsu -e -u root -c '%s'" }
                  }

# Find the available su commands on the system, ranked by suitability.

pref_cmds = []
fail_cmds = []
for su_command in su_command_info_list:
    if os.path.exists(su_command_info[su_command]["path"]):
        if su_command_info[su_command].has_key("failflag") and \
           os.path.exists("%s/%s" % (os.environ["HOME"],
                                     su_command_info[su_command]["failflag"])):
            fail_cmds.append(su_command)
        else:
            pref_cmds.append(su_command)

cmds = pref_cmds + fail_cmds

# Attempt to run the su commands, starting with the most preferred.

temp_fn = "%s/configletdb" % (temp_path,)
debconf_command = "debconf-copydb configdb configletdb -c Name:configletdb -c Driver:File -c Mode:644 -c Filename:%s" \
                  % (temp_fn,)

debconf_script = open("%s/script" % (temp_path,), "w")
debconf_script.write("%s\n" % (debconf_command,))
debconf_script.close()

for command in cmds:
    local_command = su_command_info[command]["command"] \
                    % ("/bin/sh %s/script" % (temp_path,))
    retval = os.system(local_command)
    if os.path.exists(temp_fn) and os.path.getsize(temp_fn):
        break
    else:
        if su_command_info[command].has_key("failflag"):
            fail_file = open("%s/%s" % (os.environ["HOME"], su_command_info[command]["failflag"]), "w")
            fail_file.write("Failed.")
            fail_file.close()

os.unlink("%s/script" % (temp_path,))

# If nothing seemed to work, fail with an error message.

found_result = 0
try:
    if os.path.exists(temp_fn) and os.path.getsize(temp_fn):
        found_result = 1
except:
    pass

if not found_result:
    #sys.argv = []

    import gtk
    import gnome.ui

    dialog = gnome.ui.GnomeMessageBox("""
In order for this item to work, the system must be able to gain
root access to the system.  This is typically done with the
gnome-sudo or xsu programs.  Please ensure that one of these
programs is installed, and that your account has been given 
permission to use it; see the documentation for sudo or xsu
for details on the latter.
""", gnome.ui.MESSAGE_BOX_ERROR, gnome.ui.STOCK_BUTTON_OK)
    dialog.set_position(gtk.WIN_POS_CENTER)
    dialog.run_and_close()

    os.rmdir(temp_path)
    sys.exit(1)

# Since one of the su commands appears to have succeeded, remove its
# failure flag if it has one.

working_su_info = su_command_info[command]
if working_su_info.has_key("failflag"):
    fail_path = "%s/%s" % (os.environ["HOME"], working_su_info["failflag"])
    if os.path.exists(fail_path):
        os.unlink(fail_path)

# We have results!  Read them in.

configletdb = open("%s/configletdb" % temp_path)
line = configletdb.readline()
itemhash = {}
debconf_info = []
while line:
    if re.match(r'\S+', line):
        results = re.match(r'\s*(\w+):\s*(.+)', line)
        if results:
            itemhash[results.group(1)] = results.group(2)
    else:
        if len(itemhash.keys()):
            if not itemhash.has_key("Value"):
                itemhash["Value"] = '""'
            debconf_str = "%s %s %s" % \
                          (itemhash["Template"], itemhash["Name"],
                           itemhash["Value"])
            debconf_info.append(debconf_str)
            itemhash = {}

    line = configletdb.readline()

configletdb.close()
os.unlink("%s/configletdb" % temp_path)
os.rmdir(temp_path)

# Now we can import the configlet and capplet functions.

from gnome.capplet import *
from gtk import *
import configlet

# Capplet signal handlers.

def try_signal(*args):
    pass

def revert_signal(*args):
    pass

def ok_signal(*args):
    global configlet_instance
    global dc

    if not configlet_instance.validate():
        print "XXX: configlet didn't validate, better error handler needed"
    else:
        configlet_instance.on_gnome_close()
        dc.set(configlet_instance.report_debconf())
        dc.commit()

    cancel_signal()

def cancel_signal(*args):
    mainquit()

# Other functions.

def page_validate(notebook, page, pagenum):
    global pagelist, configlet_instance

    pagename = pagelist[pagenum]
    if not configlet_instance.validate_page(pagename):
        print "XXX: page %s didn't validate, better error handler needed" \
              % pagename

    return TRUE

pagelist = []

# Set the privileged runner based on the command we were able to get
# to work before.

if command == "gnome-sudo":
    configlet.set_privileged_runner(configlet.GnomeSudoPrivilegedRunner())
elif command == "xsu":
    configlet.set_privileged_runner(configlet.XsuPrivilegedRunner())
else:
    sys.stderr.write("No privileged runner could be set.  We should not get here.\n")
    sys.exit(1)

# We need the configlet to run.  It will either be in the name
# ("foo-configlet-capplet"), or it will be the first argument
# ("configlet-capplet foo").  We need to figure out what we need.

name = os.path.basename(sys.argv[0])
if name == "configlet-capplet":
    name = sys.argv[1]
else:
    name = name[:string.rindex(name, "-", 0, string.rindex(name, "-"))]

configlet_instance = configlet.start_configlet("/usr/share/configlets/%s"
                                               % (name,))
configlet_instance.gnome_setup()

dc = configlet.get_debconf(configlet_instance.get_packages())

if len(configlet_instance.get_page_names()) > 1:
    configlet_widget = GtkNotebook()
    configlet_widget.set_tab_pos(POS_TOP)
    configlet_widget.connect("switch-page", page_validate)

    for page in configlet_instance.get_page_names():
        pagename = configlet_instance.get_page_display_title(page)
        pagelist.append(pagename)
        configlet_label = GtkLabel(pagename)
        configlet_label.show()
        pagewidget = configlet_instance.get_widget(page)
        pagewidget.unparent()
        configlet_widget.append_page(pagewidget, configlet_label)
        pagewidget.show()
else:
    configlet_widget = configlet_instance.get_widget()
    configlet_widget.unparent()

configlet_instance.load_debconf(debconf_info)

capplet = CappletWidget()
capplet.add(configlet_widget)
configlet_widget.show()

capplet.connect("try", try_signal, None)
capplet.connect("revert", revert_signal, None)
capplet.connect("ok", ok_signal, None)
capplet.connect("cancel", cancel_signal, None)

capplet.state_changed(FALSE)

capplet.show()
mainloop()
