From b28f8238c8b521e80f0cacf62872d76f951d2d6b Mon Sep 17 00:00:00 2001 From: Captain Zidgel <13912938+Coolster4000@users.noreply.github.com> Date: Sun, 4 Oct 2020 14:56:04 -0700 Subject: [PATCH 1/2] Added user kick/ban methods & permission denied callback You can now kick or ban a user with User.kick() and an optional reason keyword argument. Added callback for permission denied message type. Added Mumble.denial_type(int n) as a high-level method for decrypting the PermissionDenied.DenyType (event.type) PB field into a textual name. --- pymumble_py3/callbacks.py | 1 + pymumble_py3/constants.py | 4 +++- pymumble_py3/messages.py | 8 ++++++++ pymumble_py3/mumble.py | 14 +++++++++++++- pymumble_py3/users.py | 16 ++++++++++++++++ 5 files changed, 41 insertions(+), 2 deletions(-) diff --git a/pymumble_py3/callbacks.py b/pymumble_py3/callbacks.py index 7cefb7f..b46e883 100644 --- a/pymumble_py3/callbacks.py +++ b/pymumble_py3/callbacks.py @@ -27,6 +27,7 @@ def __init__(self): PYMUMBLE_CLBK_TEXTMESSAGERECEIVED: None, # Send the received message PYMUMBLE_CLBK_CONTEXTACTIONRECEIVED: None, # Send the contextaction message PYMUMBLE_CLBK_ACLRECEIVED: None, # Send the received ACL permissions object + PYMUMBLE_CLBK_PERMISSIONDENIED: None, # Permission Denied for some action, send information }) def set_callback(self, callback, dest): diff --git a/pymumble_py3/constants.py b/pymumble_py3/constants.py index 4ec3abe..e96a24c 100644 --- a/pymumble_py3/constants.py +++ b/pymumble_py3/constants.py @@ -71,11 +71,12 @@ PYMUMBLE_CLBK_CHANNELREMOVED = "channel_remove" PYMUMBLE_CLBK_USERCREATED = "user_created" PYMUMBLE_CLBK_USERUPDATED = "user_updated" -PYMUMBLE_CLBK_USERREMOVED = "user_remove" +PYMUMBLE_CLBK_USERREMOVED = "user_removed" PYMUMBLE_CLBK_SOUNDRECEIVED = "sound_received" PYMUMBLE_CLBK_TEXTMESSAGERECEIVED = "text_received" PYMUMBLE_CLBK_CONTEXTACTIONRECEIVED = "contextAction_received" PYMUMBLE_CLBK_ACLRECEIVED = "acl_received" +PYMUMBLE_CLBK_PERMISSIONDENIED = "permission_denied" # audio types PYMUMBLE_AUDIO_TYPE_CELT_ALPHA = 0 @@ -92,3 +93,4 @@ PYMUMBLE_CMD_TEXTPRIVATEMESSAGE = "text_private_message" PYMUMBLE_CMD_CHANNELUNLINK = "unlink" PYMUMBLE_CMD_QUERYACL = "get_acl" +PYMUMBLE_CMD_REMOVEUSER = "remove_user" diff --git a/pymumble_py3/messages.py b/pymumble_py3/messages.py index 976fc2d..8595044 100644 --- a/pymumble_py3/messages.py +++ b/pymumble_py3/messages.py @@ -61,6 +61,14 @@ def __init__(self, session, params): self.cmd = PYMUMBLE_CMD_MODUSERSTATE self.parameters = params +class RemoveUser(Cmd): + """Command to kick (ban=False) or ban (ban=True) a user""" + + def __init__(self, session, params): + Cmd.__init__(self) + + self.cmd = PYMUMBLE_CMD_REMOVEUSER + self.parameters = params class CreateChannel(Cmd): """Command to create channel""" diff --git a/pymumble_py3/mumble.py b/pymumble_py3/mumble.py index c5900cc..09ceec7 100644 --- a/pymumble_py3/mumble.py +++ b/pymumble_py3/mumble.py @@ -376,6 +376,8 @@ def dispatch_control_message(self, type, message): mess.ParseFromString(message) self.Log.debug("message: PermissionDenied : %s", mess) + self.callbacks(PYMUMBLE_CLBK_PERMISSIONDENIED, mess) + elif type == PYMUMBLE_MSG_TYPES_ACL: mess = mumble_pb2.ACL() mess.ParseFromString(message) @@ -673,7 +675,14 @@ def treat_command(self, cmd): self.send_message(PYMUMBLE_MSG_TYPES_USERSTATE, userstate) cmd.response = True self.commands.answer(cmd) - + elif cmd.cmd == PYMUMBLE_CMD_REMOVEUSER: + userremove = mumble_pb2.UserRemove() + userremove.session = cmd.parameters["session"] + userremove.reason = cmd.parameters["reason"] + userremove.ban = cmd.parameters["ban"] + self.send_message(PYMUMBLE_MSG_TYPES_USERREMOVE, userremove) + cmd.response = True + self.commands.answer(cmd) elif cmd.cmd == PYMUMBLE_CMD_QUERYACL: acl = mumble_pb2.ACL() acl.channel_id = cmd.parameters["channel_id"] @@ -691,6 +700,9 @@ def get_max_image_length(self): def my_channel(self): return self.channels[self.users.myself["channel_id"]] + def denial_type(self, n): + return mumble_pb2.PermissionDenied.DenyType.Name(n) + def stop(self): self.reconnect = None self.exit = True diff --git a/pymumble_py3/users.py b/pymumble_py3/users.py index 1eabd43..322d6e1 100644 --- a/pymumble_py3/users.py +++ b/pymumble_py3/users.py @@ -246,3 +246,19 @@ def send_text_message(self, message): cmd = messages.TextPrivateMessage(self["session"], message) self.mumble_object.execute_command(cmd) + + def kick(self, reason=""): + params = {"session": self["session"], + "reason": reason, + "ban": False} + + cmd = messages.RemoveUser(self.mumble_object.users.myself_session, params) + self.mumble_object.execute_command(cmd) + + def ban(self, reason=""): + params = {"session": self["session"], + "reason": reason, + "ban": True} + + cmd = messages.RemoveUser(self.mumble_object.users.myself_session, params) + self.mumble_object.execute_command(cmd) From ff2c311729a9e6a24dfe2433a8496eeb06fe060d Mon Sep 17 00:00:00 2001 From: Captain Zidgel <13912938+Coolster4000@users.noreply.github.com> Date: Sun, 4 Oct 2020 17:15:24 -0700 Subject: [PATCH 2/2] Docs for new kick/ban features, perms denied callback. --- API.md | 13 ++++++++++++- README.md | 4 +++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/API.md b/API.md index 90374c5..24a619a 100644 --- a/API.md +++ b/API.md @@ -69,10 +69,11 @@ Callback names are in `pymumble.constants` module, starting with `PYMUMBLE_CLBK_ - `PYMUMBLE_CLBK_CHANNELREMOVED`: send the removed channel object as parameter - `PYMUMBLE_CLBK_USERCREATED`: send the added user object as parameter - `PYMUMBLE_CLBK_USERUPDATED`: send the updated user object and a dict with all the modified fields as parameter -- `PYMUMBLE_CLBK_USERREMOVED`: send the removed user object and the mumble message as parameter +- `PYMUMBLE_CLBK_USERREMOVED`: send the removed user object and the removal event as parameters. The event contains only a `session` field if a user left manually, otherwise it adds an `actor` (person who kicked/banned), `reason`, and `ban` (`True`=ban, `False`=kick). - `PYMUMBLE_CLBK_SOUNDRECEIVED`: send the user object that received the sound and the SoundChunk object itself - `PYMUMBLE_CLBK_TEXTMESSAGERECEIVED`: send the received message - `PYMUMBLE_CLBK_ACLRECEIVED`: send the received acl permissions +- `PYMUMBLE_CLBK_PERMISSIONDENIED`: send the information regarding what caused the action to fail. `event.type` corresponds to [this DenyType enum](https://github.com/mumble-voip/mumble/blob/34c9b2503361163b649a35598de7de727a64148f/src/Mumble.proto#L271). **Callbacks are executed within the library looping thread. Keep it's work short or you could have jitter issues!** @@ -120,6 +121,10 @@ Contain the session number of the `pymumble` connection itself. Is a shortcut to `Mumble.users[Mumble.users.myself_session]`, pointing to the User object of the current connection. +> `Mumble.denial_type(n)` + +Is a shortcut to `mumble_pb2.PermissionDenied.DenyType.Name(n)`, the associated enum name for an action denial cause. (`n` comes from the callback for `PYMUMBLE_CLBK_PERMISSIONDENIED`: `event.type`. + ## User object (accessible through Mumble.users[session] or Mumble.users.myself Contain the users information and method to act on them. User also contain an instance of the SoundQueue object, containing the audio received from this user. @@ -160,6 +165,11 @@ Send a message to the specific user. Send a register demand to the murmur server (you need to have a certfile +> `user.kick()` +> `user.ban()` + +You can pass a keyword argument `reason=` if you'd like, defaults to empty string. + ## SoundQueue object (accessible through User.sound) Contains the audio received from a specific user. Take care of the decoding and keep track on the timing of the reception. @@ -330,3 +340,4 @@ Set Whisper to a specific Channel > ``Mumble.sound_output.remove_whisper()`` Remove the previously set Whisper + diff --git a/README.md b/README.md index 7611bbd..4559e44 100644 --- a/README.md +++ b/README.md @@ -46,18 +46,20 @@ For client application examples, you can check this list : - Support OPUS. Speex is not supported - Receive and send audio, get users and channels status - Set properties for users (mute, comments, etc.) and go to a specific channel +- Kick and ban users - Callback mechanism to react on server events - Manage the blobs (images, long comments, etc.) - Can send text messages to user and channel - Ping statistics - Audio targets (whisper, etc.) +- Read ACL groups ### What is missing: > I don't need these features, so if you want one, open an issue and I will work on it. - UDP media. Currently it works only in TCP tunneling mode (the standard fallback of Mumble when UDP is not working) -- Server management (user creation and registration, ACLs, groups, bans, etc.) +- Some server management features (user creation, editing ACLs, etc.) - Positioning is not managed, but it should be easy to add - Probably a lot of other small features - **WONTFIX** The **Python 2** version is available in the [master branch](https://github.com/azlux/pymumble/tree/master). It's working! But since we have moved on to Python 3, the Python 2 version will not receive future improvements.