Merge branch 'gtk3' into 'gtk3'
Limit image preview to https and httpupload See merge request gajim/gajim-plugins!47
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
[info]
|
[info]
|
||||||
name: Url image preview
|
name: Url image preview
|
||||||
short_name: url_image_preview
|
short_name: url_image_preview
|
||||||
version: 0.5.6
|
version: 2.0.1
|
||||||
description: Displays a preview of links to images
|
description: Displays a preview of links to images
|
||||||
authors = Denis Fomin <fominde@gmail.com>
|
authors = Denis Fomin <fominde@gmail.com>
|
||||||
Yann Leboulanger <asterix@lagaule.org>
|
Yann Leboulanger <asterix@lagaule.org>
|
||||||
|
|||||||
@@ -15,30 +15,28 @@
|
|||||||
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
##
|
##
|
||||||
|
|
||||||
from gi.repository import Gtk, Gdk, GLib, GObject, GdkPixbuf, Gio
|
|
||||||
import os
|
import os
|
||||||
import hashlib
|
import hashlib
|
||||||
import binascii
|
import binascii
|
||||||
|
import logging
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
import shutil
|
import shutil
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
import logging
|
from gi.repository import Gtk, Gdk, GLib, GdkPixbuf
|
||||||
import nbxmpp
|
|
||||||
from gajim.common import app
|
from gajim.common import app
|
||||||
from gajim.common import ged
|
|
||||||
from gajim.common import helpers
|
from gajim.common import helpers
|
||||||
from gajim.common import configpaths
|
from gajim.common import configpaths
|
||||||
from gajim import dialogs
|
from gajim import dialogs
|
||||||
from gajim.plugins import GajimPlugin
|
from gajim.plugins import GajimPlugin
|
||||||
from gajim.plugins.helpers import log_calls
|
from gajim.plugins.helpers import log_calls
|
||||||
from gajim.plugins.gui import GajimPluginConfigDialog
|
|
||||||
from gajim.conversation_textview import TextViewImage
|
from gajim.conversation_textview import TextViewImage
|
||||||
from .http_functions import get_http_head, get_http_file
|
from url_image_preview.http_functions import get_http_head, get_http_file
|
||||||
from .config_dialog import UrlImagePreviewConfigDialog
|
from url_image_preview.config_dialog import UrlImagePreviewConfigDialog
|
||||||
|
|
||||||
log = logging.getLogger('gajim.plugin_system.url_image_preview')
|
log = logging.getLogger('gajim.plugin_system.preview')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
@@ -54,10 +52,10 @@ try:
|
|||||||
from cryptography.hazmat.primitives.ciphers import algorithms
|
from cryptography.hazmat.primitives.ciphers import algorithms
|
||||||
from cryptography.hazmat.primitives.ciphers.modes import GCM
|
from cryptography.hazmat.primitives.ciphers.modes import GCM
|
||||||
decryption_available = True
|
decryption_available = True
|
||||||
except Exception as e:
|
except Exception:
|
||||||
DEP_MSG = 'For preview of encrypted images, ' \
|
DEP_MSG = 'For preview of encrypted images, ' \
|
||||||
'please install python-cryptography!'
|
'please install python-cryptography!'
|
||||||
log.debug('Cryptography Import Error: ' + str(e))
|
log.exception('Error')
|
||||||
log.info('Decryption/Encryption disabled due to errors')
|
log.info('Decryption/Encryption disabled due to errors')
|
||||||
decryption_available = False
|
decryption_available = False
|
||||||
|
|
||||||
@@ -71,32 +69,19 @@ class UrlImagePreviewPlugin(GajimPlugin):
|
|||||||
if not decryption_available:
|
if not decryption_available:
|
||||||
self.available_text = DEP_MSG
|
self.available_text = DEP_MSG
|
||||||
self.config_dialog = partial(UrlImagePreviewConfigDialog, self)
|
self.config_dialog = partial(UrlImagePreviewConfigDialog, self)
|
||||||
self.events_handlers = {}
|
|
||||||
self.events_handlers['message-received'] = (
|
|
||||||
ged.PRECORE, self.handle_message_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),
|
||||||
'print_special_text': (self.print_special_text, None), }
|
'history_window':
|
||||||
|
(self.connect_with_history, self.disconnect_from_history),
|
||||||
|
'print_real_text': (self.print_real_text, None), }
|
||||||
self.config_default_values = {
|
self.config_default_values = {
|
||||||
'PREVIEW_SIZE': (150, 'Preview size(10-512)'),
|
'PREVIEW_SIZE': (150, 'Preview size(10-512)'),
|
||||||
'MAX_FILE_SIZE': (524288, 'Max file size for image preview'),
|
'MAX_FILE_SIZE': (524288, 'Max file size for image preview'),
|
||||||
'LEFTCLICK_ACTION': ('open_menuitem', 'Open')}
|
'LEFTCLICK_ACTION': ('open_menuitem', 'Open'),
|
||||||
|
'ANONYMOUS_MUC': False,}
|
||||||
self.controls = {}
|
self.controls = {}
|
||||||
|
self.history_window_control = None
|
||||||
# remove oob tag if oob url == message text
|
|
||||||
def handle_message_received(self, event):
|
|
||||||
oob_node = event.stanza.getTag('x', namespace=nbxmpp.NS_X_OOB)
|
|
||||||
oob_url = None
|
|
||||||
oob_desc = None
|
|
||||||
if oob_node:
|
|
||||||
oob_url = oob_node.getTagData('url')
|
|
||||||
oob_desc = oob_node.getTagData('desc')
|
|
||||||
if oob_url and oob_url == event.msgtxt and \
|
|
||||||
(not oob_desc or oob_desc == ""):
|
|
||||||
log.debug("Detected oob tag containing same"
|
|
||||||
"url as the message text, deleting oob tag...")
|
|
||||||
event.stanza.delChild(oob_node)
|
|
||||||
|
|
||||||
@log_calls('UrlImagePreviewPlugin')
|
@log_calls('UrlImagePreviewPlugin')
|
||||||
def connect_with_chat_control(self, chat_control):
|
def connect_with_chat_control(self, chat_control):
|
||||||
@@ -104,32 +89,51 @@ class UrlImagePreviewPlugin(GajimPlugin):
|
|||||||
jid = chat_control.contact.jid
|
jid = chat_control.contact.jid
|
||||||
if account not in self.controls:
|
if account not in self.controls:
|
||||||
self.controls[account] = {}
|
self.controls[account] = {}
|
||||||
self.controls[account][jid] = Base(self, chat_control)
|
self.controls[account][jid] = Base(self, chat_control.conv_textview,
|
||||||
|
chat_control.parent_win.window)
|
||||||
|
|
||||||
@log_calls('UrlImagePreviewPlugin')
|
@log_calls('UrlImagePreviewPlugin')
|
||||||
def disconnect_from_chat_control(self, chat_control):
|
def disconnect_from_chat_control(self, chat_control):
|
||||||
account = chat_control.contact.account.name
|
account = chat_control.contact.account.name
|
||||||
jid = chat_control.contact.jid
|
jid = chat_control.contact.jid
|
||||||
self.controls[account][jid].deinit()
|
self.controls[account][jid].deinit_handlers()
|
||||||
del self.controls[account][jid]
|
del self.controls[account][jid]
|
||||||
|
|
||||||
def print_special_text(self, tv, special_text, other_tags, graphics=True,
|
@log_calls('UrlImagePreviewPlugin')
|
||||||
additional_data=None, iter_=None):
|
def connect_with_history(self, history_window):
|
||||||
|
if self.history_window_control:
|
||||||
|
log.error("connect_with_history: deinit handlers")
|
||||||
|
self.history_window_control.deinit_handlers()
|
||||||
|
log.error("connect_with_history: create base")
|
||||||
|
self.history_window_control = Base(
|
||||||
|
self, history_window.history_textview, history_window)
|
||||||
|
|
||||||
|
@log_calls('UrlImagePreviewPlugin')
|
||||||
|
def disconnect_from_history(self, history_window):
|
||||||
|
if self.history_window_control:
|
||||||
|
self.history_window_control.deinit_handlers()
|
||||||
|
self.history_window_control = None
|
||||||
|
|
||||||
|
def print_real_text(self, tv, real_text, text_tags, graphics,
|
||||||
|
iter_, additional_data):
|
||||||
|
if tv.used_in_history_window and self.history_window_control:
|
||||||
|
self.history_window_control.print_real_text(
|
||||||
|
real_text, text_tags, graphics, iter_, additional_data)
|
||||||
|
|
||||||
account = tv.account
|
account = tv.account
|
||||||
for jid in self.controls[account]:
|
for jid in self.controls[account]:
|
||||||
if self.controls[account][jid].chat_control.conv_textview != tv:
|
if self.controls[account][jid].textview != tv:
|
||||||
continue
|
continue
|
||||||
self.controls[account][jid].print_special_text(
|
self.controls[account][jid].print_real_text(
|
||||||
special_text, other_tags, graphics=graphics,
|
real_text, text_tags, graphics, iter_, additional_data)
|
||||||
additional_data=additional_data, iter_=iter_)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
class Base(object):
|
class Base(object):
|
||||||
def __init__(self, plugin, chat_control):
|
def __init__(self, plugin, textview, parent_win=None):
|
||||||
self.plugin = plugin
|
self.plugin = plugin
|
||||||
self.chat_control = chat_control
|
self.parent_win = parent_win
|
||||||
self.textview = self.chat_control.conv_textview
|
self.textview = textview
|
||||||
self.handlers = {}
|
self.handlers = {}
|
||||||
|
|
||||||
self.directory = os.path.join(configpaths.gajimpaths['MY_DATA'],
|
self.directory = os.path.join(configpaths.gajimpaths['MY_DATA'],
|
||||||
@@ -140,11 +144,11 @@ class Base(object):
|
|||||||
try:
|
try:
|
||||||
self._create_path(self.directory)
|
self._create_path(self.directory)
|
||||||
self._create_path(self.thumbpath)
|
self._create_path(self.thumbpath)
|
||||||
except Exception as e:
|
except Exception:
|
||||||
log.error("Error creating download and/or thumbnail folder!")
|
log.error("Error creating download and/or thumbnail folder!")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def deinit(self):
|
def deinit_handlers(self):
|
||||||
# remove all register handlers on wigets, created by self.xml
|
# remove all register handlers on wigets, created by self.xml
|
||||||
# to prevent circular references among objects
|
# to prevent circular references among objects
|
||||||
for i in list(self.handlers.keys()):
|
for i in list(self.handlers.keys()):
|
||||||
@@ -152,20 +156,26 @@ class Base(object):
|
|||||||
self.handlers[i].disconnect(i)
|
self.handlers[i].disconnect(i)
|
||||||
del self.handlers[i]
|
del self.handlers[i]
|
||||||
|
|
||||||
def print_special_text(self, special_text, other_tags, graphics=True,
|
def print_real_text(self, real_text, text_tags, graphics, iter_,
|
||||||
additional_data=None, iter_=None):
|
additional_data):
|
||||||
# remove qip bbcode
|
urlparts = urlparse(real_text)
|
||||||
special_text = special_text.rsplit('[/img]')[0]
|
if (urlparts.scheme not in ["https", "aesgcm"] or
|
||||||
|
not urlparts.netloc):
|
||||||
|
log.info("Not accepting URL scheme '%s' for image preview: %s",
|
||||||
|
urlparts.scheme, real_text)
|
||||||
|
return
|
||||||
|
|
||||||
if special_text.startswith('www.'):
|
try:
|
||||||
special_text = 'http://' + special_text
|
oob_url = additional_data["gajim"]["oob_url"]
|
||||||
if special_text.startswith('ftp.'):
|
except (KeyError, AttributeError):
|
||||||
special_text = 'ftp://' + special_text
|
oob_url = None
|
||||||
|
|
||||||
urlparts = urlparse(special_text)
|
# allow aesgcm uris without oob marker (aesgcm uris are always
|
||||||
if urlparts.scheme not in ["https", "http", "ftp", "ftps", 'aesgcm'] or \
|
# httpupload filetransfers)
|
||||||
not urlparts.netloc:
|
if urlparts.scheme != "aesgcm" and real_text != oob_url:
|
||||||
log.info("Not accepting URL for image preview: %s" % special_text)
|
log.info("Not accepting URL for image preview "
|
||||||
|
"(wrong or no oob data): %s", real_text)
|
||||||
|
log.debug("additional_data: %s", additional_data)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Don't print the URL in the message window (in the calling function)
|
# Don't print the URL in the message window (in the calling function)
|
||||||
@@ -178,14 +188,14 @@ class Base(object):
|
|||||||
# Show URL, until image is loaded (if ever)
|
# Show URL, until image is loaded (if ever)
|
||||||
ttt = buffer_.get_tag_table()
|
ttt = buffer_.get_tag_table()
|
||||||
repl_start = buffer_.create_mark(None, iter_, True)
|
repl_start = buffer_.create_mark(None, iter_, True)
|
||||||
buffer_.insert_with_tags(iter_, special_text,
|
buffer_.insert_with_tags(iter_, real_text,
|
||||||
*[(ttt.lookup(t) if isinstance(t, str) else t) for t in ["url"]])
|
*[(ttt.lookup(t) if isinstance(t, str) else t) for t in ["url"]])
|
||||||
repl_end = buffer_.create_mark(None, iter_, True)
|
repl_end = buffer_.create_mark(None, iter_, True)
|
||||||
|
|
||||||
filename = os.path.basename(urlparts.path)
|
filename = os.path.basename(urlparts.path)
|
||||||
ext = os.path.splitext(filename)[1]
|
ext = os.path.splitext(filename)[1]
|
||||||
name = os.path.splitext(filename)[0]
|
name = os.path.splitext(filename)[0]
|
||||||
namehash = hashlib.sha1(special_text.encode('utf-8')).hexdigest()
|
namehash = hashlib.sha1(real_text.encode('utf-8')).hexdigest()
|
||||||
newfilename = name + '_' + namehash + ext
|
newfilename = name + '_' + namehash + ext
|
||||||
thumbfilename = name + '_' + namehash + '_thumb_' \
|
thumbfilename = name + '_' + namehash + '_thumb_' \
|
||||||
+ str(self.plugin.config['PREVIEW_SIZE']) + ext
|
+ str(self.plugin.config['PREVIEW_SIZE']) + ext
|
||||||
@@ -208,15 +218,14 @@ class Base(object):
|
|||||||
iv = fragment[:12]
|
iv = fragment[:12]
|
||||||
if len(key) == 32 and len(iv) == 12:
|
if len(key) == 32 and len(iv) == 12:
|
||||||
encrypted = True
|
encrypted = True
|
||||||
|
|
||||||
# file exists but thumbnail got deleted
|
# file exists but thumbnail got deleted
|
||||||
if os.path.exists(filepath) and not os.path.exists(thumbpath):
|
if os.path.exists(filepath) and not os.path.exists(thumbpath):
|
||||||
with open(filepath, 'rb') as f:
|
with open(filepath, 'rb') as f:
|
||||||
mem = f.read()
|
mem = f.read()
|
||||||
f.closed
|
|
||||||
app.thread_interface(
|
app.thread_interface(
|
||||||
self._save_thumbnail, [thumbpath, (mem, '')],
|
self._save_thumbnail, [thumbpath, (mem, '')],
|
||||||
self._update_img, [special_text, repl_start,
|
self._update_img, [real_text, repl_start,
|
||||||
repl_end, filepath, encrypted])
|
repl_end, filepath, encrypted])
|
||||||
|
|
||||||
# display thumbnail if already downloadeded
|
# display thumbnail if already downloadeded
|
||||||
@@ -224,7 +233,7 @@ class Base(object):
|
|||||||
elif os.path.exists(filepath) and os.path.exists(thumbpath):
|
elif os.path.exists(filepath) and os.path.exists(thumbpath):
|
||||||
app.thread_interface(
|
app.thread_interface(
|
||||||
self._load_thumbnail, [thumbpath],
|
self._load_thumbnail, [thumbpath],
|
||||||
self._update_img, [special_text, repl_start,
|
self._update_img, [real_text, repl_start,
|
||||||
repl_end, filepath, encrypted])
|
repl_end, filepath, encrypted])
|
||||||
|
|
||||||
# or download file, calculate thumbnail and finally display it
|
# or download file, calculate thumbnail and finally display it
|
||||||
@@ -236,10 +245,10 @@ class Base(object):
|
|||||||
# which does not fetch data, just headers
|
# which does not fetch data, just headers
|
||||||
# then check the mime type and filesize
|
# then check the mime type and filesize
|
||||||
if urlparts.scheme == 'aesgcm':
|
if urlparts.scheme == 'aesgcm':
|
||||||
special_text = 'https://' + special_text[9:]
|
real_text = 'https://' + real_text[9:]
|
||||||
app.thread_interface(
|
app.thread_interface(
|
||||||
get_http_head, [self.textview.account, special_text],
|
get_http_head, [self.textview.account, real_text],
|
||||||
self._check_mime_size, [special_text, repl_start, repl_end,
|
self._check_mime_size, [real_text, repl_start, repl_end,
|
||||||
filepaths, key, iv, encrypted])
|
filepaths, key, iv, encrypted])
|
||||||
|
|
||||||
def _save_thumbnail(self, thumbpath, tuple_arg):
|
def _save_thumbnail(self, thumbpath, tuple_arg):
|
||||||
@@ -272,7 +281,7 @@ class Base(object):
|
|||||||
loader.close()
|
loader.close()
|
||||||
pixbuf = loader.get_pixbuf()
|
pixbuf = loader.get_pixbuf()
|
||||||
pixbuf, w, h = self._get_pixbuf_of_size(pixbuf, size)
|
pixbuf, w, h = self._get_pixbuf_of_size(pixbuf, size)
|
||||||
|
|
||||||
ok, mem = pixbuf.save_to_bufferv("jpeg", ["quality"], ["100"])
|
ok, mem = pixbuf.save_to_bufferv("jpeg", ["quality"], ["100"])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.info("Failed to load image using gdk pixbuf, "
|
log.info("Failed to load image using gdk pixbuf, "
|
||||||
@@ -289,7 +298,7 @@ class Base(object):
|
|||||||
_('Exception raised while saving thumbnail '
|
_('Exception raised while saving thumbnail '
|
||||||
'for image file (see error log for more '
|
'for image file (see error log for more '
|
||||||
'information)'),
|
'information)'),
|
||||||
transient_for=self.chat_control.parent_win.window)
|
transient_for=self.parent_win)
|
||||||
log.error(str(e))
|
log.error(str(e))
|
||||||
return (mem, alt)
|
return (mem, alt)
|
||||||
|
|
||||||
@@ -300,13 +309,13 @@ class Base(object):
|
|||||||
return (mem, '')
|
return (mem, '')
|
||||||
|
|
||||||
def _write_file(self, path, data):
|
def _write_file(self, path, data):
|
||||||
log.info("Writing '%s' of size %d..." % (path, len(data)))
|
log.info("Writing '%s' of size %d...", path, len(data))
|
||||||
try:
|
try:
|
||||||
with open(path, "wb") as output_file:
|
with open(path, "wb") as output_file:
|
||||||
output_file.write(data)
|
output_file.write(data)
|
||||||
output_file.closed
|
output_file.closed
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error("Failed to write file '%s'!" % path)
|
log.error("Failed to write file '%s'!", path)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def _update_img(self, tuple_arg, url, repl_start, repl_end,
|
def _update_img(self, tuple_arg, url, repl_start, repl_end,
|
||||||
@@ -326,11 +335,13 @@ class Base(object):
|
|||||||
# (Gtk textview is NOT threadsafe by itself!!)
|
# (Gtk textview is NOT threadsafe by itself!!)
|
||||||
def add_to_textview():
|
def add_to_textview():
|
||||||
try: # textview closed in the meantime etc.
|
try: # textview closed in the meantime etc.
|
||||||
|
at_end = self.textview.at_the_end()
|
||||||
|
|
||||||
buffer_ = repl_start.get_buffer()
|
buffer_ = repl_start.get_buffer()
|
||||||
iter_ = buffer_.get_iter_at_mark(repl_start)
|
iter_ = buffer_.get_iter_at_mark(repl_start)
|
||||||
buffer_.insert(iter_, "\n")
|
# buffer_.insert(iter_, "\n")
|
||||||
anchor = buffer_.create_child_anchor(iter_)
|
anchor = buffer_.create_child_anchor(iter_)
|
||||||
|
|
||||||
# Use url as tooltip for image
|
# Use url as tooltip for image
|
||||||
img = TextViewImage(anchor, url)
|
img = TextViewImage(anchor, url)
|
||||||
loader = GdkPixbuf.PixbufLoader()
|
loader = GdkPixbuf.PixbufLoader()
|
||||||
@@ -343,21 +354,23 @@ class Base(object):
|
|||||||
eb.show_all()
|
eb.show_all()
|
||||||
self.textview.tv.add_child_at_anchor(eb, anchor)
|
self.textview.tv.add_child_at_anchor(eb, anchor)
|
||||||
buffer_.delete(iter_,
|
buffer_.delete(iter_,
|
||||||
buffer_.get_iter_at_mark(repl_end))
|
buffer_.get_iter_at_mark(repl_end))
|
||||||
|
|
||||||
|
if at_end:
|
||||||
|
GLib.idle_add(self.textview.scroll_to_end_iter)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
log.warn("Exception while loading %s: %s" % (str(url), str(ex)))
|
log.warn("Exception while loading %s: %s", url, ex)
|
||||||
return False
|
return False
|
||||||
# add to mainloop --> make call threadsafe
|
# add to mainloop --> make call threadsafe
|
||||||
GObject.idle_add(add_to_textview)
|
GLib.idle_add(add_to_textview)
|
||||||
except Exception:
|
except Exception:
|
||||||
# URL is already displayed
|
# URL is already displayed
|
||||||
log.error('Could not display image for URL: %s'
|
log.error('Could not display image for URL: %s', url)
|
||||||
% url)
|
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
# If image could not be downloaded, URL is already displayed
|
# If image could not be downloaded, URL is already displayed
|
||||||
log.error('Could not download image for URL: %s -- %s'
|
log.error('Could not download image for URL: %s -- %s',
|
||||||
% (url, alt))
|
url, alt)
|
||||||
|
|
||||||
def _check_mime_size(self, tuple_arg,
|
def _check_mime_size(self, tuple_arg,
|
||||||
url, repl_start, repl_end, filepaths,
|
url, repl_start, repl_end, filepaths,
|
||||||
@@ -366,23 +379,24 @@ class Base(object):
|
|||||||
# Check if mime type is acceptable
|
# Check if mime type is acceptable
|
||||||
if file_mime == '' and file_size == 0:
|
if file_mime == '' and file_size == 0:
|
||||||
log.info("Failed to load HEAD Request for URL: '%s'"
|
log.info("Failed to load HEAD Request for URL: '%s'"
|
||||||
"(see debug log for more info)" % url)
|
"(see debug log for more info)", url)
|
||||||
# URL is already displayed
|
# URL is already displayed
|
||||||
return
|
return
|
||||||
if file_mime.lower() not in ACCEPTED_MIME_TYPES:
|
if file_mime.lower() not in ACCEPTED_MIME_TYPES:
|
||||||
log.info("Not accepted mime type '%s' for URL: '%s'"
|
log.info("Not accepted mime type '%s' for URL: '%s'",
|
||||||
% (file_mime.lower(), url))
|
file_mime.lower(), url)
|
||||||
# URL is already displayed
|
# URL is already displayed
|
||||||
return
|
return
|
||||||
# Check if file size is acceptable
|
# Check if file size is acceptable
|
||||||
if file_size > self.plugin.config['MAX_FILE_SIZE'] or file_size == 0:
|
max_size = int(self.plugin.config['MAX_FILE_SIZE'])
|
||||||
log.info("File size (%s) too big or unknown (zero) for URL: '%s'"
|
if file_size > max_size or file_size == 0:
|
||||||
% (str(file_size), url))
|
log.info("File size (%s) too big or unknown (zero) for URL: '%s'",
|
||||||
|
file_size, url)
|
||||||
# URL is already displayed
|
# URL is already displayed
|
||||||
return
|
return
|
||||||
|
|
||||||
attributes = {'src': url,
|
attributes = {'src': url,
|
||||||
'max_size': self.plugin.config['MAX_FILE_SIZE'],
|
'max_size': max_size,
|
||||||
'filepaths': filepaths,
|
'filepaths': filepaths,
|
||||||
'key': key,
|
'key': key,
|
||||||
'iv': iv}
|
'iv': iv}
|
||||||
@@ -412,7 +426,7 @@ class Base(object):
|
|||||||
_('Could not save file'),
|
_('Could not save file'),
|
||||||
_('Exception raised while saving image file'
|
_('Exception raised while saving image file'
|
||||||
' (see error log for more information)'),
|
' (see error log for more information)'),
|
||||||
transient_for=self.chat_control.parent_win.window)
|
transient_for=self.parent_win)
|
||||||
log.error(str(e))
|
log.error(str(e))
|
||||||
|
|
||||||
# Create thumbnail, write it to harddisk and return it
|
# Create thumbnail, write it to harddisk and return it
|
||||||
@@ -474,7 +488,7 @@ class Base(object):
|
|||||||
xml.get_object('open_file_in_browser_menuitem')
|
xml.get_object('open_file_in_browser_menuitem')
|
||||||
extras_separator = \
|
extras_separator = \
|
||||||
xml.get_object('extras_separator')
|
xml.get_object('extras_separator')
|
||||||
|
|
||||||
if data["encrypted"]:
|
if data["encrypted"]:
|
||||||
open_link_in_browser_menuitem.hide()
|
open_link_in_browser_menuitem.hide()
|
||||||
if app.config.get('autodetect_browser_mailer') \
|
if app.config.get('autodetect_browser_mailer') \
|
||||||
@@ -507,6 +521,7 @@ class Base(object):
|
|||||||
def on_save_as_menuitem_activate(self, menu, data):
|
def on_save_as_menuitem_activate(self, menu, data):
|
||||||
filepath = data["filepath"]
|
filepath = data["filepath"]
|
||||||
original_filename = data["original_filename"]
|
original_filename = data["original_filename"]
|
||||||
|
|
||||||
def on_continue(response, target_path):
|
def on_continue(response, target_path):
|
||||||
if response < 0:
|
if response < 0:
|
||||||
return
|
return
|
||||||
@@ -572,10 +587,10 @@ class Base(object):
|
|||||||
_('You cannot open encrypted files in your '
|
_('You cannot open encrypted files in your '
|
||||||
'browser directly. Try "Open Downloaded File '
|
'browser directly. Try "Open Downloaded File '
|
||||||
'in Browser" instead.'),
|
'in Browser" instead.'),
|
||||||
transient_for=self.chat_control.parent_win.window)
|
transient_for=self.parent_win)
|
||||||
else:
|
else:
|
||||||
helpers.launch_browser_mailer('url', url)
|
helpers.launch_browser_mailer('url', url)
|
||||||
|
|
||||||
def on_open_file_in_browser_menuitem_activate(self, menu, data):
|
def on_open_file_in_browser_menuitem_activate(self, menu, data):
|
||||||
if os.name == "nt":
|
if os.name == "nt":
|
||||||
filepath = "file://" + os.path.abspath(data["filepath"])
|
filepath = "file://" + os.path.abspath(data["filepath"])
|
||||||
@@ -587,7 +602,7 @@ class Base(object):
|
|||||||
_('Cannot open downloaded file in browser'),
|
_('Cannot open downloaded file in browser'),
|
||||||
_('You have to set a custom browser executable '
|
_('You have to set a custom browser executable '
|
||||||
'in your gajim settings for this to work.'),
|
'in your gajim settings for this to work.'),
|
||||||
transient_for=self.chat_control.parent_win.window)
|
transient_for=self.parent_win)
|
||||||
return
|
return
|
||||||
command = app.config.get('custombrowser')
|
command = app.config.get('custombrowser')
|
||||||
command = helpers.build_command(command, filepath)
|
command = helpers.build_command(command, filepath)
|
||||||
@@ -622,8 +637,8 @@ class Base(object):
|
|||||||
# right klick
|
# right klick
|
||||||
elif event.type == Gdk.EventType.BUTTON_PRESS and event.button == 3:
|
elif event.type == Gdk.EventType.BUTTON_PRESS and event.button == 3:
|
||||||
menu = self.make_rightclick_menu(event, data)
|
menu = self.make_rightclick_menu(event, data)
|
||||||
#menu.attach_to_widget(self.tv, None)
|
# menu.attach_to_widget(self.tv, None)
|
||||||
#menu.popup(None, None, None, event.button, event.time)
|
# menu.popup(None, None, None, event.button, event.time)
|
||||||
menu.popup_at_pointer(event)
|
menu.popup_at_pointer(event)
|
||||||
|
|
||||||
def disconnect_from_chat_control(self):
|
def disconnect_from_chat_control(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user