Specify that unknown payload types should be ignored

This commit is contained in:
Kovid Goyal
2024-07-23 21:14:29 +05:30
parent 786b7aa7c7
commit 9484814c3f
3 changed files with 29 additions and 19 deletions

View File

@@ -156,7 +156,9 @@ Key Value Default Description
direct responses to the correct window. direct responses to the correct window.
``p`` One of ``title``, ``title`` Whether the payload is the notification title or body or query. If a ``p`` One of ``title``, ``title`` Whether the payload is the notification title or body or query. If a
``body`` or ``?`` notification has no title, the body will be used as title. ``body`` or ``?`` notification has no title, the body will be used as title. Terminal
emulators should ignore payloads of unknown type to allow for future
expansion of this protocol.
``o`` One of ``always``, ``always`` When to honor the notification request. ``unfocused`` means when the window ``o`` One of ``always``, ``always`` When to honor the notification request. ``unfocused`` means when the window
``unfocused`` or the notification is sent on does not have keyboard focus. ``invisible`` ``unfocused`` or the notification is sent on does not have keyboard focus. ``invisible``

View File

@@ -137,7 +137,7 @@ class QueryResponse(Exception):
self.response_string = response_string self.response_string = response_string
def parse_osc_99(raw: str) -> NotificationCommand: def parse_osc_99(raw: str, log_warnings: bool = True) -> NotificationCommand:
cmd = NotificationCommand() cmd = NotificationCommand()
metadata, payload = raw.partition(';')[::2] metadata, payload = raw.partition(';')[::2]
payload_is_encoded = False payload_is_encoded = False
@@ -147,7 +147,8 @@ def parse_osc_99(raw: str) -> NotificationCommand:
try: try:
k, v = part.split('=', 1) k, v = part.split('=', 1)
except Exception: except Exception:
log_error('Malformed OSC 99: metadata is not key=value pairs') if log_warnings:
log_error('Malformed OSC 99: metadata is not key=value pairs')
return cmd return cmd
if k == 'p': if k == 'p':
payload_type = v payload_type = v
@@ -183,19 +184,21 @@ def parse_osc_99(raw: str) -> NotificationCommand:
i = f'i={sanitize_id(cmd.identifier or "0")}:' i = f'i={sanitize_id(cmd.identifier or "0")}:'
raise QueryResponse(f'99;{i}p=?;a={actions}:o={when}:u={urgency}') raise QueryResponse(f'99;{i}p=?;a={actions}:o={when}:u={urgency}')
if payload_type not in ('body', 'title'): if payload_type in ('body', 'title'):
log_error(f'Malformed OSC 99: unknown payload type: {payload_type}') if payload_is_encoded:
return NotificationCommand() try:
if payload_is_encoded: payload = standard_b64decode(payload).decode('utf-8')
try: except Exception:
payload = standard_b64decode(payload).decode('utf-8') if log_warnings:
except Exception: log_error('Malformed OSC 99: payload is not base64 encoded UTF-8 text')
log_error('Malformed OSC 99: payload is not base64 encoded UTF-8 text') return NotificationCommand()
return NotificationCommand() if payload_type == 'title':
if payload_type == 'title': cmd.title = payload
cmd.title = payload else:
cmd.body = payload
else: else:
cmd.body = payload if log_warnings:
log_error(f'OSC 99: unknown payload type: {payload_type}, ignoring payload')
return cmd return cmd
@@ -293,10 +296,11 @@ def handle_notification_cmd(
raw_data: str, raw_data: str,
window_id: int, window_id: int,
prev_cmd: NotificationCommand, prev_cmd: NotificationCommand,
notify_implementation: NotifyImplementation = notify_implementation notify_implementation: NotifyImplementation = notify_implementation,
log_warnings: bool = True,
) -> Optional[NotificationCommand]: ) -> Optional[NotificationCommand]:
if osc_code == 99: if osc_code == 99:
cmd = merge_osc_99(prev_cmd, parse_osc_99(raw_data)) cmd = merge_osc_99(prev_cmd, parse_osc_99(raw_data, log_warnings=log_warnings))
if cmd.done: if cmd.done:
notify_with_command(cmd, window_id, notify_implementation) notify_with_command(cmd, window_id, notify_implementation)
cmd = NotificationCommand() cmd = NotificationCommand()

View File

@@ -542,7 +542,7 @@ class TestParser(BaseTest):
def h(raw_data, osc_code=99, window_id=1): def h(raw_data, osc_code=99, window_id=1):
nonlocal prev_cmd nonlocal prev_cmd
try: try:
x = handle_notification_cmd(osc_code, raw_data, window_id, prev_cmd, notify) x = handle_notification_cmd(osc_code, raw_data, window_id, prev_cmd, notify, log_warnings=False)
if x is not None and osc_code == 99: if x is not None and osc_code == 99:
prev_cmd = x prev_cmd = x
except QueryResponse as err: except QueryResponse as err:
@@ -582,7 +582,6 @@ class TestParser(BaseTest):
self.ae(activations, [('0', 1, True, False)]) self.ae(activations, [('0', 1, True, False)])
reset() reset()
h('d=0:i=x:a=-report;title') h('d=0:i=x:a=-report;title')
h('d=1:i=x:a=report;body') h('d=1:i=x:a=report;body')
self.ae(notifications, [('titlebody', '', 'i0', Urgency.Normal)]) self.ae(notifications, [('titlebody', '', 'i0', Urgency.Normal)])
@@ -590,6 +589,11 @@ class TestParser(BaseTest):
self.ae(activations, [('x', 1, True, True)]) self.ae(activations, [('x', 1, True, True)])
reset() reset()
h('d=0:i=y;title')
h('d=1:i=y:p=xxx;title')
self.ae(notifications, [('title', '', 'i0', Urgency.Normal)])
reset()
h(';title') h(';title')
self.ae(notifications, [('title', '', 'i0', Urgency.Normal)]) self.ae(notifications, [('title', '', 'i0', Urgency.Normal)])
notification_activated(notifications[-1][-2], activated) notification_activated(notifications[-1][-2], activated)