Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
79
tundra/runtime/sms-inbox.py
Normal file
79
tundra/runtime/sms-inbox.py
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
"""Keep oFono incoming messages until Gecko durably acknowledges them."""
|
||||
import fcntl
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import time
|
||||
import uuid
|
||||
|
||||
ROOT = Path('/var/lib/tundra/sms')
|
||||
|
||||
|
||||
def transaction(change, root=ROOT, filename="inbox.json"):
|
||||
if filename not in ("inbox.json", "outgoing.json"): raise ValueError("INVALID_SMS_STORE")
|
||||
root.mkdir(parents=True, mode=0o700, exist_ok=True)
|
||||
with (root/'lock').open('a') as lock:
|
||||
fcntl.flock(lock, fcntl.LOCK_EX)
|
||||
path = root/filename
|
||||
rows = json.loads(path.read_text()) if path.exists() else []
|
||||
result = change(rows)
|
||||
temporary = path.with_suffix('.tmp')
|
||||
with open(temporary, 'w', opener=lambda p, f: os.open(p, f, 0o600)) as stream:
|
||||
os.fchmod(stream.fileno(),0o600)
|
||||
json.dump(rows,stream)
|
||||
stream.flush(); os.fsync(stream.fileno())
|
||||
temporary.replace(path)
|
||||
return result
|
||||
|
||||
|
||||
def pending():
|
||||
return transaction(lambda rows: rows[:100])
|
||||
|
||||
|
||||
def acknowledge(ids):
|
||||
if not isinstance(ids,list) or len(ids)>100 or any(not isinstance(i,str) or len(i)>40 for i in ids):
|
||||
raise ValueError('INVALID_SMS_IDS')
|
||||
def remove(rows):
|
||||
rows[:] = [row for row in rows if row['receipt'] not in ids]
|
||||
transaction(remove)
|
||||
return True
|
||||
|
||||
|
||||
def outgoing_state(path):
|
||||
rows = transaction(lambda rows: list(rows), filename='outgoing.json')
|
||||
return next((row['state'] for row in reversed(rows) if row['path'] == path), None)
|
||||
|
||||
|
||||
def record_outgoing(path, state):
|
||||
if state not in ('sent','failed'): return
|
||||
def update(rows):
|
||||
rows[:] = [row for row in rows if row['path'] != path][-999:]
|
||||
rows.append({'path':path,'state':state,'timestamp':round(time.time()*1000)})
|
||||
transaction(update, filename='outgoing.json')
|
||||
|
||||
|
||||
def main():
|
||||
import dbus
|
||||
from dbus.mainloop.glib import DBusGMainLoop
|
||||
from gi.repository import GLib
|
||||
os.umask(0o077)
|
||||
DBusGMainLoop(set_as_default=True)
|
||||
bus = dbus.SystemBus()
|
||||
def incoming(body, properties):
|
||||
row = {'receipt':str(uuid.uuid4()),'sender':str(properties.get('Sender','')),
|
||||
'body':str(body),'timestamp':round(time.time()*1000)}
|
||||
transaction(lambda rows:rows.append(row))
|
||||
bus.add_signal_receiver(incoming,signal_name='IncomingMessage',
|
||||
dbus_interface='org.ofono.MessageManager',bus_name='org.ofono',path='/ril_0')
|
||||
def outgoing(name, value, path=None):
|
||||
if name == 'State' and path and str(path).startswith('/ril_0/message'):
|
||||
record_outgoing(str(path), str(value))
|
||||
bus.add_signal_receiver(outgoing, signal_name='PropertyChanged',
|
||||
dbus_interface='org.ofono.Message', bus_name='org.ofono', path_keyword='path')
|
||||
GLib.MainLoop().run()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Loading…
Reference in a new issue