Skip to content

Commit

Permalink
Merge pull request #133 from Shizmob/develop
Browse files Browse the repository at this point in the history
v0.9.4rc1
  • Loading branch information
theunkn0wn1 authored Feb 10, 2020
2 parents 7a19ee6 + 6f5a3d7 commit 662a23c
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 2 deletions.
2 changes: 1 addition & 1 deletion pydle/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ async def handle_forever(self):
try:
await self.rawmsg("PING", self.server_tag)
data = await self.connection.recv(timeout=self.READ_TIMEOUT)
except asyncio.TimeoutError:
except (asyncio.TimeoutError, ConnectionResetError) as e:
data = None

if not data:
Expand Down
29 changes: 28 additions & 1 deletion pydle/features/ircv3/tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,24 @@
import pydle.client
import pydle.protocol
from pydle.features import rfc1459
import re

TAG_INDICATOR = '@'
TAG_SEPARATOR = ';'
TAG_VALUE_SEPARATOR = '='
TAGGED_MESSAGE_LENGTH_LIMIT = 1024

TAG_CONVERSIONS = {
r"\:": ';',
r"\s": ' ',
r"\\": '\\',
r"\r": '\r',
r"\n": '\n'
}


class TaggedMessage(rfc1459.RFC1459Message):

def __init__(self, tags=None, **kw):
super().__init__(**kw)
self._kw['tags'] = tags
Expand Down Expand Up @@ -53,6 +63,20 @@ def parse(cls, line, encoding=pydle.protocol.DEFAULT_ENCODING):
else:
tag = raw_tag
value = True
# Parse escape sequences since IRC escapes != python escapes

# convert known escapes first
for escape, replacement in TAG_CONVERSIONS.items():
value = value.replace(escape, replacement)

# convert other escape sequences based on the spec
pattern =re.compile(r"(\\[\s\S])+")
for match in pattern.finditer(value):
escape = match.group()
value = value.replace(escape, escape[1])


# Finally: add constructed tag to the output object.
tags[tag] = value

# Parse rest of message.
Expand All @@ -77,7 +101,10 @@ def construct(self, force=False):
message = TAG_INDICATOR + TAG_SEPARATOR.join(raw_tags) + ' ' + message

if len(message) > TAGGED_MESSAGE_LENGTH_LIMIT and not force:
raise protocol.ProtocolViolation('The constructed message is too long. ({len} > {maxlen})'.format(len=len(message), maxlen=TAGGED_MESSAGE_LENGTH_LIMIT), message=message)
raise protocol.ProtocolViolation(
'The constructed message is too long. ({len} > {maxlen})'.format(len=len(message),
maxlen=TAGGED_MESSAGE_LENGTH_LIMIT),
message=message)
return message


Expand Down
3 changes: 3 additions & 0 deletions pydle/features/rfc1459/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -923,6 +923,9 @@ async def on_raw_353(self, message):
safe_entry = entry.lstrip(''.join(self._nickname_prefixes.keys()))
# Parse entry and update database.
nick, metadata = self._parse_user(safe_entry)
if not nick:
# nonsense nickname
continue
self._sync_user(nick, metadata)

# Get prefixes.
Expand Down
24 changes: 24 additions & 0 deletions tests/test_ircv3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import pytest

from pydle.features import ircv3

pytestmark = pytest.mark.unit


@pytest.mark.parametrize(
"payload, expected",
[
(
rb"@+example=raw+:=,escaped\:\s\\ :irc.example.com NOTICE #channel :Message",
{"+example": """raw+:=,escaped; \\"""}
),
(
rb"@+example=\foo\bar :irc.example.com NOTICE #channel :Message",
{"+example": "foobar"}
),
]
)
def test_tagged_message_escape_sequences(payload, expected):
message = ircv3.tags.TaggedMessage.parse(payload)

assert message.tags == expected
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ markers =
slow: may take several seconds or more to complete.
meta: tests the test suite itself.
real: tests pydle against a real server. Requires PYDLE_TESTS_REAL_HOST and PYDLE_TESTS_REAL_PORT environment variables.
unit: unit tests

0 comments on commit 662a23c

Please sign in to comment.