From 28df5a8dc450afdaad2ba48a581166ca82763e3d Mon Sep 17 00:00:00 2001 From: Michael Spang Date: Tue, 4 Dec 2007 21:44:16 -0500 Subject: [PATCH] Remove old GUI --- bin/ceo-old | 31 -- pylib/csc/apps/legacy/__init__.py | 8 - pylib/csc/apps/legacy/helpers.py | 411 ----------------------- pylib/csc/apps/legacy/main.py | 531 ------------------------------ 4 files changed, 981 deletions(-) delete mode 100755 bin/ceo-old delete mode 100644 pylib/csc/apps/legacy/__init__.py delete mode 100644 pylib/csc/apps/legacy/helpers.py delete mode 100644 pylib/csc/apps/legacy/main.py diff --git a/bin/ceo-old b/bin/ceo-old deleted file mode 100755 index 8550f796d..000000000 --- a/bin/ceo-old +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/python2.4 -- -"""CEO SUID Python Wrapper Script""" -import os, sys - -safe_environment = ['LOGNAME', 'USERNAME', 'USER', 'HOME', 'TERM', 'LANG' - 'LC_ALL', 'LC_COLLATE', 'LC_CTYPE', 'LC_MESSAGES', 'LC_MONETARY', - 'LC_NUMERIC', 'LC_TIME', 'UID', 'GID', 'SSH_CONNECTION', 'SSH_AUTH_SOCK', - 'SSH_CLIENT'] - -for key in os.environ.keys(): - if key not in safe_environment: - del os.environ[key] - -os.environ['LESSSECURE'] = '1' -os.environ['PATH'] = '/usr/sbin:/usr/bin:/sbin:/bin' - -for pathent in sys.path[:]: - if not pathent.find('/usr') == 0: - sys.path.remove(pathent) - -euid = os.geteuid() -egid = os.getegid() -try: - os.setreuid(euid, euid) - os.setregid(egid, egid) -except OSError, e: - print str(e) - sys.exit(1) - -import csc.apps.legacy.main -csc.apps.legacy.main.run() diff --git a/pylib/csc/apps/legacy/__init__.py b/pylib/csc/apps/legacy/__init__.py deleted file mode 100644 index 0bc0b6553..000000000 --- a/pylib/csc/apps/legacy/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -""" -Legacy User Interface - -This module contains the legacy CEO user interface and related modules. - - main - all of the main UI logic - helpers - user interface library routines -""" diff --git a/pylib/csc/apps/legacy/helpers.py b/pylib/csc/apps/legacy/helpers.py deleted file mode 100644 index a18a1933d..000000000 --- a/pylib/csc/apps/legacy/helpers.py +++ /dev/null @@ -1,411 +0,0 @@ -""" -Helpers for legacy User Interface - -This module contains numerous functions that are designed to immitate -the look and behavior of the previous CEO. Included is code for various -curses-based UI widgets that were provided by Perl 5's Curses and -Curses::Widgets libraries. - -Though attempts have been made to keep the UI [bug-]compatible with -the previous system, some compromises have been made. For example, -the input and textboxes draw 'OK' and 'Cancel' buttons where the old -CEO had them, but they are fake. That is, the buttons in the old -CEO were selectable but non-operational, but in the new CEO they are -not even selectable. -""" -import curses.ascii - -# key constants not defined in CURSES -KEY_RETURN = ord('\n') -KEY_ESCAPE = 27 -KEY_EOT = 4 - - -def center(parent_dim, child_dim): - """Helper for centering a length in a larget length.""" - return (parent_dim-child_dim)/2 - - -def read_input(wnd, offy, offx, width, maxlen, echo=True): - """ - Read user input within a confined region of a window. - - Basic line-editing is supported: - LEFT, RIGHT, HOME, and END move around. - BACKSPACE and DEL remove characters. - INSERT switches between insert and overwrite mode. - ESC and C-d abort input. - RETURN completes input. - - Parameters: - wnd - parent window for region - offy - the vertical offset for the beginning of the input region - offx - the horizontal offset for the beginning of the input region - width - the width of the region - maxlen - greatest number of characters to read (0 for no limit) - echo - boolean: whether to display typed characters - - Returns: the string, or None when the user aborts. - """ - - # turn on cursor - try: - curses.curs_set(1) - except curses.error: - pass - - # set keypad mode to allow UP, DOWN, etc - wnd.keypad(1) - - # the input string - inputbuf = "" - - # offset of cursor in input - # i.e. the next operation is applied at input[inputoff] - inputoff = 0 - - # display offset (for scrolling) - # i.e. the first character in the region is input[displayoff] - displayoff = 0 - - # insert mode (True) or overwrite mode (False) - insert = True - - while True: - - # echo mode, display the string - if echo: - # discard characters before displayoff, - # as the window may be scrolled to the right - substring = inputbuf[displayoff:] - - # pad the string with zeroes to overwrite stale characters - substring = substring + " " * (width - len(substring)) - - # display the substring - wnd.addnstr(offy, offx, substring, width) - - # await input - key = wnd.getch(offy, offx + inputoff - displayoff) - - # not echo mode, don't display the string - else: - # await input at arbitrary location - key = wnd.getch(offy, offx) - - # enter returns input - if key == KEY_RETURN: - return inputbuf - - # escape aborts input - elif key == KEY_ESCAPE: - return None - - # EOT (C-d) aborts if there is no input - elif key == KEY_EOT: - if len(inputbuf) == 0: - return None - - # backspace removes the previous character - elif key == curses.KEY_BACKSPACE: - if inputoff > 0: - - # remove the character immediately before the input offset - inputbuf = inputbuf[0:inputoff-1] + inputbuf[inputoff:] - inputoff -= 1 - - # move either the cursor or entire line of text left - if displayoff > 0: - displayoff -= 1 - - # delete removes the current character - elif key == curses.KEY_DC: - if inputoff < len(input): - - # remove the character at the input offset - inputbuf = inputbuf[0:inputoff] + inputbuf[inputoff+1:] - - # left moves the cursor one character left - elif key == curses.KEY_LEFT: - if inputoff > 0: - - # move the cursor to the left - inputoff -= 1 - - # scroll left if necessary - if inputoff < displayoff: - displayoff -= 1 - - # right moves the cursor one character right - elif key == curses.KEY_RIGHT: - if inputoff < len(inputbuf): - - # move the cursor to the right - inputoff += 1 - - # scroll right if necessary - if displayoff - inputoff == width: - displayoff += 1 - - # home moves the cursor to the first character - elif key == curses.KEY_HOME: - inputoff = 0 - displayoff = 0 - - # end moves the cursor past the last character - elif key == curses.KEY_END: - inputoff = len(inputbuf) - displayoff = len(inputbuf) - width + 1 - - # insert toggles insert/overwrite mode - elif key == curses.KEY_IC: - insert = not insert - - # other (printable) characters are added to the input string - elif curses.ascii.isprint(key): - if len(inputbuf) < maxlen or maxlen == 0: - - # insert mode: insert before current offset - if insert: - inputbuf = inputbuf[0:inputoff] + chr(key) + inputbuf[inputoff:] - - # overwrite mode: replace current offset - else: - inputbuf = inputbuf[0:inputoff] + chr(key) + inputbuf[inputoff+1:] - - # increment the input offset - inputoff += 1 - - # scroll right if necessary - if inputoff - displayoff == width: - displayoff += 1 - - -def inputbox(wnd, prompt, field_width, echo=True): - """Display a window for user input.""" - - wnd_height, wnd_width = wnd.getmaxyx() - height, width = 12, field_width + 7 - - # draw a window for the dialog - childy, childx = center(wnd_height-1, height)+1, center(wnd_width, width) - child_wnd = wnd.subwin(height, width, childy, childx) - child_wnd.clear() - child_wnd.border() - - # draw another window for the text box - texty, textx = center(height-1, 3)+1, center(width-1, width-5)+1 - textheight, textwidth = 3, width-5 - text_wnd = child_wnd.derwin(textheight, textwidth, texty, textx) - text_wnd.clear() - text_wnd.border() - - # draw the prompt - prompty, promptx = 2, 3 - child_wnd.addnstr(prompty, promptx, prompt, width-2) - - # draw the fake buttons - fakey, fakex = 9, width - 19 - child_wnd.addstr(fakey, fakex, "< OK > < Cancel >") - child_wnd.addch(fakey, fakex+2, "O", curses.A_UNDERLINE) - child_wnd.addch(fakey, fakex+9, "C", curses.A_UNDERLINE) - - # update the screen - child_wnd.noutrefresh() - text_wnd.noutrefresh() - curses.doupdate() - - # read an input string within the field region of text_wnd - inputy, inputx, inputwidth = 1, 1, textwidth - 2 - inputbuf = read_input(text_wnd, inputy, inputx, inputwidth, 0, echo) - - # erase the window - child_wnd.erase() - child_wnd.refresh() - - return inputbuf - - -def line_wrap(line, width): - """Wrap a string to a certain width (returns a list of strings).""" - - wrapped_lines = [] - tokens = line.split(" ") - tokens.reverse() - tmp = tokens.pop() - if len(tmp) > width: - wrapped_lines.append(tmp[0:width]) - tmp = tmp[width:] - while len(tokens) > 0: - token = tokens.pop() - if len(tmp) + len(token) + 1 <= width: - tmp += " " + token - elif len(token) > width: - tmp += " " + token[0:width-len(tmp)-1] - tokens.push(token[width-len(tmp)-1:]) - else: - wrapped_lines.append(tmp) - tmp = token - wrapped_lines.append(tmp) - return wrapped_lines - - -def msgbox(wnd, msg, title="Message"): - """Display a message in a window.""" - - # split message into a list of lines - lines = msg.split("\n") - - # determine the dimensions of the method - message_height = len(lines) - message_width = 0 - for line in lines: - if len(line) > message_width: - message_width = len(line) - - # ensure the window fits the title - if len(title) > message_width: - message_width = len(title) - - # maximum message width - parent_height, parent_width = wnd.getmaxyx() - max_message_width = parent_width - 8 - - # line-wrap if necessary - if message_width > max_message_width: - newlines = [] - for line in lines: - for newline in line_wrap(line, max_message_width): - newlines.append(newline) - lines = newlines - message_width = max_message_width - message_height = len(lines) - - # random padding that perl's curses adds - pad_width = 2 - - # create the outer window - outer_height, outer_width = message_height + 8, message_width + pad_width + 6 - outer_y, outer_x = center(parent_height+1, outer_height)-1, center(parent_width, outer_width) - outer_wnd = wnd.derwin(outer_height, outer_width, outer_y, outer_x) - outer_wnd.erase() - outer_wnd.border() - - # create the inner window - inner_height, inner_width = message_height + 2, message_width + pad_width + 2 - inner_y, inner_x = 2, center(outer_width, inner_width) - inner_wnd = outer_wnd.derwin(inner_height, inner_width, inner_y, inner_x) - inner_wnd.border() - - # display the title - outer_wnd.addstr(0, 1, " " + title + " ", curses.A_REVERSE | curses.A_BOLD) - - # display the message - for i in xrange(len(lines)): - inner_wnd.addnstr(i+1, 1, lines[i], message_width) - - # draw a solid block at the end of the first few lines - if i < len(lines) - 1: - inner_wnd.addch(i+1, inner_width-1, ' ', curses.A_REVERSE) - - # display the fake OK button - fakey, fakex = outer_height - 3, outer_width - 8 - outer_wnd.addstr(fakey, fakex, "< OK >", curses.A_REVERSE) - outer_wnd.addch(fakey, fakex+2, "O", curses.A_UNDERLINE | curses.A_REVERSE) - - # update display - outer_wnd.noutrefresh() - inner_wnd.noutrefresh() - curses.doupdate() - - # read a RETURN or ESC before returning - curses.curs_set(0) - outer_wnd.keypad(1) - while True: - key = outer_wnd.getch(0, 0) - if key == KEY_RETURN or key == KEY_ESCAPE: - break - - # clear the window - outer_wnd.erase() - outer_wnd.refresh() - - -def menu(wnd, offy, offx, width, options, _acquire_wnd=None): - """ - Draw a menu and wait for a selection. - - Parameters: - wnd - parent window - offy - vertical offset for menu region - offx - horizontal offset for menu region - width - width of menu region - options - a list of selections - _acquire_wnd - hack to support resize: must be a function callback - that returns new values for wnd, offy, offx, height, - width. Unused if None. - - Returns: index into options that was selected - """ - - # the currently selected option - selected = 0 - - while True: - # disable cursor - curses.curs_set(0) - - # hack to support resize: recreate the - # parent window every iteration - if _acquire_wnd: - wnd, offy, offx, height, width = _acquire_wnd() - - # keypad mode so getch() works with up, down - wnd.keypad(1) - - # display the menu - for i in xrange(len(options)): - text, callback = options[i] - text = text + " " * (width - len(text)) - - # the selected option is displayed in reverse video - if i == selected: - wnd.addstr(i+offy, offx, text, curses.A_REVERSE) - else: - wnd.addstr(i+offy, offx, text) - # display the member - - wnd.refresh() - - # read one keypress - keypress = wnd.getch() - - # UP moves to the previous option - if (keypress == curses.KEY_UP or keypress == ord('k')) and selected > 0: - selected = (selected - 1) - - # DOWN moves to the next option - elif (keypress == curses.KEY_DOWN or keypress == ord('j')) and selected < len(options) - 1: - selected = (selected + 1) - - # RETURN runs the callback for the selected option - elif keypress == KEY_RETURN: - text, callback = options[selected] - - # highlight the selected option - text = text + " " * (width - len(text)) - wnd.addstr(selected+offy, offx, text, curses.A_REVERSE | curses.A_BOLD) - wnd.refresh() - - # execute the selected option - if callback(wnd): # success - break - - -def reset(): - """Reset the terminal and clear the screen.""" - - reset = curses.tigetstr('rs1') - if not reset: reset = '\x1bc' - curses.putp(reset) - diff --git a/pylib/csc/apps/legacy/main.py b/pylib/csc/apps/legacy/main.py deleted file mode 100644 index 98df1f734..000000000 --- a/pylib/csc/apps/legacy/main.py +++ /dev/null @@ -1,531 +0,0 @@ -""" -CEO-like Frontend - -This frontend aims to be compatible in both look and function with the -curses UI of CEO. - -Some small improvements have been made, such as not echoing passwords and -aborting when nothing is typed into the first input box during an operation. - -This frontend is poorly documented, deprecated, and undoubtedly full of bugs. -""" -import curses.ascii, re, os -from helpers import menu, inputbox, msgbox, reset -from csc.adm import accounts, members, terms -from csc.common.excep import InvalidArgument - -# color of the ceo border -BORDER_COLOR = curses.COLOR_RED - - -def read_uid(wnd): - """Read a username.""" - - prompt = 'Username:' - return inputbox(wnd, prompt, 36) - -def read_member(wnd): - """Looks up a member.""" - - # connect the members module to its backend if necessary - if not members.connected(): members.connect() - - uid = read_uid(wnd) - if not uid or uid.lower() == 'exit': - return - - member = members.get(uid) - if not member: - msgbox(wnd, "Invalid username: %s" % uid) - return - - # display user - display_member_details(wnd, member) - - return member - - -def action_library(wnd): - """Display a link to the library.""" - msgbox(wnd, "Please visit library.csclub.uwaterloo.ca") - -def action_new_member(wnd): - """Interactively add a new member.""" - - userid, program = '', '' - - msgbox(wnd, "Membership is $2.00 CDN. Please ensure\n" - "the money is desposited in the safe\n" - "before continuing.") - - # read the name - prompt = "New member's full name: " - realname = inputbox(wnd, prompt, 30) - - # abort if no name is entered - if not realname or realname.lower() == 'exit': - return False - - # read the program of study - prompt = "New member's program of study:" - program = inputbox(wnd, prompt, 30) - - # abort if exit is entered - if program is None or program.lower() == 'exit': - return False - - # read user id - prompt = "New member's UWdir username:" - while userid == '': - userid = inputbox(wnd, prompt, 30) - - # user abort - if userid is None or userid.lower() == 'exit': - return False - - # connect the members module to its backend if necessary - if not members.connected(): members.connect() - - # attempt to create the member - try: - members.new(userid, realname, program) - - msgbox(wnd, "Success! Your username is %s. You are now registered\n" - % userid + "for the " + terms.current() + " term.") - - except members.InvalidRealName: - msgbox(wnd, 'Invalid real name: "%s"' % realname) - return False - except InvalidArgument, e: - if e.argname == 'uid' and e.explanation == 'duplicate uid': - msgbox(wnd, 'A member with this user ID exists.') - return False - else: - raise - - -def action_term_register(wnd): - """Interactively register a member for a term.""" - - term = '' - - member = read_member(wnd) - if not member: - return False - uid = member['uid'][0] - - # verify member - prompt = "Is this the correct member?" - answer = None - while answer != "yes" and answer != "y" and answer != "n" and answer != "no" and answer != "exit": - answer = inputbox(wnd, prompt, 28) - - # user abort - if answer == "exit": - return False - - # read the term - prompt = "Which term to register for ([wsf]20nn):" - while not re.match('^[wsf][0-9]{4}$', term) and not term == 'exit': - term = inputbox(wnd, prompt, 41) - - # abort when exit is entered - if term.lower() == 'exit': - return False - - # already registered? - if members.registered(uid, term): - msgbox(wnd, "You are already registered for term " + term) - return False - - try: - - # attempt to register - members.register(uid, term) - - # display success message - msgbox(wnd, "You are now registered for term " + term) - - except members.InvalidTerm: - msgbox(wnd, "Term is not valid: %s" % term) - - return False - - -def action_term_register_multiple(wnd): - """Interactively register a member for multiple terms.""" - - base, num = '', None - - member = read_member(wnd) - if not member: - return False - uid = member['uid'][0] - - # verify member - prompt = "Is this the correct member?" - answer = None - while answer != "yes" and answer != "y" and answer != "n" and answer != "no" and answer != "exit": - answer = inputbox(wnd, prompt, 28) - - # user abort - if answer == "exit": - return False - - # read the base - prompt = "Which term to start registering ([fws]20nn):" - while not re.match('^[wsf][0-9]{4}$', base) and not base == 'exit': - base = inputbox(wnd, prompt, 41) - - # abort when exit is entered - if base.lower() == 'exit': - return False - - # read number of terms - prompt = 'How many terms?' - while not num or not re.match('^[0-9]*$', num): - num = inputbox(wnd, prompt, 36) - num = int(num) - - # any terms in the range? - if num < 1: - msgbox(wnd, "No terms to register.") - return False - - # compile a list to register - term_list = terms.interval(base, num) - - # already registered? - for term in term_list: - if members.registered(uid, term): - msgbox(wnd, "You are already registered for term " + term) - return False - - try: - - # attempt to register all terms - members.register(uid, term_list) - - # display success message [sic] - msgbox(wnd, "Your are now registered for terms: " + ", ".join(term_list)) - - except members.InvalidTerm: - msgbox(wnd, "Invalid term entered.") - - return False - - -def input_password(wnd): - - # password input loop - password = "password" - check = "check" - while password != check: - - # read password - prompt = "User password:" - password = None - while not password: - password = inputbox(wnd, prompt, 18, False) - - # read another password - prompt = "Enter the password again:" - check = None - while not check: - check = inputbox(wnd, prompt, 27, False) - - return password - - -def action_create_account(wnd): - """Interactively create an account for a member.""" - - member = read_member(wnd) - if not member: - return False - - # member already has an account? - if not accounts.connected(): accounts.connect() - if 'posixAccount' in member['objectClass']: - msgbox(wnd, "Account already exists.") - return False - - # verify member - prompt = "Is this the correct member?" - answer = None - while answer != "yes" and answer != "y" and answer != "n" and answer != "no" and answer != "exit": - answer = inputbox(wnd, prompt, 28) - - # user abort - if answer == "exit": - return False - - # incorrect member; abort - if answer == "no" or answer == "n": - msgbox(wnd, "I suggest searching for the member by userid or name from the main menu.") - return False - - msgbox(wnd, "Ensure the member has signed the machine\n" - "usage policy. Accounts of users who have\n" - "not signed will be suspended if discovered.") - - # read password - password = input_password(wnd) - - # create the UNIX account - try: - if not accounts.connected(): accounts.connect() - accounts.create_member(member['uid'][0], password, member['cn'][0]) - except accounts.NameConflict, e: - msgbox(wnd, str(e)) - return False - except accounts.NoAvailableIDs, e: - msgbox(wnd, str(e)) - return False - except accounts.InvalidArgument, e: - msgbox(wnd, str(e)) - return False - except accounts.LDAPException, e: - msgbox(wnd, "Error creating LDAP entry - Contact the Systems Administrator: %s" % e) - return False - except accounts.KrbException, e: - msgbox(wnd, "Error creating Kerberos principal - Contact the Systems Administrator: %s" % e) - return False - - # success - msgbox(wnd, "Please run 'addhomedir " + member['uid'][0] + "'.") - msgbox(wnd, "Success! Your account has been added") - - return False - - -def display_member_details(wnd, member): - """Display member attributes in a message box.""" - - # clone and sort term_list - if 'term' in member: - term_list = list(member['term']) - else: - term_list = [] - term_list.sort( terms.compare ) - - # labels for data - id_label, name_label = "ID:", "Name:" - program_label, terms_label = "Program:", "Terms:" - - if 'program' in member: - program = member['program'][0] - else: - program = None - - # format it all into a massive string - message = "%8s %-20s %10s %-10s\n" % (name_label, member['cn'][0], id_label, member['uid'][0]) + \ - "%8s %-20s\n" % (program_label, program ) - - message += "%s %s" % (terms_label, " ".join(term_list)) - - # display the string in a message box - msgbox(wnd, message) - - -def action_display_member(wnd): - """Interactively display a member.""" - - if not members.connected(): members.connect() - member = read_member(wnd) - return False - - -def page(text): - """Send a text buffer to an external pager for display.""" - - try: - pager = '/usr/bin/less' - pipe = os.popen(pager, 'w') - pipe.write(text) - pipe.close() - except IOError: - # broken pipe (user didn't read the whole list) - pass - - -def format_members(member_list): - """Format a member list into a string.""" - - # clone and sort member_list - member_list = list(member_list) - member_list.sort( lambda x, y: cmp(x['uid'], y['uid']) ) - - buf = '' - - for member in member_list: - if 'uid' in member: - uid = member['uid'][0] - else: - uid = None - if 'program' in member: - program = member['program'][0] - else: - program = None - attrs = ( uid, member['cn'][0], program ) - buf += "%10s %30s\n%41s\n\n" % attrs - - return buf - - -def action_list_term(wnd): - """Interactively list members registered in a term.""" - - term = None - - # read the term - prompt = "Which term to list members for ([fws]20nn): " - while term is None or (not term == '' and not re.match('^[wsf][0-9]{4}$', term) and not term == 'exit'): - term = inputbox(wnd, prompt, 41) - - # abort when exit is entered - if not term or term.lower() == 'exit': - return False - - # connect the members module to its backends if necessary - if not members.connected(): members.connect() - - # retrieve a list of members for term - member_list = members.list_term(term) - - # format the data into a mess of text - buf = format_members(member_list.values()) - - # display the mass of text with a pager - page( buf ) - - return False - - -def action_list_name(wnd): - """Interactively search for members by name.""" - - name = None - - # read the name - prompt = "Enter the member's name: " - name = inputbox(wnd, prompt, 41) - - # abort when exit is entered - if not name or name.lower() == 'exit': - return False - - # connect the members module to its backends if necessary - if not members.connected(): members.connect() - - # retrieve a list of members with similar names - member_list = members.list_name(name) - - # format the data into a mess of text - buf = format_members(member_list.values()) - - # display the mass of text with a pager - page( buf ) - - return False - - -def null_callback(wnd): - """Callback for unimplemented menu options.""" - return False - - -def exit_callback(wnd): - """Callback for the exit option.""" - return True - - -# the top level ceo menu -top_menu = [ - ( "New member", action_new_member ), - ( "Register for a term", action_term_register ), - ( "Register for multiple terms", action_term_register_multiple ), - ( "Display a member", action_display_member ), - ( "List members registered in a term", action_list_term ), - ( "Search for a member by name", action_list_name ), - ( "Create an account", action_create_account ), - ( "Library functions", action_library ), - ( "Exit", exit_callback ), -] - - -def acquire_ceo_wnd(screen=None): - """Create the top level ceo window.""" - - # hack to get a reference to the entire screen - # even when the caller doesn't (shouldn't) have one - if screen is None: - screen = globals()['screen'] - else: - globals()['screen'] = screen - - # if the screen changes size, a mess may be left - screen.erase() - - # for some reason, the legacy ceo system - # excluded the top line from its window - height, width = screen.getmaxyx() - ceo_wnd = screen.subwin(height-1, width, 1, 0) - - # draw the border around the ceo window - curses.init_pair(1, BORDER_COLOR, -1) - color_attr = curses.color_pair(1) | curses.A_BOLD - ceo_wnd.attron(color_attr) - ceo_wnd.border() - ceo_wnd.attroff(color_attr) - - # return window and dimensions of inner area - return ceo_wnd, 1, 1, height-2, width-2 - - -def ceo_main_curses(screen): - """Wrapped main for curses.""" - - curses.use_default_colors() - - # workaround for SSH sessions on virtual consoles (reset terminal) - reset() - - # create ceo window - ceo_wnd, menu_y, menu_x, menu_height, menu_width = acquire_ceo_wnd(screen) - - try: - # display the top level menu - menu(ceo_wnd, menu_y, menu_x, menu_width, top_menu, acquire_ceo_wnd) - finally: - members.disconnect() - accounts.disconnect() - - -def run(): - """Main function for legacy UI.""" - - # workaround for xterm-color (bad terminfo? - curs_set(0) fails) - if "TERM" in os.environ and os.environ['TERM'] == "xterm-color": - os.environ['TERM'] = "xterm" - - # wrap the entire program using curses.wrapper - # so that the terminal is restored to a sane state - # when the program exits - try: - curses.wrapper(ceo_main_curses) - except KeyboardInterrupt: - pass - except curses.error: - print "Is your screen too small?" - raise - except: - reset() - raise - - # clean up screen before exit - reset() - -if __name__ == '__main__': - run() -