Commit 4e4ab569 authored by mathieui's avatar mathieui

Fix #2447 (OTR & HTML) -- partial WONTFIX

- Guess-parse the OTR messages in search for xhtml upon arrival
- add a configurable option to decode it or not
- We have XHTML-IM for a reason, and therefore we will *not* implement a
  full html parser for clients that dump whatever formatting inside the
  OTR payload (looking at you, pidgin)
parent c3dd20fc
...@@ -121,6 +121,11 @@ Configuration ...@@ -121,6 +121,11 @@ Configuration
.. glossary:: .. glossary::
:sorted: :sorted:
decode_xhtml
**Default:** ``true``
Decode embedded XHTML.
keys_dir keys_dir
**Default:** ``$XDG_DATA_HOME/poezio/otr`` **Default:** ``$XDG_DATA_HOME/poezio/otr``
...@@ -141,8 +146,8 @@ Configuration ...@@ -141,8 +146,8 @@ Configuration
Log conversations (OTR start/end marker, and messages). Log conversations (OTR start/end marker, and messages).
The :term:`allow_v1`, :term:`allow_v2` and :term:`log` configuration The :term:`allow_v1`, :term:`allow_v2`, :term:`decode_html`
parameters are tab-specific. and :term:`log` configuration parameters are tab-specific.
Important details Important details
----------------- -----------------
...@@ -166,6 +171,7 @@ import curses ...@@ -166,6 +171,7 @@ import curses
from potr.context import NotEncryptedError, UnencryptedMessage, ErrorReceived, NotOTRMessage,\ from potr.context import NotEncryptedError, UnencryptedMessage, ErrorReceived, NotOTRMessage,\
STATE_ENCRYPTED, STATE_PLAINTEXT, STATE_FINISHED, Context, Account, crypt STATE_ENCRYPTED, STATE_PLAINTEXT, STATE_FINISHED, Context, Account, crypt
import xhtml
from plugin import BasePlugin from plugin import BasePlugin
from tabs import ConversationTab, DynamicConversationTab, PrivateTab from tabs import ConversationTab, DynamicConversationTab, PrivateTab
from common import safeJID from common import safeJID
...@@ -463,8 +469,14 @@ class Plugin(BasePlugin): ...@@ -463,8 +469,14 @@ class Plugin(BasePlugin):
user = None user = None
body = txt.decode() body = txt.decode()
if self.config.get_by_tabname('decode_xhtml', True, msg['from'].bare):
try:
body = xhtml.xhtml_to_poezio_colors(body, force=True)
except:
pass
tab.add_message(body, nickname=tab.nick, jid=msg['from'], tab.add_message(body, nickname=tab.nick, jid=msg['from'],
forced_user=user, typ=ctx.log, nick_color=theming.get_theme().COLOR_REMOTE_USER) forced_user=user, typ=ctx.log,
nick_color=theming.get_theme().COLOR_REMOTE_USER)
hl(tab) hl(tab)
self.core.refresh_window() self.core.refresh_window()
del msg['body'] del msg['body']
......
...@@ -281,13 +281,15 @@ def trim(string): ...@@ -281,13 +281,15 @@ def trim(string):
return re.sub(whitespace_re, ' ', string) return re.sub(whitespace_re, ' ', string)
class XHTMLHandler(sax.ContentHandler): class XHTMLHandler(sax.ContentHandler):
def __init__(self): def __init__(self, force_ns=False):
self.builder = [] self.builder = []
self.formatting = [] self.formatting = []
self.attrs = [] self.attrs = []
self.list_state = [] self.list_state = []
self.is_pre = False self.is_pre = False
self.a_start = 0 self.a_start = 0
# do not care about xhtml-in namespace
self.force_ns = force_ns
@property @property
def result(self): def result(self):
...@@ -305,7 +307,7 @@ class XHTMLHandler(sax.ContentHandler): ...@@ -305,7 +307,7 @@ class XHTMLHandler(sax.ContentHandler):
self.builder.append(characters if self.is_pre else trim(characters)) self.builder.append(characters if self.is_pre else trim(characters))
def startElementNS(self, name, _, attrs): def startElementNS(self, name, _, attrs):
if name[0] != XHTML_NS: if name[0] != XHTML_NS and not self.force_ns:
return return
builder = self.builder builder = self.builder
...@@ -356,7 +358,7 @@ class XHTMLHandler(sax.ContentHandler): ...@@ -356,7 +358,7 @@ class XHTMLHandler(sax.ContentHandler):
self.append_formatting('\x19b') self.append_formatting('\x19b')
def endElementNS(self, name, _): def endElementNS(self, name, _):
if name[0] != XHTML_NS: if name[0] != XHTML_NS and not self.force_ns:
return return
builder = self.builder builder = self.builder
...@@ -387,13 +389,13 @@ class XHTMLHandler(sax.ContentHandler): ...@@ -387,13 +389,13 @@ class XHTMLHandler(sax.ContentHandler):
if 'title' in attrs: if 'title' in attrs:
builder.append(' [' + attrs['title'] + ']') builder.append(' [' + attrs['title'] + ']')
def xhtml_to_poezio_colors(xml): def xhtml_to_poezio_colors(xml, force=False):
if isinstance(xml, str): if isinstance(xml, str):
xml = xml.encode('utf8') xml = xml.encode('utf8')
elif not isinstance(xml, bytes): elif not isinstance(xml, bytes):
xml = ET.tostring(xml) xml = ET.tostring(xml)
handler = XHTMLHandler() handler = XHTMLHandler(force_ns=force)
parser = sax.make_parser() parser = sax.make_parser()
parser.setFeature(sax.handler.feature_namespaces, True) parser.setFeature(sax.handler.feature_namespaces, True)
parser.setContentHandler(handler) parser.setContentHandler(handler)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment