home *** CD-ROM | disk | FTP | other *** search
Oberon Text | 1994-10-18 | 12.8 KB | 362 lines |
- Syntax10.Scn.Fnt
- MODULE MailServer; (*NW 17.4.89 / 10.2.94*)
- IMPORT SYSTEM, Core, Files, Texts, Oberon;
- VAR W: Texts.Writer;
- handler: Oberon.Task;
- myadr: ARRAY 16 OF CHAR;
- PROCEDURE Dispatch(F: Files.File; rno, sno, hdlen: INTEGER; bdypos: LONGINT;
- VAR orig, head: ARRAY OF CHAR);
- (*insert external message (from msg) in recipient rno's mail file*)
- VAR i, j, k, h: INTEGER;
- ch: CHAR; ok: BOOLEAN;
- pos, L, bdylen, tm, dt: LONGINT;
- fname: Core.Name;
- MF: Files.File; (*destination*)
- R, Q: Files.Rider;
- mrtab: Core.MResTab;
- mdir: Core.MailDir;
- BEGIN Core.GetFileName(rno, fname); MF := Files.Old(fname);
- IF MF # NIL THEN
- Files.Set(Q, MF, 0); Files.ReadBytes(Q, mrtab, 32);
- Files.ReadBytes(Q, mdir, SIZE(Core.MailDir))
- ELSE (*create new mailbox file*)
- MF := Files.New(fname); Files.Set(Q, MF, 0); Files.Register(MF);
- mdir[0].next := 0; mrtab[0] := {4 .. 31}; i := 1;
- REPEAT mrtab[i] := {0 .. 31}; INC(i) UNTIL i = 7;
- mrtab[7] := {0 .. 29}; i := 0;
- REPEAT mdir[i].len := 0; INC(i) UNTIL i = 31
- END ;
- Files.Set(R, F, bdypos);
- IF bdypos > 0 THEN (*find length of body*)
- Files.ReadInt(R, k); Files.ReadLInt(R, bdylen)
- ELSE bdylen := Files.Length(F)
- END ;
- ok := FALSE; i := 0;
- REPEAT INC(i) UNTIL (i = 31) OR (mdir[i].len = 0);
- IF i < 31 THEN (*free slot found, now find free blocks in file*)
- j := -1;
- REPEAT INC(j);
- IF j MOD 32 IN mrtab[j DIV 32] THEN
- h := j; k := SHORT((bdylen + hdlen + 255) DIV 256) + j;
- LOOP INC(h);
- IF h = k THEN ok := TRUE; EXIT END ;
- IF (h = 256) OR ~(h MOD 32 IN mrtab[h DIV 32]) THEN j := h; EXIT END
- END
- END
- UNTIL ok OR (j >= 255)
- END ;
- IF ok THEN (*insert msg in blocks j .. k-1*)
- pos := LONG(j) * 256; mdir[i].pos := j;
- REPEAT EXCL(mrtab[j DIV 32], j MOD 32); INC(j) UNTIL j = k;
- mdir[i].len := bdylen + hdlen;
- Oberon.GetClock(tm, dt);
- mdir[i].time := SHORT(tm DIV 2); mdir[i].date := SHORT(dt);
- j := 0;
- WHILE (j < 19) & (orig[j] > " ") DO mdir[i].originator[j] := orig[j]; INC(j) END ;
- mdir[i].originator[j] := 0X;
- mdir[i].next := mdir[0].next; mdir[0].next := i;
- Files.Set(Q, MF, 0); Files.WriteBytes(Q, mrtab, 32);
- Files.WriteBytes(Q, mdir, SIZE(Core.MailDir)); Files.Set(Q, MF, pos);
- j := 0;
- WHILE j < hdlen DO Files.Write(Q, SYSTEM.ROT(head[j], 5)); INC(j) END ;
- L := bdylen;
- WHILE L > 0 DO Files.Read(R, ch); Files.Write(Q, SYSTEM.ROT(ch, 5)); DEC(L) END ;
- L := (-Files.Pos(Q)) MOD 256;
- WHILE L > 0 DO Files.Write(Q, 0); DEC(L) END ;
- Files.Close(MF)
- ELSIF (rno # sno) & (sno > 0) & (rno > 0) THEN (*return to sender*)
- Dispatch(F, sno, sno, hdlen, bdypos, orig, head)
- ELSIF (rno # 0) & (sno # 0) THEN (*send to postmaster*)
- Dispatch(F, 0, sno, hdlen, bdypos, orig, head)
- END
- END Dispatch;
- PROCEDURE Encode(F0: Files.File; textpos: LONGINT;
- VAR orig: Core.LongName; VAR recip, subj: ARRAY OF CHAR);
- (*CX-400 encode message F0 and insert it in export queue*)
- VAR ch: CHAR;
- i, j: INTEGER;
- tm, dt, p0, p1: LONGINT;
- R, Q: Files.Rider; F1: Files.File;
- PROCEDURE WC(n: LONGINT);
- BEGIN Files.Write(Q, CHR(n))
- END WC;
- PROCEDURE WI(n: INTEGER);
- BEGIN Files.WriteBytes(Q, n, 2)
- END WI;
- PROCEDURE WL(n: LONGINT);
- BEGIN Files.WriteBytes(Q, n, 4)
- END WL;
- BEGIN F1 := Files.New(""); Files.Set(Q, F1, 0);
- WI(4000H); WL(0); (*MSG*)
- WI(5000H); WL(0); (*ENV*)
- WI(1010H); WI(6); (*MSGID*)
- Oberon.GetClock(tm, dt); p0 := tm*dt; i := 0;
- REPEAT WC(p0 MOD 10H + 41H); p0 := p0 DIV 10H; INC(i) UNTIL i = 6;
- i := 0;
- WHILE orig[i] > 0X DO INC(i) END ;
- WI(1020H); WI(i+27); (*ORIG*)
- WI(2011H); WI(2020H); WI(2030H); WI(2041H); WI(3030H); WI(i+15);
- j := 0;
- WHILE j < i DO Files.Write(Q, orig[j]); INC(j) END ;
- j := 0;
- REPEAT Files.Write(Q, myadr[j]); INC(j) UNTIL j = 15;
- i := 0;
- LOOP (*recipients*) j := i;
- WHILE recip[j] > 1X DO INC(j) END ;
- IF i = j THEN EXIT END ;
- WI(1031H); WI(j-i+12); (*RECIP*)
- WI(ORD(recip[j])+2010H); WI(2020H); WI(2030H); WI(2041H); WI(3030H); WI(j-i);
- WHILE i < j DO Files.Write(Q, recip[i]); INC(i) END ;
- INC(i)
- END ;
- i := 0; j := 0;
- WHILE subj[j] > 0X DO INC(j) END ;
- WI(1060H); WI(j); (*SUBJ*)
- WHILE i < j DO Files.Write(Q, subj[i]); INC(i) END ;
- WI(1090H); WI(6); (*SUBM*)
- WC(dt DIV 200H); WC(dt DIV 20H MOD 10H); WC(dt MOD 20H);
- WC(tm DIV 1000H); WC(tm DIV 40H MOD 40H); WC(tm MOD 40H);
- p0 := Files.Pos(Q);
- WI(6020H); WL(Files.Length(F0) - textpos); (*TEXT*)
- Files.Set(R, F0, textpos); Files.Read(R, ch);
- WHILE ~R.eof DO
- IF ch >= 7FX THEN
- IF ch = "
- " THEN ch := "a"
- ELSIF ch = "
- " THEN ch := "o"
- ELSIF ch = "
- " THEN ch := "u"
- ELSIF ch = "
- " THEN ch := "A"
- ELSIF ch = "
- " THEN ch := "O"
- ELSIF ch = "
- " THEN ch := "U"
- ELSE ch := "?"
- END
- END ;
- Files.Write(Q, ch); Files.Read(R, ch)
- END ;
- p1 := Files.Pos(Q); Files.Set(Q, F1, 2);
- WL(p1-6); WI(5000H); WL(p0-12); (*fixup*)
- Files.Close(F1);
- Core.InsertTask(Core.LineQueue, F1, Oberon.User, -1);
- Texts.Append(Oberon.Log, W.buf)
- END Encode;
- PROCEDURE Decode(F: Files.File; pos: LONGINT);
- (*CX-400 decode message from mail rider MR and dispatch*)
- CONST bufsize = 96; msgsize = 2048;
- VAR i, x, len, mx, rx, rno: INTEGER;
- list, broadcast: BOOLEAN; ch, mo, yr: CHAR;
- length: LONGINT;
- R: Files.Rider;
- rtab: ARRAY 32 OF INTEGER; (*table of recipients*)
- buf, orig: ARRAY bufsize OF CHAR;
- msg: ARRAY msgsize OF CHAR; (*message header*)
- PROCEDURE put(ch: CHAR);
- BEGIN
- IF mx < msgsize THEN msg[mx] := ch; INC(mx) END
- END put;
- PROCEDURE PutString(s: ARRAY OF CHAR);
- VAR i: INTEGER; ch: CHAR;
- BEGIN i := 0;
- REPEAT ch := s[i]; INC(i); put(ch)
- UNTIL ch <= " "
- END PutString;
- PROCEDURE PutInt(n: INTEGER);
- BEGIN put(CHR(n DIV 10 + 30H)); put(CHR(n MOD 10 + 30H))
- END PutInt;
- PROCEDURE ReadORName(len: INTEGER; VAR buf: ARRAY OF CHAR; title: ARRAY OF CHAR);
- VAR x, i, L: INTEGER; ch: CHAR;
- BEGIN Files.ReadInt(R, x); list := x = 2011H;
- Files.ReadInt(R, x); Files.ReadInt(R, x);
- Files.ReadInt(R, x); Files.ReadInt(R, L);
- Files.ReadInt(R, L); i := 0;
- IF x = 2041H THEN
- PutString(title);
- WHILE i < L DO
- Files.Read(R, ch);
- IF i < bufsize THEN buf[i] := ch END ;
- INC(i); put(ch)
- END ;
- put(0DX)
- ELSE
- WHILE i < L DO
- Files.Read(R, ch);
- IF i < bufsize THEN buf[i] := ch END ;
- INC(i)
- END ;
- END ;
- IF i >= bufsize THEN i := bufsize-1 END ;
- buf[i] := 0X; DEC(len, L+12);
- WHILE len > 0 DO Files.Read(R, ch); DEC(len) END
- END ReadORName;
- BEGIN Files.Set(R, F, pos); Files.ReadInt(R, x);
- Files.ReadLInt(R, length); INC(pos, length+6);
- IF x = 5000H THEN (*ENV*)
- mx := 0; rx := 0; broadcast := FALSE;
- IF length > 40000 THEN length := 40000 END ;
- LOOP
- IF Files.Pos(R) >= pos THEN EXIT END ;
- Files.ReadInt(R, x); Files.ReadInt(R, len);
- IF x = 1020H THEN (*ORIG*)
- ReadORName(len, orig, "From: ")
- ELSIF x DIV 10H = 103H THEN (*RECIP*)
- ReadORName(len, buf, "To: ");
- IF buf = "all@cs.inf.ethz.ch" THEN broadcast := TRUE
- ELSIF list THEN
- rno := Core.UserNum(buf);
- IF rno >= 0 THEN rtab[rx] := rno; INC(rx) END
- END
- ELSIF x DIV 10H = 106H THEN (*SUBJ, TITLE*)
- PutString("Re: "); i := 0;
- WHILE i < len DO Files.Read(R, ch); put(ch); INC(i) END ;
- put(0DX)
- ELSIF x = 1090H THEN (*SUBMI*)
- PutString("Submission: ");
- Files.Read(R, yr); Files.Read(R, mo); Files.Read(R, ch);
- PutInt(ORD(ch)); put("."); PutInt(ORD(mo)); put(".");
- PutInt(ORD(yr)); put(" ");
- Files.Read(R, ch); PutInt(ORD(ch)); put(":");
- Files.Read(R, ch); PutInt(ORD(ch)); put(":");
- Files.Read(R, ch); PutInt(ORD(ch)); put(0DX)
- ELSE Files.Set(R, F, Files.Pos(R) + len) (*skip*)
- END
- END ;
- IF broadcast THEN (*broadcast*)
- i := 1; rno := Core.NofUsers();
- WHILE i < rno DO Dispatch(F, i, 0, mx, pos, orig, msg); INC(i) END
- ELSIF rx = 0 THEN (*no valid recipient*) Dispatch(F, 0, -1, mx, pos, orig, msg)
- ELSE i := 0;
- REPEAT x := rtab[i]; INC(i); Dispatch(F, x, -1, mx, pos, orig, msg) UNTIL i = rx
- END
- END
- END Decode;
- PROCEDURE Serve;
- CONST L0 = 64; L1 = 1024;
- VAR i, j, ex, sx, sno, rno, hdlen: INTEGER;
- ch: CHAR; anyext: BOOLEAN;
- pos, length, dt, tm: LONGINT;
- F: Files.File; R: Files.Rider;
- Id: Core.ShortName;
- orig: Core.LongName;
- head, recip, subj: ARRAY L0 OF CHAR;
- extrecip: ARRAY L1 OF CHAR;
- PROCEDURE Pair(ch: CHAR; x: LONGINT);
- BEGIN head[j] := ch; INC(j);
- head[j] := CHR(x DIV 10 + 30H); INC(j); head[j] := CHR(x MOD 10 + 30H); INC(j)
- END Pair;
- BEGIN
- IF Core.MailQueue.n > 0 THEN
- Core.GetTask(Core.MailQueue, F, Id, sno);
- IF sno >= 0 THEN (*internal originator*)
- Core.GetUserName(sno, orig); Oberon.GetClock(tm, dt);
- COPY("From: ", head); i := 0; j := 6;
- WHILE orig[i] > 0X DO head[j] := orig[i]; INC(i); INC(j) END ;
- head[j] := 0DX; INC(j); head[j] := "A"; INC(j); head[j] := "t"; INC(j); head[j] := ":"; INC(j);
- Pair(" ", dt MOD 20H); Pair(".", dt DIV 20H MOD 10H); Pair(".", dt DIV 200H MOD 80H);
- Pair(" ", tm DIV 1000H MOD 20H); Pair(":", tm DIV 40H MOD 40H); Pair(":", tm MOD 40H);
- head[j] := 0DX; hdlen := j+1;
- Files.Set(R, F, 0); anyext := FALSE; ex := 0; sx := 0;
- LOOP (*next line*) pos := Files.Pos(R);
- REPEAT Files.Read(R, ch) UNTIL (ch > " ") OR R.eof;
- IF R.eof THEN EXIT END ;
- i := 0;
- REPEAT
- IF i < L0-1 THEN recip[i] := ch; INC(i) END ;
- Files.Read(R, ch)
- UNTIL ch <= ":";
- recip[i] := 0X;
- IF (recip # "To") & (recip # "cc") THEN EXIT END ;
- IF ch = ":" THEN Files.Read(R, ch) END ;
- LOOP (*next recipient*)
- WHILE ch = " " DO Files.Read(R, ch) END ;
- WHILE ch = "(" DO
- REPEAT Files.Read(R, ch) UNTIL (ch = ")") OR (ch < " ");
- IF ch = ")" THEN Files.Read(R, ch) END ;
- WHILE ch = " " DO Files.Read(R, ch) END
- END ;
- IF ch < " " THEN EXIT END ;
- i := 0;
- WHILE (ch > " ") & (ch # "@") DO
- IF i < L0-1 THEN recip[i] := ch; INC(i) END ;
- IF ex < L1-1 THEN extrecip[ex] := ch; INC(ex) END ;
- Files.Read(R, ch)
- END ;
- IF ch = "@" THEN (*external recipient*)
- REPEAT
- IF ex < L1-1 THEN extrecip[ex] := ch; INC(ex) END ;
- Files.Read(R, ch)
- UNTIL (ch <= " ") OR (ch = ",");
- extrecip[ex] := 1X; INC(ex); anyext := TRUE
- ELSE (*internal recipient*)
- recip[i] := 0X; extrecip[ex] := 0X; INC(ex);
- IF recip = "all" THEN rno := Core.NofUsers();
- WHILE rno > 1 DO (*exclude postmaster*)
- DEC(rno); Dispatch(F, rno, 0, hdlen, 0, orig, head)
- END
- ELSE rno := Core.UserNum(recip);
- IF rno < 0 THEN rno := sno END ;
- Dispatch(F, rno, sno, hdlen, 0, orig, head)
- END
- END ;
- IF ch = "," THEN Files.Read(R, ch) END
- END
- END ;
- IF anyext THEN
- IF recip = "Re" THEN
- Files.Read(R, ch);
- WHILE (ch >= " ") & (sx < L0-1) DO subj[sx] := ch; INC(sx); Files.Read(R, ch) END ;
- pos := Files.Pos(R)
- END ;
- subj[sx] := 0X; extrecip[ex] := 0X; Encode(F, pos, orig, extrecip, subj)
- END
- ELSE (*external originator*)
- pos := 0;
- LOOP Files.Set(R, F, pos); Files.ReadInt(R, i);
- IF R.eof THEN EXIT END ;
- IF i = 4000H THEN (*MSG*)
- Files.ReadLInt(R, length); INC(pos, 6); Decode(F, pos); INC(pos, length)
- ELSE Texts.WriteString(W, "message not fully decoded");
- Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf); EXIT
- END
- END
- END ;
- Core.RemoveTask(Core.MailQueue)
- END
- END Serve;
- (*------------------------ Commands --------------------------*)
- PROCEDURE Start*;
- BEGIN Oberon.Remove(handler); Oberon.Install(handler);
- Texts.WriteString(W, "Mailer started (NW 17.12.92)");
- Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
- END Start;
- PROCEDURE State*;
- BEGIN Texts.WriteString(W, "Mail queue:"); Texts.WriteInt(W, Core.MailQueue.n, 3);
- Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
- END State;
- PROCEDURE Stop*;
- BEGIN Oberon.Remove(handler); Texts.WriteString(W, "Mailer stopped");
- Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
- END Stop;
- PROCEDURE RemoveMsg*;
- VAR ch: CHAR;
- F, G: Files.File; R, Q: Files.Rider;
- id: Core.ShortName; uno: INTEGER;
- S: Texts.Scanner;
- BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
- IF Core.MailQueue.n > 0 THEN
- Core.GetTask(Core.MailQueue, F, id, uno); Files.Set(R, F, 0); Files.Read(R, ch);
- G := Files.New(S.s); Files.Set(Q, G, 0);
- WHILE ~R.eof DO Files.Write(Q, ch); Files.Read(R, ch) END ;
- Files.Register(G); Core.RemoveTask(Core.MailQueue);
- Texts.WriteString(W, S.s); Texts.WriteString(W, " saved")
- ELSE Texts.WriteString(W, " MQ empty")
- END ;
- Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
- END RemoveMsg;
- BEGIN Texts.OpenWriter(W);
- myadr := "@cs.inf.ethz.ch"; NEW(handler); handler.handle := Serve
- END MailServer.
-