Source

vasm / tvasm.py

#!/usr/bin/env python

#    This file is part of VASM.
#
#    VASM is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License v3 as published by
#    the Free Software Foundation.
#
#    VASM 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 VASM.  If not, see <http://www.gnu.org/licenses/>.

__author__ = "Moises Henriquez"
__author_email__ = "moc.liamg@xnl.E0M"[::-1]

""" urwid interface to vasm. 
    Main UI"""

import urwid
import imp
import sys
import os
import subprocess as sp
from modules.tuisupport import dialogs
from modules.tuisupport import widgets
from modules.support.vectorlinux import utils
from optparse import OptionParser
import logging

_ = utils._

logger = logging.getLogger('vasm')

palette = widgets.palette
blank = urwid.Divider()

def get_category_description(category):
    """ Returns a descriptive string about the current category """
    cats = {
        "System": "Global system settings.",
        "Hardware": "System hardware setup.",
        "Personal": "User personalization and application preferences.",
        "Network": "Networking and security settings.",
        "Graphical Environment": "User interface(s) settings."
    }
    if category in cats:
        return cats[category]
    return "%s settings"%category

class RightPane(widgets.ModuleRightPane):
    """ modified subclass of ModuleRight pane only to override method called
    by the keypress event"""
    def __init__(self, body, parent=None):
        self.body = body
        self.parent = parent
        widgets.ModuleRightPane.__init__(self, body, parent)

    def keypress(self, size, key):
        if key == 'esc':
            return self.parent.return_home()
        elif key in ('q', 'Q'):
            raise urwid.ExitMainLoop
        return super(RightPane, self).keypress(size, key)
        
class vasmbody(urwid.Pile):
    """ Body widget used inside the toplevel.  This displays the settings categories
    and their children """
    
    def show_category_children(self, widget):
        """ Display all child objects that belong to this category """
        desc = get_category_description(widget.text)
        self.parent.footer.set_text(desc)
        #self.parent.footer.set_text(widget.text)
        col = []
        for child in self.children:
            if child.category == widget.text:
                col.append(child)
        box = widgets.ModuleRightPane(col, self.parent)
        self.columns.widget_list[-1] = urwid.LineBox(box)
        #self.columns.widget_list[-1] = urwid.LineBox(urwid.ListBox(col))
    
    def __init__(self, parent):
        txt = urwid.Text("Test body area")
        self.parent = parent
        self.children = []
        self.discover_modules()
        categories = []
        col0 = []
        for child in self.children:
            if not child.category in categories:
                categories.append(child.category)
        # create category widgets
        col0.append(blank)
        for item in categories:
            cat = widgets.CategoryLabel(item, self.show_category_children,
                                        parent=self.parent)
            cat._select_method = self.do_super_vasm
            widget = urwid.AttrWrap(cat, None, 'reveal focus')
            col0.append(widget)
            col0.append(blank)
        self._category_widgets = col0
        # Add another launcher to run vasm as root. Only if running as non root
        if os.geteuid() > 0:
            cat = widgets.CategoryLabel("More Options", self.focus_super_vasm, True)
            cat._selectable = True
            cat._select_method = self.do_super_vasm
            widget = urwid.AttrWrap(cat, None, 'reveal focus')
            col0.append(widget)
        
        options = widgets.CategoryDisplay(col0)
        body = urwid.SolidFill()
        optionlist = RightPane(options, self.parent)
        #optionlist = urwid.ListBox(options)
        self.columns = urwid.Columns([('fixed', 12, optionlist), urwid.ListBox([])], 2)
        _widgets = [
            self.columns,
        ]
        urwid.Pile.__init__(self, _widgets)
    
    def do_super_vasm(self, widget):
        """ Run vasm as root"""
        self.parent._GO_TO_ROOT = True
        raise urwid.ExitMainLoop
        self.parent._mainloop.screen.stop()
        script = os.path.abspath(__file__)
        proc = sp.popen(['/bin/vsuper','python', script])
        proc.communicate()
        raise urwid.ExitMainLoop
    
    def do_popup_message(self, dialog):
        """ Pass a message to the parent so it pops up on the screen"""
        return self.parent.do_popup_message(dialog)
    
    def focus_super_vasm(self, widget):
        # Display a message that this only runs vasm as root.
        self.parent.footer.set_text(
            _("Launch this utility as Administrator for more options"))
        txt = _("Use this option to launch vasm as root and see more settings options.  " \
                "Press 'Enter' or 'Space' to activate")
        _lst = [
            ('flow', blank),
            ('flow', urwid.Text(txt)),
            urwid.SolidFill(),
        ]
        w = urwid.Pile(_lst)
        self.columns.widget_list[-1] = urwid.LineBox(w)

    def test_vasm_module(self, module):
        """ Check if the module in question is a valid vasm module
        
        Returns True when a module can be loaded on to vasm.
        False otherwise. """
        if not hasattr(module, 'VASM_CATEGORY'):
            return False
        if not hasattr(module, "__vasm_test__"):
            return False
        if not hasattr(module, "__run__"):
            return False
        return True

    def add_option(self, module):
        """ Add module launcher to the appriopriate view """
        markup = module.VASM_LABEL
        actuator = module.__run__
        launcher = widgets.Launcher(markup, module.VASM_CATEGORY, actuator, self.parent)
        widget = urwid.AttrWrap(launcher, None, 'reveal focus')
        self.children.append(widget)
        return
    
    def discover_modules(self):
        """ Discover the modules pluggable into vasm """
        modulesdir = os.path.join(os.getcwd(), "modules", "tui")
        for fname in sorted(os.listdir(modulesdir)):
            viewer = None
            if fname.endswith(".py") and fname !="__init__.py":
                pyname = fname[:-3]
                vasm_mod = self.load_module(pyname, fname, [modulesdir])
                if self.test_vasm_module(vasm_mod):
                    if vasm_mod.__vasm_test__():
                        # Module has paseed the test.  Add to the views
                        self.add_option(vasm_mod)

    def load_module(self, name, fname, path=["/home/vluser/devel/vasm/modules"]):
        """ return a named module found in the given path"""
        mod = imp.find_module(name, path)
        ret = imp.load_module(name, mod[0], fname, mod[2])
        return ret

class tvasm(urwid.Overlay):
    def __init__(self, loop = None):
        self._GO_TO_ROOT = False
        self.prevtopw = None
        shadow = urwid.AttrWrap(urwid.SolidFill(u" "), 'shadow')
        body = urwid.SolidFill()
        self._mainloop = loop
        if loop is not None:
            self.original_overlay = loop.widget
        if os.geteuid() == 0:
            header = _("VectorLinux Administration And System Menu")
        else:
            header = _("VectorLinux Administration And System Menu")
        self.header = urwid.Text(header)
        self.footer = urwid.Text('Footer Text')
        header = urwid.AttrWrap(urwid.LineBox(self.header), 'header')
        footer = urwid.AttrWrap(self.footer, 'header')
        bw = urwid.AttrWrap(urwid.SolidFill(), 'body')
        self.module_stack = []
        self.module_stack2 = []
        _pile_list = [
            ('flow', header),
            ('flow', blank),
            vasmbody(self),
            ('flow', blank),
            ('flow', footer)
        ]
        fw = urwid.Pile(_pile_list)
        urwid.Overlay.__init__(self, fw, bw, ('fixed left', 1), ('fixed right', 1),
                               ('fixed top', 1), ('fixed bottom', 1))
    
    def random_input(self, key):
        if key in ('q', 'Q'):
            raise urwid.ExitMainLoop
        elif key == 'r':
            return self.restore_widgets()
    
    def return_home(self, widget=None):
        self._mainloop.widget = urwid.AttrWrap(self.original_overlay,'body')
        #self.restore_overlay_size()
        #return self.restore_widgets(widget)
        
    def restore_widgets(self, widget=None):
        if not self.prevtopw:
            return
        newbot = urwid.AttrWrap(urwid.SolidFill(u" "), 'body')
        self.top_w = self.prevtopw
        self.bottom_w = newbot
        self.prevtopw = None
        return
    
    def pop_module(self, widget):
        """ Pop a dialog in this o verlay """
        self.original_overlay = self._mainloop.widget
        #self._previous_module_overlay = self._mainloop.widget
        # create another overlay?
        novl = urwid.Overlay(
            widget,
            self.original_overlay.top_w,
            ('fixed left', 1),
            ('fixed right', 1),
            ('fixed top', 1),
            ('fixed bottom', 1)
            
        )
        self._current_module_overlay = urwid.AttrWrap(novl, 'body')    
        self._mainloop.widget = self._current_module_overlay
        return
    
    def pop_file_dialog(self, widget):
        """ Pop a big dialog showing the contents of a file ...
        Still pops widget as the dialog, but it's resized to be big so we utilize
        more space on the screen"""
        self.old_topw = self._mainloop.widget
        widget = urwid.AttrWrap(urwid.LineBox(widget), 'dialog body')
        w = urwid.Overlay(widget, self.old_topw,
                          'center',
                          ('relative', 90),
                          'middle',
                          ('relative', 90),
                         )
        self._mainloop.widget = w
        return

    def pop_module_dialog(self, widget, level=1):
        self.old_topw = self._mainloop.widget
        #widget = urwid.AttrWrap(urwid.LineBox(widget), 'dialog body')
        if level == 1:
            widget = urwid.AttrWrap(urwid.LineBox(widget), 'dialog body')
            w = urwid.Overlay(widget,
                          self.old_topw,
                          'center',
                          ('relative', 70),
                          'middle',
                          ('relative', 40),
                          min_width = 50,
                          min_height = 15)
        elif level == 2:
            widget = urwid.AttrWrap(urwid.LineBox(widget), 'dialog body')
            w = urwid.Overlay(widget,
                              self.old_topw,
                              'center',
                              ('relative', 80),
                              'middle',
                              ('relative', 50),
                              min_width = 70,
                              min_height = 20)
        else:
            widget = urwid.AttrWrap(urwid.LineBox(widget), 'body')
            w = urwid.Overlay(widget,
                              self.old_topw,
                              'center',
                              ('relative', 70),
                              'middle',
                              ('relative', 40),
                              min_width = 50,
                              min_height = 15)

        self._mainloop.widget = w
        return
    
    def return_to_module(self, caller_widget=None):
        self._mainloop.widget = self._current_module_overlay
    
    def return_to_module_stack(self, widget=None):
        """ restore the module after the dialog has exited """
        if self.old_topw:
            self._mainloop.widget = urwid.AttrWrap(self.old_topw, 'body')
            self.old_topw = None
        else:
            # restore the original widget
            self._mainloop.widget = urwid.AttrWrap(self.original_overlay, 'body')
        return

    def restore_overlay_size(self):
        """ Restore overlay to its original size
        """
        at, aa, wt, wa=urwid.decompose_align_width(('fixed left', 1),('fixed right', 1), urwid.OverlayError)
        vt,va,ht,ha = urwid.decompose_valign_height(('fixed top', 1), ('fixed bottom', 1), urwid.OverlayError)
        self.align_type, self.align_amount = at, aa
        self.width_type, self.width_amount = wt, wa
        
        self.valign_type, self.valign_amount = vt, va
        self.height_type, self.height_amount = ht, ha

def _get_logger_level(level):
    """ return the proper logger level for the specified level"""
    levels = {'0':logging.CRITICAL,
        '1':logging.FATAL,
        '2':logging.ERROR,
        '3':logging.INFO,
        '4':logging.DEBUG}
    return levels[level] or levels['4']

def main():
    # start the logging
    logger.info("Starting vasm urwid interface as uid=%s"% os.geteuid())
    wbad = urwid.SolidFill()
    # Get the right palette
    if os.getenv("DISPLAY"):
        palette = widgets.palette
    else:
        palette = widgets.tui_palette
    loop = urwid.MainLoop(wbad, palette = palette, handle_mouse=False)
    top = tvasm(loop)
    tui = urwid.AttrWrap(top, 'body')
    #tui = urwid.LineBox(tui)
    navtxt = " Enter / Space: Select | Arrows / Tab: Navigate | q: Exit"
    _shadow_list = []
    if os.geteuid() == 0:
        _shadow_list.append(
                ('flow', urwid.AttrWrap(
                    urwid.Text('Administrator Mode. ',
                        align='right'),
                    'warning')))
    _shadow_list.append(
            urwid.AttrWrap(urwid.SolidFill(u" "), 'shadow'))
    _shadow_list.append(('flow',
            urwid.AttrWrap(urwid.Text(navtxt), 'shadow text')))
    shadow = urwid.Pile(_shadow_list)
    w = urwid.Overlay(tui, shadow,
                      ('fixed left', 1), ('fixed right', 1),
                      ('fixed top', 1), ('fixed bottom', 1))
    loop.widget = w
    loop.unhandled_input = top.random_input
    loop.run()
    if  top._GO_TO_ROOT:
        proc = sp.Popen("clear")
        proc.communicate()
        print _("You must enter the root password to access the administrative settings.")
        script = os.path.abspath(__file__)
        proc = sp.Popen(["su","-c" ,script])
        proc.communicate()
    sys.exit()

    
    

if __name__ == '__main__':
    # process commandline options
    parser = OptionParser()
    parser.add_option("-v", "--verbose", dest="verbose",
        help = "Verbosity level")
    (options, args) = parser.parse_args()
    
    if options.verbose is not None:
        logger.setLevel(_get_logger_level(options.verbose))
    # otherwide, it defaults to info
    main()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.