Remove mumble-django, use direct API.

This commit is contained in:
2010-05-17 22:35:49 +01:00
parent 1b76ccc698
commit 12287f25b6
68 changed files with 29 additions and 7720 deletions

View File

@@ -1,331 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009, withgod <withgod@sourceforge.net>
* 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
from PIL import Image
from struct import pack, unpack
from zlib import compress, decompress
from mctl import MumbleCtlBase
from utils import ObjectInfo
import dbus
from dbus.exceptions import DBusException
def MumbleCtlDbus( connstring ):
""" Choose the correct DBus handler (1.1.8 or legacy) to use. """
meta = dbus.Interface( dbus.SystemBus().get_object( connstring, '/' ), 'net.sourceforge.mumble.Meta' );
try:
meta.getVersion();
except DBusException:
return MumbleCtlDbus_Legacy( connstring, meta );
else:
return MumbleCtlDbus_118( connstring, meta );
class MumbleCtlDbus_118(MumbleCtlBase):
method = "DBus";
def __init__( self, connstring, meta ):
self.dbus_base = connstring;
self.meta = meta;
def _getDbusMeta( self ):
return self.meta;
def _getDbusServerObject( self, srvid):
if srvid not in self.getBootedServers():
raise SystemError, 'No murmur process with the given server ID (%d) is running and attached to system dbus under %s.' % ( srvid, self.meta );
return dbus.Interface( dbus.SystemBus().get_object( self.dbus_base, '/%d' % srvid ), 'net.sourceforge.mumble.Murmur' );
def getVersion( self ):
return MumbleCtlDbus_118.convertDbusTypeToNative( self.meta.getVersion() );
def getAllConf(self, srvid):
conf = self.meta.getAllConf(dbus.Int32(srvid))
info = {};
for key in conf:
if key == "playername":
info['username'] = conf[key];
else:
info[str(key)] = conf[key];
return info;
def getConf(self, srvid, key):
if key == "username":
key = "playername";
return self.meta.getConf(dbus.Int32( srvid ), key)
def setConf(self, srvid, key, value):
if key == "username":
key = "playername";
self.meta.setConf(dbus.Int32( srvid ), key, value)
def getDefaultConf(self):
conf = self.meta.getDefaultConf()
info = {};
for key in conf:
if key == "playername":
info['username'] = conf[key];
else:
info[str(key)] = conf[key];
return info;
def start( self, srvid ):
self.meta.start( srvid );
def stop( self, srvid ):
self.meta.stop( srvid );
def isBooted( self, srvid ):
return bool( self.meta.isBooted( srvid ) );
def deleteServer( self, srvid ):
srvid = dbus.Int32( srvid )
if self.meta.isBooted( srvid ):
self.meta.stop( srvid )
self.meta.deleteServer( srvid )
def newServer(self):
return self.meta.newServer()
def registerPlayer(self, srvid, name, email, password):
mumbleid = int( self._getDbusServerObject(srvid).registerPlayer(name) );
self.setRegistration( srvid, mumbleid, name, email, password );
return mumbleid;
def unregisterPlayer(self, srvid, mumbleid):
self._getDbusServerObject(srvid).unregisterPlayer(dbus.Int32( mumbleid ))
def getChannels(self, srvid):
chans = self._getDbusServerObject(srvid).getChannels()
ret = {};
for channel in chans:
print channel;
ret[ channel[0] ] = ObjectInfo(
id = int(channel[0]),
name = unicode(channel[1]),
parent = int(channel[2]),
links = [ int(lnk) for lnk in channel[3] ],
);
return ret;
def getPlayers(self, srvid):
players = self._getDbusServerObject(srvid).getPlayers();
ret = {};
for playerObj in players:
ret[ int(playerObj[0]) ] = ObjectInfo(
session = int( playerObj[0] ),
mute = bool( playerObj[1] ),
deaf = bool( playerObj[2] ),
suppress = bool( playerObj[3] ),
selfMute = bool( playerObj[4] ),
selfDeaf = bool( playerObj[5] ),
channel = int( playerObj[6] ),
userid = int( playerObj[7] ),
name = unicode( playerObj[8] ),
onlinesecs = int( playerObj[9] ),
bytespersec = int( playerObj[10] )
);
return ret;
def getRegisteredPlayers(self, srvid, filter = ''):
users = self._getDbusServerObject(srvid).getRegisteredPlayers( filter );
ret = {};
for user in users:
ret[int(user[0])] = ObjectInfo(
userid = int( user[0] ),
name = unicode( user[1] ),
email = unicode( user[2] ),
pw = unicode( user[3] )
);
return ret
def getACL(self, srvid, channelid):
raw_acls, raw_groups, raw_inherit = self._getDbusServerObject(srvid).getACL(channelid)
acls = [ ObjectInfo(
applyHere = bool(rule[0]),
applySubs = bool(rule[1]),
inherited = bool(rule[2]),
userid = int(rule[3]),
group = unicode(rule[4]),
allow = int(rule[5]),
deny = int(rule[6]),
)
for rule in raw_acls
];
groups = [ ObjectInfo(
name = unicode(group[0]),
inherited = bool(group[1]),
inherit = bool(group[2]),
inheritable = bool(group[3]),
add = [ int(usrid) for usrid in group[4] ],
remove = [ int(usrid) for usrid in group[5] ],
members = [ int(usrid) for usrid in group[6] ],
)
for group in raw_groups
];
return acls, groups, bool(raw_inherit);
def setACL(self, srvid, channelid, acls, groups, inherit):
# Pack acl ObjectInfo into a tuple and send that over dbus
dbus_acls = [
( rule.applyHere, rule.applySubs, rule.inherited, rule.userid, rule.group, rule.allow, rule.deny )
for rule in acls
];
dbus_groups = [
( group.name, group.inherited, group.inherit, group.inheritable, group.add, group.remove, group.members )
for group in groups
];
return self._getDbusServerObject(srvid).setACL( channelid, dbus_acls, dbus_groups, inherit );
def getBootedServers(self):
return MumbleCtlDbus_118.convertDbusTypeToNative(self.meta.getBootedServers())
def getAllServers(self):
return MumbleCtlDbus_118.convertDbusTypeToNative(self.meta.getAllServers())
def setSuperUserPassword(self, srvid, value):
self.meta.setSuperUserPassword(dbus.Int32(srvid), value)
def getRegistration(self, srvid, mumbleid):
user = self._getDbusServerObject(srvid).getRegistration(dbus.Int32(mumbleid))
return ObjectInfo(
userid = mumbleid,
name = unicode(user[1]),
email = unicode(user[2]),
pw = '',
);
def setRegistration(self, srvid, mumbleid, name, email, password):
return MumbleCtlDbus_118.convertDbusTypeToNative(
self._getDbusServerObject(srvid).setRegistration(dbus.Int32(mumbleid), name, email, password)
)
def getTexture(self, srvid, mumbleid):
texture = self._getDbusServerObject(srvid).getTexture(dbus.Int32(mumbleid));
if len(texture) == 0:
raise ValueError( "No Texture has been set." );
# this returns a list of bytes.
# first 4 bytes: Length of uncompressed string, rest: compressed data
orig_len = ( texture[0] << 24 ) | ( texture[1] << 16 ) | ( texture[2] << 8 ) | ( texture[3] );
# convert rest to string and run decompress
bytestr = "";
for byte in texture[4:]:
bytestr += pack( "B", int(byte) );
decompressed = decompress( bytestr );
# iterate over 4 byte chunks of the string
imgdata = "";
for idx in range( 0, orig_len, 4 ):
# read 4 bytes = BGRA and convert to RGBA
bgra = unpack( "4B", decompressed[idx:idx+4] );
imgdata += pack( "4B", bgra[2], bgra[1], bgra[0], bgra[3] );
# return an 600x60 RGBA image object created from the data
return Image.fromstring( "RGBA", ( 600, 60 ), imgdata);
def setTexture(self, srvid, mumbleid, infile):
# open image, convert to RGBA, and resize to 600x60
img = infile.convert( "RGBA" ).transform( ( 600, 60 ), Image.EXTENT, ( 0, 0, 600, 60 ) );
# iterate over the list and pack everything into a string
bgrastring = "";
for ent in list( img.getdata() ):
# ent is in RGBA format, but Murmur wants BGRA (ARGB inverse), so stuff needs
# to be reordered when passed to pack()
bgrastring += pack( "4B", ent[2], ent[1], ent[0], ent[3] );
# compress using zlib
compressed = compress( bgrastring );
# pack the original length in 4 byte big endian, and concat the compressed
# data to it to emulate qCompress().
texture = pack( ">L", len(bgrastring) ) + compressed;
# finally call murmur and set the texture
self._getDbusServerObject(srvid).setTexture(dbus.Int32( mumbleid ), texture)
def verifyPassword( self, srvid, username, password ):
player = self.getRegisteredPlayers( srvid, username );
if not player:
return -2;
ok = MumbleCtlDbus_118.convertDbusTypeToNative(
self._getDbusServerObject(srvid).verifyPassword( dbus.Int32( player[0].userid ), password )
);
if ok:
return player[0].userid;
else:
return -1;
@staticmethod
def convertDbusTypeToNative(data):
#i know dbus.* type is extends python native type.
#but dbus.* type is not native type. it's not good transparent for using Ice/Dbus.
ret = None
if isinstance(data, tuple) or type(data) is data.__class__ is dbus.Array or data.__class__ is dbus.Struct:
ret = []
for x in data:
ret.append(MumbleCtlDbus_118.convertDbusTypeToNative(x))
elif data.__class__ is dbus.Dictionary:
ret = {}
for x in data.items():
ret[MumbleCtlDbus_118.convertDbusTypeToNative(x[0])] = MumbleCtlDbus_118.convertDbusTypeToNative(x[1])
else:
if data.__class__ is dbus.Boolean:
ret = bool(data)
elif data.__class__ is dbus.String:
ret = unicode(data)
elif data.__class__ is dbus.Int32 or data.__class__ is dbus.UInt32:
ret = int(data)
elif data.__class__ is dbus.Byte:
ret = int(data)
return ret
class MumbleCtlDbus_Legacy( MumbleCtlDbus_118 ):
def getVersion( self ):
return ( 1, 1, 4, u"1.1.4" );
def setRegistration(self, srvid, mumbleid, name, email, password):
return MumbleCtlDbus_118.convertDbusTypeToNative(
self._getDbusServerObject(srvid).updateRegistration( ( dbus.Int32(mumbleid), name, email, password ) )
)

View File

@@ -1,14 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""

View File

@@ -1,138 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
from django.conf import settings
from django.contrib import admin
from django.utils.translation import ugettext_lazy as _
from mumble.forms import MumbleServerForm, MumbleAdminForm, MumbleUserAdminForm
from mumble.models import MumbleServer, Mumble, MumbleUser
class MumbleServerAdmin(admin.ModelAdmin):
list_display = [ 'dbus', 'get_murmur_online' ]
search_fields = [ 'dbus' ]
ordering = [ 'dbus' ]
form = MumbleServerForm
def get_murmur_online( self, obj ):
return obj.online
get_murmur_online.short_description = _('Master is running')
get_murmur_online.boolean = True
class MumbleAdmin(admin.ModelAdmin):
""" Specification for the "Server administration" admin section. """
list_display = [ 'name', 'srvid', 'get_addr', 'get_port', 'get_murmur_online', 'get_booted',
'get_is_public', 'get_users_regged', 'get_users_online', 'get_channel_count' ];
list_filter = [ 'addr', 'server' ];
search_fields = [ 'name', 'addr', 'port' ];
ordering = [ 'name' ];
form = MumbleAdminForm;
def get_murmur_online( self, obj ):
return obj.server.online
get_murmur_online.short_description = _('Master is running')
get_murmur_online.boolean = True
def get_addr( self, obj ):
if not obj.addr:
return "*"
return obj.addr
get_addr.short_description = _('Server Address')
def get_port( self, obj ):
if not obj.port:
return "< %d >" % (settings.MUMBLE_DEFAULT_PORT + obj.srvid - 1)
return obj.port
get_port.short_description = _('Server Port')
def get_booted( self, obj ):
return obj.booted
get_booted.short_description = _('Instance is running')
get_booted.boolean = True
def get_users_regged( self, obj ):
""" Populates the "Registered users" column. """
if obj.booted:
return obj.users_regged;
else:
return '-';
get_users_regged.short_description = _( 'Registered users' );
def get_users_online( self, obj ):
""" Populates the "Online users" column. """
if obj.booted:
return obj.users_online;
else:
return '-';
get_users_online.short_description = _( 'Online users' );
def get_channel_count( self, obj ):
""" Populates the "Channel Count" column. """
if obj.booted:
return obj.channel_cnt;
else:
return '-';
get_channel_count.short_description = _( 'Channel count' );
def get_is_public( self, obj ):
""" Populates the "Public" column. """
if obj.booted:
if obj.is_public:
return _( 'Yes' );
else:
return _( 'No' );
else:
return '-';
get_is_public.short_description = _( 'Public' );
class MumbleUserAdmin(admin.ModelAdmin):
""" Specification for the "Registered users" admin section. """
list_display = [ 'owner', 'server', 'name', 'get_acl_admin' ];
list_filter = [ 'server' ];
search_fields = [ 'owner__username', 'name' ];
ordering = [ 'owner__username' ];
form = MumbleUserAdminForm
def get_acl_admin( self, obj ):
if obj.server.booted:
return obj.aclAdmin
return None
get_acl_admin.short_description = _('Admin on root channel')
get_acl_admin.boolean = True
admin.site.register( MumbleServer, MumbleServerAdmin );
admin.site.register( Mumble, MumbleAdmin );
admin.site.register( MumbleUser, MumbleUserAdmin );

View File

@@ -1,18 +0,0 @@
BEGIN;
-- Model: Mumble
ALTER TABLE `mumble_mumble`
ADD `server_id` integer FIRST;
ALTER TABLE `mumble_mumble`
ADD `display` varchar(200) AFTER `name`;
ALTER TABLE `mumble_mumble`
MODIFY `port` integer NULL;
COMMIT;
BEGIN;
ALTER TABLE mumble_mumble DROP KEY `addr`;
COMMIT;
BEGIN;
CREATE INDEX `mumble_mumble_server_id_idx`
ON `mumble_mumble` (`server_id`);
COMMIT;

View File

@@ -1,3 +0,0 @@
INSERT INTO `mumble_mumbleserver` ( `dbus`, `secret` )
SELECT DISTINCT `dbus`, ''
FROM `mumble_mumble`;

View File

@@ -1,6 +0,0 @@
UPDATE `mumble_mumble`
SET `server_id`=(
SELECT `id`
FROM `mumble_mumbleserver`
WHERE `mumble_mumbleserver`.`dbus` = `mumble_mumble`.`dbus`
);

View File

@@ -1,29 +0,0 @@
-- Model: Mumble
ALTER TABLE `mumble_mumble`
DROP COLUMN `dbus`;
ALTER TABLE `mumble_mumble`
DROP COLUMN `url`;
ALTER TABLE `mumble_mumble`
DROP COLUMN `motd`;
ALTER TABLE `mumble_mumble`
DROP COLUMN `passwd`;
ALTER TABLE `mumble_mumble`
DROP COLUMN `supw`;
ALTER TABLE `mumble_mumble`
DROP COLUMN `users`;
ALTER TABLE `mumble_mumble`
DROP COLUMN `bwidth`;
ALTER TABLE `mumble_mumble`
DROP COLUMN `sslcrt`;
ALTER TABLE `mumble_mumble`
DROP COLUMN `sslkey`;
ALTER TABLE `mumble_mumble`
DROP COLUMN `obfsc`;
ALTER TABLE `mumble_mumble`
DROP COLUMN `player`;
ALTER TABLE `mumble_mumble`
DROP COLUMN `channel`;
ALTER TABLE `mumble_mumble`
DROP COLUMN `defchan`;
ALTER TABLE `mumble_mumble`
DROP COLUMN `booted`;

View File

@@ -1,3 +0,0 @@
-- Model: MumbleUser
ALTER TABLE `mumble_mumbleuser`
DROP COLUMN `isAdmin`;

View File

@@ -1,13 +0,0 @@
-- Model: Mumble
BEGIN;
ALTER TABLE "mumble_mumble"
ADD "server_id" integer NULL REFERENCES "mumble_mumbleserver" ("id") DEFERRABLE INITIALLY DEFERRED;
ALTER TABLE "mumble_mumble"
ADD "display" varchar(200);
ALTER TABLE "mumble_mumble"
ALTER "port" DROP NOT NULL;
CREATE INDEX "mumble_mumble_server_id" ON "mumble_mumble" ("server_id");
ALTER TABLE "mumble_mumble" DROP CONSTRAINT "mumble_mumble_addr_key";
COMMIT;

View File

@@ -1,5 +0,0 @@
BEGIN;
INSERT INTO "mumble_mumbleserver" ( "dbus", "secret" )
SELECT DISTINCT "dbus", ''
FROM "mumble_mumble";
COMMIT;

View File

@@ -1,8 +0,0 @@
BEGIN;
UPDATE "mumble_mumble"
SET "server_id"=(
SELECT "id"
FROM "mumble_mumbleserver"
WHERE "mumble_mumbleserver"."dbus" = "mumble_mumble"."dbus"
);
COMMIT;

View File

@@ -1,34 +0,0 @@
-- Model: Mumble
BEGIN;
ALTER TABLE "mumble_mumble"
DROP COLUMN "dbus";
ALTER TABLE "mumble_mumble"
DROP COLUMN "url";
ALTER TABLE "mumble_mumble"
DROP COLUMN "motd";
ALTER TABLE "mumble_mumble"
DROP COLUMN "passwd";
ALTER TABLE "mumble_mumble"
DROP COLUMN "supw";
ALTER TABLE "mumble_mumble"
DROP COLUMN "users";
ALTER TABLE "mumble_mumble"
DROP COLUMN "bwidth";
ALTER TABLE "mumble_mumble"
DROP COLUMN "sslcrt";
ALTER TABLE "mumble_mumble"
DROP COLUMN "sslkey";
ALTER TABLE "mumble_mumble"
DROP COLUMN "obfsc";
ALTER TABLE "mumble_mumble"
DROP COLUMN "player";
ALTER TABLE "mumble_mumble"
DROP COLUMN "channel";
ALTER TABLE "mumble_mumble"
DROP COLUMN "defchan";
ALTER TABLE "mumble_mumble"
DROP COLUMN "booted";
ALTER TABLE "mumble_mumble"
ALTER COLUMN "server_id" SET NOT NULL;
COMMIT;

View File

@@ -1,5 +0,0 @@
-- Model: MumbleUser
BEGIN;
ALTER TABLE "mumble_mumbleuser"
DROP COLUMN "isAdmin";
COMMIT;

View File

@@ -1,10 +0,0 @@
CREATE TABLE "mumble_mumble_new" (
"id" integer NOT NULL PRIMARY KEY,
"server_id" integer NOT NULL REFERENCES "mumble_mumbleserver" ("id"),
"name" varchar(200) NOT NULL,
"srvid" integer NOT NULL,
"addr" varchar(200) NOT NULL,
"port" integer,
"display" varchar(200) NOT NULL,
UNIQUE ("server_id", "srvid")
);

View File

@@ -1,10 +0,0 @@
CREATE TABLE "mumble_mumbleuser_new" (
"id" integer NOT NULL PRIMARY KEY,
"mumbleid" integer NOT NULL,
"name" varchar(200) NOT NULL,
"password" varchar(200) NOT NULL,
"server_id" integer NOT NULL REFERENCES "mumble_mumble" ("id"),
"owner_id" integer REFERENCES "auth_user" ("id"),
UNIQUE ("server_id", "owner_id"),
UNIQUE ("server_id", "mumbleid")
);

View File

@@ -1,3 +0,0 @@
INSERT INTO "mumble_mumbleserver" ( "dbus", "secret" )
SELECT DISTINCT "dbus", ''
FROM "mumble_mumble";

View File

@@ -1,11 +0,0 @@
INSERT INTO "mumble_mumble_new"
SELECT
"mumble_mumble"."id",
"mumble_mumbleserver"."id",
"mumble_mumble"."name",
"mumble_mumble"."srvid",
"mumble_mumble"."addr",
"mumble_mumble"."port",
''
FROM "mumble_mumble" INNER JOIN "mumble_mumbleserver"
WHERE "mumble_mumbleserver"."dbus" = "mumble_mumble"."dbus";

View File

@@ -1,9 +0,0 @@
INSERT INTO "mumble_mumbleuser_new"
SELECT
"id",
"mumbleid",
"name",
"password",
"server_id",
"owner_id"
FROM "mumble_mumbleuser";

View File

@@ -1 +0,0 @@
DROP TABLE "mumble_mumble";

View File

@@ -1 +0,0 @@
ALTER TABLE "mumble_mumble_new" RENAME TO "mumble_mumble";

View File

@@ -1 +0,0 @@
DROP TABLE "mumble_mumbleuser";

View File

@@ -1 +0,0 @@
ALTER TABLE "mumble_mumbleuser_new" RENAME TO "mumble_mumbleuser";

View File

@@ -1 +0,0 @@
SEQUENCE = ['mumble-db-update-1']

View File

@@ -1,10 +0,0 @@
from django_evolution.mutations import *
from django.db import models
MUTATIONS = [
AddField('Mumble', 'display', models.CharField, initial='', max_length=200),
AddField('Mumble', 'server', models.ForeignKey, initial='<<USER VALUE REQUIRED>>', related_model='mumble.MumbleServer'),
DeleteField('Mumble', 'dbus'),
ChangeField('Mumble', 'port', initial=None, null=True)
]

View File

@@ -1,324 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
import socket
import re
from django import forms
from django.conf import settings
from django.forms import Form, ModelForm
from django.utils.translation import ugettext_lazy as _
from mumble.models import MumbleServer, Mumble, MumbleUser
class PropertyModelForm( ModelForm ):
""" ModelForm that gets/sets fields that are not within the model's
fields as model attributes. Necessary to get forms that manipulate
properties.
"""
def __init__( self, *args, **kwargs ):
ModelForm.__init__( self, *args, **kwargs );
if self.instance:
instfields = self.instance._meta.get_all_field_names()
for fldname in self.fields:
if fldname in instfields:
continue
self.fields[fldname].initial = getattr( self.instance, fldname )
prop = getattr( self.instance.__class__, fldname )
if prop.__doc__:
self.fields[fldname].label = _(prop.__doc__)
def save( self, commit=True ):
inst = ModelForm.save( self, commit=commit )
if commit:
self.save_to_model( inst )
else:
# Update when the model has been saved.
from django.db.models import signals
self._update_inst = inst
signals.post_save.connect( self.save_listener, sender=inst.__class__ )
return inst
def save_listener( self, **kwargs ):
if kwargs['instance'] is self._update_inst:
self.save_to_model( self._update_inst )
def save_to_model( self, inst ):
instfields = inst._meta.get_all_field_names()
for fldname in self.fields:
if fldname not in instfields:
setattr( inst, fldname, self.cleaned_data[fldname] )
class MumbleForm( PropertyModelForm ):
""" The Mumble Server admin form that allows to configure settings which do
not necessarily have to be reserved to the server hoster.
Server hosters are expected to use the Django admin application instead,
where everything can be configured freely.
"""
url = forms.CharField( required=False )
motd = forms.CharField( required=False, widget=forms.Textarea )
passwd = forms.CharField( required=False, help_text=_(
"Password required to join. Leave empty for public servers.") )
supw = forms.CharField( required=False )
obfsc = forms.BooleanField( required=False, help_text=_(
"If on, IP adresses of the clients are not logged.") )
player = forms.CharField( required=False )
channel = forms.CharField( required=False )
defchan = forms.TypedChoiceField( choices=(), coerce=int, required=False )
timeout = forms.IntegerField( required=False )
certreq = forms.BooleanField( required=False )
textlen = forms.IntegerField( required=False )
html = forms.BooleanField( required=False )
def __init__( self, *args, **kwargs ):
PropertyModelForm.__init__( self, *args, **kwargs )
# Populate the `default channel' field's choices
choices = [ ('', '----------') ]
if self.instance and self.instance.srvid is not None:
if self.instance.booted:
def add_item( item, level ):
if item.is_server or item.is_channel:
choices.append( ( item.chanid, ( "-"*level + " " + item.name ) ) )
self.instance.rootchan.visit(add_item)
else:
current = self.instance.defchan
if current is not None:
choices.append( ( current, "Current value: %d" % current ) )
self.fields['defchan'].choices = choices
class Meta:
model = Mumble;
fields = ['name'];
class MumbleAdminForm( MumbleForm ):
""" A Mumble Server admin form intended to be used by the server hoster. """
users = forms.IntegerField( required=False )
bwidth = forms.IntegerField( required=False )
sslcrt = forms.CharField( required=False, widget=forms.Textarea )
sslkey = forms.CharField( required=False, widget=forms.Textarea )
booted = forms.BooleanField( required=False )
autoboot = forms.BooleanField( required=False )
bonjour = forms.BooleanField( required=False )
class Meta:
fields = None
exclude = None
def clean_port( self ):
""" Check if the port number is valid. """
port = self.cleaned_data['port'];
if port is not None and port != '':
if port < 1 or port >= 2**16:
raise forms.ValidationError(
_("Port number %(portno)d is not within the allowed range %(minrange)d - %(maxrange)d") % {
'portno': port,
'minrange': 1,
'maxrange': 2**16,
});
return port;
return None
class MumbleServerForm( ModelForm ):
defaultconf = forms.CharField( label=_("Default config"), required=False, widget=forms.Textarea )
def __init__( self, *args, **kwargs ):
ModelForm.__init__( self, *args, **kwargs )
if self.instance and self.instance.id:
if self.instance.online:
confstr = ""
conf = self.instance.defaultconf
for field in conf:
confstr += "%s: %s\n" % ( field, conf[field] )
self.fields["defaultconf"].initial = confstr
else:
self.fields["defaultconf"].initial = _("This server is currently offline.")
class Meta:
model = MumbleServer
class MumbleUserForm( ModelForm ):
""" The user registration form used to register an account. """
password = forms.CharField( widget=forms.PasswordInput, required=False )
def __init__( self, *args, **kwargs ):
ModelForm.__init__( self, *args, **kwargs );
self.server = None;
def clean_name( self ):
""" Check if the desired name is forbidden or taken. """
name = self.cleaned_data['name'];
if self.server is None:
raise AttributeError( "You need to set the form's server attribute to the server instance "
"for validation to work." );
if self.server.player and re.compile( self.server.player ).match( name ) is None:
raise forms.ValidationError( _( "That name is forbidden by the server." ) );
if not self.instance.id and len( self.server.ctl.getRegisteredPlayers( self.server.srvid, name ) ) > 0:
raise forms.ValidationError( _( "Another player already registered that name." ) );
return name;
def clean_password( self ):
""" Verify a password has been given. """
passwd = self.cleaned_data['password'];
if not passwd and ( not self.instance or self.instance.mumbleid == -1 ):
raise forms.ValidationError( _( "Cannot register player without a password!" ) );
return passwd;
class Meta:
model = MumbleUser;
fields = ( 'name', 'password' );
class MumbleUserPasswordForm( MumbleUserForm ):
""" The user registration form used to register an account on a private server in protected mode. """
serverpw = forms.CharField(
label=_('Server Password'),
help_text=_('This server is private and protected mode is active. Please enter the server password.'),
widget=forms.PasswordInput(render_value=False)
);
def clean_serverpw( self ):
""" Validate the password """
serverpw = self.cleaned_data['serverpw'];
if self.server.passwd != serverpw:
raise forms.ValidationError( _( "The password you entered is incorrect." ) );
return serverpw;
def clean( self ):
""" prevent save() from trying to store the password in the Model instance. """
# clean() will be called after clean_serverpw(), so it has already been validated here.
if 'serverpw' in self.cleaned_data:
del( self.cleaned_data['serverpw'] );
return self.cleaned_data;
class MumbleUserLinkForm( MumbleUserForm ):
""" Special registration form to either register or link an account. """
linkacc = forms.BooleanField(
label=_('Link account'),
help_text=_('The account already exists and belongs to me, just link it instead of creating.'),
required=False,
);
def __init__( self, *args, **kwargs ):
MumbleUserForm.__init__( self, *args, **kwargs );
self.mumbleid = None;
def clean_name( self ):
""" Check if the target account exists in Murmur. """
if 'linkacc' not in self.data:
return MumbleUserForm.clean_name( self );
# Check if user exists
name = self.cleaned_data['name'];
if len( self.server.ctl.getRegisteredPlayers( self.server.srvid, name ) ) != 1:
raise forms.ValidationError( _( "No such user found." ) );
return name;
def clean_password( self ):
""" Verify that the password is correct. """
if 'linkacc' not in self.data:
return MumbleUserForm.clean_password( self );
if 'name' not in self.cleaned_data:
# keep clean() from trying to find a user that CAN'T exist
self.mumbleid = -10;
return '';
# Validate password with Murmur
passwd = self.cleaned_data['password'];
self.mumbleid = self.server.ctl.verifyPassword( self.server.srvid, self.cleaned_data['name'], passwd )
if self.mumbleid <= 0:
raise forms.ValidationError( _( "The password you entered is incorrect." ) );
return passwd;
def clean( self ):
""" Create the MumbleUser instance to save in. """
if 'linkacc' not in self.data or self.mumbleid <= 0:
return self.cleaned_data;
try:
m_user = MumbleUser.objects.get( server=self.server, mumbleid=self.mumbleid );
except MumbleUser.DoesNotExist:
m_user = MumbleUser( server=self.server, name=self.cleaned_data['name'], mumbleid=self.mumbleid );
m_user.save( dontConfigureMurmur=True );
else:
if m_user.owner is not None:
raise forms.ValidationError( _( "That account belongs to someone else." ) );
if m_user.getAdmin() and not settings.ALLOW_ACCOUNT_LINKING_ADMINS:
raise forms.ValidationError( _( "Linking Admin accounts is not allowed." ) );
self.instance = m_user;
return self.cleaned_data;
class MumbleUserAdminForm( PropertyModelForm ):
aclAdmin = forms.BooleanField( required=False );
password = forms.CharField( widget=forms.PasswordInput, required=False )
def clean_password( self ):
""" Verify a password has been given. """
passwd = self.cleaned_data['password'];
if not passwd and ( not self.instance or self.instance.mumbleid == -1 ):
raise forms.ValidationError( _( "Cannot register player without a password!" ) );
return passwd;
class Meta:
model = Mumble;
class MumbleKickForm( Form ):
session = forms.IntegerField();
ban = forms.BooleanField( required=False );
reason = forms.CharField( required=False );
class MumbleTextureForm( Form ):
""" The form used to upload a new image to be set as texture. """
texturefile = forms.ImageField( label=_("User Texture") );

View File

@@ -1,580 +0,0 @@
# Croatian translation file for Mumble-Django.
#
# Copyright (C) 2009, Vid "Night" Marić <vid_maric@yahoo.com>
#
# Mumble-Django is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This package 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.
#
msgid ""
msgstr ""
"Project-Id-Version: Mumble-Django v0.8\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-03-11 16:43+0100\n"
"PO-Revision-Date: 2010-01-11 14:11\n"
"Last-Translator: <de@de.de>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Translated-Using: django-rosetta 0.5.1\n"
#: admin.py:34 admin.py:51
msgid "Master is running"
msgstr ""
#: admin.py:59 models.py:162 templates/mumble/mumble.html:28
msgid "Server Address"
msgstr "Adresa servera"
#: admin.py:66 models.py:165
msgid "Server Port"
msgstr "Port"
#: admin.py:71
msgid "Instance is running"
msgstr ""
#: admin.py:81
msgid "Registered users"
msgstr "Registrirani korisnici"
#: admin.py:91
msgid "Online users"
msgstr "Korisnici na serveru"
#: admin.py:101
msgid "Channel count"
msgstr "Broj kanala"
#: admin.py:108
msgid "Yes"
msgstr ""
#: admin.py:110
msgid "No"
msgstr ""
#: admin.py:114
msgid "Public"
msgstr "Javni server"
#: admin.py:132 models.py:626 templates/mumble/mumble.html:223
msgid "Admin on root channel"
msgstr "Administrator u glavnoj sobi"
#: forms.py:83
msgid "Password required to join. Leave empty for public servers."
msgstr ""
"Lozinka za pristup serveru. Ostaviti prazno ako se spajate na javni server."
#: forms.py:86
msgid "If on, IP adresses of the clients are not logged."
msgstr "Ako je uključeno, IP adrese klijenata se neće bilježiti."
#: forms.py:142
#, python-format
msgid ""
"Port number %(portno)d is not within the allowed range %(minrange)d - %"
"(maxrange)d"
msgstr "Port %(portno)d nije u dozvoljenom opsegu %(minrange)d - %(maxrange)d"
#: forms.py:165 templates/mumble/offline.html:12
msgid "This server is currently offline."
msgstr ""
#: forms.py:190
msgid "That name is forbidden by the server."
msgstr "Ime je zabranjeno na serveru."
#: forms.py:193 models.py:582
msgid "Another player already registered that name."
msgstr "Ovo ime je zauzeto, probajte neko drugo."
#: forms.py:201 forms.py:307 models.py:584
msgid "Cannot register player without a password!"
msgstr "Odaberite lozinku i probajte ponovno!"
#: forms.py:213 models.py:179
msgid "Server Password"
msgstr "Lozinka servera"
#: forms.py:214
msgid ""
"This server is private and protected mode is active. Please enter the server "
"password."
msgstr ""
"Ovo je privatan server i potrebna vam je lozinka za pristup. Molimo vas "
"unesite lozinku."
#: forms.py:222 forms.py:274
msgid "The password you entered is incorrect."
msgstr "Lozinka koju ste unijeli je neispravna."
#: forms.py:237
msgid "Link account"
msgstr "Povezani račun"
#: forms.py:238
msgid ""
"The account already exists and belongs to me, just link it instead of "
"creating."
msgstr "Ovaj račun već postoji. Povežite ga umjesto da radite novi račun."
#: forms.py:255
msgid "No such user found."
msgstr "Korisnik nije pronađen."
#: forms.py:290
msgid "That account belongs to someone else."
msgstr "Ovaj račun pripada drugome korisniku."
#: forms.py:293
msgid "Linking Admin accounts is not allowed."
msgstr "Povezivanje administratorskih računa nije dozvoljeno."
#: forms.py:322 templates/mumble/mumble.html:65
#: templates/mumble/mumble.html.py:148 templates/mumble/mumble.html:278
msgid "User Texture"
msgstr "Korisnička slika"
#: models.py:63
msgid "DBus or ICE base"
msgstr "DBus ili ICE"
#: models.py:64
msgid ""
"Examples: 'net.sourceforge.mumble.murmur' for DBus or 'Meta:tcp -h 127.0.0.1 "
"-p 6502' for Ice."
msgstr ""
"Primjeri: 'net.sourceforge.mumble.murmur' za DBus ili 'Meta:tcp -h 127.0.0.1 "
"-p 6502' za Ice."
#: models.py:65
msgid "Ice Secret"
msgstr ""
#: models.py:68
#, fuzzy
msgid "Mumble Server"
msgstr "ID korisnika na Mumbleu"
#: models.py:69
#, fuzzy
msgid "Mumble Servers"
msgstr "ID korisnika na Mumbleu"
#: models.py:160
msgid "Server Name"
msgstr "Ime servera"
#: models.py:161
msgid "Server ID"
msgstr "ID servera"
#: models.py:163
msgid ""
"Hostname or IP address to bind to. You should use a hostname here, because "
"it will appear on the global server list."
msgstr ""
"Ime poslužitelja (hostname) ili IP adresa adresa za spajanje. Koristite ime "
"poslužitelja ovdje zato što će se pojaviti na globalnoj listi servera."
#: models.py:166
#, fuzzy
msgid "Port number to bind to. Leave empty to auto assign one."
msgstr "Port za spajanje. Koristite -1 za automatsko dodjeljivanje porta."
#: models.py:167
#, fuzzy
msgid "Server Display Address"
msgstr "Adresa servera"
#: models.py:168
msgid ""
"This field is only relevant if you are located behind a NAT, and names the "
"Hostname or IP address to use in the Channel Viewer and for the global "
"server list registration. If not given, the addr and port fields are used. "
"If display and bind ports are equal, you can omit it here."
msgstr ""
#: models.py:174
msgid "Superuser Password"
msgstr "Lozinka Superusera (administrator)"
#: models.py:177
msgid "Website URL"
msgstr "URL internet stranice"
#: models.py:178
msgid "Welcome Message"
msgstr "Poruka dobrodošlice"
#: models.py:180
msgid "Max. Users"
msgstr "Maksimalan broj korisnika"
#: models.py:181
msgid "Bandwidth [Bps]"
msgstr "Promet [Bps]"
#: models.py:182
msgid "SSL Certificate"
msgstr "SSL certifikat"
#: models.py:183
msgid "SSL Key"
msgstr "SSL ključ"
#: models.py:184
msgid "Player name regex"
msgstr "Dozvoljeni znakovi u nazivu korisnika"
#: models.py:185
msgid "Channel name regex"
msgstr "Dozvoljeni znakovi u nazivu kanala"
#: models.py:186
msgid "Default channel"
msgstr "Početni kanal"
#: models.py:187
msgid "Timeout"
msgstr ""
#: models.py:189
msgid "IP Obfuscation"
msgstr "Bilježi IP adrese korisnika"
#: models.py:190
#, fuzzy
msgid "Require Certificate"
msgstr "SSL certifikat"
#: models.py:191
msgid "Maximum length of text messages"
msgstr ""
#: models.py:192
msgid "Allow HTML to be used in messages"
msgstr ""
#: models.py:193
msgid "Publish this server via Bonjour"
msgstr ""
#: models.py:194
msgid "Boot Server when Murmur starts"
msgstr ""
#: models.py:212 models.py:213
msgid "Boot Server"
msgstr "Pokreni server"
#: models.py:217 models.py:545
msgid "Server instance"
msgstr "Instanca servera"
#: models.py:218
msgid "Server instances"
msgstr "Instance servera"
#: models.py:505 models.py:685
msgid "This field must not be updated once the record has been saved."
msgstr "Ovo polje ne smije biti ažurirano nakon što je zapis spremljen."
#: models.py:542
msgid "Mumble player_id"
msgstr "ID korisnika na Mumbleu"
#: models.py:543
msgid "User name and Login"
msgstr "Korisničko ime"
#: models.py:544
msgid "Login password"
msgstr "Lozinka"
#: models.py:546 templates/mumble/mumble.html:293
msgid "Account owner"
msgstr "Vlasnik računa"
#: models.py:548
#, fuzzy
msgid "The user's comment."
msgstr "Korisnički račun"
#: models.py:549
msgid "The user's hash."
msgstr ""
#: models.py:553
msgid "User account"
msgstr "Korisnički račun"
#: models.py:554
msgid "User accounts"
msgstr "Korisnički računi"
#: models.py:561
#, python-format
msgid "Mumble user %(mu)s on %(srv)s owned by Django user %(du)s"
msgstr "Django korisniku %(du)s pripada Mumble račun %(mu)s na serveru %(srv)s"
#: templates/mumble/list.html:20
msgid "No server instances have been configured yet."
msgstr ""
#: templates/mumble/mumble.html:16
msgid ""
"\n"
" <b>Hint:</b><br />\n"
" This area is used to display additional information for each channel "
"and player, but requires JavaScript to be\n"
" displayed correctly. You will not see the detail pages, but you can "
"use all links and forms\n"
" that are displayed.\n"
" "
msgstr ""
"\n"
" <b>Savjet:</b><br />\n"
" Ovdje se prikazuju dodatne informacije za svaki kanali svakog igrača "
"te zahtjeva JavaScript kako bi\n"
" se informacije pravilno prikazale. Nećete vidjeti stranicu s "
"detaljima, ali možete koristiti sve linkove i forme.\n"
" "
#: templates/mumble/mumble.html:31
msgid "Website"
msgstr "Internet stranica"
#: templates/mumble/mumble.html:33
msgid "Server version"
msgstr "Verzija servera"
#: templates/mumble/mumble.html:34
msgid "Minimal view"
msgstr ""
#: templates/mumble/mumble.html:37
msgid "Welcome message"
msgstr "Poruka dobrodošlice"
#: templates/mumble/mumble.html:43
msgid "Server registration"
msgstr "Registracija servera"
#: templates/mumble/mumble.html:46
msgid "You are registered on this server"
msgstr "Registrirani ste na ovom serveru"
#: templates/mumble/mumble.html:48
msgid "You do not have an account on this server"
msgstr "Nemate račun na ovom serveru"
#: templates/mumble/mumble.html:57
#, python-format
msgid ""
"\n"
" <p>You need to be <a href=\"%(login_url)s\">logged in</a> to be able "
"to register an account on this Mumble server.</p>\n"
" "
msgstr ""
"\n"
" <p>Morate biti <a href=\"%(login_url)s\">prijavljeni (ulogirani)</a> "
"kako bi ste napravili račun na ovom Mumble serveru.</p>\n"
" "
#: templates/mumble/mumble.html:67
msgid ""
"\n"
" Sorry, due to a bug in Murmur 1.2.2, displaying and setting the "
"Texture is disabled.\n"
" "
msgstr ""
#: templates/mumble/mumble.html:72
#, fuzzy
msgid ""
"\n"
" You can upload an image that you would like to use as your user "
"texture here.\n"
" "
msgstr ""
"\n"
" Možete postaviti sliku za koju bi htjeli da zamjeni vašekorisničko "
"ime u Mumble transparentu (overlay).\n"
" "
#: templates/mumble/mumble.html:77
msgid "Your current texture is"
msgstr "Vaša trenutačna slika je"
#: templates/mumble/mumble.html:80
msgid "You don't currently have a texture set"
msgstr ""
#: templates/mumble/mumble.html:84
#, fuzzy
msgid ""
"\n"
" Hint: The texture image <b>needs</b> to be 600x60 in size. If "
"you upload an image with\n"
" a different size, it will be resized accordingly.<br />\n"
" "
msgstr ""
"\n"
" Savjet: Slika <b>mora</b> biti veličine 600x60. Ako odaberete "
"sliku drugačije veličine, veličina će biti promjenjena u 600x60.<br />\n"
" "
#: templates/mumble/mumble.html:103
msgid "Server administration"
msgstr "Administracija servera"
#: templates/mumble/mumble.html:117
msgid "Player"
msgstr "Korisnik"
#: templates/mumble/mumble.html:119
msgid "Online since"
msgstr "Na serveru od"
#: templates/mumble/mumble.html:120 templates/mumble/player.html:9
msgid "Authenticated"
msgstr "Registriran korisnik"
#: templates/mumble/mumble.html:121 templates/mumble/mumble.html.py:136
msgid "Admin"
msgstr "Administrator"
#: templates/mumble/mumble.html:122 templates/mumble/player.html:12
msgid "Muted"
msgstr "Utišan mikrofon"
#: templates/mumble/mumble.html:123 templates/mumble/player.html:18
msgid "Deafened"
msgstr "Utišani zvučnici / slušalice"
#: templates/mumble/mumble.html:124 templates/mumble/player.html:21
msgid "Muted by self"
msgstr "Samo-utišan mikrofon"
#: templates/mumble/mumble.html:125 templates/mumble/player.html:24
msgid "Deafened by self"
msgstr "Samo-utišani zvučnici / slušalice"
#: templates/mumble/mumble.html:127
#, fuzzy
msgid "IP Address"
msgstr "Adresa servera"
#: templates/mumble/mumble.html:131
msgid "User"
msgstr "Korisnik"
#: templates/mumble/mumble.html:134
msgid "Full Name"
msgstr "Ime i prezime"
#: templates/mumble/mumble.html:137
msgid "Sign-up date"
msgstr "Datum registracije"
#: templates/mumble/mumble.html:142
#, fuzzy
msgid "User Comment"
msgstr "Korisnički račun"
#: templates/mumble/mumble.html:154 templates/mumble/mumble.html.py:168
msgid "Kick user"
msgstr ""
#: templates/mumble/mumble.html:160
msgid "Reason"
msgstr ""
#: templates/mumble/mumble.html:165
#, fuzzy
msgid "Ban user"
msgstr "Korisnici na serveru"
#: templates/mumble/mumble.html:175
msgid "Channel"
msgstr "Soba"
#: templates/mumble/mumble.html:177
msgid "Channel ID"
msgstr "ID kanala"
#: templates/mumble/mumble.html:179
msgid "Connect"
msgstr "Spoji se"
#: templates/mumble/mumble.html:182
msgid "Channel description"
msgstr "Opis kanala"
#: templates/mumble/mumble.html:229
msgid "Delete"
msgstr ""
#: templates/mumble/mumble.html:265
msgid "Server Info"
msgstr "Informacije o serveru"
#: templates/mumble/mumble.html:266
msgid "Registration"
msgstr "Registracija"
#: templates/mumble/mumble.html:275
msgid "Administration"
msgstr "Administracija"
#: templates/mumble/mumble.html:282
msgid "User List"
msgstr "Lista korisnika"
#: templates/mumble/mumble.html:286
msgid "name"
msgstr ""
#: templates/mumble/mumble.html:306
#, fuzzy
msgid "Change password"
msgstr "Lozinka"
#: templates/mumble/mumble.html:319
msgid "Add"
msgstr ""
#: templates/mumble/mumble.html:331
msgid "Save"
msgstr ""
#: templates/mumble/mumble.html:357
msgid "Resync with Murmur"
msgstr "Resinkroniziraj s Murmurom"
#: templates/mumble/player.html:15
msgid "Suppressed"
msgstr ""
#: templates/mumble/player.html:27
msgid "has a User Comment set"
msgstr ""
#~ msgid ""
#~ "Enter the ID of the default channel here. The Channel viewer displays the "
#~ "ID to server admins on the channel detail page."
#~ msgstr ""
#~ "Unesite ID početnog kanala. Prikaz kanala pokazuje ID administratorima "
#~ "servera na stranici s detaljima kanala."
#~ msgid "The admin group was not found in the ACL's groups list!"
#~ msgstr "Grupa administratora nije pronađena u ACL listi grupa!"

View File

@@ -1,574 +0,0 @@
# Polskie tĹumaczenia dla Mumble-Django.
#
# Copyright (C) 2009, HuNt3r <admin@serv4u.pl>
#
# Mumble-Django is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This package 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.
#
msgid ""
msgstr ""
"Project-Id-Version: Mumble-Django v0.8\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-03-11 16:43+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: HuNt3r <admin@serv4u.pl>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: admin.py:34 admin.py:51
msgid "Master is running"
msgstr ""
#: admin.py:59 models.py:162 templates/mumble/mumble.html:28
msgid "Server Address"
msgstr "Adres serwera"
#: admin.py:66 models.py:165
msgid "Server Port"
msgstr "Port serwera"
#: admin.py:71
msgid "Instance is running"
msgstr ""
#: admin.py:81
msgid "Registered users"
msgstr "Zarejestrowani użytkownicy"
#: admin.py:91
msgid "Online users"
msgstr "Użytkownicy online"
#: admin.py:101
msgid "Channel count"
msgstr "Kanały"
#: admin.py:108
msgid "Yes"
msgstr ""
#: admin.py:110
msgid "No"
msgstr ""
#: admin.py:114
msgid "Public"
msgstr "Publiczny"
#: admin.py:132 models.py:626 templates/mumble/mumble.html:223
msgid "Admin on root channel"
msgstr "Admin na kanale głównym"
#: forms.py:83
msgid "Password required to join. Leave empty for public servers."
msgstr "Podaj hasło, lub pozostaw puste pole, aby serwer był publiczny. "
#: forms.py:86
msgid "If on, IP adresses of the clients are not logged."
msgstr "Gdy zaznaczysz, adresy IP użytkowników nie będą logowane."
#: forms.py:142
#, python-format
msgid ""
"Port number %(portno)d is not within the allowed range %(minrange)d - %"
"(maxrange)d"
msgstr "Numer portu %(portno)d jest z poza zakresu %(minrange)d - %(maxrange)d"
#: forms.py:165 templates/mumble/offline.html:12
msgid "This server is currently offline."
msgstr ""
#: forms.py:190
msgid "That name is forbidden by the server."
msgstr ""
#: forms.py:193 models.py:582
msgid "Another player already registered that name."
msgstr "Ta nazwa użytkownika jest już zajęta."
#: forms.py:201 forms.py:307 models.py:584
msgid "Cannot register player without a password!"
msgstr "Musisz podać hasło!"
#: forms.py:213 models.py:179
msgid "Server Password"
msgstr "Hasło serwera"
#: forms.py:214
msgid ""
"This server is private and protected mode is active. Please enter the server "
"password."
msgstr "Ten serwer jest prywatny. Podaj hasło aby się połączyć."
#: forms.py:222 forms.py:274
msgid "The password you entered is incorrect."
msgstr "Wprowadzone hasło jest niepoprawne"
#: forms.py:237
msgid "Link account"
msgstr ""
#: forms.py:238
msgid ""
"The account already exists and belongs to me, just link it instead of "
"creating."
msgstr ""
#: forms.py:255
msgid "No such user found."
msgstr ""
#: forms.py:290
msgid "That account belongs to someone else."
msgstr ""
#: forms.py:293
msgid "Linking Admin accounts is not allowed."
msgstr ""
#: forms.py:322 templates/mumble/mumble.html:65
#: templates/mumble/mumble.html.py:148 templates/mumble/mumble.html:278
msgid "User Texture"
msgstr "Awatar użytkownika"
#: models.py:63
msgid "DBus or ICE base"
msgstr "DBus lub baza ICE"
#: models.py:64
msgid ""
"Examples: 'net.sourceforge.mumble.murmur' for DBus or 'Meta:tcp -h 127.0.0.1 "
"-p 6502' for Ice."
msgstr ""
"Przykłąd: 'net.sourceforge.mumble.murmur' dla DBus oder 'Meta:tcp -h "
"127.0.0.1 -p 6502' dla Ice."
#: models.py:65
msgid "Ice Secret"
msgstr ""
#: models.py:68
#, fuzzy
msgid "Mumble Server"
msgstr "ID użytkownika"
#: models.py:69
#, fuzzy
msgid "Mumble Servers"
msgstr "ID użytkownika"
#: models.py:160
msgid "Server Name"
msgstr "Nazwa serwera"
#: models.py:161
msgid "Server ID"
msgstr "Serwer-ID"
#: models.py:163
msgid ""
"Hostname or IP address to bind to. You should use a hostname here, because "
"it will appear on the global server list."
msgstr ""
"Nazwa HOSTa lub adres IP. Zalecamy używać nazwy HOSTa, ponieważserwer będzie "
"widoczny na globalnej liście serwerów"
#: models.py:166
#, fuzzy
msgid "Port number to bind to. Leave empty to auto assign one."
msgstr "Numer portu. Wpisz -1 aby użyć wonego portu."
#: models.py:167
#, fuzzy
msgid "Server Display Address"
msgstr "Adres serwera"
#: models.py:168
msgid ""
"This field is only relevant if you are located behind a NAT, and names the "
"Hostname or IP address to use in the Channel Viewer and for the global "
"server list registration. If not given, the addr and port fields are used. "
"If display and bind ports are equal, you can omit it here."
msgstr ""
#: models.py:174
msgid "Superuser Password"
msgstr "Hasło SuperUser-a"
#: models.py:177
msgid "Website URL"
msgstr "Adres strony"
#: models.py:178
msgid "Welcome Message"
msgstr "Wiadomość powitalna"
#: models.py:180
msgid "Max. Users"
msgstr "Max. Użytkowników"
#: models.py:181
msgid "Bandwidth [Bps]"
msgstr "Przepustowość [Bps]"
#: models.py:182
msgid "SSL Certificate"
msgstr "SSL-Certyfikat"
#: models.py:183
msgid "SSL Key"
msgstr "SSL-Klucz"
#: models.py:184
msgid "Player name regex"
msgstr "Zabronione znaki w nazwie użytkownika"
#: models.py:185
msgid "Channel name regex"
msgstr "Zabronione znaki w nazwie kanału"
#: models.py:186
msgid "Default channel"
msgstr "Główny kanał"
#: models.py:187
msgid "Timeout"
msgstr ""
#: models.py:189
msgid "IP Obfuscation"
msgstr "IP-maskowanie"
#: models.py:190
#, fuzzy
msgid "Require Certificate"
msgstr "SSL-Certyfikat"
#: models.py:191
msgid "Maximum length of text messages"
msgstr ""
#: models.py:192
msgid "Allow HTML to be used in messages"
msgstr ""
#: models.py:193
msgid "Publish this server via Bonjour"
msgstr ""
#: models.py:194
msgid "Boot Server when Murmur starts"
msgstr ""
#: models.py:212 models.py:213
msgid "Boot Server"
msgstr "Odpal serwer"
#: models.py:217 models.py:545
msgid "Server instance"
msgstr "Aktywne serwery"
#: models.py:218
msgid "Server instances"
msgstr "Aktywne serwery"
#: models.py:505 models.py:685
msgid "This field must not be updated once the record has been saved."
msgstr "To pole nie musi być aktualizowane, było aktualizowane wcześniej."
#: models.py:542
msgid "Mumble player_id"
msgstr "ID użytkownika"
#: models.py:543
msgid "User name and Login"
msgstr "Nazwa użytkownika"
#: models.py:544
msgid "Login password"
msgstr "Hasło"
#: models.py:546 templates/mumble/mumble.html:293
msgid "Account owner"
msgstr "Właściciel konta"
#: models.py:548
#, fuzzy
msgid "The user's comment."
msgstr "Konto użytkownika"
#: models.py:549
msgid "The user's hash."
msgstr ""
#: models.py:553
msgid "User account"
msgstr "Konto użytkownika"
#: models.py:554
msgid "User accounts"
msgstr "Konta użytkowników"
#: models.py:561
#, python-format
msgid "Mumble user %(mu)s on %(srv)s owned by Django user %(du)s"
msgstr "Użytkownik %(mu)s na %(srv)s właściciel %(du)s"
#: templates/mumble/list.html:20
msgid "No server instances have been configured yet."
msgstr ""
#: templates/mumble/mumble.html:16
msgid ""
"\n"
" <b>Hint:</b><br />\n"
" This area is used to display additional information for each channel "
"and player, but requires JavaScript to be\n"
" displayed correctly. You will not see the detail pages, but you can "
"use all links and forms\n"
" that are displayed.\n"
" "
msgstr ""
"\n"
" <b>Info</b><br />\n"
" To pole jest używane do wyświetlenia dodatkowych informacji dla "
"każdegokanału i użytkownika, ale wymaga JavaScript aby\n"
" działało poprawnie. Nie zobaczysz detalów strony, lecz możesz używać "
"wszystkich linków i formatów\n"
" które zostaną wyświetlone.\n"
" "
#: templates/mumble/mumble.html:31
msgid "Website"
msgstr "Strona"
#: templates/mumble/mumble.html:33
msgid "Server version"
msgstr "Wersja serwera"
#: templates/mumble/mumble.html:34
msgid "Minimal view"
msgstr ""
#: templates/mumble/mumble.html:37
msgid "Welcome message"
msgstr "Wiadomość powitalna"
#: templates/mumble/mumble.html:43
msgid "Server registration"
msgstr "Rejestracja konta na serwerze"
#: templates/mumble/mumble.html:46
msgid "You are registered on this server"
msgstr "Masz konto na tym serwerze"
#: templates/mumble/mumble.html:48
msgid "You do not have an account on this server"
msgstr "Nie masz konta na tym serwerze"
#: templates/mumble/mumble.html:57
#, python-format
msgid ""
"\n"
" <p>You need to be <a href=\"%(login_url)s\">logged in</a> to be able "
"to register an account on this Mumble server.</p>\n"
" "
msgstr ""
"\n"
" <p>Musisz być <a href=\"%(login_url)s\">zalogowany</a> aby móc "
"zarejestrować konto na serwerze.</p>\n"
" "
#: templates/mumble/mumble.html:67
msgid ""
"\n"
" Sorry, due to a bug in Murmur 1.2.2, displaying and setting the "
"Texture is disabled.\n"
" "
msgstr ""
#: templates/mumble/mumble.html:72
#, fuzzy
msgid ""
"\n"
" You can upload an image that you would like to use as your user "
"texture here.\n"
" "
msgstr ""
"\n"
" Możesz wysłać awatar jeśli chcesz.\n"
" "
#: templates/mumble/mumble.html:77
msgid "Your current texture is"
msgstr "Twój obecny awatar"
#: templates/mumble/mumble.html:80
msgid "You don't currently have a texture set"
msgstr ""
#: templates/mumble/mumble.html:84
#, fuzzy
msgid ""
"\n"
" Hint: The texture image <b>needs</b> to be 600x60 in size. If "
"you upload an image with\n"
" a different size, it will be resized accordingly.<br />\n"
" "
msgstr ""
"\n"
" <b>Dozwolony</b> rozmiar pliku to: 600x60 pikseli. Każdy inny "
"rozmiar zostanie automatycznie zmieniony na podany wyĹĽej. "
#: templates/mumble/mumble.html:103
msgid "Server administration"
msgstr "Administracja serwerem"
#: templates/mumble/mumble.html:117
msgid "Player"
msgstr "Użytkownik"
#: templates/mumble/mumble.html:119
msgid "Online since"
msgstr "Czas online"
#: templates/mumble/mumble.html:120 templates/mumble/player.html:9
msgid "Authenticated"
msgstr "Zarejestrowany"
#: templates/mumble/mumble.html:121 templates/mumble/mumble.html.py:136
msgid "Admin"
msgstr "Administrator"
#: templates/mumble/mumble.html:122 templates/mumble/player.html:12
msgid "Muted"
msgstr "Wyciszony mikrofon"
#: templates/mumble/mumble.html:123 templates/mumble/player.html:18
msgid "Deafened"
msgstr "Wyciszone słuchawki"
#: templates/mumble/mumble.html:124 templates/mumble/player.html:21
msgid "Muted by self"
msgstr "Wyciszył mikrofon"
#: templates/mumble/mumble.html:125 templates/mumble/player.html:24
msgid "Deafened by self"
msgstr "Wyciszył słuchawki"
#: templates/mumble/mumble.html:127
#, fuzzy
msgid "IP Address"
msgstr "Adres serwera"
#: templates/mumble/mumble.html:131
msgid "User"
msgstr "Użytkownik"
#: templates/mumble/mumble.html:134
msgid "Full Name"
msgstr "Pełna nazwa"
#: templates/mumble/mumble.html:137
msgid "Sign-up date"
msgstr "Data rejestracji"
#: templates/mumble/mumble.html:142
#, fuzzy
msgid "User Comment"
msgstr "Konto użytkownika"
#: templates/mumble/mumble.html:154 templates/mumble/mumble.html.py:168
msgid "Kick user"
msgstr ""
#: templates/mumble/mumble.html:160
msgid "Reason"
msgstr ""
#: templates/mumble/mumble.html:165
#, fuzzy
msgid "Ban user"
msgstr "Użytkownicy online"
#: templates/mumble/mumble.html:175
msgid "Channel"
msgstr "Kanał"
#: templates/mumble/mumble.html:177
msgid "Channel ID"
msgstr "ID-kanału"
#: templates/mumble/mumble.html:179
msgid "Connect"
msgstr "Połącz"
#: templates/mumble/mumble.html:182
msgid "Channel description"
msgstr "Opis kanału"
#: templates/mumble/mumble.html:229
msgid "Delete"
msgstr ""
#: templates/mumble/mumble.html:265
msgid "Server Info"
msgstr "Informacje o serwerze"
#: templates/mumble/mumble.html:266
msgid "Registration"
msgstr "Rejestracja"
#: templates/mumble/mumble.html:275
msgid "Administration"
msgstr "Administracja"
#: templates/mumble/mumble.html:282
msgid "User List"
msgstr "Lista użytkowników"
#: templates/mumble/mumble.html:286
msgid "name"
msgstr ""
#: templates/mumble/mumble.html:306
#, fuzzy
msgid "Change password"
msgstr "Hasło"
#: templates/mumble/mumble.html:319
msgid "Add"
msgstr ""
#: templates/mumble/mumble.html:331
msgid "Save"
msgstr ""
#: templates/mumble/mumble.html:357
msgid "Resync with Murmur"
msgstr ""
#: templates/mumble/player.html:15
msgid "Suppressed"
msgstr ""
#: templates/mumble/player.html:27
msgid "has a User Comment set"
msgstr ""
#~ msgid ""
#~ "Enter the ID of the default channel here. The Channel viewer displays the "
#~ "ID to server admins on the channel detail page."
#~ msgstr ""
#~ "Podaj numer ID głównego kanału. Numer ID można sprawdzić w Channel-Viewer "
#~ msgid "The admin group was not found in the ACL's groups list!"
#~ msgstr "Grupa admin nie istnieje na liście grup ACL"

View File

@@ -1,530 +0,0 @@
# German translation file for Mumble-Django.
#
# Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
#
# Mumble-Django is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This package 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.
#
msgid ""
msgstr ""
"Project-Id-Version: Mumble-Django v0.8\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-03-14 18:23+0100\n"
"PO-Revision-Date: 2010-03-14 18:25\n"
"Last-Translator: <de@de.de>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Translated-Using: django-rosetta 0.5.3\n"
#: admin.py:34 admin.py:51
msgid "Master is running"
msgstr "Serverprozess läuft"
#: admin.py:59 models.py:162 templates/mumble/mumble.html:28
msgid "Server Address"
msgstr "Serveradresse"
#: admin.py:66 models.py:165
msgid "Server Port"
msgstr "Serverport"
#: admin.py:71
msgid "Instance is running"
msgstr "Serverinstanz läuft"
#: admin.py:81
msgid "Registered users"
msgstr "Registrierte Benutzer"
#: admin.py:91
msgid "Online users"
msgstr "Benutzer online"
#: admin.py:101
msgid "Channel count"
msgstr "Channels"
#: admin.py:108
msgid "Yes"
msgstr "Ja"
#: admin.py:110
msgid "No"
msgstr "Nein"
#: admin.py:114
msgid "Public"
msgstr "Öffentlich"
#: admin.py:132 models.py:631 templates/mumble/mumble.html:223
msgid "Admin on root channel"
msgstr "Admin im Wurzelkanal"
#: forms.py:83
msgid "Password required to join. Leave empty for public servers."
msgstr "Passwort was zum Verbinden benötigt wird. Lasse es leer, wenn der Server öffentlich sein soll."
#: forms.py:86
msgid "If on, IP adresses of the clients are not logged."
msgstr "Wenn das an ist werden IP-Adressen der Clients nicht ins Log geschrieben."
#: forms.py:142
#, python-format
msgid "Port number %(portno)d is not within the allowed range %(minrange)d - %(maxrange)d"
msgstr "Portnummer %(portno)d liegt nicht in %(minrange)d - %(maxrange)d"
#: forms.py:152
msgid "Default config"
msgstr "Standard-Einstellungen"
#: forms.py:165 templates/mumble/offline.html:12
msgid "This server is currently offline."
msgstr "Dieser Server ist im Moment nicht erreichbar."
#: forms.py:190
msgid "That name is forbidden by the server."
msgstr "Dieser Name wird vom Server nicht erlaubt."
#: forms.py:193 models.py:587
msgid "Another player already registered that name."
msgstr "Ein anderer Spieler hat sich unter diesem Namen bereits registriert."
#: forms.py:201 forms.py:307 models.py:589
msgid "Cannot register player without a password!"
msgstr "Kann Account nicht ohne Passwort registrieren!"
#: forms.py:213 models.py:179
msgid "Server Password"
msgstr "Serverpasswort"
#: forms.py:214
msgid "This server is private and protected mode is active. Please enter the server password."
msgstr "Dieser Server ist privat und der Registrierungsschutz ist aktiv. Bitte gib das Serverpasswort ein."
#: forms.py:222 forms.py:274
msgid "The password you entered is incorrect."
msgstr "Das eingegebene Passwort ist falsch"
#: forms.py:237
msgid "Link account"
msgstr "Accounts verknüpfen"
#: forms.py:238
msgid "The account already exists and belongs to me, just link it instead of creating."
msgstr "Dieser Account existiert bereits und gehört mir. Verknüpfe die Konten nur, anstatt ein neues zu erstellen."
#: forms.py:255
msgid "No such user found."
msgstr "Benutzer nicht gefunden."
#: forms.py:290
msgid "That account belongs to someone else."
msgstr "Dieser Account gehört jemand anderem."
#: forms.py:293
msgid "Linking Admin accounts is not allowed."
msgstr "Admin-Accounts zu verknüpfen ist nicht erlaubt."
#: forms.py:322 templates/mumble/mumble.html:65
#: templates/mumble/mumble.html.py:148 templates/mumble/mumble.html:278
msgid "User Texture"
msgstr "Benutzertextur"
#: models.py:63
msgid "DBus or ICE base"
msgstr "DBus- oder ICE-String"
#: models.py:64
msgid "Examples: 'net.sourceforge.mumble.murmur' for DBus or 'Meta:tcp -h 127.0.0.1 -p 6502' for Ice."
msgstr "Beispiele: 'net.sourceforge.mumble.murmur' für DBus oder 'Meta:tcp -h 127.0.0.1 -p 6502' für Ice."
#: models.py:65
msgid "Ice Secret"
msgstr "Ice-Passwort"
#: models.py:68 models.py:159
msgid "Mumble Server"
msgstr "Mumble-Server"
#: models.py:69
msgid "Mumble Servers"
msgstr "Mumble-Server"
#: models.py:160
msgid "Server Name"
msgstr "Servername"
#: models.py:161
msgid "Server ID"
msgstr "Server-ID"
#: models.py:163
msgid "Hostname or IP address to bind to. You should use a hostname here, because it will appear on the global server list."
msgstr "Hostname oder IP-Adresse unter der der Server erreichbar sein soll. Du solltest einen Hostname verwenden, da dieses Feld in der globalen Serverliste erscheint."
#: models.py:166
msgid "Port number to bind to. Leave empty to auto assign one."
msgstr "Portnummer auf die gebunden werden soll. Lasse das Feld leer um automatisch eine zuzuweisen."
#: models.py:167
msgid "Server Display Address"
msgstr "Angezeigte Adresse"
#: models.py:168
msgid "This field is only relevant if you are located behind a NAT, and names the Hostname or IP address to use in the Channel Viewer and for the global server list registration. If not given, the addr and port fields are used. If display and bind ports are equal, you can omit it here."
msgstr "Dieses Feld ist nur relevant wenn der Server hinter einem NAT steht, und gibt dann den Hostnamen oder die IP-Adresse die im Channel-Viewer und für die Registrierung in der Serverliste benutzt werden soll. Ist dieses Feld leer, werden die Angaben Addresse und Port stattdessen benutzt. Wenn die Ports identisch sind, kannst du den Port hier weglassen."
#: models.py:174
msgid "Superuser Password"
msgstr "SuperUser-Passwort"
#: models.py:177
msgid "Website URL"
msgstr "URL der Webseite"
#: models.py:178
msgid "Welcome Message"
msgstr "Willkommensnachricht"
#: models.py:180
msgid "Max. Users"
msgstr "Max. Benutzer"
#: models.py:181
msgid "Bandwidth [Bps]"
msgstr "Bandbreite [Bps]"
#: models.py:182
msgid "SSL Certificate"
msgstr "SSL-Zertifikat"
#: models.py:183
msgid "SSL Key"
msgstr "SSL-Schlüssel"
#: models.py:184
msgid "Player name regex"
msgstr "Regex für Spielernamen"
#: models.py:185
msgid "Channel name regex"
msgstr "Regex für Channelnamen"
#: models.py:186
msgid "Default channel"
msgstr "Standardchannel"
#: models.py:187
msgid "Timeout"
msgstr "Timeout"
#: models.py:189
msgid "IP Obfuscation"
msgstr "IP-Adressen anonymisieren"
#: models.py:190
msgid "Require Certificate"
msgstr "SSL-Zertifikat erzwingen"
#: models.py:191
msgid "Maximum length of text messages"
msgstr "Maximale Länge von Textnachrichten"
#: models.py:192
msgid "Allow HTML to be used in messages"
msgstr "Erlaube HTML in Nachrichten"
#: models.py:193
msgid "Publish this server via Bonjour"
msgstr "Server via Bonjour bekannt machen"
#: models.py:194
msgid "Boot Server when Murmur starts"
msgstr "Instanz starten wenn Murmur startet"
#: models.py:212 models.py:213
msgid "Boot Server"
msgstr "Server starten"
#: models.py:217 models.py:550
msgid "Server instance"
msgstr "Serverinstanz"
#: models.py:218
msgid "Server instances"
msgstr "Serverinstanzen"
#: models.py:510 models.py:690
msgid "This field must not be updated once the record has been saved."
msgstr "Dieses Feld darf nicht mehr verändert werden, nachdem der Eintrag zum ersten Mal gespeichert wurde."
#: models.py:547
msgid "Mumble player_id"
msgstr "ID des Spielers in Murmur"
#: models.py:548
msgid "User name and Login"
msgstr "Benutzername und Login"
#: models.py:549
msgid "Login password"
msgstr "Passwort"
#: models.py:551 templates/mumble/mumble.html:293
msgid "Account owner"
msgstr "Accountbesitzer"
#: models.py:553
msgid "The user's comment."
msgstr "Benutzer-Kommentar"
#: models.py:554
msgid "The user's hash."
msgstr "Signatur des Zertifikats"
#: models.py:558
msgid "User account"
msgstr "Benutzerkonto"
#: models.py:559
msgid "User accounts"
msgstr "Benutzerkonten"
#: models.py:566
#, python-format
msgid "Mumble user %(mu)s on %(srv)s owned by Django user %(du)s"
msgstr "Benutzeraccount %(mu)s auf %(srv)s mit Besitzer %(du)s"
#: templates/mumble/list.html:20
msgid "No server instances have been configured yet."
msgstr "Es sind noch keine Serverinstanzen konfiguriert."
#: templates/mumble/mumble.html:16
msgid ""
"\n"
" <b>Hint:</b><br />\n"
" This area is used to display additional information for each channel and player, but requires JavaScript to be\n"
" displayed correctly. You will not see the detail pages, but you can use all links and forms\n"
" that are displayed.\n"
" "
msgstr ""
"\n"
" <b>Hinweis:</b><br />\n"
" Dieser Bereich wird genutzt um zusätzliche Informationen über jeden Channel und Spieler anzuzeigen, erfordert aber JavaScript um\n"
" richtig angezeigt zu werden. Du wirst zwar die Detailseiten nicht sehen, kannst aber alle sichtbaren Formulare benutzen.\n"
" "
#: templates/mumble/mumble.html:31
msgid "Website"
msgstr "Webseite"
#: templates/mumble/mumble.html:33
msgid "Server version"
msgstr "Serverversion"
#: templates/mumble/mumble.html:34
msgid "Minimal view"
msgstr "Minimalansicht"
#: templates/mumble/mumble.html:37
msgid "Welcome message"
msgstr "Willkommensnachricht"
#: templates/mumble/mumble.html:43
msgid "Server registration"
msgstr "Benutzerregistrierung"
#: templates/mumble/mumble.html:46
msgid "You are registered on this server"
msgstr "Du bist auf diesem Server registriert"
#: templates/mumble/mumble.html:48
msgid "You do not have an account on this server"
msgstr "Du bist auf diesem Server nicht registriert"
#: templates/mumble/mumble.html:57
#, python-format
msgid ""
"\n"
" <p>You need to be <a href=\"%(login_url)s\">logged in</a> to be able to register an account on this Mumble server.</p>\n"
" "
msgstr ""
"\n"
" <p>Du musst <a href=\"%(login_url)s\">eingeloggt</a> sein um auf diesem Mumble-Server einen Account registrieren zu können.</p>\n"
" "
#: templates/mumble/mumble.html:67
msgid ""
"\n"
" Sorry, due to a bug in Murmur 1.2.2, displaying and setting the Texture is disabled.\n"
" "
msgstr ""
"\n"
"Entschuldigung, aufgrund eines Fehlers in Murmur 1.2.2 ist die Texturanzeige sowie das Hochladen für diese Version deaktiviert."
#: templates/mumble/mumble.html:72
msgid ""
"\n"
" You can upload an image that you would like to use as your user texture here.\n"
" "
msgstr ""
"\n"
"Du kannst hier ein Bild hochladen, das als deine Benutzertextur angezeigt werden soll."
#: templates/mumble/mumble.html:77
msgid "Your current texture is"
msgstr "Deine momentane Textur ist diese"
#: templates/mumble/mumble.html:80
msgid "You don't currently have a texture set"
msgstr "Du hast momentan keine Textur gesetzt"
#: templates/mumble/mumble.html:84
msgid ""
"\n"
" Hint: The texture image <b>needs</b> to be 600x60 in size. If you upload an image with\n"
" a different size, it will be resized accordingly.<br />\n"
" "
msgstr ""
"\n"
"Hinweis: Das Texturbild <b>muss</b> die Größe 600x60 haben. Wenn du ein Bild mit einer anderen Größe hochlädst, wird es automatisch zurecht geschnitten.<br />"
#: templates/mumble/mumble.html:103
msgid "Server administration"
msgstr "Server-Administration"
#: templates/mumble/mumble.html:117
msgid "Player"
msgstr "Spieler"
#: templates/mumble/mumble.html:119
msgid "Online since"
msgstr "Online seit"
#: templates/mumble/mumble.html:120 templates/mumble/player.html:9
msgid "Authenticated"
msgstr "Authentifiziert"
#: templates/mumble/mumble.html:121 templates/mumble/mumble.html.py:136
msgid "Admin"
msgstr "Administrator"
#: templates/mumble/mumble.html:122 templates/mumble/player.html:12
msgid "Muted"
msgstr "Stummgestellt"
#: templates/mumble/mumble.html:123 templates/mumble/player.html:18
msgid "Deafened"
msgstr "Taubgestellt"
#: templates/mumble/mumble.html:124 templates/mumble/player.html:21
msgid "Muted by self"
msgstr "Selbst stummgestellt"
#: templates/mumble/mumble.html:125 templates/mumble/player.html:24
msgid "Deafened by self"
msgstr "Selbst taubgestellt"
#: templates/mumble/mumble.html:127
msgid "IP Address"
msgstr "IP-Adresse"
#: templates/mumble/mumble.html:131
msgid "User"
msgstr "Benutzer"
#: templates/mumble/mumble.html:134
msgid "Full Name"
msgstr "Vollständiger Name"
#: templates/mumble/mumble.html:137
msgid "Sign-up date"
msgstr "Datum der Anmeldung"
#: templates/mumble/mumble.html:142
msgid "User Comment"
msgstr "Benutzer-Kommentar"
#: templates/mumble/mumble.html:154 templates/mumble/mumble.html.py:168
msgid "Kick user"
msgstr "Benutzer kicken"
#: templates/mumble/mumble.html:160
msgid "Reason"
msgstr "Begründung"
#: templates/mumble/mumble.html:165
msgid "Ban user"
msgstr "Benutzer bannen"
#: templates/mumble/mumble.html:175
msgid "Channel"
msgstr "Kanal"
#: templates/mumble/mumble.html:177
msgid "Channel ID"
msgstr "Kanal-ID"
#: templates/mumble/mumble.html:179
msgid "Connect"
msgstr "Verbinden"
#: templates/mumble/mumble.html:182
msgid "Channel description"
msgstr "Beschreibung des Kanals"
#: templates/mumble/mumble.html:229
msgid "Delete"
msgstr "Löschen"
#: templates/mumble/mumble.html:265
msgid "Server Info"
msgstr "Server-Infos"
#: templates/mumble/mumble.html:266
msgid "Registration"
msgstr "Registrierung"
#: templates/mumble/mumble.html:275
msgid "Administration"
msgstr "Administration"
#: templates/mumble/mumble.html:282
msgid "User List"
msgstr "Benutzerliste"
#: templates/mumble/mumble.html:286
msgid "name"
msgstr "Name"
#: templates/mumble/mumble.html:306
msgid "Change password"
msgstr "Passwort ändern"
#: templates/mumble/mumble.html:319
msgid "Add"
msgstr "Hinzufügen"
#: templates/mumble/mumble.html:331
msgid "Save"
msgstr "Speichern"
#: templates/mumble/mumble.html:357
msgid "Resync with Murmur"
msgstr "Liste neu laden"
#: templates/mumble/player.html:15
msgid "Suppressed"
msgstr "Unterdrückt"
#: templates/mumble/player.html:27
msgid "has a User Comment set"
msgstr "hat einen Benutzer-Kommentar gesetzt"

View File

@@ -1,568 +0,0 @@
# French translation file for Mumble-Django.
#
# Copyright (C) 2009, Antoine Bertin <bertinantoine@neuf.fr>
#
# Mumble-Django is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This package 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.
#
msgid ""
msgstr ""
"Project-Id-Version: Mumble-Django v2.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-03-14 18:23+0100\n"
"PO-Revision-Date: 2010-03-14 23:10+0100\n"
"Last-Translator: Antoine Bertin <bertinantoine@neuf.fr>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Translated-Using: django-rosetta 0.5.3\n"
#: admin.py:34
#: admin.py:51
msgid "Master is running"
msgstr "Le serveur fonctionne"
#: admin.py:59
#: models.py:162
#: templates/mumble/mumble.html:28
msgid "Server Address"
msgstr "Adresse du serveur"
#: admin.py:66
#: models.py:165
msgid "Server Port"
msgstr "Port du serveur"
#: admin.py:71
msgid "Instance is running"
msgstr "L'instance fonctionne"
#: admin.py:81
msgid "Registered users"
msgstr "Utilisateurs enregistrés"
#: admin.py:91
msgid "Online users"
msgstr "Utilisateurs en ligne"
#: admin.py:101
msgid "Channel count"
msgstr "Nombre de canaux"
#: admin.py:108
msgid "Yes"
msgstr "Oui"
#: admin.py:110
msgid "No"
msgstr "Non"
#: admin.py:114
msgid "Public"
msgstr "Public"
#: admin.py:132
#: models.py:631
#: templates/mumble/mumble.html:223
msgid "Admin on root channel"
msgstr "Admin sur le canal racine"
#: forms.py:83
msgid "Password required to join. Leave empty for public servers."
msgstr "Mot de passe requis pour se connecter. Laisser vide pour un serveur public."
#: forms.py:86
msgid "If on, IP adresses of the clients are not logged."
msgstr "Si oui, les adresses IP des utilisateurs ne seront pas loggées."
#: forms.py:142
#, python-format
msgid "Port number %(portno)d is not within the allowed range %(minrange)d - %(maxrange)d"
msgstr "Le port %(portno)d n'est pas dans la plage autorisée %(minrange)d - %(maxrange)d"
#: forms.py:152
msgid "Default config"
msgstr "Configuration par défaut"
#: forms.py:165
#: templates/mumble/offline.html:12
msgid "This server is currently offline."
msgstr "Ce serveur est offline."
#: forms.py:190
msgid "That name is forbidden by the server."
msgstr "Ce nom est interdit par le serveur."
#: forms.py:193
#: models.py:587
msgid "Another player already registered that name."
msgstr "Ce nom d'utilisateurs est déjà pris."
#: forms.py:201
#: forms.py:307
#: models.py:589
msgid "Cannot register player without a password!"
msgstr "Impossible d'enregistrer un utilisateur sans mot de passe!"
#: forms.py:213
#: models.py:179
msgid "Server Password"
msgstr "Mot de passe du serveur"
#: forms.py:214
msgid "This server is private and protected mode is active. Please enter the server password."
msgstr "Ce serveur est privé et le mode protégé est actif. Merci de saisir le mot de passe du serveur."
#: forms.py:222
#: forms.py:274
msgid "The password you entered is incorrect."
msgstr "Le mot de passe saisi est incorrect."
#: forms.py:237
msgid "Link account"
msgstr "Lier le compte"
#: forms.py:238
msgid "The account already exists and belongs to me, just link it instead of creating."
msgstr "Ce compte existe déjà et m'apartient. Vous pouvez le lier."
#: forms.py:255
msgid "No such user found."
msgstr "Aucun utilisateur trouvé."
#: forms.py:290
msgid "That account belongs to someone else."
msgstr "Ce compte appartient à quelqu'un d'autre."
#: forms.py:293
msgid "Linking Admin accounts is not allowed."
msgstr "Les liaisons de comptes Admin ne sont pas autorisées."
#: forms.py:322
#: templates/mumble/mumble.html:65
#: templates/mumble/mumble.html.py:148
#: templates/mumble/mumble.html:278
msgid "User Texture"
msgstr "Avatar de l'utilisateur"
#: models.py:63
msgid "DBus or ICE base"
msgstr "DBus ou ICE base"
#: models.py:64
msgid "Examples: 'net.sourceforge.mumble.murmur' for DBus or 'Meta:tcp -h 127.0.0.1 -p 6502' for Ice."
msgstr "Exemples: 'net.sourceforge.mumble.murmur' pour DBus ou 'Meta:tcp -h 127.0.0.1 -p 6502' pour Ice."
#: models.py:65
msgid "Ice Secret"
msgstr "Ice Secret"
#: models.py:68
#: models.py:159
msgid "Mumble Server"
msgstr "Serveur Mumble"
#: models.py:69
msgid "Mumble Servers"
msgstr "Serveurs Mumble"
#: models.py:160
msgid "Server Name"
msgstr "Nom du serveur"
#: models.py:161
msgid "Server ID"
msgstr "ID du serveur"
#: models.py:163
msgid "Hostname or IP address to bind to. You should use a hostname here, because it will appear on the global server list."
msgstr "Nom de domaine ou adresse IP à associer au serveur. Il est préférable d'utiliser un nom de domaine car il sera visible dans la liste des serveurs."
#: models.py:166
msgid "Port number to bind to. Leave empty to auto assign one."
msgstr "Numéro de port du serveur. Laissez vide pour assigner automatiquement."
#: models.py:167
msgid "Server Display Address"
msgstr "Adresse du serveur à afficher"
#: models.py:168
msgid "This field is only relevant if you are located behind a NAT, and names the Hostname or IP address to use in the Channel Viewer and for the global server list registration. If not given, the addr and port fields are used. If display and bind ports are equal, you can omit it here."
msgstr "Ce champ n'est valable que si vous êtes derrière un NAT. Nom de domaine ou adresse IP à utiliser dans le Channel Viewer et pour la liste des serveurs. Si vide, les champs d'adresse et de port sont utilisés. Si le port d'affichage et le port du serveur sont égaux, vous pouvez laisser vide."
#: models.py:174
msgid "Superuser Password"
msgstr "Mot de passe de Superuser"
#: models.py:177
msgid "Website URL"
msgstr "URL du site web"
#: models.py:178
msgid "Welcome Message"
msgstr "Message de bienvenue"
#: models.py:180
msgid "Max. Users"
msgstr "Utilisateurs Max."
#: models.py:181
msgid "Bandwidth [Bps]"
msgstr "Bande passante [Bps]"
#: models.py:182
msgid "SSL Certificate"
msgstr "Certificat SSL"
#: models.py:183
msgid "SSL Key"
msgstr "Clé SSL"
#: models.py:184
msgid "Player name regex"
msgstr "Regex pour le nom des utilisateurs"
#: models.py:185
msgid "Channel name regex"
msgstr "Regex pour le nom des canaux"
#: models.py:186
msgid "Default channel"
msgstr "Canal par défaut"
#: models.py:187
msgid "Timeout"
msgstr "Timeout"
#: models.py:189
msgid "IP Obfuscation"
msgstr "IP Anonyme"
#: models.py:190
msgid "Require Certificate"
msgstr "Certificat requis"
#: models.py:191
msgid "Maximum length of text messages"
msgstr "Longueur maximum des messages textes"
#: models.py:192
msgid "Allow HTML to be used in messages"
msgstr "Permettre le HTML dans les messages"
#: models.py:193
msgid "Publish this server via Bonjour"
msgstr "Publier ce serveur via Bonjour"
#: models.py:194
msgid "Boot Server when Murmur starts"
msgstr "Démarrer ce serveur au lancement de Murmur"
#: models.py:212
#: models.py:213
msgid "Boot Server"
msgstr "Serveur démarré automatiquement"
#: models.py:217
#: models.py:550
msgid "Server instance"
msgstr "Instance du serveur"
#: models.py:218
msgid "Server instances"
msgstr "Instances du serveur"
#: models.py:510
#: models.py:690
msgid "This field must not be updated once the record has been saved."
msgstr "Ce champ ne dois pas être modifié une fois l'enregistrement sauvegardé."
#: models.py:547
msgid "Mumble player_id"
msgstr "ID de l'utilisateur"
#: models.py:548
msgid "User name and Login"
msgstr "Nom d'utilisateur et login"
#: models.py:549
msgid "Login password"
msgstr "Mot de passe"
#: models.py:551
#: templates/mumble/mumble.html:293
msgid "Account owner"
msgstr "Propriétaire du compte"
#: models.py:553
msgid "The user's comment."
msgstr "Commentaire de l'utilisateur"
#: models.py:554
msgid "The user's hash."
msgstr "Hash de l'utilisateur"
#: models.py:558
msgid "User account"
msgstr "Compte d'utilisateur"
#: models.py:559
msgid "User accounts"
msgstr "Comptes d'utilisateur"
#: models.py:566
#, python-format
msgid "Mumble user %(mu)s on %(srv)s owned by Django user %(du)s"
msgstr "L'utilisateur Mumble %(mu)s sur %(srv)s correspond à l'utilisateur Django %(du)s"
#: templates/mumble/list.html:20
msgid "No server instances have been configured yet."
msgstr "Aucune instance du serveur n'a été configurée pour l'instant."
#: templates/mumble/mumble.html:16
msgid ""
"\n"
" <b>Hint:</b><br />\n"
" This area is used to display additional information for each channel and player, but requires JavaScript to be\n"
" displayed correctly. You will not see the detail pages, but you can use all links and forms\n"
" that are displayed.\n"
" "
msgstr ""
"\n"
" <b>Remarque :</b><br />\n"
" Cette zone est utilisée pour affichier des informations supplémentaires pour chaque canal et utilisateur.\n"
" JavaScript est nécessaire pour un meilleur affichage. Vous ne verrez pas les pages de détail mais vous pouvez\n"
" utiliser les liens et les formulaires.\n"
" "
#: templates/mumble/mumble.html:31
msgid "Website"
msgstr "Site web"
#: templates/mumble/mumble.html:33
msgid "Server version"
msgstr "Version du serveur"
#: templates/mumble/mumble.html:34
msgid "Minimal view"
msgstr "Vue minimaliste"
#: templates/mumble/mumble.html:37
msgid "Welcome message"
msgstr "Message de bienvenue"
#: templates/mumble/mumble.html:43
msgid "Server registration"
msgstr "Inscription serveur"
#: templates/mumble/mumble.html:46
msgid "You are registered on this server"
msgstr "Vous êtes authentifié sur ce serveur"
#: templates/mumble/mumble.html:48
msgid "You do not have an account on this server"
msgstr "Vous n'avez pas de compte sur ce serveur"
#: templates/mumble/mumble.html:57
#, python-format
msgid ""
"\n"
" <p>You need to be <a href=\"%(login_url)s\">logged in</a> to be able to register an account on this Mumble server.</p>\n"
" "
msgstr ""
"\n"
" <p>Vous devez être <a href=\"%(login_url)s\">authentifié</a> pour pouvoir inscrire un compte sur ce serveur Mumble</p>\n"
" "
#: templates/mumble/mumble.html:67
msgid ""
"\n"
" Sorry, due to a bug in Murmur 1.2.2, displaying and setting the Texture is disabled.\n"
" "
msgstr ""
"\n"
" Désolé, à cause d'un bug dans Murmur 1.2.2, l'affichage et le paramétrage des avatars sont désactivé.\n"
" "
#: templates/mumble/mumble.html:72
msgid ""
"\n"
" You can upload an image that you would like to use as your user texture here.\n"
" "
msgstr ""
"\n"
" Ici vous pouvez uploader l'avatar que vous souhaitez utiliser.\n"
" "
#: templates/mumble/mumble.html:77
msgid "Your current texture is"
msgstr "Votre avatar est"
#: templates/mumble/mumble.html:80
msgid "You don't currently have a texture set"
msgstr "Vous n'avez pas d'avatar pour l'instant"
#: templates/mumble/mumble.html:84
msgid ""
"\n"
" Hint: The texture image <b>needs</b> to be 600x60 in size. If you upload an image with\n"
" a different size, it will be resized accordingly.<br />\n"
" "
msgstr ""
"\n"
" Remarque : La taille de l'avatar <b>doit être</b> de 600x60. Si vous uploadez une image\n"
" d'une taille différente, elle sera redimensionnée.<br />\n"
" "
#: templates/mumble/mumble.html:103
msgid "Server administration"
msgstr "Administration du serveur"
#: templates/mumble/mumble.html:117
msgid "Player"
msgstr "Utilisateur"
#: templates/mumble/mumble.html:119
msgid "Online since"
msgstr "En ligne depuis"
#: templates/mumble/mumble.html:120
#: templates/mumble/player.html:9
msgid "Authenticated"
msgstr "Authentifié"
#: templates/mumble/mumble.html:121
#: templates/mumble/mumble.html.py:136
msgid "Admin"
msgstr "Admin"
#: templates/mumble/mumble.html:122
#: templates/mumble/player.html:12
msgid "Muted"
msgstr "Muet"
#: templates/mumble/mumble.html:123
#: templates/mumble/player.html:18
msgid "Deafened"
msgstr "Sourd"
#: templates/mumble/mumble.html:124
#: templates/mumble/player.html:21
msgid "Muted by self"
msgstr "Devenir muet"
#: templates/mumble/mumble.html:125
#: templates/mumble/player.html:24
msgid "Deafened by self"
msgstr "Devenir sourd"
#: templates/mumble/mumble.html:127
msgid "IP Address"
msgstr "Adresse IP du serveur"
#: templates/mumble/mumble.html:131
msgid "User"
msgstr "Utilisateur"
#: templates/mumble/mumble.html:134
msgid "Full Name"
msgstr "Nom"
#: templates/mumble/mumble.html:137
msgid "Sign-up date"
msgstr "Date d'enregistrement"
#: templates/mumble/mumble.html:142
msgid "User Comment"
msgstr "Commentaire d'utilisateur"
#: templates/mumble/mumble.html:154
#: templates/mumble/mumble.html.py:168
msgid "Kick user"
msgstr "Kicker l'utilisateur"
#: templates/mumble/mumble.html:160
msgid "Reason"
msgstr "Raison"
#: templates/mumble/mumble.html:165
msgid "Ban user"
msgstr "Bannir l'utilisateur"
#: templates/mumble/mumble.html:175
msgid "Channel"
msgstr "Canal"
#: templates/mumble/mumble.html:177
msgid "Channel ID"
msgstr "ID du canal"
#: templates/mumble/mumble.html:179
msgid "Connect"
msgstr "Se connecter"
#: templates/mumble/mumble.html:182
msgid "Channel description"
msgstr "Description du canal"
#: templates/mumble/mumble.html:229
msgid "Delete"
msgstr "Supprimer"
#: templates/mumble/mumble.html:265
msgid "Server Info"
msgstr "Information du serveur"
#: templates/mumble/mumble.html:266
msgid "Registration"
msgstr "Enregistrement"
#: templates/mumble/mumble.html:275
msgid "Administration"
msgstr "Administration"
#: templates/mumble/mumble.html:282
msgid "User List"
msgstr "Liste des utilisateurs"
#: templates/mumble/mumble.html:286
msgid "name"
msgstr "nom"
#: templates/mumble/mumble.html:306
msgid "Change password"
msgstr "Changer le mot de passe"
#: templates/mumble/mumble.html:319
msgid "Add"
msgstr "Ajouter"
#: templates/mumble/mumble.html:331
msgid "Save"
msgstr "Sauvegarder"
#: templates/mumble/mumble.html:357
msgid "Resync with Murmur"
msgstr "Synchroniser avec Murmur"
#: templates/mumble/player.html:15
msgid "Suppressed"
msgstr "Muet"
#: templates/mumble/player.html:27
msgid "has a User Comment set"
msgstr "a un commentaire"
#~ msgid "comment"
#~ msgstr "commentaire"
#~ msgid "hash"
#~ msgstr "hash"

View File

@@ -1,573 +0,0 @@
# Italian translation file for Mumble-Django.
#
# Copyright (C) 2009, satinez <info@satinez.net>
#
# Mumble-Django is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This package 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.
#
msgid ""
msgstr ""
"Project-Id-Version: Mumble-Django v0.8\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-03-14 18:23+0100\n"
"PO-Revision-Date: 2010-03-14 13:51\n"
"Last-Translator: <admin@admin.de>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Translated-Using: django-rosetta 0.5.3\n"
#: admin.py:34 admin.py:51
msgid "Master is running"
msgstr "Il Master è in esecuzione"
#: admin.py:59 models.py:162 templates/mumble/mumble.html:28
msgid "Server Address"
msgstr "Indirizzo del Server"
#: admin.py:66 models.py:165
msgid "Server Port"
msgstr "Port del Server"
#: admin.py:71
msgid "Instance is running"
msgstr "Istanza è in esecuzione"
#: admin.py:81
msgid "Registered users"
msgstr "Utenti registrati"
#: admin.py:91
msgid "Online users"
msgstr "Utenti online"
#: admin.py:101
msgid "Channel count"
msgstr "Quantità canali"
#: admin.py:108
msgid "Yes"
msgstr "Sì"
#: admin.py:110
msgid "No"
msgstr "No"
#: admin.py:114
msgid "Public"
msgstr "Publico"
#: admin.py:132 models.py:631 templates/mumble/mumble.html:223
msgid "Admin on root channel"
msgstr "Admin nel canale root"
#: forms.py:83
msgid "Password required to join. Leave empty for public servers."
msgstr "Password richiesta per entrare. Lasciare vuoto per i server pubblici."
#: forms.py:86
msgid "If on, IP adresses of the clients are not logged."
msgstr "Se è acceso, indirizzi IP dei clienti non vengono registrati."
#: forms.py:142
#, python-format
msgid ""
"Port number %(portno)d is not within the allowed range %(minrange)d - %"
"(maxrange)d"
msgstr ""
"Il Port %(portno)d non è consentito nel range %(minrange)d - %(maxrange)d"
#: forms.py:152
#, fuzzy
msgid "Default config"
msgstr "Canale default"
#: forms.py:165 templates/mumble/offline.html:12
msgid "This server is currently offline."
msgstr "Al momento questo server è offline."
#: forms.py:190
msgid "That name is forbidden by the server."
msgstr "Questo nome è proibito dal server."
#: forms.py:193 models.py:587
msgid "Another player already registered that name."
msgstr "Un altro giocatore è stato già sotto questo nome registrato."
#: forms.py:201 forms.py:307 models.py:589
msgid "Cannot register player without a password!"
msgstr "Non è possibile registrarsi senza una password!"
#: forms.py:213 models.py:179
msgid "Server Password"
msgstr "Server password"
#: forms.py:214
msgid ""
"This server is private and protected mode is active. Please enter the server "
"password."
msgstr ""
"Server privato, la protezione di registro è attiva. Digiti prego la password "
"d'accesso."
#: forms.py:222 forms.py:274
msgid "The password you entered is incorrect."
msgstr "La password d'accesso non è corretta."
#: forms.py:237
msgid "Link account"
msgstr "Link il conto"
#: forms.py:238
msgid ""
"The account already exists and belongs to me, just link it instead of "
"creating."
msgstr "L'account esiste già."
#: forms.py:255
msgid "No such user found."
msgstr "Nessun utente trovato."
#: forms.py:290
msgid "That account belongs to someone else."
msgstr "L'account appartiene a qualcun altro."
#: forms.py:293
msgid "Linking Admin accounts is not allowed."
msgstr "Collegare account Amministratore non è permesso."
#: forms.py:322 templates/mumble/mumble.html:65
#: templates/mumble/mumble.html.py:148 templates/mumble/mumble.html:278
msgid "User Texture"
msgstr "Immagine del Utente"
#: models.py:63
msgid "DBus or ICE base"
msgstr "DBus- o ICE-base"
#: models.py:64
msgid ""
"Examples: 'net.sourceforge.mumble.murmur' for DBus or 'Meta:tcp -h 127.0.0.1 "
"-p 6502' for Ice."
msgstr ""
"Esempi: 'net.sourceforge.mumble.murmur' per DBus o 'Meta: tcp-h 127.0.0.1-p "
"6502' per ICE."
#: models.py:65
msgid "Ice Secret"
msgstr "ICE Secret"
#: models.py:68 models.py:159
msgid "Mumble Server"
msgstr "Mumble Server"
#: models.py:69
msgid "Mumble Servers"
msgstr "Mumble Servers"
#: models.py:160
msgid "Server Name"
msgstr "Nome del Server"
#: models.py:161
msgid "Server ID"
msgstr "Server-ID"
#: models.py:163
msgid ""
"Hostname or IP address to bind to. You should use a hostname here, because "
"it will appear on the global server list."
msgstr ""
"Hostname o l'indirizzo IP da associare. Si dovrebbe usare un hostname qui, "
"perché sarà visualizzato nella lista globale dei server."
#: models.py:166
msgid "Port number to bind to. Leave empty to auto assign one."
msgstr "Numero del Port da associare. Lasciare vuoto per auto-assegnare uno."
#: models.py:167
msgid "Server Display Address"
msgstr "l'indirizzo Server display"
#: models.py:168
msgid ""
"This field is only relevant if you are located behind a NAT, and names the "
"Hostname or IP address to use in the Channel Viewer and for the global "
"server list registration. If not given, the addr and port fields are used. "
"If display and bind ports are equal, you can omit it here."
msgstr ""
"Questo campo è rilevante solo se si trova dietro un NAT, nomi e il Hostname "
"o indirizzi IP da utilizzare nel canale Viewer e per la lista globale dei "
"Server. \n"
"\n"
"Se il Port del display e il Port del bind sono uguali, è possibile omettere "
"qui."
#: models.py:174
msgid "Superuser Password"
msgstr "SuperUser password"
#: models.py:177
msgid "Website URL"
msgstr "URL del sito web"
#: models.py:178
msgid "Welcome Message"
msgstr "Messaggio di benvenuto"
#: models.py:180
msgid "Max. Users"
msgstr "Max. Utenti"
#: models.py:181
msgid "Bandwidth [Bps]"
msgstr "larghezza di banda [Bps]"
#: models.py:182
msgid "SSL Certificate"
msgstr "SSL-Certificato"
#: models.py:183
msgid "SSL Key"
msgstr "SSL-Chiave"
#: models.py:184
msgid "Player name regex"
msgstr "Regex per giocatori"
#: models.py:185
msgid "Channel name regex"
msgstr "Regex per Canali"
#: models.py:186
msgid "Default channel"
msgstr "Canale default"
#: models.py:187
msgid "Timeout"
msgstr "Timeout"
#: models.py:189
msgid "IP Obfuscation"
msgstr "Anonimizza indirizzo IP"
#: models.py:190
msgid "Require Certificate"
msgstr "Serve il Certificate"
#: models.py:191
msgid "Maximum length of text messages"
msgstr "La lunghezza massima dei messaggi"
#: models.py:192
msgid "Allow HTML to be used in messages"
msgstr "Permettere HTML nei messaggi"
#: models.py:193
msgid "Publish this server via Bonjour"
msgstr "Pubblica questo server tramite Bonjour"
#: models.py:194
msgid "Boot Server when Murmur starts"
msgstr "Boot Server quando si avvia Murmur"
#: models.py:212 models.py:213
msgid "Boot Server"
msgstr "Boot Server"
#: models.py:217 models.py:550
msgid "Server instance"
msgstr "Istanza di server"
#: models.py:218
msgid "Server instances"
msgstr "Istanze di server"
#: models.py:510 models.py:690
msgid "This field must not be updated once the record has been saved."
msgstr ""
"Questo campo non si puo cambiare, dopo che é stato salvato per la prima "
"volta."
#: models.py:547
msgid "Mumble player_id"
msgstr "ID del giocatore in Murmur"
#: models.py:548
msgid "User name and Login"
msgstr "Nome Utente e Login"
#: models.py:549
msgid "Login password"
msgstr "Login password"
#: models.py:551 templates/mumble/mumble.html:293
msgid "Account owner"
msgstr "Proprietario del account"
#: models.py:553
msgid "The user's comment."
msgstr "Commento dell'utente."
#: models.py:554
msgid "The user's hash."
msgstr "Hash dell'utente."
#: models.py:558
msgid "User account"
msgstr "Account del utente"
#: models.py:559
msgid "User accounts"
msgstr "Accounts degli utenti"
#: models.py:566
#, python-format
msgid "Mumble user %(mu)s on %(srv)s owned by Django user %(du)s"
msgstr "Account %(mu)s su %(srv)s con Utente %(du)s"
#: templates/mumble/list.html:20
msgid "No server instances have been configured yet."
msgstr "Nessune istanze del server sono stati configurati."
#: templates/mumble/mumble.html:16
msgid ""
"\n"
" <b>Hint:</b><br />\n"
" This area is used to display additional information for each channel "
"and player, but requires JavaScript to be\n"
" displayed correctly. You will not see the detail pages, but you can "
"use all links and forms\n"
" that are displayed.\n"
" "
msgstr ""
"\n"
" <b>Nota</b><br />\n"
" Questo settore è utilizzato per visualizzare informazioni aggiuntive "
"per ogni canale e giocatore, ma richiede JavaScript per essere\n"
" visualizzato correttamente. Non vedi il dettaglio delle pagine, ma "
"puoi utilizzare tutti i link e le forme\n"
" che vengono visualizzati.\n"
" "
#: templates/mumble/mumble.html:31
msgid "Website"
msgstr "Sito web"
#: templates/mumble/mumble.html:33
msgid "Server version"
msgstr "Versione del Server"
#: templates/mumble/mumble.html:34
msgid "Minimal view"
msgstr "La visualizzazione minimale"
#: templates/mumble/mumble.html:37
msgid "Welcome message"
msgstr "Messaggio di benvenuto"
#: templates/mumble/mumble.html:43
msgid "Server registration"
msgstr "Registrazione Server"
#: templates/mumble/mumble.html:46
msgid "You are registered on this server"
msgstr "Sei registrato su questo Server "
#: templates/mumble/mumble.html:48
msgid "You do not have an account on this server"
msgstr "Non sei registrato su questo Server "
#: templates/mumble/mumble.html:57
#, python-format
msgid ""
"\n"
" <p>You need to be <a href=\"%(login_url)s\">logged in</a> to be able "
"to register an account on this Mumble server.</p>\n"
" "
msgstr ""
"\n"
" <p>Devi avere un <a href=\"%(login_url)s\">login</a> per registrarti "
"su questo mumble server</p>\n"
" "
#: templates/mumble/mumble.html:67
msgid ""
"\n"
" Sorry, due to a bug in Murmur 1.2.2, displaying and setting the "
"Texture is disabled.\n"
" "
msgstr ""
"\n"
"Scusa, a causa di un bug in Murmur 1.2.2, la visualizzazione e "
"l'impostazione è disattivato."
#: templates/mumble/mumble.html:72
msgid ""
"\n"
" You can upload an image that you would like to use as your user "
"texture here.\n"
" "
msgstr ""
"\n"
"È possibile caricare l'immagine che si desidera utilizzare come texture "
"utente."
#: templates/mumble/mumble.html:77
msgid "Your current texture is"
msgstr "Il tuo attuale immagine"
#: templates/mumble/mumble.html:80
msgid "You don't currently have a texture set"
msgstr "Al momento non hai dei texture set"
#: templates/mumble/mumble.html:84
msgid ""
"\n"
" Hint: The texture image <b>needs</b> to be 600x60 in size. If "
"you upload an image with\n"
" a different size, it will be resized accordingly.<br />\n"
" "
msgstr ""
"\n"
"Nota! La immagine <b>deve avere</b> le dimensioni di 600x60 pixel. Se hai "
"un'immagine con una dimensione diversa, si aggiusta automaticamente. "
#: templates/mumble/mumble.html:103
msgid "Server administration"
msgstr "Amministrazione del Server"
#: templates/mumble/mumble.html:117
msgid "Player"
msgstr "Giocatore"
#: templates/mumble/mumble.html:119
msgid "Online since"
msgstr "Online da"
#: templates/mumble/mumble.html:120 templates/mumble/player.html:9
msgid "Authenticated"
msgstr "Authenticated"
#: templates/mumble/mumble.html:121 templates/mumble/mumble.html.py:136
msgid "Admin"
msgstr "Amministratore"
#: templates/mumble/mumble.html:122 templates/mumble/player.html:12
msgid "Muted"
msgstr "Muto"
#: templates/mumble/mumble.html:123 templates/mumble/player.html:18
msgid "Deafened"
msgstr "Sordo"
#: templates/mumble/mumble.html:124 templates/mumble/player.html:21
msgid "Muted by self"
msgstr "Mutato solo"
#: templates/mumble/mumble.html:125 templates/mumble/player.html:24
msgid "Deafened by self"
msgstr "Rintronarsi"
#: templates/mumble/mumble.html:127
msgid "IP Address"
msgstr "Indirizzo IP del Server"
#: templates/mumble/mumble.html:131
msgid "User"
msgstr "Utente"
#: templates/mumble/mumble.html:134
msgid "Full Name"
msgstr "Nome"
#: templates/mumble/mumble.html:137
msgid "Sign-up date"
msgstr "Data di registrazione"
#: templates/mumble/mumble.html:142
msgid "User Comment"
msgstr "User Comment"
#: templates/mumble/mumble.html:154 templates/mumble/mumble.html.py:168
msgid "Kick user"
msgstr "Kick utente"
#: templates/mumble/mumble.html:160
msgid "Reason"
msgstr "Diritto"
#: templates/mumble/mumble.html:165
msgid "Ban user"
msgstr "Ban utenti"
#: templates/mumble/mumble.html:175
msgid "Channel"
msgstr "Canale"
#: templates/mumble/mumble.html:177
msgid "Channel ID"
msgstr "ID del Canale"
#: templates/mumble/mumble.html:179
msgid "Connect"
msgstr "Connect"
#: templates/mumble/mumble.html:182
msgid "Channel description"
msgstr "descrizione del canale"
#: templates/mumble/mumble.html:229
msgid "Delete"
msgstr "Cancellare"
#: templates/mumble/mumble.html:265
msgid "Server Info"
msgstr "Informazioni del Server"
#: templates/mumble/mumble.html:266
msgid "Registration"
msgstr "Registrazione"
#: templates/mumble/mumble.html:275
msgid "Administration"
msgstr "Amministrazione"
#: templates/mumble/mumble.html:282
msgid "User List"
msgstr "Lista dei utenti"
#: templates/mumble/mumble.html:286
msgid "name"
msgstr "Nome"
#: templates/mumble/mumble.html:306
msgid "Change password"
msgstr "Cambia la password"
#: templates/mumble/mumble.html:319
msgid "Add"
msgstr "Aggiungere"
#: templates/mumble/mumble.html:331
msgid "Save"
msgstr "Salva"
#: templates/mumble/mumble.html:357
msgid "Resync with Murmur"
msgstr "Sincronizza con Murmur"
#: templates/mumble/player.html:15
msgid "Suppressed"
msgstr "Soppresso"
#: templates/mumble/player.html:27
msgid "has a User Comment set"
msgstr "Ha un commento del Utente set"

View File

@@ -1,543 +0,0 @@
# Japanese translation file for Mumble-Django.
#
# Copyright (C) 2009, withgod <noname@withgod.jp>
# Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
#
# Mumble-Django is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This package 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.
#
msgid ""
msgstr ""
"Project-Id-Version: Mumble-Django v0.8\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-03-14 18:23+0100\n"
"PO-Revision-Date: 2010-03-15 21:47\n"
"Last-Translator: <nocontents@gmail.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Translated-Using: django-rosetta 0.5.2\n"
#: admin.py:34 admin.py:51
msgid "Master is running"
msgstr "マスター実行中"
#: admin.py:59 models.py:162 templates/mumble/mumble.html:28
msgid "Server Address"
msgstr "サーバアドレス"
#: admin.py:66 models.py:165
msgid "Server Port"
msgstr "サーバポート"
#: admin.py:71
msgid "Instance is running"
msgstr "インスタンス実行中"
#: admin.py:81
msgid "Registered users"
msgstr "ユーザ登録"
#: admin.py:91
msgid "Online users"
msgstr "オンラインのユーザ"
#: admin.py:101
msgid "Channel count"
msgstr "チャンネル数"
#: admin.py:108
msgid "Yes"
msgstr "はい"
#: admin.py:110
msgid "No"
msgstr "いいえ"
#: admin.py:114
msgid "Public"
msgstr "公開"
#: admin.py:132 models.py:631 templates/mumble/mumble.html:223
msgid "Admin on root channel"
msgstr "管理者権限を与える"
#: forms.py:83
msgid "Password required to join. Leave empty for public servers."
msgstr "サーバに参加するにはパスワードが必要。空白にすると公開サーバになります。"
#: forms.py:86
msgid "If on, IP adresses of the clients are not logged."
msgstr "If on, IP adresses of the clients are not logged."
#: forms.py:142
#, python-format
msgid "Port number %(portno)d is not within the allowed range %(minrange)d - %(maxrange)d"
msgstr "ポート番号 %(portno)d は許可されていません、次の範囲が許可されています %(minrange)d - %(maxrange)d"
#: forms.py:152
msgid "Default config"
msgstr "デフォルトコンフィグ"
#: forms.py:165 templates/mumble/offline.html:12
msgid "This server is currently offline."
msgstr "このサーバーは現在停止中です。"
#: forms.py:190
msgid "That name is forbidden by the server."
msgstr "その名前はサーバによって不可視にされています"
#: forms.py:193 models.py:587
msgid "Another player already registered that name."
msgstr "その名前は既に使われています."
#: forms.py:201 forms.py:307 models.py:589
msgid "Cannot register player without a password!"
msgstr "パスワードは必須です"
#: forms.py:213 models.py:179
msgid "Server Password"
msgstr "サーバパスワード"
#: forms.py:214
msgid "This server is private and protected mode is active. Please enter the server password."
msgstr "本サーバをプライベート及びプロテクトモードで利用する場合は、パスワードを入力してください。"
#: forms.py:222 forms.py:274
msgid "The password you entered is incorrect."
msgstr "パスワードが不正です。"
#: forms.py:237
msgid "Link account"
msgstr "アカウントリンク"
#: forms.py:238
msgid "The account already exists and belongs to me, just link it instead of creating."
msgstr "アカウントは既に存在していて、自分にリンクしています。リンクの変わりに作成して下さい。"
#: forms.py:255
msgid "No such user found."
msgstr "ユーザが見つかりません"
#: forms.py:290
msgid "That account belongs to someone else."
msgstr "このアカウントは既に他のアカウントにリンクされています。"
#: forms.py:293
msgid "Linking Admin accounts is not allowed."
msgstr "管理者アカウントへのリンクは許可されていません"
#: forms.py:322 templates/mumble/mumble.html:65
#: templates/mumble/mumble.html.py:148 templates/mumble/mumble.html:278
msgid "User Texture"
msgstr "ユーザ画像"
#: models.py:63
msgid "DBus or ICE base"
msgstr "DBusもしくはICE"
#: models.py:64
msgid "Examples: 'net.sourceforge.mumble.murmur' for DBus or 'Meta:tcp -h 127.0.0.1 -p 6502' for Ice."
msgstr "例: DBusなら'net.sourceforge.mumble.murmur' Iceなら'Meta:tcp -h 127.0.0.1 -p 6502'"
#: models.py:65
msgid "Ice Secret"
msgstr "Ice Secret"
#: models.py:68 models.py:159
msgid "Mumble Server"
msgstr "マンブルユーザID"
#: models.py:69
msgid "Mumble Servers"
msgstr "マンブルユーザID"
#: models.py:160
msgid "Server Name"
msgstr "サーバ名"
#: models.py:161
msgid "Server ID"
msgstr "サーバID"
#: models.py:163
msgid "Hostname or IP address to bind to. You should use a hostname here, because it will appear on the global server list."
msgstr "利用するホスト名もしくはIPアドレス. ホスト名も利用することが出来ます。 サーバ一覧に表示されます。."
#: models.py:166
msgid "Port number to bind to. Leave empty to auto assign one."
msgstr "利用するポート番号を指定します、未指定の場合空いているポートを利用します。"
#: models.py:167
msgid "Server Display Address"
msgstr "サーバアドレス"
#: models.py:168
msgid "This field is only relevant if you are located behind a NAT, and names the Hostname or IP address to use in the Channel Viewer and for the global server list registration. If not given, the addr and port fields are used. If display and bind ports are equal, you can omit it here."
msgstr "本項目は、NATの内側等にあるサーバに適切です。ホスト名もしくはIPアドレスを、チャンネルビューアや、サーバリスト登録に使います。 "
#: models.py:174
msgid "Superuser Password"
msgstr "管理者パスワード"
#: models.py:177
msgid "Website URL"
msgstr "ウェブサイトのURL"
#: models.py:178
msgid "Welcome Message"
msgstr "サーバメッセージ"
#: models.py:180
msgid "Max. Users"
msgstr "最大ユーザ数"
#: models.py:181
msgid "Bandwidth [Bps]"
msgstr "帯域制限 [Bps]"
#: models.py:182
msgid "SSL Certificate"
msgstr "SSL認証"
#: models.py:183
msgid "SSL Key"
msgstr "SSL認証鍵"
#: models.py:184
msgid "Player name regex"
msgstr "ユーザ名の正規表現制限"
#: models.py:185
msgid "Channel name regex"
msgstr "チャンネル名の正規表現制限"
#: models.py:186
msgid "Default channel"
msgstr "デフォルトチャンネル"
#: models.py:187
msgid "Timeout"
msgstr "タイムアウト"
#: models.py:189
msgid "IP Obfuscation"
msgstr "IPアドレス隠蔽"
#: models.py:190
msgid "Require Certificate"
msgstr "SSL認証"
#: models.py:191
msgid "Maximum length of text messages"
msgstr "テキストメッセージの最大文字数"
#: models.py:192
msgid "Allow HTML to be used in messages"
msgstr "HTMLメッセージを許可する"
#: models.py:193
msgid "Publish this server via Bonjour"
msgstr "Bonjourでこのサーバを公開する"
#: models.py:194
msgid "Boot Server when Murmur starts"
msgstr "Murmur起動時にサーバを起動します"
#: models.py:212 models.py:213
msgid "Boot Server"
msgstr "サーバ起動"
#: models.py:217 models.py:550
msgid "Server instance"
msgstr "サーバインスタンス"
#: models.py:218
msgid "Server instances"
msgstr "全サーバインスタンス"
#: models.py:510 models.py:690
msgid "This field must not be updated once the record has been saved."
msgstr "この項目はアップデート出来ません."
#: models.py:547
msgid "Mumble player_id"
msgstr "マンブルユーザID"
#: models.py:548
msgid "User name and Login"
msgstr "ユーザID"
#: models.py:549
msgid "Login password"
msgstr "パスワード"
#: models.py:551 templates/mumble/mumble.html:293
msgid "Account owner"
msgstr "アカウントの所有者"
#: models.py:553
msgid "The user's comment."
msgstr "ユーザコメント"
#: models.py:554
msgid "The user's hash."
msgstr "ユーザのハッシュ"
#: models.py:558
msgid "User account"
msgstr "ユーザアカウント"
#: models.py:559
msgid "User accounts"
msgstr "全ユーザアカウント"
#: models.py:566
#, python-format
msgid "Mumble user %(mu)s on %(srv)s owned by Django user %(du)s"
msgstr "マンブルユーザ %(mu)s は %(srv)s のDjangoユーザ %(du)s です"
#: templates/mumble/list.html:20
msgid "No server instances have been configured yet."
msgstr "サーバ設定が存在しません"
#: templates/mumble/mumble.html:16
msgid ""
"\n"
" <b>Hint:</b><br />\n"
" This area is used to display additional information for each channel and player, but requires JavaScript to be\n"
" displayed correctly. You will not see the detail pages, but you can use all links and forms\n"
" that are displayed.\n"
" "
msgstr ""
"\n"
" <b>ヒント:</b><br />\n"
" このエリアはチャンネル情報をやプレーヤー情報を表示するのにjavascriptが必要です\n"
" javascriptをオンにしないと、すべての情報を閲覧することは出来ません。 "
#: templates/mumble/mumble.html:31
msgid "Website"
msgstr "ウェブサイト"
#: templates/mumble/mumble.html:33
msgid "Server version"
msgstr "サーババージョン"
#: templates/mumble/mumble.html:34
msgid "Minimal view"
msgstr "縮小表示"
#: templates/mumble/mumble.html:37
msgid "Welcome message"
msgstr "サーバメッセージ"
#: templates/mumble/mumble.html:43
msgid "Server registration"
msgstr "サーバ登録"
#: templates/mumble/mumble.html:46
msgid "You are registered on this server"
msgstr "アカウントは既に登録されています"
#: templates/mumble/mumble.html:48
msgid "You do not have an account on this server"
msgstr "アカウントは登録されていません"
#: templates/mumble/mumble.html:57
#, python-format
msgid ""
"\n"
" <p>You need to be <a href=\"%(login_url)s\">logged in</a> to be able to register an account on this Mumble server.</p>\n"
" "
msgstr ""
"\n"
" <p><a href=\"%(login_url)s\">ログイン</a>してから ユーザをこのMumbleサーバに登録する必要があります</p>\n"
" "
#: templates/mumble/mumble.html:67
msgid ""
"\n"
" Sorry, due to a bug in Murmur 1.2.2, displaying and setting the Texture is disabled.\n"
" "
msgstr ""
"\n"
"1.2.2 ではユーザ画像の表示がバグってるため、ユーザ画像表示は無効です。"
#: templates/mumble/mumble.html:72
msgid ""
"\n"
" You can upload an image that you would like to use as your user texture here.\n"
" "
msgstr ""
"\n"
"任意のユーザ画像をここから登録することがきます。"
#: templates/mumble/mumble.html:77
msgid "Your current texture is"
msgstr "現在の画像"
#: templates/mumble/mumble.html:80
msgid "You don't currently have a texture set"
msgstr "貴方は画像を持っていません"
#: templates/mumble/mumble.html:84
msgid ""
"\n"
" Hint: The texture image <b>needs</b> to be 600x60 in size. If you upload an image with\n"
" a different size, it will be resized accordingly.<br />\n"
" "
msgstr ""
"\n"
"ヒント: 画像は600x60である<b>必要</b>があります。そのサイズを超えたり収まらない 場合は、リサイズが行われます。 <br />\n"
" "
#: templates/mumble/mumble.html:103
msgid "Server administration"
msgstr "サーバ管理"
#: templates/mumble/mumble.html:117
msgid "Player"
msgstr "プレーヤ"
#: templates/mumble/mumble.html:119
msgid "Online since"
msgstr "接続開始時間"
#: templates/mumble/mumble.html:120 templates/mumble/player.html:9
msgid "Authenticated"
msgstr "登録済み"
#: templates/mumble/mumble.html:121 templates/mumble/mumble.html.py:136
msgid "Admin"
msgstr "管理者"
#: templates/mumble/mumble.html:122 templates/mumble/player.html:12
msgid "Muted"
msgstr "発言禁止"
#: templates/mumble/mumble.html:123 templates/mumble/player.html:18
msgid "Deafened"
msgstr "聴取禁止"
#: templates/mumble/mumble.html:124 templates/mumble/player.html:21
msgid "Muted by self"
msgstr "自分で発言禁止"
#: templates/mumble/mumble.html:125 templates/mumble/player.html:24
msgid "Deafened by self"
msgstr "自分で聴取禁止"
#: templates/mumble/mumble.html:127
msgid "IP Address"
msgstr "IPアドレス"
#: templates/mumble/mumble.html:131
msgid "User"
msgstr "ユーザ"
#: templates/mumble/mumble.html:134
msgid "Full Name"
msgstr "名前"
#: templates/mumble/mumble.html:137
msgid "Sign-up date"
msgstr "登録日"
#: templates/mumble/mumble.html:142
msgid "User Comment"
msgstr "ユーザアカウント"
#: templates/mumble/mumble.html:154 templates/mumble/mumble.html.py:168
msgid "Kick user"
msgstr "ユーザをキック"
#: templates/mumble/mumble.html:160
msgid "Reason"
msgstr "意味"
#: templates/mumble/mumble.html:165
msgid "Ban user"
msgstr "ユーザを追放"
#: templates/mumble/mumble.html:175
msgid "Channel"
msgstr "チャンネル"
#: templates/mumble/mumble.html:177
msgid "Channel ID"
msgstr "チャンネルID"
#: templates/mumble/mumble.html:179
msgid "Connect"
msgstr "接続"
#: templates/mumble/mumble.html:182
msgid "Channel description"
msgstr "チャンネル説明"
#: templates/mumble/mumble.html:229
msgid "Delete"
msgstr "削除"
#: templates/mumble/mumble.html:265
msgid "Server Info"
msgstr "サーバ情報"
#: templates/mumble/mumble.html:266
msgid "Registration"
msgstr "登録"
#: templates/mumble/mumble.html:275
msgid "Administration"
msgstr "管理"
#: templates/mumble/mumble.html:282
msgid "User List"
msgstr "ユーザ一覧"
#: templates/mumble/mumble.html:286
msgid "name"
msgstr "名前"
#: templates/mumble/mumble.html:306
msgid "Change password"
msgstr "パスワード"
#: templates/mumble/mumble.html:319
msgid "Add"
msgstr "追加"
#: templates/mumble/mumble.html:331
msgid "Save"
msgstr "セーブ"
#: templates/mumble/mumble.html:357
msgid "Resync with Murmur"
msgstr "Murmurと再同期"
#: templates/mumble/player.html:15
msgid "Suppressed"
msgstr "鎮められた"
#: templates/mumble/player.html:27
msgid "has a User Comment set"
msgstr "コメントをセットされています"
#~ msgid "comment"
#~ msgstr "コメント"
#~ msgid "hash"
#~ msgstr "ハッシュ"
#~ msgid "Enter the ID of the default channel here. The Channel viewer displays the ID to server admins on the channel detail page."
#~ msgstr "接続開始時に利用されるデフォルトチャンネルIDを指定して下さい。チャンネル表示一覧にて チャンネル詳細を確認すればチャンネルIDを調べられます。."
#~ msgid "The admin group was not found in the ACL's groups list!"
#~ msgstr "管理者グループが権限一覧に見当たりません."

View File

@@ -1,56 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
from shutil import copy, move
from os.path import exists, join
from django.conf import settings
from django.db import connection
from django.db.models import signals
from mumble import models
from update_schema import update_schema
from server_detect import find_existing_instances
if settings.DATABASE_ENGINE == "sqlite3":
# Move the DB to the db subdirectory if necessary.
oldpath = join( settings.MUMBLE_DJANGO_ROOT, "mumble-django.db3" )
if not exists( settings.DATABASE_NAME ) and exists( oldpath ):
move( oldpath, settings.DATABASE_NAME )
cursor = connection.cursor()
tablename = models.Mumble._meta.db_table
if tablename in connection.introspection.get_table_list(cursor):
fields = connection.introspection.get_table_description(cursor, tablename)
uptodate = "server_id" in [ entry[0] for entry in fields ]
else:
# Table doesn't yet exist, so syncdb will create it properly
uptodate = True
if not uptodate:
if settings.DATABASE_ENGINE == "sqlite3":
# backup the db before the conversion.
copy( settings.DATABASE_NAME, settings.DATABASE_NAME+".bak" )
signals.post_syncdb.connect( update_schema, sender=models );
else:
signals.post_syncdb.connect( find_existing_instances, sender=models );

View File

@@ -1,15 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""

View File

@@ -1,202 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
import os
from django.core.management.base import BaseCommand
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.conf import settings
from mumble.models import Mumble
class TestFailed( Exception ):
pass;
class Command( BaseCommand ):
help = "Run a few tests on Mumble-Django's setup."
def handle(self, **options):
try:
import Ice
except ImportError:
pass
else:
self.check_slice();
self.check_rootdir();
self.check_dbase();
self.check_sites();
self.check_mumbles();
self.check_admins();
self.check_secret_key();
def check_slice( self ):
print "Checking slice file...",
if settings.SLICE is None:
raise TestFailed( "You don't have set the SLICE variable in settings.py." )
if " " in settings.SLICE:
raise TestFailed( "You have a space char in your Slice path. This will confuse Ice, please check." )
if not settings.SLICE.endswith( ".ice" ):
raise TestFailed( "The slice file name MUST end with '.ice'." )
try:
fd = open( settings.SLICE, "rb" )
slice = fd.read()
fd.close()
except IOError, err:
raise TestFailed( "Failed opening the slice file: %s" % err )
import Ice
Ice.loadSlice( settings.SLICE )
print "[ OK ]"
def check_rootdir( self ):
print "Checking root directory access...",
if not os.path.exists( settings.MUMBLE_DJANGO_ROOT ):
raise TestFailed( "The mumble-django root directory does not exist." );
elif settings.DATABASE_ENGINE != "sqlite3":
print "not using sqlite [ OK ]"
else:
statinfo = os.stat( settings.MUMBLE_DJANGO_ROOT );
if statinfo.st_uid == 0:
raise TestFailed(
"The mumble-django root directory belongs to user root. This is "
"most certainly not what you want because it will prevent your "
"web server from being able to write to the database. Please check." );
elif not os.access( settings.MUMBLE_DJANGO_ROOT, os.W_OK ):
raise TestFailed( "The mumble-django root directory is not writable." );
else:
print "[ OK ]";
def check_dbase( self ):
print "Checking database access...",
if settings.DATABASE_ENGINE == "sqlite3":
if not os.path.exists( settings.DATABASE_NAME ):
raise TestFailed( "database does not exist. Have you run syncdb yet?" );
else:
statinfo = os.stat( settings.DATABASE_NAME );
if statinfo.st_uid == 0:
raise TestFailed(
"the database file belongs to root. This is most certainly not what "
"you want because it will prevent your web server from being able "
"to write to it. Please check." );
elif not os.access( settings.DATABASE_NAME, os.W_OK ):
raise TestFailed( "database file is not writable." );
else:
print "[ OK ]";
else:
print "not using sqlite, so I can't check.";
def check_sites( self ):
print "Checking URL configuration...",
try:
site = Site.objects.get_current();
except Site.DoesNotExist:
try:
sid = settings.SITE_ID
except AttributeError:
from django.core.exceptions import ImproperlyConfigured
raise ImproperlyConfigured(
"You're using the Django \"sites framework\" without having set the SITE_ID "
"setting. Create a site in your database and rerun this command to fix this error.")
else:
print( "none set.\n"
"Please enter the domain where Mumble-Django is reachable." );
dom = raw_input( "> " ).strip();
site = Site( id=sid, name=dom, domain=dom );
site.save();
if site.domain == 'example.com':
print( "still the default.\n"
"The domain is configured as example.com, which is the default but does not make sense. "
"Please enter the domain where Mumble-Django is reachable." );
site.domain = raw_input( "> " ).strip();
site.save();
print site.domain, "[ OK ]";
def check_admins( self ):
print "Checking if an Admin user exists...",
for user in User.objects.all():
if user.is_superuser:
print "[ OK ]";
return;
raise TestFailed( ""
"No admin user exists, so you won't be able to log in to the admin system. You "
"should run `./manage.py createsuperuser` to create one." );
def check_mumbles( self ):
print "Checking Murmur instances...",
mm = Mumble.objects.all();
if mm.count() == 0:
raise TestFailed(
"no Mumble servers are configured, you might want to run "
"`./manage.py syncdb` to run an auto detection." );
else:
for mumble in mm:
try:
mumble.ctl
except Exception, err:
raise TestFailed(
"Connecting to Murmur `%s` (%s) failed: %s" % ( mumble.name, mumble.server, err )
);
print "[ OK ]";
def check_secret_key( self ):
print "Checking SECRET_KEY...",
blacklist = ( 'u-mp185msk#z4%s(do2^5405)y5d!9adbn92)apu_p^qvqh10v', );
if settings.SECRET_KEY in blacklist:
raise TestFailed(
"Your SECRET_KEY setting matches one of the keys that were put in the settings.py "
"file shipped with Mumble-Django, which means your SECRET_KEY is all but secret. "
"You should change the setting, or run gen_secret_key.sh to do it for you."
);
else:
print "[ OK ]";

View File

@@ -1,56 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
import Ice, IcePy, os, getpass
from sys import stderr
from django.core.management.base import BaseCommand
from mumble.models import MumbleServer
class Command( BaseCommand ):
help = "Check if the known servers support getSlice."
def handle(self, **options):
prop = Ice.createProperties([])
prop.setProperty("Ice.ImplicitContext", "Shared")
idd = Ice.InitializationData()
idd.properties = prop
ice = Ice.initialize(idd)
for serv in MumbleServer.objects.all():
print "Probing server at '%s'..." % serv.dbus
if serv.secret:
ice.getImplicitContext().put( "secret", serv.secret.encode("utf-8") )
prx = ice.stringToProxy( serv.dbus.encode("utf-8") )
# Try loading the Slice from Murmur directly via its getSlice method.
try:
slice = IcePy.Operation( 'getSlice',
Ice.OperationMode.Idempotent, Ice.OperationMode.Idempotent,
True, (), (), (), IcePy._t_string, ()
).invoke(prx, ((), None))
except TypeError, err:
print " Received TypeError:", err
print " It seems your version of IcePy is incompatible."
except Ice.OperationNotExistException:
print " Your version of Murmur does not support getSlice."
else:
print " Successfully received the slice (length: %d bytes.)" % len(slice)

View File

@@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
from django.core.management.commands.runserver import Command as OrigCommand
from mumble.murmurenvutils import MumbleCommandWrapper
class Command( MumbleCommandWrapper, OrigCommand ):
pass

View File

@@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
from django.core.management.commands.shell import Command as OrigCommand
from mumble.murmurenvutils import MumbleCommandWrapper_noargs
class Command( MumbleCommandWrapper_noargs, OrigCommand ):
pass

View File

@@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
from django.core.management.commands.syncdb import Command as OrigCommand
from mumble.murmurenvutils import MumbleCommandWrapper_noargs
class Command( MumbleCommandWrapper_noargs, OrigCommand ):
pass

View File

@@ -1,169 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
import os, getpass
from django.db import DatabaseError
from django.conf import settings
from mumble.models import MumbleServer, Mumble
from mumble.mctl import MumbleCtlBase
def find_in_dicts( keys, conf, default, valueIfNotFound=None ):
if not isinstance( keys, tuple ):
keys = ( keys, );
for keyword in keys:
if keyword in conf:
return conf[keyword];
for keyword in keys:
keyword = keyword.lower();
if keyword in default:
return default[keyword];
return valueIfNotFound;
def find_existing_instances( **kwargs ):
if "verbosity" in kwargs:
v = kwargs['verbosity'];
else:
v = 1;
if v > 1:
print "Starting Mumble servers and players detection now.";
triedEnviron = False;
online = False;
while not online:
if not triedEnviron and 'MURMUR_CONNSTR' in os.environ:
dbusName = os.environ['MURMUR_CONNSTR'];
triedEnviron = True;
if v > 1:
print "Trying environment setting", dbusName;
else:
print "--- Murmur connection info ---"
print " 1) DBus -- net.sourceforge.mumble.murmur"
print " 2) ICE -- Meta:tcp -h 127.0.0.1 -p 6502"
print "Enter 1 or 2 for the defaults above, nothing to skip Server detection,"
print "and if the defaults do not fit your needs, enter the correct string."
print "Whether to use DBus or Ice will be detected automatically from the"
print "string's format."
print
dbusName = raw_input( "Service string: " ).strip();
if not dbusName:
if v:
print 'Be sure to run "python manage.py syncdb" with Murmur running before'
print "trying to use this app! Otherwise, existing Murmur servers won't be"
print 'configurable!';
return False;
elif dbusName == "1":
dbusName = "net.sourceforge.mumble.murmur";
elif dbusName == "2":
dbusName = "Meta:tcp -h 127.0.0.1 -p 6502";
icesecret = getpass.getpass("Please enter the Ice secret (if any): ");
try:
ctl = MumbleCtlBase.newInstance( dbusName, settings.SLICE, icesecret );
except Exception, instance:
if v:
print "Unable to connect using name %s. The error was:" % dbusName;
print instance;
print
else:
online = True;
if v > 1:
print "Successfully connected to Murmur via connection string %s, using %s." % ( dbusName, ctl.method );
servIDs = ctl.getAllServers();
try:
meta = MumbleServer.objects.get( dbus=dbusName );
except MumbleServer.DoesNotExist:
meta = MumbleServer( dbus=dbusName );
finally:
meta.secret = icesecret;
meta.save();
for id in servIDs:
if v > 1:
print "Checking Murmur instance with id %d." % id;
# first check that the server has not yet been inserted into the DB
try:
instance = Mumble.objects.get( server=meta, srvid=id );
except Mumble.DoesNotExist:
values = {
"server": meta,
"srvid": id,
}
if v:
print "Found new Murmur instance %d on bus '%s'... " % ( id, dbusName )
# now create a model for the record set.
instance = Mumble( **values );
else:
if v:
print "Syncing Murmur instance %d: '%s'... " % ( instance.id, instance.name )
try:
instance.configureFromMurmur();
except DatabaseError, err:
try:
# Find instances with the same address/port
dup = Mumble.objects.get( addr=instance.addr, port=instance.port )
except Mumble.DoesNotExist:
# None exist - this must've been something else.
print "Server ID / Name: %d / %s" % ( instance.srvid, instance.name )
raise err
else:
print "ERROR: There is already another server instance registered"
print " on the same address and port."
print " -------------"
print " New Server ID:", instance.srvid,
print " New Server Name:", instance.name
print " Address:", instance.addr
print " Port:", instance.port
print " Connection string:", instance.server.dbus
print " -------------"
print " Duplicate Server ID:", dup.srvid,
print "Duplicate Server Name:", dup.name
print " Address:", dup.addr
print " Port:", dup.port
print " Connection string:", dup.server.dbus
return False
except Exception, err:
print "Server ID / Name: %d / %s" % ( instance.srvid, instance.name )
raise err
# Now search for players on this server that have not yet been registered
if instance.booted:
if v > 1:
print "Looking for registered Players on Server id %d." % id;
instance.readUsersFromMurmur( verbose=v );
elif v:
print "This server is not running, can't sync players.";
if v > 1:
print "Successfully finished Servers and Players detection.";
return True;

View File

@@ -1,76 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
import os
from os.path import join
from django.db import connection, transaction
from django.db.models import signals
from django.conf import settings
from mumble import models
from mumble.management.server_detect import find_existing_instances
def update_schema( **kwargs ):
if "verbosity" in kwargs:
v = kwargs['verbosity'];
else:
v = 1;
if v:
print "Migrating Database schema for Mumble-Django 2.0 now."
scriptdir = join( settings.CONVERSIONSQL_ROOT, {
'postgresql_psycopg2': 'pgsql',
'postgresql': 'pgsql',
'mysql': 'mysql',
'sqlite3': 'sqlite',
}[settings.DATABASE_ENGINE] )
if v > 1:
print "Reading migration scripts for %s from '%s'" % ( settings.DATABASE_ENGINE, scriptdir )
scripts = [ filename for filename in os.listdir( scriptdir ) if filename.endswith( ".sql" ) ]
scripts.sort()
for filename in scripts:
cursor = connection.cursor()
scriptpath = os.path.join( scriptdir, filename )
scriptfile = open( scriptpath, "r" )
try:
if v > 1:
print "Running migration script '%s'..." % scriptpath
stmt = scriptfile.read()
cursor.execute( stmt )
except IOError, err:
print "Error reading file '%s':" % filename
print err
except cursor.db.connection.Error, err:
print "Error executing file '%s':" % filename
print err
finally:
scriptfile.close()
cursor.close()
if v:
print "Database migration finished successfully."
find_existing_instances( **kwargs )

View File

@@ -1,350 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
import socket
import datetime
import re
from time import time
from django.utils.http import urlquote
from django.conf import settings
def cmp_channels( left, rite ):
""" Compare two channels, first by position, and if that equals, by name. """
if hasattr( left, "position" ) and hasattr( rite, "position" ):
byorder = cmp( left.position, rite.position );
if byorder != 0:
return byorder;
return cmp_names( left, rite );
def cmp_names( left, rite ):
""" Compare two objects by their name property. """
return cmp( left.name, rite.name );
class mmChannel( object ):
""" Represents a channel in Murmur. """
def __init__( self, server, channel_obj, parent_chan = None ):
self.server = server;
self.players = list();
self.subchans = list();
self.linked = list();
self.channel_obj = channel_obj;
self.chanid = channel_obj.id;
self.parent = parent_chan;
if self.parent is not None:
self.parent.subchans.append( self );
self._acl = None;
# Lookup unknown attributes in self.channel_obj to automatically include Murmur's fields
def __getattr__( self, key ):
if hasattr( self.channel_obj, key ):
return getattr( self.channel_obj, key );
else:
raise AttributeError( "'%s' object has no attribute '%s'" % ( self.__class__.__name__, key ) );
def parent_channels( self ):
""" Return the names of this channel's parents in the channel tree. """
if self.parent is None or self.parent.is_server or self.parent.chanid == 0:
return [];
return self.parent.parent_channels() + [self.parent.name];
def getACL( self ):
""" Retrieve the ACL for this channel. """
if not self._acl:
self._acl = mmACL( self, self.server.ctl.getACL( self.server.srvid, self.chanid ) );
return self._acl;
acl = property( getACL );
is_server = False;
is_channel = True;
is_player = False;
playerCount = property(
lambda self: len( self.players ) + sum( [ chan.playerCount for chan in self.subchans ] ),
doc="The number of players in this channel."
);
id = property(
lambda self: "channel_%d"%self.chanid,
doc="A string ready to be used in an id property of an HTML tag."
);
top_or_not_empty = property(
lambda self: self.parent is None or self.parent.chanid == 0 or self.playerCount > 0,
doc="True if this channel needs to be shown because it is root, a child of root, or has players."
);
show = property( lambda self: settings.SHOW_EMPTY_SUBCHANS or self.top_or_not_empty );
def __str__( self ):
return '<Channel "%s" (%d)>' % ( self.name, self.chanid );
def sort( self ):
""" Sort my subchannels and players, and then iterate over them and sort them recursively. """
self.subchans.sort( cmp_channels );
self.players.sort( cmp_names );
for subc in self.subchans:
subc.sort();
def visit( self, callback, lvl = 0 ):
""" Call callback on myself, then visit my subchans, then my players. """
callback( self, lvl );
for subc in self.subchans:
subc.visit( callback, lvl + 1 );
for plr in self.players:
plr.visit( callback, lvl + 1 );
def getURL( self, for_user = None ):
""" Create an URL to connect to this channel. The URL is of the form
mumble://username@host:port/parentchans/self.name
"""
from urlparse import urlunsplit
versionstr = "version=%d.%d.%d" % tuple(self.server.version[:3]);
if self.parent is not None:
chanlist = self.parent_channels() + [self.name];
chanlist = [ urlquote( chan ) for chan in chanlist ];
urlpath = "/".join( chanlist );
else:
urlpath = "";
if for_user is not None:
netloc = "%s@%s" % ( for_user.name, self.server.netloc );
return urlunsplit(( "mumble", netloc, urlpath, versionstr, "" ))
else:
return urlunsplit(( "mumble", self.server.netloc, urlpath, versionstr, "" ))
connecturl = property( getURL );
def setDefault( self ):
""" Make this the server's default channel. """
self.server.defchan = self.chanid;
self.server.save();
is_default = property(
lambda self: self.server.defchan == self.chanid,
doc="True if this channel is the server's default channel."
);
def asDict( self ):
chandata = self.channel_obj.__dict__.copy();
chandata['players'] = [ pl.asDict() for pl in self.players ];
chandata['subchans'] = [ sc.asDict() for sc in self.subchans ];
return chandata;
def asMvXml( self, parentnode ):
""" Return an XML tree for this channel suitable for MumbleViewer-ng. """
from xml.etree.cElementTree import SubElement
me = SubElement( parentnode, "item" , id=self.id, rel='channel' )
content = SubElement( me, "content" )
name = SubElement( content , "name" )
name.text = self.name
for sc in self.subchans:
sc.asMvXml(me)
for pl in self.players:
pl.asMvXml(me)
def asMvJson( self ):
""" Return a Dict for this channel suitable for MumbleViewer-ng. """
return {
"attributes": {
"href": self.connecturl,
"id": self.id,
"rel": "channel",
},
"data": self.name,
"children": [ sc.asMvJson() for sc in self.subchans ] + \
[ pl.asMvJson() for pl in self.players ],
"state": { False: "closed", True: "open" }[self.top_or_not_empty],
}
class mmPlayer( object ):
""" Represents a Player in Murmur. """
def __init__( self, server, player_obj, player_chan ):
self.player_obj = player_obj;
self.onlinesince = datetime.datetime.fromtimestamp( float( time() - player_obj.onlinesecs ) );
self.channel = player_chan;
self.channel.players.append( self );
if self.isAuthed:
from mumble.models import MumbleUser
try:
self.mumbleuser = MumbleUser.objects.get( mumbleid=self.userid, server=server );
except MumbleUser.DoesNotExist:
self.mumbleuser = None;
else:
self.mumbleuser = None;
# Lookup unknown attributes in self.player_obj to automatically include Murmur's fields
def __getattr__( self, key ):
if hasattr( self.player_obj, key ):
return getattr( self.player_obj, key );
else:
raise AttributeError( "'%s' object has no attribute '%s'" % ( self.__class__.__name__, key ) );
def __str__( self ):
return '<Player "%s" (%d, %d)>' % ( self.name, self.session, self.userid );
hasComment = property(
lambda self: hasattr( self.player_obj, "comment" ) and bool(self.player_obj.comment),
doc="True if this player has a comment set."
);
isAuthed = property(
lambda self: self.userid != -1,
doc="True if this player is authenticated (+A)."
);
isAdmin = property(
lambda self: self.mumbleuser and self.mumbleuser.getAdmin(),
doc="True if this player is in the Admin group in the ACL."
);
is_server = False;
is_channel = False;
is_player = True;
def getIpAsString( self ):
""" Get the client's IPv4 or IPv6 address, in a pretty format. """
addr = self.player_obj.address;
if max( addr[:10] ) == 0 and addr[10:12] == (255, 255):
return "%d.%d.%d.%d" % tuple( addr[12:] );
ip6addr = [(hi << 8 | lo) for (hi, lo) in zip(addr[0::2], addr[1::2])]
# colon-separated string:
ipstr = ':'.join([ ("%x" % part) for part in ip6addr ]);
# 0:0:0 -> ::
return re.sub( "((^|:)(0:){2,})", '::', ipstr, 1 );
ipaddress = property( getIpAsString );
fqdn = property( lambda self: socket.getfqdn( self.ipaddress ),
doc="The fully qualified domain name of the user's host." );
# kept for compatibility to mmChannel (useful for traversal funcs)
playerCount = property( lambda self: -1, doc="Exists only for compatibility to mmChannel." );
id = property(
lambda self: "player_%d"%self.session,
doc="A string ready to be used in an id property of an HTML tag."
);
def visit( self, callback, lvl = 0 ):
""" Call callback on myself. """
callback( self, lvl );
def asDict( self ):
pldata = self.player_obj.__dict__.copy();
if self.mumbleuser:
if self.mumbleuser.hasTexture():
pldata['texture'] = self.mumbleuser.textureUrl;
return pldata;
def asMvXml( self, parentnode ):
""" Return an XML node for this player suitable for MumbleViewer-ng. """
from xml.etree.cElementTree import SubElement
me = SubElement( parentnode, "item" , id=self.id, rel='user' )
content = SubElement( me, "content" )
name = SubElement( content , "name" )
name.text = self.name
def asMvJson( self ):
""" Return a Dict for this player suitable for MumbleViewer-ng. """
return {
"attributes": {
"id": self.id,
"rel": "user",
},
'data': self.name,
}
class mmACL( object ):
""" Represents an ACL for a certain channel. """
def __init__( self, channel, acl_obj ):
self.channel = channel;
self.acls, self.groups, self.inherit = acl_obj;
self.groups_dict = {};
for group in self.groups:
self.groups_dict[ group.name ] = group;
def group_has_member( self, name, userid ):
""" Checks if the given userid is a member of the given group in this channel. """
if name not in self.groups_dict:
raise ReferenceError( "No such group '%s'" % name );
return userid in self.groups_dict[name].add or userid in self.groups_dict[name].members;
def group_add_member( self, name, userid ):
""" Make sure this userid is a member of the group in this channel (and subs). """
if name not in self.groups_dict:
raise ReferenceError( "No such group '%s'" % name );
group = self.groups_dict[name];
# if neither inherited nor to be added, add
if userid not in group.members and userid not in group.add:
group.add.append( userid );
# if to be removed, unremove
if userid in group.remove:
group.remove.remove( userid );
def group_remove_member( self, name, userid ):
""" Make sure this userid is NOT a member of the group in this channel (and subs). """
if name not in self.groups_dict:
raise ReferenceError( "No such group '%s'" % name );
group = self.groups_dict[name];
# if added here, unadd
if userid in group.add:
group.add.remove( userid );
# if member and not in remove, add to remove
elif userid in group.members and userid not in group.remove:
group.remove.append( userid );
def save( self ):
""" Send this ACL to Murmur. """
return self.channel.server.ctl.setACL(
self.channel.server.srvid,
self.channel.chanid,
self.acls, self.groups, self.inherit
);

View File

@@ -1,702 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
import socket, Ice, re
from sys import stderr
from django.utils.translation import ugettext_noop, ugettext_lazy as _
from django.contrib.auth.models import User
from django.db import models
from django.db.models import signals
from django.conf import settings
from mumble.mmobjects import mmChannel, mmPlayer
from mumble.mctl import MumbleCtlBase
def mk_config_property( field, doc="", get_coerce=None, get_none=None, set_coerce=unicode, set_none='' ):
""" Create a property for the given config field. """
def get_field( self ):
if self.id is not None:
val = self.getConf( field );
if val is None or val == '':
return get_none
if callable(get_coerce):
return get_coerce( val )
return val
return None
def set_field( self, value ):
if value is None:
self.setConf( field, set_none )
elif callable(set_coerce):
self.setConf( field, set_coerce(value) )
else:
self.setConf( field, value )
return property( get_field, set_field, doc=doc )
def mk_config_bool_property( field, doc="" ):
return mk_config_property( field, doc=doc,
get_coerce = lambda value: value == "true",
set_coerce = lambda value: str(value).lower()
);
class MumbleServer( models.Model ):
""" Represents a Murmur server installation. """
dbus = models.CharField( _('DBus or ICE base'), max_length=200, unique=True, default=settings.DEFAULT_CONN, help_text=_(
"Examples: 'net.sourceforge.mumble.murmur' for DBus or 'Meta:tcp -h 127.0.0.1 -p 6502' for Ice.") );
secret = models.CharField( _('Ice Secret'), max_length=200, blank=True );
class Meta:
verbose_name = _('Mumble Server');
verbose_name_plural = _('Mumble Servers');
def __init__( self, *args, **kwargs ):
models.Model.__init__( self, *args, **kwargs );
self._ctl = None;
self._conf = None;
def __unicode__( self ):
return self.dbus;
# Ctl instantiation
def getCtl( self ):
""" Instantiate and return a MumbleCtl object for this server.
Only one instance will be created, and reused on subsequent calls.
"""
if not self._ctl:
self._ctl = MumbleCtlBase.newInstance( self.dbus, settings.SLICE, self.secret );
return self._ctl;
ctl = property( getCtl, doc="Get a Control object for this server. The ctl is cached for later reuse." );
def isMethodDbus(self):
""" Return true if this instance uses DBus. """
rd = re.compile( r'^(\w+\.)*\w+$' );
return bool(rd.match(self.dbus))
method_dbus = property( isMethodDbus )
method_ice = property( lambda self: not self.isMethodDbus(), doc="Return true if this instance uses Ice." )
def getDefaultConf( self, field=None ):
""" Get a field from the default conf dictionary, or None if the field isn't set. """
if self._conf is None:
self._conf = self.ctl.getDefaultConf()
if field is None:
return self._conf
if field in self._conf:
return self._conf[field]
return None
def isOnline( self ):
""" Return true if this server process is running. """
possibleexceptions = []
try:
from Ice import ConnectionRefusedException
except ImportError, err:
if self.method_ice:
print >> stderr, err
return None
else:
possibleexceptions.append( ConnectionRefusedException )
try:
from dbus import DBusException
except ImportError, err:
if self.method_dbus:
print >> stderr, err
return None
else:
possibleexceptions.append( DBusException )
try:
self.ctl
except tuple(possibleexceptions), err:
print >> stderr, err
return False
except (EnvironmentError, RuntimeError), err:
print >> stderr, err
return None
else:
return True
online = property( isOnline )
defaultconf = property( getDefaultConf, doc="The default config dictionary." )
class Mumble( models.Model ):
""" Represents a Murmur server instance.
All configurable settings are represented by a field in this model. To change the
settings, just update the appropriate field and call the save() method.
To set up a new server instance, instanciate this Model. The first field you should
define is the "dbus" field, which tells the connector subsystem how to connect to
the Murmurd master process. Set this to the appropriate DBus service name or the
Ice proxy string.
When an instance of this model is deleted, the according server instance will be
deleted as well.
"""
server = models.ForeignKey( MumbleServer, verbose_name=_("Mumble Server") );
name = models.CharField( _('Server Name'), max_length=200 );
srvid = models.IntegerField( _('Server ID'), editable=False );
addr = models.CharField( _('Server Address'), max_length=200, blank=True, help_text=_(
"Hostname or IP address to bind to. You should use a hostname here, because it will appear on the "
"global server list.") );
port = models.IntegerField( _('Server Port'), blank=True, null=True, help_text=_(
"Port number to bind to. Leave empty to auto assign one.") );
display = models.CharField( _('Server Display Address'), max_length=200, blank=True, help_text=_(
"This field is only relevant if you are located behind a NAT, and names the Hostname or IP address "
"to use in the Channel Viewer and for the global server list registration. If not given, the addr "
"and port fields are used. If display and bind ports are equal, you can omit it here.") );
supw = property( lambda self: '',
lambda self, value: ( value and self.ctl.setSuperUserPassword( self.srvid, value ) ) or None,
doc=_('Superuser Password')
)
url = mk_config_property( "registerurl", ugettext_noop("Website URL") )
motd = mk_config_property( "welcometext", ugettext_noop("Welcome Message") )
passwd = mk_config_property( "password", ugettext_noop("Server Password") )
users = mk_config_property( "users", ugettext_noop("Max. Users"), get_coerce=int )
bwidth = mk_config_property( "bandwidth", ugettext_noop("Bandwidth [Bps]"), get_coerce=int )
sslcrt = mk_config_property( "certificate", ugettext_noop("SSL Certificate") )
sslkey = mk_config_property( "key", ugettext_noop("SSL Key") )
player = mk_config_property( "username", ugettext_noop("Player name regex") )
channel = mk_config_property( "channelname", ugettext_noop("Channel name regex") )
defchan = mk_config_property( "defaultchannel", ugettext_noop("Default channel"), get_coerce=int )
timeout = mk_config_property( "timeout", ugettext_noop("Timeout"), get_coerce=int )
obfsc = mk_config_bool_property( "obfuscate", ugettext_noop("IP Obfuscation") )
certreq = mk_config_bool_property( "certrequired", ugettext_noop("Require Certificate") )
textlen = mk_config_bool_property( "textmessagelength", ugettext_noop("Maximum length of text messages") )
html = mk_config_bool_property( "allowhtml", ugettext_noop("Allow HTML to be used in messages") )
bonjour = mk_config_bool_property( "bonjour", ugettext_noop("Publish this server via Bonjour") )
autoboot= mk_config_bool_property( "boot", ugettext_noop("Boot Server when Murmur starts") )
def getBooted( self ):
if self.id is not None:
if self.server.online:
return self.ctl.isBooted( self.srvid )
else:
return None
else:
return False
def setBooted( self, value ):
if value != self.getBooted():
if value:
self.ctl.start( self.srvid );
else:
self.ctl.stop( self.srvid );
booted = property( getBooted, setBooted, doc=ugettext_noop("Boot Server") )
online = property( getBooted, setBooted, doc=ugettext_noop("Boot Server") )
class Meta:
unique_together = ( ( 'server', 'srvid' ), );
verbose_name = _('Server instance');
verbose_name_plural = _('Server instances');
def __unicode__( self ):
if not self.id:
return u'Murmur "%s" (NOT YET CREATED)' % self.name;
return u'Murmur "%s" (%d)' % ( self.name, self.srvid );
def save( self, dontConfigureMurmur=False ):
""" Save the options configured in this model instance not only to Django's database,
but to Murmur as well.
"""
if dontConfigureMurmur:
return models.Model.save( self );
if self.id is None:
self.srvid = self.ctl.newServer();
self.ctl.setConf( self.srvid, 'registername', self.name );
if self.addr and self.addr != '0.0.0.0':
self.ctl.setConf( self.srvid, 'host', socket.gethostbyname(self.addr) );
else:
self.ctl.setConf( self.srvid, 'host', '' );
if self.port and self.port != settings.MUMBLE_DEFAULT_PORT + self.srvid - 1:
self.ctl.setConf( self.srvid, 'port', str(self.port) );
else:
self.ctl.setConf( self.srvid, 'port', '' );
if self.netloc:
self.ctl.setConf( self.srvid, 'registerhostname', self.netloc );
else:
self.ctl.setConf( self.srvid, 'registerhostname', '' );
return models.Model.save( self );
def __init__( self, *args, **kwargs ):
models.Model.__init__( self, *args, **kwargs );
self._channels = None;
self._rootchan = None;
users_regged = property( lambda self: self.mumbleuser_set.count(), doc="Number of registered users." );
users_online = property( lambda self: len(self.ctl.getPlayers(self.srvid)), doc="Number of online users." );
channel_cnt = property( lambda self: len(self.ctl.getChannels(self.srvid)), doc="Number of channels." );
is_public = property( lambda self: not self.passwd,
doc="False if a password is needed to join this server." );
is_server = True;
is_channel = False;
is_player = False;
ctl = property( lambda self: self.server.ctl );
def getConf( self, field ):
return self.ctl.getConf( self.srvid, field )
def setConf( self, field, value ):
return self.ctl.setConf( self.srvid, field, value )
def configureFromMurmur( self ):
conf = self.ctl.getAllConf( self.srvid );
if "registername" not in conf or not conf["registername"]:
self.name = "noname";
else:
self.name = conf["registername"];
if "registerhostname" in conf and conf["registerhostname"]:
if ':' in conf["registerhostname"]:
regname, regport = conf["registerhostname"].split(':')
regport = int(regport)
else:
regname = conf["registerhostname"]
regport = None
else:
regname = None
regport = None
if "host" in conf and conf["host"]:
addr = conf["host"]
else:
addr = None
if "port" in conf and conf["port"]:
self.port = int(conf["port"])
else:
self.port = None
if regname and addr:
if regport == self.port:
if socket.gethostbyname(regname) == socket.gethostbyname(addr):
self.display = ''
self.addr = regname
else:
self.display = regname
self.addr = addr
else:
self.display = conf["registerhostname"]
self.addr = addr
elif regname and not addr:
self.display = regname
self.addr = ''
elif addr and not regname:
self.display = ''
self.addr = addr
else:
self.display = ''
self.addr = ''
self.save( dontConfigureMurmur=True );
def readUsersFromMurmur( self, verbose=0 ):
if not self.booted:
raise SystemError( "This murmur instance is not currently running, can't sync." );
players = self.ctl.getRegisteredPlayers(self.srvid);
known_ids = [rec["mumbleid"]
for rec in MumbleUser.objects.filter( server=self ).values( "mumbleid" )
]
for idx in players:
playerdata = players[idx];
if playerdata.userid == 0: # Skip SuperUsers
continue;
if verbose > 1:
print "Checking Player with id %d." % playerdata.userid;
if playerdata.userid not in known_ids:
if verbose:
print 'Found new Player "%s".' % playerdata.name;
playerinstance = MumbleUser(
mumbleid = playerdata.userid,
name = playerdata.name,
password = '',
server = self,
owner = None
);
else:
if verbose > 1:
print "Player '%s' is already known." % playerdata.name;
playerinstance = MumbleUser.objects.get( server=self, mumbleid=playerdata.userid );
playerinstance.name = playerdata.name;
playerinstance.save( dontConfigureMurmur=True );
def isUserAdmin( self, user ):
""" Determine if the given user is an admin on this server. """
if user.is_authenticated():
if user.is_superuser:
return True;
try:
return self.mumbleuser_set.get( owner=user ).getAdmin();
except MumbleUser.DoesNotExist:
return False;
return False;
# Deletion handler
def deleteServer( self ):
""" Delete this server instance from Murmur. """
self.ctl.deleteServer(self.srvid)
@staticmethod
def pre_delete_listener( **kwargs ):
kwargs['instance'].deleteServer();
# Channel list
def getChannels( self ):
""" Query the channels from Murmur and create a tree structure.
Again, this will only be done for the first call to this function. Subsequent
calls will simply return the list created last time.
"""
if self._channels is None:
self._channels = {};
chanlist = self.ctl.getChannels(self.srvid).values();
links = {};
# sometimes, ICE seems to return the Channel list in a weird order.
# itercount prevents infinite loops.
itercount = 0;
maxiter = len(chanlist) * 3;
while len(chanlist) and itercount < maxiter:
itercount += 1;
for theChan in chanlist:
# Channels - Fields: 0 = ID, 1 = Name, 2 = Parent-ID, 3 = Links
if( theChan.parent == -1 ):
# No parent
self._channels[theChan.id] = mmChannel( self, theChan );
elif theChan.parent in self.channels:
# parent already known
self._channels[theChan.id] = mmChannel( self, theChan, self.channels[theChan.parent] );
else:
continue;
chanlist.remove( theChan );
self._channels[theChan.id].serverId = self.id;
# process links - if the linked channels are known, link; else save their ids to link later
for linked in theChan.links:
if linked in self._channels:
self._channels[theChan.id].linked.append( self._channels[linked] );
else:
if linked not in links:
links[linked] = list();
links[linked].append( self._channels[theChan.id] );
# check if earlier round trips saved channel ids to be linked to the current channel
if theChan.id in links:
for targetChan in links[theChan.id]:
targetChan.linked.append( self._channels[theChan.id] );
self._channels[0].name = self.name;
self.players = {};
for thePlayer in self.ctl.getPlayers(self.srvid).values():
# Players - Fields: 0 = UserID, 6 = ChannelID
self.players[ thePlayer.session ] = mmPlayer( self, thePlayer, self._channels[ thePlayer.channel ] );
self._channels[0].sort();
return self._channels;
channels = property( getChannels, doc="A convenience wrapper for getChannels()." );
rootchan = property( lambda self: self.channels[0], doc="A convenience wrapper for getChannels()[0]." );
def getNetloc( self ):
""" Return the address from the Display field (if any), or the server address.
Users from outside a NAT will need to use the Display address to connect
to this server instance.
"""
if self.display:
if ":" in self.display:
return self.display;
else:
daddr = self.display;
else:
daddr = self.addr;
if self.port and self.port != settings.MUMBLE_DEFAULT_PORT:
return "%s:%d" % (daddr, self.port);
else:
return daddr;
netloc = property( getNetloc );
def getURL( self, forUser = None ):
""" Create an URL of the form mumble://username@host:port/ for this server. """
if not self.netloc:
return None
from urlparse import urlunsplit
versionstr = "version=%d.%d.%d" % tuple(self.version[:3]);
if forUser is not None:
netloc = "%s@%s" % ( forUser.name, self.netloc );
return urlunsplit(( "mumble", netloc, "", versionstr, "" ))
else:
return urlunsplit(( "mumble", self.netloc, "", versionstr, "" ))
connecturl = property( getURL );
version = property( lambda self: self.ctl.getVersion(), doc="The version of Murmur." );
def asDict( self ):
return { 'name': self.name,
'id': self.id,
'root': self.rootchan.asDict()
};
def asMvXml( self ):
""" Return an XML tree for this server suitable for MumbleViewer-ng. """
from xml.etree.cElementTree import Element
root = Element("root")
self.rootchan.asMvXml(root)
return root
def asMvJson( self ):
""" Return a Dict for this server suitable for MumbleViewer-ng. """
return self.rootchan.asMvJson()
# "server" field protection
def __setattr__( self, name, value ):
if name == 'server':
if self.id is not None and self.server != value:
raise AttributeError( _( "This field must not be updated once the record has been saved." ) );
models.Model.__setattr__( self, name, value );
def kickUser( self, sessionid, reason="" ):
return self.ctl.kickUser( self.srvid, sessionid, reason );
def banUser( self, sessionid, reason="" ):
return self.ctl.addBanForSession( self.srvid, sessionid, reason=reason );
def mk_registration_property( field, doc="" ):
""" Create a property for the given registration field. """
def get_field( self ):
if "comment" in self.registration:
return self.registration["comment"];
else:
return None;
return property( get_field, doc=doc )
class MumbleUser( models.Model ):
""" Represents a User account in Murmur.
To change an account, simply set the according field in this model and call the save()
method to update the account in Murmur and in Django's database. Note that, once saved
for the first time, the server field must not be changed. Attempting to do this will
result in an AttributeError. To move an account to a new server, recreate it on the
new server and delete the old model.
When you delete an instance of this model, the according user account will be deleted
in Murmur as well, after revoking the user's admin privileges.
"""
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, blank=True );
server = models.ForeignKey( Mumble, verbose_name=_('Server instance'), related_name="mumbleuser_set" );
owner = models.ForeignKey( User, verbose_name=_('Account owner'), related_name="mumbleuser_set", null=True, blank=True );
comment = mk_registration_property( "comment", doc=ugettext_noop("The user's comment.") );
hash = mk_registration_property( "hash", doc=ugettext_noop("The user's hash.") );
class Meta:
unique_together = ( ( 'server', 'owner' ), ( 'server', 'mumbleid' ) );
verbose_name = _( 'User account' );
verbose_name_plural = _( 'User accounts' );
is_server = False;
is_channel = False;
is_player = True;
def __unicode__( self ):
return _("Mumble user %(mu)s on %(srv)s owned by Django user %(du)s") % {
'mu': self.name,
'srv': self.server,
'du': self.owner
};
def save( self, dontConfigureMurmur=False ):
""" Save the settings in this model to Murmur. """
if dontConfigureMurmur:
return models.Model.save( self );
ctl = self.server.ctl;
if self.owner:
email = self.owner.email;
else:
email = settings.DEFAULT_FROM_EMAIL;
if self.id is None:
# This is a new user record, so Murmur doesn't know about it yet
if len( ctl.getRegisteredPlayers( self.server.srvid, self.name ) ) > 0:
raise ValueError( _( "Another player already registered that name." ) );
if not self.password:
raise ValueError( _( "Cannot register player without a password!" ) );
self.mumbleid = ctl.registerPlayer( self.server.srvid, self.name, email, self.password );
# Update user's registration
elif self.password:
ctl.setRegistration(
self.server.srvid,
self.mumbleid,
self.name,
email,
self.password
);
# Don't save the users' passwords, we don't need them anyway
self.password = '';
return models.Model.save( self );
def __init__( self, *args, **kwargs ):
models.Model.__init__( self, *args, **kwargs );
self._registration = None;
# Admin handlers
def getAdmin( self ):
""" Get ACL of root Channel, get the admin group and see if this user is in it. """
if self.mumbleid == -1:
return False;
else:
return self.server.rootchan.acl.group_has_member( "admin", self.mumbleid );
def setAdmin( self, value ):
""" Set or revoke this user's membership in the admin group on the root channel. """
if self.mumbleid == -1:
return False;
if value:
self.server.rootchan.acl.group_add_member( "admin", self.mumbleid );
else:
self.server.rootchan.acl.group_remove_member( "admin", self.mumbleid );
self.server.rootchan.acl.save();
return value;
aclAdmin = property( getAdmin, setAdmin, doc=ugettext_noop('Admin on root channel') );
# Registration fetching
def getRegistration( self ):
""" Retrieve a user's registration from Murmur as a dict. """
if not self._registration:
self._registration = self.server.ctl.getRegistration( self.server.srvid, self.mumbleid );
return self._registration;
registration = property( getRegistration );
# Texture handlers
def getTexture( self ):
""" Get the user texture as a PIL Image. """
return self.server.ctl.getTexture(self.server.srvid, self.mumbleid);
def setTexture( self, image ):
""" Install the given image as the user's texture. """
self.server.ctl.setTexture(self.server.srvid, self.mumbleid, image)
texture = property( getTexture, setTexture,
doc="Get the texture as a PIL Image or set the Image as the texture."
);
def hasTexture( self ):
""" Check if this user has a texture set. """
try:
self.getTexture();
except ValueError:
return False;
else:
return True;
def getTextureUrl( self ):
""" Get a URL under which the texture can be retrieved. """
from views import showTexture
from django.core.urlresolvers import reverse
return reverse( showTexture, kwargs={ 'server': self.server.id, 'userid': self.id } );
textureUrl = property( getTextureUrl );
# Deletion handler
@staticmethod
def pre_delete_listener( **kwargs ):
kwargs['instance'].unregister();
def unregister( self ):
""" Delete this user account from Murmur. """
if self.getAdmin():
self.setAdmin( False );
self.server.ctl.unregisterPlayer(self.server.srvid, self.mumbleid)
# "server" field protection
def __setattr__( self, name, value ):
if name == 'server':
if self.id is not None and self.server != value:
raise AttributeError( _( "This field must not be updated once the record has been saved." ) );
models.Model.__setattr__( self, name, value );
signals.pre_delete.connect( Mumble.pre_delete_listener, sender=Mumble );
signals.pre_delete.connect( MumbleUser.pre_delete_listener, sender=MumbleUser );

View File

@@ -1,244 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
import os, subprocess, signal
from select import select
from os.path import join, exists
from shutil import copyfile
from django.conf import settings
from utils import ObjectInfo
def get_available_versions():
""" Return murmur versions installed inside the LAB_DIR. """
dirs = os.listdir( settings.TEST_MURMUR_LAB_DIR );
dirs.sort();
return dirs;
def run_callback( version, callback, *args, **kwargs ):
""" Initialize the database and run murmur, then call the callback.
After the callback has returned, kill murmur.
The callback will be passed the Popen object that wraps murmur,
and any arguments that were passed to run_callback.
If the callback raises an exception, murmur will still be properly
shutdown and the exception will be reraised.
The callback can either return an arbitrary value, or a tuple.
If it returns a tuple, it must be of the form:
( <any> intended_return_value, <bool> call_update_dbase )
That means: If the second value evaluates to True, update_dbase
will be called; the first value will be returned by run_callback.
If the callback returns anything other than a tuple, that value
will be returned directly.
So, If run_callback should return a tuple, you will need to return
the tuple form mentioned above in the callback, and put your tuple
into the first parameter.
"""
murmur_root = join( settings.TEST_MURMUR_LAB_DIR, version );
if not exists( murmur_root ):
raise EnvironmentError( "This version could not be found: '%s' does not exist!" % murmur_root );
init_dbase( version );
process = run_murmur( version );
try:
result = callback( process, *args, **kwargs );
if type(result) == tuple:
if result[1]:
update_dbase( version );
return result[0];
else:
return result;
finally:
kill_murmur( process );
def init_dbase( version ):
""" Initialize Murmur's database by copying the one from FILES_DIR. """
dbasefile = join( settings.TEST_MURMUR_FILES_DIR, "murmur-%s.db3" % version );
if not exists( dbasefile ):
raise EnvironmentError( "This version could not be found: '%s' does not exist!" % dbasefile );
murmurfile = join( settings.TEST_MURMUR_LAB_DIR, version, "murmur.sqlite" );
copyfile( dbasefile, murmurfile );
def update_dbase( version ):
""" Copy Murmur's database to FILES_DIR (the inverse of init_dbase). """
murmurfile = join( settings.TEST_MURMUR_LAB_DIR, version, "murmur.sqlite" );
if not exists( murmurfile ):
raise EnvironmentError( "Murmur's database could not be found: '%s' does not exist!" % murmurfile );
dbasefile = join( settings.TEST_MURMUR_FILES_DIR, "murmur-%s.db3" % version );
copyfile( murmurfile, dbasefile );
def run_murmur( version ):
""" Run the given Murmur version as a subprocess.
Either returns a Popen object or raises an EnvironmentError.
"""
murmur_root = join( settings.TEST_MURMUR_LAB_DIR, version );
if not exists( murmur_root ):
raise EnvironmentError( "This version could not be found: '%s' does not exist!" % murmur_root );
binary_candidates = ( 'murmur.64', 'murmur.x86', 'murmurd' );
for binname in binary_candidates:
if exists( join( murmur_root, binname ) ):
process = subprocess.Popen(
( join( murmur_root, binname ), '-fg' ),
stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
cwd=murmur_root
);
# Check capabilities by waiting for certain lines to show up.
capa = ObjectInfo( has_dbus=False, has_ice=False, has_instance=False, has_users=False );
def canRead( self, timeout=1 ):
rdy_read, rdy_write, rdy_other = select( [self.stdout], [], [], timeout );
return self.stdout in rdy_read;
setattr(subprocess.Popen, 'canRead', canRead)
while process.canRead(0.5):
line = process.stdout.readline();
#print "read line:", line
if line == 'DBus registration succeeded\n':
capa.has_dbus = True;
elif line == 'MurmurIce: Endpoint "tcp -h 127.0.0.1 -p 6502" running\n':
capa.has_ice = True;
elif line == '1 => Server listening on 0.0.0.0:64738\n':
capa.has_instance = True;
elif "> Authenticated\n" in line:
capa.has_users = True;
process.capabilities = capa;
return process;
raise EnvironmentError( "Murmur binary not found. (Tried %s)" % unicode(binary_candidates) );
def wait_for_user( process, timeout=1 ):
""" Wait for a user to connect. This call will consume any output from murmur
until a line indicating a user's attempt to connect has been found.
The timeout parameter specifies how long (in seconds) to wait for input.
It defaults to 1 second. If you set this to 0 it will return at the end
of input (and thereby tell you if a player has already connected). If
you set this to None, the call will block until a player has connected.
Returns True if a user has connected before the timeout has been hit,
False otherwise.
"""
while process.canRead( timeout ):
line = process.stdout.readline();
if "> Authenticated\n" in line:
process.capabilities.has_users = True;
return True;
return False;
def kill_murmur( process ):
""" Send a sigterm to the given process. """
return os.kill( process.pid, signal.SIGTERM );
class MumbleCommandWrapper_noargs( object ):
""" Mixin used to run a standard Django command inside MurmurEnvUtils.
To modify a standard Django command for MEU, you will need to create
a new command and derive its Command class from the wrapper, and the
Command class of the original command:
from django.core.management.commands.shell import Command as ShellCommand
from mumble.murmurenvutils import MumbleCommandWrapper
class Command( MumbleCommandWrapper, ShellCommand ):
pass
That will run the original command, after the user has had the chance to
select the version of Murmur to run.
"""
def _choose_version( self ):
print "Choose version:";
vv = get_available_versions();
for idx in range(len(vv)):
print " #%d %s" % ( idx, vv[idx] );
chosen = int( raw_input("#> ") );
return vv[chosen];
def handle_noargs( self, **options ):
self.origOpts = options;
run_callback( self._choose_version(), self.runOrig );
def runOrig( self, proc ):
super( MumbleCommandWrapper_noargs, self ).handle_noargs( **self.origOpts );
class MumbleCommandWrapper( object ):
""" Mixin used to run a standard Django command inside MurmurEnvUtils.
To modify a standard Django command for MEU, you will need to create
a new command and derive its Command class from the wrapper, and the
Command class of the original command:
from django.core.management.commands.shell import Command as ShellCommand
from mumble.murmurenvutils import MumbleCommandWrapper
class Command( MumbleCommandWrapper, ShellCommand ):
pass
That will run the original command, after the user has had the chance to
select the version of Murmur to run.
"""
def _choose_version( self ):
print "Choose version:";
vv = get_available_versions();
for idx in range(len(vv)):
print " #%d %s" % ( idx, vv[idx] );
chosen = int( raw_input("#> ") );
return vv[chosen];
def handle( self, *args, **options ):
self.origArgs = args;
self.origOpts = options;
run_callback( self._choose_version(), self.runOrig );
def runOrig( self, proc ):
super( MumbleCommandWrapper, self ).handle( *self.origArgs, **self.origOpts );

View File

@@ -1,28 +0,0 @@
{% comment %}
<!-- kate: space-indent on; indent-width 2; replace-tabs on; -->
{% endcomment %}
{% load mumble_extras %}
<div class="mumble" style="background-image: url( {{ MEDIA_URL }}/mumble/linie_v.png )">
<img src="{{ MEDIA_URL }}/mumble/knoten_v.png" alt="" />
{% if Channel.linked %}
<img src="{{ MEDIA_URL }}/mumble/channel_linked.png" alt="linked channel" />
{% else %}
<img src="{{ MEDIA_URL }}/mumble/channel.png" alt="channel" />
{% endif %}
{% if Channel.server.netloc %}
<a href="{{ Channel|chanurl:MumbleAccount }}" class="mumble" id="link_{{ Channel.id }}" title="{{ Channel.name }}">
{{ Channel.name|trunc:30 }}
</a>
{% else %}
<a class="mumble" id="link_{{ Channel.id }}" title="{{ Channel.name }}">
{{ Channel.name|trunc:30 }}
</a>
{% endif %}
{% for sub in Channel.subchans %}
{% if sub.show %}
{{ sub|chanview:MumbleAccount }}
{% endif %}
{% endfor %}
{% for player in Channel.players %}{{ player|chanview }}{% endfor %}
</div>

View File

@@ -1,24 +0,0 @@
{% extends "index.html" %}
{% comment %}
<!-- kate: space-indent on; indent-width 2; replace-tabs on; -->
{% endcomment %}
{% load i18n %}
{% load mumble_extras %}
{% block Headline %}
Configured Mumble Servers
{% endblock %}
{% block Content %}
<div class="rahmen">
<ul>
{% for mumble in MumbleObjects %}
{% if mumble.booted %}
<li><a href="{% url mumble.views.show mumble.id %}">{{ mumble.name }}</a></li>
{% else %}
<li>{{ mumble.name }} (offline)</li>
{% endif %}
{% empty %}
{% trans "No server instances have been configured yet." %}
{% endfor %}
</ul>
</div>
{% endblock %}

View File

@@ -1,21 +0,0 @@
{% extends "mobile_index.html" %}
{% comment %}
<!-- kate: space-indent on; indent-width 2; replace-tabs on; -->
{% endcomment %}
{% load mumble_extras %}
{% block Headline %}
Configured Mumble Servers
{% endblock %}
{% block LeftColumn %}
<div class="rahmen">
<ul>
{% for mumble in MumbleObjects %}
{% if mumble.booted %}
<li><a href="{% url mumble.views.mobile_show mumble.id %}">{{ mumble.name }}</a></li>
{% else %}
<li>{{ mumble.name }} (offline)</li>
{% endif %}
{% endfor %}
</ul>
</div>
{% endblock %}

View File

@@ -1,12 +0,0 @@
{% extends "mobile_index.html" %}
{% comment %}
<!-- kate: space-indent on; indent-width 2; replace-tabs on; -->
{% endcomment %}
{% load mumble_extras %}
{% load i18n %}
{% block Headline %}
{{ DBaseObject.name }}
{% endblock %}
{% block LeftColumn %}
{{ DBaseObject|chanview:MumbleAccount }}
{% endblock %}

View File

@@ -1,388 +0,0 @@
{% extends "index.html" %}
{% comment %}
<!-- kate: space-indent on; indent-width 2; replace-tabs on; -->
{% endcomment %}
{% load mumble_extras %}
{% load i18n %}
{% block Headline %}
{{ DBaseObject.name }}
{% endblock %}
{% block LeftColumn %}
{{ DBaseObject|chanview:MumbleAccount }}
{% endblock %}
{% block Content %}
<noscript>
<p>
{% blocktrans %}
<b>Hint:</b><br />
This area is used to display additional information for each channel and player, but requires JavaScript to be
displayed correctly. You will not see the detail pages, but you can use all links and forms
that are displayed.
{% endblocktrans %}
</p>
</noscript>
<div id="mumble_ext_container"></div>
<div id="mumble_motd" class="mumble-ext x-hide-display">
<ul>
{% if DBaseObject.connecturl %}
<li>{% trans "Server Address" %}: <a href="{{ DBaseObject.connecturl }}">{{ DBaseObject.connecturl }}</a></li>
{% endif %}
{% if DBaseObject.url %}
<li>{% trans "Website" %}: {{ DBaseObject.url|urlize }}</li>
{% endif %}
<li>{% trans "Server version" %}: {{ DBaseObject.version.0 }}.{{ DBaseObject.version.1 }}.{{ DBaseObject.version.2 }}</li>
<li><a href="{% url mumble.views.mobile_show DBaseObject.id %}">{% trans "Minimal view" %}</a></li>
</ul>
<fieldset>
<legend>{% trans "Welcome message" %}</legend>
{{ DBaseObject.motd|removetags:"script link meta html head body style"|safe }}
</fieldset>
</div>
<div id="mumble_registration" class="mumble-ext">
{% if user.is_authenticated %}
<h2>{% trans "Server registration" %}</h2>
<form action="{% url mumble.views.show DBaseObject.id %}" method="post">
{% if Registered %}
{% trans "You are registered on this server" %}.<br />
{% else %}
{% trans "You do not have an account on this server" %}.<br />
{% endif %}
<table>
{{ RegForm }}
</table>
<input type="hidden" name="mode" value="reg" />
<input type="submit" />
</form>
{% else %}
{% blocktrans %}
<p>You need to be <a href="{{ login_url }}">logged in</a> to be able to register an account on this Mumble server.</p>
{% endblocktrans %}
{% endif %}
</div>
{% if Registered %}
<div id="mumble_texture" class="mumble-ext">
<h2>{% trans "User Texture" %}</h2>
{% if DBaseObject|mmversion_eq:"1.2.2" %}
{% blocktrans %}
Sorry, due to a bug in Murmur 1.2.2, displaying and setting the Texture is disabled.
{% endblocktrans %}
{% else %}
<p>
{% blocktrans with DBaseObject.id as serverid %}
You can upload an image that you would like to use as your user texture here.
{% endblocktrans %}<br />
<br />
{% if MumbleAccount.hasTexture %}
{% trans "Your current texture is" %}:<br />
<img src="{% url mumble.views.showTexture DBaseObject.id MumbleAccount.id %}" alt="user texture" /><br />
{% else %}
{% trans "You don't currently have a texture set" %}.<br />
{% endif %}
<br />
{% if DBaseObject|mmversion_lt:"1.2.3" %}
{% blocktrans with DBaseObject.id as serverid %}
Hint: The texture image <b>needs</b> to be 600x60 in size. If you upload an image with
a different size, it will be resized accordingly.<br />
{% endblocktrans %}
{% endif %}
</p>
<form action="{% url mumble.views.show DBaseObject.id %}" method="post" enctype="multipart/form-data">
<table>
{{ TextureForm }}
</table>
<input type="hidden" name="mode" value="texture" />
<input type="submit" />
</form>
{% endif %}
</div>
{% endif %}
{% if CurrentUserIsAdmin %}
<div id="mumble_admin" class="mumble-ext">
<h2>{% trans "Server administration" %}</h2>
<form action="{% url mumble.views.show DBaseObject.id %}" method="post">
<table>
{{ AdminForm }}
</table>
<input type="hidden" name="mode" value="admin" />
<input type="submit" />
</form>
</div>
{% endif %}
{% for item in ChannelTable %}
{% if item.is_player %}
<div id="mumble_{{ item.id }}" class="mumble-ext x-hide-display">
<h2>{% trans "Player" %} {{ item.name }}</h2>
<ul>
<li>{% trans "Online since" %}: {{ item.onlinesince|time }}</li>
<li>{% trans "Authenticated" %}: {{ item.isAuthed|yesno }}</li>
<li>{% trans "Admin" %}: {{ item.isAdmin|yesno }}</li>
<li>{% trans "Muted" %}: {{ item.mute|yesno }}</li>
<li>{% trans "Deafened" %}: {{ item.deaf|yesno }}</li>
<li>{% trans "Muted by self" %}: {{ item.selfMute|yesno }}</li>
<li>{% trans "Deafened by self" %}: {{ item.selfDeaf|yesno }}</li>
{% if CurrentUserIsAdmin or user.is_staff %}
<li>{% trans "IP Address" %}: <acronym title="{{ item.ipaddress }}">{{ item.fqdn }}</acronym></li>
{% endif %}
</ul>
{% if item.mumbleuser and item.mumbleuser.owner %}
<h2>{% trans "User" %} {{ item.mumbleuser.owner.username|capfirst }}</h2>
<ul>
{% if item.mumbleuser.owner.first_name and item.mumbleuser.owner.last_name %}
<li>{% trans "Full Name" %}: {{ item.mumbleuser.owner.first_name }} {{ item.mumbleuser.owner.last_name }}</li>
{% endif %}
<li>{% trans "Admin" %}: {{ item.mumbleuser.owner.is_staff|yesno }}</li>
<li>{% trans "Sign-up date" %}: {{ item.mumbleuser.owner.date_joined|date }}</li>
</ul>
{% endif %}
{% if item.comment %}
<fieldset>
<legend>{% trans "User Comment" %}</legend>
{{ item.comment|removetags:"script link meta html head body style"|safe }}
</fieldset>
{% endif %}
{% if item.mumbleuser and item.mumbleuser.hasTexture %}
<fieldset>
<legend>{% trans "User Texture" %}</legend>
<img src="{% url mumble.views.showTexture DBaseObject.id item.mumbleuser.id %}" alt="user texture" />
</fieldset>
{% endif %}
{% if CurrentUserIsAdmin or user.is_staff %}
<fieldset>
<legend>{% trans "Kick user" %}</legend>
<form action="{% url mumble.views.show DBaseObject.id %}" method="POST">
<input type="hidden" name="mode" value="kick" />
<input type="hidden" name="session" value="{{ item.session }}" />
<ul>
<li>
<label for="inp_reason">{% trans "Reason" %}</label>
<input type="text" name="reason" value="" id="inp_reason" />
</li>
<li>
<input type="checkbox" name="ban" value="1" id="inp_ban" />
<label for="inp_ban">{% trans "Ban user" %}</label>
</li>
</ul>
<input type="submit" value="{% trans "Kick user" %}" />
</form>
</fieldset>
{% endif %}
</div>
{% else %}
<div id="mumble_{{ item.id }}" class="mumble-ext x-hide-display">
<h2>{% trans "Channel" %} {{ item.name }}</h2>
{% if CurrentUserIsAdmin or user.is_staff %}
{% trans "Channel ID" %}: {{ item.chanid }}<br />
{% endif %}
<a href="{{ item|chanurl:MumbleAccount }}" class="mumble">{% trans "Connect" %}</a>
{% if item.description %}
<fieldset>
<legend>{% trans "Channel description" %}</legend>
{{ item.description|removetags:"script link meta html head body style"|safe }}
</fieldset>
{% endif %}
</div>
{% endif %}
{% endfor %}
{% endblock %}
{% block HeadTag %}
<script type="text/javascript">
Ext.onReady( function(){
Ext.get( 'mumble_registration' ).addClass( 'x-hide-display' );
{% if Registered %}
Ext.get( 'mumble_texture' ).addClass( 'x-hide-display' );
{% endif %}
{% if CurrentUserIsAdmin %}
Ext.get( 'mumble_admin' ).addClass( 'x-hide-display' );
{% endif %}
{% if CurrentUserIsAdmin %}
userRecord = Ext.data.Record.create([
{ name: 'id', type: 'int' },
{ name: 'name', type: 'string' },
{ name: 'password', type: 'string' },
{ name: 'owner', type: 'int' },
{ name: 'admin', type: 'bool' },
{ name: 'delete', type: 'bool' }
]);
userAdminStore = new Ext.data.Store({
url: '{% url mumble.views.users DBaseObject.id %}',
reader: new Ext.data.JsonReader({
root: 'objects',
fields: userRecord
}),
autoLoad: true,
remoteSort: false
});
adminColumn = new Ext.grid.CheckColumn({
header: '{% trans "Admin on root channel" %}',
dataIndex: 'admin',
width: 50
});
deleteColumn = new Ext.grid.CheckColumn({
header: '{% trans "Delete" %}',
dataIndex: 'delete',
width: 50
});
ownerCombo = new Ext.form.ComboBox({
name: 'owner',
hiddenName: 'owner_id',
forceSelection: true,
triggerAction: 'all',
valueField: 'uid',
displayField: 'uname',
store: new Ext.data.Store({
url: '{% url mumble.views.djangousers %}',
reader: new Ext.data.JsonReader({
fields: [ 'uid', 'uname' ],
root: 'objects'
}),
autoLoad: true
})
});
{% endif %}
var cardpanel = new Ext.Panel({
renderTo: 'mumble_ext_container',
layout: 'card',
id: 'mumble_container',
height: 570,
activeItem: 0,
border: false,
items: [ {
id: 'mumble_tabpanel',
xtype: 'tabpanel',
defaults: { autoheight: true },
activeTab: {{ DisplayTab }},
items: [
{ contentEl: 'mumble_motd', title: '{% trans "Server Info" %}', autoScroll: true },
{ contentEl: 'mumble_registration', title: '{% trans "Registration" %}', autoScroll: true,
{% if user.is_authenticated %}
listeners: {
activate: function(){ Ext.fly("id_name").focus() }
}
{% endif %}
},
{% if CurrentUserIsAdmin %}
{ contentEl: 'mumble_admin', title: '{% trans "Administration" %}', autoScroll: true },
{% endif %}
{% if Registered %}
{ contentEl: 'mumble_texture',title: '{% trans "User Texture" %}', autoScroll: true },
{% endif %}
{% if CurrentUserIsAdmin %}
{
title: '{% trans "User List" %}',
xtype: 'editorgrid',
store: userAdminStore,
cm: new Ext.grid.ColumnModel( [ {
header: '{% trans "name" %}',
dataIndex: 'name',
sortable: true,
editor: new Ext.form.TextField({
allowBlank: false
})
}, {
header: '{% trans "Account owner" %}',
dataIndex: 'owner',
editor: ownerCombo,
sortable: true,
renderer: function( value ){
if( value == '' ) return '';
items = ownerCombo.store.data.items;
for( i = 0; i < items.length; i++ )
if( items[i].data.uid == value )
return items[i].data.uname;
}
}, adminColumn, {
header: '{% trans "Change password" %}',
dataIndex: 'password',
editor: new Ext.form.TextField({
inputType: 'password'
}),
renderer: function( value ){
ret = '';
for( i = 0; i < value.length; i++ )
ret += '*';
return ret;
}
}, deleteColumn ] ),
tbar: [{
text: '{% trans "Add" %}',
handler : function(){
userAdminStore.add( new userRecord( {
id: -1,
name: 'New User',
admin: false,
owner: '',
password: '',
'delete': false
} ) );
}
}, {
text: '{% trans "Save" %}',
handler : function(){
data = [];
for( i = 0; i < userAdminStore.data.items.length; i++ ){
rec = userAdminStore.data.items[i];
if( rec.dirty ){
data.push(rec.data);
}
}
var conn = new Ext.data.Connection();
conn.request( {
url: userAdminStore.url,
params: { data: Ext.encode( data ) },
success: function(){
for( i = 0; i < userAdminStore.data.items.length; i++ ){
rec = userAdminStore.data.items[i];
if( rec.data['delete'] == true )
userAdminStore.remove( rec );
else if( rec.dirty ){
rec.commit();
}
}
}
} );
}
}, {
text: '{% trans "Resync with Murmur" %}',
handler: function(){
userAdminStore.reload({
params: { 'resync': 'true' }
});
}
}],
plugins: [ adminColumn, deleteColumn ]
}
{% endif %}
]
},
{% for item in ChannelTable %}
{ contentEl: 'mumble_{{ item.id }}', id: 'carditem_{{ item.id }}' }{% if not forloop.last %},{% endif %}
{% endfor %}
]
});
Ext.get( 'link_server' ).on( 'click', function( event, target ){
cardpanel.layout.setActiveItem( 'mumble_tabpanel' );
event.preventDefault();
});
{% for item in ChannelTable %}
Ext.get( 'link_{{ item.id }}' ).on( 'click', function( event, target ){
cardpanel.layout.setActiveItem( 'carditem_{{ item.id }}' );
event.preventDefault();
});
{% endfor %}
} );
</script>
<meta http-equiv="refresh" content="300" />
{% endblock %}

View File

@@ -1,14 +0,0 @@
{% extends "index.html" %}
{% comment %}
<!-- kate: space-indent on; indent-width 2; replace-tabs on; -->
{% endcomment %}
{% load i18n %}
{% load mumble_extras %}
{% block Headline %}
{{ DBaseObject.name }}
{% endblock %}
{% block Content %}
<div class="rahmen">
{% trans "This server is currently offline." %}
</div>
{% endblock %}

View File

@@ -1,35 +0,0 @@
{% comment %}
<!-- kate: space-indent on; indent-width 2; replace-tabs on; -->
{% endcomment %}
{% load mumble_extras %}
{% load i18n %}
<div class="mumble" style="background-image: url( {{ MEDIA_URL }}/mumble/linie_v.png )">
<span class="mumble">
{% if Player.isAuthed %}
<img src="{{ MEDIA_URL }}/mumble/authenticated.png" alt="authed" title="{% trans "Authenticated" %}" />
{% endif %}
{% if Player.mute %}
<img src="{{ MEDIA_URL }}/mumble/muted_server.png" alt="muted" title="{% trans "Muted" %}" />
{% endif %}
{% if Player.suppress %}
<img src="{{ MEDIA_URL }}/mumble/muted_suppressed.png" alt="muted" title="{% trans "Suppressed" %}" />
{% endif %}
{% if Player.deaf %}
<img src="{{ MEDIA_URL }}/mumble/deafened_server.png" alt="deafened" title="{% trans "Deafened" %}" />
{% endif %}
{% if Player.selfMute %}
<img src="{{ MEDIA_URL }}/mumble/muted_self.png" alt="self-muted" title="{% trans "Muted by self" %}" />
{% endif %}
{% if Player.selfDeaf %}
<img src="{{ MEDIA_URL }}/mumble/deafened_self.png" alt="self-deafened" title="{% trans "Deafened by self" %}" />
{% endif %}
{% if Player.hasComment %}
<img src="{{ MEDIA_URL }}/mumble/comment.png" alt="has comment" title="{% trans "has a User Comment set" %}" />
{% endif %}
</span>
<span>
<img src="{{ MEDIA_URL }}/mumble/knoten_v.png" alt="" />
<img src="{{ MEDIA_URL }}/mumble/talking_off.png" alt="Player" />
<a id="link_{{ Player.id }}" class="mumble" href="#" title="{{ Player.name }}">{{ Player.name|trunc:30 }}</a>
</span>
</div>

View File

@@ -1,14 +0,0 @@
{% comment %}
<!-- kate: space-indent on; indent-width 2; replace-tabs on; -->
{% endcomment %}
{% load mumble_extras %}
<div style="margin-left: 20px;">
<img src="{{ MEDIA_URL }}/mumble/mumble.16x16.png" alt="server" />
<a class="mumble" id="link_server" href="{{ Server|chanurl:MumbleAccount }}">{{ Server.name|trunc:30 }}</a>
</div>
{% for sub in Server.rootchan.subchans %}
{% if sub.show %}
{{ sub|chanview:MumbleAccount }}
{% endif %}
{% endfor %}
{% for player in Server.rootchan.players %}{{ player|chanview }}{% endfor %}

View File

@@ -1,14 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""

View File

@@ -1,62 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
from django import template
from django.template.loader import render_to_string
from django.conf import settings
register = template.Library();
@register.filter
def trunc( string, maxlen = 50 ):
""" converts "a very very extaordinary long text" to "a very very extra... """
if len(string) < maxlen:
return string;
return string[:(maxlen - 3)] + "";
@register.filter
def chanview( obj, user = None ):
""" renders an mmChannel / mmPlayer object with the correct template """
if obj.is_server:
return render_to_string( 'mumble/server.html', { 'Server': obj, 'MumbleAccount': user, 'MEDIA_URL': settings.MEDIA_URL } );
elif obj.is_channel:
return render_to_string( 'mumble/channel.html', { 'Channel': obj, 'MumbleAccount': user, 'MEDIA_URL': settings.MEDIA_URL } );
elif obj.is_player:
return render_to_string( 'mumble/player.html', { 'Player': obj, 'MumbleAccount': user, 'MEDIA_URL': settings.MEDIA_URL } );
@register.filter
def chanurl( obj, user ):
""" create a connection URL and takes the user's login into account """
return obj.getURL( user );
@register.filter
def mmversion_lt( obj, version ):
""" return True if the given Server's version is less than the given version. """
return tuple(obj.version[:3]) < tuple([int(v) for v in version.split('.')])
@register.filter
def mmversion_eq( obj, version ):
""" return True if the given Server's version equals the given version. """
return tuple(obj.version[:3]) == tuple([int(v) for v in version.split('.')])
@register.filter
def mmversion_gt( obj, version ):
""" return True if the given Server's version is greater than the given version. """
return tuple(obj.version[:3]) > tuple([int(v) for v in version.split('.')])

View File

@@ -1,99 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
import os
from django.test.simple import run_tests as django_run_tests
from django.conf import settings
from murmurenvutils import get_available_versions, run_callback, wait_for_user
def run_tests( test_labels, verbosity=1, interactive=True, extra_tests=[] ):
""" Run the Django built in testing framework, but before testing the mumble
app, allow Murmur to be set up correctly.
"""
if not test_labels:
test_labels = [ appname.split('.')[-1] for appname in settings.INSTALLED_APPS ];
# No need to sync any murmur servers for the other apps
os.environ['MURMUR_CONNSTR'] = '';
# The easy way: mumble is not being tested.
if "mumble" not in test_labels:
return django_run_tests( test_labels, verbosity, interactive, extra_tests );
# First run everything apart from mumble. mumble will be tested separately, so Murmur
# can be set up properly first.
failed_tests = 0;
if len(test_labels) > 1:
# only run others if mumble is not the only app to be tested
test_labels = list(test_labels);
test_labels.remove( "mumble" );
failed_tests += django_run_tests( test_labels, verbosity, interactive, extra_tests );
failed_tests += run_mumble_tests( verbosity, interactive );
return failed_tests;
def run_mumble_tests( verbosity=1, interactive=True ):
connstrings = {
'DBus': 'net.sourceforge.mumble.murmur',
'Ice': 'Meta:tcp -h 127.0.0.1 -p 6502',
};
def django_run_tests_wrapper( process, version ):
wr_failed_tests = 0;
for method in connstrings:
# Check if this server is ready to be used with the current method
if getattr( process.capabilities, ("has_%s" % method.lower()), False ):
print "Testing mumble %s via %s" % ( version, method );
os.environ['MURMUR_CONNSTR'] = connstrings[method];
settings.DEFAULT_CONN = connstrings[method];
settings.SLICE_VERSION = [ int(dgt) for dgt in version.split('.') ];
print "MURMUR_CONNSTR:", os.environ['MURMUR_CONNSTR'];
print "DEFAULT_CONN: ", settings.DEFAULT_CONN;
print "SLICE_VERSION: ", settings.SLICE_VERSION;
if not process.capabilities.has_users:
print "Waiting for user to connect (60 seconds)."
wait_for_user( process, timeout=60 );
wr_failed_tests += django_run_tests( ('mumble',), verbosity, interactive, [] );
else:
print "Mumble %s does not support Method %s" % ( version, method );
return wr_failed_tests;
failed_tests = 0;
from mctl import MumbleCtlBase
for version in get_available_versions():
MumbleCtlBase.clearCache();
run = raw_input( "Run tests for %s? [Y/n] " % version );
if run in ('Y', 'y', ''):
failed_tests += run_callback( version, django_run_tests_wrapper, version );
return failed_tests;

View File

@@ -1,208 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
from django.conf import settings
from django.test import TestCase
from models import Mumble
from utils import ObjectInfo
class InstancesHandling( TestCase ):
""" Tests creation, editing and removing of vserver instances. """
def setUp( self ):
# Make sure we always start with a FRESH murmur instance, checking for left-over instances
# and deleting them before creating ours.
try:
self.murmur = Mumble.objects.get( addr="0.0.0.0", port=31337 );
except Mumble.DoesNotExist:
pass
else:
self.murmur.delete();
finally:
self.murmur = Mumble( name="#unit testing instance#", addr="0.0.0.0", port=31337 );
self.murmur.save();
def testDefaultConf( self ):
conf = self.murmur.ctl.getAllConf( self.murmur.srvid );
self.assert_( type(conf) == dict );
self.assert_( "host" in conf );
self.assert_( "port" in conf );
self.assert_( "certificate" in conf );
self.assert_( "key" in conf );
self.assert_( "registerhostname" in conf );
self.assert_( "registername" in conf );
self.assert_( "channelname" in conf );
self.assert_( "username" in conf );
self.assert_( "obfuscate" in conf );
self.assert_( "defaultchannel" in conf );
def testAddrPortUnique( self ):
try:
duplicate = Mumble(
name="#another unit testing instance#",
addr=self.murmur.addr, port=self.murmur.port,
dbus=settings.DEFAULT_CONN
);
if duplicate.ctl.method == "ICE":
import Murmur
self.assertRaises( Murmur.ServerFailureException, duplicate.save );
elif self.murmur.version[:2] == [ 1, 2 ]:
from dbus import DBusException
self.assertRaises( DBusException, duplicate.save );
else:
from sqlite3 import IntegrityError
self.assertRaises( IntegrityError, duplicate.save );
finally:
# make sure the duplicate is removed
duplicate.ctl.deleteServer( duplicate.srvid );
def tearDown( self ):
self.murmur.delete();
class DataReading( TestCase ):
""" Tests reading data from murmur using the low-level CTL methods. """
def setUp( self ):
# BIG FAT WARNING: This sucks ass, because it assumes the tester has a
# Murmur database like the one I have.
# I definitely need to prepare Murmur somehow before running these tests.
# Just don't yet know how.
self.murmur = Mumble.objects.get(id=1);
def testCtlGetChannels( self ):
""" Test getChannels() """
channels = self.murmur.ctl.getChannels( self.murmur.srvid );
if self.murmur.ctl.method == "ICE":
import Murmur
self.assertEquals( type( channels[0] ), Murmur.Channel );
else:
self.assertEquals( type( channels[0] ), ObjectInfo );
self.assert_( hasattr( channels[0], "id" ) );
self.assert_( hasattr( channels[0], "name" ) );
self.assert_( hasattr( channels[0], "parent" ) );
self.assert_( hasattr( channels[0], "links" ) );
def testCtlGetPlayers( self ):
""" Test getPlayers() """
players = self.murmur.ctl.getPlayers( self.murmur.srvid );
self.assert_( len(players) > 0 );
self.assertEquals( type(players), dict );
for plidx in players:
player = players[plidx];
if self.murmur.ctl.method == "ICE" and self.murmur.version[:2] == ( 1, 2 ):
import Murmur
self.assertEquals( type( player ), Murmur.User );
else:
self.assertEquals( type( player ), ObjectInfo );
self.assert_( hasattr( player, "session" ) );
self.assert_( hasattr( player, "mute" ) );
self.assert_( hasattr( player, "deaf" ) );
self.assert_( hasattr( player, "selfMute" ) );
self.assert_( hasattr( player, "selfDeaf" ) );
self.assert_( hasattr( player, "channel" ) );
self.assert_( hasattr( player, "userid" ) );
self.assert_( hasattr( player, "name" ) );
self.assert_( hasattr( player, "onlinesecs" ) );
self.assert_( hasattr( player, "bytespersec" ) );
def testCtlGetRegisteredPlayers( self ):
""" Test getRegistredPlayers() and getRegistration() """
players = self.murmur.ctl.getRegisteredPlayers( self.murmur.srvid );
self.assert_( len(players) > 0 );
self.assertEquals( type(players), dict );
for plidx in players:
player = players[plidx];
self.assertEquals( type( player ), ObjectInfo );
self.assert_( hasattr( player, "userid" ) );
self.assert_( hasattr( player, "name" ) );
self.assert_( hasattr( player, "email" ) );
self.assert_( hasattr( player, "pw" ) );
# compare with getRegistration result
reg = self.murmur.ctl.getRegistration( self.murmur.srvid, player.userid );
self.assertEquals( type( reg ), ObjectInfo );
self.assert_( hasattr( reg, "userid" ) );
self.assert_( hasattr( reg, "name" ) );
self.assert_( hasattr( reg, "email" ) );
self.assert_( hasattr( reg, "pw" ) );
self.assertEquals( player.userid, reg.userid );
self.assertEquals( player.name, reg.name );
self.assertEquals( player.email, reg.email );
self.assertEquals( player.pw, reg.pw );
def testCtlGetAcl( self ):
""" Test getACL() for the root channel """
acls, groups, inherit = self.murmur.ctl.getACL( self.murmur.srvid, 0 );
for rule in acls:
if self.murmur.ctl.method == "ICE" and self.murmur.version[:2] == ( 1, 2 ):
import Murmur
self.assertEquals( type( rule ), Murmur.ACL );
else:
self.assertEquals( type( rule ), ObjectInfo );
self.assert_( hasattr( rule, "applyHere" ) );
self.assert_( hasattr( rule, "applySubs" ) );
self.assert_( hasattr( rule, "inherited" ) );
self.assert_( hasattr( rule, "userid" ) );
self.assert_( hasattr( rule, "group" ) );
self.assert_( hasattr( rule, "allow" ) );
self.assert_( hasattr( rule, "deny" ) );
for grp in groups:
if self.murmur.ctl.method == "ICE":
import Murmur
self.assertEquals( type( grp ), Murmur.Group );
else:
self.assertEquals( type( grp ), ObjectInfo );
self.assert_( hasattr( grp, "name" ) );
self.assert_( hasattr( grp, "inherited" ) );
self.assert_( hasattr( grp, "inherit" ) );
self.assert_( hasattr( grp, "inheritable" ) );
self.assert_( hasattr( grp, "add" ) );
self.assert_( hasattr( grp, "remove" ) );
self.assert_( hasattr( grp, "members" ) );

View File

@@ -1,35 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
from django.conf.urls.defaults import patterns
urlpatterns = patterns(
'mumble.views',
( r'djangousers', 'djangousers' ),
( r'(?P<server>\d+)/users', 'users' ),
( r'(?P<server>\d+)/(?P<userid>\d+)/texture.png', 'showTexture' ),
( r'murmur/tree/(?P<server>\d+)', 'mmng_tree' ),
( r'mumbleviewer/(?P<server>\d+).xml', 'mumbleviewer_tree_xml' ),
( r'mumbleviewer/(?P<server>\d+).json', 'mumbleviewer_tree_json'),
( r'mobile/(?P<server>\d+)', 'mobile_show' ),
( r'mobile/?$', 'mobile_mumbles' ),
( r'(?P<server>\d+)', 'show' ),
( r'$', 'mumbles' ),
)

View File

@@ -1,30 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
class ObjectInfo( object ):
""" Wraps arbitrary information to be easily accessed. """
def __init__( self, **kwargs ):
self.__dict__ = kwargs;
def __str__( self ):
return unicode( self );
def __repr__( self ):
return unicode( self );
def __unicode__( self ):
return unicode( self.__dict__ );

View File

@@ -1,408 +0,0 @@
# -*- coding: utf-8 -*-
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
* Mumble-Django is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This package 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.
"""
import simplejson
from StringIO import StringIO
from PIL import Image
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404
from django.template import RequestContext
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.conf import settings
from django.core.urlresolvers import reverse
from django.contrib.auth import views as auth_views
from models import Mumble, MumbleUser
from forms import MumbleForm, MumbleUserForm, MumbleUserPasswordForm
from forms import MumbleUserLinkForm, MumbleTextureForm, MumbleKickForm
def redir( request ):
""" Redirect to the servers list. """
if request.META['HTTP_USER_AGENT'].startswith( 'BlackBerry' ) or \
"Opera Mobi" in request.META['HTTP_USER_AGENT'] or \
"Opera Mini" in request.META['HTTP_USER_AGENT'] or \
"Windows CE" in request.META['HTTP_USER_AGENT'] or \
"MIDP" in request.META['HTTP_USER_AGENT'] or \
"Palm" in request.META['HTTP_USER_AGENT'] or \
"NetFront" in request.META['HTTP_USER_AGENT'] or \
"Nokia" in request.META['HTTP_USER_AGENT'] or \
"Symbian" in request.META['HTTP_USER_AGENT'] or \
"UP.Browser" in request.META['HTTP_USER_AGENT'] or \
"UP.Link" in request.META['HTTP_USER_AGENT'] or \
"WinWAP" in request.META['HTTP_USER_AGENT'] or \
"Android" in request.META['HTTP_USER_AGENT'] or \
"DoCoMo" in request.META['HTTP_USER_AGENT'] or \
"KDDI-" in request.META['HTTP_USER_AGENT'] or \
"Softbank" in request.META['HTTP_USER_AGENT'] or \
"J-Phone" in request.META['HTTP_USER_AGENT'] or \
"IEMobile" in request.META['HTTP_USER_AGENT'] or \
"iPod" in request.META['HTTP_USER_AGENT'] or \
"iPhone" in request.META['HTTP_USER_AGENT']:
return HttpResponseRedirect( reverse( mobile_mumbles ) );
else:
return HttpResponseRedirect( reverse( mumbles ) );
def mobile_mumbles( request ):
return mumbles( request, mobile=True );
def mumbles( request, mobile=False ):
""" Display a list of all configured Mumble servers, or redirect if only one configured. """
mms = Mumble.objects.all().order_by( "name" );
if len(mms) == 1:
return HttpResponseRedirect( reverse(
{ False: show, True: mobile_show }[mobile],
kwargs={ 'server': mms[0].id, }
) );
return render_to_response(
'mumble/%s.html' % { False: 'list', True: 'mobile_list' }[mobile],
{ 'MumbleObjects': mms,
'MumbleActive': True,
},
context_instance = RequestContext(request)
);
def show( request, server ):
""" Display the channel list for the given Server ID.
This includes not only the channel list itself, but indeed the user registration,
server admin and user texture form as well. The template then uses JavaScript
to display these forms integrated into the Channel viewer.
"""
srv = get_object_or_404( Mumble, id=server );
if not srv.booted:
return render_to_response(
'mumble/offline.html',
{ 'DBaseObject': srv,
'MumbleActive': True,
}, context_instance = RequestContext(request) );
isAdmin = srv.isUserAdmin( request.user );
# The tab to start on.
displayTab = 0;
if isAdmin:
if request.method == 'POST' and "mode" in request.POST and request.POST['mode'] == 'admin':
adminform = MumbleForm( request.POST, instance=srv );
if adminform.is_valid():
adminform.save();
return HttpResponseRedirect( reverse( show, kwargs={ 'server': int(server), } ) );
else:
displayTab = 2;
else:
adminform = MumbleForm( instance=srv );
else:
adminform = None;
registered = False;
user = None;
if request.user.is_authenticated():
# Unregistered users may or may not need a password to register.
if settings.PROTECTED_MODE and srv.passwd:
unregged_user_form = MumbleUserPasswordForm;
# Unregistered users may or may not want to link an existing account
elif settings.ALLOW_ACCOUNT_LINKING:
unregged_user_form = MumbleUserLinkForm;
else:
unregged_user_form = MumbleUserForm;
if request.method == 'POST' and 'mode' in request.POST and request.POST['mode'] == 'reg':
try:
user = MumbleUser.objects.get( server=srv, owner=request.user );
except MumbleUser.DoesNotExist:
regform = unregged_user_form( request.POST );
regform.server = srv;
if regform.is_valid():
model = regform.save( commit=False );
model.owner = request.user;
model.server = srv;
# If we're linking accounts, the change is local only.
model.save( dontConfigureMurmur=( "linkacc" in regform.data ) );
return HttpResponseRedirect( reverse( show, kwargs={ 'server': int(server), } ) );
else:
displayTab = 1;
else:
regform = MumbleUserForm( request.POST, instance=user );
regform.server = srv;
if regform.is_valid():
regform.save();
return HttpResponseRedirect( reverse( show, kwargs={ 'server': int(server), } ) );
else:
displayTab = 1;
else:
try:
user = MumbleUser.objects.get( server=srv, owner=request.user );
except MumbleUser.DoesNotExist:
regform = unregged_user_form();
else:
regform = MumbleUserForm( instance=user );
registered = True;
if request.method == 'POST' and 'mode' in request.POST and request.POST['mode'] == 'texture' and registered:
textureform = MumbleTextureForm( request.POST, request.FILES );
if textureform.is_valid():
user.setTexture( Image.open( request.FILES['texturefile'] ) );
return HttpResponseRedirect( reverse( show, kwargs={ 'server': int(server), } ) );
else:
textureform = MumbleTextureForm();
else:
regform = None;
textureform = None;
if isAdmin:
if request.method == 'POST' and 'mode' in request.POST and request.POST['mode'] == 'kick':
kickform = MumbleKickForm( request.POST );
if kickform.is_valid():
if kickform.cleaned_data["ban"]:
srv.banUser( kickform.cleaned_data['session'], kickform.cleaned_data['reason'] );
srv.kickUser( kickform.cleaned_data['session'], kickform.cleaned_data['reason'] );
# ChannelTable is a somewhat misleading name, as it actually contains channels and players.
channelTable = [];
for cid in srv.channels:
if cid != 0 and srv.channels[cid].show:
channelTable.append( srv.channels[cid] );
for pid in srv.players:
channelTable.append( srv.players[pid] );
show_url = reverse( show, kwargs={ 'server': srv.id } );
login_url = reverse( auth_views.login );
return render_to_response(
'mumble/mumble.html',
{
'login_url': "%s?next=%s" % ( login_url, show_url ),
'DBaseObject': srv,
'ChannelTable': channelTable,
'CurrentUserIsAdmin': isAdmin,
'AdminForm': adminform,
'RegForm': regform,
'TextureForm': textureform,
'Registered': registered,
'DisplayTab': displayTab,
'MumbleActive': True,
'MumbleAccount':user,
},
context_instance = RequestContext(request)
);
def mobile_show( request, server ):
""" Display the channel list for the given Server ID. """
srv = get_object_or_404( Mumble, id=server );
user = None;
if request.user.is_authenticated():
try:
user = MumbleUser.objects.get( server=srv, owner=request.user );
except MumbleUser.DoesNotExist:
pass;
return render_to_response(
'mumble/mobile_mumble.html',
{
'DBaseObject': srv,
'MumbleActive': True,
'MumbleAccount':user,
},
context_instance = RequestContext(request)
);
def showTexture( request, server, userid ):
""" Pack the given user's texture into an HttpResponse.
If userid is none, use the currently logged in User.
"""
srv = get_object_or_404( Mumble, id=int(server) );
user = get_object_or_404( MumbleUser, server=srv, id=int(userid) );
try:
img = user.getTexture();
except ValueError:
raise Http404();
else:
buf = StringIO();
img.save( buf, "PNG" );
return HttpResponse( buf.getvalue(), "image/png" );
@login_required
def users( request, server ):
""" Create a list of MumbleUsers for a given server serialized as a JSON object.
If the request has a "data" field, evaluate that and update the user records.
"""
srv = get_object_or_404( Mumble, id=int(server) );
if "resync" in request.POST and request.POST['resync'] == "true":
srv.readUsersFromMurmur();
if not srv.isUserAdmin( request.user ):
return HttpResponse(
simplejson.dumps({ 'success': False, 'objects': [], 'errormsg': 'Access denied' }),
mimetype='text/javascript'
);
if request.method == 'POST':
data = simplejson.loads( request.POST['data'] );
for record in data:
if record['id'] == -1:
if record['delete']:
continue;
mu = MumbleUser( server=srv );
else:
mu = MumbleUser.objects.get( id=record['id'] );
if record['delete']:
mu.delete();
continue;
mu.name = record['name'];
mu.password = record['password'];
if record['owner']:
mu.owner = User.objects.get( id=int(record['owner']) );
mu.save();
mu.aclAdmin = record['admin'];
users = [];
for mu in srv.mumbleuser_set.all():
owner = None;
if mu.owner is not None:
owner = mu.owner.id
users.append( {
'id': mu.id,
'name': mu.name,
'password': None,
'owner': owner,
'admin': mu.aclAdmin,
} );
return HttpResponse(
simplejson.dumps( { 'success': True, 'objects': users } ),
mimetype='text/javascript'
);
@login_required
def djangousers( request ):
""" Return a list of all Django users' names and IDs. """
users = [ { 'uid': '', 'uname': '------' } ];
for du in User.objects.all().order_by( 'username' ):
users.append( {
'uid': du.id,
'uname': unicode( du ),
} );
return HttpResponse(
simplejson.dumps( { 'success': True, 'objects': users } ),
mimetype='text/javascript'
);
def mmng_tree( request, server ):
""" Return a JSON representation of the channel tree suitable for
Murmur Manager:
http://github.com/cheald/murmur-manager/tree/master/widget/
To make the client widget query this view, set the URL attribute
to "http://<mumble-django base URL>/mumble"
"""
srv = get_object_or_404( Mumble, id=int(server) );
chanlist = []
userlist = []
for chanid in srv.channels:
channel = srv.channels[chanid]
if channel.parent is not None:
parent = channel.parent.chanid
else:
parent = -1
chanlist.append({
"type": "channel",
"id": channel.chanid,
"name": channel.name,
"parent": parent,
"position": channel.position,
"state": channel.temporary and "temporary" or "permanent"
})
for sessionid in srv.players:
user = srv.players[sessionid]
userlist.append({
"type": "player",
"name": user.name,
"channel": user.channel.chanid,
"mute": user.mute or user.selfMute or user.suppress,
"deaf": user.deaf or user.selfDeaf,
"online": user.onlinesecs,
"state": "online"
})
if "callback" in request.GET:
prefix = request.GET["callback"]
else:
prefix = ""
return HttpResponse(
prefix + "(" + simplejson.dumps( { 'channels': chanlist, 'users': userlist } ) + ")",
mimetype='text/javascript'
);
def mumbleviewer_tree_xml( request, server ):
""" Get the XML tree from the server and serialize it to the client. """
from xml.etree.cElementTree import tostring as xml_to_string
srv = get_object_or_404( Mumble, id=int(server) );
return HttpResponse(
xml_to_string( srv.asMvXml(), encoding='utf-8' ),
mimetype='text/xml'
);
def mumbleviewer_tree_json( request, server ):
""" Get the Dict from the server and serialize it as JSON to the client. """
srv = get_object_or_404( Mumble, id=int(server) );
if "jsonp_callback" in request.GET:
prefix = request.GET["jsonp_callback"]
else:
prefix = ""
return HttpResponse(
prefix + "(" + simplejson.dumps( srv.asMvJson() ) + ")",
mimetype='text/javascript'
);

View File

@@ -79,7 +79,6 @@ INSTALLED_APPS = (
'registration',
'eve_proxy',
'eve_api',
'mumble',
'reddit',
'hr',
'sso',
@@ -115,12 +114,6 @@ REDDIT_USER = 'DredditVerification'
# Password for validatio account
REDDIT_PASSWD = ''
### Mumble Service Settings
DEFAULT_CONN = 'Meta:tcp -h 127.0.0.1 -p 6502'
MUMBLE_DEFAULT_PORT = 64740
SLICE = 'Murmur.ice'
### HR Settings
HR_STAFF_GROUP = 'HR Staff'

View File

@@ -1,16 +1,22 @@
from mumble.models import Mumble, MumbleUser
from sso.services import BaseService
from MumbleCtlIce import MumbleCtlIce
class MumbleService(BaseService):
settings = { 'require_user': True,
'require_password': True,
'provide_login': False,
'mumble_server_id': 1,
'name_format': r'%(alliance)s-%(corporation)s-%(name)s' }
'mumble_server_id': 2,
'name_format': r'%(alliance)s - %(corporation)s - %(name)s'
'connection_string': 'Meta:tcp -h 127.0.0.1 -p 6502'
'ice_file': 'Murmur.ice' }
def _get_server(self):
return Mumble.objects.get(id=self.settings['mumble_server_id'])
@property
def mumblectl(self):
if not hasattr(self, '_mumblectl'):
self._mumblectl = MumbleCtlIce(self.settings['connection_string'], self.settings['ice_file'])
return self._mumblectl
def add_user(self, username, password, **kwargs):
""" Add a user, returns a UID for that user """
@@ -21,36 +27,28 @@ class MumbleService(BaseService):
username = self.settings['name_format'] % details
return self.raw_add_user(username, password)
return self.raw_add_user(username, kwargs['user'].email, password)
def raw_add_user(self, username, password):
mumbleuser = MumbleUser()
mumbleuser.name = username
mumbleuser.password = password
mumbleuser.server = self._get_server()
def raw_add_user(self, username, email, password):
if self.mumblectl.registerPlayer(self.settings['mumble_server_id'], username, email, password):
return username
mumbleuser.save()
return mumbleuser.name
return False
def check_user(self, username):
""" Check if the username exists """
try:
mumbleuser = MumbleUser.objects.get(name=username, server=self._get_server())
except MumbleUser.DoesNotExist:
return False
else:
if len(self.mumblectl.getRegisteredPlayers(self.settings['mumble_server_id'], username)):
return True
else:
return False
def delete_user(self, uid):
""" Delete a user by uid """
try:
mumbleuser = MumbleUser.objects.get(name=uid, server=self._get_server())
except MumbleUser.DoesNotExist:
return True
try:
mumbleuser.delete()
except:
pass
ids = self.mumblectl.getRegisteredPlayers(self.settings['mumble_server_id'], uid)
if len(ids) > 0:
for acc in ids:
self.mumblectl.unregisterPlayer(self.settings['mumble_server_id'], acc['userid'])
return True
def disable_user(self, uid):
@@ -60,13 +58,13 @@ class MumbleService(BaseService):
def enable_user(self, uid, password):
""" Enable a user by uid """
if self.check_user(uid):
mumbleuser = MumbleUser.objects.get(name=uid, server=self._get_server())
mumbleuser.password = password
mumbleuser.save()
ids = self.mumblectl.getRegisteredPlayers(self.settings['mumble_server_id'], uid)
if len(ids) > 0:
for acc in ids:
self.mumblectl.setRegistration(self.settings['mumble_server_id'], acc['userid'], acc['name'], acc['email'], password)
return True
else:
self.raw_add_user(uid, password)
return True
return False
def reset_password(self, uid, password):
""" Reset the user's password """