summaryrefslogtreecommitdiff
path: root/appl/spree/lib/allow.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/spree/lib/allow.b')
-rw-r--r--appl/spree/lib/allow.b194
1 files changed, 194 insertions, 0 deletions
diff --git a/appl/spree/lib/allow.b b/appl/spree/lib/allow.b
new file mode 100644
index 00000000..ef088b08
--- /dev/null
+++ b/appl/spree/lib/allow.b
@@ -0,0 +1,194 @@
+implement Allow;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sets.m";
+ sets: Sets;
+ Set, set, None: import sets;
+include "../spree.m";
+ spree: Spree;
+ Attributes, Range, Object, Clique, Member, rand: import spree;
+include "allow.m";
+
+Action: adt {
+ tag: int;
+ member: ref Member;
+ action: string;
+};
+
+actions: list of Action;
+clique: ref Clique;
+
+init(srvmod: Spree, g: ref Clique)
+{
+ sys = load Sys Sys->PATH;
+ sets = load Sets Sets->PATH;
+ (clique, spree) = (g, srvmod);
+}
+
+ILLEGALNAME: con "/"; # illegal char in member names, ahem.
+archive(archiveobj: ref Object)
+{
+ i := 0;
+ for (al := actions; al != nil; al = tl al) {
+ a := hd al;
+ pname: string;
+ if (a.member != nil)
+ pname = a.member.name;
+ else
+ pname = ILLEGALNAME;
+ archiveobj.setattr(
+ "allow" + string i++,
+ sys->sprint("%d %s %s", a.tag, pname, a.action),
+ None
+ );
+ }
+}
+
+unarchive(archiveobj: ref Object)
+{
+ for (i := 0; (s := archiveobj.getattr("allow" + string i)) != nil; i++) {
+ (n, toks) := sys->tokenize(s, " ");
+ p: ref Member = nil;
+ if (hd tl toks != ILLEGALNAME) {
+ # if the member is no longer around, ignore the action. XXX do we still need to do this?
+ if ((p = clique.membernamed(hd tl toks)) == nil)
+ continue;
+ }
+ sys->print("allow: adding action %d, %ux, %s\n", int hd toks, p, concat(tl tl toks));
+ actions = Action(int hd toks, p, concat(tl tl toks)) :: actions;
+ }
+}
+
+add(tag: int, member: ref Member, action: string)
+{
+# sys->print("allow: add %d, member %ux, action: %s\n", tag, member, action);
+ actions = (tag, member, action) :: actions;
+}
+
+del(tag: int, member: ref Member)
+{
+# sys->print("allow: del %d\n", tag);
+ na: list of Action;
+ for (a := actions; a != nil; a = tl a) {
+ action := hd a;
+ if (action.tag == tag && (member == nil || action.member == member))
+ continue;
+ na = action :: na;
+ }
+ actions = na;
+}
+
+action(member: ref Member, cmd: string): (string, int, list of string)
+{
+ for (al := actions; al != nil; al = tl al) {
+ a := hd al;
+ if (a.member == nil || a.member == member) {
+ (e, v) := match(member, a.action, cmd);
+ if (e != nil || v != nil)
+ return (e, a.tag, v);
+ }
+ }
+ return ("you can't do that", -1, nil);
+}
+
+match(member: ref Member, pat, action: string): (string, list of string)
+{
+# sys->print("allow: matching pat: '%s' against action '%s'\n", pat, action);
+ toks: list of string;
+ na := len action;
+ if (na > 0 && action[na - 1] == '\n')
+ na--;
+
+ (i, j) := (0, 0);
+ for (;;) {
+ for (; i < len pat; i++)
+ if (pat[i] != ' ')
+ break;
+ for (; j < na; j++)
+ if (action[j] != ' ')
+ break;
+ for (i1 := i; i1 < len pat; i1++)
+ if (pat[i1] == ' ')
+ break;
+ for (j1 := j; j1 < na; j1++)
+ if (action[j1] == ' ')
+ break;
+ if (i == i1) {
+ if (j == j1)
+ break;
+ return (nil, nil);
+ }
+ if (j == j1) {
+ if (pat == "&")
+ break;
+ return (nil, nil);
+ }
+ pw := pat[i : i1];
+ w := action[j : j1];
+ case pw[0] {
+ '*' =>
+ toks = w :: toks;
+ '&' =>
+ toks = w :: toks;
+ pat = "&";
+ i1 = 0;
+ '%' =>
+ (ok, nw) := checkformat(member, pw[1], w);
+ if (!ok)
+ return ("invalid field value", nil);
+ toks = nw :: toks;
+ * =>
+ if (w != pw)
+ return (nil, nil);
+ toks = w :: toks;
+ }
+ (i, j) = (i1, j1);
+ }
+ return (nil, revs(toks));
+}
+
+revs(l: list of string): list of string
+{
+ m: list of string;
+ for (; l != nil; l = tl l)
+ m = hd l :: m;
+ return m;
+}
+
+checkformat(p: ref Member, fmt: int, w: string): (int, string)
+{
+ case fmt {
+ 'o' =>
+ # object id
+ if (isnum(w) && (o := p.obj(int w)) != nil)
+ return (1, string o.id);
+ 'd' =>
+ # integer
+ if (isnum(w))
+ return (1, w);
+ 'p' =>
+ # member id
+ if (isnum(w) && (member := clique.member(int w)) != nil)
+ return (1, w);
+ }
+ return (0, nil);
+}
+
+isnum(w: string): int
+{
+ # XXX lazy for the time being...
+ if (w != nil && ((w[0] >= '0' && w[0] <= '9') || w[0] == '-'))
+ return 1;
+ return 0;
+}
+
+concat(v: list of string): string
+{
+ if (v == nil)
+ return nil;
+ s := hd v;
+ for (v = tl v; v != nil; v = tl v)
+ s += " " + hd v;
+ return s;
+}