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; }; 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 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 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 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. F WalnutToPeanut.mesa Copyright Σ 1992 by Xerox Corporation. All rights reserved. Last edited by Doug Wyatt, April 19, 1983 2:58 pm 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 ... Κ•NewlineDelimiter –(cedarcode) style™headšœ™Kšœ Οeœ1™˜BL˜—L˜Lšœžœ˜L˜š  œžœžœžœ ˜.Lšœ žœ ˜L˜L˜+L˜&L˜)L˜6L˜3L˜&Lšžœ˜ L˜—L˜š œžœžœžœ ˜+šžœ"žœžœž˜6Lšžœžœžœžœ˜8Lšžœžœžœ˜,Lšžœ˜—L˜—L˜J™ΊJ™Lšœ žœžœ˜L˜š  œžœžœžœ ˜0Lšœžœ ˜#Lšœžœ˜š œžœžœ˜Lšœžœ ˜Lšžœžœ˜?Lšžœžœ ˜L˜—š œžœžœ˜Lšœžœ ˜L˜,L˜—š  œžœžœžœžœ˜'Lšœžœ ˜Lšœžœ˜"L˜Lšžœ#˜)L˜—š  œžœžœžœžœ˜%Lšœžœ ˜L˜Lšžœ%˜+L˜—L˜L˜ L˜L˜L˜ L˜L˜ L˜L˜"L˜)Lšžœ ˜L˜—L˜š  œžœžœžœžœ˜1Lšœžœ˜Lšœžœ˜Lšžœ žœžœžœ˜JLšžœ žœžœ"˜8Lšžœžœ˜Lšœ˜—L˜š  œžœžœžœžœ˜2Lšœžœ˜Lšžœ žœžœžœ˜ELšžœ˜Lšœ˜—L˜š  œžœžœ žœžœžœ˜9Lšœžœ˜!Lšžœžœ5˜RLšžœ˜ L˜—L˜š  œžœ žœžœ žœ˜ALšœžœ˜ Lšžœ žœ˜šžœ˜Lšœžœ˜ L˜ L˜ Lšžœžœ˜#Lšžœ-˜1Lšœ˜—Lšœ˜—L˜š  œžœžœ žœ˜L˜šžœž˜Lšœžœ)˜1Lšœ žœ&˜3Lšœ'žœ˜3L˜šžœžœžœ˜Lš œ žœžœžœžœ˜.L˜—L˜ Lšžœ˜—Lšœžœžœ žœ˜>šžœ žœž˜Lšœ˜L˜L˜BL˜L˜Lšžœ˜—šžœ ˜Lšœ˜L˜QLšœ žœ˜L˜—L˜—L˜š œ˜0Lšœ!˜!L˜—L˜L˜L˜šœ;˜;L˜?—L˜Lšžœ˜——…—V#