DIRECTORY BasicTime USING [GMT, Now], DB USING [ BoolType, EntitySet, GMT, IntType, RopeType, TimeType, DeclareAttribute, DeclareDomain, DeclareEntity, DeclareIndex, DeclareRelation, DeclareRelship, DestroyEntity, DestroyRelship, DomainSubset, Eq, GetF, GetP, GetPList, NameOf, NextEntity, NextRelship, Null, RelationSubset, ReleaseEntitySet, ReleaseRelshipSet, SetP, SetPList, S2V, T2V, V2I, V2T], IO, Rope, WalnutDB, WalnutVoice USING [MakeInterestEntry, VoiceMoveTo], WalnutLog USING [MsgRec, MessageRecObject, currentSegment, msgIDRope, GenerateNewMsgID, RopeFromLog, TiogaTextFromLog], WalnutSendOps USING [userRName, simpleUserName, RFC822Date], WalnutStream USING [MakeLogEntry]; WalnutDBImpl: CEDAR MONITOR IMPORTS DB, IO, Rope, BasicTime, WalnutDB, WalnutLog, WalnutSendOps, WalnutStream, WalnutVoice EXPORTS WalnutDB = BEGIN OPEN DB, WalnutDB; MsgDomain: PUBLIC Domain; MsgSetDomain: PUBLIC Domain; activeMsgSet: PUBLIC MsgSet; deletedMsgSet: PUBLIC MsgSet; msNumInSet: PUBLIC Relation; msNumInSetOf: PUBLIC Attribute; -- MsgSet msNumInSetIs: PUBLIC Attribute; -- INT mDateCode: PUBLIC Relation; mDateCodeOf: PUBLIC Attribute; -- Msg mDateCodeIs: PUBLIC Attribute; -- Time mSubject: PUBLIC Relation; mSubjectOf: PUBLIC Attribute; -- Msg mSubjectIs: PUBLIC Attribute; -- string mCategory: PUBLIC Relation; mCategoryOf: PUBLIC Attribute; -- Msg mCategoryIs: PUBLIC Attribute; -- MsgSet mCategoryDate: PUBLIC Attribute; -- Index on Category & Date mInReplyTo: PUBLIC Relation; mInReplyToOf: PUBLIC Attribute; -- Msg mInReplyToMsg: PUBLIC Attribute; -- Msg mInReplyToIs: PUBLIC Attribute; -- the string from the msg mTOCEntry: PUBLIC Relation; mTOCEntryOf: PUBLIC Attribute; -- Msg mTOCEntryIs: PUBLIC Attribute; -- string mLogPos: PUBLIC Relation; mLogPosOf: PUBLIC Attribute; -- Msg mPrefixPos: PUBLIC Attribute; -- int mHeadersPos: PUBLIC Attribute; -- int mMsgLength: PUBLIC Relation; mMsgLengthOf: PUBLIC Attribute; -- Msg mMsgLengthIs: PUBLIC Attribute; -- int mHasBeenRead: PUBLIC Relation; mHasBeenReadOf: PUBLIC Attribute; -- Msg mHasBeenReadIs: PUBLIC Attribute; -- bool NumInNegative: SIGNAL[msgSet: ROPE] = CODE; SetUpdatesPendingProc: PROC[BOOL]_ DefaultUpdateProc; DeclareMsg: PUBLIC ENTRY PROC[mName: ROPE, version: Version_ NewOrOld] RETURNS [msg: Msg, existed: BOOL] = BEGIN ENABLE UNWIND => NULL; msg_ DeclareEntity[MsgDomain, mName, OldOnly]; IF msg#NIL THEN RETURN[msg, TRUE]; IF version = NewOrOld THEN { msg_ DeclareEntity[MsgDomain, mName]; SetUpdatesPendingProc[TRUE]; }; RETURN[msg, FALSE] END; DeclareMsgSet: PUBLIC ENTRY PROC[msName: ROPE, version: Version_ NewOrOld] RETURNS [msgSet: MsgSet, existed: BOOL] = BEGIN ENABLE UNWIND => NULL; msgSet_ DeclareEntity[MsgSetDomain, msName, OldOnly]; IF msgSet#NIL THEN RETURN[msgSet, TRUE]; IF version = NewOrOld THEN { msgSet_ DeclareEntity[MsgSetDomain, msName]; SetUpdatesPendingProc[TRUE]; }; RETURN[msgSet, FALSE]; END; DestroyMsgSet: PUBLIC ENTRY PROC[msgSet: MsgSet] RETURNS[newRelList: LIST OF Relship] = BEGIN ENABLE UNWIND => NULL; rel, newRel: Relship; relListEnd: LIST OF Relship; rs: RelshipSet_ RelationSubset[mCategory, LIST[[mCategoryIs, msgSet]]]; UNTIL DB.Null[rel_ NextRelship[rs]] DO msg: Msg_ V2E[GetF[rel, mCategoryOf]]; IF (newRel_ RemoveFrom[msg, msgSet, rel]) # NIL THEN IF relListEnd=NIL THEN newRelList_ relListEnd_ CONS[newRel, NIL] ELSE relListEnd.rest_ relListEnd_ CONS[newRel, NIL]; ENDLOOP; ReleaseRelshipSet[rs]; IF ~EqEntities[msgSet, activeMsgSet] THEN DestroyEntity[msgSet]; SetUpdatesPendingProc[TRUE]; END; AddMsgToMsgSet: PUBLIC ENTRY PROC[msg: Msg, msgSet: MsgSet] RETURNS[rel: Relship, existed: BOOL] = { ENABLE UNWIND => NULL; IF Eq[msgSet, deletedMsgSet] THEN RETURN[NIL, FALSE]; -- can't AddTo "Deleted" [rel, existed]_ AddTo[msg, msgSet] }; RemoveMsgFromMsgSet: PUBLIC ENTRY PROC[msg: Msg, msgSet: MsgSet, rel: Relship_ NIL] RETURNS[newRel: Relship] = { ENABLE UNWIND => NULL; RETURN[RemoveFrom[msg, msgSet, rel]]}; SetMsgHasBeenRead: PUBLIC ENTRY PROC[msg: Msg] = BEGIN ENABLE UNWIND => NULL; []_ SetP[msg, mHasBeenReadIs, B2V[TRUE]]; SetUpdatesPendingProc[TRUE]; END; InitializeDBVars: PUBLIC ENTRY PROC = BEGIN ENABLE UNWIND => NULL; MsgDomain_ DeclareDomain[name: "Msg", segment: WalnutLog.currentSegment, estRelships: 10]; MsgSetDomain_ DeclareDomain["MsgSet", WalnutLog.currentSegment]; msNumInSet_ DeclareRelation["msNumInSet", WalnutLog.currentSegment]; msNumInSetOf_ DeclareAttribute[msNumInSet, "of", MsgSetDomain, Key]; -- MsgSet msNumInSetIs_ DeclareAttribute[msNumInSet, "is", IntType]; -- INT mDateCode_ DeclareRelation["mDateCode", WalnutLog.currentSegment]; mDateCodeOf_ DeclareAttribute[mDateCode, "of", MsgDomain, Key]; -- Msg mDateCodeIs_ DeclareAttribute[mDateCode, "is", TimeType]; -- Time: []_ DeclareIndex[mDateCode, LIST[mDateCodeIs], NewOrOld]; mSubject_ DeclareRelation["mSubject", WalnutLog.currentSegment]; mSubjectOf_ DeclareAttribute[mSubject, "of", MsgDomain, Key]; -- Msg mSubjectIs_ DeclareAttribute[mSubject, "is", RopeType]; -- string mCategory_ DeclareRelation["mCategory", WalnutLog.currentSegment]; mCategoryOf_ DeclareAttribute[mCategory, "of", MsgDomain]; -- Msg mCategoryIs_ DeclareAttribute[mCategory, "is", MsgSetDomain --, link: FALSE --]; -- MsgSet mCategoryDate_ DeclareAttribute[mCategory, "date", TimeType]; -- Time []_ DeclareIndex[mCategory, LIST[mCategoryIs, mCategoryDate], NewOrOld]; mInReplyTo_ DeclareRelation["mInReplyTo", WalnutLog.currentSegment]; mInReplyToOf_ DeclareAttribute[mInReplyTo, "of", MsgDomain, OptionalKey]; -- Msg mInReplyToIs_ DeclareAttribute[mInReplyTo, "is", RopeType]; -- Msg mTOCEntry_ DeclareRelation["mTOCEntry", WalnutLog.currentSegment]; mTOCEntryOf_ DeclareAttribute[mTOCEntry, "of", MsgDomain, Key]; -- Msg mTOCEntryIs_ DeclareAttribute[mTOCEntry, "is", RopeType]; -- string mLogPos_ DeclareRelation["mLogPos", WalnutLog.currentSegment]; mLogPosOf_ DeclareAttribute[mLogPos, "of", MsgDomain, Key]; -- Msg mPrefixPos_ DeclareAttribute[mLogPos, "prefix", IntType]; -- int mHeadersPos_ DeclareAttribute[mLogPos, "headers", IntType]; -- int mMsgLength_ DeclareRelation["mMsgLength", WalnutLog.currentSegment]; mMsgLengthOf_ DeclareAttribute[mMsgLength, "of", MsgDomain, Key]; -- Msg mMsgLengthIs_ DeclareAttribute[mMsgLength, "length", IntType]; -- int mHasBeenRead_ DeclareRelation["mHasBeenRead", WalnutLog.currentSegment]; mHasBeenReadOf_ DeclareAttribute[mHasBeenRead, "of", MsgDomain, Key]; -- Msg mHasBeenReadIs_ DeclareAttribute[mHasBeenRead, "is", BoolType]; -- bool activeMsgSet_ DeclareEntity[MsgSetDomain, "Active"]; -- NewOrOld deletedMsgSet_ DeclareEntity[MsgSetDomain, "Deleted"]; END; TiogaMsgFromLog: PUBLIC PROC[msg: Msg] RETURNS[contents: TiogaContents, startPos, length: INT] = BEGIN startPos_ V2I[GetP[msg, mHeadersPos]]; length_ V2I[GetP[msg, mMsgLengthIs]]; contents_ WalnutLog.TiogaTextFromLog[startPos, length]; END; NumInMsgSet: PUBLIC ENTRY PROC[msgSet: MsgSet] RETURNS[INT] = { ENABLE UNWIND => NULL; RETURN[V2I[GetP[msgSet, msNumInSetIs]]] }; ArchiveMsgSet: PUBLIC ENTRY PROC[msgSet: MsgSet, strm: IO.STREAM, doDelete: BOOL] RETURNS[newRelList: LIST OF Relship] = BEGIN ENABLE UNWIND => NULL; rel, newRel: Relship; endRL: LIST OF Relship_ NIL; rs: RelshipSet_ RelationSubset[mCategory, LIST[[mCategoryIs, msgSet]]]; restOfPrefix: ROPE_ Rope.Cat["\nCategories: ", DB.NameOf[msgSet], "\n"]; UNTIL DB.Null[rel_ NextRelship[rs]] DO msg: Msg_ V2E[GetF[rel, mCategoryOf]]; startPos: INT_ V2I[GetP[msg, mHeadersPos]]; length: INT_ V2I[GetP[msg, mMsgLengthIs]]; fullText: ROPE_ WalnutLog.RopeFromLog[startPos, length]; prefix: ROPE_ Rope.Cat[WalnutLog.msgIDRope, ": ", DB.NameOf[msg], restOfPrefix]; []_ WalnutStream.MakeLogEntry[strm, message, fullText, prefix]; IF doDelete THEN { newRel_ RemoveFrom[msg, msgSet, rel]; IF newRelList = NIL THEN newRelList_ endRL_ CONS[newRel, NIL] ELSE endRL_ endRL.rest_ CONS[newRel, NIL]; }; ENDLOOP; ReleaseRelshipSet[rs]; END; NameToEntity: PUBLIC ENTRY PROC[d: Domain, name: ROPE, version: Version] RETURNS[e: Entity] = BEGIN ENABLE UNWIND => NULL; e_ DeclareEntity[d, name, OldOnly]; IF e=NIL AND version=NewOrOld THEN e_ DeclareEntity[d, name, NewOnly]; END; GetEntitiesInDomain: PUBLIC ENTRY PROC[d: Domain, alphaOrder: BOOL] RETURNS[eL: LIST OF Entity] = BEGIN ENABLE UNWIND => NULL; eLend: LIST OF Entity; es: EntitySet_ IF alphaOrder THEN DomainSubset[d, NIL, "", "\177"] ELSE DomainSubset[d]; e: Entity_ NextEntity[es]; IF e=NIL THEN RETURN[NIL]; eL_ eLend_ CONS[e, NIL]; UNTIL DB.Null[e_ NextEntity[es]] DO eLend_ eLend.rest_ CONS[e, NIL]; ENDLOOP; ReleaseEntitySet[es]; END; RelationSubsetList: PUBLIC ENTRY PROC[r: Relation, constraint: AttributeValueList_ NIL] RETURNS[relList: LIST OF Relship] = BEGIN ENABLE UNWIND => NULL; rs: RelshipSet_ RelationSubset[r, constraint]; rel: Relship_ NextRelship[rs]; rLend: LIST OF Relship; IF rel = NIL THEN RETURN; relList_ rLend_ CONS[rel, NIL]; UNTIL DB.Null[rel_ NextRelship[rs]] DO rLend_ rLend.rest_ CONS[rel, NIL]; ENDLOOP; ReleaseRelshipSet[rs]; END; GetFE: PUBLIC ENTRY PROC[rel: Relship, a: Attribute] RETURNS [Entity] = { ENABLE UNWIND => NULL; RETURN[V2E[DB.GetF[rel, a]]] }; GetName: PUBLIC ENTRY PROC[e: Entity] RETURNS [ROPE] = { ENABLE UNWIND => NULL; RETURN[DB.NameOf[e]] }; Null: PUBLIC ENTRY PROC[e: Entity] RETURNS [BOOL] = { ENABLE UNWIND => NULL; RETURN[DB.Null[e]] }; MGetP: PUBLIC ENTRY PROC[m: Msg, prop: Attribute] RETURNS [Value] = { ENABLE UNWIND => NULL; RETURN[DB.GetP[m, prop]] }; MSetPList: PUBLIC ENTRY PROC[m: Msg, prop: Attribute, vl: LIST OF Value] = BEGIN ENABLE UNWIND => NULL; DB.SetPList[m, prop, vl]; SetUpdatesPendingProc[TRUE]; END; MSetP: PUBLIC ENTRY PROC[m: Msg, prop: Attribute, v: Value] RETURNS [rel: Relship] = BEGIN ENABLE UNWIND => NULL; rel_ DB.SetP[m, prop, v]; SetUpdatesPendingProc[TRUE]; END; AcquireDBLock: PUBLIC ENTRY PROC[procToCall: PROC] = BEGIN ENABLE UNWIND => NULL; procToCall[]; END; RegisterUpdatesPendingProc: PUBLIC ENTRY PROC[proc: PROC[BOOL]] = { ENABLE UNWIND => NULL; SetUpdatesPendingProc_ proc}; UnRegisterUpdatesPendingProc: PUBLIC ENTRY PROC[proc: PROC[BOOL]] = { ENABLE UNWIND => NULL; IF SetUpdatesPendingProc = proc THEN SetUpdatesPendingProc_ DefaultUpdateProc }; DefaultUpdateProc: PROC[BOOL] = { NULL }; MsgRecToMsg: PUBLIC PROC[mr: WalnutLog.MsgRec] RETURNS[msg: Msg, mExisted: BOOL, newMsgSetList: LIST OF MsgSet, newRelList: LIST OF RelshipMsgSetPair] = BEGIN CategoryRelshipList: PROC[msgSetName: ROPE] = BEGIN msgSet: MsgSet; msExisted, rExisted: BOOL; rel: Relship; [msgSet, msExisted]_ DeclareMsgSet[msgSetName, NewOrOld]; IF ~msExisted THEN newMsgSetList_ CONS[msgSet, newMsgSetList]; [rel, rExisted]_ AddToMsgSet[msg, msgSet]; IF ~rExisted THEN newRelList_ CONS[[rel, msgSet], newRelList]; END; DO [msg, mExisted]_ DeclareMsg[mr.gvID, NewOrOld]; IF ~mExisted THEN BEGIN pos: INT_ mr.gvID.Find["$"]+1; -- $ is not allowed in names, so it's unique date: ROPE_ GetTocDate[mr]; toc: ROPE_ IF mr.from.Equal[WalnutSendOps.userRName, FALSE] OR mr.from.Equal[WalnutSendOps.simpleUserName, FALSE] THEN Rope.Concat["To: ", mr.to] ELSE mr.from; mr.tocEntry_ Rope.Cat[date, " ", toc]; SetMsgAttributes[msg, mr]; IF mr.voiceID.Length[] # 0 THEN WalnutVoice.MakeInterestEntry[mr.voiceID, mr.gvID]; IF mr.categoriesList = NIL THEN CategoryRelshipList["Active"] -- add to msgSets ELSE FOR cL: LIST OF ROPE_ mr.categoriesList, cL.rest UNTIL cL = NIL DO CategoryRelshipList[cL.first] ENDLOOP; RETURN END -- new msg ELSE BEGIN len: INT_ V2I[GetP[msg, mMsgLengthIs]]; subj: ROPE; IF len # mr.msgLength THEN { WalnutLog.GenerateNewMsgID[mr]; LOOP}; subj_ V2S[GetP[msg, mSubjectIs]]; IF ~Rope.Equal[subj, mr.subject] THEN { WalnutLog.GenerateNewMsgID[mr]; LOOP}; RETURN; -- old msg END; ENDLOOP; -- in case need to change mr.gvID END; GetTocDate: PROC[mr: WalnutLog.MsgRec] RETURNS[date: ROPE] = BEGIN tyme: BasicTime.GMT; IF mr.date = NIL THEN mr.date_ WalnutSendOps.RFC822Date[]; BEGIN -- get date into canonical form ris: IO.STREAM_ IO.RIS[mr.date]; tyme_ IO.GetTime[ris ! IO.Error => GOTO badTime]; EXITS badTime => tyme_ BasicTime.Now[]; END; date_ Rope.Substr[WalnutSendOps.RFC822Date[tyme], 0, 9]; -- only want first 9 chars of date DO i: INT_ date.Find["-"]; IF i < 0 THEN RETURN; date_ date.Replace[i, 1, " "]; ENDLOOP; END; AddToMsgSet: ENTRY PROC[msg: Msg, msgSet: MsgSet] RETURNS[rel: Relship, existed: BOOL] = { ENABLE UNWIND => NULL; [rel, existed]_ AddTo[msg, msgSet] }; SetMsgAttributes: ENTRY PROC[msg: Msg, mr: WalnutLog.MsgRec] = BEGIN ENABLE UNWIND => NULL; []_ SetP[msg, mDateCodeIs, T2V[LOOPHOLE[mr.dateCode, DB.GMT]]]; []_ SetP[msg, mInReplyToIs, S2V[mr.inReplyTo]]; []_ SetP[msg, mHasBeenReadIs, B2V[mr.hasBeenRead]]; []_ SetP[msg, mTOCEntryIs, S2V[mr.tocEntry]]; []_ SetP[msg, mSubjectIs, S2V[mr.subject]]; []_ SetP[msg, mPrefixPos, I2V[mr.prefixPos]]; []_ SetP[msg, mMsgLengthIs, I2V[mr.msgLength]]; []_ SetP[msg, mHeadersPos, I2V[mr.headersPos]]; END; AddTo: INTERNAL PROC[msg: Msg, msgSet: MsgSet] RETURNS[rel: Relship, existed: BOOL] = BEGIN avl: AttributeValueList; avl_ LIST[[mCategoryOf, msg], [mCategoryIs, msgSet], [mCategoryDate, GetP[msg, mDateCodeIs]]]; rel_ DeclareRelship[mCategory, avl, OldOnly]; IF existed_ (rel # NIL) THEN RETURN; -- msg is already in this msgSet rel_ DeclareRelship[mCategory, avl, NewOnly]; ChangeNumInSet[msgSet, 1]; SetUpdatesPendingProc[TRUE]; WalnutVoice.VoiceMoveTo[DB.NameOf[msgSet], DB.NameOf[msg]]; END; RemoveFrom: INTERNAL PROC[msg: Msg, msgSet: MsgSet, rel: Relship] RETURNS[newRel: Relship] = BEGIN IF rel = NIL THEN { rs: RelshipSet_ RelationSubset[mCategory, LIST[[mCategoryOf, msg]]]; UNTIL DB.Null[rel_ NextRelship[rs]] DO IF Eq[msgSet, V2E[GetF[rel, mCategoryIs]]] THEN EXIT; ENDLOOP; ReleaseRelshipSet[rs]; }; IF rel = NIL THEN RETURN; -- ignore this call DestroyRelship[rel]; -- MEraseP[msg, mCategoryIs, msgSet]; ChangeNumInSet[msgSet, -1]; IF GetPList[msg, mCategoryIs] = NIL THEN newRel_ AddTo[msg, deletedMsgSet].rel; SetUpdatesPendingProc[TRUE]; END; ChangeNumInSet: INTERNAL PROC[msgSet: MsgSet, inc: INT] = INLINE BEGIN num: INT_ V2I[GetP[msgSet, msNumInSetIs]] + inc; IF (inc < 0) AND (num = -1) THEN SIGNAL NumInNegative[DB.NameOf[msgSet]]; []_ SetP[msgSet, msNumInSetIs, I2V[num]]; END; notExist: ROPE = "MsgSet: %g doesn't exist"; msNumIn: ROPE = "msNumInSetIs for MsgSet: %g is %g messages"; enumNumIn: ROPE = "Enumeration of MsgSet: %g says %g messages"; NumIn: PROC[msName: ROPE] RETURNS[ans: ROPE] = BEGIN msgSet: MsgSet_ DeclareEntity[MsgSetDomain, msName, OldOnly]; num: INT; IF msgSet = NIL THEN RETURN[IO.PutFR[notExist, IO.rope[msName]]]; num_ V2I[GetP[msgSet, msNumInSetIs]]; RETURN[IO.PutFR[msNumIn, IO.rope[msName], IO.int[num]]]; END; Enum: PROC[msName: ROPE] RETURNS[ans: ROPE] = BEGIN msgSet: MsgSet_ DeclareEntity[MsgSetDomain, msName, OldOnly]; num: INT_ 0; rel: Relship; rs: RelshipSet; IF msgSet = NIL THEN RETURN[IO.PutFR[notExist, IO.rope[msName]]]; rs_ RelationSubset[mCategory, LIST[[mCategoryIs, msgSet]]]; UNTIL DB.Null[rel_ NextRelship[rs]] DO num_ num + 1; ENDLOOP; ReleaseRelshipSet[rs]; RETURN[IO.PutFR[enumNumIn, IO.rope[msName], IO.int[num]]]; END; SetNumIn: PROC[msName: ROPE, num: INT] RETURNS[ans: ROPE] = BEGIN msgSet: MsgSet_ DeclareEntity[MsgSetDomain, msName, OldOnly]; IF msgSet = NIL THEN RETURN[IO.PutFR[notExist, IO.rope[msName]]]; []_ SetP[msgSet, msNumInSetIs, I2V[num]]; RETURN[IO.PutFR["msNumInSetIs for MsgSet: %g has been set to %g", IO.rope[msName], IO.int[num]]]; END; CheckAll: PROC RETURNS[ans: ROPE] = BEGIN rs: RelshipSet; rel: Relship; num, enum: INT; msgSet: Entity; eL: LIST OF Entity_ GetEntitiesInDomain[d: MsgSetDomain, alphaOrder: TRUE]; FOR elT: LIST OF Entity_ eL, elT.rest UNTIL elT=NIL DO msgSet_ elT.first; num_ V2I[GetP[msgSet, msNumInSetIs]]; enum_ 0; rs_ RelationSubset[mCategory, LIST[[mCategoryIs, msgSet]]]; UNTIL DB.Null[rel_ NextRelship[rs]] DO enum_ enum + 1; ENDLOOP; ReleaseRelshipSet[rs]; IF num # enum THEN ans_ Rope.Cat[ans, " ", DB.NameOf[msgSet]]; ENDLOOP; IF ans.Length[] = 0 THEN RETURN["All msgsets are ok"]; END; DateCode: PROC[mName: ROPE] RETURNS[ans: ROPE] = BEGIN msg: Msg_ DeclareEntity[MsgDomain, mName, OldOnly]; date: BasicTime.GMT_ V2T[GetP[msg, mDateCodeIs]]; dr: ROPE_ WalnutSendOps.RFC822Date[date]; IF msg = NIL THEN RETURN[IO.PutFR["Msg: %g doesn't exist", IO.rope[mName]]]; date_ V2T[GetP[msg, mDateCodeIs]]; RETURN[IO.PutFR["Msg: %g has DateCode: %g", IO.rope[mName], IO.rope[dr]]]; END; GetMsgAttributes: PROC[name: ROPE] RETURNS[mr: WalnutLog.MsgRec] = BEGIN msg: Msg_ DeclareEntity[MsgDomain, name, OldOnly]; IF DB.Null[msg] THEN RETURN[NIL]; mr_ NEW[WalnutLog.MessageRecObject]; mr.dateCode_ V2T[GetP[msg, mDateCodeIs]]; mr.inReplyTo_ V2S[GetP[msg, mInReplyToIs]]; mr.hasBeenRead_ V2B[GetP[msg, mHasBeenReadIs]]; mr.tocEntry_ V2S[GetP[msg, mTOCEntryIs]]; mr.subject_ V2S[GetP[msg, mSubjectIs]]; mr.prefixPos_ V2I[GetP[msg, mPrefixPos]]; mr.msgLength_ V2I[GetP[msg, mMsgLengthIs]]; mr.headersPos_ V2I[GetP[msg, mHeadersPos]]; END; END. ΔWalnutDBImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Contents: implementation for making changes in Walnut's database this is the monitored access to the database Willie-Sue, March 20, 1985 9:04:59 am PST Last Edited by: Willie-Sue, August 21, 1984 2:51:21 pm PDT Last Edited by: Donahue, July 15, 1983 1:17 pm ******************************************************** Relations on Msg entities: all have one relship per Msg unless otherwise noted. ******************************************************** ******************************************************** each operation here has a parallel operation in WalnutDBLog, which writes an entry on the current log the following are exported in WalnutDB Creates a new Msg entity (unless version = oldOnly), and sets its name to be mName. is called when messages have been read from the log or another file. If the Msg already exists, returns it and existed=TRUE Creates a new MsgSet entity (unless version = oldOnly), and sets its name to be mName. is called when user creates a message set, or a log file is read If the MsgSet already exists, returns it and existed=TRUE. DestroyMsg is not allowed; this is ONLY done by the Expunge operation Destroys the given msgSet, removing any messages from it first Adds Msg to MsgSet, if it's not already in it IF msgSet=deletedMsgSet, does nothing & returns rel=NIL, existed=FALSE rel can be NIL, in which case it is found from the database IF removing msg from msgSet would leave it in no MsgSet, then msg gets added to the distinguished MsgSet Deleted, and returns that new Relship does nothing if this Relship doesn't exist (no ERROR generated) sets the mHasBeenReadIs attribute for msg to TRUE (no check on old value) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * declare and initialize Walnut's data schema reads tioga text for msg from log needs to be entirely inside the DB monitor if doDelete is TRUE, relturns list of newRels for msgs added to Deleted returns list of entities in given domain Finds the one unique value for prop for m or NIL if none. SIGNALs NonUniquePropertyValue if more than one value. Sets the values of prop for m to be those in vl. Erases any previous property values. Sets the value of prop for m to be v. Erases any previous property value(s). Returns the relship used by the prop. to allow extended use of lock on database * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Converts msg from record to entity form make up TOC entry check if this really is an old msg - only check msgLength & subject fields * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * IF ~EqEntities[msgSet, deletedMsgSet] THEN { avl_ LIST[[mCategoryOf, msg], [mCategoryIs, deletedMsgSet], [mCategoryDate, GetP[msg, mDateCodeIs]]]; rel_ DeclareRelship[mCategory, avl, OldOnly]; IF rel # NIL THEN -- msg is in Deleted, must remove it { DestroyRelship[rel]; ChangeNumInSet[deletedMsgSet, -1]}; }; rel can be NIL, in which case it is found from the database does nothing if this Relship doesn't exist (no ERROR generated) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * debugging procs ΚΕ˜šœ™Icodešœ Οmœ1™<—Jšœ@™@šœ,™,K™)—J˜Jšœ:™:Jšœ.™.J˜šΟk ˜ Jšœ žœžœ˜šžœžœžœ˜AJ˜=J˜MJ˜PJ˜I—Jšžœ˜J˜J˜ Jšœ žœ"˜3šœ žœ˜*J˜J˜1—Jšœžœ)˜™>šžœžœžœžœ˜J˜Jšœ žœžœ ˜Jšœ*žœ˜Gšžœžœž˜&J˜&šžœ*žœž˜4š žœ žœžœžœ žœ˜@Jšžœžœ žœ˜4———Jšžœ˜J˜J˜Jšžœ#žœ˜@Jšœžœ˜—Jšžœ˜J˜——š œžœžœžœ˜;Jšžœžœ˜&—Jšœ-™-šœF™Fšœžœžœžœ˜Jš žœžœžœžœžœŸ˜NJ˜"—J˜J˜—š  œžœžœžœ)žœ˜SJšžœ˜—Jšœ;™;JšœO™OJšœ>™>šœ?™?Jš œžœžœžœžœ!˜@J˜—Jš œžœžœžœ ˜0šœI™Išžœžœžœžœ˜Jšœ"žœ˜)Jšœžœ˜—Jšžœ˜J˜—JšœE™EJšœ+™+J˜š œžœžœžœ˜%Jšžœžœžœžœ˜˜˜ J˜O—J˜@J˜˜DJšœEŸ ˜NJšœ;Ÿ˜AJ˜—˜BJšœAŸ˜GJšœ:Ÿ˜BJ˜—Jšœžœ˜9J˜˜@Jšœ>Ÿ˜DJšœ8Ÿ ˜A—˜BJšœ;Ÿ˜AJšœ<ŸœŸ ˜ZJšœ>Ÿ˜EJ˜—Jšœžœ(˜HJ˜˜DJšœJŸ˜PJšœ<Ÿ˜B—˜BJšœ@Ÿ˜FJšœ:Ÿ ˜CJ˜—˜>Jšœ<Ÿ˜BJšœ:Ÿ˜@Jšœ<Ÿ˜B—J˜DšœBŸ˜HJšœ?Ÿ˜EJ˜H—šœFŸ˜LJšœ@Ÿ˜GJ˜Jšœ6Ÿ ˜AJ˜6——Jšžœ˜J˜—š œžœžœ ˜&Jšžœ,žœ˜9—šœ!™!šž˜J˜&J˜%J˜7—Jšžœ˜J˜—š   œžœžœžœžœžœ˜=Jš œžœžœžœžœ$˜CJ˜—š  œžœžœžœžœžœ žœ˜QJšžœ žœžœ ˜&—Jšœ*™*šœG™Gšžœžœžœžœ˜J˜Jšœžœžœ žœ˜Jšœ*žœ˜GJšœžœžœ˜Hšžœžœž˜&J˜&Jšœ žœ˜+Jšœžœ˜*Jšœ žœ*˜8Jšœžœ&žœ˜PJ˜?šžœ ž˜˜'š žœžœžœžœ žœ˜=Jšžœžœ žœ˜*—J˜———Jšžœ˜J˜—Jšžœ˜J˜—š   œžœžœžœžœ˜HJšžœ ˜šžœžœžœžœ˜J˜#Jšžœžœžœžœ$˜F—Jšžœ˜J˜—š  œžœžœžœžœ˜CJšžœžœžœ ˜Jšœ(™(šžœžœžœžœ˜Jšœžœžœ˜Jš œžœ žœžœžœ˜XJ˜Jš žœžœžœžœžœ˜Jšœ žœžœ˜Jš žœžœžœžœžœžœ˜MJ˜—Jšžœ˜J˜—š  œžœžœžœ.žœ˜WJšžœ žœžœ ˜#šžœžœžœžœ˜J˜.J˜Jšœžœžœ ˜Jšžœžœžœžœ˜Jšœžœžœ˜Jš žœžœžœžœžœžœ˜RJ˜—Jšžœ˜J˜—š  œžœžœžœžœ ˜GJš œžœžœžœžœžœ˜8J˜—š  œžœžœžœ žœžœ˜6Jš œžœžœžœžœžœ˜0J˜—š  œžœžœžœ žœžœ˜3Jš œžœžœžœžœžœ ˜.J˜—š  œžœžœžœžœ ˜CJšœ9™9šœ6™6Jš œžœžœžœžœžœ˜4J˜——š   œžœžœžœžœžœ ˜JJšœ0™0Jšœ$™$šžœžœžœžœ˜Jšžœ˜Jšœžœ˜—Jšžœ˜J˜—š  œžœžœžœ$žœ˜TJšœ%™%Jšœ&™&Jšœ%™%šžœžœžœžœ˜Jšœžœ˜Jšœžœ˜—Jšžœ˜J˜—Jš   œžœžœžœ žœ˜4šœ)™)šžœžœžœžœ˜J˜ —Jšžœ˜J˜—JšœE™EJ˜š  œžœžœžœžœžœ˜AJšœžœžœžœ˜6J˜—š  œžœžœžœžœžœ˜Cšœžœžœžœ˜Jšžœžœ)˜MJ˜J˜——Jš œžœžœžœ˜)J˜JšœE™EJ˜š  œžœžœ˜.šžœžœ˜!Jš œžœžœžœžœ˜G—Jšœ'™'šž˜š œžœ žœ˜-šž˜J˜Jšœžœ˜J˜ J˜J˜9Jšžœ žœžœ˜>J˜*Jšžœ žœ žœ˜>—šžœ˜J˜———šž˜J˜/šžœ ž˜Jšž˜—šœ™JšœžœŸ,˜LJšœžœ˜šœžœžœ(žœž˜>šœ,žœ˜2Jšžœ˜Jšžœ ˜ ——J˜'J˜Jšžœžœ4˜SšžœžœžœŸ˜Ošž˜Jš žœžœžœžœžœžœž˜BJšœžœ˜&——Jšž˜JšžœŸ ˜—šž˜Jšž˜šœJ™JJšœžœ˜'Jšœžœ˜ Jšžœžœ#žœ˜CJ˜!Jšžœžœ#žœ˜NJšžœŸ ˜—Jšžœ˜—JšžœŸ!˜+—Jšžœ˜J˜—š  œžœžœžœ˜<šž˜Jšœžœ˜Jšžœ žœžœ%˜:šžœŸ˜&Jš œžœžœžœžœ ˜ Jšœžœžœ žœ ˜1šž˜J˜!——Jšžœ˜Jšœ9Ÿ"˜[šž˜Jšœžœ˜Jšžœžœžœ˜J˜—Jšžœ˜—Jšžœ˜J˜—š   œžœžœžœžœ˜Xšœžœžœžœ˜J˜"—J˜J˜—š œžœžœ"˜>šžœžœžœžœ˜Jšœžœžœžœ˜?J˜/J˜3J˜-J˜+J˜-J˜/J˜/—Jšžœ˜J˜—JšœE™EJ˜š  œžœžœžœžœ˜Ušž˜J˜J˜šžœ$ž™*šœžœ2™=J™)J™-šžœžœžœŸ$™6Jšœ:™:——J™—J˜šœžœ+˜4J˜)—J˜-Jš žœžœžœžœŸ ˜FJšœ-˜-J˜Jšœžœ˜Jšœžœžœ˜;—Jšžœ˜J˜—š  œžœžœ(˜AJšžœ˜—Jšœ;™;šœ?™?šžœ˜Jšžœžœž˜šœ,žœ˜Fšžœžœž˜&Jšžœ)žœžœ˜5—Jšžœ˜J˜J˜Jš žœžœžœžœŸ˜.JšœŸ&˜Jšžœ˜Jšžœžœžœ˜6——Jšžœ˜J˜—š  œžœžœžœžœ˜0šž˜J˜3Jšœžœ˜1Jšœžœ!˜)J˜Jš žœžœžœžœžœ žœ˜LJ˜"Jšžœžœ#žœžœ ˜J—Jšžœ˜J˜—š œžœžœžœ˜Bšž˜J˜2Jš žœžœ žœžœžœ˜!J˜Jšœžœ˜$J˜)J˜+J˜/J˜)J˜'J˜)J˜+J˜+—Jšžœ˜J˜—Jšžœ˜J˜J˜—…—Bxf