commit 646da21f7481a0e11a74f9550832dddef88b3726 Author: root Date: Sun Jan 25 01:07:44 2009 +0100 initial import diff --git a/dingenskirchen/mumble/__init__.py b/dingenskirchen/mumble/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dingenskirchen/mumble/__init__.pyc b/dingenskirchen/mumble/__init__.pyc new file mode 100644 index 0000000..03045ea Binary files /dev/null and b/dingenskirchen/mumble/__init__.pyc differ diff --git a/dingenskirchen/mumble/admin.py b/dingenskirchen/mumble/admin.py new file mode 100644 index 0000000..23a7c83 --- /dev/null +++ b/dingenskirchen/mumble/admin.py @@ -0,0 +1,18 @@ +from dingenskirchen.mumble.models import * +from django.contrib import admin + +class MumbleAdmin(admin.ModelAdmin): + list_display = [ 'name', 'addr', 'port', 'booted' ]; + list_filter = [ 'booted' ]; + search_fields = [ 'name', 'addr' ]; + ordering = [ 'name' ]; + +class MumbleUserAdmin(admin.ModelAdmin): + list_display = [ 'owner', 'server', 'name' ]; + list_filter = [ 'server' ]; + search_fields = [ 'owner__username', 'name' ]; + ordering = [ 'owner__username' ]; + + +admin.site.register( Mumble, MumbleAdmin ); +admin.site.register( MumbleUser, MumbleUserAdmin ); diff --git a/dingenskirchen/mumble/admin.pyc b/dingenskirchen/mumble/admin.pyc new file mode 100644 index 0000000..471a8a3 Binary files /dev/null and b/dingenskirchen/mumble/admin.pyc differ diff --git a/dingenskirchen/mumble/mmobjects.py b/dingenskirchen/mumble/mmobjects.py new file mode 100644 index 0000000..3293169 --- /dev/null +++ b/dingenskirchen/mumble/mmobjects.py @@ -0,0 +1,174 @@ +import dbus + +import datetime +from time import time + +# base = ice.stringToProxy( "Meta:tcp -h 127.0.0.1 -p 6502" ); +# srv = Murmur.ServerPrx.checkedCast( base ); +# met = Murmur.MetaPrx.checkedCast( base ); + +class mmServer( object ): + # channels = dict(); + # players = dict(); + # id = int(); + # rootName = str(); + + def __init__( self, serverID, serverObj, rootName = '' ): + if not isinstance( serverObj, dbus.ProxyObject ): + raise Exception, "mmServer: I need the object returned by dbus.get_object!" + + self.dbusObj = serverObj; + self.channels = dict(); + self.players = dict(); + self.id = serverID; + self.rootName = rootName; + + links = dict(); + + for theChan in serverObj.getChannels(): + # Channels - Fields: 0 = ID, 1 = Name, 2 = Parent-ID, 3 = Links + + if( theChan[2] == -1 ): + # No parent + self.channels[theChan[0]] = mmChannel( theChan ); + else: + self.channels[theChan[0]] = mmChannel( theChan, self.channels[theChan[2]] ); + + # process links - if the linked channels are known, link; else save their ids to link later + for linked in theChan[3]: + if linked in self.channels: + self.channels[theChan[0]].linked.append( self.channels[linked] ); + else: + if linked not in links: + links[linked] = list(); + links[linked].append( self.channels[theChan[0]] ); + #print "Saving link: %s <- %s" % ( linked, self.channels[theChan[0]] ); + + # check if earlier round trips saved channel ids to be linked to the current channel + if theChan[0] in links: + for targetChan in links[theChan[0]]: + targetChan.linked.append( self.channels[theChan[0]] ); + + if self.rootName: + self.channels[0].name = self.rootName; + + for thePlayer in serverObj.getPlayers(): + # Players - Fields: 0 = UserID, 6 = ChannelID + self.players[ thePlayer[0] ] = mmPlayer( thePlayer, self.channels[ thePlayer[6] ] ); + + + playerCount = property( + lambda self: len( self.players ), + None + ); + + def __str__( self ): + return '' % ( self.rootName, self.id ); + + def visit( self, callback, lvl = 0 ): + if not callable( callback ): + raise Exception, "a callback should be callable..."; + + # call callback first on myself, then visit my root chan + callback( self, lvl ); + self.channels[0].visit( callback, lvl + 1 ); + + +class mmChannel( object ): + # channels = list(); + # subchans = list(); + # id = int(); + # name = str(); + # parent = mmChannel(); + # linked = list(); + # linkedIDs = list(); + + def __init__( self, channelObj, parentChan = None ): + self.players = list(); + self.subchans = list(); + self.linked = list(); + + (self.id, self.name, parent, self.linkedIDs ) = channelObj; + + self.parent = parentChan; + if self.parent is not None: + self.parent.subchans.append( self ); + + def parentChannels( self ): + if self.parent is None or isinstance( self.parent, mmServer ): + return []; + return self.parent.parentChannels() + [self.parent.name]; + + playerCount = property( + lambda self: len( self.players ) + sum( [ chan.playerCount for chan in self.subchans ] ), + None + ); + + def __str__( self ): + return '' % ( self.name, self.id ); + + def visit( self, callback, lvl = 0 ): + # call callback on myself, then visit my subchans, then my players + callback( self, lvl ); + for sc in self.subchans: + sc.visit( callback, lvl + 1 ); + for pl in self.players: + pl.visit( callback, lvl + 1 ); + + + +class mmPlayer( object ): + # muted = bool; + # deafened = bool; + # suppressed = bool; + # selfmuted = bool; + # selfdeafened = bool; + + # channel = mmChannel(); + # dbaseid = int(); + # userid = int(); + # name = str(); + # onlinesince = time(); + # bytesPerSec = int(); + + def __init__( self, playerObj, playerChan ): + ( self.userid, self.muted, self.deafened, self.suppressed, self.selfmuted, self.selfdeafened, chanID, self.dbaseid, self.name, onlinetime, self.bytesPerSec ) = playerObj; + self.onlinesince = datetime.datetime.fromtimestamp( float( time() - onlinetime ) ); + self.channel = playerChan; + self.channel.players.append( self ); + + def __str__( self ): + return '' % ( self.name, self.userid, self.dbaseid ); + + def isAuthed( self ): + return self.dbaseid != -1; + + # kept for compatibility to mmChannel (useful for traversal funcs) + playerCount = property( + lambda self: -1, + None + ); + + def visit( self, callback, lvl = 0 ): + callback( self, lvl ); + + +if __name__ == '__main__': + # connect to dbus + bus = dbus.SystemBus(); + + # get our murmur servers + dbus_base = 'net.sourceforge.mumble.murmur'; + murmur = bus.get_object( dbus_base, '/' ); + + # example callback + def travrz( obj, lvl ): + print lvl*'-', str(obj); + + # show each server + for srv in murmur.getBootedServers(): + theSrv = bus.get_object( dbus_base, '/%d' % srv ); + + srvobj = mmServer( srv, theSrv, 'teh %d srvz root' % srv ); + srvobj.visit( travrz ); + diff --git a/dingenskirchen/mumble/mmobjects.pyc b/dingenskirchen/mumble/mmobjects.pyc new file mode 100644 index 0000000..94fc989 Binary files /dev/null and b/dingenskirchen/mumble/mmobjects.pyc differ diff --git a/dingenskirchen/mumble/models.py b/dingenskirchen/mumble/models.py new file mode 100644 index 0000000..d402c78 --- /dev/null +++ b/dingenskirchen/mumble/models.py @@ -0,0 +1,157 @@ +from django.contrib.auth.models import User +from django.db import models + +from mmobjects import mmServer + +import dbus +import socket + +class Mumble( models.Model ): + name = models.CharField( 'Server Name', max_length = 200 ); + dbus = models.CharField( 'DBus base', max_length = 200, default = 'net.sourceforge.mumble.murmur' ); + srvid = models.IntegerField( 'Server ID', editable = False ); + addr = models.CharField( 'Server Address', max_length = 200 ); + port = models.IntegerField( 'Server Port', blank = True, null = True ); + url = models.CharField( 'Website URL', max_length = 200, blank = True ); + motd = models.TextField( 'Welcome Message', blank = True ); + passwd = models.CharField( 'Server Password', max_length = 200, blank = True ); + users = models.IntegerField( 'Max. Users', blank = True, null = True ); + bwidth = models.IntegerField( 'Bandwidth [Bps]', blank = True, null = True ); + sslcrt = models.CharField( 'SSL Certificate', max_length = 200, blank = True ); + sslkey = models.CharField( 'SSL Key', max_length = 200, blank = True ); + booted = models.BooleanField( 'Boot Server', default = True ); + + def getDbusMeta( self ): + return dbus.SystemBus().get_object( self.dbus, '/' ); + + def getDbusObject( self ): + "Connects to DBus and returns an mmServer object representing this Murmur instance." + bus = dbus.SystemBus(); + murmur = bus.get_object( self.dbus, '/' ); + + if self.srvid not in murmur.getBootedServers(): + raise Exception, 'No murmur process with the given server ID (%d) is running and attached to system dbus under %s.' % ( self.srvid, self.dbus ); + + return bus.get_object( self.dbus, '/%d' % self.srvid ); + + def getServerObject( self ): + return mmServer( self.srvid, self.getDbusObject(), self.name ); + + def __unicode__( self ): + return u'Murmur "%s" (%d)' % ( self.name, self.srvid ); + + def save( self ): + # Prior to saving the model, connect to murmur via dbus and update its settings. + murmur = self.getDbusMeta(); + + # check if this server already exists, if not call newServer and set my srvid first + if self.id is None: + self.srvid = murmur.newServer(); + + srvid = dbus.Int32( self.srvid ); + + murmur.setConf( srvid, 'host', socket.gethostbyname( self.addr ) ); + murmur.setConf( srvid, 'registerName', self.name ); + murmur.setConf( srvid, 'registerUrl', self.url ); + murmur.setConf( srvid, 'welcometext', self.motd ); + murmur.setConf( srvid, 'serverpassword', self.passwd ); + murmur.setConf( srvid, 'sslCert', self.sslcrt ); + murmur.setConf( srvid, 'sslKey', self.sslkey ); + + if self.port is not None: + murmur.setConf( srvid, 'port', str(self.port) ); + else: + murmur.setConf( srvid, 'port', '' ); + + if self.users is not None: + murmur.setConf( srvid, 'users', str(self.users) ); + else: + murmur.setConf( srvid, 'users', '' ); + + if self.bwidth is not None: + murmur.setConf( srvid, 'bandwidth', str(self.port) ); + else: + murmur.setConf( srvid, 'bandwidth', '' ); + + # registerHostname needs to take the port no into account + if self.port and self.port != 64738: + murmur.setConf( srvid, 'registerHostname', "%s:%d" % ( self.addr, self.port ) ); + else: + murmur.setConf( srvid, 'registerHostname', self.addr ); + + if self.booted != murmur.isBooted( dbus.Int32(self.srvid) ): + if self.booted: + murmur.start( srvid ); + else: + murmur.stop( srvid ); + + # Now allow django to save the record set + return models.Model.save( self ); + + def deleteServer( self ): + srvid = dbus.Int32( self.srvid ); + murmur = self.getDbusMeta(); + if murmur.isBooted( srvid ): + murmur.stop( srvid ); + murmur.deleteServer( srvid ); + + @staticmethod + def pre_delete_listener( **kwargs ): + kwargs['instance'].deleteServer(); + + + + + +class MumbleUser( models.Model ): + mumbleid = models.IntegerField( 'Mumble player_id', editable = False, default = -1 ); + name = models.CharField( 'User name and Login', max_length = 200 ); + password = models.CharField( 'Login password', max_length = 200 ); + server = models.ForeignKey( Mumble ); + owner = models.ForeignKey( User ); + + def __unicode__( self ): + return u"Mumble user %s on %s owned by Django user %s" % ( self.name, self.server, self.owner ); + + def save( self ): + # Before the record set is saved, update Murmur via dbus. + murmur = self.server.getDbusObject(); + + if self.id is None: + # This is a new user record, so Murmur doesn't know about it yet + self.mumbleid = murmur.registerPlayer( dbus.String( self.name ) ); + + # Update user's registration + murmur.setRegistration( + dbus.Int32( self.mumbleid ), + dbus.String( self.name ), + dbus.String( self.owner.email ), + dbus.String( self.password ) + ); + + # Don't save the users' passwords, we don't need them anyway + self.password = ''; + + # Now allow django to save the record set + return models.Model.save( self ); + + @staticmethod + def pre_delete_listener( **kwargs ): + kwargs['instance'].unregister(); + + def unregister( self ): + # Unregister this player in Murmur via dbus. + murmur = self.server.getDbusObject(); + murmur.unregisterPlayer( dbus.Int32( self.mumbleid ) ); + + + + +from django.db.models import signals + +signals.pre_delete.connect( Mumble.pre_delete_listener, sender=Mumble ); +signals.pre_delete.connect( MumbleUser.pre_delete_listener, sender=MumbleUser ); + + + + diff --git a/dingenskirchen/mumble/models.pyc b/dingenskirchen/mumble/models.pyc new file mode 100644 index 0000000..396a87d Binary files /dev/null and b/dingenskirchen/mumble/models.pyc differ diff --git a/dingenskirchen/mumble/templatetags/__init__.py b/dingenskirchen/mumble/templatetags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dingenskirchen/mumble/templatetags/__init__.pyc b/dingenskirchen/mumble/templatetags/__init__.pyc new file mode 100644 index 0000000..a601cac Binary files /dev/null and b/dingenskirchen/mumble/templatetags/__init__.pyc differ diff --git a/dingenskirchen/mumble/templatetags/mumble_extras.py b/dingenskirchen/mumble/templatetags/mumble_extras.py new file mode 100644 index 0000000..3237936 --- /dev/null +++ b/dingenskirchen/mumble/templatetags/mumble_extras.py @@ -0,0 +1,16 @@ +from django import template + +register = template.Library(); + +### FILTER: mrange -- used to render the ||| lines in the channel tree + +def mrange( value ): + "If value > 1, returns range( value - 1 ), else returns an empty list." + val = int( value ); + if( val > 1 ): + return range( val - 1 ); + return list(); + +register.filter( 'mrange', mrange ); + + diff --git a/dingenskirchen/mumble/templatetags/mumble_extras.pyc b/dingenskirchen/mumble/templatetags/mumble_extras.pyc new file mode 100644 index 0000000..b241867 Binary files /dev/null and b/dingenskirchen/mumble/templatetags/mumble_extras.pyc differ diff --git a/dingenskirchen/mumble/urls.py b/dingenskirchen/mumble/urls.py new file mode 100644 index 0000000..ca002c2 --- /dev/null +++ b/dingenskirchen/mumble/urls.py @@ -0,0 +1,8 @@ +from django.conf.urls.defaults import * + +urlpatterns = patterns( + '', + ( r'savereg', 'mumble.views.savereg' ), + ( r'reg/(?P\d+)', 'mumble.views.register' ), + ( r'(?P\d+)', 'mumble.views.show' ), +) diff --git a/dingenskirchen/mumble/urls.pyc b/dingenskirchen/mumble/urls.pyc new file mode 100644 index 0000000..0c17063 Binary files /dev/null and b/dingenskirchen/mumble/urls.pyc differ diff --git a/dingenskirchen/mumble/views.py b/dingenskirchen/mumble/views.py new file mode 100644 index 0000000..dc84ce5 --- /dev/null +++ b/dingenskirchen/mumble/views.py @@ -0,0 +1,115 @@ +from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404 +from django.template import RequestContext +from django.http import HttpResponseRedirect +from django.core.urlresolvers import reverse +from django.contrib.auth.decorators import login_required + +from models import Mumble, MumbleUser +from mmobjects import mmServer, mmChannel + +import dingenskirchen; + +class Storage( object ): + s = list(); + r = None; + + +def show( request, server ): + "Displays the channel list for the given Server ID." + srv, o = createChannelList( server ); + + return render_to_response( + 'mumble/mumble.htm', + { 'DBaseObject': srv, 'ServerObject': o, 'ChannelTable': Storage.s }, + context_instance = RequestContext(request) + ); + + +def showContent( server, user = None ): + "Renders and returns the channel list for the given Server ID." + from django.template import Context, loader + + srv, o = createChannelList( server ); + + mumbleAcc = None; + if user is not None: + mmUsers = MumbleUser.objects.filter( owner = user ); + if mmUsers: + mumbleAcc = mmUsers[0]; + + t_content = loader.get_template( 'mumble/content.htm' ); + c_content = Context( { 'DBaseObject': srv, 'ServerObject': o, 'ChannelTable': Storage.s, 'user': user, 'mumbleAccount': mumbleAcc } ); + r_content = t_content.render( c_content ); + + return r_content; + + +def createChannelList( server ): + "Renders the channel list." + srv = get_object_or_404( Mumble, id=server ); + + o = srv.getServerObject(); + + Storage.s = list(); + Storage.r = o.channels[0]; + o.channels[0].visit( renderListItem, 0 ); + + return srv, o; + + +def renderListItem( item, level ): + "Stores a line in the channel list." + if item == Storage.r: + return; + + # Filter channels that don't have players in them and are not a subchannel of root + if level > 1 and item.playerCount == 0: + # I used to test if item is an instance of mmChannel here. For some reason, that doesn't work. Dunno why. + return; + + if isinstance( item, mmChannel ): + Storage.s.append( ( level, item, item.parentChannels() ) ); + else: + Storage.s.append( ( level, item ) ); + + + +@login_required +def register( request, server ): + # Register the current user with this mumble server, or give them a form to change their registration data. + srv = Mumble.objects.get( id=server ); + + if request.user.is_authenticated(): + reg = MumbleUser.objects.get( server=srv, owner=request.user ); + else: + reg = None; + + return render_to_response( + 'mumble/reg.htm', + { 'Mumble': srv, 'Reg': reg }, + context_instance = RequestContext(request) + ); + +@login_required +def savereg( request ): + #if not request.user.is_authenticated(): + # raise Exception, "You need to be logged in to register yourself with Mumble."; + + srv = Mumble.objects.get( id=request.POST['id'] ); + reg = MumbleUser.objects.get( server=srv, owner=request.user ); + + if reg is None: + reg = MumbleUser( name=request.POST['username'], password=request.POST['password'], server=srv, owner=request.user ); + else: + reg.name = request.POST['username']; + reg.password = request.POST['password']; + + reg.save(); + return HttpResponseRedirect( "/mumble/%d" % srv.id ); + + + + + + + diff --git a/dingenskirchen/mumble/views.pyc b/dingenskirchen/mumble/views.pyc new file mode 100644 index 0000000..a34036e Binary files /dev/null and b/dingenskirchen/mumble/views.pyc differ diff --git a/template/mumble/content.htm b/template/mumble/content.htm new file mode 100644 index 0000000..e292e9d --- /dev/null +++ b/template/mumble/content.htm @@ -0,0 +1,54 @@ +{% load mumble_extras %} +
+ + + + + {% for item in ChannelTable %} + + + + + {% endfor %} +
+ mumble + {{ ServerObject.rootName }} +
+ {% spaceless %} + {% for num in item.0|mrange %} + | + {% endfor %} + +- + {% endspaceless %} + {% if item.1.userid %} + player + {{ item.1.name }} + {% else %} + {% if item.1.linked %} + linked channel + {% else %} + channel + {% endif %} + {{ item.1.name }} + {% endif %} + + {% if item.1.userid %} + {% if item.1.isAuthed %} + authed + {% endif %} + {% if item.1.muted %} + muted + {% endif %} + {% if item.1.deafened %} + deafened + {% endif %} + {% if item.1.selfmuted %} + self-muted + {% endif %} + {% if item.1.selfdeafened %} + self-deafened + {% endif %} + {% endif %} +
+

Mumble-Account verwalten

+
diff --git a/template/mumble/content.htm.bak b/template/mumble/content.htm.bak new file mode 100644 index 0000000..7f25edd --- /dev/null +++ b/template/mumble/content.htm.bak @@ -0,0 +1,47 @@ +{% load mumble_extras %} +
+
+ mumble + {{ ServerObject.rootName }} +
+ {% for item in ChannelTable %} +
+ {% spaceless %} + {% for num in item.0|mrange %} + | + {% endfor %} + +- + {% endspaceless %} + {% if item.1.userid %} + player + {{ item.1.name }} + {% else %} + {% if item.1.linked %} + linked channel + {% else %} + channel + {% endif %} + {{ item.1.name }} + {% endif %} + + {% if item.1.userid %} + {% if item.1.isAuthed %} + authed + {% endif %} + {% if item.1.muted %} + muted + {% endif %} + {% if item.1.deafened %} + deafened + {% endif %} + {% if item.1.selfmuted %} + self-muted + {% endif %} + {% if item.1.selfdeafened %} + self-deafened + {% endif %} + {% endif %} + +
+ {% endfor %} +
diff --git a/template/mumble/mumble.htm b/template/mumble/mumble.htm new file mode 100644 index 0000000..fecb7ec --- /dev/null +++ b/template/mumble/mumble.htm @@ -0,0 +1,10 @@ +{% extends "base.htm" %} +{% block modelstyle %} + {% include "mumble/style.htm" %} +{% endblock %} +{% block headtags %} + +{% endblock %} +{% block content %} + {% include "mumble/content.htm" %} +{% endblock %} diff --git a/template/mumble/reg.htm b/template/mumble/reg.htm new file mode 100644 index 0000000..99207d4 --- /dev/null +++ b/template/mumble/reg.htm @@ -0,0 +1,29 @@ +{% extends "base.htm" %} +{% block content %} +{% if user.is_authenticated %} +

Mumble-Benutzerdaten festlegen

+

Diese Logindaten musst du angeben, um als authentifizierter Benutzer zu Mumble zu verbinden. Gib hier bitte deinen gewünschten Benutzernamen und dein gewünschtes Passwort an.

+
+ + + + + + + + + + + + + + + + + +
Server{{Mumble.name}}
Benutzername/Login
Passwort
+
+{% else %} +

Dieses Privileg steht nur den Mitgliedern des Hohen Rates zu.

+{% endif %} +{% endblock %} diff --git a/template/mumble/style.htm b/template/mumble/style.htm new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/template/mumble/style.htm @@ -0,0 +1 @@ +