DIRECTORY BasicTime USING [MonthOfYear, Unpacked], Commander USING [CommandProc, Register], Convert USING [Error, UnpackedTimeFromRope], IO USING [EndOfStream, GetTokenRope, IDProc, int, Put, PutChar, PutFR, PutRope, RIS, rope, STREAM], Rope USING [Cat, Concat, Equal, Fetch, Find, Index, ROPE, Size, SkipTo, Substr], RopeIO USING [FromFile, ToFile], TiogaFileOps USING [CreateRoot, InsertAsLastChild, Ref, SetContents, SetFormat, SetStyle, Store], UserCredentials USING [Get]; LaurelToPeanut: CEDAR PROGRAM IMPORTS Commander, Convert, IO, Rope, RopeIO, TiogaFileOps, UserCredentials = BEGIN ROPE: TYPE = Rope.ROPE; Node: TYPE = TiogaFileOps.Ref; File: TYPE = REF FileRep; FileRep: TYPE = RECORD[ 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[ date: ROPE, contents: ROPE ]; simpleUserName, userRName: ROPE ¬ NIL; InitUserName: PROC = { uN: ROPE = UserCredentials.Get[].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 }; }; 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]; RETURN[file]; }; 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]]; }; Require["*start*\n"]; SkipTo["\n"]; message.date ¬ DateFromRope[GetFieldContents[m,"\nDate: "]]; message.contents ¬ Rope.Substr[m, index]; RETURN[message]; }; RopeFromMonthArray: TYPE ~ ARRAY BasicTime.MonthOfYear OF ROPE; ropeFromMonth: REF RopeFromMonthArray ~ NEW[RopeFromMonthArray ¬ [ January: "Jan", February: "Feb", March: "Mar", April: "Apr", May: "May", June: "Jun", July: "Jul", August: "Aug", September: "Sep", October: "Oct", November: "Nov", December: "Dec", unspecified: "???"]]; DateFromRope: PROC[rope: ROPE] RETURNS[ROPE] ~ { time: BasicTime.Unpacked ~ Convert.UnpackedTimeFromRope[rope ! Convert.Error => GOTO Fail]; day: INT ~ time.day; month: ROPE ~ ropeFromMonth[time.month]; year: [0..100) ~ time.year MOD 100; RETURN[IO.PutFR["%2g-%g-%02g", IO.int[day], IO.rope[month], IO.int[year]]]; EXITS Fail => RETURN["??-???-??"]; }; 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, sender: ROPE ¬ NIL; date ¬ message.date; sender ¬ GetFieldContents[message.contents, "From: "]; IF Rope.Equal[sender, userRName, FALSE] OR Rope.Equal[sender, simpleUserName, FALSE] THEN name ¬ Rope.Concat["To: ", GetFieldContents[message.contents, "\nTo: "]] ELSE name ¬ sender; subject ¬ GetFieldContents[message.contents, "\nSubject: "]; header ¬ IO.PutFR["\t%g\t%g\t%g", IO.rope[date], IO.rope[Truncate[name, 16]], IO.rope[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; }; ReadFiles: PROC[list: ROPE, s: IO.STREAM] = { count: INT ¬ 0; listStream: IO.STREAM ¬ IO.RIS[list]; GetNextFile: PROCEDURE [] RETURNS [ROPE] = { token: ROPE ¬ IO.GetTokenRope[listStream,IO.IDProc].token; dot: INT ¬ Rope.SkipTo[token,0,"."]; IF dot=Rope.Size[token] THEN RETURN[token] ELSE RETURN[Rope.Substr[base: token, len: dot]]; }; DO log: ROPE ¬ NIL; start, length: INT ¬ 0; count: INT ¬ 0; file: File ¬ CreateFile[GetNextFile[! IO.EndOfStream => EXIT]]; s.PutRope["Opening "]; s.PutRope[file.filename]; s.PutRope["..."]; log ¬ RopeIO.FromFile[file.filename ! ANY => CONTINUE]; IF log=NIL THEN { s.PutRope["unable to open file!\n"]; LOOP }; 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"]; LOOP }; s.PutRope["Reading...\n"]; RopeIO.ToFile[Rope.Cat[file.name,".laurel"],log]; WHILE start { s.Put[IO.rope["message number"], IO.int[count],IO.rope[ "... failed!\n"]]; EXIT}; ]]; 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"]]; s.PutRope["Writing "]; s.PutRope[file.filename]; s.PutRope["..."]; StoreFile[file]; s.PutRope["ok\n"]; ENDLOOP; }; LaurelToPeanutCommand: Commander.CommandProc = { ReadFiles[cmd.commandLine, cmd.out]; }; InitUserName[]; Commander.Register["LaurelToPeanut", LaurelToPeanutCommand, "Create Peanut mail files from a list of Laurel mail files. If no extension, '.mail' is assumed. Old files are renamed xxx.laurel"]; END. . LaurelToPeanut.mesa Copyright Σ 1985, 1992 by Xerox Corporation. All rights reserved. Last Edited by: Stone, June 13, 1983 5:11 pm Last edited by Doug Wyatt, August 19, 1985 1:39:51 pm PDT A message in a laurel mail file has the following form: *start* 02203 00112 US Date: xxxx ... message header contents ... /n/n ...message contents ... message.date _ Convert.ValueToRope[[time[DateAndTime.Parse[message.date ! DateAndTime.Unintelligible => {message.date _ "??-???-??"; CONTINUE};].dt]]]; message.date _ Rope.Substr[base: message.date,len: 9]; ΚR•NewlineDelimiter –(cedarcode) style™codešœ™Kšœ Οeœ6™BK™,Kšœ9™9—K˜šΟk ˜ Kšœ žœ˜(Kšœ žœ˜(Kšœžœ˜,KšžœžœHžœžœ˜cKšœžœ*žœ˜PKšœžœ˜ Kšœ žœO˜aKšœžœ˜—K˜Kšœžœž˜Kšžœžœ-˜KKšœž˜K˜Kšžœžœžœ˜K˜Kšœžœ˜K˜Kšœžœžœ ˜šœ žœžœ˜KšœžœΟc˜'Kšœ žœŸ˜,Kšœ Ÿ ˜Kšœ Ÿ˜!K˜—K˜Kšœ žœžœ ˜šœ žœžœ˜Kšœžœ˜ Kšœ ž˜K˜—K˜Kšœžœžœ˜&K˜šΟn œžœ˜Kšœžœ˜&Kšœžœ˜Kšžœžœ<˜IKšžœ>˜BK˜—K˜K˜š  œžœžœžœ ˜.Kšœ žœ ˜K˜K˜+K˜&K˜)K˜6K˜3Kšžœ˜ K˜—K˜K˜K™—K™Kšœ žœžœ˜K˜š  œžœžœžœ ˜0Kšœžœ ˜#Kšœžœ˜š œžœžœ˜Kšœžœ ˜Kšžœžœ˜?Kšžœžœ ˜K˜—š œžœžœ˜Kšœžœ ˜K˜,K˜—š  œžœžœžœžœ˜'Kšœžœ ˜Kšœžœ˜"K˜Kšžœ#˜)K˜—K˜K˜ šœI™IKšœ;žœ ™M—Kšœ6™6K˜K˜Kšœžœžœ˜+K˜$Kšžœ žœ&žœ˜K˜BK˜K˜Kšžœ˜—K˜—K˜š œ˜0Kšœ$˜$K˜—K˜K˜K˜šœ;˜;K˜„—K˜Kšžœ˜—…—ψ$x