diff --git a/AUTHORS b/AUTHORS index 734c050..2d613ac 100644 --- a/AUTHORS +++ b/AUTHORS @@ -8,3 +8,4 @@ Others who have contributed to the application: * Thorvald "slicer" Natvig (helped a million with the Debian packaging) * Philipp "nethead" Wollermann (base path autodetection) +* Nico Wollenzin (gave Mumble Commander its name) diff --git a/cli.py b/muco.py similarity index 64% rename from cli.py rename to muco.py index 5f94f5f..b896fec 100755 --- a/cli.py +++ b/muco.py @@ -43,6 +43,7 @@ import locale import curses from curses.textpad import Textbox +from django.core.exceptions import ValidationError from django.db.models.fields.related import ForeignKey from django.db import models @@ -52,187 +53,6 @@ from mumble.forms import * locale.setlocale(locale.LC_ALL, '') -def getNum( prompt, **kwargs ): - id = None; - while type(id) != int: - print - try: - id = raw_input( "%s >>> " % prompt ).strip(); - if id == 'q': - return None; - elif id in kwargs: - return kwargs[id]; - id = int( id ); - except Exception, instance: - print "Error reading input. Did you type a number?"; - print instance; - return id; - -def util_editModel( model, blacklist = None ): - while True: - print "Current settings" - print "================" - for field in model._meta.fields: - if blacklist and field.name in blacklist: - continue; - - print "#%-5d %-30s %s" % ( model._meta.fields.index( field ), field.verbose_name, getattr( model, field.name ) ); - - print "================" - print "Enter the index of the parameter you would like to change," - print "or q to return." - - idx = getNum( "Index" ); - if idx is None: - save = raw_input( "save? Y/n >>> " ); - if not save or save.lower() == 'y': - print "saving changes."; - model.save(); - else: - print "NOT saving changes." - return; - - field = model._meta.fields[idx]; - if blacklist and field.name in blacklist: - print "This field can not be changed."; - elif isinstance( field, ForeignKey ): - print "This is a ForeignKey."; - print field.rel.to.objects.all(); - else: - value = None; - while value is None: - print - try: - value = field.to_python( raw_input( "%s >>> " % field.name ).strip() ); - except Exception, instance: - print instance; - setattr( model, field.name, value ); - - -def act_serverDetails( server ): - "View or edit server settings." - util_editModel( server, ( "id", "sslcrt", "sslkey" ) ); - - -def act_registeredUsers( server ): - "View or edit user registrations." - - mumbleusers_list = server.mumbleuser_set.all(); - - print "Currently registered accounts"; - print "============================="; - - for mu in mumbleusers_list: - if mu.owner is not None: - print "#%-5d %-20s Owner: %-20s Admin: %s" % ( mu.id, mu.name, mu.owner.username, mu.getAdmin() ); - else: - print "#%-5d %-20s" % ( mu.id, mu.name ); - - print "============================="; - print "Enter the ID of the account you would like to change, n to create a new one, or q to return." - - while True: - idx = getNum( "ID", n=-1 ); - if idx is None: - return; - - if idx == -1: - mu = MumbleUser(); - mu.server = server; - else: - mu = mumbleusers_list.get( id=idx ); - - util_editModel( mu, ( "id", "mumbleid", "server" ) ); - - -def act_listChannels( server ): - "Display a channel tree." - - def printItem( item, level ): - print "%s%s" % ( " "*level, item ); - - server.rootchan.visit( printItem ); - - -def act_chanDetails( server ): - "Display detailed information about one specific channel." - print "Please choose the channel by entering the according ID (the number in parentheses)." - act_listChannels( server ); - - id = getNum( "ID" ); - if id is None: return; - - print "Channel name: %s" % server.channels[id].name - print "Channel ID: %d" % server.channels[id].chanid - print "Users online: %d" % len( server.channels[id].players ) - print "Linked chans: %d" % len( server.channels[id].linked ) - - -def cli_chooseServer(): - mumble_all = Mumble.objects.all().order_by( 'name', 'id' ); - - print "Please choose a Server instance by typing the corresponding ID.\n"; - - for mm in mumble_all: - print "#%d\t%s" % ( mm.id, mm.name ); - print "n: Create new instance"; - print "q: Exit"; - - id = getNum( "ID", n = -1 ); - - if id is None: - return; - elif id == -1: - return Mumble(); - - return Mumble.objects.get( id=id ); - - -def cli_chooseAction( server ): - actions = { - "LISTCHAN": act_listChannels, - "CHANINFO": act_chanDetails, - "EDITSERVER": act_serverDetails, - "EDITUSERS": act_registeredUsers, - }; - - while True: - print "What do you want to do?" - - keys = actions.keys(); - - for act in keys: - print "#%-5d %-20s %s" % ( keys.index(act), act, actions[act].__doc__ ); - print "q: Return to server selection"; - - idx = getNum( "Index" ); - if idx is None: - return; - - # call action function - func = actions[ keys[idx] ] - func( server ); - print - - - -def oldmain(): - print - - while True: - mumble = cli_chooseServer(); - if mumble is None: - print "Bye."; - return; - - print "Selected %s." % mumble; - print - - cli_chooseAction( mumble ); - print - - - class BaseWindow( object ): tabName = "tehBasez"; @@ -260,13 +80,13 @@ class WndChannels( BaseWindow ): tabName = 'Channels'; def printItem( self, item, level ): - str = ""; + namestr = ""; if item.is_server or item.is_channel: - str = "%s (Channel)" % item.name; + namestr = "%s (Channel)" % item.name; else: - str = "%s (Player)" % item.name + namestr = "%s (Player)" % item.name - self.win.addstr( self.curr_y, 4*level+1, str.encode(locale.getpreferredencoding()) ) + self.win.addstr( self.curr_y, 4*level+1, namestr.encode(locale.getpreferredencoding()) ) self.curr_y += 1; def draw( self ): @@ -355,8 +175,22 @@ class WndSettings( BaseWindow ): self.win.addstr( 1, 5, msg.encode(locale.getpreferredencoding()) ); elif key in ( curses.KEY_RIGHT, curses.KEY_ENTER, ord('\n') ): - self.editors[field.name][1].edit(); - setattr( self.mm, field.name, field.to_python( self.editors[field.name][1].gather().strip() ) ); + valid = False; + while not valid: + self.editors[field.name][1].edit(); + try: + setattr( self.mm, field.name, + field.to_python( self.editors[field.name][1].gather().strip() ) + ); + except ValidationError, instance: + msg = unicode( instance ); + self.win.addstr( 1, 5, msg.encode(locale.getpreferredencoding()), curses.A_STANDOUT ); + self.win.refresh(); + else: + valid = True; + self.win.move( 1, 5 ); + self.win.clrtoeol(); + self.editors[field.name][0].refresh(); self.win.addstr( @@ -364,8 +198,17 @@ class WndSettings( BaseWindow ): field.verbose_name.encode(locale.getpreferredencoding()) ); + class WndUsers( BaseWindow ): tabName = 'Registered users'; + + def draw( self ): + curr_y = 3; + + for acc in self.mm.mumbleuser_set.all(): + self.win.addstr( curr_y, 1, acc.name.encode(locale.getpreferredencoding()) ); + curr_y += 1; + class MumbleForm( object ): @@ -453,9 +296,14 @@ def main( stdscr ): selectedIdx = 0; selectedMax = len(mumbles) - 1; + myname = "Mumble Commander"; + while( True ): selectedObj = mumbles[selectedIdx]; + maxyx = stdscr.getmaxyx(); + stdscr.addstr( 0, maxyx[1] / 2 - len(myname)/2, myname, curses.A_UNDERLINE ); + # Draw selection marker stdscr.addstr( first_y + selectedIdx, 3, '*' ); stdscr.refresh(); @@ -471,6 +319,7 @@ def main( stdscr ): elif key in ( curses.KEY_RIGHT, curses.KEY_ENTER, ord('\n') ): stdscr.clear(); + stdscr.addstr( 0, maxyx[1] / 2 - len(myname)/2, myname, curses.A_UNDERLINE ); selectedObj.mvwin( 5, first_y ); selectedObj.draw(); stdscr.refresh();