Message to a non-numeric address is dropped without an error #1

Closed
opened 2026-10-07 17:59:29 +00:00 by asxpi · 2 comments

Message to a non-numeric address is dropped without an error

What happens

A chat message to *censored*@telegram.xmpp.asxp.io (a username, not an id)
goes nowhere: nothing reaches Telegram, nothing is logged, and no error comes
back, so the client shows the message as sent.

Why

component/gateway.tcl ::tg::onMessage: peerOf returns "" for anything
but <numeric id>@<domain> (gateway.tcl:91), and the $peer eq "" branch
(gateway.tcl:253) only handles messages to the bare gateway domain (chat
commands) and otherwise returns silently.

Expected

Bounce it (the existing bounce helper) with item-not-found, e.g. "Not a
Telegram address: use the user's numeric id, or look up @username through
jabber:iq:gateway". Optionally, for a localpart that looks like a username,
resolve it and say which JID to use.

The same silent return applies to presence subscriptions to such a JID
(onPresence, gateway.tcl:158).

Environment

feat/telegram-connect at cb68dd9, in anotherim-server's compose
deployment (ejabberd 26.09), linked to a real Telegram account.

## Message to a non-numeric address is dropped without an error ### What happens A chat message to `*censored*@telegram.xmpp.asxp.io` (a username, not an id) goes nowhere: nothing reaches Telegram, nothing is logged, and no error comes back, so the client shows the message as sent. ### Why `component/gateway.tcl` `::tg::onMessage`: `peerOf` returns "" for anything but `<numeric id>@<domain>` (`gateway.tcl:91`), and the `$peer eq ""` branch (`gateway.tcl:253`) only handles messages to the bare gateway domain (chat commands) and otherwise returns silently. ### Expected Bounce it (the existing `bounce` helper) with `item-not-found`, e.g. "Not a Telegram address: use the user's numeric id, or look up @username through jabber:iq:gateway". Optionally, for a localpart that looks like a username, resolve it and say which JID to use. The same silent return applies to presence subscriptions to such a JID (`onPresence`, `gateway.tcl:158`). ### Environment `feat/telegram-connect` at `cb68dd9`, in anotherim-server's compose deployment (ejabberd 26.09), linked to a real Telegram account.
Author

Better than only bouncing: resolve the username on the gateway side, so any
client works without a jabber:iq:gateway UI.

When peerOf finds no numeric id and the localpart is a valid Telegram
username ([A-Za-z][A-Za-z0-9_]{3,31}), call the engine's resolve (the
same call onGatewaySet makes) and then either:

  1. Deliver and correct. Send the message to the resolved peer and tell
    the user the canonical address once, e.g. a chat line from the gateway
    ("@censored is censored@telegram.; messages to the username
    address are forwarded") or a roster push adding the numeric JID with the
    username as its name (XEP-0356, the privilege is already granted). Replies
    still come from the numeric JID, so the client ends up with two chats.
  2. Bounce with the answer. item-not-found (or redirect, RFC 6120
    8.3.3.14, whose text is the new address: xmpp:*censored*@telegram.<domain>)
    so the client can retry or offer the right contact. Nothing is sent.

Option 2 keeps one address per peer and is what XMPP clients already
understand; option 1 is friendlier when the client ignores the error. Either
way, an unresolvable username or an unlinked account gets the bounce from
this issue, not silence.

Confirmed the resolve works against real Telegram: jabber:iq:gateway
@*censored* → *censored*@telegram.xmpp.asxp.io.

Better than only bouncing: resolve the username on the gateway side, so any client works without a jabber:iq:gateway UI. When `peerOf` finds no numeric id and the localpart is a valid Telegram username (`[A-Za-z][A-Za-z0-9_]{3,31}`), call the engine's `resolve` (the same call `onGatewaySet` makes) and then either: 1. **Deliver and correct.** Send the message to the resolved peer and tell the user the canonical address once, e.g. a chat line from the gateway ("@*censored* is *censored*@telegram.<domain>; messages to the username address are forwarded") or a roster push adding the numeric JID with the username as its name (XEP-0356, the privilege is already granted). Replies still come from the numeric JID, so the client ends up with two chats. 2. **Bounce with the answer.** `item-not-found` (or `redirect`, RFC 6120 8.3.3.14, whose text is the new address: `xmpp:*censored*@telegram.<domain>`) so the client can retry or offer the right contact. Nothing is sent. Option 2 keeps one address per peer and is what XMPP clients already understand; option 1 is friendlier when the client ignores the error. Either way, an unresolvable username or an unlinked account gets the bounce from this issue, not silence. Confirmed the resolve works against real Telegram: jabber:iq:gateway `@*censored*` → `*censored*@telegram.xmpp.asxp.io`.
ann referenced this issue from a commit 2026-10-12 23:13:07 +00:00
The three open issues: a message to a non-numeric address is bounced instead of dropped (#1), a linked account's contacts reach the roster (#2), and the gateway's presence survives a reconnect (#3). gateway.tcl bounces a chat message to a JID on our domain that names no peer with item-not-found, saying how to address a Telegram user; when the localpart is a Telegram username the linked account resolves it and the error names the JID to write to, or says no such user; a presence subscription to such a JID is answered unsubscribed. The engine gains `contacts` (account.Contacts over contacts.getContacts, the users' access hashes kept through peers.Apply, deleted accounts left out; the fake answers Alice and Bob; docs/frames.md), and the new component/roster.tcl puts them in the user's roster when the account turns ready and every time the component's stream comes up: with the roster privilege the server states in its XEP-0356 <privilege> message, a roster get and the pushes that make it match (adds, renames, contacts gone from Telegram removed, one item per iq); without one, an XEP-0144 roster item exchange. The grant may arrive before or after the stream's ready event, so it is kept until the stream drops and the sync waits two seconds for it. On every ready main.tcl sends each linked user the gateway's presence again and a probe, and the engine's account list sends it too when the stream was up first. DESIGN.md's registration step 5 and the milestones now say what M0 does. The libtacky submodule moves to the rig that grants the privilege under XMPP_COMPONENT_PRIVILEGE=1; make e2e runs the end-to-end test in both modes, with the gateway restarted in the middle to see its presence come back and the roster left alone. make test passes (coverage 92.5 %); e2e 44 of 44 with the privilege and 44 of 44 without.
Owner

Fixed in 58b32c7 (main): a message to a JID on the gateway domain that names no peer is bounced item-not-found instead of dropped. When the localpart is a Telegram username and the account is linked, the error names the JID to write to (@alice is 1001@telegram.…); when no such user exists it says so. A presence subscription to such a JID is answered unsubscribed. Covered by make e2e.

Fixed in 58b32c7 (main): a message to a JID on the gateway domain that names no peer is bounced `item-not-found` instead of dropped. When the localpart is a Telegram username and the account is linked, the error names the JID to write to (`@alice is 1001@telegram.…`); when no such user exists it says so. A presence subscription to such a JID is answered `unsubscribed`. Covered by `make e2e`.
ann closed this issue 2026-10-12 23:17:56 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
another-im/tackygram#1
No description provided.