summaryrefslogtreecommitdiff
path: root/appl/demo/chat
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/demo/chat
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/demo/chat')
-rw-r--r--appl/demo/chat/chat.b203
-rw-r--r--appl/demo/chat/chat.disbin0 -> 3995 bytes
-rw-r--r--appl/demo/chat/chat.sbl695
-rwxr-xr-xappl/demo/chat/chatclient.sh20
-rw-r--r--appl/demo/chat/chatsrv.b268
-rw-r--r--appl/demo/chat/chatsrv.disbin0 -> 4058 bytes
-rw-r--r--appl/demo/chat/chatsrv.sbl938
-rw-r--r--appl/demo/chat/mkfile30
8 files changed, 2154 insertions, 0 deletions
diff --git a/appl/demo/chat/chat.b b/appl/demo/chat/chat.b
new file mode 100644
index 00000000..fe0d4fbf
--- /dev/null
+++ b/appl/demo/chat/chat.b
@@ -0,0 +1,203 @@
+implement Chat;
+
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+ draw: Draw;
+
+include "tk.m";
+ tk: Tk;
+
+include "tkclient.m";
+ tkclient: Tkclient;
+
+Chat: module {
+ init: fn(ctxt: ref Draw->Context, args: list of string);
+};
+
+stderr: ref Sys->FD;
+
+tksetup := array [] of {
+ "frame .f",
+ "text .f.t -state disabled -wrap word -yscrollcommand {.f.sb set}",
+ "scrollbar .f.sb -orient vertical -command {.f.t yview}",
+ "entry .e -bg white",
+ "bind .e <Key-\n> {send cmd send}",
+ "pack .f.sb -in .f -side left -fill y",
+ "pack .f.t -in .f -side left -fill both -expand 1",
+ "pack .f -side top -fill both -expand 1",
+ "pack .e -side bottom -fill x",
+ "pack propagate . 0",
+ "update",
+};
+
+init(ctxt: ref Draw->Context, args: list of string)
+{
+ sys = load Sys Sys->PATH;
+ sys->pctl(Sys->NEWPGRP, nil);
+ stderr = sys->fildes(2);
+
+ draw = load Draw Draw->PATH;
+ if (draw == nil)
+ badmodule(Draw->PATH);
+
+ tk = load Tk Tk->PATH;
+ if (tk == nil)
+ badmodule(Tk->PATH);
+
+ tkclient = load Tkclient Tkclient->PATH;
+ if (tkclient == nil)
+ badmodule(Tkclient->PATH);
+
+
+ if (args == nil || tl args == nil) {
+ sys->fprint(stderr, "usage: chat [servicedir]\n");
+ raise "fail:init";
+ }
+ args = tl args;
+
+ servicedir := ".";
+ if(args != nil)
+ servicedir = hd args;
+
+ tkclient->init();
+ (win, winctl) := tkclient->toplevel(ctxt, nil, "Chat", Tkclient->Appl);
+
+ cmd := chan of string;
+ tk->namechan(win, cmd, "cmd");
+ tkcmds(win, tksetup);
+ tkcmd(win, ". configure -height 300");
+ fittoscreen(win);
+ tkclient->onscreen(win, nil);
+ tkclient->startinput(win, "kbd"::"ptr"::nil);
+
+ msgs := chan of string;
+ conn := chan of (string, ref Sys->FD);
+ spawn connect(servicedir, msgs, conn);
+ msgsfd: ref Sys->FD;
+
+ for (;;) alt {
+ (e, fd) := <-conn =>
+ if (msgsfd == nil) {
+ if (e == nil) {
+ output(win, "*** connected");
+ msgsfd = fd;
+ } else
+ output(win, "*** " + e);
+ } else {
+ output(win, "*** disconnected");
+ msgsfd = nil;
+ }
+
+ txt := <-msgs =>
+ output(win, txt);
+
+ <- cmd =>
+ msg := tkcmd(win, ".e get");
+ if (msgsfd != nil && msg != nil) {
+ tkcmd(win, ".f.t see end");
+ tkcmd(win, ".e delete 0 end");
+ tkcmd(win, "update");
+ d := array of byte msg;
+ sys->write(msgsfd, d, len d);
+ }
+
+ s := <-win.ctxt.kbd =>
+ tk->keyboard(win, s);
+ s := <-win.ctxt.ptr =>
+ tk->pointer(win, *s);
+ s := <-win.ctxt.ctl or
+ s = <-win.wreq or
+ s = <-winctl =>
+ tkclient->wmctl(win, s);
+ }
+}
+
+err(s: string)
+{
+ sys->fprint(stderr, "chat: %s\n", s);
+ raise "fail:err";
+}
+
+badmodule(path: string)
+{
+ err(sys->sprint("can't load module %s: %r", path));
+}
+
+tkcmds(t: ref Tk->Toplevel, cmds: array of string)
+{
+ for (i := 0; i < len cmds; i++)
+ tkcmd(t, cmds[i]);
+}
+
+tkcmd(t: ref Tk->Toplevel, cmd: string): string
+{
+ s := tk->cmd(t, cmd);
+ if (s != nil && s[0] == '!')
+ sys->fprint(stderr, "chat: tk error: %s [%s]\n", s, cmd);
+ return s;
+}
+
+connect(dir: string, msgs: chan of string, conn: chan of (string, ref Sys->FD))
+{
+ srvpath := dir+"/msgs";
+ msgsfd := sys->open(srvpath, Sys->ORDWR);
+ if(msgsfd == nil) {
+ conn <-= (sys->sprint("internal error: can't open %s: %r", srvpath), nil);
+ return;
+ }
+ conn <-= (nil, msgsfd);
+ buf := array[Sys->ATOMICIO] of byte;
+ while((n := sys->read(msgsfd, buf, len buf)) > 0)
+ msgs <-= string buf[0:n];
+ conn <-= (nil, nil);
+}
+
+firstmsg := 1;
+output(win: ref Tk->Toplevel, txt: string)
+{
+ if (firstmsg)
+ firstmsg = 0;
+ else
+ txt = "\n" + txt;
+ yview := tkcmd(win, ".f.t yview");
+ (nil, toks) := sys->tokenize(yview, " ");
+ toks = tl toks;
+
+ tkcmd(win, ".f.t insert end '" + txt);
+ if (hd toks == "1")
+ tkcmd(win, ".f.t see end");
+ tkcmd(win, "update");
+}
+
+KEYBOARDH: con 90;
+
+fittoscreen(win: ref Tk->Toplevel)
+{
+ Point, Rect: import draw;
+ if (win.image == nil || win.image.screen == nil)
+ return;
+ r := win.image.screen.image.r;
+ scrsize := Point((r.max.x - r.min.x), (r.max.y - r.min.y)- KEYBOARDH);
+ bd := int tkcmd(win, ". cget -bd");
+ winsize := Point(int tkcmd(win, ". cget -actwidth") + bd * 2, int tkcmd(win, ". cget -actheight") + bd * 2);
+ if (winsize.x > scrsize.x)
+ tkcmd(win, ". configure -width " + string (scrsize.x - bd * 2));
+ if (winsize.y > scrsize.y)
+ tkcmd(win, ". configure -height " + string (scrsize.y - bd * 2));
+ actr: Rect;
+ actr.min = Point(int tkcmd(win, ". cget -actx"), int tkcmd(win, ". cget -acty"));
+ actr.max = actr.min.add((int tkcmd(win, ". cget -actwidth") + bd*2,
+ int tkcmd(win, ". cget -actheight") + bd*2));
+ (dx, dy) := (actr.dx(), actr.dy());
+ if (actr.max.x > r.max.x)
+ (actr.min.x, actr.max.x) = (r.min.x - dx, r.max.x - dx);
+ if (actr.max.y > r.max.y)
+ (actr.min.y, actr.max.y) = (r.min.y - dy, r.max.y - dy);
+ if (actr.min.x < r.min.x)
+ (actr.min.x, actr.max.x) = (r.min.x, r.min.x + dx);
+ if (actr.min.y < r.min.y)
+ (actr.min.y, actr.max.y) = (r.min.y, r.min.y + dy);
+ tkcmd(win, ". configure -x " + string actr.min.x + " -y " + string actr.min.y);
+}
diff --git a/appl/demo/chat/chat.dis b/appl/demo/chat/chat.dis
new file mode 100644
index 00000000..9dd3a3a3
--- /dev/null
+++ b/appl/demo/chat/chat.dis
Binary files differ
diff --git a/appl/demo/chat/chat.sbl b/appl/demo/chat/chat.sbl
new file mode 100644
index 00000000..860c56d7
--- /dev/null
+++ b/appl/demo/chat/chat.sbl
@@ -0,0 +1,695 @@
+limbo .sbl 2.1
+Chat
+5
+chat.b
+sys.m
+draw.m
+tk.m
+tkclient.m
+462
+37.1,25 0
+38.1,29 1
+11,23 1
+25,28 1
+1,29 1
+1,29 1
+39.1,24 2
+22,23 2
+1,24 2
+1,24 2
+41.1,28 3
+42.5,16 4
+43.2,23 5
+12,22 5
+2,23 5
+45.1,22 6
+46.5,14 7
+47.2,21 8
+12,20 8
+2,21 8
+49.1,40 9
+50.5,20 10
+51.2,27 11
+12,26 11
+2,27 11
+54.5,16 12
+20,27 12
+20,34 12
+20,34 13
+55.2,51 14
+14,20 14
+22,50 14
+2,51 14
+2,51 14
+56.2,19 15
+58.1,15 16
+60.1,18 17
+61.4,15 18
+62.2,22 19
+64.1,17 20
+1,17 20
+65.18,71 21
+37,41 21
+43,46 21
+48,54 21
+56,70 21
+18,71 21
+18,71 21
+67.1,22 22
+68.1,30 23
+14,17 23
+19,22 23
+24,29 23
+1,30 23
+1,30 23
+1,30 24
+69.1,21 25
+8,11 25
+13,20 25
+1,21 25
+70.1,38 26
+7,10 26
+12,37 26
+1,38 26
+1,38 26
+1,38 27
+71.1,17 28
+13,16 28
+1,17 28
+72.1,29 29
+20,23 29
+25,28 29
+1,29 29
+73.1,45 30
+22,25 30
+41,44 30
+34,44 30
+27,44 30
+27,44 30
+27,44 31
+1,45 30
+75.1,23 32
+76.1,38 33
+77.1,38 34
+15,25 34
+27,31 34
+33,37 34
+1,38 34
+81.14,18 35
+14,18 35
+93.10,14 35
+10,14 35
+96.4,7 35
+4,7 35
+106.8,16 35
+8,20 35
+8,20 36
+8,20 35
+108.8,16 35
+8,20 35
+8,20 37
+8,20 35
+110.8,16 35
+8,20 35
+8,20 38
+8,20 35
+111.7,15 35
+7,15 35
+112.7,13 35
+7,13 35
+80.10,16 35
+10,16 35
+10,16 35
+10,16 35
+81.12,18 35
+12,18 39
+12,18 40
+82.6,19 41
+83.7,15 42
+84.4,32 43
+11,14 43
+16,31 43
+4,32 43
+85.4,15 44
+4,15 45
+87.4,27 46
+11,14 46
+16,26 46
+4,27 46
+4,27 47
+89.3,34 48
+10,13 48
+15,33 48
+3,34 48
+90.3,15 49
+3,15 50
+3,15 51
+3,15 52
+3,15 35
+94.2,18 53
+9,12 53
+14,17 53
+2,18 53
+2,18 54
+2,18 35
+2,18 55
+97.2,29 56
+15,18 56
+20,28 56
+2,29 56
+2,29 56
+98.6,19 57
+23,33 57
+99.3,29 58
+9,12 58
+14,28 58
+3,29 58
+3,29 58
+3,29 59
+100.3,32 60
+9,12 60
+14,31 60
+3,32 60
+3,32 60
+3,32 61
+101.3,23 62
+9,12 62
+14,22 62
+3,23 62
+3,23 62
+3,23 63
+102.3,25 64
+103.3,31 65
+14,20 65
+22,23 65
+25,30 65
+3,31 65
+3,31 65
+3,31 66
+3,31 67
+3,31 35
+107.2,22 68
+15,18 68
+20,21 68
+2,22 68
+2,22 35
+109.2,22 69
+14,17 69
+19,21 69
+2,22 69
+2,22 70
+2,22 35
+2,22 35
+2,22 35
+113.2,25 71
+18,21 71
+23,24 71
+2,25 71
+2,25 71
+2,25 72
+2,25 73
+2,25 35
+119.1,37 74
+13,19 74
+21,33 74
+35,36 74
+1,37 74
+1,37 74
+120.1,17 75
+125.5,50 76
+17,43 76
+45,49 76
+5,50 76
+5,50 76
+1,51 76
+1,51 76
+1,51 77
+1,51 76
+126.0,1 78
+130.6,12 79
+18,26 80
+14,26 80
+131.2,19 81
+8,9 81
+11,18 81
+11,18 81
+2,19 81
+2,19 81
+2,19 82
+130.28,31 83
+28,31 83
+132.0,1 84
+136.1,21 85
+14,15 85
+17,20 85
+1,21 85
+1,21 85
+137.5,13 86
+17,21 86
+17,28 86
+138.2,58 87
+14,20 87
+22,49 87
+51,52 87
+54,57 87
+2,58 87
+2,58 87
+139.8,9 88
+1,9 88
+144.1,23 89
+145.1,41 90
+21,28 90
+30,40 90
+1,41 90
+1,41 90
+146.4,17 91
+147.12,69 92
+24,59 92
+61,68 92
+12,69 92
+12,69 92
+71,74 92
+2,75 92
+2,75 93
+2,75 94
+148.2,8 95
+150.11,14 96
+16,22 96
+1,23 96
+1,23 97
+1,23 98
+151.1,36 99
+152.7,45 100
+23,29 100
+31,34 100
+36,43 100
+7,45 100
+7,45 100
+7,45 100
+7,49 100
+153.18,21 101
+18,26 101
+11,26 101
+2,26 101
+2,26 102
+2,26 102
+154.11,14 103
+16,19 103
+1,20 103
+1,20 104
+1,20 105
+155.0,1 106
+160.5,13 107
+161.2,14 108
+2,14 109
+163.2,18 110
+164.1,34 111
+16,19 111
+21,33 111
+1,34 111
+1,34 111
+165.16,41 112
+30,35 112
+37,40 112
+16,41 112
+16,41 112
+7,11 112
+7,11 113
+166.1,15 114
+168.1,38 115
+7,10 115
+12,37 115
+1,38 115
+1,38 115
+1,38 116
+169.5,12 117
+5,19 117
+5,19 118
+170.2,28 119
+8,11 119
+13,27 119
+2,28 119
+2,28 119
+2,28 120
+171.1,21 121
+7,10 121
+12,20 121
+1,21 121
+1,21 121
+1,21 122
+172.0,1 123
+179.5,21 124
+25,34 124
+25,48 124
+25,48 125
+180.2,8 126
+181.6,15 127
+6,22 127
+6,28 127
+1,30 127
+1,30 128
+182.18,37 129
+39,58 129
+39,69 129
+183.11,35 130
+17,20 130
+22,34 130
+11,35 130
+11,35 130
+1,35 130
+1,35 131
+184.22,52 132
+28,31 132
+33,51 132
+22,52 132
+22,52 132
+18,52 132
+18,52 133
+55,61 132
+18,61 132
+67,98 132
+73,76 132
+78,97 132
+67,98 132
+67,98 132
+63,98 132
+63,98 134
+101,107 132
+63,107 132
+185.5,26 135
+186.2,65 136
+8,11 136
+57,63 136
+44,64 136
+37,64 136
+13,64 136
+13,64 137
+2,65 136
+2,65 136
+2,65 138
+187.5,26 139
+188.2,66 140
+8,11 140
+58,64 140
+45,65 140
+38,65 140
+13,65 140
+13,65 141
+2,66 140
+2,66 140
+2,66 142
+190.22,48 143
+28,31 143
+33,47 143
+22,48 143
+22,48 143
+18,48 143
+18,48 144
+54,80 143
+60,63 143
+65,79 143
+54,80 143
+54,80 143
+50,80 143
+50,80 145
+1,81 143
+191.30,60 146
+36,39 146
+41,59 146
+30,60 146
+30,60 146
+26,60 146
+26,60 147
+63,67 146
+26,67 146
+192.8,39 146
+14,17 146
+19,38 146
+8,39 146
+8,39 146
+4,39 146
+4,39 148
+42,46 146
+4,46 146
+191.1,192.48 146
+191.12,20 146
+12,20 146
+1,192.48 146
+191.1,192.48 146
+193.14,23 149
+14,18 149
+14,23 149
+14,23 149
+25,34 149
+25,29 149
+25,34 149
+25,34 149
+194.5,25 150
+195.30,42 151
+44,56 151
+196.5,25 152
+197.30,42 153
+44,56 153
+198.5,25 154
+199.30,37 155
+39,51 155
+200.5,25 156
+201.30,37 157
+39,51 157
+202.1,79 158
+7,10 158
+32,49 158
+12,49 158
+12,58 158
+61,78 158
+12,78 158
+12,78 159
+12,78 160
+1,79 158
+1,79 158
+1,79 161
+203.0,1 162
+13
+aSys->Dir 1:26.1,39.2 64
+11
+0:name:28.2,6 s
+4:uid:29.2,5 s
+8:gid:30.2,5 s
+12:muid:31.2,6 s
+16:qid:32.2,5 @1
+
+32:mode:33.2,6 i
+36:atime:34.2,7 i
+40:mtime:35.2,7 i
+48:length:36.2,8 B
+56:dtype:37.2,7 i
+60:dev:38.2,5 i
+aSys->Qid 11.1,16.2 16
+3
+0:path:13.2,6 B
+8:vers:14.2,6 i
+12:qtype:15.2,7 i
+aDraw->Chans 2:70.1,82.2 4
+1
+0:desc:72.2,6 i
+aDraw->Context 274.1,279.2 12
+3
+0:display:276.2,9 R@4
+
+4:screen:277.2,8 R@8
+
+8:wm:278.2,4 Ct8.2
+0:t0:15,21 s
+4:t1:15,21 Ct8.2
+0:t0:32,38 s
+4:t1:32,38 R@9
+
+
+
+aDraw->Display 201.1,230.2 20
+5
+0:image:203.2,7 R@5
+
+4:white:204.2,7 R@5
+
+8:black:205.2,7 R@5
+
+12:opaque:206.2,8 R@5
+
+16:transparent:207.2,13 R@5
+
+aDraw->Image 142.1,198.2 56
+8
+0:r:146.2,3 @6
+
+16:clipr:147.2,7 @6
+
+32:depth:148.2,7 i
+36:chans:149.2,7 @2
+
+40:repl:150.2,6 i
+44:display:151.2,9 R@4
+
+48:screen:152.2,8 R@8
+
+52:iname:153.2,7 s
+aDraw->Rect 116.1,139.2 16
+2
+0:min:118.2,5 @7
+
+8:max:119.2,5 @7
+
+aDraw->Point 99.1,113.2 8
+2
+0:x:101.2,3 i
+4:y:102.2,3 i
+aDraw->Screen 249.1,263.2 16
+4
+0:id:251.2,4 i
+4:image:252.2,7 R@5
+
+8:fill:253.2,6 R@5
+
+12:display:254.2,9 R@4
+
+aDraw->Wmcontext 282.1,291.2 28
+7
+0:kbd:284.2,5 Ci
+4:ptr:285.2,5 CR@10
+
+8:ctl:286.2,5 Cs
+12:wctl:287.2,6 Cs
+16:images:288.2,8 CR@5
+
+20:connfd:289.2,8 R@11
+
+24:ctxt:290.2,6 R@3
+
+aDraw->Pointer 266.1,271.2 16
+3
+0:buttons:268.2,9 i
+4:xy:269.2,4 @7
+
+12:msec:270.2,6 i
+aSys->FD 1:45.1,48.2 4
+1
+0:fd:47.2,4 i
+aTk->Toplevel 3:5.1,12.2 32
+5
+0:display:7.2,9 R@4
+
+4:wreq:8.2,6 Cs
+8:image:9.2,7 R@5
+
+12:ctxt:10.2,6 R@9
+
+16:screenr:11.2,9 @6
+
+8
+0:init
+2
+32:ctxt:0:35.5,9 R@3
+
+36:args:30,34 Ls
+15
+40:win:65.2,5 R@12
+
+44:winctl:7,13 Cs
+48:msgsfd:78.1,7 R@11
+
+52:s:110.1,2 s
+56:cmd:67.1,4 Cs
+60:conn:76.1,5 Ct8.2
+0:t0:18,24 s
+4:t1:18,24 R@11
+
+
+64:d:102.3,4 Ab
+68:e:81.2,3 s
+72:fd:5,7 R@11
+
+76:msg:97.2,5 s
+80:msgs:75.1,5 Cs
+84:servicedir:60.1,11 s
+88:s:106.1,2 i
+92:s:108.1,2 R@10
+
+96:txt:93.1,4 s
+n202:err
+1
+32:s:117.4,5 s
+0
+n209:badmodule
+1
+32:path:123.10,14 s
+0
+n219:tkcmds
+2
+32:t:128.7,8 R@12
+
+36:cmds:28,32 As
+1
+40:i:130.6,7 i
+n232:tkcmd
+2
+32:t:134.6,7 R@12
+
+36:cmd:27,30 s
+1
+40:s:136.1,2 s
+s249:connect
+3
+32:dir:142.8,11 s
+36:msgs:21,25 Cs
+40:conn:43,47 Ct8.2
+0:t0:58,64 s
+4:t1:58,64 R@11
+
+
+4
+44:buf:151.1,4 Ab
+48:msgsfd:145.1,7 R@11
+
+52:srvpath:144.1,8 s
+56:n:152.8,9 i
+n292:output
+2
+32:win:158.7,10 R@12
+
+36:txt:30,33 s
+2
+40:toks:165.7,11 Ls
+44:yview:164.1,6 s
+n331:fittoscreen
+1
+32:win:176.12,15 R@12
+
+7
+36:bd:183.1,3 i
+40:dx:193.2,4 i
+44:dy:6,8 i
+72:actr:189.1,5 @6
+
+88:r:181.1,2 @6
+
+104:scrsize:182.1,8 @7
+
+112:winsize:184.1,8 @7
+
+n7
+164:draw:7.1,5 mDraw
+2:1.0,298.1 0
+
+176:firstmsg:0:157.0,8 i
+196:stderr:19.0,6 R@11
+
+200:sys:4.1,4 mSys
+1:0,160.1 0
+
+204:tk:0:10.1,3 mTk
+3:1.0,25.1 0
+
+208:tkclient:0:13.1,9 mTkclient
+4:1.0,26.1 0
+
+212:tksetup:0:21.0,7 As
diff --git a/appl/demo/chat/chatclient.sh b/appl/demo/chat/chatclient.sh
new file mode 100755
index 00000000..11ebf15b
--- /dev/null
+++ b/appl/demo/chat/chatclient.sh
@@ -0,0 +1,20 @@
+#!/dis/sh
+load std
+autoload=std
+ndb/cs
+
+chatroom=$1
+
+fn ck {
+ or {$*} {
+ echo chatclient: exiting >[1=2]
+ raise error
+ }
+}
+user="{cat /dev/user}
+
+ck mount -A 'tcp!$registry!registry' /mnt/registry
+ck /dis/grid/remotelogon wm/wm {
+ k = /usr/$user/keyring/default
+ grid/find -a resource chat -a pk `{getpk -s $k} Enter {demo/chat/chat /n/client} Shell {wm/sh}
+}
diff --git a/appl/demo/chat/chatsrv.b b/appl/demo/chat/chatsrv.b
new file mode 100644
index 00000000..adf56ef4
--- /dev/null
+++ b/appl/demo/chat/chatsrv.b
@@ -0,0 +1,268 @@
+implement Chatsrv;
+
+#
+# simple text-based chat service
+#
+
+include "sys.m";
+ sys: Sys;
+ Qid: import Sys;
+
+include "draw.m";
+
+include "styx.m";
+ styx: Styx;
+ Tmsg, Rmsg: import Styx;
+
+include "styxservers.m";
+ styxservers: Styxservers;
+ Styxserver, Navigator: import styxservers;
+ nametree: Nametree;
+ Tree: import nametree;
+
+Chatsrv : module {
+ init : fn (ctxt : ref Draw->Context, args : list of string);
+};
+
+Qdir, Qusers, Qmsgs: con iota;
+
+tc: chan of ref Tmsg;
+srv: ref Styxserver;
+
+user := "inferno";
+
+dir(name: string, perm: int, path: int): Sys->Dir
+{
+ d := sys->zerodir;
+ d.name = name;
+ d.uid = user;
+ d.gid = user;
+ d.qid.path = big path;
+ if(perm & Sys->DMDIR)
+ d.qid.qtype = Sys->QTDIR;
+ else
+ d.qid.qtype = Sys->QTFILE;
+ d.mode = perm;
+ return d;
+}
+
+badmod(path: string)
+{
+ sys->fprint(sys->fildes(1), "chatsrv: cannot load %s: %r\n", path);
+ exit;
+}
+
+init(nil: ref Draw->Context, nil: list of string)
+{
+ sys = load Sys Sys->PATH;
+ styx = load Styx Styx->PATH;
+ if(styx == nil)
+ badmod(Styx->PATH);
+ styxservers = load Styxservers Styxservers->PATH;
+ if(styxservers == nil)
+ badmod(Styxservers->PATH);
+ nametree = load Nametree Nametree->PATH;
+ if(nametree == nil)
+ badmod(Nametree->PATH);
+ styx->init();
+ styxservers->init(styx);
+ nametree->init();
+
+ (tree, treeop) := nametree->start();
+ tree.create(big Qdir, dir(".", Sys->DMDIR|8r555, Qdir));
+ tree.create(big Qdir, dir("users", 8r444, Qusers));
+ tree.create(big Qdir, dir("msgs", 8r666, Qmsgs));
+
+ nextmsg = ref Msg (0, nil, nil, nil);
+ keptmsg = nextmsg;
+
+ (tc, srv) = Styxserver.new(sys->fildes(0), Navigator.new(treeop), big Qdir);
+ chatsrv(tree);
+}
+
+chatsrv(tree: ref Tree)
+{
+ while((tmsg := <-tc) != nil){
+ pick tm := tmsg {
+ Readerror =>
+ break;
+ Flush =>
+ cancelpending(tm.tag);
+ srv.reply(ref Rmsg.Flush(tm.tag));
+ Open =>
+ c := srv.open(tm);
+ if (c == nil)
+ break;
+ if (int c.path == Qmsgs){
+ newmsgclient(tm.fid, c.uname);
+ #root[0].qid.vers++; # TO DO
+ }
+ Read =>
+ c := srv.getfid(tm.fid);
+ if (c == nil || !c.isopen) {
+ srv.reply(ref Rmsg.Error(tm.tag, Styxservers->Ebadfid));
+ break;
+ }
+ case int c.path {
+ Qdir =>
+ srv.read(tm);
+ Qmsgs =>
+ mc := getmsgclient(tm.fid);
+ if (mc == nil) {
+ srv.reply(ref Rmsg.Error(tm.tag, "internal error -- lost client"));
+ continue;
+ }
+ tm.offset = big 0;
+ msg := getnextmsg(mc);
+ if (msg == nil) {
+ if(mc.pending != nil)
+ srv.reply(ref Rmsg.Error(tm.tag, "read already pending"));
+ else
+ mc.pending = tm;
+ continue;
+ }
+ srv.reply(styxservers->readstr(tm, msg));
+ Qusers =>
+ srv.reply(styxservers->readstr(tm, usernames()));
+ * =>
+ srv.reply(ref Rmsg.Error(tm.tag, "phase error -- bad path"));
+ }
+ Write =>
+ c := srv.getfid(tm.fid);
+ if (c == nil || !c.isopen) {
+ srv.reply(ref Rmsg.Error(tm.tag, Styxservers->Ebadfid));
+ continue;
+ }
+ if (int c.path != Qmsgs) {
+ srv.reply(ref Rmsg.Error(tm.tag, Styxservers->Eperm));
+ continue;
+ }
+ writemsgclients(tm.fid, c.uname, string tm.data);
+ srv.reply(ref Rmsg.Write(tm.tag, len tm.data));
+ Clunk =>
+ c := srv.clunk(tm);
+ if (c != nil && int c.path == Qmsgs){
+ closemsgclient(tm.fid);
+ # root[0].qid.vers++; # TO DO
+ }
+ * =>
+ srv.default(tmsg);
+ }
+ }
+ tree.quit();
+ sys->print("chatsrv exit\n");
+}
+
+Msg: adt {
+ fromfid: int;
+ from: string;
+ msg: string;
+ next: cyclic ref Msg;
+};
+
+Msgclient: adt {
+ fid: int;
+ name: string;
+ nextmsg: ref Msg;
+ pending: ref Tmsg.Read;
+ next: cyclic ref Msgclient;
+};
+
+NKEPT: con 6;
+keptcount := 0;
+nextmsg: ref Msg;
+keptmsg: ref Msg;
+msgclients: ref Msgclient;
+
+usernames(): string
+{
+ s := "";
+ for (c := msgclients; c != nil; c = c.next)
+ s += c.name+"\n";
+ return s;
+}
+
+newmsgclient(fid: int, name: string)
+{
+ writemsgclients(fid, nil, "+++ " + name + " has arrived");
+ msgclients = ref Msgclient(fid, name, keptmsg, nil, msgclients);
+}
+
+getmsgclient(fid: int): ref Msgclient
+{
+ for (c := msgclients; c != nil; c = c.next)
+ if (c.fid == fid)
+ return c;
+ return nil;
+}
+
+cancelpending(tag: int)
+{
+ for (c := msgclients; c != nil; c = c.next)
+ if((tm := c.pending) != nil && tm.tag == tag){
+ c.pending = nil;
+ break;
+ }
+}
+
+closemsgclient(fid: int)
+{
+ prev: ref Msgclient;
+ s := "";
+ for (c := msgclients; c != nil; c = c.next) {
+ if (c.fid == fid) {
+ if (prev == nil)
+ msgclients = c.next;
+ else
+ prev.next = c.next;
+ s = "--- " + c.name + " has left";
+ break;
+ }
+ prev = c;
+ }
+ if (s != nil)
+ writemsgclients(fid, nil, s);
+}
+
+writemsgclients(fromfid: int, from: string, msg: string)
+{
+ nm := ref Msg(0, nil, nil, nil);
+ nextmsg.fromfid = fromfid;
+ nextmsg.from = from;
+ nextmsg.msg = msg;
+ nextmsg.next = nm;
+
+ for (c := msgclients; c != nil; c = c.next) {
+ if (c.pending != nil) {
+ s := msgtext(nextmsg);
+ srv.reply(styxservers->readstr(c.pending, s));
+ c.pending = nil;
+ c.nextmsg = nm;
+ }
+ }
+ nextmsg = nm;
+ if (keptcount < NKEPT)
+ keptcount++;
+ else
+ keptmsg = keptmsg.next;
+}
+
+getnextmsg(mc: ref Msgclient): string
+{
+# uncomment next two lines to eliminate queued messages to self
+# while(mc.nextmsg.next != nil && mc.nextmsg.fromfid == mc.fid)
+# mc.nextmsg = mc.nextmsg.next;
+ if ((m := mc.nextmsg).next != nil){
+ mc.nextmsg = m.next;
+ return msgtext(m);
+ }
+ return nil;
+}
+
+msgtext(m: ref Msg): string
+{
+ prefix := "";
+ if (m.from != nil)
+ prefix = m.from + ": ";
+ return prefix + m.msg;
+}
diff --git a/appl/demo/chat/chatsrv.dis b/appl/demo/chat/chatsrv.dis
new file mode 100644
index 00000000..f333c6be
--- /dev/null
+++ b/appl/demo/chat/chatsrv.dis
Binary files differ
diff --git a/appl/demo/chat/chatsrv.sbl b/appl/demo/chat/chatsrv.sbl
new file mode 100644
index 00000000..eb2561a8
--- /dev/null
+++ b/appl/demo/chat/chatsrv.sbl
@@ -0,0 +1,938 @@
+limbo .sbl 2.1
+Chatsrv
+5
+chatsrv.b
+sys.m
+draw.m
+styx.m
+styxservers.m
+502
+1:41.18,21 0
+23,26 0
+28,31 0
+33,36 0
+39,44 0
+46,47 0
+49,50 0
+53,54 0
+56,57 0
+59,60 0
+62,67 0
+69,70 0
+72,73 0
+0:37.1,14 1
+38.1,13 2
+39.1,13 3
+40.1,22 4
+41.4,21 5
+4,21 5
+42.2,26 6
+2,26 7
+44.2,27 8
+45.1,14 9
+46.8,9 10
+1,9 10
+51.13,27 11
+25,26 11
+13,27 11
+13,27 11
+1,67 11
+1,67 11
+1,67 12
+29,60 11
+62,66 11
+1,67 11
+1,67 11
+52.1,5 13
+57.1,25 14
+58.1,28 15
+59.4,15 16
+60.2,20 17
+9,19 17
+2,20 17
+61.1,49 18
+62.4,22 19
+63.2,27 20
+9,26 20
+2,27 20
+64.1,40 21
+65.4,19 22
+66.2,24 23
+9,23 23
+2,24 23
+67.1,13 24
+1,13 24
+68.1,24 25
+19,23 25
+1,24 25
+69.1,17 26
+1,17 26
+71.19,36 27
+19,36 27
+19,36 27
+72.23,55 28
+27,30 28
+32,48 28
+50,54 28
+23,55 28
+23,55 28
+1,56 28
+1,5 28
+13,21 28
+13,21 28
+13,21 29
+13,21 30
+13,21 31
+13,21 32
+1,56 28
+1,56 28
+1,56 33
+73.23,50 34
+27,34 34
+36,41 34
+43,49 34
+23,50 34
+23,50 34
+1,51 34
+1,5 34
+13,21 34
+13,21 34
+13,21 35
+13,21 36
+13,21 37
+13,21 38
+1,51 34
+1,51 34
+1,51 39
+74.23,48 40
+27,33 40
+35,40 40
+42,47 40
+23,48 40
+23,48 40
+1,49 40
+1,5 40
+13,21 40
+13,21 40
+13,21 41
+13,21 42
+13,21 43
+13,21 44
+1,49 40
+1,49 40
+1,49 45
+76.1,37 46
+20,21 46
+23,26 46
+28,31 46
+33,36 46
+1,37 46
+1,37 47
+77.1,18 48
+79.28,42 49
+40,41 49
+28,42 49
+28,42 49
+44,65 49
+58,64 49
+44,65 49
+44,65 49
+13,76 49
+13,76 49
+13,76 50
+13,76 49
+13,76 51
+67,75 49
+13,76 49
+13,76 49
+2,4 49
+6,9 49
+6,9 52
+6,9 53
+80.1,14 54
+9,13 54
+1,14 54
+81.0,1 55
+85.7,21 56
+7,21 56
+7,28 56
+7,28 57
+86.7,17 58
+7,17 58
+88.3,8 59
+90.3,24 60
+17,23 60
+3,24 60
+91.3,36 61
+3,6 61
+13,35 61
+17,35 61
+28,34 61
+13,35 61
+13,35 62
+3,36 61
+3,36 61
+3,36 58
+93.3,20 63
+8,11 63
+17,19 63
+3,20 63
+3,20 63
+94.7,15 64
+7,15 65
+95.4,9 66
+96.7,17 67
+7,26 67
+97.4,33 68
+17,23 68
+25,32 68
+4,33 68
+4,33 69
+4,33 58
+101.3,26 70
+8,11 70
+19,25 70
+3,26 70
+3,26 70
+102.7,15 71
+20,28 71
+103.4,59 72
+4,7 72
+14,58 72
+18,58 72
+29,35 72
+37,57 72
+14,58 72
+14,58 73
+4,59 72
+4,59 72
+4,59 74
+104.4,9 75
+106.8,18 76
+8,18 76
+8,18 76
+8,18 76
+108.4,16 77
+4,7 77
+13,15 77
+4,16 77
+4,16 77
+4,16 78
+4,16 76
+110.4,30 79
+23,29 79
+4,30 79
+4,30 79
+111.8,17 80
+112.5,71 81
+5,8 81
+15,70 81
+19,70 81
+30,36 81
+38,69 81
+15,70 81
+15,70 82
+5,71 81
+5,71 81
+5,71 83
+5,71 84
+5,71 85
+113.5,13 86
+115.4,21 87
+116.4,25 88
+22,24 88
+4,25 88
+4,25 88
+117.8,18 89
+118.8,25 90
+119.6,63 91
+6,9 91
+16,62 91
+20,62 91
+31,37 91
+39,61 91
+16,62 91
+16,62 92
+6,63 91
+6,63 91
+6,63 93
+121.6,21 94
+6,21 95
+6,21 96
+6,21 97
+122.5,13 98
+124.14,43 99
+35,37 99
+39,42 99
+14,43 99
+14,43 99
+4,44 99
+4,7 99
+4,7 99
+4,7 100
+4,44 99
+4,44 99
+4,44 101
+4,44 102
+4,44 76
+126.39,50 103
+39,50 103
+39,50 103
+14,51 103
+35,37 103
+35,37 103
+35,37 104
+14,51 103
+14,51 103
+4,52 103
+4,7 103
+4,7 103
+4,7 105
+4,52 103
+4,52 103
+4,52 76
+128.4,64 106
+4,7 106
+14,63 106
+18,63 106
+29,35 106
+37,62 106
+14,63 106
+14,63 107
+4,64 106
+4,64 106
+4,64 76
+4,64 108
+4,64 58
+131.3,26 109
+8,11 109
+19,25 109
+3,26 109
+3,26 109
+132.7,15 110
+20,28 110
+133.4,59 111
+4,7 111
+14,58 111
+18,58 111
+29,35 111
+37,57 111
+14,58 111
+14,58 112
+4,59 111
+4,59 111
+4,59 113
+134.4,12 114
+136.7,17 115
+7,26 115
+137.4,57 116
+4,7 116
+14,56 116
+18,56 116
+29,35 116
+37,55 116
+14,56 116
+14,56 117
+4,57 116
+4,57 116
+4,57 118
+138.4,12 119
+140.3,51 120
+19,25 120
+27,34 120
+36,50 120
+3,51 120
+141.3,49 121
+3,6 121
+13,48 121
+17,48 121
+28,34 121
+36,47 121
+13,48 121
+13,48 122
+3,49 121
+3,49 121
+3,49 123
+3,49 58
+143.3,21 124
+8,11 124
+18,20 124
+3,21 124
+3,21 124
+144.7,15 125
+19,29 125
+19,38 125
+145.4,26 126
+19,25 126
+4,26 126
+4,26 127
+4,26 58
+149.3,20 128
+3,6 128
+15,19 128
+3,20 128
+3,20 58
+152.1,12 129
+1,5 129
+1,12 129
+153.1,29 130
+12,28 130
+1,29 130
+1,29 130
+154.0,1 131
+179.1,8 132
+180.6,21 133
+23,31 134
+181.7,13 135
+7,18 135
+2,18 135
+2,18 136
+180.33,43 137
+33,43 137
+182.8,9 138
+1,9 138
+187.1,58 139
+17,20 139
+22,25 139
+27,40 139
+27,57 139
+27,57 140
+1,58 139
+188.1,64 141
+28,31 141
+33,37 141
+39,46 141
+48,51 141
+53,63 141
+1,64 141
+1,64 142
+189.0,1 143
+193.6,21 144
+23,31 145
+194.6,18 146
+195.10,11 147
+3,11 147
+193.33,43 148
+33,43 148
+196.8,11 149
+1,11 149
+201.6,21 150
+23,31 151
+202.5,22 152
+5,22 152
+5,29 152
+5,29 153
+33,46 152
+203.3,18 154
+206.0,1 155
+201.33,43 156
+33,43 156
+206.0,1 155
+211.1,8 157
+212.6,21 158
+23,31 159
+213.6,18 160
+214.7,18 161
+215.4,23 162
+4,23 163
+217.4,22 164
+218.7,22 165
+3,36 165
+3,36 166
+219.3,8 167
+221.2,10 168
+212.33,43 169
+33,43 169
+223.5,13 170
+224.2,30 171
+18,21 171
+23,26 171
+28,29 171
+2,30 171
+225.0,1 172
+229.1,32 173
+15,16 173
+18,21 173
+23,26 173
+28,31 173
+1,32 173
+1,32 174
+230.1,26 175
+231.1,20 176
+232.1,18 177
+233.1,18 178
+235.6,21 179
+23,31 180
+236.6,22 181
+237.3,24 182
+16,23 182
+3,24 182
+3,24 182
+238.13,47 183
+34,43 183
+45,46 183
+13,47 183
+13,47 183
+3,48 183
+3,6 183
+3,6 183
+3,6 184
+3,48 183
+3,48 183
+239.3,18 185
+240.3,17 186
+3,17 187
+235.33,43 188
+33,43 188
+243.1,13 189
+244.5,22 190
+245.2,13 191
+248.0,1 192
+247.2,24 193
+248.0,1 192
+255.5,22 194
+5,22 194
+5,34 194
+5,34 195
+256.2,21 196
+257.9,19 197
+17,18 197
+9,19 197
+9,19 197
+2,19 197
+259.8,11 198
+1,11 198
+264.1,13 199
+265.5,18 200
+266.11,17 201
+2,24 201
+2,24 202
+267.8,22 203
+1,22 203
+22
+aSys->Dir 1:26.1,39.2 64
+11
+0:name:28.2,6 s
+4:uid:29.2,5 s
+8:gid:30.2,5 s
+12:muid:31.2,6 s
+16:qid:32.2,5 @1
+
+32:mode:33.2,6 i
+36:atime:34.2,7 i
+40:mtime:35.2,7 i
+48:length:36.2,8 B
+56:dtype:37.2,7 i
+60:dev:38.2,5 i
+aSys->Qid 11.1,16.2 16
+3
+0:path:13.2,6 B
+8:vers:14.2,6 i
+12:qtype:15.2,7 i
+aDraw->Chans 2:70.1,82.2 4
+1
+0:desc:72.2,6 i
+aDraw->Context 274.1,279.2 12
+3
+0:display:276.2,9 R@4
+
+4:screen:277.2,8 R@8
+
+8:wm:278.2,4 Ct8.2
+0:t0:15,21 s
+4:t1:15,21 Ct8.2
+0:t0:32,38 s
+4:t1:32,38 R@9
+
+
+
+aDraw->Display 201.1,230.2 20
+5
+0:image:203.2,7 R@5
+
+4:white:204.2,7 R@5
+
+8:black:205.2,7 R@5
+
+12:opaque:206.2,8 R@5
+
+16:transparent:207.2,13 R@5
+
+aDraw->Image 142.1,198.2 56
+8
+0:r:146.2,3 @6
+
+16:clipr:147.2,7 @6
+
+32:depth:148.2,7 i
+36:chans:149.2,7 @2
+
+40:repl:150.2,6 i
+44:display:151.2,9 R@4
+
+48:screen:152.2,8 R@8
+
+52:iname:153.2,7 s
+aDraw->Rect 116.1,139.2 16
+2
+0:min:118.2,5 @7
+
+8:max:119.2,5 @7
+
+aDraw->Point 99.1,113.2 8
+2
+0:x:101.2,3 i
+4:y:102.2,3 i
+aDraw->Screen 249.1,263.2 16
+4
+0:id:251.2,4 i
+4:image:252.2,7 R@5
+
+8:fill:253.2,6 R@5
+
+12:display:254.2,9 R@4
+
+aDraw->Wmcontext 282.1,291.2 28
+7
+0:kbd:284.2,5 Ci
+4:ptr:285.2,5 CR@10
+
+8:ctl:286.2,5 Cs
+12:wctl:287.2,6 Cs
+16:images:288.2,8 CR@5
+
+20:connfd:289.2,8 R@11
+
+24:ctxt:290.2,6 R@3
+
+aDraw->Pointer 266.1,271.2 16
+3
+0:buttons:268.2,9 i
+4:xy:269.2,4 @7
+
+12:msec:270.2,6 i
+aSys->FD 1:45.1,48.2 4
+1
+0:fd:47.2,4 i
+aNametree->Tree 4:112.1,121.2 8
+2
+0:c:113.2,3 CR@13
+
+4:reply:114.2,7 Cs
+pNametree->Treeop 122.1,132.2 0
+2
+4:reply:123.2,7 Cs
+8:q:124.2,3 B
+4
+Create:126.2,8 80
+1
+16:d:128.3,4 @0
+
+Wstat:127.2,7
+Remove:129.2,8 16
+0
+Getpath:130.2,9 16
+0
+aMsgclient 0:163.0,169.1 20
+5
+0:fid:164.1,4 i
+4:name:165.1,5 s
+8:nextmsg:166.1,8 R@15
+
+12:pending:167.1,8 R@16
+
+16:next:168.1,5 R@14
+
+aMsg 156.0,161.1 16
+4
+0:fromfid:157.1,8 i
+4:from:158.1,5 s
+8:msg:159.1,4 s
+12:next:160.1,5 R@15
+
+pStyx->Tmsg 3:75.1,123.2 0
+1
+4:tag:76.2,5 i
+14
+Readerror:78.2,11 12
+1
+8:error:79.3,8 s
+Version:80.2,9 16
+2
+8:msize:81.3,8 i
+12:version:82.3,10 s
+Auth:83.2,6 20
+3
+8:afid:84.3,7 i
+12:uname:85.3,8 s
+16:aname:10,15 s
+Attach:86.2,8 24
+4
+8:fid:87.3,6 i
+12:afid:8,12 i
+16:uname:88.3,8 s
+20:aname:10,15 s
+Flush:89.2,7 12
+1
+8:oldtag:90.3,9 i
+Walk:91.2,6 20
+3
+8:fid:92.3,6 i
+12:newfid:8,14 i
+16:names:93.3,8 As
+Open:94.2,6 16
+2
+8:fid:95.3,6 i
+12:mode:8,12 i
+Create:96.2,8 24
+4
+8:fid:97.3,6 i
+12:name:98.3,7 s
+16:perm:99.3,7 i
+20:mode:9,13 i
+Read:100.2,6 32
+3
+8:fid:101.3,6 i
+16:offset:102.3,9 B
+24:count:103.3,8 i
+Write:104.2,7 32
+3
+8:fid:105.3,6 i
+16:offset:106.3,9 B
+24:data:107.3,7 Ab
+Clunk:108.2,7 12
+1
+8:fid:111.3,6 i
+Stat:109.2,6
+Remove:110.2,8
+Wstat:112.2,7 80
+2
+8:fid:113.3,6 i
+16:stat:114.3,7 @0
+
+pStyxservers->Navop 4:31.1,42.2 0
+2
+4:reply:32.2,7 Ct8.2
+0:t0:18,30 R@0
+
+4:t1:18,30 s
+
+8:path:33.2,6 B
+3
+Stat:35.2,6 16
+0
+Walk:36.2,6 24
+1
+16:name:37.3,7 s
+Readdir:38.2,9 24
+2
+16:offset:39.3,9 i
+20:count:40.3,8 i
+aStyxservers->Styxserver 44.1,82.2 32
+7
+0:fd:45.2,4 R@11
+
+4:fids:46.2,6 ALR@19
+
+8:fidlock:47.2,9 Ci
+12:t:48.2,3 R@20
+
+16:rootpath:49.2,10 B
+24:msize:50.2,7 i
+28:replychan:51.2,11 CR@21
+
+aStyxservers->Fid 5.1,19.2 48
+9
+0:fid:6.2,5 i
+8:path:7.2,6 B
+16:qtype:8.2,7 i
+20:isopen:9.2,8 i
+24:mode:10.2,6 i
+28:doffset:11.2,9 t8.2
+0:t0:12,15 i
+4:t1:12,15 i
+
+36:uname:12.2,7 s
+40:param:13.2,7 s
+44:data:14.2,6 Ab
+aStyxservers->Navigator 21.1,29.2 8
+2
+0:c:22.2,3 CR@17
+
+4:reply:23.2,7 Ct8.2
+0:t0:18,30 R@0
+
+4:t1:18,30 s
+
+pStyx->Rmsg 3:125.1,163.2 0
+1
+4:tag:126.2,5 i
+15
+Readerror:128.2,11 12
+1
+8:error:129.3,8 s
+Version:130.2,9 16
+2
+8:msize:131.3,8 i
+12:version:132.3,10 s
+Auth:133.2,6 24
+1
+8:aqid:134.3,7 @1
+
+Attach:135.2,8 24
+1
+8:qid:136.3,6 @1
+
+Flush:137.2,7 8
+0
+Error:138.2,7 12
+1
+8:ename:139.3,8 s
+Clunk:140.2,7 8
+0
+Remove:141.2,8
+Wstat:142.2,7
+Walk:143.2,6 12
+1
+8:qids:144.3,7 A@1
+
+Create:145.2,8 32
+2
+8:qid:147.3,6 @1
+
+24:iounit:148.3,9 i
+Open:146.2,6
+Read:149.2,6 12
+1
+8:data:150.3,7 Ab
+Write:151.2,7 12
+1
+8:count:152.3,8 i
+Stat:153.2,6 72
+1
+8:stat:154.3,7 @0
+
+12
+0:dir
+3
+32:name:0:34.4,8 s
+36:perm:18,22 i
+40:path:29,33 i
+1
+48:d:36.1,2 @0
+
+@0
+25:badmod
+1
+32:path:49.7,11 s
+0
+n37:init
+0
+2
+40:tree:71.2,6 R@12
+
+44:treeop:8,14 CR@17
+
+n146:chatsrv
+1
+32:tree:83.8,12 R@12
+
+8
+36:tm:86.7,9 R@16
+
+40:c:131.3,4 R@19
+
+44:mc:110.4,6 R@14
+
+48:c:93.3,4 R@19
+
+52:c:101.3,4 R@19
+
+56:c:143.3,4 R@19
+
+60:msg:116.4,7 s
+64:tmsg:85.8,12 R@16
+
+n373:usernames
+0
+2
+32:c:180.6,7 R@14
+
+36:s:179.1,2 s
+s384:newmsgclient
+2
+32:fid:185.13,16 i
+36:name:23,27 s
+0
+n400:getmsgclient
+1
+32:fid:191.13,16 i
+1
+36:c:193.6,7 R@14
+
+R@14
+409:cancelpending
+1
+32:tag:199.14,17 i
+2
+36:c:201.6,7 R@14
+
+40:tm:202.6,8 R@16
+
+n421:closemsgclient
+1
+32:fid:208.15,18 i
+3
+36:c:212.6,7 R@14
+
+40:s:211.1,2 s
+44:prev:210.1,5 R@14
+
+n443:writemsgclients
+3
+32:fromfid:227.16,23 i
+36:from:30,34 s
+40:msg:44,47 s
+3
+44:c:235.6,7 R@14
+
+48:nm:229.1,3 R@15
+
+52:s:237.3,4 s
+n483:getnextmsg
+1
+32:mc:250.11,13 R@14
+
+1
+36:m:255.6,7 R@15
+
+s495:msgtext
+1
+32:m:262.8,9 R@15
+
+1
+36:prefix:264.1,7 s
+s10
+180:keptcount:172.0,9 i
+184:keptmsg:174.0,7 R@15
+
+188:msgclients:175.0,10 R@14
+
+196:nametree:20.1,9 mNametree
+4:110.0,135.1 0
+
+200:nextmsg:0:173.0,7 R@15
+
+220:srv:30.0,3 R@18
+
+224:styx:14.1,5 mStyx
+3:1.0,182.1 0
+
+228:styxservers:0:18.1,12 mStyxservers
+4:1.0,108.1 0
+
+232:sys:0:8.1,4 mSys
+1:4.0,160.1 0
+
+236:tc:0:29.0,2 CR@16
+
diff --git a/appl/demo/chat/mkfile b/appl/demo/chat/mkfile
new file mode 100644
index 00000000..13045209
--- /dev/null
+++ b/appl/demo/chat/mkfile
@@ -0,0 +1,30 @@
+<../../../mkconfig
+
+TARG=\
+ chat.dis\
+ chatsrv.dis\
+
+SHTARG=\
+ chatclient.sh\
+
+MODULES=\
+
+SYSMODULES= \
+ draw.m\
+ styx.m\
+ styxservers.m\
+ sys.m\
+ tk.m\
+ tkclient.m\
+
+DISBIN=$ROOT/dis/demo/chat
+
+<$ROOT/mkfiles/mkdis
+
+SHFILES=${SHTARG:%.sh=$DISBIN/%}
+install:V: $SHFILES
+%.install:V: $DISBIN/%
+%.installall:V: $DISBIN/%
+
+$DISBIN/%: %.sh
+ cp $stem.sh $target && chmod a+rx $target