[httpupload] Refactor HttpUploadPlugin Class
- There is no need for discovery code, Gajim does this already - Generate only one Base instance per account - Use less global vars and simplify code
This commit is contained in:
@@ -28,14 +28,11 @@ import binascii
|
|||||||
|
|
||||||
from common import gajim
|
from common import gajim
|
||||||
from common import ged
|
from common import ged
|
||||||
import chat_control
|
|
||||||
from plugins import GajimPlugin
|
from plugins import GajimPlugin
|
||||||
from plugins.helpers import log_calls
|
from plugins.helpers import log_calls
|
||||||
from dialogs import FileChooserDialog, ImageChooserDialog, ErrorDialog
|
from dialogs import FileChooserDialog, ErrorDialog
|
||||||
import nbxmpp
|
import nbxmpp
|
||||||
|
|
||||||
from .thumbnail import thumbnail
|
|
||||||
|
|
||||||
log = logging.getLogger('gajim.plugin_system.httpupload')
|
log = logging.getLogger('gajim.plugin_system.httpupload')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -55,165 +52,119 @@ except Exception as e:
|
|||||||
encryption_available = False
|
encryption_available = False
|
||||||
|
|
||||||
# XEP-0363 (http://xmpp.org/extensions/xep-0363.html)
|
# XEP-0363 (http://xmpp.org/extensions/xep-0363.html)
|
||||||
|
IQ_CALLBACK = {}
|
||||||
NS_HTTPUPLOAD = 'urn:xmpp:http:upload'
|
NS_HTTPUPLOAD = 'urn:xmpp:http:upload'
|
||||||
TAGSIZE = 16
|
TAGSIZE = 16
|
||||||
|
|
||||||
jid_to_servers = {}
|
|
||||||
iq_ids_to_callbacks = {}
|
|
||||||
last_info_query = {}
|
|
||||||
|
|
||||||
|
|
||||||
class HttpuploadPlugin(GajimPlugin):
|
class HttpuploadPlugin(GajimPlugin):
|
||||||
|
|
||||||
@log_calls('HttpuploadPlugin')
|
|
||||||
def init(self):
|
def init(self):
|
||||||
if not encryption_available:
|
if not encryption_available:
|
||||||
self.available_text = DEP_MSG
|
self.available_text = DEP_MSG
|
||||||
self.config_dialog = None # HttpuploadPluginConfigDialog(self)
|
self.config_dialog = None # HttpuploadPluginConfigDialog(self)
|
||||||
self.controls = []
|
|
||||||
self.events_handlers = {}
|
self.events_handlers = {}
|
||||||
self.events_handlers['agent-info-received'] = (ged.PRECORE,
|
self.events_handlers['agent-info-received'] = (
|
||||||
self.handle_agent_info_received)
|
ged.PRECORE, self.handle_agent_info_received)
|
||||||
self.events_handlers['raw-iq-received'] = (ged.PRECORE,
|
self.events_handlers['raw-iq-received'] = (
|
||||||
self.handle_iq_received)
|
ged.PRECORE, self.handle_iq_received)
|
||||||
self.gui_extension_points = {
|
self.gui_extension_points = {
|
||||||
'chat_control_base': (self.connect_with_chat_control,
|
'chat_control_base': (self.connect_with_chat_control,
|
||||||
self.disconnect_from_chat_control),
|
self.disconnect_from_chat_control),
|
||||||
'chat_control_base_update_toolbar': (self.update_button_state,
|
'chat_control_base_update_toolbar': (self.update_chat_control,
|
||||||
None)}
|
None)}
|
||||||
self.first_run = True
|
self.gui_interfaces = {}
|
||||||
|
|
||||||
def handle_iq_received(self, event):
|
@staticmethod
|
||||||
global iq_ids_to_callbacks
|
def handle_iq_received(event):
|
||||||
id_ = event.stanza.getAttr("id")
|
id_ = event.stanza.getAttr("id")
|
||||||
if str(id_) in iq_ids_to_callbacks:
|
if id_ in IQ_CALLBACK:
|
||||||
try:
|
try:
|
||||||
iq_ids_to_callbacks[str(id_)](event.stanza)
|
IQ_CALLBACK[id_](event.stanza)
|
||||||
except:
|
except:
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
del iq_ids_to_callbacks[str(id_)]
|
del IQ_CALLBACK[id_]
|
||||||
|
|
||||||
def handle_agent_info_received(self, event):
|
def handle_agent_info_received(self, event):
|
||||||
global jid_to_servers
|
if (NS_HTTPUPLOAD in event.features and
|
||||||
if NS_HTTPUPLOAD in event.features and gajim.jid_is_transport(event.jid):
|
gajim.jid_is_transport(event.jid)):
|
||||||
own_jid = gajim.get_jid_without_resource(str(event.stanza.getTo()))
|
account = event.conn.name
|
||||||
jid_to_servers[own_jid] = event.jid # map own jid to upload component's jid
|
interface = self.get_interface(account)
|
||||||
log.info(own_jid + " can do http uploads via component " + event.jid)
|
interface.enabled = True
|
||||||
# update all buttons
|
interface.component = event.jid
|
||||||
for base in self.controls:
|
interface.update_button_states(True)
|
||||||
self.update_button_state(base.chat_control)
|
|
||||||
|
|
||||||
@log_calls('HttpuploadPlugin')
|
def connect_with_chat_control(self, chat_control):
|
||||||
def connect_with_chat_control(self, control):
|
account = chat_control.contact.account.name
|
||||||
self.chat_control = control
|
self.get_interface(account).add_button(chat_control)
|
||||||
base = Base(self, self.chat_control)
|
|
||||||
self.controls.append(base)
|
|
||||||
if self.first_run:
|
|
||||||
# TODO: Potentially add back keyboard shortcut
|
|
||||||
self.first_run = False
|
|
||||||
self.update_button_state(self.chat_control)
|
|
||||||
|
|
||||||
@log_calls('HttpuploadPlugin')
|
|
||||||
def disconnect_from_chat_control(self, chat_control):
|
def disconnect_from_chat_control(self, chat_control):
|
||||||
for control in self.controls:
|
jid = chat_control.contact.jid
|
||||||
control.disconnect_from_chat_control()
|
account = chat_control.account
|
||||||
self.controls = []
|
interface = self.get_interface(account)
|
||||||
|
if jid not in interface.controls:
|
||||||
|
return
|
||||||
|
actions_hbox = chat_control.xml.get_object('actions_hbox')
|
||||||
|
actions_hbox.remove(interface.controls[jid])
|
||||||
|
|
||||||
@log_calls('HttpuploadPlugin')
|
def update_chat_control(self, chat_control):
|
||||||
def update_button_state(self, chat_control):
|
account = chat_control.account
|
||||||
global jid_to_servers
|
if gajim.connections[account].connection is None:
|
||||||
global iq_ids_to_callbacks
|
self.get_interface(account).update_button_states(False)
|
||||||
global last_info_query
|
|
||||||
|
|
||||||
if gajim.connections[chat_control.account].connection == None and \
|
def get_interface(self, account):
|
||||||
gajim.get_jid_from_account(chat_control.account) in jid_to_servers:
|
try:
|
||||||
# maybe don't delete this and detect vanished upload components when actually trying to upload something
|
return self.gui_interfaces[account]
|
||||||
log.info("Deleting %s from jid_to_servers (disconnected)" % gajim.get_jid_from_account(chat_control.account))
|
except KeyError:
|
||||||
del jid_to_servers[gajim.get_jid_from_account(chat_control.account)]
|
self.gui_interfaces[account] = Base(self)
|
||||||
|
return self.gui_interfaces[account]
|
||||||
# query info at most every 60 seconds in case something goes wrong
|
|
||||||
if ((not chat_control.account in last_info_query or
|
|
||||||
last_info_query[chat_control.account] + 60 < time.time())
|
|
||||||
and not gajim.get_jid_from_account(chat_control.account) in jid_to_servers
|
|
||||||
and gajim.account_is_connected(chat_control.account)
|
|
||||||
):
|
|
||||||
log.info("Account %s: Using dicovery to find jid of httpupload component" % chat_control.account)
|
|
||||||
id_ = gajim.get_an_id()
|
|
||||||
iq = nbxmpp.Iq(
|
|
||||||
typ='get',
|
|
||||||
to=gajim.get_server_from_jid(gajim.get_jid_from_account(chat_control.account)),
|
|
||||||
queryNS="http://jabber.org/protocol/disco#items"
|
|
||||||
)
|
|
||||||
iq.setID(id_)
|
|
||||||
def query_info(stanza):
|
|
||||||
global last_info_query
|
|
||||||
for item in stanza.getTag("query").getTags("item"):
|
|
||||||
id_ = gajim.get_an_id()
|
|
||||||
iq = nbxmpp.Iq(
|
|
||||||
typ='get',
|
|
||||||
to=item.getAttr("jid"),
|
|
||||||
queryNS="http://jabber.org/protocol/disco#info"
|
|
||||||
)
|
|
||||||
iq.setID(id_)
|
|
||||||
last_info_query[chat_control.account] = time.time()
|
|
||||||
gajim.connections[chat_control.account].connection.send(iq)
|
|
||||||
iq_ids_to_callbacks[str(id_)] = query_info
|
|
||||||
gajim.connections[chat_control.account].connection.send(iq)
|
|
||||||
#send disco query to main server jid
|
|
||||||
id_ = gajim.get_an_id()
|
|
||||||
iq = nbxmpp.Iq(
|
|
||||||
typ='get',
|
|
||||||
to=gajim.get_server_from_jid(gajim.get_jid_from_account(chat_control.account)),
|
|
||||||
queryNS="http://jabber.org/protocol/disco#info"
|
|
||||||
)
|
|
||||||
iq.setID(id_)
|
|
||||||
last_info_query[chat_control.account] = time.time()
|
|
||||||
gajim.connections[chat_control.account].connection.send(iq)
|
|
||||||
|
|
||||||
for base in self.controls:
|
|
||||||
if base.chat_control == chat_control:
|
|
||||||
is_supported = gajim.get_jid_from_account(chat_control.account) in jid_to_servers and \
|
|
||||||
gajim.connections[chat_control.account].connection != None
|
|
||||||
log.info("Account %s: httpupload is_supported: %s" % (str(chat_control.account), str(is_supported)))
|
|
||||||
if not is_supported:
|
|
||||||
text = _('Your server does not support http uploads')
|
|
||||||
else:
|
|
||||||
text = _('Send file via http upload')
|
|
||||||
base.button.set_sensitive(is_supported)
|
|
||||||
base.button.set_tooltip_text(text)
|
|
||||||
|
|
||||||
|
|
||||||
class Base(object):
|
class Base(object):
|
||||||
def __init__(self, plugin, chat_control):
|
def __init__(self, plugin):
|
||||||
self.dlg = None
|
self.dlg = None
|
||||||
self.dialog_type = 'file'
|
self.dialog_type = 'file'
|
||||||
self.plugin = plugin
|
self.plugin = plugin
|
||||||
self.encrypted_upload = False
|
self.encrypted_upload = False
|
||||||
self.chat_control = chat_control
|
self.enabled = False
|
||||||
actions_hbox = chat_control.xml.get_object('actions_hbox')
|
self.component = None
|
||||||
self.button = Gtk.Button(label=None, stock=None, use_underline=True)
|
self.controls = {}
|
||||||
self.button.set_property('can-focus', False)
|
|
||||||
self.button.set_sensitive(False)
|
def add_button(self, chat_control):
|
||||||
|
jid = chat_control.contact.jid
|
||||||
|
|
||||||
img = Gtk.Image()
|
img = Gtk.Image()
|
||||||
img.set_from_file(self.plugin.local_file_path('httpupload.png'))
|
img.set_from_file(self.plugin.local_file_path('httpupload.png'))
|
||||||
self.button.set_image(img)
|
actions_hbox = chat_control.xml.get_object('actions_hbox')
|
||||||
self.button.set_tooltip_text(_('Your server does not support http uploads'))
|
button = Gtk.Button(label=None, stock=None, use_underline=True)
|
||||||
self.button.set_relief(Gtk.ReliefStyle.NONE)
|
button.set_property('can-focus', False)
|
||||||
|
button.set_image(img)
|
||||||
|
button.set_relief(Gtk.ReliefStyle.NONE)
|
||||||
|
|
||||||
|
actions_hbox.add(button)
|
||||||
send_button = chat_control.xml.get_object('send_button')
|
send_button = chat_control.xml.get_object('send_button')
|
||||||
actions_hbox.add(self.button)
|
button_pos = actions_hbox.child_get_property(send_button, 'position')
|
||||||
send_button_pos = actions_hbox.child_get_property(send_button, 'position')
|
actions_hbox.child_set_property(button, 'position', button_pos - 1)
|
||||||
actions_hbox.child_set_property(self.button, 'position', send_button_pos - 1)
|
|
||||||
|
|
||||||
file_id = self.button.connect('clicked', self.on_file_button_clicked)
|
self.controls[jid] = button
|
||||||
chat_control.handlers[file_id] = self.button
|
id_ = button.connect('clicked', self.on_file_button_clicked, jid, chat_control)
|
||||||
self.button.show()
|
chat_control.handlers[id_] = button
|
||||||
|
self.set_button_state(self.enabled, button)
|
||||||
|
button.show()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def set_button_state(state, button):
|
||||||
|
if state:
|
||||||
|
button.set_sensitive(state)
|
||||||
|
button.set_tooltip_text(_('Send file via http upload'))
|
||||||
|
else:
|
||||||
|
button.set_sensitive(state)
|
||||||
|
button.set_tooltip_text(
|
||||||
|
_('Your server does not support http uploads'))
|
||||||
|
|
||||||
def disconnect_from_chat_control(self):
|
def update_button_states(self, state):
|
||||||
actions_hbox = self.chat_control.xml.get_object('actions_hbox')
|
for jid in self.controls:
|
||||||
actions_hbox.remove(self.button)
|
self.set_button_state(state, self.controls[jid])
|
||||||
|
|
||||||
def encryption_activated(self):
|
def encryption_activated(self):
|
||||||
if not encryption_available:
|
if not encryption_available:
|
||||||
@@ -420,7 +371,7 @@ class Base(object):
|
|||||||
|
|
||||||
self.chat_control.msg_textview.grab_focus()
|
self.chat_control.msg_textview.grab_focus()
|
||||||
|
|
||||||
def on_file_button_clicked(self, widget):
|
def on_file_button_clicked(self, widget, jid, chat_control):
|
||||||
self.dialog_type = 'file'
|
self.dialog_type = 'file'
|
||||||
self.dlg = FileChooserDialog(on_response_ok=self.on_file_dialog_ok, on_response_cancel=None,
|
self.dlg = FileChooserDialog(on_response_ok=self.on_file_dialog_ok, on_response_cancel=None,
|
||||||
title_text = _('Choose file to send'), action = Gtk.FileChooserAction.OPEN,
|
title_text = _('Choose file to send'), action = Gtk.FileChooserAction.OPEN,
|
||||||
|
|||||||
Reference in New Issue
Block a user