In the last years I have been using Mumble-Django (MD) to configure my Mumble servers and in my opinion it is one of the best admin interfaces available.

But on a box with very little RAM I wanted something very simple so I started using „mice“ on my new server.

Mice is a wrapper for the Ice connection to your Mumble server (also known as Murmur). Documentation about Ice and Mumble can be found here.

I use mice with ipython which gives you for example the ability for tab completion.

BTW: I am a noob when it comes to Python so please leave a comment if the code I used in this blog post can be simplified :)

What you need to know when using mice (and Ice in general)

Read the documentation :)

You can either use the tab completion of ipython to get a list of methods (see below) or read the documentation from Murmur, see Murmur.ice itself or its generated documentation.

Instant changes

It is very nice that all you change through Ice is instantly applied to your server. There is no need for a restart unlike editing the .ini file of your server (mostly murmur.ini or mumble-server.ini).

„Global settings“ vs „local settings“

But you can only change so called „local settings“, not „global settings“. The latter can be changed only in the .ini file and you need to reboot your server. Keep that in mind when you work with mice.

A (German) list of global and local settings can be found here (global) and here (local).

The list of all variables in the official Mumble wiki does not yet distinguish between local and global variables, see here.

A global setting is for example which backend for SQL Murmur should use, you can choose between MySQL and Sqlite (default).

A local setting is for example the name of your Mumble server (it is called „registername“).

Always lowercase

If you change settings via „setConf“ you must always use the lowercase name of what you change.

For example use

setConf("registername", "Name of your Mumble-Server")

instead of

setConf("registerName", "Name of your Mumble-Server")

Murmur won’t recognize mixed case written settings set through Ice.

Note: The case isn’t important in your murmur.ini file.

Always use strings for setConf

The method setConf requires alway strings as values, see here.

For example the next will not work:

s1.setConf("users", 127)

But this works:

s1.setConf("users", "127")

Before you start

Download mice.py onto your server and edit it.

Change the default settings like host, port and most important the „secret“ which is the equivalent of „icesecret“ or „icesecretwrite“ in your „murmur.ini“ or „mumble-server.ini“.

Encoding version

If you get an error like

