Commit e91ba351 authored by Philipp Hörist's avatar Philipp Hörist

MUC: Configure all rooms automatically on creation

parent 0322b4a5
Pipeline #3747 passed with stages
in 2 minutes and 40 seconds
...@@ -1616,3 +1616,23 @@ def get_resource(account): ...@@ -1616,3 +1616,23 @@ def get_resource(account):
'rand': rand}) 'rand': rand})
app.config.set_per('accounts', account, 'resource', resource) app.config.set_per('accounts', account, 'resource', resource)
return resource return resource
def get_default_muc_config():
return {
# XEP-0045 options
'muc#roomconfig_allowinvites': True,
'muc#roomconfig_publicroom': False,
'muc#roomconfig_membersonly': True,
'muc#roomconfig_persistentroom': True,
'muc#roomconfig_whois': 'anyone',
'muc#roomconfig_moderatedroom': False,
# Ejabberd options
'allow_voice_requests': False,
'public_list': False,
# Prosody options
'{http://prosody.im/protocol/muc}roomconfig_allowmemberinvites': True,
'muc#roomconfig_enablearchiving': True,
}
...@@ -32,6 +32,7 @@ from gajim.common.const import KindConstant ...@@ -32,6 +32,7 @@ from gajim.common.const import KindConstant
from gajim.common.const import MUCJoinedState from gajim.common.const import MUCJoinedState
from gajim.common.structs import MUCData from gajim.common.structs import MUCData
from gajim.common.helpers import AdditionalDataDict from gajim.common.helpers import AdditionalDataDict
from gajim.common.helpers import get_default_muc_config
from gajim.common import idle from gajim.common import idle
from gajim.common.caps_cache import muc_caps_cache from gajim.common.caps_cache import muc_caps_cache
from gajim.common.nec import NetworkEvent from gajim.common.nec import NetworkEvent
...@@ -100,8 +101,6 @@ class MUC(BaseModule): ...@@ -100,8 +101,6 @@ class MUC(BaseModule):
priority=49) priority=49)
] ]
self._register_callback('request_config', self._config_received)
self._muc_data = {} self._muc_data = {}
def pass_disco(self, from_, identities, features, _data, _node): def pass_disco(self, from_, identities, features, _data, _node):
...@@ -168,6 +167,77 @@ class MUC(BaseModule): ...@@ -168,6 +167,77 @@ class MUC(BaseModule):
'%s/%s' % (room_jid, muc.nick), '%s/%s' % (room_jid, muc.nick),
typ='unavailable') typ='unavailable')
def configure_room(self, room_jid):
self._nbxmpp('MUC').request_config(room_jid,
callback=self._on_room_config)
def _on_room_config(self, result):
if is_error_result(result):
self._log.info('Error: %s', result)
app.nec.push_incoming_event(NetworkEvent(
'muc-configuration-failed',
account=self._account,
room_jid=result.jid,
error=result))
return
self._log.info('Configure room: %s', result.jid)
self._apply_config(result.form)
self.set_config(result.jid,
result.form,
callback=self._on_config_result)
@staticmethod
def _apply_config(form, config=None):
if config is None:
config = get_default_muc_config()
for var, value in config.items():
try:
field = form[var]
except KeyError:
pass
else:
field.value = value
def _on_config_result(self, result):
if is_error_result(result):
self._log.info('Error: %s', result)
app.nec.push_incoming_event(NetworkEvent(
'muc-configuration-failed',
account=self._account,
room_jid=result.jid,
error=result))
return
self._log.info('Configuration finished: %s', result.jid)
app.nec.push_incoming_event(NetworkEvent(
'muc-configuration-finished',
account=self._account,
room_jid=result.jid))
self._con.get_module('Discovery').disco_muc(
result.jid, partial(self._on_disco_update, result.jid), update=True)
# If this is an automatic room creation
try:
invites = app.automatic_rooms[self._account][result.jid]['invities']
except KeyError:
return
user_list = {}
for jid in invites:
user_list[jid] = {'affiliation': 'member'}
self.set_affiliation(result.jid, user_list)
for jid in invites:
self.invite(result.jid, jid)
def _on_disco_update(self, room_jid):
app.nec.push_incoming_event(NetworkEvent(
'muc-disco-update',
account=self._account,
room_jid=room_jid))
def update_presence(self, auto=False): def update_presence(self, auto=False):
mucs = self.get_mucs_with_state([MUCJoinedState.JOINED, mucs = self.get_mucs_with_state([MUCJoinedState.JOINED,
MUCJoinedState.JOINING]) MUCJoinedState.JOINING])
...@@ -292,6 +362,8 @@ class MUC(BaseModule): ...@@ -292,6 +362,8 @@ class MUC(BaseModule):
if properties.is_muc_self_presence: if properties.is_muc_self_presence:
self._log.info('Self presence: %s', properties.jid) self._log.info('Self presence: %s', properties.jid)
self._raise_muc_event('muc-self-presence', properties) self._raise_muc_event('muc-self-presence', properties)
if properties.is_new_room:
self.configure_room(room_jid)
else: else:
self._log.info('User joined: %s', properties.jid) self._log.info('User joined: %s', properties.jid)
self._raise_muc_event('muc-user-joined', properties) self._raise_muc_event('muc-user-joined', properties)
...@@ -531,18 +603,9 @@ class MUC(BaseModule): ...@@ -531,18 +603,9 @@ class MUC(BaseModule):
type_ = InviteType.DIRECT type_ = InviteType.DIRECT
password = app.gc_passwords.get(room, None) password = app.gc_passwords.get(room, None)
self._log.info('Inivte %s to %s', to, room)
self._nbxmpp('MUC').invite(room, to, reason, password, continue_, type_) self._nbxmpp('MUC').invite(room, to, reason, password, continue_, type_)
def _config_received(self, result):
if is_error_result(result):
return
app.nec.push_incoming_event(NetworkEvent(
'muc-config',
conn=self._con,
dataform=result.form,
jid=result.jid))
def get_instance(*args, **kwargs): def get_instance(*args, **kwargs):
return MUC(*args, **kwargs), 'MUC' return MUC(*args, **kwargs), 'MUC'
...@@ -38,6 +38,7 @@ from nbxmpp.const import Affiliation ...@@ -38,6 +38,7 @@ from nbxmpp.const import Affiliation
from nbxmpp.const import Role from nbxmpp.const import Role
from nbxmpp.const import Error from nbxmpp.const import Error
from nbxmpp.const import PresenceType from nbxmpp.const import PresenceType
from nbxmpp.util import is_error_result
from gi.repository import Gtk from gi.repository import Gtk
from gi.repository import Gdk from gi.repository import Gdk
...@@ -326,6 +327,8 @@ class GroupchatControl(ChatControlBase): ...@@ -326,6 +327,8 @@ class GroupchatControl(ChatControlBase):
('muc-subject', ged.GUI1, self._on_subject), ('muc-subject', ged.GUI1, self._on_subject),
('muc-captcha-challenge', ged.GUI1, self._on_captcha_challenge), ('muc-captcha-challenge', ged.GUI1, self._on_captcha_challenge),
('muc-voice-approval', ged.GUI1, self._on_voice_approval), ('muc-voice-approval', ged.GUI1, self._on_voice_approval),
('muc-disco-update', ged.GUI1, self._on_disco_update),
('muc-configuration-finished', ged.GUI1, self._on_configuration_finished),
('gc-message-received', ged.GUI1, self._nec_gc_message_received), ('gc-message-received', ged.GUI1, self._nec_gc_message_received),
('mam-decrypted-message-received', ged.GUI1, self._nec_mam_decrypted_message_received), ('mam-decrypted-message-received', ged.GUI1, self._nec_mam_decrypted_message_received),
('update-gc-avatar', ged.GUI1, self._nec_update_avatar), ('update-gc-avatar', ged.GUI1, self._nec_update_avatar),
...@@ -593,8 +596,8 @@ class GroupchatControl(ChatControlBase): ...@@ -593,8 +596,8 @@ class GroupchatControl(ChatControlBase):
desc = app.css_config.get_font('.gajim-group-row') desc = app.css_config.get_font('.gajim-group-row')
renderer.set_property('font-desc', desc) renderer.set_property('font-desc', desc)
@event_filter(['account', 'room_jid'])
def _on_room_created(self): def _on_disco_update(self, _event):
if self.parent_win is None: if self.parent_win is None:
return return
win = self.parent_win.window win = self.parent_win.window
...@@ -663,20 +666,27 @@ class GroupchatControl(ChatControlBase): ...@@ -663,20 +666,27 @@ class GroupchatControl(ChatControlBase):
DestroyMucDialog(self.room_jid, destroy_handler=_on_confirm) DestroyMucDialog(self.room_jid, destroy_handler=_on_confirm)
def _on_configure_room(self, _action, _param): def _on_configure_room(self, _action, _param):
win = app.get_app_window('GroupchatConfig', self.account, self.room_jid)
if win is not None:
win.present()
return
contact = app.contacts.get_gc_contact( contact = app.contacts.get_gc_contact(
self.account, self.room_jid, self.nick) self.account, self.room_jid, self.nick)
if contact.affiliation.is_owner: if contact.affiliation.is_owner:
con = app.connections[self.account] con = app.connections[self.account]
con.get_module('MUC').request_config(self.room_jid) con.get_module('MUC').request_config(
self.room_jid, callback=self._on_configure_form_received)
elif contact.affiliation.is_admin: elif contact.affiliation.is_admin:
win = app.get_app_window( GroupchatConfig(self.account,
'GroupchatConfig', self.account, self.room_jid) self.room_jid,
if win is not None: contact.affiliation.value)
win.present()
else: def _on_configure_form_received(self, result):
GroupchatConfig(self.account, if is_error_result(result):
self.room_jid, log.info('Error %s %s', result.jid, result)
contact.affiliation.value) return
GroupchatConfig(self.account, result.jid, 'owner', result.form)
def _on_print_join_left(self, action, param): def _on_print_join_left(self, action, param):
action.set_state(param) action.set_state(param)
...@@ -1694,8 +1704,6 @@ class GroupchatControl(ChatControlBase): ...@@ -1694,8 +1704,6 @@ class GroupchatControl(ChatControlBase):
@event_filter(['account', 'room_jid']) @event_filter(['account', 'room_jid'])
def _on_self_presence(self, event): def _on_self_presence(self, event):
nick = event.properties.muc_nickname nick = event.properties.muc_nickname
affiliation = event.properties.affiliation
jid = str(event.properties.jid)
status_codes = event.properties.muc_status_codes or [] status_codes = event.properties.muc_status_codes or []
if not self.is_connected: if not self.is_connected:
...@@ -1704,24 +1712,6 @@ class GroupchatControl(ChatControlBase): ...@@ -1704,24 +1712,6 @@ class GroupchatControl(ChatControlBase):
self.add_contact_to_roster(nick) self.add_contact_to_roster(nick)
self.got_connected() self.got_connected()
if self.room_jid in app.automatic_rooms[self.account] and \
app.automatic_rooms[self.account][self.room_jid]['invities']:
if self.room_jid not in app.interface.instances[self.account]['gc_config']:
con = app.connections[self.account]
if affiliation.is_owner:
# We need to configure the room if it's a new one.
# We cannot know it's a new one. Status 201 is not
# sent by all servers.
con.get_module('MUC').request_config(self.room_jid)
elif 'continue_tag' in app.automatic_rooms[self.account][self.room_jid]:
# We just need to invite contacts
for jid in app.automatic_rooms[self.account][self.room_jid]['invities']:
con.get_module('MUC').invite(self.room_jid, jid)
self.add_info_message(
_('%(jid)s has been '
'invited in this room') % {'jid': jid})
if StatusCode.NON_ANONYMOUS in status_codes: if StatusCode.NON_ANONYMOUS in status_codes:
self.add_info_message( self.add_info_message(
_('Any occupant is allowed to see your full JID')) _('Any occupant is allowed to see your full JID'))
...@@ -1734,16 +1724,13 @@ class GroupchatControl(ChatControlBase): ...@@ -1734,16 +1724,13 @@ class GroupchatControl(ChatControlBase):
self.add_info_message(\ self.add_info_message(\
_('The server has assigned or modified your roomnick')) _('The server has assigned or modified your roomnick'))
if event.properties.is_new_room:
app.connections[self.account].get_module('Discovery').disco_muc(
self.room_jid, self._on_room_created, update=True)
self.add_info_message(_('A new room has been created'))
con = app.connections[self.account]
con.get_module('MUC').request_config(self.room_jid)
# Update Actions # Update Actions
self.update_actions() self.update_actions()
@event_filter(['account', 'room_jid'])
def _on_configuration_finished(self, _event):
self.add_info_message(_('A new room has been created'))
@event_filter(['account', 'room_jid']) @event_filter(['account', 'room_jid'])
def _on_nickname_changed(self, event): def _on_nickname_changed(self, event):
nick = event.properties.muc_nickname nick = event.properties.muc_nickname
......
...@@ -108,7 +108,6 @@ from gajim.gtk.join_groupchat import JoinGroupchatWindow ...@@ -108,7 +108,6 @@ from gajim.gtk.join_groupchat import JoinGroupchatWindow
from gajim.gtk.filechoosers import FileChooserDialog from gajim.gtk.filechoosers import FileChooserDialog
from gajim.gtk.emoji_data import emoji_data from gajim.gtk.emoji_data import emoji_data
from gajim.gtk.emoji_data import emoji_ascii_data from gajim.gtk.emoji_data import emoji_ascii_data
from gajim.gtk.groupchat_config import GroupchatConfig
from gajim.gtk.filetransfer import FileTransfersWindow from gajim.gtk.filetransfer import FileTransfersWindow
from gajim.gtk.http_upload_progress import HTTPUploadProgressWindow from gajim.gtk.http_upload_progress import HTTPUploadProgressWindow
from gajim.gtk.roster_item_exchange import RosterItemExchangeWindow from gajim.gtk.roster_item_exchange import RosterItemExchangeWindow
...@@ -456,52 +455,6 @@ class Interface: ...@@ -456,52 +455,6 @@ class Interface:
'unsubscribed', 'gajim-unsubscribed', 'unsubscribed', 'gajim-unsubscribed',
event_type, obj.jid) event_type, obj.jid)
def handle_event_gc_config(self, obj):
#('GC_CONFIG', account, (jid, form_node)) config is a dict
account = obj.conn.name
if obj.jid in app.automatic_rooms[account]:
if 'continue_tag' in app.automatic_rooms[account][obj.jid]:
# We're converting chat to muc. allow participants to invite
for f in obj.dataform.iter_fields():
if f.var == 'muc#roomconfig_allowinvites':
f.value = True
elif f.var == 'muc#roomconfig_publicroom':
f.value = False
elif f.var == 'muc#roomconfig_membersonly':
f.value = True
elif f.var == 'public_list':
f.value = False
obj.conn.get_module('MUC').set_config(obj.jid, obj.dataform.get_purged())
user_list = {}
for jid in app.automatic_rooms[account][obj.jid]['invities']:
user_list[jid] = {'affiliation': 'member'}
obj.conn.get_module('MUC').set_affiliation(obj.jid, user_list)
else:
# use default configuration
obj.conn.get_module('MUC').set_config(obj.jid, obj.form_node)
# invite contacts
# check if it is necessary to add <continue />
continue_tag = False
if 'continue_tag' in app.automatic_rooms[account][obj.jid]:
continue_tag = True
if 'invities' in app.automatic_rooms[account][obj.jid]:
for jid in app.automatic_rooms[account][obj.jid]['invities']:
obj.conn.get_module('MUC').invite(
obj.jid, jid, continue_=continue_tag)
gc_control = self.msg_win_mgr.get_gc_control(obj.jid,
account)
if gc_control:
gc_control.add_info_message(
_('%(jid)s has been invited in this room') % {
'jid': jid})
del app.automatic_rooms[account][obj.jid]
else:
win = app.get_app_window('GroupchatConfig', account, obj.jid)
if win is not None:
win.present()
else:
GroupchatConfig(account, obj.jid, 'owner', obj.dataform)
def handle_event_gc_decline(self, event): def handle_event_gc_decline(self, event):
gc_control = self.msg_win_mgr.get_gc_control(str(event.muc), gc_control = self.msg_win_mgr.get_gc_control(str(event.muc),
event.account) event.account)
...@@ -1275,7 +1228,6 @@ class Interface: ...@@ -1275,7 +1228,6 @@ class Interface:
'message-not-sent': [self.handle_event_msgnotsent], 'message-not-sent': [self.handle_event_msgnotsent],
'message-sent': [self.handle_event_msgsent], 'message-sent': [self.handle_event_msgsent],
'metacontacts-received': [self.handle_event_metacontacts], 'metacontacts-received': [self.handle_event_metacontacts],
'muc-config': [self.handle_event_gc_config],
'our-show': [self.handle_event_status], 'our-show': [self.handle_event_status],
'password-required': [self.handle_event_password_required], 'password-required': [self.handle_event_password_required],
'plain-connection': [self.handle_event_plain_connection], 'plain-connection': [self.handle_event_plain_connection],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment