ability to destroy a room when we are owner, give a reason and alternative room
jid. fixes #3031
This commit is contained in:
parent
81c0b528ae
commit
5920d03aee
5 changed files with 153 additions and 13 deletions
|
@ -12,7 +12,7 @@
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
|
|
||||||
<child internal-child="image">
|
<child internal-child="image">
|
||||||
<widget class="GtkImage" id="image1359">
|
<widget class="GtkImage" id="image1378">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="stock">gtk-justify-fill</property>
|
<property name="stock">gtk-justify-fill</property>
|
||||||
<property name="icon_size">1</property>
|
<property name="icon_size">1</property>
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
|
|
||||||
<child internal-child="image">
|
<child internal-child="image">
|
||||||
<widget class="GtkImage" id="image1360">
|
<widget class="GtkImage" id="image1379">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="stock">gtk-preferences</property>
|
<property name="stock">gtk-preferences</property>
|
||||||
<property name="icon_size">1</property>
|
<property name="icon_size">1</property>
|
||||||
|
@ -44,13 +44,33 @@
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="destroy_room_menuitem">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">_Destroy room</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
|
||||||
|
<child internal-child="image">
|
||||||
|
<widget class="GtkImage" id="image1380">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="stock">gtk-delete</property>
|
||||||
|
<property name="icon_size">1</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<property name="yalign">0.5</property>
|
||||||
|
<property name="xpad">0</property>
|
||||||
|
<property name="ypad">0</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkImageMenuItem" id="change_subject_menuitem">
|
<widget class="GtkImageMenuItem" id="change_subject_menuitem">
|
||||||
<property name="label" translatable="yes">Change _Subject</property>
|
<property name="label" translatable="yes">Change _Subject</property>
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
|
|
||||||
<child internal-child="image">
|
<child internal-child="image">
|
||||||
<widget class="GtkImage" id="image1361">
|
<widget class="GtkImage" id="image1381">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="stock">gtk-edit</property>
|
<property name="stock">gtk-edit</property>
|
||||||
<property name="icon_size">1</property>
|
<property name="icon_size">1</property>
|
||||||
|
@ -69,7 +89,7 @@
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
|
|
||||||
<child internal-child="image">
|
<child internal-child="image">
|
||||||
<widget class="GtkImage" id="image1362">
|
<widget class="GtkImage" id="image1382">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="stock">gtk-redo</property>
|
<property name="stock">gtk-redo</property>
|
||||||
<property name="icon_size">1</property>
|
<property name="icon_size">1</property>
|
||||||
|
@ -88,7 +108,7 @@
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
|
|
||||||
<child internal-child="image">
|
<child internal-child="image">
|
||||||
<widget class="GtkImage" id="image1363">
|
<widget class="GtkImage" id="image1383">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="stock">gtk-add</property>
|
<property name="stock">gtk-add</property>
|
||||||
<property name="icon_size">1</property>
|
<property name="icon_size">1</property>
|
||||||
|
|
|
@ -1160,10 +1160,24 @@ class Connection(ConnectionHandlers):
|
||||||
self.connection.send(msg_iq)
|
self.connection.send(msg_iq)
|
||||||
|
|
||||||
def request_gc_config(self, room_jid):
|
def request_gc_config(self, room_jid):
|
||||||
|
if not self.connection:
|
||||||
|
return
|
||||||
iq = common.xmpp.Iq(typ = 'get', queryNS = common.xmpp.NS_MUC_OWNER,
|
iq = common.xmpp.Iq(typ = 'get', queryNS = common.xmpp.NS_MUC_OWNER,
|
||||||
to = room_jid)
|
to = room_jid)
|
||||||
self.connection.send(iq)
|
self.connection.send(iq)
|
||||||
|
|
||||||
|
def destroy_gc_room(self, room_jid, reason = '', jid = ''):
|
||||||
|
if not self.connection:
|
||||||
|
return
|
||||||
|
iq = common.xmpp.Iq(typ = 'set', queryNS = common.xmpp.NS_MUC_OWNER,
|
||||||
|
to = room_jid)
|
||||||
|
destroy = iq.getTag('query').setTag('destroy')
|
||||||
|
if reason:
|
||||||
|
destroy.setTagData('reason', reason)
|
||||||
|
if jid:
|
||||||
|
destroy.setAttr('jid', jid)
|
||||||
|
self.connection.send(iq)
|
||||||
|
|
||||||
def send_gc_status(self, nick, jid, show, status):
|
def send_gc_status(self, nick, jid, show, status):
|
||||||
if not self.connection:
|
if not self.connection:
|
||||||
return
|
return
|
||||||
|
|
|
@ -1547,6 +1547,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
||||||
timestamp = None
|
timestamp = None
|
||||||
is_gc = False # is it a GC presence ?
|
is_gc = False # is it a GC presence ?
|
||||||
sigTag = None
|
sigTag = None
|
||||||
|
ns_muc_user_x = None
|
||||||
avatar_sha = None
|
avatar_sha = None
|
||||||
# JEP-0172 User Nickname
|
# JEP-0172 User Nickname
|
||||||
user_nick = prs.getTagData('nick')
|
user_nick = prs.getTagData('nick')
|
||||||
|
@ -1558,16 +1559,18 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
||||||
namespace = x.getNamespace()
|
namespace = x.getNamespace()
|
||||||
if namespace.startswith(common.xmpp.NS_MUC):
|
if namespace.startswith(common.xmpp.NS_MUC):
|
||||||
is_gc = True
|
is_gc = True
|
||||||
if namespace == common.xmpp.NS_SIGNED:
|
if namespace == common.xmpp.NS_MUC_USER and x.getTag('destroy'):
|
||||||
|
ns_muc_user_x = x
|
||||||
|
elif namespace == common.xmpp.NS_SIGNED:
|
||||||
sigTag = x
|
sigTag = x
|
||||||
if namespace == common.xmpp.NS_VCARD_UPDATE:
|
elif namespace == common.xmpp.NS_VCARD_UPDATE:
|
||||||
avatar_sha = x.getTagData('photo')
|
avatar_sha = x.getTagData('photo')
|
||||||
if namespace == common.xmpp.NS_DELAY:
|
elif namespace == common.xmpp.NS_DELAY:
|
||||||
# JEP-0091
|
# JEP-0091
|
||||||
tim = prs.getTimestamp()
|
tim = prs.getTimestamp()
|
||||||
tim = time.strptime(tim, '%Y%m%dT%H:%M:%S')
|
tim = time.strptime(tim, '%Y%m%dT%H:%M:%S')
|
||||||
timestamp = time.localtime(timegm(tim))
|
timestamp = time.localtime(timegm(tim))
|
||||||
if namespace == 'http://delx.cjb.net/protocol/roster-subsync':
|
elif namespace == 'http://delx.cjb.net/protocol/roster-subsync':
|
||||||
# see http://trac.gajim.org/ticket/326
|
# see http://trac.gajim.org/ticket/326
|
||||||
agent = gajim.get_server_from_jid(jid_stripped)
|
agent = gajim.get_server_from_jid(jid_stripped)
|
||||||
if self.connection.getRoster().getItem(agent): # to be sure it's a transport contact
|
if self.connection.getRoster().getItem(agent): # to be sure it's a transport contact
|
||||||
|
@ -1667,10 +1670,24 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
||||||
else:
|
else:
|
||||||
# save sha in mem NOW
|
# save sha in mem NOW
|
||||||
self.vcard_shas[who] = avatar_sha
|
self.vcard_shas[who] = avatar_sha
|
||||||
|
if ns_muc_user_x:
|
||||||
|
# Room has been destroyed. see
|
||||||
|
# http://www.xmpp.org/extensions/xep-0045.html#destroyroom
|
||||||
|
reason = _('Room has been destroyed')
|
||||||
|
destroy = ns_muc_user_x.getTag('destroy')
|
||||||
|
r = destroy.getTagData('reason')
|
||||||
|
if r:
|
||||||
|
reason += ' (%s)' % r
|
||||||
|
jid = destroy.getAttr('jid')
|
||||||
|
if jid:
|
||||||
|
reason += '\n' + _('You can join this room instead: %s') % jid
|
||||||
|
statusCode = 'destroyed'
|
||||||
|
else:
|
||||||
|
reason = prs.getReason()
|
||||||
|
statusCode = prs.getStatusCode()
|
||||||
self.dispatch('GC_NOTIFY', (jid_stripped, show, status, resource,
|
self.dispatch('GC_NOTIFY', (jid_stripped, show, status, resource,
|
||||||
prs.getRole(), prs.getAffiliation(), prs.getJid(),
|
prs.getRole(), prs.getAffiliation(), prs.getJid(),
|
||||||
prs.getReason(), prs.getActor(), prs.getStatusCode(),
|
reason, prs.getActor(), statusCode, prs.getNewNick()))
|
||||||
prs.getNewNick()))
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if ptype == 'subscribe':
|
if ptype == 'subscribe':
|
||||||
|
|
|
@ -1049,6 +1049,62 @@ class InputDialog:
|
||||||
self.dialog.destroy()
|
self.dialog.destroy()
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
class DubbleInputDialog:
|
||||||
|
'''Class for Dubble Input dialog'''
|
||||||
|
def __init__(self, title, label_str1, label_str2, input_str1 = None,
|
||||||
|
input_str2 = None, is_modal = True, ok_handler = None,
|
||||||
|
cancel_handler = None):
|
||||||
|
# if modal is True you also need to call get_response()
|
||||||
|
# and ok_handler won't be used
|
||||||
|
self.xml = gtkgui_helpers.get_glade('dubbleinput_dialog.glade')
|
||||||
|
self.dialog = self.xml.get_widget('dubbleinput_dialog')
|
||||||
|
label1 = self.xml.get_widget('label1')
|
||||||
|
self.input_entry1 = self.xml.get_widget('input_entry1')
|
||||||
|
label2 = self.xml.get_widget('label2')
|
||||||
|
self.input_entry2 = self.xml.get_widget('input_entry2')
|
||||||
|
self.dialog.set_title(title)
|
||||||
|
label1.set_markup(label_str1)
|
||||||
|
label2.set_markup(label_str2)
|
||||||
|
self.cancel_handler = cancel_handler
|
||||||
|
if input_str1:
|
||||||
|
self.input_entry1.set_text(input_str1)
|
||||||
|
self.input_entry1.select_region(0, -1) # select all
|
||||||
|
if input_str2:
|
||||||
|
self.input_entry2.set_text(input_str2)
|
||||||
|
self.input_entry2.select_region(0, -1) # select all
|
||||||
|
|
||||||
|
self.is_modal = is_modal
|
||||||
|
if not is_modal and ok_handler is not None:
|
||||||
|
self.ok_handler = ok_handler
|
||||||
|
okbutton = self.xml.get_widget('okbutton')
|
||||||
|
okbutton.connect('clicked', self.on_okbutton_clicked)
|
||||||
|
cancelbutton = self.xml.get_widget('cancelbutton')
|
||||||
|
cancelbutton.connect('clicked', self.on_cancelbutton_clicked)
|
||||||
|
self.xml.signal_autoconnect(self)
|
||||||
|
self.dialog.show_all()
|
||||||
|
|
||||||
|
def on_dubbleinput_dialog_destroy(self, widget):
|
||||||
|
if self.cancel_handler:
|
||||||
|
self.cancel_handler()
|
||||||
|
|
||||||
|
def on_okbutton_clicked(self, widget):
|
||||||
|
user_input1 = self.input_entry1.get_text().decode('utf-8')
|
||||||
|
user_input2 = self.input_entry2.get_text().decode('utf-8')
|
||||||
|
self.dialog.destroy()
|
||||||
|
if isinstance(self.ok_handler, tuple):
|
||||||
|
self.ok_handler[0](user_input1, user_input2, *self.ok_handler[1:])
|
||||||
|
else:
|
||||||
|
self.ok_handler(user_input1, user_input2)
|
||||||
|
|
||||||
|
def on_cancelbutton_clicked(self, widget):
|
||||||
|
self.dialog.destroy()
|
||||||
|
|
||||||
|
def get_response(self):
|
||||||
|
if self.is_modal:
|
||||||
|
response = self.dialog.run()
|
||||||
|
self.dialog.destroy()
|
||||||
|
return response
|
||||||
|
|
||||||
class SubscriptionRequestWindow:
|
class SubscriptionRequestWindow:
|
||||||
def __init__(self, jid, text, account, user_nick = None):
|
def __init__(self, jid, text, account, user_nick = None):
|
||||||
xml = gtkgui_helpers.get_glade('subscription_request_window.glade')
|
xml = gtkgui_helpers.get_glade('subscription_request_window.glade')
|
||||||
|
|
|
@ -222,6 +222,11 @@ class GroupchatControl(ChatControlBase):
|
||||||
self._on_configure_room_menuitem_activate)
|
self._on_configure_room_menuitem_activate)
|
||||||
self.handlers[id] = widget
|
self.handlers[id] = widget
|
||||||
|
|
||||||
|
widget = xm.get_widget('destroy_room_menuitem')
|
||||||
|
id = widget.connect('activate',
|
||||||
|
self._on_destroy_room_menuitem_activate)
|
||||||
|
self.handlers[id] = widget
|
||||||
|
|
||||||
widget = xm.get_widget('change_subject_menuitem')
|
widget = xm.get_widget('change_subject_menuitem')
|
||||||
id = widget.connect('activate',
|
id = widget.connect('activate',
|
||||||
self._on_change_subject_menuitem_activate)
|
self._on_change_subject_menuitem_activate)
|
||||||
|
@ -472,18 +477,21 @@ class GroupchatControl(ChatControlBase):
|
||||||
sets sensitivity state for configure_room'''
|
sets sensitivity state for configure_room'''
|
||||||
menu = self.gc_popup_menu
|
menu = self.gc_popup_menu
|
||||||
childs = menu.get_children()
|
childs = menu.get_children()
|
||||||
# hide chat buttons
|
# Check compact view menuitem
|
||||||
childs[5].set_active(self.hide_chat_buttons_current)
|
childs[6].set_active(self.hide_chat_buttons_current)
|
||||||
if gajim.gc_connected[self.account][self.room_jid]:
|
if gajim.gc_connected[self.account][self.room_jid]:
|
||||||
c = gajim.contacts.get_gc_contact(self.account, self.room_jid,
|
c = gajim.contacts.get_gc_contact(self.account, self.room_jid,
|
||||||
self.nick)
|
self.nick)
|
||||||
if c.affiliation not in ('owner', 'admin'):
|
if c.affiliation not in ('owner', 'admin'):
|
||||||
childs[1].set_sensitive(False)
|
childs[1].set_sensitive(False)
|
||||||
|
if c.affiliation != 'owner':
|
||||||
|
childs[2].set_sensitive(False)
|
||||||
else:
|
else:
|
||||||
# We are not connected to this groupchat, disable unusable menuitems
|
# We are not connected to this groupchat, disable unusable menuitems
|
||||||
childs[1].set_sensitive(False)
|
childs[1].set_sensitive(False)
|
||||||
childs[2].set_sensitive(False)
|
childs[2].set_sensitive(False)
|
||||||
childs[3].set_sensitive(False)
|
childs[3].set_sensitive(False)
|
||||||
|
childs[4].set_sensitive(False)
|
||||||
return menu
|
return menu
|
||||||
|
|
||||||
def on_message(self, nick, msg, tim, has_timestamp = False, xhtml = None):
|
def on_message(self, nick, msg, tim, has_timestamp = False, xhtml = None):
|
||||||
|
@ -888,6 +896,8 @@ class GroupchatControl(ChatControlBase):
|
||||||
os.remove(files[old_file])
|
os.remove(files[old_file])
|
||||||
os.rename(old_file, files[old_file])
|
os.rename(old_file, files[old_file])
|
||||||
self.print_conversation(s, 'info')
|
self.print_conversation(s, 'info')
|
||||||
|
elif statusCode == 'destroyed': # Room has been destroyed
|
||||||
|
self.print_conversation(reason, 'info')
|
||||||
|
|
||||||
if len(gajim.events.get_events(self.account,
|
if len(gajim.events.get_events(self.account,
|
||||||
self.room_jid + '/' + nick)) == 0:
|
self.room_jid + '/' + nick)) == 0:
|
||||||
|
@ -1442,6 +1452,29 @@ class GroupchatControl(ChatControlBase):
|
||||||
gajim.interface.instances[self.account]['gc_config'][self.room_jid]\
|
gajim.interface.instances[self.account]['gc_config'][self.room_jid]\
|
||||||
= config.GroupchatConfigWindow(self.account, self.room_jid)
|
= config.GroupchatConfigWindow(self.account, self.room_jid)
|
||||||
|
|
||||||
|
def _on_destroy_room_menuitem_activate(self, widget):
|
||||||
|
# Ask for a reason
|
||||||
|
instance = dialogs.DubbleInputDialog(_('Destroying %s') % self.room_jid,
|
||||||
|
_('You are going to definitively destroy this room.\n'
|
||||||
|
'You may specify a reason below:'),
|
||||||
|
_('You may also enter an alternate venue:'))
|
||||||
|
response = instance.get_response()
|
||||||
|
if response == gtk.RESPONSE_OK:
|
||||||
|
reason = instance.input_entry1.get_text().decode('utf-8')
|
||||||
|
jid = instance.input_entry2.get_text().decode('utf-8')
|
||||||
|
# Test jid
|
||||||
|
try:
|
||||||
|
jid = helpers.parse_jid(jid)
|
||||||
|
except:
|
||||||
|
ErrorDialog(_('Invalid group chat Jabber ID'),
|
||||||
|
_('The group chat Jabber ID has not allowed characters.'))
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
# Abord destroy operation
|
||||||
|
return
|
||||||
|
gajim.connections[self.account].destroy_gc_room(self.room_jid, reason,
|
||||||
|
jid)
|
||||||
|
|
||||||
def _on_bookmark_room_menuitem_activate(self, widget):
|
def _on_bookmark_room_menuitem_activate(self, widget):
|
||||||
bm = {
|
bm = {
|
||||||
'name': self.name,
|
'name': self.name,
|
||||||
|
|
Loading…
Add table
Reference in a new issue