UnknownLocalException: exception ::Ice::UnknownLocalException
{
unknown = ../../include/Ice/BasicStream.h:175: Ice::UnsupportedEncodingException:
protocol error: unsupported encoding version: 1.1
(can only support encodings compatible with version 1.1)

change the prxstr value in line 52 from

prxstr = "Meta:tcp -h %s -p %d -t 1000" % (host, port)

to

prxstr = "Meta -e 1.0:tcp -h %s -p %d -t 1000" % (host, port)

in order to force protocol encoding in version 1.0.

Lets start with mice

Change into the directory where your mice.py script is located. Then start ipython:

mymumbleserver # ls .
mice.py
mymumbleserver # ipython
Python 2.7.9 (default, Mar 1 2015, 18:22:53)
Type "copyright", "credits" or "license" for more information.

IPython 2.3.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.

In [1]:

Import mice:

import mice
Using default settings.
Import ice... Done
Trying to retrieve slice dynamically from server... Success
Import dynamically compiled murmur class... Done
Establish ice connection... [protected]... Done
Murmur object accessible via 'mice.murmur' or 'mice.m'
3 booted servers in 'mice.sl', 'mice.s' contains 's/1 -t -e 1.0:tcp -h 127.0.0.1 -p 6502'
--- Reached interactive mode ---

Now you are ready to start…

Some examples for working with mice

Get list of all servers

There are three Mumble servers available, lets get a list of them:

mice.m.getAllServers()
[s/1 -t -e 1.0:tcp -h 127.0.0.1 -p 6502,
s/3 -t -e 1.0:tcp -h 127.0.0.1 -p 6502,
s/5 -t -e 1.0:tcp -h 127.0.0.1 -p 6502]

Create an object for the server you want to work with

I want to work with the first one, so I get it into a new object:

s1 = mice.m.getServer(1)

List all methods for your server

s1.<PRESS TAB>
s1.
Display all 215 possibilities? (y or n)
s1.addCallback                   s1.end_getChannelState           s1.ice_datagram
s1.addChannel                    s1.end_getChannels               s1.ice_encodingVersion
s1.addContextCallback            s1.end_getConf                   s1.ice_endpointSelection
s1.addUserToGroup                s1.end_getLog                    s1.ice_endpoints
s1.begin_addCallback             s1.end_getLogLen                 s1.ice_facet
s1.begin_addChannel              s1.end_getRegisteredUsers        s1.ice_flushBatchRequests
[..]

The most interesting methods start with „get“ and „set“.

Check whether the server is running

s1.isRunning()
Out[6]: True
s1.getAllConf()
Out[7]:
{'': '',
'allowhtml': 'true',
'allowping': 'true',
'autobanattempts': '10',
'bandwidth': '128000',
'bonjour': 'false',
'boot': 'true',
[...]
s1.getConf("registername")
Out[8]: 'Natemologie-Zentrum (Opus)'

Change settings

s1.setConf("users", "150")

Restart the server

s1.stop()
s1.start()

Change the welcome message

s1.setConf("welcometext", "Welcome to my server")

Lets send a message to a specific channel on your server

In the Ice documentation we can read that the sendMessageChannel needs the following arguments:

s1.sendMessageChannel(int channelid, bool tree, string text)

If the „tree“ parameter is True the message is sent to all subchannels of the channel you send a message to.

So we can use for example:

s1.sendMessageChannel(123, False, "Test message to channel with id 123")

On the Mumble server we get:

[07:02:47] (Channel) Server: Test message to channel with id 530

Now a so called tree message to all channels on the server

Now we write a so called tree message (see above):

s1.sendMessageChannel(0, True, "This is a test message to all channels on your server")

0 is the id of the root channel of a server.

Every user on your server gets:

[07:04:04] (Tree) Server: This is a test message to all channels on your server

You can also use HTML and CSS to style your message:

s1.sendMessageChannel(0, True, "<span style='color:red;font-size:12px;'>This is a test message to all channels o
n your server</span>")

Get the server uptime in seconds

s1.getUptime()
Out[71]: 104157L

Get a list of current online users

for k,v in s1.getUsers().iteritems():
    print(k, v.name)
(194L, 'Natenom')
(197L, 'Music-Bot 2')
(198L, 'Music-Bot 5')
(199L, 'Music-Bot 3')
(200L, 'Music-Bot 1')
(201L, 'Music-Bot 4')
(19L, 'MetalRubyOceanBot')
(126L, 'someone')

The first number is the current session ID of a user.

But there is more information about a user; when you write the code above press after v. …

For example:

for k,v in s1.getUsers().iteritems():
    print(k, v.name, v.os, v.osversion, v.release, v.selfMute, v.idlesecs)
(194L, 'Natenom', 'X11', 'Arch Linux', '1.3.0', False, 1L)
(197L, 'Music-Bot 2', 'Linux x86_64', '#1 SMP Wed Feb 10 09:52:06 CET 2016', 'mumble-ruby 1.1.2', False, 3360L)
[...]

Kick a user

Lets kick Natenom, referenced by his current session id (194):

s1.kickUser(194, "Just a test :P")
[07:28:23] You were kicked from the server by the server: Just a test :P.

Note that the session id is limited to the current session; it changes when Natenom reconnects.

Playing with a specific user

Create an object with a specific user, lets say Natenom:

for k,v in s1.getUsers().iteritems():
    print(k, v.name, v.os, v.osversion, v.release, v.selfMute, v.idlesecs)
(1L, 'Natenom', 'X11', 'Arch Linux', '1.3.0', False, 12L)
Natenom = s1.getUsers()[1] #1 is the session id from above

Now type Natenom. and press .

Natenom.<press TAB>
Natenom.address          Natenom.idlesecs
[...]

The object „Natenom“ can also be used to change his current state with the help of setState().

First modify the object:

Natenom.name = "Ice is cool :P"

Nothing happened yet on the server; now:

s1.setState(Natenom)

Now Natenom was renamed on the server :)

BTW: When using Ice to rename users you are not limited to characters allowed by „username“ setting. The same applies for channel names.

Lets deaf Natenom server side:

Natenom.deaf = True
s1.setState(Natenom)

Done.

ice_is_cool

Work with channels

In order to create a new channel you need to know the ID of the parent channel; 0 in this case is the root channel so the next command will create a main channel.

s1.addChannel("Name your channel", 0)
Out[13]: 3696L

The output gives you the ID of the new channel, 3696. You need it to reference this channel in other commands.

s1.getChannelState(3696)
{
id = 3696
name = name of new channel
parent = 0
links =
{
}
description =
temporary = False
position = 0
}
mychannel = s1.getChannelState(3696)
mychannel.description = "You can use HTML and CSS in channel descriptions if allowhtml is set to true on your se
rver<br /><br /><a href='https://natenom.de'>Link to my blog</a>" 
s1.setChannelState(mychannel)

working_with_ice

Done…

Have fun with experimenting what else you can do with Mice :)

It is very powerful.