WalnutToPeanut.mesa
Copyright Ó 1992 by Xerox Corporation. All rights reserved.
Last edited by Doug Wyatt, April 19, 1983 2:58 pm
DIRECTORY
Commander USING [CommandProc, Register],
IO USING [int, Put, PutChar, PutRope, rope, STREAM],
Rope USING [Cat, Concat, Equal, Fetch, Find, Index, ROPE, Size, SkipOver, SkipTo, Substr],
RopeIO USING [FromFile],
TiogaFileOps USING [CreateRoot, InsertAsLastChild, Ref, SetContents, SetFormat, SetStyle, Store],
UserCredentials USING [GetUserCredentials];
WalnutToPeanut:
CEDAR
PROGRAM
IMPORTS Commander, IO, Rope, RopeIO, TiogaFileOps, UserCredentials
= BEGIN
ROPE: TYPE = Rope.ROPE;
Node: TYPE = TiogaFileOps.Ref;
File: TYPE = REF FileRep;
FileRep:
TYPE =
RECORD[
link: File, -- for fileList
name: ROPE, -- category name ("Active")
filename: ROPE, -- file name ("Active.mail")
root: Node, -- root node
last: Node -- last top-level node
];
Message: TYPE = REF MessageRep;
MessageRep:
TYPE =
RECORD[
sender: ROPE,
date: ROPE,
categories: ROPE,
contents: ROPE
];
simpleUserName, userRName: ROPE ¬ NIL;
InitUserName:
PROC = {
uN: ROPE = UserCredentials.GetUserCredentials[].name;
pos: INT = Rope.Find[uN, "."];
IF pos<0 THEN { simpleUserName ¬ uN; userRName ¬ Rope.Concat[uN, ".PA"] }
ELSE { simpleUserName ¬ Rope.Substr[uN, 0, pos]; userRName ¬ uN };
};
fileList: File ¬ NIL;
CreateFile:
PROC[name:
ROPE]
RETURNS[File] = {
file: File = NEW[FileRep];
file.name ¬ name;
file.filename ¬ Rope.Concat[name, ".mail"];
file.root ¬ TiogaFileOps.CreateRoot[];
TiogaFileOps.SetStyle[file.root, "Mail"];
file.last ¬ TiogaFileOps.InsertAsLastChild[file.root];
TiogaFileOps.SetContents[file.last, file.filename];
file.link ¬ fileList; fileList ¬ file;
RETURN[file];
};
GetFile:
PROC[name:
ROPE]
RETURNS[File] = {
FOR file: File ¬ fileList, file.link
UNTIL file=
NIL
DO
IF Rope.Equal[file.name, name, FALSE] THEN RETURN[file];
REPEAT FINISHED => RETURN[CreateFile[name]];
ENDLOOP;
};
A message in Walnut.DBLog has the following form:
*start*
02203 00112 US
gvMsgID: Horning.pa $ 3#203@18-Feb-83 12:37:26 PST
Categories: UserExec CedarDiscussion
... message contents ...
ParseFailed: ERROR = CODE;
ParseMessage:
PROC[m:
ROPE]
RETURNS[Message] = {
message: Message = NEW[MessageRep];
index: INT ¬ 0;
Require:
PROC[x:
ROPE] = {
start: INT = index;
IF Rope.Find[m, x, start]=start THEN index ¬ start+Rope.Size[x]
ELSE ERROR ParseFailed;
};
SkipTo:
PROC[x:
ROPE] = {
start: INT = index;
index ¬ Rope.Find[m, x, start]+Rope.Size[x];
};
ReadTo:
PROC[x:
ROPE]
RETURNS[
ROPE] = {
start: INT = index;
end: INT = Rope.Find[m, x, start];
index ¬ end+Rope.Size[x];
RETURN[Rope.Substr[m, start, end-start]];
};
ReadN:
PROC[n:
INT]
RETURNS[
ROPE] = {
start: INT = index;
index ¬ start+n;
RETURN[Rope.Substr[m, start, index-start]];
};
Require["*start*\n"];
SkipTo["\n"];
Require["gvMsgID: "];
message.sender ¬ ReadTo[" $"];
SkipTo["@"];
message.date ¬ ReadN[9];
SkipTo["\n"];
Require["Categories: "];
message.categories ¬ ReadTo["\n"];
message.contents ¬ Rope.Substr[m, index];
RETURN[message];
};
DeleteLeadingSPs:
PROC[m:
ROPE]
RETURNS[
ROPE] = {
start: INT ¬ 0;
len: INT ¬ Rope.Size[m];
WHILE start<len AND Rope.Fetch[m, start] = ' DO start ¬ start+1; ENDLOOP;
IF start>0 THEN RETURN[Rope.Substr[m, start, len-start]]
ELSE RETURN[m];
};
DeleteTrailingCRs:
PROC[m:
ROPE]
RETURNS[
ROPE] = {
len: INT ¬ Rope.Size[m];
WHILE len > 0 AND Rope.Fetch[m, len-1] = '\n DO len ¬ len-1; ENDLOOP;
RETURN[Rope.Substr[m, 0, len]];
};
Truncate:
PROC[rope:
ROPE, maxLen:
INT]
RETURNS[
ROPE] = {
s: ROPE ¬ DeleteLeadingSPs[rope];
IF Rope.Size[s] > maxLen THEN s ¬ Rope.Concat[Rope.Substr[s, 0, maxLen-3], "..."];
RETURN[s];
};
GetFieldContents:
PROC[m, name:
ROPE]
RETURNS[contents:
ROPE] = {
start: INT ¬ Rope.Find[m, name];
IF start<0 THEN contents ¬ "?"
ELSE {
end: INT;
start ¬ start + Rope.Size[name];
end ¬ Rope.Find[m, "\n", start];
IF end <= start THEN contents ¬ "?"
ELSE contents ¬ Rope.Substr[m, start, end-start];
};
};
MakeHeader:
PROC[message: Message]
RETURNS[header:
ROPE] = {
date, name, subject: ROPE ¬ NIL;
date ¬ message.date;
IF Rope.Equal[message.sender, userRName,
FALSE]
OR
Rope.Equal[message.sender, simpleUserName,
FALSE]
THEN
name ¬ Rope.Concat["To: ", GetFieldContents[message.contents, "\nTo: "]]
ELSE name ¬ message.sender;
subject ¬ GetFieldContents[message.contents, "\nSubject: "];
header ¬ Rope.Cat["\t", date, "\t", Truncate[name, 16], "\t", Truncate[subject, 44]];
RETURN[header];
};
AppendMessage:
PROC[file: File, message: Message] = {
head: Node = TiogaFileOps.InsertAsLastChild[file.root, file.last];
body: Node = TiogaFileOps.InsertAsLastChild[head];
TiogaFileOps.SetContents[head, MakeHeader[message]];
TiogaFileOps.SetFormat[head, "header"];
TiogaFileOps.SetContents[body, DeleteTrailingCRs[message.contents]];
file.last ¬ head;
};
StoreFile:
PROC[file: File] = {
TiogaFileOps.Store[file.root, file.filename];
file.root ¬ NIL; file.last ¬ NIL;
};
EnumerateNames:
PROC[rope:
ROPE, action:
PROC[
ROPE]] = {
length: INT = Rope.Size[rope];
index: INT ¬ 0;
DO
start: INT = Rope.SkipOver[rope, index, " "];
IF start<length
THEN {
end: INT = Rope.SkipTo[rope, start, " "];
name: ROPE = Rope.Substr[rope, start, end-start];
action[name];
index ¬ end;
}
ELSE EXIT;
ENDLOOP;
};
HandleMessage:
PROC[m:
ROPE] = {
message: Message = ParseMessage[m];
Put:
PROC[name:
ROPE] = {
file: File = GetFile[name];
AppendMessage[file, message];
};
EnumerateNames[message.categories, Put];
};
ReadLog:
PROC[name:
ROPE, s:
IO.
STREAM] = {
log: ROPE ¬ NIL;
start, length: INT ¬ 0;
count: INT ¬ 0;
s.PutRope["Opening "]; s.PutRope[name]; s.PutRope["..."];
log ¬ RopeIO.FromFile[name ! ANY => CONTINUE];
IF log=NIL THEN { s.PutRope["unable to open file!\n"]; RETURN };
length ¬ Rope.Size[log];
s.Put[IO.int[length], IO.rope[" bytes\n"]];
start ¬ Rope.Find[log, "*start*\n"];
IF start<0 THEN { s.PutRope["No messages found!\n"]; RETURN };
s.PutRope["Reading...\n"];
WHILE start<length
DO
end: INT = Rope.Index[log, start+8, "*start*\n"];
message: ROPE = Rope.Substr[log, start, end-start];
HandleMessage[message ! ParseFailed => GOTO Abort];
count ¬ count+1;
IF count
MOD 10=0
THEN {
s.PutChar[IF count MOD 100=0 THEN '! ELSE '~];
};
start ¬ end;
ENDLOOP;
s.Put[IO.rope["... "], IO.int[count], IO.rope[" messages\n"]];
UNTIL fileList=
NIL
DO
file: File = fileList;
fileList ¬ file.link;
s.PutRope["Writing "]; s.PutRope[file.filename]; s.PutRope["..."];
StoreFile[file];
s.PutRope["ok\n"];
ENDLOOP;
EXITS Abort => {
s.PutRope["... failed!\n"];
s.PutRope["Do an Expunge with Walnut, then try running WalnutToPeanut again.\n"];
fileList ¬ NIL;
};
};
WalnutToPeanutCommand: Commander.CommandProc = {
ReadLog["Walnut.DBLog", cmd.out];
};
InitUserName[];
Commander.Register["WalnutToPeanut", WalnutToPeanutCommand,
"Create Peanut mail files from a freshly-expunged Walnut log"];
END.