Skip to content

Parse text-mode delivery reports with message references and recipients #38

Description

@Justinabox

Summary

SMSService._on_delivery_report() assumes the second comma-separated field in a +CMGR status-report response is the recipient. For text-mode status reports that include a message reference before the recipient, it emits recipient="6" and leaves reference=0, so delivery reports cannot be correlated back to the sent SMS reference.

Affected source

  • callstack/sms/service.py:229-258
    • manually uses line.split(",") on a quoted modem response.
    • sets recipient = parts[1].strip().strip('"').
    • never populates the SMSDeliveryReportEvent.reference field even though events/types.py:70-74 defines it.
  • tests/test_delivery_reports.py verifies _RawDeliveryReport dispatch and event defaults, but does not exercise the service-level +CMGR parsing path.

Minimal reproduction

Command run on clean main (23c53805bb63c0aaa7676033b92d108f32de7d81):

PYTHONPATH=. uv run --no-project --with pyserial-asyncio python - <<'PY'
import asyncio
from callstack.events.bus import EventBus
from callstack.events.types import _RawDeliveryReport, SMSDeliveryReportEvent
from callstack.protocol.executor import ATCommandExecutor
from callstack.protocol.urc import URCDispatcher
from callstack.sms.service import SMSService
from callstack.transport.mock import MockTransport

async def main():
    bus = EventBus()
    transport = MockTransport()
    executor = ATCommandExecutor(transport, URCDispatcher(bus))
    service = SMSService(executor, bus)
    async with bus.stream(SMSDeliveryReportEvent) as stream:
        # Text-mode status-report shape: stat, fo, mr, recipient, toa, sent ts, done ts, status.
        transport.feed('+CMGR: "REC READ",6,"+12025550123",145,"24/12/25,14:30:00+04","24/12/25,14:30:05+04",0', 'OK', 'OK')
        await service._on_delivery_report(_RawDeliveryReport(storage='SM', index=5))
        event = await stream.next(timeout=1.0)
        print({'event_reference': event.reference, 'event_recipient': event.recipient, 'event_status': event.status})

asyncio.run(main())
PY

Observed output:

{'event_reference': 0, 'event_recipient': '6', 'event_status': 'delivered'}

Expected behavior

For a text-mode status report containing message reference 6 and a recipient address, Callstack should emit an SMSDeliveryReportEvent with reference=6, the recipient address in recipient, and the parsed status.

Actual behavior

The message reference is misreported as the recipient, and the event reference remains the default 0.

Suggested fix direction

Add a dedicated delivery-report parser instead of naive split(",") parsing. It should handle quoted timestamps with embedded commas, text-mode status-report field order, and populate both reference and recipient. Then wire the parsed reference into SMSDeliveryReportEvent(reference=...) and future HTTP/store surfaces.

Acceptance criteria

  • A service-level test feeds a representative +CDSI/+CMGR status report and observes SMSDeliveryReportEvent(reference=<mr>, recipient=<address>, status="delivered").
  • Pending/failure status-code ranges still map to pending/failed.
  • Quoted timestamps with embedded commas do not shift field indexes.
  • Existing delivery-report tests and full suite continue to pass.

Verification gates

git diff --check
PYTHONPATH=. uv run --no-project --with pytest --with pytest-asyncio --with pytest-aiohttp --with pyserial-asyncio --with aiosqlite pytest tests/ -q

Duplicate search performed

No existing issue/PR was found with:

  • delivery report reference SMSDeliveryReportEvent reference in:title,body
  • CDSI CMGR reference delivery report correlation in:title,body
  • PR search delivery report reference SMSDeliveryReportEvent

Related but not duplicate: #19 is about backing HTTP SMS/delivery-report listings with SMSStore; this issue is about parsing and event correlation before persistence/listing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions