Skip to content
Snippets Groups Projects
Commit 4493fead authored by Philipp Hörist's avatar Philipp Hörist
Browse files

HtmlTextview: Remove <img> support

If at all this needs to be reimplemented with libsoup
parent 636effbc
No related branches found
No related tags found
No related merge requests found
...@@ -140,7 +140,6 @@ ...@@ -140,7 +140,6 @@
'AV': False, 'AV': False,
'GEOCLUE': False, 'GEOCLUE': False,
'UPNP': False, 'UPNP': False,
'PYCURL': False,
'GSOUND': False, 'GSOUND': False,
'GSPELL': False, 'GSPELL': False,
'IDLE': False, 'IDLE': False,
...@@ -239,13 +238,6 @@ def detect_dependencies(): ...@@ -239,13 +238,6 @@ def detect_dependencies():
except ValueError: except ValueError:
pass pass
# PYCURL
try:
import pycurl # pylint: disable=unused-import
_dependencies['PYCURL'] = True
except ImportError:
pass
# IDLE # IDLE
try: try:
from gajim.common import idle from gajim.common import idle
......
...@@ -38,7 +38,6 @@ ...@@ -38,7 +38,6 @@
import hashlib import hashlib
import shlex import shlex
import socket import socket
import time
import logging import logging
import json import json
import copy import copy
...@@ -52,7 +51,6 @@ ...@@ -52,7 +51,6 @@
from string import Template from string import Template
import urllib import urllib
from urllib.parse import unquote from urllib.parse import unquote
from io import StringIO
from encodings.punycode import punycode_encode from encodings.punycode import punycode_encode
from functools import wraps from functools import wraps
from packaging.version import Version as V from packaging.version import Version as V
...@@ -84,9 +82,6 @@ ...@@ -84,9 +82,6 @@
from gajim.common.const import SHOW_LIST from gajim.common.const import SHOW_LIST
from gajim.common.structs import URI from gajim.common.structs import URI
if app.is_installed('PYCURL'):
import pycurl
log = logging.getLogger('gajim.c.helpers') log = logging.getLogger('gajim.c.helpers')
...@@ -871,137 +866,6 @@ def get_proxy(proxy_name): ...@@ -871,137 +866,6 @@ def get_proxy(proxy_name):
username=username, username=username,
password=password) password=password)
def get_proxy_info(account):
p = app.config.get_per('accounts', account, 'proxy')
if not p:
p = app.config.get('global_proxy')
if p and p in app.config.get_per('proxies'):
proxy = {}
proxyptr = app.config.get_per('proxies', p)
if not proxyptr:
return proxy
for key in proxyptr.keys():
proxy[key] = proxyptr[key]
return proxy
def _get_img_direct(attrs):
"""
Download an image. This function should be launched in a separated thread.
"""
mem = b''
alt = ''
max_size = 2*1024*1024
if 'max_size' in attrs:
max_size = attrs['max_size']
# Wait maximum 10s for connection
socket.setdefaulttimeout(10)
try:
req = urllib.request.Request(attrs['src'])
req.add_header('User-Agent', 'Gajim ' + app.version)
f = urllib.request.urlopen(req)
except Exception as ex:
log.debug('Error loading image %s ', attrs['src'] + str(ex))
alt = attrs.get('alt', 'Broken image')
else:
# Wait 2s between each byte
try:
f.fp._sock.fp._sock.settimeout(2)
except Exception:
pass
# On a slow internet connection with ~1000kbps
# you need ~10 seconds for 1 MB
deadline = time.time() + (10 * (max_size / 1048576))
while True:
if time.time() > deadline:
log.debug('Timeout loading image %s ', attrs['src'])
mem = ''
alt = attrs.get('alt', '')
if alt:
alt += '\n'
alt += _('Timeout loading image')
break
try:
temp = f.read(100)
except socket.timeout as ex:
log.debug('Timeout loading image %s ', attrs['src'] + str(ex))
alt = attrs.get('alt', '')
if alt:
alt += '\n'
alt += _('Timeout loading image')
break
if temp:
mem += temp
else:
break
if len(mem) > max_size:
alt = attrs.get('alt', '')
if alt:
alt += '\n'
alt += _('Image is too big')
break
f.close()
return (mem, alt)
def _get_img_proxy(attrs, proxy):
"""
Download an image through a proxy. This function should be launched in a
separated thread.
"""
if not app.is_installed('PYCURL'):
return '', _('PyCURL is not installed')
alt, max_size = '', 2*1024*1024
if 'max_size' in attrs:
max_size = attrs['max_size']
try:
b = StringIO()
c = pycurl.Curl()
c.setopt(pycurl.URL, attrs['src'].encode('utf-8'))
c.setopt(pycurl.FOLLOWLOCATION, 1)
# Wait maximum 10s for connection
c.setopt(pycurl.CONNECTTIMEOUT, 10)
# On a slow internet connection with ~1000kbps
# you need ~10 seconds for 1 MB
c.setopt(pycurl.TIMEOUT, 10 * (max_size / 1048576))
c.setopt(pycurl.MAXFILESIZE, max_size)
c.setopt(pycurl.WRITEFUNCTION, b.write)
c.setopt(pycurl.USERAGENT, 'Gajim ' + app.version)
# set proxy
c.setopt(pycurl.PROXY, proxy['host'].encode('utf-8'))
c.setopt(pycurl.PROXYPORT, proxy['port'])
if proxy['useauth']:
c.setopt(pycurl.PROXYUSERPWD, proxy['user'].encode('utf-8')\
+ ':' + proxy['pass'].encode('utf-8'))
c.setopt(pycurl.PROXYAUTH, pycurl.HTTPAUTH_ANY)
if proxy['type'] == 'http':
c.setopt(pycurl.PROXYTYPE, pycurl.PROXYTYPE_HTTP)
elif proxy['type'] == 'socks5':
c.setopt(pycurl.PROXYTYPE, pycurl.PROXYTYPE_SOCKS5)
c.close()
t = b.getvalue()
return (t, attrs.get('alt', ''))
except pycurl.error as ex:
alt = attrs.get('alt', '')
if alt:
alt += '\n'
if ex.errno == pycurl.E_FILESIZE_EXCEEDED:
alt += _('Image is too big')
elif ex.errno == pycurl.E_OPERATION_TIMEOUTED:
alt += _('Timeout loading image')
else:
alt += _('Error loading image')
except Exception as ex:
log.debug('Error loading image %s ', attrs['src'] + str(ex))
alt = attrs.get('alt', 'Broken image')
return ('', alt)
def download_image(account, attrs):
proxy = get_proxy_info(account)
if proxy and proxy['type'] in ('http', 'socks5'):
return _get_img_proxy(attrs, proxy)
return _get_img_direct(attrs)
def version_condition(current_version, required_version): def version_condition(current_version, required_version):
if V(current_version) < V(required_version): if V(current_version) < V(required_version):
return False return False
......
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
import re import re
import logging import logging
import urllib
import xml.sax import xml.sax
import xml.sax.handler import xml.sax.handler
from io import StringIO from io import StringIO
...@@ -42,16 +41,12 @@ ...@@ -42,16 +41,12 @@
from gi.repository import Pango from gi.repository import Pango
from gi.repository import Gtk from gi.repository import Gtk
from gi.repository import Gdk from gi.repository import Gdk
from gi.repository import GdkPixbuf
from gi.repository import GLib from gi.repository import GLib
from gajim.common import app from gajim.common import app
from gajim.common import helpers
from gajim.common.i18n import _
from gajim.common.const import StyleAttr from gajim.common.const import StyleAttr
from gajim.common.helpers import open_uri from gajim.common.helpers import open_uri
from gajim.common.helpers import parse_uri from gajim.common.helpers import parse_uri
from gajim.gtk.util import load_icon
from gajim.gtk.util import get_cursor from gajim.gtk.util import get_cursor
from gajim.gui_menu_builder import get_conv_context_menu from gajim.gui_menu_builder import get_conv_context_menu
...@@ -510,123 +505,6 @@ def _create_url(self, href, title, type_, id_): ...@@ -510,123 +505,6 @@ def _create_url(self, href, title, type_, id_):
tag.title = title tag.title = title
return tag return tag
def _update_img(self, output, attrs, img_mark, tags):
'''Callback function called after the function helpers.download_image.
'''
mem, alt = output
self._process_img(attrs, (mem, alt, img_mark, tags))
def _process_img(self, attrs, loaded=None):
'''Process a img tag.
'''
mem = ''
pixbuf = None
replace_mark = None
replace_tags = None
try:
if attrs['src'].startswith('data:image/'):
# The "data" URL scheme http://tools.ietf.org/html/rfc2397
import base64
img = attrs['src'].split(',')[1]
mem = base64.standard_b64decode(urllib.parse.unquote(
img).encode('utf-8'))
elif loaded is not None:
(mem, alt, replace_mark, replace_tags) = loaded
else:
if self.conv_textview:
img_mark = self.textbuf.create_mark(None, self.iter, True)
app.thread_interface(
helpers.download_image,
[self.conv_textview.account, attrs],
self._update_img,
[attrs, img_mark, self._get_style_tags()])
alt = attrs.get('alt', '')
if alt:
alt += '\n'
alt += _('Loading')
pixbuf = load_icon('image-missing',
self.textview,
pixbuf=True)
if mem:
# Caveat: GdkPixbuf is known not to be safe to load
# images from network... this program is now potentially
# hackable ;)
loader = GdkPixbuf.PixbufLoader()
dims = [0, 0]
def height_cb(length):
dims[1] = length
def width_cb(length):
dims[0] = length
# process width and height attributes
width = attrs.get('width')
height = attrs.get('height')
# override with width and height styles
for attr, val in style_iter(attrs.get('style', '')):
if attr == 'width':
width = val
elif attr == 'height':
height = val
if width:
self._parse_length(width, False, False, 1, 1000, width_cb)
if height:
self._parse_length(height, False, False, 1, 1000, height_cb)
def set_size(_pixbuf, width_, height_, dims):
"""
FIXME: Floats should be relative to the whole textview, and
resize with it. This needs new pifbufs for every resize,
GdkPixbuf.Pixbuf.scale_simple or similar.
"""
if isinstance(dims[0], float):
dims[0] = int(dims[0] * width_)
elif not dims[0]:
dims[0] = width_
if isinstance(dims[1], float):
dims[1] = int(dims[1] * height_)
if not dims[1]:
dims[1] = height_
loader.set_size(*dims)
if width or height:
loader.connect('size-prepared', set_size, dims)
loader.write(mem)
loader.close()
pixbuf = loader.get_pixbuf()
alt = attrs.get('alt', '')
working_iter = self.iter
if replace_mark is not None:
working_iter = self.textbuf.get_iter_at_mark(replace_mark)
next_iter = working_iter.copy()
next_iter.forward_char()
self.textbuf.delete(working_iter, next_iter)
self.textbuf.delete_mark(replace_mark)
if pixbuf is not None:
if replace_mark:
tags = replace_tags
else:
tags = self._get_style_tags()
if tags:
tmpmark = self.textbuf.create_mark(None, working_iter, True)
self.textbuf.insert_pixbuf(working_iter, pixbuf)
self.starting = False
if tags:
start = self.textbuf.get_iter_at_mark(tmpmark)
for tag in tags:
self.textbuf.apply_tag(tag, start, working_iter)
self.textbuf.delete_mark(tmpmark)
else:
self._insert_text('[IMG: %s]' % alt, working_iter)
except Exception as ex:
log.error('Error loading image %s', str(ex))
pixbuf = None
alt = attrs.get('alt', 'Broken image')
try:
loader.close()
except Exception:
pass
return pixbuf
def _begin_span(self, style, tag=None, id_=None): def _begin_span(self, style, tag=None, id_=None):
if style is None: if style is None:
self.styles.append(tag) self.styles.append(tag)
...@@ -730,8 +608,7 @@ def startElement(self, name, attrs): ...@@ -730,8 +608,7 @@ def startElement(self, name, attrs):
tag.is_anchor = True tag.is_anchor = True
elif name in LIST_ELEMS: elif name in LIST_ELEMS:
style += ';margin-left: 2em' style += ';margin-left: 2em'
elif name == 'img':
tag = self._process_img(attrs)
if name in _element_styles: if name in _element_styles:
style += _element_styles[name] style += _element_styles[name]
# so that explicit styles override implicit ones, # so that explicit styles override implicit ones,
......
...@@ -40,9 +40,6 @@ ignore_missing_imports = True ...@@ -40,9 +40,6 @@ ignore_missing_imports = True
[mypy-PIL.*] [mypy-PIL.*]
ignore_missing_imports = True ignore_missing_imports = True
[mypy-pycurl.*]
ignore_missing_imports = True
[mypy-netifaces.*] [mypy-netifaces.*]
ignore_missing_imports = True ignore_missing_imports = True
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# A comma-separated list of package or module names from where C extensions may # A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may # be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code # run arbitrary code
extension-pkg-whitelist=pycurl extension-pkg-whitelist=
# Add files or directories to the blacklist. They should be base names, not # Add files or directories to the blacklist. They should be base names, not
# paths. # paths.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment