From: NeilBrown Date: Thu, 19 Dec 2013 04:18:23 +0000 (+1100) Subject: Initial support for profiles and rules. X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=991f10f40d2cab4b86c5467480c5b62dac3b8a00;p=plato.git Initial support for profiles and rules. Alert can be controlled by rules which can be affected by time of day and number calling. --- diff --git a/alarm/alarm.c b/alarm/alarm.c index 50590c3..ea90c01 100644 --- a/alarm/alarm.c +++ b/alarm/alarm.c @@ -221,7 +221,7 @@ void event_deliver(struct alarm_ev *ev) } f = open("/run/alert/alarm", O_WRONLY | O_CREAT, 0600); if (f) { - write(f, "new\n", 4); + write(f, "alarm\n", 4); close(f); } /* Abort any current suspend cycle */ diff --git a/gsm/gsmd2.py b/gsm/gsmd2.py index a30156a..ff74988 100644 --- a/gsm/gsmd2.py +++ b/gsm/gsmd2.py @@ -77,6 +77,7 @@ def call_log_end(key): def set_alert(key, value): path = '/run/alert/' + key + tpath = '/run/alert/.new.' + key if value == None: try: os.unlink(path) @@ -84,9 +85,10 @@ def set_alert(key, value): pass else: try: - f = open(path, 'w') + f = open(tpath, 'w') f.write(value) f.close() + os.rename(tpath, path) except IOError: pass suspend.abort_cycle() @@ -1289,7 +1291,7 @@ class voice(Engine): self.number = number record('incoming', n) record('status', 'INCOMING') - set_alert('ring','new') + set_alert('ring',n) self.delay = 500 self.state = 'incoming' self.retry() @@ -1390,7 +1392,7 @@ class sms_recv(Engine): self.to_delete = res[:-10] self.retry(1) if found: - set_alert('sms','new') + set_alert('sms',reduce(lambda x,y: x+','+y, found)) self.unblock() return False if not line or line[:5] == 'ERROR' or line[:10] == '+CMS ERROR': diff --git a/lib/profile.py b/lib/profile.py new file mode 100644 index 0000000..bb396b6 --- /dev/null +++ b/lib/profile.py @@ -0,0 +1,124 @@ +# +# Load a list of profiles. Later ones over-ride +# earlier. +# These are just variable assignments stored in a map. + +import time + +expect = [ + 'tone', + 'volume', + 'vibrate', + 'LED', +] + +def read_profile(p, file): + global expect + try: + f = open(file) + l = f.readlines() + except IOError: + l = [] + for ln in l: + ln = ln.strip() + w = ln.split(':', 1) + if len(w) == 2: + k = w[0].strip() + if k in expect: + p[k] = w[1].strip() + else: + raise ValueError + +def load_profile(p, t): + if '=' in t: + pr = t.split('=', 1) + p[pr[0].strip()] = pr[1].strip() + else: + read_profile(p, "/data/profiles/"+t) + +def get_profile(event, who): + try: + f = open("/data/rules") + l = f.readlines() + except IOError: + l = [] + p = {} + for ln in l: + ln = ln.strip() + w = ln.split(':', 1) + if len(w) == 2 and rule_matches(w[0].strip(), event, who): + load_profile(p, w[1].strip()) + return p + +def rule_matches(rule, event, who): + if rule == '': + return True + if rule == event: + return True + for w in who.split(' '): + if w[-8:] == rule[-8:]: + return True + dt = rule.split(' ') + tm = time.localtime() + for d in dt: + a = day_match(d, tm) + if a == None: + a = time_match(d, tm) + if a == True: + return True + #if a == None: + # raise ValueError + return False + + +# python is broken: tm_wday==0 means monday!!! +days = ['mo','tu','we','th','fr','sa','su'] +def day_match(d, tm): + global days + dl = d.split(',') + for d1 in dl: + if d1 in days: + if days.index(d1) == tm.tm_wday: + return True + elif len(d1)==5 and d1[2] == '-': + da = d1[0:2] + db = d1[3:5] + if da not in days or db not in days: + return None + dan = days.index(da) + dbn = days.index(db) + if dan <= dbn and dan <= tm.tm_wday and tm.tm_wday <= dbn: + return True + if dan > dbn and (dan <= tm.tm_wday or dbn >= tm.tm_wday): + return True + else: + return None + return False + + +def time_match(t, tm): + tl = t.split(',') + for t1 in tl: + if len(t1) != 11 or t1[5] != '-': + return None + m1 = to_min(t1[0:5]) + m2 = to_min(t1[6:11]) + if m1 < 0 or m2 < 0: + return None + mn = tm.tm_hour*60 + tm.tm_min + if m1 <= m2 and m1 <= mn and mn <= m2: + return True + if m1 > m2 and (mn >= m1 or mn <= m2): + return True + return False + +def to_min(t): + h=t[0:2] + m=t[3:5] + if not h.isdigit() or not m.isdigit(): + return -1 + h=int(h) + m=int(m) + if h >= 24 or m >= 60: + return -1; + return h*60 + m diff --git a/sms/storesms.py b/sms/storesms.py index 4777864..2b8d411 100644 --- a/sms/storesms.py +++ b/sms/storesms.py @@ -540,7 +540,7 @@ def sms_update(messages, sim): mfile = os.path.join(dir, '.sim-mirror-'+sim) mirror = load_mirror(mfile) mirror_seen = {} - found_one = False + found_one = [] for index in messages: sender, date, txt, ref, part = messages[index] k = date[2:] + ' ' + sender @@ -549,7 +549,7 @@ def sms_update(messages, sim): sender=sender, text=txt.encode('utf-8'), state='NEW', ref=ref, part=part) store.store(sms) - found_one = True + found_one.append(sender) mirror[index] = k mirror_seen[index] = k diff --git a/utils/lock.py b/utils/lock.py index f33d037..f627608 100755 --- a/utils/lock.py +++ b/utils/lock.py @@ -97,6 +97,29 @@ def clear_vibe(): vib_han.close() vib_han = None + +from profile import * + +def do_alert(event, who): + p = get_profile(event, who) + + n = '/run/sound/10-alert' + if 'tone' in p and p['tone']: + path = p['tone'] + if 'volume' in p: + v = int(p['volume']) + if v < 10: + n = n + ('%d' % v) + if path[0] != '/': + path = os.path.join("/usr/share/openmoko/sounds",path) + try: + os.symlink(path, n) + except: + pass + if 'vib' in p and p['vib']: + set_vibrate(200,400,1800) + return n + class SetAlerts: def __init__(self, alertdir, actiondir): # arrange to respond to alerts. @@ -168,12 +191,13 @@ class SetAlerts: return False def action(self, name): - n = '/run/sound/10-alert' try: - os.symlink(os.path.join(self.actiondir, self.pref, name), n) - except: - pass - set_vibrate(200,400,1800) + f = open(os.path.join(self.alertdir, name)) + l = f.readline() + f.close() + except IOError: + l = "new" + n = do_alert(name, l) if display.state != 'on': set_dim()