Forum teuk.org

🧙 Mediabot v3: Moving DCC / CTCP Parsing into a Dedicated Module

in Mediabot · started by TeuK · 1w ago

TeuK · 1w ago

🧙 Mediabot v3: Moving DCC / CTCP Parsing into a Dedicated Module

Another cleanup and reliability milestone has been reached for Mediabot v3.

This update focuses on one fragile area that recently caused real-world pain: DCC CHAT and CTCP CHAT handling.

The Partyline already supports:

telnet localhost <partyline-port>
/ctcp <botnick> CHAT
/dcc chat <botnick>

But the parsing logic for those different client behaviors was still living directly inside mediabot.pl, mixed with the private command parser.

That worked, but it was fragile.


Why this mattered

Different IRC clients can deliver DCC / CTCP requests in different forms.

For example:

\x01CHAT\x01
\x01DCC CHAT chat <ip_int> <port>\x01
\x01DCC CHAT chat 0 0 <token>\x01
CHAT chat <ip_int> <port>

The dangerous case is raw DCC CHAT:

\x01DCC CHAT chat <ip_int> <port>\x01

If Mediabot does not intercept it early enough, the private command parser may see the first word as:

dcc

and produce:

Private command 'dcc' not found

That is exactly the kind of regression we do not want to see again.


What changed

A new module was added:

Mediabot/DCC.pm

It provides pure parsing helpers:

strip_ctcp_delimiters()
parse_ctcp_payload()
parse_dcc_chat_payload()
ip_int_to_ipv4()

The important point is that this module contains no socket handling and sends no IRC commands.

It only parses payloads.

That makes it easy to test and much safer to evolve.


Runtime integration

mediabot.pl now imports the parser:

use Mediabot::DCC qw(parse_ctcp_payload);

and routes CTCP / DCC payloads through the shared parser before the private command parser can treat raw DCC CHAT as a normal command.

The runtime now logs the new path explicitly:

CTCP CHAT request from <nick> via Mediabot::DCC parser
DCC CHAT request from <nick> via Mediabot::DCC parser ip=<ip_int> port=<port>

The older inline parsing blocks are still present as a temporary fallback, but the new parser path is now the primary route.


New parser tests

A new test file was added:

t/cases/11_dcc_parser.t

It validates the pure parser logic for:

raw CTCP CHAT
stripped CTCP CHAT
raw CTCP DCC CHAT active mode
raw CTCP DCC CHAT passive/token mode
stripped DCC CHAT
malformed DCC payloads
DCC integer IPv4 conversion

Example payloads covered:

\x01CHAT\x01
\x01DCC CHAT chat 1383695523 1024\x01
\x01DCC CHAT chat 0 0 123456\x01
CHAT chat 1383695523 1024

This gives the DCC parsing logic its own dedicated safety net.


Regression test update

The existing DCC / CTCP regression test was updated:

t/cases/10_dcc_ctcp_regression.t

It now verifies that mediabot.pl is actually wired to Mediabot::DCC and that the parser path happens before private command dispatch.

This protects against the old bug where /dcc chat <botnick> could fall through as an unknown private command named dcc.


Real tests performed

The three Partyline access paths were tested successfully:

/dcc chat mediabotv3
/ctcp mediabotv3 CHAT
telnet localhost 23456

The Partyline login flow still works, password input is not echoed, and connected Partyline users are listed correctly.


Why this is a good refactor

This is not a flashy user-visible feature, but it is an important internal cleanup.

Before:

DCC / CTCP parsing lived inline in mediabot.pl
several payload forms were handled in separate places
regressions were easy to introduce

After:

DCC / CTCP parsing has a dedicated module
the parser is unit-tested
mediabot.pl uses the shared parser
regression tests protect the runtime path

This is exactly the kind of change that makes Mediabot easier to maintain as it becomes more Eggdrop-like.


Files involved

Main files touched by this milestone:

Mediabot/DCC.pm
mediabot.pl
t/cases/10_dcc_ctcp_regression.t
t/cases/11_dcc_parser.t

Suggested commit

🧙 Portus Parserum: move DCC and CTCP parsing into a tested module

Mediabot v3 now has a cleaner and safer DCC / CTCP parsing layer, with real tests around a previously fragile Partyline path.

You must be logged in to reply.