Move invites into MUC module

This commit is contained in:
Philipp Hörist 2018-07-16 23:22:33 +02:00
parent d65253b021
commit bff5f14b92
9 changed files with 239 additions and 178 deletions

View File

@ -291,7 +291,7 @@ class StandardGroupChatCommands(CommandContainer):
@command(raw=True, empty=True)
@doc(_("Invite a user to a room for a reason"))
def invite(self, jid, reason):
self.connection.send_invite(self.room_jid, jid, reason)
self.connection.get_module('MUC').invite(self.room_jid, jid, reason)
return _("Invited %(jid)s to %(room_jid)s") % {'jid': jid,
'room_jid': self.room_jid}

View File

@ -2379,68 +2379,6 @@ class Connection(CommonConnection, ConnectionHandlers):
else:
_on_unregister_account_connect(self.connection)
def send_invite(self, room, to, reason='', continue_tag=False):
"""
Send invitation
"""
if not app.account_is_connected(self.name):
return
contact = app.contacts.get_contact_from_full_jid(self.name, to)
if contact and contact.supports(nbxmpp.NS_CONFERENCE):
# send direct invite
message=nbxmpp.Message(to=to)
attrs = {'jid': room}
if reason:
attrs['reason'] = reason
if continue_tag:
attrs['continue'] = 'true'
password = app.gc_passwords.get(room, '')
if password:
attrs['password'] = password
c = message.addChild(name='x', attrs=attrs,
namespace=nbxmpp.NS_CONFERENCE)
self.connection.send(message)
return
message=nbxmpp.Message(to=room)
c = message.addChild(name='x', namespace=nbxmpp.NS_MUC_USER)
c = c.addChild(name='invite', attrs={'to': to})
if continue_tag:
c.addChild(name='continue')
if reason != '':
c.setTagData('reason', reason)
self.connection.send(message)
def decline_invitation(self, room, to, reason=''):
"""
decline a groupchat invitation
"""
if not app.account_is_connected(self.name):
return
message=nbxmpp.Message(to=room)
c = message.addChild(name='x', namespace=nbxmpp.NS_MUC_USER)
c = c.addChild(name='decline', attrs={'to': to})
if reason != '':
c.setTagData('reason', reason)
self.connection.send(message)
def request_voice(self, room):
"""
Request voice in a moderated room
"""
if not app.account_is_connected(self.name):
return
message = nbxmpp.Message(to=room)
x = nbxmpp.DataForm(typ='submit')
x.addChild(node=nbxmpp.DataField(name='FORM_TYPE',
value=nbxmpp.NS_MUC + '#request'))
x.addChild(node=nbxmpp.DataField(name='muc#role', value='participant',
typ='text-single'))
message.addChild(node=x)
self.connection.send(message)
def _reconnect_alarm(self):
if not app.config.get_per('accounts', self.name, 'active'):
# Account may have been disabled

View File

@ -297,7 +297,8 @@ class ConnectionHandlersBase:
nbxmpp.NS_PUBSUB_EVENT,
nbxmpp.NS_ROSTERX,
nbxmpp.NS_MAM_1,
nbxmpp.NS_MAM_2])
nbxmpp.NS_MAM_2,
nbxmpp.NS_CONFERENCE])
app.ged.register_event_handler('iq-error-received', ged.CORE,
self._nec_iq_error_received)
@ -950,6 +951,12 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
# but nbxmpp executes less common handlers last
if self._message_namespaces & set(stanza.getProperties()):
return
muc_user = stanza.getTag('x', namespace=nbxmpp.NS_MUC_USER)
if muc_user is not None:
if muc_user.getChildren():
# Not a PM, handled by MUC module
return
log.debug('MessageCB')
app.nec.push_incoming_event(NetworkEvent('raw-message-received',

View File

@ -697,32 +697,6 @@ class MessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
return
self.jid = app.get_jid_without_resource(self.fjid)
# Mediated invitation?
muc_user = self.stanza.getTag('x', namespace=nbxmpp.NS_MUC_USER)
if muc_user:
if muc_user.getTag('decline'):
app.nec.push_incoming_event(
GcDeclineReceivedEvent(
None, conn=self.conn,
room_jid=self.fjid, stanza=muc_user))
return
if muc_user.getTag('invite'):
app.nec.push_incoming_event(
GcInvitationReceivedEvent(
None, conn=self.conn, jid_from=self.fjid,
mediated=True, stanza=muc_user))
return
else:
# Direct invitation?
direct = self.stanza.getTag(
'x', namespace=nbxmpp.NS_CONFERENCE)
if direct:
app.nec.push_incoming_event(
GcInvitationReceivedEvent(
None, conn=self.conn, jid_from=self.fjid,
mediated=False, stanza=direct))
return
self.thread_id = self.stanza.getThread()
self.mtype = self.stanza.getType()
if not self.mtype or self.mtype not in ('chat', 'groupchat', 'error'):
@ -840,72 +814,6 @@ class ZeroconfMessageReceivedEvent(MessageReceivedEvent):
stanza=self.stanza)
return super(ZeroconfMessageReceivedEvent, self).generate()
class GcInvitationReceivedEvent(nec.NetworkIncomingEvent):
name = 'gc-invitation-received'
base_network_events = []
def generate(self):
account = self.conn.name
if not self.mediated:
# direct invitation
try:
self.room_jid = helpers.parse_jid(self.stanza.getAttr('jid'))
except helpers.InvalidFormat:
log.warning('Invalid JID: %s, ignoring it',
self.stanza.getAttr('jid'))
return
self.reason = self.stanza.getAttr('reason')
self.password = self.stanza.getAttr('password')
self.is_continued = False
self.is_continued = self.stanza.getAttr('continue') == 'true'
else:
self.invite = self.stanza.getTag('invite')
self.room_jid = self.jid_from
try:
self.jid_from = helpers.parse_jid(self.invite.getAttr('from'))
except helpers.InvalidFormat:
log.warning('Invalid JID: %s, ignoring it',
self.invite.getAttr('from'))
return
self.reason = self.invite.getTagData('reason')
self.password = self.stanza.getTagData('password')
self.is_continued = self.stanza.getTag('continue') is not None
if self.room_jid in app.gc_connected[account] and \
app.gc_connected[account][self.room_jid]:
# We are already in groupchat. Ignore invitation
return
jid = app.get_jid_without_resource(self.jid_from)
ignore = app.config.get_per(
'accounts', account, 'ignore_unknown_contacts')
if ignore and not app.contacts.get_contacts(account, jid):
return
return True
class GcDeclineReceivedEvent(nec.NetworkIncomingEvent):
name = 'gc-decline-received'
base_network_events = []
def generate(self):
account = self.conn.name
decline = self.stanza.getTag('decline')
try:
self.jid_from = helpers.parse_jid(decline.getAttr('from'))
except helpers.InvalidFormat:
log.warning('Invalid JID: %s, ignoring it',
decline.getAttr('from'))
return
jid = app.get_jid_without_resource(self.jid_from)
ignore = app.config.get_per(
'accounts', account, 'ignore_unknown_contacts')
if ignore and not app.contacts.get_contacts(account, jid):
return
self.reason = decline.getTagData('reason')
return True
class DecryptedMessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
name = 'decrypted-message-received'

205
gajim/common/modules/muc.py Normal file
View File

@ -0,0 +1,205 @@
# This file is part of Gajim.
#
# Gajim 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; version 3 only.
#
# Gajim 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.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
# XEP-0045: Multi-User Chat
# XEP-0249: Direct MUC Invitations
import logging
import nbxmpp
from gajim.common import app
from gajim.common import helpers
from gajim.common.nec import NetworkIncomingEvent
log = logging.getLogger('gajim.c.m.muc')
class MUC:
def __init__(self, con):
self._con = con
self._account = con.name
self.handlers = [
('message', self._mediated_invite, '', nbxmpp.NS_MUC_USER),
('message', self._direct_invite, '', nbxmpp.NS_CONFERENCE),
]
def _mediated_invite(self, con, stanza):
muc_user = stanza.getTag('x', namespace=nbxmpp.NS_MUC_USER)
if muc_user is None:
return
decline = muc_user.getTag('decline')
if decline is not None:
room_jid = stanza.getFrom().getStripped()
from_ = self._get_from(room_jid, decline)
reason = decline.getTagData('reason')
log.info('Invite declined: %s, %s', reason, from_)
app.nec.push_incoming_event(
GcDeclineReceived(None,
account=self._account,
from_=from_,
room_jid=room_jid,
reason=reason))
raise nbxmpp.NodeProcessed
invite = muc_user.getTag('invite')
if invite is not None:
room_jid = stanza.getFrom().getStripped()
from_ = self._get_from(room_jid, invite)
reason = invite.getTagData('reason')
password = muc_user.getTagData('password')
is_continued = invite.getTag('continue') is not None
log.info('Mediated invite: continued: %s, reason: %s, from: %s',
is_continued, reason, from_)
if room_jid in app.gc_connected[self._account] and \
app.gc_connected[self._account][room_jid]:
# We are already in groupchat. Ignore invitation
log.info('We are already in this room')
raise nbxmpp.NodeProcessed
app.nec.push_incoming_event(
GcInvitationReceived(None,
account=self._account,
from_=from_,
room_jid=room_jid,
reason=reason,
password=password,
is_continued=is_continued))
raise nbxmpp.NodeProcessed
def _get_from(self, room_jid, stanza):
try:
from_ = nbxmpp.JID(helpers.parse_jid(stanza.getAttr('from')))
except helpers.InvalidFormat:
log.warning('Invalid JID on invite: %s, ignoring it',
stanza.getAttr('from'))
raise nbxmpp.NodeProcessed
known_contact = app.contacts.get_contacts(self._account, room_jid)
ignore = app.config.get_per(
'accounts', self._account, 'ignore_unknown_contacts')
if ignore and not known_contact:
log.info('Ignore invite from unknown contact %s', from_)
raise nbxmpp.NodeProcessed
return from_
def _direct_invite(self, con, stanza):
direct = stanza.getTag('x', namespace=nbxmpp.NS_CONFERENCE)
if direct is None:
return
from_ = stanza.getFrom()
try:
room_jid = helpers.parse_jid(direct.getAttr('jid'))
except helpers.InvalidFormat:
log.warning('Invalid JID on invite: %s, ignoring it',
direct.getAttr('jid'))
raise nbxmpp.NodeProcessed
reason = direct.getAttr('reason')
password = direct.getAttr('password')
is_continued = direct.getAttr('continue') == 'true'
log.info('Direct invite: continued: %s, reason: %s, from: %s',
is_continued, reason, from_)
app.nec.push_incoming_event(
GcInvitationReceived(None,
account=self._account,
from_=from_,
room_jid=room_jid,
reason=reason,
password=password,
is_continued=is_continued))
raise nbxmpp.NodeProcessed
def invite(self, room, to, reason=None, continue_=False):
if not app.account_is_connected(self._account):
return
contact = app.contacts.get_contact_from_full_jid(self._account, to)
if contact and contact.supports(nbxmpp.NS_CONFERENCE):
invite = self._build_direct_invite(room, to, reason, continue_)
else:
invite = self._build_mediated_invite(room, to, reason, continue_)
self._con.connection.send(invite)
def _build_direct_invite(self, room, to, reason, continue_):
message = nbxmpp.Message(to=to)
attrs = {'jid': room}
if reason:
attrs['reason'] = reason
if continue_:
attrs['continue'] = 'true'
password = app.gc_passwords.get(room, None)
if password:
attrs['password'] = password
message = message.addChild(name='x', attrs=attrs,
namespace=nbxmpp.NS_CONFERENCE)
return message
def _build_mediated_invite(self, room, to, reason, continue_):
message = nbxmpp.Message(to=room)
muc_user = message.addChild('x', namespace=nbxmpp.NS_MUC_USER)
invite = muc_user.addChild('invite', attrs={'to': to})
if continue_:
invite.addChild(name='continue')
if reason:
invite.setTagData('reason', reason)
password = app.gc_passwords.get(room, None)
if password:
muc_user.setTagData('password', password)
return message
def decline(self, room, to, reason=None):
if not app.account_is_connected(self._account):
return
message = nbxmpp.Message(to=room)
muc_user = message.addChild('x', namespace=nbxmpp.NS_MUC_USER)
decline = muc_user.addChild('decline', attrs={'to': to})
if reason:
decline.setTagData('reason', reason)
self._con.connection.send(message)
def request_voice(self, room):
if not app.account_is_connected(self._account):
return
message = nbxmpp.Message(to=room)
x = nbxmpp.DataForm(typ='submit')
x.addChild(node=nbxmpp.DataField(name='FORM_TYPE',
value=nbxmpp.NS_MUC + '#request'))
x.addChild(node=nbxmpp.DataField(name='muc#role',
value='participant',
typ='text-single'))
message.addChild(node=x)
self._con.connection.send(message)
class GcInvitationReceived(NetworkIncomingEvent):
name = 'gc-invitation-received'
class GcDeclineReceived(NetworkIncomingEvent):
name = 'gc-decline-received'
def get_instance(*args, **kwargs):
return MUC(*args, **kwargs), 'MUC'

View File

@ -4437,8 +4437,8 @@ class InvitationReceivedDialog:
self.account, self.room_jid, password=self.password)
def on_no(text):
app.connections[account].decline_invitation(self.room_jid,
self.contact_fjid, text)
app.connections[account].get_module('MUC').decline(
self.room_jid, self.contact_fjid, text)
dlg = YesNoDialog(pritext, sectext,
text_label=_('Reason (if you decline):'), on_response_yes=on_yes,

View File

@ -716,7 +716,8 @@ class GroupchatControl(ChatControlBase):
"""
Request voice in the current room
"""
app.connections[self.account].request_voice(self.room_jid)
con = app.connections[self.account]
con.get_module('MUC').request_voice(self.room_jid)
def _on_minimize(self, action, param):
"""
@ -1797,7 +1798,7 @@ class GroupchatControl(ChatControlBase):
# We just need to invite contacts
for jid in app.automatic_rooms[self.account][
self.room_jid]['invities']:
obj.conn.send_invite(self.room_jid, jid)
obj.conn.get_module('MUC').invite(self.room_jid, jid)
self.print_conversation(_('%(jid)s has been '
'invited in this room') % {'jid': jid},
graphics=False)
@ -2405,7 +2406,8 @@ class GroupchatControl(ChatControlBase):
return
contact_jid = data
app.connections[self.account].send_invite(self.room_jid, contact_jid)
con = app.connections[self.account]
con.get_module('MUC').invite(self.room_jid, contact_jid)
self.print_conversation(_('%(jid)s has been invited in this room') %
{'jid': contact_jid}, graphics=False)

View File

@ -608,8 +608,8 @@ class Interface:
continue_tag = True
if 'invities' in app.automatic_rooms[account][obj.jid]:
for jid in app.automatic_rooms[account][obj.jid]['invities']:
obj.conn.send_invite(obj.jid, jid,
continue_tag=continue_tag)
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:
@ -629,35 +629,35 @@ class Interface:
affiliation_list_received(obj.users_dict)
def handle_event_gc_decline(self, obj):
account = obj.conn.name
gc_control = self.msg_win_mgr.get_gc_control(obj.room_jid, account)
gc_control = self.msg_win_mgr.get_gc_control(obj.room_jid, obj.account)
if gc_control:
if obj.reason:
gc_control.print_conversation(
_('%(jid)s declined the invitation: %(reason)s') % {
'jid': obj.jid_from, 'reason': obj.reason}, graphics=False)
'jid': obj.from_, 'reason': obj.reason},
graphics=False)
else:
gc_control.print_conversation(
_('%(jid)s declined the invitation') % {
'jid': obj.jid_from}, graphics=False)
'jid': obj.from_}, graphics=False)
def handle_event_gc_invitation(self, obj):
#('GC_INVITATION', (room_jid, jid_from, reason, password, is_continued))
account = obj.conn.name
if helpers.allow_popup_window(account) or not self.systray_enabled:
dialogs.InvitationReceivedDialog(account, obj.room_jid,
obj.jid_from, obj.password, obj.reason,
if helpers.allow_popup_window(obj.account) or not self.systray_enabled:
dialogs.InvitationReceivedDialog(
obj.account, obj.room_jid,
str(obj.from_), obj.password, obj.reason,
is_continued=obj.is_continued)
return
event = events.GcInvitationtEvent(obj.room_jid, obj.reason,
obj.password, obj.is_continued, obj.jid_from)
self.add_event(account, obj.jid_from, event)
event = events.GcInvitationtEvent(
obj.room_jid, obj.reason,
obj.password, obj.is_continued, str(obj.from_))
self.add_event(obj.account, str(obj.from_), event)
if helpers.allow_showing_notification(account):
if helpers.allow_showing_notification(obj.account):
event_type = _('Groupchat Invitation')
app.notification.popup(
event_type, obj.jid_from, account, 'gc-invitation',
event_type, str(obj.from_), obj.account, 'gc-invitation',
'gajim-gc_invitation', event_type, obj.room_jid)
def forget_gpg_passphrase(self, keyid):

View File

@ -3091,7 +3091,8 @@ class RosterWindow:
contact_jid = contact.jid
if resource: # we MUST have one contact only in list_
contact_jid += '/' + resource
app.connections[room_account].send_invite(room_jid, contact_jid)
con = app.connections[room_account]
con.get_module('MUC').invite(room_jid, contact_jid)
gc_control = app.interface.msg_win_mgr.get_gc_control(room_jid,
room_account)
if gc_control: