[preview] Cleanup code
This commit is contained in:
committed by
Philipp Hörist
parent
1a69014952
commit
e73114c01e
@@ -91,8 +91,8 @@ class UrlImagePreviewConfigDialog(SettingsDialog):
|
|||||||
]
|
]
|
||||||
|
|
||||||
SettingsDialog.__init__(self, parent, _('UrlImagePreview Configuration'),
|
SettingsDialog.__init__(self, parent, _('UrlImagePreview Configuration'),
|
||||||
Gtk.DialogFlags.MODAL, settings, None,
|
Gtk.DialogFlags.MODAL, settings, None,
|
||||||
extend=[
|
extend=[
|
||||||
('PreviewSizeSpinSetting', SizeSpinSetting)])
|
('PreviewSizeSpinSetting', SizeSpinSetting)])
|
||||||
|
|
||||||
def on_setting(self, value, data):
|
def on_setting(self, value, data):
|
||||||
|
|||||||
@@ -1,70 +1,31 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!-- Generated with glade 3.22.1 -->
|
<!-- Generated with glade 3.22.1 -->
|
||||||
<interface>
|
<interface>
|
||||||
<requires lib="gtk+" version="3.0"/>
|
<requires lib="gtk+" version="3.20"/>
|
||||||
<object class="GtkImage" id="image1">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="stock">gtk-open</property>
|
|
||||||
</object>
|
|
||||||
<object class="GtkImage" id="image2">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="stock">gtk-save-as</property>
|
|
||||||
</object>
|
|
||||||
<object class="GtkImage" id="image3">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="stock">gtk-copy</property>
|
|
||||||
</object>
|
|
||||||
<object class="GtkImage" id="image4">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="icon_name">emblem-symbolic-link</property>
|
|
||||||
</object>
|
|
||||||
<object class="GtkImage" id="image5">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="icon_name">emblem-symbolic-link</property>
|
|
||||||
</object>
|
|
||||||
<object class="GtkImage" id="image6">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="icon_name">folder-download</property>
|
|
||||||
</object>
|
|
||||||
<object class="GtkMenu" id="context_menu">
|
<object class="GtkMenu" id="context_menu">
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkImageMenuItem" id="open_menuitem">
|
<object class="GtkMenuItem" id="open_menuitem">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
<property name="label" translatable="yes">_Open</property>
|
<property name="label" translatable="yes">_Open</property>
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
<property name="image">image1</property>
|
|
||||||
<property name="use_stock">False</property>
|
|
||||||
<property name="always_show_image">True</property>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkImageMenuItem" id="save_as_menuitem">
|
<object class="GtkMenuItem" id="save_as_menuitem">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
<property name="label" translatable="yes">_Save as</property>
|
<property name="label" translatable="yes">_Save as</property>
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
<property name="image">image2</property>
|
|
||||||
<property name="use_stock">False</property>
|
|
||||||
<property name="always_show_image">True</property>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkImageMenuItem" id="open_folder_menuitem">
|
<object class="GtkMenuItem" id="open_folder_menuitem">
|
||||||
<property name="label" translatable="yes">Open _Folder</property>
|
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Open _Folder</property>
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
<property name="image">image6</property>
|
|
||||||
<property name="use_stock">False</property>
|
|
||||||
<property name="always_show_image">True</property>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
@@ -74,25 +35,19 @@
|
|||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkImageMenuItem" id="copy_link_location_menuitem">
|
<object class="GtkMenuItem" id="copy_link_location_menuitem">
|
||||||
<property name="label" translatable="yes">_Copy Link Location</property>
|
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">_Copy Link</property>
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
<property name="image">image3</property>
|
|
||||||
<property name="use_stock">False</property>
|
|
||||||
<property name="always_show_image">True</property>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkImageMenuItem" id="open_link_in_browser_menuitem">
|
<object class="GtkMenuItem" id="open_link_in_browser_menuitem">
|
||||||
<property name="label" translatable="yes">Open Link in _Browser</property>
|
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Open Link in _Browser</property>
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
<property name="image">image4</property>
|
|
||||||
<property name="use_stock">False</property>
|
|
||||||
<property name="always_show_image">True</property>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
@@ -102,14 +57,11 @@
|
|||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkImageMenuItem" id="open_file_in_browser_menuitem">
|
<object class="GtkMenuItem" id="open_file_in_browser_menuitem">
|
||||||
<property name="label" translatable="yes">Open _Downloaded File in Browser</property>
|
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Open _Downloaded File in Browser</property>
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
<property name="image">image5</property>
|
|
||||||
<property name="use_stock">False</property>
|
|
||||||
<property name="always_show_image">True</property>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|||||||
@@ -47,17 +47,17 @@ def _get_http_head_direct(url, verify):
|
|||||||
context.check_hostname = False
|
context.check_hostname = False
|
||||||
context.verify_mode = ssl.CERT_NONE
|
context.verify_mode = ssl.CERT_NONE
|
||||||
log.warning('CERT Verification disabled')
|
log.warning('CERT Verification disabled')
|
||||||
f = urllib2.urlopen(req, timeout=30, context=context)
|
file_ = urllib2.urlopen(req, timeout=30, context=context)
|
||||||
else:
|
else:
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
f = urllib2.urlopen(req, cafile=certifi.where())
|
file_ = urllib2.urlopen(req, cafile=certifi.where())
|
||||||
else:
|
else:
|
||||||
f = urllib2.urlopen(req)
|
file_ = urllib2.urlopen(req)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
log.debug('Error', exc_info=True)
|
log.debug('Error', exc_info=True)
|
||||||
return ('', 0)
|
return ('', 0)
|
||||||
ctype = f.headers['Content-Type']
|
ctype = file_.headers['Content-Type']
|
||||||
clen = f.headers['Content-Length']
|
clen = file_.headers['Content-Length']
|
||||||
try:
|
try:
|
||||||
clen = int(clen)
|
clen = int(clen)
|
||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
@@ -65,10 +65,10 @@ def _get_http_head_direct(url, verify):
|
|||||||
return (ctype, clen)
|
return (ctype, clen)
|
||||||
|
|
||||||
def _get_http_direct(attrs):
|
def _get_http_direct(attrs):
|
||||||
"""
|
'''
|
||||||
Download a file. This function should
|
Download a file. This function should
|
||||||
be launched in a separated thread.
|
be launched in a separated thread.
|
||||||
"""
|
'''
|
||||||
log.info('Get request direct for URL: %s', attrs['src'])
|
log.info('Get request direct for URL: %s', attrs['src'])
|
||||||
mem, alt, max_size = b'', '', 2 * 1024 * 1024
|
mem, alt, max_size = b'', '', 2 * 1024 * 1024
|
||||||
if 'max_size' in attrs:
|
if 'max_size' in attrs:
|
||||||
@@ -81,12 +81,12 @@ def _get_http_direct(attrs):
|
|||||||
context.check_hostname = False
|
context.check_hostname = False
|
||||||
context.verify_mode = ssl.CERT_NONE
|
context.verify_mode = ssl.CERT_NONE
|
||||||
log.warning('CERT Verification disabled')
|
log.warning('CERT Verification disabled')
|
||||||
f = urllib2.urlopen(req, timeout=30, context=context)
|
file_ = urllib2.urlopen(req, timeout=30, context=context)
|
||||||
else:
|
else:
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
f = urllib2.urlopen(req, cafile=certifi.where())
|
file_ = urllib2.urlopen(req, cafile=certifi.where())
|
||||||
else:
|
else:
|
||||||
f = urllib2.urlopen(req)
|
file_ = urllib2.urlopen(req)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
log.debug('Error', exc_info=True)
|
log.debug('Error', exc_info=True)
|
||||||
pixbuf = None
|
pixbuf = None
|
||||||
@@ -94,7 +94,7 @@ def _get_http_direct(attrs):
|
|||||||
else:
|
else:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
temp = f.read(100)
|
temp = file_.read(100)
|
||||||
except socket.timeout as ex:
|
except socket.timeout as ex:
|
||||||
log.debug('Timeout loading image %s', attrs['src'] + str(ex))
|
log.debug('Timeout loading image %s', attrs['src'] + str(ex))
|
||||||
alt = attrs.get('alt', '')
|
alt = attrs.get('alt', '')
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ def resize_gif(mem, path, resize_to):
|
|||||||
|
|
||||||
|
|
||||||
def analyse_image(mem):
|
def analyse_image(mem):
|
||||||
"""
|
'''
|
||||||
Pre-process pass over the image to determine the mode (full or additive).
|
Pre-process pass over the image to determine the mode (full or additive).
|
||||||
Necessary as assessing single frames isn't reliable. Need to know the mode
|
Necessary as assessing single frames isn't reliable. Need to know the mode
|
||||||
before processing all frames.
|
before processing all frames.
|
||||||
"""
|
'''
|
||||||
image = Image.open(BytesIO(mem))
|
image = Image.open(BytesIO(mem))
|
||||||
results = {
|
results = {
|
||||||
'size': image.size,
|
'size': image.size,
|
||||||
|
|||||||
@@ -20,11 +20,12 @@ import hashlib
|
|||||||
import binascii
|
import binascii
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from functools import partial
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
import shutil
|
|
||||||
from functools import partial
|
|
||||||
|
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
from gi.repository import Gdk
|
from gi.repository import Gdk
|
||||||
@@ -34,9 +35,10 @@ from gi.repository import GdkPixbuf
|
|||||||
from gajim.common import app
|
from gajim.common import app
|
||||||
from gajim.common import helpers
|
from gajim.common import helpers
|
||||||
from gajim.common import configpaths
|
from gajim.common import configpaths
|
||||||
|
from gajim.gtkgui_helpers import add_css_to_widget
|
||||||
from gajim import dialogs
|
from gajim.gtk.dialogs import ErrorDialog
|
||||||
from gajim import gtkgui_helpers
|
from gajim.gtk.filechoosers import FileSaveDialog
|
||||||
|
from gajim.gtk.util import get_cursor
|
||||||
|
|
||||||
from gajim.plugins import GajimPlugin
|
from gajim.plugins import GajimPlugin
|
||||||
from gajim.plugins.helpers import log_calls
|
from gajim.plugins.helpers import log_calls
|
||||||
@@ -46,9 +48,6 @@ from url_image_preview.http_functions import get_http_head
|
|||||||
from url_image_preview.http_functions import get_http_file
|
from url_image_preview.http_functions import get_http_file
|
||||||
from url_image_preview.config_dialog import UrlImagePreviewConfigDialog
|
from url_image_preview.config_dialog import UrlImagePreviewConfigDialog
|
||||||
|
|
||||||
from gajim.gtk.filechoosers import FileSaveDialog
|
|
||||||
from gajim.gtk.util import get_cursor
|
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger('gajim.p.preview')
|
log = logging.getLogger('gajim.p.preview')
|
||||||
|
|
||||||
@@ -56,9 +55,9 @@ ERROR_MSG = None
|
|||||||
try:
|
try:
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from url_image_preview.resize_gif import resize_gif
|
from url_image_preview.resize_gif import resize_gif
|
||||||
except:
|
except ImportError:
|
||||||
log.debug('Pillow not available')
|
log.debug('Pillow not available')
|
||||||
ERROR_MSG = 'Please install python-pillow'
|
ERROR_MSG = _('Please install python-pillow')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
@@ -70,8 +69,8 @@ try:
|
|||||||
from cryptography.hazmat.primitives.ciphers.modes import GCM
|
from cryptography.hazmat.primitives.ciphers.modes import GCM
|
||||||
decryption_available = True
|
decryption_available = True
|
||||||
except Exception:
|
except Exception:
|
||||||
DEP_MSG = 'For preview of encrypted images, ' \
|
DEP_MSG = _('To enable previews for encrypted images, '
|
||||||
'please install python-cryptography!'
|
'please install python-cryptography!')
|
||||||
log.exception('Error')
|
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
|
||||||
@@ -152,7 +151,7 @@ class UrlImagePreviewPlugin(GajimPlugin):
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
class Base(object):
|
class Base:
|
||||||
def __init__(self, plugin, textview):
|
def __init__(self, plugin, textview):
|
||||||
self.plugin = plugin
|
self.plugin = plugin
|
||||||
self.textview = textview
|
self.textview = textview
|
||||||
@@ -167,11 +166,11 @@ class Base(object):
|
|||||||
self._create_path(self.directory)
|
self._create_path(self.directory)
|
||||||
self._create_path(self.thumbpath)
|
self._create_path(self.thumbpath)
|
||||||
except Exception:
|
except Exception:
|
||||||
log.error("Error creating download and/or thumbnail folder!")
|
log.error('Error creating download and/or thumbnail folder!')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def deinit_handlers(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()):
|
||||||
if self.handlers[i].handler_is_connected(i):
|
if self.handlers[i].handler_is_connected(i):
|
||||||
@@ -182,7 +181,7 @@ class Base(object):
|
|||||||
additional_data):
|
additional_data):
|
||||||
|
|
||||||
if len(real_text.split(' ')) > 1:
|
if len(real_text.split(' ')) > 1:
|
||||||
# urlparse dont recognises spaces as URL delimiter
|
# urlparse doesn't recognise spaces as URL delimiter
|
||||||
log.debug('Url with text will not be displayed: %s', real_text)
|
log.debug('Url with text will not be displayed: %s', real_text)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -200,8 +199,10 @@ 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_, real_text,
|
buffer_.insert_with_tags(
|
||||||
*[(ttt.lookup(t) if isinstance(t, str) else t) for t in ["url"]])
|
iter_,
|
||||||
|
real_text,
|
||||||
|
*[(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)
|
||||||
|
|
||||||
# Handle geo:-URIs
|
# Handle geo:-URIs
|
||||||
@@ -221,11 +222,17 @@ class Base(object):
|
|||||||
if lon == '':
|
if lon == '':
|
||||||
return
|
return
|
||||||
|
|
||||||
filename = 'location_' + geo_provider + '_' \
|
filename = 'location_%(provider)s_%(location)s' % {
|
||||||
+ location.replace(',', '_').replace('.', '-')
|
'provider': geo_provider,
|
||||||
|
'location': location.replace(',', '_').replace('.', '-')
|
||||||
|
}
|
||||||
newfilename = filename + ext
|
newfilename = filename + ext
|
||||||
thumbfilename = filename + '_thumb_' \
|
thumbfilename = '%(filename)s_thumb_%(size)s%(ext)s' % {
|
||||||
+ str(self.plugin.config['PREVIEW_SIZE']) + ext
|
'filename': filename,
|
||||||
|
'size': str(self.plugin.config['PREVIEW_SIZE']),
|
||||||
|
'ext': ext
|
||||||
|
}
|
||||||
|
|
||||||
filepath = os.path.join(self.directory, newfilename)
|
filepath = os.path.join(self.directory, newfilename)
|
||||||
thumbpath = os.path.join(self.thumbpath, thumbfilename)
|
thumbpath = os.path.join(self.thumbpath, thumbfilename)
|
||||||
filepaths = [filepath, thumbpath]
|
filepaths = [filepath, thumbpath]
|
||||||
@@ -264,9 +271,17 @@ class Base(object):
|
|||||||
# so the filename should not exceed 90
|
# so the filename should not exceed 90
|
||||||
name = name[:90]
|
name = name[:90]
|
||||||
namehash = hashlib.sha1(real_text.encode('utf-8')).hexdigest()
|
namehash = hashlib.sha1(real_text.encode('utf-8')).hexdigest()
|
||||||
newfilename = name + '_' + namehash + ext
|
newfilename = '%(name)s_%(namehash)s%(ext)s' % {
|
||||||
thumbfilename = name + '_' + namehash + '_thumb_' \
|
'name': name,
|
||||||
+ str(self.plugin.config['PREVIEW_SIZE']) + ext
|
'namehash': namehash,
|
||||||
|
'ext': ext
|
||||||
|
}
|
||||||
|
thumbfilename = '%(name)s_%(namehash)s_thumb_%(size)s%(ext)s' % {
|
||||||
|
'name': name,
|
||||||
|
'namehash': namehash,
|
||||||
|
'size': str(self.plugin.config['PREVIEW_SIZE']),
|
||||||
|
'ext': ext
|
||||||
|
}
|
||||||
|
|
||||||
filepath = os.path.join(self.directory, newfilename)
|
filepath = os.path.join(self.directory, newfilename)
|
||||||
thumbpath = os.path.join(self.thumbpath, thumbfilename)
|
thumbpath = os.path.join(self.thumbpath, thumbfilename)
|
||||||
@@ -287,19 +302,19 @@ class Base(object):
|
|||||||
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):
|
||||||
if urlparts.scheme == 'geo':
|
if urlparts.scheme == 'geo':
|
||||||
real_text = weburl
|
real_text = weburl
|
||||||
with open(filepath, 'rb') as f:
|
with open(filepath, 'rb') as file_to_preview:
|
||||||
mem = f.read()
|
mem = file_to_preview.read()
|
||||||
app.thread_interface(
|
app.thread_interface(
|
||||||
self._save_thumbnail, [thumbpath, mem],
|
self._save_thumbnail, [thumbpath, mem],
|
||||||
self._update_img, [real_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 downloaded
|
||||||
# (but only if file also exists)
|
# (but only if file exists)
|
||||||
elif os.path.exists(filepath) and os.path.exists(thumbpath):
|
elif os.path.exists(filepath) and os.path.exists(thumbpath):
|
||||||
if urlparts.scheme == 'geo':
|
if urlparts.scheme == 'geo':
|
||||||
real_text = weburl
|
real_text = weburl
|
||||||
@@ -308,7 +323,7 @@ class Base(object):
|
|||||||
self._update_img, [real_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
|
||||||
else:
|
else:
|
||||||
if encrypted and not decryption_available:
|
if encrypted and not decryption_available:
|
||||||
log.debug('Please install Crytography to decrypt pictures')
|
log.debug('Please install Crytography to decrypt pictures')
|
||||||
@@ -327,7 +342,7 @@ class Base(object):
|
|||||||
|
|
||||||
def _accept_uri(self, urlparts, real_text, additional_data):
|
def _accept_uri(self, urlparts, real_text, additional_data):
|
||||||
try:
|
try:
|
||||||
oob_url = additional_data["gajim"]["oob_url"]
|
oob_url = additional_data['gajim']['oob_url']
|
||||||
except (KeyError, AttributeError):
|
except (KeyError, AttributeError):
|
||||||
oob_url = None
|
oob_url = None
|
||||||
|
|
||||||
@@ -336,7 +351,7 @@ class Base(object):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# geo
|
# geo
|
||||||
if urlparts.scheme == "geo":
|
if urlparts.scheme == 'geo':
|
||||||
if self.plugin.config['GEO_PREVIEW_PROVIDER'] == 'no_preview':
|
if self.plugin.config['GEO_PREVIEW_PROVIDER'] == 'no_preview':
|
||||||
log.info('geo: link preview is disabled')
|
log.info('geo: link preview is disabled')
|
||||||
return False
|
return False
|
||||||
@@ -353,7 +368,7 @@ class Base(object):
|
|||||||
log.info('Incorrect oob data found')
|
log.info('Incorrect oob data found')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
log.info('Not supported URI scheme found: %s', real_text)
|
log.info('Unsupported URI scheme found: %s', real_text)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _save_thumbnail(self, thumbpath, mem):
|
def _save_thumbnail(self, thumbpath, mem):
|
||||||
@@ -372,7 +387,7 @@ class Base(object):
|
|||||||
log.debug(error)
|
log.debug(error)
|
||||||
|
|
||||||
# Try Pillow
|
# Try Pillow
|
||||||
image = Image.open(BytesIO(mem)).convert("RGBA")
|
image = Image.open(BytesIO(mem)).convert('RGBA')
|
||||||
array = GLib.Bytes.new(image.tobytes())
|
array = GLib.Bytes.new(image.tobytes())
|
||||||
width, height = image.size
|
width, height = image.size
|
||||||
pixbuf = GdkPixbuf.Pixbuf.new_from_bytes(
|
pixbuf = GdkPixbuf.Pixbuf.new_from_bytes(
|
||||||
@@ -430,30 +445,20 @@ class Base(object):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _write_file(path, data):
|
def _write_file(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 _get_at_end(self):
|
def _get_at_end(self):
|
||||||
try:
|
return self.textview.autoscroll
|
||||||
# Gajim 1.0.0
|
|
||||||
return self.textview.at_the_end()
|
|
||||||
except AttributeError:
|
|
||||||
# Gajim 1.0.1
|
|
||||||
return self.textview.autoscroll
|
|
||||||
|
|
||||||
def _scroll_to_end(self):
|
def _scroll_to_end(self):
|
||||||
try:
|
self.textview.scroll_to_end()
|
||||||
# Gajim 1.0.0
|
|
||||||
self.textview.scroll_to_end_iter()
|
|
||||||
except AttributeError:
|
|
||||||
# Gajim 1.0.1
|
|
||||||
self.textview.scroll_to_end()
|
|
||||||
|
|
||||||
def _update_img(self, pixbuf, url, repl_start, repl_end,
|
def _update_img(self, pixbuf, url, repl_start, repl_end,
|
||||||
filepath, encrypted):
|
filepath, encrypted):
|
||||||
@@ -473,7 +478,7 @@ class Base(object):
|
|||||||
|
|
||||||
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_)
|
||||||
anchor.plaintext = url
|
anchor.plaintext = url
|
||||||
|
|
||||||
@@ -491,9 +496,9 @@ class Base(object):
|
|||||||
if at_end:
|
if at_end:
|
||||||
self._scroll_to_end()
|
self._scroll_to_end()
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
log.exception("Exception while loading %s: %s", url, ex)
|
log.exception('Exception while loading %s: %s', url, ex)
|
||||||
return False
|
return False
|
||||||
# add to mainloop --> make call threadsafe
|
# Add to mainloop --> make call threadsafe
|
||||||
GLib.idle_add(add_to_textview)
|
GLib.idle_add(add_to_textview)
|
||||||
|
|
||||||
def _create_clickable_image(self, pixbuf, url):
|
def _create_clickable_image(self, pixbuf, url):
|
||||||
@@ -505,7 +510,7 @@ class Base(object):
|
|||||||
css = '''#Preview {
|
css = '''#Preview {
|
||||||
box-shadow: 0px 0px 3px 0px alpha(@theme_text_color, 0.2);
|
box-shadow: 0px 0px 3px 0px alpha(@theme_text_color, 0.2);
|
||||||
margin: 5px 10px 5px 10px; }'''
|
margin: 5px 10px 5px 10px; }'''
|
||||||
gtkgui_helpers.add_css_to_widget(image, css)
|
add_css_to_widget(image, css)
|
||||||
image.set_name('Preview')
|
image.set_name('Preview')
|
||||||
|
|
||||||
event_box = Gtk.EventBox()
|
event_box = Gtk.EventBox()
|
||||||
@@ -520,19 +525,19 @@ class Base(object):
|
|||||||
file_mime, file_size = tuple_arg
|
file_mime, file_size = tuple_arg
|
||||||
# Check if mime type is acceptable
|
# Check if mime type is acceptable
|
||||||
if not file_mime or not file_size:
|
if not file_mime or not file_size:
|
||||||
log.info("Failed to load HEAD Request for URL: '%s' "
|
log.info('Failed to load HEAD Request for URL: \'%s\' '
|
||||||
"mime: %s, size: %s", url, file_mime, file_size)
|
'mime: %s, size: %s', url, file_mime, file_size)
|
||||||
# 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
|
||||||
max_size = int(self.plugin.config['MAX_FILE_SIZE'])
|
max_size = int(self.plugin.config['MAX_FILE_SIZE'])
|
||||||
if file_size > max_size or file_size == 0:
|
if file_size > max_size or file_size == 0:
|
||||||
log.info("File size (%s) too big or unknown (zero) for URL: '%s'",
|
log.info('File size (%s) too big or unknown (zero) for URL: \'%s\'',
|
||||||
file_size, url)
|
file_size, url)
|
||||||
# URL is already displayed
|
# URL is already displayed
|
||||||
return
|
return
|
||||||
@@ -572,17 +577,17 @@ class Base(object):
|
|||||||
' (see error log for more information)'))
|
' (see error log for more information)'))
|
||||||
log.error(str(e))
|
log.error(str(e))
|
||||||
|
|
||||||
# Create thumbnail, write it to harddisk and return it
|
# Create thumbnail, write to disk and return it
|
||||||
return self._save_thumbnail(thumbpath, mem)
|
return self._save_thumbnail(thumbpath, mem)
|
||||||
|
|
||||||
def _create_path(self, folder):
|
def _create_path(self, folder):
|
||||||
if os.path.exists(folder):
|
if os.path.exists(folder):
|
||||||
return
|
return
|
||||||
log.debug("creating folder '%s'" % folder)
|
log.debug('Creating folder \'%s\'' % folder)
|
||||||
os.mkdir(folder, 0o700)
|
os.mkdir(folder, 0o700)
|
||||||
|
|
||||||
def _aes_decrypt_fast(self, key, iv, payload):
|
def _aes_decrypt_fast(self, key, iv, payload):
|
||||||
# Use AES128 GCM with the given key and iv to decrypt the payload.
|
# Use AES128 GCM with the given key and iv to decrypt the payload
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
be = backend
|
be = backend
|
||||||
else:
|
else:
|
||||||
@@ -612,7 +617,7 @@ class Base(object):
|
|||||||
'open_file_in_browser_menuitem')
|
'open_file_in_browser_menuitem')
|
||||||
extras_separator = xml.get_object('extras_separator')
|
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') \
|
||||||
or app.config.get('custombrowser') == '':
|
or app.config.get('custombrowser') == '':
|
||||||
@@ -641,25 +646,26 @@ class Base(object):
|
|||||||
return menu
|
return menu
|
||||||
|
|
||||||
def _on_open_menuitem_activate(self, menu, data):
|
def _on_open_menuitem_activate(self, menu, data):
|
||||||
filepath = data["filepath"]
|
filepath = data['filepath']
|
||||||
original_filename = data["original_filename"]
|
original_filename = data['original_filename']
|
||||||
url = data["url"]
|
url = data['url']
|
||||||
if original_filename.startswith('location_'):
|
if original_filename.startswith('location_'):
|
||||||
helpers.open_uri(url)
|
helpers.open_uri(url)
|
||||||
return
|
return
|
||||||
helpers.launch_file_manager(filepath)
|
helpers.launch_file_manager(filepath)
|
||||||
|
|
||||||
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_ok(target_path):
|
def on_ok(target_path):
|
||||||
dirname = os.path.dirname(target_path)
|
dirname = os.path.dirname(target_path)
|
||||||
if not os.access(dirname, os.W_OK):
|
if not os.access(dirname, os.W_OK):
|
||||||
dialogs.ErrorDialog(
|
ErrorDialog(
|
||||||
_('Directory "%s" is not writable') % dirname,
|
_('Directory \'%s\' is not writable') % dirname,
|
||||||
_('You do not have permission to '
|
_('You do not have the proper permissions to '
|
||||||
'create files in this directory.'))
|
'create files in this directory.'),
|
||||||
|
transient_for=app.app.get_active_window())
|
||||||
return
|
return
|
||||||
shutil.copy(filepath, target_path)
|
shutil.copy(filepath, target_path)
|
||||||
|
|
||||||
@@ -672,29 +678,29 @@ class Base(object):
|
|||||||
helpers.launch_file_manager(self.directory)
|
helpers.launch_file_manager(self.directory)
|
||||||
|
|
||||||
def _on_copy_link_location_menuitem_activate(self, menu, data):
|
def _on_copy_link_location_menuitem_activate(self, menu, data):
|
||||||
url = data["url"]
|
url = data['url']
|
||||||
clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
|
clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
|
||||||
clipboard.set_text(url, -1)
|
clipboard.set_text(url, -1)
|
||||||
clipboard.store()
|
clipboard.store()
|
||||||
|
|
||||||
def _on_open_link_in_browser_menuitem_activate(self, menu, data):
|
def _on_open_link_in_browser_menuitem_activate(self, menu, data):
|
||||||
url = data["url"]
|
url = data['url']
|
||||||
if data["encrypted"]:
|
if data['encrypted']:
|
||||||
self._on_open_menuitem_activate(self, data)
|
self._on_open_menuitem_activate(self, data)
|
||||||
else:
|
else:
|
||||||
helpers.open_uri(url)
|
helpers.open_uri(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'])
|
||||||
else:
|
else:
|
||||||
filepath = "file://" + data["filepath"]
|
filepath = 'file://' + data['filepath']
|
||||||
if app.config.get('autodetect_browser_mailer') \
|
if app.config.get('autodetect_browser_mailer') \
|
||||||
or app.config.get('custombrowser') == '':
|
or app.config.get('custombrowser') == '':
|
||||||
dialogs.ErrorDialog(
|
ErrorDialog(
|
||||||
_('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 Gajim\'s Preferences for this to work.'),
|
||||||
transient_for=app.app.get_active_window())
|
transient_for=app.app.get_active_window())
|
||||||
return
|
return
|
||||||
command = app.config.get('custombrowser')
|
command = app.config.get('custombrowser')
|
||||||
@@ -706,17 +712,17 @@ class Base(object):
|
|||||||
|
|
||||||
def _on_button_press_event(self, eb, event, filepath, original_filename,
|
def _on_button_press_event(self, eb, event, filepath, original_filename,
|
||||||
url, encrypted):
|
url, encrypted):
|
||||||
data = {"filepath": filepath,
|
data = {'filepath': filepath,
|
||||||
"original_filename": original_filename,
|
'original_filename': original_filename,
|
||||||
"url": url,
|
'url': url,
|
||||||
"encrypted": encrypted}
|
'encrypted': encrypted}
|
||||||
# left click
|
# Left click
|
||||||
if event.type == Gdk.EventType.BUTTON_PRESS and event.button == 1:
|
if event.type == Gdk.EventType.BUTTON_PRESS and event.button == 1:
|
||||||
method = getattr(self, "_on_"
|
method = getattr(self, '_on_'
|
||||||
+ self.plugin.config['LEFTCLICK_ACTION']
|
+ self.plugin.config['LEFTCLICK_ACTION']
|
||||||
+ "_activate")
|
+ '_activate')
|
||||||
method(event, data)
|
method(event, data)
|
||||||
# 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)
|
||||||
@@ -726,9 +732,9 @@ class Base(object):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def _raise_error_dialog(pritext, sectext):
|
def _raise_error_dialog(pritext, sectext):
|
||||||
# Used by methods that run in a different thread
|
# Used by methods that run in a different thread
|
||||||
dialogs.ErrorDialog(pritext,
|
ErrorDialog(pritext,
|
||||||
sectext,
|
sectext,
|
||||||
transient_for=app.app.get_active_window())
|
transient_for=app.app.get_active_window())
|
||||||
|
|
||||||
def disconnect_from_chat_control(self):
|
def disconnect_from_chat_control(self):
|
||||||
pass
|
pass
|
||||||
|
|||||||
Reference in New Issue
Block a user